diff --git a/.changeset/config.json b/.changeset/config.json index 0cfd51439c..7d93c0c8ca 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -1,19 +1,19 @@ { - "$schema": "https://unpkg.com/@changesets/config@3.1.2/schema.json", + "$schema": "https://unpkg.com/@changesets/config@4.0.1/schema.json", "changelog": [ "@changesets/changelog-github", { "repo": "TanStack/form", "disableThanks": true } ], "commit": false, "access": "public", - "baseBranch": "main", + "baseBranch": "alpha", + "privatePackages": { "version": false, "tag": false }, "updateInternalDependencies": "patch", "fixed": [ [ "@tanstack/form-core", "@tanstack/react-form", "@tanstack/react-form-start", - "@tanstack/react-form-remix", "@tanstack/react-form-nextjs", "@tanstack/angular-form", "@tanstack/vue-form", @@ -27,8 +27,5 @@ ] ], "linked": [], - "ignore": [], - "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": { - "onlyUpdatePeerDependentsWhenOutOfRange": true - } + "ignore": [] } diff --git a/.changeset/flat-rats-like.md b/.changeset/flat-rats-like.md new file mode 100644 index 0000000000..4c118e362b --- /dev/null +++ b/.changeset/flat-rats-like.md @@ -0,0 +1,13 @@ +--- +'@tanstack/form-core': patch +'@tanstack/form-devtools': patch +'@tanstack/preact-form': patch +'@tanstack/react-form': patch +--- + +BREAKING: `runOnSubmit` has been renamed in favor of `skipOnSubmit`. That way, it's easier to explain what happens when you omit the property. + +Migration: + +- rename `runOnSubmit` to `skipOnSubmit` +- invert the condition you returned. diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 0000000000..9a89b8a38f --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,4 @@ +{ + "mode": "pre", + "tag": "alpha" +} diff --git a/.changeset/pre/brave-lists-replace.md b/.changeset/pre/brave-lists-replace.md new file mode 100644 index 0000000000..cf377dbac3 --- /dev/null +++ b/.changeset/pre/brave-lists-replace.md @@ -0,0 +1,6 @@ +--- +'@tanstack/form-core': minor +'@tanstack/vue-form': minor +--- + +Restore `field.replaceValue()` and add `form.replaceFieldValue()` for replacing an array element in place diff --git a/.changeset/pre/cyan-papayas-search.md b/.changeset/pre/cyan-papayas-search.md new file mode 100644 index 0000000000..d3ac150b55 --- /dev/null +++ b/.changeset/pre/cyan-papayas-search.md @@ -0,0 +1,10 @@ +--- +'@tanstack/preact-form': minor +'@tanstack/svelte-form': minor +'@tanstack/react-form': minor +'@tanstack/solid-form': minor +'@tanstack/form-core': minor +'@tanstack/vue-form': minor +--- + +Feature: Specify default options for `createFormHook` diff --git a/.changeset/pre/fast-yaks-kneel.md b/.changeset/pre/fast-yaks-kneel.md new file mode 100644 index 0000000000..d46f669297 --- /dev/null +++ b/.changeset/pre/fast-yaks-kneel.md @@ -0,0 +1,5 @@ +--- +'@tanstack/form-core': patch +--- + +`onSubmit` now has access to `createErrorMap` diff --git a/.changeset/pre/forty-eyes-fall.md b/.changeset/pre/forty-eyes-fall.md new file mode 100644 index 0000000000..103c0c7d8d --- /dev/null +++ b/.changeset/pre/forty-eyes-fall.md @@ -0,0 +1,18 @@ +--- +'@tanstack/angular-form': patch +'@tanstack/preact-form': patch +'@tanstack/svelte-form': patch +'@tanstack/react-form': patch +'@tanstack/solid-form': patch +'@tanstack/form-core': patch +'@tanstack/lit-form': patch +'@tanstack/vue-form': patch +--- + +Refactor: Adapter `formOptions`/`appFormOptions` no longer shim the core types and runtime. + +BREAKING: `formOptions.looseSchema` and `formOptions.strictSchema` now require a schema as +first parameter. This locks down inference to get the best type safety out of it vs. the options object alone. + +Fix: `formOptions.looseSchema` now allows `defaultValues` to omit properties instead of +requiring them to be explicitly undefined. diff --git a/.changeset/pre/gentle-forms-default.md b/.changeset/pre/gentle-forms-default.md new file mode 100644 index 0000000000..0566f72803 --- /dev/null +++ b/.changeset/pre/gentle-forms-default.md @@ -0,0 +1,5 @@ +--- +'@tanstack/react-form': minor +--- + +Add default form, field, and form group options to `createFormHook`. diff --git a/.changeset/pre/grumpy-seals-dig.md b/.changeset/pre/grumpy-seals-dig.md new file mode 100644 index 0000000000..2c2655ac35 --- /dev/null +++ b/.changeset/pre/grumpy-seals-dig.md @@ -0,0 +1,21 @@ +--- +'@tanstack/angular-form': minor +'@tanstack/form-core': minor +'@tanstack/preact-form': minor +'@tanstack/react-form': minor +--- + +BREAKING: `schemaOutputs` no longer exists. It is superceded by `validatorOutputs`. This is only a name change, the schema's result is the same as before + +`validatorOutputs` now allows a callback validator to specify data that the submit function should know. Schemas do this +automatically, but now you can do it manually as well: +`run: ({ createOutput }) => createOutput('This is not a validation error and onSubmit can use this')` + +The current map is: + +| Validator | `onSubmit: ({ validatorOutputs }) => ...` | +| -------------------------- | ----------------------------------------- | +| Schema | Schema's output data | +| `createOutput(X)` | `X` | +| Default callback validator | `undefined` | +| Validation error | N/A, `onSubmit` doesn't run | diff --git a/.changeset/pre/legal-animals-design.md b/.changeset/pre/legal-animals-design.md new file mode 100644 index 0000000000..5a049e15ed --- /dev/null +++ b/.changeset/pre/legal-animals-design.md @@ -0,0 +1,5 @@ +--- +'@tanstack/form-core': patch +--- + +Docs: Add JSDoc to code and API sections to website diff --git a/.changeset/pre/odd-comics-push.md b/.changeset/pre/odd-comics-push.md new file mode 100644 index 0000000000..25de60ef11 --- /dev/null +++ b/.changeset/pre/odd-comics-push.md @@ -0,0 +1,5 @@ +--- +'@tanstack/form-core': patch +--- + +Fix: Schema output type now properly guards against dynamically enabled validators diff --git a/.changeset/pre/polite-planets-deny.md b/.changeset/pre/polite-planets-deny.md new file mode 100644 index 0000000000..436951ea8a --- /dev/null +++ b/.changeset/pre/polite-planets-deny.md @@ -0,0 +1,12 @@ +--- +'@tanstack/angular-form': patch +'@tanstack/preact-form': patch +'@tanstack/svelte-form': patch +'@tanstack/react-form': patch +'@tanstack/solid-form': patch +'@tanstack/form-core': patch +'@tanstack/lit-form': patch +'@tanstack/vue-form': patch +--- + +Fix: Subscription selectors now infer tuple return values without requiring `as const`. diff --git a/.changeset/pre/quiet-arrays-share.md b/.changeset/pre/quiet-arrays-share.md new file mode 100644 index 0000000000..497c7165c3 --- /dev/null +++ b/.changeset/pre/quiet-arrays-share.md @@ -0,0 +1,6 @@ +--- +'@tanstack/react-form': patch +'@tanstack/preact-form': patch +--- + +Provide the field context inside App Form `ArrayField`, so registered field components render there instead of throwing. diff --git a/.changeset/pre/seven-trains-play.md b/.changeset/pre/seven-trains-play.md new file mode 100644 index 0000000000..61940dd422 --- /dev/null +++ b/.changeset/pre/seven-trains-play.md @@ -0,0 +1,11 @@ +--- +'@tanstack/preact-form': minor +'@tanstack/svelte-form': minor +'@tanstack/react-form': minor +'@tanstack/solid-form': minor +'@tanstack/form-core': minor +'@tanstack/lit-form': minor +'@tanstack/vue-form': minor +--- + +Feat: Field groups may now omit identity bindings like `fields={{ a: 'a' }}` diff --git a/.changeset/pre/shy-hairs-follow.md b/.changeset/pre/shy-hairs-follow.md new file mode 100644 index 0000000000..0adaaceb15 --- /dev/null +++ b/.changeset/pre/shy-hairs-follow.md @@ -0,0 +1,6 @@ +--- +'@tanstack/form-devtools': patch +'@tanstack/form-core': patch +--- + +Refactor: Use stable validator identity instead of index diff --git a/.changeset/pre/silent-tools-cry.md b/.changeset/pre/silent-tools-cry.md new file mode 100644 index 0000000000..5fba16a46c --- /dev/null +++ b/.changeset/pre/silent-tools-cry.md @@ -0,0 +1,5 @@ +--- +'@tanstack/vue-form': patch +--- + +Keep Vue field values and validation state reactive in child components, and keep slot and injected field handlers connected after resets and field name changes. diff --git a/.changeset/pre/stable-listeners-rest.md b/.changeset/pre/stable-listeners-rest.md new file mode 100644 index 0000000000..9eab863e92 --- /dev/null +++ b/.changeset/pre/stable-listeners-rest.md @@ -0,0 +1,6 @@ +--- +'@tanstack/form-core': patch +'@tanstack/form-devtools': patch +--- + +Refactor: Use stable listener identity instead of index diff --git a/.changeset/pre/tasty-humans-joke.md b/.changeset/pre/tasty-humans-joke.md new file mode 100644 index 0000000000..82ab346146 --- /dev/null +++ b/.changeset/pre/tasty-humans-joke.md @@ -0,0 +1,5 @@ +--- +'@tanstack/form-core': patch +--- + +Refactor: Store Form Groups on trie nodes instead of the form instance diff --git a/.changeset/pre/tender-keys-own.md b/.changeset/pre/tender-keys-own.md new file mode 100644 index 0000000000..1f6fb90bf0 --- /dev/null +++ b/.changeset/pre/tender-keys-own.md @@ -0,0 +1,5 @@ +--- +'@tanstack/react-form': minor +--- + +Feat: Field and Form components can now be nested to create namespaces. diff --git a/.changeset/pre/v2-alpha.md b/.changeset/pre/v2-alpha.md new file mode 100644 index 0000000000..6134b1a958 --- /dev/null +++ b/.changeset/pre/v2-alpha.md @@ -0,0 +1,17 @@ +--- +'@tanstack/angular-form': major +'@tanstack/form-core': major +'@tanstack/form-devtools': major +'@tanstack/lit-form': major +'@tanstack/preact-form': major +'@tanstack/react-form': major +'@tanstack/react-form-devtools': major +'@tanstack/react-form-nextjs': major +'@tanstack/react-form-start': major +'@tanstack/solid-form': major +'@tanstack/solid-form-devtools': major +'@tanstack/svelte-form': major +'@tanstack/vue-form': major +--- + +Release the first alpha of TanStack Form v2. diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000000..dedfba43b4 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,19 @@ +# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json + +reviews: + request_changes_workflow: false + slop_detection: + enabled: true + auto_review: + base_branches: + - alpha + - main + path_filters: + - '!docs/reference/**' + - '!docs/framework/*/reference/**' + +knowledge_base: + code_guidelines: + enabled: true + filePatterns: + - 'CONTRIBUTING.md' diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index aac7579c4b..205aedde06 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -5,7 +5,8 @@ ## āœ… Checklist - [ ] I have followed the steps in the [Contributing guide](https://github.com/TanStack/form/blob/main/CONTRIBUTING.md). -- [ ] I have tested this code locally with `pnpm test:pr`. +- [ ] I have tested code changes locally with `pnpm test:pr`, or these tests do not apply to this pull request. +- [ ] I fully understand the code in this pull request, including any code generated with AI assistance. ## šŸš€ Release Impact diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index 5a0bd9c854..2067bc3f98 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -26,17 +26,17 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Setup Tools - uses: TanStack/config/.github/setup@99d23c6212f36eff17d30a21e58da77f55a4cfe9 # main + uses: TanStack/config/.github/setup@466151b2d479656b38942cd84a0a3dce29d48de3 # main - name: Fix formatting run: pnpm format - name: Generate Docs if: ${{ github.event_name == 'push' || github.event.inputs.generate-docs == true }} run: pnpm generate-docs - name: Apply fixes - uses: autofix-ci/action@7a166d7532b277f34e16238930461bf77f9d7ed8 + uses: autofix-ci/action@c5b2d67aa2274e7b5a18224e8171550871fc7e4a # v1.3.4 with: commit-message: 'ci: apply automated fixes and generate docs' diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 49c36c6dc2..03bb049d7b 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -19,16 +19,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: false - name: Start Nx Agents run: npx nx-cloud start-ci-run --distribute-on=".nx/workflows/dynamic-changesets.yaml" - name: Setup Tools - uses: TanStack/config/.github/setup@99d23c6212f36eff17d30a21e58da77f55a4cfe9 # main + uses: TanStack/config/.github/setup@466151b2d479656b38942cd84a0a3dce29d48de3 # main - name: Get base and head commits for `nx affected` - uses: nrwl/nx-set-shas@3e9ad7370203c1e93d109be57f3b72eb0eb511b1 # v4.4.0 + uses: nrwl/nx-set-shas@afb73a62d26e41464e9254689e1fd6122ee683c1 # v5.0.1 with: main-branch-name: main - name: Run Checks @@ -37,7 +37,7 @@ jobs: if: ${{ always() }} run: npx nx-cloud stop-all-agents - name: Upload coverage to Codecov - uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0 + uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1 with: directory: packages env: @@ -47,11 +47,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Setup Tools - uses: TanStack/config/.github/setup@99d23c6212f36eff17d30a21e58da77f55a4cfe9 # main + uses: TanStack/config/.github/setup@466151b2d479656b38942cd84a0a3dce29d48de3 # main - name: Build Packages run: pnpm run build:all - name: Publish Previews @@ -64,10 +64,10 @@ jobs: pull-requests: write steps: - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Setup Tools - uses: TanStack/config/.github/setup@99d23c6212f36eff17d30a21e58da77f55a4cfe9 # main + uses: TanStack/config/.github/setup@466151b2d479656b38942cd84a0a3dce29d48de3 # main - name: Changeset Preview - uses: TanStack/config/.github/changeset-preview@99d23c6212f36eff17d30a21e58da77f55a4cfe9 # main + uses: TanStack/config/.github/changeset-preview@466151b2d479656b38942cd84a0a3dce29d48de3 # main diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 698e7e2a19..d7835ed68e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,7 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.event.number || github.ref }} - cancel-in-progress: true + cancel-in-progress: false env: NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} @@ -23,24 +23,29 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: true # changesets/action pushes version/release changes - name: Setup Tools - uses: TanStack/config/.github/setup@99d23c6212f36eff17d30a21e58da77f55a4cfe9 # main + uses: TanStack/config/.github/setup@466151b2d479656b38942cd84a0a3dce29d48de3 # main - name: Run Tests run: pnpm run test:ci + - name: Verify Release Mode + env: + RELEASE_BRANCH: ${{ github.ref_name }} + run: pnpm run changeset:verify-release - name: Run Changesets (version or publish) id: changesets - uses: changesets/action@6a0a831ff30acef54f2c6aa1cbbc1096b066edaf # v1.7.0 + uses: changesets/action@ae32849d5ba541f9ae29e40e22a623bc13562f51 # v2.1.2 with: - version: pnpm run changeset:version - publish: pnpm run changeset:publish - commit: 'ci: Version Packages' - title: 'ci: Version Packages' + pr-base-branch: ${{ github.ref_name }} + version-script: pnpm run changeset:version + publish-script: pnpm run changeset:publish + commit-message: 'ci: Version Packages' + pr-title: 'ci: Version Packages' - name: Comment on PRs about release if: steps.changesets.outputs.published == 'true' - uses: TanStack/config/.github/comment-on-release@99d23c6212f36eff17d30a21e58da77f55a4cfe9 # main + uses: TanStack/config/.github/comment-on-release@466151b2d479656b38942cd84a0a3dce29d48de3 # main with: - published-packages: ${{ steps.changesets.outputs.publishedPackages }} + published-packages: ${{ steps.changesets.outputs.published-packages }} diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 1d4088db88..c05cda9222 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -14,12 +14,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 + uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4 with: advanced-security: false annotations: true diff --git a/.gitignore b/.gitignore index 885eed7cc3..4fc6f1f9fa 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,12 @@ stats.json stats.html *.cpuprofile .vscode/settings.json +.idea +.cursor +.claude +.codex +AGENTS.md +.agents *.log .cache @@ -43,3 +49,5 @@ stats.html vite.config.js.timestamp-* vite.config.ts.timestamp-* tsconfig.vitest-temp.json + +.nx/migrate-runs diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..af9e354350 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,10 @@ +# Agent Instructions + +Before analyzing or changing this repository, read and follow +[`CONTRIBUTING.md`](./CONTRIBUTING.md). Its contribution, development, testing, +pull request, and changeset requirements apply to AI-assisted work as well as +human-authored work. + +Keep every change focused on one topic. Understand and verify all generated +code, run the required checks, and provide a concise pull request description +that follows the repository template. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 27b46aacae..a970e6b1fa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,12 +6,23 @@ If you have questions about implementation details, help or support, then please ## Reporting Issues -If you have found what you think is a bug, please [file an issue](https://github.com/TanStack/form/issues/new/choose). **PLEASE NOTE:** Issues that are identified as implementation questions or non-issues will be immediately closed and redirected to [GitHub Discussions](https://github.com/TanStack/form/discussions) +If you have found what you think is a bug, first search the [open and closed issues](https://github.com/TanStack/form/issues?q=is%3Aissue) to make sure it has not already been reported. If you cannot find an existing report, use the [bug report template](https://github.com/TanStack/form/issues/new?template=bug_report.yml). **PLEASE NOTE:** Issues that are identified as implementation questions or non-issues will be immediately closed and redirected to [GitHub Discussions](https://github.com/TanStack/form/discussions). ## Suggesting new features If you are here to suggest a feature, first create an issue if it does not already exist. From there, we will discuss use-cases for the feature and then finally discuss how it could be implemented. +## Pull Request Guidelines + +Every pull request must follow the [TanStack Form pull request template](.github/pull_request_template.md). Complete its description and checklist without removing or bypassing the required sections. + +- Search the [open and closed pull requests](https://github.com/TanStack/form/pulls?q=is%3Apr) before starting work to avoid duplicating an existing contribution. +- Keep each pull request focused on one change or topic. Pull requests that combine unrelated changes will be closed with a request to split them into separately reviewable contributions. +- Write a concise description that clearly explains what changed and why. Follow the sections in the pull request template; a long, unstructured description makes a contribution harder to review. +- You may use AI tools to help generate code, but you remain responsible for understanding, testing, and verifying every submitted change. Do not submit unreviewed, low-quality, or irrelevant generated code. +- Do not mass-submit unrelated or low-quality AI-generated pull requests. We treat that behavior as spam and may close the pull requests, block the contributor, and report the GitHub account. +- Every change that affects a published package must include a changeset. Create it with `pnpm changeset`; documentation, CI, and development-only changes do not require one. + ## Development If you have been assigned to fix an issue or develop a new feature, please follow these steps to get started: diff --git a/README.md b/README.md index 6bd9001654..e8b928f2fb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,19 @@
- + + + + TanStack Form +

@@ -29,8 +43,9 @@
- + ### [Become a Sponsor!](https://github.com/sponsors/tannerlinsley/) +
# TanStack Form diff --git a/_artifacts/domain_map.yaml b/_artifacts/domain_map.yaml new file mode 100644 index 0000000000..470362969c --- /dev/null +++ b/_artifacts/domain_map.yaml @@ -0,0 +1,1007 @@ +schema_version: 1 +status: reviewed +review_state: phase_5_finalized +generated_from: + command: pnpm intent:scaffold + workflow: '@tanstack/intent domain-discovery' + phase: 5 +repository: + root: /home/luca/repos/tanstack/form-v2 + package_manager: pnpm@11.8.0 + monorepo: true + workspace_sources: + - package.json + - pnpm-workspace.yaml + - packages/*/package.json + - docs/**/*.md + - packages/*/src/**/*.ts + - packages/*/tests/**/*.ts + - packages/*/tests/**/*.tsx + - examples/react/**/*.tsx +maintainer_guidance: + adapter_first: true + primary_user_entrypoint: '@tanstack/react-form' + secondary_user_entrypoint: '@tanstack/solid-form' + core_role: 'Concept and implementation source, not a user workflow entrypoint.' + primary_adapter_status: + react: 'Most complete adapter; use as primary examples and skill target.' + solid: 'Important adapter but missing critical planned pieces; avoid Solid-first coverage for now.' + schema_modes: + default_form_options: + summary: 'DefaultValues-first inference.' + use_when: + - 'The form type should be inferred from defaultValues.' + - 'Validation is mostly callback-based and callbacks should receive a value type derived from defaultValues.' + properties: + - 'defaultValues is taken at face value.' + - 'The inferred defaultValues type is used for validators and callbacks.' + - 'This mode is often the simplest choice when no schema should own the form type.' + strict_schema: + summary: 'Schema-source pipeline mode.' + use_when: + - 'The schema is a transforming pipeline from input type to output type.' + - 'The schema should be the source for form typing.' + properties: + - 'defaultValues must align with the schema input type and should produce type errors when they do not.' + - 'Callbacks may not have useful inference unless a schema is present in the validator array.' + - 'onSubmit should read the transform output from validatorOutputs instead of raw value.' + loose_schema: + summary: 'Schema-source ruleset mode with editable defaults.' + use_when: + - 'The schema is a ruleset for confirming valid output, but the editable form state needs nullable or undefined starting values.' + - 'A schema such as z.date() needs a starting value like null before the user has chosen a date.' + properties: + - 'The input is looser while the parsed submit output is still the schema output type.' + - 'defaultValues must still align with the schema shape, but properties may also be null or undefined where editing requires it.' + - 'Callbacks may not have useful inference unless a schema is present in the validator array.' + - 'onSubmit should read the transform output from validatorOutputs instead of raw value.' + schema_ecosystem: + standard_schema: + role: 'Most common integration shape.' + note: 'Standard Schema is an interoperability interface, not a pipeline-vs-ruleset classification system.' + source: 'https://standardschema.dev/' + pipeline_vs_ruleset_heuristic: + status: 'maintainer commentary' + meaning: 'A mental model for deciding TanStack Form option mode: is the schema written as a pipeline of constraints/transforms, or as a firewall that only lets already-valid values through?' + caution: 'This is not part of Standard Schema and should not be presented as a Standard Schema concept.' + validation_libraries_as_of_2026_06_25: + - name: Zod + standard_schema_support: 'Supported; Zod docs recommend Standard Schema for schema-agnostic black-box validation and say Zod is included among compatible libraries.' + general_leaning: 'ruleset/firewall-leaning by default' + tanstack_form_bias: 'Often looseSchema for editable forms, with strictSchema only when a Zod schema is deliberately authored as a transform pipeline.' + source: 'https://zod.dev/library-authors' + - name: Valibot + standard_schema_support: 'Implements Standard Schema v1.' + general_leaning: 'pipeline-leaning' + tanstack_form_bias: 'Often strictSchema when the schema is authored as an input-to-output pipeline.' + source: 'https://valibot.dev/guides/integrate-valibot/' + - name: ArkType + standard_schema_support: 'Supports and co-authored Standard Schema; can consume Standard Schema validators as definitions.' + general_leaning: 'mixed; structural firewall constraints with morph/pipe support for pipeline-style transforms' + tanstack_form_bias: 'Choose by the actual schema intent rather than the library name.' + source: 'https://arktype.io/docs/integrations' + - name: Effect Schema + standard_schema_support: 'Can generate Standard Schema V1 via Schema.standardSchemaV1 for schemas without dependencies.' + general_leaning: 'pipeline/codec-leaning because schemas distinguish decoded Type from Encoded input and support decoding/encoding.' + tanstack_form_bias: 'Often strictSchema when the Effect schema is used as an encoded-to-decoded boundary.' + source: 'https://effect.website/docs/schema/standard-schema/' + query_shape: + async_defaults: 'Incoming values are often maybe undefined while data loads.' + default_values_plan: 'Do not pass query data alone as form defaults; either gate mounted fields/form until data is ready, or coalesce query data with a static shape-complete emptyFormValues object. Neither strategy is preferred globally.' + visual_language: 'Gating fields or the whole form changes the visual UI language because the form appears only after data is ready; an emptyFormValues fallback can render the form immediately with loading or placeholder state.' + submit: 'Use an async promise for endpoint calls so isSubmitting reflects the request. Catch submit errors only when they can produce validation errors that must be returned as values. Transient thrown/rejected errors may remain thrown; they set isSubmitSuccessful to false while external query/framework state preserves the error.' + hard_do_nots: + - id: no_type_assertions + rule: 'Do not type assert to make TanStack Form code compile; preserve inference and fix the mismatched API boundary.' + bad_patterns: + - 'name={`users[${index}].name` as const}' + - '{(field: any) => ...}' + - 'field: { value: string }' + preferred_patterns: + - 'Let field names infer without as const.' + - 'Let form.Field render-prop children infer their field type.' + - 'Use FieldWithValue or AnyFieldApi when a reusable component needs an explicit field prop type.' + - id: validation_errors_are_not_transient_errors + rule: 'Do not store query, network, or framework transient failures as form validation errors.' + reason: 'Validation errors from validators or onSubmit block the user from submitting; transient errors should use the query or framework error state.' + preferred_patterns: + - 'Use an async promise for endpoint calls so isSubmitting reflects the request.' + - 'Return createValidationError or parseIssues only for validation-shaped server responses.' + - 'Keep retryable network/server failures in the query or framework layer; they may throw or reject as transient failures.' + - id: validation_errors_are_values + rule: 'Do not throw validation errors from validators or onSubmit.' + reason: 'Validation errors must be returned values. Thrown/rejected errors are submit failures, not validation state.' + preferred_patterns: + - 'Return createValidationError(...) from onSubmit for validation failures.' + - 'Return parseIssues(...) when converting Standard Schema issues.' + - 'Let transient endpoint failures reject if the surrounding query/framework preserves the error state.' + - id: no_react_form_type_unions + rule: 'Do not type shared sections as unions of multiple ReactFormType forms.' + bad_patterns: + - 'form: ReactFormType | ReactFormType' + reason: 'TypeScript cannot make useful sense of different form API unions for field names and methods.' + preferred_patterns: + - 'Use ReactFormType for splitting one known form into sections.' + - 'Use field groups when a reusable section should bind into multiple different forms or paths.' + excluded_from_current_skills: + - devtools_as_entrypoint + - migration_guidance + - schema_metadata_extraction + - non_validation_error_state_ownership + - ui_library_behavior_itself + - solid_first_examples +domain_boundaries: + in_scope: + - 'React adapter-first form setup.' + - 'Core concepts explained through adapter APIs.' + - 'Standard Schema-compatible validation and submit parsing.' + - 'Choosing default, strictSchema, and looseSchema option modes.' + - 'Async default values and async submit with query-like libraries.' + - 'Error visibility policy callbacks.' + - 'Reusable split-form types and reusable validation or visibility policy modules.' + - 'Interpreting TypeScript errors caused by form/schema composition.' + - 'Authoring realistic examples that demonstrate intended usage.' + out_of_scope: + - 'Using @tanstack/form-core directly in app examples.' + - 'Devtools workflows while devtools are still changing.' + - 'Migration from v1 or other form libraries.' + - 'Deriving UI metadata from Standard Schemas.' + - 'Owning transient server/network error state inside TanStack Form.' + - 'Teaching a specific UI library as part of TanStack Form itself.' +packages: + - name: '@tanstack/form-core' + role: concept_source + public_user_entrypoint: false + relevant_concepts: + - form_options + - strict_schema + - loose_schema + - standard_schema_parsing + - validation_errors + - error_visibility + - create_error_visibility + - create_validator + - create_validators + - async_defaults + - array_helpers + - array_field_versioning + - reset_semantics + sources: + - packages/form-core/src/utils.public.ts + - packages/form-core/src/validation.public.ts + - packages/form-core/src/standardSchema.public.ts + - packages/form-core/src/standardSchema.lib.ts + - packages/form-core/src/FormApi/FormApi.public.ts + - packages/form-core/src/FormApi/FormApi.lib.ts + - packages/form-core/src/FormApi/array-methods.lib.ts + - packages/form-core/src/FieldApi/fieldState.lib.ts + - packages/form-core/tests/validation.test.ts + - packages/form-core/tests/validation.test-d.ts + - packages/form-core/tests/FormApi/default-value.spec.ts + - packages/form-core/tests/FormApi/submission-handling.spec.ts + - packages/form-core/tests/FormApi/field-array-methods.spec.ts + - name: '@tanstack/react-form' + role: primary_user_entrypoint + public_user_entrypoint: true + relevant_concepts: + - use_form + - form_field + - array_field + - form_subscribe + - app_form + - app_form_options + - create_form_hook + - field_groups + - field_subscription + - array_field_subscription + - react_form_type + - field_with_value + - any_field_api + sources: + - packages/react-form/src/ReactForm/useForm.public.ts + - packages/react-form/src/ReactForm/ReactFormApi.lib.tsx + - packages/react-form/src/ReactForm/Components.public.ts + - packages/react-form/src/ReactForm/fieldSubscriptions.lib.ts + - packages/react-form/src/ReactForm/useField.lib.ts + - packages/react-form/src/AppForm/appFormOptions.public.ts + - packages/react-form/src/AppForm/createFormHook.public.ts + - packages/react-form/src/AppForm/getFormHookHelpers.public.ts + - packages/react-form/src/FieldGroup/withFields.public.ts + - packages/react-form/src/ReactForm/formType.public.ts + - packages/react-form/tests/useForm.spec.tsx + - packages/react-form/tests/submit-return.test-d.tsx + - packages/react-form/tests/FormGroup.test-d.tsx + - packages/react-form/tests/FieldGroupApi.test-d.tsx + - name: '@tanstack/solid-form' + role: secondary_adapter + public_user_entrypoint: true + current_skill_status: deferred + note: 'Use as conceptual parity context only until planned Solid adapter pieces land.' + - name: '@tanstack/form-devtools' + role: devtools + public_user_entrypoint: false + current_skill_status: excluded + note: 'Devtools are in development and should not be treated as an entrypoint yet.' +domains: + - id: react-adapter-composition + title: React Adapter Composition + description: 'How users compose headless React forms, reusable field components, app form contexts, field groups, arrays, and UI-library bindings through @tanstack/react-form.' + package_focus: + - '@tanstack/react-form' + - '@tanstack/form-core' + core_questions: + - 'Should this be a one-off useForm example, an app-form setup, or a field-group composition?' + - 'Which pieces need to be reusable without over-constraining submit types?' + - 'Is this reducing nesting in one known form, reducing field JSX boilerplate, or reusing a section across forms?' + - 'Should split child components receive a form prop typed with ReactFormType derived from shared options, or should the section be a field group?' + - 'Does the example need field arrays or reorder behavior?' + related_skills: + - react-form-composition-setup + - examples-authoring + - type-error-debugging + - id: schema-driven-forms + title: Schema Driven Forms + description: 'How Standard Schema-compatible schemas influence form option mode, validation, field error routing, submit output, and TypeScript inference.' + package_focus: + - '@tanstack/react-form' + - '@tanstack/form-core' + core_questions: + - 'Is the schema a pipeline from input A to output B, or a ruleset for confirming B?' + - 'Should submit logic read raw value or validatorOutputs?' + - 'Do defaults need to be nullable or maybe undefined while editing?' + related_skills: + - choosing-form-options-modes + - schema-driven-forms + - type-error-debugging + - id: async-data-and-submit + title: Async Data And Submit + description: 'How query-like loading data and mutation-like submit functions interact with default values, touched fields, validation errors, and transient errors.' + package_focus: + - '@tanstack/react-form' + - '@tanstack/form-core' + core_questions: + - 'Can incoming data be undefined at first render?' + - 'Should later defaultValues update untouched fields while preserving touched fields?' + - 'Is an onSubmit failure transient or validation-related?' + related_skills: + - query-backed-forms + - error-visibility-workflows + - examples-authoring + - id: validation-and-error-visibility + title: Validation And Error Visibility + description: 'How validators produce errors, how Standard Schema issues are routed, and how visible errors are filtered by form-level or field-level callbacks.' + package_focus: + - '@tanstack/react-form' + - '@tanstack/form-core' + core_questions: + - 'When should an error become visible?' + - 'Should the visibility policy or validator trigger policy be extracted into a named reusable helper?' + - 'Is visibility form-wide, field-specific, or group-scoped?' + - 'Should submit errors be parsed from Standard Schema issues or manually created?' + related_skills: + - error-visibility-workflows + - schema-driven-forms + - query-backed-forms + - id: diagnostics-and-examples + title: Diagnostics And Examples + description: "How to turn the library's type surface and examples into agent-readable, realistic user journeys." + package_focus: + - '@tanstack/react-form' + - '@tanstack/form-core' + core_questions: + - 'What type boundary is producing the error?' + - 'Is the example demonstrating intended usage rather than only core behavior?' + - 'Which realistic integration should the example model without claiming ownership of external UI or query state?' + related_skills: + - type-error-debugging + - examples-authoring +skill_candidates: + - id: react-form-composition-setup + title: React Form Composition Setup + status: reviewed + priority: high + domain: react-adapter-composition + purpose: 'Help users build adapter-first React forms, reusable components, app-form setups, field groups, and UI-library bindings.' + entrypoints: + - '@tanstack/react-form/useForm' + - '@tanstack/react-form/ReactFormType' + - '@tanstack/react-form/FieldWithValue' + - '@tanstack/react-form/AnyFieldApi' + - '@tanstack/react-form/formOptions' + - '@tanstack/react-form/createFormHook' + - 'form.Field' + - 'form.ArrayField' + - 'form.Subscribe' + - 'form.FormGroup' + sources: + - packages/react-form/src/ReactForm/Components.public.ts + - packages/react-form/src/ReactForm/fieldSubscriptions.lib.ts + - packages/react-form/src/AppForm/createFormHook.public.ts + - packages/react-form/src/FieldGroup/withFields.public.ts + - packages/react-form/tests/submit-return.test-d.tsx + - packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts + - packages/form-core/src/FieldApi/fieldState.lib.ts + - examples/react/array/src/index.tsx + - examples/react/basic-splitting-form/src/index.tsx + - examples/react/ui-integration-shadcn/src/components/form/app-form.ts + teaches: + - 'Prefer adapter APIs over constructing core APIs directly.' + - 'Use render-prop field APIs and subscriptions instead of copying form state into component state.' + - 'Treat useForm and useAppForm as stable form creation hooks, not reactive state reads.' + - 'Use useSelector or form.Subscribe when component output must react to form state.' + - 'Keep reusable shared options submit-agnostic when child components should accept multiple submit implementations.' + - 'Use ReactFormType as one option for splitting a known form into child components that receive a form prop.' + - 'Do not union multiple ReactFormType forms for shared sections; use field groups when a section must bind into multiple different forms or paths.' + - 'Use AppForm to reduce repeated field JSX boilerplate; use split form sections to reduce component nesting; use field groups for reusable sections across forms or paths.' + - 'Let field names and form.Field children infer; use FieldWithValue or AnyFieldApi for explicit reusable field component props.' + - 'form.Field may bind an array value; it behaves immutably like other fields, so any element change changes the array value and rerenders whole-array consumers.' + - 'Use form.ArrayField when an array is a rendering boundary for child fields or list items; ArrayField subscriptions follow array shape/version changes instead of treating value as the whole render unit.' + - 'Use field groups for reusable sections with virtual-to-real field bindings.' + failure_modes: + - name: type_asserting_form_inference + symptom: 'Code adds as const to field names, annotates render-prop children as any, or uses as any to force form code to compile.' + correction: 'Remove the assertion and let names, children, and form helpers infer the types.' + evidence: + - maintainer_guidance.hard_do_nots + - packages/react-form/src/ReactForm/Components.public.ts + - name: shimmed_field_prop_type + symptom: 'A reusable component accepts a hand-written field shape like field: { value: string }.' + correction: 'Use inferred render-prop types, FieldWithValue, or AnyFieldApi instead of a structural shim.' + evidence: + - examples/react/basic-splitting-form/src/StringField.tsx + - examples/react/basic-splitting-form/src/FieldError.tsx + - name: expecting_hook_reactivity + symptom: 'A component reads form.state or derived flags from the stable useForm/useAppForm return and does not re-render when form state changes.' + correction: 'Use useSelector with form.atom or a field/group atom, or use form.Subscribe with an explicit selector.' + evidence: + - packages/react-form/src/ReactForm/ReactFormApi.lib.tsx + - packages/react-form/src/Subscribe.public.tsx + - packages/react-form/src/ReactForm/fieldSubscriptions.lib.ts + - examples/react/ui-integration-dnd-kit/src/twoLists/index.tsx + - name: core_as_user_entrypoint + symptom: 'Example imports @tanstack/form-core or constructs FormApi in React application code.' + correction: 'Use @tanstack/react-form APIs; treat core as concept and implementation source.' + evidence: + - maintainer_guidance.core_role + - packages/react-form/src/ReactForm/useForm.public.ts + - name: app_components_outside_provider + symptom: 'App field or form components throw because they are rendered outside form.Field or form.AppForm.' + correction: 'Wrap custom form components in the app-form provider pattern created by createFormHook.' + evidence: + - packages/react-form/src/AppForm/contexts.lib.ts + - examples/react/ui-integration-shadcn/src/components/form/app-form.ts + - name: over_specific_shared_form_type + symptom: 'A reusable child form prop rejects a parent form once onSubmit is added.' + correction: 'Keep shared options without onSubmit when reusable children should stay submit-agnostic.' + evidence: + - packages/react-form/src/ReactForm/formType.public.ts + - packages/react-form/tests/submit-return.test-d.tsx + - name: split_form_without_react_form_type + symptom: 'A split form section hand-writes a large form prop type or loses field-name inference.' + correction: 'Export shared form options and type the prop as ReactFormType.' + evidence: + - examples/react/basic-splitting-form/src/FormSection.tsx + - docs/framework/react/reference/type-aliases/ReactFormType.md + - name: react_form_type_union_shared_section + symptom: 'A shared section accepts a union like ReactFormType | ReactFormType and TypeScript cannot resolve field names or methods.' + correction: 'Use field groups for reusable sections across forms, or use ReactFormType only for one known shared options type.' + evidence: + - maintainer_guidance.hard_do_nots + - packages/react-form/src/FieldGroup/withFields.public.ts + - name: field_used_for_rendering_array_children + symptom: 'A Field bound to an array value is used as the boundary for rendering item fields, and item updates rerender the whole array-value consumer.' + correction: 'Use ArrayField at the list boundary, then render item Fields for the values that should update independently.' + evidence: + - examples/react/array/src/index.tsx + - packages/react-form/src/ReactForm/fieldSubscriptions.lib.ts + - packages/form-core/src/FieldApi/fieldState.lib.ts + - name: array_field_assumed_required_for_any_array_value + symptom: 'Code reaches for ArrayField only because the field value is an array, even though the array is consumed as one immutable value.' + correction: 'Use Field when the array is a single field value; reserve ArrayField for rendering child fields or list items.' + evidence: + - packages/react-form/src/ReactForm/Components.public.ts + - packages/react-form/src/ReactForm/fieldSubscriptions.lib.ts + - name: raw_array_mutation + symptom: 'Array item values and field meta fall out of sync after splice, reorder, or manual setFieldValue.' + correction: 'Use pushFieldValue, insertFieldValue, removeFieldValue, swapFieldValues, moveFieldValue, clearFieldValues, or filterFieldValues.' + evidence: + - packages/form-core/src/FormApi/array-methods.lib.ts + - packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts + - packages/form-core/tests/FormApi/field-array-methods.spec.ts + - id: reusable-form-policies + title: Reusable Form Policies + status: reviewed + priority: high + domain: validation-and-error-visibility + purpose: 'Help users extract split-form types, error visibility callbacks, and validator configs into named reusable helpers when the behavior deserves semantic intent.' + entrypoints: + - '@tanstack/react-form/ReactFormType' + - 'createErrorVisibility' + - 'createValidator' + - 'createValidators' + - 'shared formOptions' + - 'shared appFormOptions' + sources: + - examples/react/basic-splitting-form/src/FormSection.tsx + - examples/react/basic-splitting-form/src/sharedForm.ts + - packages/react-form/tests/submit-return.test-d.tsx + - packages/form-core/tests/validation.test.ts + - packages/form-core/tests/validation.test-d.ts + - examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx + teaches: + - 'Use ReactFormType as the helper type for split form sections that receive a form prop.' + - 'ReactFormType splitting reduces nesting in one known form; AppForm reduces repeated field JSX; field groups cover sections reused across different forms or paths.' + - 'Prefer form-level errorVisibility callbacks over repeated local showErrors checks.' + - 'Use helper functions when a callback or validator config deserves a semantic name that preserves intent.' + - 'Use comments or JSDoc on named helpers to explain workflow behavior, trigger timing, debounce, bailIfInvalid, skipOnSubmit, or rewardEarlyPunishLate policy.' + - 'Keep reusable visibility policies value-agnostic unless they are intentionally tied to one form shape; use inline callbacks when typed values are required.' + failure_modes: + - name: split_form_type_written_by_hand + symptom: 'A split form section loses field-name inference because its form prop type is hand-written.' + correction: 'Export shared options and type the prop as ReactFormType.' + evidence: + - examples/react/basic-splitting-form/src/FormSection.tsx + - packages/react-form/tests/submit-return.test-d.tsx + - name: reusable_section_uses_react_form_type_union + symptom: 'A shared section accepts FormA | FormB and TypeScript cannot narrow field names or methods.' + correction: 'Use field groups for shared sections that need to work across different forms or paths.' + evidence: + - maintainer_guidance.hard_do_nots + - packages/react-form/src/FieldGroup/withFields.public.ts + - name: scattered_show_errors_policy + symptom: 'Each field repeats local showErrors logic such as field.meta.isTouched && field.meta.isInvalid.' + correction: 'Move default visible-error behavior into form-level errorVisibility, or extract a named createErrorVisibility helper.' + evidence: + - packages/form-core/tests/validation.test-d.ts + - examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx + - name: duplicated_validator_config_without_intent + symptom: 'Trigger, debounce, skipOnSubmit, or bailIfInvalid config is copied without explaining the intended workflow.' + correction: 'Extract a named createValidator/createValidators helper and document the behavior intent.' + evidence: + - packages/form-core/tests/validation.test.ts + - examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx + - name: reusable_visibility_reads_concrete_values + symptom: 'A reusable createErrorVisibility callback tries to read a concrete property such as state.values.name.' + correction: 'Keep reusable policies value-agnostic, or use an inline errorVisibility callback when concrete typed values are needed.' + evidence: + - packages/form-core/tests/validation.test-d.ts + - id: choosing-form-options-modes + title: Choosing Form Options Modes + status: reviewed + priority: high + domain: schema-driven-forms + purpose: 'Help users choose default formOptions, strictSchema, or looseSchema based on whether the schema is a transform pipeline or a validation ruleset.' + entrypoints: + - '@tanstack/react-form/formOptions' + - '@tanstack/react-form/formOptions.strictSchema' + - '@tanstack/react-form/formOptions.looseSchema' + - '@tanstack/react-form/appFormOptions' + - '@tanstack/react-form/appFormOptions.strictSchema' + - '@tanstack/react-form/appFormOptions.looseSchema' + sources: + - packages/form-core/src/utils.public.ts + - packages/react-form/src/AppForm/appFormOptions.public.ts + - packages/form-core/tests/validation.test.ts + - packages/form-core/tests/validation.test-d.ts + - examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx + teaches: + - 'The option helpers are runtime identity helpers with type-level meaning.' + - 'Default formOptions infers from defaultValues; those values are taken at face value and drive validator callback value types.' + - 'strictSchema uses the schema as the typing source for a transforming input-to-output pipeline.' + - 'strictSchema defaultValues must align with the schema input type and should fail type-checking when they do not.' + - 'looseSchema uses the schema as a ruleset while allowing editable default values that include null or undefined where needed.' + - 'looseSchema defaultValues must still align with the schema shape, but the input can be looser while output remains schema output.' + - 'In schema modes, callbacks may not infer usefully unless a schema is present in the validator array.' + - 'In schema modes, onSubmit should read validatorOutputs instead of raw value.' + - 'Use Standard Schema-capable libraries as heuristic examples only: Zod generally leans ruleset/firewall, Valibot generally leans pipeline, ArkType is mixed, and Effect Schema often leans pipeline/codec.' + failure_modes: + - name: expecting_option_helper_runtime_behavior + symptom: 'User expects strictSchema or looseSchema to add validation without validators.' + correction: 'Explain that the helper shapes inference; validation still comes from configured validators.' + evidence: + - packages/form-core/src/utils.public.ts + - packages/form-core/tests/validation.test.ts + - name: schema_expected_to_type_default_form_options + symptom: 'User chooses default formOptions but expects a schema to own the form data type.' + correction: 'Use default formOptions for defaultValues-first inference, or choose a schema mode when the schema should be the typing source.' + evidence: + - maintainer_guidance.schema_modes + - packages/form-core/src/utils.public.ts + - name: strict_ruleset_schema_blocks_editing + symptom: 'Defaults or field values cannot represent empty, null, or partial UI states because strict schema typing is too narrow.' + correction: 'Use looseSchema or default formOptions when the schema is a ruleset validating final form shape.' + evidence: + - maintainer_guidance.schema_modes + - packages/form-core/src/utils.public.ts + - name: loose_schema_shape_mismatch + symptom: "Loose schema defaults include null or undefined but no longer match the schema's object shape or field structure." + correction: 'Keep the defaultValues shape aligned with the schema while allowing null or undefined where editable state needs it.' + evidence: + - maintainer_guidance.schema_modes + - packages/form-core/src/utils.public.ts + - name: schema_mode_without_schema_validator + symptom: 'Callbacks in strictSchema or looseSchema mode do not infer the expected value type.' + correction: 'Put a schema in the validator array so the helper has a schema source to infer from.' + evidence: + - maintainer_guidance.schema_modes + - packages/form-core/tests/validation.test-d.ts + - name: loose_pipeline_schema_loses_transform_intent + symptom: 'Submit logic treats raw form value as if it were the transformed schema output.' + correction: 'Use strictSchema for pipeline schemas and read the transformed value from validatorOutputs.' + evidence: + - packages/form-core/tests/validation.test.ts + - packages/form-core/tests/validation.test-d.ts + - name: on_submit_reads_value_in_schema_mode + symptom: 'onSubmit reads value even though strictSchema or looseSchema is being used.' + correction: 'Read the relevant validatorOutputs entry, because both schema modes preserve raw form value separately from parsed output.' + evidence: + - packages/form-core/tests/validation.test.ts + - packages/form-core/src/FormApi/FormApi.public.ts + - name: confusing_zod_input_with_pipeline_input + symptom: 'A Zod schema is treated as a reliable A-to-B pipeline because z.input differs from z.output.' + correction: 'Start from Zod-as-ruleset guidance unless the specific schema is deliberately written as a transform pipeline.' + evidence: + - maintainer_guidance.schema_ecosystem + - examples/react/ui-integration-shadcn/src/app/booking/schema.ts + - id: schema-driven-forms + title: Schema Driven Forms + status: reviewed + priority: high + domain: schema-driven-forms + purpose: 'Help users turn Standard Schema-compatible schemas into form validators, field errors, typed submit output, and realistic examples.' + entrypoints: + - 'validators' + - 'FormSubmitContext.validatorOutputs' + - 'parseIssues' + - 'createValidationError' + - 'Standard Schema validators' + sources: + - packages/form-core/src/standardSchema.public.ts + - packages/form-core/src/standardSchema.lib.ts + - packages/form-core/src/FormApi/FormApi.public.ts + - packages/form-core/tests/validation.test.ts + - packages/form-core/tests/validation.test-d.ts + - examples/react/ui-integration-shadcn/src/app/booking/schema.ts + - examples/react/field-groups/src/index.tsx + teaches: + - 'Use Standard Schema-compatible validators in form or field validators.' + - 'Extract reusable validator trigger configs with createValidator or createValidators when the policy is complex enough to deserve a semantic name.' + - 'Read parsed schema output from onSubmit context.validatorOutputs.' + - 'Return validation errors as values through createValidationError or parseIssues; do not throw them.' + - 'Let Standard Schema issue paths route field errors instead of hand-building brittle path maps.' + failure_modes: + - name: assuming_schema_output_replaces_value + symptom: 'onSubmit reads value expecting transformed/coerced data.' + correction: 'Use validatorOutputs for parsed schema output; value remains form state.' + evidence: + - packages/form-core/src/FormApi/FormApi.public.ts + - packages/form-core/tests/validation.test.ts + - name: returning_raw_schema_error + symptom: 'A submit validator returns or throws raw Zod/Standard Schema errors and the form does not show intended field errors.' + correction: 'Return parseIssues for Standard Schema issues or createValidationError for explicit form/field errors; validation errors must be values, not thrown errors.' + evidence: + - packages/form-core/src/FormApi/FormApi.public.ts + - packages/form-core/tests/FormApi/submission-handling.spec.ts + - name: manual_path_mapping + symptom: 'Nested and array validation errors are routed to the wrong field names.' + correction: 'Use Standard Schema parsing so paths like user.name and users[0].name are produced consistently.' + evidence: + - packages/form-core/src/standardSchema.lib.ts + - packages/form-core/tests/validation.test.ts + - name: duplicated_validator_policy + symptom: 'The same triggers, debounce, skipOnSubmit, or bailIfInvalid choices are copied across validators with no explanation.' + correction: 'Extract a named createValidator/createValidators helper when the policy has semantic meaning, and document why that behavior exists.' + evidence: + - packages/form-core/tests/validation.test.ts + - examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx + - name: schema_metadata_expectation + symptom: 'Example tries to infer required labels, descriptions, or UI decorations from Standard Schema metadata.' + correction: 'Keep UI metadata explicit or schema-library-specific; Standard Schema does not standardize metadata.' + evidence: + - maintainer_guidance.excluded_from_current_skills + - id: query-backed-forms + title: Query Backed Forms + status: reviewed + priority: high + domain: async-data-and-submit + purpose: 'Help users combine forms with query-like async defaults and mutation-like submit calls while separating transient failures from validation errors.' + entrypoints: + - 'useForm defaultValues' + - 'onSubmit' + - 'form.reset' + - 'createValidationError' + - 'parseIssues' + sources: + - packages/react-form/tests/useForm.spec.tsx + - packages/form-core/src/FormApi/FormApi.lib.ts + - packages/form-core/src/FormApi/FormApi.public.ts + - packages/form-core/tests/FormApi/default-value.spec.ts + - packages/form-core/tests/FormApi/submission-handling.spec.ts + teaches: + - 'Maybe-undefined incoming data requires an explicit default-values plan, not direct query data alone.' + - 'Approach 1: gate the fields, or the whole form, until the query is ready so mounted fields start with correct data.' + - 'Approach 2: define a static shape-complete emptyFormValues object and pass defaultValues as queryData ?? emptyFormValues.' + - 'Neither approach is preferred globally; choose based on the desired loading and visual UI language.' + - 'Gating fields changes the UI because fields mount only after data is ready, while an emptyFormValues fallback can show the form immediately.' + - 'Let updated defaultValues populate untouched fields while preserving user-touched fields.' + - 'Use an async promise for endpoint calls inside onSubmit so isSubmitting reflects the request.' + - 'Catch submit errors only when the endpoint can return validation errors that should be converted into createValidationError or parseIssues values.' + - 'Transient submit errors can throw or reject; they set isSubmitSuccessful to false while query/framework state should preserve the error details.' + - 'Remember that errors stored from validators or onSubmit block submission, so transient errors should not be converted into validation errors.' + - 'Use reset semantics deliberately when replacing values and default baselines.' + failure_modes: + - name: undefined_data_as_final_shape + symptom: 'Initial query data is undefined, so fields or schema types collapse into invalid permanent defaults.' + correction: 'Either gate mounting until data is ready, or coalesce with a static shape-complete emptyFormValues object.' + evidence: + - packages/react-form/tests/useForm.spec.tsx + - maintainer_guidance.query_shape + - name: query_data_without_fallback_plan + symptom: 'defaultValues is fed directly from query.data even though query.data can be undefined.' + correction: 'Use query.data ?? emptyFormValues, or delay mounting fields/form until the query has populated data.' + evidence: + - maintainer_guidance.query_shape + - packages/react-form/tests/useForm.spec.tsx + - name: ignoring_loading_visual_language + symptom: 'An example gates fields without accounting for the different loading UI, or renders empty fallback values without communicating that data is still loading.' + correction: 'Choose the default-values plan together with the intended visual loading language.' + evidence: + - maintainer_guidance.query_shape + - name: overwriting_touched_fields + symptom: 'Late async defaults replace user edits.' + correction: "Use the form's defaultValues update behavior, which preserves touched fields and updates untouched fields." + evidence: + - packages/form-core/src/FormApi/FormApi.lib.ts + - packages/react-form/tests/useForm.spec.tsx + - name: transient_error_as_validation_error + symptom: 'Network/server outage becomes a visible field validation error.' + correction: 'Keep transient error state in the query or framework layer; return createValidationError or parseIssues only for validation failures, because stored validation errors block submission.' + evidence: + - packages/form-core/tests/FormApi/submission-handling.spec.ts + - maintainer_guidance.query_shape + - name: non_async_endpoint_call + symptom: 'onSubmit starts an endpoint call without returning or awaiting its promise, so isSubmitting does not cover the request.' + correction: 'Return or await the async endpoint promise from onSubmit.' + evidence: + - packages/form-core/tests/FormApi/submission-handling.spec.ts + - packages/form-core/src/FormApi/handleSubmit.lib.ts + - name: thrown_validation_error + symptom: 'onSubmit throws or rejects with validation information and expects field errors.' + correction: 'Convert validation failures into returned createValidationError or parseIssues values; thrown/rejected errors are submit failures.' + evidence: + - packages/form-core/tests/FormApi/submission-handling.spec.ts + - packages/form-core/src/FormApi/FormApi.public.ts + - name: rejected_submit_expected_to_show_field_errors + symptom: 'onSubmit throws or rejects a transient failure and the user expects field errors to appear.' + correction: 'Let transient failures remain transient and use query/framework error state; only validation failures should be converted into returned validation values.' + evidence: + - packages/form-core/tests/FormApi/submission-handling.spec.ts + - packages/form-core/src/FormApi/FormApi.public.ts + - id: error-visibility-workflows + title: Error Visibility Workflows + status: reviewed + priority: high + domain: validation-and-error-visibility + purpose: 'Help users implement visible-error policies such as show-after-blur, show-after-submit, or custom workflows.' + entrypoints: + - 'errorVisibility' + - 'createErrorVisibility' + - 'createValidator' + - 'createValidators' + - 'fieldState.meta' + - 'state.submissionAttempts' + - 'form.FormGroup' + sources: + - packages/form-core/src/validation.public.ts + - packages/form-core/src/FieldApi/fieldState.lib.ts + - packages/form-core/src/utils.public.ts + - packages/form-core/tests/validation.test-d.ts + - packages/form-core/tests/FormApi/validation.spec.ts + - packages/form-core/tests/FormGroupApi/FormGroupApi.spec.ts + - examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx + teaches: + - 'errorVisibility is a callback, not a string preset.' + - 'Use form-level errorVisibility to control default visible-error behavior instead of scattering local checks like field.meta.isTouched && field.meta.isInvalid.' + - 'Reusable policies can use createErrorVisibility but only receive unknown form values.' + - 'Helper functions mainly serve to give a semantic name to a callback or validator config.' + - 'Named reusable policies are good places for JSDoc or comments that explain why errors appear at that moment.' + - 'Reusable validator configs are useful when they explain trigger timing, bailIfInvalid, debounce, skipOnSubmit, or rewardEarlyPunishLate behavior.' + - 'Inline callbacks can use typed form values from the consuming form.' + - 'Visibility callbacks see pre-filter meta, not visible errors or validity.' + - 'Group submission attempts are scoped to the nearest group.' + failure_modes: + - name: string_preset + symptom: "User writes errorVisibility: 'touched' or errorVisibility: 'always'." + correction: 'Use a callback or createErrorVisibility helper.' + evidence: + - packages/form-core/tests/validation.test-d.ts + - packages/form-core/src/validation.public.ts + - name: scattered_local_error_display + symptom: 'Each field repeats local showErrors expressions like field.meta.isTouched && field.meta.isInvalid.' + correction: 'Move default visible-error behavior into form-level errorVisibility.' + evidence: + - maintainer_guidance + - examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx + - name: checking_visible_errors_inside_visibility + symptom: 'Visibility callback tries to inspect fieldState.meta.errors or validity.' + correction: 'Base visibility on pre-filter meta such as isBlurred, isTouched, isDirty, or submissionAttempts.' + evidence: + - packages/form-core/tests/validation.test-d.ts + - packages/form-core/src/FieldApi/fieldState.lib.ts + - name: reusable_policy_expects_typed_values + symptom: 'A createErrorVisibility callback tries to read state.values.name with a concrete form type.' + correction: 'Use inline errorVisibility when typed values are required, or keep reusable policies value-agnostic.' + evidence: + - packages/form-core/tests/validation.test-d.ts + - name: undocumented_policy_intent + symptom: 'A complex visibility or validator trigger policy is copied inline, making agents preserve the code but miss the workflow intent.' + correction: 'Extract a named helper and use comments or JSDoc to document the intended user behavior.' + evidence: + - packages/form-core/tests/validation.test.ts + - examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx + - name: group_submit_scope_surprise + symptom: 'A wizard section expects form-level submit attempts and group-level submit attempts to be interchangeable.' + correction: 'Account for nearest group scoping when using state.submissionAttempts in grouped forms.' + evidence: + - packages/form-core/tests/FormGroupApi/FormGroupApi.spec.ts + - id: type-error-debugging + title: Type Error Debugging + status: reviewed + priority: medium + domain: diagnostics-and-examples + purpose: 'Help users interpret large TypeScript errors from schemas, option modes, field groups, reusable forms, and adapter APIs.' + entrypoints: + - 'ReactFormType' + - 'FieldWithValue' + - 'AnyFieldApi' + - 'formOptions' + - 'appFormOptions' + - 'createErrorVisibility' + - 'createValidators' + - 'fieldComponent.strict' + - 'fieldComponent.loose' + - 'fieldBrand.strict' + - 'fieldBrand.loose' + - 'getFieldGroupHelpers' + - 'DeepKeys' + - 'DeepValue' + sources: + - packages/form-core/tests/validation.test-d.ts + - packages/form-core/tests/deep-keys.test-d.ts + - packages/react-form/tests/submit-return.test-d.tsx + - packages/react-form/tests/FormGroup.test-d.tsx + - packages/react-form/tests/FieldGroupApi.test-d.tsx + - packages/react-form/src/AppForm/getFormHookHelpers.public.ts + - packages/react-form/src/FieldGroup/withFields.public.ts + teaches: + - 'Do not use type assertions to silence TanStack Form type errors; preserve inference and fix the mismatched boundary.' + - 'Classify the error by boundary: option mode, schema output, submit return, reusable child form prop, error visibility state, validator helper arity, form group scope, field group virtual path or binding, field component brand, deep-key path, or public API surface.' + - 'Treat ReactFormType unions in shared sections as a composition issue; use field groups instead of asserting through the union.' + - 'Separate schema strict/loose from field component strict/loose; they solve different problems.' + - 'For long errors, find the first concrete path, value, validator, or submit-return mismatch and ignore expanded generic machinery around it.' + - 'Reusable createErrorVisibility callbacks are form-agnostic; unknown values usually mean the policy should stay generic or become an inline callback.' + - 'createValidators type errors usually mean the count of run functions does not match the count of option configs.' + - 'FormGroup type errors usually mean a root-form path or value was used where group-scoped paths or values are expected.' + - 'Field-group type errors usually mean real paths were used where virtual paths are expected, a binding map is incomplete, or strict/loose slot compatibility was chosen incorrectly.' + - 'Deep-key path errors usually point to path shape; arrays use bracket segments and array helpers only accept paths whose value includes an array.' + - 'Use the first meaningful generic mismatch instead of the full expanded error wall.' + - 'Check whether the code is trying to use private/internal shape rather than public atom-based APIs.' + failure_modes: + - name: assertion_hides_form_inference + symptom: 'A user adds as const, as any, or a render-prop annotation like field: any to make an error disappear.' + correction: 'Remove the assertion and follow the inferred API boundary; use FieldWithValue or AnyFieldApi for reusable field props.' + evidence: + - maintainer_guidance.hard_do_nots + - examples/react/basic-splitting-form/src/StringField.tsx + - examples/react/basic-splitting-form/src/FieldError.tsx + - name: react_form_type_union + symptom: 'A shared section types its form prop as a union of multiple ReactFormType aliases.' + correction: 'Use field groups for shared sections across forms; ReactFormType is for splitting a known form.' + evidence: + - maintainer_guidance.hard_do_nots + - packages/react-form/src/FieldGroup/withFields.public.ts + - name: reusable_error_visibility_unknown_values + symptom: 'A createErrorVisibility helper tries to read a concrete property such as state.values.name.' + correction: 'Keep reusable policies value-agnostic, or use an inline callback when concrete form values are needed.' + evidence: + - packages/form-core/tests/validation.test-d.ts + - name: create_validators_arity_mismatch + symptom: 'createValidators reports a long tuple or overload error around missing or extra run functions.' + correction: 'Pass exactly one run function for each option config.' + evidence: + - packages/form-core/tests/validation.test-d.ts + - name: form_group_scope_mismatch + symptom: 'A FormGroup validator or field name complains about missing root fields or invalid paths.' + correction: 'Use group-scoped values and paths inside the group; reach through group.form only when root form state is intentionally needed.' + evidence: + - packages/react-form/tests/FormGroup.test-d.tsx + - name: field_group_virtual_path_mismatch + symptom: 'A field group method, watchFields entry, Field, or ArrayField rejects a real form path.' + correction: 'Use the virtual paths defined by defineFields inside the field group; map them to real paths only through withFields bindings.' + evidence: + - packages/react-form/tests/FieldGroupApi.test-d.tsx + - name: field_group_binding_map_mismatch + symptom: 'withFields rejects a binding map as incomplete, wrong, or as the internal defineFields object.' + correction: 'Provide every defined field binding, pass real form paths as bindings, and include the required form prop.' + evidence: + - packages/react-form/tests/FieldGroupApi.test-d.tsx + - name: deep_key_path_shape_mismatch + symptom: 'A field name or array helper rejects a path involving arrays, optional arrays, readonly arrays, or nullish data.' + correction: 'Check the DeepKeys path shape, including bracket array segments like users[0].name and array-valued path constraints.' + evidence: + - packages/form-core/tests/deep-keys.test-d.ts + - name: schema_strict_loose_vs_field_strict_loose + symptom: 'User assumes fieldComponent.strict/loose means strictSchema/looseSchema.' + correction: 'Explain schema option modes separately from field component value-compatibility branding.' + evidence: + - packages/react-form/src/AppForm/getFormHookHelpers.public.ts + - packages/form-core/src/utils.public.ts + - name: submit_specific_type_leaks_to_reusable_child + symptom: 'A reusable child rejects a form because TOnSubmit differs.' + correction: 'Use shared options without onSubmit or type the child around the intended ReactFormType boundary.' + evidence: + - packages/react-form/tests/submit-return.test-d.tsx + - name: strict_field_group_binding_mismatch + symptom: 'A field group strict slot rejects a real field path whose value is only assignable in one direction.' + correction: 'Use a loose field slot when the reusable group should accept wider compatible field values.' + evidence: + - packages/react-form/tests/FieldGroupApi.test-d.tsx + - packages/react-form/src/FieldGroup/withFields.public.ts + - name: public_api_store_confusion + symptom: 'Type error mentions missing store because example uses form.store or field.store.' + correction: 'Use public atom-based APIs and adapter subscriptions.' + evidence: + - packages/react-form/tests/FormGroup.test-d.tsx + - packages/react-form/src/ReactForm/fieldSubscriptions.lib.ts + - id: examples-authoring + title: Examples Authoring + status: reviewed + priority: high + domain: diagnostics-and-examples + purpose: 'Help Codex scaffold substantial maintainer examples for testing, future documentation, and user reference.' + entrypoints: + - 'examples/react/basic' + - 'examples/react/array' + - 'examples/react/basic-splitting-form' + - 'examples/react/field-groups' + - 'examples/react/ui-integration-shadcn' + - 'examples/react/ui-integration-dnd-kit' + sources: + - examples/react/basic/src/index.tsx + - examples/react/array/src/index.tsx + - examples/react/basic-splitting-form/src/index.tsx + - examples/react/field-groups/src/index.tsx + - examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx + - examples/react/ui-integration-shadcn/src/app/booking/booking-form.tsx + - examples/react/ui-integration-dnd-kit/src/singleList/index.tsx + - examples/react/ui-integration-dnd-kit/src/twoLists/index.tsx + teaches: + - 'Examples are scaffolding targets for maintainers in this private repository, and future users experience them as reference examples.' + - 'Examples should model user journeys, not just newly added core behavior.' + - 'Use React adapter APIs and realistic composition patterns.' + - 'When an example renders arrays of fields, use ArrayField at the list boundary and Field for item properties; when an array is one immutable value, Field is acceptable.' + - 'Show schema mode choice, async defaults, submit handling, and error visibility together when that reflects a real task.' + - 'Use useSelector or form.Subscribe for reactive form state reads; the form hook return is stable by design.' + - 'Keep UI library and query-library ownership boundaries honest.' + failure_modes: + - name: barren_core_test_example + symptom: 'Example only proves a core feature works and does not teach how a user should compose a real form.' + correction: 'Write examples around realistic adapter-first user journeys.' + evidence: + - maintainer_guidance.adapter_first + - examples/react/basic/src/index.tsx + - examples/react/ui-integration-shadcn/src/app/booking/booking-form.tsx + - name: dnd_multi_list_index_model + symptom: 'Multi-list drag-and-drop stores items as a single indexed array and races React with the DnD library.' + correction: 'Use stable item IDs with separate order arrays for cross-list movement.' + evidence: + - examples/react/ui-integration-dnd-kit/src/twoLists/index.tsx + - name: native_reset_surprise + symptom: 'A reset button triggers browser-native reset instead of form.reset semantics.' + correction: 'Prevent default button behavior and call form.reset intentionally.' + evidence: + - examples/react/basic/src/index.tsx + - packages/form-core/tests/FormApi/default-value.spec.ts + - name: submit_button_not_subscribed + symptom: 'Submit button does not reflect canSubmit or isSubmitting reliably.' + correction: 'Use form.Subscribe selectors for submit-related state.' + evidence: + - examples/react/basic/src/index.tsx + - packages/react-form/src/ReactForm/Components.public.ts +gaps: + - id: missing-tanstack-query-example + skill: query-backed-forms + status: open + question: 'No checked-in query-backed example was available in this filesystem snapshot.' + context: 'The IDE referenced examples/react/tanstack-query/src/App.tsx, but examples/react/tanstack-query was absent. Query-backed guidance is therefore sourced from tests and maintainer interview until a realistic example is scaffolded.' +evidence_constraints: + - id: docs-are-mostly-reference + status: noted + note: 'The docs directory is largely generated API reference; conceptual documentation is sparse.' + implication: 'Generated skills should lean on source, tests, examples, and maintainer interview for current intent.' + - id: no-private-issue-signal + status: resolved + note: 'Maintainer clarified private issues are developer TODOs/plans and not useful user-problem evidence.' + implication: 'Do not mine private issues for skill priorities in this repository.' + - id: examples-are-maintainer-scaffolds + status: resolved + note: "Examples are needed so maintainers can test scenarios and expand future documentation; intent skills should improve Codex's ability to scaffold them." + implication: 'Do not treat example selection as a public roadmap priority question. Future users primarily consume examples as references.' +tensions: + - id: schema_strictness_vs_editable_defaults + skills: + - choosing-form-options-modes + - schema-driven-forms + - type-error-debugging + description: 'Schema-source typing improves parsed output confidence, but editable form defaults may need nullable or undefined intermediate values.' + implication: 'Agents may choose strictSchema for a ruleset-style form and then fight nullish defaults with assertions, or choose looseSchema for a true transform pipeline and read raw value.' + - id: query_loading_ui_vs_form_initialization + skills: + - query-backed-forms + - examples-authoring + description: 'Gating a form until query data arrives gives correct initial state, while fallback empty values let the UI render immediately.' + implication: 'Agents may pass maybe-undefined query data directly or choose a loading strategy without matching the visual workflow.' + - id: validation_state_vs_transient_state + skills: + - query-backed-forms + - schema-driven-forms + - error-visibility-workflows + description: 'Validation errors are form state that can block submission; transient query/network/framework failures belong outside validation state.' + implication: 'Agents may convert retryable endpoint failures into visible field errors and accidentally block the next submit.' + - id: reuse_vs_inference_boundaries + skills: + - react-form-composition-setup + - reusable-form-policies + - type-error-debugging + - examples-authoring + description: 'Reusable sections improve examples and app code, but the wrong abstraction boundary breaks inference.' + implication: 'Agents may assert field names, hand-write field props, or union ReactFormType forms instead of using inferred children, helper types, or field groups.' +cross_references: + - from: react-form-composition-setup + to: examples-authoring + reason: 'Examples should model adapter-first composition choices instead of core-level API proofs.' + - from: react-form-composition-setup + to: reusable-form-policies + reason: 'Split sections, AppForm, and field groups determine which reusable helper type or policy boundary is appropriate.' + - from: reusable-form-policies + to: react-form-composition-setup + reason: 'Reusable policies should not replace the larger composition choice between split forms, AppForm, and field groups.' + - from: reusable-form-policies + to: error-visibility-workflows + reason: 'Named visibility helpers should preserve the user workflow that controls when errors appear.' + - from: reusable-form-policies + to: type-error-debugging + reason: 'Reusable helper boundaries often explain long ReactFormType, createErrorVisibility, and createValidators errors.' + - from: examples-authoring + to: react-form-composition-setup + reason: 'Example scaffolds need the Field, ArrayField, Subscribe, AppForm, ReactFormType, and field-group boundaries.' + - from: choosing-form-options-modes + to: schema-driven-forms + reason: 'Schema validation and submit output depend on the selected option mode.' + - from: choosing-form-options-modes + to: type-error-debugging + reason: 'Many large type errors originate at the default, strictSchema, or looseSchema boundary.' + - from: schema-driven-forms + to: query-backed-forms + reason: 'Query-backed submit handlers often need to convert server validation responses into returned validation values.' + - from: query-backed-forms + to: error-visibility-workflows + reason: 'Async defaults and submit failures often change when users expect validation errors to become visible.' + - from: type-error-debugging + to: react-form-composition-setup + reason: 'Most type fixes should preserve adapter inference instead of adding assertions.' +phase5_finalization: + reviewed_on: '2026-06-25' + resolved_interview_topics: + - hard_do_nots + - schema_mode_wording + - query_backed_default_value_strategies + - async_on_submit_errors + - reusable_policy_helpers + - app_form_vs_split_sections_vs_field_groups + - field_vs_array_field + - type_error_debugging_from_type_tests + - examples_as_maintainer_scaffolds + - standard_schema_libraries_as_heuristic_examples + remaining_open_gaps: + - missing-tanstack-query-example diff --git a/_artifacts/skill_spec.md b/_artifacts/skill_spec.md new file mode 100644 index 0000000000..ce1e85d5e1 --- /dev/null +++ b/_artifacts/skill_spec.md @@ -0,0 +1,480 @@ +# TanStack Form V2 Skill Spec + +Status: reviewed, Phase 5 finalized. + +This reviewed artifact follows the `pnpm intent:scaffold` domain-discovery workflow. It is intentionally adapter-first: user-facing guidance starts from `@tanstack/react-form`, with `@tanstack/form-core` used as the source of concepts and behavior rather than as a workflow entrypoint. + +## Scope + +In scope: + +- React form composition with `useForm`, `form.Field`, `form.ArrayField`, `form.Subscribe`, app-form helpers, and field groups. +- Standard Schema-compatible schema usage. +- Choosing between default form options, `strictSchema`, and `looseSchema`. +- Query-like async defaults and mutation-like submit handling. +- Error visibility callback workflows. +- Split-form helper types and reusable validation or visibility policy modules. +- Type error diagnosis for schema/form composition. +- Authoring richer React examples. + +Out of scope for this pass: + +- Devtools as an entrypoint. +- Migration guidance. +- Schema metadata extraction, such as automatically deriving required labels. +- TanStack Form owning transient or non-validation error state. +- Teaching UI-library behavior as part of TanStack Form itself. +- Solid-first coverage. + +## Hard Do Nots + +- Do not type assert to make TanStack Form code compile. The library is built around inference, and assertions are usually a sign that the code is fighting the API. +- Do not write field names like ``name={`users[${index}].name` as const}``; `name` is inferred without the assertion. +- Do not annotate render-prop children as `any`; field children already receive inferred field APIs. +- Do not shim field prop types by hand, such as `{ value: string }`; use inferred render-prop types, `FieldWithValue`, or `AnyFieldApi` when a reusable component needs an explicit field prop type. +- Do not treat validation errors and transient errors as the same thing. Errors stored from validators or `onSubmit` block the user from submitting. +- Do not store query/network/framework transient failures as form validation errors. Most query libraries already own transient error state; use that state instead. +- Do not throw validation errors from validators or `onSubmit`; validation errors must be returned values, such as `createValidationError` or `parseIssues`. +- Do not type a shared section as `form: FormA | FormB` where each form is a different `ReactFormType`; TypeScript cannot make sense of that union. Use field groups for shared sections that need to work across different forms. + +## Proposed Skills + +### 1. React Form Composition Setup + +Purpose: Help users build adapter-first React forms, reusable field components, app-form setups, field groups, arrays, and UI-library bindings. + +Primary APIs: + +- `useForm` +- `ReactFormType` +- `FieldWithValue` +- `AnyFieldApi` +- `formOptions` +- `createFormHook` +- `form.Field` +- `form.ArrayField` +- `form.Subscribe` +- `form.FormGroup` +- `withFields` + +Core guidance: + +- Start from `@tanstack/react-form`, not `@tanstack/form-core`. +- Use render-prop field APIs and subscriptions for state reads. +- Treat `useForm` and `useAppForm` as stable form creation hooks, not reactive state reads by themselves. +- Use `useSelector` or `form.Subscribe` when component output must update in response to form state. +- Use app-form helpers when an application wants reusable field and form components. +- Keep shared form options submit-agnostic when child components need to accept forms with different `onSubmit` handlers. +- Use `ReactFormType` as one option for splitting a known form into child sections that receive the form as a prop. +- Do not use unions like `ReactFormType | ReactFormType` for shared sections; use field groups when one section should bind into multiple different forms. +- Use AppForm to reduce repeated field JSX boilerplate. Use split form sections to reduce component nesting. Use field groups for reusable sections that bind to different form paths or different forms. +- Let field `name` props and render-prop children infer their types; use `FieldWithValue` or `AnyFieldApi` for explicit reusable field component props. +- `form.Field` may bind to an array value. It treats that array immutably like any other field value, so changing one element changes the field `value` and rerenders consumers of the whole array field. +- Use `form.ArrayField` when the array is a rendering boundary for child fields or list items, and those child fields are the reactive units the example cares about. +- Use array helpers for array mutations and reorders. + +Important failure modes: + +- Adding `as const`, `as any`, render-prop `field: any`, or other assertions to force form code to compile. +- Shimming field prop types by hand instead of using inferred field types, `FieldWithValue`, or `AnyFieldApi`. +- Reading from the stable `useForm` or `useAppForm` return and expecting the component to re-render as form state changes. +- Importing core directly in examples or application code. +- Rendering app field components outside their required app-form or field context. +- Making a reusable child form prop too specific by baking in an `onSubmit` type. +- Splitting a form by hand-writing a large form prop type instead of deriving it from shared options with `ReactFormType`. +- Typing a shared section as a union of multiple `ReactFormType` forms instead of using field groups. +- Using `form.Field` to render a list of child fields, then being surprised that item changes rerender the whole array-value consumer. +- Treating `form.ArrayField` as required for every array-typed value, instead of using it when the array will render child fields or list items. +- Mutating arrays manually and desynchronizing values from field meta. + +Source trail: + +- `packages/react-form/src/ReactForm/Components.public.ts` +- `packages/react-form/src/ReactForm/ReactFormApi.lib.tsx` +- `packages/react-form/src/Subscribe.public.tsx` +- `packages/react-form/src/ReactForm/fieldSubscriptions.lib.ts` +- `packages/react-form/src/AppForm/createFormHook.public.ts` +- `packages/react-form/src/AppForm/contexts.lib.ts` +- `docs/reference/type-aliases/FieldWithValue.md` +- `docs/reference/type-aliases/AnyFieldApi.md` +- `docs/framework/react/reference/type-aliases/ReactFormType.md` +- `packages/react-form/tests/submit-return.test-d.tsx` +- `packages/form-core/src/FormApi/array-methods.lib.ts` +- `packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts` +- `packages/form-core/src/FieldApi/fieldState.lib.ts` +- `examples/react/array/src/index.tsx` +- `examples/react/basic-splitting-form/src/index.tsx` +- `examples/react/basic-splitting-form/src/FormSection.tsx` +- `examples/react/basic-splitting-form/src/StringField.tsx` +- `examples/react/basic-splitting-form/src/FieldError.tsx` +- `examples/react/ui-integration-shadcn/src/components/form/app-form.ts` + +### Cross-Cutting: Reusable Form Policies + +Purpose: Help agents recognize when form behavior should be extracted into a named reusable helper rather than repeated inline. + +Primary APIs: + +- `ReactFormType` +- `createErrorVisibility` +- `createValidator` +- `createValidators` +- shared `formOptions` / `appFormOptions` + +Core guidance: + +- Use `ReactFormType` as the helper type for split form sections that receive a `form` prop. +- Treat `ReactFormType` splitting as one composition option, not a general replacement for AppForm or field groups. +- AppForm reduces repeated field JSX boilerplate; split sections reduce nesting in a known form; field groups cover shared sections across different forms or field paths. +- Prefer form-level `errorVisibility` callbacks over scattered local patterns like `const showErrors = field.meta.isTouched && field.meta.isInvalid`. +- Use helper functions mainly when a callback or validator config deserves a semantic name that preserves intent. +- Extract validator configs with `createValidator` or `createValidators` when trigger timing, debounce, `bailIfInvalid`, or `skipOnSubmit` policy is complex enough to name. +- Use comments or JSDoc on named helpers to explain behavior intent, such as why errors wait for blur or submit, or why a validator uses a `rewardEarlyPunishLate` policy. +- Keep reusable policies value-agnostic unless they are intentionally tied to a specific form shape; inline callbacks are better when typed values are required. + +Important failure modes: + +- A split form loses field-name inference because the child prop type was hand-written. +- A shared section accepts `FormA | FormB` and TypeScript cannot narrow field names or form methods enough to make the section usable. +- Error display behavior is scattered through local `showErrors` variables instead of being controlled by form-level `errorVisibility`. +- A complex visibility workflow is duplicated inline and later examples preserve code shape but lose the user-workflow reason. +- Validator trigger settings are copied without explanation, so agents cannot tell whether `blur`, `change`, debounce, or `bailIfInvalid` is intentional. +- A reusable visibility function tries to read a concrete `state.values.name` even though reusable visibility callbacks are form-agnostic. + +Source trail: + +- `examples/react/basic-splitting-form/src/FormSection.tsx` +- `examples/react/basic-splitting-form/src/sharedForm.ts` +- `packages/react-form/tests/submit-return.test-d.tsx` +- `packages/form-core/tests/validation.test.ts` +- `packages/form-core/tests/validation.test-d.ts` +- `examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx` + +### 2. Choosing Form Options Modes + +Purpose: Help users decide between default `formOptions`, `strictSchema`, and `looseSchema`. + +Primary APIs: + +- `formOptions` +- `formOptions.strictSchema` +- `formOptions.looseSchema` +- `appFormOptions` +- `appFormOptions.strictSchema` +- `appFormOptions.looseSchema` + +Core guidance: + +- Treat the option helpers as runtime identity helpers with type-level meaning. +- Use default `formOptions` when the form should be inferred from `defaultValues`; the default values are taken at face value and that type flows into validators and callbacks. +- Default `formOptions` is especially useful for callback-based validation because callback `value` is already typed from the form defaults. +- Use `strictSchema` when the schema is the source of typing and acts as a transforming pipeline from input type to output type. +- In `strictSchema`, `defaultValues` should type-check against the schema input type. If they do not align, the defaults should produce type errors. +- Use `looseSchema` when the schema is a ruleset for confirming valid output, but editable defaults need nullable or undefined values, such as a date field that starts as `null`. +- In `looseSchema`, default values must still align with the schema shape, but properties may also be `null` or `undefined` where editing requires it. +- In both schema modes, callbacks may not have useful inference unless there is a schema in the validator array for the helper to infer from. +- In both schema modes, `onSubmit` should read the parsed transform output from `validatorOutputs` rather than raw `value`. +- Treat pipeline-vs-ruleset as TanStack Form guidance, not a Standard Schema concept. Standard Schema only gives the shared validation/typing interface. +- Explain the mental model as: is this schema a pipeline of constraints/transforms, or a firewall that only lets valid values through? +- List current Standard Schema-capable libraries as examples with a general leaning, not as hard categories. +- Zod generally leans ruleset/firewall for form work, while explicit transforms/codecs can still make a Zod schema pipeline-like. +- Valibot generally leans pipeline because its docs center `pipe` and validation/transformation actions. +- ArkType is mixed: structural constraints often read like a firewall, while morphs/pipes can make it pipeline-like. +- Effect Schema often leans pipeline/codec when used as an encoded-to-decoded boundary. + +Important failure modes: + +- Expecting `strictSchema` or `looseSchema` to add runtime validation by itself. +- Using default `formOptions` while expecting the schema to be the source of the form type. +- Using strict schema mode for a form whose editable UI states cannot satisfy the schema type. +- Using `looseSchema` but providing default values that no longer match the schema shape at all. +- Using schema modes without putting a schema in the validator array, then expecting callbacks to infer from that schema. +- Using loose schema mode for a true pipeline and then reading raw `value` as if it were parsed output. +- Reading `value` in `onSubmit` for schema-mode forms instead of reading the corresponding `validatorOutputs` entry. +- Treating all Zod `input` and `output` differences as a real pipeline decision. + +Source trail: + +- `packages/form-core/src/utils.public.ts` +- `packages/react-form/src/AppForm/appFormOptions.public.ts` +- `packages/form-core/tests/validation.test.ts` +- `packages/form-core/tests/validation.test-d.ts` +- `examples/react/ui-integration-shadcn/src/app/booking/schema.ts` +- `examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx` +- `https://standardschema.dev/` +- `https://zod.dev/library-authors` +- `https://valibot.dev/guides/integrate-valibot/` +- `https://arktype.io/docs/integrations` +- `https://effect.website/docs/schema/standard-schema/` + +### 3. Schema Driven Forms + +Purpose: Help users take a Standard Schema-compatible schema and wire it into validation, field errors, submit output, and type inference. + +Primary APIs: + +- `validators` +- `FormSubmitContext.validatorOutputs` +- `parseIssues` +- `createValidationError` + +Core guidance: + +- Configure schema validation through validators. +- Extract reusable validator trigger configs with `createValidator` or `createValidators` when the behavior is complex enough to need a semantic name. +- Read parsed schema output from `onSubmit` context's `validatorOutputs`; raw `value` remains form state. +- Route submit validation errors as returned values through `createValidationError` or `parseIssues`; do not throw them. +- Let Standard Schema issue paths route nested and array field errors when possible. +- Keep UI metadata explicit or schema-library-specific; Standard Schema does not standardize it. + +Important failure modes: + +- Expecting schema output to replace form `value`. +- Returning or throwing raw schema errors from submit code and expecting field errors. +- Throwing validation errors instead of returning `createValidationError` or `parseIssues` values. +- Manually mapping nested issue paths incorrectly. +- Duplicating validator trigger, debounce, submit, or bail policy inline without documenting why that behavior exists. +- Trying to build general UI metadata extraction from Standard Schema. + +Source trail: + +- `packages/form-core/src/standardSchema.public.ts` +- `packages/form-core/src/standardSchema.lib.ts` +- `packages/form-core/src/FormApi/FormApi.public.ts` +- `packages/form-core/tests/validation.test.ts` +- `packages/form-core/tests/FormApi/submission-handling.spec.ts` +- `examples/react/field-groups/src/index.tsx` + +### 4. Query Backed Forms + +Purpose: Help users combine form state with query-like async defaults and mutation-like submit calls. + +Primary APIs: + +- `useForm({ defaultValues })` +- `onSubmit` +- `form.reset` +- `createValidationError` +- `parseIssues` + +Core guidance: + +- Do not feed maybe-undefined query data into the form by itself; choose an explicit default-values plan. +- Approach 1: do not mount the fields until the query is finished. The whole form can also be gated so the first mounted form state is populated with correct data. +- Approach 2: define a static shape-complete `emptyFormValues` object and pass defaults as `query.data ?? emptyFormValues`. +- Neither approach is preferred globally; choose based on the desired loading and visual UI language. +- Gating fields changes the UI because fields or the whole form appear only after data is ready. The fallback approach can render the form immediately, often with loading or placeholder state around it. +- Update defaults when async data arrives and rely on touched-field preservation for user edits. +- Separate transient errors from validation errors. +- Use an async promise for the endpoint call inside `onSubmit` so `isSubmitting` reflects the request. +- Catch submit failures only when the endpoint can return validation errors that should be converted into returned `createValidationError` or `parseIssues` values. +- Transient submit failures may throw or reject; the form will set `isSubmitSuccessful` to false, and query/framework state should preserve the transient error details. +- Leave transient query, network, and framework failures in the query/framework error state instead of converting them into form validation errors. +- Use reset options deliberately when replacing both values and default baselines. + +Important failure modes: + +- Treating initial `undefined` query data as a final form shape. +- Passing `query.data` directly as defaults without either gated mounting or an `emptyFormValues` fallback. +- Gating fields without accounting for the different loading UI, or rendering fallback values without communicating that query data is still loading. +- Overwriting touched user edits when async defaults arrive. +- Starting an endpoint call inside `onSubmit` without returning or awaiting its promise, so `isSubmitting` does not cover the request. +- Turning transient network or server failures into validation errors and accidentally blocking future submits. +- Throwing validation errors from `onSubmit` instead of returning validation values. +- Treating a rejected transient `onSubmit` as something that should produce visible field errors. + +Source trail: + +- `packages/react-form/tests/useForm.spec.tsx` +- `packages/form-core/src/FormApi/FormApi.lib.ts` +- `packages/form-core/src/FormApi/FormApi.public.ts` +- `packages/form-core/tests/FormApi/default-value.spec.ts` +- `packages/form-core/tests/FormApi/submission-handling.spec.ts` + +Open evidence gap: the IDE referenced `examples/react/tanstack-query/src/App.tsx`, but this checkout did not contain `examples/react/tanstack-query`. + +### 5. Error Visibility Workflows + +Purpose: Help users implement policies such as "show after blur", "show after submit", or "show after blur or submit". + +Primary APIs: + +- `errorVisibility` +- `createErrorVisibility` +- `createValidator` +- `createValidators` +- `fieldState.meta` +- `state.submissionAttempts` +- `form.FormGroup` + +Core guidance: + +- `errorVisibility` is callback-based. +- Use form-level `errorVisibility` to control default visible-error behavior instead of scattering local checks like `field.meta.isTouched && field.meta.isInvalid`. +- Reusable visibility policies created with `createErrorVisibility` should be value-agnostic. +- Use `createErrorVisibility`, `createValidator`, and `createValidators` mainly when a policy benefits from a semantic name or intent-focused comments/JSDoc. +- Inline callbacks can use the consuming form's typed values. +- Visibility callbacks receive pre-filter field meta, not visible errors or validity. +- Grouped forms scope submission attempts to the nearest group. + +Important failure modes: + +- Writing string presets such as `errorVisibility: 'touched'`. +- Repeating local `showErrors` expressions across fields instead of setting the form's default error visibility behavior. +- Inspecting `fieldState.meta.errors` or validity inside the visibility callback. +- Expecting reusable `createErrorVisibility` callbacks to know a concrete form value shape. +- Copying complex visibility or validator policy inline without documenting the workflow intent. +- Forgetting group-scoped submission attempts in wizard or section-level flows. + +Source trail: + +- `packages/form-core/src/validation.public.ts` +- `packages/form-core/src/FieldApi/fieldState.lib.ts` +- `packages/form-core/tests/validation.test-d.ts` +- `packages/form-core/tests/FormApi/validation.spec.ts` +- `packages/form-core/tests/FormGroupApi/FormGroupApi.spec.ts` +- `examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx` + +### 6. Type Error Debugging + +Purpose: Help users interpret large TypeScript errors from schemas, option modes, field groups, reusable forms, and adapter APIs. + +Primary APIs and concepts: + +- `ReactFormType` +- `formOptions` +- `appFormOptions` +- `createErrorVisibility` +- `createValidators` +- schema `strictSchema` / `looseSchema` +- field component `strict` / `loose` +- field group `strict` / `loose` +- `DeepKeys` +- `DeepValue` +- public `atom` APIs + +Core guidance: + +- Do not use type assertions to silence TanStack Form type errors; preserve inference and fix the mismatched boundary. +- Classify the error by boundary: schema option mode, schema output, submit return, reusable child form props, error visibility state, validator helper arity, form group scope, field group virtual path/binding, field component brand, deep-key path, or public/private API mismatch. +- Treat a `ReactFormType` union in a shared section as a design issue, not a TypeScript problem to assert through; reach for field groups instead. +- Do not confuse schema strict/loose with field component or field group strict/loose. +- For long errors, find the first concrete path, value, validator, or submit-return mismatch and ignore the expanded generic machinery around it. +- Reusable `createErrorVisibility` callbacks are form-agnostic; if a type error mentions `unknown` values, use an inline callback for form-specific values. +- `createValidators` type errors often mean the number of run functions does not match the number of option configs. +- FormGroup type errors often mean the code used a root-form path/value where the group expects group-scoped paths/values. +- Field-group type errors often mean the code used real form paths where virtual paths are expected, passed an incomplete binding map, or chose `strict` when the real path is only loosely compatible. +- Deep-key path errors usually point to path shape: arrays use bracket segments such as `users[${number}].name`, and array helpers only accept paths whose value includes an array. +- Look for the first meaningful generic mismatch rather than the full expanded error wall. +- Prefer source-backed explanation over broad TypeScript folklore. + +Important failure modes: + +- Adding assertions like `as const`, `as any`, or `(field: any)` instead of letting form names and children infer. +- Hand-writing shim field prop types instead of using inferred props, `FieldWithValue`, or `AnyFieldApi`. +- Typing a shared section as `ReactFormType | ReactFormType`. +- Expecting a reusable `createErrorVisibility` callback to read concrete form values. +- Calling `createValidators` with fewer or more run functions than option configs. +- Using root-form field names or values inside a `FormGroup` validator or grouped field. +- Passing real form paths into a field group API where virtual paths are required. +- Providing an incomplete `withFields` binding map, passing the internal defined-fields object as a binding, or omitting the required `form` prop. +- Reading `form.store` or `field.store` instead of public `atom` APIs. +- Treating `fieldComponent.strict/loose` as schema mode selection. +- Passing a submit-specific form type to a reusable child that should accept several submit handlers. +- Binding a strict field group slot to a field path whose value is only loosely compatible. + +Source trail: + +- `packages/form-core/tests/validation.test-d.ts` +- `packages/form-core/tests/deep-keys.test-d.ts` +- `packages/react-form/tests/submit-return.test-d.tsx` +- `packages/react-form/tests/FormGroup.test-d.tsx` +- `packages/react-form/tests/FieldGroupApi.test-d.tsx` +- `packages/react-form/src/AppForm/getFormHookHelpers.public.ts` +- `packages/react-form/src/FieldGroup/withFields.public.ts` + +### 7. Examples Authoring + +Purpose: Help Codex scaffold substantial maintainer examples for testing, future documentation, and user reference. + +Primary example areas: + +- Basic form and submit handling. +- Schema-driven form. +- Query-backed form. +- Error visibility workflow. +- App-form and UI-library integration. +- Field groups. +- Arrays and reorder behavior. + +Core guidance: + +- Examples are scaffolding targets for maintainers in this private repository, and future users experience them as reference examples. +- Examples should be adapter-first and user-journey-shaped. +- Combine features when real workflows combine them, such as schema mode plus async defaults plus submit validation plus visibility policy. +- Keep boundaries explicit: TanStack Form handles validation and form state; query/framework code owns transient errors; UI libraries own visual behavior. +- Show reactive state reads with `useSelector` or `form.Subscribe`; do not imply the stable hook return is itself reactive. +- Prefer realistic examples over minimal API proofs once behavior has test coverage. + +Important failure modes: + +- Writing barren examples that resemble core tests more than user workflows. +- Modeling complex DnD multi-list state as a single indexed array and creating UI races. +- Letting native reset behavior fight form reset semantics. +- Reading form state from the stable hook return without a selector or subscription, then wondering why UI does not update. +- Reading submit state outside `form.Subscribe` and missing updates. + +Source trail: + +- `examples/react/basic/src/index.tsx` +- `examples/react/array/src/index.tsx` +- `examples/react/basic-splitting-form/src/index.tsx` +- `examples/react/field-groups/src/index.tsx` +- `examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx` +- `examples/react/ui-integration-shadcn/src/app/booking/booking-form.tsx` +- `examples/react/ui-integration-dnd-kit/src/singleList/index.tsx` +- `examples/react/ui-integration-dnd-kit/src/twoLists/index.tsx` + +## Cross-Skill Relationships + +- React Form Composition Setup is the base skill for all example work. +- Reusable Form Policies sits between React Form Composition Setup, Error Visibility Workflows, and Type Error Debugging. +- Choosing Form Options Modes feeds Schema Driven Forms and Type Error Debugging. +- Schema Driven Forms feeds Query Backed Forms when submit returns server-side validation. +- Error Visibility Workflows is often layered on top of Schema Driven Forms and Query Backed Forms. +- Examples Authoring should compose the other skills into realistic maintainer scaffolds that can later serve as references. + +## Cross-Skill Tensions + +- Schema strictness vs editable defaults: strict schema typing helps submit output, but editable forms often need nullable or undefined intermediate values. +- Query loading UI vs form initialization: gated mounting gives correct first form state, while `emptyFormValues` lets the UI render immediately. +- Validation state vs transient state: validation errors block submit, while query/network/framework failures should remain outside form validation state. +- Reuse vs inference boundaries: reusable sections are valuable, but assertions, hand-written field props, or `ReactFormType` unions break the intended inference model. + +## Remaining Gaps + +- Query Backed Forms: the IDE referenced `examples/react/tanstack-query/src/App.tsx`, but this checkout did not contain `examples/react/tanstack-query`. Query-backed guidance is reviewed from tests and maintainer interview, and should be exercised by scaffolding a realistic example later. + +## Phase 5 Finalization + +Resolved in the detail interview: + +- Hard do-nots, especially no type assertions and no transient errors as validation errors. +- Schema mode wording for default `formOptions`, `strictSchema`, and `looseSchema`. +- Query-backed default-value strategies and their visual loading language. +- Async `onSubmit` behavior, including `isSubmitting`, `isSubmitSuccessful`, returned validation values, and thrown transient failures. +- Reusable policy helpers as semantic names for complex callbacks/configs. +- AppForm, `ReactFormType` split sections, and field groups as separate composition tools. +- Field vs `ArrayField`, especially array-as-immutable-value versus array-as-child-field-rendering-boundary. +- Type-error debugging categories derived from the type tests. +- Examples authoring as maintainer scaffolding for testing and future reference examples. +- Standard Schema libraries as heuristic examples, with pipeline-vs-firewall/ruleset clearly marked as TanStack Form guidance rather than a Standard Schema concept. + +Reviewed acceptance criteria: + +- Skills never make `@tanstack/form-core` the user-facing workflow entrypoint. +- Skills explain schemas through adapter APIs while preserving core semantics. +- Skills distinguish validation errors from transient async failures. +- Skills do not promise schema metadata extraction. +- Skills do not use devtools or migration as current entrypoints. +- Examples guidance is realistic enough for agents to build non-barren examples. diff --git a/_artifacts/skill_tree.yaml b/_artifacts/skill_tree.yaml new file mode 100644 index 0000000000..5be3cbdd3c --- /dev/null +++ b/_artifacts/skill_tree.yaml @@ -0,0 +1,224 @@ +schema_version: 1 +status: reviewed +library: + name: TanStack Form v2 + version: '0.0.0' + repository: https://github.com/TanStack/form-v2 + description: 'Headless form state, validation, schema, and adapter APIs for TanStack Form v2, with React as the primary skill target.' +generated_from: + domain_map: _artifacts/domain_map.yaml + skill_spec: _artifacts/skill_spec.md +generated_at: '2026-06-25' +layout: + kind: flat + reason: 'The reviewed skills are task-focused and independently discoverable; no router skill is needed for 8 skills.' + default_package: packages/react-form + adapter_first: true +skills: + - name: React Form Composition Setup + slug: react-form-composition-setup + type: framework + domain: react-adapter-composition + path: packages/react-form/skills/react-form-composition-setup/SKILL.md + package: packages/react-form + description: 'Use when building adapter-first React forms with useForm, form.Field, form.ArrayField, form.Subscribe, AppForm, ReactFormType, field groups, reusable field components, or UI-library bindings.' + sources: + - packages/react-form/src/ReactForm/Components.public.ts + - packages/react-form/src/ReactForm/fieldSubscriptions.lib.ts + - packages/react-form/src/AppForm/createFormHook.public.ts + - packages/react-form/src/FieldGroup/withFields.public.ts + - packages/react-form/tests/submit-return.test-d.tsx + - packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts + - packages/form-core/src/FieldApi/fieldState.lib.ts + - examples/react/array/src/index.tsx + - examples/react/basic-splitting-form/src/index.tsx + - examples/react/ui-integration-shadcn/src/components/form/app-form.ts + - name: Reusable Form Policies + slug: reusable-form-policies + type: framework + domain: validation-and-error-visibility + path: packages/react-form/skills/reusable-form-policies/SKILL.md + package: packages/react-form + description: 'Use when extracting ReactFormType split-form props, createErrorVisibility policies, createValidator/createValidators configs, shared formOptions, or appFormOptions into named reusable helpers with documented intent.' + requires: + - react-form-composition-setup + - error-visibility-workflows + sources: + - examples/react/basic-splitting-form/src/FormSection.tsx + - examples/react/basic-splitting-form/src/sharedForm.ts + - packages/react-form/tests/submit-return.test-d.tsx + - packages/form-core/tests/validation.test.ts + - packages/form-core/tests/validation.test-d.ts + - examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx + references: + - references/reusable-policy-boundaries.md + - name: Choosing Form Options Modes + slug: choosing-form-options-modes + type: framework + domain: schema-driven-forms + path: packages/react-form/skills/choosing-form-options-modes/SKILL.md + package: packages/react-form + description: 'Use when choosing between default formOptions, formOptions.strictSchema, formOptions.looseSchema, appFormOptions, and schema-source typing for React forms.' + sources: + - packages/form-core/src/utils.public.ts + - packages/react-form/src/AppForm/appFormOptions.public.ts + - packages/form-core/tests/validation.test.ts + - packages/form-core/tests/validation.test-d.ts + - examples/react/ui-integration-shadcn/src/app/booking/schema.ts + - examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx + - https://standardschema.dev/ + - https://zod.dev/library-authors + - https://valibot.dev/guides/integrate-valibot/ + - https://arktype.io/docs/integrations + - https://effect.website/docs/schema/standard-schema/ + references: + - references/schema-option-modes.md + - references/standard-schema-library-leanings.md + - name: Schema Driven Forms + slug: schema-driven-forms + type: framework + domain: schema-driven-forms + path: packages/react-form/skills/schema-driven-forms/SKILL.md + package: packages/react-form + description: 'Use when wiring Standard Schema-compatible validators, validators arrays, outputs, parseIssues, createValidationError, nested issue paths, and schema submit output into React forms.' + requires: + - choosing-form-options-modes + sources: + - packages/form-core/src/standardSchema.public.ts + - packages/form-core/src/standardSchema.lib.ts + - packages/form-core/src/FormApi/FormApi.public.ts + - packages/form-core/tests/validation.test.ts + - packages/form-core/tests/validation.test-d.ts + - packages/form-core/tests/FormApi/submission-handling.spec.ts + - examples/react/field-groups/src/index.tsx + references: + - references/schema-validation-and-submit-output.md + - name: Query Backed Forms + slug: query-backed-forms + type: composition + domain: async-data-and-submit + path: packages/react-form/skills/query-backed-forms/SKILL.md + package: packages/react-form + description: 'Use when combining React forms with query-like async defaults, maybe-undefined incoming data, emptyFormValues fallbacks, gated field mounting, async onSubmit, mutation calls, and transient-vs-validation errors.' + requires: + - react-form-composition-setup + sources: + - packages/react-form/tests/useForm.spec.tsx + - packages/form-core/src/FormApi/FormApi.lib.ts + - packages/form-core/src/FormApi/FormApi.public.ts + - packages/form-core/src/FormApi/handleSubmit.lib.ts + - packages/form-core/tests/FormApi/default-value.spec.ts + - packages/form-core/tests/FormApi/submission-handling.spec.ts + - maintainer_guidance.query_shape + references: + - references/query-backed-defaults-and-submit.md + - name: Error Visibility Workflows + slug: error-visibility-workflows + type: framework + domain: validation-and-error-visibility + path: packages/react-form/skills/error-visibility-workflows/SKILL.md + package: packages/react-form + description: 'Use when implementing errorVisibility callbacks, createErrorVisibility helpers, show-after-blur, show-after-submit, grouped submission attempts, fieldState.meta visibility, or reusable validation trigger policies.' + sources: + - packages/form-core/src/validation.public.ts + - packages/form-core/src/FieldApi/fieldState.lib.ts + - packages/form-core/src/utils.public.ts + - packages/form-core/tests/validation.test-d.ts + - packages/form-core/tests/FormApi/validation.spec.ts + - packages/form-core/tests/FormGroupApi/FormGroupApi.spec.ts + - examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx + references: + - references/error-visibility-policies.md + - name: Type Error Debugging + slug: type-error-debugging + type: framework + domain: diagnostics-and-examples + path: packages/react-form/skills/type-error-debugging/SKILL.md + package: packages/react-form + description: 'Use when explaining large TypeScript errors from ReactFormType, FieldWithValue, AnyFieldApi, formOptions, appFormOptions, createErrorVisibility, createValidators, field groups, DeepKeys, DeepValue, or schema modes.' + requires: + - react-form-composition-setup + - choosing-form-options-modes + sources: + - packages/form-core/tests/validation.test-d.ts + - packages/form-core/tests/deep-keys.test-d.ts + - packages/react-form/tests/submit-return.test-d.tsx + - packages/react-form/tests/FormGroup.test-d.tsx + - packages/react-form/tests/FieldGroupApi.test-d.tsx + - packages/react-form/src/AppForm/getFormHookHelpers.public.ts + - packages/react-form/src/FieldGroup/withFields.public.ts + references: + - references/type-error-boundaries.md + - name: Examples Authoring + slug: examples-authoring + type: lifecycle + domain: diagnostics-and-examples + path: packages/react-form/skills/examples-authoring/SKILL.md + package: packages/react-form + description: 'Use when scaffolding realistic React examples for TanStack Form v2, including schema-driven forms, query-backed forms, error visibility workflows, app-form UI integrations, field groups, arrays, and reorder behavior.' + requires: + - react-form-composition-setup + sources: + - examples/react/basic/src/index.tsx + - examples/react/array/src/index.tsx + - examples/react/basic-splitting-form/src/index.tsx + - examples/react/field-groups/src/index.tsx + - examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx + - examples/react/ui-integration-shadcn/src/app/booking/booking-form.tsx + - examples/react/ui-integration-dnd-kit/src/singleList/index.tsx + - examples/react/ui-integration-dnd-kit/src/twoLists/index.tsx + references: + - references/example-scenarios.md +tensions: + - name: schema_strictness_vs_editable_defaults + skills: + - choosing-form-options-modes + - schema-driven-forms + - type-error-debugging + implication: 'Generated skills must warn against fighting nullish editable defaults with assertions or reading raw value for pipeline output.' + - name: query_loading_ui_vs_form_initialization + skills: + - query-backed-forms + - examples-authoring + implication: 'Generated skills must tie the default-values plan to the visual loading workflow.' + - name: validation_state_vs_transient_state + skills: + - query-backed-forms + - schema-driven-forms + - error-visibility-workflows + implication: 'Generated skills must keep transient query/network failures out of form validation state.' + - name: reuse_vs_inference_boundaries + skills: + - react-form-composition-setup + - reusable-form-policies + - type-error-debugging + - examples-authoring + implication: 'Generated skills must prefer inference, helper types, and field groups over assertions, hand-written field shims, or ReactFormType unions.' +cross_references: + - from: react-form-composition-setup + to: examples-authoring + - from: react-form-composition-setup + to: reusable-form-policies + - from: reusable-form-policies + to: react-form-composition-setup + - from: reusable-form-policies + to: error-visibility-workflows + - from: reusable-form-policies + to: type-error-debugging + - from: examples-authoring + to: react-form-composition-setup + - from: choosing-form-options-modes + to: schema-driven-forms + - from: choosing-form-options-modes + to: type-error-debugging + - from: schema-driven-forms + to: query-backed-forms + - from: query-backed-forms + to: error-visibility-workflows + - from: type-error-debugging + to: react-form-composition-setup +gaps: + - id: missing-tanstack-query-example + skill: query-backed-forms + status: open + note: 'No checked-in examples/react/tanstack-query example existed during discovery; query-backed form guidance is reviewed from tests and maintainer interview.' diff --git a/docs/arrays.md b/docs/arrays.md new file mode 100644 index 0000000000..ef2d56ce88 --- /dev/null +++ b/docs/arrays.md @@ -0,0 +1,429 @@ +--- +id: arrays +title: Arrays +--- + +TanStack Form fields can hold arrays just like any other value. The important distinction is whether the array is the field value itself or whether you're rendering fields for the items inside it. + +If one control reads and replaces the whole array, use a regular field. If you're rendering fields for individual items and need to add, remove, or reorder them, use an array field. + +This guide covers both cases and how to choose between them. + +## An array as the field value + +Use a regular field when one control reads and replaces the complete array. A +multi-select, tag picker, or checkbox group can pass its next array to +`handleChange` like any other field value: + + + +# React + +```tsx + + {(field) => ( + field.handleChange(roleIds)} + /> + )} + +``` + +# Preact + +```tsx + + {(field) => ( + field.handleChange(roleIds)} + /> + )} + +``` + +# Solid + +```tsx + + {(field) => ( + field().handleChange(roleIds)} + /> + )} + +``` + +# Angular + +```html + + + +``` + +# Lit + +```ts +this.form.field( + { name: 'selectedRoleIds' }, + (field) => html` + >) => + field.handleChange(event.detail)} + > + `, +) +``` + +# Svelte + +```svelte + + {#snippet children(field)} + field.handleChange(roleIds)} + /> + {/snippet} + +``` + +# Vue + +```vue + + + +``` + + + +## Rendering fields in an array + +If you need to edit fields inside each array item, the previous approach has two problems. + +- Editing any item's value would cause the whole array to rerender. +- Moving items within the array would not update fields, since it was only changing the array's value. + + + +# React + +This is where `form.ArrayField` comes in. It ensures that each item in the array is rendered independently, while still subscribing to +item changes like swapping, removing or pushing new values. + +```tsx + + {(array) => ( +
    + {array.value.map((person, index) => ( +
  • + + {(field) => } + +
  • + ))} +
+ )} +
+``` + +# Preact + +This is where `form.ArrayField` comes in. It ensures that each item in the array is rendered independently, while still subscribing to +item changes like swapping, removing or pushing new values. + +```tsx + + {(array) => ( +
    + {array.value.map((person, index) => ( +
  • + + {(field) => } + +
  • + ))} +
+ )} +
+``` + +# Solid + +This is where `form.ArrayField` comes in. It ensures that each item in the array is rendered independently, while still subscribing to +item changes like swapping, removing or pushing new values. + +```tsx + + {(array) => ( +
    + + {(_person, index) => ( +
  • + + {(field) => } + +
  • + )} +
    +
+ )} +
+``` + +# Angular + +This is where `TanStackArrayField` comes in. It ensures that each item in the array is rendered independently, while still subscribing to +item changes like swapping, removing or pushing new values. + +```ts +import { Component } from '@angular/core' +import { + TanStackArrayField, + TanStackField, + injectForm, +} from '@tanstack/angular-form' + +@Component({ + selector: 'app-people-form', + standalone: true, + imports: [TanStackArrayField, TanStackField], + template: ` + +
    + @for (person of people.api.value; track person.id; let index = $index) { +
  • + + + +
  • + } +
+
+ `, +}) +export class PeopleFormComponent { + form = injectForm({ + defaultValues: { + people: [{ id: 'person-1', name: '' }], + }, + }) + + personName(index: number): `people[${number}].name` { + return `people[${index}].name` + } +} +``` + +# Lit + +This is where `form.arrayField` comes in. It ensures that each item in the array is rendered independently, while still subscribing to +item changes like swapping, removing or pushing new values. + +```ts +this.form.arrayField( + { name: 'people' }, + (array) => html` +
    + ${repeat( + array.value, + (person) => person.id, + (_person, index) => html` +
  • + ${this.form.field( + { name: `people[${index}].name` }, + (field) => html``, + )} +
  • + `, + )} +
+ `, +) +``` + +# Svelte + +This is where `form.ArrayField` comes in. It ensures that each item in the array is rendered independently, while still subscribing to +item changes like swapping, removing or pushing new values. + +```svelte + + {#snippet children(array)} +
    + {#each array.value as person, index (person.id)} +
  • + + {#snippet children(field)} + + {/snippet} + +
  • + {/each} +
+ {/snippet} +
+``` + +# Vue + +This is where `form.ArrayField` comes in. It ensures that each item in the array is rendered independently, while still subscribing to +item changes like swapping, removing or pushing new values. + +```vue + +
    +
  • + + + +
  • +
+
+``` + + + +### Keeping item identity for objects + +While the nested fields use the index in their `name`, use your adapter's identity mechanism to keep each object tied +to the same rendered item. + + + +# React + +```tsx +array.value.map((person) =>
  • Item fields
  • ) +``` + +# Preact + +```tsx +array.value.map((person) =>
  • Item fields
  • ) +``` + +# Solid + +```tsx +{() =>
  • Item fields
  • }
    +``` + +# Angular + +```html +@for (person of people.api.value; track person.id) { +
  • Item fields
  • +} +``` + +# Lit + +```ts +repeat( + array.value, + (person) => person.id, + () => html`
  • Item fields
  • `, +) +``` + +# Svelte + +```svelte +{#each array.value as person (person.id)} +
  • Item fields
  • +{/each} +``` + +# Vue + +```vue +
  • Item fields
  • +``` + + + +## Updating array values + +Use the array field's mutation methods for structural changes. You can perform the same mutations from the form API by +passing the field name first. + + + +```ts file="Field methods" +// Append an item. +field.pushValue(value) + +// Insert an item at an index. +field.insertValue(index, value) + +// Remove the item at an index. +field.removeValue(index) + +// Replace the item at an index. +field.replaceValue(index, value) + +// Exchange two items. +field.swapValues(indexA, indexB) + +// Move an item from one index to another. +field.moveValue(fromIndex, toIndex) + +// Keep the items accepted by a predicate. +field.filterValues((value, i) => isEnabled(value)) + +// Remove every item. +field.clearValues() +``` + +```ts file="Form methods" +// Append an item. +form.pushFieldValue('items', value) + +// Insert an item at an index. +form.insertFieldValue('items', index, value) + +// Remove the item at an index. +form.removeFieldValue('items', index) + +// Replace the item at an index. +form.replaceFieldValue('items', index, value) + +// Exchange two items. +form.swapFieldValues('items', indexA, indexB) + +// Move an item from one index to another. +form.moveFieldValue('items', fromIndex, toIndex) + +// Keep the items accepted by a predicate. +form.filterFieldValues('items', (value, i) => isEnabled(value)) + +// Remove every item. +form.clearFieldValues('items') +``` + + + +You could make these changes yourself with `handleChange`, but these helpers also take care of the registered fields +for each item. When an item moves, its field state moves with it. When an item is removed, its field state is removed too. + +A successful array mutation marks the array field as touched and dirty and causes validation by default. diff --git a/docs/assets/field-states-extended.png b/docs/assets/field-states-extended.png deleted file mode 100644 index 1ecc677af0..0000000000 Binary files a/docs/assets/field-states-extended.png and /dev/null differ diff --git a/docs/assets/field-states.png b/docs/assets/field-states.png deleted file mode 100644 index 869f41f5c6..0000000000 Binary files a/docs/assets/field-states.png and /dev/null differ diff --git a/docs/assets/react_form_composability.svg b/docs/assets/react_form_composability.svg deleted file mode 100644 index 9761825c5c..0000000000 --- a/docs/assets/react_form_composability.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -

    Yes

    No

    Yes

    No

    Yes

    No

    Yes

    No

    Yes

    No

    Do you need to reuse state (like defaultValues)?

    Use 'formOptions()

    Do you need to custom validation functions?

    Wrap 'useForm' hook into custom app hook

    Do you need to reuse custom UI components?

    Do you need access to the 'field'?

    Do you need to reuse whole subsections of your form?

    Use 'createFormHooks''s 'fieldComponents' (EG: 'TextInput' and 'NumberInput')

    Use 'createFormsHook''s 'formComponents' (EG: 'SubmitButton')

    Use 'withForm' from 'createFormHook'

    Use 'form.Subscribe' and 'form.Field'

    diff --git a/docs/assets/stepper.png b/docs/assets/stepper.png deleted file mode 100644 index 8e006d9e79..0000000000 Binary files a/docs/assets/stepper.png and /dev/null differ diff --git a/docs/config.json b/docs/config.json index 181f6139e7..7fd0732a8c 100644 --- a/docs/config.json +++ b/docs/config.json @@ -1,10 +1,5 @@ { "$schema": "https://raw.githubusercontent.com/TanStack/tanstack.com/main/tanstack-docs-config.schema.json", - "docSearch": { - "appId": "", - "apiKey": "", - "indexName": "tanstack-form" - }, "sections": [ { "label": "Community Resources", @@ -22,6 +17,10 @@ "label": "Installation", "to": "installation" }, + { + "label": "Migrating from v1", + "to": "migrate-from-v1" + }, { "label": "Philosophy", "to": "philosophy" @@ -103,75 +102,40 @@ }, { "label": "Guides", - "children": [], + "children": [ + { + "label": "Splitting Forms", + "to": "splitting-forms" + }, + { + "label": "Arrays", + "to": "arrays" + } + ], "frameworks": [ { "label": "react", "children": [ - { - "label": "Basic Concepts", - "to": "framework/react/guides/basic-concepts" - }, { "label": "Form Validation", "to": "framework/react/guides/validation" }, { - "label": "Dynamic Validation", - "to": "framework/react/guides/dynamic-validation" + "label": "Field Groups", + "to": "framework/react/guides/field-groups" }, { "label": "Async Initial Values", "to": "framework/react/guides/async-initial-values" }, - { - "label": "Arrays", - "to": "framework/react/guides/arrays" - }, - { - "label": "Form Groups", - "to": "framework/react/guides/form-groups" - }, - { - "label": "Linked Fields", - "to": "framework/react/guides/linked-fields" - }, - { - "label": "Reactivity", - "to": "framework/react/guides/reactivity" - }, - { - "label": "Listeners", - "to": "framework/react/guides/listeners" - }, - { - "label": "Custom Errors", - "to": "framework/react/guides/custom-errors" - }, - { - "label": "Submission Handling", - "to": "framework/react/guides/submission-handling" - }, { "label": "UI Libraries", "to": "framework/react/guides/ui-libraries" }, - { - "label": "Focus Management", - "to": "framework/react/guides/focus-management" - }, - { - "label": "Form Composition", - "to": "framework/react/guides/form-composition" - }, { "label": "React Native", "to": "framework/react/guides/react-native" }, - { - "label": "SSR/TanStack Start/Next.js", - "to": "framework/react/guides/ssr" - }, { "label": "Debugging", "to": "framework/react/guides/debugging" @@ -185,164 +149,191 @@ { "label": "preact", "children": [ - { - "label": "Basic Concepts", - "to": "framework/preact/guides/basic-concepts" - }, { "label": "Form Validation", "to": "framework/preact/guides/validation" }, - { - "label": "Dynamic Validation", - "to": "framework/preact/guides/dynamic-validation" - }, { "label": "Async Initial Values", "to": "framework/preact/guides/async-initial-values" }, { - "label": "Arrays", - "to": "framework/preact/guides/arrays" - }, - { - "label": "Form Groups", - "to": "framework/preact/guides/form-groups" + "label": "UI Libraries", + "to": "framework/preact/guides/ui-libraries" }, { - "label": "Linked Fields", - "to": "framework/preact/guides/linked-fields" - }, + "label": "Debugging", + "to": "framework/preact/guides/debugging" + } + ] + }, + { + "label": "vue", + "children": [ { - "label": "Reactivity", - "to": "framework/preact/guides/reactivity" + "label": "Form Validation", + "to": "framework/vue/guides/validation" }, { - "label": "Listeners", - "to": "framework/preact/guides/listeners" + "label": "Async Initial Values", + "to": "framework/vue/guides/async-initial-values" }, { - "label": "Custom Errors", - "to": "framework/preact/guides/custom-errors" + "label": "UI Libraries", + "to": "framework/vue/guides/ui-libraries" }, { - "label": "Submission Handling", - "to": "framework/preact/guides/submission-handling" - }, + "label": "Debugging", + "to": "framework/vue/guides/debugging" + } + ] + }, + { + "label": "solid", + "children": [ { - "label": "UI Libraries", - "to": "framework/preact/guides/ui-libraries" + "label": "Form Validation", + "to": "framework/solid/guides/validation" }, { - "label": "Focus Management", - "to": "framework/preact/guides/focus-management" + "label": "Async Initial Values", + "to": "framework/solid/guides/async-initial-values" }, { - "label": "Form Composition", - "to": "framework/preact/guides/form-composition" + "label": "UI Libraries", + "to": "framework/solid/guides/ui-libraries" }, { "label": "Debugging", - "to": "framework/preact/guides/debugging" + "to": "framework/solid/guides/debugging" } ] }, { - "label": "vue", + "label": "lit", "children": [ - { - "label": "Basic Concepts", - "to": "framework/vue/guides/basic-concepts" - }, { "label": "Form Validation", - "to": "framework/vue/guides/validation" - }, - { - "label": "Dynamic Validation", - "to": "framework/vue/guides/dynamic-validation" + "to": "framework/lit/guides/validation" }, { "label": "Async Initial Values", - "to": "framework/vue/guides/async-initial-values" - }, - { - "label": "Arrays", - "to": "framework/vue/guides/arrays" + "to": "framework/lit/guides/async-initial-values" }, { - "label": "Form Groups", - "to": "framework/vue/guides/form-groups" + "label": "UI Libraries", + "to": "framework/lit/guides/ui-libraries" }, { - "label": "Linked Fields", - "to": "framework/vue/guides/linked-fields" + "label": "Debugging", + "to": "framework/lit/guides/debugging" } ] }, { - "label": "angular", + "label": "svelte", "children": [ - { - "label": "Basic Concepts", - "to": "framework/angular/guides/basic-concepts" - }, { "label": "Form Validation", - "to": "framework/angular/guides/validation" + "to": "framework/svelte/guides/validation" }, { - "label": "Dynamic Validation", - "to": "framework/angular/guides/dynamic-validation" + "label": "Async Initial Values", + "to": "framework/svelte/guides/async-initial-values" }, { - "label": "Arrays", - "to": "framework/angular/guides/arrays" + "label": "UI Libraries", + "to": "framework/svelte/guides/ui-libraries" }, { - "label": "Form Groups", - "to": "framework/angular/guides/form-groups" + "label": "Debugging", + "to": "framework/svelte/guides/debugging" + } + ] + } + ] + }, + { + "label": "Recommended Types", + "collapsible": true, + "defaultCollapsed": false, + "children": [ + { + "label": "AnyFieldApi", + "to": "reference/type-aliases/AnyFieldApi" + }, + { + "label": "FieldWithValue", + "to": "reference/type-aliases/FieldWithValue" + }, + { + "label": "AnyFormApi", + "to": "reference/type-aliases/AnyFormApi" + } + ], + "frameworks": [ + { + "label": "react", + "children": [ + { + "label": "AnyReactFormApi", + "to": "framework/react/reference/type-aliases/AnyReactFormApi" }, { - "label": "Form Composition", - "to": "framework/angular/guides/form-composition" + "label": "ReactFormType", + "to": "framework/react/reference/type-aliases/ReactFormType" } ] }, { - "label": "solid", + "label": "preact", "children": [ { - "label": "Basic Concepts", - "to": "framework/solid/guides/basic-concepts" + "label": "AnyPreactFormApi", + "to": "framework/preact/reference/type-aliases/AnyPreactFormApi" }, { - "label": "Form Validation", - "to": "framework/solid/guides/validation" - }, + "label": "PreactFormType", + "to": "framework/preact/reference/type-aliases/PreactFormType" + } + ] + }, + { + "label": "vue", + "children": [ { - "label": "Dynamic Validation", - "to": "framework/solid/guides/dynamic-validation" + "label": "AnyVueFormApi", + "to": "framework/vue/reference/type-aliases/AnyVueFormApi" }, { - "label": "Async Initial Values", - "to": "framework/solid/guides/async-initial-values" - }, + "label": "VueFormType", + "to": "framework/vue/reference/type-aliases/VueFormType" + } + ] + }, + { + "label": "angular", + "children": [ { - "label": "Arrays", - "to": "framework/solid/guides/arrays" + "label": "AnyAngularFormApi", + "to": "framework/angular/reference/type-aliases/AnyAngularFormApi" }, { - "label": "Form Groups", - "to": "framework/solid/guides/form-groups" - }, + "label": "AngularFormType", + "to": "framework/angular/reference/type-aliases/AngularFormType" + } + ] + }, + { + "label": "solid", + "children": [ { - "label": "Linked Fields", - "to": "framework/solid/guides/linked-fields" + "label": "AnySolidFormApi", + "to": "framework/solid/reference/type-aliases/AnySolidFormApi" }, { - "label": "Form Composition", - "to": "framework/solid/guides/form-composition" + "label": "SolidFormType", + "to": "framework/solid/reference/type-aliases/SolidFormType" } ] }, @@ -350,28 +341,100 @@ "label": "lit", "children": [ { - "label": "Basic Concepts", - "to": "framework/lit/guides/basic-concepts" + "label": "AnyLitFormApi", + "to": "framework/lit/reference/type-aliases/AnyLitFormApi" }, { - "label": "Form Validation", - "to": "framework/lit/guides/validation" - }, + "label": "LitFormType", + "to": "framework/lit/reference/type-aliases/LitFormType" + } + ] + }, + { + "label": "svelte", + "children": [ { - "label": "Dynamic Validation", - "to": "framework/lit/guides/dynamic-validation" - }, + "label": "AnySvelteFormApi", + "to": "framework/svelte/reference/type-aliases/AnySvelteFormApi" + } + ] + } + ] + }, + { + "label": "Form creation", + "collapsible": true, + "defaultCollapsed": true, + "children": [ + { + "label": "formOptions()", + "to": "reference/variables/formOptions" + }, + { + "label": "formOptions.strictSchema()", + "to": "reference/type-aliases/FormOptionsStrictSchemaFn" + }, + { + "label": "formOptions.looseSchema()", + "to": "reference/type-aliases/FormOptionsLooseSchemaFn" + }, + { + "label": "FormOptions", + "to": "reference/interfaces/FormOptions" + } + ], + "frameworks": [ + { + "label": "react", + "children": [ { - "label": "Arrays", - "to": "framework/lit/guides/arrays" - }, + "label": "useForm()", + "to": "framework/react/reference/variables/useForm" + } + ] + }, + { + "label": "preact", + "children": [ { - "label": "Form Groups", - "to": "framework/lit/guides/form-groups" - }, + "label": "useForm()", + "to": "framework/preact/reference/variables/useForm" + } + ] + }, + { + "label": "vue", + "children": [ { - "label": "Form Composition", - "to": "framework/lit/guides/form-composition" + "label": "useForm()", + "to": "framework/vue/reference/variables/useForm" + } + ] + }, + { + "label": "angular", + "children": [ + { + "label": "injectForm()", + "to": "framework/angular/reference/functions/injectForm" + } + ] + }, + { + "label": "solid", + "children": [ + { + "label": "createForm()", + "to": "framework/solid/reference/variables/createForm" + } + ] + }, + { + "label": "lit", + "children": [ + { + "label": "TanStackFormController", + "to": "framework/lit/reference/classes/TanStackFormController" } ] }, @@ -379,442 +442,479 @@ "label": "svelte", "children": [ { - "label": "Basic Concepts", - "to": "framework/svelte/guides/basic-concepts" + "label": "createForm()", + "to": "framework/svelte/reference/variables/createForm" + } + ] + } + ] + }, + + { + "label": "Form Composition API Reference", + "collapsible": true, + "defaultCollapsed": true, + "children": [], + "frameworks": [ + { + "label": "react", + "children": [ + { + "label": "createFormHook()", + "to": "framework/react/reference/functions/createFormHook" }, { - "label": "Form Validation", - "to": "framework/svelte/guides/validation" + "label": "CreateFormHookOptions", + "to": "framework/react/reference/interfaces/CreateFormHookOptions" }, { - "label": "Dynamic Validation", - "to": "framework/svelte/guides/dynamic-validation" + "label": "AppFormHookResult", + "to": "framework/react/reference/interfaces/AppFormHookResult" }, { - "label": "Async Initial Values", - "to": "framework/svelte/guides/async-initial-values" + "label": "FormHookHelpers", + "to": "framework/react/reference/interfaces/FormHookHelpers" }, { - "label": "Arrays", - "to": "framework/svelte/guides/arrays" + "label": "FieldBrandHelper", + "to": "framework/react/reference/interfaces/FieldBrandHelper" }, { - "label": "Form Groups", - "to": "framework/svelte/guides/form-groups" + "label": "FieldComponentHelper", + "to": "framework/react/reference/interfaces/FieldComponentHelper" }, { - "label": "Linked Fields", - "to": "framework/svelte/guides/linked-fields" + "label": "defineFieldGroup()", + "to": "framework/react/reference/variables/defineFieldGroup" }, { - "label": "Form Composition", - "to": "framework/svelte/guides/form-composition" + "label": "FieldGroupApi", + "to": "framework/react/reference/interfaces/FieldGroupApi" + }, + { + "label": "FieldGroupDefinition", + "to": "framework/react/reference/interfaces/FieldGroupDefinition" + }, + { + "label": "FieldGroupHelper", + "to": "reference/interfaces/FieldGroupHelper" } ] } ] }, { + "label": "FormApi Reference", "collapsible": true, "defaultCollapsed": true, - "label": "API Reference", "children": [ { - "label": "JavaScript Reference", - "to": "reference/index" + "label": "form.setFieldValue()", + "to": "reference/type-aliases/SetFieldValueFn" }, { - "label": "Classes / FieldApi", - "to": "reference/classes/FieldApi" + "label": "form.getFieldValue()", + "to": "reference/type-aliases/GetFieldValueFn" }, { - "label": "Classes / FormApi", - "to": "reference/classes/FormApi" + "label": "form.resetField()", + "to": "reference/type-aliases/ResetFieldFn" }, { - "label": "Functions / formOptions", - "to": "reference/functions/formOptions" + "label": "form.swapFieldValues()", + "to": "reference/type-aliases/SwapFieldValuesFn" }, { - "label": "Functions / mergeForm", - "to": "reference/functions/mergeForm" + "label": "form.moveFieldValue()", + "to": "reference/type-aliases/MoveFieldValueFn" }, { - "label": "Interfaces / FieldApiOptions", - "to": "reference/interfaces/FieldApiOptions" + "label": "form.pushFieldValue()", + "to": "reference/type-aliases/PushFieldValueFn" }, { - "label": "Interfaces / FieldOptions", - "to": "reference/interfaces/FieldOptions" + "label": "form.insertFieldValue()", + "to": "reference/type-aliases/InsertFieldValueFn" }, { - "label": "Interfaces / FieldValidators", - "to": "reference/interfaces/FieldValidators" + "label": "form.clearFieldValues()", + "to": "reference/type-aliases/ClearFieldValuesFn" }, { - "label": "Interfaces / FormOptions", - "to": "reference/interfaces/FormOptions" + "label": "form.removeFieldValue()", + "to": "reference/type-aliases/RemoveFieldValueFn" }, { - "label": "Interfaces / FormValidators", - "to": "reference/interfaces/FormValidators" + "label": "form.filterFieldValues()", + "to": "reference/type-aliases/FilterFieldValuesFn" }, { - "label": "Types / DeepKeys", - "to": "reference/type-aliases/DeepKeys" + "label": "form.handleSubmit()", + "to": "reference/type-aliases/HandleSubmitFn" }, { - "label": "Types / DeepValue", - "to": "reference/type-aliases/DeepValue" + "label": "form.reset()", + "to": "reference/type-aliases/ResetFn" }, { - "label": "Types / FieldInfo", - "to": "reference/type-aliases/FieldInfo" + "label": "FormApi", + "to": "reference/interfaces/FormApi" }, { - "label": "Types / FieldMeta", - "to": "reference/type-aliases/FieldMeta" + "label": "FormOptions", + "to": "reference/interfaces/FormOptions" }, { - "label": "Types / FieldState", - "to": "reference/type-aliases/FieldState" + "label": "FormState", + "to": "reference/interfaces/FormState" }, { - "label": "Types / BaseFormState", - "to": "reference/type-aliases/BaseFormState" + "label": "FormResetOptions", + "to": "reference/interfaces/FormResetOptions" }, { - "label": "Types / DerivedFormState", - "to": "reference/type-aliases/DerivedFormState" + "label": "FormSubmitContext", + "to": "reference/interfaces/FormSubmitContext" }, { - "label": "Types / Updater", - "to": "reference/type-aliases/Updater" + "label": "FormSubmitInvalidContext", + "to": "reference/interfaces/FormSubmitInvalidContext" + } + ] + }, + { + "label": "Form Listener API Reference", + "collapsible": true, + "defaultCollapsed": true, + "children": [ + { + "label": "FormListener", + "to": "reference/interfaces/FormListener" }, { - "label": "Types / UpdaterFn", - "to": "reference/type-aliases/UpdaterFn" + "label": "FormListenerTriggers", + "to": "reference/type-aliases/FormListenerTriggers" }, { - "label": "Types / ValidationError", - "to": "reference/type-aliases/ValidationError" + "label": "FormListenerFn", + "to": "reference/type-aliases/FormListenerFn" }, { - "label": "Types / ValidationMeta", - "to": "reference/type-aliases/ValidationMeta" + "label": "FormListenerContext", + "to": "reference/interfaces/FormListenerContext" } - ], + ] + }, + { + "label": "Field Listener API Reference", + "collapsible": true, + "defaultCollapsed": true, + "children": [ + { + "label": "FieldListener", + "to": "reference/interfaces/FieldListener" + }, + { + "label": "FieldListenerTriggers", + "to": "reference/type-aliases/FieldListenerTriggers" + }, + { + "label": "FieldListenerFn", + "to": "reference/type-aliases/FieldListenerFn" + }, + { + "label": "FieldListenerContext", + "to": "reference/interfaces/FieldListenerContext" + } + ] + }, + { + "label": "Examples", + "children": [], "frameworks": [ { "label": "react", "children": [ { - "label": "React Reference", - "to": "framework/react/reference/index" - }, - { - "label": "Variables / Field", - "to": "framework/react/reference/variables/Field" - }, - { - "label": "Functions / useField", - "to": "framework/react/reference/functions/useField" + "label": "Simple", + "to": "framework/react/examples/simple" }, { - "label": "Functions / useForm", - "to": "framework/react/reference/functions/useForm" + "label": "Basic", + "to": "framework/react/examples/basic" }, { - "label": "Functions / useTransform", - "to": "framework/react/reference/functions/useTransform" + "label": "Form Splitting", + "to": "framework/react/examples/basic-splitting-form" }, { - "label": "Types / FieldComponent", - "to": "framework/react/reference/type-aliases/FieldComponent" + "label": "Arrays", + "to": "framework/react/examples/array" }, { - "label": "Types / UseField", - "to": "framework/react/reference/type-aliases/UseField" - } - ] - }, - { - "label": "preact", - "children": [ - { - "label": "Preact Reference", - "to": "framework/preact/reference/index" + "label": "Field Groups", + "to": "framework/react/examples/field-groups" }, { - "label": "Variables / Field", - "to": "framework/preact/reference/variables/Field" + "label": "Form Composition", + "to": "framework/react/examples/large-form" }, { - "label": "Functions / useField", - "to": "framework/preact/reference/functions/useField" + "label": "Multi-Step Wizard", + "to": "framework/react/examples/multi-step-wizard" }, { - "label": "Functions / useForm", - "to": "framework/preact/reference/functions/useForm" + "label": "Standard Schema", + "to": "framework/react/examples/standard-schema" }, { - "label": "Types / FieldComponent", - "to": "framework/preact/reference/type-aliases/FieldComponent" + "label": "React Compiler", + "to": "framework/react/examples/compiler" }, { - "label": "Types / UseField", - "to": "framework/preact/reference/type-aliases/UseField" + "label": "Expo", + "to": "framework/react/examples/expo" } ] }, { - "label": "vue", + "label": "preact", "children": [ { - "label": "Vue Reference", - "to": "framework/vue/reference/index" - }, - { - "label": "Variables / Field", - "to": "framework/vue/reference/variables/Field" - }, - { - "label": "Functions / useField", - "to": "framework/vue/reference/functions/useField" - }, - { - "label": "Functions / useForm", - "to": "framework/vue/reference/functions/useForm" + "label": "Simple", + "to": "framework/preact/examples/simple" }, { - "label": "Types / FieldComponent", - "to": "framework/vue/reference/type-aliases/FieldComponent" + "label": "Basic", + "to": "framework/preact/examples/basic" }, { - "label": "Types / UseField", - "to": "framework/vue/reference/type-aliases/UseField" - } - ] - }, - { - "label": "solid", - "children": [ - { - "label": "Solid Reference", - "to": "framework/solid/reference/index" + "label": "Form Splitting", + "to": "framework/preact/examples/basic-splitting-form" }, { - "label": "Functions / createField", - "to": "framework/solid/reference/functions/createField" + "label": "Arrays", + "to": "framework/preact/examples/array" }, { - "label": "Functions / createForm", - "to": "framework/solid/reference/functions/createForm" + "label": "Field Groups", + "to": "framework/preact/examples/field-groups" }, { - "label": "Functions / Field", - "to": "framework/solid/reference/functions/Field" + "label": "Form Composition", + "to": "framework/preact/examples/large-form" }, { - "label": "Types / CreateField", - "to": "framework/solid/reference/type-aliases/CreateField" + "label": "Multi-Step Wizard", + "to": "framework/preact/examples/multi-step-wizard" }, { - "label": "Types / FieldComponent", - "to": "framework/solid/reference/type-aliases/FieldComponent" + "label": "Standard Schema", + "to": "framework/preact/examples/standard-schema" } ] }, { - "label": "lit", + "label": "vue", "children": [ { - "label": "Lit Reference", - "to": "framework/lit/reference/index" + "label": "Simple", + "to": "framework/vue/examples/simple" }, { - "label": "Classes / TanStackFormController", - "to": "framework/lit/reference/classes/TanStackFormController" - } - ] - }, - { - "label": "angular", - "children": [ - { - "label": "Angular Reference", - "to": "framework/angular/reference/index" + "label": "Arrays", + "to": "framework/vue/examples/array" }, { - "label": "Classes / TanStackField", - "to": "framework/angular/reference/classes/TanStackField" + "label": "Form Composition", + "to": "framework/vue/examples/large-form" }, { - "label": "Functions / injectForm", - "to": "framework/angular/reference/functions/injectForm" + "label": "Multi-Step Wizard", + "to": "framework/vue/examples/multi-step-wizard" }, { - "label": "Functions / injectStore", - "to": "framework/angular/reference/functions/injectStore" + "label": "Standard Schema", + "to": "framework/vue/examples/standard-schema" } ] - } - ] - }, - { - "label": "Examples", - "children": [], - "frameworks": [ + }, { - "label": "react", + "label": "angular", "children": [ { "label": "Simple", - "to": "framework/react/examples/simple" + "to": "framework/angular/examples/simple" }, { - "label": "Multi-Step Wizard", - "to": "framework/react/examples/multi-step-wizard" + "label": "Basic", + "to": "framework/angular/examples/basic" + }, + { + "label": "Form Splitting", + "to": "framework/angular/examples/basic-splitting-form" }, { "label": "Arrays", - "to": "framework/react/examples/array" + "to": "framework/angular/examples/array" }, { - "label": "Form Composition", - "to": "framework/react/examples/large-form" + "label": "Field Groups", + "to": "framework/angular/examples/field-groups" }, { - "label": "Dynamic Validation", - "to": "framework/react/examples/dynamic" + "label": "Form Composition", + "to": "framework/angular/examples/large-form" }, { - "label": "TanStack Query Integration", - "to": "framework/react/examples/query-integration" + "label": "Multi-Step Wizard", + "to": "framework/angular/examples/multi-step-wizard" }, { "label": "Standard Schema", - "to": "framework/react/examples/standard-schema" - }, + "to": "framework/angular/examples/standard-schema" + } + ] + }, + { + "label": "solid", + "children": [ { - "label": "TanStack Start", - "to": "framework/react/examples/tanstack-start" + "label": "Simple", + "to": "framework/solid/examples/simple" }, { - "label": "Next Server Actions", - "to": "framework/react/examples/next-server-actions" + "label": "Basic", + "to": "framework/solid/examples/basic" }, { - "label": "Remix", - "to": "framework/react/examples/remix" + "label": "Form Splitting", + "to": "framework/solid/examples/basic-splitting-form" }, { - "label": "UI Libraries", - "to": "framework/react/examples/ui-libraries" + "label": "Arrays", + "to": "framework/solid/examples/array" }, { - "label": "Field Errors From Form Validators", - "to": "framework/react/examples/field-errors-from-form-validators" + "label": "Field Groups", + "to": "framework/solid/examples/field-groups" }, { - "label": "Devtools", - "to": "framework/react/examples/devtools" - } - ] - }, - { - "label": "vue", - "children": [ - { - "label": "Simple", - "to": "framework/vue/examples/simple" + "label": "Form Composition", + "to": "framework/solid/examples/large-form" }, { "label": "Multi-Step Wizard", - "to": "framework/vue/examples/multi-step-wizard" - }, - { - "label": "Arrays", - "to": "framework/vue/examples/array" + "to": "framework/solid/examples/multi-step-wizard" }, { "label": "Standard Schema", - "to": "framework/vue/examples/standard-schema" + "to": "framework/solid/examples/standard-schema" } ] }, { - "label": "angular", + "label": "lit", "children": [ { "label": "Simple", - "to": "framework/angular/examples/simple" + "to": "framework/lit/examples/simple" }, { - "label": "Multi-Step Wizard", - "to": "framework/angular/examples/multi-step-wizard" + "label": "Basic", + "to": "framework/lit/examples/basic" + }, + { + "label": "Form Splitting", + "to": "framework/lit/examples/basic-splitting-form" }, { "label": "Arrays", - "to": "framework/angular/examples/array" + "to": "framework/lit/examples/array" + }, + { + "label": "Field Groups", + "to": "framework/lit/examples/field-groups" }, { "label": "Form Composition", - "to": "framework/angular/examples/large-form" + "to": "framework/lit/examples/large-form" + }, + { + "label": "Multi-Step Wizard", + "to": "framework/lit/examples/multi-step-wizard" }, { "label": "Standard Schema", - "to": "framework/angular/examples/standard-schema" + "to": "framework/lit/examples/standard-schema" } ] }, { - "label": "solid", + "label": "svelte", "children": [ { "label": "Simple", - "to": "framework/solid/examples/simple" + "to": "framework/svelte/examples/simple" }, { - "label": "Multi-Step Wizard", - "to": "framework/solid/examples/multi-step-wizard" + "label": "Basic", + "to": "framework/svelte/examples/basic" + }, + { + "label": "Form Splitting", + "to": "framework/svelte/examples/basic-splitting-form" }, { "label": "Arrays", - "to": "framework/solid/examples/array" + "to": "framework/svelte/examples/array" + }, + { + "label": "Field Groups", + "to": "framework/svelte/examples/field-groups" }, { "label": "Form Composition", - "to": "framework/solid/examples/large-form" + "to": "framework/svelte/examples/large-form" + }, + { + "label": "Multi-Step Wizard", + "to": "framework/svelte/examples/multi-step-wizard" }, { "label": "Standard Schema", - "to": "framework/solid/examples/standard-schema" + "to": "framework/svelte/examples/standard-schema" } ] - }, + } + ] + }, + { + "label": "Framework & Library Integrations", + "children": [], + "frameworks": [ { - "label": "lit", + "label": "react", "children": [ { - "label": "Simple", - "to": "framework/lit/examples/simple" + "label": "TanStack Query", + "to": "framework/react/examples/query-integration" }, { - "label": "Multi-Step Wizard", - "to": "framework/lit/examples/multi-step-wizard" + "label": "Next.js", + "to": "framework/react/examples/nextjs" }, { - "label": "Array", - "to": "framework/lit/examples/array" + "label": "Next Server Actions", + "to": "framework/react/examples/next-server-actions" }, { - "label": "UI Libraries", - "to": "framework/lit/examples/ui-libraries" + "label": "Next Server Actions with Zod", + "to": "framework/react/examples/next-server-actions-zod" }, { - "label": "Standard Schema", - "to": "framework/lit/examples/standard-schema" + "label": "TanStack Start", + "to": "framework/react/examples/tanstack-start" } ] }, @@ -822,37 +922,63 @@ "label": "preact", "children": [ { - "label": "Simple", - "to": "framework/preact/examples/simple" - }, + "label": "TanStack Query", + "to": "framework/preact/examples/query-integration" + } + ] + }, + { + "label": "angular", + "children": [ { - "label": "Multi-Step Wizard", - "to": "framework/preact/examples/multi-step-wizard" + "label": "TanStack Query", + "to": "framework/angular/examples/query-integration" } ] }, { - "label": "svelte", + "label": "solid", "children": [ { - "label": "Simple", - "to": "framework/svelte/examples/simple" - }, + "label": "TanStack Query", + "to": "framework/solid/examples/query-integration" + } + ] + }, + { + "label": "lit", + "children": [ { - "label": "Multi-Step Wizard", - "to": "framework/svelte/examples/multi-step-wizard" - }, + "label": "TanStack Query", + "to": "framework/lit/examples/query-integration" + } + ] + }, + { + "label": "svelte", + "children": [ { - "label": "Arrays", - "to": "framework/svelte/examples/array" - }, + "label": "TanStack Query", + "to": "framework/svelte/examples/query-integration" + } + ] + } + ] + }, + { + "label": "UI Integrations", + "children": [], + "frameworks": [ + { + "label": "react", + "children": [ { - "label": "Standard Schema", - "to": "framework/svelte/examples/standard-schema" + "label": "DnD Kit", + "to": "framework/react/examples/ui-integration-dnd-kit" }, { - "label": "Form Composition", - "to": "framework/svelte/examples/large-form" + "label": "shadcn/ui", + "to": "framework/react/examples/ui-integration-shadcn" } ] } diff --git a/docs/framework/angular/guides/arrays.md b/docs/framework/angular/guides/arrays.md deleted file mode 100644 index ac2d998c88..0000000000 --- a/docs/framework/angular/guides/arrays.md +++ /dev/null @@ -1,170 +0,0 @@ ---- -id: arrays -title: Arrays ---- - -TanStack Form supports arrays as values in a form, including sub-object values inside of an array. - -## Basic Usage - -To use an array, you can use `field.api.state.value` on an array value: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - -
    - @for (_ of people.api.state.value; track $index) { - - } -
    -
    - `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - people: [] as Array<{ name: string; age: number }>, - }, - onSubmit({ value }) { - alert(JSON.stringify(value)) - }, - }) -} -``` - -This will generate the mapped JSX every time you run `pushValue` on `field`: - -```angular-html - -``` - -Finally, you can use a subfield like so: - -```angular-html - -
    - -
    -
    -``` - -Where `getPeopleName` is a method on the class like so: - -```typescript -export class AppComponent { - getPeopleName = (idx: number) => `people[${idx}].name` as const - - // ... -} -``` - -> While it's unfortunate that you need to use a function to get the field name, it's a requirement for how our strict TypeScript types work. -> -> See, if we did the following: -> -> ```angular-html -> [tanstackField]="form" -> [name]="'people[' + $index + '].name'" -> > -> ``` -> -> We'd be running into a TypeScript issue where `"one" + "two"` is `string` rather than the required `"onetwo"` type -> -> Moreover, while Angular supports template literals in the template, they may not contain dynamic interpolation within them, such as our `$index` argument. - -> It's possible that we've missed something! If you can think of a better fix for this problem, [drop us a line on our GitHub discussions](https://github.com/TanStack/form/discussions). - -## Full Example - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` -
    -
    - -
    - @for (_ of people.api.state.value; track $index) { - -
    - -
    -
    - } -
    - -
    -
    - -
    - `, -}) -export class AppComponent { - defaultPerson = { name: '', age: 0 } - - form = injectForm({ - defaultValues: { - people: [] as Array<{ name: string; age: number }>, - }, - onSubmit({ value }) { - alert(JSON.stringify(value)) - }, - }) - - getPeopleName = (idx: number) => `people[${idx}].name` as const - - canSubmit = injectStore(this.form, (state) => state.canSubmit) - isSubmitting = injectStore(this.form, (state) => state.isSubmitting) - - handleSubmit(event: SubmitEvent) { - event.preventDefault() - event.stopPropagation() - this.form.handleSubmit() - } -} -``` diff --git a/docs/framework/angular/guides/async-initial-values.md b/docs/framework/angular/guides/async-initial-values.md new file mode 100644 index 0000000000..40a40d6e4b --- /dev/null +++ b/docs/framework/angular/guides/async-initial-values.md @@ -0,0 +1,159 @@ +--- +id: async-initial-values +title: Async Initial Values +--- + +Forms often edit data loaded from an API. A server-state library such as +TanStack Query should own fetching, caching, loading, and retries; TanStack +Form should own the editable copy. + +There are two useful patterns for async initial values in Angular: resolve the +data before constructing the form, or construct the form immediately with +complete fallback values and reset it when data arrives. + +## Resolve data before constructing the editor + +Angular Router resolvers can make the record available synchronously when the +editor component is constructed. This lets `defaultValues` start with the +complete loaded value. + +```ts +import { Component, inject } from '@angular/core' +import { ActivatedRoute } from '@angular/router' +import type { ResolveFn, Routes } from '@angular/router' +import { injectForm } from '@tanstack/angular-form' + +type User = { + firstName: string + lastName: string +} + +export const userResolver: ResolveFn = async (route) => { + const response = await fetch(`/api/users/${route.paramMap.get('userId')}`) + return response.json() +} + +@Component({ + selector: 'app-user-editor', + standalone: true, + template: `
    `, +}) +export class UserEditorComponent { + private route = inject(ActivatedRoute) + private user = this.route.snapshot.data['user'] as User + + form = injectForm({ + defaultValues: this.user, + onSubmit: async ({ value }) => { + await fetch('/api/users', { + method: 'PUT', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(value), + }) + }, + }) +} + +export const routes: Routes = [ + { + path: 'users/:userId', + component: UserEditorComponent, + resolve: { user: userResolver }, + }, +] +``` + +This pattern is useful when no form state is needed during loading. It gives +the form complete data on its initial construction. If the router reuses the +same component instance for another record, reset that form from the new +resolved data or arrange for a fresh editor instance. + +## Create the form before data arrives + +You can instead use `injectForm` in the same component as `injectQuery`. +Provide a static, shape-complete fallback so `defaultValues` are never +`undefined`, then deliberately reset the untouched form when query data +arrives. + +```ts +import { Component, effect, inject } from '@angular/core' +import { ActivatedRoute } from '@angular/router' +import { injectQuery } from '@tanstack/angular-query-experimental' +import { injectForm } from '@tanstack/angular-form' + +type User = { + firstName: string + lastName: string +} + +const emptyUser: User = { + firstName: '', + lastName: '', +} + +@Component({ + selector: 'app-user-page', + standalone: true, + template: ` + @if (userQuery.isPending()) { +

    Loading…

    + } @else if (userQuery.isError()) { +

    Could not load the user.

    + } @else { +
    + } + `, +}) +export class UserPageComponent { + private route = inject(ActivatedRoute) + private userId = this.route.snapshot.paramMap.get('userId')! + + userQuery = injectQuery(() => ({ + queryKey: ['user', this.userId], + queryFn: async (): Promise => { + const response = await fetch(`/api/users/${this.userId}`) + return response.json() + }, + })) + + form = injectForm({ + defaultValues: emptyUser, + onSubmit: async ({ value }) => { + await fetch('/api/users', { + method: 'PUT', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(value), + }) + }, + }) + + constructor() { + effect(() => { + const user = this.userQuery.data() + if (user && !this.form.state.isTouched) { + this.form.reset(user) + } + }) + } +} +``` + +In this example, fields remain unmounted during loading, so the user cannot +edit them before the loaded values arrive. You can render the empty form +immediately when that better suits the UI, but then decide how incoming data +should interact with edits. + +This is the approach demonstrated by the repository's +`examples/angular/query-integration` example. + +## Background refetches and record changes + +`defaultValues` establish the form's baseline; they are not a fully controlled +`values` prop. When background data arrives, decide at the product level +whether to keep local edits, prompt before replacing them, or call +`form.reset(nextValues)` deliberately. Do not overwrite in-progress input +merely because a query refreshed. + +When switching to a different record, construct a fresh editor or deliberately +reset the existing form. Otherwise, values from the previous record can remain +in the form. diff --git a/docs/framework/angular/guides/basic-concepts.md b/docs/framework/angular/guides/basic-concepts.md deleted file mode 100644 index facc91c612..0000000000 --- a/docs/framework/angular/guides/basic-concepts.md +++ /dev/null @@ -1,363 +0,0 @@ ---- -id: basic-concepts -title: Basic Concepts and Terminology ---- - -This page introduces the basic concepts and terminology used in the `@tanstack/angular-form` library. Familiarizing yourself with these concepts will help you better understand and work with the library. - -## Form Instance - -A Form Instance is an object that represents an individual form and provides methods and properties for working with the form. You create a form instance using the `injectForm` function. The hook accepts an object with an `onSubmit` function, which is called when the form is submitted. - -```typescript -const form = injectForm({ - onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) - }, -}) -``` - -## Field - -A Field represents a single form input element, such as a text input or a checkbox. Fields are created using the `tanstackField` directive. The directive accepts a name prop, which should match a key in the form's default values. It also exposes a `field` named instance of the directive's internals that should be used via a template variable to access the field's internals. - -Example: - -```html - - - -``` - -## Field State - -Each field has its own state, which includes its current value, validation status, error messages, and other metadata. You can access a field's state using the `fieldApi.state` property. - -Example: - -```ts -const { - value, - meta: { errors, isValidating }, -} = field.state -``` - -There are four states in the metadata that can be useful to see how the user interacts with a field: - -- _"isTouched"_, after the user changes the field or blurs the field -- _"isDirty"_, after the field's value has been changed, even if it's been reverted to the default. Opposite of _"isPristine"_ -- _"isPristine"_, until the user changes the field value. Opposite of _"isDirty"_ -- _"isBlurred"_, after the field has been blurred - -```ts -const { isTouched, isDirty, isPristine, isBlurred } = field.state.meta -``` - -![Field states](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states.png) - -## Understanding 'isDirty' in Different Libraries - -Non-Persistent `dirty` state - -- **Libraries**: React Hook Form (RHF), Formik, Final Form. -- **Behavior**: A field is 'dirty' if its value differs from the default. Reverting to the default value makes it 'clean' again. - -Persistent `dirty` state - -- **Libraries**: Angular Form, Vue FormKit. -- **Behavior**: A field remains 'dirty' once changed, even if reverted to the default value. - -We have chosen the persistent 'dirty' state model. To also support a non-persistent 'dirty' state, we introduce an additional flag: - -- _"isDefaultValue"_, whether the field's current value is the default value - -```ts -const { isDefaultValue, isTouched } = field.state.meta - -// The following line will re-create the non-Persistent `dirty` functionality. -const nonPersistentIsDirty = !isDefaultValue -``` - -![Field states extended](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states-extended.png) - -## Field API - -The Field API is an object accessed in the `tanstackField.api` property when creating a field. It provides methods for working with the field's state. - -Example: - -```angular-html - -``` - -## Validation - -`@tanstack/angular-form` provides both synchronous and asynchronous validation out of the box. Validation functions can be passed to the `tanstackField` directive using the `validators` prop. - -Example: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - - `, -}) -export class AppComponent { - firstNameValidator: FieldValidateFn = ({ value }) => - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined - - firstNameAsyncValidator: FieldValidateAsyncFn = async ({ - value, - }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value.includes('error') && 'No "error" allowed in first name' - } - - form = injectForm({ - defaultValues: { - firstName: '', - }, - onSubmit({ value }) { - console.log(value) - }, - }) -} -``` - -## Validation with Standard Schema Libraries - -In addition to hand-rolled validation options, we also support the [Standard Schema](https://github.com/standard-schema/standard-schema) specification. - -You can define a schema using any of the libraries implementing the specification and pass it to a form or field validator. - -Supported libraries include: - -- [Zod](https://zod.dev/) (v3.24.0 or higher) -- [Valibot](https://valibot.dev/) (v1.0.0 or higher) -- [ArkType](https://arktype.io/) (v2.1.20 or higher) -- [Yup](https://github.com/jquense/yup) (v1.7.0 or higher) - -Example: - -```angular-ts -import { z } from 'zod' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - - `, -}) -export class AppComponent { - firstNameAsyncValidator = z.string().refine( - async (value) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return !value.includes('error') - }, - { - message: "No 'error' allowed in first name", - }, - ) - - form = injectForm({ - defaultValues: { - firstName: '', - }, - onSubmit({ value }) { - // Do something with form data - console.log(value) - }, - }) - - z = z -} -``` - -## Reactivity - -`@tanstack/angular-form` offers a way to subscribe to form and field state changes via `injectStore(this.form, selector)`. - -Example: - -```typescript -import { injectForm, injectStore } from '@tanstack/angular-form' - -@Component(/*...*/) -class AppComponent { - form = injectForm(/*...*/) - canSubmit = injectStore(this.form, (state) => state.canSubmit) - isSubmitting = injectStore(this.form, (state) => state.isSubmitting) -} -``` - -## Listeners - -`@tanstack/angular-form` allows you to react to specific triggers and "listen" to them to dispatch side effects. - -Example: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - `, -}) - -... - -onCountryChange: FieldListenerFn = ({ - value, - }) => { - console.log(`Country changed to: ${value}, resetting province`) - this.form.setFieldValue('province', '') - } -``` - -More information can be found at [Listeners](./listeners.md) - -## Array Fields - -Array fields allow you to manage a list of values within a form, such as a list of hobbies. You can create an array field using the `tanstackField` directive. - -When working with array fields, you can use the fields `pushValue`, `removeValue`, `swapValues` and `moveValue` methods to add, remove, swap, and move a value from one index to another within the array, respectively. Additional helper methods such as `insertValue`, `replaceValue`, and `clearValues` are also available for inserting, replacing, and clearing array values. - -Example: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - -
    - Hobbies -
    - @if (!hobbies.api.state.value.length) { - No hobbies found - } - @for (_ of hobbies.api.state.value; track $index) { -
    - -
    - - - -
    -
    - -
    - - -
    -
    -
    - } -
    - -
    -
    - `, -}) -export class AppComponent { - defaultHobby = { - name: '', - description: '', - yearsOfExperience: 0, - } - - getHobbyName = (idx: number) => `hobbies[${idx}].name` as const - getHobbyDesc = (idx: number) => `hobbies[${idx}].description` as const - - form = injectForm({ - defaultValues: { - hobbies: [] as Array<{ - name: string - description: string - yearsOfExperience: number - }>, - }, - onSubmit({ value }) { - alert(JSON.stringify(value)) - }, - }) -} -``` - -These are the basic concepts and terminology used in the `@tanstack/angular-form` library. Understanding these concepts will help you work more effectively with the library and create complex forms with ease. diff --git a/docs/framework/angular/guides/debugging.md b/docs/framework/angular/guides/debugging.md new file mode 100644 index 0000000000..92590d4b88 --- /dev/null +++ b/docs/framework/angular/guides/debugging.md @@ -0,0 +1,99 @@ +--- +id: debugging +title: Debugging Angular Usage +--- + +This page covers common Angular and TypeScript problems when using TanStack +Form. + +## An input initially renders `undefined` + +Every value rendered by an input must exist in form-level `defaultValues` from +the first render. + +```ts +form = injectForm({ + defaultValues: { + firstName: '', + subscribed: false, + }, +}) +``` + +Do not omit `defaultValues` or rely on a field-level default. When values come +from an API, render a loading state before mounting the editable fields or +supply a complete fallback shape. + +## A field value is `unknown` + +Field names and values are inferred from `defaultValues`. Check that you have +not widened the initial object to `Record`, `any`, or an +unrelated union. Prefer a concrete value type: + +```ts +type Profile = { firstName: string; age: number } + +const defaults: Profile = { firstName: '', age: 0 } +form = injectForm({ defaultValues: defaults }) +``` + +For extremely large forms, split UI into typed components or scoped form and +field groups instead of casting each field value. + +## A child component rejects the form input + +Use `formOptions` for reusable base options and derive the input type with +`AngularFormType`. This keeps the child compatible when the parent adds +`onSubmit`: + +```ts +import { Component, input } from '@angular/core' +import { formOptions } from '@tanstack/angular-form' +import type { AngularFormType } from '@tanstack/angular-form' + +export const profileFormOptions = formOptions({ + defaultValues: { firstName: '', age: 0 }, +}) + +@Component({ + selector: 'app-profile-fields', + standalone: true, + template: ``, +}) +export class ProfileFieldsComponent { + form = input.required>() +} +``` + +## Async defaults do not update + +`injectForm` receives its initial options when the component is constructed. +When data arrives later, call `form.reset(nextValues)` deliberately, normally +inside an Angular `effect`, or resolve the data before constructing the form. +Guard against replacing edits the user has already made. + +## `injectForm` reports a missing injection context + +Call `injectForm`, `injectSelector`, and `injectField` in an Angular injection +context, such as a component field initializer or constructor. Do not call +them later from an event handler, subscription callback, or arbitrary utility +function. + +## Type instantiation is excessively deep + +This TypeScript error usually involves a very large recursive value shape, a +widely inferred union, or unsupported composition. Reduce it to the smallest +form that reproduces the problem, keep `defaultValues` concrete, and avoid +unnecessary generic wrappers. + +If the minimal reproduction still fails, report it in the +[TanStack Form issue tracker](https://github.com/TanStack/form/issues). Include +the Angular and TypeScript versions, the form value type, and the smallest +failing field. + +## Errors exist but are not displayed + +`field.api.errors` respects the form's `errorVisibility` policy. Inspect +`field.api.meta.original.errors` when debugging whether validation ran but the +issues are intentionally hidden. Also confirm that the input calls +`field.api.handleBlur()` if the policy depends on `isBlurred`. diff --git a/docs/framework/angular/guides/dynamic-validation.md b/docs/framework/angular/guides/dynamic-validation.md deleted file mode 100644 index 455613002e..0000000000 --- a/docs/framework/angular/guides/dynamic-validation.md +++ /dev/null @@ -1,313 +0,0 @@ ---- -id: dynamic-validation -title: Dynamic Validation ---- - -In many cases, you want to change the validation rules based depending on the state of the form or other conditions. The most popular -example of this is when you want to validate a field differently based on whether the user has submitted the form for the first time or not. - -We support this through our `onDynamic` validation function. - -```angular-ts -import { Component } from '@angular/core' -import { - TanStackField, - injectForm, - revalidateLogic, -} from '@tanstack/angular-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - firstName: '', - lastName: '', - }, - // If this is omitted, onDynamic will not be called - validationLogic: revalidateLogic(), - validators: { - onDynamic: ({ value }) => { - if (!value.firstName) { - return { firstName: 'A first name is required' } - } - return undefined - }, - }, - }) -} -``` - -> By default `onDynamic` is not called, so you need to pass `revalidateLogic()` to the `validationLogic` option of `injectForm`. - -## Revalidation Options - -`revalidateLogic` allows you to specify when validation should be run and change the validation rules dynamically based on the current submission state of the form. - -It takes two arguments: - -- `mode`: The mode of validation prior to the first form submission. This can be one of the following: - - `change`: Validate on every change. - - `blur`: Validate on blur. - - `submit`: Validate on submit. (**default**) - -- `modeAfterSubmission`: The mode of validation after the form has been submitted. This can be one of the following: - - `change`: Validate on every change. (**default**) - - `blur`: Validate on blur. - - `submit`: Validate on submit. - -You can, for example, use the following to revalidate on blur after the first submission: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` `, -}) -export class AppComponent { - form = injectForm({ - // ... - validationLogic: revalidateLogic({ - mode: 'submit', - modeAfterSubmission: 'blur', - }), - // ... - }) -} -``` - -## Accessing Errors - -Just as you might access errors from an `onChange` or `onBlur` validation, you can access the errors from the `onDynamic` validation function using the form's error map through `injectStore`. - -```angular-ts -import { Component } from '@angular/core' -import { - TanStackField, - injectForm, - injectStore, - revalidateLogic, -} from '@tanstack/angular-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: `

    {{ formErrorMap().onDynamic?.firstName }}

    `, -}) -export class AppComponent { - form = injectForm({ - // ... - validationLogic: revalidateLogic(), - validators: { - onDynamic: ({ value }) => { - if (!value.firstName) { - return { firstName: 'A first name is required' } - } - return undefined - }, - }, - }) - - formErrorMap = injectStore(this.form, (state) => state.errorMap) -} -``` - -## Usage with Other Validation Logic - -You can use `onDynamic` validation alongside other validation logic, such as `onChange` or `onBlur`. - -```angular-ts -import { Component } from '@angular/core' -import { - TanStackField, - injectForm, - injectStore, - revalidateLogic, -} from '@tanstack/angular-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` -
    -

    {{ formErrorMap().onChange?.firstName }}

    -

    {{ formErrorMap().onDynamic?.lastName }}

    -
    - `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - firstName: '', - lastName: '', - }, - validationLogic: revalidateLogic(), - validators: { - onChange: ({ value }) => { - if (!value.firstName) { - return { firstName: 'A first name is required' } - } - return undefined - }, - onDynamic: ({ value }) => { - if (!value.lastName) { - return { lastName: 'A last name is required' } - } - return undefined - }, - }, - }) - - formErrorMap = injectStore(this.form, (state) => state.errorMap) -} -``` - -### Usage with Fields - -You can also use `onDynamic` validation with fields, just like you would with other validation logic. - -```angular-ts -import { Component } from '@angular/core' -import { - TanStackField, - injectForm, - revalidateLogic, -} from '@tanstack/angular-form' -import type { FieldValidateFn } from '@tanstack/angular-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` -
    - - - @if (age.api.state.meta.errorMap.onDynamic) { -

    - {{ age.api.state.meta.errorMap.onDynamic }} -

    - } -
    - -
    - `, -}) -export class AppComponent { - ageValidator: FieldValidateFn = ({ value }) => - value > 18 ? undefined : 'Age must be greater than 18' - - form = injectForm({ - defaultValues: { - name: '', - age: 0, - }, - validationLogic: revalidateLogic(), - onSubmit({ value }) { - alert(JSON.stringify(value)) - }, - }) - - handleSubmit(event: SubmitEvent) { - event.preventDefault() - event.stopPropagation() - this.form.handleSubmit() - } -} -``` - -### Async Validation - -Async validation can also be used with `onDynamic` just like with other validation logic. You can even debounce the async validation to avoid excessive calls. - -```angular-ts -import { Component } from '@angular/core' -import { - TanStackField, - injectForm, - revalidateLogic, -} from '@tanstack/angular-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - username: '', - }, - validationLogic: revalidateLogic(), - validators: { - onDynamicAsyncDebounceMs: 500, // Debounce the async validation by 500ms - onDynamicAsync: async ({ value }) => { - if (!value.username) { - return { username: 'Username is required' } - } - // Simulate an async validation - const isValid = await validateUsername(value.username) - return isValid ? undefined : { username: 'Username is already taken' } - }, - }, - }) -} -``` - -### Standard Schema Validation - -You can also use standard schema validation libraries like Valibot or Zod with `onDynamic` validation. This allows you to define complex validation rules that can change dynamically based on the form state. - -```angular-ts -import { Component } from '@angular/core' -import { - TanStackField, - injectForm, - revalidateLogic, -} from '@tanstack/angular-form' -import { z } from 'zod' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` `, -}) -export class AppComponent { - schema = z.object({ - firstName: z.string().min(1, 'A first name is required'), - lastName: z.string().min(1, 'A last name is required'), - }) - - form = injectForm({ - defaultValues: { - firstName: '', - lastName: '', - }, - validationLogic: revalidateLogic(), - validators: { - onDynamic: this.schema, - }, - }) -} -``` diff --git a/docs/framework/angular/guides/form-composition.md b/docs/framework/angular/guides/form-composition.md deleted file mode 100644 index 35bb092628..0000000000 --- a/docs/framework/angular/guides/form-composition.md +++ /dev/null @@ -1,271 +0,0 @@ ---- -id: form-composition -title: Form Composition ---- - -A common criticism of TanStack Form is its verbosity out-of-the-box. While this _can_ be useful for educational purposes - helping enforce understanding our APIs - it's not ideal in production use cases. - -As a result, while basic usage of `[tanstackField]` enables the most powerful and flexible usage of TanStack Form, we provide APIs that wrap it and make your application code less verbose. - -## Pre-bound Field Components - -If you've ever used TanStack Form in Angular to bind more than one input, you'll have quickly realized how much goes into each input: - -```angular-ts -import { Component } from '@angular/core' -import { TanStackField, injectForm, injectStore } from '@tanstack/angular-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` -
    - - - - @if (firstName.api.state.meta.isTouched) { - @for (error of firstName.api.state.meta.errors; track $index) { -
    - {{ error }} -
    - } - } - @if (firstName.api.state.meta.isValidating) { -

    Validating...

    - } -
    -
    -
    - - - - @if (lastName.api.state.meta.isTouched) { - @for (error of lastName.api.state.meta.errors; track $index) { -
    - {{ error }} -
    - } - } - @if (lastName.api.state.meta.isValidating) { -

    Validating...

    - } -
    -
    - `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - firstName: '', - lastName: '', - }, - onSubmit({ value }) { - // Do something with form data - console.log(value) - }, - }) -} -``` - -This is functionally correct, but introduces a _lot_ of repeated templating behavior over and over. Instead, let's move the error handling, label to input binding, and other repeated logic into a component: - -```angular-ts -import { injectField } from '@tanstack/angular-form' - -@Component({ - selector: 'app-text-field', - standalone: true, - template: ` - - - @if (field.api.state.meta.isTouched) { - @for (error of field.api.state.meta.errors; track $index) { -
    - {{ error }} -
    - } - } - @if (field.api.state.meta.isValidating) { -

    Validating...

    - } - `, -}) -export class AppTextField { - label = input.required() - // This API requires another part to it from the parent component - field = injectField() -} -``` - -> `injectField` accepts a single generic to define the `field.state.value` type. -> -> As a result, a numerical text field would be represented as `injectField`, for example. - -Now, we can use the `TanStackAppField` directive (`tanstack-app-field`) to `provide` the expected field associated with this input: - -```angular-ts -import { Component } from '@angular/core' -import { - TanStackAppField, - TanStackField, - injectForm, -} from '@tanstack/angular-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField, TanStackAppField, AppTextField], - template: ` -
    - -
    -
    - -
    - `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - firstName: '', - lastName: '', - }, - onSubmit({ value }) { - // Do something with form data - console.log(value) - }, - }) -} -``` - -> Here, the `tanstack-app-field` directive is taking the properties from `[tanstackField]` and `provide`ing them down to the `app-text-field` so that they can be more easily consumed as a component. - -## Breaking big forms into smaller pieces - -Sometimes forms get very large; it's just how it goes sometimes. While TanStack Form supports large forms well, it's never fun to work with hundreds or thousands of lines of code in a single component. - -To solve this, we support breaking forms into smaller pieces using the `[tanstack-with-form]` directive together with the `injectWithForm` function. - -The parent component owns the `form` (created via `injectForm`) and passes it down to a child component using the `tanstack-with-form` directive. The child component reads it back via `injectWithForm`, which returns a fully-typed reference to that same `FormApi` — meaning the child can render `[tanstackField]` bindings, `tanstack-app-field` components, etc. against the parent's form without needing to redeclare any generics. - -First, lift your shared form options out using `formOptions` so both the parent and the child can reference the same shape: - -```angular-ts -// shared-form.ts -import { formOptions } from '@tanstack/angular-form' - -export const peopleFormOpts = formOptions({ - defaultValues: { - firstName: '', - lastName: '', - }, -}) -``` - -Then, build a child component that consumes the form via `injectWithForm`: - -```angular-ts -// child-form.component.ts -import { Component } from '@angular/core' -import { - TanStackAppField, - TanStackField, - injectWithForm, -} from '@tanstack/angular-form' -import { AppTextField } from './app-text-field.component' -import { peopleFormOpts } from './shared-form' - -@Component({ - selector: 'app-child-form', - standalone: true, - imports: [TanStackField, TanStackAppField, AppTextField], - template: ` - - - `, -}) -export class ChildForm { - // Spreading the form options into `injectWithForm` is what gives `withForm.form` - // its full type inference — no generics needed. - withForm = injectWithForm({ ...peopleFormOpts }) -} -``` - -> The options passed to `injectWithForm({ ...peopleFormOpts })` are only used for type inference. They are not read at runtime; the actual `FormApi` instance comes from the ancestor `tanstack-with-form` directive. - -Finally, in the parent component, create the form with `injectForm` and pass it to the child via the `tanstack-with-form` directive: - -```angular-ts -// app.component.ts -import { Component } from '@angular/core' -import { TanStackWithForm, injectForm } from '@tanstack/angular-form' -import { ChildForm } from './child-form.component' -import { peopleFormOpts } from './shared-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackWithForm, ChildForm], - template: ` -
    - - - - `, -}) -export class AppComponent { - form = injectForm({ - ...peopleFormOpts, - onSubmit({ value }) { - console.log(value) - }, - }) - - handleSubmit(event: SubmitEvent) { - event.preventDefault() - event.stopPropagation() - this.form.handleSubmit() - } -} -``` - -This pattern lets you split a large form across many components while keeping a single source of truth for the form's state and types. Any descendant of the `tanstack-with-form` directive can call `injectWithForm({ ...peopleFormOpts })` to gain typed access to the same form instance. diff --git a/docs/framework/angular/guides/form-groups.md b/docs/framework/angular/guides/form-groups.md deleted file mode 100644 index 96beebddd6..0000000000 --- a/docs/framework/angular/guides/form-groups.md +++ /dev/null @@ -1,302 +0,0 @@ ---- -id: form-groups -title: Form Groups ---- - -When building a multi-stage form that has many stages, like so: - -![Form stepper](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/stepper.png) - -It's common for each step to have its own form. However, this complicates the form submission and validation process by requiring you to add complex logic. - -Luckily, TanStack Form provides a way to build out sub-forms that make this kind of development trivial to implement: `[tanstackFormGroup]`. - -## Usage - -To use a form group in TanStack Form, you'll use `injectForm` to create a `form` variable, then reference it with the `tanstackFormGroup` directive like you would with `tanstackField`: - -```angular-ts -import { Component } from '@angular/core' -import { TanStackFormGroup, injectForm } from '@tanstack/angular-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackFormGroup], - template: ` - - - - - `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - step1: { - name: '', - }, - step2: { - age: 0, - }, - }, - }) -} -``` - -This becomes much more useful when paired with external state to conditionally render a form group: - -```angular-ts -import { Component, signal } from '@angular/core' -import { - TanStackField, - TanStackFormGroup, - injectForm, -} from '@tanstack/angular-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField, TanStackFormGroup], - template: ` - @if (step() === 0) { - -
    - - - -
    -
    - } - - @if (step() === 1) { - -
    - - - -
    -
    - } - `, -}) -export class AppComponent { - step = signal(0) - submitMeta = {} as SomeType - - form = injectForm({ - defaultValues: { - step1: { - name: '', - }, - step2: { - age: 0, - }, - }, - }) - - onStep1Submit = () => { - // We can move the step forward when validation passes - this.step.update((step) => step + 1) - } - - onStep1SubmitInvalid = () => { - // Or handle invalid submissions, just like a top-level form - } - - onStep2Submit = () => { - // Then, use `form.handleSubmit()` to submit the entire form - this.form.handleSubmit() - } -} -``` - -When you split each step into its own component, pass the parent form down with [`tanstack-with-form`](./form-composition.md) and read it in the child with `injectWithForm`. The child can then use `[tanstackFormGroup]="withForm.form"` and `[tanstackField]="withForm.form"` against the same parent form instance. - -## Form Group Validation - -Form groups have a distinct validation procedure that we think makes sense for sub-forms: - -- Form groups can have their own validation: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackFormGroup], - template: ` - - - - - `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - step1: { name: '' }, - }, - }) - - groupValidator = () => 'Error' -} -``` - -- Can set errors on sub-fields: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackFormGroup], - template: ` - - `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - step1: { name: '' }, - }, - }) - - groupValidator = ({ value }: { value: { name: string } }) => ({ - group: value.name === 'error' ? 'Group error' : undefined, - fields: { - // Must use the name of the field relative to the FormGroup as the error key, - // to stay consistent with how standard schema works with form groups - name: value.name === 'error' ? 'Field error' : undefined, - }, - }) -} -``` - -- And can even accept standard schemas: - -```angular-ts -import { z } from 'zod' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackFormGroup], - template: ` - - `, -}) -export class AppComponent { - step1Schema = z.object({ - name: z.string().min(2), - }) - - form = injectForm({ - defaultValues: { - step1: { name: '' }, - }, - }) -} -``` - -> The reason we don't use the full path names for fields is so that you can compose your schemas like so: -> -> ```ts -> const step1Schema = z.object({ -> name: z.string().min(2), -> }) -> -> const schema = z.object({ -> step1: step1Schema, -> step2: step2Schema, -> }) -> ``` -> -> And pass the `step1Schema` to a form group and `schema` to the parent form. That way, partially validated data will still flag errors if the group is bypassed. - -### Dynamic Group Validation - -If you want to use [dynamic validation (`onDynamic`)](./dynamic-validation.md) with a form group, do not rely on the `onDynamic` validator passed to `injectForm`: - -```ts -form = injectForm({ - validationLogic: revalidateLogic(), - validators: { - // This validator will not run `onChange` when a sub-form is submitted; - // it will only run `onChange` when the form itself is submitted. - onDynamic: schema, - }, -}) -``` - -Instead, pass your sub-schema for the group to the `onDynamic` validation of the group itself: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackFormGroup], - template: ` - - `, -}) -export class AppComponent { - step1Schema = step1Schema - - form = injectForm({ - defaultValues: { - step1: { name: '' }, - }, - }) -} -``` - -It will treat `group.api.submissionAttempts` as the way to change what validator is run before/after submit. - -## Form Group State - -Just like you're able to access `group.api.state.meta.errors`, you're also able to access the group's value using `group.api.state.value`. Likewise, here are some valuable properties you can access in the `group.api.state.meta`: - -- `group.api.state.meta.isFieldsValid`: `true` when the field-level validators have no errors -- `group.api.state.meta.isGroupValid`: `true` when the group-level validators have no errors -- `group.api.state.meta.isValid`: `true` when both the field-level and group-level validators have no errors -- `group.api.state.meta.isSubmitting`: `true` when the group is in the process of being submitted diff --git a/docs/framework/angular/guides/listeners.md b/docs/framework/angular/guides/listeners.md deleted file mode 100644 index 8da6e75017..0000000000 --- a/docs/framework/angular/guides/listeners.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -id: listeners -title: Side effects for event triggers ---- - -For situations where you want to "affect" or "react" to triggers, there's the listener API. For example, if you, as the developer, want to reset a form field as a result of another field changing, you would use the listener API. - -Imagine the following user flow: - -- User selects a country from a drop-down. -- User then selects a province from another drop-down. -- User changes the selected country to a different one. - -In this example, when the user changes the country, the selected province needs to be reset as it's no longer valid. With the listener API, we can subscribe to the onChange event and dispatch a reset to the field "province" when the listener is fired. - -Events that can be "listened" to are: - -- `onChange` -- `onBlur` -- `onMount` -- `onSubmit` -- `onUnmount` - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - - `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - country: '', - province: '', - }, - }) - - onCountryChange: FieldListenerFn = ({ - value, - }) => { - console.log(`Country changed to: ${value}, resetting province`) - this.form.setFieldValue('province', '') - } -} -``` diff --git a/docs/framework/angular/guides/submission-handling.md b/docs/framework/angular/guides/submission-handling.md deleted file mode 100644 index b441ca7a57..0000000000 --- a/docs/framework/angular/guides/submission-handling.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -id: submission-handling -title: Submission handling ---- - -## Passing additional data to submission handling - -You may have multiple types of submission behaviour, for example, going back to another page or staying on the form. -You can accomplish this by specifying the `onSubmitMeta` property. This meta data will be passed to the `onSubmit` function. - -> Note: if `form.handleSubmit()` is called without metadata, it will use the provided default. - -```angular-ts -import { Component } from '@angular/core' -import { injectForm } from '@tanstack/angular-form' - -type FormMeta = { - submitAction: 'continue' | 'backToMenu' | null -} - -// Metadata is not required to call form.handleSubmit(). -// Specify what values to use as default if no meta is passed -const defaultMeta: FormMeta = { - submitAction: null, -} - -@Component({ - selector: 'app-root', - template: ` -
    - - -
    - `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - data: '', - }, - // Define what meta values to expect on submission - onSubmitMeta: defaultMeta, - onSubmit: async ({ value, meta }) => { - // Do something with the values passed via handleSubmit - console.log(`Selected action - ${meta.submitAction}`, value) - }, - }) - - handleSubmit(event: SubmitEvent) { - event.preventDefault() - event.stopPropagation() - } - - handleClick(meta: FormMeta) { - // Overwrites the default specified in onSubmitMeta - this.form.handleSubmit(meta) - } -} -``` - -## Transforming data with Standard Schemas - -While Tanstack Form provides [Standard Schema support](./validation.md) for validation, it does not preserve the Schema's output data. - -The value passed to the `onSubmit` function will always be the input data. To receive the output data of a Standard Schema, parse it in the `onSubmit` function: - -```tsx -import { z } from 'zod' -// ... - -const schema = z.object({ - age: z.string().transform((age) => Number(age)), -}) - -// Tanstack Form uses the input type of Standard Schemas -const defaultValues: z.input = { - age: '13', -} - -// ... - -@Component({ - // ... -}) -export class AppComponent { - form = injectForm({ - defaultValues, - validators: { - onChange: schema, - }, - onSubmit: ({ value }) => { - const inputAge: string = value.age - // Pass it through the schema to get the transformed value - const result = schema.parse(value) - const outputAge: number = result.age - }, - }) -} -``` diff --git a/docs/framework/angular/guides/ui-libraries.md b/docs/framework/angular/guides/ui-libraries.md new file mode 100644 index 0000000000..62d3d472ce --- /dev/null +++ b/docs/framework/angular/guides/ui-libraries.md @@ -0,0 +1,131 @@ +--- +id: ui-libraries +title: UI Libraries +--- + +TanStack Form is headless. UI library integration consists of adapting a +field's value, blur callback, change callback, invalid state, and errors to the +component's inputs and outputs. + +## Text inputs + +Wrap a UI component with `TanStackField` and pass its emitted value to +`field.api.handleChange`: + +```html + + + +``` + +```ts +errorMessage = (error: { message: string }) => error.message +``` + +Pass the current `value`, not a one-time default, so the UI component remains +driven by form state. + +## Checkboxes and switches + +Adapt the output used by the component library: + +```html + + + +``` + +Some libraries emit a details object or a union such as +`boolean | 'indeterminate'`. Normalize it at the boundary: + +```html + +``` + +## Selects, date pickers, and custom controls + +The integration does not require a native event. Pass the value emitted by the +component to `field.api.handleChange`: + +```html + +``` + +Choose a serializable form value appropriate for your application, then adapt +the UI library's richer object at the component boundary if necessary. + +## Reuse the adapter + +When the same wiring appears throughout the application, create an Angular +field component that calls `injectField`: + +```ts +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { injectField } from '@tanstack/angular-form' + +@Component({ + selector: 'app-text-field', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + `, +}) +export class TextFieldComponent { + label = input.required() + field = injectField() +} +``` + +Apply `tanstack-app-field` alongside the field directive so the component can +inject its field API: + +```html + +``` + +Import `TanStackAppField`, `TanStackField`, and the reusable field component in +the parent. + +For the helper types used when passing a form or field to an extracted +component, see [Splitting forms](../../../splitting-forms). + +The repository's `examples/angular/basic-splitting-form` and +`examples/angular/large-form` examples demonstrate this pattern with typed +child components. diff --git a/docs/framework/angular/guides/validation.md b/docs/framework/angular/guides/validation.md index 11de82dbe6..60a81a4957 100644 --- a/docs/framework/angular/guides/validation.md +++ b/docs/framework/angular/guides/validation.md @@ -3,694 +3,315 @@ id: form-validation title: Form and Field Validation --- -At the core of TanStack Form's functionalities is the concept of validation. TanStack Form makes validation highly customizable: - -- You can control when to perform the validation (on change, on input, on blur, on submit...) -- Validation rules can be defined at the field level or at the form level -- Validation can be synchronous or asynchronous (for example, as a result of an API call) - -## When is validation performed? - -It's up to you! The `[tanstackField]` directive accepts some callbacks as props such as `onChange` or `onBlur`. Those callbacks are passed the current value of the field, as well as the fieldAPI object, so that you can perform the validation. If you find a validation error, simply return the error message as string and it will be available in `field.api.state.meta.errors`. - -Here is an example: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - - @if (age.api.state.meta.errors) { - {{ age.api.state.meta.errors.join(', ') }} - } - - `, -}) -export class AppComponent { - ageValidator: FieldValidateFn = ({ value }) => - value < 13 ? 'You must be 13 to make an account' : undefined +TanStack Form supports synchronous, asynchronous, field-level, form-level, and +Standard Schema validation. Every validator is an ordered object with a `run` +implementation and explicit `triggers`. + +## Choose when validation runs + +Use `change` for immediate feedback and `blur` for feedback after leaving an +input. Submission runs validators by default regardless of their configured +change and blur triggers. + +```ts +ageValidators = [ + { + triggers: ['change'] as const, + run: ({ value }: { value: number }) => + value >= 13 ? undefined : 'You must be at least 13', + }, + { + triggers: ['blur'] as const, + run: ({ value }: { value: number }) => + value >= 0 ? undefined : 'Age cannot be negative', + }, +] +``` - // ... -} +```html + + + ``` -In the example above, the validation is done at each keystroke (`onChange`). If, instead, we wanted the validation to be done when the field is blurred, we would change the code above like so: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - - - - @if (age.api.state.meta.errors) { - {{ age.api.state.meta.errors.join(', ') }} - } - - `, -}) -export class AppComponent { - ageValidator: FieldValidateFn = ({ value }) => - value < 13 ? 'You must be 13 to make an account' : undefined +Additional controls include: - // ... -} -``` +- `runOnMount`: run once when the form is constructed or when a field or form + group first mounts. +- `skipOnSubmit`: conditionally skip submit-time execution. +- `triggerDebounceMs`: debounce change and blur execution. +- `bailIfInvalid`: skip this and subsequent validators when an earlier one + failed. +- trigger objects with `when`: enable a trigger conditionally. +- `watchFields`: rerun a field validator when related fields trigger it. -So you can control when the validation is done by implementing the desired callback. You can even perform different pieces of validation at different times: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - - - - @if (!age.api.state.meta.isValid) { - {{ age.api.state.meta.errors.join(', ') }} - } - - `, -}) -export class AppComponent { - ageValidator: FieldValidateFn = ({ value }) => - value < 13 ? 'You must be 13 to make an account' : undefined +## Control when errors are visible - minimumAgeValidator: FieldValidateFn = ({ - value, - }) => (value < 0 ? 'Invalid value' : undefined) +Validation and presentation are separate. `errorVisibility` decides when +field issues appear in `field.api.errors`: - // ... -} -``` +```ts +import { injectForm } from '@tanstack/angular-form' -In the example above, we are validating different things on the same field at different times (at each keystroke and when blurring the field). Since `field.state.meta.errors` is an array, all the relevant errors at a given time are displayed. You can also use `field.state.meta.errorMap` to get errors based on _when_ the validation was done (onChange, onBlur etc...). More info about displaying errors below. - -## Displaying Errors - -Once you have your validation in place, you can map the errors from an array to be displayed in your UI: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - @if (age.api.state.meta.errors) { - {{ age.api.state.meta.errors.join(', ') }} - } - - `, +form = injectForm({ + defaultValues: { email: '' }, + errorVisibility: ({ fieldState, state }) => + fieldState.meta.isBlurred || state.submissionAttempts > 0, }) -export class AppComponent { - ageValidator: FieldValidateFn = ({ value }) => - value < 13 ? 'You must be 13 to make an account' : undefined - - // ... -} ``` -Or use the `errorMap` property to access the specific error you're looking for: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - @if (age.api.state.meta.errorMap['onChange']) { - {{ age.api.state.meta.errorMap['onChange'] }} - } - - `, -}) -export class AppComponent { - ageValidator: FieldValidateFn = ({ value }) => - value < 13 ? 'You must be 13 to make an account' : undefined +Use `field.api.meta.original.errors` for the unfiltered issues when debugging +or building a custom visibility system. - // ... -} -``` +## Form-level validation -It's worth mentioning that our `errors` array and the `errorMap` matches the types returned by the validators. This means that: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - - - @if (!age.api.state.meta.errorMap['onChange']?.isOldEnough) { - The user is not old enough - } - - `, -}) -export class AppComponent { - ageValidator: FieldValidateFn = ({ value }) => - value < 13 ? 'You must be 13 to make an account' : undefined +A form validator can produce a form issue and route issues to typed field paths +with `createErrorMap`: - // ... -} -``` +```ts +import { injectForm, injectSelector } from '@tanstack/angular-form' -## Validation at field level vs at form level - -As shown above, each `[tanstackField]` accepts its own validation rules via the `onChange`, `onBlur` etc... callbacks. It is also possible to define validation rules at the form level (as opposed to field by field) by passing similar callbacks to the `injectForm()` function. - -Example: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` -
    - - - @if (formErrorMap().onChange) { -
    - There was an error on the form: {{ formErrorMap().onChange }} -
    - } - -
    -
    - `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - age: 0, - }, - onSubmit({ value }) { - console.log(value) - }, - validators: { - // Add validators to the form the same way you would add them to a field - onChange({ value }) { - if (value.age < 13) { - return 'Must be 13 or older to sign' +form = injectForm({ + defaultValues: { + email: '', + phone: '', + }, + validators: [ + { + triggers: ['change'], + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() + + if (!value.email && !value.phone) { + errors.form = 'Provide an email address or phone number' + errors.fields.email = 'Email is required when phone is empty' + errors.fields.phone = 'Phone is required when email is empty' } - return undefined + + return errors }, }, - }) + ], +}) - // Subscribe to the form's error map so that updates to it will render - formErrorMap = injectStore(this.form, (state) => state.errorMap) -} +formErrors = injectSelector(this.form, (state) => state.errors) ``` -### Setting field-level errors from the form's validators - -You can set errors on the fields from the form's validators. One common use case for this is validating all the fields on submit by calling a single API endpoint in the form's `onSubmitAsync` validator. - -```angular-ts -@Component({ - selector: 'app-root', - imports: [TanStackField], - template: ` -
    -
    - - - - @if (ageField.api.state.meta.errors.length > 0) { - {{ - ageField.api.state.meta.errors.join(', ') - }} - } - -
    - -
    - `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - age: 0, - socials: [], - details: { - email: '', - }, +`injectSelector` exposes form-level issues as an Angular signal. Lower-level +integrations can subscribe to `form.atom` directly. Field-routed issues appear +in the corresponding `field.api.errors`. + +## Asynchronous validation and debouncing + +`run` may return a promise. Put cheap synchronous checks first and use +`bailIfInvalid` to avoid unnecessary requests: + +```ts +usernameValidators = [ + { + triggers: ['change'] as const, + run: ({ value }: { value: string }) => + value.length >= 3 ? undefined : 'Use at least 3 characters', + }, + { + triggers: ['change'] as const, + triggerDebounceMs: 500, + bailIfInvalid: true, + run: async ({ value }: { value: string }) => { + const available = await checkUsername(value) + return available ? undefined : 'That username is already taken' }, - validators: { - onSubmitAsync: async ({ value }) => { - // Validate the value on the server - const hasErrors = await verifyDataOnServer(value) - if (hasErrors) { - return { - form: 'Invalid data', // The `form` key is optional - fields: { - age: 'Must be 13 or older to sign', - // Set errors on nested fields with the field's name - 'socials[0].url': 'The provided URL does not exist', - 'details.email': 'An email is required', - }, - } - } + }, +] +``` - return null - }, - }, - }) +Pass this array to the field with `[validators]="usernameValidators"`. +Submit validation always runs immediately, even when a trigger is debounced. +`field.api.meta.isValidating` and `form.state.isValidating` expose pending +work. - handleSubmit(event: SubmitEvent) { - event.preventDefault() - event.stopPropagation() - this.form.handleSubmit() - } -} -``` +## Standard Schema validation -> Something worth mentioning is that if you have a form validation function that returns an error, that error may be overwritten by the field-specific validation. -> -> This means that: -> -> ```angular-ts -> @Component({ -> selector: 'app-root', -> standalone: true, -> imports: [TanStackField], -> template: ` ->
    -> [tanstackField]="form" -> name="age" -> #ageField="field" -> [validators]="{ -> onChange: fieldValidator, -> }" -> > -> type="number" -> [value]="ageField.api.state.value" -> (input)=" -> ageField.api.handleChange($any($event).target.valueAsNumber) -> " -> /> -> @if (ageField.api.state.meta.errors.length > 0) { -> {{ -> ageField.api.state.meta.errors.join(', ') -> }} -> } -> ->
    -> `, -> }) -> export class AppComponent { -> form = injectForm({ -> defaultValues: { -> age: 0, -> }, -> validators: { -> onChange: ({ value }) => { -> return { -> fields: { -> age: value.age < 12 ? 'Too young!' : undefined, -> }, -> } -> }, -> }, -> }) -> -> fieldValidator: FieldValidateFn = ({ value }) => -> value % 2 === 0 ? 'Must be odd!' : undefined -> } -> ``` -> -> Will only show `'Must be odd!` even if the 'Too young!' error is returned by the form-level validation. - -## Asynchronous Functional Validation - -While we suspect most validations will be synchronous, there are many instances where a network call or some other async operation would be useful to validate against. - -To do this, we have dedicated `onChangeAsync`, `onBlurAsync`, and other methods that can be used to validate against: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - - @if (age.api.state.meta.errors) { - {{ age.api.state.meta.errors.join(', ') }} - } - - `, +Any Standard Schema implementation can be supplied as `run`: + +```ts +import { injectForm } from '@tanstack/angular-form' +import { z } from 'zod' + +const accountSchema = z.object({ + email: z.string().email(), + age: z.number().min(13), }) -export class AppComponent { - ageValidator: FieldValidateAsyncFn = async ({ - value, - }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value < 13 ? 'You must be 13 to make an account' : undefined - } - - // ... -} -``` -Synchronous and Asynchronous validations can coexist. For example, it is possible to define both `onBlur` and `onBlurAsync` on the same field: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - - @if (age.api.state.meta.errors) { - {{ age.api.state.meta.errors.join(', ') }} - } - - `, +form = injectForm({ + defaultValues: { email: '', age: 0 }, + validators: [ + { + triggers: ['change'], + run: accountSchema, + }, + ], }) -export class AppComponent { - ensureAge13: FieldValidateFn = ({ value }) => - value < 13 ? 'You must be at least 13' : undefined - - ensureOlderAge: FieldValidateAsyncFn = async ({ - value, - }) => { - const currentAge = await fetchCurrentAgeOnProfile() - return value < currentAge ? 'You can only increase the age' : undefined - } - - // ... -} ``` -The synchronous validation method (`onBlur`) is run first and the asynchronous method (`onBlurAsync`) is only run if the synchronous one (`onBlur`) succeeds. To change this behaviour, set the `asyncAlways` option to `true`, and the async method will be run regardless of the result of the sync method. +Schema paths are routed to matching fields. Parsed outputs are available by +validator index in `schemaOutputs` during submit, for example +`schemaOutputs[0]`. `value` remains the form's raw editable state rather than +the parsed output. -### Built-in Debouncing +For custom schema routing, call a schema's safe parse API inside `run` and pass +its issues to the provided `parseIssues` helper. -While async calls are the way to go when validating against the database, running a network request on every keystroke is a good way to DDOS your database. +## Validate related fields -Instead, we enable an easy method for debouncing your `async` calls by adding a single property: +Use `watchFields` when one field's validity depends on another: -```angular-html - - - -``` +```ts +import type { FieldValidators } from '@tanstack/angular-form' -This will debounce every async call with a 500ms delay. You can even override this property on a per-validation property: +type DateFormValues = { startDate: string; endDate: string } -```angular-html +endDateValidators = [ + { + triggers: ['change', 'blur'], + watchFields: ['startDate'], + run: ({ value, formApi }) => + value >= formApi.getFieldValue('startDate') + ? undefined + : 'End date must be on or after the start date', + }, +] satisfies FieldValidators +``` + +```html - + ``` -> This will run `onChangeAsync` every 1500ms while `onBlurAsync` will run every 500ms. - -## Validation through Schema Libraries - -While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries that provide schema-based validation to make shorthand and type-strict validation substantially easier. You can also define a single schema for your entire form and pass it to the form level, errors will be automatically propagated to the fields. - -### Standard Schema Libraries - -TanStack Form natively supports all libraries following the [Standard Schema specification](https://github.com/standard-schema/standard-schema), most notably: +## Validate a scoped form group -- [Zod](https://zod.dev/) -- [Valibot](https://valibot.dev/) -- [ArkType](https://arktype.io/) +`TanStackFormGroup` creates a v2 group for one concrete section of a form. The +directive exports its API as `formGroup`, and `fieldName` resolves a +group-relative name to the concrete form path: -_Note:_ make sure to use the latest version of the schema libraries as older versions might not support Standard Schema yet. +```ts +import { TanStackField, TanStackFormGroup } from '@tanstack/angular-form' +import type { FormGroupValidators } from '@tanstack/angular-form' -> Validation will not provide you with transformed values. See [submission handling](./submission-handling.md) for more information. +profileValidators = [ + { + triggers: [], + run: ({ value }: { value: { name: string } }) => + value.name.length >= 2 ? undefined : 'Enter a name', + }, +] satisfies FormGroupValidators<{ name: string }> -To use schemas from these libraries you can pass them to the `validators` props as you would do with a custom function: - -```angular-ts -import { z } from 'zod' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - - `, -}) -export class AppComponent { - form = injectForm({ - // ... - }) - - z = z - - // ... +submitGroup(event: SubmitEvent, group: { handleSubmit: () => unknown }) { + event.preventDefault() + void group.handleSubmit() } ``` -Async validations on form and field level are supported as well: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - +```html + +
    + + - `, -}) -export class AppComponent { - increaseAge = z.number().refine( - async (value) => { - const currentAge = await fetchCurrentAgeOnProfile() - return value >= currentAge - }, - { - message: 'You can only increase the age', - }, - ) - // ... -} + @for (error of profile.api.state.errors; track error) { + {{ error.message }} + } + +
    +
    ``` -If you need even more control over your Standard Schema validation, you can combine a Standard Schema with a callback function like so: - -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - - `, -}) -export class AppComponent { - ageValidator: FieldValidateAsyncFn = async ({ - value, - fieldApi, - }) => { - const errors = fieldApi.parseValueWithSchema( - z.number().gte(13, 'You must be 13 to make an account'), - ) - if (errors) return errors - - // continue with your validation - } - - // ... -} -``` +Import both directives in the standalone component. Use a Form Group for a +scoped section of one form; use reusable field mappings when a component must +work with different concrete field paths. -## Preventing invalid forms from being submitted +## Return errors from submission -The `onChange`, `onBlur` etc... callbacks are also run when the form is submitted and the submission is blocked if the form is invalid. +Endpoint validation belongs in `onSubmit`. Return +`createValidationError(...)` to feed server issues back into normal form state: -The form state object has a `canSubmit` flag that is false when any field is invalid and the form has been touched (`canSubmit` is true until the form has been touched, even if some fields are "technically" invalid based on their `onChange`/`onBlur` props). +```ts +form = injectForm({ + defaultValues: { email: '' }, + onSubmit: async ({ value, createValidationError }) => { + const result = await saveProfile(value) -You can subscribe to it via `injectStore` and use the value in order to, for example, disable the submit button when the form is invalid (in practice, disabled buttons are not accessible, use `aria-disabled` instead). + if (!result.ok) { + return createValidationError({ + form: 'Could not save the profile', + fields: { email: 'This email is already registered' }, + }) + } -```angular-ts -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` - - - `, + return null + }, }) -export class AppComponent { - canSubmit = injectStore(this.form, (state) => state.canSubmit) - isSubmitting = injectStore(this.form, (state) => state.isSubmitting) +``` - // ... -} +## Prevent invalid submission + +`form.handleSubmit()` skips `onSubmit` when validation fails and resolves with +the validation errors. `onSubmitInvalid` is currently available on form +groups; root-form support is planned but not yet implemented. Select +`canSubmit` and `isSubmitting` as Angular signals to reflect that state in the +submit UI: + +```ts +canSubmit = injectSelector(this.form, (state) => state.canSubmit) +isSubmitting = injectSelector(this.form, (state) => state.isSubmitting) +``` + +```html + ``` -To prevent the form from being submitted before any interaction, combine `canSubmit` with `isPristine` flags. A simple condition like `!canSubmit || isPristine` effectively disables submissions until the user has made changes. +If a disabled submit button would hide useful validation feedback, keep it +focusable with `aria-disabled` and let `handleSubmit()` report the issues. diff --git a/docs/framework/angular/quick-start.md b/docs/framework/angular/quick-start.md index ac6879f281..d81805c3ac 100644 --- a/docs/framework/angular/quick-start.md +++ b/docs/framework/angular/quick-start.md @@ -3,53 +3,127 @@ id: quick-start title: Quick Start --- -The bare minimum to get started with TanStack Form is to create a form and add a field. Keep in mind that this example does not include any validation or error handling... yet. +TanStack Form is a headless, type-safe form library. It owns form state and +validation while leaving markup, styling, and component choice to you. -```angular-ts -import { Component } from '@angular/core' -import { bootstrapApplication } from '@angular/platform-browser' -import { TanStackField, injectForm } from '@tanstack/angular-form' +Install the Angular adapter: + +```bash +npm install @tanstack/angular-form +``` + +## Create a form + +`injectForm` requires `defaultValues`. Their shape becomes the form's inferred +value type. Call it in an Angular injection context, such as a component field +initializer. + +```ts +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { + TanStackField, + injectForm, + injectSelector, +} from '@tanstack/angular-form' @Component({ - selector: 'app-root', + selector: 'app-profile-form', standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, imports: [TanStackField], template: `
    -
    - - + + + + + + -
    - + + + +
    `, }) -export class AppComponent { +export class ProfileFormComponent { + fullNameValidators = [ + { + triggers: ['change', 'blur'] as const, + run: ({ value }: { value: string }) => + value.trim() ? undefined : 'Enter your full name', + }, + ] + + ageValidators = [ + { + triggers: ['change'] as const, + run: ({ value }: { value: number }) => + value >= 13 ? undefined : 'You must be at least 13', + }, + ] + form = injectForm({ defaultValues: { fullName: '', + age: 0, }, - onSubmit({ value }) { - // Do something with form data + onSubmit: async ({ value }) => { console.log(value) }, }) + canSubmit = injectSelector(this.form, (state) => state.canSubmit) + isSubmitting = injectSelector(this.form, (state) => state.isSubmitting) + handleSubmit(event: SubmitEvent) { event.preventDefault() - event.stopPropagation() - this.form.handleSubmit() + void this.form.handleSubmit() } } - -bootstrapApplication(AppComponent).catch((err) => console.error(err)) ``` -From here, you'll be ready to explore all of the other features of TanStack Form! +The important pieces are: + +- `defaultValues` define the complete initial value and drive type inference. +- `TanStackField` turns an element or `ng-container` with `[tanstackField]` + into a field directive. The exported `field` reference exposes `api.value`, + `api.meta`, and event handlers. +- Validators are ordered objects with a `run` function and explicit + `triggers`. +- `injectSelector` creates an Angular signal for selected form state without + making unrelated fields rerender. +- `form.handleSubmit()` validates the form before calling `onSubmit`. diff --git a/docs/framework/angular/reference/classes/TanStackAppArrayField.md b/docs/framework/angular/reference/classes/TanStackAppArrayField.md new file mode 100644 index 0000000000..2f0782fcee --- /dev/null +++ b/docs/framework/angular/reference/classes/TanStackAppArrayField.md @@ -0,0 +1,189 @@ +--- +id: TanStackAppArrayField +title: TanStackAppArrayField +--- + +Defined in: [app-field.ts:37](https://github.com/TanStack/form/blob/main/packages/angular-form/src/app-field.ts#L37) + +## Extends + +- [`TanStackArrayField`](TanStackArrayField.md)\<`TSource`, `TFieldName`, `TFieldValue`, `TFieldValidators`\> + +## Type Parameters + +### TSource + +`TSource` *extends* [`AngularFieldSource`](../type-aliases/AngularFieldSource.md) + +### TFieldName + +`TFieldName` *extends* `DeepKeys`\<[`AngularFieldData`](../type-aliases/AngularFieldData.md)\<`TSource`\>\> + +### TFieldValue + +`TFieldValue` *extends* `DeepValue`\<[`AngularFieldData`](../type-aliases/AngularFieldData.md)\<`TSource`\>, `TFieldName`\> + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<[`AngularFieldData`](../type-aliases/AngularFieldData.md)\<`TSource`\>, `TFieldName`, `TFieldValue`\> + +## Constructors + +### Constructor + +```ts +new TanStackAppArrayField(): TanStackAppArrayField; +``` + +Defined in: [app-field.ts:56](https://github.com/TanStack/form/blob/main/packages/angular-form/src/app-field.ts#L56) + +#### Returns + +`TanStackAppArrayField`\<`TSource`, `TFieldName`, `TFieldValue`, `TFieldValidators`\> + +#### Overrides + +[`TanStackArrayField`](TanStackArrayField.md).[`constructor`](TanStackArrayField.md#constructor) + +## Properties + +### errorBoundary + +```ts +errorBoundary: InputSignal; +``` + +Defined in: [tanstack-field.ts:152](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L152) + +#### Inherited from + +[`TanStackArrayField`](TanStackArrayField.md).[`errorBoundary`](TanStackArrayField.md#errorboundary) + +*** + +### errorVisibility + +```ts +errorVisibility: InputSignal< + | ErrorVisibility, AngularSourceFormErrorTypes> +| undefined>; +``` + +Defined in: [tanstack-field.ts:145](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L145) + +#### Inherited from + +[`TanStackArrayField`](TanStackArrayField.md).[`errorVisibility`](TanStackArrayField.md#errorvisibility) + +*** + +### isArrayField + +```ts +protected readonly isArrayField: true = true; +``` + +Defined in: [tanstack-field.ts:298](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L298) + +#### Inherited from + +[`TanStackArrayField`](TanStackArrayField.md).[`isArrayField`](TanStackArrayField.md#isarrayfield) + +*** + +### listeners + +```ts +listeners: InputSignal< + | NoInfer, TFieldName, TFieldValue, FallbackToValidationIssue< + | ExtractValidatorFieldError> + | ExtractFormFieldError> + | unknown extends AngularSourceGroupFieldError ? never : AngularSourceGroupFieldError>, AngularParentFormData, AngularSourceFormErrorTypes>> +| undefined>; +``` + +Defined in: [tanstack-field.ts:128](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L128) + +#### Inherited from + +[`TanStackArrayField`](TanStackArrayField.md).[`listeners`](TanStackArrayField.md#listeners) + +*** + +### name + +```ts +name: InputSignal; +``` + +Defined in: [tanstack-field.ts:126](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L126) + +#### Inherited from + +[`TanStackArrayField`](TanStackArrayField.md).[`name`](TanStackArrayField.md#name) + +*** + +### tanstackArrayField + +```ts +tanstackArrayField: InputSignal; +``` + +Defined in: [tanstack-field.ts:297](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L297) + +#### Inherited from + +[`TanStackArrayField`](TanStackArrayField.md).[`tanstackArrayField`](TanStackArrayField.md#tanstackarrayfield) + +*** + +### validators + +```ts +validators: InputSignal | undefined>; +``` + +Defined in: [tanstack-field.ts:127](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L127) + +#### Inherited from + +[`TanStackArrayField`](TanStackArrayField.md).[`validators`](TanStackArrayField.md#validators) + +## Accessors + +### api + +#### Get Signature + +```ts +get api(): AngularSourceFieldApi; +``` + +Defined in: [tanstack-field.ts:190](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L190) + +##### Returns + +`AngularSourceFieldApi`\<`TSource`, `TFieldName`, `TFieldValue`, `TFieldValidators`\> + +#### Inherited from + +[`TanStackArrayField`](TanStackArrayField.md).[`api`](TanStackArrayField.md#api) + +## Methods + +### getSource() + +```ts +protected getSource(): TSource; +``` + +Defined in: [tanstack-field.ts:299](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L299) + +#### Returns + +`TSource` + +#### Inherited from + +[`TanStackArrayField`](TanStackArrayField.md).[`getSource`](TanStackArrayField.md#getsource) diff --git a/docs/framework/angular/reference/classes/TanStackAppField.md b/docs/framework/angular/reference/classes/TanStackAppField.md index 90f93ebd16..9dfb03bbb0 100644 --- a/docs/framework/angular/reference/classes/TanStackAppField.md +++ b/docs/framework/angular/reference/classes/TanStackAppField.md @@ -3,121 +3,43 @@ id: TanStackAppField title: TanStackAppField --- -# Class: TanStackAppField\ - -Defined in: [angular-form/src/app-field.ts:20](https://github.com/TanStack/form/blob/main/packages/angular-form/src/app-field.ts#L20) +Defined in: [app-field.ts:12](https://github.com/TanStack/form/blob/main/packages/angular-form/src/app-field.ts#L12) ## Extends -- [`TanStackField`](TanStackField.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> +- [`TanStackField`](TanStackField.md)\<`TSource`, `TFieldName`, `TFieldValue`, `TFieldValidators`\> ## Type Parameters -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +### TSource -### TFormOnBlur +`TSource` *extends* [`AngularFieldSource`](../type-aliases/AngularFieldSource.md) -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +### TFieldName -### TFormOnBlurAsync +`TFieldName` *extends* `DeepKeys`\<[`AngularFieldData`](../type-aliases/AngularFieldData.md)\<`TSource`\>\> -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +### TFieldValue -### TFormOnSubmit +`TFieldValue` *extends* `DeepValue`\<[`AngularFieldData`](../type-aliases/AngularFieldData.md)\<`TSource`\>, `TFieldName`\> -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +### TFieldValidators -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TSubmitMeta - -`TSubmitMeta` +`TFieldValidators` *extends* `FieldValidators`\<[`AngularFieldData`](../type-aliases/AngularFieldData.md)\<`TSource`\>, `TFieldName`, `TFieldValue`\> ## Constructors ### Constructor ```ts -new TanStackAppField(): TanStackAppField; +new TanStackAppField(): TanStackAppField; ``` -Defined in: [angular-form/src/app-field.ts:79](https://github.com/TanStack/form/blob/main/packages/angular-form/src/app-field.ts#L79) +Defined in: [app-field.ts:26](https://github.com/TanStack/form/blob/main/packages/angular-form/src/app-field.ts#L26) #### Returns -`TanStackAppField`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> +`TanStackAppField`\<`TSource`, `TFieldName`, `TFieldValue`, `TFieldValidators`\> #### Overrides @@ -125,127 +47,47 @@ Defined in: [angular-form/src/app-field.ts:79](https://github.com/TanStack/form/ ## Properties -### \_api - -```ts -_api: Signal>; -``` - -Defined in: [angular-form/src/tanstack-field.ts:150](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L150) - -#### Inherited from - -[`TanStackField`](TanStackField.md).[`_api`](TanStackField.md#_api) - -*** - -### asyncAlways - -```ts -asyncAlways: InputSignalWithTransform; -``` - -Defined in: [angular-form/src/tanstack-field.ts:75](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L75) - -#### Inherited from - -[`TanStackField`](TanStackField.md).[`asyncAlways`](TanStackField.md#asyncalways) - -*** - -### asyncDebounceMs +### errorBoundary ```ts -asyncDebounceMs: InputSignalWithTransform; +errorBoundary: InputSignal; ``` -Defined in: [angular-form/src/tanstack-field.ts:72](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L72) +Defined in: [tanstack-field.ts:152](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L152) #### Inherited from -[`TanStackField`](TanStackField.md).[`asyncDebounceMs`](TanStackField.md#asyncdebouncems) +[`TanStackField`](TanStackField.md).[`errorBoundary`](TanStackField.md#errorboundary) *** -### base +### errorVisibility ```ts -base: TanStackFieldInjectable; -``` - -Defined in: [angular-form/src/app-field.ts:77](https://github.com/TanStack/form/blob/main/packages/angular-form/src/app-field.ts#L77) - -*** - -### cd - -```ts -cd: ChangeDetectorRef; -``` - -Defined in: [angular-form/src/tanstack-field.ts:237](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L237) - -#### Inherited from - -[`TanStackField`](TanStackField.md).[`cd`](TanStackField.md#cd) - -*** - -### defaultMeta - -```ts -defaultMeta: InputSignal< - | Partial> +errorVisibility: InputSignal< + | ErrorVisibility, AngularSourceFormErrorTypes> | undefined>; ``` -Defined in: [angular-form/src/tanstack-field.ts:117](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L117) +Defined in: [tanstack-field.ts:145](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L145) #### Inherited from -[`TanStackField`](TanStackField.md).[`defaultMeta`](TanStackField.md#defaultmeta) +[`TanStackField`](TanStackField.md).[`errorVisibility`](TanStackField.md#errorvisibility) *** -### defaultValue +### isArrayField ```ts -defaultValue: InputSignal | undefined>; +protected readonly isArrayField: false = false; ``` -Defined in: [angular-form/src/tanstack-field.ts:71](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L71) +Defined in: [tanstack-field.ts:271](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L271) #### Inherited from -[`TanStackField`](TanStackField.md).[`defaultValue`](TanStackField.md#defaultvalue) - -*** - -### disableErrorFlat - -```ts -disableErrorFlat: InputSignal; -``` - -Defined in: [angular-form/src/tanstack-field.ts:148](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L148) - -#### Inherited from - -[`TanStackField`](TanStackField.md).[`disableErrorFlat`](TanStackField.md#disableerrorflat) - -*** - -### injector - -```ts -injector: Injector; -``` - -Defined in: [angular-form/src/tanstack-field.ts:221](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L221) - -#### Inherited from - -[`TanStackField`](TanStackField.md).[`injector`](TanStackField.md#injector) +[`TanStackField`](TanStackField.md).[`isArrayField`](TanStackField.md#isarrayfield) *** @@ -253,11 +95,14 @@ Defined in: [angular-form/src/tanstack-field.ts:221](https://github.com/TanStack ```ts listeners: InputSignal< - | NoInfer> + | NoInfer, TFieldName, TFieldValue, FallbackToValidationIssue< + | ExtractValidatorFieldError> + | ExtractFormFieldError> + | unknown extends AngularSourceGroupFieldError ? never : AngularSourceGroupFieldError>, AngularParentFormData, AngularSourceFormErrorTypes>> | undefined>; ``` -Defined in: [angular-form/src/tanstack-field.ts:116](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L116) +Defined in: [tanstack-field.ts:128](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L128) #### Inherited from @@ -265,27 +110,13 @@ Defined in: [angular-form/src/tanstack-field.ts:116](https://github.com/TanStack *** -### mode - -```ts -mode: InputSignal<"value" | "array" | undefined>; -``` - -Defined in: [angular-form/src/tanstack-field.ts:146](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L146) - -#### Inherited from - -[`TanStackField`](TanStackField.md).[`mode`](TanStackField.md#mode) - -*** - ### name ```ts -name: InputSignal; +name: InputSignal; ``` -Defined in: [angular-form/src/tanstack-field.ts:70](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L70) +Defined in: [tanstack-field.ts:126](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L126) #### Inherited from @@ -293,27 +124,13 @@ Defined in: [angular-form/src/tanstack-field.ts:70](https://github.com/TanStack/ *** -### options - -```ts -options: Signal>; -``` - -Defined in: [angular-form/src/tanstack-field.ts:182](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L182) - -#### Inherited from - -[`TanStackField`](TanStackField.md).[`options`](TanStackField.md#options) - -*** - ### tanstackField ```ts -tanstackField: InputSignal>; +tanstackField: InputSignal; ``` -Defined in: [angular-form/src/tanstack-field.ts:78](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L78) +Defined in: [tanstack-field.ts:270](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L270) #### Inherited from @@ -324,12 +141,10 @@ Defined in: [angular-form/src/tanstack-field.ts:78](https://github.com/TanStack/ ### validators ```ts -validators: InputSignal< - | NoInfer> -| undefined>; +validators: InputSignal | undefined>; ``` -Defined in: [angular-form/src/tanstack-field.ts:96](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L96) +Defined in: [tanstack-field.ts:127](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L127) #### Inherited from @@ -342,14 +157,14 @@ Defined in: [angular-form/src/tanstack-field.ts:96](https://github.com/TanStack/ #### Get Signature ```ts -get api(): FieldApi; +get api(): AngularSourceFieldApi; ``` -Defined in: [angular-form/src/tanstack-field.ts:154](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L154) +Defined in: [tanstack-field.ts:190](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L190) ##### Returns -`FieldApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> +`AngularSourceFieldApi`\<`TSource`, `TFieldName`, `TFieldValue`, `TFieldValidators`\> #### Inherited from @@ -357,24 +172,18 @@ Defined in: [angular-form/src/tanstack-field.ts:154](https://github.com/TanStack ## Methods -### ngOnInit() +### getSource() ```ts -ngOnInit(): void; +protected getSource(): TSource; ``` -Defined in: [angular-form/src/tanstack-field.ts:239](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L239) - -A callback method that is invoked immediately after the -default change detector has checked the directive's -data-bound properties for the first time, -and before any of the view or content children have been checked. -It is invoked only once when the directive is instantiated. +Defined in: [tanstack-field.ts:272](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L272) #### Returns -`void` +`TSource` #### Inherited from -[`TanStackField`](TanStackField.md).[`ngOnInit`](TanStackField.md#ngoninit) +[`TanStackField`](TanStackField.md).[`getSource`](TanStackField.md#getsource) diff --git a/docs/framework/angular/reference/classes/TanStackArrayField.md b/docs/framework/angular/reference/classes/TanStackArrayField.md new file mode 100644 index 0000000000..4899d0311e --- /dev/null +++ b/docs/framework/angular/reference/classes/TanStackArrayField.md @@ -0,0 +1,212 @@ +--- +id: TanStackArrayField +title: TanStackArrayField +--- + +Defined in: [tanstack-field.ts:282](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L282) + +## Extends + +- `TanStackFieldBase`\<`TSource`, `TFieldName`, `TFieldValue`, `TFieldValidators`\> + +## Extended by + +- [`TanStackAppArrayField`](TanStackAppArrayField.md) + +## Type Parameters + +### TSource + +`TSource` *extends* [`AngularFieldSource`](../type-aliases/AngularFieldSource.md) + +### TFieldName + +`TFieldName` *extends* `DeepKeys`\<[`AngularFieldData`](../type-aliases/AngularFieldData.md)\<`TSource`\>\> + +### TFieldValue + +`TFieldValue` *extends* `DeepValue`\<[`AngularFieldData`](../type-aliases/AngularFieldData.md)\<`TSource`\>, `TFieldName`\> + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<[`AngularFieldData`](../type-aliases/AngularFieldData.md)\<`TSource`\>, `TFieldName`, `TFieldValue`\> + +## Constructors + +### Constructor + +```ts +new TanStackArrayField(): TanStackArrayField; +``` + +Defined in: [tanstack-field.ts:201](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L201) + +#### Returns + +`TanStackArrayField`\<`TSource`, `TFieldName`, `TFieldValue`, `TFieldValidators`\> + +#### Inherited from + +```ts +TanStackFieldBase< + TSource, + TFieldName, + TFieldValue, + TFieldValidators +>.constructor +``` + +## Properties + +### errorBoundary + +```ts +errorBoundary: InputSignal; +``` + +Defined in: [tanstack-field.ts:152](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L152) + +#### Inherited from + +```ts +TanStackFieldBase.errorBoundary +``` + +*** + +### errorVisibility + +```ts +errorVisibility: InputSignal< + | ErrorVisibility, AngularSourceFormErrorTypes> +| undefined>; +``` + +Defined in: [tanstack-field.ts:145](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L145) + +#### Inherited from + +```ts +TanStackFieldBase.errorVisibility +``` + +*** + +### isArrayField + +```ts +protected readonly isArrayField: true = true; +``` + +Defined in: [tanstack-field.ts:298](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L298) + +#### Overrides + +```ts +TanStackFieldBase.isArrayField +``` + +*** + +### listeners + +```ts +listeners: InputSignal< + | NoInfer, TFieldName, TFieldValue, FallbackToValidationIssue< + | ExtractValidatorFieldError> + | ExtractFormFieldError> + | unknown extends AngularSourceGroupFieldError ? never : AngularSourceGroupFieldError>, AngularParentFormData, AngularSourceFormErrorTypes>> +| undefined>; +``` + +Defined in: [tanstack-field.ts:128](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L128) + +#### Inherited from + +```ts +TanStackFieldBase.listeners +``` + +*** + +### name + +```ts +name: InputSignal; +``` + +Defined in: [tanstack-field.ts:126](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L126) + +#### Inherited from + +```ts +TanStackFieldBase.name +``` + +*** + +### tanstackArrayField + +```ts +tanstackArrayField: InputSignal; +``` + +Defined in: [tanstack-field.ts:297](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L297) + +*** + +### validators + +```ts +validators: InputSignal | undefined>; +``` + +Defined in: [tanstack-field.ts:127](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L127) + +#### Inherited from + +```ts +TanStackFieldBase.validators +``` + +## Accessors + +### api + +#### Get Signature + +```ts +get api(): AngularSourceFieldApi; +``` + +Defined in: [tanstack-field.ts:190](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L190) + +##### Returns + +`AngularSourceFieldApi`\<`TSource`, `TFieldName`, `TFieldValue`, `TFieldValidators`\> + +#### Inherited from + +```ts +TanStackFieldBase.api +``` + +## Methods + +### getSource() + +```ts +protected getSource(): TSource; +``` + +Defined in: [tanstack-field.ts:299](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L299) + +#### Returns + +`TSource` + +#### Overrides + +```ts +TanStackFieldBase.getSource +``` diff --git a/docs/framework/angular/reference/classes/TanStackField.md b/docs/framework/angular/reference/classes/TanStackField.md index 745dd4d525..b3d8ec3c69 100644 --- a/docs/framework/angular/reference/classes/TanStackField.md +++ b/docs/framework/angular/reference/classes/TanStackField.md @@ -3,9 +3,11 @@ id: TanStackField title: TanStackField --- -# Class: TanStackField\ +Defined in: [tanstack-field.ts:255](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L255) -Defined in: [angular-form/src/tanstack-field.ts:37](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L37) +## Extends + +- `TanStackFieldBase`\<`TSource`, `TFieldName`, `TFieldValue`, `TFieldValidators`\> ## Extended by @@ -13,261 +15,159 @@ Defined in: [angular-form/src/tanstack-field.ts:37](https://github.com/TanStack/ ## Type Parameters -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic +### TSource -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +`TSource` *extends* [`AngularFieldSource`](../type-aliases/AngularFieldSource.md) -### TFormOnDynamicAsync +### TFieldName -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +`TFieldName` *extends* `DeepKeys`\<[`AngularFieldData`](../type-aliases/AngularFieldData.md)\<`TSource`\>\> -### TFormOnServer +### TFieldValue -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +`TFieldValue` *extends* `DeepValue`\<[`AngularFieldData`](../type-aliases/AngularFieldData.md)\<`TSource`\>, `TFieldName`\> -### TSubmitMeta +### TFieldValidators -`TSubmitMeta` - -## Implements - -- `OnInit` +`TFieldValidators` *extends* `FieldValidators`\<[`AngularFieldData`](../type-aliases/AngularFieldData.md)\<`TSource`\>, `TFieldName`, `TFieldValue`\> ## Constructors ### Constructor ```ts -new TanStackField(): TanStackField; +new TanStackField(): TanStackField; ``` -Defined in: [angular-form/src/tanstack-field.ts:223](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L223) +Defined in: [tanstack-field.ts:201](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L201) #### Returns -`TanStackField`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> - -## Properties - -### \_api - -```ts -_api: Signal>; -``` - -Defined in: [angular-form/src/tanstack-field.ts:150](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L150) - -*** +`TanStackField`\<`TSource`, `TFieldName`, `TFieldValue`, `TFieldValidators`\> -### asyncAlways +#### Inherited from ```ts -asyncAlways: InputSignalWithTransform; +TanStackFieldBase< + TSource, + TFieldName, + TFieldValue, + TFieldValidators +>.constructor ``` -Defined in: [angular-form/src/tanstack-field.ts:75](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L75) - -*** +## Properties -### asyncDebounceMs +### errorBoundary ```ts -asyncDebounceMs: InputSignalWithTransform; +errorBoundary: InputSignal; ``` -Defined in: [angular-form/src/tanstack-field.ts:72](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L72) - -*** +Defined in: [tanstack-field.ts:152](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L152) -### cd +#### Inherited from ```ts -cd: ChangeDetectorRef; +TanStackFieldBase.errorBoundary ``` -Defined in: [angular-form/src/tanstack-field.ts:237](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L237) - *** -### defaultMeta +### errorVisibility ```ts -defaultMeta: InputSignal< - | Partial> +errorVisibility: InputSignal< + | ErrorVisibility, AngularSourceFormErrorTypes> | undefined>; ``` -Defined in: [angular-form/src/tanstack-field.ts:117](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L117) +Defined in: [tanstack-field.ts:145](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L145) -*** - -### defaultValue +#### Inherited from ```ts -defaultValue: InputSignal | undefined>; +TanStackFieldBase.errorVisibility ``` -Defined in: [angular-form/src/tanstack-field.ts:71](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L71) - *** -### disableErrorFlat +### isArrayField ```ts -disableErrorFlat: InputSignal; +protected readonly isArrayField: false = false; ``` -Defined in: [angular-form/src/tanstack-field.ts:148](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L148) +Defined in: [tanstack-field.ts:271](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L271) -*** - -### injector +#### Overrides ```ts -injector: Injector; +TanStackFieldBase.isArrayField ``` -Defined in: [angular-form/src/tanstack-field.ts:221](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L221) - *** ### listeners ```ts listeners: InputSignal< - | NoInfer> + | NoInfer, TFieldName, TFieldValue, FallbackToValidationIssue< + | ExtractValidatorFieldError> + | ExtractFormFieldError> + | unknown extends AngularSourceGroupFieldError ? never : AngularSourceGroupFieldError>, AngularParentFormData, AngularSourceFormErrorTypes>> | undefined>; ``` -Defined in: [angular-form/src/tanstack-field.ts:116](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L116) - -*** +Defined in: [tanstack-field.ts:128](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L128) -### mode +#### Inherited from ```ts -mode: InputSignal<"value" | "array" | undefined>; +TanStackFieldBase.listeners ``` -Defined in: [angular-form/src/tanstack-field.ts:146](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L146) - *** ### name ```ts -name: InputSignal; +name: InputSignal; ``` -Defined in: [angular-form/src/tanstack-field.ts:70](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L70) - -*** +Defined in: [tanstack-field.ts:126](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L126) -### options +#### Inherited from ```ts -options: Signal>; +TanStackFieldBase.name ``` -Defined in: [angular-form/src/tanstack-field.ts:182](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L182) - *** ### tanstackField ```ts -tanstackField: InputSignal>; +tanstackField: InputSignal; ``` -Defined in: [angular-form/src/tanstack-field.ts:78](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L78) +Defined in: [tanstack-field.ts:270](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L270) *** ### validators ```ts -validators: InputSignal< - | NoInfer> -| undefined>; +validators: InputSignal | undefined>; ``` -Defined in: [angular-form/src/tanstack-field.ts:96](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L96) +Defined in: [tanstack-field.ts:127](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L127) + +#### Inherited from + +```ts +TanStackFieldBase.validators +``` ## Accessors @@ -276,37 +176,37 @@ Defined in: [angular-form/src/tanstack-field.ts:96](https://github.com/TanStack/ #### Get Signature ```ts -get api(): FieldApi; +get api(): AngularSourceFieldApi; ``` -Defined in: [angular-form/src/tanstack-field.ts:154](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L154) +Defined in: [tanstack-field.ts:190](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L190) ##### Returns -`FieldApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> +`AngularSourceFieldApi`\<`TSource`, `TFieldName`, `TFieldValue`, `TFieldValidators`\> + +#### Inherited from + +```ts +TanStackFieldBase.api +``` ## Methods -### ngOnInit() +### getSource() ```ts -ngOnInit(): void; +protected getSource(): TSource; ``` -Defined in: [angular-form/src/tanstack-field.ts:239](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L239) - -A callback method that is invoked immediately after the -default change detector has checked the directive's -data-bound properties for the first time, -and before any of the view or content children have been checked. -It is invoked only once when the directive is instantiated. +Defined in: [tanstack-field.ts:272](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L272) #### Returns -`void` +`TSource` -#### Implementation of +#### Overrides ```ts -OnInit.ngOnInit +TanStackFieldBase.getSource ``` diff --git a/docs/framework/angular/reference/classes/TanStackFieldInjectable.md b/docs/framework/angular/reference/classes/TanStackFieldInjectable.md index af4a590a1c..46885566c2 100644 --- a/docs/framework/angular/reference/classes/TanStackFieldInjectable.md +++ b/docs/framework/angular/reference/classes/TanStackFieldInjectable.md @@ -3,37 +3,51 @@ id: TanStackFieldInjectable title: TanStackFieldInjectable --- -# Class: TanStackFieldInjectable\ - -Defined in: [angular-form/src/injectable.ts:5](https://github.com/TanStack/form/blob/main/packages/angular-form/src/injectable.ts#L5) +Defined in: [injectable.ts:5](https://github.com/TanStack/form/blob/main/packages/angular-form/src/injectable.ts#L5) ## Type Parameters -### T +### TFieldValue + +`TFieldValue` + +### TFieldName + +`TFieldName` = `any` + +### TFieldError + +`TFieldError` = `any` + +### TFormData + +`TFormData` = `any` + +### TFormErrorTypes -`T` +`TFormErrorTypes` *extends* `FormErrorTypes` = `any` ## Constructors ### Constructor ```ts -new TanStackFieldInjectable(): TanStackFieldInjectable; +new TanStackFieldInjectable(): TanStackFieldInjectable; ``` #### Returns -`TanStackFieldInjectable`\<`T`\> +`TanStackFieldInjectable`\<`TFieldValue`, `TFieldName`, `TFieldError`, `TFormData`, `TFormErrorTypes`\> ## Properties ### \_api ```ts -_api: WritableSignal>; +_api: WritableSignal>; ``` -Defined in: [angular-form/src/injectable.ts:6](https://github.com/TanStack/form/blob/main/packages/angular-form/src/injectable.ts#L6) +Defined in: [injectable.ts:12](https://github.com/TanStack/form/blob/main/packages/angular-form/src/injectable.ts#L12) ## Accessors @@ -42,11 +56,11 @@ Defined in: [angular-form/src/injectable.ts:6](https://github.com/TanStack/form/ #### Get Signature ```ts -get api(): FieldApi; +get api(): FieldApi; ``` -Defined in: [angular-form/src/injectable.ts:34](https://github.com/TanStack/form/blob/main/packages/angular-form/src/injectable.ts#L34) +Defined in: [injectable.ts:16](https://github.com/TanStack/form/blob/main/packages/angular-form/src/injectable.ts#L16) ##### Returns -`FieldApi`\<`any`, `any`, `T`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`\> +`FieldApi`\<`TFieldName`, `TFieldValue`, `TFieldError`, `TFormData`, `TFormErrorTypes`\> diff --git a/docs/framework/angular/reference/classes/TanStackFormGroup.md b/docs/framework/angular/reference/classes/TanStackFormGroup.md index 5bf2ad8861..f8f44341a5 100644 --- a/docs/framework/angular/reference/classes/TanStackFormGroup.md +++ b/docs/framework/angular/reference/classes/TanStackFormGroup.md @@ -3,319 +3,99 @@ id: TanStackFormGroup title: TanStackFormGroup --- -# Class: TanStackFormGroup\ - -Defined in: [angular-form/src/tanstack-form-group.ts:34](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L34) +Defined in: [form-group.ts:25](https://github.com/TanStack/form/blob/main/packages/angular-form/src/form-group.ts#L25) ## Type Parameters -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TSubmitMeta - -`TSubmitMeta` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit +### TFormData -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +`TFormData` -### TFormOnSubmitAsync +### TGroupName -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +`TGroupName` *extends* `DeepKeys`\<`TFormData`\> -### TFormOnDynamic +### TGroupValue -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +`TGroupValue` *extends* `DeepValue`\<`TFormData`, `TGroupName`\> -### TFormOnDynamicAsync +### TGroupValidators -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +`TGroupValidators` *extends* `FormGroupValidators`\<`TGroupValue`\> -### TFormOnServer +### TFormValidators -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> -### TParentSubmitMeta +### TSubmitReturn -`TParentSubmitMeta` - -## Implements - -- `OnInit` +`TSubmitReturn` ## Constructors ### Constructor ```ts -new TanStackFormGroup(): TanStackFormGroup; +new TanStackFormGroup(): TanStackFormGroup; ``` -Defined in: [angular-form/src/tanstack-form-group.ts:303](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L303) +Defined in: [form-group.ts:84](https://github.com/TanStack/form/blob/main/packages/angular-form/src/form-group.ts#L84) #### Returns -`TanStackFormGroup`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> +`TanStackFormGroup`\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupValidators`, `TFormValidators`, `TSubmitReturn`\> ## Properties -### \_api - -```ts -_api: Signal>; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:224](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L224) - -*** - -### asyncAlways - -```ts -asyncAlways: InputSignalWithTransform; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:79](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L79) - -*** - -### asyncDebounceMs - -```ts -asyncDebounceMs: InputSignalWithTransform; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:76](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L76) - -*** - -### canSubmitWhenInvalid - -```ts -canSubmitWhenInvalid: InputSignalWithTransform; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:82](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L82) - -*** - -### cd - -```ts -cd: ChangeDetectorRef; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:317](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L317) - -*** - -### defaultMeta - -```ts -defaultMeta: InputSignal< - | Partial> -| undefined>; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:125](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L125) - -*** - -### defaultState - -```ts -defaultState: InputSignal | undefined>; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:154](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L154) - -*** - -### defaultValue - -```ts -defaultValue: InputSignal | undefined>; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:75](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L75) - -*** - -### injector - -```ts -injector: Injector; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:301](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L301) - -*** - -### listeners - -```ts -listeners: InputSignal< - | NoInfer> -| undefined>; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:123](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L123) - -*** - -### mode - -```ts -mode: InputSignal<"value" | "array" | undefined>; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:222](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L222) - -*** - ### name ```ts -name: InputSignal; +name: InputSignal; ``` -Defined in: [angular-form/src/tanstack-form-group.ts:74](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L74) +Defined in: [form-group.ts:35](https://github.com/TanStack/form/blob/main/packages/angular-form/src/form-group.ts#L35) *** -### onGroupSubmit +### onSubmit ```ts -onGroupSubmit: InputSignal any | undefined> | undefined>; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:158](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L158) - -*** - -### onGroupSubmitInvalid - -```ts -onGroupSubmitInvalid: InputSignal void | undefined> | undefined>; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:190](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L190) - -*** - -### onSubmitMeta - -```ts -onSubmitMeta: InputSignal | undefined>; +onSubmit: InputSignal< + | FormGroupSubmitFn> +| undefined>; ``` -Defined in: [angular-form/src/tanstack-form-group.ts:156](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L156) +Defined in: [form-group.ts:37](https://github.com/TanStack/form/blob/main/packages/angular-form/src/form-group.ts#L37) *** -### options +### onSubmitInvalid ```ts -options: Signal>; +onSubmitInvalid: InputSignal<((context) => void | Promise) | undefined>; ``` -Defined in: [angular-form/src/tanstack-form-group.ts:257](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L257) +Defined in: [form-group.ts:47](https://github.com/TanStack/form/blob/main/packages/angular-form/src/form-group.ts#L47) *** ### tanstackFormGroup ```ts -tanstackFormGroup: InputSignal>; +tanstackFormGroup: InputSignal>; ``` -Defined in: [angular-form/src/tanstack-form-group.ts:85](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L85) +Defined in: [form-group.ts:33](https://github.com/TanStack/form/blob/main/packages/angular-form/src/form-group.ts#L33) *** ### validators ```ts -validators: InputSignal< - | NoInfer> -| undefined>; +validators: InputSignal | undefined>; ``` -Defined in: [angular-form/src/tanstack-form-group.ts:103](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L103) +Defined in: [form-group.ts:36](https://github.com/TanStack/form/blob/main/packages/angular-form/src/form-group.ts#L36) ## Accessors @@ -324,37 +104,11 @@ Defined in: [angular-form/src/tanstack-form-group.ts:103](https://github.com/Tan #### Get Signature ```ts -get api(): FormGroupApi; +get api(): InternalFormGroupApi>; ``` -Defined in: [angular-form/src/tanstack-form-group.ts:228](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L228) +Defined in: [form-group.ts:77](https://github.com/TanStack/form/blob/main/packages/angular-form/src/form-group.ts#L77) ##### Returns -`FormGroupApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Methods - -### ngOnInit() - -```ts -ngOnInit(): void; -``` - -Defined in: [angular-form/src/tanstack-form-group.ts:319](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-form-group.ts#L319) - -A callback method that is invoked immediately after the -default change detector has checked the directive's -data-bound properties for the first time, -and before any of the view or content children have been checked. -It is invoked only once when the directive is instantiated. - -#### Returns - -`void` - -#### Implementation of - -```ts -OnInit.ngOnInit -``` +`InternalFormGroupApi`\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupValidators`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>\> diff --git a/docs/framework/angular/reference/classes/TanStackWithForm.md b/docs/framework/angular/reference/classes/TanStackWithForm.md deleted file mode 100644 index 596d998b4a..0000000000 --- a/docs/framework/angular/reference/classes/TanStackWithForm.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -id: TanStackWithForm -title: TanStackWithForm ---- - -# Class: TanStackWithForm\ - -Defined in: [angular-form/src/with-form.ts:14](https://github.com/TanStack/form/blob/main/packages/angular-form/src/with-form.ts#L14) - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` - -## Constructors - -### Constructor - -```ts -new TanStackWithForm(): TanStackWithForm; -``` - -Defined in: [angular-form/src/with-form.ts:48](https://github.com/TanStack/form/blob/main/packages/angular-form/src/with-form.ts#L48) - -#### Returns - -`TanStackWithForm`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -## Properties - -### base - -```ts -base: TanStackWithFormInjectable; -``` - -Defined in: [angular-form/src/with-form.ts:46](https://github.com/TanStack/form/blob/main/packages/angular-form/src/with-form.ts#L46) - -*** - -### form - -```ts -form: InputSignal>; -``` - -Defined in: [angular-form/src/with-form.ts:28](https://github.com/TanStack/form/blob/main/packages/angular-form/src/with-form.ts#L28) diff --git a/docs/framework/angular/reference/classes/TanStackWithFormInjectable.md b/docs/framework/angular/reference/classes/TanStackWithFormInjectable.md deleted file mode 100644 index ee7a312dc4..0000000000 --- a/docs/framework/angular/reference/classes/TanStackWithFormInjectable.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -id: TanStackWithFormInjectable -title: TanStackWithFormInjectable ---- - -# Class: TanStackWithFormInjectable - -Defined in: [angular-form/src/with-form-injectable.ts:10](https://github.com/TanStack/form/blob/main/packages/angular-form/src/with-form-injectable.ts#L10) - -## Constructors - -### Constructor - -```ts -new TanStackWithFormInjectable(): TanStackWithFormInjectable; -``` - -#### Returns - -`TanStackWithFormInjectable` - -## Properties - -### \_form - -```ts -_form: WritableSignal>; -``` - -Defined in: [angular-form/src/with-form-injectable.ts:11](https://github.com/TanStack/form/blob/main/packages/angular-form/src/with-form-injectable.ts#L11) diff --git a/docs/framework/angular/reference/functions/injectField.md b/docs/framework/angular/reference/functions/injectField.md index 913d8d5df9..cf11ea4b3f 100644 --- a/docs/framework/angular/reference/functions/injectField.md +++ b/docs/framework/angular/reference/functions/injectField.md @@ -3,20 +3,20 @@ id: injectField title: injectField --- -# Function: injectField() - ```ts -function injectField(): TanStackFieldInjectable; +function injectField(): TanStackFieldInjectable; ``` -Defined in: [angular-form/src/injectable.ts:39](https://github.com/TanStack/form/blob/main/packages/angular-form/src/injectable.ts#L39) +Defined in: [injectable.ts:22](https://github.com/TanStack/form/blob/main/packages/angular-form/src/injectable.ts#L22) + +Injects the field provided by an ancestor `tanstack-app-field` directive. ## Type Parameters -### T +### TFieldValue -`T` +`TFieldValue` ## Returns -[`TanStackFieldInjectable`](../classes/TanStackFieldInjectable.md)\<`T`\> +[`TanStackFieldInjectable`](../classes/TanStackFieldInjectable.md)\<`TFieldValue`\> diff --git a/docs/framework/angular/reference/functions/injectForm.md b/docs/framework/angular/reference/functions/injectForm.md index 7c1c94143b..807a2c8258 100644 --- a/docs/framework/angular/reference/functions/injectForm.md +++ b/docs/framework/angular/reference/functions/injectForm.md @@ -3,70 +3,68 @@ id: injectForm title: injectForm --- -# Function: injectForm() - ```ts -function injectForm(opts?): FormApi; +function injectForm(options): InternalFormApi; ``` -Defined in: [angular-form/src/inject-form.ts:9](https://github.com/TanStack/form/blob/main/packages/angular-form/src/inject-form.ts#L9) - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` +Defined in: [inject-form.ts:38](https://github.com/TanStack/form/blob/main/packages/angular-form/src/inject-form.ts#L38) -### TOnChangeAsync +Creates and mounts a form in the current Angular injection context. -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` +`defaultValues` establish the initial state and inferred form value type. +Form state changes notify Angular change detection, including OnPush +components, and the form is cleaned up when the injection context is +destroyed. -### TOnBlur +Call this in a component field initializer, constructor, provider factory, +or another active injection context. -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlurAsync +## Type Parameters -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` +### TFormData -### TOnSubmit +`TFormData` -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` +Library-managed. Do not specify explicitly. -### TOnSubmitAsync +### TFormValidators -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> -### TOnDynamic +Library-managed. Do not specify explicitly. -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` +### TSubmitReturn -### TOnDynamicAsync +`TSubmitReturn` -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` +Library-managed. Do not specify explicitly. -### TOnServer +## Parameters -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` +### options -### TSubmitMeta +`FormOptions`\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\> -`TSubmitMeta` +The initial form options. `defaultValues` drive form value +inference. -## Parameters +## Returns -### opts? +`InternalFormApi`\<`TFormData`, `TFormValidators`, `TSubmitReturn`\> -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> +The mounted form API registered for injection-context cleanup. -## Returns +## Example -`FormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> +```ts +@Component({ + selector: 'app-profile-form', + template: `
    `, +}) +class ProfileFormComponent { + form = injectForm({ + defaultValues: { name: '' }, + onSubmit: ({ value }) => saveProfile(value), + }) +} +``` diff --git a/docs/framework/angular/reference/functions/injectSelector.md b/docs/framework/angular/reference/functions/injectSelector.md new file mode 100644 index 0000000000..49ad13be66 --- /dev/null +++ b/docs/framework/angular/reference/functions/injectSelector.md @@ -0,0 +1,47 @@ +--- +id: injectSelector +title: injectSelector +--- + +```ts +function injectSelector( + form, + selector?, +options?): Signal; +``` + +Defined in: [inject-selector.ts:7](https://github.com/TanStack/form/blob/main/packages/angular-form/src/inject-selector.ts#L7) + +Selects form state as an Angular signal. + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes`\<`ValidationIssue`, `ValidationIssue`\> + +### TSelected + +`TSelected` = `NoInfer`\<`FormState`\<`TFormData`, `TFormErrorTypes`\>\> + +## Parameters + +### form + +`FormApi`\<`TFormData`, `TFormErrorTypes`\> + +### selector? + +(`state`) => `TSelected` + +### options? + +`InjectSelectorOptions`\<`TSelected`\> + +## Returns + +`Signal`\<`TSelected`\> diff --git a/docs/framework/angular/reference/functions/injectStore.md b/docs/framework/angular/reference/functions/injectStore.md deleted file mode 100644 index 105329704f..0000000000 --- a/docs/framework/angular/reference/functions/injectStore.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -id: injectStore -title: injectStore ---- - -# Function: injectStore() - -```ts -function injectStore(form, selector?): Signal; -``` - -Defined in: [angular-form/src/inject-store.ts:9](https://github.com/TanStack/form/blob/main/packages/angular-form/src/inject-store.ts#L9) - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` - -### TSelected - -`TSelected` = `NoInfer`\<`FormState`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`\>\> - -## Parameters - -### form - -`FormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -### selector? - -(`state`) => `TSelected` - -## Returns - -`Signal`\<`TSelected`\> diff --git a/docs/framework/angular/reference/functions/injectWithForm.md b/docs/framework/angular/reference/functions/injectWithForm.md deleted file mode 100644 index 0b1fc50400..0000000000 --- a/docs/framework/angular/reference/functions/injectWithForm.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -id: injectWithForm -title: injectWithForm ---- - -# Function: injectWithForm() - -```ts -function injectWithForm(_opts?): TanStackWithFormRef; -``` - -Defined in: [angular-form/src/with-form-injectable.ts:59](https://github.com/TanStack/form/blob/main/packages/angular-form/src/with-form-injectable.ts#L59) - -Injects the form provided by an ancestor `[tanstack-with-form]` directive. - -Pass form options (typically the same options used to create the form) so -the returned `form` is typed correctly without needing to specify generics: - -```ts -const withForm = injectWithForm({ ...peopleFormOpts }) -withForm.form // FormApi -``` - -The options are only used for type inference and are not read at runtime. - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` - -## Parameters - -### \_opts? - -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -## Returns - -`TanStackWithFormRef`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> diff --git a/docs/framework/angular/reference/index.md b/docs/framework/angular/reference/index.md index c2b21c849c..978570ef5c 100644 --- a/docs/framework/angular/reference/index.md +++ b/docs/framework/angular/reference/index.md @@ -3,20 +3,25 @@ id: "@tanstack/angular-form" title: "@tanstack/angular-form" --- -# @tanstack/angular-form - ## Classes +- [TanStackAppArrayField](classes/TanStackAppArrayField.md) - [TanStackAppField](classes/TanStackAppField.md) +- [TanStackArrayField](classes/TanStackArrayField.md) - [TanStackField](classes/TanStackField.md) - [TanStackFieldInjectable](classes/TanStackFieldInjectable.md) - [TanStackFormGroup](classes/TanStackFormGroup.md) -- [TanStackWithForm](classes/TanStackWithForm.md) -- [TanStackWithFormInjectable](classes/TanStackWithFormInjectable.md) + +## Type Aliases + +- [AngularFieldApi](type-aliases/AngularFieldApi.md) +- [AngularFieldData](type-aliases/AngularFieldData.md) +- [AngularFieldSource](type-aliases/AngularFieldSource.md) +- [AngularFormType](type-aliases/AngularFormType.md) +- [AnyAngularFormApi](type-aliases/AnyAngularFormApi.md) ## Functions - [injectField](functions/injectField.md) - [injectForm](functions/injectForm.md) -- [injectStore](functions/injectStore.md) -- [injectWithForm](functions/injectWithForm.md) +- [injectSelector](functions/injectSelector.md) diff --git a/docs/framework/angular/reference/type-aliases/AngularFieldApi.md b/docs/framework/angular/reference/type-aliases/AngularFieldApi.md new file mode 100644 index 0000000000..b91061aa53 --- /dev/null +++ b/docs/framework/angular/reference/type-aliases/AngularFieldApi.md @@ -0,0 +1,36 @@ +--- +id: AngularFieldApi +title: AngularFieldApi +--- + +```ts +type AngularFieldApi = FieldApi>, TFormData, ToFormErrorTypes>; +``` + +Defined in: [tanstack-field.ts:96](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L96) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFieldName + +`TFieldName` *extends* `DeepKeys`\<`TFormData`\> + +### TFieldValue + +`TFieldValue` *extends* `DeepValue`\<`TFormData`, `TFieldName`\> + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFormData`, `TFieldName`, `TFieldValue`\> + +### TFormValidators + +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> + +### TSubmitReturn + +`TSubmitReturn` diff --git a/docs/framework/angular/reference/type-aliases/AngularFieldData.md b/docs/framework/angular/reference/type-aliases/AngularFieldData.md new file mode 100644 index 0000000000..a82152dda1 --- /dev/null +++ b/docs/framework/angular/reference/type-aliases/AngularFieldData.md @@ -0,0 +1,16 @@ +--- +id: AngularFieldData +title: AngularFieldData +--- + +```ts +type AngularFieldData = TSource extends InternalFormGroupApi ? TGroupValue : TSource extends InternalFormApi ? TFormData : never; +``` + +Defined in: [tanstack-field.ts:33](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L33) + +## Type Parameters + +### TSource + +`TSource` *extends* [`AngularFieldSource`](AngularFieldSource.md) diff --git a/docs/framework/angular/reference/type-aliases/AngularFieldSource.md b/docs/framework/angular/reference/type-aliases/AngularFieldSource.md new file mode 100644 index 0000000000..5bd191afbc --- /dev/null +++ b/docs/framework/angular/reference/type-aliases/AngularFieldSource.md @@ -0,0 +1,12 @@ +--- +id: AngularFieldSource +title: AngularFieldSource +--- + +```ts +type AngularFieldSource = + | AnyInternalFormApi +| InternalFormGroupApi; +``` + +Defined in: [tanstack-field.ts:30](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.ts#L30) diff --git a/docs/framework/angular/reference/type-aliases/AngularFormType.md b/docs/framework/angular/reference/type-aliases/AngularFormType.md new file mode 100644 index 0000000000..b560f73ecc --- /dev/null +++ b/docs/framework/angular/reference/type-aliases/AngularFormType.md @@ -0,0 +1,38 @@ +--- +id: AngularFormType +title: AngularFormType +--- + +```ts +type AngularFormType = TOptions extends FormOptions ? InternalFormApi> : never; +``` + +Defined in: [form-type.ts:57](https://github.com/TanStack/form/blob/main/packages/angular-form/src/form-type.ts#L57) + +Derives the Angular form API type represented by a reusable options object. + +Use it to type inputs for components that belong to one known form shape. +Options such as `onSubmit` can be defined either in the shared options or +when the form is created in the component. + +## Type Parameters + +### TOptions + +`TOptions` *extends* `AnyFormOptions` + +The reusable form options from which the API derives its form data, validator, and submit-result types. + +## Example + +```ts +const profileOptions = formOptions({ + defaultValues: { name: '' }, +}) + +type ProfileForm = AngularFormType + +export class NameFieldComponent { + form = input.required() +} +``` diff --git a/docs/framework/angular/reference/type-aliases/AnyAngularFormApi.md b/docs/framework/angular/reference/type-aliases/AnyAngularFormApi.md new file mode 100644 index 0000000000..53349e1d69 --- /dev/null +++ b/docs/framework/angular/reference/type-aliases/AnyAngularFormApi.md @@ -0,0 +1,30 @@ +--- +id: AnyAngularFormApi +title: AnyAngularFormApi +--- + +```ts +type AnyAngularFormApi = AnyInternalFormApi; +``` + +Defined in: [form-type.ts:33](https://github.com/TanStack/form/blob/main/packages/angular-form/src/form-type.ts#L33) + +An Angular form API whose form data, validator, and submit types are erased. + +Use it for reusable Angular components that only need form operations common +to every form. Field paths and values are not checked against a particular +form shape; use `AngularFormType` when a component depends on one known form. + +## Example + +```ts +@Component({ + selector: 'app-reset-button', + template: ` + + `, +}) +export class ResetButtonComponent { + form = input.required() +} +``` diff --git a/docs/framework/lit/guides/arrays.md b/docs/framework/lit/guides/arrays.md deleted file mode 100644 index 2c14a4185b..0000000000 --- a/docs/framework/lit/guides/arrays.md +++ /dev/null @@ -1,174 +0,0 @@ ---- -id: arrays -title: Arrays ---- - -TanStack Form supports arrays as values in a form, including sub-object values inside of an array. - -## Basic Usage - -To use an array, you can use `field.state.value` on an array value, as in: - -```ts -export class TestForm extends LitElement { - #form = new TanStackFormController(this, { - defaultValues: { - people: [] as Array<{ name: string; age: string }>, - }, - }) - render() { - return html` -
    { - e.preventDefault() - }} - > -

    Please enter your details

    - ${this.#form.field( - { - name: `people`, - }, - (peopleField) => { - return html`${repeat( - peopleField.state.value, - (_, index) => index, - (_, index) => { - return html` // ... ` - }, - )} ` - }, - )} -
    - ` - } -} -``` - -This will generate the mapped HTML every time you run pushValue on the field: - -```html -
    - -
    -``` - -Finally, you can use a subfield like so: - -```ts -return html` - ${this.#form.field( - { - name: `people[${index}].name`, - }, - (field) => { - return html` - - ` - }, - )} -` -``` - -## Full Example - -```typescript -export class TestForm extends LitElement { - #form = new TanStackFormController(this, { - defaultValues: { - people: [] as Array<{ name: string }>, - }, - }); - render() { - return html` -
    { - e.preventDefault(); - }} - > -

    Please enter your details

    - ${this.#form.field( - { - name: `people`, - }, - (peopleField) => { - return html`${repeat( - peopleField.state.value, - (_, index) => index, - (_, index) => { - return html` - ${this.#form.field( - { - name: `people[${index}].name`, - }, - (field) => { - return html`
    -
    - - -
    -
    `; - } - )} - `; - } - )} - -
    - -
    `; - } - )} - -
    - - -
    -
    - `; - } - -declare global { - interface HTMLElementTagNameMap { - "test-form": TestForm; - } -} -``` diff --git a/docs/framework/lit/guides/async-initial-values.md b/docs/framework/lit/guides/async-initial-values.md new file mode 100644 index 0000000000..a2845fcf79 --- /dev/null +++ b/docs/framework/lit/guides/async-initial-values.md @@ -0,0 +1,135 @@ +--- +id: async-initial-values +title: Async Initial Values +--- + +Forms often edit data loaded from an API. A server-state library should own +fetching, caching, loading, and retries; TanStack Form should own the editable +copy. + +There are two supported approaches: wait to create the controller until the +data is ready, or create it immediately with complete fallback values. Choose +the one that matches the loading experience your element needs. + +## Wait before creating the editor + +Keep the controller optional, fetch the data, and create it only after complete +defaults exist: + +```ts +import { LitElement, html } from 'lit' +import { + TanStackFormController, + formOptions, + type LitFormType, +} from '@tanstack/lit-form' + +type User = { + firstName: string + lastName: string +} + +const userFormShape = formOptions({ + defaultValues: { + firstName: '', + lastName: '', + }, +}) + +class UserEditor extends LitElement { + private form?: LitFormType + private loadError = false + + connectedCallback() { + super.connectedCallback() + void this.loadUser() + } + + private async loadUser() { + try { + const response = await fetch('/api/users/1') + const user = (await response.json()) as User + + this.form = new TanStackFormController(this, { + defaultValues: user, + onSubmit: async ({ value }) => { + await fetch('/api/users/1', { + method: 'PUT', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(value), + }) + }, + }) + } catch { + this.loadError = true + } + this.requestUpdate() + } + + render() { + if (this.loadError) return html`

    Could not load.

    ` + if (!this.form) return html`

    Loading…

    ` + return html`
    ` + } +} +``` + +This is useful when no form state is needed during loading. Creating a fresh +editor for a different record also makes record changes explicit. + +## Create the form before data arrives + +Provide a static, shape-complete fallback, then call `form.update(...)` when +the query result changes. Keep option creation in one function so callbacks and +validation settings remain consistent. + +```ts +import { TanStackFormController, formOptions } from '@tanstack/lit-form' + +const emptyUser: User = { + firstName: '', + lastName: '', +} + +class UserEditor extends LitElement { + private form = new TanStackFormController(this, this.options(emptyUser)) + + private options(defaultValues: User) { + return formOptions({ + defaultValues, + onSubmit: async ({ value }) => { + await saveUser(value) + }, + }) + } + + connectedCallback() { + super.connectedCallback() + void loadUser().then((user) => { + this.form.update(this.options(user)) + this.requestUpdate() + }) + } +} +``` + +When loaded data replaces the fallback, TanStack Form applies the new defaults +to untouched fields while preserving fields the user already touched. You can +hide the fields during loading or render the empty form immediately. + +The repository's `examples/lit/query-integration` example demonstrates this +pattern with `QueryObserver` from TanStack Query Core. + +## Background refetches and record changes + +`defaultValues` establish the baseline; they are not a fully controlled +`values` property. Later `form.update(...)` calls preserve touched fields. + +If a background refetch arrives while a user is editing, decide whether to keep +local edits, prompt before replacing them, or deliberately call +`form.api.reset(nextValues)`. Do not overwrite in-progress input merely because +a query refreshed. + +When switching records, create a fresh editor element/controller or explicitly +reset the existing form. Otherwise, touched values from the previous record can +be preserved when new defaults arrive. diff --git a/docs/framework/lit/guides/basic-concepts.md b/docs/framework/lit/guides/basic-concepts.md deleted file mode 100644 index efc3a7c607..0000000000 --- a/docs/framework/lit/guides/basic-concepts.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -id: basic-concepts -title: Basic Concepts and Terminology ---- - -This page introduces the basic concepts and terminology used in the `@tanstack/lit-form` library. Familiarizing yourself with these concepts will help you better understand and work with the library and its usage with Lit. - -## Form Options - -You can create options for your form so that it can be shared between multiple forms by using the `formOptions` function. - -For Example: - -```tsx -const formOpts = formOptions({ - defaultValues: { - firstName: '', - lastName: '', - employed: false, - jobTitle: '', - } as Employee, -}) -``` - -## Form Instance - -A Form Instance is an object that represents an individual form and provides methods and properties for working with the form. You create a form instance using the `TanStackFormController` interface provided by `@tanstack/lit-form`. The `TanStackFormController` is instantiated with the current form's (`this`) class and some default form options. It initializes the form state, handles form submission, and provides methods to manage form fields and their validation. - -```tsx -#form = new TanStackFormController(this, { - defaultValues: { - firstName: '', - lastName: '', - employed: false, - jobTitle: '', - } as Employee, -}) -``` - -You may also create a form instance without using `formOptions` by using the standalone `TanStackFormController` API: - -```tsx -#form = new TanStackFormController(this, { - ...formOpts, -}) -``` - -## Field - -A Field represents a single form input element, such as a text input or a checkbox. Fields are created using the `field(FieldOptions, callback)` provided by the form instance. The component accepts a `FieldOptions` object and a callback function that receives a `FieldApi` object. This object provides methods to get the current value of the field, handle input changes, and handle blur events. - -For Example: - -```ts - ${this.#form.field( - { - name: `firstName`, - validators: { - onChange: ({ value }) => - value.length < 3 ? "Not long enough" : undefined, - }, - }, - (field: FieldApi) => { - return html`
    - - -
    `; - }, -)} -``` - -## Field State - -Each field has its own state, which includes its current value, validation status, error messages, and other metadata. You can access a field's state using its `field.state` property. - -```ts -const { - value, - meta: { errors, isValidating }, -} = field.state -``` - -There are four states in the metadata that can be useful to see how the user interacts with a field: - -- _"isTouched"_, after the user changes the field or blurs the field -- _"isDirty"_, after the field's value has been changed, even if it's been reverted to the default. Opposite of `isPristine` -- _"isPristine"_, until the user changes the field value. Opposite of `isDirty` -- _"isBlurred"_, after the field has been blurred - -```ts -const { isTouched, isDirty, isPristine, isBlurred } = field.state.meta -``` - -![Field states](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states.png) - -## Understanding 'isDirty' in Different Libraries - -Non-Persistent `dirty` state - -- **Libraries**: React Hook Form (RHF), Formik, Final Form. -- **Behavior**: A field is 'dirty' if its value differs from the default. Reverting to the default value makes it 'clean' again. - -Persistent `dirty` state - -- **Libraries**: Angular Form, Vue FormKit. -- **Behavior**: A field remains 'dirty' once changed, even if reverted to the default value. - -We have chosen the persistent 'dirty' state model. To also support a non-persistent 'dirty' state, we introduce an additional flag: - -- _"isDefaultValue"_, whether the field's current value is the default value - -```ts -const { isDefaultValue, isTouched } = field.state.meta - -// The following line will re-create the non-Persistent `dirty` functionality. -const nonPersistentIsDirty = !isDefaultValue -``` - -![Field states extended](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states-extended.png) diff --git a/docs/framework/lit/guides/debugging.md b/docs/framework/lit/guides/debugging.md new file mode 100644 index 0000000000..0621befff2 --- /dev/null +++ b/docs/framework/lit/guides/debugging.md @@ -0,0 +1,76 @@ +--- +id: debugging +title: Debugging Lit Usage +--- + +This page covers common Lit and TypeScript problems when using TanStack Form. + +## An input renders an empty or undefined value + +Every value bound to an input must exist in form-level `defaultValues` from the +first render. + +```ts +private form = new TanStackFormController(this, { + defaultValues: { + firstName: '', + subscribed: false, + }, +}) +``` + +Do not omit `defaultValues` or rely on a field-level default. When values come +from an API, render a loading state before creating the editable controller or +provide a complete fallback shape and call `form.update(...)` when data arrives. + +## A field value is `unknown` + +Field names and values are inferred from `defaultValues`. Check that the +initial object has not been widened to `Record`, `any`, or an +unrelated union. Prefer a concrete value type: + +```ts +type Profile = { firstName: string; age: number } + +const defaults: Profile = { firstName: '', age: 0 } +const form = new TanStackFormController(this, { defaultValues: defaults }) +``` + +For large forms, split rendering into functions typed with `LitFormType`, use a +scoped `form.formGroup(...)`, or build reusable virtual field bundles with +`getFieldGroupHelpers()` instead of casting each field value. + +## Form state changed but the template did not update + +Render field state inside `form.field(...)` and selected form state inside +`form.subscribe(...)`. These Lit directives update only their own child parts. +Reading `form.api.state` directly in `render()` does not subscribe that markup +to later changes. + +```ts +this.form.subscribe( + (state) => state.isSubmitting, + (isSubmitting) => html` `, +) +``` + +Both directives must be interpolated into a Lit child part. They cannot be used +as attribute directives. + +## Type instantiation is excessively deep + +This TypeScript error usually involves a very large recursive value shape, a +widely inferred union, or an unsupported generic wrapper. Reduce it to the +smallest form that reproduces the problem, keep `defaultValues` concrete, and +avoid unnecessary generic layers. + +If the minimal reproduction still fails, report it in the +[TanStack Form issue tracker](https://github.com/TanStack/form/issues). Include +the TypeScript version, form value type, and smallest failing field. + +## Errors exist but are not displayed + +`field.errors` respects the form's `errorVisibility` policy. Inspect +`field.meta.original.errors` to determine whether validation ran but the issues +were intentionally hidden. Confirm that the input calls `field.handleBlur()` if +the policy depends on `isBlurred`. diff --git a/docs/framework/lit/guides/dynamic-validation.md b/docs/framework/lit/guides/dynamic-validation.md deleted file mode 100644 index c601e47621..0000000000 --- a/docs/framework/lit/guides/dynamic-validation.md +++ /dev/null @@ -1,269 +0,0 @@ ---- -id: dynamic-validation -title: Dynamic Validation ---- - -In many cases, you want to change the validation rules based depending on the state of the form or other conditions. The most popular -example of this is when you want to validate a field differently based on whether the user has submitted the form for the first time or not. - -We support this through our `onDynamic` validation function. - -```ts -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' -import { TanStackFormController, revalidateLogic } from '@tanstack/lit-form' - -@customElement('my-form') -export class MyForm extends LitElement { - #form = new TanStackFormController(this, { - defaultValues: { - firstName: '', - lastName: '', - }, - // If this is omitted, onDynamic will not be called - validationLogic: revalidateLogic(), - validators: { - onDynamic: ({ value }) => { - if (!value.firstName) { - return { firstName: 'A first name is required' } - } - return undefined - }, - }, - }) - - render() { - return html`` - } -} -``` - -> By default `onDynamic` is not called, so you need to pass `revalidateLogic()` to the `validationLogic` option of `useForm`. - -## Revalidation Options - -`revalidateLogic` allows you to specify when validation should be run and change the validation rules dynamically based on the current submission state of the form. - -It takes two arguments: - -- `mode`: The mode of validation prior to the first form submission. This can be one of the following: - - `change`: Validate on every change. - - `blur`: Validate on blur. - - `submit`: Validate on submit. (**default**) - -- `modeAfterSubmission`: The mode of validation after the form has been submitted. This can be one of the following: - - `change`: Validate on every change. (**default**) - - `blur`: Validate on blur. - - `submit`: Validate on submit. - -You can, for example, use the following to revalidate on blur after the first submission: - -```ts -@customElement('my-form') -export class MyForm extends LitElement { - #form = new TanStackFormController(this, { - // ... - validationLogic: revalidateLogic({ - mode: 'submit', - modeAfterSubmission: 'blur', - }), - // ... - }) -} -``` - -## Accessing Errors - -Just as you might access errors from an `onChange` or `onBlur` validation, you can access the errors from the `onDynamic` validation function using the `form.api.state.errorMap` object. - -```ts -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' -import { TanStackFormController, revalidateLogic } from '@tanstack/lit-form' - -@customElement('my-form') -export class MyForm extends LitElement { - #form = new TanStackFormController(this, { - // ... - validationLogic: revalidateLogic(), - validators: { - onDynamic: ({ value }) => { - if (!value.firstName) { - return { firstName: 'A first name is required' } - } - return undefined - }, - }, - }) - - render() { - return html`

    ${this.#form.api.state.errorMap.onDynamic?.firstName}

    ` - } -} -``` - -## Usage with Other Validation Logic - -You can use `onDynamic` validation alongside other validation logic, such as `onChange` or `onBlur`. - -```ts -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' -import { TanStackFormController, revalidateLogic } from '@tanstack/lit-form' - -@customElement('my-form') -export class MyForm extends LitElement { - #form = new TanStackFormController(this, { - defaultValues: { - firstName: '', - lastName: '', - }, - validationLogic: revalidateLogic(), - validators: { - onChange: ({ value }) => { - if (!value.firstName) { - return { firstName: 'A first name is required' } - } - return undefined - }, - onDynamic: ({ value }) => { - if (!value.lastName) { - return { lastName: 'A last name is required' } - } - return undefined - }, - }, - }) - - render() { - return html` -
    -

    ${this.#form.api.state.errorMap.onChange?.firstName}

    -

    ${this.#form.api.state.errorMap.onDynamic?.lastName}

    -
    - ` - } -} -``` - -### Usage with Fields - -You can also use `onDynamic` validation with fields, just like you would with other validation logic. - -```ts -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' -import { TanStackFormController, revalidateLogic } from '@tanstack/lit-form' - -@customElement('my-form') -export class MyForm extends LitElement { - #form = new TanStackFormController(this, { - defaultValues: { - name: '', - age: 0, - }, - validationLogic: revalidateLogic(), - onSubmit({ value }) { - alert(JSON.stringify(value)) - }, - }) - - render() { - return html` -
    { - e.preventDefault() - e.stopPropagation() - this.#form.api.handleSubmit() - }} - > - ${this.#form.field( - { - name: 'age', - validators: { - onDynamic: ({ value }) => - value > 18 ? undefined : 'Age must be greater than 18', - }, - }, - (field) => html` -
    - { - const target = e.target as HTMLInputElement - field.handleChange(target.valueAsNumber) - }} - @blur=${() => field.handleBlur()} - /> -

    ${field.state.meta.errorMap.onDynamic}

    -
    - `, - )} - -
    - ` - } -} -``` - -### Async Validation - -Async validation can also be used with `onDynamic` just like with other validation logic. You can even debounce the async validation to avoid excessive calls. - -```ts -import { LitElement } from 'lit' -import { customElement } from 'lit/decorators.js' -import { TanStackFormController, revalidateLogic } from '@tanstack/lit-form' - -@customElement('my-form') -export class MyForm extends LitElement { - #form = new TanStackFormController(this, { - defaultValues: { - username: '', - }, - validationLogic: revalidateLogic(), - validators: { - onDynamicAsyncDebounceMs: 500, // Debounce the async validation by 500ms - onDynamicAsync: async ({ value }) => { - if (!value.username) { - return { username: 'Username is required' } - } - // Simulate an async validation - const isValid = await validateUsername(value.username) - return isValid ? undefined : { username: 'Username is already taken' } - }, - }, - }) -} -``` - -### Standard Schema Validation - -You can also use standard schema validation libraries like Valibot or Zod with `onDynamic` validation. This allows you to define complex validation rules that can change dynamically based on the form state. - -```ts -import { LitElement } from 'lit' -import { customElement } from 'lit/decorators.js' -import { TanStackFormController, revalidateLogic } from '@tanstack/lit-form' -import { z } from 'zod' - -const schema = z.object({ - firstName: z.string().min(1, 'A first name is required'), - lastName: z.string().min(1, 'A last name is required'), -}) - -@customElement('my-form') -export class MyForm extends LitElement { - #form = new TanStackFormController(this, { - defaultValues: { - firstName: '', - lastName: '', - }, - validationLogic: revalidateLogic(), - validators: { - onDynamic: schema, - }, - }) -} -``` diff --git a/docs/framework/lit/guides/form-composition.md b/docs/framework/lit/guides/form-composition.md deleted file mode 100644 index e9157095ae..0000000000 --- a/docs/framework/lit/guides/form-composition.md +++ /dev/null @@ -1,233 +0,0 @@ ---- -id: form-composition -title: Form Composition ---- - -A common criticism of TanStack Form is its verbosity out-of-the-box. While this _can_ be useful for educational purposes — helping enforce understanding our APIs — it's not ideal in production use cases. - -This guide covers the patterns that work well in Lit: - -- Building reusable field UI as custom elements that accept the `FieldApi` as a property. -- Splitting big forms across multiple custom elements while keeping the `form` property fully typed via `getFormType`. - -## Reusable field components with `AnyFieldApi` - -The most direct way to share field UI across multiple forms in Lit is to write a custom element that accepts the `FieldApi` instance as a property. The `AnyFieldApi` type from `@tanstack/lit-form` gives you a "this is some field, I don't care about the exact generics" type that's perfect for that property. - -Because the field is a property of the custom element rather than something the element owns, the host needs to subscribe to the field's store so it re-renders when the field's value or metadata change. The `TanStackStoreSelector` reactive controller from [`@tanstack/lit-store`](https://tanstack.com/store/latest/docs/framework/lit/quick-start) does exactly that. - -```ts -// text-field.ts -import { LitElement, html } from 'lit' -import { customElement, property } from 'lit/decorators.js' -import { TanStackStoreSelector } from '@tanstack/lit-store' -import type { AnyFieldApi } from '@tanstack/lit-form' - -@customElement('text-field') -export class TextField extends LitElement { - @property({ attribute: false }) - field!: AnyFieldApi - - @property({ type: String }) - label = '' - - // Re-render whenever this field's store updates. - _selector = new TanStackStoreSelector(this, () => this.field?.store) - - render() { - return html` - - ${this.field.state.meta.isTouched && this.field.state.meta.errors.length - ? html`
    - ${this.field.state.meta.errors.join(', ')} -
    ` - : ''} - ` - } -} -``` - -Use it inside the `field` directive's render callback by passing the `field` instance as a property: - -```ts -import { LitElement, html } from 'lit' -import { TanStackFormController } from '@tanstack/lit-form' -import './text-field.js' - -export class AppForm extends LitElement { - form = new TanStackFormController(this, { - defaultValues: { firstName: '', lastName: '' }, - }) - - render() { - return html` - ${this.form.field( - { name: 'firstName' }, - (field) => html` - - `, - )} - ${this.form.field( - { name: 'lastName' }, - (field) => html` - - `, - )} - ` - } -} -``` - -The `field` parameter inside the render callback remains fully typed against the `name` you passed, so `field.state.value` and `field.handleChange` are still type-checked at the call site. `` itself uses `AnyFieldApi` internally because it has to accept any field shape. - -> If your reusable component only ever wraps fields of a specific value type (for example, only `string` fields), you can narrow the property type with the generic `FieldApi<...>` instead of `AnyFieldApi` — but `AnyFieldApi` is the easiest option to start with and matches how the directive is exposed in render callbacks elsewhere. - -> `TanStackStoreSelector` accepts an optional second argument to scope what triggers a re-render — for example, `(snapshot) => snapshot.meta.errors`. Passing nothing re-renders on any change to the field's store, which is the simplest default. - -## Breaking big forms into smaller pieces - -Sometimes forms get very large. To keep things manageable, you can break a form across multiple custom elements that each receive the `TanStackFormController` as a property. - -The challenge is typing that property correctly. Writing the full `TanStackFormController<…>` generics by hand is verbose and error-prone, so `@tanstack/lit-form` provides a `getFormType` helper. - -`getFormType` is a type-only utility — it does no work at runtime — that takes the same `FormOptions` you'd pass to `new TanStackFormController(...)` and returns a value whose **type** matches the controller that those options would produce. - -```ts -// shared-form.ts -import { formOptions } from '@tanstack/lit-form' - -export const peopleFormOpts = formOptions({ - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, -}) -``` - -Then derive the property type for a child custom element from those shared options. As with reusable field elements, the child element receives the controller as a property and won't re-render automatically when the form's state changes — wire it up with `TanStackStoreSelector` against `form.api.store`: - -```ts -// child-form.ts -import { LitElement, html } from 'lit' -import { customElement, property } from 'lit/decorators.js' -import { TanStackStoreSelector } from '@tanstack/lit-store' -import { getFormType } from '@tanstack/lit-form' -import { peopleFormOpts } from './shared-form.js' -import './text-field.js' - -const formType = getFormType(peopleFormOpts) - -@customElement('child-form') -export class ChildForm extends LitElement { - @property({ attribute: false }) - form!: typeof formType - - @property({ type: String }) - title = 'Child Form' - - // Re-render when the form's state changes. - _selector = new TanStackStoreSelector(this, () => this.form?.api.store) - - render() { - return html` -

    ${this.title}

    - ${this.form.field( - { name: 'firstName' }, - (field) => html` - - `, - )} - ` - } -} -``` - -And use it from the parent element by passing the controller as a property: - -```ts -// app.ts -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' -import { TanStackFormController } from '@tanstack/lit-form' -import { peopleFormOpts } from './shared-form.js' -import './child-form.js' - -@customElement('app-root') -export class AppRoot extends LitElement { - form = new TanStackFormController(this, peopleFormOpts) - - render() { - return html`` - } -} -``` - -The child element gets a fully typed `form` property — including all of the `field` and `group` directives — without having to spell out the controller's generics by hand or maintain a hand-written type alias. - -> `getFormType` only carries types; **never** call its return value at runtime. Use it as `typeof getFormType(opts)` (or assign to a `const` and use `typeof`) and pass the actual controller instance from the parent element via the `.form` property. - -## Reusing groups of fields across multiple forms - -The same pattern works for sharing a group of related fields (for example, a password + confirm-password pair) across forms. Define a small custom element that takes the `form` as a property typed with `getFormType` — keyed against just the slice of form data the group needs — and renders the relevant `form.field(...)` calls. - -```ts -// password-fields.ts -import { LitElement, html } from 'lit' -import { customElement, property } from 'lit/decorators.js' -import { TanStackStoreSelector } from '@tanstack/lit-store' -import { formOptions, getFormType } from '@tanstack/lit-form' -import './text-field.js' - -const passwordFormOpts = formOptions({ - defaultValues: { - password: '', - confirm_password: '', - }, -}) - -const passwordFormType = getFormType(passwordFormOpts) - -@customElement('password-fields') -export class PasswordFields extends LitElement { - @property({ attribute: false }) - form!: typeof passwordFormType - - _selector = new TanStackStoreSelector(this, () => this.form?.api.store) - - render() { - return html` - ${this.form.field( - { name: 'password' }, - (field) => html` - - `, - )} - ${this.form.field( - { - name: 'confirm_password', - validators: { - onChangeListenTo: ['password'], - onChange: ({ value, fieldApi }) => - value !== fieldApi.form.getFieldValue('password') - ? 'Passwords do not match' - : undefined, - }, - }, - (field) => html` - - `, - )} - ` - } -} -``` - -The host form just needs to include the same fields in its own `defaultValues` (TypeScript will check that the `form` property assigned via `.form=${this.form}` is structurally compatible with `passwordFormType`). diff --git a/docs/framework/lit/guides/form-groups.md b/docs/framework/lit/guides/form-groups.md deleted file mode 100644 index 1736602ffa..0000000000 --- a/docs/framework/lit/guides/form-groups.md +++ /dev/null @@ -1,236 +0,0 @@ ---- -id: form-groups -title: Form Groups ---- - -When building a multi-stage form that has many stages, like so: - -![Form stepper](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/stepper.png) - -It's common for each step to have its own form. However, this complicates the form submission and validation process by requiring you to add complex logic. - -Luckily, TanStack Form provides a way to build out sub-forms that make this kind of development trivial to implement: `form.group(...)`. - -## Usage - -To use a form group in TanStack Form, you'll create a `TanStackFormController`, then use its `group` directive like you would use its `field` directive: - -```ts -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' -import { TanStackFormController } from '@tanstack/lit-form' - -@customElement('my-form') -export class MyForm extends LitElement { - #form = new TanStackFormController(this, { - defaultValues: { - step1: { - name: '', - }, - step2: { - age: 0, - }, - }, - }) - - render() { - return html` - ${this.#form.group({ name: 'step1' }, (group) => { - // `group` here has all of the form-like methods you'd expect like `deleteField` or `insertFieldValue` - // ... - return html`` - })} - ` - } -} -``` - -This becomes much more useful when paired with external state to conditionally render a form group: - -```ts -import { LitElement, html, nothing } from 'lit' -import { customElement, state } from 'lit/decorators.js' -import { TanStackFormController } from '@tanstack/lit-form' - -@customElement('my-form') -export class MyForm extends LitElement { - @state() - private step = 0 - - #form = new TanStackFormController(this, { - defaultValues: { - step1: { - name: '', - }, - step2: { - age: 0, - }, - }, - }) - - render() { - return html` - ${this.step === 0 - ? this.#form.group( - { - name: 'step1', - onGroupSubmit: () => { - // We can move the step forward when validation passes - this.step++ - }, - onGroupSubmitInvalid: () => { - // Or handle invalid submissions, just like a top-level form - }, - onSubmitMeta: {} as SomeType, - }, - (group) => html` -
    { - e.preventDefault() - e.stopPropagation() - // Use `group.handleSubmit()` to submit the sub-form, but not the parent form - group.handleSubmit() - }} - > - ${this.#form.field( - { name: 'step1.name' }, - (field) => html``, - )} -
    - `, - ) - : nothing} - ${this.step === 1 - ? this.#form.group( - { - name: 'step2', - onGroupSubmit: () => { - // Then, use `this.#form.api.handleSubmit()` to submit the entire form - this.#form.api.handleSubmit() - }, - }, - (group) => html` -
    { - e.preventDefault() - e.stopPropagation() - group.handleSubmit() - }} - > - ${this.#form.field( - { name: 'step2.age' }, - (field) => html``, - )} -
    - `, - ) - : nothing} - ` - } -} -``` - -When you split each step into its own custom element, pass the `TanStackFormController` as a property and type it with [`getFormType`](./form-composition.md). Because Lit child elements that receive a controller by property do not automatically re-render when the controller state changes, subscribe to `form.api.store` with `TanStackStoreSelector` in the child element. - -## Form Group Validation - -Form groups have a distinct validation procedure that we think makes sense for sub-forms: - -- Form groups can have their own validation: - -```ts -${this.#form.group( - { name: 'step1', validators: { onChange: () => 'Error' } }, - (group) => html` - - - `, -)} -``` - -- Can set errors on sub-fields: - -```ts -${this.#form.group( - { - name: 'step1', - validators: { - onChange: ({ value, groupApi }) => ({ - group: value.name === 'error' ? 'Group error' : undefined, - fields: { - // Must use the name of the field relative to the form group as the error key, - // to stay consistent with how standard schema works with form groups - name: value.name === 'error' ? 'Field error' : undefined, - }, - }), - }, - }, - (group) => html``, -)} -``` - -- And can even accept standard schemas: - -```ts -${this.#form.group( - { - name: 'step1', - validators: { - onChange: z.object({ - name: z.string().min(2), - }), - }, - }, - (group) => html``, -)} -``` - -> The reason we don't use the full path names for fields is so that you can compose your schemas like so: -> -> ```ts -> const step1Schema = z.object({ -> name: z.string().min(2), -> }) -> -> const schema = z.object({ -> step1: step1Schema, -> step2: step2Schema, -> }) -> ``` -> -> And pass the `step1Schema` to a form group and `schema` to the parent form. That way, partially validated data will still flag errors if the group is bypassed. - -### Dynamic Group Validation - -If you want to use [dynamic validation (`onDynamic`)](./dynamic-validation.md) with a form group, do not rely on the `onDynamic` validator passed to `TanStackFormController`: - -```ts -#form = new TanStackFormController(this, { - validationLogic: revalidateLogic(), - validators: { - // This validator will not run `onChange` when a sub-form is submitted; - // it will only run `onChange` when the form itself is submitted. - onDynamic: schema, - }, -}) -``` - -Instead, pass your sub-schema for the group to the `onDynamic` validation of the group itself: - -```ts -${this.#form.group( - { name: 'step1', validators: { onDynamic: step1Schema } }, - (group) => html``, -)} -``` - -It will treat `group.submissionAttempts` as the way to change what validator is run before/after submit. - -## Form Group State - -Just like you're able to access `group.state.meta.errors`, you're also able to access the group's value using `group.state.value`. Likewise, here are some valuable properties you can access in the `group.state.meta`: - -- `group.state.meta.isFieldsValid`: `true` when the field-level validators have no errors -- `group.state.meta.isGroupValid`: `true` when the group-level validators have no errors -- `group.state.meta.isValid`: `true` when both the field-level and group-level validators have no errors -- `group.state.meta.isSubmitting`: `true` when the group is in the process of being submitted diff --git a/docs/framework/lit/guides/ui-libraries.md b/docs/framework/lit/guides/ui-libraries.md new file mode 100644 index 0000000000..22a620dff3 --- /dev/null +++ b/docs/framework/lit/guides/ui-libraries.md @@ -0,0 +1,113 @@ +--- +id: ui-libraries +title: UI Libraries +--- + +TanStack Form is headless. UI library integration consists of adapting a +field's value, blur callback, change callback, invalid state, and errors to the +custom element or component's property and event names. + +## Text inputs + +For web components, use Lit property bindings for non-string values and event +bindings for change notifications: + +```ts +this.form.field( + { name: 'name' }, + (field) => html` + field.handleBlur()} + @input=${(event: InputEvent) => + field.handleChange((event.currentTarget as HTMLInputElement).value)} + .error=${field.errors.map((error) => error.message).join(', ')} + > + `, +) +``` + +Bind the current `field.value`; do not pass a one-time default. The form remains +the source of truth. + +## Checkboxes and switches + +DOM-style checkbox components expose `checked` on the event target: + +```ts +this.form.field( + { name: 'acceptedTerms' }, + (field) => html` + field.handleBlur()} + @change=${(event: Event) => + field.handleChange((event.currentTarget as HTMLInputElement).checked)} + aria-invalid=${field.meta.isInvalid ? 'true' : 'false'} + > + `, +) +``` + +Some libraries emit a boolean, details object, or union such as +`boolean | 'indeterminate'`. Normalize the custom event at the boundary: + +```ts +html`) => + field.handleChange(event.detail === true)} +>` +``` + +## Selects, date pickers, and custom controls + +The integration does not require a native event. Pass the value emitted by the +component to `field.handleChange`: + +```ts +html`) => + field.handleChange(event.detail)} + @blur=${() => field.handleBlur()} +>` +``` + +Choose a serializable form value appropriate for your application, then adapt +the UI library's richer object at the component boundary if necessary. + +## Reuse the adapter + +If the same wiring appears throughout the application, extract a render +function or Lit component that accepts `FieldWithValue`: + +```ts +import type { FieldWithValue } from '@tanstack/lit-form' + +function textField(field: FieldWithValue, label: string) { + return html` + + ` +} +``` + +Use `LitFormType` when a split component or render helper +needs the type of one concrete form. Use +`getFieldGroupHelpers().withFields(...)` when a reusable bundle should accept +typed virtual names that callers map to different concrete paths. + +For the helper types used when passing a form or field to an extracted +component, see [Splitting forms](../../../splitting-forms). + +See the repository's `examples/lit/basic-splitting-form` and +`examples/lit/field-groups` examples for both patterns. diff --git a/docs/framework/lit/guides/validation.md b/docs/framework/lit/guides/validation.md index 4c8b693c4b..5c8de4cb5e 100644 --- a/docs/framework/lit/guides/validation.md +++ b/docs/framework/lit/guides/validation.md @@ -3,631 +3,258 @@ id: form-validation title: Form and Field Validation --- -At the core of TanStack Form's functionalities is the concept of validation. TanStack Form makes validation highly customizable: +TanStack Form supports synchronous, asynchronous, field-level, form-level, and +Standard Schema validation. Every validator is an ordered object with a `run` +implementation and explicit `triggers`. -- You can control when to perform the validation (on change, on input, on blur, on submit...) -- Validation rules can be defined at the field level or at the form level -- Validation can be synchronous or asynchronous (for example, as a result of an API call) +## Choose when validation runs -## When is validation performed? - -It's up to you! The `field()` method accepts some callbacks as validators such as `onChange` or `onBlur`. Those callbacks are passed the current value of the field, as well as the fieldAPI object, so that you can perform the validation. If you find a validation error, simply return the error message as string and it will be available in `field.state.meta.errors`. - -Here is an example: +Use `change` for immediate feedback and `blur` for feedback after leaving an +input. Submission runs validators by default regardless of their configured +change and blur triggers. ```ts -import { html, nothing } from 'lit' -;`${this.#form.field( +this.form.field( { name: 'age', - validators: { - onChange: ({ value }) => - value < 13 ? 'You must be 13 to make an account' : undefined, - }, - }, - (field) => { - return html` - - - ${!field.state.meta.isValid - ? html`${field.state.meta.errors.join(', ')}` - : nothing} - ` - }, -)}` -``` - -In the example above, the validation is done at each keystroke (`onChange`). If, instead, we wanted the validation to be done when the field is blurred, we would change the code above like so: - -```ts -import { html, nothing } from 'lit' -;`${this.#form.field( - { - name: 'age', - validators: { - onBlur: ({ value }) => - value < 13 ? 'You must be 13 to make an account' : undefined, - }, + validators: [ + { + triggers: ['change'], + run: ({ value }) => + value >= 13 ? undefined : 'You must be at least 13', + }, + { + triggers: ['blur'], + run: ({ value }) => (value >= 0 ? undefined : 'Age cannot be negative'), + }, + ], }, - (field) => { - return html` - + (field) => html` + + `, +) ``` -So you can control when the validation is done by implementing the desired callback. You can even perform different pieces of validation at different times: - -```ts -import { html, nothing } from 'lit' -;`${this.#form.field( - { - name: 'age', - validators: { - onChange: ({ value }) => - value < 13 ? 'You must be 13 to make an account' : undefined, - onBlur: ({ value }) => (value < 0 ? 'Invalid value' : undefined), - }, - }, - (field) => { - return html` - - - ${!field.state.meta.isValid - ? html`${field.state.meta.errors.join(', ')}` - : nothing} - ` - }, -)}` -``` +Additional controls include: -In the example above, we are validating different things on the same field at different times (at each keystroke and when blurring the field). Since `field.state.meta.errors` is an array, all the relevant errors at a given time are displayed. You can also use `field.state.meta.errorMap` to get errors based on _when_ the validation was done (onChange, onBlur etc...). More info about displaying errors below. +- `runOnMount`: run once when the form is constructed or when a field or form + group first mounts. +- `skipOnSubmit`: conditionally skip submit-time execution. +- `triggerDebounceMs`: debounce change and blur execution. +- `bailIfInvalid`: skip this and subsequent validators when an earlier one + failed. +- trigger objects with `when`: enable a trigger conditionally. +- `watchFields`: rerun a field validator when related fields trigger it. -## Displaying Errors +## Control when errors are visible -Once you have your validation in place, you can map the errors from an array to be displayed in your UI: +Validation and presentation are separate. `errorVisibility` decides when field +issues appear in `field.errors`: ```ts -import { html, nothing } from 'lit' -;`${this.#form.field( - { - name: 'age', - validators: { - onChange: ({ value }) => - value < 13 ? 'You must be 13 to make an account' : undefined, - }, - }, - (field) => { - return html` - - ${!field.state.meta.isValid - ? html`${field.state.meta.errors.join(',')}` - : nothing} - ` - }, -)}` +private form = new TanStackFormController(this, { + defaultValues: { email: '' }, + errorVisibility: ({ fieldState, state }) => + fieldState.meta.isBlurred || state.submissionAttempts > 0, +}) ``` -Or use the `errorMap` property to access the specific error you're looking for: +Use `field.meta.original.errors` for unfiltered issues when debugging or +building a custom visibility system. -```ts -import { html, nothing } from 'lit' -;`${this.#form.field( - { - name: 'age', - validators: { - onChange: ({ value }) => - value < 13 ? 'You must be 13 to make an account' : undefined, - }, - }, - (field) => { - return html` - - ${field.state.meta.errorMap['onChange'] - ? html`${field.state.meta.errorMap['onChange']}` - : nothing} - ` - }, -)}` -``` +## Form-level validation -It's worth mentioning that our `errors` array and the `errorMap` matches the types returned by the validators. This means that: +A form validator can produce a form issue and route issues to typed field paths +with `createErrorMap`: ```ts -import { html, nothing } from 'lit' - -;`${this.#form.field( - { - name: 'age', - validators: { - onChange: ({ value }) => (value < 13 ? { isOldEnough: false } : undefined), - }, +private form = new TanStackFormController(this, { + defaultValues: { + email: '', + phone: '', }, - (field) => { - return html` - - - - ${!field.state.meta.errorMap['onChange']?.isOldEnough - ? html`The user is not old enough` - : nothing} - ` - }, -)}` -``` - -## Validation at field level vs at form level - -As shown above, each field accepts its own validation rules via the `onChange`, `onBlur` etc... callbacks. It is also possible to define validation rules at the form level (as opposed to field by field) by passing similar callbacks to the `TanStackFormController` constructor. - -Example: - -```ts -import { LitElement, html, nothing } from 'lit' -import { customElement } from 'lit/decorators.js' -import { TanStackFormController } from '@tanstack/lit-form' - -@customElement('my-form') -export class MyForm extends LitElement { - #form = new TanStackFormController(this, { - defaultValues: { - age: 0, - }, - onSubmit: async ({ value }) => { - console.log(value) - }, - validators: { - // Add validators to the form the same way you would add them to a field - onChange({ value }) { - if (value.age < 13) { - return 'Must be 13 or older to sign' - } - return undefined - }, - }, - }) - - render() { - return html` -
    - - ${this.#form.api.state.errorMap.onChange - ? html` -
    - There was an error on the form: - ${this.#form.api.state.errorMap.onChange} -
    - ` - : nothing} - -
    - ` - } -} -``` - -### Setting field-level errors from the form's validators - -You can set errors on the fields from the form's validators. One common use case for this is validating all the fields on submit by calling a single API endpoint in the form's `onSubmitAsync` validator. - -```ts -import { LitElement, html, nothing } from 'lit' -import { customElement } from 'lit/decorators.js' -import { TanStackFormController } from '@tanstack/lit-form' - -@customElement('my-form') -export class MyForm extends LitElement { - #form = new TanStackFormController(this, { - defaultValues: { - age: 0, - socials: [], - details: { - email: '', - }, - }, - validators: { - onSubmitAsync: async ({ value }) => { - // Validate the value on the server - const hasErrors = await verifyDataOnServer(value) - if (hasErrors) { - return { - form: 'Invalid data', // The `form` key is optional - fields: { - age: 'Must be 13 or older to sign', - // Set errors on nested fields with the field's name - 'socials[0].url': 'The provided URL does not exist', - 'details.email': 'An email is required', - }, - } + validators: [ + { + triggers: ['change'], + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() + + if (!value.email && !value.phone) { + errors.form = 'Provide an email address or phone number' + errors.fields.email = 'Email is required when phone is empty' + errors.fields.phone = 'Phone is required when email is empty' } - return null + return errors }, }, - }) - - render() { - return html` -
    -
    - ${this.#form.field( - { name: 'age' }, - (field) => html` - - - ${!field.state.meta.isValid - ? html`${field.state.meta.errors.join(', ')}` - : nothing} - `, - )} - ${this.#form.api.state.errorMap.onSubmit - ? html` -
    - There was an error on the form: - ${this.#form.api.state.errorMap.onSubmit} -
    - ` - : nothing} - -
    -
    - ` - } -} + ], +}) ``` -> Something worth mentioning is that if you have a form validation function that returns an error, that error may be overwritten by the field-specific validation. -> -> This means that: -> -> ```ts -> const form = new TanStackFormController(this, { -> defaultValues: { -> age: 0, -> }, -> validators: { -> onChange: ({ value }) => { -> return { -> fields: { -> age: value.age < 12 ? 'Too young!' : undefined, -> }, -> } -> }, -> }, -> }) -> -> // ... -> -> return html` -> ${this.#form.field( -> { -> name: 'age', -> validators: { -> onChange: ({ value }) => -> value % 2 === 0 ? 'Must be odd!' : undefined, -> }, -> }, -> () => html``, -> )} -> ` -> ``` -> -> Will only show `'Must be odd!` even if the 'Too young!' error is returned by the form-level validation. - -## Asynchronous Functional Validation - -While we suspect most validations will be synchronous, there are many instances where a network call or some other async operation would be useful to validate against. - -To do this, we have dedicated `onChangeAsync`, `onBlurAsync`, and other methods that can be used to validate against: +Use `form.subscribe(...)` to reactively select form-level issues from +`form.api.state.errors`. Lower-level integrations can subscribe to +`form.api.atom`. +Field-routed issues appear in the corresponding `field.errors`. ```ts -import { html, nothing } from 'lit' -;`${this.#form.field( - { - name: 'age', - validators: { - onChangeAsync: async ({ value }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value < 13 ? 'You must be 13 to make an account' : undefined - }, - }, - }, - (field) => { - return html` - - - ${!field.state.meta.isValid - ? html`${field.state.meta.errors.join(', ')}` - : nothing} - ` - }, -)}` +this.form.subscribe( + (state) => state.errors, + (errors) => html` + ${errors.map((error) => html`

    ${error.message}

    `)} + `, +) ``` -Synchronous and Asynchronous validations can coexist. For example, it is possible to define both `onBlur` and `onBlurAsync` on the same field: +## Asynchronous validation and debouncing -```ts -import { html, nothing } from 'lit' -;`${this.#form.field( - { - name: 'age', - validators: { - onBlur: ({ value }) => - value < 13 ? 'You must be at least 13' : undefined, - onBlurAsync: async ({ value }) => { - const currentAge = await fetchCurrentAgeOnProfile() - return value < currentAge ? 'You can only increase the age' : undefined - }, - }, - }, - (field) => { - return html` - - - ${!field.state.meta.isValid - ? html`${field.state.meta.errors.join(', ')}` - : nothing} - ` - }, -)}` -``` - -The synchronous validation method (`onBlur`) is run first and the asynchronous method (`onBlurAsync`) is only run if the synchronous one (`onBlur`) succeeds. To change this behaviour, set the `asyncAlways` option to `true`, and the async method will be run regardless of the result of the sync method. - -### Built-in Debouncing - -While async calls are the way to go when validating against the database, running a network request on every keystroke is a good way to DDOS your database. - -Instead, we enable an easy method for debouncing your `async` calls by adding a single property: +`run` may return a promise. Put cheap synchronous checks first and use +`bailIfInvalid` to avoid unnecessary requests: ```ts -;`${this.#form.field( +validators: [ { - name: 'age', - asyncDebounceMs: 500, - validators: { - onChangeAsync: async ({ value }) => { - // ... - }, - }, - }, - (field) => { - return html`` + triggers: ['change'], + run: ({ value }) => + value.length >= 3 ? undefined : 'Use at least 3 characters', }, -)}` -``` - -This will debounce every async call with a 500ms delay. You can even override this property on a per-validation property: - -```ts -;`${this.#form.field( { - name: 'age', - asyncDebounceMs: 500, - validators: { - onChangeAsyncDebounceMs: 1500, - onChangeAsync: async ({ value }) => { - // ... - }, - onBlurAsync: async ({ value }) => { - // ... - }, + triggers: ['change'], + triggerDebounceMs: 500, + bailIfInvalid: true, + run: async ({ value }) => { + const available = await checkUsername(value) + return available ? undefined : 'That username is already taken' }, }, - (field) => { - return html`` - }, -)}` +] ``` -This will run `onChangeAsync` every 1500ms while `onBlurAsync` will run every 500ms. - -## Validation through Schema Libraries - -While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries that provide schema-based validation to make shorthand and type-strict validation substantially easier. You can also define a single schema for your entire form and pass it to the form level, errors will be automatically propagated to the fields. +Submit validation always runs immediately, even when a trigger is debounced. +`field.meta.isValidating` and `form.api.state.isValidating` expose pending work. +Render form-wide pending state through `form.subscribe(...)` so it stays +reactive. -### Standard Schema Libraries +## Standard Schema validation -TanStack Form natively supports all libraries following the [Standard Schema specification](https://github.com/standard-schema/standard-schema), most notably: - -- [Zod](https://zod.dev/) -- [Valibot](https://valibot.dev/) -- [ArkType](https://arktype.io/) -- [Effect/Schema](https://effect.website/docs/schema/standard-schema/) - -_Note:_ make sure to use the latest version of the schema libraries as older versions might not support Standard Schema yet. - -> Validation will not provide you with transformed values. Use submission handling (docs pending). - -To use schemas from these libraries you can pass them to the `validators` props as you would do with a custom function: +Any Standard Schema implementation can be supplied as `run`: ```ts import { z } from 'zod' -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' -import { TanStackFormController } from '@tanstack/lit-form' -const userSchema = z.object({ - age: z.number().gte(13, 'You must be 13 to make an account'), +const accountSchema = z.object({ + email: z.string().email(), + age: z.number().min(13), }) -@customElement('my-form') -export class MyForm extends LitElement { - #form = new TanStackFormController(this, { - defaultValues: { - age: 0, +private form = new TanStackFormController(this, { + defaultValues: { email: '', age: 0 }, + validators: [ + { + triggers: ['change'], + run: accountSchema, }, - validators: { - onChange: userSchema, - }, - }) - - render() { - return html` -
    - ${this.#form.field({ name: 'age' }, (field) => { - return html`` - })} -
    - ` - } -} + ], +}) ``` -Async validations on form and field level are supported as well: +Schema paths are routed to matching fields. Parsed outputs are available by +validator index in `schemaOutputs` during submit, for example +`schemaOutputs[0]`. `value` remains the raw editable state rather than the +parsed output. -```ts -import { html } from 'lit' -import { z } from 'zod' +For custom schema routing, call a schema's safe-parse API inside `run` and pass +its issues to the provided `parseIssues` helper. -${this.#form.field( - { - name: 'age', - validators: { - onChange: z.number().gte(13, 'You must be 13 to make an account'), - onChangeAsyncDebounceMs: 500, - onChangeAsync: z.number().refine( - async (value) => { - const currentAge = await fetchCurrentAgeOnProfile() - return value >= currentAge - }, - { - message: 'You can only increase the age', - }, - ), - }, - }, - (field) => { - return html`` - }, -)} -``` +## Validate related fields -If you need even more control over your Standard Schema validation, you can combine a Standard Schema with a callback function like so: +Use `watchFields` when one field's validity depends on another: ```ts -import { html } from 'lit' -import { z } from 'zod' - -${this.#form.field( +this.form.field( { - name: 'age', - asyncDebounceMs: 500, - validators: { - onChangeAsync: async ({ value, fieldApi }) => { - const errors = fieldApi.parseValueWithSchema( - z.number().gte(13, 'You must be 13 to make an account'), - ) - if (errors) return errors - // continue with your validation + name: 'endDate', + validators: [ + { + triggers: ['change', 'blur'], + watchFields: ['startDate'], + run: ({ value, formApi }) => + value >= formApi.getFieldValue('startDate') + ? undefined + : 'End date must be on or after the start date', }, - }, + ], }, - (field) => { - return html`` - }, -)} + (field) => html` + field.handleBlur()} + @input=${(event: InputEvent) => + field.handleChange((event.currentTarget as HTMLInputElement).value)} + aria-invalid=${field.meta.isInvalid ? 'true' : 'false'} + /> + `, +) ``` -## Preventing invalid forms from being submitted +## Return errors from submission + +Endpoint validation belongs in `onSubmit`. Return +`createValidationError(...)` to feed server issues back into normal form state: -The `onChange`, `onBlur` etc... callbacks are also run when the form is submitted and the submission is blocked if the form is invalid. +```ts +private form = new TanStackFormController(this, { + defaultValues: { email: '' }, + onSubmit: async ({ value, createValidationError }) => { + const result = await saveProfile(value) + + if (!result.ok) { + return createValidationError({ + form: 'Could not save the profile', + fields: { email: 'This email is already registered' }, + }) + } + + return null + }, +}) +``` -The form state object has a `canSubmit` flag that is false when any field is invalid and the form has been touched (`canSubmit` is true until the form has been touched, even if some fields are "technically" invalid based on their `onChange`/`onBlur` props). +## Prevent invalid submission -You can access this flag via `this.#form.api.state` and use the value in order to, for example, disable the submit button when the form is invalid (in practice, disabled buttons are not accessible, use `aria-disabled` instead). +`form.api.handleSubmit()` skips `onSubmit` when validation fails and resolves +with the validation errors. `onSubmitInvalid` is currently available on form +groups; root-form support is planned but not yet implemented. Subscribe to +`canSubmit` and `isSubmitting` to reflect that state in the submit UI: ```ts -class MyForm extends LitElement { - #form = new TanStackFormController(this, { - /* ... */ - }) - - render() { - return html` - - - - - ` - } -} +this.form.subscribe( + (state) => [state.canSubmit, state.isSubmitting] as const, + ([canSubmit, isSubmitting]) => html` + + `, +) ``` -To prevent the form from being submitted before any interaction, combine `canSubmit` with `isPristine` flags. A simple condition like `!canSubmit || isPristine` effectively disables submissions until the user has made changes. +If a disabled submit button would hide useful validation feedback, keep it +focusable with `aria-disabled` and let `handleSubmit()` report the issues. diff --git a/docs/framework/lit/quick-start.md b/docs/framework/lit/quick-start.md index 6bb0bdf748..11f4a394a0 100644 --- a/docs/framework/lit/quick-start.md +++ b/docs/framework/lit/quick-start.md @@ -3,81 +3,126 @@ id: quick-start title: Quick Start --- -The bare minimum to get started with TanStack Form is to create a `TanstackFormController` as seen below with the `Employee` interface for our test form: +TanStack Form is a headless, type-safe form library. It owns form state and +validation while leaving markup, styling, and component choice to you. -```ts -interface Employee { - firstName: string - lastName: string - employed: boolean - jobTitle: string -} +Install the Lit adapter: -#form = new TanStackFormController()(this, { - defaultValues: { - firstName: '', - lastName: '', - employed: false, - jobTitle: '', - }, -}) +```bash +npm install @tanstack/lit-form ``` -In this example `this` references the instance of your `LitElement` in which you want to use TanStack Form. - -To wire a form element in your template up with TanStack Form, use the `field` method of `TanstackFormController`. +## Create a form -The first parameter of `field` is `FieldOptions` and the second is callback to render your element. +Create a `TanStackFormController` as a field on your Lit element. The controller +requires complete `defaultValues`; their shape becomes the inferred form value +type. ```ts -field(FieldOptions, callback) -``` - -Our completed test form should look something like below. The form collects first name from a user input field: +import { LitElement, html } from 'lit' +import { TanStackFormController } from '@tanstack/lit-form' -```ts -export class TestForm extends LitElement { - #form = new TanStackFormController(this, { +class ProfileForm extends LitElement { + private form = new TanStackFormController(this, { defaultValues: { - firstName: '', - lastName: '', - employed: false, - jobTitle: '', + fullName: '', + age: 0, + }, + onSubmit: async ({ value }) => { + console.log(value) }, }) + render() { - return html`

    Please enter your first name

    - ${this.#form.field( - { - name: `firstName`, - validators: { - onChange: ({ value }) => - value.length < 3 ? 'Not long enough' : undefined, + return html` +
    { + event.preventDefault() + void this.form.api.handleSubmit() + }} + > + ${this.form.field( + { + name: 'fullName', + validators: [ + { + triggers: ['change', 'blur'], + run: ({ value }) => + value.trim() ? undefined : 'Enter your full name', + }, + ], + }, + (field) => html` + + `, + )} + ${this.form.field( + { + name: 'age', + validators: [ + { + triggers: ['change'], + run: ({ value }) => + value >= 13 ? undefined : 'You must be at least 13', + }, + ], }, - }, - (field: FieldApi) => { - return html`
    - - -
    ` - }, - )}` + (field) => html` + + `, + )} + ${this.form.subscribe( + (state) => [state.canSubmit, state.isSubmitting] as const, + ([canSubmit, isSubmitting]) => html` + + `, + )} + + ` } } + +customElements.define('profile-form', ProfileForm) ``` -Be aware that you need -to handle updating the element and form yourself as seen in the example above. +The important pieces are: + +- `defaultValues` define the complete initial value and drive type inference. +- `form.field(...)` subscribes only its Lit child part to one field. Its render + callback exposes `field.value`, `field.meta`, and event handlers. +- Validators are ordered objects with a `run` function and explicit + `triggers`. +- `form.subscribe(...)` updates only its child part when the selected form state + changes. +- The public form API is available through `form.api`; calling + `form.api.handleSubmit()` validates before running `onSubmit`. diff --git a/docs/framework/lit/reference/classes/TanStackFormController.md b/docs/framework/lit/reference/classes/TanStackFormController.md index 91e62aa15c..8e966931cf 100644 --- a/docs/framework/lit/reference/classes/TanStackFormController.md +++ b/docs/framework/lit/reference/classes/TanStackFormController.md @@ -3,73 +3,71 @@ id: TanStackFormController title: TanStackFormController --- -# Class: TanStackFormController\ +Defined in: [tanstack-form-controller.ts:209](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L209) -Defined in: [tanstack-form-controller.ts:226](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L226) +Owns a form for a Lit reactive-controller host and provides Lit-specific +field, form-group, and subscription render helpers. -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +`defaultValues` establish the initial state and inferred form value type. +The form mounts when its host connects and is cleaned up when the host +disconnects. Call `update(...)` to apply later options without replacing the +form instance, and access the framework-agnostic form API through `api`. -### TFormOnChangeAsync +## Example -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +```ts +class ProfileForm extends LitElement { + private form = new TanStackFormController(this, { + defaultValues: { name: '' }, + onSubmit: ({ value }) => saveProfile(value), + }) + + render() { + return html`
    { + event.preventDefault() + void this.form.api.handleSubmit() + }} + >
    ` + } +} +``` -### TFormOnSubmitAsync +## Type Parameters -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +### TFormData -### TFormOnDynamic +`TFormData` -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +Library-managed. Do not specify explicitly. -### TFormOnDynamicAsync +### TFormValidators -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> -### TFormOnServer +Library-managed. Do not specify explicitly. -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +### TSubmitReturn -### TSubmitMeta +`TSubmitReturn` -`TSubmitMeta` +Library-managed. Do not specify explicitly. ## Implements - `ReactiveController` +- [`LitFieldMethods`](../interfaces/LitFieldMethods.md)\<`TFormData`, `never`, `TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>\> +- [`LitSubscribeMethod`](../interfaces/LitSubscribeMethod.md)\<`FormState`\<`TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>\>\> ## Constructors ### Constructor ```ts -new TanStackFormController(host, config?): TanStackFormController; +new TanStackFormController(host, options): TanStackFormController; ``` -Defined in: [tanstack-form-controller.ts:255](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L255) +Defined in: [tanstack-form-controller.ts:241](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L241) #### Parameters @@ -77,195 +75,144 @@ Defined in: [tanstack-form-controller.ts:255](https://github.com/TanStack/form/b `ReactiveControllerHost` -##### config? +The Lit host that owns the controller and form lifecycle. + +##### options -`FormOptions`\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> +`FormOptions`\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\> + +The initial form options. `defaultValues` drive form value +inference. #### Returns -`TanStackFormController`\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> +`TanStackFormController`\<`TFormData`, `TFormValidators`, `TSubmitReturn`\> -## Properties +## Accessors ### api +#### Get Signature + ```ts -api: FormApi; +get api(): FormApi>; ``` -Defined in: [tanstack-form-controller.ts:240](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L240) +Defined in: [tanstack-form-controller.ts:229](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L229) + +##### Returns + +`FormApi`\<`TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>\> ## Methods -### field() +### arrayField() ```ts -field(fieldConfig, render): object; +arrayField(options, render): unknown; ``` -Defined in: [tanstack-form-controller.ts:300](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L300) +Defined in: [tanstack-form-controller.ts:308](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L308) #### Type Parameters -##### TName - -`TName` *extends* `string` - -##### TData - -`TData` - -##### TOnMount - -`TOnMount` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` +##### TFieldName -##### TOnChange +`TFieldName` *extends* `never` -`TOnChange` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` +##### TFieldValidators -##### TOnChangeAsync - -`TOnChangeAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -##### TOnBlur - -`TOnBlur` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -##### TOnBlurAsync - -`TOnBlurAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -##### TOnSubmit - -`TOnSubmit` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -##### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -##### TOnDynamic - -`TOnDynamic` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -##### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` +`TFieldValidators` *extends* `FieldValidators`\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>\> #### Parameters -##### fieldConfig +##### options -`FieldOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`\> +`LitFieldOptions`\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>\> ##### render -`renderCallback`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> +`RenderCallback`\<`LitFieldRenderApi`\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>\>\> #### Returns -`object` - -##### values - -```ts -values: object; -``` - -###### values.form - -```ts -form: FormApi; -``` - -###### values.options +`unknown` -```ts -options: FieldOptions; -``` +#### Implementation of -###### values.render - -```ts -render: renderCallback; -``` +[`LitFieldMethods`](../interfaces/LitFieldMethods.md).[`arrayField`](../interfaces/LitFieldMethods.md#arrayfield) *** -### group() +### field() ```ts -group(groupConfig, render): unknown; +field(options, render): unknown; ``` -Defined in: [tanstack-form-controller.ts:390](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L390) +Defined in: [tanstack-form-controller.ts:271](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L271) #### Type Parameters -##### TName +##### TFieldName -`TName` *extends* `string` +`TFieldName` *extends* `string` -##### TData +##### TFieldValidators -`TData` +`TFieldValidators` *extends* `FieldValidators`\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>\> -##### TOnMount +#### Parameters -`TOnMount` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` +##### options -##### TOnChange +`LitFieldOptions`\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>\> -`TOnChange` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` +##### render -##### TOnChangeAsync +`RenderCallback`\<`LitFieldRenderApi`\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>\>\> -`TOnChangeAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` +#### Returns -##### TOnBlur +`unknown` -`TOnBlur` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` +#### Implementation of -##### TOnBlurAsync +[`LitFieldMethods`](../interfaces/LitFieldMethods.md).[`field`](../interfaces/LitFieldMethods.md#field) -`TOnBlurAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` +*** -##### TOnSubmit +### formGroup() -`TOnSubmit` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` +```ts +formGroup(options, render): unknown; +``` -##### TOnSubmitAsync +Defined in: [tanstack-form-controller.ts:358](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L358) -`TOnSubmitAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` +#### Type Parameters -##### TOnDynamic +##### TGroupName -`TOnDynamic` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` +`TGroupName` *extends* `string` -##### TOnDynamicAsync +##### TGroupValue -`TOnDynamicAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` +`TGroupValue` -##### TGroupSubmitMeta +##### TGroupValidators -`TGroupSubmitMeta` +`TGroupValidators` *extends* `FormGroupValidators`\<`TGroupValue`\> #### Parameters -##### groupConfig +##### options -`Omit`\<`FormGroupApiOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TGroupSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\>, `"form"`\> +`Omit`\<`FormGroupOptions`\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupValidators`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>\>, `"form"`\> ##### render -`groupRenderCallback`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TGroupSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> +`RenderCallback`\<[`LitFormGroupApi`](../type-aliases/LitFormGroupApi.md)\<`TFormData`, `TGroupName`, `TGroupValue`, `ToFormGroupErrorTypes`\<`TGroupValidators`\>, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>\>\> #### Returns @@ -279,7 +226,7 @@ Defined in: [tanstack-form-controller.ts:390](https://github.com/TanStack/form/b hostConnected(): void; ``` -Defined in: [tanstack-form-controller.ts:296](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L296) +Defined in: [tanstack-form-controller.ts:250](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L250) Called when the host is connected to the component tree. For custom element hosts, this corresponds to the `connectedCallback()` lifecycle, @@ -303,7 +250,7 @@ ReactiveController.hostConnected hostDisconnected(): void; ``` -Defined in: [tanstack-form-controller.ts:298](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L298) +Defined in: [tanstack-form-controller.ts:255](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L255) Called when the host is disconnected from the component tree. For custom element hosts, this corresponds to the `disconnectedCallback()` lifecycle, @@ -319,3 +266,66 @@ document. ```ts ReactiveController.hostDisconnected ``` + +*** + +### subscribe() + +```ts +subscribe( + selector, + render, + when?): unknown; +``` + +Defined in: [tanstack-form-controller.ts:345](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L345) + +#### Type Parameters + +##### TSelected + +`TSelected` + +#### Parameters + +##### selector + +(`state`) => `TSelected` + +##### render + +`RenderCallback`\<`NoInfer`\<`TSelected`\>\> + +##### when? + +(`selected`) => `boolean` + +#### Returns + +`unknown` + +#### Implementation of + +[`LitSubscribeMethod`](../interfaces/LitSubscribeMethod.md).[`subscribe`](../interfaces/LitSubscribeMethod.md#subscribe) + +*** + +### update() + +```ts +update(options): void; +``` + +Defined in: [tanstack-form-controller.ts:265](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L265) + +Updates reactive form options without replacing the form instance. + +#### Parameters + +##### options + +`FormOptions`\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\> + +#### Returns + +`void` diff --git a/docs/framework/lit/reference/functions/getFormType.md b/docs/framework/lit/reference/functions/getFormType.md index a155439db2..2e919043cd 100644 --- a/docs/framework/lit/reference/functions/getFormType.md +++ b/docs/framework/lit/reference/functions/getFormType.md @@ -3,105 +3,27 @@ id: getFormType title: getFormType --- -# Function: getFormType() - ```ts -function getFormType(_formOptions): TanStackFormController; +function getFormType(_formOptions): LitFormType; ``` -Defined in: [getFormType.ts:43](https://github.com/TanStack/form/blob/main/packages/lit-form/src/getFormType.ts#L43) - -A type-only helper that returns a value whose type matches the -`TanStackFormController` instance that would be produced for the given -`FormOptions`. It does not run any logic at runtime. +Defined in: [get-form-type.ts:76](https://github.com/TanStack/form/blob/main/packages/lit-form/src/get-form-type.ts#L76) -Use this together with shared `formOptions` to derive the expected -controller type for a `form` property on a child Lit element, without -having to spell out all of `TanStackFormController`'s generics by hand. +Type-only helper for declaring a child element's form property from shared +`formOptions`. It intentionally has no runtime value. ## Type Parameters -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamic +### TOptions -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` +`TOptions` *extends* `AnyFormOptions` ## Parameters ### \_formOptions -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> +`TOptions` ## Returns -[`TanStackFormController`](../classes/TanStackFormController.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -## Example - -```ts -import { formOptions, getFormType } from '@tanstack/lit-form' - -export const peopleFormOpts = formOptions({ - defaultValues: { firstName: '', lastName: '' }, -}) - -// In a child element: -class ChildForm extends LitElement { - @property({ attribute: false }) - form!: ReturnType> -} -``` - -Most users will pass `formOptions` directly: - -```ts -const formType = getFormType(peopleFormOpts) - -class ChildForm extends LitElement { - @property({ attribute: false }) - form!: typeof formType -} -``` +[`LitFormType`](../type-aliases/LitFormType.md)\<`TOptions`\> diff --git a/docs/framework/lit/reference/index.md b/docs/framework/lit/reference/index.md index 2c8b6d0b9f..1368aa8395 100644 --- a/docs/framework/lit/reference/index.md +++ b/docs/framework/lit/reference/index.md @@ -3,12 +3,32 @@ id: "@tanstack/lit-form" title: "@tanstack/lit-form" --- -# @tanstack/lit-form - ## Classes - [TanStackFormController](classes/TanStackFormController.md) +## Interfaces + +- [FieldGroupDefinition](interfaces/FieldGroupDefinition.md) +- [LitFieldMethods](interfaces/LitFieldMethods.md) +- [LitSubscribeMethod](interfaces/LitSubscribeMethod.md) + +## Type Aliases + +- [AnyLitFormApi](type-aliases/AnyLitFormApi.md) +- [DefineFieldGroupFn](type-aliases/DefineFieldGroupFn.md) +- [FieldGroupFieldBindingsOf](type-aliases/FieldGroupFieldBindingsOf.md) +- [FieldGroupFieldsOf](type-aliases/FieldGroupFieldsOf.md) +- [FieldGroupWithFieldsFn](type-aliases/FieldGroupWithFieldsFn.md) +- [LitFieldGroup](type-aliases/LitFieldGroup.md) +- [LitFieldGroupApi](type-aliases/LitFieldGroupApi.md) +- [LitFormGroupApi](type-aliases/LitFormGroupApi.md) +- [LitFormType](type-aliases/LitFormType.md) + +## Variables + +- [defineFieldGroup](variables/defineFieldGroup.md) + ## Functions - [getFormType](functions/getFormType.md) diff --git a/docs/framework/lit/reference/interfaces/FieldGroupDefinition.md b/docs/framework/lit/reference/interfaces/FieldGroupDefinition.md new file mode 100644 index 0000000000..49c7535aa9 --- /dev/null +++ b/docs/framework/lit/reference/interfaces/FieldGroupDefinition.md @@ -0,0 +1,36 @@ +--- +id: FieldGroupDefinition +title: FieldGroupDefinition +--- + +Defined in: [with-fields.ts:82](https://github.com/TanStack/form/blob/main/packages/lit-form/src/with-fields.ts#L82) + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +## Properties + +### bindComponent + +```ts +bindComponent: FieldGroupWithFieldsFn>; +``` + +Defined in: [with-fields.ts:86](https://github.com/TanStack/form/blob/main/packages/lit-form/src/with-fields.ts#L86) + +Binds a renderer's virtual field API to concrete paths in a form. + +*** + +### fields + +```ts +fields: LitFieldGroup; +``` + +Defined in: [with-fields.ts:84](https://github.com/TanStack/form/blob/main/packages/lit-form/src/with-fields.ts#L84) + +The virtual field-group API injected into the bound renderer. diff --git a/docs/framework/lit/reference/interfaces/LitFieldMethods.md b/docs/framework/lit/reference/interfaces/LitFieldMethods.md new file mode 100644 index 0000000000..eab07648af --- /dev/null +++ b/docs/framework/lit/reference/interfaces/LitFieldMethods.md @@ -0,0 +1,92 @@ +--- +id: LitFieldMethods +title: LitFieldMethods +--- + +Defined in: [tanstack-form-controller.ts:81](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L81) + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TGroupFieldError + +`TGroupFieldError` + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +## Methods + +### arrayField() + +```ts +arrayField(options, render): unknown; +``` + +Defined in: [tanstack-form-controller.ts:117](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L117) + +#### Type Parameters + +##### TFieldName + +`TFieldName` *extends* `never` + +##### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\> + +#### Parameters + +##### options + +`LitFieldOptions`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `TFieldValidators`, `TGroupFieldError`, `TFormData`, `TFormErrorTypes`\> + +##### render + +`RenderCallback`\<`LitFieldRenderApi`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `TFieldValidators`, `TGroupFieldError`, `TFormData`, `TFormErrorTypes`\>\> + +#### Returns + +`unknown` + +*** + +### field() + +```ts +field(options, render): unknown; +``` + +Defined in: [tanstack-form-controller.ts:87](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L87) + +#### Type Parameters + +##### TFieldName + +`TFieldName` *extends* `string` + +##### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\> + +#### Parameters + +##### options + +`LitFieldOptions`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `TFieldValidators`, `TGroupFieldError`, `TFormData`, `TFormErrorTypes`\> + +##### render + +`RenderCallback`\<`LitFieldRenderApi`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `TFieldValidators`, `TGroupFieldError`, `TFormData`, `TFormErrorTypes`\>\> + +#### Returns + +`unknown` diff --git a/docs/framework/lit/reference/interfaces/LitSubscribeMethod.md b/docs/framework/lit/reference/interfaces/LitSubscribeMethod.md new file mode 100644 index 0000000000..3330896334 --- /dev/null +++ b/docs/framework/lit/reference/interfaces/LitSubscribeMethod.md @@ -0,0 +1,49 @@ +--- +id: LitSubscribeMethod +title: LitSubscribeMethod +--- + +Defined in: [tanstack-form-controller.ts:148](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L148) + +## Type Parameters + +### TState + +`TState` + +## Methods + +### subscribe() + +```ts +subscribe( + selector, + render, + when?): unknown; +``` + +Defined in: [tanstack-form-controller.ts:149](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L149) + +#### Type Parameters + +##### TSelected + +`TSelected` + +#### Parameters + +##### selector + +(`state`) => `TSelected` + +##### render + +`RenderCallback`\<`NoInfer`\<`TSelected`\>\> + +##### when? + +(`selected`) => `boolean` + +#### Returns + +`unknown` diff --git a/docs/framework/lit/reference/type-aliases/AnyLitFormApi.md b/docs/framework/lit/reference/type-aliases/AnyLitFormApi.md new file mode 100644 index 0000000000..35ef639f15 --- /dev/null +++ b/docs/framework/lit/reference/type-aliases/AnyLitFormApi.md @@ -0,0 +1,33 @@ +--- +id: AnyLitFormApi +title: AnyLitFormApi +--- + +```ts +type AnyLitFormApi = TanStackFormController; +``` + +Defined in: [get-form-type.ts:31](https://github.com/TanStack/form/blob/main/packages/lit-form/src/get-form-type.ts#L31) + +A Lit form controller whose form data, validator, and submit types are +erased. + +Use it for reusable render helpers that only need controller operations +common to every form. Field paths and values are not checked against a +particular form shape; use `LitFormType` when a helper depends on one known +form. + +## Example + +```ts +function formSubmitButton(form: AnyLitFormApi) { + return form.subscribe( + (state) => state.isSubmitting, + (isSubmitting) => html` + + `, + ) +} +``` diff --git a/docs/framework/lit/reference/type-aliases/DefineFieldGroupFn.md b/docs/framework/lit/reference/type-aliases/DefineFieldGroupFn.md new file mode 100644 index 0000000000..ee84b1f743 --- /dev/null +++ b/docs/framework/lit/reference/type-aliases/DefineFieldGroupFn.md @@ -0,0 +1,26 @@ +--- +id: DefineFieldGroupFn +title: DefineFieldGroupFn +--- + +```ts +type DefineFieldGroupFn = (defineFn) => FieldGroupDefinition; +``` + +Defined in: [with-fields.ts:89](https://github.com/TanStack/form/blob/main/packages/lit-form/src/with-fields.ts#L89) + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +## Parameters + +### defineFn + +(`helper`) => `TFields` + +## Returns + +[`FieldGroupDefinition`](../interfaces/FieldGroupDefinition.md)\<`TFields`\> diff --git a/docs/framework/lit/reference/type-aliases/FieldGroupFieldBindingsOf.md b/docs/framework/lit/reference/type-aliases/FieldGroupFieldBindingsOf.md new file mode 100644 index 0000000000..727fa49b28 --- /dev/null +++ b/docs/framework/lit/reference/type-aliases/FieldGroupFieldBindingsOf.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupFieldBindingsOf +title: FieldGroupFieldBindingsOf +--- + +```ts +type FieldGroupFieldBindingsOf = FieldGroupFieldsOf extends FieldGroupFields ? FieldGroupFieldBindings, TFormData> : never; +``` + +Defined in: [with-fields.ts:55](https://github.com/TanStack/form/blob/main/packages/lit-form/src/with-fields.ts#L55) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` + +### TFormData + +`TFormData` diff --git a/docs/framework/lit/reference/type-aliases/FieldGroupFieldsOf.md b/docs/framework/lit/reference/type-aliases/FieldGroupFieldsOf.md new file mode 100644 index 0000000000..c8a3aa961a --- /dev/null +++ b/docs/framework/lit/reference/type-aliases/FieldGroupFieldsOf.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupFieldsOf +title: FieldGroupFieldsOf +--- + +```ts +type FieldGroupFieldsOf = TFieldGroup extends object ? TFields : never; +``` + +Defined in: [with-fields.ts:43](https://github.com/TanStack/form/blob/main/packages/lit-form/src/with-fields.ts#L43) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` diff --git a/docs/framework/lit/reference/type-aliases/FieldGroupWithFieldsFn.md b/docs/framework/lit/reference/type-aliases/FieldGroupWithFieldsFn.md new file mode 100644 index 0000000000..f41edfdafd --- /dev/null +++ b/docs/framework/lit/reference/type-aliases/FieldGroupWithFieldsFn.md @@ -0,0 +1,40 @@ +--- +id: FieldGroupWithFieldsFn +title: FieldGroupWithFieldsFn +--- + +```ts +type FieldGroupWithFieldsFn = (render, fieldsPropName) => (props) => unknown; +``` + +Defined in: [with-fields.ts:62](https://github.com/TanStack/form/blob/main/packages/lit-form/src/with-fields.ts#L62) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` *extends* `object` + +## Type Parameters + +### TProps + +`TProps` *extends* `object` + +### TFieldsPropName + +`TFieldsPropName` *extends* `FieldGroupFieldsPropName`\<`TProps`, `TFieldGroup`\> + +## Parameters + +### render + +(`props`) => `unknown` + +### fieldsPropName + +`TFieldsPropName` + +## Returns + +\<`TFormData`\>(`props`) => `unknown` diff --git a/docs/framework/lit/reference/type-aliases/LitFieldGroup.md b/docs/framework/lit/reference/type-aliases/LitFieldGroup.md new file mode 100644 index 0000000000..5db896891c --- /dev/null +++ b/docs/framework/lit/reference/type-aliases/LitFieldGroup.md @@ -0,0 +1,24 @@ +--- +id: LitFieldGroup +title: LitFieldGroup +--- + +```ts +type LitFieldGroup = LitFieldGroupApi> & object; +``` + +Defined in: [with-fields.ts:49](https://github.com/TanStack/form/blob/main/packages/lit-form/src/with-fields.ts#L49) + +## Type Declaration + +### \[fieldGroupFieldsSymbol\] + +```ts +readonly [fieldGroupFieldsSymbol]: TFields; +``` + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` diff --git a/docs/framework/lit/reference/type-aliases/LitFieldGroupApi.md b/docs/framework/lit/reference/type-aliases/LitFieldGroupApi.md new file mode 100644 index 0000000000..840d39f2da --- /dev/null +++ b/docs/framework/lit/reference/type-aliases/LitFieldGroupApi.md @@ -0,0 +1,24 @@ +--- +id: LitFieldGroupApi +title: LitFieldGroupApi +--- + +```ts +type LitFieldGroupApi = LitFieldMethods & LitSubscribeMethod & FormApiFieldMethods & FormApiArrayMethods & object; +``` + +Defined in: [with-fields.ts:31](https://github.com/TanStack/form/blob/main/packages/lit-form/src/with-fields.ts#L31) + +## Type Declaration + +### atom + +```ts +atom: ReadonlyAtom; +``` + +## Type Parameters + +### TFieldData + +`TFieldData` diff --git a/docs/framework/lit/reference/type-aliases/LitFormGroupApi.md b/docs/framework/lit/reference/type-aliases/LitFormGroupApi.md new file mode 100644 index 0000000000..55cc02f96b --- /dev/null +++ b/docs/framework/lit/reference/type-aliases/LitFormGroupApi.md @@ -0,0 +1,32 @@ +--- +id: LitFormGroupApi +title: LitFormGroupApi +--- + +```ts +type LitFormGroupApi = FormGroupApi & LitFieldMethods & LitSubscribeMethod>; +``` + +Defined in: [tanstack-form-controller.ts:156](https://github.com/TanStack/form/blob/main/packages/lit-form/src/tanstack-form-controller.ts#L156) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` diff --git a/docs/framework/lit/reference/type-aliases/LitFormType.md b/docs/framework/lit/reference/type-aliases/LitFormType.md new file mode 100644 index 0000000000..ee3c890d90 --- /dev/null +++ b/docs/framework/lit/reference/type-aliases/LitFormType.md @@ -0,0 +1,41 @@ +--- +id: LitFormType +title: LitFormType +--- + +```ts +type LitFormType = TOptions extends FormOptions ? TanStackFormController> : never; +``` + +Defined in: [get-form-type.ts:58](https://github.com/TanStack/form/blob/main/packages/lit-form/src/get-form-type.ts#L58) + +Derives the Lit form controller type represented by a reusable options +object. + +Use it to type child element properties and render helpers that belong to one +known form shape. Options such as `onSubmit` can be defined either in the +shared options or when the form is created in the component. + +## Type Parameters + +### TOptions + +`TOptions` *extends* `AnyFormOptions` + +The reusable form options from which the controller derives its form data, validator, and submit-result types. + +## Example + +```ts +const profileOptions = formOptions({ + defaultValues: { name: '' }, +}) + +type ProfileForm = LitFormType + +function nameField(form: ProfileForm) { + return form.field({ name: 'name' }, (field) => html` + + `) +} +``` diff --git a/docs/framework/lit/reference/variables/defineFieldGroup.md b/docs/framework/lit/reference/variables/defineFieldGroup.md new file mode 100644 index 0000000000..645fe4a364 --- /dev/null +++ b/docs/framework/lit/reference/variables/defineFieldGroup.md @@ -0,0 +1,10 @@ +--- +id: defineFieldGroup +title: defineFieldGroup +--- + +```ts +const defineFieldGroup: DefineFieldGroupFn; +``` + +Defined in: [with-fields.ts:196](https://github.com/TanStack/form/blob/main/packages/lit-form/src/with-fields.ts#L196) diff --git a/docs/framework/preact/guides/arrays.md b/docs/framework/preact/guides/arrays.md deleted file mode 100644 index 499a2000e4..0000000000 --- a/docs/framework/preact/guides/arrays.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -id: arrays -title: Arrays ---- - -TanStack Form supports arrays as values in a form, including sub-object values inside of an array. - -## Basic Usage - -To use an array, you can use `field.state.value` on an array value: - -```jsx -function App() { - const form = useForm({ - defaultValues: { - people: [], - }, - }) - - return ( - - {(field) => ( -
    - {field.state.value.map((_, i) => { - // ... - })} -
    - )} -
    - ) -} -``` - -This will generate the mapped JSX every time you run `pushValue` on `field`: - -```jsx - -``` - -Finally, you can use a subfield like so: - -```jsx - - {(subField) => ( - subField.handleChange(e.target.value)} - /> - )} - -``` - -## Full Example - -```jsx -function App() { - const form = useForm({ - defaultValues: { - people: [], - }, - onSubmit({ value }) { - alert(JSON.stringify(value)) - }, - }) - - return ( -
    -
    { - e.preventDefault() - e.stopPropagation() - form.handleSubmit() - }} - > - - {(field) => { - return ( -
    - {field.state.value.map((_, i) => { - return ( - - {(subField) => { - return ( -
    - -
    - ) - }} -
    - ) - })} - -
    - ) - }} -
    - [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( - - )} - /> - -
    - ) -} -``` diff --git a/docs/framework/preact/guides/async-initial-values.md b/docs/framework/preact/guides/async-initial-values.md index 6ebf4ae069..da8fddf97b 100644 --- a/docs/framework/preact/guides/async-initial-values.md +++ b/docs/framework/preact/guides/async-initial-values.md @@ -3,49 +3,120 @@ id: async-initial-values title: Async Initial Values --- -Let's say that you want to fetch some data from an API and use it as the initial value of a form. +Forms often edit data loaded from an API. A server-state library such as +TanStack Query should own fetching, caching, loading, and retries; TanStack Form +should own the editable copy. -While this problem sounds simple on the surface, there are hidden complexities you might not have thought of thus far. +TanStack Query does not publish a separate Preact adapter. With +`@preact/preset-vite`, use `@tanstack/react-query` through Preact's compatibility +aliases, as shown below and in the repository example. -For example, you might want to show a loading spinner while the data is being fetched, or you might want to handle errors gracefully. -Likewise, you could also find yourself looking for a way to cache the data so that you don't have to fetch it every time the form is rendered. +There are two supported ways to provide async initial values: wait to create the +form until the data is ready, or create it immediately with complete fallback +values. Choose the approach that best matches the loading experience your UI +needs. -While we could implement many of these features from scratch, it would end up looking a lot like another project we maintain: [TanStack Query](https://tanstack.com/query). +## Wait for data before creating the editor -As such, this guide shows you how you can mix-n-match TanStack Form with TanStack Query to achieve the desired behavior. - -## Basic Usage +Render a loading or error state first, then mount a component whose +`defaultValues` are complete. ```tsx -import { useForm } from '@tanstack/preact-form' import { useQuery } from '@tanstack/react-query' +import { useForm } from '@tanstack/preact-form' -export default function App() { - const {data, isLoading} = useQuery({ - queryKey: ['data'], - queryFn: async () => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return {firstName: 'FirstName', lastName: "LastName"} - } +type User = { + firstName: string + lastName: string +} + +export function UserPage({ userId }: { userId: string }) { + const userQuery = useQuery({ + queryKey: ['user', userId], + queryFn: () => fetch(`/api/users/${userId}`).then((res) => res.json()), }) + if (userQuery.isPending) return

    Loading…

    + if (userQuery.isError) return

    Could not load the user.

    + + return +} + +function UserEditor({ user }: { user: User }) { const form = useForm({ - defaultValues: { - firstName: data?.firstName ?? '', - lastName: data?.lastName ?? '', + defaultValues: user, + onSubmit: async ({ value }) => { + await fetch('/api/users', { + method: 'PUT', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(value), + }) }, + }) + + return
    {/* fields */}
    +} +``` + +This pattern is useful when no form state is needed during loading. Mounting the +editor only after data exists also makes it explicit when switching records +should create a fresh form. + +## Create the form before data arrives + +You can instead call `useForm` in the same component as `useQuery`. Provide a +static, shape-complete fallback so `defaultValues` are never `undefined`. + +```tsx +const emptyUser: User = { + firstName: '', + lastName: '', +} + +export function UserPage({ userId }: { userId: string }) { + const userQuery = useQuery({ + queryKey: ['user', userId], + queryFn: () => fetch(`/api/users/${userId}`).then((res) => res.json()), + }) + + const form = useForm({ + defaultValues: userQuery.data ?? emptyUser, onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) + await fetch('/api/users', { + method: 'PUT', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(value), + }) }, }) - if (isLoading) return

    Loading...

    + if (userQuery.isPending) return

    Loading…

    + if (userQuery.isError) return

    Could not load the user.

    - return ( - // ... - ) + return
    {/* fields */}
    } ``` -This will show a loading spinner until the data is fetched, and then it will render the form with the fetched data as the initial values. +When the query data replaces the fallback, TanStack Form applies the new +`defaultValues` to untouched fields while preserving fields the user has +already touched. In this example, the fields remain unmounted during loading, +so the user cannot edit them before the loaded values arrive. You can also +render the empty form immediately when that better suits the UI. + +This is the approach demonstrated by the repository's +`examples/preact/query-integration` example. + +## Background refetches and record changes + +`defaultValues` establish the form's baseline; they are not a fully controlled +`values` prop. In the fallback pattern, later `defaultValues` updates use the +same touched-field-preserving behavior. + +If background refetches arrive while a user is editing, decide at the product +level whether to keep local edits, prompt before replacing them, or call +`form.reset(nextValues)` deliberately. Do not overwrite in-progress input merely +because a query refreshed. + +When switching to a different record, either remount a keyed editor as in the +first pattern or deliberately reset the existing form. Otherwise, touched +values from the previous record can be preserved when the new defaults arrive. diff --git a/docs/framework/preact/guides/basic-concepts.md b/docs/framework/preact/guides/basic-concepts.md deleted file mode 100644 index 1b35934d25..0000000000 --- a/docs/framework/preact/guides/basic-concepts.md +++ /dev/null @@ -1,404 +0,0 @@ ---- -id: basic-concepts -title: Basic Concepts and Terminology ---- - -This page introduces the basic concepts and terminology used in the `@tanstack/preact-form` library. Familiarizing yourself with these concepts will help you better understand and work with the library. - -## Form Options - -You can customize your form by creating configuration options with the `formOptions` function. These options can be shared between multiple forms. - -Example: - -```tsx -interface User { - firstName: string - lastName: string - hobbies: Array -} -const defaultUser: User = { firstName: '', lastName: '', hobbies: [] } - -const formOpts = formOptions({ - defaultValues: defaultUser, -}) -``` - -## Form Instance - -A Form instance is an object that represents an individual form and provides methods and properties for working with the form. You create a Form instance using the `useForm` hook provided by the form options. The hook accepts an object with an `onSubmit` function, which is called when the form is submitted. - -```tsx -const form = useForm({ - ...formOpts, - onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) - }, -}) -``` - -You may also create a Form instance without using `formOptions` by using the standalone `useForm` API: - -```tsx -interface User { - firstName: string - lastName: string - hobbies: Array -} -const defaultUser: User = { firstName: '', lastName: '', hobbies: [] } - -const form = useForm({ - defaultValues: defaultUser, - onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) - }, -}) -``` - -## Field - -A Field represents a single form input element, such as a text input or a checkbox. Fields are created using the `form.Field` component provided by the Form instance. The component accepts a `name` prop, which should match a key in the form's default values. It also accepts a `children` prop, which is a render prop function that takes a `field` object as its argument. - -Example: - -```tsx - ( - <> - field.handleChange(e.target.value)} - /> - - - )} -/> -``` - -If you run into issues handling `children` as props, make sure to check your linting rules. - -Example (ESLint): - -```json - "rules": { - "react/no-children-prop": [ - true, - { - "allowFunctions": true - } - ], - } -``` - -## Field State - -Each field has its own state, which includes its current value, validation status, error messages, and other metadata. You can access a field's state using the `field.state` property. - -Example: - -```ts -const { - value, - meta: { errors, isValidating }, -} = field.state -``` - -There are four states in the metadata that can be useful for seeing how the user interacts with a field: - -- **isTouched**: is `true` once the user changes or blurs the field -- **isDirty**: is `true` once the field's value is changed, even if it's reverted to the default. Opposite of `isPristine` -- **isPristine**: is `true` until the user changes the field's value. Opposite of `isDirty` -- **isBlurred**: is `true` once the field loses focus (is blurred) -- **isDefaultValue**: is `true` when the field's current value is the default value - -```ts -const { isTouched, isDirty, isPristine, isBlurred } = field.state.meta -``` - -![Field states](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states.png) - -## Understanding 'isDirty' in Different Libraries - -Non-Persistent `dirty` state - -- **Libraries**: React Hook Form (RHF), Formik, Final Form. -- **Behavior**: A field is 'dirty' if its value differs from the default. Reverting to the default value makes it 'clean' again. - -Persistent `dirty` state - -- **Libraries**: Angular Form, Vue FormKit. -- **Behavior**: A field remains 'dirty' once changed, even if reverted to the default value. - -We have chosen the persistent 'dirty' state model. However, we have introduced the `isDefaultValue` flag to also support a non-persistent 'dirty' state. - -```ts -const { isDefaultValue, isTouched } = field.state.meta - -// The following line will re-create the non-persistent `dirty` functionality. -const nonPersistentIsDirty = !isDefaultValue -``` - -![Field states extended](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states-extended.png) - -## Field API - -The Field API is an object passed to the render prop function when creating a field. It provides methods for working with the field's state. - -Example: - -```tsx - field.handleChange(e.target.value)} -/> -``` - -## Validation - -`@tanstack/preact-form` provides both synchronous and asynchronous validation out of the box. Validation functions can be passed to the `form.Field` component using the `validators` prop. - -Example: - -```tsx - - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined, - onChangeAsync: async ({ value }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value.includes('error') && 'No "error" allowed in first name' - }, - }} - children={(field) => ( - <> - field.handleChange(e.target.value)} - /> - - - )} -/> -``` - -## Validation with Standard Schema Libraries - -In addition to hand-rolled validation options, we also support the [Standard Schema](https://github.com/standard-schema/standard-schema) specification. - -You can define a schema using any of the libraries implementing the specification and pass it to a form or field validator. - -Supported libraries include: - -- [Zod](https://zod.dev/) (v3.24.0 or higher) -- [Valibot](https://valibot.dev/) (v1.0.0 or higher) -- [ArkType](https://arktype.io/) (v2.1.20 or higher) -- [Yup](https://github.com/jquense/yup) (v1.7.0 or higher) - -```tsx -import { z } from 'zod' - -const userSchema = z.object({ - age: z.number().gte(13, 'You must be 13 to make an account'), -}) - -function App() { - const form = useForm({ - defaultValues: { - age: 0, - }, - validators: { - onChange: userSchema, - }, - }) - return ( -
    - { - return <>{/* ... */} - }} - /> -
    - ) -} -``` - -## Reactivity - -`@tanstack/preact-form` offers various ways to subscribe to form and field state changes, most notably the `useSelector(form.store, …)` hook and the `form.Subscribe` component. These methods allow you to optimize your form's rendering performance by only updating components when necessary. - -Example: - -```tsx -import { useSelector } from '@tanstack/preact-form' - -const firstName = useSelector(form.store, (state) => state.values.firstName) -//... - [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( - - )} -/> -``` - -It is important to remember that while the `useSelector` hook's `selector` prop is optional, it is strongly recommended to provide one, as omitting it will result in unnecessary re-renders. - -```tsx -// Correct use -const firstName = useSelector(form.store, (state) => state.values.firstName) -const errors = useSelector(form.store, (state) => state.errorMap) -// Incorrect use -const store = useSelector(form.store) -``` - -Note: The usage of the `useField` hook to achieve reactivity is discouraged since it is designed to be used thoughtfully within the `form.Field` component. You might want to use `useSelector(form.store, …)` instead. - -## Listeners - -`@tanstack/preact-form` allows you to react to specific triggers and "listen" to them to dispatch side effects. - -Example: - -```tsx - { - console.log(`Country changed to: ${value}, resetting province`) - form.setFieldValue('province', '') - }, - }} -/> -``` - -More information can be found at [Listeners](./listeners.md) - -## Array Fields - -Array fields allow you to manage a list of values within a form, such as a list of hobbies. You can create an array field using the `form.Field` component with the `mode="array"` prop. - -When working with array fields, you can use the `pushValue`, `removeValue`, `swapValues`, and `moveValue` methods to add, remove, swap, and move a value from one index to another within the array, respectively. Additional helper methods such as `insertValue`, `replaceValue`, and `clearValues` are also available for inserting, replacing, and clearing array values. - -Example: - -```tsx - ( -
    - Hobbies -
    - {!hobbiesField.state.value.length - ? 'No hobbies found.' - : hobbiesField.state.value.map((_, i) => ( -
    - { - return ( -
    - - field.handleChange(e.target.value)} - /> - - -
    - ) - }} - /> - { - return ( -
    - - field.handleChange(e.target.value)} - /> - -
    - ) - }} - /> -
    - ))} -
    - -
    - )} -/> -``` - -## Reset Buttons - -When using ` - - ) -} -``` - -### Async Validation - -Async validation can also be used with `onDynamicAsync` just like with other validation logic. You can even debounce the async validation to avoid excessive calls. - -```tsx -const form = useForm({ - defaultValues: { - username: '', - }, - validationLogic: revalidateLogic(), - validators: { - onDynamicAsyncDebounceMs: 500, // Debounce the async validation by 500ms - onDynamicAsync: async ({ value }) => { - if (!value.username) { - return { username: 'Username is required' } - } - // Simulate an async validation - const isValid = await validateUsername(value.username) - return isValid ? undefined : { username: 'Username is already taken' } - }, - }, -}) -``` - -### Standard Schema Validation - -You can also use standard schema validation libraries like Valibot or Zod with `onDynamic` validation. This allows you to define complex validation rules that can change dynamically based on the form state. - -```tsx -import { z } from 'zod' - -const schema = z.object({ - firstName: z.string().min(1, 'A first name is required'), - lastName: z.string().min(1, 'A last name is required'), -}) - -const form = useForm({ - defaultValues: { - firstName: '', - lastName: '', - }, - validationLogic: revalidateLogic(), - validators: { - onDynamic: schema, - }, -}) -``` diff --git a/docs/framework/preact/guides/focus-management.md b/docs/framework/preact/guides/focus-management.md deleted file mode 100644 index 5f0fe9d4ab..0000000000 --- a/docs/framework/preact/guides/focus-management.md +++ /dev/null @@ -1,142 +0,0 @@ ---- -id: focus-management -title: Focus Management ---- - -In some instances, you may want to focus the first input with an error. - -[Because TanStack Form intentionally does not have insights into your markup](../../../philosophy.md), we cannot add a built-in focus management feature. - -However, you can easily add this feature into your application without this hypothetical built-in feature. - -## DOM - -```tsx -import { useForm } from '@tanstack/preact-form' -import { z } from 'zod' - -export default function App() { - const form = useForm({ - defaultValues: { age: 0 }, - validators: { - onChange: z.object({ - age: z.number().min(12), - }), - }, - onSubmit() { - alert('Submitted!') - }, - onSubmitInvalid() { - const InvalidInput = document.querySelector( - '[aria-invalid="true"]', - ) as HTMLInputElement - - InvalidInput?.focus() - }, - }) - - return ( -
    { - e.preventDefault() - e.stopPropagation() - void form.handleSubmit() - }} - > - ( - - )} - /> -
    - -
    - - ) -} -``` - -## React Native (via compat) - -Because React Native doesn't have access to the DOM's `querySelectorAll` API, we need to manually manage the element list -of the inputs. This allows us to focus the first input with an error: - -```tsx -import { useRef } from 'preact/hooks' -import { Text, View, TextInput, Button, Alert } from 'react-native' -import { useForm } from '@tanstack/preact-form' -import { z } from 'zod' - -export default function App() { - // This can be extracted to a hook that returns the `fields` ref, a `focusFirstField` function, and a `addField` function - const fields = useRef([] as Array<{ input: TextInput; name: string }>) - - const form = useForm({ - defaultValues: { age: 0 }, - validators: { - onChange: z.object({ - age: z.number().min(12), - }), - }, - onSubmit() { - Alert.alert('Submitted!') - }, - onSubmitInvalid({ formApi }) { - const errorMap = formApi.state.errorMap.onChange - const inputs = fields.current - - let firstInput - for (const input of inputs) { - if (!input || !input.input) continue - if (!!errorMap[input.name]) { - firstInput = input.input - break - } - } - firstInput?.focus() - }, - }) - - return ( - - ( - - Age - { - // fields.current needs to be manually incremented so that we know what fields are rendered or not and in what order - fields.current[0] = { input, name: field.name } - }} - style={{ - borderWidth: 1, - borderColor: '#999999', - borderRadius: 4, - marginTop: 8, - padding: 8, - }} - onChangeText={(val) => field.handleChange(Number(val))} - value={field.state.value} - /> - - )} - /> - - )} -
    - ) -} - -const { useAppForm, withForm } = createFormHook({ - fieldComponents: {}, - formComponents: { - SubscribeButton, - }, - fieldContext, - formContext, -}) - -function App() { - const form = useAppForm({ - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, - }) - - return ( - - // Notice the `AppForm` component wrapper; `AppForm` provides the required - context - - - ) -} -``` - -## Breaking big forms into smaller pieces - -Sometimes forms get very large; it's just how it goes sometimes. While TanStack Form supports large forms well, it's never fun to work with hundreds or thousands of lines of code in single files. - -To solve this, we support breaking forms into smaller pieces using the `withForm` higher-order component. - -```tsx -const { useAppForm, withForm } = createFormHook({ - fieldComponents: { - TextField, - }, - formComponents: { - SubscribeButton, - }, - fieldContext, - formContext, -}) - -const ChildForm = withForm({ - // These values are only used for type-checking, and are not used at runtime - // This allows you to `...formOpts` from `formOptions` without needing to redeclare the options - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, - // Optional, but adds props to the `render` function in addition to `form` - props: { - // These props are also set as default values for the `render` function - title: 'Child Form', - }, - render: function Render({ form, title }) { - return ( -
    -

    {title}

    - } - /> - - - -
    - ) - }, -}) - -function App() { - const form = useAppForm({ - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, - }) - - return -} -``` - -### `withForm` FAQ - -> Why a higher-order component instead of a hook? - -While hooks are the future of React, higher-order components are still a powerful tool for composition. In particular, the API of `withForm` enables us to have strong type-safety without requiring users to pass generics. - -> Why am I getting ESLint errors about hooks in `render`? - -ESLint looks for hooks in the top-level of a function, and `render` may not be recogized as a top-level component, depending on how you defined it. - -```tsx -// This will cause ESLint errors with hooks usage -const ChildForm = withForm({ - // ... - render: ({ form, title }) => { - // ... - }, -}) -``` - -```tsx -// This works fine -const ChildForm = withForm({ - // ... - render: function Render({ form, title }) { - // ... - }, -}) -``` - -### Context as a last resort - -There are cases where passing `form` with `withForm` is not feasible. You may encounter it with components that don't -allow you to change their props. - -For example, consider the following TanStack Router usage: - -```ts -function RouteComponent() { - const form = useAppForm({...formOptions, /* ... */ }) - // cannot be customized or receive additional props - return -} -``` - -In edge cases like this, a context-based fallback is available to access the form instance. - -```ts -const { useAppForm, useTypedAppFormContext } = createFormHook({ - fieldContext, - formContext, - fieldComponents: {}, - formComponents: {}, -}) -``` - -> [!IMPORTANT] Type safety -> This mechanism exists solely to bridge integration constraints and should be avoided whenever `withForm` is possible. -> Context will not warn you when the types do not align. You risk runtime errors with this implementation. - -Usage: - -```tsx -// sharedOpts.ts -const formOpts = formOptions({ - /* ... */ -}) - -function ParentComponent() { - const form = useAppForm({ ...formOptions /* ... */ }) - - return ( - - - - ) -} - -function ChildComponent() { - const form = useTypedAppFormContext({ ...formOptions }) - - // You now have access to form components, field components and fields -} -``` - -## Reusing groups of fields in multiple forms - -Sometimes, a pair of fields are so closely related that it makes sense to group and reuse them — like the password example listed in the [linked fields guide](./linked-fields.md). Instead of repeating this logic across multiple forms, you can utilize the `withFieldGroup` higher-order component. - -> Unlike `withForm`, validators cannot be specified and could be any value. -> Ensure that your fields can accept unknown error types. - -Rewriting the passwords example using `withFieldGroup` would look like this: - -```tsx -const { useAppForm, withForm, withFieldGroup } = createFormHook({ - fieldComponents: { - TextField, - ErrorInfo, - }, - formComponents: { - SubscribeButton, - }, - fieldContext, - formContext, -}) - -type PasswordFields = { - password: string - confirm_password: string -} - -// These default values are not used at runtime, but the keys are needed for mapping purposes. -// This allows you to spread `formOptions` without needing to redeclare it. -const defaultValues: PasswordFields = { - password: '', - confirm_password: '', -} - -const FieldGroupPasswordFields = withFieldGroup({ - defaultValues, - // You may also restrict the group to only use forms that implement this submit meta. - // If none is provided, any form with the right defaultValues may use it. - // onSubmitMeta: { action: '' } - - // Optional, but adds props to the `render` function in addition to `form` - props: { - // These props are set as default values for the `render` function - title: 'Password', - }, - // Internally, you will have access to a `group` instead of a `form` - render: function Render({ group, title }) { - // access reactive values using the group store - const password = useSelector(group.store, (state) => state.values.password) - // or the form itself - const isSubmitting = useSelector( - group.form.store, - (state) => state.isSubmitting, - ) - - return ( -
    -

    {title}

    - {/* Groups also have access to Field, Subscribe, Field, AppField and AppForm */} - - {(field) => } - - { - // The form could be any values, so it is typed as 'unknown' - const values: unknown = fieldApi.form.state.values - // use the group methods instead - if (value !== group.getFieldValue('password')) { - return 'Passwords do not match' - } - return undefined - }, - }} - > - {(field) => ( -
    - - -
    - )} -
    -
    - ) - }, -}) -``` - -We can now use these grouped fields in any form that implements the default values: - -```tsx -// You are allowed to extend the group fields as long as the -// existing properties remain unchanged -type Account = PasswordFields & { - provider: string - username: string -} - -// You may nest the group fields wherever you want -type FormValues = { - name: string - age: number - account_data: PasswordFields - linked_accounts: Account[] -} - -const defaultValues: FormValues = { - name: '', - age: 0, - account_data: { - password: '', - confirm_password: '', - }, - linked_accounts: [ - { - provider: 'TanStack', - username: '', - password: '', - confirm_password: '', - }, - ], -} - -function App() { - const form = useAppForm({ - defaultValues, - // If the group didn't specify an `onSubmitMeta` property, - // the form may implement any meta it wants. - // Otherwise, the meta must be defined and match. - onSubmitMeta: { action: '' }, - }) - - return ( - - - - {(field) => - field.state.value.map((account, i) => ( - - )) - } - - - ) -} -``` - -### Mapping field group values to a different field - -You may want to keep the password fields on the top level of your form, or rename the properties for clarity. You can map field group values -to their true location by changing the `field` property: - -> [!IMPORTANT] -> Due to TypeScript limitations, field mapping is only allowed for objects. You can use records or arrays at the top level of a field group, but you will not be able to map the fields. - -```tsx -// To have an easier form, you can keep the fields on the top level -type FormValues = { - name: string - age: number - password: string - confirm_password: string -} - -const defaultValues: FormValues = { - name: '', - age: 0, - password: '', - confirm_password: '', -} - -function App() { - const form = useAppForm({ - defaultValues, - }) - - return ( - - - - ) -} -``` - -If you expect your fields to always be at the top level of your form, you can create a quick map -of your field groups using a helper function: - -```tsx -const defaultValues: PasswordFields = { - password: '', - confirm_password: '', -} - -const passwordFields = createFieldMap(defaultValues) -/* This generates the following map: - { - 'password': 'password', - 'confirm_password': 'confirm_password' - } -*/ - -// Usage: - -``` - -## Tree-shaking form and field components - -While the above examples are great for getting started, they're not ideal for certain use-cases where you might have hundreds of form and field components. -In particular, you may not want to include all of your form and field components in the bundle of every file that uses your form hook. - -To solve this, you can mix the `createFormHook` TanStack API with the React `lazy` and `Suspense` components: - -```typescript -// src/hooks/form-context.ts -import { createFormHookContexts } from '@tanstack/preact-form' - -export const { fieldContext, useFieldContext, formContext, useFormContext } = - createFormHookContexts() -``` - -```tsx -// src/components/text-field.tsx -import { useFieldContext } from '../hooks/form-context.tsx' - -export default function TextField({ label }: { label: string }) { - const field = useFieldContext() - - return ( - - ) -} -``` - -```tsx -// src/hooks/form.ts -import { lazy } from 'preact/compat' -import { createFormHook } from '@tanstack/preact-form' - -const TextField = lazy(() => import('../components/text-fields.tsx')) - -const { useAppForm, withForm } = createFormHook({ - fieldContext, - formContext, - fieldComponents: { - TextField, - }, - formComponents: {}, -}) -``` - -```tsx -// src/App.tsx -import { Suspense } from 'preact/compat' -import { PeoplePage } from './features/people/form.tsx' - -export default function App() { - return ( - Loading...

    }> - -
    - ) -} -``` - -This will show the Suspense fallback while the `TextField` component is being loaded, and then render the form once it's loaded. - -## Putting it all together - -Now that we've covered the basics of creating custom form hooks, let's put it all together in a single example. - -```tsx -// /src/hooks/form.ts, to be used across the entire app -const { fieldContext, useFieldContext, formContext, useFormContext } = - createFormHookContexts() - -function TextField({ label }: { label: string }) { - const field = useFieldContext() - return ( - - ) -} - -function SubscribeButton({ label }: { label: string }) { - const form = useFormContext() - return ( - state.isSubmitting}> - {(isSubmitting) => } - - ) -} - -const { useAppForm, withForm } = createFormHook({ - fieldComponents: { - TextField, - }, - formComponents: { - SubscribeButton, - }, - fieldContext, - formContext, -}) - -// /src/features/people/shared-form.ts, to be used across `people` features -const formOpts = formOptions({ - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, -}) - -// /src/features/people/nested-form.ts, to be used in the `people` page -const ChildForm = withForm({ - ...formOpts, - // Optional, but adds props to the `render` function outside of `form` - props: { - title: 'Child Form', - }, - render: ({ form, title }) => { - return ( -
    -

    {title}

    - } - /> - - - -
    - ) - }, -}) - -// /src/features/people/page.ts -const Parent = () => { - const form = useAppForm({ - ...formOpts, - }) - - return -} -``` - -## API Usage Guidance - -Here's a chart to help you decide what APIs you should be using: - -![](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/react_form_composability.svg) diff --git a/docs/framework/preact/guides/form-groups.md b/docs/framework/preact/guides/form-groups.md deleted file mode 100644 index f3d908d31b..0000000000 --- a/docs/framework/preact/guides/form-groups.md +++ /dev/null @@ -1,177 +0,0 @@ ---- -id: form-groups -title: Form Groups ---- - -When building a multi-stage form that has many stages, like so: - -![Form stepper](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/stepper.png) - -It's common for each step to have its own form. However, this complicates the form submission and validation process by requiring you to add complex logic. - -Luckily, TanStack Form provides a way to build out sub-forms that make this kind of development trivial to implement: ``. - -## Usage - -To use a form group in TanStack Form, you'll use `useForm` or [`useAppForm`](./form-composition.md) to create a `form` variable, then reference its `FormGroup` component like you would a `Field`: - -```tsx -const form = useForm({ - defaultValues: { - step1: { - name: "" - }, - step2: { - age: 0 - } - } -}) - -return ( - ( - // `group` here has all of the form-like methods you'd expect like `deleteField` or `insertFieldValue` - // ... - )} - /> -) -``` - -This becomes much more useful when paired with external state to conditionally render a `FormGroup`: - -```tsx -const [step, setStep] = useState(0) -const form = useForm({ - defaultValues: { - step1: { - name: "" - }, - step2: { - age: 0 - } - } -}) - -return ( - <> - {step === 0 ? { - // We can move the step forward when validation passes - setStep(step + 1) - }} - onGroupSubmitInvalid={() => { - // Or handle invalid submissions, just like a top-level form - }} - onSubmitMeta={{} as SomeType} - children={group => ( - // Use `group.handleSubmit()` to submit the sub-form, but not the parent form - // ... - )} - /> : null } - {step === 1 ? ( - // Then, use `form.handleSubmit()` to submit the entire form - // ... - )} - /> : null } - -) -``` - -## Form Group Validation - -Form groups have a distinct validation proceedure that we think makes sense for sub-forms: - -- Form groups can have their own validation: - -```tsx - 'Error' }} - children={(group) => { - group.state.meta.errorMap // {onChange: "Error" | undefined} - group.state.meta.errors // ("Error")[] - }} -/> -``` - -- Can set errors on sub-fields: - -```tsx - ({ - group: value.name === 'error' ? 'Group error' : undefined, - fields: { - // Must use the name of the field relative to the FormGroup as the error key, - // to stay consistent with how standard schema works with form groups - name: value.name === 'error' ? 'Field error' : undefined, - }, - }), - }} -/> -``` - -- And can even accept standard schemas: - -```tsx - -``` - -> The reason we don't use the full path names for fields is so that you can compose your schemas like so: -> -> ``` -> const step1Schema = z.object({ -> name: z.string().min(2) -> }) -> -> const schema = z.object({ -> step1: step1Schema, -> step2: step2Schema -> }) -> ``` -> -> And pass the `step1Schema` to a form group and `schema` to the parent form. That way, partially validated data will still flag errors if the group is bypassed. - -### Dynamic Group Validation - -If you want to use [dynamic validation (`onDynamic`)](./dynamic-validation.md) with a form group, do not rely on the `onDynamic` validator passed to `useForm`: - -```tsx -useForm({ - validationLogic: revalidateLogic(), - validators: { - // This validator will not run `onChange` when a sub-form is submitted; - // it will only run `onChange` when the form itself is submitted. - onDynamic: schema, - }, -}) -``` - -Instead, pass your sub-schema for the group to the `onDynamic` validation of the `FormGroup` itself: - -```tsx - -``` - -It will treat `group.submissionAttempts` as the way to change what validator is ran before/after submit. - -## Form Group State - -Just like you're able to access `group.state.meta.errors`, you're also able to access the group's value using `group.state.value`. Likewise, here are some valuable properties you can access in the `group.state.meta`: - -- `group.state.meta.isFieldsValid`: `true` when the field-level validators have no errors -- `group.state.meta.isGroupValid`: `true` when the group-level validators have no errors -- `group.state.meta.isValid`: `true` when both the field-level and group-level validators have no errors -- `group.state.meta.isSubmitting`: `true` when the group is in the process of being submitted diff --git a/docs/framework/preact/guides/linked-fields.md b/docs/framework/preact/guides/linked-fields.md deleted file mode 100644 index 123a2971b5..0000000000 --- a/docs/framework/preact/guides/linked-fields.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -id: linked-fields -title: Link Two Form Fields Together ---- - -You may find yourself needing to link two fields together, such that one is validated when another's value has changed. -One such use case is when you have both a `password` and a `confirm_password` field. -Here, you want the `confirm_password` field to error out if its value doesn't match that of the `password` field, regardless of which field triggered the value change. - -Imagine the following user flow: - -- User updates the `confirm_password` field. -- User updates the `password` field. - -In this example, the form will still have errors present because the `confirm_password` field's validation has not been re-run to mark the field as valid. - -To solve this, you need to make sure that the `confirm_password` field's validation is re-run when the `password` field is updated. -To do this, you can add an `onChangeListenTo` prop to the `confirm_password` field. - -```tsx -function App() { - const form = useForm({ - defaultValues: { - password: '', - confirm_password: '', - }, - // ... - }) - - return ( -
    - - {(field) => ( - - )} - - { - if (value !== fieldApi.form.getFieldValue('password')) { - return 'Passwords do not match' - } - return undefined - }, - }} - > - {(field) => ( -
    - - {field.state.meta.errors.map((err) => ( -
    {err}
    - ))} -
    - )} -
    -
    - ) -} -``` - -This is similar to the `onBlurListenTo` prop, which re-runs the validation when the linked field is blurred. diff --git a/docs/framework/preact/guides/listeners.md b/docs/framework/preact/guides/listeners.md deleted file mode 100644 index 358a203a7f..0000000000 --- a/docs/framework/preact/guides/listeners.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -id: listeners -title: Side effects for event triggers ---- - -For situations where you want to "affect" or "react" to triggers, there's the listener API. For example, if you, as the developer, want to reset a form field as a result of another field changing, you would use the listener API. - -Imagine the following user flow: - -- User selects a country from a drop-down. -- User then selects a province from another drop-down. -- User changes the selected country to a different one. - -In this example, when the user changes the country, the selected province needs to be reset as it's no longer valid. With the listener API, we can subscribe to the `onChange` event and dispatch a reset to the "province" field when the listener is fired. - -Events that can be "listened" to are: - -- `onChange` -- `onBlur` -- `onMount` -- `onSubmit` -- `onUnmount` - -```tsx -function App() { - const form = useForm({ - defaultValues: { - country: '', - province: '', - }, - // ... - }) - - return ( -
    - { - console.log(`Country changed to: ${value}, resetting province`) - form.setFieldValue('province', '') - }, - }} - > - {(field) => ( - - )} - - - - {(field) => ( - - )} - -
    - ) -} -``` - -### Built-in Debouncing - -If you are making an API request inside a listener, you may want to debounce the calls as it can lead to performance issues. -We enable an easy method for debouncing your listeners by adding a `onChangeDebounceMs` or `onBlurDebounceMs`. - -```tsx - { - console.log(`Country changed to: ${value} without a change within 500ms, resetting province`) - form.setFieldValue('province', '') - }, - }} -> - {(field) => ( - /* ... */ - )} - -``` - -### Form listeners - -At a higher level, listeners are also available at the form level, allowing you access to the `onMount` and `onSubmit` events, and having `onChange` and `onBlur` propagated to all the form's children. Form-level listeners can also be debounced in the same way as previously discussed. - -`onMount` and `onSubmit` listeners have the following parameters: - -- `formApi` - -`onChange` and `onBlur` listeners have access to: - -- `fieldApi` -- `formApi` - -```tsx -const form = useForm({ - listeners: { - onMount: ({ formApi }) => { - // custom logging service - loggingService('mount', formApi.state.values) - }, - - onChange: ({ formApi, fieldApi }) => { - // autosave logic - if (formApi.state.isValid) { - formApi.handleSubmit() - } - - // fieldApi represents the field that triggered the event. - console.log(fieldApi.name, fieldApi.state.value) - }, - onChangeDebounceMs: 500, - }, -}) -``` diff --git a/docs/framework/preact/guides/reactivity.md b/docs/framework/preact/guides/reactivity.md deleted file mode 100644 index 8e92075c30..0000000000 --- a/docs/framework/preact/guides/reactivity.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: reactivity -title: Reactivity ---- - -Tanstack Form doesn't cause re-renders when interacting with the form. So, you might find yourself trying to use a form or field state value without success. - -If you would like to access reactive values, you will need to subscribe to them using one of two methods: `useSelector` or the `form.Subscribe` component. - -Some uses for these subscriptions are rendering up-to-date field values, determining what to render based on a condition, or using field values inside the logic of your component. - -> For situations where you want to "react" to triggers, check out the [listener](./listeners.md) API. - -## useSelector - -Import `useSelector` from `@tanstack/preact-form` when you need form values inside component logic. - -```tsx -import { useSelector } from '@tanstack/preact-form' - -const firstName = useSelector(form.store, (state) => state.values.firstName) -const errors = useSelector(form.store, (state) => state.errorMap) -``` - -> **Migration:** `useStore` is still exported but deprecated; use `useSelector` with the same arguments. - -## form.Subscribe - -The `form.Subscribe` component is best suited when you need to react to something within the UI of your component. For example, showing or hiding UI based on the value of a form field. - -```tsx - state.values.firstName} - children={(firstName) => ( - - {(field) => ( - - )} - - )} -/> -``` - -> The `form.Subscribe` component doesn't trigger component-level re-renders. Anytime the value subscribed to changes, only the `form.Subscribe` component re-renders. - -The choice between whether to use `useSelector` or `form.Subscribe` mainly boils down to your use case. If you're aiming for direct UI updates based on form state, use `form.Subscribe` for its optimization perks. And if you need the reactivity within the logic, then `useSelector` is the better choice. diff --git a/docs/framework/preact/guides/submission-handling.md b/docs/framework/preact/guides/submission-handling.md deleted file mode 100644 index 42891a6bc4..0000000000 --- a/docs/framework/preact/guides/submission-handling.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -id: submission-handling -title: Submission handling ---- - -## Passing additional data to submission handling - -You may have multiple types of submission behaviour, for example, going back to the previous page or staying on the form. -You can accomplish this by specifying the `onSubmitMeta` property. This meta data will be passed to the `onSubmit` function. - -> Note: if `form.handleSubmit()` is called without metadata, it will use the provided default. - -```tsx -import { useForm } from '@tanstack/preact-form' - -type FormMeta = { - submitAction: 'continue' | 'backToMenu' | null -} - -// Metadata is not required to call form.handleSubmit(). -// Specify what values to use as default if no meta is passed -const defaultMeta: FormMeta = { - submitAction: null, -} - -function App() { - const form = useForm({ - defaultValues: { - data: '', - }, - // Define what meta values to expect on submission - onSubmitMeta: defaultMeta, - onSubmit: async ({ value, meta }) => { - // Do something with the values passed via handleSubmit - console.log(`Selected action - ${meta.submitAction}`, value) - }, - }) - - return ( -
    { - e.preventDefault() - e.stopPropagation() - }} - > - {/* ... */} - - -
    - ) -} -``` - -## Transforming data with Standard Schemas - -While Tanstack Form provides [Standard Schema support](./validation.md) for validation, it does not preserve the Schema's output data. - -The value passed to the `onSubmit` function will always be the input data. To receive the output data of a Standard Schema, parse it in the `onSubmit` function: - -```tsx -const schema = z.object({ - age: z.string().transform((age) => Number(age)), -}) - -// Tanstack Form uses the input type of Standard Schemas -const defaultValues: z.input = { - age: '13', -} - -const form = useForm({ - defaultValues, - validators: { - onChange: schema, - }, - onSubmit: ({ value }) => { - const inputAge: string = value.age - // Pass it through the schema to get the transformed value - const result = schema.parse(value) - const outputAge: number = result.age - }, -}) -``` diff --git a/docs/framework/preact/guides/ui-libraries.md b/docs/framework/preact/guides/ui-libraries.md index e1e76b346c..1449a81dc9 100644 --- a/docs/framework/preact/guides/ui-libraries.md +++ b/docs/framework/preact/guides/ui-libraries.md @@ -3,214 +3,83 @@ id: ui-libraries title: UI Libraries --- -## Usage of TanStack Form with UI Libraries +TanStack Form is headless. UI library integration consists of adapting a +field's value, blur callback, change callback, invalid state, and errors to the +component's prop names. -TanStack Form is a headless library, offering you complete flexibility to style it as you see fit. It's compatible with a wide range of UI libraries, including `Chakra UI`, `Tailwind`, `Material UI`, `Mantine`, `shadcn/ui`, or even plain CSS. +## Text inputs -This guide focuses on `Chakra UI`, `Material UI`, `Mantine`, and `shadcn/ui`, but the concepts are applicable to any UI library of your choice. - -### Prerequisites - -Before integrating TanStack Form with a UI library, ensure the necessary dependencies are installed in your project: - -- For `Chakra UI`, follow the installation instructions on their [official site](https://chakra-ui.com/docs/get-started/installation) -- For `Material UI`, follow the installation instructions on their [official site](https://mui.com/material-ui/getting-started/). -- For `Mantine`, refer to their [documentation](https://mantine.dev/). -- For `shadcn/ui`, refer to their [official site](https://ui.shadcn.com/). - -Note: While you can mix and match libraries, it's generally advisable to stick with one to maintain consistency and minimize bloat. - -### Example with Mantine - -Here's an example demonstrating the integration of TanStack Form with Mantine components: - -```tsx -import { TextInput, Checkbox } from '@mantine/core' -import { useForm } from '@tanstack/preact-form' - -export default function App() { - const { Field, handleSubmit, state } = useForm({ - defaultValues: { - name: '', - isChecked: false, - }, - onSubmit: async ({ value }) => { - // Handle form submission - console.log(value) - }, - }) - - return ( - <> -
    { - e.preventDefault() - handleSubmit() - }} - > - ( - handleChange(e.target.value)} - onBlur={handleBlur} - placeholder="Enter your name" - /> - )} - /> - ( - handleChange(e.target.checked)} - onBlur={handleBlur} - checked={state.value} - /> - )} - /> - -
    -
    {JSON.stringify(state.values, null, 2)}
    -
    - - ) -} -``` - -- Initially, we utilize the `useForm` hook from TanStack and destructure the necessary properties. This step is optional; alternatively, you could use `const form = useForm()` if preferred. TypeScript's type inference ensures a smooth experience regardless of the approach. -- The `Field` component, derived from `useForm`, accepts several properties, such as `validators`. For this demonstration, we focus on two primary properties: `name` and `children`. - - The `name` property identifies each `Field`, for instance, `name` in our example. - - The `children` property leverages the concept of render props, allowing us to integrate components without unnecessary abstractions. -- TanStack's design relies heavily on render props, providing access to `children` within the `Field` component. This approach is entirely type-safe. When integrating with Mantine components, such as `TextInput`, we selectively destructure properties like `state.value`, `handleChange`, and `handleBlur`. This selective approach is due to the slight differences in types between `TextInput` and the `field` we get in the children. -- By following these steps, you can seamlessly integrate Mantine components with TanStack Form. -- This methodology is equally applicable to other components, such as `Checkbox`, ensuring consistent integration across different UI elements. - -### Usage with MaterialĀ UI - -The process for integrating MaterialĀ UI components is similar. Here's an example using TextField and Checkbox from MaterialĀ UI: +Most controlled text inputs accept DOM-like props directly: ```tsx - { - return ( - handleChange(e.target.value)} - onBlur={handleBlur} - placeholder="Enter your name" - /> - ); - }} -/> - - { - return ( - handleChange(e.target.checked)} - onBlur={handleBlur} - checked={state.value} - /> - ); - }} -/> - + + {(field) => ( + field.handleChange(event.currentTarget.value)} + error={field.errors.map((error) => error.message).join(', ')} + /> + )} + ``` -- The integration approach is the same as with Mantine. -- The primary difference lies in the specific Material UI component properties and styling options. +Use `value`, not `defaultValue`, so the UI component remains controlled by form +state. -### Usage with shadcn/ui +## Checkboxes and switches -The process for integrating shadcn/ui components is similar. Here's an example using Input and Checkbox from shadcn/ui: +DOM-style checkbox components expose `event.currentTarget.checked`: ```tsx - ( - handleChange(e.target.value)} - onBlur={handleBlur} - placeholder="Enter your name" - /> - )} -/> - ( + + {(field) => ( handleChange(checked === true)} - onBlur={handleBlur} - checked={state.value} + checked={field.value} + onBlur={field.handleBlur} + onChange={(event) => field.handleChange(event.currentTarget.checked)} + aria-invalid={field.meta.isInvalid} /> )} -/> + ``` -- The integration approach is the same as with Mantine, Material UI. -- The primary difference lies in the specific shadcn/ui component properties and styling options. -- Note the onCheckedChange property of Checkbox instead of onChange. - -The ShadCN library includes a dedicated guide covering common scenarios for integrating TanStack Form with its components: [https://ui.shadcn.com/docs/forms/tanstack-form](https://ui.shadcn.com/docs/forms/tanstack-form) - -### Usage with Chakra UI - -The process for integrating Chakra UI components is similar. Here's an example using Input and Checkbox from Chakra UI: +Some libraries call back with a boolean, a details object, or a union such as +`boolean | 'indeterminate'`. Normalize that value at the boundary: ```tsx - ( - handleChange(e.target.value)} - onBlur={handleBlur} - placeholder="Enter your name" - /> - )} -/> - ( - handleChange(!!details.checked)} - onBlur={handleBlur} - > - - - Accept terms - - )} + field.handleChange(checked === true)} /> ``` -- The integration approach is the same as with Mantine, Material UI, and shadcn/ui. -- Chakra UI exposes its Checkbox as a composable component with separate `Checkbox.Root`, `Checkbox.Control`, `Checkbox.Label`, and `Checkbox.HiddenInput` parts that you wire together. -- The double negation `!!` is used on `onCheckedChange` to coerce Chakra's `"indeterminate"` state to a boolean, ensuring it matches the form state. See the [Chakra UI Checkbox documentation](https://chakra-ui.com/docs/components/checkbox#indeterminate) for more details. -- Alternatively, Chakra UI offers a pre-composed Checkbox component that works the same way as their standard examples, without requiring manual composition. You can learn more about this closed component approach in the [Chakra UI Checkbox documentation](https://chakra-ui.com/docs/components/checkbox#closed-component). -- The TanStack Form integration works identically with either approach—simply attach the `checked`, `onCheckedChange`, and `onBlur` handlers to your chosen component. +## Selects, date pickers, and custom controls -Example using the closed Checkbox component: +The integration does not require a native event. Pass the value produced by the +component to `field.handleChange`: ```tsx - ( - handleChange(!!details.checked)} - onBlur={handleBlur} - > - Accept terms - - )} + field.handleChange(nextDate)} + onBlur={field.handleBlur} /> ``` + +Choose a serializable form value appropriate for your application, then adapt +the UI library's richer object at the component boundary if necessary. + +## Reuse the adapter + +If the same wiring appears throughout the application, extract a Preact +component that accepts `FieldWithValue` or register it with +`createFormHook`. + +For the helper types used when passing a form or field to an extracted +component, see [Splitting forms](../../../splitting-forms). + +The repository's `examples/preact/large-form` example demonstrates reusable +field and form components with the v2 Preact adapter. diff --git a/docs/framework/preact/guides/validation.md b/docs/framework/preact/guides/validation.md index aaa3fe2faf..95aa5b7d0c 100644 --- a/docs/framework/preact/guides/validation.md +++ b/docs/framework/preact/guides/validation.md @@ -3,561 +3,239 @@ id: form-validation title: Form and Field Validation --- -At the core of TanStack Form's functionality is the concept of validation. TanStack Form makes validation highly customizable: +TanStack Form supports synchronous, asynchronous, field-level, form-level, and +Standard Schema validation. Every validator is an ordered object with a `run` +implementation and explicit `triggers`. -- You can control when to perform the validation (on change, on input, on blur, on submit, etc.) -- Validation rules can be defined at the field-level or at the form-level -- Validation can be synchronous or asynchronous (for example, as a result of an API call) +## Choose when validation runs -## When is validation performed? - -It's up to you! The `` component accepts some callbacks as props such as `onChange` or `onBlur`. Those callbacks are passed the current value of the field, as well as the `fieldApi` object, so that you can perform the validation. If you find a validation error, simply return the error message as a string, and it will be available in `field.state.meta.errors`. - -Here is an example: - -```tsx - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {(field) => ( - <> - - field.handleChange(e.target.valueAsNumber)} - /> - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(', ')} - )} - - )} - -``` - -In the example above, the validation is done at each keystroke (`onChange`). If, instead, we wanted the validation to be done when the field is blurred, we would change the code above like so: - -```tsx - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {(field) => ( - <> - - field.handleChange(e.target.valueAsNumber)} - /> - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(', ')} - )} - - )} - -``` - -So, you can control when the validation is done by implementing the desired callback. You can even perform different pieces of validation at different times: +Use `change` for immediate feedback and `blur` for feedback after leaving an +input. Submission runs validators by default regardless of their configured +change and blur triggers. ```tsx - value < 13 ? 'You must be 13 to make an account' : undefined, - onBlur: ({ value }) => (value < 0 ? 'Invalid value' : undefined), - }} + validators={[ + { + triggers: ['change'], + run: ({ value }) => (value >= 13 ? undefined : 'You must be at least 13'), + }, + { + triggers: ['blur'], + run: ({ value }) => (value >= 0 ? undefined : 'Age cannot be negative'), + }, + ]} > {(field) => ( - <> - + )} ``` -In the example above, we are validating different things on the same field at different times (at each keystroke and when blurring the field). Since `field.state.meta.errors` is an array, all the relevant errors at a given time are displayed. You can also use `field.state.meta.errorMap` to get errors based on _when_ the validation was done (onChange, onBlur, etc.). More information about displaying errors is below. - -## Displaying Errors - -Once you have your validation in place, you can map the errors from an array to be displayed in your UI: +Additional controls include: -```tsx - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {(field) => { - return ( - <> - {/* ... */} - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(',')} - )} - - ) - }} - -``` - -Or use the `errorMap` property to access the specific error you're looking for: +- `runOnMount`: run once when the form is constructed or when a field or form + group first mounts. +- `skipOnSubmit`: conditionally skip submit-time execution. +- `triggerDebounceMs`: debounce change and blur execution. +- `bailIfInvalid`: skip this and subsequent validators when an earlier one + failed. +- trigger objects with `when`: enable a trigger conditionally. +- `watchFields`: rerun a field validator when related fields trigger it. -```tsx - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {(field) => ( - <> - {/* ... */} - {field.state.meta.errorMap['onChange'] ? ( - {field.state.meta.errorMap['onChange']} - ) : null} - - )} - -``` +## Control when errors are visible -It's worth mentioning that our `errors` array and the `errorMap` match the types returned by the validators. This means that: +Validation and presentation are separate. `errorVisibility` decides when field +issues appear in `field.errors`: ```tsx - (value < 13 ? { isOldEnough: false } : undefined), - }} -> - {(field) => ( - <> - {/* ... */} - {/* errorMap.onChange is type `{isOldEnough: false} | undefined` */} - {/* meta.errors is type `Array<{isOldEnough: false} | undefined>` */} - {!field.state.meta.errorMap['onChange']?.isOldEnough ? ( - The user is not old enough - ) : null} - - )} - +const form = useForm({ + defaultValues: { email: '' }, + errorVisibility: ({ fieldState, state }) => + fieldState.meta.isBlurred || state.submissionAttempts > 0, +}) ``` -## Validation at field-level vs at form-level +Use `field.meta.original.errors` for the unfiltered issues when debugging or +building a custom visibility system. -As shown above, each `` accepts its own validation rules via the callbacks such as `onChange` and `onBlur`. It is also possible to define validation rules at the form-level (as opposed to field-by-field) by passing similar callbacks to the `useForm()` hook. +## Form-level validation -Example: +A form validator can produce a form issue and route issues to typed field paths +with `createErrorMap`: ```tsx -export default function App() { - const form = useForm({ - defaultValues: { - age: 0, - }, - onSubmit: async ({ value }) => { - console.log(value) - }, - validators: { - // Add validators to the form the same way you would add them to a field - onChange({ value }) { - if (value.age < 13) { - return 'Must be 13 or older to sign' - } - return undefined - }, - }, - }) - - // Subscribe to the form's `errorMap` so that updates to it will cause re-renders - // Alternatively, you can use `form.Subscribe` - const formErrorMap = useSelector(form.store, (state) => state.errorMap) - - return ( -
    - {/* ... */} - {formErrorMap.onChange ? ( -
    - There was an error on the form: {formErrorMap.onChange} -
    - ) : null} - {/* ... */} -
    - ) -} -``` - -### Setting field-level errors from the form's validators +const form = useForm({ + defaultValues: { + email: '', + phone: '', + }, + validators: [ + { + triggers: ['change'], + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() -You can set errors on the fields from the form's validators. One common use case for this is validating all the fields on submit by calling a single API endpoint in the form's `onSubmitAsync` validator. - -```tsx -export default function App() { - const form = useForm({ - defaultValues: { - age: 0, - socials: [], - details: { - email: '', - }, - }, - validators: { - onSubmitAsync: async ({ value }) => { - // Validate the value on the server - const hasErrors = await verifyDataOnServer(value) - if (hasErrors) { - return { - form: 'Invalid data', // The `form` key is optional - fields: { - age: 'Must be 13 or older to sign', - // Set errors on nested fields with the field's name - 'socials[0].url': 'The provided URL does not exist', - 'details.email': 'An email is required', - }, - } + if (!value.email && !value.phone) { + errors.form = 'Provide an email address or phone number' + errors.fields.email = 'Email is required when phone is empty' + errors.fields.phone = 'Phone is required when email is empty' } - return null + return errors }, }, - }) - - return ( -
    -
    { - e.preventDefault() - e.stopPropagation() - void form.handleSubmit() - }} - > - - {(field) => ( - <> - - field.handleChange(e.target.valueAsNumber)} - /> - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(', ')} - )} - - )} - - [state.errorMap]} - children={([errorMap]) => - errorMap.onSubmit ? ( -
    - There was an error on the form: {errorMap.onSubmit} -
    - ) : null - } - /> - {/*...*/} - -
    - ) -} + ], +}) ``` -> Something worth mentioning is that if you have a form validation function that returns an error, that error may be overwritten by the field-specific validation. -> -> This means that: -> -> ```jsx -> const form = useForm({ -> defaultValues: { -> age: 0, -> }, -> validators: { -> onChange: ({ value }) => { -> return { -> fields: { -> age: value.age < 12 ? 'Too young!' : undefined, -> }, -> } -> }, -> }, -> }) -> -> // ... -> -> return ( -> name="age" -> validators={{ -> onChange: ({ value }) => (value % 2 === 0 ? 'Must be odd!' : undefined), -> }} -> children={() => <>{/* ... */}} -> /> -> ) -> ``` -> -> Will only show `'Must be odd!'` even if the 'Too young!' error is returned by the form-level validation. +Use `form.Subscribe` to reactively select form-level issues from +`form.state.errors`. Lower-level integrations can subscribe to `form.atom`. +Field-routed issues appear in the corresponding `field.errors`. -## Asynchronous Functional Validation - -While we suspect most validation will be synchronous, there are many instances where a network call or some other async operation would be useful to validate against. - -To do this, we have dedicated `onChangeAsync`, `onBlurAsync`, and other methods that can be used to validate against: - -```tsx - { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value < 13 ? 'You must be 13 to make an account' : undefined - }, - }} -> - {(field) => ( - <> - - field.handleChange(e.target.valueAsNumber)} - /> - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(', ')} - )} - - )} - -``` +## Asynchronous validation and debouncing -Synchronous and asynchronous validators can coexist. For example, it is possible to define both `onBlur` and `onBlurAsync` on the same field: +`run` may return a promise. Put cheap synchronous checks first and use +`bailIfInvalid` to avoid unnecessary requests: ```tsx - (value < 13 ? 'You must be at least 13' : undefined), - onBlurAsync: async ({ value }) => { - const currentAge = await fetchCurrentAgeOnProfile() - return value < currentAge ? 'You can only increase the age' : undefined +validators={[ + { + triggers: ['change'], + run: ({ value }) => + value.length >= 3 ? undefined : 'Use at least 3 characters', + }, + { + triggers: ['change'], + triggerDebounceMs: 500, + bailIfInvalid: true, + run: async ({ value }) => { + const available = await checkUsername(value) + return available ? undefined : 'That username is already taken' }, - }} -> - {(field) => ( - <> - - field.handleChange(e.target.valueAsNumber)} - /> - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(', ')} - )} - - )} - + }, +]} ``` -The synchronous validation method (`onBlur`) is run first, and the asynchronous method (`onBlurAsync`) is only run if the synchronous one (`onBlur`) succeeds. To change this behaviour, set the `asyncAlways` option to `true`, and the async method will be run regardless of the result of the sync method. +Submit validation always runs immediately, even when a trigger is debounced. +`field.meta.isValidating` and `form.state.isValidating` expose pending work. -### Built-in Debouncing +## Standard Schema validation -While async calls are the way to go when validating against the database, running a network request on every keystroke is a good way to DDoS your database. - -Instead, we enable an easy method for debouncing your `async` calls by adding a single property: +Any Standard Schema implementation can be supplied as `run`: ```tsx - { - // ... - }, - }} - children={(field) => { - return <>{/* ... */} - }} -/> -``` +import { z } from 'zod' -This will debounce every async call with a 500ms delay. You can even override this property on a per-validation property: +const accountSchema = z.object({ + email: z.string().email(), + age: z.number().min(13), +}) -```tsx - { - // ... +const form = useForm({ + defaultValues: { email: '', age: 0 }, + validators: [ + { + triggers: ['change'], + run: accountSchema, }, - onBlurAsync: async ({ value }) => { - // ... - }, - }} - children={(field) => { - return <>{/* ... */} - }} -/> + ], +}) ``` -This will run `onChangeAsync` every 1500ms, whereas `onBlurAsync` will run every 500ms. - -## Validation through Schema Libraries - -While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries that provide schema-based validation to make shorthand and type-strict validation substantially easier. You can also define a single schema for your entire form and pass it to the form-level validators; errors will automatically propagate to the fields. +Schema paths are routed to matching fields. Parsed outputs are available by +validator index in `schemaOutputs` during submit (for example, +`schemaOutputs[0]`); `value` remains the form's raw editable state rather than +the parsed output. -### Standard Schema Libraries +For custom schema routing, call a schema's safe parse API inside `run` and pass +its issues to the provided `parseIssues` helper. -TanStack Form natively supports all libraries following the [Standard Schema specification](https://github.com/standard-schema/standard-schema), most notably: +## Validate related fields -- [Zod](https://zod.dev/) -- [Valibot](https://valibot.dev/) -- [ArkType](https://arktype.io/) -- [Effect/Schema](https://effect.website/docs/schema/standard-schema/) - -_Note:_ make sure to use the latest version of the schema libraries as older versions might not support Standard Schema yet. - -> Validation will not provide you with transformed values. See [submission handling](./submission-handling.md) for more information. - -To use schemas from these libraries you can pass them to the `validators` props as you would do with a custom function: +Use `watchFields` when one field's validity depends on another: ```tsx -const userSchema = z.object({ - age: z.number().gte(13, 'You must be 13 to make an account'), -}) - -function App() { - const form = useForm({ - defaultValues: { - age: 0, - }, - validators: { - onChange: userSchema, + + value >= formApi.getFieldValue('startDate') + ? undefined + : 'End date must be on or after the start date', }, - }) - return ( -
    - { - return <>{/* ... */} - }} - /> -
    - ) -} + ]} +> + {(field) => ( + field.handleChange(event.currentTarget.value)} + aria-invalid={field.meta.isInvalid} + /> + )} +
    ``` -Async validators at the form- and field-level are supported as well: - -```tsx - { - const currentAge = await fetchCurrentAgeOnProfile() - return value >= currentAge - }, - { - message: 'You can only increase the age', - }, - ), - }} - children={(field) => { - return <>{/* ... */} - }} -/> -``` +## Return errors from submission -If you need even more control over your Standard Schema validation, you can combine a Standard Schema with a callback function like so: +Endpoint validation belongs in `onSubmit`. Return +`createValidationError(...)` to feed server issues back into normal form state: ```tsx - { - const errors = fieldApi.parseValueWithSchema( - z.number().gte(13, 'You must be 13 to make an account'), - ) - if (errors) return errors - // continue with your validation - }, - }} - children={(field) => { - return <>{/* ... */} - }} -/> -``` +onSubmit: async ({ value, createValidationError }) => { + const result = await saveProfile(value) -## Preventing invalid forms from being submitted + if (!result.ok) { + return createValidationError({ + form: 'Could not save the profile', + fields: { email: 'This email is already registered' }, + }) + } -The callbacks, such as `onChange` and `onBlur`, are also run when the form is submitted and the submission is blocked because the form is invalid. + return null +} +``` -The form state object has a `canSubmit` flag that is `false` when any field is invalid and the form has been touched (`canSubmit` is true until the form has been touched, even if some fields are "technically" invalid based on their `onChange`/`onBlur` props). +## Prevent invalid submission -You can subscribe to `canSubmit` via `form.Subscribe` and use the value in order to, for example, disable the submit button when the form is invalid (in practice, disabled buttons are not accessible, use `aria-disabled` instead). +`form.handleSubmit()` skips `onSubmit` when validation fails and resolves with +the validation errors. `onSubmitInvalid` is currently available on form groups; +root-form support is planned but not yet implemented. Subscribe to `canSubmit` +and `isSubmitting` to reflect that state in the submit UI: ```tsx -const form = useForm(/* ... */) - -return ( - /* ... */ - - // Dynamic submit button - [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( - - )} - /> -) + [state.canSubmit, state.isSubmitting]}> + {([canSubmit, isSubmitting]) => ( + + )} + ``` -To prevent the form from being submitted before any interaction, combine `canSubmit` with `isPristine` flags. A simple condition like `!canSubmit || isPristine` effectively disables submissions until the user has made changes. +If a disabled submit button would hide useful validation feedback, keep it +focusable with `aria-disabled` and let `handleSubmit()` report the issues. diff --git a/docs/framework/preact/quick-start.md b/docs/framework/preact/quick-start.md index 83bdfd565b..54f894e8df 100644 --- a/docs/framework/preact/quick-start.md +++ b/docs/framework/preact/quick-start.md @@ -3,132 +3,118 @@ id: quick-start title: Quick Start --- -TanStack Form is unlike most form libraries you've used before. It's designed for large-scale production usage, with a focus on type safety, performance and composition for an unmatched developer experience. +TanStack Form is a headless, type-safe form library. It owns form state and +validation while leaving markup, styling, and component choice to you. -As a result, we've developed [a philosophy around the library's usage](../../philosophy.md) that values scalability and long-term developer experience over short and sharable code snippets. +Install the Preact adapter: -Here's an example of a form following many of our best practices, which will allow you to rapidly develop even high-complexity forms after a short onboarding experience: +```bash +npm install @tanstack/preact-form +``` -```tsx -import { render } from 'preact' -import { createFormHook, createFormHookContexts } from '@tanstack/preact-form' -// Form components that pre-bind events from the form hook; check our "Form Composition" guide for more -import { TextField, NumberField, SubmitButton } from '~our-app/ui-library' -// We also support Valibot, ArkType, and any other standard schema library -import { z } from 'zod' +## Create a form -const { fieldContext, formContext } = createFormHookContexts() +`useForm` requires `defaultValues`. Their shape becomes the form's inferred +value type. -// Allow us to bind components to the form to keep type safety but reduce production boilerplate -// Define this once to have a generator of consistent form instances throughout your app -const { useAppForm } = createFormHook({ - fieldComponents: { - TextField, - NumberField, - }, - formComponents: { - SubmitButton, - }, - fieldContext, - formContext, -}) +```tsx +import { useForm } from '@tanstack/preact-form' -const PeoplePage = () => { - const form = useAppForm({ +export function ProfileForm() { + const form = useForm({ defaultValues: { - username: '', + fullName: '', age: 0, }, - validators: { - // Pass a schema or function to validate - onInput: z.object({ - username: z.string(), - age: z.number().min(13), - }), - }, - onSubmit: ({ value }) => { - // Do something with form data - alert(JSON.stringify(value, null, 2)) + onSubmit: async ({ value }) => { + console.log(value) }, }) return (
    { - e.preventDefault() - form.handleSubmit() + onSubmit={(event) => { + event.preventDefault() + void form.handleSubmit() }} > -

    Personal Information

    - {/* Components are bound to `form` and `field` to ensure extreme type safety */} - {/* Use `form.AppField` to render a component bound to a single field */} - } - /> - {/* The "name" property will throw a TypeScript error if typo'd */} - + value.trim() ? undefined : 'Enter your full name', + }, + ]} + > + {(field) => ( + + )} + + + } - /> - {/* Components in `form.AppForm` have access to the form context */} - - - + validators={[ + { + triggers: ['change'], + run: ({ value }) => + value >= 13 ? undefined : 'You must be at least 13', + }, + ]} + > + {(field) => ( + + )} + + + [state.canSubmit, state.isSubmitting]} + > + {([canSubmit, isSubmitting]) => ( + + )} + ) } - -const rootElement = document.getElementById('root')! -render(, rootElement) ``` -While we generally suggest using `createFormHook` for reduced boilerplate in the long-run, we also support one-off components and other behaviors using `useForm` and `form.Field`: - -```tsx -import { render } from 'preact' -import { useForm } from '@tanstack/preact-form' - -const PeoplePage = () => { - const form = useForm({ - defaultValues: { - username: '', - age: 0, - }, - onSubmit: ({ value }) => { - // Do something with form data - alert(JSON.stringify(value, null, 2)) - }, - }) - - return ( - - value > 13 ? undefined : 'Must be 13 or older', - }} - children={(field) => ( - <> - field.handleChange(e.target.valueAsNumber)} - /> - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(',')} - )} - - )} - /> - ) -} - -const rootElement = document.getElementById('root')! -render(, rootElement) -``` +The important pieces are: -All properties from `useForm` can be used in `useAppForm` and all properties from `form.Field` can be used in `form.AppField`. +- `defaultValues` define the complete initial value and drive type inference. +- `form.Field` subscribes to one field. Its render prop exposes `field.value`, + `field.meta`, and event handlers. +- Validators are ordered objects with a `run` function and explicit + `triggers`. +- `form.Subscribe` rerenders only its own children when the selected form state + changes. +- `form.handleSubmit()` validates the form before calling `onSubmit`. diff --git a/docs/framework/preact/reference/classes/ReadonlyStore.md b/docs/framework/preact/reference/classes/ReadonlyStore.md new file mode 100644 index 0000000000..e764546914 --- /dev/null +++ b/docs/framework/preact/reference/classes/ReadonlyStore.md @@ -0,0 +1,122 @@ +--- +id: ReadonlyStore +title: ReadonlyStore +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:22 + +## Type Parameters + +### T + +`T` + +## Implements + +- `Omit`\<[`Store`](Store.md)\<`T`\>, `"setState"` \| `"actions"`\> + +## Constructors + +### Constructor + +```ts +new ReadonlyStore(getValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:24 + +#### Parameters + +##### getValue + +(`prev?`) => `T` + +#### Returns + +`ReadonlyStore`\<`T`\> + +### Constructor + +```ts +new ReadonlyStore(initialValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:25 + +#### Parameters + +##### initialValue + +`T` + +#### Returns + +`ReadonlyStore`\<`T`\> + +## Accessors + +### state + +#### Get Signature + +```ts +get state(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:26 + +##### Returns + +`T` + +#### Implementation of + +```ts +Omit.state +``` + +## Methods + +### get() + +```ts +get(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:27 + +#### Returns + +`T` + +#### Implementation of + +```ts +Omit.get +``` + +*** + +### subscribe() + +```ts +subscribe(observerOrFn): Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:28 + +#### Parameters + +##### observerOrFn + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +#### Returns + +[`Subscription`](../interfaces/Subscription.md) + +#### Implementation of + +```ts +Omit.subscribe +``` diff --git a/docs/framework/preact/reference/classes/Store.md b/docs/framework/preact/reference/classes/Store.md new file mode 100644 index 0000000000..3e93a261b2 --- /dev/null +++ b/docs/framework/preact/reference/classes/Store.md @@ -0,0 +1,156 @@ +--- +id: Store +title: Store +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:11 + +## Type Parameters + +### T + +`T` + +### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) = `never` + +## Constructors + +### Constructor + +```ts +new Store(getValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:14 + +#### Parameters + +##### getValue + +(`prev?`) => `T` + +#### Returns + +`Store`\<`T`, `TActions`\> + +### Constructor + +```ts +new Store(initialValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:15 + +#### Parameters + +##### initialValue + +`T` + +#### Returns + +`Store`\<`T`, `TActions`\> + +### Constructor + +```ts +new Store(initialValue, actionsFactory): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:16 + +#### Parameters + +##### initialValue + +`NonFunction`\<`T`\> + +##### actionsFactory + +[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> + +#### Returns + +`Store`\<`T`, `TActions`\> + +## Properties + +### actions + +```ts +readonly actions: TActions; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:13 + +## Accessors + +### state + +#### Get Signature + +```ts +get state(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:18 + +##### Returns + +`T` + +## Methods + +### get() + +```ts +get(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:19 + +#### Returns + +`T` + +*** + +### setState() + +```ts +setState(updater): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:17 + +#### Parameters + +##### updater + +(`prev`) => `T` + +#### Returns + +`void` + +*** + +### subscribe() + +```ts +subscribe(observerOrFn): Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:20 + +#### Parameters + +##### observerOrFn + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +#### Returns + +[`Subscription`](../interfaces/Subscription.md) diff --git a/docs/framework/preact/reference/functions/Subscribe.md b/docs/framework/preact/reference/functions/Subscribe.md new file mode 100644 index 0000000000..73c67f9ead --- /dev/null +++ b/docs/framework/preact/reference/functions/Subscribe.md @@ -0,0 +1,34 @@ +--- +id: Subscribe +title: Subscribe +--- + +```ts +function Subscribe(props): ComponentChildren; +``` + +Defined in: [packages/preact-form/src/Subscribe.public.tsx:38](https://github.com/TanStack/form/blob/main/packages/preact-form/src/Subscribe.public.tsx#L38) + +A Preact component that allows you to subscribe to source state. + +This is useful for opting into state re-renders for specific parts of the state. + +## Type Parameters + +### TSourceData + +`TSourceData` + +### TSelected + +`TSelected` + +## Parameters + +### props + +[`SubscribeProps`](../interfaces/SubscribeProps.md)\<`TSourceData`, `TSelected`\> + +## Returns + +`ComponentChildren` diff --git a/docs/framework/preact/reference/functions/batch.md b/docs/framework/preact/reference/functions/batch.md new file mode 100644 index 0000000000..ad5677dbb2 --- /dev/null +++ b/docs/framework/preact/reference/functions/batch.md @@ -0,0 +1,20 @@ +--- +id: batch +title: batch +--- + +```ts +function batch(fn): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:5 + +## Parameters + +### fn + +() => `void` + +## Returns + +`void` diff --git a/docs/framework/preact/reference/functions/createAsyncAtom.md b/docs/framework/preact/reference/functions/createAsyncAtom.md new file mode 100644 index 0000000000..5ec22ca780 --- /dev/null +++ b/docs/framework/preact/reference/functions/createAsyncAtom.md @@ -0,0 +1,30 @@ +--- +id: createAsyncAtom +title: createAsyncAtom +--- + +```ts +function createAsyncAtom(getValue, options?): ReadonlyAtom>; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:16 + +## Type Parameters + +### T + +`T` + +## Parameters + +### getValue + +() => `Promise`\<`T`\> + +### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`AsyncAtomState`\<`T`, `unknown`\>\> + +## Returns + +[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`AsyncAtomState`\<`T`, `unknown`\>\> diff --git a/docs/framework/preact/reference/functions/createAtom.md b/docs/framework/preact/reference/functions/createAtom.md new file mode 100644 index 0000000000..d41435b132 --- /dev/null +++ b/docs/framework/preact/reference/functions/createAtom.md @@ -0,0 +1,60 @@ +--- +id: createAtom +title: createAtom +--- + +## Call Signature + +```ts +function createAtom(getValue, options?): ReadonlyAtom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:17 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`T`\> + +## Call Signature + +```ts +function createAtom(initialValue, options?): Atom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:18 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`Atom`](../interfaces/Atom.md)\<`T`\> diff --git a/docs/framework/preact/reference/functions/createFormHook.md b/docs/framework/preact/reference/functions/createFormHook.md index f36f3afd09..4c7c7bd1ce 100644 --- a/docs/framework/preact/reference/functions/createFormHook.md +++ b/docs/framework/preact/reference/functions/createFormHook.md @@ -3,334 +3,34 @@ id: createFormHook title: createFormHook --- -# Function: createFormHook() - ```ts -function createFormHook(__namedParameters): object; +function createFormHook(createOptions): AppFormHookResult<{ + fieldComponents: TFieldComponents; + formComponents: TFormComponents; +}>; ``` -Defined in: [packages/preact-form/src/createFormHook.tsx:294](https://github.com/TanStack/form/blob/main/packages/preact-form/src/createFormHook.tsx#L294) +Defined in: [packages/preact-form/src/AppForm/createFormHook.public.ts:14](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHook.public.ts#L14) ## Type Parameters -### TComponents +### TFormComponents -`TComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> +`TFormComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> -### TFormComponents +### TFieldComponents -`TFormComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> ## Parameters -### \_\_namedParameters +### createOptions -`CreateFormHookProps`\<`TComponents`, `TFormComponents`\> +[`CreateFormHookOptions`](../interfaces/CreateFormHookOptions.md)\<`TFormComponents`, `TFieldComponents`\> ## Returns -### useAppForm() - -```ts -useAppForm: (props) => AppFieldExtendedPreactFormApi; -``` - -#### Type Parameters - -##### TFormData - -`TFormData` - -##### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TSubmitMeta - -`TSubmitMeta` - -#### Parameters - -##### props - -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -#### Returns - -`AppFieldExtendedPreactFormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents`, `TFormComponents`\> - -### useTypedAppFormContext() - -```ts -useTypedAppFormContext: (_props) => AppFieldExtendedPreactFormApi; -``` - -āš ļø **Use withForm whenever possible.** - -Gets a typed form from the `` context. - -#### Type Parameters - -##### TFormData - -`TFormData` - -##### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TSubmitMeta - -`TSubmitMeta` - -#### Parameters - -##### \_props - -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -#### Returns - -`AppFieldExtendedPreactFormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents`, `TFormComponents`\> - -### withFieldGroup() - -```ts -withFieldGroup: (__namedParameters) => (params) => ComponentChildren; -``` - -#### Type Parameters - -##### TFieldGroupData - -`TFieldGroupData` - -##### TSubmitMeta - -`TSubmitMeta` - -##### TRenderProps - -`TRenderProps` *extends* `object` = \{ -\} - -#### Parameters - -##### \_\_namedParameters - -[`WithFieldGroupProps`](../interfaces/WithFieldGroupProps.md)\<`TFieldGroupData`, `TComponents`, `TFormComponents`, `TSubmitMeta`, `TRenderProps`\> - -#### Returns - -```ts -(params): ComponentChildren; -``` - -##### Type Parameters - -###### TFormData - -`TFormData` - -###### TFields - -`TFields` *extends* - \| `string` - \| \{ \[K in string \| number \| symbol\]: DeepKeysOfType\ \} - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TFormSubmitMeta - -`TFormSubmitMeta` - -##### Parameters - -###### params - -[`PropsWithChildren`](../type-aliases/PropsWithChildren.md)\<`NoInfer`\<`TRenderProps`\> & `object`\> - -##### Returns - -`ComponentChildren` - -### withForm() - -```ts -withForm: (__namedParameters) => FunctionComponent> & object>>; -``` - -#### Type Parameters - -##### TFormData - -`TFormData` - -##### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TSubmitMeta - -`TSubmitMeta` - -##### TRenderProps - -`TRenderProps` *extends* `object` = \{ -\} - -#### Parameters - -##### \_\_namedParameters - -[`WithFormProps`](../interfaces/WithFormProps.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents`, `TFormComponents`, `TRenderProps`\> - -#### Returns - -`FunctionComponent`\<[`PropsWithChildren`](../type-aliases/PropsWithChildren.md)\<`NoInfer`\<`UnwrapOrAny`\<`TRenderProps`\>\> & `object`\>\> +[`AppFormHookResult`](../interfaces/AppFormHookResult.md)\<\{ + `fieldComponents`: `TFieldComponents`; + `formComponents`: `TFormComponents`; +\}\> diff --git a/docs/framework/preact/reference/functions/createFormHookContexts.md b/docs/framework/preact/reference/functions/createFormHookContexts.md deleted file mode 100644 index 35acc2b894..0000000000 --- a/docs/framework/preact/reference/functions/createFormHookContexts.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -id: createFormHookContexts -title: createFormHookContexts ---- - -# Function: createFormHookContexts() - -```ts -function createFormHookContexts(): object; -``` - -Defined in: [packages/preact-form/src/createFormHook.tsx:91](https://github.com/TanStack/form/blob/main/packages/preact-form/src/createFormHook.tsx#L91) - -## Returns - -`object` - -### fieldContext - -```ts -fieldContext: Context = FieldContext; -``` - -### formContext - -```ts -formContext: Context = FormContext; -``` - -### useFieldContext() - -```ts -useFieldContext: () => FieldApi; -``` - -#### Type Parameters - -##### TData - -`TData` - -#### Returns - -`FieldApi`\<`any`, `string`, `TData`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`\> - -### useFormContext() - -```ts -useFormContext: () => PreactFormExtendedApi, any, any, any, any, any, any, any, any, any, any, any>; -``` - -#### Returns - -[`PreactFormExtendedApi`](../type-aliases/PreactFormExtendedApi.md)\<`Record`\<`string`, `never`\>, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`\> diff --git a/docs/framework/preact/reference/functions/createStore.md b/docs/framework/preact/reference/functions/createStore.md new file mode 100644 index 0000000000..069cfed200 --- /dev/null +++ b/docs/framework/preact/reference/functions/createStore.md @@ -0,0 +1,84 @@ +--- +id: createStore +title: createStore +--- + +## Call Signature + +```ts +function createStore(getValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:30 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +### Returns + +[`ReadonlyStore`](../classes/ReadonlyStore.md)\<`T`\> + +## Call Signature + +```ts +function createStore(initialValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:31 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +### Returns + +[`Store`](../classes/Store.md)\<`T`\> + +## Call Signature + +```ts +function createStore(initialValue, actions): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:32 + +### Type Parameters + +#### T + +`T` + +#### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) + +### Parameters + +#### initialValue + +`NonFunction`\<`T`\> + +#### actions + +[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> + +### Returns + +[`Store`](../classes/Store.md)\<`T`, `TActions`\> diff --git a/docs/framework/preact/reference/functions/createStoreContext.md b/docs/framework/preact/reference/functions/createStoreContext.md new file mode 100644 index 0000000000..2dea749d39 --- /dev/null +++ b/docs/framework/preact/reference/functions/createStoreContext.md @@ -0,0 +1,93 @@ +--- +id: createStoreContext +title: createStoreContext +--- + +```ts +function createStoreContext(): object; +``` + +Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.2\_preact@10.29.8/node\_modules/@tanstack/preact-store/dist/createStoreContext.d.ts:44 + +Creates a typed Preact context for sharing a bundle of atoms and stores with +a subtree. + +The returned `StoreProvider` only transports the provided object through +Preact context. Consumers destructure the contextual atoms and stores, then +compose them with the existing hooks like [useSelector](useSelector.md) and +[useAtom](useAtom.md). + +The object shape is preserved exactly, so keyed atoms and stores remain fully +typed when read back with `useStoreContext()`. + +## Type Parameters + +### TValue + +`TValue` *extends* `object` + +## Returns + +`object` + +### StoreProvider + +```ts +StoreProvider: (__namedParameters) => Element; +``` + +#### Parameters + +##### \_\_namedParameters + +###### children? + +`ComponentChildren` + +###### value + +`TValue` + +#### Returns + +`Element` + +### useStoreContext + +```ts +useStoreContext: () => TValue; +``` + +#### Returns + +`TValue` + +## Example + +```tsx +const { StoreProvider, useStoreContext } = createStoreContext<{ + countAtom: Atom + totalsStore: Store<{ count: number }> +}>() + +function CountButton() { + const { countAtom, totalsStore } = useStoreContext() + const count = useSelector(countAtom) + const total = useSelector(totalsStore, (state) => state.count) + + return ( + + ) +} +``` + +## Throws + +When `useStoreContext()` is called outside the matching `StoreProvider`. diff --git a/docs/framework/preact/reference/functions/flush.md b/docs/framework/preact/reference/functions/flush.md new file mode 100644 index 0000000000..a229192539 --- /dev/null +++ b/docs/framework/preact/reference/functions/flush.md @@ -0,0 +1,14 @@ +--- +id: flush +title: flush +--- + +```ts +function flush(): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:6 + +## Returns + +`void` diff --git a/docs/framework/preact/reference/functions/getFormHookHelpers.md b/docs/framework/preact/reference/functions/getFormHookHelpers.md new file mode 100644 index 0000000000..54d53f32dc --- /dev/null +++ b/docs/framework/preact/reference/functions/getFormHookHelpers.md @@ -0,0 +1,14 @@ +--- +id: getFormHookHelpers +title: getFormHookHelpers +--- + +```ts +function getFormHookHelpers(): FormHookHelpers; +``` + +Defined in: [packages/preact-form/src/AppForm/getFormHookHelpers.public.ts:103](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/getFormHookHelpers.public.ts#L103) + +## Returns + +[`FormHookHelpers`](../interfaces/FormHookHelpers.md) diff --git a/docs/framework/preact/reference/functions/shallow.md b/docs/framework/preact/reference/functions/shallow.md new file mode 100644 index 0000000000..db1f393577 --- /dev/null +++ b/docs/framework/preact/reference/functions/shallow.md @@ -0,0 +1,30 @@ +--- +id: shallow +title: shallow +--- + +```ts +function shallow(objA, objB): boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/shallow.d.ts:2 + +## Type Parameters + +### T + +`T` + +## Parameters + +### objA + +`T` + +### objB + +`T` + +## Returns + +`boolean` diff --git a/docs/framework/preact/reference/functions/toObserver.md b/docs/framework/preact/reference/functions/toObserver.md new file mode 100644 index 0000000000..add0d3bbdf --- /dev/null +++ b/docs/framework/preact/reference/functions/toObserver.md @@ -0,0 +1,37 @@ +--- +id: toObserver +title: toObserver +--- + +```ts +function toObserver( + nextHandler?, + errorHandler?, +completionHandler?): Observer; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:4 + +## Type Parameters + +### T + +`T` + +## Parameters + +### nextHandler? + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +### errorHandler? + +(`error`) => `void` + +### completionHandler? + +() => `void` + +## Returns + +[`Observer`](../type-aliases/Observer.md)\<`T`\> diff --git a/docs/framework/preact/reference/functions/useAtom.md b/docs/framework/preact/reference/functions/useAtom.md new file mode 100644 index 0000000000..2a19df7ac6 --- /dev/null +++ b/docs/framework/preact/reference/functions/useAtom.md @@ -0,0 +1,47 @@ +--- +id: useAtom +title: useAtom +--- + +```ts +function useAtom(atom, options?): [TValue, (fn) => void & (value) => void]; +``` + +Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.2\_preact@10.29.8/node\_modules/@tanstack/preact-store/dist/useAtom.d.ts:22 + +Returns the current atom value together with a stable setter. + +Use this when a component needs to both read and update the same writable +atom. + +## Type Parameters + +### TValue + +`TValue` + +## Parameters + +### atom + +[`Atom`](../interfaces/Atom.md)\<`TValue`\> + +### options? + +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TValue`\> + +## Returns + +\[`TValue`, (`fn`) => `void` & (`value`) => `void`\] + +## Example + +```tsx +const [count, setCount] = useAtom(countAtom) + +return ( + +) +``` diff --git a/docs/framework/preact/reference/functions/useCreateAtom.md b/docs/framework/preact/reference/functions/useCreateAtom.md new file mode 100644 index 0000000000..98036ce6f5 --- /dev/null +++ b/docs/framework/preact/reference/functions/useCreateAtom.md @@ -0,0 +1,102 @@ +--- +id: useCreateAtom +title: useCreateAtom +--- + +## Call Signature + +```ts +function useCreateAtom(getValue, options?): ReadonlyAtom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.2\_preact@10.29.8/node\_modules/@tanstack/preact-store/dist/useCreateAtom.d.ts:25 + +Creates a stable atom instance for the lifetime of the component. + +Pass an initial value to create a writable atom, or a getter function to +create a readonly derived atom. This mirrors [createAtom](createAtom.md), but only +creates the atom once per component mount. + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`T`\> + +### Example + +```tsx +function Counter() { + const countAtom = useCreateAtom(0) + const [count, setCount] = useAtom(countAtom) + + return ( + + ) +} +``` + +## Call Signature + +```ts +function useCreateAtom(initialValue, options?): Atom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.2\_preact@10.29.8/node\_modules/@tanstack/preact-store/dist/useCreateAtom.d.ts:26 + +Creates a stable atom instance for the lifetime of the component. + +Pass an initial value to create a writable atom, or a getter function to +create a readonly derived atom. This mirrors [createAtom](createAtom.md), but only +creates the atom once per component mount. + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`Atom`](../interfaces/Atom.md)\<`T`\> + +### Example + +```tsx +function Counter() { + const countAtom = useCreateAtom(0) + const [count, setCount] = useAtom(countAtom) + + return ( + + ) +} +``` diff --git a/docs/framework/preact/reference/functions/useCreateStore.md b/docs/framework/preact/reference/functions/useCreateStore.md new file mode 100644 index 0000000000..ee4784f367 --- /dev/null +++ b/docs/framework/preact/reference/functions/useCreateStore.md @@ -0,0 +1,159 @@ +--- +id: useCreateStore +title: useCreateStore +--- + +## Call Signature + +```ts +function useCreateStore(getValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.2\_preact@10.29.8/node\_modules/@tanstack/preact-store/dist/useCreateStore.d.ts:30 + +Creates a stable store instance for the lifetime of the component. + +Pass an initial value to create a writable store, or a getter function to +create a readonly derived store. This mirrors [createStore](createStore.md), but only +creates the store once per component mount. + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +### Returns + +[`ReadonlyStore`](../classes/ReadonlyStore.md)\<`T`\> + +### Example + +```tsx +function Counter() { + const counterStore = useCreateStore({ count: 0 }) + const count = useSelector(counterStore, (state) => state.count) + const setState = useSetValue(counterStore) + + return ( + + ) +} +``` + +## Call Signature + +```ts +function useCreateStore(initialValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.2\_preact@10.29.8/node\_modules/@tanstack/preact-store/dist/useCreateStore.d.ts:31 + +Creates a stable store instance for the lifetime of the component. + +Pass an initial value to create a writable store, or a getter function to +create a readonly derived store. This mirrors [createStore](createStore.md), but only +creates the store once per component mount. + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +### Returns + +[`Store`](../classes/Store.md)\<`T`\> + +### Example + +```tsx +function Counter() { + const counterStore = useCreateStore({ count: 0 }) + const count = useSelector(counterStore, (state) => state.count) + const setState = useSetValue(counterStore) + + return ( + + ) +} +``` + +## Call Signature + +```ts +function useCreateStore(initialValue, actions): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.2\_preact@10.29.8/node\_modules/@tanstack/preact-store/dist/useCreateStore.d.ts:32 + +Creates a stable store instance for the lifetime of the component. + +Pass an initial value to create a writable store, or a getter function to +create a readonly derived store. This mirrors [createStore](createStore.md), but only +creates the store once per component mount. + +### Type Parameters + +#### T + +`T` + +#### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) + +### Parameters + +#### initialValue + +`NonFunction`\<`T`\> + +#### actions + +[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> + +### Returns + +[`Store`](../classes/Store.md)\<`T`, `TActions`\> + +### Example + +```tsx +function Counter() { + const counterStore = useCreateStore({ count: 0 }) + const count = useSelector(counterStore, (state) => state.count) + const setState = useSetValue(counterStore) + + return ( + + ) +} +``` diff --git a/docs/framework/preact/reference/functions/useField.md b/docs/framework/preact/reference/functions/useField.md deleted file mode 100644 index e308635ab3..0000000000 --- a/docs/framework/preact/reference/functions/useField.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -id: useField -title: useField ---- - -# Function: useField() - -```ts -function useField(opts): FieldApi; -``` - -Defined in: [packages/preact-form/src/useField.tsx:104](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useField.tsx#L104) - -A hook for managing a field in a form. - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TPatentSubmitMeta - -`TPatentSubmitMeta` - -## Parameters - -### opts - -[`UseFieldOptions`](../interfaces/UseFieldOptions.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TPatentSubmitMeta`\> - -An object with field options. - -## Returns - -`FieldApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TPatentSubmitMeta`\> - -The `FieldApi` instance for the specified field. diff --git a/docs/framework/preact/reference/functions/useFieldGroup.md b/docs/framework/preact/reference/functions/useFieldGroup.md deleted file mode 100644 index 38f195436c..0000000000 --- a/docs/framework/preact/reference/functions/useFieldGroup.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -id: useFieldGroup -title: useFieldGroup ---- - -# Function: useFieldGroup() - -```ts -function useFieldGroup(opts): AppFieldExtendedPreactFieldGroupApi; -``` - -Defined in: [packages/preact-form/src/useFieldGroup.tsx:90](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useFieldGroup.tsx#L90) - -## Type Parameters - -### TFormData - -`TFormData` - -### TFieldGroupData - -`TFieldGroupData` - -### TFields - -`TFields` *extends* - \| `string` - \| \{ \[K in string \| number \| symbol\]: DeepKeysOfType\ \} - -### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TComponents - -`TComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> - -### TFormComponents - -`TFormComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> - -### TSubmitMeta - -`TSubmitMeta` = `never` - -## Parameters - -### opts - -#### defaultValues? - -`TFieldGroupData` - -#### fields - -`TFields` - -#### form - - \| `AppFieldExtendedPreactFormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents`, `TFormComponents`\> - \| `AppFieldExtendedPreactFieldGroupApi`\<`unknown`, `TFormData`, `string` \| `FieldsMap`\<`unknown`, `TFormData`\>, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `TSubmitMeta`, `TComponents`, `TFormComponents`\> - -#### formComponents - -`TFormComponents` - -#### onSubmitMeta? - -`TSubmitMeta` - -## Returns - -`AppFieldExtendedPreactFieldGroupApi`\<`TFormData`, `TFieldGroupData`, `TFields`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents`, `TFormComponents`\> diff --git a/docs/framework/preact/reference/functions/useForm.md b/docs/framework/preact/reference/functions/useForm.md deleted file mode 100644 index 2470f41a9d..0000000000 --- a/docs/framework/preact/reference/functions/useForm.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -id: useForm -title: useForm ---- - -# Function: useForm() - -```ts -function useForm(opts?): PreactFormExtendedApi; -``` - -Defined in: [packages/preact-form/src/useForm.tsx:173](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useForm.tsx#L173) - -A custom React Hook that returns an extended instance of the `FormApi` class. - -This API encapsulates all the necessary functionalities related to the form. It allows you to manage form state, handle submissions, and interact with form fields - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` - -## Parameters - -### opts? - -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -## Returns - -[`PreactFormExtendedApi`](../type-aliases/PreactFormExtendedApi.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> diff --git a/docs/framework/preact/reference/functions/useFormGroup.md b/docs/framework/preact/reference/functions/useFormGroup.md deleted file mode 100644 index f2a8fd2425..0000000000 --- a/docs/framework/preact/reference/functions/useFormGroup.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -id: useFormGroup -title: useFormGroup ---- - -# Function: useFormGroup() - -```ts -function useFormGroup(opts): FormGroupApi; -``` - -Defined in: [packages/preact-form/src/useFormGroup.tsx:111](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useFormGroup.tsx#L111) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Parameters - -### opts - -`FormGroupApiOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Returns - -`FormGroupApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> diff --git a/docs/framework/preact/reference/functions/useSelector.md b/docs/framework/preact/reference/functions/useSelector.md index 4c5a5f0d74..122638d1fb 100644 --- a/docs/framework/preact/reference/functions/useSelector.md +++ b/docs/framework/preact/reference/functions/useSelector.md @@ -3,8 +3,6 @@ id: useSelector title: useSelector --- -# Function: useSelector() - ```ts function useSelector( source, @@ -12,7 +10,7 @@ function useSelector( options?): TSelected; ``` -Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.1\_preact@10.29.2/node\_modules/@tanstack/preact-store/dist/useSelector.d.ts:29 +Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.2\_preact@10.29.8/node\_modules/@tanstack/preact-store/dist/useSelector.d.ts:29 Selects a slice of state from an atom or store and subscribes the component to that selection. @@ -43,7 +41,7 @@ subscribe to the whole value. ### options? -`UseSelectorOptions`\<`TSelected`\> +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TSelected`\> ## Returns diff --git a/docs/framework/preact/reference/functions/useStore.md b/docs/framework/preact/reference/functions/useStore.md new file mode 100644 index 0000000000..2083738162 --- /dev/null +++ b/docs/framework/preact/reference/functions/useStore.md @@ -0,0 +1,62 @@ +--- +id: _useStore +title: _useStore +--- + +```ts +function _useStore( + store, + selector, + options?): [TSelected, [TActions] extends [never] ? (updater) => void : TActions]; +``` + +Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.2\_preact@10.29.8/node\_modules/@tanstack/preact-store/dist/\_useStore.d.ts:22 + +Experimental combined read+write hook for stores, mirroring useAtom's tuple +pattern. + +Returns `[selected, actions]` when the store has an actions factory, or +`[selected, setState]` for plain stores. + +## Type Parameters + +### TState + +`TState` + +### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) + +### TSelected + +`TSelected` = `NoInfer`\<`TState`\> + +## Parameters + +### store + +[`Store`](../classes/Store.md)\<`TState`, `TActions`\> + +### selector + +(`state`) => `TSelected` + +### options? + +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TSelected`\> + +## Returns + +\[`TSelected`, \[`TActions`\] *extends* \[`never`\] ? (`updater`) => `void` : `TActions`\] + +## Example + +```tsx +// Store with actions +const [cats, { addCat }] = _useStore(petStore, (s) => s.cats) + +// Store without actions +const [count, setState] = _useStore(plainStore, (s) => s) +setState((prev) => prev + 1) +``` diff --git a/docs/framework/preact/reference/index.md b/docs/framework/preact/reference/index.md index 4bf99c58e5..11722ada9f 100644 --- a/docs/framework/preact/reference/index.md +++ b/docs/framework/preact/reference/index.md @@ -3,40 +3,100 @@ id: "@tanstack/preact-form" title: "@tanstack/preact-form" --- -# @tanstack/preact-form +## Classes + +- [ReadonlyStore](classes/ReadonlyStore.md) +- [Store](classes/Store.md) ## Interfaces -- [PreactFormApi](interfaces/PreactFormApi.md) -- [UseFieldOptions](interfaces/UseFieldOptions.md) -- [UseFieldOptionsBound](interfaces/UseFieldOptionsBound.md) -- [WithFieldGroupProps](interfaces/WithFieldGroupProps.md) -- [WithFormProps](interfaces/WithFormProps.md) +- [AppFormHookResult](interfaces/AppFormHookResult.md) +- [Atom](interfaces/Atom.md) +- [AtomOptions](interfaces/AtomOptions.md) +- [BaseAtom](interfaces/BaseAtom.md) +- [CreateFormHookOptions](interfaces/CreateFormHookOptions.md) +- [FieldGroupApi](interfaces/FieldGroupApi.md) +- [FieldGroupArrayFieldComponent](interfaces/FieldGroupArrayFieldComponent.md) +- [FieldGroupDefinition](interfaces/FieldGroupDefinition.md) +- [FieldGroupFieldComponent](interfaces/FieldGroupFieldComponent.md) +- [FormHookHelpers](interfaces/FormHookHelpers.md) +- [InternalBaseAtom](interfaces/InternalBaseAtom.md) +- [InternalReadonlyAtom](interfaces/InternalReadonlyAtom.md) +- [InteropSubscribable](interfaces/InteropSubscribable.md) +- [PreactFormComponentMap](interfaces/PreactFormComponentMap.md) +- [PreactFormFieldProps](interfaces/PreactFormFieldProps.md) +- [PreactFormGroupApi](interfaces/PreactFormGroupApi.md) +- [PreactFormGroupComponent](interfaces/PreactFormGroupComponent.md) +- [PreactFormGroupFieldComponent](interfaces/PreactFormGroupFieldComponent.md) +- [PreactFormGroupProps](interfaces/PreactFormGroupProps.md) +- [PreactTanStackFormComponents](interfaces/PreactTanStackFormComponents.md) +- [Readable](interfaces/Readable.md) +- [ReadonlyAtom](interfaces/ReadonlyAtom.md) +- [Subscribable](interfaces/Subscribable.md) +- [SubscribeProps](interfaces/SubscribeProps.md) +- [Subscription](interfaces/Subscription.md) +- [UseSelectorOptions](interfaces/UseSelectorOptions.md) ## Type Aliases -- [FieldComponent](type-aliases/FieldComponent.md) -- [FormGroupComponent](type-aliases/FormGroupComponent.md) -- [LensFieldComponent](type-aliases/LensFieldComponent.md) -- [PreactFormExtendedApi](type-aliases/PreactFormExtendedApi.md) -- [PropsWithChildren](type-aliases/PropsWithChildren.md) -- [ServerFormState](type-aliases/ServerFormState.md) -- [UseField](type-aliases/UseField.md) -- [UseFormGroup](type-aliases/UseFormGroup.md) +- [AnyAtom](type-aliases/AnyAtom.md) +- [AnyFieldGroupApi](type-aliases/AnyFieldGroupApi.md) +- [AnyPreactFormApi](type-aliases/AnyPreactFormApi.md) +- [AnyPreactFormComponentMap](type-aliases/AnyPreactFormComponentMap.md) +- [AppFormComponent](type-aliases/AppFormComponent.md) +- [CrossVersionPreactNode](type-aliases/CrossVersionPreactNode.md) +- [DefaultPreactFormComponentMap](type-aliases/DefaultPreactFormComponentMap.md) +- [DefineFieldGroupFn](type-aliases/DefineFieldGroupFn.md) +- [FieldGroupFieldBindingsOf](type-aliases/FieldGroupFieldBindingsOf.md) +- [FieldGroupFieldComponentsOf](type-aliases/FieldGroupFieldComponentsOf.md) +- [FieldGroupFieldsOf](type-aliases/FieldGroupFieldsOf.md) +- [FieldGroupForm](type-aliases/FieldGroupForm.md) +- [FieldGroupFormState](type-aliases/FieldGroupFormState.md) +- [FieldGroupSubscribeComponent](type-aliases/FieldGroupSubscribeComponent.md) +- [FieldGroupSubscribeProps](type-aliases/FieldGroupSubscribeProps.md) +- [FieldGroupWithFieldsFn](type-aliases/FieldGroupWithFieldsFn.md) +- [Observer](type-aliases/Observer.md) +- [PreactAppFormApi](type-aliases/PreactAppFormApi.md) +- [PreactFieldApi](type-aliases/PreactFieldApi.md) +- [PreactFieldGroup](type-aliases/PreactFieldGroup.md) +- [PreactFormApi](type-aliases/PreactFormApi.md) +- [PreactFormArrayFieldComponent](type-aliases/PreactFormArrayFieldComponent.md) +- [PreactFormFieldComponent](type-aliases/PreactFormFieldComponent.md) +- [PreactFormGroupArrayFieldComponent](type-aliases/PreactFormGroupArrayFieldComponent.md) +- [PreactFormGroupSubscribeComponent](type-aliases/PreactFormGroupSubscribeComponent.md) +- [PreactFormGroupSubscribeProps](type-aliases/PreactFormGroupSubscribeProps.md) +- [PreactFormSubscribeComponent](type-aliases/PreactFormSubscribeComponent.md) +- [PreactFormSubscribeProps](type-aliases/PreactFormSubscribeProps.md) +- [PreactFormType](type-aliases/PreactFormType.md) +- [Selection](type-aliases/Selection.md) +- [StoreAction](type-aliases/StoreAction.md) +- [StoreActionMap](type-aliases/StoreActionMap.md) +- [StoreActionsFactory](type-aliases/StoreActionsFactory.md) +- [SubscribeSource](type-aliases/SubscribeSource.md) +- [UseAppFormHook](type-aliases/UseAppFormHook.md) +- [UseFormHook](type-aliases/UseFormHook.md) ## Variables -- [Field](variables/Field.md) -- [FormGroup](variables/FormGroup.md) -- [useIsomorphicLayoutEffect](variables/useIsomorphicLayoutEffect.md) +- [defineFieldGroup](variables/defineFieldGroup.md) +- [useForm](variables/useForm.md) - [~~useStore~~](variables/useStore.md) ## Functions +- [\_useStore](functions/useStore.md) +- [batch](functions/batch.md) +- [createAsyncAtom](functions/createAsyncAtom.md) +- [createAtom](functions/createAtom.md) - [createFormHook](functions/createFormHook.md) -- [createFormHookContexts](functions/createFormHookContexts.md) -- [useField](functions/useField.md) -- [useFieldGroup](functions/useFieldGroup.md) -- [useForm](functions/useForm.md) -- [useFormGroup](functions/useFormGroup.md) +- [createStore](functions/createStore.md) +- [createStoreContext](functions/createStoreContext.md) +- [flush](functions/flush.md) +- [getFormHookHelpers](functions/getFormHookHelpers.md) +- [shallow](functions/shallow.md) +- [Subscribe](functions/Subscribe.md) +- [toObserver](functions/toObserver.md) +- [useAtom](functions/useAtom.md) +- [useCreateAtom](functions/useCreateAtom.md) +- [useCreateStore](functions/useCreateStore.md) - [useSelector](functions/useSelector.md) diff --git a/docs/framework/preact/reference/interfaces/AppFormHookResult.md b/docs/framework/preact/reference/interfaces/AppFormHookResult.md new file mode 100644 index 0000000000..e3e25d012a --- /dev/null +++ b/docs/framework/preact/reference/interfaces/AppFormHookResult.md @@ -0,0 +1,163 @@ +--- +id: AppFormHookResult +title: AppFormHookResult +--- + +Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:118](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L118) + +App Form hooks and helpers bound to the components registered with +`createFormHook`. + +## Type Parameters + +### TComponents + +`TComponents` *extends* [`AnyPreactFormComponentMap`](../type-aliases/AnyPreactFormComponentMap.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### appFormOptions + +```ts +appFormOptions: FormOptionsApi; +``` + +Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:145](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L145) + +Defines reusable form options that retain the components registered with +`createFormHook`. + +Use the result with `PreactFormType` when a child component needs the type +of one known App Form, including its registered field and form components. + +#### Example + +```tsx +const profileOptions = appFormOptions({ + defaultValues: { name: '' }, +}) + +type ProfileForm = PreactFormType + +function NameField({ form }: { form: ProfileForm }) { + return ( + + {(field) => } + + ) +} +``` + +*** + +### defineAppFieldGroup + +```ts +defineAppFieldGroup: DefineFieldGroupFn; +``` + +Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:177](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L177) + +Defines a reusable field group whose fields expose the field components +registered with `createFormHook`. + +#### Example + +```tsx +const { defineAppFieldGroup } = createFormHook({ + fieldComponents: { + TextField, + }, + formComponents: {}, +}) + +const contactFields = defineAppFieldGroup(({ strict }) => ({ + name: strict(), + email: strict(), +})) + +function ContactFields({ + fields, +}: { + fields: typeof contactFields.fields +}) { + return ( + + {(field) => } + + ) +} +``` + +*** + +### useAppForm + +```ts +useAppForm: UseAppFormHook; +``` + +Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:202](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L202) + +Creates a Preact form API extended with the field and form components +registered with `createFormHook`. + +Form data, validators, and submission results are inferred from the passed +options. + +#### Example + +```tsx +function ProfileForm() { + const form = useAppForm({ + defaultValues: { name: '' }, + }) + + return ( + + + {(field) => } + + + ) +} +``` + +*** + +### useFormContext + +```ts +useFormContext: () => PreactAppFormApi; +``` + +Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:226](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L226) + +Reads the current App Form API from the nearest `form.AppForm` provider. + +Use this hook inside form components registered with `createFormHook`. It +throws when called outside a `form.AppForm` subtree. + +#### Returns + +[`PreactAppFormApi`](../type-aliases/PreactAppFormApi.md)\<`any`, `any`, `TComponents`\> + +#### Example + +```tsx +function SubmitButton({ label }: { label: string }) { + const form = useFormContext() + + return ( + state.isSubmitting}> + {(isSubmitting) => ( + + )} + + ) +} +``` diff --git a/docs/framework/preact/reference/interfaces/Atom.md b/docs/framework/preact/reference/interfaces/Atom.md new file mode 100644 index 0000000000..e536822283 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/Atom.md @@ -0,0 +1,60 @@ +--- +id: Atom +title: Atom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:29 + +## Extends + +- [`BaseAtom`](BaseAtom.md)\<`T`\> + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`get`](BaseAtom.md#get) + +*** + +### set + +```ts +set: (fn) => void & (value) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:31 + +Sets the value of the atom using a function. + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`subscribe`](BaseAtom.md#subscribe) diff --git a/docs/framework/preact/reference/interfaces/AtomOptions.md b/docs/framework/preact/reference/interfaces/AtomOptions.md new file mode 100644 index 0000000000..84f594c6e0 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/AtomOptions.md @@ -0,0 +1,36 @@ +--- +id: AtomOptions +title: AtomOptions +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:33 + +## Type Parameters + +### T + +`T` + +## Properties + +### compare? + +```ts +optional compare?: (prev, next) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:34 + +#### Parameters + +##### prev + +`T` + +##### next + +`T` + +#### Returns + +`boolean` diff --git a/docs/framework/preact/reference/interfaces/BaseAtom.md b/docs/framework/preact/reference/interfaces/BaseAtom.md new file mode 100644 index 0000000000..fc0695a37a --- /dev/null +++ b/docs/framework/preact/reference/interfaces/BaseAtom.md @@ -0,0 +1,53 @@ +--- +id: BaseAtom +title: BaseAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:22 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\>.[`Readable`](Readable.md)\<`T`\> + +## Extended by + +- [`Atom`](Atom.md) +- [`ReadonlyAtom`](ReadonlyAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`Readable`](Readable.md).[`get`](Readable.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/preact/reference/interfaces/CreateFormHookOptions.md b/docs/framework/preact/reference/interfaces/CreateFormHookOptions.md new file mode 100644 index 0000000000..7311a81e63 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/CreateFormHookOptions.md @@ -0,0 +1,150 @@ +--- +id: CreateFormHookOptions +title: CreateFormHookOptions +--- + +Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:46](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L46) + +Configures the components and reusable defaults returned by +`createFormHook`. + +Form core resolves each default object before the corresponding usage-site +options. Non-listener properties passed at the usage site take precedence, +including when explicitly set to `undefined`. Listener arrays follow the +configured `listenersMerge` strategy. + +## Example + +```tsx +const { useAppForm } = createFormHook({ + formComponents: {}, + fieldComponents: { + TextField, + }, + defaultFormOptions: { + errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred, + }, + defaultFieldOptions: { + errorBoundary: true, + }, +}) +``` + +## Extends + +- [`PreactFormComponentMap`](PreactFormComponentMap.md)\<`TFormComponents`, `TFieldComponents`\> + +## Type Parameters + +### TFormComponents + +`TFormComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +Library-managed. Do not specify explicitly. + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +Library-managed. Do not specify explicitly. + +## Properties + +### defaultFieldOptions? + +```ts +optional defaultFieldOptions?: DefaultFieldOptions; +``` + +Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:79](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L79) + +Defaults for every field and array-field component owned by the form. + +Non-listener options passed to the component override these defaults, +including when explicitly set to `undefined`. Listener arrays follow +`listenersMerge`. This includes `group.Field` and `group.ArrayField`. + +#### Example + +```tsx +defaultFieldOptions: { + errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred, +}, +``` + +*** + +### defaultFormGroupOptions? + +```ts +optional defaultFormGroupOptions?: DefaultFormGroupOptions; +``` + +Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:95](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L95) + +Defaults for every `form.FormGroup` component. + +Options passed to the component override these defaults, including when +an option is explicitly `undefined`. + +#### Example + +```tsx +defaultFormGroupOptions: { + onSubmitInvalid: ({ groupApi }) => { + console.error('Invalid group', groupApi.name) + }, +}, +``` + +*** + +### defaultFormOptions? + +```ts +optional defaultFormOptions?: DefaultFormOptions; +``` + +Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:64](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L64) + +Defaults for every form created by `useAppForm`. + +Non-listener options passed to `useAppForm` override these defaults, +including when explicitly set to `undefined`. Listener arrays follow +`listenersMerge`. + +#### Example + +```tsx +defaultFormOptions: { + errorVisibility: ({ state }) => state.submissionAttempts > 0, +}, +``` + +*** + +### fieldComponents + +```ts +fieldComponents: TFieldComponents; +``` + +Defined in: [packages/preact-form/src/AppForm/componentMap.public.ts:8](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/componentMap.public.ts#L8) + +#### Inherited from + +[`PreactFormComponentMap`](PreactFormComponentMap.md).[`fieldComponents`](PreactFormComponentMap.md#fieldcomponents) + +*** + +### formComponents + +```ts +formComponents: TFormComponents; +``` + +Defined in: [packages/preact-form/src/AppForm/componentMap.public.ts:7](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/componentMap.public.ts#L7) + +#### Inherited from + +[`PreactFormComponentMap`](PreactFormComponentMap.md).[`formComponents`](PreactFormComponentMap.md#formcomponents) diff --git a/docs/framework/preact/reference/interfaces/FieldGroupApi.md b/docs/framework/preact/reference/interfaces/FieldGroupApi.md new file mode 100644 index 0000000000..61fd79aaa4 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/FieldGroupApi.md @@ -0,0 +1,60 @@ +--- +id: FieldGroupApi +title: FieldGroupApi +--- + +Defined in: [packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts:74](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts#L74) + +## Extends + +- `FormApiFieldMethods`\<`TFieldData`\>.`FormApiArrayMethods`\<`TFieldData`\> + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> = `Record`\<`never`, `never`\> + +## Properties + +### ArrayField + +```ts +ArrayField: FieldGroupArrayFieldComponent; +``` + +Defined in: [packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts:82](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts#L82) + +*** + +### atom + +```ts +atom: ReadonlyAtom; +``` + +Defined in: [packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts:80](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts#L80) + +*** + +### Field + +```ts +Field: FieldGroupFieldComponent; +``` + +Defined in: [packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts:81](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts#L81) + +*** + +### Subscribe + +```ts +Subscribe: FieldGroupSubscribeComponent; +``` + +Defined in: [packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts:83](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts#L83) diff --git a/docs/framework/preact/reference/interfaces/FieldGroupArrayFieldComponent.md b/docs/framework/preact/reference/interfaces/FieldGroupArrayFieldComponent.md new file mode 100644 index 0000000000..7b8add2425 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/FieldGroupArrayFieldComponent.md @@ -0,0 +1,38 @@ +--- +id: FieldGroupArrayFieldComponent +title: FieldGroupArrayFieldComponent +--- + +Defined in: [packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts:42](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts#L42) + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +```ts +FieldGroupArrayFieldComponent(props): ComponentChildren; +``` + +Defined in: [packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts:46](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts#L46) + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `never` + +## Parameters + +### props + +[`PreactFormFieldProps`](PreactFormFieldProps.md)\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\>, `ValidationIssue`, `unknown`, `FormErrorTypes`\<`ValidationIssue`, `ValidationIssue`\>, `TFieldComponents`\> + +## Returns + +`ComponentChildren` diff --git a/docs/framework/preact/reference/interfaces/FieldGroupDefinition.md b/docs/framework/preact/reference/interfaces/FieldGroupDefinition.md new file mode 100644 index 0000000000..245f89a4ee --- /dev/null +++ b/docs/framework/preact/reference/interfaces/FieldGroupDefinition.md @@ -0,0 +1,40 @@ +--- +id: FieldGroupDefinition +title: FieldGroupDefinition +--- + +Defined in: [packages/preact-form/src/FieldGroup/withFields.public.ts:71](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/withFields.public.ts#L71) + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +## Properties + +### bindComponent + +```ts +bindComponent: FieldGroupWithFieldsFn>; +``` + +Defined in: [packages/preact-form/src/FieldGroup/withFields.public.ts:78](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/withFields.public.ts#L78) + +Binds a component's virtual field API to concrete paths in a form. + +*** + +### fields + +```ts +fields: PreactFieldGroup; +``` + +Defined in: [packages/preact-form/src/FieldGroup/withFields.public.ts:76](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/withFields.public.ts#L76) + +The virtual field-group API injected into the bound component. diff --git a/docs/framework/preact/reference/interfaces/FieldGroupFieldComponent.md b/docs/framework/preact/reference/interfaces/FieldGroupFieldComponent.md new file mode 100644 index 0000000000..358187cca2 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/FieldGroupFieldComponent.md @@ -0,0 +1,38 @@ +--- +id: FieldGroupFieldComponent +title: FieldGroupFieldComponent +--- + +Defined in: [packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts:20](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts#L20) + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +```ts +FieldGroupFieldComponent(props): ComponentChildren; +``` + +Defined in: [packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts:24](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts#L24) + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `string` + +## Parameters + +### props + +[`PreactFormFieldProps`](PreactFormFieldProps.md)\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\>, `ValidationIssue`, `unknown`, `FormErrorTypes`\<`ValidationIssue`, `ValidationIssue`\>, `TFieldComponents`\> + +## Returns + +`ComponentChildren` diff --git a/docs/framework/preact/reference/interfaces/FormHookHelpers.md b/docs/framework/preact/reference/interfaces/FormHookHelpers.md new file mode 100644 index 0000000000..a7b6ea4ab3 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/FormHookHelpers.md @@ -0,0 +1,26 @@ +--- +id: FormHookHelpers +title: FormHookHelpers +--- + +Defined in: [packages/preact-form/src/AppForm/getFormHookHelpers.public.ts:98](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/getFormHookHelpers.public.ts#L98) + +## Properties + +### fieldBrand + +```ts +fieldBrand: FieldBrandHelper; +``` + +Defined in: [packages/preact-form/src/AppForm/getFormHookHelpers.public.ts:99](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/getFormHookHelpers.public.ts#L99) + +*** + +### fieldComponent + +```ts +fieldComponent: FieldComponentHelper; +``` + +Defined in: [packages/preact-form/src/AppForm/getFormHookHelpers.public.ts:100](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/getFormHookHelpers.public.ts#L100) diff --git a/docs/framework/preact/reference/interfaces/InternalBaseAtom.md b/docs/framework/preact/reference/interfaces/InternalBaseAtom.md new file mode 100644 index 0000000000..f73167d4a2 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/InternalBaseAtom.md @@ -0,0 +1,86 @@ +--- +id: InternalBaseAtom +title: InternalBaseAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:23 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\>.[`Readable`](Readable.md)\<`T`\> + +## Extended by + +- [`InternalReadonlyAtom`](InternalReadonlyAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### \_snapshot + +```ts +_snapshot: T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:25 + +**`Internal`** + +*** + +### \_update + +```ts +_update: (getValue?) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:27 + +**`Internal`** + +#### Parameters + +##### getValue? + +`T` \| ((`snapshot`) => `T`) + +#### Returns + +`boolean` + +*** + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`Readable`](Readable.md).[`get`](Readable.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/preact/reference/interfaces/InternalReadonlyAtom.md b/docs/framework/preact/reference/interfaces/InternalReadonlyAtom.md new file mode 100644 index 0000000000..ac5a197160 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/InternalReadonlyAtom.md @@ -0,0 +1,170 @@ +--- +id: InternalReadonlyAtom +title: InternalReadonlyAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:37 + +## Extends + +- [`InternalBaseAtom`](InternalBaseAtom.md)\<`T`\>.`ReactiveNode` + +## Type Parameters + +### T + +`T` + +## Properties + +### \_snapshot + +```ts +_snapshot: T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:25 + +**`Internal`** + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`_snapshot`](InternalBaseAtom.md#_snapshot) + +*** + +### \_update + +```ts +_update: (getValue?) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:27 + +**`Internal`** + +#### Parameters + +##### getValue? + +`T` \| ((`snapshot`) => `T`) + +#### Returns + +`boolean` + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`_update`](InternalBaseAtom.md#_update) + +*** + +### deps? + +```ts +optional deps?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:3 + +#### Inherited from + +```ts +ReactiveNode.deps +``` + +*** + +### depsTail? + +```ts +optional depsTail?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:4 + +#### Inherited from + +```ts +ReactiveNode.depsTail +``` + +*** + +### flags + +```ts +flags: number; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:7 + +#### Inherited from + +```ts +ReactiveNode.flags +``` + +*** + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`get`](InternalBaseAtom.md#get) + +*** + +### subs? + +```ts +optional subs?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:5 + +#### Inherited from + +```ts +ReactiveNode.subs +``` + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`subscribe`](InternalBaseAtom.md#subscribe) + +*** + +### subsTail? + +```ts +optional subsTail?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:6 + +#### Inherited from + +```ts +ReactiveNode.subsTail +``` diff --git a/docs/framework/preact/reference/interfaces/InteropSubscribable.md b/docs/framework/preact/reference/interfaces/InteropSubscribable.md new file mode 100644 index 0000000000..7a0c023915 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/InteropSubscribable.md @@ -0,0 +1,36 @@ +--- +id: InteropSubscribable +title: InteropSubscribable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:5 + +## Extended by + +- [`Subscribable`](Subscribable.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### subscribe + +```ts +subscribe: (observer) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:6 + +#### Parameters + +##### observer + +[`Observer`](../type-aliases/Observer.md)\<`T`\> + +#### Returns + +[`Subscription`](Subscription.md) diff --git a/docs/framework/preact/reference/interfaces/PreactFormApi.md b/docs/framework/preact/reference/interfaces/PreactFormApi.md deleted file mode 100644 index 282966bc10..0000000000 --- a/docs/framework/preact/reference/interfaces/PreactFormApi.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -id: PreactFormApi -title: PreactFormApi ---- - -# Interface: PreactFormApi\ - -Defined in: [packages/preact-form/src/useForm.tsx:24](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useForm.tsx#L24) - -Fields that are added onto the `FormAPI` from `@tanstack/form-core` and returned from `useForm` - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` - -## Properties - -### Field - -```ts -Field: FieldComponent; -``` - -Defined in: [packages/preact-form/src/useForm.tsx:41](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useForm.tsx#L41) - -A Preact component to render form fields. With this, you can render and manage individual form fields. - -*** - -### FormGroup - -```ts -FormGroup: FormGroupComponent; -``` - -Defined in: [packages/preact-form/src/useForm.tsx:55](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useForm.tsx#L55) - -*** - -### Subscribe() - -```ts -Subscribe: (props) => ComponentChildren; -``` - -Defined in: [packages/preact-form/src/useForm.tsx:72](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useForm.tsx#L72) - -A `Subscribe` function that allows you to listen and react to changes in the form's state. It's especially useful when you need to execute side effects or render specific components in response to state updates. - -#### Type Parameters - -##### TSelected - -`TSelected` = `NoInfer`\<`FormState`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`\>\> - -#### Parameters - -##### props - -###### children - -`ComponentChild` \| (`state`) => `ComponentChild` - -###### selector? - -(`state`) => `TSelected` - -#### Returns - -`ComponentChildren` diff --git a/docs/framework/preact/reference/interfaces/PreactFormComponentMap.md b/docs/framework/preact/reference/interfaces/PreactFormComponentMap.md new file mode 100644 index 0000000000..6fcf1825e5 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/PreactFormComponentMap.md @@ -0,0 +1,40 @@ +--- +id: PreactFormComponentMap +title: PreactFormComponentMap +--- + +Defined in: [packages/preact-form/src/AppForm/componentMap.public.ts:3](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/componentMap.public.ts#L3) + +## Extended by + +- [`CreateFormHookOptions`](CreateFormHookOptions.md) + +## Type Parameters + +### TFormComponents + +`TFormComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +## Properties + +### fieldComponents + +```ts +fieldComponents: TFieldComponents; +``` + +Defined in: [packages/preact-form/src/AppForm/componentMap.public.ts:8](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/componentMap.public.ts#L8) + +*** + +### formComponents + +```ts +formComponents: TFormComponents; +``` + +Defined in: [packages/preact-form/src/AppForm/componentMap.public.ts:7](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/componentMap.public.ts#L7) diff --git a/docs/framework/preact/reference/interfaces/PreactFormFieldProps.md b/docs/framework/preact/reference/interfaces/PreactFormFieldProps.md new file mode 100644 index 0000000000..aa38d4c11a --- /dev/null +++ b/docs/framework/preact/reference/interfaces/PreactFormFieldProps.md @@ -0,0 +1,64 @@ +--- +id: PreactFormFieldProps +title: PreactFormFieldProps +--- + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:113](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L113) + +## Extends + +- `FieldApiOptions`\<`TFieldData`, `TFieldName`, `TFieldValue`, `TFieldValidators`, `TGroupFieldError`, `TFormData`, `TFormErrorTypes`\> + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldName + +`TFieldName` + +### TFieldValue + +`TFieldValue` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFieldData`, `TFieldName`, `TFieldValue`\> + +### TGroupFieldError + +`TGroupFieldError` + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +## Properties + +### children + +```ts +children: (fieldApi) => ComponentChildren; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:135](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L135) + +#### Parameters + +##### fieldApi + +[`PreactFieldApi`](../type-aliases/PreactFieldApi.md)\<`TFieldName`, `TFieldValue`, `ToFieldError`\<`NoInfer`\<`TFieldValidators`\>, `TGroupFieldError`, `TFormErrorTypes`\>, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +#### Returns + +`ComponentChildren` diff --git a/docs/framework/preact/reference/interfaces/PreactFormGroupApi.md b/docs/framework/preact/reference/interfaces/PreactFormGroupApi.md new file mode 100644 index 0000000000..6c5aebbd44 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/PreactFormGroupApi.md @@ -0,0 +1,66 @@ +--- +id: PreactFormGroupApi +title: PreactFormGroupApi +--- + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:279](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L279) + +## Extends + +- `FormGroupApi`\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupErrorTypes`, `TFormErrorTypes`\> + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +## Properties + +### ArrayField + +```ts +ArrayField: PreactFormGroupArrayFieldComponent; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:300](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L300) + +*** + +### Field + +```ts +Field: PreactFormGroupFieldComponent; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:293](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L293) + +*** + +### Subscribe + +```ts +Subscribe: PreactFormGroupSubscribeComponent; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:307](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L307) diff --git a/docs/framework/preact/reference/interfaces/PreactFormGroupComponent.md b/docs/framework/preact/reference/interfaces/PreactFormGroupComponent.md new file mode 100644 index 0000000000..dd8e25ee9b --- /dev/null +++ b/docs/framework/preact/reference/interfaces/PreactFormGroupComponent.md @@ -0,0 +1,50 @@ +--- +id: PreactFormGroupComponent +title: PreactFormGroupComponent +--- + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:339](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L339) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +```ts +PreactFormGroupComponent(props): ComponentChildren; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:344](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L344) + +## Type Parameters + +### TGroupName + +`TGroupName` *extends* `string` + +### TGroupValue + +`TGroupValue` + +### TGroupValidators + +`TGroupValidators` *extends* `FormGroupValidators`\<`TGroupValue`\> + +## Parameters + +### props + +[`PreactFormGroupProps`](PreactFormGroupProps.md)\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupValidators`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`ComponentChildren` diff --git a/docs/framework/preact/reference/interfaces/PreactFormGroupFieldComponent.md b/docs/framework/preact/reference/interfaces/PreactFormGroupFieldComponent.md new file mode 100644 index 0000000000..905804762a --- /dev/null +++ b/docs/framework/preact/reference/interfaces/PreactFormGroupFieldComponent.md @@ -0,0 +1,54 @@ +--- +id: PreactFormGroupFieldComponent +title: PreactFormGroupFieldComponent +--- + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:223](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L223) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +```ts +PreactFormGroupFieldComponent(props): ComponentChildren; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:230](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L230) + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `string` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>\> + +## Parameters + +### props + +[`PreactFormFieldProps`](PreactFormFieldProps.md)\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>, `TFieldValidators`, `TGroupErrorTypes`\[`"fieldError"`\], `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`ComponentChildren` diff --git a/docs/framework/preact/reference/interfaces/PreactFormGroupProps.md b/docs/framework/preact/reference/interfaces/PreactFormGroupProps.md new file mode 100644 index 0000000000..eb4887ac31 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/PreactFormGroupProps.md @@ -0,0 +1,56 @@ +--- +id: PreactFormGroupProps +title: PreactFormGroupProps +--- + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:310](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L310) + +## Extends + +- `Omit`\<`FormGroupOptions`\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupValidators`, `TFormErrorTypes`\>, `"form"`\> + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupValidators + +`TGroupValidators` *extends* `FormGroupValidators`\<`TGroupValue`\> + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +## Properties + +### children + +```ts +children: (groupApi) => ComponentChildren; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:327](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L327) + +#### Parameters + +##### groupApi + +[`PreactFormGroupApi`](PreactFormGroupApi.md)\<`TFormData`, `TGroupName`, `TGroupValue`, `ToFormGroupErrorTypes`\<`NoInfer`\<`TGroupValidators`\>\>, `TFormErrorTypes`, `TFieldComponents`\> + +#### Returns + +`ComponentChildren` diff --git a/docs/framework/preact/reference/interfaces/PreactTanStackFormComponents.md b/docs/framework/preact/reference/interfaces/PreactTanStackFormComponents.md new file mode 100644 index 0000000000..4e299351ea --- /dev/null +++ b/docs/framework/preact/reference/interfaces/PreactTanStackFormComponents.md @@ -0,0 +1,62 @@ +--- +id: PreactTanStackFormComponents +title: PreactTanStackFormComponents +--- + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:360](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L360) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +## Properties + +### ArrayField + +```ts +ArrayField: PreactFormArrayFieldComponent; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:370](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L370) + +*** + +### Field + +```ts +Field: PreactFormFieldComponent; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:368](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L368) + +TODO docs + +*** + +### FormGroup + +```ts +FormGroup: PreactFormGroupComponent; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:378](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L378) + +*** + +### Subscribe + +```ts +Subscribe: PreactFormSubscribeComponent; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:376](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L376) diff --git a/docs/framework/preact/reference/interfaces/Readable.md b/docs/framework/preact/reference/interfaces/Readable.md new file mode 100644 index 0000000000..ff2095ebfe --- /dev/null +++ b/docs/framework/preact/reference/interfaces/Readable.md @@ -0,0 +1,49 @@ +--- +id: Readable +title: Readable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:19 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\> + +## Extended by + +- [`BaseAtom`](BaseAtom.md) +- [`InternalBaseAtom`](InternalBaseAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/preact/reference/interfaces/ReadonlyAtom.md b/docs/framework/preact/reference/interfaces/ReadonlyAtom.md new file mode 100644 index 0000000000..bbc1e1d9c3 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/ReadonlyAtom.md @@ -0,0 +1,58 @@ +--- +id: ReadonlyAtom +title: ReadonlyAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:49 + +An atom that is read-only and cannot be set. + +## Example + +```ts +const atom = createAtom(() => 42); +// @ts-expect-error - Cannot set a readonly atom +atom.set(43); +``` + +## Extends + +- [`BaseAtom`](BaseAtom.md)\<`T`\> + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`get`](BaseAtom.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`subscribe`](BaseAtom.md#subscribe) diff --git a/docs/framework/preact/reference/interfaces/Subscribable.md b/docs/framework/preact/reference/interfaces/Subscribable.md new file mode 100644 index 0000000000..a11bf60b2a --- /dev/null +++ b/docs/framework/preact/reference/interfaces/Subscribable.md @@ -0,0 +1,36 @@ +--- +id: Subscribable +title: Subscribable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:16 + +## Extends + +- [`InteropSubscribable`](InteropSubscribable.md)\<`T`\> + +## Extended by + +- [`BaseAtom`](BaseAtom.md) +- [`InternalBaseAtom`](InternalBaseAtom.md) +- [`Readable`](Readable.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Overrides + +[`InteropSubscribable`](InteropSubscribable.md).[`subscribe`](InteropSubscribable.md#subscribe) diff --git a/docs/framework/preact/reference/interfaces/SubscribeProps.md b/docs/framework/preact/reference/interfaces/SubscribeProps.md new file mode 100644 index 0000000000..51dbf20d4d --- /dev/null +++ b/docs/framework/preact/reference/interfaces/SubscribeProps.md @@ -0,0 +1,84 @@ +--- +id: SubscribeProps +title: SubscribeProps +--- + +Defined in: [packages/preact-form/src/Subscribe.public.tsx:17](https://github.com/TanStack/form/blob/main/packages/preact-form/src/Subscribe.public.tsx#L17) + +Subscribe to `form.atom` (full form state). The selector receives the full +FormState. + +## Type Parameters + +### TSourceData + +`TSourceData` + +### TSelected + +`TSelected` + +## Properties + +### children + +```ts +children: ComponentChildren | ((state) => ComponentChildren); +``` + +Defined in: [packages/preact-form/src/Subscribe.public.tsx:28](https://github.com/TanStack/form/blob/main/packages/preact-form/src/Subscribe.public.tsx#L28) + +*** + +### selector + +```ts +selector: (state) => TSelected; +``` + +Defined in: [packages/preact-form/src/Subscribe.public.tsx:23](https://github.com/TanStack/form/blob/main/packages/preact-form/src/Subscribe.public.tsx#L23) + +Select from full form state. Re-renders when the selected value changes +(shallow compare). + +#### Parameters + +##### state + +`TSourceData` + +#### Returns + +`TSelected` + +*** + +### source + +```ts +source: SubscribeSource; +``` + +Defined in: [packages/preact-form/src/Subscribe.public.tsx:18](https://github.com/TanStack/form/blob/main/packages/preact-form/src/Subscribe.public.tsx#L18) + +*** + +### when? + +```ts +optional when?: (selected) => boolean; +``` + +Defined in: [packages/preact-form/src/Subscribe.public.tsx:27](https://github.com/TanStack/form/blob/main/packages/preact-form/src/Subscribe.public.tsx#L27) + +Optional. If provided, the component will only render when the `when` function returns `true`. + +#### Parameters + +##### selected + +`NoInfer`\<`TSelected`\> + +#### Returns + +`boolean` diff --git a/docs/framework/preact/reference/interfaces/Subscription.md b/docs/framework/preact/reference/interfaces/Subscription.md new file mode 100644 index 0000000000..fab2f285ee --- /dev/null +++ b/docs/framework/preact/reference/interfaces/Subscription.md @@ -0,0 +1,20 @@ +--- +id: Subscription +title: Subscription +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:13 + +## Properties + +### unsubscribe + +```ts +unsubscribe: () => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:14 + +#### Returns + +`void` diff --git a/docs/framework/preact/reference/interfaces/UseFieldOptions.md b/docs/framework/preact/reference/interfaces/UseFieldOptions.md deleted file mode 100644 index 50db2418cf..0000000000 --- a/docs/framework/preact/reference/interfaces/UseFieldOptions.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -id: UseFieldOptions -title: UseFieldOptions ---- - -# Interface: UseFieldOptions\ - -Defined in: [packages/preact-form/src/types.ts:21](https://github.com/TanStack/form/blob/main/packages/preact-form/src/types.ts#L21) - -The field options. - -## Extends - -- `FieldApiOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\>.`FieldOptionsMode` - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TSubmitMeta - -`TSubmitMeta` - -## Properties - -### mode? - -```ts -optional mode: "value" | "array"; -``` - -Defined in: [packages/preact-form/src/types.ts:15](https://github.com/TanStack/form/blob/main/packages/preact-form/src/types.ts#L15) - -#### Inherited from - -```ts -FieldOptionsMode.mode -``` diff --git a/docs/framework/preact/reference/interfaces/UseFieldOptionsBound.md b/docs/framework/preact/reference/interfaces/UseFieldOptionsBound.md deleted file mode 100644 index d7c053bf13..0000000000 --- a/docs/framework/preact/reference/interfaces/UseFieldOptionsBound.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -id: UseFieldOptionsBound -title: UseFieldOptionsBound ---- - -# Interface: UseFieldOptionsBound\ - -Defined in: [packages/preact-form/src/types.ts:82](https://github.com/TanStack/form/blob/main/packages/preact-form/src/types.ts#L82) - -## Extends - -- `FieldOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`\>.`FieldOptionsMode` - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -## Properties - -### mode? - -```ts -optional mode: "value" | "array"; -``` - -Defined in: [packages/preact-form/src/types.ts:15](https://github.com/TanStack/form/blob/main/packages/preact-form/src/types.ts#L15) - -#### Inherited from - -```ts -FieldOptionsMode.mode -``` diff --git a/docs/framework/preact/reference/interfaces/UseSelectorOptions.md b/docs/framework/preact/reference/interfaces/UseSelectorOptions.md new file mode 100644 index 0000000000..c77d6a8d00 --- /dev/null +++ b/docs/framework/preact/reference/interfaces/UseSelectorOptions.md @@ -0,0 +1,36 @@ +--- +id: UseSelectorOptions +title: UseSelectorOptions +--- + +Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.2\_preact@10.29.8/node\_modules/@tanstack/preact-store/dist/useSelector.d.ts:2 + +## Type Parameters + +### TSelected + +`TSelected` + +## Properties + +### compare? + +```ts +optional compare?: (a, b) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.2\_preact@10.29.8/node\_modules/@tanstack/preact-store/dist/useSelector.d.ts:3 + +#### Parameters + +##### a + +`TSelected` + +##### b + +`TSelected` + +#### Returns + +`boolean` diff --git a/docs/framework/preact/reference/interfaces/WithFieldGroupProps.md b/docs/framework/preact/reference/interfaces/WithFieldGroupProps.md deleted file mode 100644 index 72387be305..0000000000 --- a/docs/framework/preact/reference/interfaces/WithFieldGroupProps.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -id: WithFieldGroupProps -title: WithFieldGroupProps ---- - -# Interface: WithFieldGroupProps\ - -Defined in: [packages/preact-form/src/createFormHook.tsx:257](https://github.com/TanStack/form/blob/main/packages/preact-form/src/createFormHook.tsx#L257) - -## Extends - -- `BaseFormOptions`\<`TFieldGroupData`, `TSubmitMeta`\> - -## Type Parameters - -### TFieldGroupData - -`TFieldGroupData` - -### TFieldComponents - -`TFieldComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> - -### TFormComponents - -`TFormComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> - -### TSubmitMeta - -`TSubmitMeta` - -### TRenderProps - -`TRenderProps` *extends* `object` = `Record`\<`string`, `never`\> - -## Properties - -### props? - -```ts -optional props: TRenderProps; -``` - -Defined in: [packages/preact-form/src/createFormHook.tsx:265](https://github.com/TanStack/form/blob/main/packages/preact-form/src/createFormHook.tsx#L265) - -*** - -### render - -```ts -render: FunctionComponent & object>>; -``` - -Defined in: [packages/preact-form/src/createFormHook.tsx:266](https://github.com/TanStack/form/blob/main/packages/preact-form/src/createFormHook.tsx#L266) diff --git a/docs/framework/preact/reference/interfaces/WithFormProps.md b/docs/framework/preact/reference/interfaces/WithFormProps.md deleted file mode 100644 index bfddacb6cd..0000000000 --- a/docs/framework/preact/reference/interfaces/WithFormProps.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -id: WithFormProps -title: WithFormProps ---- - -# Interface: WithFormProps\ - -Defined in: [packages/preact-form/src/createFormHook.tsx:201](https://github.com/TanStack/form/blob/main/packages/preact-form/src/createFormHook.tsx#L201) - -## Extends - -- `FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` - -### TFieldComponents - -`TFieldComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> - -### TFormComponents - -`TFormComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> - -### TRenderProps - -`TRenderProps` *extends* `object` = `Record`\<`string`, `never`\> - -## Properties - -### props? - -```ts -optional props: TRenderProps; -``` - -Defined in: [packages/preact-form/src/createFormHook.tsx:232](https://github.com/TanStack/form/blob/main/packages/preact-form/src/createFormHook.tsx#L232) - -*** - -### render - -```ts -render: FunctionComponent & object>>; -``` - -Defined in: [packages/preact-form/src/createFormHook.tsx:233](https://github.com/TanStack/form/blob/main/packages/preact-form/src/createFormHook.tsx#L233) diff --git a/docs/framework/preact/reference/type-aliases/AnyAtom.md b/docs/framework/preact/reference/type-aliases/AnyAtom.md new file mode 100644 index 0000000000..6491b16950 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/AnyAtom.md @@ -0,0 +1,10 @@ +--- +id: AnyAtom +title: AnyAtom +--- + +```ts +type AnyAtom = BaseAtom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:36 diff --git a/docs/framework/preact/reference/type-aliases/AnyFieldGroupApi.md b/docs/framework/preact/reference/type-aliases/AnyFieldGroupApi.md new file mode 100644 index 0000000000..cd5a80a3a8 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/AnyFieldGroupApi.md @@ -0,0 +1,10 @@ +--- +id: AnyFieldGroupApi +title: AnyFieldGroupApi +--- + +```ts +type AnyFieldGroupApi = FieldGroupApi>>; +``` + +Defined in: [packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts:86](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts#L86) diff --git a/docs/framework/preact/reference/type-aliases/AnyPreactFormApi.md b/docs/framework/preact/reference/type-aliases/AnyPreactFormApi.md new file mode 100644 index 0000000000..89cd2a5114 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/AnyPreactFormApi.md @@ -0,0 +1,34 @@ +--- +id: AnyPreactFormApi +title: AnyPreactFormApi +--- + +```ts +type AnyPreactFormApi = AnyFormApi & PreactTanStackFormComponents; +``` + +Defined in: [packages/preact-form/src/PreactForm/formApiTypes.public.ts:50](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/formApiTypes.public.ts#L50) + +A Preact form API whose form data and error types are erased. + +Use it for reusable Preact components that only need core form operations +and the `Field`, `ArrayField`, `Subscribe`, or `FormGroup` components common +to every Preact form. Field paths and values are not checked against a +particular form shape; use `PreactFormType` when a component depends on one +known form. + +## Example + +```tsx +function FormSubmitButton({ form }: { form: AnyPreactFormApi }) { + return ( + state.isSubmitting}> + {(isSubmitting) => ( + + )} + + ) +} +``` diff --git a/docs/framework/preact/reference/type-aliases/AnyPreactFormComponentMap.md b/docs/framework/preact/reference/type-aliases/AnyPreactFormComponentMap.md new file mode 100644 index 0000000000..f93608c85c --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/AnyPreactFormComponentMap.md @@ -0,0 +1,10 @@ +--- +id: AnyPreactFormComponentMap +title: AnyPreactFormComponentMap +--- + +```ts +type AnyPreactFormComponentMap = PreactFormComponentMap>, Record>>; +``` + +Defined in: [packages/preact-form/src/AppForm/componentMap.public.ts:11](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/componentMap.public.ts#L11) diff --git a/docs/framework/preact/reference/type-aliases/AppFormComponent.md b/docs/framework/preact/reference/type-aliases/AppFormComponent.md new file mode 100644 index 0000000000..6317c86c84 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/AppFormComponent.md @@ -0,0 +1,12 @@ +--- +id: AppFormComponent +title: AppFormComponent +--- + +```ts +type AppFormComponent = FunctionComponent<{ + children: Exclude>; +}>; +``` + +Defined in: [packages/preact-form/src/AppForm/PreactAppFormApi.public.tsx:7](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/PreactAppFormApi.public.tsx#L7) diff --git a/docs/framework/preact/reference/type-aliases/CrossVersionPreactNode.md b/docs/framework/preact/reference/type-aliases/CrossVersionPreactNode.md new file mode 100644 index 0000000000..fbdfd3550d --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/CrossVersionPreactNode.md @@ -0,0 +1,13 @@ +--- +id: CrossVersionPreactNode +title: CrossVersionPreactNode +--- + +```ts +type CrossVersionPreactNode = ReturnType>; +``` + +Defined in: [packages/preact-form/src/preactTypes.public.ts:6](https://github.com/TanStack/form/blob/main/packages/preact-form/src/preactTypes.public.ts#L6) + +Keeps component children compatible across supported Preact versions. diff --git a/docs/framework/preact/reference/type-aliases/DefaultPreactFormComponentMap.md b/docs/framework/preact/reference/type-aliases/DefaultPreactFormComponentMap.md new file mode 100644 index 0000000000..b75aeee904 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/DefaultPreactFormComponentMap.md @@ -0,0 +1,10 @@ +--- +id: DefaultPreactFormComponentMap +title: DefaultPreactFormComponentMap +--- + +```ts +type DefaultPreactFormComponentMap = PreactFormComponentMap, Record>; +``` + +Defined in: [packages/preact-form/src/AppForm/componentMap.public.ts:16](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/componentMap.public.ts#L16) diff --git a/docs/framework/preact/reference/type-aliases/DefineFieldGroupFn.md b/docs/framework/preact/reference/type-aliases/DefineFieldGroupFn.md new file mode 100644 index 0000000000..d0ddd1e3e2 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/DefineFieldGroupFn.md @@ -0,0 +1,34 @@ +--- +id: DefineFieldGroupFn +title: DefineFieldGroupFn +--- + +```ts +type DefineFieldGroupFn = (defineFn) => FieldGroupDefinition; +``` + +Defined in: [packages/preact-form/src/FieldGroup/withFields.public.ts:84](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/withFields.public.ts#L84) + +Signature shared by `defineFieldGroup` and app-form field-group definers. + +## Type Parameters + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +## Parameters + +### defineFn + +(`helper`) => `TFields` + +## Returns + +[`FieldGroupDefinition`](../interfaces/FieldGroupDefinition.md)\<`TFields`, `TFieldComponents`\> diff --git a/docs/framework/preact/reference/type-aliases/FieldComponent.md b/docs/framework/preact/reference/type-aliases/FieldComponent.md deleted file mode 100644 index 6c4bfe0c61..0000000000 --- a/docs/framework/preact/reference/type-aliases/FieldComponent.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -id: FieldComponent -title: FieldComponent ---- - -# Type Alias: FieldComponent()\ - -```ts -type FieldComponent = ({ - children, - ...fieldOptions -}) => ReturnType; -``` - -Defined in: [packages/preact-form/src/useField.tsx:472](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useField.tsx#L472) - -A type alias representing a field component for a specific form data type. - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TPatentSubmitMeta - -`TPatentSubmitMeta` - -### ExtendedApi - -`ExtendedApi` = \{ -\} - -## Type Parameters - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -## Parameters - -### \{ - children, - ...fieldOptions -\} - -`FieldComponentBoundProps`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TPatentSubmitMeta`, `ExtendedApi`\> - -## Returns - -`ReturnType`\<`FunctionComponent`\> diff --git a/docs/framework/preact/reference/type-aliases/FieldGroupFieldBindingsOf.md b/docs/framework/preact/reference/type-aliases/FieldGroupFieldBindingsOf.md new file mode 100644 index 0000000000..82c02bfaae --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/FieldGroupFieldBindingsOf.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupFieldBindingsOf +title: FieldGroupFieldBindingsOf +--- + +```ts +type FieldGroupFieldBindingsOf = FieldGroupFieldsOf extends FieldGroupFields ? FieldGroupFieldBindings, TFormData> : never; +``` + +Defined in: [packages/preact-form/src/FieldGroup/withFields.public.ts:48](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/withFields.public.ts#L48) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` + +### TFormData + +`TFormData` diff --git a/docs/framework/preact/reference/type-aliases/FieldGroupFieldComponentsOf.md b/docs/framework/preact/reference/type-aliases/FieldGroupFieldComponentsOf.md new file mode 100644 index 0000000000..d5ad980fa0 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/FieldGroupFieldComponentsOf.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupFieldComponentsOf +title: FieldGroupFieldComponentsOf +--- + +```ts +type FieldGroupFieldComponentsOf = TFieldGroup extends PreactFieldGroup ? TFieldComponents : never; +``` + +Defined in: [packages/preact-form/src/FieldGroup/withFields.public.ts:34](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/withFields.public.ts#L34) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` diff --git a/docs/framework/preact/reference/type-aliases/FieldGroupFieldsOf.md b/docs/framework/preact/reference/type-aliases/FieldGroupFieldsOf.md new file mode 100644 index 0000000000..c3a95208c3 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/FieldGroupFieldsOf.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupFieldsOf +title: FieldGroupFieldsOf +--- + +```ts +type FieldGroupFieldsOf = TFieldGroup extends object ? TFields : never; +``` + +Defined in: [packages/preact-form/src/FieldGroup/withFields.public.ts:18](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/withFields.public.ts#L18) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` diff --git a/docs/framework/preact/reference/type-aliases/FieldGroupForm.md b/docs/framework/preact/reference/type-aliases/FieldGroupForm.md new file mode 100644 index 0000000000..fc8370efac --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/FieldGroupForm.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupForm +title: FieldGroupForm +--- + +```ts +type FieldGroupForm = FormApi & PreactTanStackFormComponents; +``` + +Defined in: [packages/preact-form/src/FieldGroup/withFields.public.ts:39](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/withFields.public.ts#L39) + +## Type Parameters + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> = `Record`\<`never`, `never`\> + +### TFormData + +`TFormData` = `any` diff --git a/docs/framework/preact/reference/type-aliases/FieldGroupFormState.md b/docs/framework/preact/reference/type-aliases/FieldGroupFormState.md new file mode 100644 index 0000000000..c9d433ac5a --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/FieldGroupFormState.md @@ -0,0 +1,10 @@ +--- +id: FieldGroupFormState +title: FieldGroupFormState +--- + +```ts +type FieldGroupFormState = FormState; +``` + +Defined in: [packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts:91](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts#L91) diff --git a/docs/framework/preact/reference/type-aliases/FieldGroupSubscribeComponent.md b/docs/framework/preact/reference/type-aliases/FieldGroupSubscribeComponent.md new file mode 100644 index 0000000000..7a53ec85c7 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/FieldGroupSubscribeComponent.md @@ -0,0 +1,26 @@ +--- +id: FieldGroupSubscribeComponent +title: FieldGroupSubscribeComponent +--- + +```ts +type FieldGroupSubscribeComponent = (props) => CrossVersionPreactNode; +``` + +Defined in: [packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts:70](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts#L70) + +## Type Parameters + +### TSelected + +`TSelected` + +## Parameters + +### props + +[`FieldGroupSubscribeProps`](FieldGroupSubscribeProps.md)\<`TSelected`\> + +## Returns + +[`CrossVersionPreactNode`](CrossVersionPreactNode.md) diff --git a/docs/framework/preact/reference/type-aliases/FieldGroupSubscribeProps.md b/docs/framework/preact/reference/type-aliases/FieldGroupSubscribeProps.md new file mode 100644 index 0000000000..ab9d11634e --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/FieldGroupSubscribeProps.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupSubscribeProps +title: FieldGroupSubscribeProps +--- + +```ts +type FieldGroupSubscribeProps = PreactFormSubscribeProps; +``` + +Defined in: [packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts:64](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/FieldGroupApi.public.ts#L64) + +## Type Parameters + +### TSelected + +`TSelected` diff --git a/docs/framework/preact/reference/type-aliases/FieldGroupWithFieldsFn.md b/docs/framework/preact/reference/type-aliases/FieldGroupWithFieldsFn.md new file mode 100644 index 0000000000..5b97c35fdc --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/FieldGroupWithFieldsFn.md @@ -0,0 +1,40 @@ +--- +id: FieldGroupWithFieldsFn +title: FieldGroupWithFieldsFn +--- + +```ts +type FieldGroupWithFieldsFn = (Component, fieldsPropName) => (props) => CrossVersionPreactNode; +``` + +Defined in: [packages/preact-form/src/FieldGroup/withFields.public.ts:53](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/withFields.public.ts#L53) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` *extends* [`PreactFieldGroup`](PreactFieldGroup.md)\<`any`, `any`\> + +## Type Parameters + +### TProps + +`TProps` *extends* `object` + +### TFieldsPropName + +`TFieldsPropName` *extends* `FieldGroupFieldsPropName`\<`TProps`, `TFieldGroup`\> + +## Parameters + +### Component + +(`props`) => [`CrossVersionPreactNode`](CrossVersionPreactNode.md) + +### fieldsPropName + +`TFieldsPropName` + +## Returns + +\<`TFormData`\>(`props`) => [`CrossVersionPreactNode`](CrossVersionPreactNode.md) diff --git a/docs/framework/preact/reference/type-aliases/FormGroupComponent.md b/docs/framework/preact/reference/type-aliases/FormGroupComponent.md deleted file mode 100644 index edeca239fb..0000000000 --- a/docs/framework/preact/reference/type-aliases/FormGroupComponent.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -id: FormGroupComponent -title: FormGroupComponent ---- - -# Type Alias: FormGroupComponent()\ - -```ts -type FormGroupComponent = ({ - children, - ...formGroupOptions -}) => ReturnType; -``` - -Defined in: [packages/preact-form/src/useFormGroup.tsx:559](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useFormGroup.tsx#L559) - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` - -### ExtendedApi - -`ExtendedApi` = \{ -\} - -## Type Parameters - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TSubmitMeta - -`TSubmitMeta` - -## Parameters - -### \{ - children, - ...formGroupOptions -\} - -`FormGroupComponentBoundProps`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`, `ExtendedApi`\> - -## Returns - -`ReturnType`\<`FunctionComponent`\> diff --git a/docs/framework/preact/reference/type-aliases/LensFieldComponent.md b/docs/framework/preact/reference/type-aliases/LensFieldComponent.md deleted file mode 100644 index 2fcc1c19d0..0000000000 --- a/docs/framework/preact/reference/type-aliases/LensFieldComponent.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -id: LensFieldComponent -title: LensFieldComponent ---- - -# Type Alias: LensFieldComponent()\ - -```ts -type LensFieldComponent = ({ - children, - ...fieldOptions -}) => ReturnType; -``` - -Defined in: [packages/preact-form/src/useField.tsx:547](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useField.tsx#L547) - -A type alias representing a field component for a form lens data type. - -## Type Parameters - -### TLensData - -`TLensData` - -### TParentSubmitMeta - -`TParentSubmitMeta` - -### ExtendedApi - -`ExtendedApi` = \{ -\} - -## Type Parameters - -### TName - -`TName` *extends* `DeepKeys`\<`TLensData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TLensData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`unknown`, `string`, `TData`\> - -## Parameters - -### \{ - children, - ...fieldOptions -\} - -`Omit`\<`FieldComponentBoundProps`\<`unknown`, `string`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `TParentSubmitMeta`, `ExtendedApi`\>, `"name"` \| `"validators"`\> & `object` - -## Returns - -`ReturnType`\<`FunctionComponent`\> diff --git a/docs/framework/preact/reference/type-aliases/Observer.md b/docs/framework/preact/reference/type-aliases/Observer.md new file mode 100644 index 0000000000..c32765443c --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/Observer.md @@ -0,0 +1,70 @@ +--- +id: Observer +title: Observer +--- + +```ts +type Observer = object; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:8 + +## Type Parameters + +### T + +`T` + +## Properties + +### complete? + +```ts +optional complete?: () => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:11 + +#### Returns + +`void` + +*** + +### error? + +```ts +optional error?: (err) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:10 + +#### Parameters + +##### err + +`unknown` + +#### Returns + +`void` + +*** + +### next? + +```ts +optional next?: (value) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:9 + +#### Parameters + +##### value + +`T` + +#### Returns + +`void` diff --git a/docs/framework/preact/reference/type-aliases/PreactAppFormApi.md b/docs/framework/preact/reference/type-aliases/PreactAppFormApi.md new file mode 100644 index 0000000000..4fc37056b1 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/PreactAppFormApi.md @@ -0,0 +1,32 @@ +--- +id: PreactAppFormApi +title: PreactAppFormApi +--- + +```ts +type PreactAppFormApi = PreactFormApi & object; +``` + +Defined in: [packages/preact-form/src/AppForm/PreactAppFormApi.public.tsx:11](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/PreactAppFormApi.public.tsx#L11) + +## Type Declaration + +### AppForm + +```ts +AppForm: AppFormComponent; +``` + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TComponents + +`TComponents` *extends* [`AnyPreactFormComponentMap`](AnyPreactFormComponentMap.md) diff --git a/docs/framework/preact/reference/type-aliases/PreactFieldApi.md b/docs/framework/preact/reference/type-aliases/PreactFieldApi.md new file mode 100644 index 0000000000..d26865d403 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/PreactFieldApi.md @@ -0,0 +1,36 @@ +--- +id: PreactFieldApi +title: PreactFieldApi +--- + +```ts +type PreactFieldApi = FieldApi & FieldComponentsMatchingType; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:78](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L78) + +## Type Parameters + +### TFieldName + +`TFieldName` + +### TFieldValue + +`TFieldValue` + +### TFieldError + +`TFieldError` + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> diff --git a/docs/framework/preact/reference/type-aliases/PreactFieldGroup.md b/docs/framework/preact/reference/type-aliases/PreactFieldGroup.md new file mode 100644 index 0000000000..deb32309c2 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/PreactFieldGroup.md @@ -0,0 +1,28 @@ +--- +id: PreactFieldGroup +title: PreactFieldGroup +--- + +```ts +type PreactFieldGroup = FieldGroupApi, TFieldComponents> & object; +``` + +Defined in: [packages/preact-form/src/FieldGroup/withFields.public.ts:24](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/withFields.public.ts#L24) + +## Type Declaration + +### \[fieldGroupFieldsSymbol\] + +```ts +readonly [fieldGroupFieldsSymbol]: TFields; +``` + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> = `Record`\<`never`, `never`\> diff --git a/docs/framework/preact/reference/type-aliases/PreactFormApi.md b/docs/framework/preact/reference/type-aliases/PreactFormApi.md new file mode 100644 index 0000000000..f4d4087c4e --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/PreactFormApi.md @@ -0,0 +1,24 @@ +--- +id: PreactFormApi +title: PreactFormApi +--- + +```ts +type PreactFormApi = unknown extends TComponents["formComponents"] ? ExtendedFormApi : ExtendedFormApi & TComponents["formComponents"]; +``` + +Defined in: [packages/preact-form/src/PreactForm/formApiTypes.public.ts:13](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/formApiTypes.public.ts#L13) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TComponents + +`TComponents` *extends* [`AnyPreactFormComponentMap`](AnyPreactFormComponentMap.md) diff --git a/docs/framework/preact/reference/type-aliases/PreactFormArrayFieldComponent.md b/docs/framework/preact/reference/type-aliases/PreactFormArrayFieldComponent.md new file mode 100644 index 0000000000..d26bb540c4 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/PreactFormArrayFieldComponent.md @@ -0,0 +1,44 @@ +--- +id: PreactFormArrayFieldComponent +title: PreactFormArrayFieldComponent +--- + +```ts +type PreactFormArrayFieldComponent = (props) => ComponentChildren; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:177](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L177) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `never` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>\> + +## Parameters + +### props + +[`PreactFormFieldProps`](../interfaces/PreactFormFieldProps.md)\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`ComponentChildren` diff --git a/docs/framework/preact/reference/type-aliases/PreactFormExtendedApi.md b/docs/framework/preact/reference/type-aliases/PreactFormExtendedApi.md deleted file mode 100644 index d8eba6b212..0000000000 --- a/docs/framework/preact/reference/type-aliases/PreactFormExtendedApi.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -id: PreactFormExtendedApi -title: PreactFormExtendedApi ---- - -# Type Alias: PreactFormExtendedApi\ - -```ts -type PreactFormExtendedApi = FormApi & PreactFormApi; -``` - -Defined in: [packages/preact-form/src/useForm.tsx:113](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useForm.tsx#L113) - -An extended version of the `FormApi` class that includes Preact-specific functionalities from `PreactFormApi` - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` diff --git a/docs/framework/preact/reference/type-aliases/PreactFormFieldComponent.md b/docs/framework/preact/reference/type-aliases/PreactFormFieldComponent.md new file mode 100644 index 0000000000..7a95a095ab --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/PreactFormFieldComponent.md @@ -0,0 +1,44 @@ +--- +id: PreactFormFieldComponent +title: PreactFormFieldComponent +--- + +```ts +type PreactFormFieldComponent = (props) => ComponentChildren; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:151](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L151) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `string` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>\> + +## Parameters + +### props + +[`PreactFormFieldProps`](../interfaces/PreactFormFieldProps.md)\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`ComponentChildren` diff --git a/docs/framework/preact/reference/type-aliases/PreactFormGroupArrayFieldComponent.md b/docs/framework/preact/reference/type-aliases/PreactFormGroupArrayFieldComponent.md new file mode 100644 index 0000000000..42a8c2ab11 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/PreactFormGroupArrayFieldComponent.md @@ -0,0 +1,52 @@ +--- +id: PreactFormGroupArrayFieldComponent +title: PreactFormGroupArrayFieldComponent +--- + +```ts +type PreactFormGroupArrayFieldComponent = (props) => ComponentChildren; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:251](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L251) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\> + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `never` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>\> + +## Parameters + +### props + +[`PreactFormFieldProps`](../interfaces/PreactFormFieldProps.md)\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>, `TFieldValidators`, `TGroupErrorTypes`\[`"fieldError"`\], `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`ComponentChildren` diff --git a/docs/framework/preact/reference/type-aliases/PreactFormGroupSubscribeComponent.md b/docs/framework/preact/reference/type-aliases/PreactFormGroupSubscribeComponent.md new file mode 100644 index 0000000000..17a82055d1 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/PreactFormGroupSubscribeComponent.md @@ -0,0 +1,36 @@ +--- +id: PreactFormGroupSubscribeComponent +title: PreactFormGroupSubscribeComponent +--- + +```ts +type PreactFormGroupSubscribeComponent = (props) => CrossVersionPreactNode; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:212](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L212) + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +## Type Parameters + +### TSelected + +`TSelected` + +## Parameters + +### props + +[`PreactFormGroupSubscribeProps`](PreactFormGroupSubscribeProps.md)\<`TGroupValue`, `TGroupErrorTypes`, `TSelected`\> + +## Returns + +[`CrossVersionPreactNode`](CrossVersionPreactNode.md) diff --git a/docs/framework/preact/reference/type-aliases/PreactFormGroupSubscribeProps.md b/docs/framework/preact/reference/type-aliases/PreactFormGroupSubscribeProps.md new file mode 100644 index 0000000000..040606686c --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/PreactFormGroupSubscribeProps.md @@ -0,0 +1,24 @@ +--- +id: PreactFormGroupSubscribeProps +title: PreactFormGroupSubscribeProps +--- + +```ts +type PreactFormGroupSubscribeProps = PreactSubscribeProps, TSelected>; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:203](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L203) + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TSelected + +`TSelected` diff --git a/docs/framework/preact/reference/type-aliases/PreactFormSubscribeComponent.md b/docs/framework/preact/reference/type-aliases/PreactFormSubscribeComponent.md new file mode 100644 index 0000000000..c92536962d --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/PreactFormSubscribeComponent.md @@ -0,0 +1,36 @@ +--- +id: PreactFormSubscribeComponent +title: PreactFormSubscribeComponent +--- + +```ts +type PreactFormSubscribeComponent = (props) => CrossVersionPreactNode; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:106](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L106) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +## Type Parameters + +### TSelected + +`TSelected` + +## Parameters + +### props + +[`PreactFormSubscribeProps`](PreactFormSubscribeProps.md)\<`TFormData`, `TFormErrorTypes`, `TSelected`\> + +## Returns + +[`CrossVersionPreactNode`](CrossVersionPreactNode.md) diff --git a/docs/framework/preact/reference/type-aliases/PreactFormSubscribeProps.md b/docs/framework/preact/reference/type-aliases/PreactFormSubscribeProps.md new file mode 100644 index 0000000000..2dea9680a0 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/PreactFormSubscribeProps.md @@ -0,0 +1,24 @@ +--- +id: PreactFormSubscribeProps +title: PreactFormSubscribeProps +--- + +```ts +type PreactFormSubscribeProps = PreactSubscribeProps, TSelected>; +``` + +Defined in: [packages/preact-form/src/PreactForm/Components.public.ts:100](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/Components.public.ts#L100) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TSelected + +`TSelected` diff --git a/docs/framework/preact/reference/type-aliases/PreactFormType.md b/docs/framework/preact/reference/type-aliases/PreactFormType.md new file mode 100644 index 0000000000..a295228983 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/PreactFormType.md @@ -0,0 +1,45 @@ +--- +id: PreactFormType +title: PreactFormType +--- + +```ts +type PreactFormType = TOptions extends FormOptions ? PreactFormApi, TComponents extends AnyPreactFormComponentMap ? TComponents : DefaultPreactFormComponentMap> : never; +``` + +Defined in: [packages/preact-form/src/PreactForm/formType.public.ts:55](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/formType.public.ts#L55) + +Derives the Preact form API type represented by a reusable options object. + +Use it to type props for components that belong to one known form shape. It +preserves the inferred form data and any components registered through +`appFormOptions`. Options such as `onSubmit` can be defined either in the +shared options or when the form is created in the component. + +## Type Parameters + +### TOptions + +`TOptions` *extends* `AnyFormOptions` + +The reusable form or app-form options from which the API derives its form data, error, and registered-component types. + +## Example + +```tsx +const profileOptions = formOptions({ + defaultValues: { name: '' }, +}) + +type ProfileForm = PreactFormType + +function NameField(props: { + form: ProfileForm +}) { + return ( + + {(field) => } + + ) +} +``` diff --git a/docs/framework/preact/reference/type-aliases/PropsWithChildren.md b/docs/framework/preact/reference/type-aliases/PropsWithChildren.md deleted file mode 100644 index d2e052bb15..0000000000 --- a/docs/framework/preact/reference/type-aliases/PropsWithChildren.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -id: PropsWithChildren -title: PropsWithChildren ---- - -# Type Alias: PropsWithChildren\ - -```ts -type PropsWithChildren

    = P & object; -``` - -Defined in: [packages/preact-form/src/types.ts:141](https://github.com/TanStack/form/blob/main/packages/preact-form/src/types.ts#L141) - -## Type Declaration - -### children? - -```ts -optional children: ComponentChildren; -``` - -## Type Parameters - -### P - -`P` = `unknown` diff --git a/docs/framework/preact/reference/type-aliases/Selection.md b/docs/framework/preact/reference/type-aliases/Selection.md new file mode 100644 index 0000000000..0ec13fa14b --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/Selection.md @@ -0,0 +1,16 @@ +--- +id: Selection +title: Selection +--- + +```ts +type Selection = Readable; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:4 + +## Type Parameters + +### TSelected + +`TSelected` diff --git a/docs/framework/preact/reference/type-aliases/ServerFormState.md b/docs/framework/preact/reference/type-aliases/ServerFormState.md deleted file mode 100644 index 53dfa5bc72..0000000000 --- a/docs/framework/preact/reference/type-aliases/ServerFormState.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -id: ServerFormState -title: ServerFormState ---- - -# Type Alias: ServerFormState\ - -```ts -type ServerFormState = Pick, "values" | "errors" | "errorMap">; -``` - -Defined in: [packages/preact-form/src/types.ts:121](https://github.com/TanStack/form/blob/main/packages/preact-form/src/types.ts#L121) - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> diff --git a/docs/framework/preact/reference/type-aliases/StoreAction.md b/docs/framework/preact/reference/type-aliases/StoreAction.md new file mode 100644 index 0000000000..3c38ef14ec --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/StoreAction.md @@ -0,0 +1,20 @@ +--- +id: StoreAction +title: StoreAction +--- + +```ts +type StoreAction = (...args) => any; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:4 + +## Parameters + +### args + +...`any`[] + +## Returns + +`any` diff --git a/docs/framework/preact/reference/type-aliases/StoreActionMap.md b/docs/framework/preact/reference/type-aliases/StoreActionMap.md new file mode 100644 index 0000000000..c23e39e1bd --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/StoreActionMap.md @@ -0,0 +1,10 @@ +--- +id: StoreActionMap +title: StoreActionMap +--- + +```ts +type StoreActionMap = Record; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:5 diff --git a/docs/framework/preact/reference/type-aliases/StoreActionsFactory.md b/docs/framework/preact/reference/type-aliases/StoreActionsFactory.md new file mode 100644 index 0000000000..b87f92ecf9 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/StoreActionsFactory.md @@ -0,0 +1,36 @@ +--- +id: StoreActionsFactory +title: StoreActionsFactory +--- + +```ts +type StoreActionsFactory = (store) => TActions; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:6 + +## Type Parameters + +### T + +`T` + +### TActions + +`TActions` *extends* [`StoreActionMap`](StoreActionMap.md) + +## Parameters + +### store + +#### get + +[`Store`](../classes/Store.md)\<`T`\>\[`"get"`\] + +#### setState + +[`Store`](../classes/Store.md)\<`T`\>\[`"setState"`\] + +## Returns + +`TActions` diff --git a/docs/framework/preact/reference/type-aliases/SubscribeSource.md b/docs/framework/preact/reference/type-aliases/SubscribeSource.md new file mode 100644 index 0000000000..3c41e1f30f --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/SubscribeSource.md @@ -0,0 +1,20 @@ +--- +id: SubscribeSource +title: SubscribeSource +--- + +```ts +type SubscribeSource = + | Atom + | ReadonlyAtom + | Store +| ReadonlyStore; +``` + +Defined in: [packages/preact-form/src/Subscribe.public.tsx:10](https://github.com/TanStack/form/blob/main/packages/preact-form/src/Subscribe.public.tsx#L10) + +## Type Parameters + +### TValue + +`TValue` diff --git a/docs/framework/preact/reference/type-aliases/UseAppFormHook.md b/docs/framework/preact/reference/type-aliases/UseAppFormHook.md new file mode 100644 index 0000000000..9fb0924d89 --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/UseAppFormHook.md @@ -0,0 +1,40 @@ +--- +id: UseAppFormHook +title: UseAppFormHook +--- + +```ts +type UseAppFormHook = (options) => PreactAppFormApi, TComponents>; +``` + +Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:98](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L98) + +## Type Parameters + +### TComponents + +`TComponents` *extends* [`AnyPreactFormComponentMap`](AnyPreactFormComponentMap.md) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> + +### TSubmitReturn + +`TSubmitReturn` + +## Parameters + +### options + +`FormOptions`\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\> + +## Returns + +[`PreactAppFormApi`](PreactAppFormApi.md)\<`TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>, `TComponents`\> diff --git a/docs/framework/preact/reference/type-aliases/UseField.md b/docs/framework/preact/reference/type-aliases/UseField.md deleted file mode 100644 index f6b349da0f..0000000000 --- a/docs/framework/preact/reference/type-aliases/UseField.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -id: UseField -title: UseField ---- - -# Type Alias: UseField()\ - -```ts -type UseField = (opts) => FieldApi; -``` - -Defined in: [packages/preact-form/src/useField.tsx:24](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useField.tsx#L24) - -A type representing a hook for using a field in a form with the given form data type. - -A function that takes an optional object with a `name` property and field options, and returns a `FieldApi` instance for the specified field. - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TPatentSubmitMeta - -`TPatentSubmitMeta` - -## Type Parameters - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -## Parameters - -### opts - -[`UseFieldOptionsBound`](../interfaces/UseFieldOptionsBound.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`\> - -## Returns - -`FieldApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TPatentSubmitMeta`\> diff --git a/docs/framework/preact/reference/type-aliases/UseFormGroup.md b/docs/framework/preact/reference/type-aliases/UseFormGroup.md deleted file mode 100644 index 2e895bc302..0000000000 --- a/docs/framework/preact/reference/type-aliases/UseFormGroup.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -id: UseFormGroup -title: UseFormGroup ---- - -# Type Alias: UseFormGroup()\ - -```ts -type UseFormGroup = (opts) => FormGroupApi; -``` - -Defined in: [packages/preact-form/src/useFormGroup.tsx:17](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useFormGroup.tsx#L17) - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Type Parameters - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TSubmitMeta - -`TSubmitMeta` - -## Parameters - -### opts - -`FormGroupApiOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Returns - -`FormGroupApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> diff --git a/docs/framework/preact/reference/type-aliases/UseFormHook.md b/docs/framework/preact/reference/type-aliases/UseFormHook.md new file mode 100644 index 0000000000..3f4980021f --- /dev/null +++ b/docs/framework/preact/reference/type-aliases/UseFormHook.md @@ -0,0 +1,40 @@ +--- +id: UseFormHook +title: UseFormHook +--- + +```ts +type UseFormHook = (options) => PreactFormApi, TComponents>; +``` + +Defined in: [packages/preact-form/src/PreactForm/useForm.public.ts:13](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/useForm.public.ts#L13) + +## Type Parameters + +### TComponents + +`TComponents` *extends* [`AnyPreactFormComponentMap`](AnyPreactFormComponentMap.md) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> + +### TSubmitReturn + +`TSubmitReturn` + +## Parameters + +### options + +`FormOptions`\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\> + +## Returns + +[`PreactFormApi`](PreactFormApi.md)\<`TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>, `TComponents`\> diff --git a/docs/framework/preact/reference/variables/Field.md b/docs/framework/preact/reference/variables/Field.md deleted file mode 100644 index 82991ba648..0000000000 --- a/docs/framework/preact/reference/variables/Field.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -id: Field -title: Field ---- - -# Variable: Field() - -```ts -const Field: (__namedParameters) => ComponentChildren; -``` - -Defined in: [packages/preact-form/src/useField.tsx:637](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useField.tsx#L637) - -A function component that takes field options and a render function as children and returns a React component. - -The `Field` component uses the `useField` hook internally to manage the field instance. - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TPatentSubmitMeta - -`TPatentSubmitMeta` - -## Parameters - -### \_\_namedParameters - -`FieldComponentProps`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TPatentSubmitMeta`\> - -## Returns - -`ComponentChildren` diff --git a/docs/framework/preact/reference/variables/FormGroup.md b/docs/framework/preact/reference/variables/FormGroup.md deleted file mode 100644 index 408bad4c1d..0000000000 --- a/docs/framework/preact/reference/variables/FormGroup.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -id: FormGroup -title: FormGroup ---- - -# Variable: FormGroup() - -```ts -const FormGroup: (__namedParameters) => ComponentChildren; -``` - -Defined in: [packages/preact-form/src/useFormGroup.tsx:639](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useFormGroup.tsx#L639) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Parameters - -### \_\_namedParameters - -`FormGroupComponentProps`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Returns - -`ComponentChildren` diff --git a/docs/framework/preact/reference/variables/defineFieldGroup.md b/docs/framework/preact/reference/variables/defineFieldGroup.md new file mode 100644 index 0000000000..db6f990827 --- /dev/null +++ b/docs/framework/preact/reference/variables/defineFieldGroup.md @@ -0,0 +1,12 @@ +--- +id: defineFieldGroup +title: defineFieldGroup +--- + +```ts +const defineFieldGroup: DefineFieldGroupFn>; +``` + +Defined in: [packages/preact-form/src/FieldGroup/withFields.public.ts:91](https://github.com/TanStack/form/blob/main/packages/preact-form/src/FieldGroup/withFields.public.ts#L91) + +Defines a reusable group of virtual fields. diff --git a/docs/framework/preact/reference/variables/useForm.md b/docs/framework/preact/reference/variables/useForm.md new file mode 100644 index 0000000000..dacb93d00d --- /dev/null +++ b/docs/framework/preact/reference/variables/useForm.md @@ -0,0 +1,44 @@ +--- +id: useForm +title: useForm +--- + +```ts +const useForm: UseFormHook; +``` + +Defined in: [packages/preact-form/src/PreactForm/useForm.public.ts:63](https://github.com/TanStack/form/blob/main/packages/preact-form/src/PreactForm/useForm.public.ts#L63) + +Creates a Preact form whose instance and lifecycle are owned by the current +component. + +`defaultValues` establish the initial state and inferred form value type. +Later renders apply changed options to the same form instance, and unmounting +the component cleans it up. + +Call this hook at the top level of a Preact component or custom hook. + +## Example + +```tsx +function ProfileForm() { + const form = useForm({ + defaultValues: { name: '' }, + onSubmit: ({ value }) => saveProfile(value), + }) + + return ( +

    { + event.preventDefault() + void form.handleSubmit() + }} + /> + ) +} +``` + +## Returns + +The Preact form API with typed field, subscription, and form-group +components attached. diff --git a/docs/framework/preact/reference/variables/useIsomorphicLayoutEffect.md b/docs/framework/preact/reference/variables/useIsomorphicLayoutEffect.md deleted file mode 100644 index 3b91e238cd..0000000000 --- a/docs/framework/preact/reference/variables/useIsomorphicLayoutEffect.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -id: useIsomorphicLayoutEffect -title: useIsomorphicLayoutEffect ---- - -# Variable: useIsomorphicLayoutEffect() - -```ts -const useIsomorphicLayoutEffect: (effect, inputs?) => void; -``` - -Defined in: [packages/preact-form/src/useIsomorphicLayoutEffect.ts:3](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useIsomorphicLayoutEffect.ts#L3) - -Accepts a function that contains imperative, possibly effectful code. -Use this to read layout from the DOM and synchronously re-render. -Updates scheduled inside `useLayoutEffect` will be flushed synchronously, after all DOM mutations but before the browser has a chance to paint. -Prefer the standard `useEffect` hook when possible to avoid blocking visual updates. - -## Parameters - -### effect - -`EffectCallback` - -Imperative function that can return a cleanup function - -### inputs? - -`Inputs` - -If present, effect will only activate if the values in the list change (using ===). - -## Returns - -`void` diff --git a/docs/framework/preact/reference/variables/useStore.md b/docs/framework/preact/reference/variables/useStore.md index 46bd3c832a..573a966fca 100644 --- a/docs/framework/preact/reference/variables/useStore.md +++ b/docs/framework/preact/reference/variables/useStore.md @@ -3,13 +3,11 @@ id: useStore title: useStore --- -# ~~Variable: useStore()~~ - ```ts const useStore: (source, selector?, compare?) => TSelected; ``` -Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.1\_preact@10.29.2/node\_modules/@tanstack/preact-store/dist/useStore.d.ts:12 +Defined in: node\_modules/.pnpm/@tanstack+preact-store@0.13.2\_preact@10.29.8/node\_modules/@tanstack/preact-store/dist/useStore.d.ts:12 Deprecated alias for [useSelector](../functions/useSelector.md). diff --git a/docs/framework/react/guides/arrays.md b/docs/framework/react/guides/arrays.md deleted file mode 100644 index 90a5e49f45..0000000000 --- a/docs/framework/react/guides/arrays.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -id: arrays -title: Arrays ---- - -TanStack Form supports arrays as values in a form, including sub-object values inside of an array. - -## Basic Usage - -To use an array, you can use `field.state.value` on an array value: - -```jsx -function App() { - const form = useForm({ - defaultValues: { - people: [], - }, - }) - - return ( - - {(field) => ( -
    - {field.state.value.map((_, i) => { - // ... - })} -
    - )} -
    - ) -} -``` - -This will generate the mapped JSX every time you run `pushValue` on `field`: - -```jsx - -``` - -Finally, you can use a subfield like so: - -```jsx - - {(subField) => ( - subField.handleChange(e.target.value)} - /> - )} - -``` - -## Full Example - -```jsx -function App() { - const form = useForm({ - defaultValues: { - people: [], - }, - onSubmit({ value }) { - alert(JSON.stringify(value)) - }, - }) - - return ( -
    - { - e.preventDefault() - e.stopPropagation() - form.handleSubmit() - }} - > - - {(field) => { - return ( -
    - {field.state.value.map((_, i) => { - return ( - - {(subField) => { - return ( -
    - -
    - ) - }} -
    - ) - })} - -
    - ) - }} -
    - [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( - - )} - /> - -
    - ) -} -``` diff --git a/docs/framework/react/guides/async-initial-values.md b/docs/framework/react/guides/async-initial-values.md index a8c647431b..631e2a3b8b 100644 --- a/docs/framework/react/guides/async-initial-values.md +++ b/docs/framework/react/guides/async-initial-values.md @@ -3,49 +3,116 @@ id: async-initial-values title: Async Initial Values --- -Let's say that you want to fetch some data from an API and use it as the initial value of a form. +Forms often edit data loaded from an API. A server-state library such as +TanStack Query should own fetching, caching, loading, and retries; TanStack Form +should own the editable copy. -While this problem sounds simple on the surface, there are hidden complexities you might not have thought of thus far. +There are two supported ways to provide async initial values: wait to create the +form until the data is ready, or create it immediately with complete fallback +values. Choose the approach that best matches the loading experience your UI +needs. -For example, you might want to show a loading spinner while the data is being fetched, or you might want to handle errors gracefully. -Likewise, you could also find yourself looking for a way to cache the data so that you don't have to fetch it every time the form is rendered. +## Wait for data before creating the editor -While we could implement many of these features from scratch, it would end up looking a lot like another project we maintain: [TanStack Query](https://tanstack.com/query). - -As such, this guide shows you how you can mix-n-match TanStack Form with TanStack Query to achieve the desired behavior. - -## Basic Usage +Render a loading or error state first, then mount a component whose +`defaultValues` are complete. ```tsx -import { useForm } from '@tanstack/react-form' import { useQuery } from '@tanstack/react-query' +import { useForm } from '@tanstack/react-form' -export default function App() { - const {data, isLoading} = useQuery({ - queryKey: ['data'], - queryFn: async () => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return {firstName: 'FirstName', lastName: "LastName"} - } +type User = { + firstName: string + lastName: string +} + +export function UserPage({ userId }: { userId: string }) { + const userQuery = useQuery({ + queryKey: ['user', userId], + queryFn: () => fetch(`/api/users/${userId}`).then((res) => res.json()), }) + if (userQuery.isPending) return

    Loading…

    + if (userQuery.isError) return

    Could not load the user.

    + + return +} + +function UserEditor({ user }: { user: User }) { const form = useForm({ - defaultValues: { - firstName: data?.firstName ?? '', - lastName: data?.lastName ?? '', + defaultValues: user, + onSubmit: async ({ value }) => { + await fetch('/api/users', { + method: 'PUT', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(value), + }) }, + }) + + return
    {/* fields */}
    +} +``` + +This pattern is useful when no form state is needed during loading. Mounting the +editor only after data exists also makes it explicit when switching records +should create a fresh form. + +## Create the form before data arrives + +You can instead call `useForm` in the same component as `useQuery`. Provide a +static, shape-complete fallback so `defaultValues` are never `undefined`. + +```tsx +const emptyUser: User = { + firstName: '', + lastName: '', +} + +export function UserPage({ userId }: { userId: string }) { + const userQuery = useQuery({ + queryKey: ['user', userId], + queryFn: () => fetch(`/api/users/${userId}`).then((res) => res.json()), + }) + + const form = useForm({ + defaultValues: userQuery.data ?? emptyUser, onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) + await fetch('/api/users', { + method: 'PUT', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(value), + }) }, }) - if (isLoading) return

    Loading...

    + if (userQuery.isPending) return

    Loading…

    + if (userQuery.isError) return

    Could not load the user.

    - return ( - // ... - ) + return
    {/* fields */}
    } ``` -This will show a loading spinner until the data is fetched, and then it will render the form with the fetched data as the initial values. +When the query data replaces the fallback, TanStack Form applies the new +`defaultValues` to untouched fields while preserving fields the user has +already touched. In this example, the fields remain unmounted during loading, +so the user cannot edit them before the loaded values arrive. You can also +render the empty form immediately when that better suits the UI. + +This is the approach demonstrated by the repository's +`examples/react/query-integration` example. + +## Background refetches and record changes + +`defaultValues` establish the form's baseline; they are not a fully controlled +`values` prop. In the fallback pattern, later `defaultValues` updates use the +same touched-field-preserving behavior. + +If background refetches arrive while a user is editing, decide at the product +level whether to keep local edits, prompt before replacing them, or call +`form.reset(nextValues)` deliberately. Do not overwrite in-progress input merely +because a query refreshed. + +When switching to a different record, either remount a keyed editor as in the +first pattern or deliberately reset the existing form. Otherwise, touched +values from the previous record can be preserved when the new defaults arrive. diff --git a/docs/framework/react/guides/basic-concepts.md b/docs/framework/react/guides/basic-concepts.md deleted file mode 100644 index a838dfae06..0000000000 --- a/docs/framework/react/guides/basic-concepts.md +++ /dev/null @@ -1,406 +0,0 @@ ---- -id: basic-concepts -title: Basic Concepts and Terminology ---- - -This page introduces the basic concepts and terminology used in the `@tanstack/react-form` library. Familiarizing yourself with these concepts will help you better understand and work with the library. - -## Form Options - -You can customize your form by creating configuration options with the `formOptions` function. These options can be shared between multiple forms. - -Example: - -```tsx -interface User { - firstName: string - lastName: string - hobbies: Array -} -const defaultUser: User = { firstName: '', lastName: '', hobbies: [] } - -const formOpts = formOptions({ - defaultValues: defaultUser, -}) -``` - -## Form Instance - -A Form instance is an object that represents an individual form and provides methods and properties for working with the form. You create a Form instance using the `useForm` hook provided by the form options. The hook accepts an object with an `onSubmit` function, which is called when the form is submitted. - -```tsx -const form = useForm({ - ...formOpts, - onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) - }, -}) -``` - -You may also create a Form instance without using `formOptions` by using the standalone `useForm` API: - -```tsx -interface User { - firstName: string - lastName: string - hobbies: Array -} -const defaultUser: User = { firstName: '', lastName: '', hobbies: [] } - -const form = useForm({ - defaultValues: defaultUser, - onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) - }, -}) -``` - -## Field - -A Field represents a single form input element, such as a text input or a checkbox. Fields are created using the `form.Field` component provided by the Form instance. The component accepts a `name` prop, which should match a key in the form's default values. It also accepts a `children` prop, which is a render prop function that takes a `field` object as its argument. - -Example: - -```tsx - ( - <> - field.handleChange(e.target.value)} - /> - - - )} -/> -``` - -If you run into issues handling `children` as props, make sure to check your linting rules. - -Example (ESLint): - -```json - "rules": { - "react/no-children-prop": [ - true, - { - "allowFunctions": true - } - ], - } -``` - -## Field State - -Each field has its own state, which includes its current value, validation status, error messages, and other metadata. You can access a field's state using the `field.state` property. - -Example: - -```ts -const { - value, - meta: { errors, isValidating }, -} = field.state -``` - -There are four states in the metadata that can be useful for seeing how the user interacts with a field: - -- **isTouched**: is `true` once the user changes or blurs the field -- **isDirty**: is `true` once the field's value is changed, even if it's reverted to the default. Opposite of `isPristine` -- **isPristine**: is `true` until the user changes the field's value. Opposite of `isDirty` -- **isBlurred**: is `true` once the field loses focus (is blurred) -- **isDefaultValue**: is `true` when the field's current value is the default value - -```ts -const { isTouched, isDirty, isPristine, isBlurred } = field.state.meta -``` - -![Field states](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states.png) - -## Understanding 'isDirty' in Different Libraries - -Non-Persistent `dirty` state - -- **Libraries**: React Hook Form (RHF), Formik, Final Form. -- **Behavior**: A field is 'dirty' if its value differs from the default. Reverting to the default value makes it 'clean' again. - -Persistent `dirty` state - -- **Libraries**: Angular Form, Vue FormKit. -- **Behavior**: A field remains 'dirty' once changed, even if reverted to the default value. - -We have chosen the persistent 'dirty' state model. However, we have introduced the `isDefaultValue` flag to also support a non-persistent 'dirty' state. - -```ts -const { isDefaultValue, isTouched } = field.state.meta - -// The following line will re-create the non-persistent `dirty` functionality. -const nonPersistentIsDirty = !isDefaultValue -``` - -![Field states extended](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states-extended.png) - -## Field API - -The Field API is an object passed to the render prop function when creating a field. It provides methods for working with the field's state. - -Example: - -```tsx - field.handleChange(e.target.value)} -/> -``` - -## Validation - -`@tanstack/react-form` provides both synchronous and asynchronous validation out of the box. Validation functions can be passed to the `form.Field` component using the `validators` prop. - -Example: - -```tsx - - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined, - onChangeAsync: async ({ value }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value.includes('error') && 'No "error" allowed in first name' - }, - }} - children={(field) => ( - <> - field.handleChange(e.target.value)} - /> - - - )} -/> -``` - -## Validation with Standard Schema Libraries - -In addition to hand-rolled validation options, we also support the [Standard Schema](https://github.com/standard-schema/standard-schema) specification. - -You can define a schema using any of the libraries implementing the specification and pass it to a form or field validator. - -Supported libraries include: - -- [Zod](https://zod.dev/) (v3.24.0 or higher) -- [Valibot](https://valibot.dev/) (v1.0.0 or higher) -- [ArkType](https://arktype.io/) (v2.1.20 or higher) -- [Yup](https://github.com/jquense/yup) (v1.7.0 or higher) - -```tsx -import { z } from 'zod' - -const userSchema = z.object({ - age: z.number().gte(13, 'You must be 13 to make an account'), -}) - -function App() { - const form = useForm({ - defaultValues: { - age: 0, - }, - validators: { - onChange: userSchema, - }, - }) - return ( -
    - { - return <>{/* ... */} - }} - /> -
    - ) -} -``` - -## Reactivity - -`@tanstack/react-form` offers various ways to subscribe to form and field state changes, most notably the `useSelector(form.store, …)` hook and the `form.Subscribe` component. These methods allow you to optimize your form's rendering performance by only updating components when necessary. - -Example: - -```tsx -import { useSelector } from '@tanstack/react-form' - -const firstName = useSelector(form.store, (state) => state.values.firstName) -//... - [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( - - )} -/> -``` - -It is important to remember that while the `useSelector` hook's selector argument is optional, it is strongly recommended to provide one, as omitting it will result in unnecessary re-renders. - -```tsx -import { useSelector } from '@tanstack/react-form' - -// Correct use -const firstName = useSelector(form.store, (state) => state.values.firstName) -const errors = useSelector(form.store, (state) => state.errorMap) -// Incorrect use -const store = useSelector(form.store) -``` - -Note: The usage of the `useField` hook to achieve reactivity is discouraged since it is designed to be used thoughtfully within the `form.Field` component. You might want to use `useSelector(form.store, …)` instead. - -## Listeners - -`@tanstack/react-form` allows you to react to specific triggers and "listen" to them to dispatch side effects. - -Example: - -```tsx - { - console.log(`Country changed to: ${value}, resetting province`) - form.setFieldValue('province', '') - }, - }} -/> -``` - -More information can be found at [Listeners](./listeners.md) - -## Array Fields - -Array fields allow you to manage a list of values within a form, such as a list of hobbies. You can create an array field using the `form.Field` component with the `mode="array"` prop. - -When working with array fields, you can use the `pushValue`, `removeValue`, `swapValues`, and `moveValue` methods to add, remove, swap, and move a value from one index to another within the array, respectively. Additional helper methods such as `insertValue`, `replaceValue`, and `clearValues` are also available for inserting, replacing, and clearing array values. - -Example: - -```tsx - ( -
    - Hobbies -
    - {!hobbiesField.state.value.length - ? 'No hobbies found.' - : hobbiesField.state.value.map((_, i) => ( -
    - { - return ( -
    - - field.handleChange(e.target.value)} - /> - - -
    - ) - }} - /> - { - return ( -
    - - field.handleChange(e.target.value)} - /> - -
    - ) - }} - /> -
    - ))} -
    - -
    - )} -/> -``` - -## Reset Buttons - -When using ` - - ) -} -``` - -### Async Validation - -Async validation can also be used with `onDynamicAsync` just like with other validation logic. You can even debounce the async validation to avoid excessive calls. - -```tsx -const form = useForm({ - defaultValues: { - username: '', - }, - validationLogic: revalidateLogic(), - validators: { - onDynamicAsyncDebounceMs: 500, // Debounce the async validation by 500ms - onDynamicAsync: async ({ value }) => { - if (!value.username) { - return { username: 'Username is required' } - } - // Simulate an async validation - const isValid = await validateUsername(value.username) - return isValid ? undefined : { username: 'Username is already taken' } - }, - }, -}) -``` - -### Standard Schema Validation - -You can also use standard schema validation libraries like Valibot or Zod with `onDynamic` validation. This allows you to define complex validation rules that can change dynamically based on the form state. - -```tsx -import { z } from 'zod' - -const schema = z.object({ - firstName: z.string().min(1, 'A first name is required'), - lastName: z.string().min(1, 'A last name is required'), -}) - -const form = useForm({ - defaultValues: { - firstName: '', - lastName: '', - }, - validationLogic: revalidateLogic(), - validators: { - onDynamic: schema, - }, -}) -``` diff --git a/docs/framework/react/guides/field-groups.md b/docs/framework/react/guides/field-groups.md new file mode 100644 index 0000000000..026e437eb0 --- /dev/null +++ b/docs/framework/react/guides/field-groups.md @@ -0,0 +1,537 @@ +--- +id: field-groups +title: Build Reusable React Form Sections with Field Groups +--- + +Related fields often travel together. A scheduling form might need start and end +times, consistent `HH:mm` formatting, and a rule that prevents the end from +preceding the start. Another form needs the same behavior, but stores those +values at different paths. + +A field group makes that component reusable by defining it around the fields it +needs rather than the shape of a particular parent form. Each form can then bind +its own field paths to the component. + +This guide assumes you are comfortable creating fields with `useForm`. See the +[React Quick Start](../quick-start) for that foundation. If you only need to +move fields from one known form into another file, start with +[Splitting forms](../../../splitting-forms). + +## A section tied to one form + +Suppose an availability editor stores its times at `availability.opensAt` and +`availability.closesAt`. A natural first step is to extract those inputs into a +component that accepts the editor's concrete form type. We can even put the +blur formatter in that component so its caller does not have to repeat it. + + + +```tsx file="AvailabilityTimeRange.tsx" +import type { AvailabilityForm } from './form' +import { TextInput } from './TextInput' +import { formatTime } from './time-utils' + +function AvailabilityTimeRange({ form }: { form: AvailabilityForm }) { + return ( +
    + Availability + fieldApi.handleChange(formatTime), + }, + ]} + > + {(field) => } + + fieldApi.handleChange(formatTime), + }, + ]} + > + {(field) => } + +
    + ) +} +``` + +```ts file="form.ts" +import { formOptions, type ReactFormType } from '@tanstack/react-form' + +export const availabilityFormOptions = formOptions({ + defaultValues: { + availability: { + opensAt: '', + closesAt: '', + }, + }, +}) + +export type AvailabilityForm = ReactFormType +``` + +```tsx file="TextInput.tsx" +import type { FieldWithValue } from '@tanstack/react-form' + +export function TextInput({ + field, + label, +}: { + field: FieldWithValue + label: string +}) { + return ( + + ) +} +``` + +```ts file="time-utils.ts" +export function formatTime(value: string) { + const match = /^(\d{1,2}):(\d{1,2})$/.exec(value.trim()) + if (!match) return value + + const hours = Number(match[1]) + const minutes = Number(match[2]) + if (hours > 23 || minutes > 59) return value + + return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}` +} +``` + + + +This is a useful component for the availability editor. It owns the input +wiring and turns a value such as `9:5` into `09:05` when the field loses focus. +The limitation appears when a booking form stores the same concept at +`schedule.departureTime` and `schedule.arrivalTime`. Both the form type and +the field names tie this component to the availability form. + +We could type `form` as a union of every form that uses the time range, +but that makes the API difficult to use. It also means constantly fixing +its type as more forms need it. The time range does not care which form owns the +values, it only needs certain fields with the declared value types. + +## Define virtual fields + +Let's turn that dependency around. We have fields that need a certain type and depend on each other. +`defineFieldGroup` lets us define the contract that we expect any given form to complete. Since the fields can come from +anywhere, the field group can give them virtual names. This time range will call them `start` and `end`. + +The returned definition connects that contract to a React component in two +steps. Its `fields` value types the field group API that can be used within the component, while `bindComponent` +creates a callable wrapper that a form can render. + + + +```tsx file="TimeRangeSection.tsx" +import { defineFieldGroup } from '@tanstack/react-form' + +const timeRangeGroup = defineFieldGroup((helper) => ({ + // Both virtual fields must bind to concrete fields typed exactly as string. + // To only allow the exact type, use `strict`. + start: helper.strict(), + end: helper.strict(), +})) + +function TimeRangeFields(_props: { + fields: typeof timeRangeGroup.fields + label: string +}) { + // ... + return null +} + +export const TimeRangeSection = timeRangeGroup.bindComponent( + TimeRangeFields, + // The prop that receives the field-group API. + 'fields', +) +``` + + + +The parent form still owns the field values and their default state. + +We will fill in the component body in the next section. For now, its `fields` +prop is limited to the declared `start` and `end` paths, including their field +components, methods, and values. + +> [!TIP] Why `bindComponent`? +> The selected prop keeps its name, but its role changes. Inside the component, +> it contains the field-group API. At the call site, it contains the +> virtual-to-concrete field map. +> `bindComponent` covers both the runtime as well as the types for you. + +## Add field behavior + +Now we can implement formatting and validation against `start` and `end`. The +blur listeners normalize both values, while the `end` validator watches `start` +and reports an error when the end precedes it. + +Run the example, enter `9:5` in either field, then move focus away. The value +becomes `09:05`. + +```tsx group=time-range-field-group env=react file=/App.tsx entry +import { defineFieldGroup, useForm } from '@tanstack/react-form' +import { TextInput } from './TextInput' +import { formatTime, toMinutes } from './time-utils' + +const timeRangeGroup = defineFieldGroup(({ strict }) => ({ + start: strict(), + end: strict(), +})) + +interface TimeRangeFieldsProps { + fields: typeof timeRangeGroup.fields + label: string +} + +function TimeRangeFields({ fields, label }: TimeRangeFieldsProps) { + return ( +
    + {label} + fields.setFieldValue('start', formatTime), + }, + ]} + > + {(field) => } + + { + const start = toMinutes(fields.getFieldValue('start')) + const end = toMinutes(value) + + if (start !== undefined && end !== undefined && end < start) { + return 'End time must not be before the start time' + } + }, + }, + ]} + listeners={[ + { + triggers: ['blur'], + run: () => fields.setFieldValue('end', formatTime), + }, + ]} + > + {(field) => } + +
    + ) +} + +const TimeRangeSection = timeRangeGroup.bindComponent(TimeRangeFields, 'fields') + +export default function App() { + const form = useForm({ + defaultValues: { + availability: { + opensAt: '', + closesAt: '', + }, + schedule: { + departureTime: '08:30', + arrivalTime: '10:00', + }, + }, + }) + + return ( +
    + + + state.values}> + {(values) => ( +
    {JSON.stringify(values, null, 2)}
    + )} +
    +
    + ) +} +``` + +```tsx group=time-range-field-group file=/TextInput.tsx collapsed +import type { FieldWithValue } from '@tanstack/react-form' + +export function TextInput({ + field, + label, +}: { + field: FieldWithValue + label: string +}) { + return ( + + ) +} +``` + +```ts group=time-range-field-group file=/time-utils.ts collapsed +export function formatTime(value: string) { + const match = /^(\d{1,2}):(\d{1,2})$/.exec(value.trim()) + if (!match) return value + + const hours = Number(match[1]) + const minutes = Number(match[2]) + if (hours > 23 || minutes > 59) return value + + return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}` +} + +export function toMinutes(value: string) { + const match = /^([01]\d|2[0-3]):([0-5]\d)$/.exec(value) + if (!match) return undefined + return Number(match[1]) * 60 + Number(match[2]) +} +``` + +```json group=time-range-field-group file=/package.json collapsed +{ + "dependencies": { + "@tanstack/react-form": "2.0.0-alpha.2", + "react": "19.2.3", + "react-dom": "19.2.3" + } +} +``` + +Both time ranges apply the same formatting and validation even though their +values use different paths in the parent form. + +## Bind the group to a form + +The `fields` prop maps each virtual field to a concrete path. TypeScript checks +that every mapping exists and that each destination satisfies its field slot. + +TanStack Form applies the current map to field rendering, field methods, +validators, listeners, and their `watchFields`. When the end validator watches +`start`, it therefore resolves the start path for the same time-range instance. + +> [!NOTE] Dynamic paths are allowed +> Bindings may include array indices and other runtime paths, such as +> `ranges[${index}].start`. + +The field group remains part of the parent form. It uses the parent's state, +validation lifecycle, and submission. It does not create a nested form or a +separate submit boundary. + +### Read field-group values + +The range validator reads the current start time with +`fields.getFieldValue('start')`. That is a good fit for a value needed only +while an event is running. + +When rendered output should react to several group values, pass `fields.atom` +to `useSelector`. The selector stays typed to the virtual fields and does not +subscribe the component to unrelated form values. + + + +```tsx file="TimeRangeSection.tsx" +import { useSelector } from '@tanstack/react-form' + +interface TimeRangeSummaryProps { + fields: typeof timeRangeGroup.fields +} + +function TimeRangeSummary({ fields }: TimeRangeSummaryProps) { + const start = useSelector(fields.atom, (state) => state.start) + const end = useSelector(fields.atom, (state) => state.end) + + return ( + + {start} to {end} + + ) +} +``` + + + +`fields.Subscribe` remains useful for parent form metadata such as submission +attempts or `isSubmitting`. + +> [!WARNING] Avoid parent form values +> Parent form values can have any shape. Read values through the field-group +> API instead. Form metadata remains safe to access. + +### Omit identity mappings + +This binding map adds no information when the parent form already stores +compatible fields at `start` and `end`. + + + +```tsx file="OfficeHoursForm.tsx" + +``` + + + +In this case, omit the `fields` prop. Supply it only to reroute virtual names, +and include every virtual field when you do. + +### Choose strict or loose bindings + +The time-range group uses `strict()` because its formatter and inputs +expect ordinary strings. Strict slots accept only concrete fields with exactly +the declared value type. This catches a surprising binding before the section +can read or write it. + +Use `loose()` when the concrete field type may be narrower than `T`. + +| Concrete field type | `strict()` | `loose()` | +| ----------------------------- | -------------------------- | ------------------------- | +| `number \| null` | āœ“ | āœ“ | +| `number` | X | āœ“ | +| `null` | X | āœ“ | +| `string \| null` | X | X | +| `number \| null \| undefined` | X | X | + +## Usage in Form Composition + +Since each `createFormHook` can define its own field components, `defineFieldGroup` does not know of them ahead of time. +If you want to use field components in field groups, use `defineAppFieldGroup` instead. The remaining syntax is exactly the same. + + + +```tsx file="AppTimeRangeSection.tsx" +import { createFormHook } from '@tanstack/react-form' +import { TextInput } from './TextInput' + +const { defineAppFieldGroup } = createFormHook({ + fieldComponents: { + TextInput, + }, + formComponents: {}, +}) + +const appTimeRangeGroup = defineAppFieldGroup(({ strict }) => ({ + start: strict(), + end: strict(), +})) + +function AppTimeRangeFields({ + fields, + label, +}: { + fields: typeof appTimeRangeGroup.fields + label: string +}) { + return ( +
    + {label} + + {(field) => } + + + {(field) => } + +
    + ) +} + +export const AppTimeRangeSection = appTimeRangeGroup.bindComponent( + AppTimeRangeFields, + 'fields', +) +``` + +```tsx file="TextInput.tsx" +import type { FieldWithValue } from '@tanstack/react-form' + +export function TextInput({ + field, + label, +}: { + field: FieldWithValue + label: string +}) { + return ( + + ) +} +``` + + diff --git a/docs/framework/react/guides/focus-management.md b/docs/framework/react/guides/focus-management.md deleted file mode 100644 index 0fb19292e0..0000000000 --- a/docs/framework/react/guides/focus-management.md +++ /dev/null @@ -1,142 +0,0 @@ ---- -id: focus-management -title: Focus Management ---- - -In some instances, you may want to focus the first input with an error. - -[Because TanStack Form intentionally does not have insights into your markup](../../../philosophy.md), we cannot add a built-in focus management feature. - -However, you can easily add this feature into your application without this hypothetical built-in feature. - -## React DOM - -```tsx -import { useForm } from '@tanstack/react-form' -import { z } from 'zod' - -export default function App() { - const form = useForm({ - defaultValues: { age: 0 }, - validators: { - onChange: z.object({ - age: z.number().min(12), - }), - }, - onSubmit() { - alert('Submitted!') - }, - onSubmitInvalid() { - const InvalidInput = document.querySelector( - '[aria-invalid="true"]', - ) as HTMLInputElement - - InvalidInput?.focus() - }, - }) - - return ( -
    { - e.preventDefault() - e.stopPropagation() - void form.handleSubmit() - }} - > - ( - - )} - /> -
    - -
    - - ) -} -``` - -## React Native - -Because React Native doesn't have access to the DOM's `querySelectorAll` API, we need to manually manage the element list -of the inputs. This allows us to focus the first input with an error: - -```tsx -import { useRef } from 'react' -import { Text, View, TextInput, Button, Alert } from 'react-native' -import { useForm } from '@tanstack/react-form' -import { z } from 'zod' - -export default function App() { - // This can be extracted to a hook that returns the `fields` ref, a `focusFirstField` function, and a `addField` function - const fields = useRef([] as Array<{ input: TextInput; name: string }>) - - const form = useForm({ - defaultValues: { age: 0 }, - validators: { - onChange: z.object({ - age: z.number().min(12), - }), - }, - onSubmit() { - Alert.alert('Submitted!') - }, - onSubmitInvalid({ formApi }) { - const errorMap = formApi.state.errorMap.onChange - const inputs = fields.current - - let firstInput - for (const input of inputs) { - if (!input || !input.input) continue - if (!!errorMap[input.name]) { - firstInput = input.input - break - } - } - firstInput?.focus() - }, - }) - - return ( - - ( - - Age - { - // fields.current needs to be manually incremented so that we know what fields are rendered or not and in what order - fields.current[0] = { input, name: field.name } - }} - style={{ - borderWidth: 1, - borderColor: '#999999', - borderRadius: 4, - marginTop: 8, - padding: 8, - }} - onChangeText={(val) => field.handleChange(Number(val))} - value={field.state.value} - /> - - )} - /> - - )} -
    - ) -} - -const { useAppForm, withForm } = createFormHook({ - fieldComponents: {}, - formComponents: { - SubscribeButton, - }, - fieldContext, - formContext, -}) - -function App() { - const form = useAppForm({ - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, - }) - - return ( - - // Notice the `AppForm` component wrapper; `AppForm` provides the required - context - - - ) -} -``` - -### Extending custom appForm - -It is quite common for platform teams to ship pre built appForms. It can be exported from a library in a monorepo or as a standalone package on npm. - -```tsx weyland-yutan-corp/forms-context.tsx -export const { fieldContext, formContext, useFieldContext, useFormContext } = - createFormHookContexts() -``` - -```tsx weyland-yutan-corp/forms.tsx -import { createFormHook } from '@tanstack/react-form' -import { fieldContext, formContext } from 'weyland-yutan-corp/forms-context' - -// fields -import { UserIdField } from './FieldComponents/UserIdField' - -// components -import { SubmitButton } from './FormComponents/SubmitButton' - -const ProfileForm = createFormHook({ - fieldContext, - formContext, - fieldComponents: { UserIdField }, - formComponents: { SubmitButton }, -}) - -export default ProfileForm -``` - -There is a situation that you might have a field exclusive to a downstream dev team, in such a case you can extend the AppForm like so. - -1 - Create new AppForm fields - -```tsx AppForm.tsx -// imported from the same AppForm you want to extend -import { useFieldContext } from 'weyland-yutan-corp/forms-context' - -export function CustomTextField({ label }: { label: string }) { - const field = useFieldContext() - return ( -
    - -
    - ) -} -``` - -2 - Extend the AppForm - -```tsx AppForm.tsx -// notice the same import as above -import ProfileForm from 'weyland-yutan-corp/forms' - -import { CustomTextField } from './FieldComponents/CustomTextField' -import { SubmitButton } from './FormComponents/SubmitButton' - -export const { useAppForm } = ProfileForm.extendForm({ - fieldComponents: { CustomTextField }, - // Ts will error since the parent appForm already has a component called SubmitButton - formComponents: { SubmitButton }, -}) -``` - -This way you can add extra fields that are unique to your team without bloating the upstream AppForm. - -## Breaking big forms into smaller pieces - -Sometimes forms get very large; it's just how it goes sometimes. While TanStack Form supports large forms well, it's never fun to work with hundreds or thousands of lines of code in single files. - -To solve this, we support breaking forms into smaller pieces using the `withForm` higher-order component. - -```tsx -const { useAppForm, withForm } = createFormHook({ - fieldComponents: { - TextField, - }, - formComponents: { - SubscribeButton, - }, - fieldContext, - formContext, -}) - -const ChildForm = withForm({ - // These values are only used for type-checking, and are not used at runtime - // This allows you to `...formOpts` from `formOptions` without needing to redeclare the options - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, - // Optional, but adds props to the `render` function in addition to `form` - props: { - // These props are also set as default values for the `render` function - title: 'Child Form', - }, - render: function Render({ form, title }) { - return ( -
    -

    {title}

    - } - /> - - - -
    - ) - }, -}) - -function App() { - const form = useAppForm({ - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, - }) - - return -} -``` - -> Something worth mentioning, is that while multiple chaining of `AppForm` extensions is possible it is can lead to decreases in TypeScript performance. -> For most users that may only extend an appForm once this isn't a problem, however we recommend limiting it to 3-5 extensions. - -### `withForm` FAQ - -> Why a higher-order component instead of a hook? - -While hooks are the future of React, higher-order components are still a powerful tool for composition. In particular, the API of `withForm` enables us to have strong type-safety without requiring users to pass generics. - -> Why am I getting ESLint errors about hooks in `render`? - -ESLint looks for hooks in the top-level of a function, and `render` may not be recogized as a top-level component, depending on how you defined it. - -```tsx -// This will cause ESLint errors with hooks usage -const ChildForm = withForm({ - // ... - render: ({ form, title }) => { - // ... - }, -}) -``` - -```tsx -// This works fine -const ChildForm = withForm({ - // ... - render: function Render({ form, title }) { - // ... - }, -}) -``` - -### Context as a last resort - -There are cases where passing `form` with `withForm` is not feasible. You may encounter it with components that don't -allow you to change their props. - -For example, consider the following TanStack Router usage: - -```ts -function RouteComponent() { - const form = useAppForm({...formOptions, /* ... */ }) - // cannot be customized or receive additional props - return -} -``` - -In edge cases like this, a context-based fallback is available to access the form instance. - -```ts -const { useAppForm, useTypedAppFormContext } = createFormHook({ - fieldContext, - formContext, - fieldComponents: {}, - formComponents: {}, -}) -``` - -> [!IMPORTANT] Type safety -> This mechanism exists solely to bridge integration constraints and should be avoided whenever `withForm` is possible. -> Context will not warn you when the types do not align. You risk runtime errors with this implementation. - -Usage: - -```tsx -// sharedOpts.ts -const formOpts = formOptions({ - /* ... */ -}) - -function ParentComponent() { - const form = useAppForm({ ...formOptions /* ... */ }) - - return ( - - - - ) -} - -function ChildComponent() { - const form = useTypedAppFormContext({ ...formOptions }) - - // You now have access to form components, field components and fields -} -``` - -## Reusing groups of fields in multiple forms - -Sometimes, a pair of fields are so closely related that it makes sense to group and reuse them — like the password example listed in the [linked fields guide](./linked-fields.md). Instead of repeating this logic across multiple forms, you can utilize the `withFieldGroup` higher-order component. - -> Unlike `withForm`, validators cannot be specified and could be any value. -> Ensure that your fields can accept unknown error types. - -Rewriting the passwords example using `withFieldGroup` would look like this: - -```tsx -const { useAppForm, withForm, withFieldGroup } = createFormHook({ - fieldComponents: { - TextField, - ErrorInfo, - }, - formComponents: { - SubscribeButton, - }, - fieldContext, - formContext, -}) - -type PasswordFields = { - password: string - confirm_password: string -} - -// These default values are not used at runtime, but the keys are needed for mapping purposes. -// This allows you to spread `formOptions` without needing to redeclare it. -const defaultValues: PasswordFields = { - password: '', - confirm_password: '', -} - -const FieldGroupPasswordFields = withFieldGroup({ - defaultValues, - // You may also restrict the group to only use forms that implement this submit meta. - // If none is provided, any form with the right defaultValues may use it. - // onSubmitMeta: { action: '' } - - // Optional, but adds props to the `render` function in addition to `form` - props: { - // These props are set as default values for the `render` function - title: 'Password', - }, - // Internally, you will have access to a `group` instead of a `form` - render: function Render({ group, title }) { - // access reactive values using the group store - const password = useSelector(group.store, (state) => state.values.password) - // or the form itself - const isSubmitting = useSelector( - group.form.store, - (state) => state.isSubmitting, - ) - - return ( -
    -

    {title}

    - {/* Groups also have access to Field, Subscribe, Field, AppField and AppForm */} - - {(field) => } - - { - // The form could be any values, so it is typed as 'unknown' - const values: unknown = fieldApi.form.state.values - // use the group methods instead - if (value !== group.getFieldValue('password')) { - return 'Passwords do not match' - } - return undefined - }, - }} - > - {(field) => ( -
    - - -
    - )} -
    -
    - ) - }, -}) -``` - -We can now use these grouped fields in any form that implements the default values: - -```tsx -// You are allowed to extend the group fields as long as the -// existing properties remain unchanged -type Account = PasswordFields & { - provider: string - username: string -} - -// You may nest the group fields wherever you want -type FormValues = { - name: string - age: number - account_data: PasswordFields - linked_accounts: Account[] -} - -const defaultValues: FormValues = { - name: '', - age: 0, - account_data: { - password: '', - confirm_password: '', - }, - linked_accounts: [ - { - provider: 'TanStack', - username: '', - password: '', - confirm_password: '', - }, - ], -} - -function App() { - const form = useAppForm({ - defaultValues, - // If the group didn't specify an `onSubmitMeta` property, - // the form may implement any meta it wants. - // Otherwise, the meta must be defined and match. - onSubmitMeta: { action: '' }, - }) - - return ( - - - - {(field) => - field.state.value.map((account, i) => ( - - )) - } - - - ) -} -``` - -### Mapping field group values to a different field - -You may want to keep the password fields on the top level of your form, or rename the properties for clarity. You can map field group values -to their true location by changing the `field` property: - -> [!IMPORTANT] -> Due to TypeScript limitations, field mapping is only allowed for objects. You can use records or arrays at the top level of a field group, but you will not be able to map the fields. - -```tsx -// To have an easier form, you can keep the fields on the top level -type FormValues = { - name: string - age: number - password: string - confirm_password: string -} - -const defaultValues: FormValues = { - name: '', - age: 0, - password: '', - confirm_password: '', -} - -function App() { - const form = useAppForm({ - defaultValues, - }) - - return ( - - - - ) -} -``` - -If you expect your fields to always be at the top level of your form, you can create a quick map -of your field groups using a helper function: - -```tsx -const defaultValues: PasswordFields = { - password: '', - confirm_password: '', -} - -const passwordFields = createFieldMap(defaultValues) -/* This generates the following map: - { - 'password': 'password', - 'confirm_password': 'confirm_password' - } -*/ - -// Usage: - -``` - -## Tree-shaking form and field components - -While the above examples are great for getting started, they're not ideal for certain use-cases where you might have hundreds of form and field components. -In particular, you may not want to include all of your form and field components in the bundle of every file that uses your form hook. - -To solve this, you can mix the `createFormHook` TanStack API with the React `lazy` and `Suspense` components: - -```typescript -// src/hooks/form-context.ts -import { createFormHookContexts } from '@tanstack/react-form' - -export const { fieldContext, useFieldContext, formContext, useFormContext } = - createFormHookContexts() -``` - -```tsx -// src/components/text-field.tsx -import { useFieldContext } from '../hooks/form-context.tsx' - -export default function TextField({ label }: { label: string }) { - const field = useFieldContext() - - return ( - - ) -} -``` - -```tsx -// src/hooks/form.ts -import { lazy } from 'react' -import { createFormHook } from '@tanstack/react-form' - -const TextField = lazy(() => import('../components/text-fields.tsx')) - -const { useAppForm, withForm } = createFormHook({ - fieldContext, - formContext, - fieldComponents: { - TextField, - }, - formComponents: {}, -}) -``` - -```tsx -// src/App.tsx -import { Suspense } from 'react' -import { PeoplePage } from './features/people/form.tsx' - -export default function App() { - return ( - Loading...

    }> - -
    - ) -} -``` - -This will show the Suspense fallback while the `TextField` component is being loaded, and then render the form once it's loaded. - -## Putting it all together - -Now that we've covered the basics of creating custom form hooks, let's put it all together in a single example. - -```tsx -// /src/hooks/form.ts, to be used across the entire app -const { fieldContext, useFieldContext, formContext, useFormContext } = - createFormHookContexts() - -function TextField({ label }: { label: string }) { - const field = useFieldContext() - return ( - - ) -} - -function SubscribeButton({ label }: { label: string }) { - const form = useFormContext() - return ( - state.isSubmitting}> - {(isSubmitting) => } - - ) -} - -const { useAppForm, withForm } = createFormHook({ - fieldComponents: { - TextField, - }, - formComponents: { - SubscribeButton, - }, - fieldContext, - formContext, -}) - -// /src/features/people/shared-form.ts, to be used across `people` features -const formOpts = formOptions({ - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, -}) - -// /src/features/people/nested-form.ts, to be used in the `people` page -const ChildForm = withForm({ - ...formOpts, - // Optional, but adds props to the `render` function outside of `form` - props: { - title: 'Child Form', - }, - render: ({ form, title }) => { - return ( -
    -

    {title}

    - } - /> - - - -
    - ) - }, -}) - -// /src/features/people/page.ts -const Parent = () => { - const form = useAppForm({ - ...formOpts, - }) - - return -} -``` - -## API Usage Guidance - -Here's a chart to help you decide what APIs you should be using: - -![](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/react_form_composability.svg) diff --git a/docs/framework/react/guides/form-groups.md b/docs/framework/react/guides/form-groups.md deleted file mode 100644 index f3d908d31b..0000000000 --- a/docs/framework/react/guides/form-groups.md +++ /dev/null @@ -1,177 +0,0 @@ ---- -id: form-groups -title: Form Groups ---- - -When building a multi-stage form that has many stages, like so: - -![Form stepper](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/stepper.png) - -It's common for each step to have its own form. However, this complicates the form submission and validation process by requiring you to add complex logic. - -Luckily, TanStack Form provides a way to build out sub-forms that make this kind of development trivial to implement: ``. - -## Usage - -To use a form group in TanStack Form, you'll use `useForm` or [`useAppForm`](./form-composition.md) to create a `form` variable, then reference its `FormGroup` component like you would a `Field`: - -```tsx -const form = useForm({ - defaultValues: { - step1: { - name: "" - }, - step2: { - age: 0 - } - } -}) - -return ( - ( - // `group` here has all of the form-like methods you'd expect like `deleteField` or `insertFieldValue` - // ... - )} - /> -) -``` - -This becomes much more useful when paired with external state to conditionally render a `FormGroup`: - -```tsx -const [step, setStep] = useState(0) -const form = useForm({ - defaultValues: { - step1: { - name: "" - }, - step2: { - age: 0 - } - } -}) - -return ( - <> - {step === 0 ? { - // We can move the step forward when validation passes - setStep(step + 1) - }} - onGroupSubmitInvalid={() => { - // Or handle invalid submissions, just like a top-level form - }} - onSubmitMeta={{} as SomeType} - children={group => ( - // Use `group.handleSubmit()` to submit the sub-form, but not the parent form - // ... - )} - /> : null } - {step === 1 ? ( - // Then, use `form.handleSubmit()` to submit the entire form - // ... - )} - /> : null } - -) -``` - -## Form Group Validation - -Form groups have a distinct validation proceedure that we think makes sense for sub-forms: - -- Form groups can have their own validation: - -```tsx - 'Error' }} - children={(group) => { - group.state.meta.errorMap // {onChange: "Error" | undefined} - group.state.meta.errors // ("Error")[] - }} -/> -``` - -- Can set errors on sub-fields: - -```tsx - ({ - group: value.name === 'error' ? 'Group error' : undefined, - fields: { - // Must use the name of the field relative to the FormGroup as the error key, - // to stay consistent with how standard schema works with form groups - name: value.name === 'error' ? 'Field error' : undefined, - }, - }), - }} -/> -``` - -- And can even accept standard schemas: - -```tsx - -``` - -> The reason we don't use the full path names for fields is so that you can compose your schemas like so: -> -> ``` -> const step1Schema = z.object({ -> name: z.string().min(2) -> }) -> -> const schema = z.object({ -> step1: step1Schema, -> step2: step2Schema -> }) -> ``` -> -> And pass the `step1Schema` to a form group and `schema` to the parent form. That way, partially validated data will still flag errors if the group is bypassed. - -### Dynamic Group Validation - -If you want to use [dynamic validation (`onDynamic`)](./dynamic-validation.md) with a form group, do not rely on the `onDynamic` validator passed to `useForm`: - -```tsx -useForm({ - validationLogic: revalidateLogic(), - validators: { - // This validator will not run `onChange` when a sub-form is submitted; - // it will only run `onChange` when the form itself is submitted. - onDynamic: schema, - }, -}) -``` - -Instead, pass your sub-schema for the group to the `onDynamic` validation of the `FormGroup` itself: - -```tsx - -``` - -It will treat `group.submissionAttempts` as the way to change what validator is ran before/after submit. - -## Form Group State - -Just like you're able to access `group.state.meta.errors`, you're also able to access the group's value using `group.state.value`. Likewise, here are some valuable properties you can access in the `group.state.meta`: - -- `group.state.meta.isFieldsValid`: `true` when the field-level validators have no errors -- `group.state.meta.isGroupValid`: `true` when the group-level validators have no errors -- `group.state.meta.isValid`: `true` when both the field-level and group-level validators have no errors -- `group.state.meta.isSubmitting`: `true` when the group is in the process of being submitted diff --git a/docs/framework/react/guides/linked-fields.md b/docs/framework/react/guides/linked-fields.md deleted file mode 100644 index 75c7f98f23..0000000000 --- a/docs/framework/react/guides/linked-fields.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -id: linked-fields -title: Link Two Form Fields Together ---- - -You may find yourself needing to link two fields together, such that one is validated when another's value has changed. -One such use case is when you have both a `password` and a `confirm_password` field. -Here, you want the `confirm_password` field to error out if its value doesn't match that of the `password` field, regardless of which field triggered the value change. - -Imagine the following user flow: - -- User updates the `confirm_password` field. -- User updates the `password` field. - -In this example, the form will still have errors present because the `confirm_password` field's validation has not been re-run to mark the field as valid. - -To solve this, you need to make sure that the `confirm_password` field's validation is re-run when the `password` field is updated. -To do this, you can add an `onChangeListenTo` prop to the `confirm_password` field. - -```tsx -function App() { - const form = useForm({ - defaultValues: { - password: '', - confirm_password: '', - }, - // ... - }) - - return ( -
    - - {(field) => ( - - )} - - { - if (value !== fieldApi.form.getFieldValue('password')) { - return 'Passwords do not match' - } - return undefined - }, - }} - > - {(field) => ( -
    - - {field.state.meta.errors.map((err) => ( -
    {err}
    - ))} -
    - )} -
    -
    - ) -} -``` - -This is similar to the `onBlurListenTo` prop, which re-runs the validation when the linked field is blurred. diff --git a/docs/framework/react/guides/listeners.md b/docs/framework/react/guides/listeners.md deleted file mode 100644 index f42cb6dcda..0000000000 --- a/docs/framework/react/guides/listeners.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -id: listeners -title: Side effects for event triggers ---- - -For situations where you want to "affect" or "react" to triggers, there's the listener API. For example, if you, as the developer, want to reset a form field as a result of another field changing, you would use the listener API. - -Imagine the following user flow: - -- User selects a country from a drop-down. -- User then selects a province from another drop-down. -- User changes the selected country to a different one. - -In this example, when the user changes the country, the selected province needs to be reset as it's no longer valid. With the listener API, we can subscribe to the `onChange` event and dispatch a reset to the "province" field when the listener is fired. - -Events that can be "listened" to are: - -- `onChange` -- `onBlur` -- `onMount` -- `onSubmit` -- `onUnmount` - -```tsx -function App() { - const form = useForm({ - defaultValues: { - country: '', - province: '', - }, - // ... - }) - - return ( -
    - { - console.log(`Country changed to: ${value}, resetting province`) - form.setFieldValue('province', '') - }, - }} - > - {(field) => ( - - )} - - - - {(field) => ( - - )} - -
    - ) -} -``` - -### Built-in Debouncing - -If you are making an API request inside a listener, you may want to debounce the calls as it can lead to performance issues. -We enable an easy method for debouncing your listeners by adding a `onChangeDebounceMs` or `onBlurDebounceMs`. - -```tsx - { - console.log(`Country changed to: ${value} without a change within 500ms, resetting province`) - form.setFieldValue('province', '') - }, - }} -> - {(field) => ( - /* ... */ - )} - -``` - -### Form listeners - -At a higher level, listeners are also available at the form level, allowing you access to the `onMount` and `onSubmit` events, and having `onChange` and `onBlur` propagated to all the form's children. Form-level listeners can also be debounced in the same way as previously discussed. - -`onMount` and `onSubmit` listeners have the following parameters: - -- `formApi` - -`onChange` and `onBlur` listeners have access to: - -- `fieldApi` -- `formApi` - -```tsx -const form = useForm({ - listeners: { - onMount: ({ formApi }) => { - // custom logging service - loggingService('mount', formApi.state.values) - }, - - onChange: ({ formApi, fieldApi }) => { - // autosave logic - if (formApi.state.isValid) { - formApi.handleSubmit() - } - - // fieldApi represents the field that triggered the event. - console.log(fieldApi.name, fieldApi.state.value) - }, - onChangeDebounceMs: 500, - }, -}) -``` diff --git a/docs/framework/react/guides/react-native.md b/docs/framework/react/guides/react-native.md index c098a6e82b..ecb6932e62 100644 --- a/docs/framework/react/guides/react-native.md +++ b/docs/framework/react/guides/react-native.md @@ -3,26 +3,55 @@ id: react-native title: Usage with React Native --- -TanStack Form is headless and it should support React Native out-of-the-box without needing any additional configuration. - -Here is an example: +TanStack Form is headless, so React Native uses the same form and validation +APIs. Connect the field handlers to the props exposed by native controls. ```tsx - - val < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {(field) => ( - <> - Age: - - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(', ')} - )} - - )} - +import { Button, Text, TextInput, View } from 'react-native' +import { useForm } from '@tanstack/react-form' + +export function AccountForm() { + const form = useForm({ + defaultValues: { age: '' }, + onSubmit: ({ value }) => console.log(value), + }) + + return ( + + + Number(value) >= 13 ? undefined : 'You must be at least 13', + }, + ]} + > + {(field) => ( + + Age + + {field.errors.map((error) => ( + + {error.message} + + ))} + + )} + + + - )} -
    - - ) -} -``` - -## Using TanStack Form in a Next.js App Router - -> Before reading this section, it's suggested you understand how React Server Components and React Server Actions work. [Check out this blog series for more information](https://playfulprogramming.com/collections/react-beyond-the-render) - -This section focuses on integrating TanStack Form with `Next.js`, particularly using the `App Router` and `Server Actions`. - -### Next.js Prerequisites - -- Start a new `Next.js` project, following the steps in the [Next.js Documentation](https://nextjs.org/docs/getting-started/installation). Ensure you select `yes` for `Would you like to use App Router?` during the setup to access all new features provided by Next.js. -- Install `@tanstack/react-form` -- Install any [form validator](./validation#validation-through-schema-libraries) of your choice. [Optional] - -## App Router integration - -Let's start by creating a `formOption` that we'll use to share the form's shape across the client and server. - -```typescript -// shared-code.ts -// Notice the import path is different from the client -import { formOptions } from '@tanstack/react-form-nextjs' - -// You can pass other form options here -export const formOpts = formOptions({ - defaultValues: { - firstName: '', - age: 0, - }, -}) -``` - -Next, we can create [a React Server Action](https://playfulprogramming.com/posts/what-are-react-server-components) that will handle the form submission on the server. - -```typescript -// action.ts -'use server' - -// Notice the import path is different from the client -import { - ServerValidateError, - createServerValidate, -} from '@tanstack/react-form-nextjs' -import { formOpts } from './shared-code' - -// Create the server action that will infer the types of the form from `formOpts` -const serverValidate = createServerValidate({ - ...formOpts, - onServerValidate: ({ value }) => { - if (value.age < 12) { - return 'Server validation: You must be at least 12 to sign up' - } - }, -}) - -export default async function someAction(prev: unknown, formData: FormData) { - try { - const validatedData = await serverValidate(formData) - console.log('validatedData', validatedData) - // Persist the form data to the database - // await sql` - // INSERT INTO users (name, email, password) - // VALUES (${validatedData.name}, ${validatedData.email}, ${validatedData.password}) - // ` - } catch (e) { - if (e instanceof ServerValidateError) { - return e.formState - } - - // Some other error occurred while validating your form - throw e - } - - // Your form has successfully validated! -} -``` - -Finally, we'll use `someAction` in our client-side form component. - -```tsx -// client-component.tsx -'use client' - -import { useActionState } from 'react' -import { - initialFormState, - mergeForm, - useForm, - useSelector, - useTransform, -} from '@tanstack/react-form-nextjs' -import someAction from './action' -import { formOpts } from './shared-code' - -export const ClientComp = () => { - const [state, action] = useActionState(someAction, initialFormState) - - const form = useForm({ - ...formOpts, - transform: useTransform((baseForm) => mergeForm(baseForm, state!), [state]), - }) - - const formErrors = useSelector(form.store, (formState) => formState.errors) - - return ( -
    form.handleSubmit()}> - {formErrors.map((error) => ( -

    {error}

    - ))} - - - value < 8 ? 'Client validation: You must be at least 8' : undefined, - }} - > - {(field) => { - return ( -
    - field.handleChange(e.target.valueAsNumber)} - /> - {field.state.meta.errors.map((error) => ( -

    {error}

    - ))} -
    - ) - }} -
    - [formState.canSubmit, formState.isSubmitting]} - > - {([canSubmit, isSubmitting]) => ( - - )} - -
    - ) -} -``` - -Here, we're using [React's `useActionState` hook](https://playfulprogramming.com/posts/what-is-use-action-state-and-form-status) and TanStack Form's `useTransform` hook to merge state returned from the server action with the form state. - -> If you get the following error in your Next.js application: -> -> ```typescript -> x You're importing a component that needs `useState`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive. -> ``` -> -> This is because you're not importing server-side code from `@tanstack/react-form-nextjs`. Ensure you're importing the correct module based on the environment. -> -> [This is a limitation of Next.js](https://github.com/phryneas/rehackt). Other meta-frameworks will likely not have this same problem. - -## Using TanStack Form in Remix - -> Before reading this section, it's suggested you understand how Remix actions work. [Check out Remix's docs for more information](https://remix.run/docs/en/main/discussion/data-flow#route-action) - -### Remix Prerequisites - -- Start a new `Remix` project, following the steps in the [Remix Documentation](https://remix.run/docs/en/main/start/quickstart). -- Install `@tanstack/react-form` -- Install any [form validator](./validation#validation-through-schema-libraries) of your choice. [Optional] - -## Remix integration - -Let's start by creating a `formOption` that we'll use to share the form's shape across the client and server. - -```typescript -// routes/_index/route.tsx -import { formOptions } from '@tanstack/react-form-remix' - -// You can pass other form options here -export const formOpts = formOptions({ - defaultValues: { - firstName: '', - age: 0, - }, -}) -``` - -Next, we can create [an action](https://remix.run/docs/en/main/discussion/data-flow#route-action) that will handle the form submission on the server. - -```tsx -// routes/_index/route.tsx - -import { - ServerValidateError, - createServerValidate, - formOptions, -} from '@tanstack/react-form-remix' - -import type { ActionFunctionArgs } from '@remix-run/node' - -// export const formOpts = formOptions({ - -// Create the server action that will infer the types of the form from `formOpts` -const serverValidate = createServerValidate({ - ...formOpts, - onServerValidate: ({ value }) => { - if (value.age < 12) { - return 'Server validation: You must be at least 12 to sign up' - } - }, -}) - -export async function action({ request }: ActionFunctionArgs) { - const formData = await request.formData() - try { - const validatedData = await serverValidate(formData) - console.log('validatedData', validatedData) - // Persist the form data to the database - // await sql` - // INSERT INTO users (name, email, password) - // VALUES (${validatedData.name}, ${validatedData.email}, ${validatedData.password}) - // ` - } catch (e) { - if (e instanceof ServerValidateError) { - return e.formState - } - - // Some other error occurred while validating your form - throw e - } - - // Your form has successfully validated! -} -``` - -Finally, the `action` will be called when the form submits. - -```tsx -// routes/_index/route.tsx -import { - Form, - mergeForm, - useActionData, - useForm, - useSelector, - useTransform, -} from '@tanstack/react-form' -import { - ServerValidateError, - createServerValidate, - formOptions, - initialFormState, -} from '@tanstack/react-form-remix' - -import type { ActionFunctionArgs } from '@remix-run/node' - -// export const formOpts = formOptions({ - -// const serverValidate = createServerValidate({ - -// export async function action({request}: ActionFunctionArgs) { - -export default function Index() { - const actionData = useActionData() - - const form = useForm({ - ...formOpts, - transform: useTransform( - (baseForm) => mergeForm(baseForm, actionData ?? initialFormState), - [actionData], - ), - }) - - const formErrors = useSelector(form.store, (formState) => formState.errors) - - return ( -
    form.handleSubmit()}> - {formErrors.map((error) => ( -

    {error}

    - ))} - - - value < 8 ? 'Client validation: You must be at least 8' : undefined, - }} - > - {(field) => { - return ( -
    - field.handleChange(e.target.valueAsNumber)} - /> - {field.state.meta.errors.map((error) => ( -

    {error}

    - ))} -
    - ) - }} -
    - [formState.canSubmit, formState.isSubmitting]} - > - {([canSubmit, isSubmitting]) => ( - - )} - -
    - ) -} -``` - -Here, we're using [Remix's `useActionData` hook](https://remix.run/docs/en/main/hooks/use-action-data) and TanStack Form's `useTransform` hook to merge state returned from the server action with the form state. diff --git a/docs/framework/react/guides/submission-handling.md b/docs/framework/react/guides/submission-handling.md deleted file mode 100644 index 7198217be0..0000000000 --- a/docs/framework/react/guides/submission-handling.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -id: submission-handling -title: Submission handling ---- - -## Passing additional data to submission handling - -You may have multiple types of submission behaviour, for example, going back to the previous page or staying on the form. -You can accomplish this by specifying the `onSubmitMeta` property. This meta data will be passed to the `onSubmit` function. - -> Note: if `form.handleSubmit()` is called without metadata, it will use the provided default. - -```tsx -import { useForm } from '@tanstack/react-form' - -type FormMeta = { - submitAction: 'continue' | 'backToMenu' | null -} - -// Metadata is not required to call form.handleSubmit(). -// Specify what values to use as default if no meta is passed -const defaultMeta: FormMeta = { - submitAction: null, -} - -function App() { - const form = useForm({ - defaultValues: { - data: '', - }, - // Define what meta values to expect on submission - onSubmitMeta: defaultMeta, - onSubmit: async ({ value, meta }) => { - // Do something with the values passed via handleSubmit - console.log(`Selected action - ${meta.submitAction}`, value) - }, - }) - - return ( -
    { - e.preventDefault() - e.stopPropagation() - }} - > - {/* ... */} - - -
    - ) -} -``` - -## Transforming data with Standard Schemas - -While Tanstack Form provides [Standard Schema support](./validation.md) for validation, it does not preserve the Schema's output data. - -The value passed to the `onSubmit` function will always be the input data. To receive the output data of a Standard Schema, parse it in the `onSubmit` function: - -```tsx -const schema = z.object({ - age: z.string().transform((age) => Number(age)), -}) - -// Tanstack Form uses the input type of Standard Schemas -const defaultValues: z.input = { - age: '13', -} - -const form = useForm({ - defaultValues, - validators: { - onChange: schema, - }, - onSubmit: ({ value }) => { - const inputAge: string = value.age - // Pass it through the schema to get the transformed value - const result = schema.parse(value) - const outputAge: number = result.age - }, -}) -``` diff --git a/docs/framework/react/guides/ui-libraries.md b/docs/framework/react/guides/ui-libraries.md index 02207fb84b..934195499e 100644 --- a/docs/framework/react/guides/ui-libraries.md +++ b/docs/framework/react/guides/ui-libraries.md @@ -3,214 +3,86 @@ id: ui-libraries title: UI Libraries --- -## Usage of TanStack Form with UI Libraries +TanStack Form is headless. UI library integration consists of adapting a +field's value, blur callback, change callback, invalid state, and errors to the +component's prop names. -TanStack Form is a headless library, offering you complete flexibility to style it as you see fit. It's compatible with a wide range of UI libraries, including `Chakra UI`, `Tailwind`, `Material UI`, `Mantine`, `shadcn/ui`, or even plain CSS. +## Text inputs -This guide focuses on `Chakra UI`, `Material UI`, `Mantine`, and `shadcn/ui`, but the concepts are applicable to any UI library of your choice. +Most controlled text inputs accept DOM-like props directly: -### Prerequisites - -Before integrating TanStack Form with a UI library, ensure the necessary dependencies are installed in your project: - -- For `Chakra UI`, follow the installation instructions on their [official site](https://chakra-ui.com/docs/get-started/installation) -- For `Material UI`, follow the installation instructions on their [official site](https://mui.com/material-ui/getting-started/). -- For `Mantine`, refer to their [documentation](https://mantine.dev/). -- For `shadcn/ui`, refer to their [official site](https://ui.shadcn.com/). +```tsx + + {(field) => ( + field.handleChange(event.target.value)} + error={field.errors.map((error) => error.message).join(', ')} + /> + )} + +``` -Note: While you can mix and match libraries, it's generally advisable to stick with one to maintain consistency and minimize bloat. +Use `value`, not `defaultValue`, so the UI component remains controlled by form +state. -### Example with Mantine +## Checkboxes and switches -Here's an example demonstrating the integration of TanStack Form with Mantine components: +DOM-style checkbox components expose `event.target.checked`: ```tsx -import { TextInput, Checkbox } from '@mantine/core' -import { useForm } from '@tanstack/react-form' - -export default function App() { - const { Field, handleSubmit, state } = useForm({ - defaultValues: { - name: '', - isChecked: false, - }, - onSubmit: async ({ value }) => { - // Handle form submission - console.log(value) - }, - }) - - return ( - <> -
    { - e.preventDefault() - handleSubmit() - }} - > - ( - handleChange(e.target.value)} - onBlur={handleBlur} - placeholder="Enter your name" - /> - )} - /> - ( - handleChange(e.target.checked)} - onBlur={handleBlur} - checked={state.value} - /> - )} - /> - -
    -
    {JSON.stringify(state.values, null, 2)}
    -
    - - ) -} + + {(field) => ( + field.handleChange(event.target.checked)} + aria-invalid={field.meta.isInvalid} + /> + )} + ``` -- Initially, we utilize the `useForm` hook from TanStack and destructure the necessary properties. This step is optional; alternatively, you could use `const form = useForm()` if preferred. TypeScript's type inference ensures a smooth experience regardless of the approach. -- The `Field` component, derived from `useForm`, accepts several properties, such as `validators`. For this demonstration, we focus on two primary properties: `name` and `children`. - - The `name` property identifies each `Field`, for instance, `name` in our example. - - The `children` property leverages the concept of render props, allowing us to integrate components without unnecessary abstractions. -- TanStack's design relies heavily on render props, providing access to `children` within the `Field` component. This approach is entirely type-safe. When integrating with Mantine components, such as `TextInput`, we selectively destructure properties like `state.value`, `handleChange`, and `handleBlur`. This selective approach is due to the slight differences in types between `TextInput` and the `field` we get in the children. -- By following these steps, you can seamlessly integrate Mantine components with TanStack Form. -- This methodology is equally applicable to other components, such as `Checkbox`, ensuring consistent integration across different UI elements. - -### Usage with MaterialĀ UI - -The process for integrating MaterialĀ UI components is similar. Here's an example using TextField and Checkbox from MaterialĀ UI: +Some libraries call back with a boolean, a details object, or a union such as +`boolean | 'indeterminate'`. Normalize that value at the boundary: ```tsx - { - return ( - handleChange(e.target.value)} - onBlur={handleBlur} - placeholder="Enter your name" - /> - ); - }} + field.handleChange(checked === true)} /> - - { - return ( - handleChange(e.target.checked)} - onBlur={handleBlur} - checked={state.value} - /> - ); - }} -/> - ``` -- The integration approach is the same as with Mantine. -- The primary difference lies in the specific Material UI component properties and styling options. +## Selects, date pickers, and custom controls -### Usage with shadcn/ui - -The process for integrating shadcn/ui components is similar. Here's an example using Input and Checkbox from shadcn/ui: +The integration does not require a native event. Pass the value produced by the +component to `field.handleChange`: ```tsx - ( - handleChange(e.target.value)} - onBlur={handleBlur} - placeholder="Enter your name" - /> - )} -/> - ( - handleChange(checked === true)} - onBlur={handleBlur} - checked={state.value} - /> - )} + field.handleChange(nextDate)} + onBlur={field.handleBlur} /> ``` -- The integration approach is the same as with Mantine, Material UI. -- The primary difference lies in the specific shadcn/ui component properties and styling options. -- Note the onCheckedChange property of Checkbox instead of onChange. +Choose a serializable form value appropriate for your application, then adapt +the UI library's richer object at the component boundary if necessary. -The ShadCN library includes a dedicated guide covering common scenarios for integrating TanStack Form with its components: [https://ui.shadcn.com/docs/forms/tanstack-form](https://ui.shadcn.com/docs/forms/tanstack-form) +## Reuse the adapter -### Usage with Chakra UI +If the same wiring appears throughout the application, extract a component that +accepts `FieldWithValue` or register it with `createFormHook`. -The process for integrating Chakra UI components is similar. Here's an example using Input and Checkbox from Chakra UI: +For the helper types used when passing a form or field to an extracted +component, see [Splitting forms](../../../splitting-forms). -```tsx - ( - handleChange(e.target.value)} - onBlur={handleBlur} - placeholder="Enter your name" - /> - )} -/> - ( - handleChange(!!details.checked)} - onBlur={handleBlur} - > - - - Accept terms - - )} -/> -``` - -- The integration approach is the same as with Mantine, Material UI, and shadcn/ui. -- Chakra UI exposes its Checkbox as a composable component with separate `Checkbox.Root`, `Checkbox.Control`, `Checkbox.Label`, and `Checkbox.HiddenInput` parts that you wire together. -- The double negation `!!` is used on `onCheckedChange` to coerce Chakra's `"indeterminate"` state to a boolean, ensuring it matches the form state. See the [Chakra UI Checkbox documentation](https://chakra-ui.com/docs/components/checkbox#indeterminate) for more details. -- Alternatively, Chakra UI offers a pre-composed Checkbox component that works the same way as their standard examples, without requiring manual composition. You can learn more about this closed component approach in the [Chakra UI Checkbox documentation](https://chakra-ui.com/docs/components/checkbox#closed-component). -- The TanStack Form integration works identically with either approach—simply attach the `checked`, `onCheckedChange`, and `onBlur` handlers to your chosen component. +To reuse several related fields together across different form shapes, see +[Field groups](./field-groups). -Example using the closed Checkbox component: - -```tsx - ( - handleChange(!!details.checked)} - onBlur={handleBlur} - > - Accept terms - - )} -/> -``` +The repository's `examples/react/ui-integration-shadcn` example demonstrates a +larger component system with branded fields, lazy-loaded controls, labels, +descriptions, and accessible error rendering. diff --git a/docs/framework/react/guides/validation.md b/docs/framework/react/guides/validation.md index 158261b3dc..1c472d13bf 100644 --- a/docs/framework/react/guides/validation.md +++ b/docs/framework/react/guides/validation.md @@ -3,579 +3,237 @@ id: form-validation title: Form and Field Validation --- -At the core of TanStack Form's functionality is the concept of validation. TanStack Form makes validation highly customizable: +TanStack Form supports synchronous, asynchronous, field-level, form-level, and +Standard Schema validation. Every validator is an ordered object with a `run` +implementation and explicit `triggers`. -- You can control when to perform the validation (on change, on input, on blur, on submit, etc.) -- Validation rules can be defined at the field-level or at the form-level -- Validation can be synchronous or asynchronous (for example, as a result of an API call) +## Choose when validation runs -## When is validation performed? - -It's up to you! The `` component accepts some callbacks as props such as `onChange` or `onBlur`. Those callbacks are passed the current value of the field, as well as the `fieldApi` object, so that you can perform the validation. If you find a validation error, simply return the error message as a string, and it will be available in `field.state.meta.errors`. - -Here is an example: +Use `change` for immediate feedback and `blur` for feedback after leaving an +input. Submission runs validators by default regardless of their configured +change and blur triggers. ```tsx - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {(field) => ( - <> - - field.handleChange(e.target.valueAsNumber)} - /> - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(', ')} - )} - - )} - -``` - -In the example above, the validation is done at each keystroke (`onChange`). If, instead, we wanted the validation to be done when the field is blurred, we would change the code above like so: - -```tsx - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} + validators={[ + { + triggers: ['change'], + run: ({ value }) => (value >= 13 ? undefined : 'You must be at least 13'), + }, + { + triggers: ['blur'], + run: ({ value }) => (value >= 0 ? undefined : 'Age cannot be negative'), + }, + ]} > {(field) => ( - <> - + )} ``` -So, you can control when the validation is done by implementing the desired callback. You can even perform different pieces of validation at different times: +Additional controls include: -```tsx - - value < 13 ? 'You must be 13 to make an account' : undefined, - onBlur: ({ value }) => (value < 0 ? 'Invalid value' : undefined), - }} -> - {(field) => ( - <> - - field.handleChange(e.target.valueAsNumber)} - /> - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(', ')} - )} - - )} - -``` +- `runOnMount`: run once when the form is constructed or when a field or form + group first mounts. +- `skipOnSubmit`: conditionally skip submit-time execution. +- `triggerDebounceMs`: debounce change and blur execution. +- `bailIfInvalid`: skip this and subsequent validators when an earlier one + failed. +- trigger objects with `when`: enable a trigger conditionally. +- `watchFields`: rerun a field validator when related fields trigger it. -In the example above, we are validating different things on the same field at different times (at each keystroke and when blurring the field). Since `field.state.meta.errors` is an array, all the relevant errors at a given time are displayed. You can also use `field.state.meta.errorMap` to get errors based on _when_ the validation was done (onChange, onBlur, etc.). More information about displaying errors is below. +## Control when errors are visible -## Displaying Errors - -Once you have your validation in place, you can map the errors from an array to be displayed in your UI: +Validation and presentation are separate. `errorVisibility` decides when field +issues appear in `field.errors`: ```tsx - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {(field) => { - return ( - <> - {/* ... */} - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(',')} - )} - - ) - }} - +const form = useForm({ + defaultValues: { email: '' }, + errorVisibility: ({ fieldState, state }) => + fieldState.meta.isBlurred || state.submissionAttempts > 0, +}) ``` -Or use the `errorMap` property to access the specific error you're looking for: +Use `field.meta.original.errors` for the unfiltered issues when debugging or +building a custom visibility system. -```tsx - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {(field) => ( - <> - {/* ... */} - {field.state.meta.errorMap['onChange'] ? ( - {field.state.meta.errorMap['onChange']} - ) : null} - - )} - -``` +## Form-level validation -It's worth mentioning that our `errors` array and the `errorMap` match the types returned by the validators. This means that: +A form validator can produce a form issue and route issues to typed field paths +with `createErrorMap`: ```tsx - (value < 13 ? { isOldEnough: false } : undefined), - }} -> - {(field) => ( - <> - {/* ... */} - {/* errorMap.onChange is type `{isOldEnough: false} | undefined` */} - {/* meta.errors is type `Array<{isOldEnough: false} | undefined>` */} - {!field.state.meta.errorMap['onChange']?.isOldEnough ? ( - The user is not old enough - ) : null} - - )} - -``` - -## Validation at field-level vs at form-level - -As shown above, each `` accepts its own validation rules via the callbacks such as `onChange` and `onBlur`. It is also possible to define validation rules at the form-level (as opposed to field-by-field) by passing similar callbacks to the `useForm()` hook. - -Example: +const form = useForm({ + defaultValues: { + email: '', + phone: '', + }, + validators: [ + { + triggers: ['change'], + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() -```tsx -export default function App() { - const form = useForm({ - defaultValues: { - age: 0, - }, - onSubmit: async ({ value }) => { - console.log(value) - }, - validators: { - // Add validators to the form the same way you would add them to a field - onChange({ value }) { - if (value.age < 13) { - return 'Must be 13 or older to sign' + if (!value.email && !value.phone) { + errors.form = 'Provide an email address or phone number' + errors.fields.email = 'Email is required when phone is empty' + errors.fields.phone = 'Phone is required when email is empty' } - return undefined + + return errors }, }, - }) - - // Subscribe to the form's `errorMap` so that updates to it will cause re-renders - // Alternatively, you can use `form.Subscribe` - const formErrorMap = useSelector(form.store, (state) => state.errorMap) - - return ( -
    - {/* ... */} - {formErrorMap.onChange ? ( -
    - There was an error on the form: {formErrorMap.onChange} -
    - ) : null} - {/* ... */} -
    - ) -} + ], +}) ``` -_Note:_ The example above uses a function validator that returns a `string`. When using a [Standard Schema](#standard-schema-libraries) validator (Zod, Valibot, ArkType, Effect/Schema), `state.errorMap.onChange` is typed as `Record` instead, keyed by field name. Iterate the record to render the messages: - -```tsx -{ - formErrorMap.onChange ? ( -
    - - There was an error on the form:{' '} - {Object.values(formErrorMap.onChange) - .flat() - .map((issue) => issue.message) - .join(', ')} - -
    - ) : null -} -``` +Use `form.Subscribe` to reactively select form-level issues from +`form.state.errors`. Lower-level integrations can subscribe to `form.atom`. +Field-routed issues appear in the corresponding `field.errors`. -### Setting field-level errors from the form's validators +## Asynchronous validation and debouncing -You can set errors on the fields from the form's validators. One common use case for this is validating all the fields on submit by calling a single API endpoint in the form's `onSubmitAsync` validator. +`run` may return a promise. Put cheap synchronous checks first and use +`bailIfInvalid` to avoid unnecessary requests: ```tsx -export default function App() { - const form = useForm({ - defaultValues: { - age: 0, - socials: [], - details: { - email: '', - }, +validators={[ + { + triggers: ['change'], + run: ({ value }) => + value.length >= 3 ? undefined : 'Use at least 3 characters', + }, + { + triggers: ['change'], + triggerDebounceMs: 500, + bailIfInvalid: true, + run: async ({ value }) => { + const available = await checkUsername(value) + return available ? undefined : 'That username is already taken' }, - validators: { - onSubmitAsync: async ({ value }) => { - // Validate the value on the server - const hasErrors = await verifyDataOnServer(value) - if (hasErrors) { - return { - form: 'Invalid data', // The `form` key is optional - fields: { - age: 'Must be 13 or older to sign', - // Set errors on nested fields with the field's name - 'socials[0].url': 'The provided URL does not exist', - 'details.email': 'An email is required', - }, - } - } - - return null - }, - }, - }) - - return ( -
    -
    { - e.preventDefault() - e.stopPropagation() - void form.handleSubmit() - }} - > - - {(field) => ( - <> - - field.handleChange(e.target.valueAsNumber)} - /> - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(', ')} - )} - - )} - - [state.errorMap]} - children={([errorMap]) => - errorMap.onSubmit ? ( -
    - There was an error on the form: {errorMap.onSubmit} -
    - ) : null - } - /> - {/*...*/} - -
    - ) -} + }, +]} ``` -> Something worth mentioning is that if you have a form validation function that returns an error, that error may be overwritten by the field-specific validation. -> -> This means that: -> -> ```jsx -> const form = useForm({ -> defaultValues: { -> age: 0, -> }, -> validators: { -> onChange: ({ value }) => { -> return { -> fields: { -> age: value.age < 12 ? 'Too young!' : undefined, -> }, -> } -> }, -> }, -> }) -> -> // ... -> -> return ( -> name="age" -> validators={{ -> onChange: ({ value }) => (value % 2 === 0 ? 'Must be odd!' : undefined), -> }} -> children={() => <>{/* ... */}} -> /> -> ) -> ``` -> -> Will only show `'Must be odd!'` even if the 'Too young!' error is returned by the form-level validation. - -## Asynchronous Functional Validation +Submit validation always runs immediately, even when a trigger is debounced. +`field.meta.isValidating` and `form.state.isValidating` expose pending work. -While we suspect most validation will be synchronous, there are many instances where a network call or some other async operation would be useful to validate against. +## Standard Schema validation -To do this, we have dedicated `onChangeAsync`, `onBlurAsync`, and other methods that can be used to validate against: +Any Standard Schema implementation can be supplied as `run`: ```tsx - { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value < 13 ? 'You must be 13 to make an account' : undefined - }, - }} -> - {(field) => ( - <> - - field.handleChange(e.target.valueAsNumber)} - /> - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(', ')} - )} - - )} - -``` +import { z } from 'zod' -Synchronous and asynchronous validators can coexist. For example, it is possible to define both `onBlur` and `onBlurAsync` on the same field: +const accountSchema = z.object({ + email: z.string().email(), + age: z.number().min(13), +}) -```tsx - (value < 13 ? 'You must be at least 13' : undefined), - onBlurAsync: async ({ value }) => { - const currentAge = await fetchCurrentAgeOnProfile() - return value < currentAge ? 'You can only increase the age' : undefined +const form = useForm({ + defaultValues: { email: '', age: 0 }, + validators: [ + { + triggers: ['change'], + run: accountSchema, }, - }} -> - {(field) => ( - <> - - field.handleChange(e.target.valueAsNumber)} - /> - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(', ')} - )} - - )} - + ], +}) ``` -The synchronous validation method (`onBlur`) is run first, and the asynchronous method (`onBlurAsync`) is only run if the synchronous one (`onBlur`) succeeds. To change this behaviour, set the `asyncAlways` option to `true`, and the async method will be run regardless of the result of the sync method. +Schema paths are routed to matching fields. Parsed outputs are available by +validator index in `schemaOutputs` during submit (for example, +`schemaOutputs[0]`); `value` remains the form's raw editable state rather than +the parsed output. -### Built-in Debouncing +For custom schema routing, call a schema's safe parse API inside `run` and pass +its issues to the provided `parseIssues` helper. -While async calls are the way to go when validating against the database, running a network request on every keystroke is a good way to DDoS your database. +## Validate related fields -Instead, we enable an easy method for debouncing your `async` calls by adding a single property: +Use `watchFields` when one field's validity depends on another: ```tsx { - // ... + name="endDate" + validators={[ + { + triggers: ['change', 'blur'], + watchFields: ['startDate'], + run: ({ value, formApi }) => + value >= formApi.getFieldValue('startDate') + ? undefined + : 'End date must be on or after the start date', }, - }} - children={(field) => { - return <>{/* ... */} - }} -/> -``` - -This will debounce every async call with a 500ms delay. You can even override this property on a per-validation property: - -```tsx - { - // ... - }, - onBlurAsync: async ({ value }) => { - // ... - }, - }} - children={(field) => { - return <>{/* ... */} - }} -/> + ]} +> + {(field) => ( + field.handleChange(event.target.value)} + aria-invalid={field.meta.isInvalid} + /> + )} + ``` -This will run `onChangeAsync` every 1500ms, whereas `onBlurAsync` will run every 500ms. - -## Validation through Schema Libraries - -While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries that provide schema-based validation to make shorthand and type-strict validation substantially easier. You can also define a single schema for your entire form and pass it to the form-level validators; errors will automatically propagate to the fields. - -### Standard Schema Libraries - -TanStack Form natively supports all libraries following the [Standard Schema specification](https://github.com/standard-schema/standard-schema), most notably: - -- [Zod](https://zod.dev/) -- [Valibot](https://valibot.dev/) -- [ArkType](https://arktype.io/) -- [Effect/Schema](https://effect.website/docs/schema/standard-schema/) - -_Note:_ make sure to use the latest version of the schema libraries as older versions might not support Standard Schema yet. - -> Validation will not provide you with transformed values. See [submission handling](./submission-handling.md) for more information. - -To use schemas from these libraries you can pass them to the `validators` props as you would do with a custom function: - -```tsx -const userSchema = z.object({ - age: z.number().gte(13, 'You must be 13 to make an account'), -}) - -function App() { - const form = useForm({ - defaultValues: { - age: 0, - }, - validators: { - onChange: userSchema, - }, - }) - return ( -
    - { - return <>{/* ... */} - }} - /> -
    - ) -} -``` +## Return errors from submission -Async validators at the form- and field-level are supported as well: +Endpoint validation belongs in `onSubmit`. Return +`createValidationError(...)` to feed server issues back into normal form state: ```tsx - { - const currentAge = await fetchCurrentAgeOnProfile() - return value >= currentAge - }, - { - message: 'You can only increase the age', - }, - ), - }} - children={(field) => { - return <>{/* ... */} - }} -/> -``` +onSubmit: async ({ value, createValidationError }) => { + const result = await saveProfile(value) -If you need even more control over your Standard Schema validation, you can combine a Standard Schema with a callback function like so: + if (!result.ok) { + return createValidationError({ + form: 'Could not save the profile', + fields: { email: 'This email is already registered' }, + }) + } -```tsx - { - const errors = fieldApi.parseValueWithSchema( - z.number().gte(13, 'You must be 13 to make an account'), - ) - if (errors) return errors - // continue with your validation - }, - }} - children={(field) => { - return <>{/* ... */} - }} -/> + return null +} ``` -## Preventing invalid forms from being submitted - -The callbacks, such as `onChange` and `onBlur`, are also run when the form is submitted and the submission is blocked because the form is invalid. +## Prevent invalid submission -The form state object has a `canSubmit` flag that is `false` when any field is invalid and the form has been touched (`canSubmit` is true until the form has been touched, even if some fields are "technically" invalid based on their `onChange`/`onBlur` props). - -You can subscribe to `canSubmit` via `form.Subscribe` and use the value in order to, for example, disable the submit button when the form is invalid (in practice, disabled buttons are not accessible, use `aria-disabled` instead). +`form.handleSubmit()` skips `onSubmit` when validation fails and resolves with +the validation errors. `onSubmitInvalid` is currently available on form groups; +root-form support is planned but not yet implemented. Subscribe to `canSubmit` +and `isSubmitting` to reflect that state in the submit UI: ```tsx -const form = useForm(/* ... */) - -return ( - /* ... */ - - // Dynamic submit button - [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( - - )} - /> -) + [state.canSubmit, state.isSubmitting]}> + {([canSubmit, isSubmitting]) => ( + + )} + ``` -To prevent the form from being submitted before any interaction, combine `canSubmit` with `isPristine` flags. A simple condition like `!canSubmit || isPristine` effectively disables submissions until the user has made changes. +If a disabled submit button would hide useful validation feedback, keep it +focusable with `aria-disabled` and let `handleSubmit()` report the issues. diff --git a/docs/framework/react/quick-start.md b/docs/framework/react/quick-start.md index 6fc27e6c7e..5b870e57c6 100644 --- a/docs/framework/react/quick-start.md +++ b/docs/framework/react/quick-start.md @@ -3,134 +3,118 @@ id: quick-start title: Quick Start --- -TanStack Form is unlike most form libraries you've used before. It's designed for large-scale production usage, with a focus on type safety, performance and composition for an unmatched developer experience. +TanStack Form is a headless, type-safe form library. It owns form state and +validation while leaving markup, styling, and component choice to you. -As a result, we've developed [a philosophy around the library's usage](../../philosophy.md) that values scalability and long-term developer experience over short and sharable code snippets. +Install the React adapter: -Here's an example of a form following many of our best practices, which will allow you to rapidly develop even high-complexity forms after a short onboarding experience: +```bash +npm install @tanstack/react-form +``` -```tsx -import React from 'react' -import ReactDOM from 'react-dom/client' -import { createFormHook, createFormHookContexts } from '@tanstack/react-form' -// Form components that pre-bind events from the form hook; check our "Form Composition" guide for more -import { TextField, NumberField, SubmitButton } from '~our-app/ui-library' -// We also support Valibot, ArkType, and any other standard schema library -import { z } from 'zod' +## Create a form -const { fieldContext, formContext } = createFormHookContexts() +`useForm` requires `defaultValues`. Their shape becomes the form's inferred +value type. -// Allow us to bind components to the form to keep type safety but reduce production boilerplate -// Define this once to have a generator of consistent form instances throughout your app -const { useAppForm } = createFormHook({ - fieldComponents: { - TextField, - NumberField, - }, - formComponents: { - SubmitButton, - }, - fieldContext, - formContext, -}) +```tsx +import { useForm } from '@tanstack/react-form' -const PeoplePage = () => { - const form = useAppForm({ +export function ProfileForm() { + const form = useForm({ defaultValues: { - username: '', + fullName: '', age: 0, }, - validators: { - // Pass a schema or function to validate - onChange: z.object({ - username: z.string(), - age: z.number().min(13), - }), - }, - onSubmit: ({ value }) => { - // Do something with form data - alert(JSON.stringify(value, null, 2)) + onSubmit: async ({ value }) => { + console.log(value) }, }) return (
    { - e.preventDefault() - form.handleSubmit() + onSubmit={(event) => { + event.preventDefault() + void form.handleSubmit() }} > -

    Personal Information

    - {/* Components are bound to `form` and `field` to ensure extreme type safety */} - {/* Use `form.AppField` to render a component bound to a single field */} - } - /> - {/* The "name" property will throw a TypeScript error if typo'd */} - + value.trim() ? undefined : 'Enter your full name', + }, + ]} + > + {(field) => ( + + )} + + + } - /> - {/* Components in `form.AppForm` have access to the form context */} - - - + validators={[ + { + triggers: ['change'], + run: ({ value }) => + value >= 13 ? undefined : 'You must be at least 13', + }, + ]} + > + {(field) => ( + + )} + + + [state.canSubmit, state.isSubmitting]} + > + {([canSubmit, isSubmitting]) => ( + + )} + ) } - -const rootElement = document.getElementById('root')! -ReactDOM.createRoot(rootElement).render() ``` -While we generally suggest using `createFormHook` for reduced boilerplate in the long-run, we also support one-off components and other behaviors using `useForm` and `form.Field`: - -```tsx -import React from 'react' -import ReactDOM from 'react-dom/client' -import { useForm } from '@tanstack/react-form' - -const PeoplePage = () => { - const form = useForm({ - defaultValues: { - username: '', - age: 0, - }, - onSubmit: ({ value }) => { - // Do something with form data - alert(JSON.stringify(value, null, 2)) - }, - }) - - return ( - - value > 13 ? undefined : 'Must be 13 or older', - }} - children={(field) => ( - <> - field.handleChange(e.target.valueAsNumber)} - /> - {!field.state.meta.isValid && ( - {field.state.meta.errors.join(',')} - )} - - )} - /> - ) -} - -const rootElement = document.getElementById('root')! -ReactDOM.createRoot(rootElement).render() -``` +The important pieces are: -All properties from `useForm` can be used in `useAppForm` and all properties from `form.Field` can be used in `form.AppField`. +- `defaultValues` define the complete initial value and drive type inference. +- `form.Field` subscribes to one field. Its render prop exposes `field.value`, + `field.meta`, and event handlers. +- Validators are ordered objects with a `run` function and explicit + `triggers`. +- `form.Subscribe` rerenders only its own children when the selected form state + changes. +- `form.handleSubmit()` validates the form before calling `onSubmit`. diff --git a/docs/framework/react/reference/classes/ReadonlyStore.md b/docs/framework/react/reference/classes/ReadonlyStore.md new file mode 100644 index 0000000000..046f5bc143 --- /dev/null +++ b/docs/framework/react/reference/classes/ReadonlyStore.md @@ -0,0 +1,122 @@ +--- +id: ReadonlyStore +title: ReadonlyStore +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:22 + +## Type Parameters + +### T + +`T` + +## Implements + +- `Omit`\<[`Store`](Store.md)\<`T`\>, `"setState"` \| `"actions"`\> + +## Constructors + +### Constructor + +```ts +new ReadonlyStore(getValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:24 + +#### Parameters + +##### getValue + +(`prev?`) => `T` + +#### Returns + +`ReadonlyStore`\<`T`\> + +### Constructor + +```ts +new ReadonlyStore(initialValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:25 + +#### Parameters + +##### initialValue + +`T` + +#### Returns + +`ReadonlyStore`\<`T`\> + +## Accessors + +### state + +#### Get Signature + +```ts +get state(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:26 + +##### Returns + +`T` + +#### Implementation of + +```ts +Omit.state +``` + +## Methods + +### get() + +```ts +get(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:27 + +#### Returns + +`T` + +#### Implementation of + +```ts +Omit.get +``` + +*** + +### subscribe() + +```ts +subscribe(observerOrFn): Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:28 + +#### Parameters + +##### observerOrFn + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +#### Returns + +[`Subscription`](../interfaces/Subscription.md) + +#### Implementation of + +```ts +Omit.subscribe +``` diff --git a/docs/framework/react/reference/classes/Store.md b/docs/framework/react/reference/classes/Store.md new file mode 100644 index 0000000000..dc9d5daeff --- /dev/null +++ b/docs/framework/react/reference/classes/Store.md @@ -0,0 +1,156 @@ +--- +id: Store +title: Store +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:11 + +## Type Parameters + +### T + +`T` + +### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) = `never` + +## Constructors + +### Constructor + +```ts +new Store(getValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:14 + +#### Parameters + +##### getValue + +(`prev?`) => `T` + +#### Returns + +`Store`\<`T`, `TActions`\> + +### Constructor + +```ts +new Store(initialValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:15 + +#### Parameters + +##### initialValue + +`T` + +#### Returns + +`Store`\<`T`, `TActions`\> + +### Constructor + +```ts +new Store(initialValue, actionsFactory): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:16 + +#### Parameters + +##### initialValue + +`NonFunction`\<`T`\> + +##### actionsFactory + +[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> + +#### Returns + +`Store`\<`T`, `TActions`\> + +## Properties + +### actions + +```ts +readonly actions: TActions; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:13 + +## Accessors + +### state + +#### Get Signature + +```ts +get state(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:18 + +##### Returns + +`T` + +## Methods + +### get() + +```ts +get(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:19 + +#### Returns + +`T` + +*** + +### setState() + +```ts +setState(updater): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:17 + +#### Parameters + +##### updater + +(`prev`) => `T` + +#### Returns + +`void` + +*** + +### subscribe() + +```ts +subscribe(observerOrFn): Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:20 + +#### Parameters + +##### observerOrFn + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +#### Returns + +[`Subscription`](../interfaces/Subscription.md) diff --git a/docs/framework/react/reference/functions/Subscribe.md b/docs/framework/react/reference/functions/Subscribe.md new file mode 100644 index 0000000000..f4db3d857e --- /dev/null +++ b/docs/framework/react/reference/functions/Subscribe.md @@ -0,0 +1,34 @@ +--- +id: Subscribe +title: Subscribe +--- + +```ts +function Subscribe(props): ReactNode; +``` + +Defined in: [packages/react-form/src/Subscribe.public.tsx:36](https://github.com/TanStack/form/blob/main/packages/react-form/src/Subscribe.public.tsx#L36) + +A React component that allows you to subscribe to source state. + +This is useful for opting into state re-renders for specific parts of the state. + +## Type Parameters + +### TSourceData + +`TSourceData` + +### TSelected + +`TSelected` + +## Parameters + +### props + +[`SubscribeProps`](../interfaces/SubscribeProps.md)\<`TSourceData`, `TSelected`\> + +## Returns + +`ReactNode` diff --git a/docs/framework/react/reference/functions/batch.md b/docs/framework/react/reference/functions/batch.md new file mode 100644 index 0000000000..82825258f3 --- /dev/null +++ b/docs/framework/react/reference/functions/batch.md @@ -0,0 +1,20 @@ +--- +id: batch +title: batch +--- + +```ts +function batch(fn): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/atom.d.ts:5 + +## Parameters + +### fn + +() => `void` + +## Returns + +`void` diff --git a/docs/framework/react/reference/functions/createAsyncAtom.md b/docs/framework/react/reference/functions/createAsyncAtom.md new file mode 100644 index 0000000000..812a0e582d --- /dev/null +++ b/docs/framework/react/reference/functions/createAsyncAtom.md @@ -0,0 +1,30 @@ +--- +id: createAsyncAtom +title: createAsyncAtom +--- + +```ts +function createAsyncAtom(getValue, options?): ReadonlyAtom>; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/atom.d.ts:16 + +## Type Parameters + +### T + +`T` + +## Parameters + +### getValue + +() => `Promise`\<`T`\> + +### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`AsyncAtomState`\<`T`, `unknown`\>\> + +## Returns + +[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`AsyncAtomState`\<`T`, `unknown`\>\> diff --git a/docs/framework/react/reference/functions/createAtom.md b/docs/framework/react/reference/functions/createAtom.md new file mode 100644 index 0000000000..c948994233 --- /dev/null +++ b/docs/framework/react/reference/functions/createAtom.md @@ -0,0 +1,60 @@ +--- +id: createAtom +title: createAtom +--- + +## Call Signature + +```ts +function createAtom(getValue, options?): ReadonlyAtom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/atom.d.ts:17 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`T`\> + +## Call Signature + +```ts +function createAtom(initialValue, options?): Atom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/atom.d.ts:18 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`Atom`](../interfaces/Atom.md)\<`T`\> diff --git a/docs/framework/react/reference/functions/createFormHook.md b/docs/framework/react/reference/functions/createFormHook.md index 76b3f6baef..9f1b96c290 100644 --- a/docs/framework/react/reference/functions/createFormHook.md +++ b/docs/framework/react/reference/functions/createFormHook.md @@ -3,1736 +3,34 @@ id: createFormHook title: createFormHook --- -# Function: createFormHook() - ```ts -function createFormHook(__namedParameters): object; +function createFormHook(createOptions): AppFormHookResult<{ + fieldComponents: TFieldComponents; + formComponents: TFormComponents; +}>; ``` -Defined in: [packages/react-form/src/createFormHook.tsx:293](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L293) +Defined in: [packages/react-form/src/AppForm/createFormHook.public.ts:14](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/createFormHook.public.ts#L14) ## Type Parameters -### TComponents +### TFormComponents -`TComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> +`TFormComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) -### TFormComponents +### TFieldComponents -`TFormComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> +`TFieldComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) ## Parameters -### \_\_namedParameters +### createOptions -`CreateFormHookProps`\<`TComponents`, `TFormComponents`\> +[`CreateFormHookOptions`](../interfaces/CreateFormHookOptions.md)\<`TFormComponents`, `TFieldComponents`\> ## Returns -### extendForm() - -```ts -extendForm: (extension) => object; -``` - -#### Type Parameters - -##### TNewField - -`TNewField` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> & \{ \[K in string \| number \| symbol\]?: "Error: field component names must be unique — this key already exists in the base form" \} - -##### TNewForm - -`TNewForm` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> & \{ \[K in string \| number \| symbol\]?: "Error: form component names must be unique — this key already exists in the base form" \} - -#### Parameters - -##### extension - -###### fieldComponents? - -`TNewField` - -###### formComponents? - -`TNewForm` - -#### Returns - -##### extendForm() - -```ts -extendForm: (extension) => object; -``` - -###### Type Parameters - -###### TNewField - -`TNewField` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> & \{ \[K in string \| number \| symbol\]?: "Error: field component names must be unique — this key already exists in the base form" \} - -###### TNewForm - -`TNewForm` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> & \{ \[K in string \| number \| symbol\]?: "Error: form component names must be unique — this key already exists in the base form" \} - -###### Parameters - -###### extension - -###### fieldComponents? - -`TNewField` - -###### formComponents? - -`TNewForm` - -###### Returns - -###### extendForm() - -```ts -extendForm: (extension) => object; -``` - -###### Type Parameters - -###### TNewField - -`TNewField` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> & \{ \[K in string \| number \| symbol\]?: "Error: field component names must be unique — this key already exists in the base form" \} - -###### TNewForm - -`TNewForm` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> & \{ \[K in string \| number \| symbol\]?: "Error: form component names must be unique — this key already exists in the base form" \} - -###### Parameters - -###### extension - -###### fieldComponents? - -`TNewField` - -###### formComponents? - -`TNewForm` - -###### Returns - -###### extendForm() - -```ts -extendForm: (extension) => object; -``` - -###### Type Parameters - -###### TNewField - -`TNewField` *extends* `Record`\<`string`, `ComponentType`\<...\>\> & \{ \[K in (...) \| (...) \| (...)\]?: (...) \| (...) \} - -###### TNewForm - -`TNewForm` *extends* `Record`\<`string`, `ComponentType`\<...\>\> & \{ \[K in (...) \| (...) \| (...)\]?: (...) \| (...) \} - -###### Parameters - -###### extension - -###### fieldComponents? - -`TNewField` - -###### formComponents? - -`TNewForm` - -###### Returns - -###### extendForm() - -```ts -extendForm: (extension) => object; -``` - -###### Type Parameters - -###### TNewField - -`TNewField` *extends* ... & ... - -###### TNewForm - -`TNewForm` *extends* ... & ... - -###### Parameters - -###### extension - -###### fieldComponents? - -... - -###### formComponents? - -... - -###### Returns - -`object` - -###### extendForm - -```ts -extendForm: ...; -``` - -###### useAppForm - -```ts -useAppForm: ...; -``` - -###### useTypedAppFormContext - -```ts -useTypedAppFormContext: ...; -``` - -###### withFieldGroup - -```ts -withFieldGroup: ...; -``` - -###### withForm - -```ts -withForm: ...; -``` - -###### useAppForm() - -```ts -useAppForm: (props) => AppFieldExtendedReactFormApi<..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...>; -``` - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TOnMount - -`TOnMount` *extends* ... \| ... - -###### TOnChange - -`TOnChange` *extends* ... \| ... - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* ... \| ... - -###### TOnBlur - -`TOnBlur` *extends* ... \| ... - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* ... \| ... - -###### TOnSubmit - -`TOnSubmit` *extends* ... \| ... - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* ... \| ... - -###### TOnDynamic - -`TOnDynamic` *extends* ... \| ... - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* ... \| ... - -###### TOnServer - -`TOnServer` *extends* ... \| ... - -###### TSubmitMeta - -`TSubmitMeta` - -###### Parameters - -###### props - -`FormOptions`\<..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...\> - -###### Returns - -`AppFieldExtendedReactFormApi`\<..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...\> - -###### useTypedAppFormContext() - -```ts -useTypedAppFormContext: (_props) => AppFieldExtendedReactFormApi<..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...>; -``` - -āš ļø **Use withForm whenever possible.** - -Gets a typed form from the `` context. - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TOnMount - -`TOnMount` *extends* ... \| ... - -###### TOnChange - -`TOnChange` *extends* ... \| ... - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* ... \| ... - -###### TOnBlur - -`TOnBlur` *extends* ... \| ... - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* ... \| ... - -###### TOnSubmit - -`TOnSubmit` *extends* ... \| ... - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* ... \| ... - -###### TOnDynamic - -`TOnDynamic` *extends* ... \| ... - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* ... \| ... - -###### TOnServer - -`TOnServer` *extends* ... \| ... - -###### TSubmitMeta - -`TSubmitMeta` - -###### Parameters - -###### \_props - -`FormOptions`\<..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...\> - -###### Returns - -`AppFieldExtendedReactFormApi`\<..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...\> - -###### withFieldGroup() - -```ts -withFieldGroup: (__namedParameters) => (params) => ...; -``` - -###### Type Parameters - -###### TFieldGroupData - -`TFieldGroupData` - -###### TSubmitMeta - -`TSubmitMeta` - -###### TRenderProps - -`TRenderProps` *extends* `object` = \{ -\} - -###### Parameters - -###### \_\_namedParameters - -[`WithFieldGroupProps`](../interfaces/WithFieldGroupProps.md)\<..., ..., ..., ..., ...\> - -###### Returns - -```ts -(params): ...; -``` - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TFields - -`TFields` *extends* ... - -###### TOnMount - -`TOnMount` *extends* ... - -###### TOnChange - -`TOnChange` *extends* ... - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* ... - -###### TOnBlur - -`TOnBlur` *extends* ... - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* ... - -###### TOnSubmit - -`TOnSubmit` *extends* ... - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* ... - -###### TOnDynamic - -`TOnDynamic` *extends* ... - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* ... - -###### TOnServer - -`TOnServer` *extends* ... - -###### TFormSubmitMeta - -`TFormSubmitMeta` - -###### Parameters - -###### params - -... - -###### Returns - -... - -###### withForm() - -```ts -withForm: (__namedParameters) => FunctionComponent<...>; -``` - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TOnMount - -`TOnMount` *extends* ... \| ... - -###### TOnChange - -`TOnChange` *extends* ... \| ... - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* ... \| ... - -###### TOnBlur - -`TOnBlur` *extends* ... \| ... - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* ... \| ... - -###### TOnSubmit - -`TOnSubmit` *extends* ... \| ... - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* ... \| ... - -###### TOnDynamic - -`TOnDynamic` *extends* ... \| ... - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* ... \| ... - -###### TOnServer - -`TOnServer` *extends* ... \| ... - -###### TSubmitMeta - -`TSubmitMeta` - -###### TRenderProps - -`TRenderProps` *extends* `object` = \{ -\} - -###### Parameters - -###### \_\_namedParameters - -[`WithFormProps`](../interfaces/WithFormProps.md)\<..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...\> - -###### Returns - -`FunctionComponent`\<...\> - -###### useAppForm() - -```ts -useAppForm: (props) => AppFieldExtendedReactFormApi; -``` - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TSubmitMeta - -`TSubmitMeta` - -###### Parameters - -###### props - -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -###### Returns - -`AppFieldExtendedReactFormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents` & `TNewField` & `TNewField` & `TNewField`, `TFormComponents` & `TNewForm` & `TNewForm` & `TNewForm`\> - -###### useTypedAppFormContext() - -```ts -useTypedAppFormContext: (_props) => AppFieldExtendedReactFormApi; -``` - -āš ļø **Use withForm whenever possible.** - -Gets a typed form from the `` context. - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TSubmitMeta - -`TSubmitMeta` - -###### Parameters - -###### \_props - -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -###### Returns - -`AppFieldExtendedReactFormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents` & `TNewField` & `TNewField` & `TNewField`, `TFormComponents` & `TNewForm` & `TNewForm` & `TNewForm`\> - -###### withFieldGroup() - -```ts -withFieldGroup: (__namedParameters) => (params) => ReactNode | Promise<...>; -``` - -###### Type Parameters - -###### TFieldGroupData - -`TFieldGroupData` - -###### TSubmitMeta - -`TSubmitMeta` - -###### TRenderProps - -`TRenderProps` *extends* `object` = \{ -\} - -###### Parameters - -###### \_\_namedParameters - -[`WithFieldGroupProps`](../interfaces/WithFieldGroupProps.md)\<`TFieldGroupData`, `TComponents` & `TNewField` & `TNewField` & `TNewField`, `TFormComponents` & `TNewForm` & `TNewForm` & `TNewForm`, `TSubmitMeta`, `TRenderProps`\> - -###### Returns - -```ts -(params): ReactNode | Promise<...>; -``` - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TFields - -`TFields` *extends* `string` \| `{ [K in (...)]: (...) }` - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<...\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<...\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<...\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<...\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<...\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<...\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<...\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<...\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<...\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<...\> \| `undefined` - -###### TFormSubmitMeta - -`TFormSubmitMeta` - -###### Parameters - -###### params - -`PropsWithChildren`\<... & ...\> - -###### Returns - -`ReactNode` \| `Promise`\<...\> - -###### withForm() - -```ts -withForm: (__namedParameters) => FunctionComponent>; -``` - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TSubmitMeta - -`TSubmitMeta` - -###### TRenderProps - -`TRenderProps` *extends* `object` = \{ -\} - -###### Parameters - -###### \_\_namedParameters - -[`WithFormProps`](../interfaces/WithFormProps.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents` & `TNewField` & `TNewField` & `TNewField`, `TFormComponents` & `TNewForm` & `TNewForm` & `TNewForm`, `TRenderProps`\> - -###### Returns - -`FunctionComponent`\<`PropsWithChildren`\<... & ...\>\> - -###### useAppForm() - -```ts -useAppForm: (props) => AppFieldExtendedReactFormApi; -``` - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TSubmitMeta - -`TSubmitMeta` - -###### Parameters - -###### props - -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -###### Returns - -`AppFieldExtendedReactFormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents` & `TNewField` & `TNewField`, `TFormComponents` & `TNewForm` & `TNewForm`\> - -###### useTypedAppFormContext() - -```ts -useTypedAppFormContext: (_props) => AppFieldExtendedReactFormApi; -``` - -āš ļø **Use withForm whenever possible.** - -Gets a typed form from the `` context. - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TSubmitMeta - -`TSubmitMeta` - -###### Parameters - -###### \_props - -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -###### Returns - -`AppFieldExtendedReactFormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents` & `TNewField` & `TNewField`, `TFormComponents` & `TNewForm` & `TNewForm`\> - -###### withFieldGroup() - -```ts -withFieldGroup: (__namedParameters) => (params) => ReactNode | Promise; -``` - -###### Type Parameters - -###### TFieldGroupData - -`TFieldGroupData` - -###### TSubmitMeta - -`TSubmitMeta` - -###### TRenderProps - -`TRenderProps` *extends* `object` = \{ -\} - -###### Parameters - -###### \_\_namedParameters - -[`WithFieldGroupProps`](../interfaces/WithFieldGroupProps.md)\<`TFieldGroupData`, `TComponents` & `TNewField` & `TNewField`, `TFormComponents` & `TNewForm` & `TNewForm`, `TSubmitMeta`, `TRenderProps`\> - -###### Returns - -```ts -(params): ReactNode | Promise; -``` - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TFields - -`TFields` *extends* - \| `string` - \| \{ \[K in string \| number \| symbol\]: DeepKeysOfType\ \} - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TFormSubmitMeta - -`TFormSubmitMeta` - -###### Parameters - -###### params - -`PropsWithChildren`\<`NoInfer`\<`TRenderProps`\> & `object`\> - -###### Returns - -`ReactNode` \| `Promise`\<`ReactNode`\> - -###### withForm() - -```ts -withForm: (__namedParameters) => FunctionComponent> & object>>; -``` - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TSubmitMeta - -`TSubmitMeta` - -###### TRenderProps - -`TRenderProps` *extends* `object` = \{ -\} - -###### Parameters - -###### \_\_namedParameters - -[`WithFormProps`](../interfaces/WithFormProps.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents` & `TNewField` & `TNewField`, `TFormComponents` & `TNewForm` & `TNewForm`, `TRenderProps`\> - -###### Returns - -`FunctionComponent`\<`PropsWithChildren`\<`NoInfer`\<`UnwrapOrAny`\<...\>\> & `object`\>\> - -##### useAppForm() - -```ts -useAppForm: (props) => AppFieldExtendedReactFormApi; -``` - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TSubmitMeta - -`TSubmitMeta` - -###### Parameters - -###### props - -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -###### Returns - -`AppFieldExtendedReactFormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents` & `TNewField`, `TFormComponents` & `TNewForm`\> - -##### useTypedAppFormContext() - -```ts -useTypedAppFormContext: (_props) => AppFieldExtendedReactFormApi; -``` - -āš ļø **Use withForm whenever possible.** - -Gets a typed form from the `` context. - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TSubmitMeta - -`TSubmitMeta` - -###### Parameters - -###### \_props - -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -###### Returns - -`AppFieldExtendedReactFormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents` & `TNewField`, `TFormComponents` & `TNewForm`\> - -##### withFieldGroup() - -```ts -withFieldGroup: (__namedParameters) => (params) => ReactNode | Promise; -``` - -###### Type Parameters - -###### TFieldGroupData - -`TFieldGroupData` - -###### TSubmitMeta - -`TSubmitMeta` - -###### TRenderProps - -`TRenderProps` *extends* `object` = \{ -\} - -###### Parameters - -###### \_\_namedParameters - -[`WithFieldGroupProps`](../interfaces/WithFieldGroupProps.md)\<`TFieldGroupData`, `TComponents` & `TNewField`, `TFormComponents` & `TNewForm`, `TSubmitMeta`, `TRenderProps`\> - -###### Returns - -```ts -(params): ReactNode | Promise; -``` - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TFields - -`TFields` *extends* - \| `string` - \| \{ \[K in string \| number \| symbol\]: DeepKeysOfType\ \} - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TFormSubmitMeta - -`TFormSubmitMeta` - -###### Parameters - -###### params - -`PropsWithChildren`\<`NoInfer`\<`TRenderProps`\> & `object`\> - -###### Returns - -`ReactNode` \| `Promise`\<`ReactNode`\> - -##### withForm() - -```ts -withForm: (__namedParameters) => FunctionComponent> & object>>; -``` - -###### Type Parameters - -###### TFormData - -`TFormData` - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TSubmitMeta - -`TSubmitMeta` - -###### TRenderProps - -`TRenderProps` *extends* `object` = \{ -\} - -###### Parameters - -###### \_\_namedParameters - -[`WithFormProps`](../interfaces/WithFormProps.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents` & `TNewField`, `TFormComponents` & `TNewForm`, `TRenderProps`\> - -###### Returns - -`FunctionComponent`\<`PropsWithChildren`\<`NoInfer`\<`UnwrapOrAny`\<`TRenderProps`\>\> & `object`\>\> - -### useAppForm() - -```ts -useAppForm: (props) => AppFieldExtendedReactFormApi; -``` - -#### Type Parameters - -##### TFormData - -`TFormData` - -##### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TSubmitMeta - -`TSubmitMeta` - -#### Parameters - -##### props - -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -#### Returns - -`AppFieldExtendedReactFormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents`, `TFormComponents`\> - -### useTypedAppFormContext() - -```ts -useTypedAppFormContext: (_props) => AppFieldExtendedReactFormApi; -``` - -āš ļø **Use withForm whenever possible.** - -Gets a typed form from the `` context. - -#### Type Parameters - -##### TFormData - -`TFormData` - -##### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TSubmitMeta - -`TSubmitMeta` - -#### Parameters - -##### \_props - -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -#### Returns - -`AppFieldExtendedReactFormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents`, `TFormComponents`\> - -### withFieldGroup() - -```ts -withFieldGroup: (__namedParameters) => (params) => ReactNode | Promise; -``` - -#### Type Parameters - -##### TFieldGroupData - -`TFieldGroupData` - -##### TSubmitMeta - -`TSubmitMeta` - -##### TRenderProps - -`TRenderProps` *extends* `object` = \{ -\} - -#### Parameters - -##### \_\_namedParameters - -[`WithFieldGroupProps`](../interfaces/WithFieldGroupProps.md)\<`TFieldGroupData`, `TComponents`, `TFormComponents`, `TSubmitMeta`, `TRenderProps`\> - -#### Returns - -```ts -(params): ReactNode | Promise; -``` - -##### Type Parameters - -###### TFormData - -`TFormData` - -###### TFields - -`TFields` *extends* - \| `string` - \| \{ \[K in string \| number \| symbol\]: DeepKeysOfType\ \} - -###### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TFormSubmitMeta - -`TFormSubmitMeta` - -##### Parameters - -###### params - -`PropsWithChildren`\<`NoInfer`\<`TRenderProps`\> & `object`\> - -##### Returns - -`ReactNode` \| `Promise`\<`ReactNode`\> - -### withForm() - -```ts -withForm: (__namedParameters) => FunctionComponent> & object>>; -``` - -#### Type Parameters - -##### TFormData - -`TFormData` - -##### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TSubmitMeta - -`TSubmitMeta` - -##### TRenderProps - -`TRenderProps` *extends* `object` = \{ -\} - -#### Parameters - -##### \_\_namedParameters - -[`WithFormProps`](../interfaces/WithFormProps.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents`, `TFormComponents`, `TRenderProps`\> - -#### Returns - -`FunctionComponent`\<`PropsWithChildren`\<`NoInfer`\<`UnwrapOrAny`\<`TRenderProps`\>\> & `object`\>\> +[`AppFormHookResult`](../interfaces/AppFormHookResult.md)\<\{ + `fieldComponents`: `TFieldComponents`; + `formComponents`: `TFormComponents`; +\}\> diff --git a/docs/framework/react/reference/functions/createFormHookContexts.md b/docs/framework/react/reference/functions/createFormHookContexts.md deleted file mode 100644 index 7f0c321468..0000000000 --- a/docs/framework/react/reference/functions/createFormHookContexts.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -id: createFormHookContexts -title: createFormHookContexts ---- - -# Function: createFormHookContexts() - -```ts -function createFormHookContexts(): object; -``` - -Defined in: [packages/react-form/src/createFormHook.tsx:95](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L95) - -## Returns - -`object` - -### fieldContext - -```ts -fieldContext: Context; -``` - -### formContext - -```ts -formContext: Context; -``` - -### useFieldContext() - -```ts -useFieldContext: () => FieldApi; -``` - -#### Type Parameters - -##### TData - -`TData` - -#### Returns - -`FieldApi`\<`any`, `string`, `TData`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`\> - -### useFormContext() - -```ts -useFormContext: () => ReactFormExtendedApi, any, any, any, any, any, any, any, any, any, any, any>; -``` - -#### Returns - -[`ReactFormExtendedApi`](../type-aliases/ReactFormExtendedApi.md)\<`Record`\<`string`, `never`\>, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`\> diff --git a/docs/framework/react/reference/functions/createStore.md b/docs/framework/react/reference/functions/createStore.md new file mode 100644 index 0000000000..065ef46534 --- /dev/null +++ b/docs/framework/react/reference/functions/createStore.md @@ -0,0 +1,84 @@ +--- +id: createStore +title: createStore +--- + +## Call Signature + +```ts +function createStore(getValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:30 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +### Returns + +[`ReadonlyStore`](../classes/ReadonlyStore.md)\<`T`\> + +## Call Signature + +```ts +function createStore(initialValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:31 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +### Returns + +[`Store`](../classes/Store.md)\<`T`\> + +## Call Signature + +```ts +function createStore(initialValue, actions): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:32 + +### Type Parameters + +#### T + +`T` + +#### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) + +### Parameters + +#### initialValue + +`NonFunction`\<`T`\> + +#### actions + +[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> + +### Returns + +[`Store`](../classes/Store.md)\<`T`, `TActions`\> diff --git a/docs/framework/react/reference/functions/createStoreContext.md b/docs/framework/react/reference/functions/createStoreContext.md new file mode 100644 index 0000000000..fad5f78544 --- /dev/null +++ b/docs/framework/react/reference/functions/createStoreContext.md @@ -0,0 +1,84 @@ +--- +id: createStoreContext +title: createStoreContext +--- + +```ts +function createStoreContext(): object; +``` + +Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.2.8\_react@19.2.8\_\_react@19.2.8/node\_modules/@tanstack/react-store/dist/createStoreContext.d.ts:40 + +Creates a typed React context for sharing a bundle of atoms and stores with a subtree. + +The returned `StoreProvider` only transports the provided object through +React context. Consumers destructure the contextual atoms and stores, then +compose them with the existing hooks like [useSelector](useSelector.md), +[useSelector](useSelector.md) and [useAtom](useAtom.md). + +The object shape is preserved exactly, so keyed atoms and stores remain fully +typed when read back with `useStoreContext()`. + +## Type Parameters + +### TValue + +`TValue` *extends* `object` + +## Returns + +`object` + +### StoreProvider + +```ts +StoreProvider: (props) => ReactElement; +``` + +#### Parameters + +##### props + +`object` & `object` + +#### Returns + +`ReactElement` + +### useStoreContext + +```ts +useStoreContext: () => TValue; +``` + +#### Returns + +`TValue` + +## Example + +```tsx +const { StoreProvider, useStoreContext } = createStoreContext<{ + countAtom: Atom + totalsStore: Store<{ count: number }> +}>() + +function CountButton() { + const { countAtom, totalsStore } = useStoreContext() + const count = useSelector(countAtom) + const total = useSelector(totalsStore, (state) => state.count) + + return ( + + ) +} +``` + +## Throws + +When `useStoreContext()` is called outside the matching `StoreProvider`. diff --git a/docs/framework/react/reference/functions/flush.md b/docs/framework/react/reference/functions/flush.md new file mode 100644 index 0000000000..b05ac9871f --- /dev/null +++ b/docs/framework/react/reference/functions/flush.md @@ -0,0 +1,14 @@ +--- +id: flush +title: flush +--- + +```ts +function flush(): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/atom.d.ts:6 + +## Returns + +`void` diff --git a/docs/framework/react/reference/functions/getFormHookHelpers.md b/docs/framework/react/reference/functions/getFormHookHelpers.md new file mode 100644 index 0000000000..77e96070c3 --- /dev/null +++ b/docs/framework/react/reference/functions/getFormHookHelpers.md @@ -0,0 +1,45 @@ +--- +id: getFormHookHelpers +title: getFormHookHelpers +--- + +```ts +function getFormHookHelpers(): FormHookHelpers; +``` + +Defined in: [packages/react-form/src/AppForm/getFormHookHelpers.public.ts:268](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/getFormHookHelpers.public.ts#L268) + +Creates helpers that make React field components value-aware for +`createFormHook`. + +`fieldComponent` injects the current App Form field API into a selected prop. +`fieldBrand` only adds compile-time field-value compatibility and returns the +original component at runtime. + +## Returns + +[`FormHookHelpers`](../interfaces/FormHookHelpers.md) + +## Example + +```tsx +import { createFormHook, getFormHookHelpers } from '@tanstack/react-form' +import type { FieldWithValue } from '@tanstack/react-form' + +function TextInput({ field }: { field: FieldWithValue }) { + return ( + field.handleChange(event.target.value)} + /> + ) +} + +const { fieldComponent } = getFormHookHelpers() +const TextField = fieldComponent.strict(TextInput, 'field') + +export const { useAppForm } = createFormHook({ + fieldComponents: { TextField }, + formComponents: {}, +}) +``` diff --git a/docs/framework/react/reference/functions/shallow.md b/docs/framework/react/reference/functions/shallow.md new file mode 100644 index 0000000000..1f6aa52b2a --- /dev/null +++ b/docs/framework/react/reference/functions/shallow.md @@ -0,0 +1,30 @@ +--- +id: shallow +title: shallow +--- + +```ts +function shallow(objA, objB): boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/shallow.d.ts:2 + +## Type Parameters + +### T + +`T` + +## Parameters + +### objA + +`T` + +### objB + +`T` + +## Returns + +`boolean` diff --git a/docs/framework/react/reference/functions/toObserver.md b/docs/framework/react/reference/functions/toObserver.md new file mode 100644 index 0000000000..04b52e1c6e --- /dev/null +++ b/docs/framework/react/reference/functions/toObserver.md @@ -0,0 +1,37 @@ +--- +id: toObserver +title: toObserver +--- + +```ts +function toObserver( + nextHandler?, + errorHandler?, +completionHandler?): Observer; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/atom.d.ts:4 + +## Type Parameters + +### T + +`T` + +## Parameters + +### nextHandler? + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +### errorHandler? + +(`error`) => `void` + +### completionHandler? + +() => `void` + +## Returns + +[`Observer`](../type-aliases/Observer.md)\<`T`\> diff --git a/docs/framework/react/reference/functions/useAtom.md b/docs/framework/react/reference/functions/useAtom.md new file mode 100644 index 0000000000..c80bfdb608 --- /dev/null +++ b/docs/framework/react/reference/functions/useAtom.md @@ -0,0 +1,41 @@ +--- +id: useAtom +title: useAtom +--- + +```ts +function useAtom(atom, options?): [TValue, (fn) => void & (value) => void]; +``` + +Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.2.8\_react@19.2.8\_\_react@19.2.8/node\_modules/@tanstack/react-store/dist/useAtom.d.ts:16 + +Returns the current atom value together with a stable setter. + +This is the writable-atom convenience hook for components that need to both +read and update the same atom. + +## Type Parameters + +### TValue + +`TValue` + +## Parameters + +### atom + +[`Atom`](../interfaces/Atom.md)\<`TValue`\> + +### options? + +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TValue`\> + +## Returns + +\[`TValue`, (`fn`) => `void` & (`value`) => `void`\] + +## Example + +```tsx +const [count, setCount] = useAtom(countAtom) +``` diff --git a/docs/framework/react/reference/functions/useCreateAtom.md b/docs/framework/react/reference/functions/useCreateAtom.md new file mode 100644 index 0000000000..21f4c39a08 --- /dev/null +++ b/docs/framework/react/reference/functions/useCreateAtom.md @@ -0,0 +1,84 @@ +--- +id: useCreateAtom +title: useCreateAtom +--- + +## Call Signature + +```ts +function useCreateAtom(getValue, options?): ReadonlyAtom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.2.8\_react@19.2.8\_\_react@19.2.8/node\_modules/@tanstack/react-store/dist/useCreateAtom.d.ts:16 + +Creates a stable atom instance for the lifetime of the component. + +Pass an initial value to create a writable atom, or a getter function to +create a readonly derived atom. This hook mirrors the overloads from +[createAtom](createAtom.md), but ensures the atom is only created once per mount. + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`T`\> + +### Example + +```tsx +const countAtom = useCreateAtom(0) +``` + +## Call Signature + +```ts +function useCreateAtom(initialValue, options?): Atom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.2.8\_react@19.2.8\_\_react@19.2.8/node\_modules/@tanstack/react-store/dist/useCreateAtom.d.ts:17 + +Creates a stable atom instance for the lifetime of the component. + +Pass an initial value to create a writable atom, or a getter function to +create a readonly derived atom. This hook mirrors the overloads from +[createAtom](createAtom.md), but ensures the atom is only created once per mount. + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`Atom`](../interfaces/Atom.md)\<`T`\> + +### Example + +```tsx +const countAtom = useCreateAtom(0) +``` diff --git a/docs/framework/react/reference/functions/useCreateStore.md b/docs/framework/react/reference/functions/useCreateStore.md new file mode 100644 index 0000000000..4e4fcd9872 --- /dev/null +++ b/docs/framework/react/reference/functions/useCreateStore.md @@ -0,0 +1,120 @@ +--- +id: useCreateStore +title: useCreateStore +--- + +## Call Signature + +```ts +function useCreateStore(getValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.2.8\_react@19.2.8\_\_react@19.2.8/node\_modules/@tanstack/react-store/dist/useCreateStore.d.ts:17 + +Creates a stable store instance for the lifetime of the component. + +Pass an initial value to create a writable store, or a getter function to +create a readonly derived store. This hook mirrors the overloads from +[createStore](createStore.md), but ensures the store is only created once per mount. + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +### Returns + +[`ReadonlyStore`](../classes/ReadonlyStore.md)\<`T`\> + +### Example + +```tsx +const counterStore = useCreateStore({ count: 0 }) +``` + +## Call Signature + +```ts +function useCreateStore(initialValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.2.8\_react@19.2.8\_\_react@19.2.8/node\_modules/@tanstack/react-store/dist/useCreateStore.d.ts:18 + +Creates a stable store instance for the lifetime of the component. + +Pass an initial value to create a writable store, or a getter function to +create a readonly derived store. This hook mirrors the overloads from +[createStore](createStore.md), but ensures the store is only created once per mount. + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +### Returns + +[`Store`](../classes/Store.md)\<`T`\> + +### Example + +```tsx +const counterStore = useCreateStore({ count: 0 }) +``` + +## Call Signature + +```ts +function useCreateStore(initialValue, actions): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.2.8\_react@19.2.8\_\_react@19.2.8/node\_modules/@tanstack/react-store/dist/useCreateStore.d.ts:19 + +Creates a stable store instance for the lifetime of the component. + +Pass an initial value to create a writable store, or a getter function to +create a readonly derived store. This hook mirrors the overloads from +[createStore](createStore.md), but ensures the store is only created once per mount. + +### Type Parameters + +#### T + +`T` + +#### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) + +### Parameters + +#### initialValue + +`NonFunction`\<`T`\> + +#### actions + +[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> + +### Returns + +[`Store`](../classes/Store.md)\<`T`, `TActions`\> + +### Example + +```tsx +const counterStore = useCreateStore({ count: 0 }) +``` diff --git a/docs/framework/react/reference/functions/useField.md b/docs/framework/react/reference/functions/useField.md deleted file mode 100644 index b2c254eb3b..0000000000 --- a/docs/framework/react/reference/functions/useField.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -id: useField -title: useField ---- - -# Function: useField() - -```ts -function useField(opts): FieldApi; -``` - -Defined in: [packages/react-form/src/useField.tsx:106](https://github.com/TanStack/form/blob/main/packages/react-form/src/useField.tsx#L106) - -A hook for managing a field in a form. - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TPatentSubmitMeta - -`TPatentSubmitMeta` - -## Parameters - -### opts - -[`UseFieldOptions`](../interfaces/UseFieldOptions.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TPatentSubmitMeta`\> - -An object with field options. - -## Returns - -`FieldApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TPatentSubmitMeta`\> - -The `FieldApi` instance for the specified field. diff --git a/docs/framework/react/reference/functions/useFieldGroup.md b/docs/framework/react/reference/functions/useFieldGroup.md deleted file mode 100644 index 7c261ce914..0000000000 --- a/docs/framework/react/reference/functions/useFieldGroup.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -id: useFieldGroup -title: useFieldGroup ---- - -# Function: useFieldGroup() - -```ts -function useFieldGroup(opts): AppFieldExtendedReactFieldGroupApi; -``` - -Defined in: [packages/react-form/src/useFieldGroup.tsx:96](https://github.com/TanStack/form/blob/main/packages/react-form/src/useFieldGroup.tsx#L96) - -## Type Parameters - -### TFormData - -`TFormData` - -### TFieldGroupData - -`TFieldGroupData` - -### TFields - -`TFields` *extends* - \| `string` - \| \{ \[K in string \| number \| symbol\]: DeepKeysOfType\ \} - -### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TComponents - -`TComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> - -### TFormComponents - -`TFormComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> - -### TSubmitMeta - -`TSubmitMeta` = `never` - -## Parameters - -### opts - -#### defaultValues? - -`TFieldGroupData` - -#### fields - -`TFields` - -#### form - - \| `AppFieldExtendedReactFormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents`, `TFormComponents`\> - \| `AppFieldExtendedReactFieldGroupApi`\<`unknown`, `TFormData`, `string` \| `FieldsMap`\<`unknown`, `TFormData`\>, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `TSubmitMeta`, `TComponents`, `TFormComponents`\> - -#### formComponents - -`TFormComponents` - -#### onSubmitMeta? - -`TSubmitMeta` - -## Returns - -`AppFieldExtendedReactFieldGroupApi`\<`TFormData`, `TFieldGroupData`, `TFields`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents`, `TFormComponents`\> diff --git a/docs/framework/react/reference/functions/useForm.md b/docs/framework/react/reference/functions/useForm.md deleted file mode 100644 index 7368ec629f..0000000000 --- a/docs/framework/react/reference/functions/useForm.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -id: useForm -title: useForm ---- - -# Function: useForm() - -```ts -function useForm(opts?): ReactFormExtendedApi; -``` - -Defined in: [packages/react-form/src/useForm.tsx:174](https://github.com/TanStack/form/blob/main/packages/react-form/src/useForm.tsx#L174) - -A custom React Hook that returns an extended instance of the `FormApi` class. - -This API encapsulates all the necessary functionalities related to the form. It allows you to manage form state, handle submissions, and interact with form fields - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` - -## Parameters - -### opts? - -`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -## Returns - -[`ReactFormExtendedApi`](../type-aliases/ReactFormExtendedApi.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> diff --git a/docs/framework/react/reference/functions/useFormGroup.md b/docs/framework/react/reference/functions/useFormGroup.md deleted file mode 100644 index 8313e2be6f..0000000000 --- a/docs/framework/react/reference/functions/useFormGroup.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -id: useFormGroup -title: useFormGroup ---- - -# Function: useFormGroup() - -```ts -function useFormGroup(opts): FormGroupApi; -``` - -Defined in: [packages/react-form/src/useFormGroup.tsx:113](https://github.com/TanStack/form/blob/main/packages/react-form/src/useFormGroup.tsx#L113) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Parameters - -### opts - -`FormGroupApiOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Returns - -`FormGroupApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> diff --git a/docs/framework/react/reference/functions/useSelector.md b/docs/framework/react/reference/functions/useSelector.md index 27b8b52788..75f88ea1bb 100644 --- a/docs/framework/react/reference/functions/useSelector.md +++ b/docs/framework/react/reference/functions/useSelector.md @@ -3,8 +3,6 @@ id: useSelector title: useSelector --- -# Function: useSelector() - ```ts function useSelector( source, @@ -12,7 +10,7 @@ function useSelector( options?): TSelected; ``` -Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.1.0\_react@19.1.0\_\_react@19.1.0/node\_modules/@tanstack/react-store/dist/useSelector.d.ts:31 +Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.2.8\_react@19.2.8\_\_react@19.2.8/node\_modules/@tanstack/react-store/dist/useSelector.d.ts:31 Selects a slice of state from an atom or store and subscribes the component to that selection. @@ -45,7 +43,7 @@ Omit the selector to subscribe to the whole value. ### options? -`UseSelectorOptions`\<`TSelected`\> +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TSelected`\> ## Returns diff --git a/docs/framework/react/reference/functions/useStore.md b/docs/framework/react/reference/functions/useStore.md new file mode 100644 index 0000000000..e6fa65613d --- /dev/null +++ b/docs/framework/react/reference/functions/useStore.md @@ -0,0 +1,62 @@ +--- +id: _useStore +title: _useStore +--- + +```ts +function _useStore( + store, + selector, + options?): [TSelected, [TActions] extends [never] ? (updater) => void : TActions]; +``` + +Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.2.8\_react@19.2.8\_\_react@19.2.8/node\_modules/@tanstack/react-store/dist/\_useStore.d.ts:22 + +Experimental combined read+write hook for stores, mirroring useAtom's tuple +pattern. + +Returns `[selected, actions]` when the store has an actions factory, or +`[selected, setState]` for plain stores. + +## Type Parameters + +### TState + +`TState` + +### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) + +### TSelected + +`TSelected` = `NoInfer`\<`TState`\> + +## Parameters + +### store + +[`Store`](../classes/Store.md)\<`TState`, `TActions`\> + +### selector + +(`state`) => `TSelected` + +### options? + +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TSelected`\> + +## Returns + +\[`TSelected`, \[`TActions`\] *extends* \[`never`\] ? (`updater`) => `void` : `TActions`\] + +## Example + +```tsx +// Store with actions +const [cats, { addCat }] = _useStore(petStore, (s) => s.cats) + +// Store without actions +const [count, setState] = _useStore(plainStore, (s) => s) +setState((prev) => prev + 1) +``` diff --git a/docs/framework/react/reference/index.md b/docs/framework/react/reference/index.md index 199f47fb57..a148f8acaa 100644 --- a/docs/framework/react/reference/index.md +++ b/docs/framework/react/reference/index.md @@ -3,39 +3,102 @@ id: "@tanstack/react-form" title: "@tanstack/react-form" --- -# @tanstack/react-form +## Classes + +- [ReadonlyStore](classes/ReadonlyStore.md) +- [Store](classes/Store.md) ## Interfaces -- [ReactFormApi](interfaces/ReactFormApi.md) -- [UseFieldOptions](interfaces/UseFieldOptions.md) -- [UseFieldOptionsBound](interfaces/UseFieldOptionsBound.md) -- [WithFieldGroupProps](interfaces/WithFieldGroupProps.md) -- [WithFormProps](interfaces/WithFormProps.md) +- [AppFormHookResult](interfaces/AppFormHookResult.md) +- [Atom](interfaces/Atom.md) +- [AtomOptions](interfaces/AtomOptions.md) +- [BaseAtom](interfaces/BaseAtom.md) +- [CreateFormHookOptions](interfaces/CreateFormHookOptions.md) +- [FieldBrandHelper](interfaces/FieldBrandHelper.md) +- [FieldComponentHelper](interfaces/FieldComponentHelper.md) +- [FieldGroupApi](interfaces/FieldGroupApi.md) +- [FieldGroupArrayFieldComponent](interfaces/FieldGroupArrayFieldComponent.md) +- [FieldGroupDefinition](interfaces/FieldGroupDefinition.md) +- [FieldGroupFieldComponent](interfaces/FieldGroupFieldComponent.md) +- [FormHookHelpers](interfaces/FormHookHelpers.md) +- [InternalBaseAtom](interfaces/InternalBaseAtom.md) +- [InternalReadonlyAtom](interfaces/InternalReadonlyAtom.md) +- [InteropSubscribable](interfaces/InteropSubscribable.md) +- [ReactFormComponentMap](interfaces/ReactFormComponentMap.md) +- [ReactFormFieldProps](interfaces/ReactFormFieldProps.md) +- [ReactFormGroupApi](interfaces/ReactFormGroupApi.md) +- [ReactFormGroupComponent](interfaces/ReactFormGroupComponent.md) +- [ReactFormGroupFieldComponent](interfaces/ReactFormGroupFieldComponent.md) +- [ReactFormGroupProps](interfaces/ReactFormGroupProps.md) +- [ReactTanStackFormComponents](interfaces/ReactTanStackFormComponents.md) +- [Readable](interfaces/Readable.md) +- [ReadonlyAtom](interfaces/ReadonlyAtom.md) +- [Subscribable](interfaces/Subscribable.md) +- [SubscribeProps](interfaces/SubscribeProps.md) +- [Subscription](interfaces/Subscription.md) +- [UseSelectorOptions](interfaces/UseSelectorOptions.md) ## Type Aliases -- [FieldComponent](type-aliases/FieldComponent.md) -- [FormGroupComponent](type-aliases/FormGroupComponent.md) -- [LensFieldComponent](type-aliases/LensFieldComponent.md) -- [ReactFormExtendedApi](type-aliases/ReactFormExtendedApi.md) -- [ServerFormState](type-aliases/ServerFormState.md) -- [UseField](type-aliases/UseField.md) -- [UseFormGroup](type-aliases/UseFormGroup.md) +- [AnyAtom](type-aliases/AnyAtom.md) +- [AnyFieldGroupApi](type-aliases/AnyFieldGroupApi.md) +- [AnyReactFormApi](type-aliases/AnyReactFormApi.md) +- [AnyReactFormComponentMap](type-aliases/AnyReactFormComponentMap.md) +- [AppFormComponent](type-aliases/AppFormComponent.md) +- [DefaultReactFormComponentMap](type-aliases/DefaultReactFormComponentMap.md) +- [DefineFieldGroupFn](type-aliases/DefineFieldGroupFn.md) +- [FieldGroupFieldBindingsOf](type-aliases/FieldGroupFieldBindingsOf.md) +- [FieldGroupFieldComponentsOf](type-aliases/FieldGroupFieldComponentsOf.md) +- [FieldGroupFieldsOf](type-aliases/FieldGroupFieldsOf.md) +- [FieldGroupForm](type-aliases/FieldGroupForm.md) +- [FieldGroupFormState](type-aliases/FieldGroupFormState.md) +- [FieldGroupSubscribeComponent](type-aliases/FieldGroupSubscribeComponent.md) +- [FieldGroupSubscribeProps](type-aliases/FieldGroupSubscribeProps.md) +- [FieldGroupWithFieldsFn](type-aliases/FieldGroupWithFieldsFn.md) +- [Observer](type-aliases/Observer.md) +- [ReactAppFormApi](type-aliases/ReactAppFormApi.md) +- [ReactComponentTree](type-aliases/ReactComponentTree.md) +- [ReactFieldApi](type-aliases/ReactFieldApi.md) +- [ReactFieldGroup](type-aliases/ReactFieldGroup.md) +- [ReactFormApi](type-aliases/ReactFormApi.md) +- [ReactFormArrayFieldComponent](type-aliases/ReactFormArrayFieldComponent.md) +- [ReactFormFieldComponent](type-aliases/ReactFormFieldComponent.md) +- [ReactFormGroupArrayFieldComponent](type-aliases/ReactFormGroupArrayFieldComponent.md) +- [ReactFormGroupSubscribeComponent](type-aliases/ReactFormGroupSubscribeComponent.md) +- [ReactFormGroupSubscribeProps](type-aliases/ReactFormGroupSubscribeProps.md) +- [ReactFormSubscribeComponent](type-aliases/ReactFormSubscribeComponent.md) +- [ReactFormSubscribeProps](type-aliases/ReactFormSubscribeProps.md) +- [ReactFormType](type-aliases/ReactFormType.md) +- [Selection](type-aliases/Selection.md) +- [StoreAction](type-aliases/StoreAction.md) +- [StoreActionMap](type-aliases/StoreActionMap.md) +- [StoreActionsFactory](type-aliases/StoreActionsFactory.md) +- [SubscribeSource](type-aliases/SubscribeSource.md) +- [UseAppFormHook](type-aliases/UseAppFormHook.md) +- [UseFormHook](type-aliases/UseFormHook.md) ## Variables -- [Field](variables/Field.md) -- [FormGroup](variables/FormGroup.md) -- [useIsomorphicLayoutEffect](variables/useIsomorphicLayoutEffect.md) +- [defineFieldGroup](variables/defineFieldGroup.md) +- [useForm](variables/useForm.md) - [~~useStore~~](variables/useStore.md) ## Functions +- [\_useStore](functions/useStore.md) +- [batch](functions/batch.md) +- [createAsyncAtom](functions/createAsyncAtom.md) +- [createAtom](functions/createAtom.md) - [createFormHook](functions/createFormHook.md) -- [createFormHookContexts](functions/createFormHookContexts.md) -- [useField](functions/useField.md) -- [useFieldGroup](functions/useFieldGroup.md) -- [useForm](functions/useForm.md) -- [useFormGroup](functions/useFormGroup.md) +- [createStore](functions/createStore.md) +- [createStoreContext](functions/createStoreContext.md) +- [flush](functions/flush.md) +- [getFormHookHelpers](functions/getFormHookHelpers.md) +- [shallow](functions/shallow.md) +- [Subscribe](functions/Subscribe.md) +- [toObserver](functions/toObserver.md) +- [useAtom](functions/useAtom.md) +- [useCreateAtom](functions/useCreateAtom.md) +- [useCreateStore](functions/useCreateStore.md) - [useSelector](functions/useSelector.md) diff --git a/docs/framework/react/reference/interfaces/AppFormHookResult.md b/docs/framework/react/reference/interfaces/AppFormHookResult.md new file mode 100644 index 0000000000..e6151beb0a --- /dev/null +++ b/docs/framework/react/reference/interfaces/AppFormHookResult.md @@ -0,0 +1,170 @@ +--- +id: AppFormHookResult +title: AppFormHookResult +--- + +Defined in: [packages/react-form/src/AppForm/createFormHookTypes.public.ts:128](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/createFormHookTypes.public.ts#L128) + +App Form hooks and helpers bound to the components registered with +`createFormHook`. + +## Type Parameters + +### TComponents + +`TComponents` *extends* [`AnyReactFormComponentMap`](../type-aliases/AnyReactFormComponentMap.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### appFormOptions + +```ts +appFormOptions: FormOptionsApi; +``` + +Defined in: [packages/react-form/src/AppForm/createFormHookTypes.public.ts:155](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/createFormHookTypes.public.ts#L155) + +Defines reusable form options that retain the components registered with +`createFormHook`. + +Use the result with `ReactFormType` when a child component needs the type +of one known App Form, including its registered field and form components. + +#### Example + +```tsx +const profileOptions = appFormOptions({ + defaultValues: { name: '' }, +}) + +type ProfileForm = ReactFormType + +function NameField({ form }: { form: ProfileForm }) { + return ( + + {(field) => } + + ) +} +``` + +*** + +### defineAppFieldGroup + +```ts +defineAppFieldGroup: DefineFieldGroupFn; +``` + +Defined in: [packages/react-form/src/AppForm/createFormHookTypes.public.ts:194](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/createFormHookTypes.public.ts#L194) + +Defines a field group whose fields expose the field components registered +with `createFormHook`. + +#### Example + +```tsx +const { defineAppFieldGroup } = createFormHook({ + fieldComponents: { + TextField, + }, + formComponents: {}, +}) + +const passwordFieldGroup = defineAppFieldGroup(({ strict }) => ({ + password: strict(), + confirmPassword: strict(), +})) + +interface PasswordFieldsProps { + fields: typeof passwordFieldGroup.fields +} + +function PasswordFields({ fields }: PasswordFieldsProps) { + return ( + <> + + {(field) => } + + + {(field) => ( + + )} + + + ) +} +``` + +*** + +### useAppForm + +```ts +useAppForm: UseAppFormHook; +``` + +Defined in: [packages/react-form/src/AppForm/createFormHookTypes.public.ts:219](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/createFormHookTypes.public.ts#L219) + +Creates a React form API extended with the field and form components +registered with `createFormHook`. + +Form data, validators, and submission results are inferred from the passed +options. + +#### Example + +```tsx +function ProfileForm() { + const form = useAppForm({ + defaultValues: { name: '' }, + }) + + return ( + + + {(field) => } + + + ) +} +``` + +*** + +### useFormContext + +```ts +useFormContext: () => ReactAppFormApi; +``` + +Defined in: [packages/react-form/src/AppForm/createFormHookTypes.public.ts:243](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/createFormHookTypes.public.ts#L243) + +Reads the current App Form API from the nearest `form.AppForm` provider. + +Use this hook inside form components registered with `createFormHook`. It +throws when called outside a `form.AppForm` subtree. + +#### Returns + +[`ReactAppFormApi`](../type-aliases/ReactAppFormApi.md)\<`any`, `any`, `TComponents`\> + +#### Example + +```tsx +function SubmitButton({ label }: { label: string }) { + const form = useFormContext() + + return ( + state.isSubmitting}> + {(isSubmitting) => ( + + )} + + ) +} +``` diff --git a/docs/framework/react/reference/interfaces/Atom.md b/docs/framework/react/reference/interfaces/Atom.md new file mode 100644 index 0000000000..202040f845 --- /dev/null +++ b/docs/framework/react/reference/interfaces/Atom.md @@ -0,0 +1,60 @@ +--- +id: Atom +title: Atom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:29 + +## Extends + +- [`BaseAtom`](BaseAtom.md)\<`T`\> + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`get`](BaseAtom.md#get) + +*** + +### set + +```ts +set: (fn) => void & (value) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:31 + +Sets the value of the atom using a function. + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`subscribe`](BaseAtom.md#subscribe) diff --git a/docs/framework/react/reference/interfaces/AtomOptions.md b/docs/framework/react/reference/interfaces/AtomOptions.md new file mode 100644 index 0000000000..55a18d2a25 --- /dev/null +++ b/docs/framework/react/reference/interfaces/AtomOptions.md @@ -0,0 +1,36 @@ +--- +id: AtomOptions +title: AtomOptions +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:33 + +## Type Parameters + +### T + +`T` + +## Properties + +### compare? + +```ts +optional compare?: (prev, next) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:34 + +#### Parameters + +##### prev + +`T` + +##### next + +`T` + +#### Returns + +`boolean` diff --git a/docs/framework/react/reference/interfaces/BaseAtom.md b/docs/framework/react/reference/interfaces/BaseAtom.md new file mode 100644 index 0000000000..7eb9467768 --- /dev/null +++ b/docs/framework/react/reference/interfaces/BaseAtom.md @@ -0,0 +1,53 @@ +--- +id: BaseAtom +title: BaseAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:22 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\>.[`Readable`](Readable.md)\<`T`\> + +## Extended by + +- [`Atom`](Atom.md) +- [`ReadonlyAtom`](ReadonlyAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`Readable`](Readable.md).[`get`](Readable.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/react/reference/interfaces/CreateFormHookOptions.md b/docs/framework/react/reference/interfaces/CreateFormHookOptions.md new file mode 100644 index 0000000000..a1c5cdb85a --- /dev/null +++ b/docs/framework/react/reference/interfaces/CreateFormHookOptions.md @@ -0,0 +1,164 @@ +--- +id: CreateFormHookOptions +title: CreateFormHookOptions +--- + +Defined in: [packages/react-form/src/AppForm/createFormHookTypes.public.ts:56](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/createFormHookTypes.public.ts#L56) + +Configures the components and reusable defaults returned by +`createFormHook`. + +Default objects are resolved by form core before the corresponding +usage-site options. Non-listener properties always take precedence, +including when explicitly set to `undefined`. Listener arrays follow the +configured `listenersMerge` strategy. + +## Example + +```tsx +const { useAppForm } = createFormHook({ + formComponents: { + actions: { + SubmitButton, + }, + }, + fieldComponents: { + inputs: { + TextField, + }, + }, + defaultFormOptions: { + errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred, + }, + defaultFieldOptions: { + errorBoundary: true, + }, +}) + +// Registered namespaces retain their shape on the form and field APIs: +// +// +``` + +## Extends + +- [`ReactFormComponentMap`](ReactFormComponentMap.md)\<`TFormComponents`, `TFieldComponents`\> + +## Type Parameters + +### TFormComponents + +`TFormComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +Library-managed. Do not specify explicitly. + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### defaultFieldOptions? + +```ts +optional defaultFieldOptions?: DefaultFieldOptions; +``` + +Defined in: [packages/react-form/src/AppForm/createFormHookTypes.public.ts:89](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/createFormHookTypes.public.ts#L89) + +Defaults for every field and array-field component owned by the form. + +Non-listener options passed to the component override these defaults, +including when explicitly set to `undefined`. Listener arrays follow +`listenersMerge`. This includes `group.Field` and `group.ArrayField`. + +#### Example + +```tsx +defaultFieldOptions: { + errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred, +}, +``` + +*** + +### defaultFormGroupOptions? + +```ts +optional defaultFormGroupOptions?: DefaultFormGroupOptions; +``` + +Defined in: [packages/react-form/src/AppForm/createFormHookTypes.public.ts:105](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/createFormHookTypes.public.ts#L105) + +Defaults for every `form.FormGroup` component. + +Options passed to the component override these defaults, including when +an option is explicitly `undefined`. + +#### Example + +```tsx +defaultFormGroupOptions: { + onSubmitInvalid: ({ groupApi }) => { + console.error('Invalid group', groupApi.name) + }, +}, +``` + +*** + +### defaultFormOptions? + +```ts +optional defaultFormOptions?: DefaultFormOptions; +``` + +Defined in: [packages/react-form/src/AppForm/createFormHookTypes.public.ts:74](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/createFormHookTypes.public.ts#L74) + +Defaults for every form created by `useAppForm`. + +Non-listener options passed to `useAppForm` override these defaults, +including when explicitly set to `undefined`. Listener arrays follow +`listenersMerge`. + +#### Example + +```tsx +defaultFormOptions: { + errorVisibility: ({ state }) => state.submissionAttempts > 0, +}, +``` + +*** + +### fieldComponents + +```ts +fieldComponents: TFieldComponents; +``` + +Defined in: [packages/react-form/src/AppForm/componentMap.public.ts:31](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/componentMap.public.ts#L31) + +Components and component namespaces exposed on each App Field API. + +#### Inherited from + +[`ReactFormComponentMap`](ReactFormComponentMap.md).[`fieldComponents`](ReactFormComponentMap.md#fieldcomponents) + +*** + +### formComponents + +```ts +formComponents: TFormComponents; +``` + +Defined in: [packages/react-form/src/AppForm/componentMap.public.ts:29](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/componentMap.public.ts#L29) + +Components and component namespaces exposed on each App Form API. + +#### Inherited from + +[`ReactFormComponentMap`](ReactFormComponentMap.md).[`formComponents`](ReactFormComponentMap.md#formcomponents) diff --git a/docs/framework/react/reference/interfaces/FieldBrandHelper.md b/docs/framework/react/reference/interfaces/FieldBrandHelper.md new file mode 100644 index 0000000000..5eba86bdf1 --- /dev/null +++ b/docs/framework/react/reference/interfaces/FieldBrandHelper.md @@ -0,0 +1,90 @@ +--- +id: FieldBrandHelper +title: FieldBrandHelper +--- + +Defined in: [packages/react-form/src/AppForm/getFormHookHelpers.public.ts:162](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/getFormHookHelpers.public.ts#L162) + +Adds field-value compatibility metadata to components without wrapping them +or changing their runtime props. + +## Properties + +### loose + +```ts +loose: () => (Component) => LooseBrandedFieldComponent; +``` + +Defined in: [packages/react-form/src/AppForm/getFormHookHelpers.public.ts:210](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/getFormHookHelpers.public.ts#L210) + +Brands a component for fields whose value type is assignable to +`TValue`. + +The returned value is the original component at runtime. Unlike +`fieldComponent.loose`, this helper does not inject a field API prop. + +#### Type Parameters + +##### TValue + +`TValue` + +The field value type accepted by the component. + +#### Returns + +\<`TComponent`\>(`Component`) => `LooseBrandedFieldComponent`\<`TComponent`, `TValue`\> + +#### Example + +```tsx +import { getFormHookHelpers } from '@tanstack/react-form' + +function FieldDescription() { + return Changes are saved automatically. +} + +const { fieldBrand } = getFormHookHelpers() +const Description = fieldBrand.loose()(FieldDescription) +``` + +*** + +### strict + +```ts +strict: () => (Component) => StrictBrandedFieldComponent; +``` + +Defined in: [packages/react-form/src/AppForm/getFormHookHelpers.public.ts:184](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/getFormHookHelpers.public.ts#L184) + +Brands a component for fields whose value type exactly matches `TValue`. + +The returned value is the original component at runtime. Unlike +`fieldComponent.strict`, this helper does not inject a field API prop. + +#### Type Parameters + +##### TValue + +`TValue` + +The exact field value type that exposes the component. + +#### Returns + +\<`TComponent`\>(`Component`) => `StrictBrandedFieldComponent`\<`TComponent`, `TValue`\> + +#### Example + +```tsx +import { getFormHookHelpers } from '@tanstack/react-form' + +function Adornment() { + return Required +} + +const { fieldBrand } = getFormHookHelpers() +const StringAdornment = fieldBrand.strict()(Adornment) +``` diff --git a/docs/framework/react/reference/interfaces/FieldComponentHelper.md b/docs/framework/react/reference/interfaces/FieldComponentHelper.md new file mode 100644 index 0000000000..78f57370db --- /dev/null +++ b/docs/framework/react/reference/interfaces/FieldComponentHelper.md @@ -0,0 +1,161 @@ +--- +id: FieldComponentHelper +title: FieldComponentHelper +--- + +Defined in: [packages/react-form/src/AppForm/getFormHookHelpers.public.ts:68](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/getFormHookHelpers.public.ts#L68) + +Wraps components that accept a field API prop so App Form can supply that +prop from field context. + +## Properties + +### loose + +```ts +loose: (Component, fieldPropKey) => LooseInjectedFieldComponent; +``` + +Defined in: [packages/react-form/src/AppForm/getFormHookHelpers.public.ts:147](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/getFormHookHelpers.public.ts#L147) + +Wraps a component for fields whose value type is assignable to the value +type accepted by its field API prop. + +The returned component omits `fieldPropKey` from its public props and reads +that field API from the nearest App Form field context. Use this mode for a +component that intentionally supports a broader range of field values. + +#### Type Parameters + +##### TComponent + +`TComponent` *extends* `AnyFieldComponent` + +Library-managed. Do not specify explicitly. + +##### TProps + +`TProps` = `PropsOf`\<`TComponent`\> + +Library-managed. Do not specify explicitly. + +##### TFieldPropKey + +`TFieldPropKey` *extends* `string` \| `number` \| `symbol` = `FieldValuePropKeys`\<`TProps`\> + +Library-managed. Do not specify explicitly. + +#### Parameters + +##### Component + +`TComponent` + +The component whose field API prop should be injected. + +##### fieldPropKey + +`TFieldPropKey` + +The prop that accepts the current field API. + +#### Returns + +`LooseInjectedFieldComponent`\<`TComponent`, `TProps`, `TFieldPropKey`\> + +#### Example + +```tsx +import { getFormHookHelpers } from '@tanstack/react-form' +import type { AnyFieldApi } from '@tanstack/react-form' + +function FieldErrors({ field }: { field: AnyFieldApi }) { + return {field.errors.map((error) => error.message).join(', ')} +} + +const { fieldComponent } = getFormHookHelpers() +const Errors = fieldComponent.loose(FieldErrors, 'field') +``` + +*** + +### strict + +```ts +strict: (Component, fieldPropKey) => StrictInjectedFieldComponent; +``` + +Defined in: [packages/react-form/src/AppForm/getFormHookHelpers.public.ts:110](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/getFormHookHelpers.public.ts#L110) + +Wraps a component for fields whose value type exactly matches the value +type of its field API prop. + +The returned component omits `fieldPropKey` from its public props and reads +that field API from the nearest App Form field context. It must be rendered +beneath an App Form or field-group `Field` or `ArrayField` component. + +#### Type Parameters + +##### TComponent + +`TComponent` *extends* `AnyFieldComponent` + +Library-managed. Do not specify explicitly. + +##### TProps + +`TProps` = `PropsOf`\<`TComponent`\> + +Library-managed. Do not specify explicitly. + +##### TFieldPropKey + +`TFieldPropKey` *extends* `string` \| `number` \| `symbol` = `FieldValuePropKeys`\<`TProps`\> + +Library-managed. Do not specify explicitly. + +#### Parameters + +##### Component + +`TComponent` + +The component whose field API prop should be injected. + +##### fieldPropKey + +`TFieldPropKey` + +The prop that accepts the current field API. + +#### Returns + +`StrictInjectedFieldComponent`\<`TComponent`, `TProps`, `TFieldPropKey`\> + +#### Example + +```tsx +import { getFormHookHelpers } from '@tanstack/react-form' +import type { FieldWithValue } from '@tanstack/react-form' + +function TextInput({ + field, + label, +}: { + field: FieldWithValue + label: string +}) { + return ( + + ) +} + +const { fieldComponent } = getFormHookHelpers() +const TextField = fieldComponent.strict(TextInput, 'field') +``` diff --git a/docs/framework/react/reference/interfaces/FieldGroupApi.md b/docs/framework/react/reference/interfaces/FieldGroupApi.md new file mode 100644 index 0000000000..9adec65cbb --- /dev/null +++ b/docs/framework/react/reference/interfaces/FieldGroupApi.md @@ -0,0 +1,60 @@ +--- +id: FieldGroupApi +title: FieldGroupApi +--- + +Defined in: [packages/react-form/src/FieldGroup/FieldGroupApi.public.ts:175](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/FieldGroupApi.public.ts#L175) + +## Extends + +- `FormApiFieldMethods`\<`TFieldData`\>.`FormApiArrayMethods`\<`TFieldData`\> + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +## Properties + +### ArrayField + +```ts +ArrayField: FieldGroupArrayFieldComponent; +``` + +Defined in: [packages/react-form/src/FieldGroup/FieldGroupApi.public.ts:182](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/FieldGroupApi.public.ts#L182) + +*** + +### atom + +```ts +atom: ReadonlyAtom; +``` + +Defined in: [packages/react-form/src/FieldGroup/FieldGroupApi.public.ts:180](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/FieldGroupApi.public.ts#L180) + +*** + +### Field + +```ts +Field: FieldGroupFieldComponent; +``` + +Defined in: [packages/react-form/src/FieldGroup/FieldGroupApi.public.ts:181](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/FieldGroupApi.public.ts#L181) + +*** + +### Subscribe + +```ts +Subscribe: FieldGroupSubscribeComponent; +``` + +Defined in: [packages/react-form/src/FieldGroup/FieldGroupApi.public.ts:183](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/FieldGroupApi.public.ts#L183) diff --git a/docs/framework/react/reference/interfaces/FieldGroupArrayFieldComponent.md b/docs/framework/react/reference/interfaces/FieldGroupArrayFieldComponent.md new file mode 100644 index 0000000000..0ed528081b --- /dev/null +++ b/docs/framework/react/reference/interfaces/FieldGroupArrayFieldComponent.md @@ -0,0 +1,78 @@ +--- +id: FieldGroupArrayFieldComponent +title: FieldGroupArrayFieldComponent +--- + +Defined in: [packages/react-form/src/FieldGroup/FieldGroupApi.public.ts:85](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/FieldGroupApi.public.ts#L85) + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +```ts +FieldGroupArrayFieldComponent(props): ReactNode; +``` + +Defined in: [packages/react-form/src/FieldGroup/FieldGroupApi.public.ts:129](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/FieldGroupApi.public.ts#L129) + +Renders an array field from this field group. + +The field name is automatically connected to the form section where the +field group is used. + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `never` + +## Parameters + +### props + +[`ReactFormFieldProps`](ReactFormFieldProps.md)\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\>, `ValidationIssue`, `unknown`, `FormErrorTypes`\<`ValidationIssue`, `ValidationIssue`\>, `TFieldComponents`\> + +## Returns + +`ReactNode` + +## Example + +```tsx +const contactFieldGroup = defineFieldGroup(({ strict }) => ({ + emails: strict>(), +})) + +interface ContactFieldsProps { + fields: typeof contactFieldGroup.fields +} + +function ContactFields({ fields }: ContactFieldsProps) { + return ( + + {(emails) => ( + <> + {emails.value.map((_, index) => ( + + {(field) => ( + + field.handleChange(event.target.value) + } + /> + )} + + ))} + + )} + + ) +} +``` diff --git a/docs/framework/react/reference/interfaces/FieldGroupDefinition.md b/docs/framework/react/reference/interfaces/FieldGroupDefinition.md new file mode 100644 index 0000000000..15fdddc647 --- /dev/null +++ b/docs/framework/react/reference/interfaces/FieldGroupDefinition.md @@ -0,0 +1,103 @@ +--- +id: FieldGroupDefinition +title: FieldGroupDefinition +--- + +Defined in: [packages/react-form/src/FieldGroup/withFields.public.ts:118](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/withFields.public.ts#L118) + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +## Properties + +### bindComponent + +```ts +bindComponent: FieldGroupWithFieldsFn>; +``` + +Defined in: [packages/react-form/src/FieldGroup/withFields.public.ts:191](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/withFields.public.ts#L191) + +Binds a component's field-group API prop to concrete paths in a parent +form. + +The returned component accepts the original component props except for the +injected field-group API prop and adds a `form` prop. When every virtual +field name is already a compatible form path, those paths bind +automatically when the bindings prop is omitted. A complete bindings map +can still reroute them. Otherwise, the injected prop name is reused for the +required virtual-to-concrete field binding map. + +#### Example + +```tsx +const passwordFieldGroup = defineFieldGroup(({ strict }) => ({ + password: strict(), + confirmPassword: strict(), +})) + +interface PasswordFieldsProps { + fields: typeof passwordFieldGroup.fields + legend: string +} + +function PasswordFields({ fields, legend }: PasswordFieldsProps) { + return ( +
    + {legend} + + {(field) => ( + field.handleChange(event.target.value)} + /> + )} + + + {(field) => ( + field.handleChange(event.target.value)} + /> + )} + +
    + ) +} + +const PasswordSection = passwordFieldGroup.bindComponent( + PasswordFields, + 'fields', +) + + +``` + +*** + +### fields + +```ts +fields: ReactFieldGroup; +``` + +Defined in: [packages/react-form/src/FieldGroup/withFields.public.ts:126](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/withFields.public.ts#L126) + +The virtual field-group API injected into the component passed to +`bindComponent`. diff --git a/docs/framework/react/reference/interfaces/FieldGroupFieldComponent.md b/docs/framework/react/reference/interfaces/FieldGroupFieldComponent.md new file mode 100644 index 0000000000..887cfaad1c --- /dev/null +++ b/docs/framework/react/reference/interfaces/FieldGroupFieldComponent.md @@ -0,0 +1,81 @@ +--- +id: FieldGroupFieldComponent +title: FieldGroupFieldComponent +--- + +Defined in: [packages/react-form/src/FieldGroup/FieldGroupApi.public.ts:20](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/FieldGroupApi.public.ts#L20) + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +```ts +FieldGroupFieldComponent(props): ReactNode; +``` + +Defined in: [packages/react-form/src/FieldGroup/FieldGroupApi.public.ts:67](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/FieldGroupApi.public.ts#L67) + +Renders a field from this field group. + +The field name is automatically connected to the form section where the +field group is used. + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `string` + +## Parameters + +### props + +[`ReactFormFieldProps`](ReactFormFieldProps.md)\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\>, `ValidationIssue`, `unknown`, `FormErrorTypes`\<`ValidationIssue`, `ValidationIssue`\>, `TFieldComponents`\> + +## Returns + +`ReactNode` + +## Example + +```tsx +const passwordFieldGroup = defineFieldGroup(({ strict }) => ({ + password: strict(), + confirmPassword: strict(), +})) + +interface PasswordFieldsProps { + fields: typeof passwordFieldGroup.fields +} + +function PasswordFields({ fields }: PasswordFieldsProps) { + return ( + <> + + {(field) => ( + field.handleChange(event.target.value)} + /> + )} + + + {(field) => ( + field.handleChange(event.target.value)} + /> + )} + + + ) +} +``` diff --git a/docs/framework/react/reference/interfaces/FormHookHelpers.md b/docs/framework/react/reference/interfaces/FormHookHelpers.md new file mode 100644 index 0000000000..7dbc7748a9 --- /dev/null +++ b/docs/framework/react/reference/interfaces/FormHookHelpers.md @@ -0,0 +1,45 @@ +--- +id: FormHookHelpers +title: FormHookHelpers +--- + +Defined in: [packages/react-form/src/AppForm/getFormHookHelpers.public.ts:230](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/getFormHookHelpers.public.ts#L230) + +Helpers for preparing value-compatible field components for registration +with `createFormHook`. + +Use `fieldComponent` when the current field API should be injected into a +component prop. Use `fieldBrand` when the component should retain its +original runtime props. + +## Example + +```tsx +import { getFormHookHelpers } from '@tanstack/react-form' + +const { fieldBrand, fieldComponent } = getFormHookHelpers() +``` + +## Properties + +### fieldBrand + +```ts +fieldBrand: FieldBrandHelper; +``` + +Defined in: [packages/react-form/src/AppForm/getFormHookHelpers.public.ts:232](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/getFormHookHelpers.public.ts#L232) + +Brands components without wrapping them or injecting a field API prop. + +*** + +### fieldComponent + +```ts +fieldComponent: FieldComponentHelper; +``` + +Defined in: [packages/react-form/src/AppForm/getFormHookHelpers.public.ts:234](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/getFormHookHelpers.public.ts#L234) + +Wraps components and injects the current field API into a selected prop. diff --git a/docs/framework/react/reference/interfaces/InternalBaseAtom.md b/docs/framework/react/reference/interfaces/InternalBaseAtom.md new file mode 100644 index 0000000000..995d4140bc --- /dev/null +++ b/docs/framework/react/reference/interfaces/InternalBaseAtom.md @@ -0,0 +1,86 @@ +--- +id: InternalBaseAtom +title: InternalBaseAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:23 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\>.[`Readable`](Readable.md)\<`T`\> + +## Extended by + +- [`InternalReadonlyAtom`](InternalReadonlyAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### \_snapshot + +```ts +_snapshot: T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:25 + +**`Internal`** + +*** + +### \_update + +```ts +_update: (getValue?) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:27 + +**`Internal`** + +#### Parameters + +##### getValue? + +`T` \| ((`snapshot`) => `T`) + +#### Returns + +`boolean` + +*** + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`Readable`](Readable.md).[`get`](Readable.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/react/reference/interfaces/InternalReadonlyAtom.md b/docs/framework/react/reference/interfaces/InternalReadonlyAtom.md new file mode 100644 index 0000000000..e1d575a47c --- /dev/null +++ b/docs/framework/react/reference/interfaces/InternalReadonlyAtom.md @@ -0,0 +1,170 @@ +--- +id: InternalReadonlyAtom +title: InternalReadonlyAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:37 + +## Extends + +- [`InternalBaseAtom`](InternalBaseAtom.md)\<`T`\>.`ReactiveNode` + +## Type Parameters + +### T + +`T` + +## Properties + +### \_snapshot + +```ts +_snapshot: T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:25 + +**`Internal`** + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`_snapshot`](InternalBaseAtom.md#_snapshot) + +*** + +### \_update + +```ts +_update: (getValue?) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:27 + +**`Internal`** + +#### Parameters + +##### getValue? + +`T` \| ((`snapshot`) => `T`) + +#### Returns + +`boolean` + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`_update`](InternalBaseAtom.md#_update) + +*** + +### deps? + +```ts +optional deps?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/alien.d.ts:3 + +#### Inherited from + +```ts +ReactiveNode.deps +``` + +*** + +### depsTail? + +```ts +optional depsTail?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/alien.d.ts:4 + +#### Inherited from + +```ts +ReactiveNode.depsTail +``` + +*** + +### flags + +```ts +flags: ReactiveFlags; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/alien.d.ts:7 + +#### Inherited from + +```ts +ReactiveNode.flags +``` + +*** + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`get`](InternalBaseAtom.md#get) + +*** + +### subs? + +```ts +optional subs?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/alien.d.ts:5 + +#### Inherited from + +```ts +ReactiveNode.subs +``` + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`subscribe`](InternalBaseAtom.md#subscribe) + +*** + +### subsTail? + +```ts +optional subsTail?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/alien.d.ts:6 + +#### Inherited from + +```ts +ReactiveNode.subsTail +``` diff --git a/docs/framework/react/reference/interfaces/InteropSubscribable.md b/docs/framework/react/reference/interfaces/InteropSubscribable.md new file mode 100644 index 0000000000..7fb35c3bd5 --- /dev/null +++ b/docs/framework/react/reference/interfaces/InteropSubscribable.md @@ -0,0 +1,36 @@ +--- +id: InteropSubscribable +title: InteropSubscribable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:5 + +## Extended by + +- [`Subscribable`](Subscribable.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### subscribe + +```ts +subscribe: (observer) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:6 + +#### Parameters + +##### observer + +[`Observer`](../type-aliases/Observer.md)\<`T`\> + +#### Returns + +[`Subscription`](Subscription.md) diff --git a/docs/framework/react/reference/interfaces/ReactFormApi.md b/docs/framework/react/reference/interfaces/ReactFormApi.md deleted file mode 100644 index f27c2340a4..0000000000 --- a/docs/framework/react/reference/interfaces/ReactFormApi.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -id: ReactFormApi -title: ReactFormApi ---- - -# Interface: ReactFormApi\ - -Defined in: [packages/react-form/src/useForm.tsx:25](https://github.com/TanStack/form/blob/main/packages/react-form/src/useForm.tsx#L25) - -Fields that are added onto the `FormAPI` from `@tanstack/form-core` and returned from `useForm` - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` - -## Properties - -### Field - -```ts -Field: FieldComponent; -``` - -Defined in: [packages/react-form/src/useForm.tsx:42](https://github.com/TanStack/form/blob/main/packages/react-form/src/useForm.tsx#L42) - -A React component to render form fields. With this, you can render and manage individual form fields. - -*** - -### FormGroup - -```ts -FormGroup: FormGroupComponent; -``` - -Defined in: [packages/react-form/src/useForm.tsx:56](https://github.com/TanStack/form/blob/main/packages/react-form/src/useForm.tsx#L56) - -*** - -### Subscribe() - -```ts -Subscribe: (props) => ReactNode | Promise; -``` - -Defined in: [packages/react-form/src/useForm.tsx:73](https://github.com/TanStack/form/blob/main/packages/react-form/src/useForm.tsx#L73) - -A `Subscribe` function that allows you to listen and react to changes in the form's state. It's especially useful when you need to execute side effects or render specific components in response to state updates. - -#### Type Parameters - -##### TSelected - -`TSelected` = `NoInfer`\<`FormState`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`\>\> - -#### Parameters - -##### props - -###### children - -`ReactNode` \| (`state`) => `ReactNode` - -###### selector? - -(`state`) => `TSelected` - -#### Returns - -`ReactNode` \| `Promise`\<`ReactNode`\> diff --git a/docs/framework/react/reference/interfaces/ReactFormComponentMap.md b/docs/framework/react/reference/interfaces/ReactFormComponentMap.md new file mode 100644 index 0000000000..12ddca3e21 --- /dev/null +++ b/docs/framework/react/reference/interfaces/ReactFormComponentMap.md @@ -0,0 +1,44 @@ +--- +id: ReactFormComponentMap +title: ReactFormComponentMap +--- + +Defined in: [packages/react-form/src/AppForm/componentMap.public.ts:24](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/componentMap.public.ts#L24) + +## Extended by + +- [`CreateFormHookOptions`](CreateFormHookOptions.md) + +## Type Parameters + +### TFormComponents + +`TFormComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +## Properties + +### fieldComponents + +```ts +fieldComponents: TFieldComponents; +``` + +Defined in: [packages/react-form/src/AppForm/componentMap.public.ts:31](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/componentMap.public.ts#L31) + +Components and component namespaces exposed on each App Field API. + +*** + +### formComponents + +```ts +formComponents: TFormComponents; +``` + +Defined in: [packages/react-form/src/AppForm/componentMap.public.ts:29](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/componentMap.public.ts#L29) + +Components and component namespaces exposed on each App Form API. diff --git a/docs/framework/react/reference/interfaces/ReactFormFieldProps.md b/docs/framework/react/reference/interfaces/ReactFormFieldProps.md new file mode 100644 index 0000000000..5fad8341e0 --- /dev/null +++ b/docs/framework/react/reference/interfaces/ReactFormFieldProps.md @@ -0,0 +1,64 @@ +--- +id: ReactFormFieldProps +title: ReactFormFieldProps +--- + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:115](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L115) + +## Extends + +- `FieldApiOptions`\<`TFieldData`, `TFieldName`, `TFieldValue`, `TFieldValidators`, `TGroupFieldError`, `TFormData`, `TFormErrorTypes`\> + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldName + +`TFieldName` + +### TFieldValue + +`TFieldValue` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFieldData`, `TFieldName`, `TFieldValue`\> + +### TGroupFieldError + +`TGroupFieldError` + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +## Properties + +### children + +```ts +children: (fieldApi) => ReactNode; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:137](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L137) + +#### Parameters + +##### fieldApi + +[`ReactFieldApi`](../type-aliases/ReactFieldApi.md)\<`TFieldName`, `TFieldValue`, `ToFieldError`\<`NoInfer`\<`TFieldValidators`\>, `TGroupFieldError`, `TFormErrorTypes`\>, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +#### Returns + +`ReactNode` diff --git a/docs/framework/react/reference/interfaces/ReactFormGroupApi.md b/docs/framework/react/reference/interfaces/ReactFormGroupApi.md new file mode 100644 index 0000000000..9db76cd580 --- /dev/null +++ b/docs/framework/react/reference/interfaces/ReactFormGroupApi.md @@ -0,0 +1,66 @@ +--- +id: ReactFormGroupApi +title: ReactFormGroupApi +--- + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:277](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L277) + +## Extends + +- `FormGroupApi`\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupErrorTypes`, `TFormErrorTypes`\> + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +## Properties + +### ArrayField + +```ts +ArrayField: ReactFormGroupArrayFieldComponent; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:298](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L298) + +*** + +### Field + +```ts +Field: ReactFormGroupFieldComponent; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:291](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L291) + +*** + +### Subscribe + +```ts +Subscribe: ReactFormGroupSubscribeComponent; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:305](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L305) diff --git a/docs/framework/react/reference/interfaces/ReactFormGroupComponent.md b/docs/framework/react/reference/interfaces/ReactFormGroupComponent.md new file mode 100644 index 0000000000..780085fa8b --- /dev/null +++ b/docs/framework/react/reference/interfaces/ReactFormGroupComponent.md @@ -0,0 +1,50 @@ +--- +id: ReactFormGroupComponent +title: ReactFormGroupComponent +--- + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:337](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L337) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +```ts +ReactFormGroupComponent(props): ReactNode; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:342](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L342) + +## Type Parameters + +### TGroupName + +`TGroupName` *extends* `string` + +### TGroupValue + +`TGroupValue` + +### TGroupValidators + +`TGroupValidators` *extends* `FormGroupValidators`\<`TGroupValue`\> + +## Parameters + +### props + +[`ReactFormGroupProps`](ReactFormGroupProps.md)\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupValidators`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`ReactNode` diff --git a/docs/framework/react/reference/interfaces/ReactFormGroupFieldComponent.md b/docs/framework/react/reference/interfaces/ReactFormGroupFieldComponent.md new file mode 100644 index 0000000000..7ee05cd45f --- /dev/null +++ b/docs/framework/react/reference/interfaces/ReactFormGroupFieldComponent.md @@ -0,0 +1,54 @@ +--- +id: ReactFormGroupFieldComponent +title: ReactFormGroupFieldComponent +--- + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:221](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L221) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +```ts +ReactFormGroupFieldComponent(props): ReactNode; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:228](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L228) + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `string` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>\> + +## Parameters + +### props + +[`ReactFormFieldProps`](ReactFormFieldProps.md)\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>, `TFieldValidators`, `TGroupErrorTypes`\[`"fieldError"`\], `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`ReactNode` diff --git a/docs/framework/react/reference/interfaces/ReactFormGroupProps.md b/docs/framework/react/reference/interfaces/ReactFormGroupProps.md new file mode 100644 index 0000000000..7a4ef08fb2 --- /dev/null +++ b/docs/framework/react/reference/interfaces/ReactFormGroupProps.md @@ -0,0 +1,56 @@ +--- +id: ReactFormGroupProps +title: ReactFormGroupProps +--- + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:308](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L308) + +## Extends + +- `Omit`\<`FormGroupOptions`\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupValidators`, `TFormErrorTypes`\>, `"form"`\> + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupValidators + +`TGroupValidators` *extends* `FormGroupValidators`\<`TGroupValue`\> + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +## Properties + +### children + +```ts +children: (groupApi) => ReactNode; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:325](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L325) + +#### Parameters + +##### groupApi + +[`ReactFormGroupApi`](ReactFormGroupApi.md)\<`TFormData`, `TGroupName`, `TGroupValue`, `ToFormGroupErrorTypes`\<`NoInfer`\<`TGroupValidators`\>\>, `TFormErrorTypes`, `TFieldComponents`\> + +#### Returns + +`ReactNode` diff --git a/docs/framework/react/reference/interfaces/ReactTanStackFormComponents.md b/docs/framework/react/reference/interfaces/ReactTanStackFormComponents.md new file mode 100644 index 0000000000..4a7632d97c --- /dev/null +++ b/docs/framework/react/reference/interfaces/ReactTanStackFormComponents.md @@ -0,0 +1,62 @@ +--- +id: ReactTanStackFormComponents +title: ReactTanStackFormComponents +--- + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:358](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L358) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](../type-aliases/ReactComponentTree.md) + +## Properties + +### ArrayField + +```ts +ArrayField: ReactFormArrayFieldComponent; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:368](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L368) + +*** + +### Field + +```ts +Field: ReactFormFieldComponent; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:366](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L366) + +TODO docs + +*** + +### FormGroup + +```ts +FormGroup: ReactFormGroupComponent; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:376](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L376) + +*** + +### Subscribe + +```ts +Subscribe: ReactFormSubscribeComponent; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:374](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L374) diff --git a/docs/framework/react/reference/interfaces/Readable.md b/docs/framework/react/reference/interfaces/Readable.md new file mode 100644 index 0000000000..dfb78d0d0f --- /dev/null +++ b/docs/framework/react/reference/interfaces/Readable.md @@ -0,0 +1,49 @@ +--- +id: Readable +title: Readable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:19 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\> + +## Extended by + +- [`BaseAtom`](BaseAtom.md) +- [`InternalBaseAtom`](InternalBaseAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/react/reference/interfaces/ReadonlyAtom.md b/docs/framework/react/reference/interfaces/ReadonlyAtom.md new file mode 100644 index 0000000000..167ed3f7d3 --- /dev/null +++ b/docs/framework/react/reference/interfaces/ReadonlyAtom.md @@ -0,0 +1,58 @@ +--- +id: ReadonlyAtom +title: ReadonlyAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:49 + +An atom that is read-only and cannot be set. + +## Example + +```ts +const atom = createAtom(() => 42); +// @ts-expect-error - Cannot set a readonly atom +atom.set(43); +``` + +## Extends + +- [`BaseAtom`](BaseAtom.md)\<`T`\> + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`get`](BaseAtom.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`subscribe`](BaseAtom.md#subscribe) diff --git a/docs/framework/react/reference/interfaces/Subscribable.md b/docs/framework/react/reference/interfaces/Subscribable.md new file mode 100644 index 0000000000..88172ebbbd --- /dev/null +++ b/docs/framework/react/reference/interfaces/Subscribable.md @@ -0,0 +1,36 @@ +--- +id: Subscribable +title: Subscribable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:16 + +## Extends + +- [`InteropSubscribable`](InteropSubscribable.md)\<`T`\> + +## Extended by + +- [`BaseAtom`](BaseAtom.md) +- [`InternalBaseAtom`](InternalBaseAtom.md) +- [`Readable`](Readable.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Overrides + +[`InteropSubscribable`](InteropSubscribable.md).[`subscribe`](InteropSubscribable.md#subscribe) diff --git a/docs/framework/react/reference/interfaces/SubscribeProps.md b/docs/framework/react/reference/interfaces/SubscribeProps.md new file mode 100644 index 0000000000..255f62f823 --- /dev/null +++ b/docs/framework/react/reference/interfaces/SubscribeProps.md @@ -0,0 +1,84 @@ +--- +id: SubscribeProps +title: SubscribeProps +--- + +Defined in: [packages/react-form/src/Subscribe.public.tsx:17](https://github.com/TanStack/form/blob/main/packages/react-form/src/Subscribe.public.tsx#L17) + +Subscribe to `form.atom` (full form state). The selector receives the full +FormState. + +## Type Parameters + +### TSourceData + +`TSourceData` + +### TSelected + +`TSelected` + +## Properties + +### children + +```ts +children: ReactNode | ((state) => ReactNode); +``` + +Defined in: [packages/react-form/src/Subscribe.public.tsx:28](https://github.com/TanStack/form/blob/main/packages/react-form/src/Subscribe.public.tsx#L28) + +*** + +### selector + +```ts +selector: (state) => TSelected; +``` + +Defined in: [packages/react-form/src/Subscribe.public.tsx:23](https://github.com/TanStack/form/blob/main/packages/react-form/src/Subscribe.public.tsx#L23) + +Select from full form state. Re-renders when the selected value changes +(shallow compare). + +#### Parameters + +##### state + +`TSourceData` + +#### Returns + +`TSelected` + +*** + +### source + +```ts +source: SubscribeSource; +``` + +Defined in: [packages/react-form/src/Subscribe.public.tsx:18](https://github.com/TanStack/form/blob/main/packages/react-form/src/Subscribe.public.tsx#L18) + +*** + +### when? + +```ts +optional when?: (selected) => boolean; +``` + +Defined in: [packages/react-form/src/Subscribe.public.tsx:27](https://github.com/TanStack/form/blob/main/packages/react-form/src/Subscribe.public.tsx#L27) + +Optional. If provided, the component will only render when the `when` function returns `true`. + +#### Parameters + +##### selected + +`NoInfer`\<`TSelected`\> + +#### Returns + +`boolean` diff --git a/docs/framework/react/reference/interfaces/Subscription.md b/docs/framework/react/reference/interfaces/Subscription.md new file mode 100644 index 0000000000..da7bc0471c --- /dev/null +++ b/docs/framework/react/reference/interfaces/Subscription.md @@ -0,0 +1,20 @@ +--- +id: Subscription +title: Subscription +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:13 + +## Properties + +### unsubscribe + +```ts +unsubscribe: () => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:14 + +#### Returns + +`void` diff --git a/docs/framework/react/reference/interfaces/UseFieldOptions.md b/docs/framework/react/reference/interfaces/UseFieldOptions.md deleted file mode 100644 index 417057f438..0000000000 --- a/docs/framework/react/reference/interfaces/UseFieldOptions.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -id: UseFieldOptions -title: UseFieldOptions ---- - -# Interface: UseFieldOptions\ - -Defined in: [packages/react-form/src/types.ts:20](https://github.com/TanStack/form/blob/main/packages/react-form/src/types.ts#L20) - -The field options. - -## Extends - -- `FieldApiOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\>.`FieldOptionsMode` - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TSubmitMeta - -`TSubmitMeta` - -## Properties - -### mode? - -```ts -optional mode: "value" | "array"; -``` - -Defined in: [packages/react-form/src/types.ts:14](https://github.com/TanStack/form/blob/main/packages/react-form/src/types.ts#L14) - -#### Inherited from - -```ts -FieldOptionsMode.mode -``` diff --git a/docs/framework/react/reference/interfaces/UseFieldOptionsBound.md b/docs/framework/react/reference/interfaces/UseFieldOptionsBound.md deleted file mode 100644 index 1685ccc125..0000000000 --- a/docs/framework/react/reference/interfaces/UseFieldOptionsBound.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -id: UseFieldOptionsBound -title: UseFieldOptionsBound ---- - -# Interface: UseFieldOptionsBound\ - -Defined in: [packages/react-form/src/types.ts:81](https://github.com/TanStack/form/blob/main/packages/react-form/src/types.ts#L81) - -## Extends - -- `FieldOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`\>.`FieldOptionsMode` - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -## Properties - -### mode? - -```ts -optional mode: "value" | "array"; -``` - -Defined in: [packages/react-form/src/types.ts:14](https://github.com/TanStack/form/blob/main/packages/react-form/src/types.ts#L14) - -#### Inherited from - -```ts -FieldOptionsMode.mode -``` diff --git a/docs/framework/react/reference/interfaces/UseSelectorOptions.md b/docs/framework/react/reference/interfaces/UseSelectorOptions.md new file mode 100644 index 0000000000..154275a8fe --- /dev/null +++ b/docs/framework/react/reference/interfaces/UseSelectorOptions.md @@ -0,0 +1,36 @@ +--- +id: UseSelectorOptions +title: UseSelectorOptions +--- + +Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.2.8\_react@19.2.8\_\_react@19.2.8/node\_modules/@tanstack/react-store/dist/useSelector.d.ts:2 + +## Type Parameters + +### TSelected + +`TSelected` + +## Properties + +### compare? + +```ts +optional compare?: (a, b) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.2.8\_react@19.2.8\_\_react@19.2.8/node\_modules/@tanstack/react-store/dist/useSelector.d.ts:3 + +#### Parameters + +##### a + +`TSelected` + +##### b + +`TSelected` + +#### Returns + +`boolean` diff --git a/docs/framework/react/reference/interfaces/WithFieldGroupProps.md b/docs/framework/react/reference/interfaces/WithFieldGroupProps.md deleted file mode 100644 index 4013223a52..0000000000 --- a/docs/framework/react/reference/interfaces/WithFieldGroupProps.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -id: WithFieldGroupProps -title: WithFieldGroupProps ---- - -# Interface: WithFieldGroupProps\ - -Defined in: [packages/react-form/src/createFormHook.tsx:256](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L256) - -## Extends - -- `BaseFormOptions`\<`TFieldGroupData`, `TSubmitMeta`\> - -## Type Parameters - -### TFieldGroupData - -`TFieldGroupData` - -### TFieldComponents - -`TFieldComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> - -### TFormComponents - -`TFormComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> - -### TSubmitMeta - -`TSubmitMeta` - -### TRenderProps - -`TRenderProps` *extends* `object` = `Record`\<`string`, `never`\> - -## Properties - -### props? - -```ts -optional props: TRenderProps; -``` - -Defined in: [packages/react-form/src/createFormHook.tsx:264](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L264) - -*** - -### render - -```ts -render: FunctionComponent & object>>; -``` - -Defined in: [packages/react-form/src/createFormHook.tsx:265](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L265) diff --git a/docs/framework/react/reference/interfaces/WithFormProps.md b/docs/framework/react/reference/interfaces/WithFormProps.md deleted file mode 100644 index 414bb9f852..0000000000 --- a/docs/framework/react/reference/interfaces/WithFormProps.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -id: WithFormProps -title: WithFormProps ---- - -# Interface: WithFormProps\ - -Defined in: [packages/react-form/src/createFormHook.tsx:200](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L200) - -## Extends - -- `FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` - -### TFieldComponents - -`TFieldComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> - -### TFormComponents - -`TFormComponents` *extends* `Record`\<`string`, `ComponentType`\<`any`\>\> - -### TRenderProps - -`TRenderProps` *extends* `object` = `Record`\<`string`, `never`\> - -## Properties - -### props? - -```ts -optional props: TRenderProps; -``` - -Defined in: [packages/react-form/src/createFormHook.tsx:231](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L231) - -*** - -### render - -```ts -render: FunctionComponent & object>>; -``` - -Defined in: [packages/react-form/src/createFormHook.tsx:232](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L232) diff --git a/docs/framework/react/reference/type-aliases/AnyAtom.md b/docs/framework/react/reference/type-aliases/AnyAtom.md new file mode 100644 index 0000000000..45bd838a33 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/AnyAtom.md @@ -0,0 +1,10 @@ +--- +id: AnyAtom +title: AnyAtom +--- + +```ts +type AnyAtom = BaseAtom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:36 diff --git a/docs/framework/react/reference/type-aliases/AnyFieldGroupApi.md b/docs/framework/react/reference/type-aliases/AnyFieldGroupApi.md new file mode 100644 index 0000000000..72b94573aa --- /dev/null +++ b/docs/framework/react/reference/type-aliases/AnyFieldGroupApi.md @@ -0,0 +1,10 @@ +--- +id: AnyFieldGroupApi +title: AnyFieldGroupApi +--- + +```ts +type AnyFieldGroupApi = FieldGroupApi>>; +``` + +Defined in: [packages/react-form/src/FieldGroup/FieldGroupApi.public.ts:186](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/FieldGroupApi.public.ts#L186) diff --git a/docs/framework/react/reference/type-aliases/AnyReactFormApi.md b/docs/framework/react/reference/type-aliases/AnyReactFormApi.md new file mode 100644 index 0000000000..b164e2e0bb --- /dev/null +++ b/docs/framework/react/reference/type-aliases/AnyReactFormApi.md @@ -0,0 +1,33 @@ +--- +id: AnyReactFormApi +title: AnyReactFormApi +--- + +```ts +type AnyReactFormApi = AnyFormApi & ReactTanStackFormComponents; +``` + +Defined in: [packages/react-form/src/ReactForm/formApiTypes.public.ts:51](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/formApiTypes.public.ts#L51) + +A React form API whose form data and error types are erased. + +Use it for reusable React components that only need core form operations and +the `Field`, `ArrayField`, `Subscribe`, or `FormGroup` components common to +every React form. Field paths and values are not checked against a particular +form shape; use `ReactFormType` when a component depends on one known form. + +## Example + +```tsx +function FormSubmitButton({ form }: { form: AnyReactFormApi }) { + return ( + state.isSubmitting}> + {(isSubmitting) => ( + + )} + + ) +} +``` diff --git a/docs/framework/react/reference/type-aliases/AnyReactFormComponentMap.md b/docs/framework/react/reference/type-aliases/AnyReactFormComponentMap.md new file mode 100644 index 0000000000..6df300c774 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/AnyReactFormComponentMap.md @@ -0,0 +1,10 @@ +--- +id: AnyReactFormComponentMap +title: AnyReactFormComponentMap +--- + +```ts +type AnyReactFormComponentMap = ReactFormComponentMap; +``` + +Defined in: [packages/react-form/src/AppForm/componentMap.public.ts:34](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/componentMap.public.ts#L34) diff --git a/docs/framework/react/reference/type-aliases/AppFormComponent.md b/docs/framework/react/reference/type-aliases/AppFormComponent.md new file mode 100644 index 0000000000..b9587fc967 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/AppFormComponent.md @@ -0,0 +1,12 @@ +--- +id: AppFormComponent +title: AppFormComponent +--- + +```ts +type AppFormComponent = FunctionComponent<{ + children: Exclude>; +}>; +``` + +Defined in: [packages/react-form/src/AppForm/ReactAppFormApi.public.tsx:6](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/ReactAppFormApi.public.tsx#L6) diff --git a/docs/framework/react/reference/type-aliases/DefaultReactFormComponentMap.md b/docs/framework/react/reference/type-aliases/DefaultReactFormComponentMap.md new file mode 100644 index 0000000000..6e6b978dab --- /dev/null +++ b/docs/framework/react/reference/type-aliases/DefaultReactFormComponentMap.md @@ -0,0 +1,10 @@ +--- +id: DefaultReactFormComponentMap +title: DefaultReactFormComponentMap +--- + +```ts +type DefaultReactFormComponentMap = ReactFormComponentMap, Record>; +``` + +Defined in: [packages/react-form/src/AppForm/componentMap.public.ts:39](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/componentMap.public.ts#L39) diff --git a/docs/framework/react/reference/type-aliases/DefineFieldGroupFn.md b/docs/framework/react/reference/type-aliases/DefineFieldGroupFn.md new file mode 100644 index 0000000000..3d91955940 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/DefineFieldGroupFn.md @@ -0,0 +1,34 @@ +--- +id: DefineFieldGroupFn +title: DefineFieldGroupFn +--- + +```ts +type DefineFieldGroupFn = (defineFn) => FieldGroupDefinition; +``` + +Defined in: [packages/react-form/src/FieldGroup/withFields.public.ts:199](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/withFields.public.ts#L199) + +Signature shared by `defineFieldGroup` and app-form field-group definers. + +## Type Parameters + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](ReactComponentTree.md) + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +## Parameters + +### defineFn + +(`helper`) => `TFields` + +## Returns + +[`FieldGroupDefinition`](../interfaces/FieldGroupDefinition.md)\<`TFields`, `TFieldComponents`\> diff --git a/docs/framework/react/reference/type-aliases/FieldComponent.md b/docs/framework/react/reference/type-aliases/FieldComponent.md deleted file mode 100644 index 21fda3fe85..0000000000 --- a/docs/framework/react/reference/type-aliases/FieldComponent.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -id: FieldComponent -title: FieldComponent ---- - -# Type Alias: FieldComponent()\ - -```ts -type FieldComponent = ({ - children, - ...fieldOptions -}) => ReturnType; -``` - -Defined in: [packages/react-form/src/useField.tsx:480](https://github.com/TanStack/form/blob/main/packages/react-form/src/useField.tsx#L480) - -A type alias representing a field component for a specific form data type. - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TPatentSubmitMeta - -`TPatentSubmitMeta` - -### ExtendedApi - -`ExtendedApi` = \{ -\} - -## Type Parameters - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -## Parameters - -### \{ - children, - ...fieldOptions -\} - -`FieldComponentBoundProps`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TPatentSubmitMeta`, `ExtendedApi`\> - -## Returns - -`ReturnType`\<`FunctionComponent`\> diff --git a/docs/framework/react/reference/type-aliases/FieldGroupFieldBindingsOf.md b/docs/framework/react/reference/type-aliases/FieldGroupFieldBindingsOf.md new file mode 100644 index 0000000000..362a999bd2 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/FieldGroupFieldBindingsOf.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupFieldBindingsOf +title: FieldGroupFieldBindingsOf +--- + +```ts +type FieldGroupFieldBindingsOf = FieldGroupFieldsOf extends FieldGroupFields ? FieldGroupFieldBindings, TFormData> : never; +``` + +Defined in: [packages/react-form/src/FieldGroup/withFields.public.ts:42](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/withFields.public.ts#L42) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` + +### TFormData + +`TFormData` diff --git a/docs/framework/react/reference/type-aliases/FieldGroupFieldComponentsOf.md b/docs/framework/react/reference/type-aliases/FieldGroupFieldComponentsOf.md new file mode 100644 index 0000000000..40da4b02a5 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/FieldGroupFieldComponentsOf.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupFieldComponentsOf +title: FieldGroupFieldComponentsOf +--- + +```ts +type FieldGroupFieldComponentsOf = TFieldGroup extends ReactFieldGroup ? TFieldComponents : never; +``` + +Defined in: [packages/react-form/src/FieldGroup/withFields.public.ts:31](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/withFields.public.ts#L31) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` diff --git a/docs/framework/react/reference/type-aliases/FieldGroupFieldsOf.md b/docs/framework/react/reference/type-aliases/FieldGroupFieldsOf.md new file mode 100644 index 0000000000..c8557f3d3d --- /dev/null +++ b/docs/framework/react/reference/type-aliases/FieldGroupFieldsOf.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupFieldsOf +title: FieldGroupFieldsOf +--- + +```ts +type FieldGroupFieldsOf = TFieldGroup extends object ? TFields : never; +``` + +Defined in: [packages/react-form/src/FieldGroup/withFields.public.ts:18](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/withFields.public.ts#L18) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` diff --git a/docs/framework/react/reference/type-aliases/FieldGroupForm.md b/docs/framework/react/reference/type-aliases/FieldGroupForm.md new file mode 100644 index 0000000000..0549ee780c --- /dev/null +++ b/docs/framework/react/reference/type-aliases/FieldGroupForm.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupForm +title: FieldGroupForm +--- + +```ts +type FieldGroupForm = FormApi & ReactTanStackFormComponents; +``` + +Defined in: [packages/react-form/src/FieldGroup/withFields.public.ts:36](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/withFields.public.ts#L36) + +## Type Parameters + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](ReactComponentTree.md) = `Record`\<`never`, `never`\> + +### TFormData + +`TFormData` = `any` diff --git a/docs/framework/react/reference/type-aliases/FieldGroupFormState.md b/docs/framework/react/reference/type-aliases/FieldGroupFormState.md new file mode 100644 index 0000000000..4aa7dfc483 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/FieldGroupFormState.md @@ -0,0 +1,10 @@ +--- +id: FieldGroupFormState +title: FieldGroupFormState +--- + +```ts +type FieldGroupFormState = FormState; +``` + +Defined in: [packages/react-form/src/FieldGroup/FieldGroupApi.public.ts:191](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/FieldGroupApi.public.ts#L191) diff --git a/docs/framework/react/reference/type-aliases/FieldGroupSubscribeComponent.md b/docs/framework/react/reference/type-aliases/FieldGroupSubscribeComponent.md new file mode 100644 index 0000000000..2f18f9b334 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/FieldGroupSubscribeComponent.md @@ -0,0 +1,44 @@ +--- +id: FieldGroupSubscribeComponent +title: FieldGroupSubscribeComponent +--- + +```ts +type FieldGroupSubscribeComponent = (props) => ReactNode; +``` + +Defined in: [packages/react-form/src/FieldGroup/FieldGroupApi.public.ts:171](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/FieldGroupApi.public.ts#L171) + +Reads form state from inside a field-group component. + +Because a field group can be used with different forms, `state.values` +cannot be safely typed here and is provided as `unknown`. + +To read values from this field group, use its `atom` with `useSelector` +instead. + +## Type Parameters + +### TSelected + +`TSelected` + +## Parameters + +### props + +[`FieldGroupSubscribeProps`](FieldGroupSubscribeProps.md)\<`TSelected`\> + +## Returns + +`ReactNode` + +## Example + +```tsx + state.submissionAttempts}> + {(submissionAttempts) => ( + Submit attempts: {submissionAttempts} + )} + +``` diff --git a/docs/framework/react/reference/type-aliases/FieldGroupSubscribeProps.md b/docs/framework/react/reference/type-aliases/FieldGroupSubscribeProps.md new file mode 100644 index 0000000000..07dcc8a9e4 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/FieldGroupSubscribeProps.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupSubscribeProps +title: FieldGroupSubscribeProps +--- + +```ts +type FieldGroupSubscribeProps = ReactFormSubscribeProps; +``` + +Defined in: [packages/react-form/src/FieldGroup/FieldGroupApi.public.ts:147](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/FieldGroupApi.public.ts#L147) + +## Type Parameters + +### TSelected + +`TSelected` diff --git a/docs/framework/react/reference/type-aliases/FieldGroupWithFieldsFn.md b/docs/framework/react/reference/type-aliases/FieldGroupWithFieldsFn.md new file mode 100644 index 0000000000..989459bf8e --- /dev/null +++ b/docs/framework/react/reference/type-aliases/FieldGroupWithFieldsFn.md @@ -0,0 +1,93 @@ +--- +id: FieldGroupWithFieldsFn +title: FieldGroupWithFieldsFn +--- + +```ts +type FieldGroupWithFieldsFn = (Component, fieldsPropName) => (props) => ReactNode; +``` + +Defined in: [packages/react-form/src/FieldGroup/withFields.public.ts:100](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/withFields.public.ts#L100) + +Wraps a component that accepts a field-group API and returns a component +that accepts a form and, when needed, virtual-to-concrete field bindings. + +If every virtual field name is already a compatible path in the form, the +returned component binds those paths automatically when the bindings prop is +omitted. A complete bindings map can still reroute them. Otherwise, the +bindings prop is required. + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` *extends* [`ReactFieldGroup`](ReactFieldGroup.md)\<`any`, `any`\> + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TProps + +`TProps` *extends* `object` + +### TFieldsPropName + +`TFieldsPropName` *extends* `FieldGroupFieldsPropName`\<`TProps`, `TFieldGroup`\> + +## Parameters + +### Component + +(`props`) => `ReactNode` + +### fieldsPropName + +`TFieldsPropName` + +## Returns + +\<`TFormData`\>(`props`) => `ReactNode` + +## Example + +```tsx +const passwordFieldGroup = defineFieldGroup(({ strict }) => ({ + password: strict(), + confirmPassword: strict(), +})) + +interface PasswordFieldsProps { + fields: typeof passwordFieldGroup.fields +} + +function PasswordFields({ fields }: PasswordFieldsProps) { + // ... +} + +const PasswordSection = passwordFieldGroup.bindComponent( + PasswordFields, + 'fields', +) + +function AccountForm() { + const form = useForm({ + defaultValues: { + account: { + password: '', + confirmPassword: '', + }, + }, + }) + + return ( + + ) +} +``` diff --git a/docs/framework/react/reference/type-aliases/FormGroupComponent.md b/docs/framework/react/reference/type-aliases/FormGroupComponent.md deleted file mode 100644 index bc612fb7e7..0000000000 --- a/docs/framework/react/reference/type-aliases/FormGroupComponent.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -id: FormGroupComponent -title: FormGroupComponent ---- - -# Type Alias: FormGroupComponent()\ - -```ts -type FormGroupComponent = ({ - children, - ...formGroupOptions -}) => ReturnType; -``` - -Defined in: [packages/react-form/src/useFormGroup.tsx:562](https://github.com/TanStack/form/blob/main/packages/react-form/src/useFormGroup.tsx#L562) - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` - -### ExtendedApi - -`ExtendedApi` = \{ -\} - -## Type Parameters - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TSubmitMeta - -`TSubmitMeta` - -## Parameters - -### \{ - children, - ...formGroupOptions -\} - -`FormGroupComponentBoundProps`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`, `ExtendedApi`\> - -## Returns - -`ReturnType`\<`FunctionComponent`\> diff --git a/docs/framework/react/reference/type-aliases/LensFieldComponent.md b/docs/framework/react/reference/type-aliases/LensFieldComponent.md deleted file mode 100644 index f6b54061a5..0000000000 --- a/docs/framework/react/reference/type-aliases/LensFieldComponent.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -id: LensFieldComponent -title: LensFieldComponent ---- - -# Type Alias: LensFieldComponent()\ - -```ts -type LensFieldComponent = ({ - children, - ...fieldOptions -}) => ReturnType; -``` - -Defined in: [packages/react-form/src/useField.tsx:555](https://github.com/TanStack/form/blob/main/packages/react-form/src/useField.tsx#L555) - -A type alias representing a field component for a form lens data type. - -## Type Parameters - -### TLensData - -`TLensData` - -### TParentSubmitMeta - -`TParentSubmitMeta` - -### ExtendedApi - -`ExtendedApi` = \{ -\} - -## Type Parameters - -### TName - -`TName` *extends* `DeepKeys`\<`TLensData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TLensData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`unknown`, `string`, `TData`\> - -## Parameters - -### \{ - children, - ...fieldOptions -\} - -`Omit`\<`FieldComponentBoundProps`\<`unknown`, `string`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `TParentSubmitMeta`, `ExtendedApi`\>, `"name"` \| `"validators"`\> & `object` - -## Returns - -`ReturnType`\<`FunctionComponent`\> diff --git a/docs/framework/react/reference/type-aliases/Observer.md b/docs/framework/react/reference/type-aliases/Observer.md new file mode 100644 index 0000000000..a3abe781fd --- /dev/null +++ b/docs/framework/react/reference/type-aliases/Observer.md @@ -0,0 +1,70 @@ +--- +id: Observer +title: Observer +--- + +```ts +type Observer = object; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:8 + +## Type Parameters + +### T + +`T` + +## Properties + +### complete? + +```ts +optional complete?: () => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:11 + +#### Returns + +`void` + +*** + +### error? + +```ts +optional error?: (err) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:10 + +#### Parameters + +##### err + +`unknown` + +#### Returns + +`void` + +*** + +### next? + +```ts +optional next?: (value) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:9 + +#### Parameters + +##### value + +`T` + +#### Returns + +`void` diff --git a/docs/framework/react/reference/type-aliases/ReactAppFormApi.md b/docs/framework/react/reference/type-aliases/ReactAppFormApi.md new file mode 100644 index 0000000000..af7a245acf --- /dev/null +++ b/docs/framework/react/reference/type-aliases/ReactAppFormApi.md @@ -0,0 +1,32 @@ +--- +id: ReactAppFormApi +title: ReactAppFormApi +--- + +```ts +type ReactAppFormApi = ReactFormApi & object; +``` + +Defined in: [packages/react-form/src/AppForm/ReactAppFormApi.public.tsx:10](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/ReactAppFormApi.public.tsx#L10) + +## Type Declaration + +### AppForm + +```ts +AppForm: AppFormComponent; +``` + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TComponents + +`TComponents` *extends* [`AnyReactFormComponentMap`](AnyReactFormComponentMap.md) diff --git a/docs/framework/react/reference/type-aliases/ReactComponentTree.md b/docs/framework/react/reference/type-aliases/ReactComponentTree.md new file mode 100644 index 0000000000..facd88f62a --- /dev/null +++ b/docs/framework/react/reference/type-aliases/ReactComponentTree.md @@ -0,0 +1,33 @@ +--- +id: ReactComponentTree +title: ReactComponentTree +--- + +```ts +type ReactComponentTree = object; +``` + +Defined in: [packages/react-form/src/AppForm/componentMap.public.ts:20](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/componentMap.public.ts#L20) + +A recursively nested collection of components registered with +`createFormHook`. + +Component trees are inferred from `fieldComponents` and `formComponents` in +normal usage. This type is primarily useful when building wrappers around +`createFormHook` or declaring reusable component registries. + +## Index Signature + +```ts +[name: string]: FunctionComponent | ReactComponentTree +``` + +## Example + +```tsx +const fields = { + inputs: { + TextField, + }, +} satisfies ReactComponentTree +``` diff --git a/docs/framework/react/reference/type-aliases/ReactFieldApi.md b/docs/framework/react/reference/type-aliases/ReactFieldApi.md new file mode 100644 index 0000000000..e74347508c --- /dev/null +++ b/docs/framework/react/reference/type-aliases/ReactFieldApi.md @@ -0,0 +1,36 @@ +--- +id: ReactFieldApi +title: ReactFieldApi +--- + +```ts +type ReactFieldApi = FieldApi & FieldComponentsMatchingType; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:82](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L82) + +## Type Parameters + +### TFieldName + +`TFieldName` + +### TFieldValue + +`TFieldValue` + +### TFieldError + +`TFieldError` + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](ReactComponentTree.md) diff --git a/docs/framework/react/reference/type-aliases/ReactFieldGroup.md b/docs/framework/react/reference/type-aliases/ReactFieldGroup.md new file mode 100644 index 0000000000..404cdb43e5 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/ReactFieldGroup.md @@ -0,0 +1,28 @@ +--- +id: ReactFieldGroup +title: ReactFieldGroup +--- + +```ts +type ReactFieldGroup = FieldGroupApi, TFieldComponents> & object; +``` + +Defined in: [packages/react-form/src/FieldGroup/withFields.public.ts:24](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/withFields.public.ts#L24) + +## Type Declaration + +### \[fieldGroupFieldsSymbol\] + +```ts +readonly [fieldGroupFieldsSymbol]: TFields; +``` + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](ReactComponentTree.md) = `Record`\<`never`, `never`\> diff --git a/docs/framework/react/reference/type-aliases/ReactFormApi.md b/docs/framework/react/reference/type-aliases/ReactFormApi.md new file mode 100644 index 0000000000..7913ab3ad6 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/ReactFormApi.md @@ -0,0 +1,24 @@ +--- +id: ReactFormApi +title: ReactFormApi +--- + +```ts +type ReactFormApi = unknown extends TComponents["formComponents"] ? ExtendedFormApi : ExtendedFormApi & TComponents["formComponents"]; +``` + +Defined in: [packages/react-form/src/ReactForm/formApiTypes.public.ts:15](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/formApiTypes.public.ts#L15) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TComponents + +`TComponents` *extends* [`AnyReactFormComponentMap`](AnyReactFormComponentMap.md) diff --git a/docs/framework/react/reference/type-aliases/ReactFormArrayFieldComponent.md b/docs/framework/react/reference/type-aliases/ReactFormArrayFieldComponent.md new file mode 100644 index 0000000000..16a1a95607 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/ReactFormArrayFieldComponent.md @@ -0,0 +1,44 @@ +--- +id: ReactFormArrayFieldComponent +title: ReactFormArrayFieldComponent +--- + +```ts +type ReactFormArrayFieldComponent = (props) => ReactNode; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:179](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L179) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](ReactComponentTree.md) + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `never` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>\> + +## Parameters + +### props + +[`ReactFormFieldProps`](../interfaces/ReactFormFieldProps.md)\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`ReactNode` diff --git a/docs/framework/react/reference/type-aliases/ReactFormExtendedApi.md b/docs/framework/react/reference/type-aliases/ReactFormExtendedApi.md deleted file mode 100644 index 9ccb6af24b..0000000000 --- a/docs/framework/react/reference/type-aliases/ReactFormExtendedApi.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -id: ReactFormExtendedApi -title: ReactFormExtendedApi ---- - -# Type Alias: ReactFormExtendedApi\ - -```ts -type ReactFormExtendedApi = FormApi & ReactFormApi; -``` - -Defined in: [packages/react-form/src/useForm.tsx:114](https://github.com/TanStack/form/blob/main/packages/react-form/src/useForm.tsx#L114) - -An extended version of the `FormApi` class that includes React-specific functionalities from `ReactFormApi` - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` diff --git a/docs/framework/react/reference/type-aliases/ReactFormFieldComponent.md b/docs/framework/react/reference/type-aliases/ReactFormFieldComponent.md new file mode 100644 index 0000000000..0002e9ed36 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/ReactFormFieldComponent.md @@ -0,0 +1,44 @@ +--- +id: ReactFormFieldComponent +title: ReactFormFieldComponent +--- + +```ts +type ReactFormFieldComponent = (props) => ReactNode; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:153](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L153) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](ReactComponentTree.md) + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `string` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>\> + +## Parameters + +### props + +[`ReactFormFieldProps`](../interfaces/ReactFormFieldProps.md)\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`ReactNode` diff --git a/docs/framework/react/reference/type-aliases/ReactFormGroupArrayFieldComponent.md b/docs/framework/react/reference/type-aliases/ReactFormGroupArrayFieldComponent.md new file mode 100644 index 0000000000..fc38916c06 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/ReactFormGroupArrayFieldComponent.md @@ -0,0 +1,52 @@ +--- +id: ReactFormGroupArrayFieldComponent +title: ReactFormGroupArrayFieldComponent +--- + +```ts +type ReactFormGroupArrayFieldComponent = (props) => ReactNode; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:249](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L249) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* [`ReactComponentTree`](ReactComponentTree.md) + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `never` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>\> + +## Parameters + +### props + +[`ReactFormFieldProps`](../interfaces/ReactFormFieldProps.md)\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>, `TFieldValidators`, `TGroupErrorTypes`\[`"fieldError"`\], `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`ReactNode` diff --git a/docs/framework/react/reference/type-aliases/ReactFormGroupSubscribeComponent.md b/docs/framework/react/reference/type-aliases/ReactFormGroupSubscribeComponent.md new file mode 100644 index 0000000000..c0969273e8 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/ReactFormGroupSubscribeComponent.md @@ -0,0 +1,36 @@ +--- +id: ReactFormGroupSubscribeComponent +title: ReactFormGroupSubscribeComponent +--- + +```ts +type ReactFormGroupSubscribeComponent = (props) => ReactNode; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:214](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L214) + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +## Type Parameters + +### TSelected + +`TSelected` + +## Parameters + +### props + +[`ReactFormGroupSubscribeProps`](ReactFormGroupSubscribeProps.md)\<`TGroupValue`, `TGroupErrorTypes`, `TSelected`\> + +## Returns + +`ReactNode` diff --git a/docs/framework/react/reference/type-aliases/ReactFormGroupSubscribeProps.md b/docs/framework/react/reference/type-aliases/ReactFormGroupSubscribeProps.md new file mode 100644 index 0000000000..80586fb63a --- /dev/null +++ b/docs/framework/react/reference/type-aliases/ReactFormGroupSubscribeProps.md @@ -0,0 +1,24 @@ +--- +id: ReactFormGroupSubscribeProps +title: ReactFormGroupSubscribeProps +--- + +```ts +type ReactFormGroupSubscribeProps = ReactSubscribeProps, TSelected>; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:205](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L205) + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TSelected + +`TSelected` diff --git a/docs/framework/react/reference/type-aliases/ReactFormSubscribeComponent.md b/docs/framework/react/reference/type-aliases/ReactFormSubscribeComponent.md new file mode 100644 index 0000000000..2e5318372d --- /dev/null +++ b/docs/framework/react/reference/type-aliases/ReactFormSubscribeComponent.md @@ -0,0 +1,36 @@ +--- +id: ReactFormSubscribeComponent +title: ReactFormSubscribeComponent +--- + +```ts +type ReactFormSubscribeComponent = (props) => ReactNode; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:108](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L108) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +## Type Parameters + +### TSelected + +`TSelected` + +## Parameters + +### props + +[`ReactFormSubscribeProps`](ReactFormSubscribeProps.md)\<`TFormData`, `TFormErrorTypes`, `TSelected`\> + +## Returns + +`ReactNode` diff --git a/docs/framework/react/reference/type-aliases/ReactFormSubscribeProps.md b/docs/framework/react/reference/type-aliases/ReactFormSubscribeProps.md new file mode 100644 index 0000000000..7dc6ce9ee1 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/ReactFormSubscribeProps.md @@ -0,0 +1,24 @@ +--- +id: ReactFormSubscribeProps +title: ReactFormSubscribeProps +--- + +```ts +type ReactFormSubscribeProps = ReactSubscribeProps, TSelected>; +``` + +Defined in: [packages/react-form/src/ReactForm/Components.public.ts:102](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/Components.public.ts#L102) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TSelected + +`TSelected` diff --git a/docs/framework/react/reference/type-aliases/ReactFormType.md b/docs/framework/react/reference/type-aliases/ReactFormType.md new file mode 100644 index 0000000000..2cd5284803 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/ReactFormType.md @@ -0,0 +1,45 @@ +--- +id: ReactFormType +title: ReactFormType +--- + +```ts +type ReactFormType = TOptions extends FormOptions ? ReactFormApi, TComponents extends AnyReactFormComponentMap ? TComponents : DefaultReactFormComponentMap> : never; +``` + +Defined in: [packages/react-form/src/ReactForm/formType.public.ts:55](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/formType.public.ts#L55) + +Derives the React form API type represented by a reusable options object. + +Use it to type props for components that belong to one known form shape. It +preserves the inferred form data and any components registered through +`appFormOptions`. Options such as `onSubmit` can be defined either in the +shared options or when the form is created in the component. + +## Type Parameters + +### TOptions + +`TOptions` *extends* `AnyFormOptions` + +The reusable form or app-form options from which the API derives its form data, error, and registered-component types. + +## Example + +```tsx +const profileOptions = formOptions({ + defaultValues: { name: '' }, +}) + +type ProfileForm = ReactFormType + +function NameField(props: { + form: ProfileForm +}) { + return ( + + {(field) => } + + ) +} +``` diff --git a/docs/framework/react/reference/type-aliases/Selection.md b/docs/framework/react/reference/type-aliases/Selection.md new file mode 100644 index 0000000000..4c9583de45 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/Selection.md @@ -0,0 +1,16 @@ +--- +id: Selection +title: Selection +--- + +```ts +type Selection = Readable; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/types.d.ts:4 + +## Type Parameters + +### TSelected + +`TSelected` diff --git a/docs/framework/react/reference/type-aliases/ServerFormState.md b/docs/framework/react/reference/type-aliases/ServerFormState.md deleted file mode 100644 index 429deb22a7..0000000000 --- a/docs/framework/react/reference/type-aliases/ServerFormState.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -id: ServerFormState -title: ServerFormState ---- - -# Type Alias: ServerFormState\ - -```ts -type ServerFormState = Pick, "values" | "errors" | "errorMap">; -``` - -Defined in: [packages/react-form/src/types.ts:120](https://github.com/TanStack/form/blob/main/packages/react-form/src/types.ts#L120) - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> diff --git a/docs/framework/react/reference/type-aliases/StoreAction.md b/docs/framework/react/reference/type-aliases/StoreAction.md new file mode 100644 index 0000000000..dda47bb944 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/StoreAction.md @@ -0,0 +1,20 @@ +--- +id: StoreAction +title: StoreAction +--- + +```ts +type StoreAction = (...args) => any; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:4 + +## Parameters + +### args + +...`any`[] + +## Returns + +`any` diff --git a/docs/framework/react/reference/type-aliases/StoreActionMap.md b/docs/framework/react/reference/type-aliases/StoreActionMap.md new file mode 100644 index 0000000000..6c17ae5e6e --- /dev/null +++ b/docs/framework/react/reference/type-aliases/StoreActionMap.md @@ -0,0 +1,10 @@ +--- +id: StoreActionMap +title: StoreActionMap +--- + +```ts +type StoreActionMap = Record; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:5 diff --git a/docs/framework/react/reference/type-aliases/StoreActionsFactory.md b/docs/framework/react/reference/type-aliases/StoreActionsFactory.md new file mode 100644 index 0000000000..d411ec97be --- /dev/null +++ b/docs/framework/react/reference/type-aliases/StoreActionsFactory.md @@ -0,0 +1,36 @@ +--- +id: StoreActionsFactory +title: StoreActionsFactory +--- + +```ts +type StoreActionsFactory = (store) => TActions; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.0/node\_modules/@tanstack/store/dist/store.d.ts:6 + +## Type Parameters + +### T + +`T` + +### TActions + +`TActions` *extends* [`StoreActionMap`](StoreActionMap.md) + +## Parameters + +### store + +#### get + +[`Store`](../classes/Store.md)\<`T`\>\[`"get"`\] + +#### setState + +[`Store`](../classes/Store.md)\<`T`\>\[`"setState"`\] + +## Returns + +`TActions` diff --git a/docs/framework/react/reference/type-aliases/SubscribeSource.md b/docs/framework/react/reference/type-aliases/SubscribeSource.md new file mode 100644 index 0000000000..f3dc7d8659 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/SubscribeSource.md @@ -0,0 +1,20 @@ +--- +id: SubscribeSource +title: SubscribeSource +--- + +```ts +type SubscribeSource = + | Atom + | ReadonlyAtom + | Store +| ReadonlyStore; +``` + +Defined in: [packages/react-form/src/Subscribe.public.tsx:10](https://github.com/TanStack/form/blob/main/packages/react-form/src/Subscribe.public.tsx#L10) + +## Type Parameters + +### TValue + +`TValue` diff --git a/docs/framework/react/reference/type-aliases/UseAppFormHook.md b/docs/framework/react/reference/type-aliases/UseAppFormHook.md new file mode 100644 index 0000000000..9529091d69 --- /dev/null +++ b/docs/framework/react/reference/type-aliases/UseAppFormHook.md @@ -0,0 +1,40 @@ +--- +id: UseAppFormHook +title: UseAppFormHook +--- + +```ts +type UseAppFormHook = (options) => ReactAppFormApi, TComponents>; +``` + +Defined in: [packages/react-form/src/AppForm/createFormHookTypes.public.ts:108](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/createFormHookTypes.public.ts#L108) + +## Type Parameters + +### TComponents + +`TComponents` *extends* [`AnyReactFormComponentMap`](AnyReactFormComponentMap.md) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> + +### TSubmitReturn + +`TSubmitReturn` + +## Parameters + +### options + +`FormOptions`\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\> + +## Returns + +[`ReactAppFormApi`](ReactAppFormApi.md)\<`TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>, `TComponents`\> diff --git a/docs/framework/react/reference/type-aliases/UseField.md b/docs/framework/react/reference/type-aliases/UseField.md deleted file mode 100644 index fdb8c13af1..0000000000 --- a/docs/framework/react/reference/type-aliases/UseField.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -id: UseField -title: UseField ---- - -# Type Alias: UseField()\ - -```ts -type UseField = (opts) => FieldApi; -``` - -Defined in: [packages/react-form/src/useField.tsx:26](https://github.com/TanStack/form/blob/main/packages/react-form/src/useField.tsx#L26) - -A type representing a hook for using a field in a form with the given form data type. - -A function that takes an optional object with a `name` property and field options, and returns a `FieldApi` instance for the specified field. - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TPatentSubmitMeta - -`TPatentSubmitMeta` - -## Type Parameters - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -## Parameters - -### opts - -[`UseFieldOptionsBound`](../interfaces/UseFieldOptionsBound.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`\> - -## Returns - -`FieldApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TPatentSubmitMeta`\> diff --git a/docs/framework/react/reference/type-aliases/UseFormGroup.md b/docs/framework/react/reference/type-aliases/UseFormGroup.md deleted file mode 100644 index a5a140e8e4..0000000000 --- a/docs/framework/react/reference/type-aliases/UseFormGroup.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -id: UseFormGroup -title: UseFormGroup ---- - -# Type Alias: UseFormGroup()\ - -```ts -type UseFormGroup = (opts) => FormGroupApi; -``` - -Defined in: [packages/react-form/src/useFormGroup.tsx:19](https://github.com/TanStack/form/blob/main/packages/react-form/src/useFormGroup.tsx#L19) - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Type Parameters - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TSubmitMeta - -`TSubmitMeta` - -## Parameters - -### opts - -`FormGroupApiOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Returns - -`FormGroupApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> diff --git a/docs/framework/react/reference/type-aliases/UseFormHook.md b/docs/framework/react/reference/type-aliases/UseFormHook.md new file mode 100644 index 0000000000..a3b5ea1aab --- /dev/null +++ b/docs/framework/react/reference/type-aliases/UseFormHook.md @@ -0,0 +1,40 @@ +--- +id: UseFormHook +title: UseFormHook +--- + +```ts +type UseFormHook = (options) => ReactFormApi, TComponents>; +``` + +Defined in: [packages/react-form/src/ReactForm/useForm.public.ts:13](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/useForm.public.ts#L13) + +## Type Parameters + +### TComponents + +`TComponents` *extends* [`AnyReactFormComponentMap`](AnyReactFormComponentMap.md) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> + +### TSubmitReturn + +`TSubmitReturn` + +## Parameters + +### options + +`FormOptions`\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\> + +## Returns + +[`ReactFormApi`](ReactFormApi.md)\<`TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>, `TComponents`\> diff --git a/docs/framework/react/reference/variables/Field.md b/docs/framework/react/reference/variables/Field.md deleted file mode 100644 index 3f514508f7..0000000000 --- a/docs/framework/react/reference/variables/Field.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -id: Field -title: Field ---- - -# Variable: Field() - -```ts -const Field: (__namedParameters) => ReactNode | Promise; -``` - -Defined in: [packages/react-form/src/useField.tsx:645](https://github.com/TanStack/form/blob/main/packages/react-form/src/useField.tsx#L645) - -A function component that takes field options and a render function as children and returns a React component. - -The `Field` component uses the `useField` hook internally to manage the field instance. - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TPatentSubmitMeta - -`TPatentSubmitMeta` - -## Parameters - -### \_\_namedParameters - -`FieldComponentProps`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TPatentSubmitMeta`\> - -## Returns - -`ReactNode` \| `Promise`\<`ReactNode`\> diff --git a/docs/framework/react/reference/variables/FormGroup.md b/docs/framework/react/reference/variables/FormGroup.md deleted file mode 100644 index 8ce9f56a40..0000000000 --- a/docs/framework/react/reference/variables/FormGroup.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -id: FormGroup -title: FormGroup ---- - -# Variable: FormGroup() - -```ts -const FormGroup: (__namedParameters) => ReactNode | Promise; -``` - -Defined in: [packages/react-form/src/useFormGroup.tsx:642](https://github.com/TanStack/form/blob/main/packages/react-form/src/useFormGroup.tsx#L642) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Parameters - -### \_\_namedParameters - -`FormGroupComponentProps`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Returns - -`ReactNode` \| `Promise`\<`ReactNode`\> diff --git a/docs/framework/react/reference/variables/defineFieldGroup.md b/docs/framework/react/reference/variables/defineFieldGroup.md new file mode 100644 index 0000000000..5791cfa54a --- /dev/null +++ b/docs/framework/react/reference/variables/defineFieldGroup.md @@ -0,0 +1,60 @@ +--- +id: defineFieldGroup +title: defineFieldGroup +--- + +```ts +const defineFieldGroup: DefineFieldGroupFn>; +``` + +Defined in: [packages/react-form/src/FieldGroup/withFields.public.ts:255](https://github.com/TanStack/form/blob/main/packages/react-form/src/FieldGroup/withFields.public.ts#L255) + +Defines a reusable group of virtual fields that can be bound to concrete +paths in different parent forms. + +Use `strict` when a binding must have exactly the declared value type. Use +`loose` when a binding may have the declared type or a narrower assignable +type. + +## Example + +```tsx +const passwordFieldGroup = defineFieldGroup(({ strict }) => ({ + password: strict(), + confirmPassword: strict(), +})) + +interface PasswordFieldsProps { + fields: typeof passwordFieldGroup.fields +} + +function PasswordFields({ fields }: PasswordFieldsProps) { + return ( + <> + + {(field) => ( + field.handleChange(event.target.value)} + /> + )} + + + {(field) => ( + field.handleChange(event.target.value)} + /> + )} + + + ) +} + +export const PasswordSection = passwordFieldGroup.bindComponent( + PasswordFields, + 'fields', +) +``` diff --git a/docs/framework/react/reference/variables/useForm.md b/docs/framework/react/reference/variables/useForm.md new file mode 100644 index 0000000000..325c06a462 --- /dev/null +++ b/docs/framework/react/reference/variables/useForm.md @@ -0,0 +1,44 @@ +--- +id: useForm +title: useForm +--- + +```ts +const useForm: UseFormHook; +``` + +Defined in: [packages/react-form/src/ReactForm/useForm.public.ts:62](https://github.com/TanStack/form/blob/main/packages/react-form/src/ReactForm/useForm.public.ts#L62) + +Creates a React form whose instance and lifecycle are owned by the current +component. + +`defaultValues` establish the initial state and inferred form value type. +Later renders apply changed options to the same form instance, and unmounting +the component cleans it up. + +Call this hook at the top level of a React component or custom hook. + +## Example + +```tsx +function ProfileForm() { + const form = useForm({ + defaultValues: { name: '' }, + onSubmit: ({ value }) => saveProfile(value), + }) + + return ( +
    { + event.preventDefault() + void form.handleSubmit() + }} + /> + ) +} +``` + +## Returns + +The React form API with typed field, subscription, and form-group +components attached. diff --git a/docs/framework/react/reference/variables/useIsomorphicLayoutEffect.md b/docs/framework/react/reference/variables/useIsomorphicLayoutEffect.md deleted file mode 100644 index df740aa3b9..0000000000 --- a/docs/framework/react/reference/variables/useIsomorphicLayoutEffect.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -id: useIsomorphicLayoutEffect -title: useIsomorphicLayoutEffect ---- - -# Variable: useIsomorphicLayoutEffect() - -```ts -const useIsomorphicLayoutEffect: (effect, deps?) => void; -``` - -Defined in: [packages/react-form/src/useIsomorphicLayoutEffect.ts:3](https://github.com/TanStack/form/blob/main/packages/react-form/src/useIsomorphicLayoutEffect.ts#L3) - -The signature is identical to `useEffect`, but it fires synchronously after all DOM mutations. -Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside -`useLayoutEffect` will be flushed synchronously, before the browser has a chance to paint. - -Prefer the standard `useEffect` when possible to avoid blocking visual updates. - -If you’re migrating code from a class component, `useLayoutEffect` fires in the same phase as -`componentDidMount` and `componentDidUpdate`. - -## Parameters - -### effect - -`EffectCallback` - -### deps? - -`DependencyList` - -## Returns - -`void` - -## Version - -16.8.0 - -## See - -[https://react.dev/reference/react/useLayoutEffect](https://react.dev/reference/react/useLayoutEffect) diff --git a/docs/framework/react/reference/variables/useStore.md b/docs/framework/react/reference/variables/useStore.md index 0707446971..8f64fc37c9 100644 --- a/docs/framework/react/reference/variables/useStore.md +++ b/docs/framework/react/reference/variables/useStore.md @@ -3,13 +3,11 @@ id: useStore title: useStore --- -# ~~Variable: useStore()~~ - ```ts const useStore: (source, selector?, compare?) => TSelected; ``` -Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.1.0\_react@19.1.0\_\_react@19.1.0/node\_modules/@tanstack/react-store/dist/useStore.d.ts:12 +Defined in: node\_modules/.pnpm/@tanstack+react-store@0.11.0\_react-dom@19.2.8\_react@19.2.8\_\_react@19.2.8/node\_modules/@tanstack/react-store/dist/useStore.d.ts:12 Deprecated alias for [useSelector](../functions/useSelector.md). diff --git a/docs/framework/solid/guides/arrays.md b/docs/framework/solid/guides/arrays.md deleted file mode 100644 index 8c1b5240e2..0000000000 --- a/docs/framework/solid/guides/arrays.md +++ /dev/null @@ -1,126 +0,0 @@ ---- -id: arrays -title: Arrays ---- - -TanStack Form supports arrays as values in a form, including sub-object values inside of an array. - -## Basic Usage - -To use an array, you can use `field.state.value` on an array value in conjunction -with [`Index` from `solid-js`](https://www.solidjs.com/tutorial/flow_index): - -```jsx -function App() { - const form = createForm(() => ({ - defaultValues: { - people: [], - }, - })) - - return ( - - {(field) => ( - 0}> - {/* Do not change this to `For` or things will not work as-expected */} - - { - (_, i) => null // ... - } - - - )} - - ) -} -``` - -> You must use `Index` from `solid-js` and not `For` because `For` will cause the inner components to be re-rendered -> every time the array changes. -> -> This causes the field to lose its value and therefore delete the subfield's value. - -This will generate the mapped JSX every time you run `pushValue` on `field`: - -```jsx - -``` - -Finally, you can use a subfield like so: - -```jsx - - {(subField) => ( - { - subField().handleChange(e.currentTarget.value) - }} - /> - )} - -``` - -## Full Example - -```jsx -function App() { - const form = createForm(() => ({ - defaultValues: { - people: [], - }, - onSubmit: ({ value }) => alert(JSON.stringify(value)), - })) - - return ( -
    - { - e.preventDefault() - e.stopPropagation() - form.handleSubmit() - }} - > - - {(field) => ( -
    - 0}> - {/* Do not change this to For or the test will fail */} - - {(_, i) => ( - - {(subField) => ( -
    - -
    - )} -
    - )} -
    -
    - - -
    - )} -
    - - -
    - ) -} -``` diff --git a/docs/framework/solid/guides/async-initial-values.md b/docs/framework/solid/guides/async-initial-values.md index 647962144b..e0197a3711 100644 --- a/docs/framework/solid/guides/async-initial-values.md +++ b/docs/framework/solid/guides/async-initial-values.md @@ -3,50 +3,158 @@ id: async-initial-values title: Async Initial Values --- -Let's say that you want to fetch some data from an API and use it as the initial value of a form. +Forms often edit data loaded from an API. A server-state library such as +TanStack Query should own fetching, caching, loading, and retries; TanStack Form +should own the editable copy. -While this problem sounds simple on the surface, there are hidden complexities you might not have thought of thus far. +There are two supported ways to provide async initial values: wait to create the +form until the data is ready, or create it immediately with complete fallback +values. Choose the approach that best matches the loading experience your UI +needs. -For example, you might want to show a loading spinner while the data is being fetched, or you might want to handle errors gracefully. -Likewise, you could also find yourself looking for a way to cache the data so that you don't have to fetch it every time the form is rendered. +## Wait for data before creating the editor -While we could implement many of these features from scratch, it would end up looking a lot like another project we maintain: [TanStack Query](https://tanstack.com/query). +Render a loading or error state first, then mount a component whose +`defaultValues` are complete. -As such, this guide shows you how you can mix-n-match TanStack Form with TanStack Query to achieve the desired behavior. +```tsx +// UserPage.tsx +import { Show } from 'solid-js' +import { createQuery } from '@tanstack/solid-query' +import { UserEditor } from './UserEditor' +import type { User } from './types' -## Basic Usage +export function UserPage(props: { userId: string }) { + const userQuery = createQuery(() => ({ + queryKey: ['user', props.userId], + queryFn: async (): Promise => { + const response = await fetch(`/api/users/${props.userId}`) + return response.json() + }, + })) + + return ( + Could not load the user.

    } + > + Loading…

    }> + {(user) => } +
    +
    + ) +} +``` ```tsx +// UserEditor.tsx import { createForm } from '@tanstack/solid-form' -import { createQuery } from '@tanstack/solid-query' +import type { User } from './types' + +export function UserEditor(props: { user: User }) { + const form = createForm(() => ({ + defaultValues: props.user, + onSubmit: async ({ value }) => { + await fetch('/api/users', { + method: 'PUT', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(value), + }) + }, + })) + + return ( +
    { + event.preventDefault() + form.handleSubmit() + }} + > + {/* fields */} +
    + ) +} +``` + +This pattern is useful when no form state is needed during loading. The keyed +`Show` recreates the editor when a different user object arrives. + +## Create the form before data arrives + +You can instead call `createForm` in the same component as `createQuery`. +Provide a static, shape-complete fallback so `defaultValues` are never +`undefined`. + +```tsx import { Show } from 'solid-js' +import { createQuery } from '@tanstack/solid-query' +import { createForm } from '@tanstack/solid-form' +import type { User } from './types' + +const emptyUser: User = { + firstName: '', + lastName: '', +} -export default function App() { - const query = createQuery(() => ({ - queryKey: ['data'], - queryFn: async () => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return { firstName: 'FirstName', lastName: 'LastName' } +export function UserPage(props: { userId: string }) { + const userQuery = createQuery(() => ({ + queryKey: ['user', props.userId], + queryFn: async (): Promise => { + const response = await fetch(`/api/users/${props.userId}`) + return response.json() }, })) const form = createForm(() => ({ - defaultValues: { - firstName: query.data?.firstName ?? '', - lastName: query.data?.lastName ?? '', - }, + defaultValues: userQuery.data ?? emptyUser, onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) + await fetch('/api/users', { + method: 'PUT', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(value), + }) }, })) return ( - Loading..

    }> - <> + Could not load the user.

    } + > + Loading…

    }> +
    { + event.preventDefault() + form.handleSubmit() + }} + > + {/* fields */} +
    +
    ) } ``` -This will show a loading spinner until the data is fetched, and then it will render the form with the fetched data as the initial values. +Because both integrations receive accessors, reading `userQuery.data` inside +the form options accessor keeps the options reactive. When query data replaces +the fallback, TanStack Form applies the new `defaultValues` to untouched fields +while preserving fields the user has already touched. + +This is the approach demonstrated by the repository's +`examples/solid/query-integration` example. + +## Background refetches and record changes + +`defaultValues` establish the form's baseline; they are not a fully controlled +`values` prop. In the fallback pattern, later `defaultValues` updates use the +same touched-field-preserving behavior. + +If background refetches arrive while a user is editing, decide at the product +level whether to keep local edits, prompt before replacing them, or call +`form.reset(nextValues)` deliberately. Do not overwrite in-progress input merely +because a query refreshed. + +When switching to a different record, either recreate a keyed editor as in the +first pattern or deliberately reset the existing form. Otherwise, touched +values from the previous record can be preserved when the new defaults arrive. diff --git a/docs/framework/solid/guides/basic-concepts.md b/docs/framework/solid/guides/basic-concepts.md deleted file mode 100644 index 16a5ce808f..0000000000 --- a/docs/framework/solid/guides/basic-concepts.md +++ /dev/null @@ -1,326 +0,0 @@ ---- -id: basic-concepts -title: Basic Concepts and Terminology ---- - -This page introduces the basic concepts and terminology used in the `@tanstack/solid-form` library. Familiarizing yourself with these concepts will help you better understand and work with the library. - -## Form Options - -You can create options for your form so that it can be shared between multiple forms by using the `formOptions` function. - -Example: - -```tsx -const formOpts = formOptions({ - defaultValues: { - firstName: '', - lastName: '', - hobbies: [], - } as Person, -}) -``` - -## Form Instance - -A Form Instance is an object that represents an individual form and provides methods and properties for working with the form. You create a form instance using the `createForm` hook provided by the form options. The hook accepts an object with an `onSubmit` function, which is called when the form is submitted. - -```tsx -const form = createForm(() => ({ - ...formOpts, - onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) - }, -})) -``` - -You may also create a form instance without using `formOptions` by using the standalone `createForm` API: - -```tsx -const form = createForm(() => ({ - onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) - }, - defaultValues: { - firstName: '', - lastName: '', - hobbies: [], - }, -})) -``` - -## Field - -A Field represents a single form input element, such as a text input or a checkbox. Fields are created using the `form.Field` component provided by the form instance. The component accepts a name prop, which should match a key in the form's default values. It also accepts a children prop, which is a render prop function that takes a field object as its argument. - -Example: - -```tsx - ( - field().handleChange(e.target.value)} - /> - )} -/> -``` - -## Field State - -Each field has its own state, which includes its current value, validation status, error messages, and other metadata. You can access a field's state using the `field().state` property. - -Example: - -```ts -const { - value, - meta: { errors, isValidating }, -} = field().state -``` - -There are four states in the metadata that can be useful to see how the user interacts with a field: - -- _"isTouched"_, after the user changes the field or blurs the field -- _"isDirty"_, after the field's value has been changed, even if it's been reverted to the default. Opposite of `isPristine` -- _"isPristine"_, until the user changes the field value. Opposite of `isDirty` -- _"isBlurred"_, after the field has been blurred - -```ts -const { isTouched, isDirty, isPristine, isBlurred } = field().state.meta -``` - -![Field states](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states.png) - -## Understanding 'isDirty' in Different Libraries - -Non-Persistent `dirty` state - -- **Libraries**: React Hook Form (RHF), Formik, Final Form. -- **Behavior**: A field is 'dirty' if its value differs from the default. Reverting to the default value makes it 'clean' again. - -Persistent `dirty` state - -- **Libraries**: Angular Form, Vue FormKit. -- **Behavior**: A field remains 'dirty' once changed, even if reverted to the default value. - -We have chosen the persistent 'dirty' state model. To also support a non-persistent 'dirty' state, we introduce an additional flag: - -- _"isDefaultValue"_, whether the field's current value is the default value - -```ts -const { isDefaultValue, isTouched } = field().state.meta - -// The following line will re-create the non-Persistent `dirty` functionality. -const nonPersistentIsDirty = !isDefaultValue -``` - -![Field states extended](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states-extended.png) - -## Field API - -The Field API is an object passed to the render prop function when creating a field. It provides methods for working with the field's state. - -Example: - -```tsx - field().handleChange(e.target.value)} -/> -``` - -## Validation - -`@tanstack/solid-form` provides both synchronous and asynchronous validation out of the box. Validation functions can be passed to the `form.Field` component using the `validators` prop. - -Example: - -```tsx - - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined, - onChangeAsync: async ({ value }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value.includes('error') && 'No "error" allowed in first name' - }, - }} - children={(field) => ( - <> - field().handleChange(e.target.value)} - /> -

    {field().state.meta.errors[0]}

    - - )} -/> -``` - -## Validation with Standard Schema Libraries - -In addition to hand-rolled validation options, we also support the [Standard Schema](https://github.com/standard-schema/standard-schema) specification. - -You can define a schema using any of the libraries implementing the specification and pass it to a form or field validator. - -Supported libraries include: - -- [Zod](https://zod.dev/) (v3.24.0 or higher) -- [Valibot](https://valibot.dev/) (v1.0.0 or higher) -- [ArkType](https://arktype.io/) (v2.1.20 or higher) -- [Yup](https://github.com/jquense/yup) (v1.7.0 or higher) - -```tsx -import { z } from 'zod' - -// ... -; { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return !value.includes('error') - }, - { - message: 'No "error" allowed in first name', - }, - ), - }} - children={(field) => ( - <> - field().handleChange(e.target.value)} - /> -

    {field().state.meta.errors[0]}

    - - )} -/> -``` - -## Reactivity - -`@tanstack/solid-form` offers various ways to subscribe to form and field state changes, most notably the `form.useSelector` hook and the `form.Subscribe` component. These methods allow you to optimize your form's rendering performance by only updating components when necessary. - -Example: - -```tsx -const firstName = form.useSelector((state) => state.values.firstName) -//... - ({ - canSubmit: state.canSubmit, - isSubmitting: state.isSubmitting, - })} - children={(state) => ( - - )} -/> -``` - -## Array Fields - -Array fields allow you to manage a list of values within a form, such as a list of hobbies. You can create an array field using the `form.Field` component with the `mode="array"` prop. - -When working with array fields, you can use the fields `pushValue`, `removeValue`, `swapValues` and `moveValue` methods to add, remove, swap, and move a value from one index to another within the array, respectively. Additional helper methods such as `insertValue`, `replaceValue`, and `clearValues` are also available for inserting, replacing, and clearing array values. - -Example: - -```tsx - ( -
    - Hobbies -
    - 0} - fallback={'No hobbies found.'} - > - - {(_, i) => ( -
    - ( -
    - - field().handleChange(e.target.value)} - /> - -
    - )} - /> - { - return ( -
    - - field().handleChange(e.target.value)} - /> -
    - ) - }} - /> -
    - )} -
    -
    -
    - -
    - )} -/> -``` - -These are the basic concepts and terminology used in the `@tanstack/solid-form` library. Understanding these concepts will help you work more effectively with the library and create complex forms with ease. diff --git a/docs/framework/solid/guides/debugging.md b/docs/framework/solid/guides/debugging.md new file mode 100644 index 0000000000..96bc68300a --- /dev/null +++ b/docs/framework/solid/guides/debugging.md @@ -0,0 +1,63 @@ +--- +id: debugging +title: Debugging Solid Usage +--- + +This page covers common Solid and TypeScript problems when using TanStack Form. + +## An input does not start with the expected value + +Every value rendered by an input should exist in form-level `defaultValues` +when the form is created. + +```tsx +import { createForm } from '@tanstack/solid-form' + +const form = createForm(() => ({ + defaultValues: { + firstName: '', + subscribed: false, + }, +})) +``` + +Do not omit `defaultValues` or rely on a field-level default. When values come +from an API, render a loading state before mounting the editable form or supply +a complete fallback shape. + +## A field value is `unknown` + +Field names and values are inferred from `defaultValues`. Check that you have +not widened the initial object to `Record`, `any`, or an +unrelated union. Prefer a concrete value type: + +```tsx +import { createForm } from '@tanstack/solid-form' + +type Profile = { firstName: string; age: number } + +const defaults: Profile = { firstName: '', age: 0 } +const form = createForm(() => ({ defaultValues: defaults })) +``` + +For extremely large forms, split UI into typed components or scoped form and +field groups instead of casting each field value. + +## Type instantiation is excessively deep + +This TypeScript error usually involves a very large recursive value shape, a +widely inferred union, or an unsupported composition. Reduce it to the smallest +form that reproduces the problem, keep `defaultValues` concrete, and avoid +unnecessary generic wrappers. + +If the minimal reproduction still fails, report it in the +[TanStack Form issue tracker](https://github.com/TanStack/form/issues). Include +the TypeScript and Solid versions, the form value type, and the smallest failing +field. + +## Errors exist but are not displayed + +`field().errors` respects the form's `errorVisibility` policy. Inspect +`field().meta.original.errors` when debugging whether validation ran but the +issues are intentionally hidden. Also confirm that the input calls +`field().handleBlur` if the policy depends on `isBlurred`. diff --git a/docs/framework/solid/guides/devtools.md b/docs/framework/solid/guides/devtools.md deleted file mode 100644 index a238f5ec2d..0000000000 --- a/docs/framework/solid/guides/devtools.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -id: devtools -title: Devtools ---- - -TanStack Form comes with a ready to go suit of devtools. - -## Setup - -Install the [TanStack Devtools](https://tanstack.com/devtools/latest/docs/quick-start) library and the [TanStack Form plugin](http://npmjs.com/package/@tanstack/solid-form-devtools), from the framework adapter that your working in (in this case `@tanstack/solid-devtools`, and `@tanstack/solid-form-devtools`). - -```bash -npm i @tanstack/solid-devtools -npm i @tanstack/solid-form-devtools -``` - -Next in the root of your application import the `TanStackDevtools`. - -```tsx -import { TanStackDevtools } from '@tanstack/solid-devtools' - -import App from './App' - -render( - () => ( - <> - - - - - ), - root!, -) -``` - -Import the `formDevtoolsPlugin` from **TanStack Form** and provide it to the `TanStackDevtools` component. - -```tsx -import { TanStackDevtools } from '@tanstack/solid-devtools' -import { formDevtoolsPlugin } from '@tanstack/solid-form-devtools' - -import App from './app' - -const root = document.getElementById('root') - -render( - () => ( - <> - - - - - ), - root!, -) -``` - -Finally add any additional configuration you desire to the `TanStackDevtools` component, more information can be found under the [TanStack Devtools Configuration](https://tanstack.com/devtools/) section. - -A complete working example can be found in our [examples section](https://tanstack.com/form/latest/docs/framework/solid/examples/devtools). diff --git a/docs/framework/solid/guides/dynamic-validation.md b/docs/framework/solid/guides/dynamic-validation.md deleted file mode 100644 index 14d6088181..0000000000 --- a/docs/framework/solid/guides/dynamic-validation.md +++ /dev/null @@ -1,224 +0,0 @@ ---- -id: dynamic-validation -title: Dynamic Validation ---- - -In many cases, you want to change the validation rules based depending on the state of the form or other conditions. The most popular -example of this is when you want to validate a field differently based on whether the user has submitted the form for the first time or not. - -We support this through our `onDynamic` validation function. - -```tsx -import { revalidateLogic, createForm } from '@tanstack/solid-form' - -// ... - -const form = createForm(() => ({ - defaultValues: { - firstName: '', - lastName: '', - }, - // If this is omitted, onDynamic will not be called - validationLogic: revalidateLogic(), - validators: { - onDynamic: ({ value }) => { - if (!value.firstName) { - return { firstName: 'A first name is required' } - } - return undefined - }, - }, -})) -``` - -> By default `onDynamic` is not called, so you need to pass `revalidateLogic()` to the `validationLogic` option of `createForm`. - -## Revalidation Options - -`revalidateLogic` allows you to specify when validation should be run and change the validation rules dynamically based on the current submission state of the form. - -It takes two arguments: - -- `mode`: The mode of validation prior to the first form submission. This can be one of the following: - - `change`: Validate on every change. - - `blur`: Validate on blur. - - `submit`: Validate on submit. (**default**) - -- `modeAfterSubmission`: The mode of validation after the form has been submitted. This can be one of the following: - - `change`: Validate on every change. (**default**) - - `blur`: Validate on blur. - - `submit`: Validate on submit. - -You can, for example, use the following to revalidate on blur after the first submission: - -```tsx -const form = createForm(() => ({ - // ... - validationLogic: revalidateLogic({ - mode: 'submit', - modeAfterSubmission: 'blur', - }), - // ... -})) -``` - -## Accessing Errors - -Just as you might access errors from an `onChange` or `onBlur` validation, you can access the errors from the `onDynamic` validation function using the `form.state.errorMap` object. - -```tsx -function App() { - const form = createForm(() => ({ - // ... - validationLogic: revalidateLogic(), - validators: { - onDynamic: ({ value }) => { - if (!value.firstName) { - return { firstName: 'A first name is required' } - } - return undefined - }, - }, - })) - - return

    {form.state.errorMap.onDynamic?.firstName}

    -} -``` - -## Usage with Other Validation Logic - -You can use `onDynamic` validation alongside other validation logic, such as `onChange` or `onBlur`. - -```tsx -import { revalidateLogic, createForm } from '@tanstack/solid-form' - -function App() { - const form = createForm(() => ({ - defaultValues: { - firstName: '', - lastName: '', - }, - validationLogic: revalidateLogic(), - validators: { - onChange: ({ value }) => { - if (!value.firstName) { - return { firstName: 'A first name is required' } - } - return undefined - }, - onDynamic: ({ value }) => { - if (!value.lastName) { - return { lastName: 'A last name is required' } - } - return undefined - }, - }, - })) - - return ( -
    -

    {form.state.errorMap.onChange?.firstName}

    -

    {form.state.errorMap.onDynamic?.lastName}

    -
    - ) -} -``` - -### Usage with Fields - -You can also use `onDynamic` validation with fields, just like you would with other validation logic. - -```tsx -function App() { - const form = createForm(() => ({ - defaultValues: { - name: '', - age: 0, - }, - validationLogic: revalidateLogic(), - onSubmit({ value }) { - alert(JSON.stringify(value)) - }, - })) - - return ( -
    { - e.preventDefault() - e.stopPropagation() - form.handleSubmit() - }} - > - - value > 18 ? undefined : 'Age must be greater than 18', - }} - children={(field) => ( -
    - field().handleChange(e.target.valueAsNumber)} - onBlur={field().handleBlur} - value={field().state.value} - /> -

    - {field().state.meta.errorMap.onDynamic} -

    -
    - )} - /> - - - ) -} -``` - -### Async Validation - -Async validation can also be used with `onDynamic` just like with other validation logic. You can even debounce the async validation to avoid excessive calls. - -```tsx -const form = createForm(() => ({ - defaultValues: { - username: '', - }, - validationLogic: revalidateLogic(), - validators: { - onDynamicAsyncDebounceMs: 500, // Debounce the async validation by 500ms - onDynamicAsync: async ({ value }) => { - if (!value.username) { - return { username: 'Username is required' } - } - // Simulate an async validation - const isValid = await validateUsername(value.username) - return isValid ? undefined : { username: 'Username is already taken' } - }, - }, -})) -``` - -### Standard Schema Validation - -You can also use standard schema validation libraries like Valibot or Zod with `onDynamic` validation. This allows you to define complex validation rules that can change dynamically based on the form state. - -```tsx -import { z } from 'zod' - -const schema = z.object({ - firstName: z.string().min(1, 'A first name is required'), - lastName: z.string().min(1, 'A last name is required'), -}) - -const form = createForm(() => ({ - defaultValues: { - firstName: '', - lastName: '', - }, - validationLogic: revalidateLogic(), - validators: { - onDynamic: schema, - }, -})) -``` diff --git a/docs/framework/solid/guides/form-composition.md b/docs/framework/solid/guides/form-composition.md deleted file mode 100644 index 0056fdeb75..0000000000 --- a/docs/framework/solid/guides/form-composition.md +++ /dev/null @@ -1,610 +0,0 @@ ---- -id: form-composition -title: Form Composition ---- - -A common criticism of TanStack Form is its verbosity out-of-the-box. While this _can_ be useful for educational purposes - helping enforce understanding our APIs - it's not ideal in production use cases. - -As a result, while `form.Field` enables the most powerful and flexible usage of TanStack Form, we provide APIs that wrap it and make your application code less verbose. - -## Custom Form Hooks - -The most powerful way to compose forms is to create custom form hooks. This allows you to create a form hook that is tailored to your application's needs, including pre-bound custom UI components and more. - -At it's most basic, `createFormHook` is a function that takes a `fieldContext` and `formContext` and returns a `useAppForm` hook. - -> This un-customized `useAppForm` hook is identical to `useForm`, but that will quickly change as we add more options to `createFormHook`. - -```tsx -import { createFormHookContexts, createFormHook } from '@tanstack/solid-form' - -// export useFieldContext for use in your custom components -export const { fieldContext, formContext, useFieldContext } = - createFormHookContexts() - -const { useAppForm } = createFormHook({ - fieldContext, - formContext, - // We'll learn more about these options later - fieldComponents: {}, - formComponents: {}, -}) - -function App() { - const form = useAppForm(() => ({ - // Supports all useForm options - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, - })) - - return // ... -} -``` - -### Pre-bound Field Components - -Once this scaffolding is in place, you can start adding custom field and form components to your form hook. - -> Note: the `useFieldContext` must be the same one exported from your custom form context - -```tsx -import { useFieldContext } from './form-context.tsx' - -export function TextField(props: { label: string }) { - // The `Field` infers that it should have a `value` type of `string` - const field = useFieldContext() - return ( - - ) -} -``` - -You're then able to register this component with your form hook. - -```tsx -import { TextField } from './text-field.tsx' - -const { useAppForm } = createFormHook({ - fieldContext, - formContext, - fieldComponents: { - TextField, - }, - formComponents: {}, -}) -``` - -And use it in your form: - -```tsx -function App() { - const form = useAppForm(() => ({ - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, - })) - - return ( - // Notice the `AppField` instead of `Field`; `AppField` provides the required context - } - /> - ) -} -``` - -This not only allows you to reuse the UI of your shared component, but retains the type-safety you'd expect from TanStack Form: Typo `name` and get a TypeScript error. - -### Pre-bound Form Components - -While `form.AppField` solves many of the problems with Field boilerplate and reusability, it doesn't solve the problem of _form_ boilerplate and reusability. - -In particular, being able to share instances of `form.Subscribe` for, say, a reactive form submission button is a common usecase. - -```tsx -function SubscribeButton(props: { label: string }) { - const form = useFormContext() - return ( - state.isSubmitting}> - {(isSubmitting) => ( - - )} - - ) -} - -const { useAppForm, withForm } = createFormHook({ - fieldComponents: {}, - formComponents: { - SubscribeButton, - }, - fieldContext, - formContext, -}) - -function App() { - const form = useAppForm(() => ({ - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, - })) - - return ( - - // Notice the `AppForm` component wrapper; `AppForm` provides the required - context - - - ) -} -``` - -## Breaking big forms into smaller pieces - -Sometimes forms get very large; it's just how it goes sometimes. While TanStack Form supports large forms well, it's never fun to work with hundreds or thousands of lines of code long files. - -To solve this, we support breaking forms into smaller pieces using the `withForm` higher-order component. - -```tsx -const { useAppForm, withForm, withFieldGroup } = createFormHook({ - fieldComponents: { - TextField, - }, - formComponents: { - SubscribeButton, - }, - fieldContext, - formContext, -}) - -const ChildForm = withForm({ - // These values are only used for type-checking, and are not used at runtime - // This allows you to `...formOpts` from `formOptions` without needing to redeclare the options - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, - // Optional, but adds props to the `render` function in addition to `form` - props: { - // These props are also set as default values for the `render` function - title: 'Child Form', - }, - render: function Render(props) { - return ( -
    -

    {props.title}

    - } - /> - - - -
    - ) - }, -}) - -function App() { - const form = useAppForm(() => ({ - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, - })) - - return -} -``` - -### `withForm` FAQ - -> Why a higher-order component instead of a hook? -> -> While hooks are the future of Solid, higher-order components are still a powerful tool for composition. In particular, the API of `withForm` enables us to have strong type-safety without requiring users to pass generics. - -## Reusing groups of fields in multiple forms - -Sometimes, a pair of fields are so closely related that it makes sense to group and reuse them — like the password example listed in the [linked fields guide](./linked-fields.md). Instead of repeating this logic across multiple forms, you can utilize the `withFieldGroup` higher-order component. - -> Unlike `withForm`, validators cannot be specified and could be any value. -> Ensure that your fields can accept unknown error types. - -Rewriting the passwords example using `withFieldGroup` would look like this: - -```tsx -const { useAppForm, withForm, withFieldGroup } = createFormHook({ - fieldComponents: { - TextField, - ErrorInfo, - }, - formComponents: { - SubscribeButton, - }, - fieldContext, - formContext, -}) - -type PasswordFields = { - password: string - confirm_password: string -} - -// These default values are not used at runtime, but the keys are needed for mapping purposes. -// This allows you to spread `formOptions` without needing to redeclare it. -const defaultValues: PasswordFields = { - password: '', - confirm_password: '', -} - -const FieldGroupPasswordFields = withFieldGroup({ - defaultValues, - // You may also restrict the group to only use forms that implement this submit meta. - // If none is provided, any form with the right defaultValues may use it. - // onSubmitMeta: { action: '' } - - // Optional, but adds props to the `render` function in addition to `form` - props: { - // These props are set as default values for the `render` function - title: 'Password', - }, - // Internally, you will have access to a `group` instead of a `form` - render: function Render(props) { - // access reactive values using the group store - const password = useSelector( - props.group.store, - (state) => state.values.password, - ) - // or the form itself - const isSubmitting = useSelector( - props.group.form.store, - (state) => state.isSubmitting, - ) - - return ( -
    -

    {props.title}

    - {/* Groups also have access to Field, Subscribe, Field, AppField and AppForm */} - - {(field) => } - - { - // The form could be any values, so it is typed as 'unknown' - const values: unknown = fieldApi.form.state.values - // use the group methods instead - if (value !== props.group.getFieldValue('password')) { - return 'Passwords do not match' - } - return undefined - }, - }} - > - {(field) => ( -
    - - -
    - )} -
    -
    - ) - }, -}) -``` - -We can now use these grouped fields in any form that implements the default values: - -```tsx -// You are allowed to extend the group fields as long as the -// existing properties remain unchanged -type Account = PasswordFields & { - provider: string - username: string -} - -// You may nest the group fields wherever you want -type FormValues = { - name: string - age: number - account_data: PasswordFields - linked_accounts: Account[] -} - -const defaultValues: FormValues = { - name: '', - age: 0, - account_data: { - password: '', - confirm_password: '', - }, - linked_accounts: [ - { - provider: 'TanStack', - username: '', - password: '', - confirm_password: '', - }, - ], -} - -function App() { - const form = useAppForm(() => ({ - defaultValues, - // If the group didn't specify an `onSubmitMeta` property, - // the form may implement any meta it wants. - // Otherwise, the meta must be defined and match. - onSubmitMeta: { action: '' }, - })) - - return ( - - - - {(field) => - field().state.value.map((account, i) => ( - - )) - } - - - ) -} -``` - -### Mapping field group values to a different field - -You may want to keep the password fields on the top level of your form, or rename the properties for clarity. You can map field group values -to their true location by changing the `field` property: - -> [!IMPORTANT] -> Due to TypeScript limitations, field mapping is only allowed for objects. You can use records or arrays at the top level of a field group, but you will not be able to map the fields. - -```tsx -// To have an easier form, you can keep the fields on the top level -type FormValues = { - name: string - age: number - password: string - confirm_password: string -} - -const defaultValues: FormValues = { - name: '', - age: 0, - password: '', - confirm_password: '', -} - -function App() { - const form = useAppForm(() => ({ - defaultValues, - })) - - return ( - - - - ) -} -``` - -If you expect your fields to always be at the top level of your form, you can create a quick map -of your field groups using a helper function: - -```tsx -const defaultValues: PasswordFields = { - password: '', - confirm_password: '', -} - -const passwordFields = createFieldMap(defaultValues) -/* This generates the following map: - { - 'password': 'password', - 'confirm_password': 'confirm_password' - } -*/ - -// Usage: - -``` - -## Tree-shaking form and field components - -While the above examples are great for getting started, they're not ideal for certain use-cases where you might have hundreds of form and field components. -In particular, you may not want to include all of your form and field components in the bundle of every file that uses your form hook. - -To solve this, you can mix the `createFormHook` TanStack API with the Solid `lazy` and `Suspense` components: - -```typescript -// src/hooks/form-context.ts -import { createFormHookContexts } from '@tanstack/solid-form' - -export const { fieldContext, useFieldContext, formContext, useFormContext } = - createFormHookContexts() -``` - -```tsx -// src/components/text-field.tsx -import { useFieldContext } from '../hooks/form-context.tsx' - -export default function TextField(props: { label: string }) { - const field = useFieldContext() - - return ( - - ) -} -``` - -```tsx -// src/hooks/form.ts -import { lazy } from 'solid-js' -import { createFormHook } from '@tanstack/solid-form' - -const TextField = lazy(() => import('../components/text-fields.tsx')) - -const { useAppForm, withForm } = createFormHook({ - fieldContext, - formContext, - fieldComponents: { - TextField, - }, - formComponents: {}, -}) -``` - -```tsx -// src/App.tsx -import { Suspense } from 'solid-js' -import { PeoplePage } from './features/people/form.tsx' - -export default function App() { - return ( - Loading...

    }> - -
    - ) -} -``` - -This will show the Suspense fallback while the `TextField` component is being loaded, and then render the form once it's loaded. - -## Putting it all together - -Now that we've covered the basics of creating custom form hooks, let's put it all together in a single example. - -```tsx -// /src/hooks/form.ts, to be used across the entire app -const { fieldContext, useFieldContext, formContext, useFormContext } = - createFormHookContexts() - -function TextField(props: { label: string }) { - const field = useFieldContext() - return ( - - ) -} - -function SubscribeButton(props: { label: string }) { - const form = useFormContext() - return ( - state.isSubmitting}> - {(isSubmitting) => ( - - )} - - ) -} - -const { useAppForm, withForm, withFieldGroup } = createFormHook({ - fieldComponents: { - TextField, - }, - formComponents: { - SubscribeButton, - }, - fieldContext, - formContext, -}) - -// /src/features/people/shared-form.ts, to be used across `people` features -const formOpts = formOptions({ - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, -}) - -// /src/features/people/nested-form.ts, to be used in the `people` page -const ChildForm = withForm({ - ...formOpts, - // Optional, but adds props to the `render` function outside of `form` - props: { - title: 'Child Form', - }, - render: (props) => { - return ( -
    -

    {props.title}

    - } - /> - - - -
    - ) - }, -}) - -// /src/features/people/page.ts -const Parent = () => { - const form = useAppForm(() => ({ - ...formOpts, - })) - - return -} -``` - -## API Usage Guidance - -Here's a chart to help you decide what APIs you should be using: - -![](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/react_form_composability.svg) diff --git a/docs/framework/solid/guides/form-groups.md b/docs/framework/solid/guides/form-groups.md deleted file mode 100644 index 1a6e97ac93..0000000000 --- a/docs/framework/solid/guides/form-groups.md +++ /dev/null @@ -1,178 +0,0 @@ ---- -id: form-groups -title: Form Groups ---- - -When building a multi-stage form that has many stages, like so: - -![Form stepper](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/stepper.png) - -It's common for each step to have its own form. However, this complicates the form submission and validation process by requiring you to add complex logic. - -Luckily, TanStack Form provides a way to build out sub-forms that make this kind of development trivial to implement: ``. - -## Usage - -To use a form group in TanStack Form, you'll use `createForm` or [`useAppForm`](./form-composition.md) to create a `form` variable, then reference its `FormGroup` component like you would a `Field`: - -```tsx -const form = createForm(() => ({ - defaultValues: { - step1: { - name: '', - }, - step2: { - age: 0, - }, - }, -})) - -return ( - - {(group) => ( - // `group()` here has all of the form-like methods you'd expect like `deleteField` or `insertFieldValue` - // ... - )} - -) -``` - -This becomes much more useful when paired with external state to conditionally render a `FormGroup`: - -```tsx -const [step, setStep] = createSignal(0) -const form = createForm(() => ({ - defaultValues: { - step1: { - name: '', - }, - step2: { - age: 0, - }, - }, -})) - -return ( - <> - - { - // We can move the step forward when validation passes - setStep(step() + 1) - }} - onGroupSubmitInvalid={() => { - // Or handle invalid submissions, just like a top-level form - }} - onSubmitMeta={{} as SomeType} - > - {(group) => ( - // Use `group().handleSubmit()` to submit the sub-form, but not the parent form - // ... - )} - - - - - {(group) => ( - // Then, use `form.handleSubmit()` to submit the entire form - // ... - )} - - - -) -``` - -## Form Group Validation - -Form groups have a distinct validation proceedure that we think makes sense for sub-forms: - -- Form groups can have their own validation: - -```tsx - 'Error' }}> - {(group) => { - group().state.meta.errorMap // {onChange: "Error" | undefined} - group().state.meta.errors // ("Error")[] - }} - -``` - -- Can set errors on sub-fields: - -```tsx - ({ - group: value.name === 'error' ? 'Group error' : undefined, - fields: { - // Must use the name of the field relative to the FormGroup as the error key, - // to stay consistent with how standard schema works with form groups - name: value.name === 'error' ? 'Field error' : undefined, - }, - }), - }} -/> -``` - -- And can even accept standard schemas: - -```tsx - -``` - -> The reason we don't use the full path names for fields is so that you can compose your schemas like so: -> -> ``` -> const step1Schema = z.object({ -> name: z.string().min(2) -> }) -> -> const schema = z.object({ -> step1: step1Schema, -> step2: step2Schema -> }) -> ``` -> -> And pass the `step1Schema` to a form group and `schema` to the parent form. That way, partially validated data will still flag errors if the group is bypassed. - -### Dynamic Group Validation - -If you want to use [dynamic validation (`onDynamic`)](./dynamic-validation.md) with a form group, do not rely on the `onDynamic` validator passed to `createForm`: - -```tsx -createForm(() => ({ - validationLogic: revalidateLogic(), - validators: { - // This validator will not run `onChange` when a sub-form is submitted; - // it will only run `onChange` when the form itself is submitted. - onDynamic: schema, - }, -})) -``` - -Instead, pass your sub-schema for the group to the `onDynamic` validation of the `FormGroup` itself: - -```tsx - -``` - -It will treat `group().submissionAttempts` as the way to change what validator is ran before/after submit. - -## Form Group State - -Just like you're able to access `group().state.meta.errors`, you're also able to access the group's value using `group().state.value`. Likewise, here are some valuable properties you can access in the `group().state.meta`: - -- `group().state.meta.isFieldsValid`: `true` when the field-level validators have no errors -- `group().state.meta.isGroupValid`: `true` when the group-level validators have no errors -- `group().state.meta.isValid`: `true` when both the field-level and group-level validators have no errors -- `group().state.meta.isSubmitting`: `true` when the group is in the process of being submitted diff --git a/docs/framework/solid/guides/linked-fields.md b/docs/framework/solid/guides/linked-fields.md deleted file mode 100644 index 489a05436f..0000000000 --- a/docs/framework/solid/guides/linked-fields.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -id: linked-fields -title: Link Two Form Fields Together ---- - -You may find yourself needing to link two fields together; when one is validated as another field's value has changed. -One such usage is when you have both a `password` and `confirm_password` field, -where you want to `confirm_password` to error out when `password`'s value does not match; -regardless of which field triggered the value change. - -Imagine the following userflow: - -- User updates confirm password field. -- User updates the non-confirm password field. - -In this example, the form will still have errors present, -as the "confirm password" field validation has not been re-ran to mark as accepted. - -To solve this, we need to make sure that the "confirm password" validation is re-run when the password field is updated. -To do this, you can add a `onChangeListenTo` property to the `confirm_password` field. - -```tsx -export default function App() { - const form = createForm(() => ({ - defaultValues: { - password: '', - confirm_password: '', - }, - // ... - })) - - return ( -
    - - {(field) => ( - - )} - - { - if (value !== fieldApi.form.getFieldValue('password')) { - return 'Passwords do not match' - } - return undefined - }, - }} - > - {(field) => ( -
    - - - {(err) =>
    {err()}
    } -
    -
    - )} -
    -
    - ) -} -``` - -This similarly works with `onBlurListenTo` property, which will re-run the validation when the field is blurred. diff --git a/docs/framework/solid/guides/submission-handling.md b/docs/framework/solid/guides/submission-handling.md deleted file mode 100644 index 0ff523e1c0..0000000000 --- a/docs/framework/solid/guides/submission-handling.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -id: submission-handling -title: Submission handling ---- - -## Passing additional data to submission handling - -You may have multiple types of submission behaviour, for example, going back to another page or staying on the form. -You can accomplish this by specifying the `onSubmitMeta` property. This meta data will be passed to the `onSubmit` function. - -> Note: if `form.handleSubmit()` is called without metadata, it will use the provided default. - -```tsx -import { createForm } from '@tanstack/solid-form' - -type FormMeta = { - submitAction: 'continue' | 'backToMenu' | null -} - -// Metadata is not required to call form.handleSubmit(). -// Specify what values to use as default if no meta is passed -const defaultMeta: FormMeta = { - submitAction: null, -} - -export default function App() { - const form = createForm(() => ({ - defaultValues: { - data: '', - }, - // Define what meta values to expect on submission - onSubmitMeta: defaultMeta, - onSubmit: async ({ value, meta }) => { - // Do something with the values passed via handleSubmit - console.log(`Selected action - ${meta.submitAction}`, value) - }, - })) - - return ( -
    { - e.preventDefault() - e.stopPropagation() - }} - > - {/* ... */} - - -
    - ) -} -``` - -## Transforming data with Standard Schemas - -While Tanstack Form provides [Standard Schema support](./validation.md) for validation, it does not preserve the Schema's output data. - -The value passed to the `onSubmit` function will always be the input data. To receive the output data of a Standard Schema, parse it in the `onSubmit` function: - -```tsx -import { createForm } from '@tanstack/solid-form' -import { z } from 'zod' - -// ... - -const schema = z.object({ - age: z.string().transform((age) => Number(age)), -}) - -// Tanstack Form uses the input type of Standard Schemas -const defaultValues: z.input = { - age: '13', -} - -const form = createForm(() => ({ - defaultValues, - validators: { - onChange: schema, - }, - onSubmit: ({ value }) => { - const inputAge: string = value.age - // Pass it through the schema to get the transformed value - const result = schema.parse(value) - const outputAge: number = result.age - }, -})) -``` diff --git a/docs/framework/solid/guides/ui-libraries.md b/docs/framework/solid/guides/ui-libraries.md new file mode 100644 index 0000000000..aaef57c636 --- /dev/null +++ b/docs/framework/solid/guides/ui-libraries.md @@ -0,0 +1,87 @@ +--- +id: ui-libraries +title: UI Libraries +--- + +TanStack Form is headless. UI library integration consists of adapting a +field's value, blur callback, change callback, invalid state, and errors to the +component's prop names. + +## Text inputs + +Many Solid text-input components accept DOM-like props: + +```tsx + + {(field) => ( + field().handleChange(event.currentTarget.value)} + error={field() + .errors.map((error) => error.message) + .join(', ')} + /> + )} + +``` + +Pass `value` instead of using a component's one-time default-value prop so the +component reflects form state. + +## Checkboxes and switches + +DOM-style checkbox components expose `event.currentTarget.checked`: + +```tsx + + {(field) => ( + field().handleChange(event.currentTarget.checked)} + aria-invalid={field().meta.isInvalid} + /> + )} + +``` + +Some libraries call back with a boolean, a details object, or a union such as +`boolean | 'indeterminate'`. Normalize that value at the boundary: + +```tsx + field().handleChange(checked === true)} +/> +``` + +## Selects, date pickers, and custom controls + +The integration does not require a native event. Pass the value produced by the +component to `field().handleChange`: + +```tsx + field().handleChange(nextDate)} + onBlur={field().handleBlur} +/> +``` + +Choose a serializable form value appropriate for your application, then adapt +the UI library's richer object at the component boundary if necessary. + +## Reuse the adapter + +If the same wiring appears throughout the application, extract a Solid +component that accepts `Accessor>` or register it with +`createFormHook`. + +For the helper types used when passing a form or field to an extracted +component, see [Splitting forms](../../../splitting-forms). + +The repository's `examples/solid/large-form` example demonstrates reusable +field and form components with the v2 Solid adapter. diff --git a/docs/framework/solid/guides/validation.md b/docs/framework/solid/guides/validation.md index c1ff12dbf0..c1bcd6a4d9 100644 --- a/docs/framework/solid/guides/validation.md +++ b/docs/framework/solid/guides/validation.md @@ -3,566 +3,261 @@ id: form-validation title: Form and Field Validation --- -At the core of TanStack Form's functionalities is the concept of validation. TanStack Form makes validation highly customizable: +TanStack Form supports synchronous, asynchronous, field-level, form-level, and +Standard Schema validation. Every validator is an ordered object with a `run` +implementation and explicit `triggers`. -- You can control when to perform the validation (on change, on input, on blur, on submit...) -- Validation rules can be defined at the field level or at the form level -- Validation can be synchronous or asynchronous (for example, as a result of an API call) +## Choose when validation runs -## When is validation performed? - -It's up to you! The `` component accepts some callbacks as props such as `onChange` or `onBlur`. Those callbacks are passed the current value of the field, as well as the fieldAPI object, so that you can perform the validation. If you find a validation error, simply return the error message as string and it will be available in `field().state.meta.errors`. - -Here is an example: - -```tsx - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {(field) => ( - <> - - field().handleChange(e.target.valueAsNumber)} - /> - {!field().state.meta.isValid ? ( - {field().state.meta.errors.join(', ')} - ) : null} - - )} - -``` - -In the example above, the validation is done at each keystroke (`onChange`). If, instead, we wanted the validation to be done when the field is blurred, we would change the code above like so: - -```tsx - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {(field) => ( - <> - - field().handleChange(e.target.valueAsNumber)} - /> - {!field().state.meta.isValid ? ( - {field().state.meta.errors.join(', ')} - ) : null} - - )} - -``` - -So you can control when the validation is done by implementing the desired callback. You can even perform different pieces of validation at different times: +Use `change` for immediate feedback and `blur` for feedback after leaving an +input. Submission runs validators by default regardless of their configured +change and blur triggers. ```tsx - value < 13 ? 'You must be 13 to make an account' : undefined, - onBlur: ({ value }) => (value < 0 ? 'Invalid value' : undefined), - }} + validators={[ + { + triggers: ['change'], + run: ({ value }) => (value >= 13 ? undefined : 'You must be at least 13'), + }, + { + triggers: ['blur'], + run: ({ value }) => (value >= 0 ? undefined : 'Age cannot be negative'), + }, + ]} > {(field) => ( - <> - + )} ``` -In the example above, we are validating different things on the same field at different times (at each keystroke and when blurring the field). Since `field().state.meta.errors` is an array, all the relevant errors at a given time are displayed. You can also use `field().state.meta.errorMap` to get errors based on _when_ the validation was done (onChange, onBlur etc...). More info about displaying errors below. +Additional controls include: -## Displaying Errors +- `runOnMount`: run once when the form is constructed or when a field or form + group first mounts. +- `skipOnSubmit`: conditionally skip submit-time execution. +- `triggerDebounceMs`: debounce change and blur execution. +- `bailIfInvalid`: skip this and subsequent validators when an earlier one + failed. +- trigger objects with `when`: enable a trigger conditionally. +- `watchFields`: rerun a field validator when related fields trigger it. -Once you have your validation in place, you can map the errors from an array to be displayed in your UI: - -```tsx - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {(field) => { - return ( - <> - {/* ... */} - {!field().state.meta.isValid ? ( - {field().state.meta.errors.join(',')} - ) : null} - - ) - }} - -``` +## Control when errors are visible -Or use the `errorMap` property to access the specific error you're looking for: +Validation and presentation are separate. `errorVisibility` decides when field +issues appear in `field().errors`: ```tsx - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {(field) => ( - <> - {/* ... */} - {field().state.meta.errorMap['onChange'] ? ( - {field().state.meta.errorMap['onChange']} - ) : null} - - )} - -``` - -It's worth mentioning that our `errors` array and the `errorMap` matches the types returned by the validators. This means that: +import { createForm } from '@tanstack/solid-form' -```tsx - (value < 13 ? { isOldEnough: false } : undefined), - }} -> - {(field) => ( - <> - {/* ... */} - {/* errorMap.onChange is type `{isOldEnough: false} | undefined` */} - {/* meta.errors is type `Array<{isOldEnough: false} | undefined>` */} - {!field().state.meta.errorMap['onChange']?.isOldEnough ? ( - The user is not old enough - ) : null} - - )} - +const form = createForm(() => ({ + defaultValues: { email: '' }, + errorVisibility: ({ fieldState, state }) => + fieldState.meta.isBlurred || state.submissionAttempts > 0, +})) ``` -## Validation at field level vs at form level +Use `field().meta.original.errors` for the unfiltered issues when debugging or +building a custom visibility system. -As shown above, each `` accepts its own validation rules via the `onChange`, `onBlur` etc... callbacks. It is also possible to define validation rules at the form level (as opposed to field by field) by passing similar callbacks to the `createForm()` hook. +## Form-level validation -Example: +A form validator can produce a form issue and route issues to typed field paths +with `createErrorMap`: ```tsx -export default function App() { - const form = createForm(() => ({ - defaultValues: { - age: 0, - }, - onSubmit: async ({ value }) => { - console.log(value) - }, - validators: { - // Add validators to the form the same way you would add them to a field - onChange({ value }) { - if (value.age < 13) { - return 'Must be 13 or older to sign' - } - return undefined - }, - }, - })) - - // Subscribe to the form's error map so that updates to it will render - // alternately, you can use `form.Subscribe` - const formErrorMap = form.useSelector((state) => state.errorMap) - - return ( -
    - {/* ... */} - {formErrorMap().onChange ? ( -
    - There was an error on the form: {formErrorMap().onChange} -
    - ) : null} - {/* ... */} -
    - ) -} -``` - -### Setting field-level errors from the form's validators - -You can set errors on the fields from the form's validators. One common use case for this is validating all the fields on submit by calling a single API endpoint in the form's `onSubmitAsync` validator. - -```tsx -import { Show } from 'solid-js' import { createForm } from '@tanstack/solid-form' -export default function App() { - const form = createForm(() => ({ - defaultValues: { - age: 0, - socials: [], - details: { - email: '', - }, - }, - validators: { - onSubmitAsync: async ({ value }) => { - // Validate the value on the server - const hasErrors = await validateDataOnServer(value) - if (hasErrors) { - return { - form: 'Invalid data', // The `form` key is optional - fields: { - age: 'Must be 13 or older to sign', - // Set errors on nested fields with the field's name - 'socials[0].url': 'The provided URL does not exist', - 'details.email': 'An email is required', - }, - } +const form = createForm(() => ({ + defaultValues: { + email: '', + phone: '', + }, + validators: [ + { + triggers: ['change'], + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() + + if (!value.email && !value.phone) { + errors.form = 'Provide an email address or phone number' + errors.fields.email = 'Email is required when phone is empty' + errors.fields.phone = 'Phone is required when email is empty' } - return null + return errors }, }, - })) - - return ( -
    -
    { - e.preventDefault() - e.stopPropagation() - void form.handleSubmit() - }} - > - ( - <> - - field().handleChange(e.target.valueAsNumber)} - /> - 0}> - {field().state.meta.errors.join(', ')} - - - )} - /> - ({ errors: state.errors })} - children={(state) => ( - 0}> -
    - - There was an error on the form: {state().errors.join(', ')} - -
    -
    - )} - /> - - - {/*...*/} - -
    - ) -} + ], +})) ``` -> Something worth mentioning is that if you have a form validation function that returns an error, that error may be overwritten by the field-specific validation. -> -> This means that: -> -> ```tsx -> const form = createForm(() => ({ -> defaultValues: { -> age: 0, -> }, -> validators: { -> onChange: ({ value }) => { -> return { -> fields: { -> age: value.age < 12 ? 'Too young!' : undefined, -> }, -> }; -> }, -> }, -> })); -> -> return ( -> name="age" -> validators={{ -> onChange: ({ value }) => (value % 2 === 0 ? 'Must be odd!' : undefined), -> }} -> children={() => <>{/* ... */}} -> /> -> ); -> } -> ``` -> -> Will only show `'Must be odd!` even if the 'Too young!' error is returned by the form-level validation. - -## Asynchronous Functional Validation +Use `form.Subscribe` to reactively select form-level issues from +`form.state.errors`. Lower-level integrations can subscribe to `form.atom` with +`useSelector`. Field-routed issues appear in the corresponding +`field().errors`. -While we suspect most validations will be synchronous, there are many instances where a network call or some other async operation would be useful to validate against. +## Asynchronous validation and debouncing -To do this, we have dedicated `onChangeAsync`, `onBlurAsync`, and other methods that can be used to validate against: +`run` may return a promise. Put cheap synchronous checks first and use +`bailIfInvalid` to avoid unnecessary requests: ```tsx { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value < 13 ? 'You must be 13 to make an account' : undefined + name="username" + validators={[ + { + triggers: ['change'], + run: ({ value }) => + value.length >= 3 ? undefined : 'Use at least 3 characters', }, - }} -> - {(field) => ( - <> - - field().handleChange(e.target.valueAsNumber)} - /> - {!field().state.meta.isValid ? ( - {field().state.meta.errors.join(', ')} - ) : null} - - )} - -``` - -Synchronous and Asynchronous validations can coexist. For example, it is possible to define both `onBlur` and `onBlurAsync` on the same field: - -```tsx - (value < 13 ? 'You must be at least 13' : undefined), - onBlurAsync: async ({ value }) => { - const currentAge = await fetchCurrentAgeOnProfile() - return value < currentAge ? 'You can only increase the age' : undefined + { + triggers: ['change'], + triggerDebounceMs: 500, + bailIfInvalid: true, + run: async ({ value }) => { + const available = await checkUsername(value) + return available ? undefined : 'That username is already taken' + }, }, - }} + ]} > {(field) => ( - <> - - field().handleChange(e.target.valueAsNumber)} - /> - {field().state.meta.errors ? ( - {field().state.meta.errors.join(', ')} - ) : null} - + field().handleChange(event.currentTarget.value)} + /> )} ``` -The synchronous validation method (`onBlur`) is run first and the asynchronous method (`onBlurAsync`) is only run if the synchronous one (`onBlur`) succeeds. To change this behaviour, set the `asyncAlways` option to `true`, and the async method will be run regardless of the result of the sync method. - -### Built-in Debouncing +Submit validation always runs immediately, even when a trigger is debounced. +`field().meta.isValidating` and `form.state.isValidating` expose pending work. -While async calls are the way to go when validating against the database, running a network request on every keystroke is a good way to DDOS your database. +## Standard Schema validation -Instead, we enable an easy method for debouncing your `async` calls by adding a single property: - -```tsx - { - // ... - }, - }} - children={(field) => { - return <>{/* ... */} - }} -/> -``` - -This will debounce every async call with a 500ms delay. You can even override this property on a per-validation property: - -```tsx - { - // ... - }, - onBlurAsync: async ({ value }) => { - // ... - }, - }} - children={(field) => { - return <>{/* ... */} - }} -/> -``` - -This will run `onChangeAsync` every 1500ms while `onBlurAsync` will run every 500ms. - -## Validation through Schema Libraries - -While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries that provide schema-based validation to make shorthand and type-strict validation substantially easier. You can also define a single schema for your entire form and pass it to the form level, errors will be automatically propagated to the fields. - -### Standard Schema Libraries - -TanStack Form natively supports all libraries following the [Standard Schema specification](https://github.com/standard-schema/standard-schema), most notably: - -- [Zod](https://zod.dev/) -- [Valibot](https://valibot.dev/) -- [ArkType](https://arktype.io/) - -_Note:_ make sure to use the latest version of the schema libraries as older versions might not support Standard Schema yet. - -> Validation will not provide you with transformed values. See [submission handling](./submission-handling.md) for more information. - -To use schemas from these libraries you can pass them to the `validators` props as you would do with a custom function: +Any Standard Schema implementation can be supplied as `run`: ```tsx +import { createForm } from '@tanstack/solid-form' import { z } from 'zod' -// ... +const accountSchema = z.object({ + email: z.string().email(), + age: z.number().min(13), +}) const form = createForm(() => ({ - // ... + defaultValues: { email: '', age: 0 }, + validators: [ + { + triggers: ['change'], + run: accountSchema, + }, + ], })) - -; { - return <>{/* ... */} - }} -/> ``` -Async validations on form and field level are supported as well: +Schema paths are routed to matching fields. Parsed outputs are available by +validator index in `schemaOutputs` during submit, for example +`schemaOutputs[0]`. `value` remains the form's raw editable state rather than +the parsed output. -```tsx - { - const currentAge = await fetchCurrentAgeOnProfile() - return value >= currentAge - }, - { - message: 'You can only increase the age', - }, - ), - }} - children={(field) => { - return <>{/* ... */} - }} -/> -``` +For custom schema routing, call a schema's safe parse API inside `run` and pass +its issues to the provided `parseIssues` helper. -If you need even more control over your Standard Schema validation, you can combine a Standard Schema with a callback function like so: +## Validate related fields + +Use `watchFields` when one field's validity depends on another: ```tsx { - const errors = fieldApi.parseValueWithSchema( - z.number().gte(13, 'You must be 13 to make an account'), - ) - - if (errors) return errors - - // continue with your validation + name="endDate" + validators={[ + { + triggers: ['change', 'blur'], + watchFields: ['startDate'], + run: ({ value, formApi }) => + value >= formApi.getFieldValue('startDate') + ? undefined + : 'End date must be on or after the start date', }, - }} - children={(field) => { - return <>{/* ... */} - }} -/> + ]} +> + {(field) => ( + field().handleChange(event.currentTarget.value)} + aria-invalid={field().meta.isInvalid} + /> + )} + ``` -## Preventing invalid forms from being submitted - -The `onChange`, `onBlur` etc... callbacks are also run when the form is submitted and the submission is blocked if the form is invalid. +## Return errors from submission -The form state object has a `canSubmit` flag that is false when any field is invalid and the form has been touched (`canSubmit` is true until the form has been touched, even if some fields are "technically" invalid based on their `onChange`/`onBlur` props). - -You can subscribe to it via `form.Subscribe` and use the value in order to, for example, disable the submit button when the form is invalid (in practice, disabled buttons are not accessible, use `aria-disabled` instead). +Endpoint validation belongs in `onSubmit`. Return +`createValidationError(...)` to feed server issues back into normal form state: ```tsx +import { createForm } from '@tanstack/solid-form' + const form = createForm(() => ({ - /* ... */ + defaultValues: { email: '' }, + onSubmit: async ({ value, createValidationError }) => { + const result = await saveProfile(value) + + if (!result.ok) { + return createValidationError({ + form: 'Could not save the profile', + fields: { email: 'This email is already registered' }, + }) + } + + return null + }, })) +``` + +## Prevent invalid submission -return ( - /* ... */ - - // Dynamic submit button - ({ - canSubmit: state.canSubmit, - isSubmitting: state.isSubmitting, - })} - children={(state) => ( - - )} - /> -) +`form.handleSubmit()` skips `onSubmit` when validation fails and resolves with +the validation errors. `onSubmitInvalid` is currently available on form groups; +root-form support is planned but not yet implemented. Subscribe to `canSubmit` +and `isSubmitting` to reflect that state in the submit UI: + +```tsx + [state.canSubmit, state.isSubmitting] as const} +> + {(state) => ( + + )} + ``` -To prevent the form from being submitted before any interaction, combine `canSubmit` with `isPristine` flags. A simple condition like `!canSubmit || isPristine` effectively disables submissions until the user has made changes. +If a disabled submit button would hide useful validation feedback, keep it +focusable with `aria-disabled` and let `handleSubmit()` report the issues. diff --git a/docs/framework/solid/quick-start.md b/docs/framework/solid/quick-start.md index 36561fe6d6..4d645c76d1 100644 --- a/docs/framework/solid/quick-start.md +++ b/docs/framework/solid/quick-start.md @@ -3,50 +3,117 @@ id: quick-start title: Quick Start --- -The bare minimum to get started with TanStack Form is to create a form and add a field. Keep in mind that this example does not include any validation or error handling... yet. +TanStack Form is a headless, type-safe form library. It owns form state and +validation while leaving markup, styling, and component choice to you. + +Install the Solid adapter: + +```bash +npm install @tanstack/solid-form +``` + +## Create a form + +`createForm` requires an options accessor and form-level `defaultValues`. Their +shape becomes the form's inferred value type. ```tsx +import { For } from 'solid-js' import { createForm } from '@tanstack/solid-form' -function App() { +export function ProfileForm() { const form = createForm(() => ({ defaultValues: { fullName: '', + age: 0, }, onSubmit: async ({ value }) => { - // Do something with form data console.log(value) }, })) return ( -
    -

    Simple Form Example

    -
    { - e.preventDefault() - e.stopPropagation() - form.handleSubmit() - }} + { + event.preventDefault() + form.handleSubmit() + }} + > + + value.trim() ? undefined : 'Enter your full name', + }, + ]} > -
    - ( - field().handleChange(e.target.value)} - /> - )} - /> -
    - - -
    + {(field) => ( + + )} +
    + + + value >= 13 ? undefined : 'You must be at least 13', + }, + ]} + > + {(field) => ( + + )} + + + [state.canSubmit, state.isSubmitting] as const} + > + {(state) => ( + + )} + + ) } ``` -From here, you'll be ready to explore all of the other features of TanStack Form! +The important pieces are: + +- `defaultValues` define the complete initial value and drive type inference. +- `form.Field` subscribes to one field. Its child receives an accessor that + exposes `field().value`, `field().meta`, and event handlers. +- Validators are ordered objects with a `run` function and explicit `triggers`. +- `form.Subscribe` exposes the selected form state as a Solid accessor. +- `form.handleSubmit()` validates the form before calling `onSubmit`. diff --git a/docs/framework/solid/reference/classes/ReadonlyStore.md b/docs/framework/solid/reference/classes/ReadonlyStore.md new file mode 100644 index 0000000000..e764546914 --- /dev/null +++ b/docs/framework/solid/reference/classes/ReadonlyStore.md @@ -0,0 +1,122 @@ +--- +id: ReadonlyStore +title: ReadonlyStore +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:22 + +## Type Parameters + +### T + +`T` + +## Implements + +- `Omit`\<[`Store`](Store.md)\<`T`\>, `"setState"` \| `"actions"`\> + +## Constructors + +### Constructor + +```ts +new ReadonlyStore(getValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:24 + +#### Parameters + +##### getValue + +(`prev?`) => `T` + +#### Returns + +`ReadonlyStore`\<`T`\> + +### Constructor + +```ts +new ReadonlyStore(initialValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:25 + +#### Parameters + +##### initialValue + +`T` + +#### Returns + +`ReadonlyStore`\<`T`\> + +## Accessors + +### state + +#### Get Signature + +```ts +get state(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:26 + +##### Returns + +`T` + +#### Implementation of + +```ts +Omit.state +``` + +## Methods + +### get() + +```ts +get(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:27 + +#### Returns + +`T` + +#### Implementation of + +```ts +Omit.get +``` + +*** + +### subscribe() + +```ts +subscribe(observerOrFn): Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:28 + +#### Parameters + +##### observerOrFn + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +#### Returns + +[`Subscription`](../interfaces/Subscription.md) + +#### Implementation of + +```ts +Omit.subscribe +``` diff --git a/docs/framework/solid/reference/classes/Store.md b/docs/framework/solid/reference/classes/Store.md new file mode 100644 index 0000000000..3e93a261b2 --- /dev/null +++ b/docs/framework/solid/reference/classes/Store.md @@ -0,0 +1,156 @@ +--- +id: Store +title: Store +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:11 + +## Type Parameters + +### T + +`T` + +### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) = `never` + +## Constructors + +### Constructor + +```ts +new Store(getValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:14 + +#### Parameters + +##### getValue + +(`prev?`) => `T` + +#### Returns + +`Store`\<`T`, `TActions`\> + +### Constructor + +```ts +new Store(initialValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:15 + +#### Parameters + +##### initialValue + +`T` + +#### Returns + +`Store`\<`T`, `TActions`\> + +### Constructor + +```ts +new Store(initialValue, actionsFactory): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:16 + +#### Parameters + +##### initialValue + +`NonFunction`\<`T`\> + +##### actionsFactory + +[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> + +#### Returns + +`Store`\<`T`, `TActions`\> + +## Properties + +### actions + +```ts +readonly actions: TActions; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:13 + +## Accessors + +### state + +#### Get Signature + +```ts +get state(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:18 + +##### Returns + +`T` + +## Methods + +### get() + +```ts +get(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:19 + +#### Returns + +`T` + +*** + +### setState() + +```ts +setState(updater): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:17 + +#### Parameters + +##### updater + +(`prev`) => `T` + +#### Returns + +`void` + +*** + +### subscribe() + +```ts +subscribe(observerOrFn): Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:20 + +#### Parameters + +##### observerOrFn + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +#### Returns + +[`Subscription`](../interfaces/Subscription.md) diff --git a/docs/framework/solid/reference/functions/Field.md b/docs/framework/solid/reference/functions/Field.md deleted file mode 100644 index 216195906b..0000000000 --- a/docs/framework/solid/reference/functions/Field.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -id: Field -title: Field ---- - -# Function: Field() - -```ts -function Field(props): Element; -``` - -Defined in: [packages/solid-form/src/createField.tsx:660](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createField.tsx#L660) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Parameters - -### props - -`FieldComponentProps`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Returns - -`Element` diff --git a/docs/framework/solid/reference/functions/FormGroup.md b/docs/framework/solid/reference/functions/FormGroup.md deleted file mode 100644 index 215cf7cea9..0000000000 --- a/docs/framework/solid/reference/functions/FormGroup.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -id: FormGroup -title: FormGroup ---- - -# Function: FormGroup() - -```ts -function FormGroup(props): Element; -``` - -Defined in: [packages/solid-form/src/createFormGroup.tsx:524](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createFormGroup.tsx#L524) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Parameters - -### props - -`FormGroupComponentProps`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Returns - -`Element` diff --git a/docs/framework/solid/reference/functions/Subscribe.md b/docs/framework/solid/reference/functions/Subscribe.md new file mode 100644 index 0000000000..1faeee1a56 --- /dev/null +++ b/docs/framework/solid/reference/functions/Subscribe.md @@ -0,0 +1,32 @@ +--- +id: Subscribe +title: Subscribe +--- + +```ts +function Subscribe(props): Element; +``` + +Defined in: [packages/solid-form/src/Subscribe.public.ts:22](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Subscribe.public.ts#L22) + +Subscribe to a TanStack Store source and expose the selection as an accessor. + +## Type Parameters + +### TSourceData + +`TSourceData` + +### TSelected + +`TSelected` + +## Parameters + +### props + +[`SubscribeProps`](../interfaces/SubscribeProps.md)\<`TSourceData`, `TSelected`\> + +## Returns + +`Element` diff --git a/docs/framework/solid/reference/functions/batch.md b/docs/framework/solid/reference/functions/batch.md new file mode 100644 index 0000000000..ad5677dbb2 --- /dev/null +++ b/docs/framework/solid/reference/functions/batch.md @@ -0,0 +1,20 @@ +--- +id: batch +title: batch +--- + +```ts +function batch(fn): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:5 + +## Parameters + +### fn + +() => `void` + +## Returns + +`void` diff --git a/docs/framework/solid/reference/functions/createAsyncAtom.md b/docs/framework/solid/reference/functions/createAsyncAtom.md new file mode 100644 index 0000000000..5ec22ca780 --- /dev/null +++ b/docs/framework/solid/reference/functions/createAsyncAtom.md @@ -0,0 +1,30 @@ +--- +id: createAsyncAtom +title: createAsyncAtom +--- + +```ts +function createAsyncAtom(getValue, options?): ReadonlyAtom>; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:16 + +## Type Parameters + +### T + +`T` + +## Parameters + +### getValue + +() => `Promise`\<`T`\> + +### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`AsyncAtomState`\<`T`, `unknown`\>\> + +## Returns + +[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`AsyncAtomState`\<`T`, `unknown`\>\> diff --git a/docs/framework/solid/reference/functions/createAtom.md b/docs/framework/solid/reference/functions/createAtom.md new file mode 100644 index 0000000000..d41435b132 --- /dev/null +++ b/docs/framework/solid/reference/functions/createAtom.md @@ -0,0 +1,60 @@ +--- +id: createAtom +title: createAtom +--- + +## Call Signature + +```ts +function createAtom(getValue, options?): ReadonlyAtom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:17 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`T`\> + +## Call Signature + +```ts +function createAtom(initialValue, options?): Atom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:18 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`Atom`](../interfaces/Atom.md)\<`T`\> diff --git a/docs/framework/solid/reference/functions/createField.md b/docs/framework/solid/reference/functions/createField.md deleted file mode 100644 index c13a0e996f..0000000000 --- a/docs/framework/solid/reference/functions/createField.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -id: createField -title: createField ---- - -# Function: createField() - -```ts -function createField(opts): () => FieldApi & SolidFieldApi; -``` - -Defined in: [packages/solid-form/src/createField.tsx:218](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createField.tsx#L218) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Parameters - -### opts - -() => [`CreateFieldOptions`](../interfaces/CreateFieldOptions.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Returns - -```ts -(): FieldApi & SolidFieldApi; -``` - -### Returns - -`FieldApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> & `SolidFieldApi`\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> diff --git a/docs/framework/solid/reference/functions/createFieldGroup.md b/docs/framework/solid/reference/functions/createFieldGroup.md deleted file mode 100644 index 6d72365f3f..0000000000 --- a/docs/framework/solid/reference/functions/createFieldGroup.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -id: createFieldGroup -title: createFieldGroup ---- - -# Function: createFieldGroup() - -```ts -function createFieldGroup(opts): AppFieldExtendedSolidFieldGroupApi; -``` - -Defined in: [packages/solid-form/src/createFieldGroup.tsx:74](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createFieldGroup.tsx#L74) - -## Type Parameters - -### TFormData - -`TFormData` - -### TFieldGroupData - -`TFieldGroupData` - -### TFields - -`TFields` *extends* - \| `string` - \| \{ \[K in string \| number \| symbol\]: DeepKeysOfType\ \} - -### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TComponents - -`TComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> - -### TFormComponents - -`TFormComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> - -### TSubmitMeta - -`TSubmitMeta` = `never` - -## Parameters - -### opts - -() => `object` - -## Returns - -`AppFieldExtendedSolidFieldGroupApi`\<`TFormData`, `TFieldGroupData`, `TFields`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents`, `TFormComponents`\> diff --git a/docs/framework/solid/reference/functions/createForm.md b/docs/framework/solid/reference/functions/createForm.md deleted file mode 100644 index b0617a38f7..0000000000 --- a/docs/framework/solid/reference/functions/createForm.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -id: createForm -title: createForm ---- - -# Function: createForm() - -```ts -function createForm(opts?): FormApi & SolidFormApi; -``` - -Defined in: [packages/solid-form/src/createForm.tsx:213](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createForm.tsx#L213) - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` - -## Parameters - -### opts? - -() => `FormOptions`\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> - -## Returns - -`FormApi`\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> & [`SolidFormApi`](../interfaces/SolidFormApi.md)\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> diff --git a/docs/framework/solid/reference/functions/createFormGroup.md b/docs/framework/solid/reference/functions/createFormGroup.md deleted file mode 100644 index 6effb94557..0000000000 --- a/docs/framework/solid/reference/functions/createFormGroup.md +++ /dev/null @@ -1,134 +0,0 @@ ---- -id: createFormGroup -title: createFormGroup ---- - -# Function: createFormGroup() - -```ts -function createFormGroup(opts): () => FormGroupApi; -``` - -Defined in: [packages/solid-form/src/createFormGroup.tsx:127](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createFormGroup.tsx#L127) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Parameters - -### opts - -() => `FormGroupApiOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Returns - -```ts -(): FormGroupApi; -``` - -### Returns - -`FormGroupApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> diff --git a/docs/framework/solid/reference/functions/createFormHook.md b/docs/framework/solid/reference/functions/createFormHook.md index a4afeba67a..4132e0a28b 100644 --- a/docs/framework/solid/reference/functions/createFormHook.md +++ b/docs/framework/solid/reference/functions/createFormHook.md @@ -3,278 +3,34 @@ id: createFormHook title: createFormHook --- -# Function: createFormHook() - ```ts -function createFormHook(opts): object; +function createFormHook(createOptions): AppFormHookResult<{ + fieldComponents: TFieldComponents; + formComponents: TFormComponents; +}>; ``` -Defined in: [packages/solid-form/src/createFormHook.tsx:300](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createFormHook.tsx#L300) +Defined in: [packages/solid-form/src/AppForm/createFormHook.public.ts:14](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/createFormHook.public.ts#L14) ## Type Parameters -### TComponents - -`TComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> - ### TFormComponents `TFormComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> -## Parameters - -### opts - -`CreateFormHookProps`\<`TComponents`, `TFormComponents`\> - -## Returns - -`object` - -### useAppForm() - -```ts -useAppForm: (props) => AppFieldExtendedSolidFormApi; -``` - -#### Type Parameters - -##### TFormData - -`TFormData` - -##### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TSubmitMeta - -`TSubmitMeta` - -#### Parameters - -##### props - -`Accessor`\<`FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\>\> - -#### Returns - -`AppFieldExtendedSolidFormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents`, `TFormComponents`\> - -### withFieldGroup() - -```ts -withFieldGroup: (__namedParameters) => (params) => Element; -``` - -#### Type Parameters - -##### TFieldGroupData - -`TFieldGroupData` - -##### TSubmitMeta - -`TSubmitMeta` - -##### TRenderProps - -`TRenderProps` *extends* `Record`\<`string`, `unknown`\> = \{ -\} - -#### Parameters - -##### \_\_namedParameters - -[`WithFieldGroupProps`](../interfaces/WithFieldGroupProps.md)\<`TFieldGroupData`, `TComponents`, `TFormComponents`, `TSubmitMeta`, `TRenderProps`\> - -#### Returns - -```ts -(params): Element; -``` - -##### Type Parameters - -###### TFormData - -`TFormData` - -###### TFields - -`TFields` *extends* - \| `string` - \| \{ \[K in string \| number \| symbol\]: DeepKeysOfType\ \} +### TFieldComponents -###### TOnMount +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -###### TFormSubmitMeta - -`TFormSubmitMeta` - -##### Parameters - -###### params - -`ParentProps`\<`NoInfer`\<`TRenderProps`\> & `object`\> - -##### Returns - -`Element` - -### withForm() - -```ts -withForm: (__namedParameters) => (props) => Element; -``` - -#### Type Parameters - -##### TFormData - -`TFormData` - -##### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -##### TSubmitMeta - -`TSubmitMeta` - -##### TRenderProps - -`TRenderProps` *extends* `Record`\<`string`, `unknown`\> = \{ -\} - -#### Parameters - -##### \_\_namedParameters - -[`WithFormProps`](../interfaces/WithFormProps.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`, `TComponents`, `TFormComponents`, `TRenderProps`\> - -#### Returns - -```ts -(props): Element; -``` - -##### Parameters +## Parameters -###### props +### createOptions -`ParentProps`\<`NoInfer`\<`UnwrapOrAny`\<`TRenderProps`\>\> & `object`\> +[`CreateFormHookOptions`](../interfaces/CreateFormHookOptions.md)\<`TFormComponents`, `TFieldComponents`\> -##### Returns +## Returns -`Element` +[`AppFormHookResult`](../interfaces/AppFormHookResult.md)\<\{ + `fieldComponents`: `TFieldComponents`; + `formComponents`: `TFormComponents`; +\}\> diff --git a/docs/framework/solid/reference/functions/createFormHookContexts.md b/docs/framework/solid/reference/functions/createFormHookContexts.md deleted file mode 100644 index 2719651e14..0000000000 --- a/docs/framework/solid/reference/functions/createFormHookContexts.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -id: createFormHookContexts -title: createFormHookContexts ---- - -# Function: createFormHookContexts() - -```ts -function createFormHookContexts(): object; -``` - -Defined in: [packages/solid-form/src/createFormHook.tsx:69](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createFormHook.tsx#L69) - -## Returns - -`object` - -### fieldContext - -```ts -fieldContext: Context>; -``` - -### formContext - -```ts -formContext: Context; -``` - -### useFieldContext() - -```ts -useFieldContext: () => Accessor>; -``` - -#### Type Parameters - -##### TData - -`TData` - -#### Returns - -`Accessor`\<`FieldApi`\<`any`, `string`, `TData`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`\>\> - -### useFormContext() - -```ts -useFormContext: () => SolidFormExtendedApi, any, any, any, any, any, any, any, any, any, any, any>; -``` - -#### Returns - -[`SolidFormExtendedApi`](../type-aliases/SolidFormExtendedApi.md)\<`Record`\<`string`, `never`\>, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`\> diff --git a/docs/framework/solid/reference/functions/createStore.md b/docs/framework/solid/reference/functions/createStore.md new file mode 100644 index 0000000000..069cfed200 --- /dev/null +++ b/docs/framework/solid/reference/functions/createStore.md @@ -0,0 +1,84 @@ +--- +id: createStore +title: createStore +--- + +## Call Signature + +```ts +function createStore(getValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:30 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +### Returns + +[`ReadonlyStore`](../classes/ReadonlyStore.md)\<`T`\> + +## Call Signature + +```ts +function createStore(initialValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:31 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +### Returns + +[`Store`](../classes/Store.md)\<`T`\> + +## Call Signature + +```ts +function createStore(initialValue, actions): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:32 + +### Type Parameters + +#### T + +`T` + +#### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) + +### Parameters + +#### initialValue + +`NonFunction`\<`T`\> + +#### actions + +[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> + +### Returns + +[`Store`](../classes/Store.md)\<`T`, `TActions`\> diff --git a/docs/framework/solid/reference/functions/createStoreContext.md b/docs/framework/solid/reference/functions/createStoreContext.md new file mode 100644 index 0000000000..ccc77349c7 --- /dev/null +++ b/docs/framework/solid/reference/functions/createStoreContext.md @@ -0,0 +1,89 @@ +--- +id: createStoreContext +title: createStoreContext +--- + +```ts +function createStoreContext(): object; +``` + +Defined in: node\_modules/.pnpm/@tanstack+solid-store@0.11.1\_solid-js@1.9.14/node\_modules/@tanstack/solid-store/dist/createStoreContext.d.ts:43 + +Creates a typed Solid context for sharing a bundle of atoms and stores with a +subtree. + +The returned `StoreProvider` only transports the provided object through +Solid context. Consumers destructure the contextual atoms and stores, then +compose them with the existing hooks like [useSelector](useSelector.md) and +[useAtom](useAtom.md). + +The object shape is preserved exactly, so keyed atoms and stores remain fully +typed when read back with `useStoreContext()`. + +## Type Parameters + +### TValue + +`TValue` *extends* `object` + +## Returns + +`object` + +### StoreProvider + +```ts +StoreProvider: (props) => Element; +``` + +#### Parameters + +##### props + +`ParentProps`\<\{ + `value`: `TValue`; +\}\> + +#### Returns + +`Element` + +### useStoreContext + +```ts +useStoreContext: () => TValue; +``` + +#### Returns + +`TValue` + +## Example + +```tsx +const { StoreProvider, useStoreContext } = createStoreContext<{ + countAtom: Atom + totalsStore: Store<{ count: number }> +}>() + +function CountButton() { + const { countAtom, totalsStore } = useStoreContext() + const count = useSelector(countAtom) + const total = useSelector(totalsStore, (state) => state.count) + + return ( + + ) +} +``` + +## Throws + +When `useStoreContext()` is called outside the matching `StoreProvider`. diff --git a/docs/framework/solid/reference/functions/flush.md b/docs/framework/solid/reference/functions/flush.md new file mode 100644 index 0000000000..a229192539 --- /dev/null +++ b/docs/framework/solid/reference/functions/flush.md @@ -0,0 +1,14 @@ +--- +id: flush +title: flush +--- + +```ts +function flush(): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:6 + +## Returns + +`void` diff --git a/docs/framework/solid/reference/functions/getFormHookHelpers.md b/docs/framework/solid/reference/functions/getFormHookHelpers.md new file mode 100644 index 0000000000..1e3b993a42 --- /dev/null +++ b/docs/framework/solid/reference/functions/getFormHookHelpers.md @@ -0,0 +1,14 @@ +--- +id: getFormHookHelpers +title: getFormHookHelpers +--- + +```ts +function getFormHookHelpers(): FormHookHelpers; +``` + +Defined in: [packages/solid-form/src/AppForm/getFormHookHelpers.public.ts:86](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/getFormHookHelpers.public.ts#L86) + +## Returns + +[`FormHookHelpers`](../interfaces/FormHookHelpers.md) diff --git a/docs/framework/solid/reference/functions/shallow.md b/docs/framework/solid/reference/functions/shallow.md new file mode 100644 index 0000000000..db1f393577 --- /dev/null +++ b/docs/framework/solid/reference/functions/shallow.md @@ -0,0 +1,30 @@ +--- +id: shallow +title: shallow +--- + +```ts +function shallow(objA, objB): boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/shallow.d.ts:2 + +## Type Parameters + +### T + +`T` + +## Parameters + +### objA + +`T` + +### objB + +`T` + +## Returns + +`boolean` diff --git a/docs/framework/solid/reference/functions/toObserver.md b/docs/framework/solid/reference/functions/toObserver.md new file mode 100644 index 0000000000..add0d3bbdf --- /dev/null +++ b/docs/framework/solid/reference/functions/toObserver.md @@ -0,0 +1,37 @@ +--- +id: toObserver +title: toObserver +--- + +```ts +function toObserver( + nextHandler?, + errorHandler?, +completionHandler?): Observer; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:4 + +## Type Parameters + +### T + +`T` + +## Parameters + +### nextHandler? + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +### errorHandler? + +(`error`) => `void` + +### completionHandler? + +() => `void` + +## Returns + +[`Observer`](../type-aliases/Observer.md)\<`T`\> diff --git a/docs/framework/solid/reference/functions/useAtom.md b/docs/framework/solid/reference/functions/useAtom.md new file mode 100644 index 0000000000..5252104261 --- /dev/null +++ b/docs/framework/solid/reference/functions/useAtom.md @@ -0,0 +1,47 @@ +--- +id: useAtom +title: useAtom +--- + +```ts +function useAtom(atom, options?): [Accessor, (fn) => void & (value) => void]; +``` + +Defined in: node\_modules/.pnpm/@tanstack+solid-store@0.11.1\_solid-js@1.9.14/node\_modules/@tanstack/solid-store/dist/useAtom.d.ts:23 + +Returns the current atom accessor together with a setter. + +Use this when a component needs to both read and update the same writable +atom. + +## Type Parameters + +### TValue + +`TValue` + +## Parameters + +### atom + +[`Atom`](../interfaces/Atom.md)\<`TValue`\> + +### options? + +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TValue`\> + +## Returns + +\[`Accessor`\<`TValue`\>, (`fn`) => `void` & (`value`) => `void`\] + +## Example + +```tsx +const [count, setCount] = useAtom(countAtom) + +return ( + +) +``` diff --git a/docs/framework/solid/reference/functions/useSelector.md b/docs/framework/solid/reference/functions/useSelector.md index 5f1b554978..59da1f1e55 100644 --- a/docs/framework/solid/reference/functions/useSelector.md +++ b/docs/framework/solid/reference/functions/useSelector.md @@ -3,8 +3,6 @@ id: useSelector title: useSelector --- -# Function: useSelector() - ```ts function useSelector( source, @@ -12,7 +10,7 @@ function useSelector( options?): Accessor; ``` -Defined in: node\_modules/.pnpm/@tanstack+solid-store@0.11.0\_solid-js@1.9.13/node\_modules/@tanstack/solid-store/dist/useSelector.d.ts:34 +Defined in: node\_modules/.pnpm/@tanstack+solid-store@0.11.1\_solid-js@1.9.14/node\_modules/@tanstack/solid-store/dist/useSelector.d.ts:34 Selects a slice of state from an atom or store and subscribes the component to that selection. @@ -44,7 +42,7 @@ Omit the selector to subscribe to the whole value. ### options? -`UseSelectorOptions`\<`TSelected`\> +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TSelected`\> ## Returns diff --git a/docs/framework/solid/reference/functions/useStore.md b/docs/framework/solid/reference/functions/useStore.md new file mode 100644 index 0000000000..5cc1f3ce47 --- /dev/null +++ b/docs/framework/solid/reference/functions/useStore.md @@ -0,0 +1,62 @@ +--- +id: _useStore +title: _useStore +--- + +```ts +function _useStore( + store, + selector, + options?): [Accessor, [TActions] extends [never] ? (updater) => void : TActions]; +``` + +Defined in: node\_modules/.pnpm/@tanstack+solid-store@0.11.1\_solid-js@1.9.14/node\_modules/@tanstack/solid-store/dist/\_useStore.d.ts:23 + +Experimental combined read+write hook for stores, mirroring useAtom's tuple +pattern. + +Returns `[selected, actions]` when the store has an actions factory, or +`[selected, setState]` for plain stores. + +## Type Parameters + +### TState + +`TState` + +### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) + +### TSelected + +`TSelected` = `NoInfer`\<`TState`\> + +## Parameters + +### store + +[`Store`](../classes/Store.md)\<`TState`, `TActions`\> + +### selector + +(`state`) => `TSelected` + +### options? + +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TSelected`\> + +## Returns + +\[`Accessor`\<`TSelected`\>, \[`TActions`\] *extends* \[`never`\] ? (`updater`) => `void` : `TActions`\] + +## Example + +```tsx +// Store with actions +const [cats, { addCat }] = _useStore(petStore, (s) => s.cats) + +// Store without actions +const [count, setState] = _useStore(plainStore, (s) => s) +setState((prev) => prev + 1) +``` diff --git a/docs/framework/solid/reference/index.md b/docs/framework/solid/reference/index.md index d96e438f5e..853307f9be 100644 --- a/docs/framework/solid/reference/index.md +++ b/docs/framework/solid/reference/index.md @@ -3,35 +3,99 @@ id: "@tanstack/solid-form" title: "@tanstack/solid-form" --- -# @tanstack/solid-form +## Classes + +- [ReadonlyStore](classes/ReadonlyStore.md) +- [Store](classes/Store.md) ## Interfaces -- [CreateFieldOptions](interfaces/CreateFieldOptions.md) -- [CreateFieldOptionsBound](interfaces/CreateFieldOptionsBound.md) -- [SolidFormApi](interfaces/SolidFormApi.md) -- [WithFieldGroupProps](interfaces/WithFieldGroupProps.md) -- [WithFormProps](interfaces/WithFormProps.md) +- [AppFormHookResult](interfaces/AppFormHookResult.md) +- [Atom](interfaces/Atom.md) +- [AtomOptions](interfaces/AtomOptions.md) +- [BaseAtom](interfaces/BaseAtom.md) +- [CreateFormHookOptions](interfaces/CreateFormHookOptions.md) +- [FieldGroupApi](interfaces/FieldGroupApi.md) +- [FieldGroupArrayFieldComponent](interfaces/FieldGroupArrayFieldComponent.md) +- [FieldGroupDefinition](interfaces/FieldGroupDefinition.md) +- [FieldGroupFieldComponent](interfaces/FieldGroupFieldComponent.md) +- [FormHookHelpers](interfaces/FormHookHelpers.md) +- [InternalBaseAtom](interfaces/InternalBaseAtom.md) +- [InternalReadonlyAtom](interfaces/InternalReadonlyAtom.md) +- [InteropSubscribable](interfaces/InteropSubscribable.md) +- [Readable](interfaces/Readable.md) +- [ReadonlyAtom](interfaces/ReadonlyAtom.md) +- [SolidFormArrayFieldComponent](interfaces/SolidFormArrayFieldComponent.md) +- [SolidFormArrayFieldProps](interfaces/SolidFormArrayFieldProps.md) +- [SolidFormComponentMap](interfaces/SolidFormComponentMap.md) +- [SolidFormFieldComponent](interfaces/SolidFormFieldComponent.md) +- [SolidFormFieldProps](interfaces/SolidFormFieldProps.md) +- [SolidFormGroupApi](interfaces/SolidFormGroupApi.md) +- [SolidFormGroupArrayFieldComponent](interfaces/SolidFormGroupArrayFieldComponent.md) +- [SolidFormGroupComponent](interfaces/SolidFormGroupComponent.md) +- [SolidFormGroupFieldComponent](interfaces/SolidFormGroupFieldComponent.md) +- [SolidFormGroupProps](interfaces/SolidFormGroupProps.md) +- [SolidTanStackFormComponents](interfaces/SolidTanStackFormComponents.md) +- [Subscribable](interfaces/Subscribable.md) +- [SubscribeProps](interfaces/SubscribeProps.md) +- [Subscription](interfaces/Subscription.md) +- [UseSelectorOptions](interfaces/UseSelectorOptions.md) ## Type Aliases -- [FieldComponent](type-aliases/FieldComponent.md) -- [FormGroupComponent](type-aliases/FormGroupComponent.md) -- [LensFieldComponent](type-aliases/LensFieldComponent.md) -- [SolidFormExtendedApi](type-aliases/SolidFormExtendedApi.md) +- [AnyAtom](type-aliases/AnyAtom.md) +- [AnyFieldGroupApi](type-aliases/AnyFieldGroupApi.md) +- [AnySolidFormApi](type-aliases/AnySolidFormApi.md) +- [AnySolidFormComponentMap](type-aliases/AnySolidFormComponentMap.md) +- [AppFormComponent](type-aliases/AppFormComponent.md) +- [CreateFormHook](type-aliases/CreateFormHook.md) +- [DefaultSolidFormComponentMap](type-aliases/DefaultSolidFormComponentMap.md) +- [DefineFieldGroupFn](type-aliases/DefineFieldGroupFn.md) +- [FieldGroupFieldBindingsOf](type-aliases/FieldGroupFieldBindingsOf.md) +- [FieldGroupFieldComponentsOf](type-aliases/FieldGroupFieldComponentsOf.md) +- [FieldGroupFieldsOf](type-aliases/FieldGroupFieldsOf.md) +- [FieldGroupForm](type-aliases/FieldGroupForm.md) +- [FieldGroupFormState](type-aliases/FieldGroupFormState.md) +- [FieldGroupSubscribeComponent](type-aliases/FieldGroupSubscribeComponent.md) +- [FieldGroupSubscribeProps](type-aliases/FieldGroupSubscribeProps.md) +- [FieldGroupWithFieldsFn](type-aliases/FieldGroupWithFieldsFn.md) +- [Observer](type-aliases/Observer.md) +- [Selection](type-aliases/Selection.md) +- [SolidAppFormApi](type-aliases/SolidAppFormApi.md) +- [SolidFieldApi](type-aliases/SolidFieldApi.md) +- [SolidFieldGroup](type-aliases/SolidFieldGroup.md) +- [SolidFormApi](type-aliases/SolidFormApi.md) +- [SolidFormGroupAccessor](type-aliases/SolidFormGroupAccessor.md) +- [SolidFormGroupSubscribeComponent](type-aliases/SolidFormGroupSubscribeComponent.md) +- [SolidFormGroupSubscribeProps](type-aliases/SolidFormGroupSubscribeProps.md) +- [SolidFormSubscribeComponent](type-aliases/SolidFormSubscribeComponent.md) +- [SolidFormSubscribeProps](type-aliases/SolidFormSubscribeProps.md) +- [SolidFormType](type-aliases/SolidFormType.md) +- [StoreAction](type-aliases/StoreAction.md) +- [StoreActionMap](type-aliases/StoreActionMap.md) +- [StoreActionsFactory](type-aliases/StoreActionsFactory.md) +- [SubscribeSource](type-aliases/SubscribeSource.md) +- [UseAppFormHook](type-aliases/UseAppFormHook.md) ## Variables +- [createForm](variables/createForm.md) +- [defineFieldGroup](variables/defineFieldGroup.md) - [~~useStore~~](variables/useStore.md) ## Functions -- [createField](functions/createField.md) -- [createFieldGroup](functions/createFieldGroup.md) -- [createForm](functions/createForm.md) -- [createFormGroup](functions/createFormGroup.md) +- [\_useStore](functions/useStore.md) +- [batch](functions/batch.md) +- [createAsyncAtom](functions/createAsyncAtom.md) +- [createAtom](functions/createAtom.md) - [createFormHook](functions/createFormHook.md) -- [createFormHookContexts](functions/createFormHookContexts.md) -- [Field](functions/Field.md) -- [FormGroup](functions/FormGroup.md) +- [createStore](functions/createStore.md) +- [createStoreContext](functions/createStoreContext.md) +- [flush](functions/flush.md) +- [getFormHookHelpers](functions/getFormHookHelpers.md) +- [shallow](functions/shallow.md) +- [Subscribe](functions/Subscribe.md) +- [toObserver](functions/toObserver.md) +- [useAtom](functions/useAtom.md) - [useSelector](functions/useSelector.md) diff --git a/docs/framework/solid/reference/interfaces/AppFormHookResult.md b/docs/framework/solid/reference/interfaces/AppFormHookResult.md new file mode 100644 index 0000000000..7766440a29 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/AppFormHookResult.md @@ -0,0 +1,56 @@ +--- +id: AppFormHookResult +title: AppFormHookResult +--- + +Defined in: [packages/solid-form/src/AppForm/createFormHookTypes.public.ts:112](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/createFormHookTypes.public.ts#L112) + +## Type Parameters + +### TComponents + +`TComponents` *extends* [`AnySolidFormComponentMap`](../type-aliases/AnySolidFormComponentMap.md) + +## Properties + +### appFormOptions + +```ts +appFormOptions: FormOptionsApi; +``` + +Defined in: [packages/solid-form/src/AppForm/createFormHookTypes.public.ts:115](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/createFormHookTypes.public.ts#L115) + +*** + +### defineAppFieldGroup + +```ts +defineAppFieldGroup: DefineFieldGroupFn; +``` + +Defined in: [packages/solid-form/src/AppForm/createFormHookTypes.public.ts:116](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/createFormHookTypes.public.ts#L116) + +*** + +### useAppForm + +```ts +useAppForm: UseAppFormHook; +``` + +Defined in: [packages/solid-form/src/AppForm/createFormHookTypes.public.ts:117](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/createFormHookTypes.public.ts#L117) + +*** + +### useFormContext + +```ts +useFormContext: () => SolidAppFormApi; +``` + +Defined in: [packages/solid-form/src/AppForm/createFormHookTypes.public.ts:118](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/createFormHookTypes.public.ts#L118) + +#### Returns + +[`SolidAppFormApi`](../type-aliases/SolidAppFormApi.md)\<`any`, `any`, `TComponents`\> diff --git a/docs/framework/solid/reference/interfaces/Atom.md b/docs/framework/solid/reference/interfaces/Atom.md new file mode 100644 index 0000000000..e536822283 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/Atom.md @@ -0,0 +1,60 @@ +--- +id: Atom +title: Atom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:29 + +## Extends + +- [`BaseAtom`](BaseAtom.md)\<`T`\> + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`get`](BaseAtom.md#get) + +*** + +### set + +```ts +set: (fn) => void & (value) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:31 + +Sets the value of the atom using a function. + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`subscribe`](BaseAtom.md#subscribe) diff --git a/docs/framework/solid/reference/interfaces/AtomOptions.md b/docs/framework/solid/reference/interfaces/AtomOptions.md new file mode 100644 index 0000000000..84f594c6e0 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/AtomOptions.md @@ -0,0 +1,36 @@ +--- +id: AtomOptions +title: AtomOptions +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:33 + +## Type Parameters + +### T + +`T` + +## Properties + +### compare? + +```ts +optional compare?: (prev, next) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:34 + +#### Parameters + +##### prev + +`T` + +##### next + +`T` + +#### Returns + +`boolean` diff --git a/docs/framework/solid/reference/interfaces/BaseAtom.md b/docs/framework/solid/reference/interfaces/BaseAtom.md new file mode 100644 index 0000000000..fc0695a37a --- /dev/null +++ b/docs/framework/solid/reference/interfaces/BaseAtom.md @@ -0,0 +1,53 @@ +--- +id: BaseAtom +title: BaseAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:22 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\>.[`Readable`](Readable.md)\<`T`\> + +## Extended by + +- [`Atom`](Atom.md) +- [`ReadonlyAtom`](ReadonlyAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`Readable`](Readable.md).[`get`](Readable.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/solid/reference/interfaces/CreateFieldOptions.md b/docs/framework/solid/reference/interfaces/CreateFieldOptions.md deleted file mode 100644 index 3cf8fb81b6..0000000000 --- a/docs/framework/solid/reference/interfaces/CreateFieldOptions.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -id: CreateFieldOptions -title: CreateFieldOptions ---- - -# Interface: CreateFieldOptions\ - -Defined in: [packages/solid-form/src/types.ts:19](https://github.com/TanStack/form/blob/main/packages/solid-form/src/types.ts#L19) - -## Extends - -- `FieldApiOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TSubmitMeta - -`TSubmitMeta` - -## Properties - -### mode? - -```ts -optional mode: "value" | "array"; -``` - -Defined in: [packages/solid-form/src/types.ts:16](https://github.com/TanStack/form/blob/main/packages/solid-form/src/types.ts#L16) - -#### Inherited from - -```ts -FieldOptionsMode.mode -``` diff --git a/docs/framework/solid/reference/interfaces/CreateFieldOptionsBound.md b/docs/framework/solid/reference/interfaces/CreateFieldOptionsBound.md deleted file mode 100644 index ba9af60763..0000000000 --- a/docs/framework/solid/reference/interfaces/CreateFieldOptionsBound.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -id: CreateFieldOptionsBound -title: CreateFieldOptionsBound ---- - -# Interface: CreateFieldOptionsBound\ - -Defined in: [packages/solid-form/src/types.ts:80](https://github.com/TanStack/form/blob/main/packages/solid-form/src/types.ts#L80) - -## Extends - -- `FieldOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`\> - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -## Properties - -### mode? - -```ts -optional mode: "value" | "array"; -``` - -Defined in: [packages/solid-form/src/types.ts:16](https://github.com/TanStack/form/blob/main/packages/solid-form/src/types.ts#L16) - -#### Inherited from - -```ts -FieldOptionsMode.mode -``` diff --git a/docs/framework/solid/reference/interfaces/CreateFormHookOptions.md b/docs/framework/solid/reference/interfaces/CreateFormHookOptions.md new file mode 100644 index 0000000000..a5295caf07 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/CreateFormHookOptions.md @@ -0,0 +1,150 @@ +--- +id: CreateFormHookOptions +title: CreateFormHookOptions +--- + +Defined in: [packages/solid-form/src/AppForm/createFormHookTypes.public.ts:46](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/createFormHookTypes.public.ts#L46) + +Configures the components and reusable defaults returned by +`createFormHook`. + +Form core resolves each default object before the corresponding usage-site +options. Non-listener properties passed at the usage site take precedence, +including when explicitly set to `undefined`. Listener arrays follow the +configured `listenersMerge` strategy. + +## Example + +```tsx +const { useAppForm } = createFormHook({ + formComponents: {}, + fieldComponents: { + TextField, + }, + defaultFormOptions: { + errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred, + }, + defaultFieldOptions: { + errorBoundary: true, + }, +}) +``` + +## Extends + +- [`SolidFormComponentMap`](SolidFormComponentMap.md)\<`TFormComponents`, `TFieldComponents`\> + +## Type Parameters + +### TFormComponents + +`TFormComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +Library-managed. Do not specify explicitly. + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +Library-managed. Do not specify explicitly. + +## Properties + +### defaultFieldOptions? + +```ts +optional defaultFieldOptions?: DefaultFieldOptions; +``` + +Defined in: [packages/solid-form/src/AppForm/createFormHookTypes.public.ts:79](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/createFormHookTypes.public.ts#L79) + +Defaults for every field and array-field component owned by the form. + +Non-listener options passed to the component override these defaults, +including when explicitly set to `undefined`. Listener arrays follow +`listenersMerge`. This includes `group.Field` and `group.ArrayField`. + +#### Example + +```tsx +defaultFieldOptions: { + errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred, +}, +``` + +*** + +### defaultFormGroupOptions? + +```ts +optional defaultFormGroupOptions?: DefaultFormGroupOptions; +``` + +Defined in: [packages/solid-form/src/AppForm/createFormHookTypes.public.ts:95](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/createFormHookTypes.public.ts#L95) + +Defaults for every `form.FormGroup` component. + +Options passed to the component override these defaults, including when +an option is explicitly `undefined`. + +#### Example + +```tsx +defaultFormGroupOptions: { + onSubmitInvalid: ({ groupApi }) => { + console.error('Invalid group', groupApi.name) + }, +}, +``` + +*** + +### defaultFormOptions? + +```ts +optional defaultFormOptions?: DefaultFormOptions; +``` + +Defined in: [packages/solid-form/src/AppForm/createFormHookTypes.public.ts:64](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/createFormHookTypes.public.ts#L64) + +Defaults for every form created by `useAppForm`. + +Non-listener options returned by the `useAppForm` options accessor +override these defaults, including when explicitly set to `undefined`. +Listener arrays follow `listenersMerge`. + +#### Example + +```tsx +defaultFormOptions: { + errorVisibility: ({ state }) => state.submissionAttempts > 0, +}, +``` + +*** + +### fieldComponents + +```ts +fieldComponents: TFieldComponents; +``` + +Defined in: [packages/solid-form/src/AppForm/componentMap.public.ts:8](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/componentMap.public.ts#L8) + +#### Inherited from + +[`SolidFormComponentMap`](SolidFormComponentMap.md).[`fieldComponents`](SolidFormComponentMap.md#fieldcomponents) + +*** + +### formComponents + +```ts +formComponents: TFormComponents; +``` + +Defined in: [packages/solid-form/src/AppForm/componentMap.public.ts:7](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/componentMap.public.ts#L7) + +#### Inherited from + +[`SolidFormComponentMap`](SolidFormComponentMap.md).[`formComponents`](SolidFormComponentMap.md#formcomponents) diff --git a/docs/framework/solid/reference/interfaces/FieldGroupApi.md b/docs/framework/solid/reference/interfaces/FieldGroupApi.md new file mode 100644 index 0000000000..86c659497c --- /dev/null +++ b/docs/framework/solid/reference/interfaces/FieldGroupApi.md @@ -0,0 +1,60 @@ +--- +id: FieldGroupApi +title: FieldGroupApi +--- + +Defined in: [packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts:73](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts#L73) + +## Extends + +- `FormApiFieldMethods`\<`TFieldData`\>.`FormApiArrayMethods`\<`TFieldData`\> + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> = `Record`\<`never`, `never`\> + +## Properties + +### ArrayField + +```ts +ArrayField: FieldGroupArrayFieldComponent; +``` + +Defined in: [packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts:83](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts#L83) + +*** + +### atom + +```ts +atom: ReadonlyAtom; +``` + +Defined in: [packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts:81](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts#L81) + +*** + +### Field + +```ts +Field: FieldGroupFieldComponent; +``` + +Defined in: [packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts:82](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts#L82) + +*** + +### Subscribe + +```ts +Subscribe: FieldGroupSubscribeComponent; +``` + +Defined in: [packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts:84](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts#L84) diff --git a/docs/framework/solid/reference/interfaces/FieldGroupArrayFieldComponent.md b/docs/framework/solid/reference/interfaces/FieldGroupArrayFieldComponent.md new file mode 100644 index 0000000000..666a025138 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/FieldGroupArrayFieldComponent.md @@ -0,0 +1,38 @@ +--- +id: FieldGroupArrayFieldComponent +title: FieldGroupArrayFieldComponent +--- + +Defined in: [packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts:41](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts#L41) + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +```ts +FieldGroupArrayFieldComponent(props): Element; +``` + +Defined in: [packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts:45](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts#L45) + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `never` + +## Parameters + +### props + +[`SolidFormFieldProps`](SolidFormFieldProps.md)\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\>, `ValidationIssue`, `unknown`, `FormErrorTypes`\<`ValidationIssue`, `ValidationIssue`\>, `TFieldComponents`\> + +## Returns + +`Element` diff --git a/docs/framework/solid/reference/interfaces/FieldGroupDefinition.md b/docs/framework/solid/reference/interfaces/FieldGroupDefinition.md new file mode 100644 index 0000000000..0932605b48 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/FieldGroupDefinition.md @@ -0,0 +1,40 @@ +--- +id: FieldGroupDefinition +title: FieldGroupDefinition +--- + +Defined in: [packages/solid-form/src/FieldGroup/withFields.public.ts:67](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/withFields.public.ts#L67) + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +## Properties + +### bindComponent + +```ts +bindComponent: FieldGroupWithFieldsFn>; +``` + +Defined in: [packages/solid-form/src/FieldGroup/withFields.public.ts:74](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/withFields.public.ts#L74) + +Binds a component's virtual field API to concrete paths in a form. + +*** + +### fields + +```ts +fields: SolidFieldGroup; +``` + +Defined in: [packages/solid-form/src/FieldGroup/withFields.public.ts:72](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/withFields.public.ts#L72) + +The virtual field-group API injected into the bound component. diff --git a/docs/framework/solid/reference/interfaces/FieldGroupFieldComponent.md b/docs/framework/solid/reference/interfaces/FieldGroupFieldComponent.md new file mode 100644 index 0000000000..f9602498b8 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/FieldGroupFieldComponent.md @@ -0,0 +1,38 @@ +--- +id: FieldGroupFieldComponent +title: FieldGroupFieldComponent +--- + +Defined in: [packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts:19](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts#L19) + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +```ts +FieldGroupFieldComponent(props): Element; +``` + +Defined in: [packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts:23](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts#L23) + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `string` + +## Parameters + +### props + +[`SolidFormFieldProps`](SolidFormFieldProps.md)\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\>, `ValidationIssue`, `unknown`, `FormErrorTypes`\<`ValidationIssue`, `ValidationIssue`\>, `TFieldComponents`\> + +## Returns + +`Element` diff --git a/docs/framework/solid/reference/interfaces/FormHookHelpers.md b/docs/framework/solid/reference/interfaces/FormHookHelpers.md new file mode 100644 index 0000000000..0dc04b6d17 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/FormHookHelpers.md @@ -0,0 +1,26 @@ +--- +id: FormHookHelpers +title: FormHookHelpers +--- + +Defined in: [packages/solid-form/src/AppForm/getFormHookHelpers.public.ts:81](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/getFormHookHelpers.public.ts#L81) + +## Properties + +### fieldBrand + +```ts +fieldBrand: FieldBrandHelper; +``` + +Defined in: [packages/solid-form/src/AppForm/getFormHookHelpers.public.ts:82](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/getFormHookHelpers.public.ts#L82) + +*** + +### fieldComponent + +```ts +fieldComponent: FieldComponentHelper; +``` + +Defined in: [packages/solid-form/src/AppForm/getFormHookHelpers.public.ts:83](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/getFormHookHelpers.public.ts#L83) diff --git a/docs/framework/solid/reference/interfaces/InternalBaseAtom.md b/docs/framework/solid/reference/interfaces/InternalBaseAtom.md new file mode 100644 index 0000000000..f73167d4a2 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/InternalBaseAtom.md @@ -0,0 +1,86 @@ +--- +id: InternalBaseAtom +title: InternalBaseAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:23 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\>.[`Readable`](Readable.md)\<`T`\> + +## Extended by + +- [`InternalReadonlyAtom`](InternalReadonlyAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### \_snapshot + +```ts +_snapshot: T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:25 + +**`Internal`** + +*** + +### \_update + +```ts +_update: (getValue?) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:27 + +**`Internal`** + +#### Parameters + +##### getValue? + +`T` \| ((`snapshot`) => `T`) + +#### Returns + +`boolean` + +*** + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`Readable`](Readable.md).[`get`](Readable.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/solid/reference/interfaces/InternalReadonlyAtom.md b/docs/framework/solid/reference/interfaces/InternalReadonlyAtom.md new file mode 100644 index 0000000000..ac5a197160 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/InternalReadonlyAtom.md @@ -0,0 +1,170 @@ +--- +id: InternalReadonlyAtom +title: InternalReadonlyAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:37 + +## Extends + +- [`InternalBaseAtom`](InternalBaseAtom.md)\<`T`\>.`ReactiveNode` + +## Type Parameters + +### T + +`T` + +## Properties + +### \_snapshot + +```ts +_snapshot: T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:25 + +**`Internal`** + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`_snapshot`](InternalBaseAtom.md#_snapshot) + +*** + +### \_update + +```ts +_update: (getValue?) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:27 + +**`Internal`** + +#### Parameters + +##### getValue? + +`T` \| ((`snapshot`) => `T`) + +#### Returns + +`boolean` + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`_update`](InternalBaseAtom.md#_update) + +*** + +### deps? + +```ts +optional deps?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:3 + +#### Inherited from + +```ts +ReactiveNode.deps +``` + +*** + +### depsTail? + +```ts +optional depsTail?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:4 + +#### Inherited from + +```ts +ReactiveNode.depsTail +``` + +*** + +### flags + +```ts +flags: number; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:7 + +#### Inherited from + +```ts +ReactiveNode.flags +``` + +*** + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`get`](InternalBaseAtom.md#get) + +*** + +### subs? + +```ts +optional subs?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:5 + +#### Inherited from + +```ts +ReactiveNode.subs +``` + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`subscribe`](InternalBaseAtom.md#subscribe) + +*** + +### subsTail? + +```ts +optional subsTail?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:6 + +#### Inherited from + +```ts +ReactiveNode.subsTail +``` diff --git a/docs/framework/solid/reference/interfaces/InteropSubscribable.md b/docs/framework/solid/reference/interfaces/InteropSubscribable.md new file mode 100644 index 0000000000..7a0c023915 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/InteropSubscribable.md @@ -0,0 +1,36 @@ +--- +id: InteropSubscribable +title: InteropSubscribable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:5 + +## Extended by + +- [`Subscribable`](Subscribable.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### subscribe + +```ts +subscribe: (observer) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:6 + +#### Parameters + +##### observer + +[`Observer`](../type-aliases/Observer.md)\<`T`\> + +#### Returns + +[`Subscription`](Subscription.md) diff --git a/docs/framework/solid/reference/interfaces/Readable.md b/docs/framework/solid/reference/interfaces/Readable.md new file mode 100644 index 0000000000..ff2095ebfe --- /dev/null +++ b/docs/framework/solid/reference/interfaces/Readable.md @@ -0,0 +1,49 @@ +--- +id: Readable +title: Readable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:19 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\> + +## Extended by + +- [`BaseAtom`](BaseAtom.md) +- [`InternalBaseAtom`](InternalBaseAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/solid/reference/interfaces/ReadonlyAtom.md b/docs/framework/solid/reference/interfaces/ReadonlyAtom.md new file mode 100644 index 0000000000..bbc1e1d9c3 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/ReadonlyAtom.md @@ -0,0 +1,58 @@ +--- +id: ReadonlyAtom +title: ReadonlyAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:49 + +An atom that is read-only and cannot be set. + +## Example + +```ts +const atom = createAtom(() => 42); +// @ts-expect-error - Cannot set a readonly atom +atom.set(43); +``` + +## Extends + +- [`BaseAtom`](BaseAtom.md)\<`T`\> + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`get`](BaseAtom.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`subscribe`](BaseAtom.md#subscribe) diff --git a/docs/framework/solid/reference/interfaces/SolidFormApi.md b/docs/framework/solid/reference/interfaces/SolidFormApi.md deleted file mode 100644 index 496c2d03d6..0000000000 --- a/docs/framework/solid/reference/interfaces/SolidFormApi.md +++ /dev/null @@ -1,178 +0,0 @@ ---- -id: SolidFormApi -title: SolidFormApi ---- - -# Interface: SolidFormApi\ - -Defined in: [packages/solid-form/src/createForm.tsx:16](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createForm.tsx#L16) - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TSubmitMeta - -`TSubmitMeta` - -## Properties - -### Field - -```ts -Field: FieldComponent; -``` - -Defined in: [packages/solid-form/src/createForm.tsx:30](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createForm.tsx#L30) - -*** - -### FormGroup - -```ts -FormGroup: FormGroupComponent; -``` - -Defined in: [packages/solid-form/src/createForm.tsx:44](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createForm.tsx#L44) - -*** - -### Subscribe() - -```ts -Subscribe: (props) => Element; -``` - -Defined in: [packages/solid-form/src/createForm.tsx:131](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createForm.tsx#L131) - -#### Type Parameters - -##### TSelected - -`TSelected` = `NoInfer`\<`FormState`\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`\>\> - -#### Parameters - -##### props - -###### children - -`Element` \| (`state`) => `Element` - -###### selector? - -(`state`) => `TSelected` - -#### Returns - -`Element` - -*** - -### useSelector() - -```ts -useSelector: (selector?) => () => TSelected; -``` - -Defined in: [packages/solid-form/src/createForm.tsx:58](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createForm.tsx#L58) - -#### Type Parameters - -##### TSelected - -`TSelected` = `NoInfer`\<`FormState`\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`\>\> - -#### Parameters - -##### selector? - -(`state`) => `TSelected` - -#### Returns - -```ts -(): TSelected; -``` - -##### Returns - -`TSelected` - -*** - -### ~~useStore()~~ - -```ts -useStore: (selector?) => () => TSelected; -``` - -Defined in: [packages/solid-form/src/createForm.tsx:96](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createForm.tsx#L96) - -#### Type Parameters - -##### TSelected - -`TSelected` = `NoInfer`\<`FormState`\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`\>\> - -#### Parameters - -##### selector? - -(`state`) => `TSelected` - -#### Returns - -```ts -(): TSelected; -``` - -##### Returns - -`TSelected` - -#### Deprecated - -Use `form.useSelector` instead. diff --git a/docs/framework/solid/reference/interfaces/SolidFormArrayFieldComponent.md b/docs/framework/solid/reference/interfaces/SolidFormArrayFieldComponent.md new file mode 100644 index 0000000000..38c20023f6 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/SolidFormArrayFieldComponent.md @@ -0,0 +1,46 @@ +--- +id: SolidFormArrayFieldComponent +title: SolidFormArrayFieldComponent +--- + +Defined in: [packages/solid-form/src/Components.public.ts:170](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L170) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +```ts +SolidFormArrayFieldComponent(props): Element; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:175](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L175) + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `never` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>\> + +## Parameters + +### props + +[`SolidFormFieldProps`](SolidFormFieldProps.md)\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`Element` diff --git a/docs/framework/solid/reference/interfaces/SolidFormArrayFieldProps.md b/docs/framework/solid/reference/interfaces/SolidFormArrayFieldProps.md new file mode 100644 index 0000000000..74ab0bc028 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/SolidFormArrayFieldProps.md @@ -0,0 +1,58 @@ +--- +id: SolidFormArrayFieldProps +title: SolidFormArrayFieldProps +--- + +Defined in: [packages/solid-form/src/Components.public.ts:127](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L127) + +## Extends + +- [`SolidFormFieldProps`](SolidFormFieldProps.md)\<`TFormData`, `TFieldName`, `TFieldValue`, `TFieldValidators`, `never`, `TFormData`, `TFormErrorTypes`, `Record`\<`never`, `never`\>\> + +## Type Parameters + +### TFormData + +`TFormData` + +### TFieldName + +`TFieldName` + +### TFieldValue + +`TFieldValue` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFormData`, `TFieldName`, `TFieldValue`\> + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +## Properties + +### children + +```ts +children: (fieldApi) => Element; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:111](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L111) + +#### Parameters + +##### fieldApi + +[`SolidFieldApi`](../type-aliases/SolidFieldApi.md)\<`TFieldName`, `TFieldValue`, `FallbackToValidationIssue`\< + \| `ExtractValidatorFieldError`\<`NoInfer`\<`TFieldValidators`\>, `FieldValidators`\<`any`, `any`, `any`\>\> + \| `ExtractFormFieldError`\<`TFormErrorTypes`\>\>, `TFormData`, `TFormErrorTypes`, `Record`\<`never`, `never`\>\> + +#### Returns + +`Element` + +#### Inherited from + +[`SolidFormFieldProps`](SolidFormFieldProps.md).[`children`](SolidFormFieldProps.md#children) diff --git a/docs/framework/solid/reference/interfaces/SolidFormComponentMap.md b/docs/framework/solid/reference/interfaces/SolidFormComponentMap.md new file mode 100644 index 0000000000..25cd7c9cb9 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/SolidFormComponentMap.md @@ -0,0 +1,40 @@ +--- +id: SolidFormComponentMap +title: SolidFormComponentMap +--- + +Defined in: [packages/solid-form/src/AppForm/componentMap.public.ts:3](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/componentMap.public.ts#L3) + +## Extended by + +- [`CreateFormHookOptions`](CreateFormHookOptions.md) + +## Type Parameters + +### TFormComponents + +`TFormComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +## Properties + +### fieldComponents + +```ts +fieldComponents: TFieldComponents; +``` + +Defined in: [packages/solid-form/src/AppForm/componentMap.public.ts:8](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/componentMap.public.ts#L8) + +*** + +### formComponents + +```ts +formComponents: TFormComponents; +``` + +Defined in: [packages/solid-form/src/AppForm/componentMap.public.ts:7](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/componentMap.public.ts#L7) diff --git a/docs/framework/solid/reference/interfaces/SolidFormFieldComponent.md b/docs/framework/solid/reference/interfaces/SolidFormFieldComponent.md new file mode 100644 index 0000000000..b8a93a316e --- /dev/null +++ b/docs/framework/solid/reference/interfaces/SolidFormFieldComponent.md @@ -0,0 +1,46 @@ +--- +id: SolidFormFieldComponent +title: SolidFormFieldComponent +--- + +Defined in: [packages/solid-form/src/Components.public.ts:144](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L144) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +```ts +SolidFormFieldComponent(props): Element; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:149](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L149) + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `string` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>\> + +## Parameters + +### props + +[`SolidFormFieldProps`](SolidFormFieldProps.md)\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`Element` diff --git a/docs/framework/solid/reference/interfaces/SolidFormFieldProps.md b/docs/framework/solid/reference/interfaces/SolidFormFieldProps.md new file mode 100644 index 0000000000..734d1db335 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/SolidFormFieldProps.md @@ -0,0 +1,68 @@ +--- +id: SolidFormFieldProps +title: SolidFormFieldProps +--- + +Defined in: [packages/solid-form/src/Components.public.ts:93](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L93) + +## Extends + +- `FieldApiOptions`\<`TFieldData`, `TFieldName`, `TFieldValue`, `TFieldValidators`, `TGroupFieldError`, `TFormData`, `TFormErrorTypes`\> + +## Extended by + +- [`SolidFormArrayFieldProps`](SolidFormArrayFieldProps.md) + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldName + +`TFieldName` + +### TFieldValue + +`TFieldValue` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFieldData`, `TFieldName`, `TFieldValue`\> + +### TGroupFieldError + +`TGroupFieldError` + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +## Properties + +### children + +```ts +children: (fieldApi) => Element; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:111](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L111) + +#### Parameters + +##### fieldApi + +[`SolidFieldApi`](../type-aliases/SolidFieldApi.md)\<`TFieldName`, `TFieldValue`, `ToFieldError`\<`NoInfer`\<`TFieldValidators`\>, `TGroupFieldError`, `TFormErrorTypes`\>, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +#### Returns + +`Element` diff --git a/docs/framework/solid/reference/interfaces/SolidFormGroupApi.md b/docs/framework/solid/reference/interfaces/SolidFormGroupApi.md new file mode 100644 index 0000000000..f86338256a --- /dev/null +++ b/docs/framework/solid/reference/interfaces/SolidFormGroupApi.md @@ -0,0 +1,66 @@ +--- +id: SolidFormGroupApi +title: SolidFormGroupApi +--- + +Defined in: [packages/solid-form/src/Components.public.ts:268](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L268) + +## Extends + +- `FormGroupApi`\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupErrorTypes`, `TFormErrorTypes`\> + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +## Properties + +### ArrayField + +```ts +ArrayField: SolidFormGroupArrayFieldComponent; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:289](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L289) + +*** + +### Field + +```ts +Field: SolidFormGroupFieldComponent; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:282](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L282) + +*** + +### Subscribe + +```ts +Subscribe: SolidFormGroupSubscribeComponent; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:296](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L296) diff --git a/docs/framework/solid/reference/interfaces/SolidFormGroupArrayFieldComponent.md b/docs/framework/solid/reference/interfaces/SolidFormGroupArrayFieldComponent.md new file mode 100644 index 0000000000..16d634c8c3 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/SolidFormGroupArrayFieldComponent.md @@ -0,0 +1,54 @@ +--- +id: SolidFormGroupArrayFieldComponent +title: SolidFormGroupArrayFieldComponent +--- + +Defined in: [packages/solid-form/src/Components.public.ts:240](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L240) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +```ts +SolidFormGroupArrayFieldComponent(props): Element; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:247](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L247) + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `never` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>\> + +## Parameters + +### props + +[`SolidFormFieldProps`](SolidFormFieldProps.md)\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>, `TFieldValidators`, `TGroupErrorTypes`\[`"fieldError"`\], `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`Element` diff --git a/docs/framework/solid/reference/interfaces/SolidFormGroupComponent.md b/docs/framework/solid/reference/interfaces/SolidFormGroupComponent.md new file mode 100644 index 0000000000..70e81890ce --- /dev/null +++ b/docs/framework/solid/reference/interfaces/SolidFormGroupComponent.md @@ -0,0 +1,50 @@ +--- +id: SolidFormGroupComponent +title: SolidFormGroupComponent +--- + +Defined in: [packages/solid-form/src/Components.public.ts:357](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L357) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +```ts +SolidFormGroupComponent(props): Element; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:362](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L362) + +## Type Parameters + +### TGroupName + +`TGroupName` *extends* `string` + +### TGroupValue + +`TGroupValue` + +### TGroupValidators + +`TGroupValidators` *extends* `FormGroupValidators`\<`TGroupValue`\> + +## Parameters + +### props + +[`SolidFormGroupProps`](SolidFormGroupProps.md)\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupValidators`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`Element` diff --git a/docs/framework/solid/reference/interfaces/SolidFormGroupFieldComponent.md b/docs/framework/solid/reference/interfaces/SolidFormGroupFieldComponent.md new file mode 100644 index 0000000000..9f86698367 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/SolidFormGroupFieldComponent.md @@ -0,0 +1,54 @@ +--- +id: SolidFormGroupFieldComponent +title: SolidFormGroupFieldComponent +--- + +Defined in: [packages/solid-form/src/Components.public.ts:212](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L212) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +```ts +SolidFormGroupFieldComponent(props): Element; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:219](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L219) + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* `string` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>\> + +## Parameters + +### props + +[`SolidFormFieldProps`](SolidFormFieldProps.md)\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>, `TFieldValidators`, `TGroupErrorTypes`\[`"fieldError"`\], `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> + +## Returns + +`Element` diff --git a/docs/framework/solid/reference/interfaces/SolidFormGroupProps.md b/docs/framework/solid/reference/interfaces/SolidFormGroupProps.md new file mode 100644 index 0000000000..f32dd4f554 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/SolidFormGroupProps.md @@ -0,0 +1,56 @@ +--- +id: SolidFormGroupProps +title: SolidFormGroupProps +--- + +Defined in: [packages/solid-form/src/Components.public.ts:328](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L328) + +## Extends + +- `Omit`\<`FormGroupOptions`\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupValidators`, `TFormErrorTypes`\>, `"form"`\> + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupValidators + +`TGroupValidators` *extends* `FormGroupValidators`\<`TGroupValue`\> + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +## Properties + +### children + +```ts +children: (groupApi) => Element; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:345](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L345) + +#### Parameters + +##### groupApi + +[`SolidFormGroupAccessor`](../type-aliases/SolidFormGroupAccessor.md)\<`TFormData`, `TGroupName`, `TGroupValue`, `ToFormGroupErrorTypes`\<`NoInfer`\<`TGroupValidators`\>\>, `TFormErrorTypes`, `TFieldComponents`\> + +#### Returns + +`Element` diff --git a/docs/framework/solid/reference/interfaces/SolidTanStackFormComponents.md b/docs/framework/solid/reference/interfaces/SolidTanStackFormComponents.md new file mode 100644 index 0000000000..d1e091628f --- /dev/null +++ b/docs/framework/solid/reference/interfaces/SolidTanStackFormComponents.md @@ -0,0 +1,60 @@ +--- +id: SolidTanStackFormComponents +title: SolidTanStackFormComponents +--- + +Defined in: [packages/solid-form/src/Components.public.ts:378](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L378) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> = `Record`\<`never`, `never`\> + +## Properties + +### ArrayField + +```ts +ArrayField: SolidFormArrayFieldComponent; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:387](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L387) + +*** + +### Field + +```ts +Field: SolidFormFieldComponent; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:386](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L386) + +*** + +### FormGroup + +```ts +FormGroup: SolidFormGroupComponent; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:393](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L393) + +*** + +### Subscribe + +```ts +Subscribe: SolidFormSubscribeComponent; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:392](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L392) diff --git a/docs/framework/solid/reference/interfaces/Subscribable.md b/docs/framework/solid/reference/interfaces/Subscribable.md new file mode 100644 index 0000000000..a11bf60b2a --- /dev/null +++ b/docs/framework/solid/reference/interfaces/Subscribable.md @@ -0,0 +1,36 @@ +--- +id: Subscribable +title: Subscribable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:16 + +## Extends + +- [`InteropSubscribable`](InteropSubscribable.md)\<`T`\> + +## Extended by + +- [`BaseAtom`](BaseAtom.md) +- [`InternalBaseAtom`](InternalBaseAtom.md) +- [`Readable`](Readable.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Overrides + +[`InteropSubscribable`](InteropSubscribable.md).[`subscribe`](InteropSubscribable.md#subscribe) diff --git a/docs/framework/solid/reference/interfaces/SubscribeProps.md b/docs/framework/solid/reference/interfaces/SubscribeProps.md new file mode 100644 index 0000000000..f825593810 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/SubscribeProps.md @@ -0,0 +1,76 @@ +--- +id: SubscribeProps +title: SubscribeProps +--- + +Defined in: [packages/solid-form/src/Subscribe.public.ts:14](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Subscribe.public.ts#L14) + +## Type Parameters + +### TSourceData + +`TSourceData` + +### TSelected + +`TSelected` + +## Properties + +### children + +```ts +children: Element | ((state) => Element); +``` + +Defined in: [packages/solid-form/src/Subscribe.public.ts:18](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Subscribe.public.ts#L18) + +*** + +### selector + +```ts +selector: (state) => TSelected; +``` + +Defined in: [packages/solid-form/src/Subscribe.public.ts:16](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Subscribe.public.ts#L16) + +#### Parameters + +##### state + +`TSourceData` + +#### Returns + +`TSelected` + +*** + +### source + +```ts +source: SubscribeSource; +``` + +Defined in: [packages/solid-form/src/Subscribe.public.ts:15](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Subscribe.public.ts#L15) + +*** + +### when? + +```ts +optional when?: (selected) => boolean; +``` + +Defined in: [packages/solid-form/src/Subscribe.public.ts:17](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Subscribe.public.ts#L17) + +#### Parameters + +##### selected + +`NoInfer`\<`TSelected`\> + +#### Returns + +`boolean` diff --git a/docs/framework/solid/reference/interfaces/Subscription.md b/docs/framework/solid/reference/interfaces/Subscription.md new file mode 100644 index 0000000000..fab2f285ee --- /dev/null +++ b/docs/framework/solid/reference/interfaces/Subscription.md @@ -0,0 +1,20 @@ +--- +id: Subscription +title: Subscription +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:13 + +## Properties + +### unsubscribe + +```ts +unsubscribe: () => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:14 + +#### Returns + +`void` diff --git a/docs/framework/solid/reference/interfaces/UseSelectorOptions.md b/docs/framework/solid/reference/interfaces/UseSelectorOptions.md new file mode 100644 index 0000000000..a0fa358afe --- /dev/null +++ b/docs/framework/solid/reference/interfaces/UseSelectorOptions.md @@ -0,0 +1,36 @@ +--- +id: UseSelectorOptions +title: UseSelectorOptions +--- + +Defined in: node\_modules/.pnpm/@tanstack+solid-store@0.11.1\_solid-js@1.9.14/node\_modules/@tanstack/solid-store/dist/useSelector.d.ts:4 + +## Type Parameters + +### TSelected + +`TSelected` + +## Properties + +### compare? + +```ts +optional compare?: (a, b) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+solid-store@0.11.1\_solid-js@1.9.14/node\_modules/@tanstack/solid-store/dist/useSelector.d.ts:5 + +#### Parameters + +##### a + +`TSelected` + +##### b + +`TSelected` + +#### Returns + +`boolean` diff --git a/docs/framework/solid/reference/interfaces/WithFieldGroupProps.md b/docs/framework/solid/reference/interfaces/WithFieldGroupProps.md deleted file mode 100644 index 5eaa38fd70..0000000000 --- a/docs/framework/solid/reference/interfaces/WithFieldGroupProps.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -id: WithFieldGroupProps -title: WithFieldGroupProps ---- - -# Interface: WithFieldGroupProps\ - -Defined in: [packages/solid-form/src/createFormHook.tsx:263](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createFormHook.tsx#L263) - -## Extends - -- `BaseFormOptions`\<`TFieldGroupData`, `TSubmitMeta`\> - -## Type Parameters - -### TFieldGroupData - -`TFieldGroupData` - -### TFieldComponents - -`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> - -### TFormComponents - -`TFormComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> - -### TSubmitMeta - -`TSubmitMeta` - -### TRenderProps - -`TRenderProps` *extends* `Record`\<`string`, `unknown`\> = `Record`\<`string`, `never`\> - -## Properties - -### props? - -```ts -optional props: TRenderProps; -``` - -Defined in: [packages/solid-form/src/createFormHook.tsx:271](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createFormHook.tsx#L271) - -*** - -### render() - -```ts -render: (props) => Element; -``` - -Defined in: [packages/solid-form/src/createFormHook.tsx:272](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createFormHook.tsx#L272) - -#### Parameters - -##### props - -`ParentProps`\<`NoInfer`\<`TRenderProps`\> & `object`\> - -#### Returns - -`Element` diff --git a/docs/framework/solid/reference/interfaces/WithFormProps.md b/docs/framework/solid/reference/interfaces/WithFormProps.md deleted file mode 100644 index cfbb707915..0000000000 --- a/docs/framework/solid/reference/interfaces/WithFormProps.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -id: WithFormProps -title: WithFormProps ---- - -# Interface: WithFormProps\ - -Defined in: [packages/solid-form/src/createFormHook.tsx:207](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createFormHook.tsx#L207) - -## Extends - -- `FormOptions`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` - -### TFieldComponents - -`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> - -### TFormComponents - -`TFormComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> - -### TRenderProps - -`TRenderProps` *extends* `Record`\<`string`, `unknown`\> = `Record`\<`string`, `never`\> - -## Properties - -### props? - -```ts -optional props: TRenderProps; -``` - -Defined in: [packages/solid-form/src/createFormHook.tsx:238](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createFormHook.tsx#L238) - -*** - -### render() - -```ts -render: (props) => Element; -``` - -Defined in: [packages/solid-form/src/createFormHook.tsx:239](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createFormHook.tsx#L239) - -#### Parameters - -##### props - -`ParentProps`\<`NoInfer`\<`TRenderProps`\> & `object`\> - -#### Returns - -`Element` diff --git a/docs/framework/solid/reference/type-aliases/AnyAtom.md b/docs/framework/solid/reference/type-aliases/AnyAtom.md new file mode 100644 index 0000000000..6491b16950 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/AnyAtom.md @@ -0,0 +1,10 @@ +--- +id: AnyAtom +title: AnyAtom +--- + +```ts +type AnyAtom = BaseAtom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:36 diff --git a/docs/framework/solid/reference/type-aliases/AnyFieldGroupApi.md b/docs/framework/solid/reference/type-aliases/AnyFieldGroupApi.md new file mode 100644 index 0000000000..f40e0d4240 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/AnyFieldGroupApi.md @@ -0,0 +1,10 @@ +--- +id: AnyFieldGroupApi +title: AnyFieldGroupApi +--- + +```ts +type AnyFieldGroupApi = FieldGroupApi>>; +``` + +Defined in: [packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts:87](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts#L87) diff --git a/docs/framework/solid/reference/type-aliases/AnySolidFormApi.md b/docs/framework/solid/reference/type-aliases/AnySolidFormApi.md new file mode 100644 index 0000000000..5997057e4c --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/AnySolidFormApi.md @@ -0,0 +1,33 @@ +--- +id: AnySolidFormApi +title: AnySolidFormApi +--- + +```ts +type AnySolidFormApi = AnyFormApi & SolidTanStackFormComponents; +``` + +Defined in: [packages/solid-form/src/formApiTypes.public.ts:52](https://github.com/TanStack/form/blob/main/packages/solid-form/src/formApiTypes.public.ts#L52) + +A Solid form API whose form data and error types are erased. + +Use it for reusable Solid components that only need core form operations and +the `Field`, `ArrayField`, `Subscribe`, or `FormGroup` components common to +every Solid form. Field paths and values are not checked against a particular +form shape; use `SolidFormType` when a component depends on one known form. + +## Example + +```tsx +function FormSubmitButton(props: { form: AnySolidFormApi }) { + return ( + state.isSubmitting}> + {(isSubmitting) => ( + + )} + + ) +} +``` diff --git a/docs/framework/solid/reference/type-aliases/AnySolidFormComponentMap.md b/docs/framework/solid/reference/type-aliases/AnySolidFormComponentMap.md new file mode 100644 index 0000000000..2a3b53251a --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/AnySolidFormComponentMap.md @@ -0,0 +1,10 @@ +--- +id: AnySolidFormComponentMap +title: AnySolidFormComponentMap +--- + +```ts +type AnySolidFormComponentMap = SolidFormComponentMap>, Record>>; +``` + +Defined in: [packages/solid-form/src/AppForm/componentMap.public.ts:11](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/componentMap.public.ts#L11) diff --git a/docs/framework/solid/reference/type-aliases/AppFormComponent.md b/docs/framework/solid/reference/type-aliases/AppFormComponent.md new file mode 100644 index 0000000000..01f5a72c1d --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/AppFormComponent.md @@ -0,0 +1,10 @@ +--- +id: AppFormComponent +title: AppFormComponent +--- + +```ts +type AppFormComponent = ParentComponent; +``` + +Defined in: [packages/solid-form/src/AppForm/SolidAppFormApi.public.ts:6](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/SolidAppFormApi.public.ts#L6) diff --git a/docs/framework/solid/reference/type-aliases/CreateFormHook.md b/docs/framework/solid/reference/type-aliases/CreateFormHook.md new file mode 100644 index 0000000000..107b427fba --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/CreateFormHook.md @@ -0,0 +1,34 @@ +--- +id: CreateFormHook +title: CreateFormHook +--- + +```ts +type CreateFormHook = (options) => SolidFormApi, DefaultSolidFormComponentMap>; +``` + +Defined in: [packages/solid-form/src/createForm.public.ts:11](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createForm.public.ts#L11) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> + +### TSubmitReturn + +`TSubmitReturn` + +## Parameters + +### options + +`Accessor`\<`FormOptions`\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\>\> + +## Returns + +[`SolidFormApi`](SolidFormApi.md)\<`TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>, [`DefaultSolidFormComponentMap`](DefaultSolidFormComponentMap.md)\> diff --git a/docs/framework/solid/reference/type-aliases/DefaultSolidFormComponentMap.md b/docs/framework/solid/reference/type-aliases/DefaultSolidFormComponentMap.md new file mode 100644 index 0000000000..d6d7da2e89 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/DefaultSolidFormComponentMap.md @@ -0,0 +1,10 @@ +--- +id: DefaultSolidFormComponentMap +title: DefaultSolidFormComponentMap +--- + +```ts +type DefaultSolidFormComponentMap = SolidFormComponentMap, Record>; +``` + +Defined in: [packages/solid-form/src/AppForm/componentMap.public.ts:16](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/componentMap.public.ts#L16) diff --git a/docs/framework/solid/reference/type-aliases/DefineFieldGroupFn.md b/docs/framework/solid/reference/type-aliases/DefineFieldGroupFn.md new file mode 100644 index 0000000000..94b1a673c9 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/DefineFieldGroupFn.md @@ -0,0 +1,34 @@ +--- +id: DefineFieldGroupFn +title: DefineFieldGroupFn +--- + +```ts +type DefineFieldGroupFn = (defineFn) => FieldGroupDefinition; +``` + +Defined in: [packages/solid-form/src/FieldGroup/withFields.public.ts:80](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/withFields.public.ts#L80) + +Signature shared by `defineFieldGroup` and app-form field-group definers. + +## Type Parameters + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +## Parameters + +### defineFn + +(`helper`) => `TFields` + +## Returns + +[`FieldGroupDefinition`](../interfaces/FieldGroupDefinition.md)\<`TFields`, `TFieldComponents`\> diff --git a/docs/framework/solid/reference/type-aliases/FieldComponent.md b/docs/framework/solid/reference/type-aliases/FieldComponent.md deleted file mode 100644 index 8525c288c5..0000000000 --- a/docs/framework/solid/reference/type-aliases/FieldComponent.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -id: FieldComponent -title: FieldComponent ---- - -# Type Alias: FieldComponent()\ - -```ts -type FieldComponent = ({ - children, - ...fieldOptions -}) => JSX.Element; -``` - -Defined in: [packages/solid-form/src/createField.tsx:414](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createField.tsx#L414) - -A type alias representing a field component for a specific form data type. - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TPatentSubmitMeta - -`TPatentSubmitMeta` - -### ExtendedApi - -`ExtendedApi` = \{ -\} - -## Type Parameters - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -## Parameters - -### \{ - children, - ...fieldOptions -\} - -`FieldComponentBoundProps`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TPatentSubmitMeta`, `ExtendedApi`\> - -## Returns - -`JSX.Element` diff --git a/docs/framework/solid/reference/type-aliases/FieldGroupFieldBindingsOf.md b/docs/framework/solid/reference/type-aliases/FieldGroupFieldBindingsOf.md new file mode 100644 index 0000000000..f0e6384be9 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/FieldGroupFieldBindingsOf.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupFieldBindingsOf +title: FieldGroupFieldBindingsOf +--- + +```ts +type FieldGroupFieldBindingsOf = FieldGroupFieldsOf extends FieldGroupFields ? FieldGroupFieldBindings, TFormData> : never; +``` + +Defined in: [packages/solid-form/src/FieldGroup/withFields.public.ts:44](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/withFields.public.ts#L44) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` + +### TFormData + +`TFormData` diff --git a/docs/framework/solid/reference/type-aliases/FieldGroupFieldComponentsOf.md b/docs/framework/solid/reference/type-aliases/FieldGroupFieldComponentsOf.md new file mode 100644 index 0000000000..e2e4bf5449 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/FieldGroupFieldComponentsOf.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupFieldComponentsOf +title: FieldGroupFieldComponentsOf +--- + +```ts +type FieldGroupFieldComponentsOf = TFieldGroup extends SolidFieldGroup ? TFieldComponents : never; +``` + +Defined in: [packages/solid-form/src/FieldGroup/withFields.public.ts:31](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/withFields.public.ts#L31) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` diff --git a/docs/framework/solid/reference/type-aliases/FieldGroupFieldsOf.md b/docs/framework/solid/reference/type-aliases/FieldGroupFieldsOf.md new file mode 100644 index 0000000000..74bb814995 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/FieldGroupFieldsOf.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupFieldsOf +title: FieldGroupFieldsOf +--- + +```ts +type FieldGroupFieldsOf = TFieldGroup extends object ? TFields : never; +``` + +Defined in: [packages/solid-form/src/FieldGroup/withFields.public.ts:16](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/withFields.public.ts#L16) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` diff --git a/docs/framework/solid/reference/type-aliases/FieldGroupForm.md b/docs/framework/solid/reference/type-aliases/FieldGroupForm.md new file mode 100644 index 0000000000..29e05b682f --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/FieldGroupForm.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupForm +title: FieldGroupForm +--- + +```ts +type FieldGroupForm = FormApi & SolidTanStackFormComponents; +``` + +Defined in: [packages/solid-form/src/FieldGroup/withFields.public.ts:35](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/withFields.public.ts#L35) + +## Type Parameters + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> = `Record`\<`never`, `never`\> + +### TFormData + +`TFormData` = `any` diff --git a/docs/framework/solid/reference/type-aliases/FieldGroupFormState.md b/docs/framework/solid/reference/type-aliases/FieldGroupFormState.md new file mode 100644 index 0000000000..b9e924b363 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/FieldGroupFormState.md @@ -0,0 +1,10 @@ +--- +id: FieldGroupFormState +title: FieldGroupFormState +--- + +```ts +type FieldGroupFormState = FormState; +``` + +Defined in: [packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts:91](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts#L91) diff --git a/docs/framework/solid/reference/type-aliases/FieldGroupSubscribeComponent.md b/docs/framework/solid/reference/type-aliases/FieldGroupSubscribeComponent.md new file mode 100644 index 0000000000..bfca780697 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/FieldGroupSubscribeComponent.md @@ -0,0 +1,26 @@ +--- +id: FieldGroupSubscribeComponent +title: FieldGroupSubscribeComponent +--- + +```ts +type FieldGroupSubscribeComponent = (props) => JSX.Element; +``` + +Defined in: [packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts:69](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts#L69) + +## Type Parameters + +### TSelected + +`TSelected` + +## Parameters + +### props + +[`FieldGroupSubscribeProps`](FieldGroupSubscribeProps.md)\<`TSelected`\> + +## Returns + +`JSX.Element` diff --git a/docs/framework/solid/reference/type-aliases/FieldGroupSubscribeProps.md b/docs/framework/solid/reference/type-aliases/FieldGroupSubscribeProps.md new file mode 100644 index 0000000000..6b008aeee1 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/FieldGroupSubscribeProps.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupSubscribeProps +title: FieldGroupSubscribeProps +--- + +```ts +type FieldGroupSubscribeProps = SolidFormSubscribeProps; +``` + +Defined in: [packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts:63](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/FieldGroupApi.public.ts#L63) + +## Type Parameters + +### TSelected + +`TSelected` diff --git a/docs/framework/solid/reference/type-aliases/FieldGroupWithFieldsFn.md b/docs/framework/solid/reference/type-aliases/FieldGroupWithFieldsFn.md new file mode 100644 index 0000000000..24d8c7b4ee --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/FieldGroupWithFieldsFn.md @@ -0,0 +1,40 @@ +--- +id: FieldGroupWithFieldsFn +title: FieldGroupWithFieldsFn +--- + +```ts +type FieldGroupWithFieldsFn = (Component, fieldsPropName) => (props) => JSX.Element; +``` + +Defined in: [packages/solid-form/src/FieldGroup/withFields.public.ts:49](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/withFields.public.ts#L49) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` *extends* [`SolidFieldGroup`](SolidFieldGroup.md)\<`any`, `any`\> + +## Type Parameters + +### TProps + +`TProps` *extends* `object` + +### TFieldsPropName + +`TFieldsPropName` *extends* `FieldGroupFieldsPropName`\<`TProps`, `TFieldGroup`\> + +## Parameters + +### Component + +(`props`) => `JSX.Element` + +### fieldsPropName + +`TFieldsPropName` + +## Returns + +\<`TFormData`\>(`props`) => `JSX.Element` diff --git a/docs/framework/solid/reference/type-aliases/FormGroupComponent.md b/docs/framework/solid/reference/type-aliases/FormGroupComponent.md deleted file mode 100644 index 65c2fa9ef2..0000000000 --- a/docs/framework/solid/reference/type-aliases/FormGroupComponent.md +++ /dev/null @@ -1,137 +0,0 @@ ---- -id: FormGroupComponent -title: FormGroupComponent ---- - -# Type Alias: FormGroupComponent()\ - -```ts -type FormGroupComponent = (props) => JSXElement; -``` - -Defined in: [packages/solid-form/src/createFormGroup.tsx:350](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createFormGroup.tsx#L350) - -A type alias representing a form group component for a specific form data type. - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` - -### ExtendedApi - -`ExtendedApi` = \{ -\} - -## Type Parameters - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TSubmitMeta - -`TSubmitMeta` - -## Parameters - -### props - -`FormGroupComponentBoundProps`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`, `ExtendedApi`\> - -## Returns - -`JSXElement` diff --git a/docs/framework/solid/reference/type-aliases/LensFieldComponent.md b/docs/framework/solid/reference/type-aliases/LensFieldComponent.md deleted file mode 100644 index 0d4a57494e..0000000000 --- a/docs/framework/solid/reference/type-aliases/LensFieldComponent.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -id: LensFieldComponent -title: LensFieldComponent ---- - -# Type Alias: LensFieldComponent()\ - -```ts -type LensFieldComponent = ({ - children, - ...fieldOptions -}) => JSX.Element; -``` - -Defined in: [packages/solid-form/src/createField.tsx:575](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createField.tsx#L575) - -A type alias representing a field component for a form lens data type. - -## Type Parameters - -### TLensData - -`TLensData` - -### TParentSubmitMeta - -`TParentSubmitMeta` - -### ExtendedApi - -`ExtendedApi` = \{ -\} - -## Type Parameters - -### TName - -`TName` *extends* `DeepKeys`\<`TLensData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TLensData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`unknown`, `string`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`unknown`, `string`, `TData`\> - -## Parameters - -### \{ - children, - ...fieldOptions -\} - -`Omit`\<`FieldComponentBoundProps`\<`unknown`, `string`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `undefined` \| `FormValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `undefined` \| `FormAsyncValidateOrFn`\<`unknown`\>, `TParentSubmitMeta`, `ExtendedApi`\>, `"name"` \| `"validators"`\> & `object` - -## Returns - -`JSX.Element` diff --git a/docs/framework/solid/reference/type-aliases/Observer.md b/docs/framework/solid/reference/type-aliases/Observer.md new file mode 100644 index 0000000000..c32765443c --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/Observer.md @@ -0,0 +1,70 @@ +--- +id: Observer +title: Observer +--- + +```ts +type Observer = object; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:8 + +## Type Parameters + +### T + +`T` + +## Properties + +### complete? + +```ts +optional complete?: () => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:11 + +#### Returns + +`void` + +*** + +### error? + +```ts +optional error?: (err) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:10 + +#### Parameters + +##### err + +`unknown` + +#### Returns + +`void` + +*** + +### next? + +```ts +optional next?: (value) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:9 + +#### Parameters + +##### value + +`T` + +#### Returns + +`void` diff --git a/docs/framework/solid/reference/type-aliases/Selection.md b/docs/framework/solid/reference/type-aliases/Selection.md new file mode 100644 index 0000000000..0ec13fa14b --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/Selection.md @@ -0,0 +1,16 @@ +--- +id: Selection +title: Selection +--- + +```ts +type Selection = Readable; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:4 + +## Type Parameters + +### TSelected + +`TSelected` diff --git a/docs/framework/solid/reference/type-aliases/SolidAppFormApi.md b/docs/framework/solid/reference/type-aliases/SolidAppFormApi.md new file mode 100644 index 0000000000..d4ad6acfeb --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/SolidAppFormApi.md @@ -0,0 +1,32 @@ +--- +id: SolidAppFormApi +title: SolidAppFormApi +--- + +```ts +type SolidAppFormApi = SolidFormApi & object; +``` + +Defined in: [packages/solid-form/src/AppForm/SolidAppFormApi.public.ts:8](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/SolidAppFormApi.public.ts#L8) + +## Type Declaration + +### AppForm + +```ts +AppForm: AppFormComponent; +``` + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TComponents + +`TComponents` *extends* [`AnySolidFormComponentMap`](AnySolidFormComponentMap.md) diff --git a/docs/framework/solid/reference/type-aliases/SolidFieldApi.md b/docs/framework/solid/reference/type-aliases/SolidFieldApi.md new file mode 100644 index 0000000000..000f1aa819 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/SolidFieldApi.md @@ -0,0 +1,36 @@ +--- +id: SolidFieldApi +title: SolidFieldApi +--- + +```ts +type SolidFieldApi = Accessor> & FieldComponentsMatchingType; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:62](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L62) + +## Type Parameters + +### TFieldName + +`TFieldName` + +### TFieldValue + +`TFieldValue` + +### TFieldError + +`TFieldError` + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> diff --git a/docs/framework/solid/reference/type-aliases/SolidFieldGroup.md b/docs/framework/solid/reference/type-aliases/SolidFieldGroup.md new file mode 100644 index 0000000000..65a693377f --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/SolidFieldGroup.md @@ -0,0 +1,28 @@ +--- +id: SolidFieldGroup +title: SolidFieldGroup +--- + +```ts +type SolidFieldGroup = FieldGroupApi, TFieldComponents> & object; +``` + +Defined in: [packages/solid-form/src/FieldGroup/withFields.public.ts:22](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/withFields.public.ts#L22) + +## Type Declaration + +### \[fieldGroupFieldsSymbol\] + +```ts +readonly [fieldGroupFieldsSymbol]: TFields; +``` + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> = `Record`\<`never`, `never`\> diff --git a/docs/framework/solid/reference/type-aliases/SolidFormApi.md b/docs/framework/solid/reference/type-aliases/SolidFormApi.md new file mode 100644 index 0000000000..b1de973a61 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/SolidFormApi.md @@ -0,0 +1,24 @@ +--- +id: SolidFormApi +title: SolidFormApi +--- + +```ts +type SolidFormApi = unknown extends TComponents["formComponents"] ? ExtendedFormApi : ExtendedFormApi & TComponents["formComponents"]; +``` + +Defined in: [packages/solid-form/src/formApiTypes.public.ts:16](https://github.com/TanStack/form/blob/main/packages/solid-form/src/formApiTypes.public.ts#L16) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TComponents + +`TComponents` *extends* [`AnySolidFormComponentMap`](AnySolidFormComponentMap.md) = [`DefaultSolidFormComponentMap`](DefaultSolidFormComponentMap.md) diff --git a/docs/framework/solid/reference/type-aliases/SolidFormExtendedApi.md b/docs/framework/solid/reference/type-aliases/SolidFormExtendedApi.md deleted file mode 100644 index 5b1cbcfff4..0000000000 --- a/docs/framework/solid/reference/type-aliases/SolidFormExtendedApi.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -id: SolidFormExtendedApi -title: SolidFormExtendedApi ---- - -# Type Alias: SolidFormExtendedApi\ - -```ts -type SolidFormExtendedApi = FormApi & SolidFormApi; -``` - -Defined in: [packages/solid-form/src/createForm.tsx:172](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createForm.tsx#L172) - -An extended version of the `FormApi` class that includes React-specific functionalities from `ReactFormApi` - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` diff --git a/docs/framework/solid/reference/type-aliases/SolidFormGroupAccessor.md b/docs/framework/solid/reference/type-aliases/SolidFormGroupAccessor.md new file mode 100644 index 0000000000..79c4bd726a --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/SolidFormGroupAccessor.md @@ -0,0 +1,36 @@ +--- +id: SolidFormGroupAccessor +title: SolidFormGroupAccessor +--- + +```ts +type SolidFormGroupAccessor = Accessor> & Pick, "Field" | "ArrayField" | "Subscribe">; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:299](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L299) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> diff --git a/docs/framework/solid/reference/type-aliases/SolidFormGroupSubscribeComponent.md b/docs/framework/solid/reference/type-aliases/SolidFormGroupSubscribeComponent.md new file mode 100644 index 0000000000..1b83242d04 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/SolidFormGroupSubscribeComponent.md @@ -0,0 +1,36 @@ +--- +id: SolidFormGroupSubscribeComponent +title: SolidFormGroupSubscribeComponent +--- + +```ts +type SolidFormGroupSubscribeComponent = (props) => JSX.Element; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:205](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L205) + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +## Type Parameters + +### TSelected + +`TSelected` + +## Parameters + +### props + +[`SolidFormGroupSubscribeProps`](SolidFormGroupSubscribeProps.md)\<`TGroupValue`, `TGroupErrorTypes`, `TSelected`\> + +## Returns + +`JSX.Element` diff --git a/docs/framework/solid/reference/type-aliases/SolidFormGroupSubscribeProps.md b/docs/framework/solid/reference/type-aliases/SolidFormGroupSubscribeProps.md new file mode 100644 index 0000000000..51519cd3b7 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/SolidFormGroupSubscribeProps.md @@ -0,0 +1,24 @@ +--- +id: SolidFormGroupSubscribeProps +title: SolidFormGroupSubscribeProps +--- + +```ts +type SolidFormGroupSubscribeProps = SolidSubscribeProps, TSelected>; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:196](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L196) + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TSelected + +`TSelected` diff --git a/docs/framework/solid/reference/type-aliases/SolidFormSubscribeComponent.md b/docs/framework/solid/reference/type-aliases/SolidFormSubscribeComponent.md new file mode 100644 index 0000000000..f8ec405f0e --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/SolidFormSubscribeComponent.md @@ -0,0 +1,36 @@ +--- +id: SolidFormSubscribeComponent +title: SolidFormSubscribeComponent +--- + +```ts +type SolidFormSubscribeComponent = (props) => JSX.Element; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:86](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L86) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +## Type Parameters + +### TSelected + +`TSelected` + +## Parameters + +### props + +[`SolidFormSubscribeProps`](SolidFormSubscribeProps.md)\<`TFormData`, `TFormErrorTypes`, `TSelected`\> + +## Returns + +`JSX.Element` diff --git a/docs/framework/solid/reference/type-aliases/SolidFormSubscribeProps.md b/docs/framework/solid/reference/type-aliases/SolidFormSubscribeProps.md new file mode 100644 index 0000000000..659e425f5f --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/SolidFormSubscribeProps.md @@ -0,0 +1,24 @@ +--- +id: SolidFormSubscribeProps +title: SolidFormSubscribeProps +--- + +```ts +type SolidFormSubscribeProps = SolidSubscribeProps, TSelected>; +``` + +Defined in: [packages/solid-form/src/Components.public.ts:80](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Components.public.ts#L80) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TSelected + +`TSelected` diff --git a/docs/framework/solid/reference/type-aliases/SolidFormType.md b/docs/framework/solid/reference/type-aliases/SolidFormType.md new file mode 100644 index 0000000000..14bae50d29 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/SolidFormType.md @@ -0,0 +1,45 @@ +--- +id: SolidFormType +title: SolidFormType +--- + +```ts +type SolidFormType = TOptions extends FormOptions ? SolidFormApi, TComponents extends AnySolidFormComponentMap ? TComponents : DefaultSolidFormComponentMap> : never; +``` + +Defined in: [packages/solid-form/src/formType.public.ts:49](https://github.com/TanStack/form/blob/main/packages/solid-form/src/formType.public.ts#L49) + +Derives the Solid form API type represented by a reusable options object. + +Use it to type props for components that belong to one known form shape. It +preserves the inferred form data and any components registered through +`appFormOptions`. Options such as `onSubmit` can be defined either in the +shared options or when the form is created in the component. + +## Type Parameters + +### TOptions + +`TOptions` *extends* `AnyFormOptions` + +The reusable form or app-form options from which the API derives its form data, error, and registered-component types. + +## Example + +```tsx +const profileOptions = formOptions({ + defaultValues: { name: '' }, +}) + +type ProfileForm = SolidFormType + +function NameField(props: { + form: ProfileForm +}) { + return ( + + {(field) => } + + ) +} +``` diff --git a/docs/framework/solid/reference/type-aliases/StoreAction.md b/docs/framework/solid/reference/type-aliases/StoreAction.md new file mode 100644 index 0000000000..3c38ef14ec --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/StoreAction.md @@ -0,0 +1,20 @@ +--- +id: StoreAction +title: StoreAction +--- + +```ts +type StoreAction = (...args) => any; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:4 + +## Parameters + +### args + +...`any`[] + +## Returns + +`any` diff --git a/docs/framework/solid/reference/type-aliases/StoreActionMap.md b/docs/framework/solid/reference/type-aliases/StoreActionMap.md new file mode 100644 index 0000000000..c23e39e1bd --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/StoreActionMap.md @@ -0,0 +1,10 @@ +--- +id: StoreActionMap +title: StoreActionMap +--- + +```ts +type StoreActionMap = Record; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:5 diff --git a/docs/framework/solid/reference/type-aliases/StoreActionsFactory.md b/docs/framework/solid/reference/type-aliases/StoreActionsFactory.md new file mode 100644 index 0000000000..b87f92ecf9 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/StoreActionsFactory.md @@ -0,0 +1,36 @@ +--- +id: StoreActionsFactory +title: StoreActionsFactory +--- + +```ts +type StoreActionsFactory = (store) => TActions; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:6 + +## Type Parameters + +### T + +`T` + +### TActions + +`TActions` *extends* [`StoreActionMap`](StoreActionMap.md) + +## Parameters + +### store + +#### get + +[`Store`](../classes/Store.md)\<`T`\>\[`"get"`\] + +#### setState + +[`Store`](../classes/Store.md)\<`T`\>\[`"setState"`\] + +## Returns + +`TActions` diff --git a/docs/framework/solid/reference/type-aliases/SubscribeSource.md b/docs/framework/solid/reference/type-aliases/SubscribeSource.md new file mode 100644 index 0000000000..e8a8558e25 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/SubscribeSource.md @@ -0,0 +1,20 @@ +--- +id: SubscribeSource +title: SubscribeSource +--- + +```ts +type SubscribeSource = + | Atom + | ReadonlyAtom + | Store +| ReadonlyStore; +``` + +Defined in: [packages/solid-form/src/Subscribe.public.ts:11](https://github.com/TanStack/form/blob/main/packages/solid-form/src/Subscribe.public.ts#L11) + +## Type Parameters + +### TValue + +`TValue` diff --git a/docs/framework/solid/reference/type-aliases/UseAppFormHook.md b/docs/framework/solid/reference/type-aliases/UseAppFormHook.md new file mode 100644 index 0000000000..3b0c79faa7 --- /dev/null +++ b/docs/framework/solid/reference/type-aliases/UseAppFormHook.md @@ -0,0 +1,40 @@ +--- +id: UseAppFormHook +title: UseAppFormHook +--- + +```ts +type UseAppFormHook = (options) => SolidAppFormApi, TComponents>; +``` + +Defined in: [packages/solid-form/src/AppForm/createFormHookTypes.public.ts:98](https://github.com/TanStack/form/blob/main/packages/solid-form/src/AppForm/createFormHookTypes.public.ts#L98) + +## Type Parameters + +### TComponents + +`TComponents` *extends* [`AnySolidFormComponentMap`](AnySolidFormComponentMap.md) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> + +### TSubmitReturn + +`TSubmitReturn` + +## Parameters + +### options + +`Accessor`\<`FormOptions`\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\>\> + +## Returns + +[`SolidAppFormApi`](SolidAppFormApi.md)\<`TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>, `TComponents`\> diff --git a/docs/framework/solid/reference/variables/createForm.md b/docs/framework/solid/reference/variables/createForm.md new file mode 100644 index 0000000000..d856c29eee --- /dev/null +++ b/docs/framework/solid/reference/variables/createForm.md @@ -0,0 +1,43 @@ +--- +id: createForm +title: createForm +--- + +```ts +const createForm: CreateFormHook; +``` + +Defined in: [packages/solid-form/src/createForm.public.ts:62](https://github.com/TanStack/form/blob/main/packages/solid-form/src/createForm.public.ts#L62) + +Creates a Solid form whose instance and lifecycle are owned by the current +reactive owner. + +Pass an options accessor. `defaultValues` establish the initial state and +inferred form value type, while signals read by the accessor update the same +form instance when they change. The form is cleaned up when its owner is +disposed. + +## Example + +```tsx +function ProfileForm() { + const form = createForm(() => ({ + defaultValues: { name: '' }, + onSubmit: ({ value }) => saveProfile(value), + })) + + return ( +
    { + event.preventDefault() + void form.handleSubmit() + }} + /> + ) +} +``` + +## Returns + +The Solid form API with typed field, subscription, and form-group +components attached. diff --git a/docs/framework/solid/reference/variables/defineFieldGroup.md b/docs/framework/solid/reference/variables/defineFieldGroup.md new file mode 100644 index 0000000000..4ee7f77212 --- /dev/null +++ b/docs/framework/solid/reference/variables/defineFieldGroup.md @@ -0,0 +1,12 @@ +--- +id: defineFieldGroup +title: defineFieldGroup +--- + +```ts +const defineFieldGroup: DefineFieldGroupFn>; +``` + +Defined in: [packages/solid-form/src/FieldGroup/withFields.public.ts:87](https://github.com/TanStack/form/blob/main/packages/solid-form/src/FieldGroup/withFields.public.ts#L87) + +Defines a reusable group of virtual fields. diff --git a/docs/framework/solid/reference/variables/useStore.md b/docs/framework/solid/reference/variables/useStore.md index 14e47e5694..64526d4a78 100644 --- a/docs/framework/solid/reference/variables/useStore.md +++ b/docs/framework/solid/reference/variables/useStore.md @@ -3,13 +3,11 @@ id: useStore title: useStore --- -# ~~Variable: useStore()~~ - ```ts const useStore: (source, selector?, compare?) => Accessor; ``` -Defined in: node\_modules/.pnpm/@tanstack+solid-store@0.11.0\_solid-js@1.9.13/node\_modules/@tanstack/solid-store/dist/useStore.d.ts:14 +Defined in: node\_modules/.pnpm/@tanstack+solid-store@0.11.1\_solid-js@1.9.14/node\_modules/@tanstack/solid-store/dist/useStore.d.ts:14 Deprecated alias for [useSelector](../functions/useSelector.md). diff --git a/docs/framework/svelte/guides/arrays.md b/docs/framework/svelte/guides/arrays.md deleted file mode 100644 index 8684726e57..0000000000 --- a/docs/framework/svelte/guides/arrays.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -id: arrays -title: Arrays ---- - -TanStack Form supports arrays as values in a form, including sub-object values inside of an array. - -## Basic Usage - -To use an array, you can use `field.state.value` on an array value in conjunction -with [`each blocks`](https://svelte.dev/docs/svelte/each): - -```svelte - - - - {#snippet children(field)} - {#each field.state.value as person, i} - - {/each} - {/snippet} - -``` - -This will regenerate the list every time you run `pushValue` on `field`: - -```svelte - -``` - -Finally, you can use a subfield like so: - -```svelte - - {#snippet children(subField)} - { - subField.handleChange(e.currentTarget.value) - }} - /> - {/snippet} - -``` - -## Full Example - -```svelte - - - { - e.preventDefault() - e.stopPropagation() - form.handleSubmit() - }} -> - - {#snippet children(field)} -
    - {#each field.state.value as person, i} - - {#snippet children(subField)} -
    - -
    - {/snippet} -
    - {/each} - - -
    - {/snippet} -
    - - - -``` diff --git a/docs/framework/svelte/guides/async-initial-values.md b/docs/framework/svelte/guides/async-initial-values.md index 3550b1934d..6765e21744 100644 --- a/docs/framework/svelte/guides/async-initial-values.md +++ b/docs/framework/svelte/guides/async-initial-values.md @@ -3,49 +3,163 @@ id: async-initial-values title: Async Initial Values --- -Let's say that you want to fetch some data from an API and use it as the initial value of a form. +Forms often edit data loaded from an API. A server-state library such as +TanStack Query should own fetching, caching, loading, and retries; TanStack Form +should own the editable copy. -While this problem sounds simple on the surface, there are hidden complexities you might not have thought of thus far. +There are two supported ways to provide async initial values: wait to create the +form until the data is ready, or create it immediately with complete fallback +values. Choose the approach that best matches the loading experience your UI +needs. -For example, you might want to show a loading spinner while the data is being fetched, or you might want to handle errors gracefully. -Likewise, you could also find yourself looking for a way to cache the data so that you don't have to fetch it every time the form is rendered. +## Wait for data before creating the editor -While we could implement many of these features from scratch, it would end up looking a lot like another project we maintain: [TanStack Query](https://tanstack.com/query). +Render a loading or error state first, then mount a component whose +`defaultValues` are complete. -As such, this guide shows you how you can mix-n-match TanStack Form with TanStack Query to achieve the desired behavior. +```svelte + + + +{#if $userQuery.isPending} +

    Loading…

    +{:else if $userQuery.isError} +

    Could not load the user.

    +{:else} + {#key userId} + + {/key} +{/if} +``` + +```svelte + + + +
    { + event.preventDefault() + form.handleSubmit() + }} +> + +
    +``` + +This pattern is useful when no form state is needed during loading. Mounting the +editor only after data exists also makes it explicit when switching records +should create a fresh form. The keyed block recreates the editor when `userId` +changes. -## Basic Usage +## Create the form before data arrives + +You can instead call `createForm` in the same component as `createQuery`. +Provide a static, shape-complete fallback so `defaultValues` are never +`undefined`. ```svelte - -{#if $isLoading} -

    Loading...

    +{#if $userQuery.isPending} +

    Loading…

    +{:else if $userQuery.isError} +

    Could not load the user.

    {:else} - +
    { + event.preventDefault() + form.handleSubmit() + }} + > + +
    {/if} ``` -This will show a loading spinner until the data is fetched, and then it will render the form with the fetched data as the initial values. +Because `createForm` receives an options function, reading `$userQuery` inside +that function keeps the options reactive. When the query data replaces the +fallback, TanStack Form applies the new `defaultValues` to untouched fields +while preserving fields the user has already touched. + +This is the approach demonstrated by the repository's +`examples/svelte/query-integration` example. + +## Background refetches and record changes + +`defaultValues` establish the form's baseline; they are not a fully controlled +`values` prop. In the fallback pattern, later `defaultValues` updates use the +same touched-field-preserving behavior. + +If background refetches arrive while a user is editing, decide at the product +level whether to keep local edits, prompt before replacing them, or call +`form.reset(nextValues)` deliberately. Do not overwrite in-progress input merely +because a query refreshed. + +When switching to a different record, either recreate a keyed editor as in the +first pattern or deliberately reset the existing form. Otherwise, touched +values from the previous record can be preserved when the new defaults arrive. diff --git a/docs/framework/svelte/guides/basic-concepts.md b/docs/framework/svelte/guides/basic-concepts.md deleted file mode 100644 index 7273ed4ab1..0000000000 --- a/docs/framework/svelte/guides/basic-concepts.md +++ /dev/null @@ -1,319 +0,0 @@ ---- -id: basic-concepts -title: Basic Concepts and Terminology ---- - -This page introduces the basic concepts and terminology used in the `@tanstack/svelte-form` library. Familiarizing yourself with these concepts will help you better understand and work with the library. - -## Form Options - -You can create options for your form so that it can be shared between multiple forms by using the `formOptions` function. - -Example: - -```ts -const formOpts = formOptions({ - defaultValues: { - firstName: '', - lastName: '', - hobbies: [], - } as Person, -}) -``` - -## Form Instance - -A Form Instance is an object that represents an individual form and provides methods and properties for working with the form. You create a form instance using the `createForm` function. The function accepts an object with an `onSubmit` function, which is called when the form is submitted. - -```ts -const form = createForm(() => ({ - ...formOpts, - onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) - }, -})) -``` - -You may also create a form instance without using `formOptions`: - -```ts -const form = createForm(() => ({ - onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) - }, - defaultValues: { - firstName: '', - lastName: '', - hobbies: [], - }, -})) -``` - -## Field - -A Field represents a single form input element, such as a text input or a checkbox. Fields are created using the `form.Field` component provided by the form instance. The component accepts a name prop, which should match a key in the form's default values. It also accepts a children prop, which is a render prop function that takes a field object as its argument. - -Example: - -```svelte - - {#snippet children(field)} - field.handleChange(e.target.value)} - /> - {/snippet} - -``` - -## Field State - -Each field has its own state, which includes its current value, validation status, error messages, and other metadata. You can access a field's state using the `field.state` property. - -Example: - -```ts -const { - value, - meta: { errors, isValidating }, -} = field.state -``` - -There are four states in the metadata that can be useful to see how the user interacts with a field: - -- _"isTouched"_, after the user changes the field or blurs the field -- _"isDirty"_, after the field's value has been changed, even if it's been reverted to the default. Opposite of `isPristine` -- _"isPristine"_, until the user changes the field value. Opposite of `isDirty` -- _"isBlurred"_, after the field has been blurred - -```ts -const { isTouched, isDirty, isPristine, isBlurred } = field.state.meta -``` - -![Field states](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states.png) - -## Understanding 'isDirty' in Different Libraries - -Non-Persistent `dirty` state - -- **Libraries**: React Hook Form (RHF), Formik, Final Form. -- **Behavior**: A field is 'dirty' if its value differs from the default. Reverting to the default value makes it 'clean' again. - -Persistent `dirty` state - -- **Libraries**: Angular Form, Vue FormKit. -- **Behavior**: A field remains 'dirty' once changed, even if reverted to the default value. - -We have chosen the persistent 'dirty' state model. To also support a non-persistent 'dirty' state, we introduce an additional flag: - -- _"isDefaultValue"_, whether the field's current value is the default value - -```ts -const { isDefaultValue, isTouched } = field.state.meta - -// The following line will re-create the non-Persistent `dirty` functionality. -const nonPersistentIsDirty = !isDefaultValue -``` - -![Field states extended](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states-extended.png) - -## Field API - -The Field API is an object passed to the render prop function when creating a field. It provides methods for working with the field's state. - -Example: - -```svelte - field.handleChange(e.target.value)} -/> -``` - -## Validation - -`@tanstack/svelte-form` provides both synchronous and asynchronous validation out of the box. Validation functions can be passed to the `form.Field` component using the `validators` prop. - -Example: - -```svelte - - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined, - onChangeAsync: async ({ value }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value.includes('error') && 'No "error" allowed in first name' - }, - }} -> - {#snippet children(field)} - field.handleChange(e.target.value)} - /> -

    {field.state.meta.errors[0]}

    - {/snippet} -
    -``` - -## Validation with Standard Schema Libraries - -In addition to hand-rolled validation options, we also support the [Standard Schema](https://github.com/standard-schema/standard-schema) specification. - -You can define a schema using any of the libraries implementing the specification and pass it to a form or field validator. - -Supported libraries include: - -- [Zod](https://zod.dev/) (v3.24.0 or higher) -- [Valibot](https://valibot.dev/) (v1.0.0 or higher) -- [ArkType](https://arktype.io/) (v2.1.20 or higher) -- [Yup](https://github.com/jquense/yup) (v1.7.0 or higher) - -```svelte - - - { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return !value.includes('error') - }, - { - message: 'No "error" allowed in first name', - }, - ), - }} -> - {#snippet children(field)} - field.handleChange(e.target.value)} - /> -

    {field.state.meta.errors[0]}

    - {/snippet} -
    -``` - -## Reactivity - -`@tanstack/svelte-form` offers various ways to subscribe to form and field state changes, most notably the `form.useSelector` hook and the `form.Subscribe` component. These methods allow you to optimize your form's rendering performance by only updating components when necessary. - -Example: - -```svelte - - - ({ - canSubmit: state.canSubmit, - isSubmitting: state.isSubmitting, - })} -> - {#snippet children(state)} - - {/snippet} - -``` - -## Array Fields - -Array fields allow you to manage a list of values within a form, such as a list of hobbies. You can create an array field using the `form.Field` component with the `mode="array"` prop. - -When working with array fields, you can use the fields `pushValue`, `removeValue`, `swapValues` and `moveValue` methods to add, remove, swap, and move a value from one index to another within the array, respectively. Additional helper methods such as `insertValue`, `replaceValue`, and `clearValues` are also available for inserting, replacing, and clearing array values. - -Example: - -```svelte - - {#snippet children(hobbiesField)} -
    - Hobbies -
    - {#each hobbiesField.state.value as _, i} -
    - - {#snippet children(field)} -
    - - field.handleChange(e.target.value)} - /> - -
    - {/snippet} -
    - - {#snippet children(field)} -
    - - field.handleChange(e.target.value)} - /> -
    - {/snippet} -
    -
    - {:else} - No hobbies found. - {/each} -
    - -
    - {/snippet} -
    -``` - -These are the basic concepts and terminology used in the `@tanstack/svelte-form` library. Understanding these concepts will help you work more effectively with the library and create complex forms with ease. diff --git a/docs/framework/svelte/guides/debugging.md b/docs/framework/svelte/guides/debugging.md new file mode 100644 index 0000000000..1a9f3ab236 --- /dev/null +++ b/docs/framework/svelte/guides/debugging.md @@ -0,0 +1,68 @@ +--- +id: debugging +title: Debugging Svelte Usage +--- + +This page covers common Svelte and TypeScript problems when using TanStack +Form. + +## An input does not start with the expected value + +Every value rendered by an input should exist in form-level `defaultValues` +when the form is created. + +```svelte + +``` + +Do not omit `defaultValues` or rely on a field-level default. When values come +from an API, render a loading state before mounting the editable form or supply +a complete fallback shape. + +## A field value is `unknown` + +Field names and values are inferred from `defaultValues`. Check that you have +not widened the initial object to `Record`, `any`, or an +unrelated union. Prefer a concrete value type: + +```svelte + +``` + +For extremely large forms, split UI into typed components or scoped form and +field groups instead of casting each field value. + +## Type instantiation is excessively deep + +This TypeScript error usually involves a very large recursive value shape, a +widely inferred union, or an unsupported composition. Reduce it to the smallest +form that reproduces the problem, keep `defaultValues` concrete, and avoid +unnecessary generic wrappers. + +If the minimal reproduction still fails, report it in the +[TanStack Form issue tracker](https://github.com/TanStack/form/issues). Include +the TypeScript and Svelte versions, the form value type, and the smallest +failing field. + +## Errors exist but are not displayed + +`field.errors` respects the form's `errorVisibility` policy. Inspect +`field.meta.original.errors` when debugging whether validation ran but the +issues are intentionally hidden. Also confirm that the input calls +`field.handleBlur` if the policy depends on `isBlurred`. diff --git a/docs/framework/svelte/guides/dynamic-validation.md b/docs/framework/svelte/guides/dynamic-validation.md deleted file mode 100644 index 8fce94586c..0000000000 --- a/docs/framework/svelte/guides/dynamic-validation.md +++ /dev/null @@ -1,225 +0,0 @@ ---- -id: dynamic-validation -title: Dynamic Validation ---- - -In many cases, you want to change the validation rules based depending on the state of the form or other conditions. The most popular -example of this is when you want to validate a field differently based on whether the user has submitted the form for the first time or not. - -We support this through our `onDynamic` validation function. - -```ts -import { revalidateLogic, createForm } from '@tanstack/svelte-form' - -// ... - -const form = createForm(() => ({ - defaultValues: { - firstName: '', - lastName: '', - }, - // If this is omitted, onDynamic will not be called - validationLogic: revalidateLogic(), - validators: { - onDynamic: ({ value }) => { - if (!value.firstName) { - return { firstName: 'A first name is required' } - } - return undefined - }, - }, -})) -``` - -> By default `onDynamic` is not called, so you need to pass `revalidateLogic()` to the `validationLogic` option of `createForm`. - -## Revalidation Options - -`revalidateLogic` allows you to specify when validation should be run and change the validation rules dynamically based on the current submission state of the form. - -It takes two arguments: - -- `mode`: The mode of validation prior to the first form submission. This can be one of the following: - - `change`: Validate on every change. - - `blur`: Validate on blur. - - `submit`: Validate on submit. (**default**) - -- `modeAfterSubmission`: The mode of validation after the form has been submitted. This can be one of the following: - - `change`: Validate on every change. (**default**) - - `blur`: Validate on blur. - - `submit`: Validate on submit. - -You can, for example, use the following to revalidate on blur after the first submission: - -```ts -const form = createForm(() => ({ - // ... - validationLogic: revalidateLogic({ - mode: 'submit', - modeAfterSubmission: 'blur', - }), - // ... -})) -``` - -## Accessing Errors - -Just as you might access errors from an `onChange` or `onBlur` validation, you can access the errors from the `onDynamic` validation function using the `form.state.errorMap` object. - -```svelte - - -

    {form.state.errorMap.onDynamic?.firstName}

    -``` - -## Usage with Other Validation Logic - -You can use `onDynamic` validation alongside other validation logic, such as `onChange` or `onBlur`. - -```svelte - - -
    -

    {form.state.errorMap.onChange?.firstName}

    -

    {form.state.errorMap.onDynamic?.lastName}

    -
    -``` - -### Usage with Fields - -You can also use `onDynamic` validation with fields, just like you would with other validation logic. - -```svelte - - -
    { - e.preventDefault() - e.stopPropagation() - form.handleSubmit() - }} -> - - value > 18 ? undefined : 'Age must be greater than 18', - }} - > - {#snippet children(field)} -
    - field.handleChange(e.target.valueAsNumber)} - onblur={field.handleBlur} - value={field.state.value} - /> -

    - {field.state.meta.errorMap.onDynamic} -

    -
    - {/snippet} -
    - -
    -``` - -### Async Validation - -Async validation can also be used with `onDynamic` just like with other validation logic. You can even debounce the async validation to avoid excessive calls. - -```ts -const form = createForm(() => ({ - defaultValues: { - username: '', - }, - validationLogic: revalidateLogic(), - validators: { - onDynamicAsyncDebounceMs: 500, // Debounce the async validation by 500ms - onDynamicAsync: async ({ value }) => { - if (!value.username) { - return { username: 'Username is required' } - } - // Simulate an async validation - const isValid = await validateUsername(value.username) - return isValid ? undefined : { username: 'Username is already taken' } - }, - }, -})) -``` - -### Standard Schema Validation - -You can also use standard schema validation libraries like Valibot or Zod with `onDynamic` validation. This allows you to define complex validation rules that can change dynamically based on the form state. - -```ts -import { z } from 'zod' - -const schema = z.object({ - firstName: z.string().min(1, 'A first name is required'), - lastName: z.string().min(1, 'A last name is required'), -}) - -const form = createForm(() => ({ - defaultValues: { - firstName: '', - lastName: '', - }, - validationLogic: revalidateLogic(), - validators: { - onDynamic: schema, - }, -})) -``` diff --git a/docs/framework/svelte/guides/form-composition.md b/docs/framework/svelte/guides/form-composition.md deleted file mode 100644 index d0e5e7426f..0000000000 --- a/docs/framework/svelte/guides/form-composition.md +++ /dev/null @@ -1,553 +0,0 @@ ---- -id: form-composition -title: Form Composition ---- - -A common criticism of TanStack Form is its verbosity out-of-the-box. While this _can_ be useful for educational purposes - helping enforce understanding our APIs - it's not ideal in production use cases. - -As a result, while `form.Field` enables the most powerful and flexible usage of TanStack Form, we provide APIs that wrap it and make your application code less verbose. - -## Custom Form Methods - -The most powerful way to compose forms is to create custom form methods. This allows you to create a form method that is tailored to your application's needs, including pre-bound custom UI components and more. - -At its most basic, `createFormCreator` is a function that returns a `createAppForm` method. - -> This un-customized `createAppForm` method is identical to `createForm`, but that will quickly change as we add more options to `createFormCreator`. - -```ts -// form-context.ts -import { createFormCreatorContexts } from '@tanstack/svelte-form' - -// export useFieldContext and useFormContext for use in your custom components -export const { useFieldContext, useFormContext } = createFormCreatorContexts() -``` - -```ts -// form.ts -import { createFormCreator } from '@tanstack/svelte-form' - -export const { createAppForm } = createFormCreator({ - // We'll learn more about these options later - fieldComponents: {}, - formComponents: {}, -}) -``` - -```svelte - - - - - - -``` - -### Pre-bound Field Components - -Once this scaffolding is in place, you can start adding custom field and form components to your form method. - -> Note: the `useFieldContext` must be the same one exported from your custom form context - -```svelte - - - - -``` - -You're then able to register this component with your form method. - -```ts -import { createFormCreator } from '@tanstack/svelte-form' -import TextField from './text-field.svelte' - -export const { createAppForm } = createFormCreator({ - fieldComponents: { - TextField, - }, - formComponents: {}, -}) -``` - -And use it in your form: - -```svelte - - - - - {#snippet children(field)} - - {/snippet} - -``` - -This not only allows you to reuse the UI of your shared component, but retains the type-safety you'd expect from TanStack Form: Typo `name` and get a TypeScript error. - -### Pre-bound Form Components - -While `form.AppField` solves many of the problems with Field boilerplate and reusability, it doesn't solve the problem of _form_ boilerplate and reusability. - -In particular, being able to share instances of `form.Subscribe` for, say, a reactive form submission button is a common usecase. - -```svelte - - - - state.isSubmitting}> - {#snippet children(isSubmitting)} - - {/snippet} - -``` - -```ts -// form.ts -import { createFormCreator } from '@tanstack/svelte-form' -import TextField from './text-field.svelte' -import SubscribeButton from './subscribe-button.svelte' - -export const { createAppForm, getFormType } = createFormCreator({ - fieldComponents: { - TextField, - }, - formComponents: { - SubscribeButton, - }, -}) -``` - -```svelte - - - - - - {#snippet children()} - - {/snippet} - -``` - -## Breaking big forms into smaller pieces - -Sometimes forms get very large; it's just how it goes sometimes. While TanStack Form supports large forms well, it's never fun to work with hundreds or thousands of lines of code long files. - -To solve this, you can break forms into smaller Svelte components that accept the form as a prop. - -```ts -// shared-form.ts -import { formOptions } from '@tanstack/svelte-form' - -export const peopleFormOpts = formOptions({ - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, -}) -``` - -```svelte - - - -
    -

    {title}

    - - {#snippet children(field)} - - {/snippet} - - - {#snippet children()} - - {/snippet} - -
    -``` - -```svelte - - - - -``` - -## Getting the Form Type - -When you split a form into smaller child components, those child components need a typed `form` prop so that `form.AppField`, `form.AppForm`, and the registered field/form components remain fully type-safe. Writing out the full `createAppForm` generics by hand is verbose and error-prone. - -`createFormCreator` returns a `getFormType` helper alongside `createAppForm` for exactly this purpose. It accepts the same options object as `createAppForm` and returns a value whose type matches the form instance that `createAppForm` would produce — without actually running any logic at runtime. - -```ts -// form.ts -import { createFormCreator } from '@tanstack/svelte-form' -import TextField from './text-field.svelte' -import SubscribeButton from './subscribe-button.svelte' - -export const { createAppForm, getFormType } = createFormCreator({ - fieldComponents: { - TextField, - }, - formComponents: { - SubscribeButton, - }, -}) -``` - -Use it together with your shared `formOptions` to derive the expected `form` prop type: - -```svelte - - - - - {#snippet children(field)} - - {/snippet} - -``` - -This gives the child component a fully typed `form` prop — including the registered `fieldComponents` and `formComponents` — without having to repeat the form generics by hand or maintain a `ReturnType>` alias. - -> `useFormContext` is still the best fit for registered form components rendered inside `form.AppForm`. Use `getFormType` when you pass the form instance down as a prop to a child component. - -## Reusing groups of fields in multiple forms - -Sometimes, a pair of fields are so closely related that it makes sense to group and reuse them — like the password example listed in the [linked fields guide](./linked-fields.md). Instead of repeating this logic across multiple forms, you can create reusable field group components. - -> Unlike form-level components, validators in field groups cannot be strictly typed and could be any value. -> Ensure that your fields can accept unknown error types. - -Rewriting the passwords example as a reusable component would look like this: - -```svelte - - - -
    -

    {title}

    - - {#snippet children(field)} - - {/snippet} - - { - if (value !== fieldApi.form.getFieldValue('password')) { - return 'Passwords do not match' - } - return undefined - }, - }} - > - {#snippet children(field)} -
    - - {#each field.state.meta.errors as error} -
    {error}
    - {/each} -
    - {/snippet} -
    -
    -``` - -We can now use these grouped fields in any form that implements the required fields: - -```svelte - - - - - {#snippet children()} - - {#snippet children(field)} - - {/snippet} - - - - {/snippet} - -``` - -## Tree-shaking form and field components - -While the above examples are great for getting started, they're not ideal for certain use-cases where you might have hundreds of form and field components. -In particular, you may not want to include all of your form and field components in the bundle of every file that uses your form method. - -To solve this, you can use dynamic imports with Svelte's component loading: - -```ts -// src/utils/form-context.ts -import { createFormCreatorContexts } from '@tanstack/svelte-form' - -export const { useFieldContext, useFormContext } = createFormCreatorContexts() -``` - -```svelte - - - - -``` - -```ts -// src/utils/form.ts -import { createFormCreator } from '@tanstack/svelte-form' -import TextField from '../components/text-field.svelte' -import SubscribeButton from '../components/subscribe-button.svelte' - -export const { createAppForm, getFormType } = createFormCreator({ - fieldComponents: { - TextField, - }, - formComponents: { - SubscribeButton, - }, -}) -``` - -```svelte - - - - -``` - -## Putting it all together - -Now that we've covered the basics of creating custom form methods, let's put it all together in a single example. - -```ts -// /src/utils/form-context.ts, to be used across the entire app -import { createFormCreatorContexts } from '@tanstack/svelte-form' - -export const { useFieldContext, useFormContext } = createFormCreatorContexts() -``` - -```svelte - - - - -``` - -```svelte - - - - state.isSubmitting}> - {#snippet children(isSubmitting)} - - {/snippet} - -``` - -```ts -// /src/utils/form.ts -import { createFormCreator } from '@tanstack/svelte-form' -import TextField from '../components/text-field.svelte' -import SubscribeButton from '../components/subscribe-button.svelte' - -export const { createAppForm, getFormType } = createFormCreator({ - fieldComponents: { - TextField, - }, - formComponents: { - SubscribeButton, - }, -}) -``` - -```ts -// /src/features/people/shared-form.ts, to be used across `people` features -import { formOptions } from '@tanstack/svelte-form' - -export const peopleFormOpts = formOptions({ - defaultValues: { - firstName: 'John', - lastName: 'Doe', - }, -}) -``` - -```svelte - - - -
    -

    {title}

    - - {#snippet children(field)} - - {/snippet} - - - {#snippet children()} - - {/snippet} - -
    -``` - -```svelte - - - - -``` - -## API Usage Guidance - -Here's a chart to help you decide what APIs you should be using: - -![](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/svelte_form_composability.svg) diff --git a/docs/framework/svelte/guides/form-groups.md b/docs/framework/svelte/guides/form-groups.md deleted file mode 100644 index f6a85c99b6..0000000000 --- a/docs/framework/svelte/guides/form-groups.md +++ /dev/null @@ -1,196 +0,0 @@ ---- -id: form-groups -title: Form Groups ---- - -When building a multi-stage form that has many stages, like so: - -![Form stepper](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/stepper.png) - -It's common for each step to have its own form. However, this complicates the form submission and validation process by requiring you to add complex logic. - -Luckily, TanStack Form provides a way to build out sub-forms that make this kind of development trivial to implement: ``. - -## Usage - -To use a form group in TanStack Form, you'll use `createForm` or [`createAppForm`](./form-composition.md) to create a `form` variable, then reference its `FormGroup` component like you would a `Field`: - -```svelte - - - - {#snippet children(group)} - - - {/snippet} - -``` - -This becomes much more useful when paired with external state to conditionally render a `FormGroup`: - -```svelte - - -{#if step === 0} - { - // We can move the step forward when validation passes - step++ - }} - onGroupSubmitInvalid={() => { - // Or handle invalid submissions, just like a top-level form - }} - onSubmitMeta={{} as SomeType} - > - {#snippet children(group)} -
    { - e.preventDefault() - e.stopPropagation() - // Use `group.handleSubmit()` to submit the sub-form, but not the parent form - group.handleSubmit() - }} - > - -
    - {/snippet} -
    -{:else if step === 1} - form.handleSubmit()}> - {#snippet children(group)} -
    { - e.preventDefault() - e.stopPropagation() - group.handleSubmit() - }} - > - - -
    - {/snippet} -
    -{/if} -``` - -## Form Group Validation - -Form groups have a distinct validation procedure that we think makes sense for sub-forms: - -- Form groups can have their own validation: - -```svelte - 'Error' }}> - {#snippet children(group)} - - - {/snippet} - -``` - -- Can set errors on sub-fields: - -```svelte - ({ - group: value.name === 'error' ? 'Group error' : undefined, - fields: { - // Must use the name of the field relative to the FormGroup as the error key, - // to stay consistent with how standard schema works with form groups - name: value.name === 'error' ? 'Field error' : undefined, - }, - }), - }} -/> -``` - -- And can even accept standard schemas: - -```svelte - -``` - -> The reason we don't use the full path names for fields is so that you can compose your schemas like so: -> -> ```ts -> const step1Schema = z.object({ -> name: z.string().min(2), -> }) -> -> const schema = z.object({ -> step1: step1Schema, -> step2: step2Schema, -> }) -> ``` -> -> And pass the `step1Schema` to a form group and `schema` to the parent form. That way, partially validated data will still flag errors if the group is bypassed. - -### Dynamic Group Validation - -If you want to use [dynamic validation (`onDynamic`)](./dynamic-validation.md) with a form group, do not rely on the `onDynamic` validator passed to `createForm`: - -```ts -createForm(() => ({ - validationLogic: revalidateLogic(), - validators: { - // This validator will not run `onChange` when a sub-form is submitted; - // it will only run `onChange` when the form itself is submitted. - onDynamic: schema, - }, -})) -``` - -Instead, pass your sub-schema for the group to the `onDynamic` validation of the `FormGroup` itself: - -```svelte - -``` - -It will treat `group.submissionAttempts` as the way to change what validator is ran before/after submit. - -## Form Group State - -Just like you're able to access `group.state.meta.errors`, you're also able to access the group's value using `group.state.value`. Likewise, here are some valuable properties you can access in the `group.state.meta`: - -- `group.state.meta.isFieldsValid`: `true` when the field-level validators have no errors -- `group.state.meta.isGroupValid`: `true` when the group-level validators have no errors -- `group.state.meta.isValid`: `true` when both the field-level and group-level validators have no errors -- `group.state.meta.isSubmitting`: `true` when the group is in the process of being submitted diff --git a/docs/framework/svelte/guides/linked-fields.md b/docs/framework/svelte/guides/linked-fields.md deleted file mode 100644 index c74cb34b52..0000000000 --- a/docs/framework/svelte/guides/linked-fields.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -id: linked-fields -title: Link Two Form Fields Together ---- - -You may find yourself needing to link two fields together; when one is validated as another field's value has changed. -One such usage is when you have both a `password` and `confirm_password` field, -where you want to `confirm_password` to error out when `password`'s value does not match; -regardless of which field triggered the value change. - -Imagine the following userflow: - -- User updates confirm password field. -- User updates the non-confirm password field. - -In this example, the form will still have errors present, -as the "confirm password" field validation has not been re-ran to mark as accepted. - -To solve this, we need to make sure that the "confirm password" validation is re-run when the password field is updated. -To do this, you can add a `onChangeListenTo` property to the `confirm_password` field. - -```svelte - - -
    - - {#snippet children(field)} - - {/snippet} - - { - if (value !== fieldApi.form.getFieldValue('password')) { - return 'Passwords do not match' - } - return undefined - }, - }} - > - {#snippet children(field)} -
    - - {#each field.state.meta.errors as err} -
    {err}
    - {/each} -
    - {/snippet} -
    -
    -``` - -This similarly works with `onBlurListenTo` property, which will re-run the validation when the field is blurred. diff --git a/docs/framework/svelte/guides/ui-libraries.md b/docs/framework/svelte/guides/ui-libraries.md new file mode 100644 index 0000000000..f39862be77 --- /dev/null +++ b/docs/framework/svelte/guides/ui-libraries.md @@ -0,0 +1,85 @@ +--- +id: ui-libraries +title: UI Libraries +--- + +TanStack Form is headless. UI library integration consists of adapting a +field's value, blur callback, change callback, invalid state, and errors to the +component's prop names. + +## Text inputs + +Many Svelte text-input components accept DOM-like props: + +```svelte + + {#snippet children(field)} + field.handleChange(event.currentTarget.value)} + error={field.errors.map((error) => error.message).join(', ')} + /> + {/snippet} + +``` + +Pass `value` instead of using a component's one-time default-value prop so the +component reflects form state. + +## Checkboxes and switches + +DOM-style checkbox components expose `event.currentTarget.checked`: + +```svelte + + {#snippet children(field)} + field.handleChange(event.currentTarget.checked)} + aria-invalid={field.meta.isInvalid} + /> + {/snippet} + +``` + +Some libraries call back with a boolean, a details object, or a union such as +`boolean | 'indeterminate'`. Normalize that value at the boundary: + +```svelte + field.handleChange(checked === true)} +/> +``` + +## Selects, date pickers, and custom controls + +The integration does not require a native event. Pass the value produced by the +component to `field.handleChange`: + +```svelte + field.handleChange(nextDate)} + onblur={field.handleBlur} +/> +``` + +Choose a serializable form value appropriate for your application, then adapt +the UI library's richer object at the component boundary if necessary. + +## Reuse the adapter + +If the same wiring appears throughout the application, extract a Svelte +component that accepts `FieldWithValue` or register it with +`createFormHook`. + +For the helper types used when passing a form or field to an extracted +component, see [Splitting forms](../../../splitting-forms). + +The repository's `examples/svelte/large-form` example demonstrates reusable +field and form components with the v2 Svelte adapter. diff --git a/docs/framework/svelte/guides/validation.md b/docs/framework/svelte/guides/validation.md index a04bffc2da..1a50925215 100644 --- a/docs/framework/svelte/guides/validation.md +++ b/docs/framework/svelte/guides/validation.md @@ -3,401 +3,269 @@ id: form-validation title: Form and Field Validation --- -At the core of TanStack Form's functionalities is the concept of validation. TanStack Form makes validation highly customizable: +TanStack Form supports synchronous, asynchronous, field-level, form-level, and +Standard Schema validation. Every validator is an ordered object with a `run` +implementation and explicit `triggers`. -- You can control when to perform the validation (on change, on input, on blur, on submit...) -- Validation rules can be defined at the field level or at the form level -- Validation can be synchronous or asynchronous (for example, as a result of an API call) +## Choose when validation runs -## When is validation performed? - -It's up to you! The `` component accepts some callbacks as props such as `onChange` or `onBlur`. Those callbacks are passed the current value of the field, as well as the fieldAPI object, so that you can perform the validation. If you find a validation error, simply return the error message as string and it will be available in `field.state.meta.errors`. - -Here is an example: - -```svelte - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {#snippet children(field)} - - field.handleChange(e.target.valueAsNumber)} - /> - {#if field.state.meta.errors} - {field.state.meta.errors.join(', ')} - {/if} - {/snippet} - -``` - -In the example above, the validation is done at each keystroke (`onchange`). If, instead, we wanted the validation to be done when the field is blurred, we would change the code above like so: +Use `change` for immediate feedback and `blur` for feedback after leaving an +input. Submission runs validators by default regardless of their configured +change and blur triggers. ```svelte - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {#snippet children(field)} - - field.handleChange(e.target.valueAsNumber)} - /> - {#if field.state.meta.errors} - {field.state.meta.errors.join(', ')} - {/if} - {/snippet} - -``` - -So you can control when the validation is done by implementing the desired callback. You can even perform different pieces of validation at different times: - -```svelte - - value < 13 ? 'You must be 13 to make an account' : undefined, - onBlur: ({ value }) => (value < 0 ? 'Invalid value' : undefined), - }} + validators={[ + { + triggers: ['change'], + run: ({ value }) => + value >= 13 ? undefined : 'You must be at least 13', + }, + { + triggers: ['blur'], + run: ({ value }) => + value >= 0 ? undefined : 'Age cannot be negative', + }, + ]} > {#snippet children(field)} - - field.handleChange(e.target.valueAsNumber)} - /> - {#if field.state.meta.errors} - {field.state.meta.errors.join(', ')} - {/if} + {/snippet} ``` -In the example above, we are validating different things on the same field at different times (at each keystroke and when blurring the field). Since `field.state.meta.errors` is an array, all the relevant errors at a given time are displayed. You can also use `field.state.meta.errorMap` to get errors based on _when_ the validation was done (onChange, onBlur etc...). More info about displaying errors below. +Additional controls include: -## Displaying Errors +- `runOnMount`: run once when the form is constructed or when a field or form + group first mounts. +- `skipOnSubmit`: conditionally skip submit-time execution. +- `triggerDebounceMs`: debounce change and blur execution. +- `bailIfInvalid`: skip this and subsequent validators when an earlier one + failed. +- trigger objects with `when`: enable a trigger conditionally. +- `watchFields`: rerun a field validator when related fields trigger it. -Once you have your validation in place, you can map the errors from an array to be displayed in your UI: +## Control when errors are visible -```svelte - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {#snippet children(field)} - - {#if field.state.meta.errors} - {field.state.meta.errors.join(', ')} - {/if} - {/snippet} - -``` - -Or use the `errorMap` property to access the specific error you're looking for: +Validation and presentation are separate. `errorVisibility` decides when field +issues appear in `field.errors`: ```svelte - - value < 13 ? 'You must be 13 to make an account' : undefined, - }} -> - {#snippet children(field)} - - {#if field.state.meta.errorMap['onChange']} - {field.state.meta.errorMap['onChange']} - {/if} - {/snippet} - -``` - -It's worth mentioning that our `errors` array and the `errorMap` matches the types returned by the validators. This means that: + ``` -## Validation at field level vs at form level +Use `field.meta.original.errors` for the unfiltered issues when debugging or +building a custom visibility system. -As shown above, each `` accepts its own validation rules via the `onChange`, `onBlur` etc... callbacks. It is also possible to define validation rules at the form level (as opposed to field by field) by passing similar callbacks to the `createForm()` hook. +## Form-level validation -Example: +A form validator can produce a form issue and route issues to typed field paths +with `createErrorMap`: ```svelte - - -
    - - {#if formErrorMap.current.onChange} -
    - There was an error on the form: {formErrorMap.current.onChange} -
    - {/if} - -
    ``` -## Asynchronous Functional Validation +Use `form.Subscribe` to reactively select form-level issues from +`form.state.errors`. Lower-level integrations can subscribe to `form.atom`. +Field-routed issues appear in the corresponding `field.errors`. -While we suspect most validations will be synchronous, there are many instances where a network call or some other async operation would be useful to validate against. +## Asynchronous validation and debouncing -To do this, we have dedicated `onChangeAsync`, `onBlurAsync`, and other methods that can be used to validate against: +`run` may return a promise. Put cheap synchronous checks first and use +`bailIfInvalid` to avoid unnecessary requests: ```svelte { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value < 13 ? 'You must be 13 to make an account' : undefined + name="username" + validators={[ + { + triggers: ['change'], + run: ({ value }) => + value.length >= 3 ? undefined : 'Use at least 3 characters', }, - }} -> - {#snippet children(field)} - - field.handleChange(e.target.valueAsNumber)} - /> - {#if field.state.meta.errors} - {field.state.meta.errors.join(', ')} - {/if} - {/snippet} - -``` - -Synchronous and Asynchronous validations can coexist. For example, it is possible to define both `onBlur` and `onBlurAsync` on the same field: - -```svelte - (value < 13 ? 'You must be at least 13' : undefined), - onBlurAsync: async ({ value }) => { - const currentAge = await fetchCurrentAgeOnProfile() - return value < currentAge ? 'You can only increase the age' : undefined + { + triggers: ['change'], + triggerDebounceMs: 500, + bailIfInvalid: true, + run: async ({ value }) => { + const available = await checkUsername(value) + return available ? undefined : 'That username is already taken' + }, }, - }} + ]} > {#snippet children(field)} - field.handleChange(e.target.valueAsNumber)} + value={field.value} + oninput={(event) => field.handleChange(event.currentTarget.value)} /> - {#if field.state.meta.errors} - {field.state.meta.errors.join(', ')} - {/if} {/snippet} ``` -The synchronous validation method (`onBlur`) is run first and the asynchronous method (`onBlurAsync`) is only run if the synchronous one (`onBlur`) succeeds. To change this behaviour, set the `asyncAlways` option to `true`, and the async method will be run regardless of the result of the sync method. +Submit validation always runs immediately, even when a trigger is debounced. +`field.meta.isValidating` and `form.state.isValidating` expose pending work. -### Built-in Debouncing +## Standard Schema validation -While async calls are the way to go when validating against the database, running a network request on every keystroke is a good way to DDOS your database. - -Instead, we enable an easy method for debouncing your `async` calls by adding a single property: +Any Standard Schema implementation can be supplied as `run`: ```svelte - { - // ... - }, - }} -> - - -``` - -This will debounce every async call with a 500ms delay. You can even override this property on a per-validation property: - -```svelte - { - // ... - }, - onBlurAsync: async ({ value }) => { - // ... - }, - }} -> - - -``` - -> This will run `onChangeAsync` every 1500ms while `onBlurAsync` will run every 500ms. - -## Validation through Schema Libraries - -While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries that provide schema-based validation to make shorthand and type-strict validation substantially easier. You can also define a single schema for your entire form and pass it to the form level, errors will be automatically propagated to the fields. - -### Standard Schema Libraries - -TanStack Form natively supports all libraries following the [Standard Schema specification](https://github.com/standard-schema/standard-schema), most notably: - -- [Zod](https://zod.dev/) -- [Valibot](https://valibot.dev/) -- [ArkType](https://arktype.io/) - -_Note:_ make sure to use the latest version of the schema libraries as older versions might not support Standard Schema yet. - -To use schemas from these libraries you can pass them to the `validators` props as you would do with a custom function: - -```svelte - - - - - ``` -Async validations on form and field level are supported as well: +Schema paths are routed to matching fields. Parsed outputs are available by +validator index in `schemaOutputs` during submit, for example +`schemaOutputs[0]`. `value` remains the form's raw editable state rather than +the parsed output. + +For custom schema routing, call a schema's safe parse API inside `run` and pass +its issues to the provided `parseIssues` helper. + +## Validate related fields + +Use `watchFields` when one field's validity depends on another: ```svelte { - const currentAge = await fetchCurrentAgeOnProfile() - return value >= currentAge - }, - { - message: 'You can only increase the age', - }, - ), - }} + name="endDate" + validators={[ + { + triggers: ['change', 'blur'], + watchFields: ['startDate'], + run: ({ value, formApi }) => + value >= formApi.getFieldValue('startDate') + ? undefined + : 'End date must be on or after the start date', + }, + ]} > - + {#snippet children(field)} + field.handleChange(event.currentTarget.value)} + aria-invalid={field.meta.isInvalid} + /> + {/snippet} ``` -## Preventing invalid forms from being submitted - -The `onChange`, `onBlur` etc... callbacks are also run when the form is submitted and the submission is blocked if the form is invalid. - -The form state object has a `canSubmit` flag that is false when any field is invalid and the form has been touched (`canSubmit` is true until the form has been touched, even if some fields are "technically" invalid based on their `onChange`/`onBlur` props). +## Return errors from submission -You can subscribe to it via `form.Subscribe` and use the value in order to, for example, disable the submit button when the form is invalid (in practice, disabled buttons are not accessible, use `aria-disabled` instead). +Endpoint validation belongs in `onSubmit`. Return +`createValidationError(...)` to feed server issues back into normal form state: ```svelte - +``` - +## Prevent invalid submission - +`form.handleSubmit()` skips `onSubmit` when validation fails and resolves with +the validation errors. `onSubmitInvalid` is currently available on form groups; +root-form support is planned but not yet implemented. Subscribe to `canSubmit` +and `isSubmitting` to reflect that state in the submit UI: + +```svelte ({ - canSubmit: state.canSubmit, - isSubmitting: state.isSubmitting, - })} + selector={(state) => [state.canSubmit, state.isSubmitting]} > - {#snippet children(state)} - {/snippet} ``` -To prevent the form from being submitted before any interaction, combine `canSubmit` with `isPristine` flags. A simple condition like `!canSubmit || isPristine` effectively disables submissions until the user has made changes. +If a disabled submit button would hide useful validation feedback, keep it +focusable with `aria-disabled` and let `handleSubmit()` report the issues. diff --git a/docs/framework/svelte/quick-start.md b/docs/framework/svelte/quick-start.md index 106b0a2bde..19eca17d30 100644 --- a/docs/framework/svelte/quick-start.md +++ b/docs/framework/svelte/quick-start.md @@ -3,47 +3,112 @@ id: quick-start title: Quick Start --- -The bare minimum to get started with TanStack Form is to create a form and add a field. Keep in mind that this example does not include any validation or error handling... yet. +TanStack Form is a headless, type-safe form library. It owns form state and +validation while leaving markup, styling, and component choice to you. + +Install the Svelte adapter: + +```bash +npm install @tanstack/svelte-form +``` + +## Create a form + +`createForm` requires an options function and form-level `defaultValues`. Their +shape becomes the form's inferred value type. ```svelte - -
    -

    Simple Form Example

    -
    { - e.preventDefault() - e.stopPropagation() - form.handleSubmit() - }} + { + event.preventDefault() + form.handleSubmit() + }} +> + + value.trim() ? undefined : 'Enter your full name', + }, + ]} > -
    - - {#snippet children(field)} - field.handleChange(e.target.value)} - /> - {/snippet} - -
    - - -
    + {#snippet children(field)} + + {/snippet} +
    + + + value >= 13 ? undefined : 'You must be at least 13', + }, + ]} + > + {#snippet children(field)} + + {/snippet} + + + [state.canSubmit, state.isSubmitting] as const} + > + {#snippet children([canSubmit, isSubmitting])} + + {/snippet} + + ``` -From here, you'll be ready to explore all of the other features of TanStack Form! +The important pieces are: + +- `defaultValues` define the complete initial value and drive type inference. +- `form.Field` subscribes to one field. Its child snippet exposes `field.value`, + `field.meta`, and event handlers. +- Validators are ordered objects with a `run` function and explicit `triggers`. +- `form.Subscribe` updates only its child snippet when the selected form state + changes. +- `form.handleSubmit()` validates the form before calling `onSubmit`. diff --git a/docs/framework/svelte/reference/classes/ReadonlyStore.md b/docs/framework/svelte/reference/classes/ReadonlyStore.md new file mode 100644 index 0000000000..e764546914 --- /dev/null +++ b/docs/framework/svelte/reference/classes/ReadonlyStore.md @@ -0,0 +1,122 @@ +--- +id: ReadonlyStore +title: ReadonlyStore +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:22 + +## Type Parameters + +### T + +`T` + +## Implements + +- `Omit`\<[`Store`](Store.md)\<`T`\>, `"setState"` \| `"actions"`\> + +## Constructors + +### Constructor + +```ts +new ReadonlyStore(getValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:24 + +#### Parameters + +##### getValue + +(`prev?`) => `T` + +#### Returns + +`ReadonlyStore`\<`T`\> + +### Constructor + +```ts +new ReadonlyStore(initialValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:25 + +#### Parameters + +##### initialValue + +`T` + +#### Returns + +`ReadonlyStore`\<`T`\> + +## Accessors + +### state + +#### Get Signature + +```ts +get state(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:26 + +##### Returns + +`T` + +#### Implementation of + +```ts +Omit.state +``` + +## Methods + +### get() + +```ts +get(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:27 + +#### Returns + +`T` + +#### Implementation of + +```ts +Omit.get +``` + +*** + +### subscribe() + +```ts +subscribe(observerOrFn): Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:28 + +#### Parameters + +##### observerOrFn + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +#### Returns + +[`Subscription`](../interfaces/Subscription.md) + +#### Implementation of + +```ts +Omit.subscribe +``` diff --git a/docs/framework/svelte/reference/classes/Store.md b/docs/framework/svelte/reference/classes/Store.md new file mode 100644 index 0000000000..3e93a261b2 --- /dev/null +++ b/docs/framework/svelte/reference/classes/Store.md @@ -0,0 +1,156 @@ +--- +id: Store +title: Store +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:11 + +## Type Parameters + +### T + +`T` + +### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) = `never` + +## Constructors + +### Constructor + +```ts +new Store(getValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:14 + +#### Parameters + +##### getValue + +(`prev?`) => `T` + +#### Returns + +`Store`\<`T`, `TActions`\> + +### Constructor + +```ts +new Store(initialValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:15 + +#### Parameters + +##### initialValue + +`T` + +#### Returns + +`Store`\<`T`, `TActions`\> + +### Constructor + +```ts +new Store(initialValue, actionsFactory): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:16 + +#### Parameters + +##### initialValue + +`NonFunction`\<`T`\> + +##### actionsFactory + +[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> + +#### Returns + +`Store`\<`T`, `TActions`\> + +## Properties + +### actions + +```ts +readonly actions: TActions; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:13 + +## Accessors + +### state + +#### Get Signature + +```ts +get state(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:18 + +##### Returns + +`T` + +## Methods + +### get() + +```ts +get(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:19 + +#### Returns + +`T` + +*** + +### setState() + +```ts +setState(updater): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:17 + +#### Parameters + +##### updater + +(`prev`) => `T` + +#### Returns + +`void` + +*** + +### subscribe() + +```ts +subscribe(observerOrFn): Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:20 + +#### Parameters + +##### observerOrFn + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +#### Returns + +[`Subscription`](../interfaces/Subscription.md) diff --git a/docs/framework/svelte/reference/functions/batch.md b/docs/framework/svelte/reference/functions/batch.md new file mode 100644 index 0000000000..ad5677dbb2 --- /dev/null +++ b/docs/framework/svelte/reference/functions/batch.md @@ -0,0 +1,20 @@ +--- +id: batch +title: batch +--- + +```ts +function batch(fn): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:5 + +## Parameters + +### fn + +() => `void` + +## Returns + +`void` diff --git a/docs/framework/svelte/reference/functions/createAsyncAtom.md b/docs/framework/svelte/reference/functions/createAsyncAtom.md new file mode 100644 index 0000000000..5ec22ca780 --- /dev/null +++ b/docs/framework/svelte/reference/functions/createAsyncAtom.md @@ -0,0 +1,30 @@ +--- +id: createAsyncAtom +title: createAsyncAtom +--- + +```ts +function createAsyncAtom(getValue, options?): ReadonlyAtom>; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:16 + +## Type Parameters + +### T + +`T` + +## Parameters + +### getValue + +() => `Promise`\<`T`\> + +### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`AsyncAtomState`\<`T`, `unknown`\>\> + +## Returns + +[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`AsyncAtomState`\<`T`, `unknown`\>\> diff --git a/docs/framework/svelte/reference/functions/createAtom.md b/docs/framework/svelte/reference/functions/createAtom.md new file mode 100644 index 0000000000..d41435b132 --- /dev/null +++ b/docs/framework/svelte/reference/functions/createAtom.md @@ -0,0 +1,60 @@ +--- +id: createAtom +title: createAtom +--- + +## Call Signature + +```ts +function createAtom(getValue, options?): ReadonlyAtom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:17 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`T`\> + +## Call Signature + +```ts +function createAtom(initialValue, options?): Atom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:18 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`Atom`](../interfaces/Atom.md)\<`T`\> diff --git a/docs/framework/svelte/reference/functions/createFormHook.md b/docs/framework/svelte/reference/functions/createFormHook.md new file mode 100644 index 0000000000..e7a5bb0a48 --- /dev/null +++ b/docs/framework/svelte/reference/functions/createFormHook.md @@ -0,0 +1,38 @@ +--- +id: createFormHook +title: createFormHook +--- + +```ts +function createFormHook(createOptions): AppFormHookResult<{ + fieldComponents: TFieldComponents; + formComponents: TFormComponents; +}>; +``` + +Defined in: [packages/svelte-form/src/AppForm/createFormHook.public.ts:14](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/createFormHook.public.ts#L14) + +## Type Parameters + +### TFormComponents + +`TFormComponents` *extends* `Record`\<`string`, `Component`\<`any`, \{ +\}, `string`\>\> + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`, \{ +\}, `string`\>\> + +## Parameters + +### createOptions + +[`CreateFormHookOptions`](../interfaces/CreateFormHookOptions.md)\<`TFormComponents`, `TFieldComponents`\> + +## Returns + +[`AppFormHookResult`](../interfaces/AppFormHookResult.md)\<\{ + `fieldComponents`: `TFieldComponents`; + `formComponents`: `TFormComponents`; +\}\> diff --git a/docs/framework/svelte/reference/functions/createStore.md b/docs/framework/svelte/reference/functions/createStore.md new file mode 100644 index 0000000000..069cfed200 --- /dev/null +++ b/docs/framework/svelte/reference/functions/createStore.md @@ -0,0 +1,84 @@ +--- +id: createStore +title: createStore +--- + +## Call Signature + +```ts +function createStore(getValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:30 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +### Returns + +[`ReadonlyStore`](../classes/ReadonlyStore.md)\<`T`\> + +## Call Signature + +```ts +function createStore(initialValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:31 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +### Returns + +[`Store`](../classes/Store.md)\<`T`\> + +## Call Signature + +```ts +function createStore(initialValue, actions): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:32 + +### Type Parameters + +#### T + +`T` + +#### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) + +### Parameters + +#### initialValue + +`NonFunction`\<`T`\> + +#### actions + +[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> + +### Returns + +[`Store`](../classes/Store.md)\<`T`, `TActions`\> diff --git a/docs/framework/svelte/reference/functions/flush.md b/docs/framework/svelte/reference/functions/flush.md new file mode 100644 index 0000000000..a229192539 --- /dev/null +++ b/docs/framework/svelte/reference/functions/flush.md @@ -0,0 +1,14 @@ +--- +id: flush +title: flush +--- + +```ts +function flush(): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:6 + +## Returns + +`void` diff --git a/docs/framework/svelte/reference/functions/getFormHookHelpers.md b/docs/framework/svelte/reference/functions/getFormHookHelpers.md new file mode 100644 index 0000000000..7ce0374ff3 --- /dev/null +++ b/docs/framework/svelte/reference/functions/getFormHookHelpers.md @@ -0,0 +1,14 @@ +--- +id: getFormHookHelpers +title: getFormHookHelpers +--- + +```ts +function getFormHookHelpers(): FormHookHelpers; +``` + +Defined in: [packages/svelte-form/src/AppForm/getFormHookHelpers.public.ts:71](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/getFormHookHelpers.public.ts#L71) + +## Returns + +[`FormHookHelpers`](../interfaces/FormHookHelpers.md) diff --git a/docs/framework/svelte/reference/functions/shallow.md b/docs/framework/svelte/reference/functions/shallow.md new file mode 100644 index 0000000000..db1f393577 --- /dev/null +++ b/docs/framework/svelte/reference/functions/shallow.md @@ -0,0 +1,30 @@ +--- +id: shallow +title: shallow +--- + +```ts +function shallow(objA, objB): boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/shallow.d.ts:2 + +## Type Parameters + +### T + +`T` + +## Parameters + +### objA + +`T` + +### objB + +`T` + +## Returns + +`boolean` diff --git a/docs/framework/svelte/reference/functions/toObserver.md b/docs/framework/svelte/reference/functions/toObserver.md new file mode 100644 index 0000000000..add0d3bbdf --- /dev/null +++ b/docs/framework/svelte/reference/functions/toObserver.md @@ -0,0 +1,37 @@ +--- +id: toObserver +title: toObserver +--- + +```ts +function toObserver( + nextHandler?, + errorHandler?, +completionHandler?): Observer; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:4 + +## Type Parameters + +### T + +`T` + +## Parameters + +### nextHandler? + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +### errorHandler? + +(`error`) => `void` + +### completionHandler? + +() => `void` + +## Returns + +[`Observer`](../type-aliases/Observer.md)\<`T`\> diff --git a/docs/framework/svelte/reference/functions/useAtom.md b/docs/framework/svelte/reference/functions/useAtom.md new file mode 100644 index 0000000000..588bb43663 --- /dev/null +++ b/docs/framework/svelte/reference/functions/useAtom.md @@ -0,0 +1,47 @@ +--- +id: useAtom +title: useAtom +--- + +```ts +function useAtom(atom, options?): [{ + current: TValue; +}, (fn) => void & (value) => void]; +``` + +Defined in: node\_modules/.pnpm/@tanstack+svelte-store@0.12.1\_svelte@5.56.8\_@typescript-eslint+types@8.66.0\_/node\_modules/@tanstack/svelte-store/dist/useAtom.d.ts:16 + +Returns the current atom holder together with a setter. + +Use this when a component needs to both read and update the same writable +atom. + +## Type Parameters + +### TValue + +`TValue` + +## Parameters + +### atom + +[`Atom`](../interfaces/Atom.md)\<`TValue`\> + +### options? + +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TValue`\> + +## Returns + +\[\{ + `current`: `TValue`; +\}, (`fn`) => `void` & (`value`) => `void`\] + +## Example + +```ts +const [count, setCount] = useAtom(countAtom) +setCount((prev) => prev + 1) +console.log(count.current) +``` diff --git a/docs/framework/svelte/reference/functions/useSelector.md b/docs/framework/svelte/reference/functions/useSelector.md new file mode 100644 index 0000000000..5d3541edc7 --- /dev/null +++ b/docs/framework/svelte/reference/functions/useSelector.md @@ -0,0 +1,66 @@ +--- +id: useSelector +title: useSelector +--- + +```ts +function useSelector( + source, + selector?, + options?): object; +``` + +Defined in: node\_modules/.pnpm/@tanstack+svelte-store@0.12.1\_svelte@5.56.8\_@typescript-eslint+types@8.66.0\_/node\_modules/@tanstack/svelte-store/dist/useSelector.svelte.d.ts:22 + +Selects a slice of state from an atom or store and exposes it through a +rune-friendly holder object. + +Read the selected value from `.current`. + +## Type Parameters + +### TState + +`TState` + +### TSelected + +`TSelected` = `NoInfer`\<`TState`\> + +## Parameters + +### source + + \| [`Atom`](../interfaces/Atom.md)\<`TState`\> + \| [`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`TState`\> + \| [`Store`](../classes/Store.md)\<`TState`, `any`\> + \| [`ReadonlyStore`](../classes/ReadonlyStore.md)\<`TState`\> + +### selector? + +(`state`) => `TSelected` + +### options? + +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TSelected`\> + +## Returns + +`object` + +### current + +```ts +readonly current: TSelected; +``` + +## Examples + +```ts +const count = useSelector(counterStore, (state) => state.count) +console.log(count.current) +``` + +```ts +const doubled = useSelector(countAtom, (value) => value * 2) +``` diff --git a/docs/framework/svelte/reference/functions/useStore.md b/docs/framework/svelte/reference/functions/useStore.md new file mode 100644 index 0000000000..01a76ac4a9 --- /dev/null +++ b/docs/framework/svelte/reference/functions/useStore.md @@ -0,0 +1,65 @@ +--- +id: _useStore +title: _useStore +--- + +```ts +function _useStore( + store, + selector, + options?): [{ + current: TSelected; +}, [TActions] extends [never] ? (updater) => void : TActions]; +``` + +Defined in: node\_modules/.pnpm/@tanstack+svelte-store@0.12.1\_svelte@5.56.8\_@typescript-eslint+types@8.66.0\_/node\_modules/@tanstack/svelte-store/dist/\_useStore.d.ts:19 + +Experimental combined read+write hook for stores, mirroring useAtom's tuple +pattern. + +Returns `[selected, actions]` when the store has an actions factory, or +`[selected, setState]` for plain stores. + +## Type Parameters + +### TState + +`TState` + +### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) + +### TSelected + +`TSelected` = `NoInfer`\<`TState`\> + +## Parameters + +### store + +[`Store`](../classes/Store.md)\<`TState`, `TActions`\> + +### selector + +(`state`) => `TSelected` + +### options? + +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TSelected`\> + +## Returns + +\[\{ + `current`: `TSelected`; +\}, \[`TActions`\] *extends* \[`never`\] ? (`updater`) => `void` : `TActions`\] + +## Example + +```ts +// Store with actions +const [cats, { addCat }] = _useStore(petStore, (s) => s.cats) + +// Store without actions +const [count, setState] = _useStore(plainStore, (s) => s) +``` diff --git a/docs/framework/svelte/reference/index.md b/docs/framework/svelte/reference/index.md new file mode 100644 index 0000000000..8beec980e5 --- /dev/null +++ b/docs/framework/svelte/reference/index.md @@ -0,0 +1,103 @@ +--- +id: "@tanstack/svelte-form" +title: "@tanstack/svelte-form" +--- + +## Classes + +- [ReadonlyStore](classes/ReadonlyStore.md) +- [Store](classes/Store.md) + +## Interfaces + +- [AppFormHookResult](interfaces/AppFormHookResult.md) +- [Atom](interfaces/Atom.md) +- [AtomOptions](interfaces/AtomOptions.md) +- [BaseAtom](interfaces/BaseAtom.md) +- [CreateFormHookOptions](interfaces/CreateFormHookOptions.md) +- [FieldGroupApi](interfaces/FieldGroupApi.md) +- [FieldGroupDefinition](interfaces/FieldGroupDefinition.md) +- [FormHookHelpers](interfaces/FormHookHelpers.md) +- [InternalBaseAtom](interfaces/InternalBaseAtom.md) +- [InternalReadonlyAtom](interfaces/InternalReadonlyAtom.md) +- [InteropSubscribable](interfaces/InteropSubscribable.md) +- [Readable](interfaces/Readable.md) +- [ReadonlyAtom](interfaces/ReadonlyAtom.md) +- [Subscribable](interfaces/Subscribable.md) +- [Subscription](interfaces/Subscription.md) +- [SvelteFormComponentMap](interfaces/SvelteFormComponentMap.md) +- [SvelteFormFieldProps](interfaces/SvelteFormFieldProps.md) +- [SvelteFormGroupApi](interfaces/SvelteFormGroupApi.md) +- [SvelteFormGroupProps](interfaces/SvelteFormGroupProps.md) +- [SvelteFormSelectors](interfaces/SvelteFormSelectors.md) +- [SvelteTanStackFormComponents](interfaces/SvelteTanStackFormComponents.md) +- [UseSelectorOptions](interfaces/UseSelectorOptions.md) + +## Type Aliases + +- [AnyAtom](type-aliases/AnyAtom.md) +- [AnyFieldGroupApi](type-aliases/AnyFieldGroupApi.md) +- [AnySvelteFormApi](type-aliases/AnySvelteFormApi.md) +- [AnySvelteFormComponentMap](type-aliases/AnySvelteFormComponentMap.md) +- [AppFormComponent](type-aliases/AppFormComponent.md) +- [CreateForm](type-aliases/CreateForm.md) +- [DefaultSvelteFormComponentMap](type-aliases/DefaultSvelteFormComponentMap.md) +- [DefineFieldGroupFn](type-aliases/DefineFieldGroupFn.md) +- [Field](type-aliases/Field.md) +- [FieldGroupArrayFieldComponent](type-aliases/FieldGroupArrayFieldComponent.md) +- [FieldGroupFieldBindingsOf](type-aliases/FieldGroupFieldBindingsOf.md) +- [FieldGroupFieldComponent](type-aliases/FieldGroupFieldComponent.md) +- [FieldGroupFieldComponentsOf](type-aliases/FieldGroupFieldComponentsOf.md) +- [FieldGroupFieldsOf](type-aliases/FieldGroupFieldsOf.md) +- [FieldGroupForm](type-aliases/FieldGroupForm.md) +- [FieldGroupFormState](type-aliases/FieldGroupFormState.md) +- [FieldGroupSubscribeComponent](type-aliases/FieldGroupSubscribeComponent.md) +- [FieldGroupWithFieldsFn](type-aliases/FieldGroupWithFieldsFn.md) +- [Observer](type-aliases/Observer.md) +- [Selection](type-aliases/Selection.md) +- [StoreAction](type-aliases/StoreAction.md) +- [StoreActionMap](type-aliases/StoreActionMap.md) +- [StoreActionsFactory](type-aliases/StoreActionsFactory.md) +- [SvelteAppFormApi](type-aliases/SvelteAppFormApi.md) +- [SvelteFieldApi](type-aliases/SvelteFieldApi.md) +- [SvelteFieldGroup](type-aliases/SvelteFieldGroup.md) +- [SvelteFormApi](type-aliases/SvelteFormApi.md) +- [SvelteFormArrayFieldComponent](type-aliases/SvelteFormArrayFieldComponent.md) +- [SvelteFormFieldComponent](type-aliases/SvelteFormFieldComponent.md) +- [SvelteFormGroupArrayFieldComponent](type-aliases/SvelteFormGroupArrayFieldComponent.md) +- [SvelteFormGroupComponent](type-aliases/SvelteFormGroupComponent.md) +- [SvelteFormGroupFieldComponent](type-aliases/SvelteFormGroupFieldComponent.md) +- [SvelteFormGroupSubscribeComponent](type-aliases/SvelteFormGroupSubscribeComponent.md) +- [SvelteFormSubscribeComponent](type-aliases/SvelteFormSubscribeComponent.md) +- [SvelteFormSubscribeProps](type-aliases/SvelteFormSubscribeProps.md) +- [SvelteFormType](type-aliases/SvelteFormType.md) +- [UseAppFormHook](type-aliases/UseAppFormHook.md) +- [WithoutFunction](type-aliases/WithoutFunction.md) + +## Variables + +- [createForm](variables/createForm.md) +- [defineFieldGroup](variables/defineFieldGroup.md) +- [Field](variables/Field.md) +- [~~useStore~~](variables/useStore.md) + +## Functions + +- [\_useStore](functions/useStore.md) +- [batch](functions/batch.md) +- [createAsyncAtom](functions/createAsyncAtom.md) +- [createAtom](functions/createAtom.md) +- [createFormHook](functions/createFormHook.md) +- [createStore](functions/createStore.md) +- [flush](functions/flush.md) +- [getFormHookHelpers](functions/getFormHookHelpers.md) +- [shallow](functions/shallow.md) +- [toObserver](functions/toObserver.md) +- [useAtom](functions/useAtom.md) +- [useSelector](functions/useSelector.md) + +## References + +### FormGroup + +Renames and re-exports [Field](variables/Field.md) diff --git a/docs/framework/svelte/reference/interfaces/AppFormHookResult.md b/docs/framework/svelte/reference/interfaces/AppFormHookResult.md new file mode 100644 index 0000000000..7f0feaaa23 --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/AppFormHookResult.md @@ -0,0 +1,56 @@ +--- +id: AppFormHookResult +title: AppFormHookResult +--- + +Defined in: [packages/svelte-form/src/AppForm/createFormHookTypes.public.ts:115](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/createFormHookTypes.public.ts#L115) + +## Type Parameters + +### TComponents + +`TComponents` *extends* [`AnySvelteFormComponentMap`](../type-aliases/AnySvelteFormComponentMap.md) + +## Properties + +### appFormOptions + +```ts +appFormOptions: FormOptionsApi; +``` + +Defined in: [packages/svelte-form/src/AppForm/createFormHookTypes.public.ts:118](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/createFormHookTypes.public.ts#L118) + +*** + +### defineAppFieldGroup + +```ts +defineAppFieldGroup: DefineFieldGroupFn; +``` + +Defined in: [packages/svelte-form/src/AppForm/createFormHookTypes.public.ts:119](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/createFormHookTypes.public.ts#L119) + +*** + +### useAppForm + +```ts +useAppForm: UseAppFormHook; +``` + +Defined in: [packages/svelte-form/src/AppForm/createFormHookTypes.public.ts:120](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/createFormHookTypes.public.ts#L120) + +*** + +### useFormContext + +```ts +useFormContext: () => SvelteAppFormApi; +``` + +Defined in: [packages/svelte-form/src/AppForm/createFormHookTypes.public.ts:121](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/createFormHookTypes.public.ts#L121) + +#### Returns + +[`SvelteAppFormApi`](../type-aliases/SvelteAppFormApi.md)\<`any`, `any`, `TComponents`\> diff --git a/docs/framework/svelte/reference/interfaces/Atom.md b/docs/framework/svelte/reference/interfaces/Atom.md new file mode 100644 index 0000000000..e536822283 --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/Atom.md @@ -0,0 +1,60 @@ +--- +id: Atom +title: Atom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:29 + +## Extends + +- [`BaseAtom`](BaseAtom.md)\<`T`\> + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`get`](BaseAtom.md#get) + +*** + +### set + +```ts +set: (fn) => void & (value) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:31 + +Sets the value of the atom using a function. + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`subscribe`](BaseAtom.md#subscribe) diff --git a/docs/framework/svelte/reference/interfaces/AtomOptions.md b/docs/framework/svelte/reference/interfaces/AtomOptions.md new file mode 100644 index 0000000000..84f594c6e0 --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/AtomOptions.md @@ -0,0 +1,36 @@ +--- +id: AtomOptions +title: AtomOptions +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:33 + +## Type Parameters + +### T + +`T` + +## Properties + +### compare? + +```ts +optional compare?: (prev, next) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:34 + +#### Parameters + +##### prev + +`T` + +##### next + +`T` + +#### Returns + +`boolean` diff --git a/docs/framework/svelte/reference/interfaces/BaseAtom.md b/docs/framework/svelte/reference/interfaces/BaseAtom.md new file mode 100644 index 0000000000..fc0695a37a --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/BaseAtom.md @@ -0,0 +1,53 @@ +--- +id: BaseAtom +title: BaseAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:22 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\>.[`Readable`](Readable.md)\<`T`\> + +## Extended by + +- [`Atom`](Atom.md) +- [`ReadonlyAtom`](ReadonlyAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`Readable`](Readable.md).[`get`](Readable.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/svelte/reference/interfaces/CreateFormHookOptions.md b/docs/framework/svelte/reference/interfaces/CreateFormHookOptions.md new file mode 100644 index 0000000000..3479c94a1f --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/CreateFormHookOptions.md @@ -0,0 +1,150 @@ +--- +id: CreateFormHookOptions +title: CreateFormHookOptions +--- + +Defined in: [packages/svelte-form/src/AppForm/createFormHookTypes.public.ts:46](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/createFormHookTypes.public.ts#L46) + +Configures the components and reusable defaults returned by +`createFormHook`. + +Form core resolves each default object before the corresponding usage-site +options. Non-listener properties passed at the usage site take precedence, +including when explicitly set to `undefined`. Listener arrays follow the +configured `listenersMerge` strategy. + +## Example + +```ts +const { useAppForm } = createFormHook({ + formComponents: {}, + fieldComponents: { + TextField, + }, + defaultFormOptions: { + errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred, + }, + defaultFieldOptions: { + errorBoundary: true, + }, +}) +``` + +## Extends + +- [`SvelteFormComponentMap`](SvelteFormComponentMap.md)\<`TFormComponents`, `TFieldComponents`\> + +## Type Parameters + +### TFormComponents + +`TFormComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +Library-managed. Do not specify explicitly. + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +Library-managed. Do not specify explicitly. + +## Properties + +### defaultFieldOptions? + +```ts +optional defaultFieldOptions?: DefaultFieldOptions; +``` + +Defined in: [packages/svelte-form/src/AppForm/createFormHookTypes.public.ts:79](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/createFormHookTypes.public.ts#L79) + +Defaults for every field and array-field component owned by the form. + +Non-listener options passed to the component override these defaults, +including when explicitly set to `undefined`. Listener arrays follow +`listenersMerge`. This includes `group.Field` and `group.ArrayField`. + +#### Example + +```ts +defaultFieldOptions: { + errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred, +}, +``` + +*** + +### defaultFormGroupOptions? + +```ts +optional defaultFormGroupOptions?: DefaultFormGroupOptions; +``` + +Defined in: [packages/svelte-form/src/AppForm/createFormHookTypes.public.ts:95](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/createFormHookTypes.public.ts#L95) + +Defaults for every `form.FormGroup` component. + +Options passed to the component override these defaults, including when +an option is explicitly `undefined`. + +#### Example + +```ts +defaultFormGroupOptions: { + onSubmitInvalid: ({ groupApi }) => { + console.error('Invalid group', groupApi.name) + }, +}, +``` + +*** + +### defaultFormOptions? + +```ts +optional defaultFormOptions?: DefaultFormOptions; +``` + +Defined in: [packages/svelte-form/src/AppForm/createFormHookTypes.public.ts:64](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/createFormHookTypes.public.ts#L64) + +Defaults for every form created by `useAppForm`. + +Non-listener options returned by the `useAppForm` options accessor +override these defaults, including when explicitly set to `undefined`. +Listener arrays follow `listenersMerge`. + +#### Example + +```ts +defaultFormOptions: { + errorVisibility: ({ state }) => state.submissionAttempts > 0, +}, +``` + +*** + +### fieldComponents + +```ts +fieldComponents: TFieldComponents; +``` + +Defined in: [packages/svelte-form/src/AppForm/componentMap.public.ts:8](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/componentMap.public.ts#L8) + +#### Inherited from + +[`SvelteFormComponentMap`](SvelteFormComponentMap.md).[`fieldComponents`](SvelteFormComponentMap.md#fieldcomponents) + +*** + +### formComponents + +```ts +formComponents: TFormComponents; +``` + +Defined in: [packages/svelte-form/src/AppForm/componentMap.public.ts:7](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/componentMap.public.ts#L7) + +#### Inherited from + +[`SvelteFormComponentMap`](SvelteFormComponentMap.md).[`formComponents`](SvelteFormComponentMap.md#formcomponents) diff --git a/docs/framework/svelte/reference/interfaces/FieldGroupApi.md b/docs/framework/svelte/reference/interfaces/FieldGroupApi.md new file mode 100644 index 0000000000..9db5480ad3 --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/FieldGroupApi.md @@ -0,0 +1,60 @@ +--- +id: FieldGroupApi +title: FieldGroupApi +--- + +Defined in: [packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts:82](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts#L82) + +## Extends + +- `FormApiFieldMethods`\<`TFieldData`\>.`FormApiArrayMethods`\<`TFieldData`\> + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> = `Record`\<`never`, `never`\> + +## Properties + +### ArrayField + +```ts +ArrayField: FieldGroupArrayFieldComponent; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts:92](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts#L92) + +*** + +### atom + +```ts +atom: ReadonlyAtom; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts:90](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts#L90) + +*** + +### Field + +```ts +Field: FieldGroupFieldComponent; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts:91](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts#L91) + +*** + +### Subscribe + +```ts +Subscribe: FieldGroupSubscribeComponent; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts:93](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts#L93) diff --git a/docs/framework/svelte/reference/interfaces/FieldGroupDefinition.md b/docs/framework/svelte/reference/interfaces/FieldGroupDefinition.md new file mode 100644 index 0000000000..e9ee15cb1b --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/FieldGroupDefinition.md @@ -0,0 +1,40 @@ +--- +id: FieldGroupDefinition +title: FieldGroupDefinition +--- + +Defined in: [packages/svelte-form/src/FieldGroup/withFields.public.ts:82](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/withFields.public.ts#L82) + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +### TComponents + +`TComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +## Properties + +### bindComponent + +```ts +bindComponent: FieldGroupWithFieldsFn>; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/withFields.public.ts:89](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/withFields.public.ts#L89) + +Binds a component's virtual field API to concrete paths in a form. + +*** + +### fields + +```ts +fields: SvelteFieldGroup; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/withFields.public.ts:87](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/withFields.public.ts#L87) + +The virtual field-group API injected into the bound component. diff --git a/docs/framework/svelte/reference/interfaces/FormHookHelpers.md b/docs/framework/svelte/reference/interfaces/FormHookHelpers.md new file mode 100644 index 0000000000..b56f38a4da --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/FormHookHelpers.md @@ -0,0 +1,26 @@ +--- +id: FormHookHelpers +title: FormHookHelpers +--- + +Defined in: [packages/svelte-form/src/AppForm/getFormHookHelpers.public.ts:66](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/getFormHookHelpers.public.ts#L66) + +## Properties + +### fieldBrand + +```ts +fieldBrand: FieldBrandHelper; +``` + +Defined in: [packages/svelte-form/src/AppForm/getFormHookHelpers.public.ts:67](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/getFormHookHelpers.public.ts#L67) + +*** + +### fieldComponent + +```ts +fieldComponent: FieldComponentHelper; +``` + +Defined in: [packages/svelte-form/src/AppForm/getFormHookHelpers.public.ts:68](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/getFormHookHelpers.public.ts#L68) diff --git a/docs/framework/svelte/reference/interfaces/InternalBaseAtom.md b/docs/framework/svelte/reference/interfaces/InternalBaseAtom.md new file mode 100644 index 0000000000..f73167d4a2 --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/InternalBaseAtom.md @@ -0,0 +1,86 @@ +--- +id: InternalBaseAtom +title: InternalBaseAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:23 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\>.[`Readable`](Readable.md)\<`T`\> + +## Extended by + +- [`InternalReadonlyAtom`](InternalReadonlyAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### \_snapshot + +```ts +_snapshot: T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:25 + +**`Internal`** + +*** + +### \_update + +```ts +_update: (getValue?) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:27 + +**`Internal`** + +#### Parameters + +##### getValue? + +`T` \| ((`snapshot`) => `T`) + +#### Returns + +`boolean` + +*** + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`Readable`](Readable.md).[`get`](Readable.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/svelte/reference/interfaces/InternalReadonlyAtom.md b/docs/framework/svelte/reference/interfaces/InternalReadonlyAtom.md new file mode 100644 index 0000000000..ac5a197160 --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/InternalReadonlyAtom.md @@ -0,0 +1,170 @@ +--- +id: InternalReadonlyAtom +title: InternalReadonlyAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:37 + +## Extends + +- [`InternalBaseAtom`](InternalBaseAtom.md)\<`T`\>.`ReactiveNode` + +## Type Parameters + +### T + +`T` + +## Properties + +### \_snapshot + +```ts +_snapshot: T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:25 + +**`Internal`** + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`_snapshot`](InternalBaseAtom.md#_snapshot) + +*** + +### \_update + +```ts +_update: (getValue?) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:27 + +**`Internal`** + +#### Parameters + +##### getValue? + +`T` \| ((`snapshot`) => `T`) + +#### Returns + +`boolean` + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`_update`](InternalBaseAtom.md#_update) + +*** + +### deps? + +```ts +optional deps?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:3 + +#### Inherited from + +```ts +ReactiveNode.deps +``` + +*** + +### depsTail? + +```ts +optional depsTail?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:4 + +#### Inherited from + +```ts +ReactiveNode.depsTail +``` + +*** + +### flags + +```ts +flags: number; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:7 + +#### Inherited from + +```ts +ReactiveNode.flags +``` + +*** + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`get`](InternalBaseAtom.md#get) + +*** + +### subs? + +```ts +optional subs?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:5 + +#### Inherited from + +```ts +ReactiveNode.subs +``` + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`subscribe`](InternalBaseAtom.md#subscribe) + +*** + +### subsTail? + +```ts +optional subsTail?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:6 + +#### Inherited from + +```ts +ReactiveNode.subsTail +``` diff --git a/docs/framework/svelte/reference/interfaces/InteropSubscribable.md b/docs/framework/svelte/reference/interfaces/InteropSubscribable.md new file mode 100644 index 0000000000..7a0c023915 --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/InteropSubscribable.md @@ -0,0 +1,36 @@ +--- +id: InteropSubscribable +title: InteropSubscribable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:5 + +## Extended by + +- [`Subscribable`](Subscribable.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### subscribe + +```ts +subscribe: (observer) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:6 + +#### Parameters + +##### observer + +[`Observer`](../type-aliases/Observer.md)\<`T`\> + +#### Returns + +[`Subscription`](Subscription.md) diff --git a/docs/framework/svelte/reference/interfaces/Readable.md b/docs/framework/svelte/reference/interfaces/Readable.md new file mode 100644 index 0000000000..ff2095ebfe --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/Readable.md @@ -0,0 +1,49 @@ +--- +id: Readable +title: Readable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:19 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\> + +## Extended by + +- [`BaseAtom`](BaseAtom.md) +- [`InternalBaseAtom`](InternalBaseAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/svelte/reference/interfaces/ReadonlyAtom.md b/docs/framework/svelte/reference/interfaces/ReadonlyAtom.md new file mode 100644 index 0000000000..bbc1e1d9c3 --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/ReadonlyAtom.md @@ -0,0 +1,58 @@ +--- +id: ReadonlyAtom +title: ReadonlyAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:49 + +An atom that is read-only and cannot be set. + +## Example + +```ts +const atom = createAtom(() => 42); +// @ts-expect-error - Cannot set a readonly atom +atom.set(43); +``` + +## Extends + +- [`BaseAtom`](BaseAtom.md)\<`T`\> + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`get`](BaseAtom.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`subscribe`](BaseAtom.md#subscribe) diff --git a/docs/framework/svelte/reference/interfaces/Subscribable.md b/docs/framework/svelte/reference/interfaces/Subscribable.md new file mode 100644 index 0000000000..a11bf60b2a --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/Subscribable.md @@ -0,0 +1,36 @@ +--- +id: Subscribable +title: Subscribable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:16 + +## Extends + +- [`InteropSubscribable`](InteropSubscribable.md)\<`T`\> + +## Extended by + +- [`BaseAtom`](BaseAtom.md) +- [`InternalBaseAtom`](InternalBaseAtom.md) +- [`Readable`](Readable.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Overrides + +[`InteropSubscribable`](InteropSubscribable.md).[`subscribe`](InteropSubscribable.md#subscribe) diff --git a/docs/framework/svelte/reference/interfaces/Subscription.md b/docs/framework/svelte/reference/interfaces/Subscription.md new file mode 100644 index 0000000000..fab2f285ee --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/Subscription.md @@ -0,0 +1,20 @@ +--- +id: Subscription +title: Subscription +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:13 + +## Properties + +### unsubscribe + +```ts +unsubscribe: () => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:14 + +#### Returns + +`void` diff --git a/docs/framework/svelte/reference/interfaces/SvelteFormComponentMap.md b/docs/framework/svelte/reference/interfaces/SvelteFormComponentMap.md new file mode 100644 index 0000000000..fd9b0373f0 --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/SvelteFormComponentMap.md @@ -0,0 +1,40 @@ +--- +id: SvelteFormComponentMap +title: SvelteFormComponentMap +--- + +Defined in: [packages/svelte-form/src/AppForm/componentMap.public.ts:3](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/componentMap.public.ts#L3) + +## Extended by + +- [`CreateFormHookOptions`](CreateFormHookOptions.md) + +## Type Parameters + +### TFormComponents + +`TFormComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +## Properties + +### fieldComponents + +```ts +fieldComponents: TFieldComponents; +``` + +Defined in: [packages/svelte-form/src/AppForm/componentMap.public.ts:8](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/componentMap.public.ts#L8) + +*** + +### formComponents + +```ts +formComponents: TFormComponents; +``` + +Defined in: [packages/svelte-form/src/AppForm/componentMap.public.ts:7](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/componentMap.public.ts#L7) diff --git a/docs/framework/svelte/reference/interfaces/SvelteFormFieldProps.md b/docs/framework/svelte/reference/interfaces/SvelteFormFieldProps.md new file mode 100644 index 0000000000..46f92d6ee9 --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/SvelteFormFieldProps.md @@ -0,0 +1,57 @@ +--- +id: SvelteFormFieldProps +title: SvelteFormFieldProps +--- + +Defined in: [packages/svelte-form/src/Components.public.ts:100](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L100) + +## Extends + +- `FieldApiOptions`\<`TFieldData`, `TFieldName`, `TFieldValue`, `TFieldValidators`, `TGroupFieldError`, `TFormData`, `TFormErrorTypes`\> + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldName + +`TFieldName` + +### TFieldValue + +`TFieldValue` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFieldData`, `TFieldName`, `TFieldValue`\> + +### TGroupFieldError + +`TGroupFieldError` + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +## Properties + +### children + +```ts +children: Snippet<[SvelteFieldApi, FieldValidators> + | unknown extends TGroupFieldError ? never : TGroupFieldError +| ExtractFormFieldError>, TFormData, TFormErrorTypes, TFieldComponents>]>; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:118](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L118) diff --git a/docs/framework/svelte/reference/interfaces/SvelteFormGroupApi.md b/docs/framework/svelte/reference/interfaces/SvelteFormGroupApi.md new file mode 100644 index 0000000000..f9454d028e --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/SvelteFormGroupApi.md @@ -0,0 +1,66 @@ +--- +id: SvelteFormGroupApi +title: SvelteFormGroupApi +--- + +Defined in: [packages/svelte-form/src/Components.public.ts:266](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L266) + +## Extends + +- `FormGroupApi`\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupErrorTypes`, `TFormErrorTypes`\> + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +## Properties + +### ArrayField + +```ts +ArrayField: SvelteFormGroupArrayFieldComponent; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:287](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L287) + +*** + +### Field + +```ts +Field: SvelteFormGroupFieldComponent; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:280](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L280) + +*** + +### Subscribe + +```ts +Subscribe: SvelteFormGroupSubscribeComponent; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:294](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L294) diff --git a/docs/framework/svelte/reference/interfaces/SvelteFormGroupProps.md b/docs/framework/svelte/reference/interfaces/SvelteFormGroupProps.md new file mode 100644 index 0000000000..fd664fd598 --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/SvelteFormGroupProps.md @@ -0,0 +1,46 @@ +--- +id: SvelteFormGroupProps +title: SvelteFormGroupProps +--- + +Defined in: [packages/svelte-form/src/Components.public.ts:297](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L297) + +## Extends + +- `Omit`\<`FormGroupOptions`\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupValidators`, `TFormErrorTypes`\>, `"form"`\> + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupValidators + +`TGroupValidators` *extends* `FormGroupValidators`\<`TGroupValue`\> + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +## Properties + +### children + +```ts +children: Snippet<[SvelteFormGroupApi>, TFormErrorTypes, TFieldComponents>]>; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:314](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L314) diff --git a/docs/framework/svelte/reference/interfaces/SvelteFormSelectors.md b/docs/framework/svelte/reference/interfaces/SvelteFormSelectors.md new file mode 100644 index 0000000000..d1e38c0838 --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/SvelteFormSelectors.md @@ -0,0 +1,48 @@ +--- +id: SvelteFormSelectors +title: SvelteFormSelectors +--- + +Defined in: [packages/svelte-form/src/formApiTypes.public.ts:14](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/formApiTypes.public.ts#L14) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +## Properties + +### useSelector + +```ts +useSelector: (selector?) => object; +``` + +Defined in: [packages/svelte-form/src/formApiTypes.public.ts:18](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/formApiTypes.public.ts#L18) + +#### Type Parameters + +##### TSelected + +`TSelected` = `FormState`\<`TFormData`, `TFormErrorTypes`\> + +#### Parameters + +##### selector? + +(`state`) => `TSelected` + +#### Returns + +`object` + +##### current + +```ts +readonly current: TSelected; +``` diff --git a/docs/framework/svelte/reference/interfaces/SvelteTanStackFormComponents.md b/docs/framework/svelte/reference/interfaces/SvelteTanStackFormComponents.md new file mode 100644 index 0000000000..944b1ab84e --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/SvelteTanStackFormComponents.md @@ -0,0 +1,60 @@ +--- +id: SvelteTanStackFormComponents +title: SvelteTanStackFormComponents +--- + +Defined in: [packages/svelte-form/src/Components.public.ts:351](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L351) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> = `Record`\<`never`, `never`\> + +## Properties + +### ArrayField + +```ts +ArrayField: SvelteFormArrayFieldComponent; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:360](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L360) + +*** + +### Field + +```ts +Field: SvelteFormFieldComponent; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:359](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L359) + +*** + +### FormGroup + +```ts +FormGroup: SvelteFormGroupComponent; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:366](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L366) + +*** + +### Subscribe + +```ts +Subscribe: SvelteFormSubscribeComponent; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:365](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L365) diff --git a/docs/framework/svelte/reference/interfaces/UseSelectorOptions.md b/docs/framework/svelte/reference/interfaces/UseSelectorOptions.md new file mode 100644 index 0000000000..f86b5ed699 --- /dev/null +++ b/docs/framework/svelte/reference/interfaces/UseSelectorOptions.md @@ -0,0 +1,36 @@ +--- +id: UseSelectorOptions +title: UseSelectorOptions +--- + +Defined in: node\_modules/.pnpm/@tanstack+svelte-store@0.12.1\_svelte@5.56.8\_@typescript-eslint+types@8.66.0\_/node\_modules/@tanstack/svelte-store/dist/useSelector.svelte.d.ts:2 + +## Type Parameters + +### TSelected + +`TSelected` + +## Properties + +### compare? + +```ts +optional compare?: (a, b) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+svelte-store@0.12.1\_svelte@5.56.8\_@typescript-eslint+types@8.66.0\_/node\_modules/@tanstack/svelte-store/dist/useSelector.svelte.d.ts:3 + +#### Parameters + +##### a + +`TSelected` + +##### b + +`TSelected` + +#### Returns + +`boolean` diff --git a/docs/framework/svelte/reference/type-aliases/AnyAtom.md b/docs/framework/svelte/reference/type-aliases/AnyAtom.md new file mode 100644 index 0000000000..6491b16950 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/AnyAtom.md @@ -0,0 +1,10 @@ +--- +id: AnyAtom +title: AnyAtom +--- + +```ts +type AnyAtom = BaseAtom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:36 diff --git a/docs/framework/svelte/reference/type-aliases/AnyFieldGroupApi.md b/docs/framework/svelte/reference/type-aliases/AnyFieldGroupApi.md new file mode 100644 index 0000000000..47acd8b1a6 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/AnyFieldGroupApi.md @@ -0,0 +1,10 @@ +--- +id: AnyFieldGroupApi +title: AnyFieldGroupApi +--- + +```ts +type AnyFieldGroupApi = FieldGroupApi>>; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts:96](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts#L96) diff --git a/docs/framework/svelte/reference/type-aliases/AnySvelteFormApi.md b/docs/framework/svelte/reference/type-aliases/AnySvelteFormApi.md new file mode 100644 index 0000000000..357925b9a3 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/AnySvelteFormApi.md @@ -0,0 +1,34 @@ +--- +id: AnySvelteFormApi +title: AnySvelteFormApi +--- + +```ts +type AnySvelteFormApi = AnyFormApi & SvelteTanStackFormComponents & SvelteFormSelectors; +``` + +Defined in: [packages/svelte-form/src/formApiTypes.public.ts:68](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/formApiTypes.public.ts#L68) + +A Svelte form API whose form data and error types are erased. + +Use it for reusable Svelte components that only need core form operations, +selectors, and the `Field`, `ArrayField`, `Subscribe`, or `FormGroup` +components common to every Svelte form. Field paths and values are not +checked against a particular form shape; use `SvelteFormType` when a +component depends on one known form. + +## Example + +```svelte + + + state.isSubmitting}> + {#snippet children(isSubmitting)} + + {/snippet} + +``` diff --git a/docs/framework/svelte/reference/type-aliases/AnySvelteFormComponentMap.md b/docs/framework/svelte/reference/type-aliases/AnySvelteFormComponentMap.md new file mode 100644 index 0000000000..f4f0c3a8ba --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/AnySvelteFormComponentMap.md @@ -0,0 +1,10 @@ +--- +id: AnySvelteFormComponentMap +title: AnySvelteFormComponentMap +--- + +```ts +type AnySvelteFormComponentMap = SvelteFormComponentMap>, Record>>; +``` + +Defined in: [packages/svelte-form/src/AppForm/componentMap.public.ts:11](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/componentMap.public.ts#L11) diff --git a/docs/framework/svelte/reference/type-aliases/AppFormComponent.md b/docs/framework/svelte/reference/type-aliases/AppFormComponent.md new file mode 100644 index 0000000000..c1f0f698ef --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/AppFormComponent.md @@ -0,0 +1,12 @@ +--- +id: AppFormComponent +title: AppFormComponent +--- + +```ts +type AppFormComponent = Component<{ + children: Snippet; +}>; +``` + +Defined in: [packages/svelte-form/src/AppForm/SvelteAppFormApi.public.ts:6](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/SvelteAppFormApi.public.ts#L6) diff --git a/docs/framework/svelte/reference/type-aliases/CreateForm.md b/docs/framework/svelte/reference/type-aliases/CreateForm.md new file mode 100644 index 0000000000..64e871e417 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/CreateForm.md @@ -0,0 +1,34 @@ +--- +id: CreateForm +title: CreateForm +--- + +```ts +type CreateForm = (options) => SvelteFormApi, DefaultSvelteFormComponentMap>; +``` + +Defined in: [packages/svelte-form/src/createForm.public.ts:10](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/createForm.public.ts#L10) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> + +### TSubmitReturn + +`TSubmitReturn` + +## Parameters + +### options + +() => `FormOptions`\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\> + +## Returns + +[`SvelteFormApi`](SvelteFormApi.md)\<`TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>, [`DefaultSvelteFormComponentMap`](DefaultSvelteFormComponentMap.md)\> diff --git a/docs/framework/svelte/reference/type-aliases/DefaultSvelteFormComponentMap.md b/docs/framework/svelte/reference/type-aliases/DefaultSvelteFormComponentMap.md new file mode 100644 index 0000000000..c502cffb13 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/DefaultSvelteFormComponentMap.md @@ -0,0 +1,10 @@ +--- +id: DefaultSvelteFormComponentMap +title: DefaultSvelteFormComponentMap +--- + +```ts +type DefaultSvelteFormComponentMap = SvelteFormComponentMap, Record>; +``` + +Defined in: [packages/svelte-form/src/AppForm/componentMap.public.ts:16](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/componentMap.public.ts#L16) diff --git a/docs/framework/svelte/reference/type-aliases/DefineFieldGroupFn.md b/docs/framework/svelte/reference/type-aliases/DefineFieldGroupFn.md new file mode 100644 index 0000000000..42b3a6060a --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/DefineFieldGroupFn.md @@ -0,0 +1,34 @@ +--- +id: DefineFieldGroupFn +title: DefineFieldGroupFn +--- + +```ts +type DefineFieldGroupFn = (defineFn) => FieldGroupDefinition; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/withFields.public.ts:93](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/withFields.public.ts#L93) + +Signature shared by `defineFieldGroup` and app-form field-group definers. + +## Type Parameters + +### TComponents + +`TComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +## Parameters + +### defineFn + +(`helper`) => `TFields` + +## Returns + +[`FieldGroupDefinition`](../interfaces/FieldGroupDefinition.md)\<`TFields`, `TComponents`\> diff --git a/docs/framework/svelte/reference/type-aliases/Field.md b/docs/framework/svelte/reference/type-aliases/Field.md new file mode 100644 index 0000000000..977c285fd5 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/Field.md @@ -0,0 +1,10 @@ +--- +id: Field +title: Field +--- + +```ts +type Field = SvelteComponent; +``` + +Defined in: node\_modules/.pnpm/svelte@5.56.8\_@typescript-eslint+types@8.66.0/node\_modules/svelte/types/index.d.ts:3212 diff --git a/docs/framework/svelte/reference/type-aliases/FieldGroupArrayFieldComponent.md b/docs/framework/svelte/reference/type-aliases/FieldGroupArrayFieldComponent.md new file mode 100644 index 0000000000..f9a1942e4c --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/FieldGroupArrayFieldComponent.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupArrayFieldComponent +title: FieldGroupArrayFieldComponent +--- + +```ts +type FieldGroupArrayFieldComponent = (options) => SvelteComponent & Component & WithoutFunction; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts:48](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts#L48) + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> diff --git a/docs/framework/svelte/reference/type-aliases/FieldGroupFieldBindingsOf.md b/docs/framework/svelte/reference/type-aliases/FieldGroupFieldBindingsOf.md new file mode 100644 index 0000000000..8ee0d19469 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/FieldGroupFieldBindingsOf.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupFieldBindingsOf +title: FieldGroupFieldBindingsOf +--- + +```ts +type FieldGroupFieldBindingsOf = FieldGroupFieldsOf extends FieldGroupFields ? FieldGroupFieldBindings, TData> : never; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/withFields.public.ts:55](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/withFields.public.ts#L55) + +## Type Parameters + +### TGroup + +`TGroup` + +### TData + +`TData` diff --git a/docs/framework/svelte/reference/type-aliases/FieldGroupFieldComponent.md b/docs/framework/svelte/reference/type-aliases/FieldGroupFieldComponent.md new file mode 100644 index 0000000000..a2a9cfe511 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/FieldGroupFieldComponent.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupFieldComponent +title: FieldGroupFieldComponent +--- + +```ts +type FieldGroupFieldComponent = (options) => SvelteComponent & Component & WithoutFunction; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts:24](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts#L24) + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> diff --git a/docs/framework/svelte/reference/type-aliases/FieldGroupFieldComponentsOf.md b/docs/framework/svelte/reference/type-aliases/FieldGroupFieldComponentsOf.md new file mode 100644 index 0000000000..a4aef9d6d2 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/FieldGroupFieldComponentsOf.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupFieldComponentsOf +title: FieldGroupFieldComponentsOf +--- + +```ts +type FieldGroupFieldComponentsOf = TGroup extends object ? TComponents : never; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/withFields.public.ts:39](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/withFields.public.ts#L39) + +## Type Parameters + +### TGroup + +`TGroup` diff --git a/docs/framework/svelte/reference/type-aliases/FieldGroupFieldsOf.md b/docs/framework/svelte/reference/type-aliases/FieldGroupFieldsOf.md new file mode 100644 index 0000000000..313d279978 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/FieldGroupFieldsOf.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupFieldsOf +title: FieldGroupFieldsOf +--- + +```ts +type FieldGroupFieldsOf = TGroup extends object ? TFields : never; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/withFields.public.ts:24](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/withFields.public.ts#L24) + +## Type Parameters + +### TGroup + +`TGroup` diff --git a/docs/framework/svelte/reference/type-aliases/FieldGroupForm.md b/docs/framework/svelte/reference/type-aliases/FieldGroupForm.md new file mode 100644 index 0000000000..f7987f1c8c --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/FieldGroupForm.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupForm +title: FieldGroupForm +--- + +```ts +type FieldGroupForm = FormApi & SvelteTanStackFormComponents; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/withFields.public.ts:47](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/withFields.public.ts#L47) + +## Type Parameters + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> = `Record`\<`never`, `never`\> + +### TFormData + +`TFormData` = `any` diff --git a/docs/framework/svelte/reference/type-aliases/FieldGroupFormState.md b/docs/framework/svelte/reference/type-aliases/FieldGroupFormState.md new file mode 100644 index 0000000000..ee3136390a --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/FieldGroupFormState.md @@ -0,0 +1,10 @@ +--- +id: FieldGroupFormState +title: FieldGroupFormState +--- + +```ts +type FieldGroupFormState = FormState; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts:100](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts#L100) diff --git a/docs/framework/svelte/reference/type-aliases/FieldGroupSubscribeComponent.md b/docs/framework/svelte/reference/type-aliases/FieldGroupSubscribeComponent.md new file mode 100644 index 0000000000..cff42c83d6 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/FieldGroupSubscribeComponent.md @@ -0,0 +1,10 @@ +--- +id: FieldGroupSubscribeComponent +title: FieldGroupSubscribeComponent +--- + +```ts +type FieldGroupSubscribeComponent = (options) => SvelteComponent & Component & WithoutFunction; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts:74](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/FieldGroupApi.public.ts#L74) diff --git a/docs/framework/svelte/reference/type-aliases/FieldGroupWithFieldsFn.md b/docs/framework/svelte/reference/type-aliases/FieldGroupWithFieldsFn.md new file mode 100644 index 0000000000..7a9d73eb26 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/FieldGroupWithFieldsFn.md @@ -0,0 +1,40 @@ +--- +id: FieldGroupWithFieldsFn +title: FieldGroupWithFieldsFn +--- + +```ts +type FieldGroupWithFieldsFn = (Component, fieldsPropName) => (options) => SvelteComponent & Component & WithoutFunction; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/withFields.public.ts:60](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/withFields.public.ts#L60) + +## Type Parameters + +### TGroup + +`TGroup` *extends* `object` + +## Type Parameters + +### TProps + +`TProps` *extends* `object` + +### TPropName + +`TPropName` *extends* `FieldGroupFieldsPropName`\<`TProps`, `TGroup`\> + +## Parameters + +### Component + +`Component`\<`TProps`\> + +### fieldsPropName + +`TPropName` + +## Returns + +\<`TFormData`\>(`options`) => `SvelteComponent` & `Component`\<`any`\> & [`WithoutFunction`](WithoutFunction.md)\<`Component`\> diff --git a/docs/framework/svelte/reference/type-aliases/Observer.md b/docs/framework/svelte/reference/type-aliases/Observer.md new file mode 100644 index 0000000000..c32765443c --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/Observer.md @@ -0,0 +1,70 @@ +--- +id: Observer +title: Observer +--- + +```ts +type Observer = object; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:8 + +## Type Parameters + +### T + +`T` + +## Properties + +### complete? + +```ts +optional complete?: () => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:11 + +#### Returns + +`void` + +*** + +### error? + +```ts +optional error?: (err) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:10 + +#### Parameters + +##### err + +`unknown` + +#### Returns + +`void` + +*** + +### next? + +```ts +optional next?: (value) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:9 + +#### Parameters + +##### value + +`T` + +#### Returns + +`void` diff --git a/docs/framework/svelte/reference/type-aliases/Selection.md b/docs/framework/svelte/reference/type-aliases/Selection.md new file mode 100644 index 0000000000..0ec13fa14b --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/Selection.md @@ -0,0 +1,16 @@ +--- +id: Selection +title: Selection +--- + +```ts +type Selection = Readable; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:4 + +## Type Parameters + +### TSelected + +`TSelected` diff --git a/docs/framework/svelte/reference/type-aliases/StoreAction.md b/docs/framework/svelte/reference/type-aliases/StoreAction.md new file mode 100644 index 0000000000..3c38ef14ec --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/StoreAction.md @@ -0,0 +1,20 @@ +--- +id: StoreAction +title: StoreAction +--- + +```ts +type StoreAction = (...args) => any; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:4 + +## Parameters + +### args + +...`any`[] + +## Returns + +`any` diff --git a/docs/framework/svelte/reference/type-aliases/StoreActionMap.md b/docs/framework/svelte/reference/type-aliases/StoreActionMap.md new file mode 100644 index 0000000000..c23e39e1bd --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/StoreActionMap.md @@ -0,0 +1,10 @@ +--- +id: StoreActionMap +title: StoreActionMap +--- + +```ts +type StoreActionMap = Record; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:5 diff --git a/docs/framework/svelte/reference/type-aliases/StoreActionsFactory.md b/docs/framework/svelte/reference/type-aliases/StoreActionsFactory.md new file mode 100644 index 0000000000..b87f92ecf9 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/StoreActionsFactory.md @@ -0,0 +1,36 @@ +--- +id: StoreActionsFactory +title: StoreActionsFactory +--- + +```ts +type StoreActionsFactory = (store) => TActions; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:6 + +## Type Parameters + +### T + +`T` + +### TActions + +`TActions` *extends* [`StoreActionMap`](StoreActionMap.md) + +## Parameters + +### store + +#### get + +[`Store`](../classes/Store.md)\<`T`\>\[`"get"`\] + +#### setState + +[`Store`](../classes/Store.md)\<`T`\>\[`"setState"`\] + +## Returns + +`TActions` diff --git a/docs/framework/svelte/reference/type-aliases/SvelteAppFormApi.md b/docs/framework/svelte/reference/type-aliases/SvelteAppFormApi.md new file mode 100644 index 0000000000..70d637c6fc --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/SvelteAppFormApi.md @@ -0,0 +1,32 @@ +--- +id: SvelteAppFormApi +title: SvelteAppFormApi +--- + +```ts +type SvelteAppFormApi = SvelteFormApi & object; +``` + +Defined in: [packages/svelte-form/src/AppForm/SvelteAppFormApi.public.ts:8](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/SvelteAppFormApi.public.ts#L8) + +## Type Declaration + +### AppForm + +```ts +AppForm: AppFormComponent; +``` + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TComponents + +`TComponents` *extends* [`AnySvelteFormComponentMap`](AnySvelteFormComponentMap.md) diff --git a/docs/framework/svelte/reference/type-aliases/SvelteFieldApi.md b/docs/framework/svelte/reference/type-aliases/SvelteFieldApi.md new file mode 100644 index 0000000000..73b7411e84 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/SvelteFieldApi.md @@ -0,0 +1,36 @@ +--- +id: SvelteFieldApi +title: SvelteFieldApi +--- + +```ts +type SvelteFieldApi = FieldApi & FieldComponentsMatchingType; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:67](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L67) + +## Type Parameters + +### TFieldName + +`TFieldName` + +### TFieldValue + +`TFieldValue` + +### TFieldError + +`TFieldError` + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> diff --git a/docs/framework/svelte/reference/type-aliases/SvelteFieldGroup.md b/docs/framework/svelte/reference/type-aliases/SvelteFieldGroup.md new file mode 100644 index 0000000000..e182ad8808 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/SvelteFieldGroup.md @@ -0,0 +1,34 @@ +--- +id: SvelteFieldGroup +title: SvelteFieldGroup +--- + +```ts +type SvelteFieldGroup = FieldGroupApi, TFieldComponents> & object; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/withFields.public.ts:29](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/withFields.public.ts#L29) + +## Type Declaration + +### \[fieldGroupFieldComponentsSymbol\] + +```ts +readonly [fieldGroupFieldComponentsSymbol]: TFieldComponents; +``` + +### \[fieldGroupFieldsSymbol\] + +```ts +readonly [fieldGroupFieldsSymbol]: TFields; +``` + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> = `Record`\<`never`, `never`\> diff --git a/docs/framework/svelte/reference/type-aliases/SvelteFormApi.md b/docs/framework/svelte/reference/type-aliases/SvelteFormApi.md new file mode 100644 index 0000000000..52b1832c0c --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/SvelteFormApi.md @@ -0,0 +1,24 @@ +--- +id: SvelteFormApi +title: SvelteFormApi +--- + +```ts +type SvelteFormApi = unknown extends TComponents["formComponents"] ? ExtendedFormApi : ExtendedFormApi & TComponents["formComponents"]; +``` + +Defined in: [packages/svelte-form/src/formApiTypes.public.ts:31](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/formApiTypes.public.ts#L31) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TComponents + +`TComponents` *extends* [`AnySvelteFormComponentMap`](AnySvelteFormComponentMap.md) = [`DefaultSvelteFormComponentMap`](DefaultSvelteFormComponentMap.md) diff --git a/docs/framework/svelte/reference/type-aliases/SvelteFormArrayFieldComponent.md b/docs/framework/svelte/reference/type-aliases/SvelteFormArrayFieldComponent.md new file mode 100644 index 0000000000..3959a36928 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/SvelteFormArrayFieldComponent.md @@ -0,0 +1,24 @@ +--- +id: SvelteFormArrayFieldComponent +title: SvelteFormArrayFieldComponent +--- + +```ts +type SvelteFormArrayFieldComponent = (options) => SvelteComponent & Component & WithoutFunction; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:164](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L164) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> diff --git a/docs/framework/svelte/reference/type-aliases/SvelteFormFieldComponent.md b/docs/framework/svelte/reference/type-aliases/SvelteFormFieldComponent.md new file mode 100644 index 0000000000..b65e4dbf68 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/SvelteFormFieldComponent.md @@ -0,0 +1,24 @@ +--- +id: SvelteFormFieldComponent +title: SvelteFormFieldComponent +--- + +```ts +type SvelteFormFieldComponent = (options) => SvelteComponent & Component & WithoutFunction; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:136](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L136) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> diff --git a/docs/framework/svelte/reference/type-aliases/SvelteFormGroupArrayFieldComponent.md b/docs/framework/svelte/reference/type-aliases/SvelteFormGroupArrayFieldComponent.md new file mode 100644 index 0000000000..a6d2b74476 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/SvelteFormGroupArrayFieldComponent.md @@ -0,0 +1,32 @@ +--- +id: SvelteFormGroupArrayFieldComponent +title: SvelteFormGroupArrayFieldComponent +--- + +```ts +type SvelteFormGroupArrayFieldComponent = (options) => SvelteComponent & Component & WithoutFunction; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:236](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L236) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> diff --git a/docs/framework/svelte/reference/type-aliases/SvelteFormGroupComponent.md b/docs/framework/svelte/reference/type-aliases/SvelteFormGroupComponent.md new file mode 100644 index 0000000000..9345e8d64b --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/SvelteFormGroupComponent.md @@ -0,0 +1,24 @@ +--- +id: SvelteFormGroupComponent +title: SvelteFormGroupComponent +--- + +```ts +type SvelteFormGroupComponent = (options) => SvelteComponent & Component & WithoutFunction; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:328](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L328) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> diff --git a/docs/framework/svelte/reference/type-aliases/SvelteFormGroupFieldComponent.md b/docs/framework/svelte/reference/type-aliases/SvelteFormGroupFieldComponent.md new file mode 100644 index 0000000000..aa8408e535 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/SvelteFormGroupFieldComponent.md @@ -0,0 +1,32 @@ +--- +id: SvelteFormGroupFieldComponent +title: SvelteFormGroupFieldComponent +--- + +```ts +type SvelteFormGroupFieldComponent = (options) => SvelteComponent & Component & WithoutFunction; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:206](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L206) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\<`any`\>\> diff --git a/docs/framework/svelte/reference/type-aliases/SvelteFormGroupSubscribeComponent.md b/docs/framework/svelte/reference/type-aliases/SvelteFormGroupSubscribeComponent.md new file mode 100644 index 0000000000..ff62fa8652 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/SvelteFormGroupSubscribeComponent.md @@ -0,0 +1,20 @@ +--- +id: SvelteFormGroupSubscribeComponent +title: SvelteFormGroupSubscribeComponent +--- + +```ts +type SvelteFormGroupSubscribeComponent = (options) => SvelteComponent & Component & WithoutFunction; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:192](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L192) + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` diff --git a/docs/framework/svelte/reference/type-aliases/SvelteFormSubscribeComponent.md b/docs/framework/svelte/reference/type-aliases/SvelteFormSubscribeComponent.md new file mode 100644 index 0000000000..87a95aba2f --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/SvelteFormSubscribeComponent.md @@ -0,0 +1,20 @@ +--- +id: SvelteFormSubscribeComponent +title: SvelteFormSubscribeComponent +--- + +```ts +type SvelteFormSubscribeComponent = (options) => SvelteComponent & Component & WithoutFunction; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:89](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L89) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` diff --git a/docs/framework/svelte/reference/type-aliases/SvelteFormSubscribeProps.md b/docs/framework/svelte/reference/type-aliases/SvelteFormSubscribeProps.md new file mode 100644 index 0000000000..88e44cb7d3 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/SvelteFormSubscribeProps.md @@ -0,0 +1,24 @@ +--- +id: SvelteFormSubscribeProps +title: SvelteFormSubscribeProps +--- + +```ts +type SvelteFormSubscribeProps = SvelteSubscribeProps, TSelected>; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:83](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L83) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TSelected + +`TSelected` diff --git a/docs/framework/svelte/reference/type-aliases/SvelteFormType.md b/docs/framework/svelte/reference/type-aliases/SvelteFormType.md new file mode 100644 index 0000000000..f9897f45c9 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/SvelteFormType.md @@ -0,0 +1,16 @@ +--- +id: SvelteFormType +title: SvelteFormType +--- + +```ts +type SvelteFormType = TOptions extends FormOptions ? SvelteFormApi, TComponents extends AnySvelteFormComponentMap ? TComponents : DefaultSvelteFormComponentMap> : never; +``` + +Defined in: [packages/svelte-form/src/formType.public.ts:20](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/formType.public.ts#L20) + +## Type Parameters + +### TOptions + +`TOptions` *extends* `AnyFormOptions` diff --git a/docs/framework/svelte/reference/type-aliases/UseAppFormHook.md b/docs/framework/svelte/reference/type-aliases/UseAppFormHook.md new file mode 100644 index 0000000000..d7bd3ba0e8 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/UseAppFormHook.md @@ -0,0 +1,40 @@ +--- +id: UseAppFormHook +title: UseAppFormHook +--- + +```ts +type UseAppFormHook = (options) => SvelteAppFormApi, TComponents>; +``` + +Defined in: [packages/svelte-form/src/AppForm/createFormHookTypes.public.ts:98](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/AppForm/createFormHookTypes.public.ts#L98) + +## Type Parameters + +### TComponents + +`TComponents` *extends* [`AnySvelteFormComponentMap`](AnySvelteFormComponentMap.md) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> + +### TSubmitReturn + +`TSubmitReturn` + +## Parameters + +### options + +() => `FormOptions`\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\> + +## Returns + +[`SvelteAppFormApi`](SvelteAppFormApi.md)\<`TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>, `TComponents`\> diff --git a/docs/framework/svelte/reference/type-aliases/WithoutFunction.md b/docs/framework/svelte/reference/type-aliases/WithoutFunction.md new file mode 100644 index 0000000000..692662eeb3 --- /dev/null +++ b/docs/framework/svelte/reference/type-aliases/WithoutFunction.md @@ -0,0 +1,16 @@ +--- +id: WithoutFunction +title: WithoutFunction +--- + +```ts +type WithoutFunction = { [K in keyof T as T[K] extends Function ? never : K]: T[K] }; +``` + +Defined in: [packages/svelte-form/src/Components.public.ts:24](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/Components.public.ts#L24) + +## Type Parameters + +### T + +`T` diff --git a/docs/framework/svelte/reference/variables/Field.md b/docs/framework/svelte/reference/variables/Field.md new file mode 100644 index 0000000000..2cd380a9d9 --- /dev/null +++ b/docs/framework/svelte/reference/variables/Field.md @@ -0,0 +1,10 @@ +--- +id: Field +title: Field +--- + +```ts +const Field: LegacyComponentType; +``` + +Defined in: node\_modules/.pnpm/svelte@5.56.8\_@typescript-eslint+types@8.66.0/node\_modules/svelte/types/index.d.ts:3212 diff --git a/docs/framework/svelte/reference/variables/createForm.md b/docs/framework/svelte/reference/variables/createForm.md new file mode 100644 index 0000000000..a927ae9a3a --- /dev/null +++ b/docs/framework/svelte/reference/variables/createForm.md @@ -0,0 +1,34 @@ +--- +id: createForm +title: createForm +--- + +```ts +const createForm: CreateForm; +``` + +Defined in: [packages/svelte-form/src/createForm.public.ts:53](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/createForm.public.ts#L53) + +Creates a Svelte form whose instance and lifecycle are owned by the current +component. + +Pass an options function. `defaultValues` establish the initial state and +inferred form value type, while reactive values read by the function update +the same form instance when they change. + +Call this during component initialization. The form mounts with the +component and is cleaned up when the component unmounts. + +## Example + +```ts +const form = createForm(() => ({ + defaultValues: { name: '' }, + onSubmit: ({ value }) => saveProfile(value), +})) +``` + +## Returns + +The Svelte form API with typed field, subscription, and form-group +components attached. diff --git a/docs/framework/svelte/reference/variables/defineFieldGroup.md b/docs/framework/svelte/reference/variables/defineFieldGroup.md new file mode 100644 index 0000000000..2eeb0978bf --- /dev/null +++ b/docs/framework/svelte/reference/variables/defineFieldGroup.md @@ -0,0 +1,12 @@ +--- +id: defineFieldGroup +title: defineFieldGroup +--- + +```ts +const defineFieldGroup: DefineFieldGroupFn>; +``` + +Defined in: [packages/svelte-form/src/FieldGroup/withFields.public.ts:100](https://github.com/TanStack/form/blob/main/packages/svelte-form/src/FieldGroup/withFields.public.ts#L100) + +Defines a reusable group of virtual fields. diff --git a/docs/framework/svelte/reference/variables/useStore.md b/docs/framework/svelte/reference/variables/useStore.md new file mode 100644 index 0000000000..4183d4548d --- /dev/null +++ b/docs/framework/svelte/reference/variables/useStore.md @@ -0,0 +1,60 @@ +--- +id: useStore +title: useStore +--- + +```ts +const useStore: (source, selector?, compare?) => object; +``` + +Defined in: node\_modules/.pnpm/@tanstack+svelte-store@0.12.1\_svelte@5.56.8\_@typescript-eslint+types@8.66.0\_/node\_modules/@tanstack/svelte-store/dist/useStore.d.ts:13 + +Deprecated alias for [useSelector](../functions/useSelector.md). + +## Type Parameters + +### TState + +`TState` + +### TSelected + +`TSelected` = `NoInfer`\<`TState`\> + +## Parameters + +### source + + \| [`Atom`](../interfaces/Atom.md)\<`TState`\> + \| [`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`TState`\> + \| [`Store`](../classes/Store.md)\<`TState`, `any`\> + \| [`ReadonlyStore`](../classes/ReadonlyStore.md)\<`TState`\> + +### selector? + +(`state`) => `TSelected` + +### compare? + +(`a`, `b`) => `boolean` + +## Returns + +`object` + +### ~~current~~ + +```ts +readonly current: TSelected; +``` + +## Example + +```ts +const count = useStore(counterStore, (state) => state.count) +console.log(count.current) +``` + +## Deprecated + +Use `useSelector` instead. diff --git a/docs/framework/vue/guides/arrays.md b/docs/framework/vue/guides/arrays.md deleted file mode 100644 index 3d3eb1bcaf..0000000000 --- a/docs/framework/vue/guides/arrays.md +++ /dev/null @@ -1,148 +0,0 @@ ---- -id: arrays -title: Arrays ---- - -TanStack Form supports arrays as values in a form, including sub-object values inside of an array. - -## Basic Usage - -To use an array, you can use `field.state.value` on an array value in conjunction with `v-for`: - -```vue - - - -``` - -This will generate the mapped slot every time you run `pushValue` on `field`: - -```vue - -``` - -Finally, you can use a subfield like so: - -```vue - - - -``` - -## Full Example - -```vue - - - -``` diff --git a/docs/framework/vue/guides/async-initial-values.md b/docs/framework/vue/guides/async-initial-values.md index c8410a8503..81577546c3 100644 --- a/docs/framework/vue/guides/async-initial-values.md +++ b/docs/framework/vue/guides/async-initial-values.md @@ -3,57 +3,160 @@ id: async-initial-values title: Async Initial Values --- -Let's say that you want to fetch some data from an API and use it as the initial value of a form. +Forms often edit data loaded from an API. A server-state library such as +TanStack Query should own fetching, caching, loading, and retries; TanStack Form +should own the editable copy. -While this problem sounds simple on the surface, there are hidden complexities you might not have thought of thus far. +There are two supported ways to provide async initial values: wait to create +the form until the data is ready, or create it immediately with complete +fallback values. Choose the approach that best matches the loading experience +your UI needs. -For example, you might want to show a loading spinner while the data is being fetched, or you might want to handle errors gracefully. +## Wait for data before creating the editor -Likewise, you could also find yourself looking for a way to cache the data so that you don't have to fetch it every time the form is rendered. +Render a loading or error state first, then mount a component whose +`defaultValues` are complete. -While we could implement many of these features from scratch, it would end up looking a lot like another project we maintain: [TanStack Query](https://tanstack.com/query). +```vue + + -## Basic Usage + +``` ```vue + + + +``` -const firstName = computed(() => data.value?.firstName || '') -const lastName = computed(() => data.value?.lastName || '') +This pattern is useful when no form state is needed during loading. Mounting +the editor only after data exists also makes it explicit when switching records +should create a fresh form. The `:key` recreates the editor when `userId` +changes. -const defaultValues = reactive({ - firstName, - lastName, +## Create the form before data arrives + +You can instead call `useForm` in the same component as `useQuery`. Provide a +static, shape-complete fallback so `defaultValues` are never `undefined`, then +update a reactive options object when data arrives. + +```vue + ``` -This will show a loading text until the data is fetched, and then it will render the form with the fetched data as the initial values. +The Vue adapter observes the reactive options object. When query data replaces +the fallback, TanStack Form applies the new `defaultValues` to untouched fields +while preserving fields the user has already touched. In this example, the +fields remain unmounted during loading, so the user cannot edit them before the +loaded values arrive. You can also render the empty form immediately when that +better suits the UI. + +## Background refetches and record changes + +`defaultValues` establish the form's baseline; they are not a fully controlled +`values` prop. In the fallback pattern, later `defaultValues` updates use the +same touched-field-preserving behavior. + +If background refetches arrive while a user is editing, decide at the product +level whether to keep local edits, prompt before replacing them, or call +`form.reset(nextValues)` deliberately. Do not overwrite in-progress input +merely because a query refreshed. + +When switching to a different record, either remount a keyed editor as in the +first pattern or deliberately reset the existing form. Otherwise, touched +values from the previous record can be preserved when the new defaults arrive. diff --git a/docs/framework/vue/guides/basic-concepts.md b/docs/framework/vue/guides/basic-concepts.md deleted file mode 100644 index 7d37a38077..0000000000 --- a/docs/framework/vue/guides/basic-concepts.md +++ /dev/null @@ -1,381 +0,0 @@ ---- -id: basic-concepts -title: Basic Concepts and Terminology ---- - -This page introduces the basic concepts and terminology used in the `@tanstack/vue-form` library. Familiarizing yourself with these concepts will help you better understand and work with the library. - -## Form Options - -You can create options for your form so that it can be shared between multiple forms by using the `formOptions` function. - -Example: - -```ts -const formOpts = formOptions({ - defaultValues: { - firstName: '', - lastName: '', - hobbies: [], - } as Person, -}) -``` - -## Form Instance - -A Form Instance is an object that represents an individual form and provides methods and properties for working with the form. You create a form instance using the `useForm` function. The function accepts an object with an `onSubmit` function, which is called when the form is submitted. - -```js -const form = useForm({ - ...formOpts, - onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) - }, -}) -``` - -You may also create a form instance without using `formOptions` by using the standalone `useForm` API: - -```ts -const form = useForm({ - onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) - }, - defaultValues: { - firstName: '', - lastName: '', - hobbies: [], - } as Person, -}) -``` - -## Field - -A Field represents a single form input element, such as a text input or a checkbox. Fields are created using the form.Field component provided by the form instance. The component accepts a name prop, which should match a key in the form's default values. It also accepts a scoped slot defined by the `v-slot` directive which takes a `field` object as its argument. - -Example: - -```vue - -``` - -## Field State - -Each field has its own state, which includes its current value, validation status, error messages, and other metadata. You can access a field's state using the `field().state` property. - -Example: - -```ts -const { - value, - meta: { errors, isValidating }, -} = field.state -``` - -There are four states in the metadata that can be useful to see how the user interacts with a field: - -- _"isTouched"_, after the user changes the field or blurs the field -- _"isDirty"_, after the field's value has been changed, even if it's been reverted to the default. Opposite of `isPristine` -- _"isPristine"_, until the user changes the field value. Opposite of `isDirty` -- _"isBlurred"_, after the field has been blurred - -```ts -const { isTouched, isDirty, isPristine, isBlurred } = field.state.meta -``` - -![Field states](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states.png) - -## Understanding 'isDirty' in Different Libraries - -Non-Persistent `dirty` state - -- **Libraries**: React Hook Form (RHF), Formik, Final Form. -- **Behavior**: A field is 'dirty' if its value differs from the default. Reverting to the default value makes it 'clean' again. - -Persistent `dirty` state - -- **Libraries**: Angular Form, Vue FormKit. -- **Behavior**: A field remains 'dirty' once changed, even if reverted to the default value. - -We have chosen the persistent 'dirty' state model. To also support a non-persistent 'dirty' state, we introduce an additional flag: - -- _"isDefaultValue"_, whether the field's current value is the default value - -```ts -const { isDefaultValue, isTouched } = field.state.meta - -// The following line will re-create the non-Persistent `dirty` functionality. -const nonPersistentIsDirty = !isDefaultValue -``` - -![Field states extended](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states-extended.png) - -## Field API - -The Field API is an object provided by a scoped slot using the `v-slot` directive. This slot receives an argument named `field` that provides methods and properties for working with the field's state. - -Example: - -```vue - -``` - -## Validation - -`@tanstack/vue-form` provides both synchronous and asynchronous validation out of the box. Validation functions can be passed to the `form.Field` component using the `validators` prop. - -Example: - -```vue - -``` - -## Validation with Standard Schema Libraries - -In addition to hand-rolled validation options, we also support the [Standard Schema](https://github.com/standard-schema/standard-schema) specification. - -You can define a schema using any of the libraries implementing the specification and pass it to a form or field validator. - -Supported libraries include: - -- [Zod](https://zod.dev/) (v3.24.0 or higher) -- [Valibot](https://valibot.dev/) (v1.0.0 or higher) -- [ArkType](https://arktype.io/) (v2.1.20 or higher) -- [Yup](https://github.com/jquense/yup) (v1.7.0 or higher) - -```vue - - - -``` - -## Reactivity - -`@tanstack/vue-form` offers various ways to subscribe to form and field state changes, most notably the `form.useSelector` method and the `form.Subscribe` component. These methods allow you to optimize your form's rendering performance by only updating components when necessary. - -Example: - -```vue - - - -``` - -## Listeners - -`@tanstack/vue-form` allows you to react to specific triggers and "listen" to them to dispatch side effects. - -Example: - -```vue - -``` - -More information can be found at [Listeners](./listeners.md) - -Note: The usage of the `form.useField` method to achieve reactivity is discouraged since it is designed to be used thoughtfully within the `form.Field` component. You might want to use `form.useSelector` instead. - -## Array Fields - -Array fields allow you to manage a list of values within a form, such as a list of hobbies. You can create an array field using the `form.Field` component with the `mode="array"` prop. - -When working with array fields, you can use the fields `pushValue`, `removeValue`, `swapValues` and `moveValue` methods to add, remove, swap, and move a value from one index to another within the array, respectively. Additional helper methods such as `insertValue`, `replaceValue`, and `clearValues` are also available for inserting, replacing, and clearing array values. - -Example: - -```vue - -``` - -These are the basic concepts and terminology used in the `@tanstack/vue-form` library. Understanding these concepts will help you work more effectively with the library and create complex forms with ease. diff --git a/docs/framework/vue/guides/debugging.md b/docs/framework/vue/guides/debugging.md new file mode 100644 index 0000000000..9eaad5cb12 --- /dev/null +++ b/docs/framework/vue/guides/debugging.md @@ -0,0 +1,76 @@ +--- +id: debugging +title: Debugging Vue Usage +--- + +This page covers common Vue and TypeScript problems when using TanStack Form. + +## An input initially renders `undefined` + +Every value rendered by an input must exist in form-level `defaultValues` from +the first render. + +```vue + +``` + +Do not omit `defaultValues` or rely on a field-level default. When values come +from an API, render a loading state before mounting the editable form or supply +a complete fallback shape. + +## A field value is `unknown` + +Field names and values are inferred from `defaultValues`. Check that you have +not widened the initial object to `Record`, `any`, or an +unrelated union. Prefer a concrete value type: + +```ts +type Profile = { firstName: string; age: number } + +const defaults: Profile = { firstName: '', age: 0 } +const form = useForm({ defaultValues: defaults }) +``` + +For extremely large forms, split UI into typed components or scoped form and +field groups instead of casting each field value. + +## Async defaults do not update + +The Vue adapter observes reactive option objects. If data arrives after +`useForm` runs, update `defaultValues` through a `reactive` options object or +mount the editor only after the data exists. A plain object containing a +one-time snapshot is not reactive. + +## Composition types fail under Vue 3.5 + +Form v2 requires Vue 3.6 or newer. The adapter's typed field components, +injection-based `AppForm`, and form composition rely on Vue 3.6 behavior that +is not available in Vue 3.5. + +## Type instantiation is excessively deep + +This TypeScript error usually involves a very large recursive value shape, a +widely inferred union, or unsupported composition. Reduce it to the smallest +form that reproduces the problem, keep `defaultValues` concrete, and avoid +unnecessary generic wrappers. + +If the minimal reproduction still fails, report it in the +[TanStack Form issue tracker](https://github.com/TanStack/form/issues). Include +the Vue and TypeScript versions, the form value type, and the smallest failing +field. + +## Errors exist but are not displayed + +`field.errors` respects the form's `errorVisibility` policy. Inspect +`field.meta.original.errors` when debugging whether validation ran but the +issues are intentionally hidden. Also confirm that the input calls +`field.handleBlur` if the policy depends on `isBlurred`. diff --git a/docs/framework/vue/guides/dynamic-validation.md b/docs/framework/vue/guides/dynamic-validation.md deleted file mode 100644 index b2b1d2957d..0000000000 --- a/docs/framework/vue/guides/dynamic-validation.md +++ /dev/null @@ -1,240 +0,0 @@ ---- -id: dynamic-validation -title: Dynamic Validation ---- - -In many cases, you want to change the validation rules based depending on the state of the form or other conditions. The most popular -example of this is when you want to validate a field differently based on whether the user has submitted the form for the first time or not. - -We support this through our `onDynamic` validation function. - -```vue - -``` - -> By default `onDynamic` is not called, so you need to pass `revalidateLogic()` to the `validationLogic` option of `useForm`. - -## Revalidation Options - -`revalidateLogic` allows you to specify when validation should be run and change the validation rules dynamically based on the current submission state of the form. - -It takes two arguments: - -- `mode`: The mode of validation prior to the first form submission. This can be one of the following: - - `change`: Validate on every change. - - `blur`: Validate on blur. - - `submit`: Validate on submit. (**default**) - -- `modeAfterSubmission`: The mode of validation after the form has been submitted. This can be one of the following: - - `change`: Validate on every change. (**default**) - - `blur`: Validate on blur. - - `submit`: Validate on submit. - -You can, for example, use the following to revalidate on blur after the first submission: - -```vue - -``` - -## Accessing Errors - -Just as you might access errors from an `onChange` or `onBlur` validation, you can access the errors from the `onDynamic` validation function using the `form.state.errorMap` object. - -```vue - - - -``` - -## Usage with Other Validation Logic - -You can use `onDynamic` validation alongside other validation logic, such as `onChange` or `onBlur`. - -```vue - - - -``` - -### Usage with Fields - -You can also use `onDynamic` validation with fields, just like you would with other validation logic. - -```vue - - - -``` - -### Async Validation - -Async validation can also be used with `onDynamic` just like with other validation logic. You can even debounce the async validation to avoid excessive calls. - -```vue - -``` - -### Standard Schema Validation - -You can also use standard schema validation libraries like Valibot or Zod with `onDynamic` validation. This allows you to define complex validation rules that can change dynamically based on the form state. - -```vue - -``` diff --git a/docs/framework/vue/guides/form-groups.md b/docs/framework/vue/guides/form-groups.md deleted file mode 100644 index 0a4da5ed50..0000000000 --- a/docs/framework/vue/guides/form-groups.md +++ /dev/null @@ -1,200 +0,0 @@ ---- -id: form-groups -title: Form Groups ---- - -When building a multi-stage form that has many stages, like so: - -![Form stepper](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/stepper.png) - -It's common for each step to have its own form. However, this complicates the form submission and validation process by requiring you to add complex logic. - -Luckily, TanStack Form provides a way to build out sub-forms that make this kind of development trivial to implement: ``. - -## Usage - -To use a form group in TanStack Form, you'll use `useForm` to create a `form` variable, then reference its `FormGroup` component like you would a `Field`: - -```vue - - - -``` - -This becomes much more useful when paired with external state to conditionally render a `FormGroup`: - -```vue - - - -``` - -## Form Group Validation - -Form groups have a distinct validation proceedure that we think makes sense for sub-forms: - -- Form groups can have their own validation: - -```vue - -``` - -- Can set errors on sub-fields: - -```vue - -``` - -- And can even accept standard schemas: - -```vue - -``` - -> The reason we don't use the full path names for fields is so that you can compose your schemas like so: -> -> ```ts -> const step1Schema = z.object({ -> name: z.string().min(2), -> }) -> -> const schema = z.object({ -> step1: step1Schema, -> step2: step2Schema, -> }) -> ``` -> -> And pass the `step1Schema` to a form group and `schema` to the parent form. That way, partially validated data will still flag errors if the group is bypassed. - -### Dynamic Group Validation - -If you want to use [dynamic validation (`onDynamic`)](./dynamic-validation.md) with a form group, do not rely on the `onDynamic` validator passed to `useForm`: - -```ts -useForm({ - validationLogic: revalidateLogic(), - validators: { - // This validator will not run `onChange` when a sub-form is submitted; - // it will only run `onChange` when the form itself is submitted. - onDynamic: schema, - }, -}) -``` - -Instead, pass your sub-schema for the group to the `onDynamic` validation of the `FormGroup` itself: - -```vue - -``` - -It will treat `formGroup.submissionAttempts` as the way to change what validator is ran before/after submit. - -## Form Group State - -Just like you're able to access `formGroup.state.meta.errors`, you're also able to access the group's value using `formGroup.state.value`. Likewise, here are some valuable properties you can access in the `formGroup.state.meta`: - -- `formGroup.state.meta.isFieldsValid`: `true` when the field-level validators have no errors -- `formGroup.state.meta.isGroupValid`: `true` when the group-level validators have no errors -- `formGroup.state.meta.isValid`: `true` when both the field-level and group-level validators have no errors -- `formGroup.state.meta.isSubmitting`: `true` when the group is in the process of being submitted diff --git a/docs/framework/vue/guides/linked-fields.md b/docs/framework/vue/guides/linked-fields.md deleted file mode 100644 index 53436d7911..0000000000 --- a/docs/framework/vue/guides/linked-fields.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -id: linked-fields -title: Link Two Form Fields Together ---- - -You may find yourself needing to link two fields together; when one is validated as another field's value has changed. -One such usage is when you have both a `password` and `confirm_password` field, -where you want to `confirm_password` to error out when `password`'s value does not match; -regardless of which field triggered the value change. - -Imagine the following userflow: - -- User updates confirm password field. -- User updates the non-confirm password field. - -In this example, the form will still have errors present, -as the "confirm password" field validation has not been re-ran to mark as accepted. - -To solve this, we need to make sure that the "confirm password" validation is re-run when the password field is updated. -To do this, you can add a `onChangeListenTo` property to the `confirm_password` field. - -```vue - - - -``` - -This similarly works with `onBlurListenTo` property, which will re-run the validation when the field is blurred. diff --git a/docs/framework/vue/guides/listeners.md b/docs/framework/vue/guides/listeners.md deleted file mode 100644 index f5af87fc37..0000000000 --- a/docs/framework/vue/guides/listeners.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -id: listeners -title: Side effects for event triggers ---- - -For situations where you want to "affect" or "react" to triggers, there's the listener API. For example, if you, as the developer, want to reset a form field as a result of another field changing, you would use the listener API. - -Imagine the following user flow: - -- User selects a country from a drop-down. -- User then selects a province from another drop-down. -- User changes the selected country to a different one. - -In this example, when the user changes the country, the selected province needs to be reset as it's no longer valid. With the listener API, we can subscribe to the onChange event and dispatch a reset to the field "province" when the listener is fired. - -Events that can be "listened" to are: - -- `onChange` -- `onBlur` -- `onMount` -- `onSubmit` -- `onUnmount` - -```vue - - - -``` - -### Built-in Debouncing - -If you are making an API request inside a listener, you may want to debounce the calls as it can lead to performance issues. -We enable an easy method for debouncing your listeners by adding a `onChangeDebounceMs` or `onBlurDebounceMs`. - -```vue - -``` - -### Form listeners - -At a higher level, listeners are also available at the form level, allowing you access to the `onMount` and `onSubmit` events, and having `onChange` and `onBlur` propagated to all the form's children. Form-level listeners can also be debounced in the same way as previously discussed. - -`onMount` and `onSubmit` listeners have the following parameters: - -- `formApi` - -`onChange` and `onBlur` listeners have access to: - -- `fieldApi` -- `formApi` - -```vue - -``` diff --git a/docs/framework/vue/guides/submission-handling.md b/docs/framework/vue/guides/submission-handling.md deleted file mode 100644 index 2976e0b854..0000000000 --- a/docs/framework/vue/guides/submission-handling.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -id: submission-handling -title: Submission handling ---- - -## Passing additional data to submission handling - -You may have multiple types of submission behaviour, for example, going back to another page or staying on the form. -You can accomplish this by specifying the `onSubmitMeta` property. This meta data will be passed to the `onSubmit` function. - -> Note: if `form.handleSubmit()` is called without metadata, it will use the provided default. - -```vue - - - -``` - -## Transforming data with Standard Schemas - -While Tanstack Form provides [Standard Schema support](./validation.md) for validation, it does not preserve the Schema's output data. - -The value passed to the `onSubmit` function will always be the input data. To receive the output data of a Standard Schema, parse it in the `onSubmit` function: - -```vue - - -``` diff --git a/docs/framework/vue/guides/ui-libraries.md b/docs/framework/vue/guides/ui-libraries.md new file mode 100644 index 0000000000..a97bb17b33 --- /dev/null +++ b/docs/framework/vue/guides/ui-libraries.md @@ -0,0 +1,82 @@ +--- +id: ui-libraries +title: UI Libraries +--- + +TanStack Form is headless. UI library integration consists of adapting a +field's value, blur callback, change callback, invalid state, and errors to the +component's props and emitted events. + +## Text inputs + +Many Vue components use `modelValue` and emit `update:modelValue`: + +```vue + + + +``` + +Pass the current value rather than a one-time default so the UI remains driven +by form state. + +## Checkboxes and switches + +Adapt the event used by the component library: + +```vue + + + +``` + +Some libraries emit a details object or a union such as +`boolean | 'indeterminate'`. Normalize it at the boundary: + +```vue + +``` + +## Selects, date pickers, and custom controls + +The integration does not require a native event. Pass the value emitted by the +component to `field.handleChange`: + +```vue + +``` + +Choose a serializable form value appropriate for your application, then adapt +the UI library's richer object at the component boundary if necessary. + +## Reuse the adapter + +If the same wiring appears throughout the application, extract a component +whose props include `FieldWithValue`, then register it with `createFormHook` +when it should be available as a typed app field component. + +For the helper types used when passing a form or field to an extracted +component, see [Splitting forms](../../../splitting-forms). + +The repository's Vue large-form example demonstrates +`getFormHookHelpers`, `createFormHook`, injected app fields, and a reusable +field group. diff --git a/docs/framework/vue/guides/validation.md b/docs/framework/vue/guides/validation.md index 90fbefe291..70e4c444c6 100644 --- a/docs/framework/vue/guides/validation.md +++ b/docs/framework/vue/guides/validation.md @@ -3,231 +3,84 @@ id: form-validation title: Form and Field Validation --- -At the core of TanStack Form's functionalities is the concept of validation. TanStack Form makes validation highly customizable: +TanStack Form supports synchronous, asynchronous, field-level, form-level, and +Standard Schema validation. Every validator is an ordered object with a `run` +implementation and explicit `triggers`. -- You can control when to perform the validation (on change, on input, on blur, on submit...) -- Validation rules can be defined at the field level or at the form level -- Validation can be synchronous or asynchronous (for example, as a result of an API call) +## Choose when validation runs -## When is validation performed? - -It's up to you! The `` component accepts some callbacks as props such as `onChange` or `onBlur`. Those callbacks are passed the current value of the field, as well as the `fieldAPI` object, so that you can perform the validation. If you find a validation error, simply return the error message as string and it will be available in `field.state.meta.errors`. - -Here is an example: - -```vue - -``` - -In the example above, the validation is done at each keystroke (`onChange`). If, instead, we wanted the validation to be done when the field is blurred, we would change the code above like so: - -```vue - -``` - -So you can control when the validation is done by implementing the desired callback. You can even perform different pieces of validation at different times: - -```vue - -``` - -In the example above, we are validating different things on the same field at different times (at each keystroke and when blurring the field). Since `field.state.meta.errors` is an array, all the relevant errors at a given time are displayed. You can also use `field.state.meta.errorMap` to get errors based on _when_ the validation was done (onChange, onBlur etc...). More info about displaying errors below. - -## Displaying Errors - -Once you have your validation in place, you can map the errors from an array to be displayed in your UI: - -```vue - -``` - -Or use the `errorMap` property to access the specific error you're looking for: - -```vue - -``` - -It's worth mentioning that our `errors` array and the `errorMap` matches the types returned by the validators. This means that: +Use `change` for immediate feedback and `blur` for feedback after leaving an +input. Submission runs validators by default regardless of their configured +change and blur triggers. ```vue - + + + + {{ error.message }} + ``` -## Validation at field level vs at form level +Additional controls include: + +- `runOnMount`: run once when the form is constructed or when a field or form + group first mounts. +- `skipOnSubmit`: conditionally skip submit-time execution. +- `triggerDebounceMs`: debounce change and blur execution. +- `bailIfInvalid`: skip this and subsequent validators when an earlier one + failed. +- trigger objects with `when`: enable a trigger conditionally. +- `watchFields`: rerun a field validator when related fields trigger it. -As shown above, each `` accepts its own validation rules via the `onChange`, `onBlur` etc... callbacks. It is also possible to define validation rules at the form level (as opposed to field by field) by passing similar callbacks to the `useForm()` function. +## Control when errors are visible -Example: +Validation and presentation are separate. `errorVisibility` decides when field +issues appear in `field.errors`: ```vue - - ``` -### Setting field-level errors from the form's validators +Use `field.meta.original.errors` for the unfiltered issues when debugging or +building a custom visibility system. + +## Form-level validation -You can set errors on the fields from the form's validators. One common use case for this is validating all the fields on submit by calling a single API endpoint in the form's `onSubmitAsync` validator. +A form validator can produce a form issue and route issues to typed field paths +with `createErrorMap`: ```vue - - ``` -> Something worth mentioning is that if you have a form validation function that returns an error, that error may be overwritten by the field-specific validation. -> -> This means that: -> -> ```vue -> -> -> -> ``` -> -> Will only show `'Must be odd!` even if the 'Too young!' error is returned by the form-level validation. - -## Asynchronous Functional Validation +Use `form.Subscribe` to reactively select form-level issues from +`form.state.errors`. Lower-level integrations can subscribe to `form.atom` with +`useSelector`. Field-routed issues appear in the corresponding `field.errors`. -While we suspect most validations will be synchronous, there are many instances where a network call or some other async operation would be useful to validate against. +## Asynchronous validation and debouncing -To do this, we have dedicated `onChangeAsync`, `onBlurAsync`, and other methods that can be used to validate against: +`run` may return a promise. Put cheap synchronous checks first and use +`bailIfInvalid` to avoid unnecessary requests: ```vue - +Submit validation always runs immediately, even when a trigger is debounced. +`field.meta.isValidating` and `form.state.isValidating` expose pending work. - -``` +## Standard Schema validation -Synchronous and Asynchronous validations can coexist. For example, it is possible to define both `onBlur` and `onBlurAsync` on the same field: +Any Standard Schema implementation can be supplied as `run`: ```vue - - ``` -The synchronous validation method (`onBlur`) is run first and the asynchronous method (`onBlurAsync`) is only run if the synchronous one (`onBlur`) succeeds. To change this behaviour, set the `asyncAlways` option to `true`, and the async method will be run regardless of the result of the sync method. +Schema paths are routed to matching fields. Parsed outputs are available by +validator index in `schemaOutputs` during submit, for example +`schemaOutputs[0]`. `value` remains the form's raw editable state rather than +the parsed output. -### Built-in Debouncing +For custom schema routing, call a schema's safe parse API inside `run` and pass +its issues to the provided `parseIssues` helper. -While async calls are the way to go when validating against the database, running a network request on every keystroke is a good way to DDOS your database. +## Validate related fields -Instead, we enable an easy method for debouncing your `async` calls by adding a single property: +Use `watchFields` when one field's validity depends on another: ```vue - -``` - -This will debounce every async call with a 500ms delay. You can even override this property on a per-validation property: - -```vue - + + + ``` -This will run `onChangeAsync` every 1500ms while `onBlurAsync` will run every 500ms. - -## Validation through Schema Libraries - -While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries that provide schema-based validation to make shorthand and type-strict validation substantially easier. You can also define a single schema for your entire form and pass it to the form level, errors will be automatically propagated to the fields. +## Return errors from submission -### Standard Schema Libraries - -TanStack Form natively supports all libraries following the [Standard Schema specification](https://github.com/standard-schema/standard-schema), most notably: - -- [Zod](https://zod.dev/) -- [Valibot](https://valibot.dev/) -- [ArkType](https://arktype.io/) - -_Note:_ make sure to use the latest version of the schema libraries as older versions might not support Standard Schema yet. - -> Validation will not provide you with transformed values. See [submission handling](./submission-handling.md) for more information. - -To use schemas from these libraries you can pass them to the `validators` props as you would do with a custom function: +Endpoint validation belongs in `onSubmit`. Return +`createValidationError(...)` to feed server issues back into normal form state: ```vue - - -``` - -Async validations on form and field level are supported as well: - -```vue - -``` - -If you need even more control over your Standard Schema validation, you can combine a Standard Schema with a callback function like so: - -```vue - ``` -## Preventing invalid forms from being submitted +## Prevent invalid submission -The `onChange`, `onBlur` etc... callbacks are also run when the form is submitted and the submission is blocked if the form is invalid. - -The form state object has a `canSubmit` flag that is false when any field is invalid and the form has been touched (`canSubmit` is true until the form has been touched, even if some fields are "technically" invalid based on their `onChange`/`onBlur` props). - -You can subscribe to it via `form.Subscribe` and use the value in order to, for example, disable the submit button when the form is invalid (in practice, disabled buttons are not accessible, use `aria-disabled` instead). +`form.handleSubmit()` skips `onSubmit` when validation fails and resolves with +the validation errors. `onSubmitInvalid` is currently available on form groups; +root-form support is planned but not yet implemented. Subscribe to `canSubmit` +and `isSubmitting` to reflect that state in the submit UI: ```vue - - - + + + ``` -To prevent the form from being submitted before any interaction, combine `canSubmit` with `isPristine` flags. A simple condition like `!canSubmit || isPristine` effectively disables submissions until the user has made changes. +If a disabled submit button would hide useful validation feedback, keep it +focusable with `aria-disabled` and let `handleSubmit()` report the issues. diff --git a/docs/framework/vue/quick-start.md b/docs/framework/vue/quick-start.md index 1c4b84154b..3a1aab510d 100644 --- a/docs/framework/vue/quick-start.md +++ b/docs/framework/vue/quick-start.md @@ -3,43 +3,115 @@ id: quick-start title: Quick Start --- -The bare minimum to get started with TanStack Form is to create a form and add a field. Keep in mind that this example does not include any validation or error handling... yet. +TanStack Form is a headless, type-safe form library. It owns form state and +validation while leaving markup, styling, and component choice to you. + +The Form v2 Vue adapter requires Vue 3.6 or newer. At the time of writing, Vue +3.6 is available as a release candidate but has not yet been released as +stable. We hope it will be stable by the time TanStack Form v2 becomes stable. + +Vue 3.6 provides the component and composition behavior needed for Form +Composition to work correctly and to preserve form and field types across +templates and extracted components. Setting this minimum in v2 from the start +avoids introducing a breaking Vue version requirement later. + +Install the Vue adapter: + +```bash +npm install @tanstack/vue-form +``` + +## Create a form + +`useForm` requires `defaultValues`. Their shape becomes the form's inferred +value type. ```vue - - ``` -From here, you'll be ready to explore all of the other features of TanStack Form! +The important pieces are: + +- `defaultValues` define the complete initial value and drive type inference. +- `form.Field` subscribes to one field. Its slot exposes `field.value`, + `field.meta`, and event handlers. +- Validators are ordered objects with a `run` function and explicit + `triggers`. +- `form.Subscribe` rerenders only its slot when the selected form state + changes. +- `form.handleSubmit()` validates the form before calling `onSubmit`. diff --git a/docs/framework/vue/reference/classes/ReadonlyStore.md b/docs/framework/vue/reference/classes/ReadonlyStore.md new file mode 100644 index 0000000000..e764546914 --- /dev/null +++ b/docs/framework/vue/reference/classes/ReadonlyStore.md @@ -0,0 +1,122 @@ +--- +id: ReadonlyStore +title: ReadonlyStore +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:22 + +## Type Parameters + +### T + +`T` + +## Implements + +- `Omit`\<[`Store`](Store.md)\<`T`\>, `"setState"` \| `"actions"`\> + +## Constructors + +### Constructor + +```ts +new ReadonlyStore(getValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:24 + +#### Parameters + +##### getValue + +(`prev?`) => `T` + +#### Returns + +`ReadonlyStore`\<`T`\> + +### Constructor + +```ts +new ReadonlyStore(initialValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:25 + +#### Parameters + +##### initialValue + +`T` + +#### Returns + +`ReadonlyStore`\<`T`\> + +## Accessors + +### state + +#### Get Signature + +```ts +get state(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:26 + +##### Returns + +`T` + +#### Implementation of + +```ts +Omit.state +``` + +## Methods + +### get() + +```ts +get(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:27 + +#### Returns + +`T` + +#### Implementation of + +```ts +Omit.get +``` + +*** + +### subscribe() + +```ts +subscribe(observerOrFn): Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:28 + +#### Parameters + +##### observerOrFn + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +#### Returns + +[`Subscription`](../interfaces/Subscription.md) + +#### Implementation of + +```ts +Omit.subscribe +``` diff --git a/docs/framework/vue/reference/classes/Store.md b/docs/framework/vue/reference/classes/Store.md new file mode 100644 index 0000000000..3e93a261b2 --- /dev/null +++ b/docs/framework/vue/reference/classes/Store.md @@ -0,0 +1,156 @@ +--- +id: Store +title: Store +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:11 + +## Type Parameters + +### T + +`T` + +### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) = `never` + +## Constructors + +### Constructor + +```ts +new Store(getValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:14 + +#### Parameters + +##### getValue + +(`prev?`) => `T` + +#### Returns + +`Store`\<`T`, `TActions`\> + +### Constructor + +```ts +new Store(initialValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:15 + +#### Parameters + +##### initialValue + +`T` + +#### Returns + +`Store`\<`T`, `TActions`\> + +### Constructor + +```ts +new Store(initialValue, actionsFactory): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:16 + +#### Parameters + +##### initialValue + +`NonFunction`\<`T`\> + +##### actionsFactory + +[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> + +#### Returns + +`Store`\<`T`, `TActions`\> + +## Properties + +### actions + +```ts +readonly actions: TActions; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:13 + +## Accessors + +### state + +#### Get Signature + +```ts +get state(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:18 + +##### Returns + +`T` + +## Methods + +### get() + +```ts +get(): T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:19 + +#### Returns + +`T` + +*** + +### setState() + +```ts +setState(updater): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:17 + +#### Parameters + +##### updater + +(`prev`) => `T` + +#### Returns + +`void` + +*** + +### subscribe() + +```ts +subscribe(observerOrFn): Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:20 + +#### Parameters + +##### observerOrFn + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +#### Returns + +[`Subscription`](../interfaces/Subscription.md) diff --git a/docs/framework/vue/reference/functions/batch.md b/docs/framework/vue/reference/functions/batch.md new file mode 100644 index 0000000000..ad5677dbb2 --- /dev/null +++ b/docs/framework/vue/reference/functions/batch.md @@ -0,0 +1,20 @@ +--- +id: batch +title: batch +--- + +```ts +function batch(fn): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:5 + +## Parameters + +### fn + +() => `void` + +## Returns + +`void` diff --git a/docs/framework/vue/reference/functions/createAsyncAtom.md b/docs/framework/vue/reference/functions/createAsyncAtom.md new file mode 100644 index 0000000000..5ec22ca780 --- /dev/null +++ b/docs/framework/vue/reference/functions/createAsyncAtom.md @@ -0,0 +1,30 @@ +--- +id: createAsyncAtom +title: createAsyncAtom +--- + +```ts +function createAsyncAtom(getValue, options?): ReadonlyAtom>; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:16 + +## Type Parameters + +### T + +`T` + +## Parameters + +### getValue + +() => `Promise`\<`T`\> + +### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`AsyncAtomState`\<`T`, `unknown`\>\> + +## Returns + +[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`AsyncAtomState`\<`T`, `unknown`\>\> diff --git a/docs/framework/vue/reference/functions/createAtom.md b/docs/framework/vue/reference/functions/createAtom.md new file mode 100644 index 0000000000..d41435b132 --- /dev/null +++ b/docs/framework/vue/reference/functions/createAtom.md @@ -0,0 +1,60 @@ +--- +id: createAtom +title: createAtom +--- + +## Call Signature + +```ts +function createAtom(getValue, options?): ReadonlyAtom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:17 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`T`\> + +## Call Signature + +```ts +function createAtom(initialValue, options?): Atom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:18 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +#### options? + +[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> + +### Returns + +[`Atom`](../interfaces/Atom.md)\<`T`\> diff --git a/docs/framework/vue/reference/functions/createFormHook.md b/docs/framework/vue/reference/functions/createFormHook.md new file mode 100644 index 0000000000..c76e561a71 --- /dev/null +++ b/docs/framework/vue/reference/functions/createFormHook.md @@ -0,0 +1,36 @@ +--- +id: createFormHook +title: createFormHook +--- + +```ts +function createFormHook(createOptions): AppFormHookResult<{ + fieldComponents: TFieldComponents; + formComponents: TFormComponents; +}>; +``` + +Defined in: [packages/vue-form/src/AppForm/createFormHook.public.ts:14](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/createFormHook.public.ts#L14) + +## Type Parameters + +### TFormComponents + +`TFormComponents` *extends* `Record`\<`string`, `Component`\> + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +## Parameters + +### createOptions + +[`CreateFormHookOptions`](../interfaces/CreateFormHookOptions.md)\<`TFormComponents`, `TFieldComponents`\> + +## Returns + +[`AppFormHookResult`](../interfaces/AppFormHookResult.md)\<\{ + `fieldComponents`: `TFieldComponents`; + `formComponents`: `TFormComponents`; +\}\> diff --git a/docs/framework/vue/reference/functions/createStore.md b/docs/framework/vue/reference/functions/createStore.md new file mode 100644 index 0000000000..069cfed200 --- /dev/null +++ b/docs/framework/vue/reference/functions/createStore.md @@ -0,0 +1,84 @@ +--- +id: createStore +title: createStore +--- + +## Call Signature + +```ts +function createStore(getValue): ReadonlyStore; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:30 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### getValue + +(`prev?`) => `T` + +### Returns + +[`ReadonlyStore`](../classes/ReadonlyStore.md)\<`T`\> + +## Call Signature + +```ts +function createStore(initialValue): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:31 + +### Type Parameters + +#### T + +`T` + +### Parameters + +#### initialValue + +`T` + +### Returns + +[`Store`](../classes/Store.md)\<`T`\> + +## Call Signature + +```ts +function createStore(initialValue, actions): Store; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:32 + +### Type Parameters + +#### T + +`T` + +#### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) + +### Parameters + +#### initialValue + +`NonFunction`\<`T`\> + +#### actions + +[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> + +### Returns + +[`Store`](../classes/Store.md)\<`T`, `TActions`\> diff --git a/docs/framework/vue/reference/functions/flush.md b/docs/framework/vue/reference/functions/flush.md new file mode 100644 index 0000000000..a229192539 --- /dev/null +++ b/docs/framework/vue/reference/functions/flush.md @@ -0,0 +1,14 @@ +--- +id: flush +title: flush +--- + +```ts +function flush(): void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:6 + +## Returns + +`void` diff --git a/docs/framework/vue/reference/functions/getFormHookHelpers.md b/docs/framework/vue/reference/functions/getFormHookHelpers.md new file mode 100644 index 0000000000..2ee6e40f20 --- /dev/null +++ b/docs/framework/vue/reference/functions/getFormHookHelpers.md @@ -0,0 +1,14 @@ +--- +id: getFormHookHelpers +title: getFormHookHelpers +--- + +```ts +function getFormHookHelpers(): FormHookHelpers; +``` + +Defined in: [packages/vue-form/src/AppForm/getFormHookHelpers.public.ts:98](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/getFormHookHelpers.public.ts#L98) + +## Returns + +[`FormHookHelpers`](../interfaces/FormHookHelpers.md) diff --git a/docs/framework/vue/reference/functions/shallow.md b/docs/framework/vue/reference/functions/shallow.md new file mode 100644 index 0000000000..db1f393577 --- /dev/null +++ b/docs/framework/vue/reference/functions/shallow.md @@ -0,0 +1,30 @@ +--- +id: shallow +title: shallow +--- + +```ts +function shallow(objA, objB): boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/shallow.d.ts:2 + +## Type Parameters + +### T + +`T` + +## Parameters + +### objA + +`T` + +### objB + +`T` + +## Returns + +`boolean` diff --git a/docs/framework/vue/reference/functions/toObserver.md b/docs/framework/vue/reference/functions/toObserver.md new file mode 100644 index 0000000000..add0d3bbdf --- /dev/null +++ b/docs/framework/vue/reference/functions/toObserver.md @@ -0,0 +1,37 @@ +--- +id: toObserver +title: toObserver +--- + +```ts +function toObserver( + nextHandler?, + errorHandler?, +completionHandler?): Observer; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/atom.d.ts:4 + +## Type Parameters + +### T + +`T` + +## Parameters + +### nextHandler? + +[`Observer`](../type-aliases/Observer.md)\<`T`\> \| ((`value`) => `void`) + +### errorHandler? + +(`error`) => `void` + +### completionHandler? + +() => `void` + +## Returns + +[`Observer`](../type-aliases/Observer.md)\<`T`\> diff --git a/docs/framework/vue/reference/functions/useAtom.md b/docs/framework/vue/reference/functions/useAtom.md new file mode 100644 index 0000000000..4db6d6f9c9 --- /dev/null +++ b/docs/framework/vue/reference/functions/useAtom.md @@ -0,0 +1,44 @@ +--- +id: useAtom +title: useAtom +--- + +```ts +function useAtom(atom, options?): [Readonly>, (fn) => void & (value) => void]; +``` + +Defined in: node\_modules/.pnpm/@tanstack+vue-store@0.11.1\_vue@3.6.0-rc.9\_typescript@6.0.3\_/node\_modules/@tanstack/vue-store/dist/useAtom.d.ts:20 + +Returns the current atom ref together with a setter. + +Use this when a component needs to both read and update the same writable +atom. + +## Type Parameters + +### TValue + +`TValue` + +## Parameters + +### atom + +[`Atom`](../interfaces/Atom.md)\<`TValue`\> + +### options? + +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TValue`\> + +## Returns + +\[`Readonly`\<`Ref`\<`TValue`, `TValue`\>\>, (`fn`) => `void` & (`value`) => `void`\] + +## Example + +```ts +const [count, setCount] = useAtom(countAtom) + +setCount((prev) => prev + 1) +console.log(count.value) +``` diff --git a/docs/framework/vue/reference/functions/useField.md b/docs/framework/vue/reference/functions/useField.md deleted file mode 100644 index 4f18ba9d31..0000000000 --- a/docs/framework/vue/reference/functions/useField.md +++ /dev/null @@ -1,182 +0,0 @@ ---- -id: useField -title: useField ---- - -# Function: useField() - -```ts -function useField(opts): object; -``` - -Defined in: [packages/vue-form/src/useField.tsx:189](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useField.tsx#L189) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Parameters - -### opts - -`UseFieldOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Returns - -`object` - -### api - -```ts -readonly api: FieldApi = extendedFieldApi.value; -``` - -### state - -#### Get Signature - -```ts -get state(): object; -``` - -##### Returns - -`object` - -###### meta - -```ts -meta: object; -``` - -###### meta.errorMap - -```ts -errorMap: ValidationErrorMap, UnwrapFieldValidateOrFn, UnwrapFieldAsyncValidateOrFn, UnwrapFieldValidateOrFn, UnwrapFieldAsyncValidateOrFn, UnwrapFieldValidateOrFn, UnwrapFieldAsyncValidateOrFn, UnwrapFieldValidateOrFn, UnwrapFieldAsyncValidateOrFn, unknown>; -``` - -###### meta.errorSourceMap - -```ts -errorSourceMap: ValidationErrorMapSource; -``` - -###### meta.isBlurred - -```ts -isBlurred: boolean; -``` - -###### meta.isDirty - -```ts -isDirty: boolean; -``` - -###### meta.isTouched - -```ts -isTouched: boolean; -``` - -###### meta.isValidating - -```ts -isValidating: boolean; -``` - -###### value - -```ts -value: TData; -``` diff --git a/docs/framework/vue/reference/functions/useForm.md b/docs/framework/vue/reference/functions/useForm.md deleted file mode 100644 index 7e5d6dbb8f..0000000000 --- a/docs/framework/vue/reference/functions/useForm.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -id: useForm -title: useForm ---- - -# Function: useForm() - -```ts -function useForm(opts?): FormApi & VueFormApi; -``` - -Defined in: [packages/vue-form/src/useForm.tsx:243](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useForm.tsx#L243) - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` - -## Parameters - -### opts? - -`FormOptions`\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> - -## Returns - -`FormApi`\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> & [`VueFormApi`](../interfaces/VueFormApi.md)\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TSubmitMeta`\> diff --git a/docs/framework/vue/reference/functions/useFormGroup.md b/docs/framework/vue/reference/functions/useFormGroup.md deleted file mode 100644 index 730074a556..0000000000 --- a/docs/framework/vue/reference/functions/useFormGroup.md +++ /dev/null @@ -1,140 +0,0 @@ ---- -id: useFormGroup -title: useFormGroup ---- - -# Function: useFormGroup() - -```ts -function useFormGroup(opts): object; -``` - -Defined in: [packages/vue-form/src/useFormGroup.tsx:221](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useFormGroup.tsx#L221) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `string` - -### TData - -`TData` - -### TOnMount - -`TOnMount` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` - -### TFormOnMount - -`TFormOnMount` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChange - -`TFormOnChange` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlur - -`TFormOnBlur` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `FormValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TFormOnServer - -`TFormOnServer` *extends* `FormAsyncValidateOrFn`\<`TParentData`\> \| `undefined` - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Parameters - -### opts - -`FormGroupApiOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Returns - -`object` - -### api - -```ts -readonly api: FormGroupApi = formGroupApi; -``` - -### state - -```ts -readonly state: Readonly, FormGroupStoreState>> = groupState; -``` diff --git a/docs/framework/vue/reference/functions/useSelector.md b/docs/framework/vue/reference/functions/useSelector.md index 09dd5f1d8f..e7d09bf2ca 100644 --- a/docs/framework/vue/reference/functions/useSelector.md +++ b/docs/framework/vue/reference/functions/useSelector.md @@ -3,8 +3,6 @@ id: useSelector title: useSelector --- -# Function: useSelector() - ```ts function useSelector( source, @@ -12,7 +10,7 @@ function useSelector( options?): Readonly>; ``` -Defined in: node\_modules/.pnpm/@tanstack+vue-store@0.11.0\_vue@3.5.34\_typescript@5.9.3\_/node\_modules/@tanstack/vue-store/dist/useSelector.d.ts:33 +Defined in: node\_modules/.pnpm/@tanstack+vue-store@0.11.1\_vue@3.6.0-rc.9\_typescript@6.0.3\_/node\_modules/@tanstack/vue-store/dist/useSelector.d.ts:33 Selects a slice of state from an atom or store and subscribes the component to that selection. @@ -44,7 +42,7 @@ Omit the selector to subscribe to the whole value. ### options? -`UseSelectorOptions`\<`TSelected`\> +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TSelected`\> ## Returns diff --git a/docs/framework/vue/reference/functions/useStore.md b/docs/framework/vue/reference/functions/useStore.md new file mode 100644 index 0000000000..e4aac698b2 --- /dev/null +++ b/docs/framework/vue/reference/functions/useStore.md @@ -0,0 +1,63 @@ +--- +id: _useStore +title: _useStore +--- + +```ts +function _useStore( + store, + selector, + options?): [Readonly>, [TActions] extends [never] ? (updater) => void : TActions]; +``` + +Defined in: node\_modules/.pnpm/@tanstack+vue-store@0.11.1\_vue@3.6.0-rc.9\_typescript@6.0.3\_/node\_modules/@tanstack/vue-store/dist/\_useStore.d.ts:24 + +Experimental combined read+write hook for stores, mirroring useAtom's tuple +pattern. + +Returns `[selected, actions]` when the store has an actions factory, or +`[selected, setState]` for plain stores. + +## Type Parameters + +### TState + +`TState` + +### TActions + +`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) + +### TSelected + +`TSelected` = `NoInfer`\<`TState`\> + +## Parameters + +### store + +[`Store`](../classes/Store.md)\<`TState`, `TActions`\> + +### selector + +(`state`) => `TSelected` + +### options? + +[`UseSelectorOptions`](../interfaces/UseSelectorOptions.md)\<`TSelected`\> + +## Returns + +\[`Readonly`\<`Ref`\<`TSelected`, `TSelected`\>\>, \[`TActions`\] *extends* \[`never`\] ? (`updater`) => `void` : `TActions`\] + +## Example + +```ts +// Store with actions +const [cats, { addCat }] = _useStore(petStore, (s) => s.cats) +console.log(cats.value) + +// Store without actions +const [count, setState] = _useStore(plainStore, (s) => s) +setState((prev) => prev + 1) +``` diff --git a/docs/framework/vue/reference/index.md b/docs/framework/vue/reference/index.md index 299caca6bb..3b7a9ef265 100644 --- a/docs/framework/vue/reference/index.md +++ b/docs/framework/vue/reference/index.md @@ -3,32 +3,97 @@ id: "@tanstack/vue-form" title: "@tanstack/vue-form" --- -# @tanstack/vue-form +## Classes + +- [ReadonlyStore](classes/ReadonlyStore.md) +- [Store](classes/Store.md) ## Interfaces -- [VueFieldApi](interfaces/VueFieldApi.md) -- [VueFormApi](interfaces/VueFormApi.md) +- [AppFormHookResult](interfaces/AppFormHookResult.md) +- [Atom](interfaces/Atom.md) +- [AtomOptions](interfaces/AtomOptions.md) +- [BaseAtom](interfaces/BaseAtom.md) +- [CreateFormHookOptions](interfaces/CreateFormHookOptions.md) +- [FieldGroupApi](interfaces/FieldGroupApi.md) +- [FieldGroupDefinition](interfaces/FieldGroupDefinition.md) +- [FormHookHelpers](interfaces/FormHookHelpers.md) +- [InternalBaseAtom](interfaces/InternalBaseAtom.md) +- [InternalReadonlyAtom](interfaces/InternalReadonlyAtom.md) +- [InteropSubscribable](interfaces/InteropSubscribable.md) +- [Readable](interfaces/Readable.md) +- [ReadonlyAtom](interfaces/ReadonlyAtom.md) +- [Subscribable](interfaces/Subscribable.md) +- [SubscribeProps](interfaces/SubscribeProps.md) +- [Subscription](interfaces/Subscription.md) +- [UseSelectorOptions](interfaces/UseSelectorOptions.md) +- [VueFormComponentMap](interfaces/VueFormComponentMap.md) +- [VueFormFieldProps](interfaces/VueFormFieldProps.md) - [VueFormGroupApi](interfaces/VueFormGroupApi.md) +- [VueFormGroupProps](interfaces/VueFormGroupProps.md) +- [VueTanStackFormComponents](interfaces/VueTanStackFormComponents.md) ## Type Aliases -- [FieldComponent](type-aliases/FieldComponent.md) -- [FieldComponentBoundProps](type-aliases/FieldComponentBoundProps.md) -- [FieldComponentProps](type-aliases/FieldComponentProps.md) -- [FormGroupComponent](type-aliases/FormGroupComponent.md) -- [FormGroupComponentBoundProps](type-aliases/FormGroupComponentBoundProps.md) -- [FormGroupComponentProps](type-aliases/FormGroupComponentProps.md) +- [AnyAtom](type-aliases/AnyAtom.md) +- [AnyFieldGroupApi](type-aliases/AnyFieldGroupApi.md) +- [AnyVueFormApi](type-aliases/AnyVueFormApi.md) +- [AnyVueFormComponentMap](type-aliases/AnyVueFormComponentMap.md) +- [AppFormComponent](type-aliases/AppFormComponent.md) +- [DefaultVueFormComponentMap](type-aliases/DefaultVueFormComponentMap.md) +- [DefineFieldGroupFn](type-aliases/DefineFieldGroupFn.md) +- [FieldGroupArrayFieldComponent](type-aliases/FieldGroupArrayFieldComponent.md) +- [FieldGroupFieldBindingsOf](type-aliases/FieldGroupFieldBindingsOf.md) +- [FieldGroupFieldComponent](type-aliases/FieldGroupFieldComponent.md) +- [FieldGroupFieldComponentsOf](type-aliases/FieldGroupFieldComponentsOf.md) +- [FieldGroupFieldsOf](type-aliases/FieldGroupFieldsOf.md) +- [FieldGroupForm](type-aliases/FieldGroupForm.md) +- [FieldGroupFormState](type-aliases/FieldGroupFormState.md) +- [FieldGroupSubscribeComponent](type-aliases/FieldGroupSubscribeComponent.md) +- [FieldGroupSubscribeProps](type-aliases/FieldGroupSubscribeProps.md) +- [FieldGroupWithFieldsFn](type-aliases/FieldGroupWithFieldsFn.md) +- [Observer](type-aliases/Observer.md) +- [Selection](type-aliases/Selection.md) +- [StoreAction](type-aliases/StoreAction.md) +- [StoreActionMap](type-aliases/StoreActionMap.md) +- [StoreActionsFactory](type-aliases/StoreActionsFactory.md) +- [SubscribeComponent](type-aliases/SubscribeComponent.md) +- [SubscribeSource](type-aliases/SubscribeSource.md) +- [UseAppFormHook](type-aliases/UseAppFormHook.md) +- [UseFormHook](type-aliases/UseFormHook.md) +- [VueAppFormApi](type-aliases/VueAppFormApi.md) +- [VueFieldApi](type-aliases/VueFieldApi.md) +- [VueFieldGroup](type-aliases/VueFieldGroup.md) +- [VueFormApi](type-aliases/VueFormApi.md) +- [VueFormArrayFieldComponent](type-aliases/VueFormArrayFieldComponent.md) +- [VueFormFieldComponent](type-aliases/VueFormFieldComponent.md) +- [VueFormGroupArrayFieldComponent](type-aliases/VueFormGroupArrayFieldComponent.md) +- [VueFormGroupComponent](type-aliases/VueFormGroupComponent.md) +- [VueFormGroupFieldComponent](type-aliases/VueFormGroupFieldComponent.md) +- [VueFormGroupSubscribeComponent](type-aliases/VueFormGroupSubscribeComponent.md) +- [VueFormGroupSubscribeProps](type-aliases/VueFormGroupSubscribeProps.md) +- [VueFormSubscribeComponent](type-aliases/VueFormSubscribeComponent.md) +- [VueFormSubscribeProps](type-aliases/VueFormSubscribeProps.md) +- [VueFormType](type-aliases/VueFormType.md) ## Variables -- [Field](variables/Field.md) -- [FormGroup](variables/FormGroup.md) +- [defineFieldGroup](variables/defineFieldGroup.md) +- [Subscribe](variables/Subscribe.md) +- [useForm](variables/useForm.md) - [~~useStore~~](variables/useStore.md) ## Functions -- [useField](functions/useField.md) -- [useForm](functions/useForm.md) -- [useFormGroup](functions/useFormGroup.md) +- [\_useStore](functions/useStore.md) +- [batch](functions/batch.md) +- [createAsyncAtom](functions/createAsyncAtom.md) +- [createAtom](functions/createAtom.md) +- [createFormHook](functions/createFormHook.md) +- [createStore](functions/createStore.md) +- [flush](functions/flush.md) +- [getFormHookHelpers](functions/getFormHookHelpers.md) +- [shallow](functions/shallow.md) +- [toObserver](functions/toObserver.md) +- [useAtom](functions/useAtom.md) - [useSelector](functions/useSelector.md) diff --git a/docs/framework/vue/reference/interfaces/AppFormHookResult.md b/docs/framework/vue/reference/interfaces/AppFormHookResult.md new file mode 100644 index 0000000000..303df240be --- /dev/null +++ b/docs/framework/vue/reference/interfaces/AppFormHookResult.md @@ -0,0 +1,56 @@ +--- +id: AppFormHookResult +title: AppFormHookResult +--- + +Defined in: [packages/vue-form/src/AppForm/createFormHookTypes.public.ts:110](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/createFormHookTypes.public.ts#L110) + +## Type Parameters + +### TComponents + +`TComponents` *extends* [`AnyVueFormComponentMap`](../type-aliases/AnyVueFormComponentMap.md) + +## Properties + +### appFormOptions + +```ts +appFormOptions: FormOptionsApi; +``` + +Defined in: [packages/vue-form/src/AppForm/createFormHookTypes.public.ts:111](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/createFormHookTypes.public.ts#L111) + +*** + +### defineAppFieldGroup + +```ts +defineAppFieldGroup: DefineFieldGroupFn; +``` + +Defined in: [packages/vue-form/src/AppForm/createFormHookTypes.public.ts:112](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/createFormHookTypes.public.ts#L112) + +*** + +### useAppForm + +```ts +useAppForm: UseAppFormHook; +``` + +Defined in: [packages/vue-form/src/AppForm/createFormHookTypes.public.ts:113](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/createFormHookTypes.public.ts#L113) + +*** + +### useFormContext + +```ts +useFormContext: () => VueAppFormApi; +``` + +Defined in: [packages/vue-form/src/AppForm/createFormHookTypes.public.ts:114](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/createFormHookTypes.public.ts#L114) + +#### Returns + +[`VueAppFormApi`](../type-aliases/VueAppFormApi.md)\<`any`, `any`, `TComponents`\> diff --git a/docs/framework/vue/reference/interfaces/Atom.md b/docs/framework/vue/reference/interfaces/Atom.md new file mode 100644 index 0000000000..e536822283 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/Atom.md @@ -0,0 +1,60 @@ +--- +id: Atom +title: Atom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:29 + +## Extends + +- [`BaseAtom`](BaseAtom.md)\<`T`\> + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`get`](BaseAtom.md#get) + +*** + +### set + +```ts +set: (fn) => void & (value) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:31 + +Sets the value of the atom using a function. + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`subscribe`](BaseAtom.md#subscribe) diff --git a/docs/framework/vue/reference/interfaces/AtomOptions.md b/docs/framework/vue/reference/interfaces/AtomOptions.md new file mode 100644 index 0000000000..84f594c6e0 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/AtomOptions.md @@ -0,0 +1,36 @@ +--- +id: AtomOptions +title: AtomOptions +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:33 + +## Type Parameters + +### T + +`T` + +## Properties + +### compare? + +```ts +optional compare?: (prev, next) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:34 + +#### Parameters + +##### prev + +`T` + +##### next + +`T` + +#### Returns + +`boolean` diff --git a/docs/framework/vue/reference/interfaces/BaseAtom.md b/docs/framework/vue/reference/interfaces/BaseAtom.md new file mode 100644 index 0000000000..fc0695a37a --- /dev/null +++ b/docs/framework/vue/reference/interfaces/BaseAtom.md @@ -0,0 +1,53 @@ +--- +id: BaseAtom +title: BaseAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:22 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\>.[`Readable`](Readable.md)\<`T`\> + +## Extended by + +- [`Atom`](Atom.md) +- [`ReadonlyAtom`](ReadonlyAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`Readable`](Readable.md).[`get`](Readable.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/vue/reference/interfaces/CreateFormHookOptions.md b/docs/framework/vue/reference/interfaces/CreateFormHookOptions.md new file mode 100644 index 0000000000..e766cf7467 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/CreateFormHookOptions.md @@ -0,0 +1,150 @@ +--- +id: CreateFormHookOptions +title: CreateFormHookOptions +--- + +Defined in: [packages/vue-form/src/AppForm/createFormHookTypes.public.ts:46](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/createFormHookTypes.public.ts#L46) + +Configures the components and reusable defaults returned by +`createFormHook`. + +Form core resolves each default object before the corresponding usage-site +options. Non-listener properties passed at the usage site take precedence, +including when explicitly set to `undefined`. Listener arrays follow the +configured `listenersMerge` strategy. + +## Example + +```ts +const { useAppForm } = createFormHook({ + formComponents: {}, + fieldComponents: { + TextField, + }, + defaultFormOptions: { + errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred, + }, + defaultFieldOptions: { + errorBoundary: true, + }, +}) +``` + +## Extends + +- [`VueFormComponentMap`](VueFormComponentMap.md)\<`TFormComponents`, `TFieldComponents`\> + +## Type Parameters + +### TFormComponents + +`TFormComponents` *extends* `Record`\<`string`, `Component`\> + +Library-managed. Do not specify explicitly. + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +Library-managed. Do not specify explicitly. + +## Properties + +### defaultFieldOptions? + +```ts +optional defaultFieldOptions?: DefaultFieldOptions; +``` + +Defined in: [packages/vue-form/src/AppForm/createFormHookTypes.public.ts:79](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/createFormHookTypes.public.ts#L79) + +Defaults for every field and array-field component owned by the form. + +Non-listener options passed to the component override these defaults, +including when explicitly set to `undefined`. Listener arrays follow +`listenersMerge`. This includes `group.Field` and `group.ArrayField`. + +#### Example + +```ts +defaultFieldOptions: { + errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred, +}, +``` + +*** + +### defaultFormGroupOptions? + +```ts +optional defaultFormGroupOptions?: DefaultFormGroupOptions; +``` + +Defined in: [packages/vue-form/src/AppForm/createFormHookTypes.public.ts:95](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/createFormHookTypes.public.ts#L95) + +Defaults for every `form.FormGroup` component. + +Options passed to the component override these defaults, including when +an option is explicitly `undefined`. + +#### Example + +```ts +defaultFormGroupOptions: { + onSubmitInvalid: ({ groupApi }) => { + console.error('Invalid group', groupApi.name) + }, +}, +``` + +*** + +### defaultFormOptions? + +```ts +optional defaultFormOptions?: DefaultFormOptions; +``` + +Defined in: [packages/vue-form/src/AppForm/createFormHookTypes.public.ts:64](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/createFormHookTypes.public.ts#L64) + +Defaults for every form created by `useAppForm`. + +Non-listener options passed to `useAppForm` override these defaults, +including when explicitly set to `undefined`. Listener arrays follow +`listenersMerge`. + +#### Example + +```ts +defaultFormOptions: { + errorVisibility: ({ state }) => state.submissionAttempts > 0, +}, +``` + +*** + +### fieldComponents + +```ts +fieldComponents: TFieldComponents; +``` + +Defined in: [packages/vue-form/src/AppForm/componentMap.public.ts:8](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/componentMap.public.ts#L8) + +#### Inherited from + +[`VueFormComponentMap`](VueFormComponentMap.md).[`fieldComponents`](VueFormComponentMap.md#fieldcomponents) + +*** + +### formComponents + +```ts +formComponents: TFormComponents; +``` + +Defined in: [packages/vue-form/src/AppForm/componentMap.public.ts:7](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/componentMap.public.ts#L7) + +#### Inherited from + +[`VueFormComponentMap`](VueFormComponentMap.md).[`formComponents`](VueFormComponentMap.md#formcomponents) diff --git a/docs/framework/vue/reference/interfaces/FieldGroupApi.md b/docs/framework/vue/reference/interfaces/FieldGroupApi.md new file mode 100644 index 0000000000..9b82cd0ff1 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/FieldGroupApi.md @@ -0,0 +1,60 @@ +--- +id: FieldGroupApi +title: FieldGroupApi +--- + +Defined in: [packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts:133](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts#L133) + +## Extends + +- `FormApiFieldMethods`\<`TFieldData`\>.`FormApiArrayMethods`\<`TFieldData`\> + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> = `Record`\<`never`, `never`\> + +## Properties + +### ArrayField + +```ts +ArrayField: FieldGroupArrayFieldComponent; +``` + +Defined in: [packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts:143](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts#L143) + +*** + +### atom + +```ts +atom: ReadonlyAtom; +``` + +Defined in: [packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts:141](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts#L141) + +*** + +### Field + +```ts +Field: FieldGroupFieldComponent; +``` + +Defined in: [packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts:142](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts#L142) + +*** + +### Subscribe + +```ts +Subscribe: FieldGroupSubscribeComponent; +``` + +Defined in: [packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts:144](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts#L144) diff --git a/docs/framework/vue/reference/interfaces/FieldGroupDefinition.md b/docs/framework/vue/reference/interfaces/FieldGroupDefinition.md new file mode 100644 index 0000000000..b123e322db --- /dev/null +++ b/docs/framework/vue/reference/interfaces/FieldGroupDefinition.md @@ -0,0 +1,40 @@ +--- +id: FieldGroupDefinition +title: FieldGroupDefinition +--- + +Defined in: [packages/vue-form/src/FieldGroup/withFields.public.ts:95](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/withFields.public.ts#L95) + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +## Properties + +### bindComponent + +```ts +bindComponent: FieldGroupWithFieldsFn>; +``` + +Defined in: [packages/vue-form/src/FieldGroup/withFields.public.ts:102](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/withFields.public.ts#L102) + +Binds a component's virtual field API to concrete paths in a form. + +*** + +### fields + +```ts +fields: VueFieldGroup; +``` + +Defined in: [packages/vue-form/src/FieldGroup/withFields.public.ts:100](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/withFields.public.ts#L100) + +The virtual field-group API injected into the bound component. diff --git a/docs/framework/vue/reference/interfaces/FormHookHelpers.md b/docs/framework/vue/reference/interfaces/FormHookHelpers.md new file mode 100644 index 0000000000..b8c91923b7 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/FormHookHelpers.md @@ -0,0 +1,26 @@ +--- +id: FormHookHelpers +title: FormHookHelpers +--- + +Defined in: [packages/vue-form/src/AppForm/getFormHookHelpers.public.ts:93](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/getFormHookHelpers.public.ts#L93) + +## Properties + +### fieldBrand + +```ts +fieldBrand: FieldBrandHelper; +``` + +Defined in: [packages/vue-form/src/AppForm/getFormHookHelpers.public.ts:94](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/getFormHookHelpers.public.ts#L94) + +*** + +### fieldComponent + +```ts +fieldComponent: FieldComponentHelper; +``` + +Defined in: [packages/vue-form/src/AppForm/getFormHookHelpers.public.ts:95](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/getFormHookHelpers.public.ts#L95) diff --git a/docs/framework/vue/reference/interfaces/InternalBaseAtom.md b/docs/framework/vue/reference/interfaces/InternalBaseAtom.md new file mode 100644 index 0000000000..f73167d4a2 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/InternalBaseAtom.md @@ -0,0 +1,86 @@ +--- +id: InternalBaseAtom +title: InternalBaseAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:23 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\>.[`Readable`](Readable.md)\<`T`\> + +## Extended by + +- [`InternalReadonlyAtom`](InternalReadonlyAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### \_snapshot + +```ts +_snapshot: T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:25 + +**`Internal`** + +*** + +### \_update + +```ts +_update: (getValue?) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:27 + +**`Internal`** + +#### Parameters + +##### getValue? + +`T` \| ((`snapshot`) => `T`) + +#### Returns + +`boolean` + +*** + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`Readable`](Readable.md).[`get`](Readable.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/vue/reference/interfaces/InternalReadonlyAtom.md b/docs/framework/vue/reference/interfaces/InternalReadonlyAtom.md new file mode 100644 index 0000000000..ac5a197160 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/InternalReadonlyAtom.md @@ -0,0 +1,170 @@ +--- +id: InternalReadonlyAtom +title: InternalReadonlyAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:37 + +## Extends + +- [`InternalBaseAtom`](InternalBaseAtom.md)\<`T`\>.`ReactiveNode` + +## Type Parameters + +### T + +`T` + +## Properties + +### \_snapshot + +```ts +_snapshot: T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:25 + +**`Internal`** + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`_snapshot`](InternalBaseAtom.md#_snapshot) + +*** + +### \_update + +```ts +_update: (getValue?) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:27 + +**`Internal`** + +#### Parameters + +##### getValue? + +`T` \| ((`snapshot`) => `T`) + +#### Returns + +`boolean` + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`_update`](InternalBaseAtom.md#_update) + +*** + +### deps? + +```ts +optional deps?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:3 + +#### Inherited from + +```ts +ReactiveNode.deps +``` + +*** + +### depsTail? + +```ts +optional depsTail?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:4 + +#### Inherited from + +```ts +ReactiveNode.depsTail +``` + +*** + +### flags + +```ts +flags: number; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:7 + +#### Inherited from + +```ts +ReactiveNode.flags +``` + +*** + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`get`](InternalBaseAtom.md#get) + +*** + +### subs? + +```ts +optional subs?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:5 + +#### Inherited from + +```ts +ReactiveNode.subs +``` + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`InternalBaseAtom`](InternalBaseAtom.md).[`subscribe`](InternalBaseAtom.md#subscribe) + +*** + +### subsTail? + +```ts +optional subsTail?: Link; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/alien.d.ts:6 + +#### Inherited from + +```ts +ReactiveNode.subsTail +``` diff --git a/docs/framework/vue/reference/interfaces/InteropSubscribable.md b/docs/framework/vue/reference/interfaces/InteropSubscribable.md new file mode 100644 index 0000000000..7a0c023915 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/InteropSubscribable.md @@ -0,0 +1,36 @@ +--- +id: InteropSubscribable +title: InteropSubscribable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:5 + +## Extended by + +- [`Subscribable`](Subscribable.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### subscribe + +```ts +subscribe: (observer) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:6 + +#### Parameters + +##### observer + +[`Observer`](../type-aliases/Observer.md)\<`T`\> + +#### Returns + +[`Subscription`](Subscription.md) diff --git a/docs/framework/vue/reference/interfaces/Readable.md b/docs/framework/vue/reference/interfaces/Readable.md new file mode 100644 index 0000000000..ff2095ebfe --- /dev/null +++ b/docs/framework/vue/reference/interfaces/Readable.md @@ -0,0 +1,49 @@ +--- +id: Readable +title: Readable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:19 + +## Extends + +- [`Subscribable`](Subscribable.md)\<`T`\> + +## Extended by + +- [`BaseAtom`](BaseAtom.md) +- [`InternalBaseAtom`](InternalBaseAtom.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/framework/vue/reference/interfaces/ReadonlyAtom.md b/docs/framework/vue/reference/interfaces/ReadonlyAtom.md new file mode 100644 index 0000000000..bbc1e1d9c3 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/ReadonlyAtom.md @@ -0,0 +1,58 @@ +--- +id: ReadonlyAtom +title: ReadonlyAtom +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:49 + +An atom that is read-only and cannot be set. + +## Example + +```ts +const atom = createAtom(() => 42); +// @ts-expect-error - Cannot set a readonly atom +atom.set(43); +``` + +## Extends + +- [`BaseAtom`](BaseAtom.md)\<`T`\> + +## Type Parameters + +### T + +`T` + +## Properties + +### get + +```ts +get: () => T; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:20 + +#### Returns + +`T` + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`get`](BaseAtom.md#get) + +*** + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Inherited from + +[`BaseAtom`](BaseAtom.md).[`subscribe`](BaseAtom.md#subscribe) diff --git a/docs/framework/vue/reference/interfaces/Subscribable.md b/docs/framework/vue/reference/interfaces/Subscribable.md new file mode 100644 index 0000000000..a11bf60b2a --- /dev/null +++ b/docs/framework/vue/reference/interfaces/Subscribable.md @@ -0,0 +1,36 @@ +--- +id: Subscribable +title: Subscribable +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:16 + +## Extends + +- [`InteropSubscribable`](InteropSubscribable.md)\<`T`\> + +## Extended by + +- [`BaseAtom`](BaseAtom.md) +- [`InternalBaseAtom`](InternalBaseAtom.md) +- [`Readable`](Readable.md) + +## Type Parameters + +### T + +`T` + +## Properties + +### subscribe + +```ts +subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:17 + +#### Overrides + +[`InteropSubscribable`](InteropSubscribable.md).[`subscribe`](InteropSubscribable.md#subscribe) diff --git a/docs/framework/vue/reference/interfaces/SubscribeProps.md b/docs/framework/vue/reference/interfaces/SubscribeProps.md new file mode 100644 index 0000000000..284421ec02 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/SubscribeProps.md @@ -0,0 +1,66 @@ +--- +id: SubscribeProps +title: SubscribeProps +--- + +Defined in: [packages/vue-form/src/Subscribe.public.ts:14](https://github.com/TanStack/form/blob/main/packages/vue-form/src/Subscribe.public.ts#L14) + +## Type Parameters + +### TSourceData + +`TSourceData` + +### TSelected + +`TSelected` + +## Properties + +### selector + +```ts +selector: (state) => TSelected; +``` + +Defined in: [packages/vue-form/src/Subscribe.public.ts:16](https://github.com/TanStack/form/blob/main/packages/vue-form/src/Subscribe.public.ts#L16) + +#### Parameters + +##### state + +`TSourceData` + +#### Returns + +`TSelected` + +*** + +### source + +```ts +source: SubscribeSource; +``` + +Defined in: [packages/vue-form/src/Subscribe.public.ts:15](https://github.com/TanStack/form/blob/main/packages/vue-form/src/Subscribe.public.ts#L15) + +*** + +### when? + +```ts +optional when?: (selected) => boolean; +``` + +Defined in: [packages/vue-form/src/Subscribe.public.ts:17](https://github.com/TanStack/form/blob/main/packages/vue-form/src/Subscribe.public.ts#L17) + +#### Parameters + +##### selected + +`NoInfer`\<`TSelected`\> + +#### Returns + +`boolean` diff --git a/docs/framework/vue/reference/interfaces/Subscription.md b/docs/framework/vue/reference/interfaces/Subscription.md new file mode 100644 index 0000000000..fab2f285ee --- /dev/null +++ b/docs/framework/vue/reference/interfaces/Subscription.md @@ -0,0 +1,20 @@ +--- +id: Subscription +title: Subscription +--- + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:13 + +## Properties + +### unsubscribe + +```ts +unsubscribe: () => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:14 + +#### Returns + +`void` diff --git a/docs/framework/vue/reference/interfaces/UseSelectorOptions.md b/docs/framework/vue/reference/interfaces/UseSelectorOptions.md new file mode 100644 index 0000000000..ef376148d5 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/UseSelectorOptions.md @@ -0,0 +1,36 @@ +--- +id: UseSelectorOptions +title: UseSelectorOptions +--- + +Defined in: node\_modules/.pnpm/@tanstack+vue-store@0.11.1\_vue@3.6.0-rc.9\_typescript@6.0.3\_/node\_modules/@tanstack/vue-store/dist/useSelector.d.ts:4 + +## Type Parameters + +### TSelected + +`TSelected` + +## Properties + +### compare? + +```ts +optional compare?: (a, b) => boolean; +``` + +Defined in: node\_modules/.pnpm/@tanstack+vue-store@0.11.1\_vue@3.6.0-rc.9\_typescript@6.0.3\_/node\_modules/@tanstack/vue-store/dist/useSelector.d.ts:5 + +#### Parameters + +##### a + +`TSelected` + +##### b + +`TSelected` + +#### Returns + +`boolean` diff --git a/docs/framework/vue/reference/interfaces/VueFieldApi.md b/docs/framework/vue/reference/interfaces/VueFieldApi.md deleted file mode 100644 index b41b59aff3..0000000000 --- a/docs/framework/vue/reference/interfaces/VueFieldApi.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -id: VueFieldApi -title: VueFieldApi ---- - -# Interface: VueFieldApi\ - -Defined in: [packages/vue-form/src/useField.tsx:159](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useField.tsx#L159) - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Properties - -### Field - -```ts -Field: FieldComponent; -``` - -Defined in: [packages/vue-form/src/useField.tsx:173](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useField.tsx#L173) diff --git a/docs/framework/vue/reference/interfaces/VueFormApi.md b/docs/framework/vue/reference/interfaces/VueFormApi.md deleted file mode 100644 index fad8c6a51a..0000000000 --- a/docs/framework/vue/reference/interfaces/VueFormApi.md +++ /dev/null @@ -1,144 +0,0 @@ ---- -id: VueFormApi -title: VueFormApi ---- - -# Interface: VueFormApi\ - -Defined in: [packages/vue-form/src/useForm.tsx:113](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useForm.tsx#L113) - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TSubmitMeta - -`TSubmitMeta` - -## Properties - -### Field - -```ts -Field: FieldComponent; -``` - -Defined in: [packages/vue-form/src/useForm.tsx:127](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useForm.tsx#L127) - -*** - -### FormGroup - -```ts -FormGroup: FormGroupComponent; -``` - -Defined in: [packages/vue-form/src/useForm.tsx:141](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useForm.tsx#L141) - -*** - -### Subscribe - -```ts -Subscribe: SubscribeComponent; -``` - -Defined in: [packages/vue-form/src/useForm.tsx:228](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useForm.tsx#L228) - -*** - -### useSelector() - -```ts -useSelector: (selector?) => Readonly>; -``` - -Defined in: [packages/vue-form/src/useForm.tsx:155](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useForm.tsx#L155) - -#### Type Parameters - -##### TSelected - -`TSelected` = `NoInfer`\<`FormState`\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`\>\> - -#### Parameters - -##### selector? - -(`state`) => `TSelected` - -#### Returns - -`Readonly`\<`Ref`\<`TSelected`\>\> - -*** - -### ~~useStore()~~ - -```ts -useStore: (selector?) => Readonly>; -``` - -Defined in: [packages/vue-form/src/useForm.tsx:193](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useForm.tsx#L193) - -#### Type Parameters - -##### TSelected - -`TSelected` = `NoInfer`\<`FormState`\<`TParentData`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`\>\> - -#### Parameters - -##### selector? - -(`state`) => `TSelected` - -#### Returns - -`Readonly`\<`Ref`\<`TSelected`\>\> - -#### Deprecated - -Use `form.useSelector` instead. diff --git a/docs/framework/vue/reference/interfaces/VueFormComponentMap.md b/docs/framework/vue/reference/interfaces/VueFormComponentMap.md new file mode 100644 index 0000000000..9e8ff0a97f --- /dev/null +++ b/docs/framework/vue/reference/interfaces/VueFormComponentMap.md @@ -0,0 +1,40 @@ +--- +id: VueFormComponentMap +title: VueFormComponentMap +--- + +Defined in: [packages/vue-form/src/AppForm/componentMap.public.ts:3](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/componentMap.public.ts#L3) + +## Extended by + +- [`CreateFormHookOptions`](CreateFormHookOptions.md) + +## Type Parameters + +### TFormComponents + +`TFormComponents` *extends* `Record`\<`string`, `Component`\> + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +## Properties + +### fieldComponents + +```ts +fieldComponents: TFieldComponents; +``` + +Defined in: [packages/vue-form/src/AppForm/componentMap.public.ts:8](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/componentMap.public.ts#L8) + +*** + +### formComponents + +```ts +formComponents: TFormComponents; +``` + +Defined in: [packages/vue-form/src/AppForm/componentMap.public.ts:7](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/componentMap.public.ts#L7) diff --git a/docs/framework/vue/reference/interfaces/VueFormFieldProps.md b/docs/framework/vue/reference/interfaces/VueFormFieldProps.md new file mode 100644 index 0000000000..a29e7b4bf3 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/VueFormFieldProps.md @@ -0,0 +1,54 @@ +--- +id: VueFormFieldProps +title: VueFormFieldProps +--- + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:97](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L97) + +## Extends + +- `FieldApiOptions`\<`TFieldData`, `TFieldName`, `TFieldValue`, `TFieldValidators`, `TGroupFieldError`, `TFormData`, `TFormErrorTypes`\> + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldName + +`TFieldName` + +### TFieldValue + +`TFieldValue` + +### TFieldValidators + +`TFieldValidators` *extends* `FieldValidators`\<`TFieldData`, `TFieldName`, `TFieldValue`\> + +### TGroupFieldError + +`TGroupFieldError` + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +## Properties + +### \[fieldComponentsType\]? + +```ts +readonly optional [fieldComponentsType]?: TFieldComponents; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:119](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L119) diff --git a/docs/framework/vue/reference/interfaces/VueFormGroupApi.md b/docs/framework/vue/reference/interfaces/VueFormGroupApi.md index 00cb41e258..d29cf66674 100644 --- a/docs/framework/vue/reference/interfaces/VueFormGroupApi.md +++ b/docs/framework/vue/reference/interfaces/VueFormGroupApi.md @@ -3,66 +3,64 @@ id: VueFormGroupApi title: VueFormGroupApi --- -# Interface: VueFormGroupApi\ +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:343](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L343) -Defined in: [packages/vue-form/src/useFormGroup.tsx:191](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useFormGroup.tsx#L191) +## Extends -## Type Parameters - -### TParentData - -`TParentData` +- `FormGroupApi`\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupErrorTypes`, `TFormErrorTypes`\> -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +## Type Parameters -### TFormOnChange +### TFormData -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +`TFormData` -### TFormOnChangeAsync +### TGroupName -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +`TGroupName` -### TFormOnBlur +### TGroupValue -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +`TGroupValue` -### TFormOnBlurAsync +### TGroupErrorTypes -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +`TGroupErrorTypes` *extends* `FormErrorTypes` -### TFormOnSubmit +### TFormErrorTypes -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +`TFormErrorTypes` *extends* `FormErrorTypes` -### TFormOnSubmitAsync +### TFieldComponents -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> -### TFormOnDynamic +## Properties -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +### ArrayField -### TFormOnDynamicAsync +```ts +ArrayField: VueFormGroupArrayFieldComponent; +``` -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:364](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L364) -### TFormOnServer +*** -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +### Field -### TParentSubmitMeta +```ts +Field: VueFormGroupFieldComponent; +``` -`TParentSubmitMeta` +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:357](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L357) -## Properties +*** -### FormGroup +### Subscribe ```ts -FormGroup: FormGroupComponent; +Subscribe: VueFormGroupSubscribeComponent; ``` -Defined in: [packages/vue-form/src/useFormGroup.tsx:205](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useFormGroup.tsx#L205) +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:371](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L371) diff --git a/docs/framework/vue/reference/interfaces/VueFormGroupProps.md b/docs/framework/vue/reference/interfaces/VueFormGroupProps.md new file mode 100644 index 0000000000..13fe41be65 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/VueFormGroupProps.md @@ -0,0 +1,46 @@ +--- +id: VueFormGroupProps +title: VueFormGroupProps +--- + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:374](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L374) + +## Extends + +- `Omit`\<`FormGroupOptions`\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupValidators`, `TFormErrorTypes`\>, `"form"`\> + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupValidators + +`TGroupValidators` *extends* `FormGroupValidators`\<`TGroupValue`\> + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +## Properties + +### \[fieldComponentsType\]? + +```ts +readonly optional [fieldComponentsType]?: TFieldComponents; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:391](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L391) diff --git a/docs/framework/vue/reference/interfaces/VueTanStackFormComponents.md b/docs/framework/vue/reference/interfaces/VueTanStackFormComponents.md new file mode 100644 index 0000000000..f9526cb859 --- /dev/null +++ b/docs/framework/vue/reference/interfaces/VueTanStackFormComponents.md @@ -0,0 +1,60 @@ +--- +id: VueTanStackFormComponents +title: VueTanStackFormComponents +--- + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:435](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L435) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> = `Record`\<`never`, `never`\> + +## Properties + +### ArrayField + +```ts +ArrayField: VueFormArrayFieldComponent; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:444](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L444) + +*** + +### Field + +```ts +Field: VueFormFieldComponent; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:443](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L443) + +*** + +### FormGroup + +```ts +FormGroup: VueFormGroupComponent; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:450](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L450) + +*** + +### Subscribe + +```ts +Subscribe: VueFormSubscribeComponent; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:449](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L449) diff --git a/docs/framework/vue/reference/type-aliases/AnyAtom.md b/docs/framework/vue/reference/type-aliases/AnyAtom.md new file mode 100644 index 0000000000..6491b16950 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/AnyAtom.md @@ -0,0 +1,10 @@ +--- +id: AnyAtom +title: AnyAtom +--- + +```ts +type AnyAtom = BaseAtom; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:36 diff --git a/docs/framework/vue/reference/type-aliases/AnyFieldGroupApi.md b/docs/framework/vue/reference/type-aliases/AnyFieldGroupApi.md new file mode 100644 index 0000000000..a864520f7c --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/AnyFieldGroupApi.md @@ -0,0 +1,10 @@ +--- +id: AnyFieldGroupApi +title: AnyFieldGroupApi +--- + +```ts +type AnyFieldGroupApi = FieldGroupApi>; +``` + +Defined in: [packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts:147](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts#L147) diff --git a/docs/framework/vue/reference/type-aliases/AnyVueFormApi.md b/docs/framework/vue/reference/type-aliases/AnyVueFormApi.md new file mode 100644 index 0000000000..e37433f3d0 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/AnyVueFormApi.md @@ -0,0 +1,36 @@ +--- +id: AnyVueFormApi +title: AnyVueFormApi +--- + +```ts +type AnyVueFormApi = AnyFormApi & VueTanStackFormComponents; +``` + +Defined in: [packages/vue-form/src/VueForm/formApiTypes.public.ts:55](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/formApiTypes.public.ts#L55) + +A Vue form API whose form data and error types are erased. + +Use it for reusable Vue components that only need core form operations and +the `Field`, `ArrayField`, `Subscribe`, or `FormGroup` components common to +every Vue form. Field paths and values are not checked against a particular +form shape; use `VueFormType` when a component depends on one known form. + +## Example + +```vue + + + +``` diff --git a/docs/framework/vue/reference/type-aliases/AnyVueFormComponentMap.md b/docs/framework/vue/reference/type-aliases/AnyVueFormComponentMap.md new file mode 100644 index 0000000000..a2c10b1425 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/AnyVueFormComponentMap.md @@ -0,0 +1,10 @@ +--- +id: AnyVueFormComponentMap +title: AnyVueFormComponentMap +--- + +```ts +type AnyVueFormComponentMap = VueFormComponentMap, Record>; +``` + +Defined in: [packages/vue-form/src/AppForm/componentMap.public.ts:11](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/componentMap.public.ts#L11) diff --git a/docs/framework/vue/reference/type-aliases/AppFormComponent.md b/docs/framework/vue/reference/type-aliases/AppFormComponent.md new file mode 100644 index 0000000000..fd75acb025 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/AppFormComponent.md @@ -0,0 +1,28 @@ +--- +id: AppFormComponent +title: AppFormComponent +--- + +```ts +type AppFormComponent = (props) => VueComponentInstance<{ +}, { + default: { + }; +}>; +``` + +Defined in: [packages/vue-form/src/AppForm/VueAppFormApi.public.ts:7](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/VueAppFormApi.public.ts#L7) + +## Parameters + +### props + +`PublicProps` + +## Returns + +`VueComponentInstance`\<\{ +\}, \{ + `default`: \{ + \}; +\}\> diff --git a/docs/framework/vue/reference/type-aliases/DefaultVueFormComponentMap.md b/docs/framework/vue/reference/type-aliases/DefaultVueFormComponentMap.md new file mode 100644 index 0000000000..f60e75eb4a --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/DefaultVueFormComponentMap.md @@ -0,0 +1,10 @@ +--- +id: DefaultVueFormComponentMap +title: DefaultVueFormComponentMap +--- + +```ts +type DefaultVueFormComponentMap = VueFormComponentMap, Record>; +``` + +Defined in: [packages/vue-form/src/AppForm/componentMap.public.ts:16](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/componentMap.public.ts#L16) diff --git a/docs/framework/vue/reference/type-aliases/DefineFieldGroupFn.md b/docs/framework/vue/reference/type-aliases/DefineFieldGroupFn.md new file mode 100644 index 0000000000..3c5a5b18f4 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/DefineFieldGroupFn.md @@ -0,0 +1,34 @@ +--- +id: DefineFieldGroupFn +title: DefineFieldGroupFn +--- + +```ts +type DefineFieldGroupFn = (defineFn) => FieldGroupDefinition; +``` + +Defined in: [packages/vue-form/src/FieldGroup/withFields.public.ts:108](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/withFields.public.ts#L108) + +Signature shared by `defineFieldGroup` and app-form field-group definers. + +## Type Parameters + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +## Parameters + +### defineFn + +(`helper`) => `TFields` + +## Returns + +[`FieldGroupDefinition`](../interfaces/FieldGroupDefinition.md)\<`TFields`, `TFieldComponents`\> diff --git a/docs/framework/vue/reference/type-aliases/FieldComponent.md b/docs/framework/vue/reference/type-aliases/FieldComponent.md deleted file mode 100644 index e3e1477a81..0000000000 --- a/docs/framework/vue/reference/type-aliases/FieldComponent.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -id: FieldComponent -title: FieldComponent ---- - -# Type Alias: FieldComponent()\ - -```ts -type FieldComponent = (props) => CreateComponentPublicInstanceWithMixins, { -}, { -}, { -}, { -}, ComponentOptionsMixin, ComponentOptionsMixin, EmitsOptions, PublicProps, { -}, false, { -}, SlotsType<{ - default: { - field: FieldApi; - state: FieldApi["state"]; - }; -}>>; -``` - -Defined in: [packages/vue-form/src/useField.tsx:25](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useField.tsx#L25) - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Parameters - -### props - -[`FieldComponentBoundProps`](FieldComponentBoundProps.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`\> & `EmitsToProps`\<`EmitsOptions`\> & `PublicProps` - -## Returns - -`CreateComponentPublicInstanceWithMixins`\<[`FieldComponentBoundProps`](FieldComponentBoundProps.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`\>, \{ -\}, \{ -\}, \{ -\}, \{ -\}, `ComponentOptionsMixin`, `ComponentOptionsMixin`, `EmitsOptions`, `PublicProps`, \{ -\}, `false`, \{ -\}, `SlotsType`\<\{ - `default`: \{ - `field`: `FieldApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\>; - `state`: `FieldApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\>\[`"state"`\]; - \}; -\}\>\> diff --git a/docs/framework/vue/reference/type-aliases/FieldComponentBoundProps.md b/docs/framework/vue/reference/type-aliases/FieldComponentBoundProps.md deleted file mode 100644 index 563286862b..0000000000 --- a/docs/framework/vue/reference/type-aliases/FieldComponentBoundProps.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -id: FieldComponentBoundProps -title: FieldComponentBoundProps ---- - -# Type Alias: FieldComponentBoundProps\ - -```ts -type FieldComponentBoundProps = UseFieldOptionsBound; -``` - -Defined in: [packages/vue-form/src/useField.tsx:444](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useField.tsx#L444) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> diff --git a/docs/framework/vue/reference/type-aliases/FieldComponentProps.md b/docs/framework/vue/reference/type-aliases/FieldComponentProps.md deleted file mode 100644 index b3a54c7f64..0000000000 --- a/docs/framework/vue/reference/type-aliases/FieldComponentProps.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -id: FieldComponentProps -title: FieldComponentProps ---- - -# Type Alias: FieldComponentProps\ - -```ts -type FieldComponentProps = UseFieldOptions; -``` - -Defined in: [packages/vue-form/src/useField.tsx:386](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useField.tsx#L386) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` diff --git a/docs/framework/vue/reference/type-aliases/FieldGroupArrayFieldComponent.md b/docs/framework/vue/reference/type-aliases/FieldGroupArrayFieldComponent.md new file mode 100644 index 0000000000..eba64be62d --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/FieldGroupArrayFieldComponent.md @@ -0,0 +1,38 @@ +--- +id: FieldGroupArrayFieldComponent +title: FieldGroupArrayFieldComponent +--- + +```ts +type FieldGroupArrayFieldComponent = (props) => VueComponentInstance, FieldValidators>, ValidationIssue, unknown, FormErrorTypes, TFieldComponents>, { + default: { + field: VueFieldApi, ToFieldError>, ValidationIssue, FormErrorTypes>, unknown, FormErrorTypes, TFieldComponents>; + }; +}>; +``` + +Defined in: [packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts:70](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts#L70) + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +## Parameters + +### props + +[`VueFormFieldProps`](../interfaces/VueFormFieldProps.md)\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\>, `ValidationIssue`, `unknown`, `FormErrorTypes`, `TFieldComponents`\> & `PublicProps` + +## Returns + +`VueComponentInstance`\<[`VueFormFieldProps`](../interfaces/VueFormFieldProps.md)\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\>, `ValidationIssue`, `unknown`, `FormErrorTypes`, `TFieldComponents`\>, \{ + `default`: \{ + `field`: [`VueFieldApi`](VueFieldApi.md)\<`TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `ToFieldError`\<`FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\>, `ValidationIssue`, `FormErrorTypes`\>, `unknown`, `FormErrorTypes`, `TFieldComponents`\>; + \}; +\}\> diff --git a/docs/framework/vue/reference/type-aliases/FieldGroupFieldBindingsOf.md b/docs/framework/vue/reference/type-aliases/FieldGroupFieldBindingsOf.md new file mode 100644 index 0000000000..0b78582b9a --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/FieldGroupFieldBindingsOf.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupFieldBindingsOf +title: FieldGroupFieldBindingsOf +--- + +```ts +type FieldGroupFieldBindingsOf = FieldGroupFieldsOf extends FieldGroupFields ? FieldGroupFieldBindings, TFormData> : never; +``` + +Defined in: [packages/vue-form/src/FieldGroup/withFields.public.ts:39](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/withFields.public.ts#L39) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` + +### TFormData + +`TFormData` diff --git a/docs/framework/vue/reference/type-aliases/FieldGroupFieldComponent.md b/docs/framework/vue/reference/type-aliases/FieldGroupFieldComponent.md new file mode 100644 index 0000000000..3663d7afe9 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/FieldGroupFieldComponent.md @@ -0,0 +1,38 @@ +--- +id: FieldGroupFieldComponent +title: FieldGroupFieldComponent +--- + +```ts +type FieldGroupFieldComponent = (props) => VueComponentInstance, FieldValidators>, ValidationIssue, unknown, FormErrorTypes, TFieldComponents>, { + default: { + field: VueFieldApi, ToFieldError>, ValidationIssue, FormErrorTypes>, unknown, FormErrorTypes, TFieldComponents>; + }; +}>; +``` + +Defined in: [packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts:22](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts#L22) + +## Type Parameters + +### TFieldData + +`TFieldData` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +## Parameters + +### props + +[`VueFormFieldProps`](../interfaces/VueFormFieldProps.md)\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\>, `ValidationIssue`, `unknown`, `FormErrorTypes`, `TFieldComponents`\> & `PublicProps` + +## Returns + +`VueComponentInstance`\<[`VueFormFieldProps`](../interfaces/VueFormFieldProps.md)\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\>, `ValidationIssue`, `unknown`, `FormErrorTypes`, `TFieldComponents`\>, \{ + `default`: \{ + `field`: [`VueFieldApi`](VueFieldApi.md)\<`TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>, `ToFieldError`\<`FieldValidators`\<`TFieldData`, `TFieldName`, `DeepValue`\<`TFieldData`, `TFieldName`\>\>, `ValidationIssue`, `FormErrorTypes`\>, `unknown`, `FormErrorTypes`, `TFieldComponents`\>; + \}; +\}\> diff --git a/docs/framework/vue/reference/type-aliases/FieldGroupFieldComponentsOf.md b/docs/framework/vue/reference/type-aliases/FieldGroupFieldComponentsOf.md new file mode 100644 index 0000000000..4538b99ee6 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/FieldGroupFieldComponentsOf.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupFieldComponentsOf +title: FieldGroupFieldComponentsOf +--- + +```ts +type FieldGroupFieldComponentsOf = TFieldGroup extends VueFieldGroup ? TFieldComponents : never; +``` + +Defined in: [packages/vue-form/src/FieldGroup/withFields.public.ts:29](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/withFields.public.ts#L29) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` diff --git a/docs/framework/vue/reference/type-aliases/FieldGroupFieldsOf.md b/docs/framework/vue/reference/type-aliases/FieldGroupFieldsOf.md new file mode 100644 index 0000000000..939be1679a --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/FieldGroupFieldsOf.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupFieldsOf +title: FieldGroupFieldsOf +--- + +```ts +type FieldGroupFieldsOf = TFieldGroup extends object ? TFields : never; +``` + +Defined in: [packages/vue-form/src/FieldGroup/withFields.public.ts:17](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/withFields.public.ts#L17) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` diff --git a/docs/framework/vue/reference/type-aliases/FieldGroupForm.md b/docs/framework/vue/reference/type-aliases/FieldGroupForm.md new file mode 100644 index 0000000000..88a7be1f70 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/FieldGroupForm.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupForm +title: FieldGroupForm +--- + +```ts +type FieldGroupForm = FormApi & VueTanStackFormComponents; +``` + +Defined in: [packages/vue-form/src/FieldGroup/withFields.public.ts:33](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/withFields.public.ts#L33) + +## Type Parameters + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> = `Record`\<`never`, `never`\> + +### TFormData + +`TFormData` = `any` diff --git a/docs/framework/vue/reference/type-aliases/FieldGroupFormState.md b/docs/framework/vue/reference/type-aliases/FieldGroupFormState.md new file mode 100644 index 0000000000..629f2f17e8 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/FieldGroupFormState.md @@ -0,0 +1,10 @@ +--- +id: FieldGroupFormState +title: FieldGroupFormState +--- + +```ts +type FieldGroupFormState = FormState; +``` + +Defined in: [packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts:148](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts#L148) diff --git a/docs/framework/vue/reference/type-aliases/FieldGroupSubscribeComponent.md b/docs/framework/vue/reference/type-aliases/FieldGroupSubscribeComponent.md new file mode 100644 index 0000000000..0c943d7b63 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/FieldGroupSubscribeComponent.md @@ -0,0 +1,24 @@ +--- +id: FieldGroupSubscribeComponent +title: FieldGroupSubscribeComponent +--- + +```ts +type FieldGroupSubscribeComponent = (props) => VueComponentInstance, { + default: NoInfer; +}>; +``` + +Defined in: [packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts:126](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts#L126) + +## Parameters + +### props + +[`FieldGroupSubscribeProps`](FieldGroupSubscribeProps.md)\<`TSelected`\> & `PublicProps` + +## Returns + +`VueComponentInstance`\<[`FieldGroupSubscribeProps`](FieldGroupSubscribeProps.md)\<`TSelected`\>, \{ + `default`: `NoInfer`\<`TSelected`\>; +\}\> diff --git a/docs/framework/vue/reference/type-aliases/FieldGroupSubscribeProps.md b/docs/framework/vue/reference/type-aliases/FieldGroupSubscribeProps.md new file mode 100644 index 0000000000..d0c55b5b26 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/FieldGroupSubscribeProps.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupSubscribeProps +title: FieldGroupSubscribeProps +--- + +```ts +type FieldGroupSubscribeProps = VueFormSubscribeProps; +``` + +Defined in: [packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts:120](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/FieldGroupApi.public.ts#L120) + +## Type Parameters + +### TSelected + +`TSelected` diff --git a/docs/framework/vue/reference/type-aliases/FieldGroupWithFieldsFn.md b/docs/framework/vue/reference/type-aliases/FieldGroupWithFieldsFn.md new file mode 100644 index 0000000000..d2c3fca2ea --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/FieldGroupWithFieldsFn.md @@ -0,0 +1,42 @@ +--- +id: FieldGroupWithFieldsFn +title: FieldGroupWithFieldsFn +--- + +```ts +type FieldGroupWithFieldsFn = (component, fieldsPropName) => (props) => VueComponentInstance & object & FieldGroupFieldBindingsInstanceProp & Record, { +}>; +``` + +Defined in: [packages/vue-form/src/FieldGroup/withFields.public.ts:68](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/withFields.public.ts#L68) + +## Type Parameters + +### TFieldGroup + +`TFieldGroup` *extends* [`VueFieldGroup`](VueFieldGroup.md)\<`any`, `any`\> + +## Type Parameters + +### TProps + +`TProps` *extends* `object` + +### TFieldsPropName + +`TFieldsPropName` *extends* `PropertyKey` + +## Parameters + +### component + +`Component` & (`props`) => `any` + +### fieldsPropName + +`TFieldsPropName` & `FieldGroupFieldsPropName`\<`TProps`, `TFieldGroup`\> + +## Returns + +\<`TFormData`\>(`props`) => `VueComponentInstance`\<`Omit`\<`TProps`, `TFieldsPropName` \| `"form"`\> & `object` & `FieldGroupFieldBindingsInstanceProp`\<`TFieldGroup`, `TFormData`, `TFieldsPropName`\> & `Record`\<`string`, `any`\>, \{ +\}\> diff --git a/docs/framework/vue/reference/type-aliases/FormGroupComponent.md b/docs/framework/vue/reference/type-aliases/FormGroupComponent.md deleted file mode 100644 index e7dc01bb10..0000000000 --- a/docs/framework/vue/reference/type-aliases/FormGroupComponent.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -id: FormGroupComponent -title: FormGroupComponent ---- - -# Type Alias: FormGroupComponent()\ - -```ts -type FormGroupComponent = (props) => CreateComponentPublicInstanceWithMixins, { -}, { -}, { -}, { -}, ComponentOptionsMixin, ComponentOptionsMixin, EmitsOptions, PublicProps, { -}, false, { -}, SlotsType<{ - default: { - group: FormGroupApi; - state: FormGroupApi["state"]; - }; -}>>; -``` - -Defined in: [packages/vue-form/src/useFormGroup.tsx:24](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useFormGroup.tsx#L24) - -## Type Parameters - -### TParentData - -`TParentData` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Parameters - -### props - -[`FormGroupComponentBoundProps`](FormGroupComponentBoundProps.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> & `EmitsToProps`\<`EmitsOptions`\> & `PublicProps` - -## Returns - -`CreateComponentPublicInstanceWithMixins`\<[`FormGroupComponentBoundProps`](FormGroupComponentBoundProps.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\>, \{ -\}, \{ -\}, \{ -\}, \{ -\}, `ComponentOptionsMixin`, `ComponentOptionsMixin`, `EmitsOptions`, `PublicProps`, \{ -\}, `false`, \{ -\}, `SlotsType`\<\{ - `default`: \{ - `group`: `FormGroupApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\>; - `state`: `FormGroupApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\>\[`"state"`\]; - \}; -\}\>\> diff --git a/docs/framework/vue/reference/type-aliases/FormGroupComponentBoundProps.md b/docs/framework/vue/reference/type-aliases/FormGroupComponentBoundProps.md deleted file mode 100644 index 67eb21e781..0000000000 --- a/docs/framework/vue/reference/type-aliases/FormGroupComponentBoundProps.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -id: FormGroupComponentBoundProps -title: FormGroupComponentBoundProps ---- - -# Type Alias: FormGroupComponentBoundProps\ - -```ts -type FormGroupComponentBoundProps = FormGroupOptions; -``` - -Defined in: [packages/vue-form/src/useFormGroup.tsx:384](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useFormGroup.tsx#L384) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TSubmitMeta - -`TSubmitMeta` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` diff --git a/docs/framework/vue/reference/type-aliases/FormGroupComponentProps.md b/docs/framework/vue/reference/type-aliases/FormGroupComponentProps.md deleted file mode 100644 index 9e2da7a157..0000000000 --- a/docs/framework/vue/reference/type-aliases/FormGroupComponentProps.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -id: FormGroupComponentProps -title: FormGroupComponentProps ---- - -# Type Alias: FormGroupComponentProps\ - -```ts -type FormGroupComponentProps = FormGroupApiOptions; -``` - -Defined in: [packages/vue-form/src/useFormGroup.tsx:318](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useFormGroup.tsx#L318) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* `DeepKeys`\<`TParentData`\> - -### TData - -`TData` *extends* `DeepValue`\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TSubmitMeta - -`TSubmitMeta` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` diff --git a/docs/framework/vue/reference/type-aliases/Observer.md b/docs/framework/vue/reference/type-aliases/Observer.md new file mode 100644 index 0000000000..c32765443c --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/Observer.md @@ -0,0 +1,70 @@ +--- +id: Observer +title: Observer +--- + +```ts +type Observer = object; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:8 + +## Type Parameters + +### T + +`T` + +## Properties + +### complete? + +```ts +optional complete?: () => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:11 + +#### Returns + +`void` + +*** + +### error? + +```ts +optional error?: (err) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:10 + +#### Parameters + +##### err + +`unknown` + +#### Returns + +`void` + +*** + +### next? + +```ts +optional next?: (value) => void; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:9 + +#### Parameters + +##### value + +`T` + +#### Returns + +`void` diff --git a/docs/framework/vue/reference/type-aliases/Selection.md b/docs/framework/vue/reference/type-aliases/Selection.md new file mode 100644 index 0000000000..0ec13fa14b --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/Selection.md @@ -0,0 +1,16 @@ +--- +id: Selection +title: Selection +--- + +```ts +type Selection = Readable; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/types.d.ts:4 + +## Type Parameters + +### TSelected + +`TSelected` diff --git a/docs/framework/vue/reference/type-aliases/StoreAction.md b/docs/framework/vue/reference/type-aliases/StoreAction.md new file mode 100644 index 0000000000..3c38ef14ec --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/StoreAction.md @@ -0,0 +1,20 @@ +--- +id: StoreAction +title: StoreAction +--- + +```ts +type StoreAction = (...args) => any; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:4 + +## Parameters + +### args + +...`any`[] + +## Returns + +`any` diff --git a/docs/framework/vue/reference/type-aliases/StoreActionMap.md b/docs/framework/vue/reference/type-aliases/StoreActionMap.md new file mode 100644 index 0000000000..c23e39e1bd --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/StoreActionMap.md @@ -0,0 +1,10 @@ +--- +id: StoreActionMap +title: StoreActionMap +--- + +```ts +type StoreActionMap = Record; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:5 diff --git a/docs/framework/vue/reference/type-aliases/StoreActionsFactory.md b/docs/framework/vue/reference/type-aliases/StoreActionsFactory.md new file mode 100644 index 0000000000..b87f92ecf9 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/StoreActionsFactory.md @@ -0,0 +1,36 @@ +--- +id: StoreActionsFactory +title: StoreActionsFactory +--- + +```ts +type StoreActionsFactory = (store) => TActions; +``` + +Defined in: node\_modules/.pnpm/@tanstack+store@0.11.1/node\_modules/@tanstack/store/dist/store.d.ts:6 + +## Type Parameters + +### T + +`T` + +### TActions + +`TActions` *extends* [`StoreActionMap`](StoreActionMap.md) + +## Parameters + +### store + +#### get + +[`Store`](../classes/Store.md)\<`T`\>\[`"get"`\] + +#### setState + +[`Store`](../classes/Store.md)\<`T`\>\[`"setState"`\] + +## Returns + +`TActions` diff --git a/docs/framework/vue/reference/type-aliases/SubscribeComponent.md b/docs/framework/vue/reference/type-aliases/SubscribeComponent.md new file mode 100644 index 0000000000..1fda9a1d0f --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/SubscribeComponent.md @@ -0,0 +1,24 @@ +--- +id: SubscribeComponent +title: SubscribeComponent +--- + +```ts +type SubscribeComponent = (props) => InstanceType, { + default: NoInfer; +}>>; +``` + +Defined in: [packages/vue-form/src/Subscribe.public.ts:20](https://github.com/TanStack/form/blob/main/packages/vue-form/src/Subscribe.public.ts#L20) + +## Parameters + +### props + +[`SubscribeProps`](../interfaces/SubscribeProps.md)\<`TSourceData`, `TSelected`\> + +## Returns + +`InstanceType`\<`VueComponentWithSlots`\<[`SubscribeProps`](../interfaces/SubscribeProps.md)\<`TSourceData`, `TSelected`\>, \{ + `default`: `NoInfer`\<`TSelected`\>; +\}\>\> diff --git a/docs/framework/vue/reference/type-aliases/SubscribeSource.md b/docs/framework/vue/reference/type-aliases/SubscribeSource.md new file mode 100644 index 0000000000..faaf51bafd --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/SubscribeSource.md @@ -0,0 +1,20 @@ +--- +id: SubscribeSource +title: SubscribeSource +--- + +```ts +type SubscribeSource = + | Atom + | ReadonlyAtom + | Store +| ReadonlyStore; +``` + +Defined in: [packages/vue-form/src/Subscribe.public.ts:11](https://github.com/TanStack/form/blob/main/packages/vue-form/src/Subscribe.public.ts#L11) + +## Type Parameters + +### TValue + +`TValue` diff --git a/docs/framework/vue/reference/type-aliases/UseAppFormHook.md b/docs/framework/vue/reference/type-aliases/UseAppFormHook.md new file mode 100644 index 0000000000..91558982f7 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/UseAppFormHook.md @@ -0,0 +1,40 @@ +--- +id: UseAppFormHook +title: UseAppFormHook +--- + +```ts +type UseAppFormHook = (options) => VueAppFormApi, TComponents>; +``` + +Defined in: [packages/vue-form/src/AppForm/createFormHookTypes.public.ts:98](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/createFormHookTypes.public.ts#L98) + +## Type Parameters + +### TComponents + +`TComponents` *extends* [`AnyVueFormComponentMap`](AnyVueFormComponentMap.md) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> + +### TSubmitReturn + +`TSubmitReturn` + +## Parameters + +### options + +`FormOptions`\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\> + +## Returns + +[`VueAppFormApi`](VueAppFormApi.md)\<`TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>, `TComponents`\> diff --git a/docs/framework/vue/reference/type-aliases/UseFormHook.md b/docs/framework/vue/reference/type-aliases/UseFormHook.md new file mode 100644 index 0000000000..5f83d976e8 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/UseFormHook.md @@ -0,0 +1,40 @@ +--- +id: UseFormHook +title: UseFormHook +--- + +```ts +type UseFormHook = (options) => VueFormApi, TComponents>; +``` + +Defined in: [packages/vue-form/src/VueForm/useForm.public.ts:13](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/useForm.public.ts#L13) + +## Type Parameters + +### TComponents + +`TComponents` *extends* [`AnyVueFormComponentMap`](AnyVueFormComponentMap.md) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* `FormValidators`\<`TFormData`\> + +### TSubmitReturn + +`TSubmitReturn` + +## Parameters + +### options + +`FormOptions`\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\> + +## Returns + +[`VueFormApi`](VueFormApi.md)\<`TFormData`, `ToFormErrorTypes`\<`TFormValidators`, `TSubmitReturn`\>, `TComponents`\> diff --git a/docs/framework/vue/reference/type-aliases/VueAppFormApi.md b/docs/framework/vue/reference/type-aliases/VueAppFormApi.md new file mode 100644 index 0000000000..96008c7339 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueAppFormApi.md @@ -0,0 +1,32 @@ +--- +id: VueAppFormApi +title: VueAppFormApi +--- + +```ts +type VueAppFormApi = VueFormApi & object; +``` + +Defined in: [packages/vue-form/src/AppForm/VueAppFormApi.public.ts:11](https://github.com/TanStack/form/blob/main/packages/vue-form/src/AppForm/VueAppFormApi.public.ts#L11) + +## Type Declaration + +### AppForm + +```ts +AppForm: AppFormComponent; +``` + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TComponents + +`TComponents` *extends* [`AnyVueFormComponentMap`](AnyVueFormComponentMap.md) diff --git a/docs/framework/vue/reference/type-aliases/VueFieldApi.md b/docs/framework/vue/reference/type-aliases/VueFieldApi.md new file mode 100644 index 0000000000..4c8ba85327 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueFieldApi.md @@ -0,0 +1,36 @@ +--- +id: VueFieldApi +title: VueFieldApi +--- + +```ts +type VueFieldApi = FieldApi & FieldComponentsMatchingType; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:65](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L65) + +## Type Parameters + +### TFieldName + +`TFieldName` + +### TFieldValue + +`TFieldValue` + +### TFieldError + +`TFieldError` + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> diff --git a/docs/framework/vue/reference/type-aliases/VueFieldGroup.md b/docs/framework/vue/reference/type-aliases/VueFieldGroup.md new file mode 100644 index 0000000000..1a21693f19 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueFieldGroup.md @@ -0,0 +1,28 @@ +--- +id: VueFieldGroup +title: VueFieldGroup +--- + +```ts +type VueFieldGroup = FieldGroupApi, TFieldComponents> & object; +``` + +Defined in: [packages/vue-form/src/FieldGroup/withFields.public.ts:23](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/withFields.public.ts#L23) + +## Type Declaration + +### \[fieldGroupFieldsSymbol\] + +```ts +readonly [fieldGroupFieldsSymbol]: TFields; +``` + +## Type Parameters + +### TFields + +`TFields` *extends* `FieldGroupFields` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> = `Record`\<`never`, `never`\> diff --git a/docs/framework/vue/reference/type-aliases/VueFormApi.md b/docs/framework/vue/reference/type-aliases/VueFormApi.md new file mode 100644 index 0000000000..b5f1713c61 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueFormApi.md @@ -0,0 +1,24 @@ +--- +id: VueFormApi +title: VueFormApi +--- + +```ts +type VueFormApi = unknown extends TComponents["formComponents"] ? ExtendedFormApi : ExtendedFormApi & TComponents["formComponents"]; +``` + +Defined in: [packages/vue-form/src/VueForm/formApiTypes.public.ts:16](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/formApiTypes.public.ts#L16) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TComponents + +`TComponents` *extends* [`AnyVueFormComponentMap`](AnyVueFormComponentMap.md) = [`DefaultVueFormComponentMap`](DefaultVueFormComponentMap.md) diff --git a/docs/framework/vue/reference/type-aliases/VueFormArrayFieldComponent.md b/docs/framework/vue/reference/type-aliases/VueFormArrayFieldComponent.md new file mode 100644 index 0000000000..975b5e592d --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueFormArrayFieldComponent.md @@ -0,0 +1,42 @@ +--- +id: VueFormArrayFieldComponent +title: VueFormArrayFieldComponent +--- + +```ts +type VueFormArrayFieldComponent = (props) => VueComponentInstance, TFieldValidators, never, TFormData, TFormErrorTypes, TFieldComponents>, { + default: { + field: VueFieldApi, ToFieldError, never, TFormErrorTypes>, TFormData, TFormErrorTypes, TFieldComponents>; + }; +}>; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:170](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L170) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +## Parameters + +### props + +[`VueFormFieldProps`](../interfaces/VueFormFieldProps.md)\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> & `PublicProps` + +## Returns + +`VueComponentInstance`\<[`VueFormFieldProps`](../interfaces/VueFormFieldProps.md)\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\>, \{ + `default`: \{ + `field`: [`VueFieldApi`](VueFieldApi.md)\<`TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `ToFieldError`\<`NoInfer`\<`TFieldValidators`\>, `never`, `TFormErrorTypes`\>, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\>; + \}; +\}\> diff --git a/docs/framework/vue/reference/type-aliases/VueFormFieldComponent.md b/docs/framework/vue/reference/type-aliases/VueFormFieldComponent.md new file mode 100644 index 0000000000..fb90d71a42 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueFormFieldComponent.md @@ -0,0 +1,42 @@ +--- +id: VueFormFieldComponent +title: VueFormFieldComponent +--- + +```ts +type VueFormFieldComponent = (props) => VueComponentInstance, TFieldValidators, never, TFormData, TFormErrorTypes, TFieldComponents>, { + default: { + field: VueFieldApi, ToFieldError, never, TFormErrorTypes>, TFormData, TFormErrorTypes, TFieldComponents>; + }; +}>; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:122](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L122) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +## Parameters + +### props + +[`VueFormFieldProps`](../interfaces/VueFormFieldProps.md)\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> & `PublicProps` + +## Returns + +`VueComponentInstance`\<[`VueFormFieldProps`](../interfaces/VueFormFieldProps.md)\<`TFormData`, `TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `TFieldValidators`, `never`, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\>, \{ + `default`: \{ + `field`: [`VueFieldApi`](VueFieldApi.md)\<`TFieldName`, `DeepValue`\<`TFormData`, `TFieldName`\>, `ToFieldError`\<`NoInfer`\<`TFieldValidators`\>, `never`, `TFormErrorTypes`\>, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\>; + \}; +\}\> diff --git a/docs/framework/vue/reference/type-aliases/VueFormGroupArrayFieldComponent.md b/docs/framework/vue/reference/type-aliases/VueFormGroupArrayFieldComponent.md new file mode 100644 index 0000000000..d84d8de6c1 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueFormGroupArrayFieldComponent.md @@ -0,0 +1,50 @@ +--- +id: VueFormGroupArrayFieldComponent +title: VueFormGroupArrayFieldComponent +--- + +```ts +type VueFormGroupArrayFieldComponent = (props) => VueComponentInstance, TFieldValidators, TGroupErrorTypes["fieldError"], TFormData, TFormErrorTypes, TFieldComponents>, { + default: { + field: VueFieldApi, ToFieldError, TGroupErrorTypes["fieldError"], TFormErrorTypes>, TFormData, TFormErrorTypes, TFieldComponents>; + }; +}>; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:289](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L289) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +## Parameters + +### props + +[`VueFormFieldProps`](../interfaces/VueFormFieldProps.md)\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>, `TFieldValidators`, `TGroupErrorTypes`\[`"fieldError"`\], `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> & `PublicProps` + +## Returns + +`VueComponentInstance`\<[`VueFormFieldProps`](../interfaces/VueFormFieldProps.md)\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>, `TFieldValidators`, `TGroupErrorTypes`\[`"fieldError"`\], `TFormData`, `TFormErrorTypes`, `TFieldComponents`\>, \{ + `default`: \{ + `field`: [`VueFieldApi`](VueFieldApi.md)\<`TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>, `ToFieldError`\<`NoInfer`\<`TFieldValidators`\>, `TGroupErrorTypes`\[`"fieldError"`\], `TFormErrorTypes`\>, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\>; + \}; +\}\> diff --git a/docs/framework/vue/reference/type-aliases/VueFormGroupComponent.md b/docs/framework/vue/reference/type-aliases/VueFormGroupComponent.md new file mode 100644 index 0000000000..152de72a0e --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueFormGroupComponent.md @@ -0,0 +1,42 @@ +--- +id: VueFormGroupComponent +title: VueFormGroupComponent +--- + +```ts +type VueFormGroupComponent = (props) => VueComponentInstance, { + default: { + group: VueFormGroupApi>, TFormErrorTypes, TFieldComponents>; + }; +}>; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:394](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L394) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +## Parameters + +### props + +[`VueFormGroupProps`](../interfaces/VueFormGroupProps.md)\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupValidators`, `TFormErrorTypes`, `TFieldComponents`\> & `PublicProps` + +## Returns + +`VueComponentInstance`\<[`VueFormGroupProps`](../interfaces/VueFormGroupProps.md)\<`TFormData`, `TGroupName`, `TGroupValue`, `TGroupValidators`, `TFormErrorTypes`, `TFieldComponents`\>, \{ + `default`: \{ + `group`: [`VueFormGroupApi`](../interfaces/VueFormGroupApi.md)\<`TFormData`, `TGroupName`, `TGroupValue`, `ToFormGroupErrorTypes`\<`NoInfer`\<`TGroupValidators`\>\>, `TFormErrorTypes`, `TFieldComponents`\>; + \}; +\}\> diff --git a/docs/framework/vue/reference/type-aliases/VueFormGroupFieldComponent.md b/docs/framework/vue/reference/type-aliases/VueFormGroupFieldComponent.md new file mode 100644 index 0000000000..161423b8ec --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueFormGroupFieldComponent.md @@ -0,0 +1,50 @@ +--- +id: VueFormGroupFieldComponent +title: VueFormGroupFieldComponent +--- + +```ts +type VueFormGroupFieldComponent = (props) => VueComponentInstance, TFieldValidators, TGroupErrorTypes["fieldError"], TFormData, TFormErrorTypes, TFieldComponents>, { + default: { + field: VueFieldApi, ToFieldError, TGroupErrorTypes["fieldError"], TFormErrorTypes>, TFormData, TFormErrorTypes, TFieldComponents>; + }; +}>; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:235](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L235) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TFieldComponents + +`TFieldComponents` *extends* `Record`\<`string`, `Component`\> + +## Parameters + +### props + +[`VueFormFieldProps`](../interfaces/VueFormFieldProps.md)\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>, `TFieldValidators`, `TGroupErrorTypes`\[`"fieldError"`\], `TFormData`, `TFormErrorTypes`, `TFieldComponents`\> & `PublicProps` + +## Returns + +`VueComponentInstance`\<[`VueFormFieldProps`](../interfaces/VueFormFieldProps.md)\<`TGroupValue`, `TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>, `TFieldValidators`, `TGroupErrorTypes`\[`"fieldError"`\], `TFormData`, `TFormErrorTypes`, `TFieldComponents`\>, \{ + `default`: \{ + `field`: [`VueFieldApi`](VueFieldApi.md)\<`TFieldName`, `DeepValue`\<`TGroupValue`, `TFieldName`\>, `ToFieldError`\<`NoInfer`\<`TFieldValidators`\>, `TGroupErrorTypes`\[`"fieldError"`\], `TFormErrorTypes`\>, `TFormData`, `TFormErrorTypes`, `TFieldComponents`\>; + \}; +\}\> diff --git a/docs/framework/vue/reference/type-aliases/VueFormGroupSubscribeComponent.md b/docs/framework/vue/reference/type-aliases/VueFormGroupSubscribeComponent.md new file mode 100644 index 0000000000..b166a364da --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueFormGroupSubscribeComponent.md @@ -0,0 +1,34 @@ +--- +id: VueFormGroupSubscribeComponent +title: VueFormGroupSubscribeComponent +--- + +```ts +type VueFormGroupSubscribeComponent = (props) => VueComponentInstance, { + default: NoInfer; +}>; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:224](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L224) + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +## Parameters + +### props + +[`VueFormGroupSubscribeProps`](VueFormGroupSubscribeProps.md)\<`TGroupValue`, `TGroupErrorTypes`, `TSelected`\> & `PublicProps` + +## Returns + +`VueComponentInstance`\<[`VueFormGroupSubscribeProps`](VueFormGroupSubscribeProps.md)\<`TGroupValue`, `TGroupErrorTypes`, `TSelected`\>, \{ + `default`: `NoInfer`\<`TSelected`\>; +\}\> diff --git a/docs/framework/vue/reference/type-aliases/VueFormGroupSubscribeProps.md b/docs/framework/vue/reference/type-aliases/VueFormGroupSubscribeProps.md new file mode 100644 index 0000000000..1324e16eb6 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueFormGroupSubscribeProps.md @@ -0,0 +1,24 @@ +--- +id: VueFormGroupSubscribeProps +title: VueFormGroupSubscribeProps +--- + +```ts +type VueFormGroupSubscribeProps = VueSubscribeProps, TSelected>; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:218](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L218) + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* `FormErrorTypes` + +### TSelected + +`TSelected` diff --git a/docs/framework/vue/reference/type-aliases/VueFormSubscribeComponent.md b/docs/framework/vue/reference/type-aliases/VueFormSubscribeComponent.md new file mode 100644 index 0000000000..c684f1c966 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueFormSubscribeComponent.md @@ -0,0 +1,34 @@ +--- +id: VueFormSubscribeComponent +title: VueFormSubscribeComponent +--- + +```ts +type VueFormSubscribeComponent = (props) => VueComponentInstance, { + default: NoInfer; +}>; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:86](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L86) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +## Parameters + +### props + +[`VueFormSubscribeProps`](VueFormSubscribeProps.md)\<`TFormData`, `TFormErrorTypes`, `TSelected`\> & `PublicProps` + +## Returns + +`VueComponentInstance`\<[`VueFormSubscribeProps`](VueFormSubscribeProps.md)\<`TFormData`, `TFormErrorTypes`, `TSelected`\>, \{ + `default`: `NoInfer`\<`TSelected`\>; +\}\> diff --git a/docs/framework/vue/reference/type-aliases/VueFormSubscribeProps.md b/docs/framework/vue/reference/type-aliases/VueFormSubscribeProps.md new file mode 100644 index 0000000000..8fb996a6ed --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueFormSubscribeProps.md @@ -0,0 +1,24 @@ +--- +id: VueFormSubscribeProps +title: VueFormSubscribeProps +--- + +```ts +type VueFormSubscribeProps = VueSubscribeProps, TSelected>; +``` + +Defined in: [packages/vue-form/src/VueForm/Components.public.ts:80](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/Components.public.ts#L80) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* `FormErrorTypes` + +### TSelected + +`TSelected` diff --git a/docs/framework/vue/reference/type-aliases/VueFormType.md b/docs/framework/vue/reference/type-aliases/VueFormType.md new file mode 100644 index 0000000000..89e4e43114 --- /dev/null +++ b/docs/framework/vue/reference/type-aliases/VueFormType.md @@ -0,0 +1,39 @@ +--- +id: VueFormType +title: VueFormType +--- + +```ts +type VueFormType = TOptions extends FormOptions ? VueFormApi, TComponents extends AnyVueFormComponentMap ? TComponents : DefaultVueFormComponentMap> : never; +``` + +Defined in: [packages/vue-form/src/VueForm/formType.public.ts:43](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/formType.public.ts#L43) + +Derives the Vue form API type represented by a reusable options object. + +Use it to type props for components that belong to one known form shape. It +preserves the inferred form data and any components registered through +`appFormOptions`. Options such as `onSubmit` can be defined either in the +shared options or when the form is created in the component. + +## Type Parameters + +### TOptions + +`TOptions` *extends* `AnyFormOptions` + +The reusable form or app-form options from which the API derives its form data, error, and registered-component types. + +## Example + +```ts +const profileOptions = formOptions({ + defaultValues: { name: '' }, +}) + +type ProfileForm = VueFormType + +const props = defineProps<{ + form: ProfileForm +}>() +``` diff --git a/docs/framework/vue/reference/variables/Field.md b/docs/framework/vue/reference/variables/Field.md deleted file mode 100644 index d80472329c..0000000000 --- a/docs/framework/vue/reference/variables/Field.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -id: Field -title: Field ---- - -# Variable: Field() - -```ts -const Field: (props) => CreateComponentPublicInstanceWithMixins & - | { -[key: `on${Capitalize}`]: (...args) => any | undefined; -} - | { -[key: `on${Capitalize}`]: (...args) => any | undefined; -}, { -}, { -}, { -}, { -}, ComponentOptionsMixin, ComponentOptionsMixin, EmitsOptions, PublicProps, { -}, false, { -}, { -}>; -``` - -Defined in: [packages/vue-form/src/useField.tsx:480](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useField.tsx#L480) - -## Parameters - -### props - -UseFieldOptions\ & (\{ ...; \} \| \{ ...; \}) & `VNodeProps` & `AllowedComponentProps` & `ComponentCustomProps` - -## Returns - -`CreateComponentPublicInstanceWithMixins`\<`UseFieldOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> & - \| \{ -\[`key`: `` `on${Capitalize}` ``\]: (...`args`) => `any` \| `undefined`; -\} - \| \{ -\[`key`: `` `on${Capitalize}` ``\]: (...`args`) => `any` \| `undefined`; -\}, \{ -\}, \{ -\}, \{ -\}, \{ -\}, `ComponentOptionsMixin`, `ComponentOptionsMixin`, `EmitsOptions`, `PublicProps`, \{ -\}, `false`, \{ -\}, \{ -\}\> diff --git a/docs/framework/vue/reference/variables/FormGroup.md b/docs/framework/vue/reference/variables/FormGroup.md deleted file mode 100644 index 5f396efc62..0000000000 --- a/docs/framework/vue/reference/variables/FormGroup.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -id: FormGroup -title: FormGroup ---- - -# Variable: FormGroup() - -```ts -const FormGroup: (props) => CreateComponentPublicInstanceWithMixins & - | { -[key: `on${Capitalize}`]: (...args) => any | undefined; -} - | { -[key: `on${Capitalize}`]: (...args) => any | undefined; -}, { -}, { -}, { -}, { -}, ComponentOptionsMixin, ComponentOptionsMixin, EmitsOptions, PublicProps, { -}, false, { -}, { -}>; -``` - -Defined in: [packages/vue-form/src/useFormGroup.tsx:450](https://github.com/TanStack/form/blob/main/packages/vue-form/src/useFormGroup.tsx#L450) - -## Parameters - -### props - -FormGroupApiOptions\ & (\{ ...; \} \| \{ ...; \}) & `VNodeProps` & `AllowedComponentProps` & `ComponentCustomProps` - -## Returns - -`CreateComponentPublicInstanceWithMixins`\<`FormGroupApiOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> & - \| \{ -\[`key`: `` `on${Capitalize}` ``\]: (...`args`) => `any` \| `undefined`; -\} - \| \{ -\[`key`: `` `on${Capitalize}` ``\]: (...`args`) => `any` \| `undefined`; -\}, \{ -\}, \{ -\}, \{ -\}, \{ -\}, `ComponentOptionsMixin`, `ComponentOptionsMixin`, `EmitsOptions`, `PublicProps`, \{ -\}, `false`, \{ -\}, \{ -\}\> diff --git a/docs/framework/vue/reference/variables/Subscribe.md b/docs/framework/vue/reference/variables/Subscribe.md new file mode 100644 index 0000000000..14c236154b --- /dev/null +++ b/docs/framework/vue/reference/variables/Subscribe.md @@ -0,0 +1,10 @@ +--- +id: Subscribe +title: Subscribe +--- + +```ts +const Subscribe: SubscribeComponent; +``` + +Defined in: [packages/vue-form/src/Subscribe.public.ts:46](https://github.com/TanStack/form/blob/main/packages/vue-form/src/Subscribe.public.ts#L46) diff --git a/docs/framework/vue/reference/variables/defineFieldGroup.md b/docs/framework/vue/reference/variables/defineFieldGroup.md new file mode 100644 index 0000000000..ca2b11b8be --- /dev/null +++ b/docs/framework/vue/reference/variables/defineFieldGroup.md @@ -0,0 +1,12 @@ +--- +id: defineFieldGroup +title: defineFieldGroup +--- + +```ts +const defineFieldGroup: DefineFieldGroupFn>; +``` + +Defined in: [packages/vue-form/src/FieldGroup/withFields.public.ts:115](https://github.com/TanStack/form/blob/main/packages/vue-form/src/FieldGroup/withFields.public.ts#L115) + +Defines a reusable group of virtual fields. diff --git a/docs/framework/vue/reference/variables/useForm.md b/docs/framework/vue/reference/variables/useForm.md new file mode 100644 index 0000000000..fad1acd82c --- /dev/null +++ b/docs/framework/vue/reference/variables/useForm.md @@ -0,0 +1,34 @@ +--- +id: useForm +title: useForm +--- + +```ts +const useForm: UseFormHook; +``` + +Defined in: [packages/vue-form/src/VueForm/useForm.public.ts:51](https://github.com/TanStack/form/blob/main/packages/vue-form/src/VueForm/useForm.public.ts#L51) + +Creates a Vue form whose instance and lifecycle are owned by the current +component. + +`defaultValues` establish the initial state and inferred form value type. To +update the existing form after creation, pass a reactive options object; +tracked changes are applied without replacing the form instance. + +Call this during the component's setup phase. The form mounts with the +component and is cleaned up when the component unmounts. + +## Example + +```ts +const form = useForm({ + defaultValues: { name: '' }, + onSubmit: ({ value }) => saveProfile(value), +}) +``` + +## Returns + +The Vue form API with typed field, subscription, and form-group +components attached. diff --git a/docs/framework/vue/reference/variables/useStore.md b/docs/framework/vue/reference/variables/useStore.md index f32fb67c8d..233453c58e 100644 --- a/docs/framework/vue/reference/variables/useStore.md +++ b/docs/framework/vue/reference/variables/useStore.md @@ -3,13 +3,11 @@ id: useStore title: useStore --- -# ~~Variable: useStore()~~ - ```ts const useStore: (source, selector?, compare?) => Readonly>; ``` -Defined in: node\_modules/.pnpm/@tanstack+vue-store@0.11.0\_vue@3.5.34\_typescript@5.9.3\_/node\_modules/@tanstack/vue-store/dist/useStore.d.ts:14 +Defined in: node\_modules/.pnpm/@tanstack+vue-store@0.11.1\_vue@3.6.0-rc.9\_typescript@6.0.3\_/node\_modules/@tanstack/vue-store/dist/useStore.d.ts:14 Deprecated alias for [useSelector](../functions/useSelector.md). diff --git a/docs/installation.md b/docs/installation.md index e23e6ecd90..b1ae99d343 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -7,12 +7,13 @@ TanStack Form is compatible with various front-end frameworks, including React, -react: @tanstack/react-form -vue: @tanstack/vue-form -angular: @tanstack/angular-form -solid: @tanstack/solid-form -lit: @tanstack/lit-form -svelte: @tanstack/svelte-form +react: @tanstack/react-form@alpha +angular: @tanstack/angular-form@alpha +preact: @tanstack/preact-form@alpha +vue: @tanstack/vue-form@alpha +solid: @tanstack/solid-form@alpha +svelte: @tanstack/svelte-form@alpha +lit: @tanstack/lit-form@alpha @@ -26,15 +27,13 @@ If you're using a meta-framework, TanStack Form provides additional adapters to - TanStack Start - Next.js -- Remix -react: @tanstack/react-form-start -react: @tanstack/react-form-nextjs -react: @tanstack/react-form-remix +react: @tanstack/react-form-start@alpha +react: @tanstack/react-form-nextjs@alpha @@ -56,10 +55,8 @@ Developer tools are available using [TanStack Devtools](https://tanstack.com/dev -react: @tanstack/react-devtools -react: @tanstack/react-form-devtools -solid: @tanstack/solid-devtools -solid: @tanstack/solid-form-devtools +react: @tanstack/react-devtools@alpha +react: @tanstack/react-form-devtools@alpha diff --git a/docs/migrate-from-v1.md b/docs/migrate-from-v1.md new file mode 100644 index 0000000000..e08030e2fa --- /dev/null +++ b/docs/migrate-from-v1.md @@ -0,0 +1,1088 @@ +--- +id: migrate-from-v1 +title: Migrating from v1 +--- + +TanStack Form v2 keeps the same core idea as v1: create a form with +`useForm`, render fields from the returned form API, and submit with +`form.handleSubmit()`. Most migrations are not a full rewrite, but v2 does +change several React-facing APIs that show up in examples and integration +tests. + +This page is a starting checklist for migrating React apps from v1 to v2. + +## Quick checklist + +- Keep `useForm`, `defaultValues`, `onSubmit`, `form.Field`, and + `form.Subscribe`, but update render props from `field.state.value` and + `field.state.meta` to `field.value` and `field.meta`. +- Always provide `defaultValues` to `useForm`. v2 does not support omitting + them. +- Move field-level `defaultValue` props into form-level `defaultValues`. +- Remove field-level `defaultMeta` props. Model initial validation and error + visibility through validators, `runOnMount`, and `errorVisibility`. +- Change validation from keyed event objects like `{ onChange, onBlur }` to + arrays of validator objects with `run` and `triggers`. +- Change async validator debounce options such as `onChangeAsyncDebounceMs` to + `triggerDebounceMs` on the validator object. +- Change field cross-validation from `onChangeListenTo` / `onBlurListenTo` to + `watchFields` on validators or listeners. +- Replace `mode="array"` fields with `form.ArrayField`. +- Keep array mutations on the `ArrayField` render prop, such as + `array.pushValue(...)`, or use path-based form methods such as + `form.pushFieldValue(...)` when the control lives outside the render prop. +- Rename `form.moveFieldValues` to `form.moveFieldValue`, and replace removed + form methods such as `setFieldMeta` and `validateField` as described in + [Removed and renamed form methods](#removed-and-renamed-form-methods). +- Read errors from `field.errors`, `group.state.errors`, and + `form.state.errors` as validation issue objects. Use `error.message` when + rendering text. +- In form- and group-level validators, build routed errors with + `createErrorMap(...)` and return the map directly. +- Return `createValidationError(...)` from `onSubmit` when a submit handler + needs to route server errors back to form or field state. +- Use `useSelector`, which replaces v1's deprecated `useStore` usage. +- Subscribe to `form.atom` and `field.atom` instead of `form.store` and + `field.store`. +- Use `formOptions(...)` for shared base form options. +- Replace `withForm` components with plain components that accept a `form` prop + typed as `ReactFormType`. +- Replace `useFormGroup` with `form.FormGroup` for scoped sections of the same + form. +- Replace `withFieldGroup` with `defineFieldGroup(...).bindComponent(...)` for + reusable field bundles that map virtual field names to different concrete + form paths. +- Upgrade Vue to version 3.6 or newer when using the Vue adapter. Form + Composition relies on behavior introduced in Vue 3.6. +- Update CommonJS integrations to consume ESM. The v2 packages do not publish + a CommonJS build and require Node.js 18 or newer. +- Upgrade React to version 18 or newer. The v2 React adapter no longer supports + React 17. +- Update CommonJS integrations to consume ESM. The v2 packages do not publish + a CommonJS build and require Node.js 18 or newer. + +## React version + +The v2 React adapter supports React 18 and 19. React 17 is no longer supported, +so upgrade `react`, `react-dom`, and their corresponding type packages before +migrating. If you imported `CrossVersionReactNode` from `@tanstack/react-form`, +import `ReactNode` from `react` instead. + +## Vue version + +The v2 Vue adapter requires Vue 3.6 or newer. At the time of writing, Vue 3.6 +has not yet been released as stable and is available as a release candidate. +We hope Vue 3.6 will be stable by the time TanStack Form v2 becomes stable. + +Form Composition relies on Vue 3.6 behavior to work correctly. Requiring it +from the start lets the Vue adapter support Form Composition without adding a +breaking minimum-version change later in the v2 release line. + +## Package format + +The v2 core, framework, devtools, and server-adapter packages publish ESM +exports only and declare Node.js 18 as their minimum version. Prefer `import` / +`export` syntax, use dynamic `import()` when consuming them from CommonJS, and +make sure any Node-based test, SSR, or build tooling can load ESM dependencies. +There is no separate CommonJS build or `require` export to fall back to. + +## Basic fields + +The v1 simple example and v2 basic example are intentionally similar. The main +render-prop difference is that v2 exposes the subscribed field surface directly. + +```tsx +// v1 + + {(field) => ( + field.handleChange(event.target.value)} + /> + )} + +``` + +```tsx +// v2 + + {(field) => ( + field.handleChange(event.target.value)} + aria-invalid={field.meta.isInvalid} + /> + )} + +``` + +The same applies to common meta and error reads: + +```tsx +// v1 +field.state.value +field.state.meta.isTouched +field.state.meta.isValid +field.state.meta.errors.join(',') +``` + +```tsx +// v2 +field.value +field.meta.isTouched +field.meta.isValid +field.errors.map((error) => error.message).join(',') +``` + +v2 also exposes `field.meta.isInvalid`, which is the inverse of `isValid` and +is convenient for attributes such as `aria-invalid`. + +The v2 React integration tests also assert that fields rerender independently +when sibling fields change. Prefer reading only the subscribed field values and +meta you need in each render prop. + +## Defaults and initial meta + +In v1, a form could rely on field-level `defaultValue` props: + +```tsx +// v1 +const form = useForm({ + defaultValues: {} as Person, +}) + + + {(field) => } + +``` + +In v2, `defaultValues` are required on the form and are the only place to define +initial values: + +```tsx +// v2 +const form = useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, +}) + + + {(field) => } + +``` + +`` was also removed. If v1 code used +`defaultMeta={{ isTouched: true }}` to show errors immediately, replace the +implicit meta state with mount validation and an explicit visibility policy: + +```tsx +// v2 +const form = useForm({ + defaultValues: { + firstName: '', + }, +}) + + (value ? undefined : 'First name is required'), + }, + ]} +> + {(field) => ( + <> + field.handleChange(event.target.value)} + /> + {field.errors.map((error) => ( +

    {error.message}

    + ))} + + )} +
    +``` + +If errors should validate on mount but remain hidden until the user blurs the +field or tries to submit, use a form-level policy such as +`errorVisibility: ({ fieldState, state }) => fieldState.meta.isBlurred || +state.submissionAttempts > 0` instead. + +## Validators + +v1 validators are keyed by event names: + +```tsx +// v1 + + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + onChangeAsyncDebounceMs: 500, + onChangeAsync: async ({ value }) => { + await checkName(value) + return value.includes('error') + ? 'No "error" allowed in first name' + : undefined + }, + }} +/> +``` + +v2 validators are ordered arrays. Each validator has a `run` function or +standard schema, a `triggers` list, and optional behavior like debouncing or +bailing: + +```tsx +// v2 + { + if (value.length === 0) return 'A first name is required' + if (value.length < 3) return 'First name is too short' + }, + triggers: ['change', 'blur'], + triggerDebounceMs: 300, + }, + { + run: async ({ value }) => { + await checkName(value) + return value.toLowerCase().includes('error') + ? 'No "error" allowed in first name' + : undefined + }, + triggers: ['change'], + bailIfInvalid: true, + }, + ]} +/> +``` + +Useful translations: + +| v1 | v2 | +| ------------------------------------- | --------------------------------------------------------------------------------- | +| `validators.onMount` | validator with `runOnMount: true` | +| `validators.onChange` | validator with `triggers: ['change']` | +| `validators.onBlur` | validator with `triggers: ['blur']` | +| `validators.onSubmit` | validator with `triggers: []`, or rely on submit running validators by default | +| `onChangeAsync` | async `run` with `triggers: ['change']` | +| `onChangeAsyncDebounceMs` | `triggerDebounceMs` | +| `onChangeListenTo` / `onBlurListenTo` | `watchFields` | +| `validationLogic: revalidateLogic()` | migrate to explicit `triggers`, `when`, `skipOnSubmit`, and `bailIfInvalid` rules | + +Submission is separate from the `triggers` list: every validator runs during +submission by default. An empty `triggers: []` therefore means "no change or +blur validation, but still validate on submit." Set `skipOnSubmit: true` when a +validator must not run during client submission; do not add `'submit'` to +`triggers`. + +`triggers` can contain strings or trigger config objects. Use config objects +when a validator should only run for some changes: + +```tsx +validators={[ + { + triggers: [ + { + trigger: 'change', + when: ({ value }) => Boolean(value), + }, + ], + watchFields: ['startDate'], + run: ({ value, formApi }) => { + const startDate = formApi.getFieldValue('startDate') + if (value < startDate) return 'End date must be after the start date' + }, + }, +]} +``` + +Predicate callbacks are scope-aware. A `when` callback, a function-valued +`skipOnSubmit`, or a function-valued `triggerDebounceMs` receives `scope` and +`formApi`; field predicates receive the field being validated as `fieldApi`, +while group predicates also receive `groupApi`. For form and group predicates, +an optional `fieldApi` is the field that triggered validation. + +Use `createValidator(...)` when the scheduling policy should be reused with +different validator functions or schemas while preserving their inferred +types: + +```tsx +import { createValidator } from '@tanstack/react-form' + +const validateAfterSubmit = createValidator({ + triggers: [ + { + trigger: 'change', + when: ({ groupApi, formApi }) => + (groupApi?.state.submissionAttempts ?? + formApi.state.submissionAttempts) > 0, + }, + ], +}) + +const validators = [validateAfterSubmit(schema)] +``` + +## Standard schemas + +v1 accepted standard schemas in event-keyed validators: + +```tsx +// v1 +useForm({ + defaultValues, + validators: { + onChange: schema, + }, +}) +``` + +In v2, pass schemas as `run` values inside the validators array: + +```tsx +// v2 +useForm({ + defaultValues, + validators: [ + { + run: schema, + triggers: ['change'], + }, + ], +}) +``` + +The form's `value` remains its editable input state. When a Standard Schema +validator runs successfully during submission, its parsed output is available +in `onSubmit` at the corresponding `schemaOutputs` index. Non-schema entries +are `undefined`. Validators with literal `skipOnSubmit: true` are skipped during +submission, and their slots are typed as `undefined`. Use the parsed entry when +an endpoint expects the schema's output type. + +For schema-led option inference, pass the schema first and the options second. +`formOptions.strictSchema(...)` uses the schema input as the form shape, while +`formOptions.looseSchema(...)` permits editable nullish defaults and combines +them with the schema shape. These option helpers only affect types; the +validators still perform the runtime parsing. + +When manually calling a schema, return `parseIssues(...)` with the failed issue +array. In a field validator it produces field issues; in a form or group +validator it routes issue paths into a form/field map; and in `onSubmit` it +produces a branded submit validation result. The v2 field-group example uses +this helper after calling `schema.safeParse(...)`. + +## Errors and submit results + +v1 examples commonly render errors from `field.state.meta.errors`. In v2, +render from `field.errors` for fields, `group.state.errors` for form groups, and +`form.state.errors` for the form. Each of the group and form collections is an +array. The items are validation issue objects, so render `error.message`. + +```tsx +function FieldError({ field }: { field: AnyFieldApi }) { + return ( + + {field.errors.map((error) => error.message).join('\n')} + + ) +} +``` + +Form- and group-level validators can route errors to the form and individual +fields. Build a map with the `createErrorMap` supplied to `run`, then return the +map itself: + +```tsx +const form = useForm({ + defaultValues: { + firstName: '', + }, + validators: [ + { + triggers: ['change'], + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() + + if (!value.firstName.trim()) { + errors.form = 'Please correct the highlighted fields' + errors.fields.firstName = 'First name is required' + } + + return errors + }, + }, + ], +}) +``` + +`createErrorMap` also accepts an initial `{ form, fields }` object. An empty +returned map is treated as a valid result. +Field-level validators continue to return their own issue, string, issue array, +or a valid result directly. + +Submit handlers can now return a typed validation result. Use +`createValidationError` to route endpoint errors back into form state: + +```tsx +const form = useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, + onSubmit: async ({ value, createValidationError }) => { + const result = await saveUser(value) + + if (!result.ok) { + return createValidationError({ + form: 'Could not save user', + fields: { + firstName: 'Name already exists', + lastName: 'Name already exists', + }, + }) + } + + return null + }, +}) +``` + +`form.handleSubmit()` resolves to the validation-result array for that +submission attempt, so framework examples can await it and continue to native +or server submission when `errors.length === 0`. A thrown or rejected +`onSubmit` marks submission unsuccessful but is not added to that array. Return +`createValidationError(...)` or `parseIssues(...)` when a submit failure should +become validation state. + +## Selectors and atoms + +v1 re-exported `useStore` from `@tanstack/react-store`, but that usage was +deprecated before v2. In v2, use `useSelector` and subscribe to atoms: + +```tsx +// v1 +import { useStore } from '@tanstack/react-store' + +const errors = useStore(form.store, (state) => state.errors) +const fieldErrors = useStore(field.store, (state) => state.meta.errors) +``` + +```tsx +// v2 +import { useSelector } from '@tanstack/react-form' + +const errors = useSelector(form.atom, (state) => state.errors) +const fieldErrors = useSelector(field.atom, (state) => state.meta.errors) +``` + +The same rename applies when subscribing to field groups: + +```tsx +const values = useSelector(fields.atom, (values) => values) +``` + +Reading `form.state` or `group.state` gives an imperative snapshot; it does not +subscribe a React component. Use field render props, `form.Subscribe`, +`group.Subscribe`, or `useSelector` for reactive reads, and keep selectors +focused on the state the component renders. + +## Arrays + +v1 represented array fields with `mode="array"` and exposed array helpers from +the field render prop: + +```tsx +// v1 + + {(field) => ( + <> + {field.state.value.map((_, index) => ( + + {(subField) => ( + subField.handleChange(event.target.value)} + /> + )} + + ))} + + + )} + +``` + +v2 uses a dedicated `form.ArrayField` component for array subscriptions. Its +render prop still exposes array methods, so the direct migration can keep the +mutation next to the rendered array: + +```tsx +// v2 + + {(array) => ( + <> + {array.value.map((_, index) => ( + + {(field) => ( + field.handleChange(event.target.value)} + /> + )} + + ))} + + + )} + +``` + +When the mutation control is outside `ArrayField`, use the path-based form API +instead: + +```tsx +form.pushFieldValue('people', { name: '', age: 0 }) +``` + +The same choice is available for inserting, removing, moving, swapping, +filtering, and clearing values: use the relative methods on `array` or the +field-path methods on `form`. + +The v2 array example calls out the performance reason for this change: +`ArrayField` lets the array shell rerender when the array structure changes +without forcing the whole list to rerender for every item value change. + +For current usage and adapter-specific examples, see [Arrays](./arrays). + +## Removed and renamed form methods + +The v2 form API is smaller than v1's. It reads and updates values, mutates +arrays, runs form-level validation, submits, and resets. Field metadata now +lives on the field API, validators and submit results produce errors instead +of code writing them directly, and nothing replaces the internal +field-registry helpers. + +| v1 | v2 | +| ------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | +| `moveFieldValues(name, from, to)` | `moveFieldValue(name, from, to)` | +| `setFieldMeta(name, updater)` | `setFieldValue` update options, `handleSubmit()`, or `errorVisibility` | +| `getFieldMeta(name)` | `field.meta` | +| `resetFieldMeta(...)` | `resetField(name)`, `field.reset()`, or `reset(form.state.values, { updateDefaultValues: false })` | +| `validateField(name, cause)` | validator `triggers` and `watchFields` | +| `validateAllFields(cause)` | `handleSubmit()` | +| `validateArrayFieldsStartingFrom(...)` | array methods run change validation unless `causeValidation: false` | +| `validate(cause)` | `validate('change' \| 'blur')`, which runs form-level validators only | +| `getAllErrors()` | `form.state.errors`, `field.errors`, `form.state.isValid`, or the `handleSubmit()` result | +| `setErrorMap(errorMap)` | errors returned from validators, `createValidationError(...)` from `onSubmit`, or `serverState` | +| `deleteField(name)` | `removeFieldValue` / `filterFieldValues` for array items, `setFieldValue` on the parent object | +| `getFieldInfo(name)` | none; it exposed internal field registration | +| `parseValuesWithSchema(schema)` and its `Async` variant | a schema validator plus `schemaOutputs` in `onSubmit`, or call the schema directly | +| `getFormGroupMeta(name)` | `group.state` from `form.FormGroup` | + +### Field metadata + +v1 code often wrote field meta directly, for example to mark a field as touched +when its value was set programmatically. In v2, meta is derived from updates. +Pass `FieldUpdateOptions` to `setFieldValue`, the array methods, or +`field.handleChange` to control what an update marks: + +```tsx +// v1 +form.setFieldValue('firstName', 'Ada', { + dontUpdateMeta: true, + dontValidate: true, +}) +form.setFieldMeta('firstName', (prev) => ({ ...prev, isTouched: true })) +``` + +```tsx +// v2 +form.setFieldValue('firstName', 'Ada', { + markAsTouched: true, + markAsDirty: false, + causeValidation: false, +}) +``` + +| v1 update option | v2 update option | +| ------------------ | -------------------------------------------- | +| `dontUpdateMeta` | `markAsTouched: false`, `markAsDirty: false` | +| `dontValidate` | `causeValidation: false` | +| `dontRunListeners` | none | + +To touch every field before showing errors, call `form.handleSubmit()`, which +marks all registered fields as touched. To show errors without touching fields, +configure `errorVisibility` instead. + +Read meta from the field API, as `field.meta` in a render prop or with +`useSelector(field.atom, (state) => state.meta)`. The form API does not look up +meta by path. + +To clear meta, `form.resetField(name)` and `field.reset()` reset one field's +value and meta. To clear every field's meta but keep the values the user +entered, reset the form to its current values without moving the default +baseline: + +```tsx +form.reset(form.state.values, { updateDefaultValues: false }) +``` + +This also clears form-level errors, submission state, and dirty history. + +### On-demand validation + +v2 has no public method that validates a single field or every field outside +submission. Express when a field validates through its validators instead: + +- Use `triggers` to choose the events that run a validator. +- Use `watchFields` to rerun a validator when another field changes, which + covers most v1 `validateField` calls made from another field's `onChange`. +- Call `form.handleSubmit()` to validate every field and the form together. + Unlike `validateAllFields`, it also calls `onSubmit` when validation passes. + It resolves to the error results, so an empty array means everything is + valid. + +`form.validate('change')` and `form.validate('blur')` still exist, but they run +form-level validators only. Field validators do not run. + +### Errors + +v2 does not write error maps directly. Return errors from a validator, or from +`onSubmit` with `createValidationError(...)` as shown in +[Errors and submit results](#errors-and-submit-results). For server-rendered +errors, pass `serverState` to `useForm`. + +To read errors, `form.state.errors` holds form-level errors only. Errors routed +to fields stay on the fields, available as `field.errors`. Use +`form.state.isValid` to check both levels at once. + +### Schemas + +`parseValuesWithSchema` checked the current values against a schema without +storing errors. To keep that behavior, call the schema yourself: + +```tsx +const result = await schema['~standard'].validate(form.state.values) + +if (result.issues) { + // handle issues +} +``` + +To validate with the schema and use its parsed output, add it to `validators` +and read `schemaOutputs` in `onSubmit`, as described in +[Standard schemas](#standard-schemas). + +## Shared form options + +For extracted components, v1 composition examples often use a custom +`useAppForm` hook plus `withForm` from `createFormHook`. v2 still supports app +form hooks, but `withForm` was removed. The smaller building block for shared +defaults is `formOptions(...)`: + +```tsx +import { formOptions } from '@tanstack/react-form' + +export const sharedFormOptions = formOptions({ + defaultValues: { + firstName: '', + lastName: '', + address: { + street: '', + country: '', + }, + }, +}) + +const form = useForm({ + ...sharedFormOptions, + onSubmit: ({ value }) => { + console.log(value) + }, +}) +``` + +When typing extracted components, prefer the v2 public types covered in +[Splitting forms](./splitting-forms): + +```tsx +import type { AnyReactFormApi, FieldWithValue } from '@tanstack/react-form' + +function StringField({ field }: { field: FieldWithValue }) { + return ( + field.handleChange(event.target.value)} + /> + ) +} + +function SubmitButton({ form }: { form: AnyReactFormApi }) { + return ( + [state.canSubmit, state.isSubmitting]}> + {([canSubmit, isSubmitting]) => ( + + )} + + ) +} +``` + +`AnyReactFormApi` and `FieldWithValue` intentionally erase unrelated type +details for generic UI pieces. Use `ReactFormType` when a +component needs the option-derived data and field-path surface. Options created +with `appFormOptions` also retain their app component map. Submit error types +may intentionally widen when the shared options omit `onSubmit` so it can be +supplied later. Prefer these aliases over spelling the full `FormApi` or +`FieldApi` generic lists in application components. + +For components that previously used `withForm`, pass the form API explicitly and +type it from the same options object: + +```tsx +// v1 +const AddressFields = withForm({ + defaultValues: { + address: { + street: '', + country: '', + }, + }, + render: ({ form }) => ( + <> + {/* ... */} + {/* ... */} + + ), +}) +``` + +```tsx +// v2 +import { formOptions } from '@tanstack/react-form' +import type { ReactFormType } from '@tanstack/react-form' + +export const profileFormOptions = formOptions({ + defaultValues: { + address: { + street: '', + country: '', + }, + }, +}) + +interface AddressFieldsProps { + form: ReactFormType +} + +function AddressFields({ form }: AddressFieldsProps) { + return ( + <> + {/* ... */} + {/* ... */} + + ) +} +``` + +## Form groups and field groups + +Replace v1 form group usage with `form.FormGroup`. It is the v2 tool for +multi-step forms and scoped validation when a section is part of one concrete +form shape: + +```tsx + goToNextStep()}> + {(group) => ( + <> + + {(field) => ( + field.handleChange(event.target.value)} + /> + )} + + + + )} + +``` + +Inside the group, field names are scoped. `name="name"` becomes +`guestDetails.name`, `group.ArrayField name="guests"` becomes +`guestDetails.guests`, and watched fields are scoped the same way. + +Group submission is its own validation cycle. `group.handleSubmit()` validates +the group and its fields and then calls the group's `onSubmit` or +`onSubmitInvalid`; `form.handleSubmit()` does not also run the group's +validators. Keep any rules required for final whole-form submission in the +form-level validator pipeline as well. `group.handleSubmit()` resolves to an +error array, and `group.state.errors` is an array. + +For a field inside a mounted group, scalar state exposed to `errorVisibility` +(such as `submissionAttempts` and `isDirty`) is scoped to the nearest group. +The callback's `values` and `errors` remain form-wide. + +v1's `withFieldGroup` HOC was removed. v2 replaces it with +`defineFieldGroup(...)` for reusable field bundles. Use it when a component +should not care where its fields live in the parent form: + +```tsx +import { defineFieldGroup } from '@tanstack/react-form' + +const rangeFieldGroup = defineFieldGroup(({ strict }) => ({ + lower: strict(), + upper: strict(), +})) + +function RangeFieldsImpl({ + fields, +}: { + fields: typeof rangeFieldGroup.fields +}) { + return ( + <> + + {(field) => ( + field.handleChange(event.target.value)} + /> + )} + + { + const lower = fields.getFieldValue('lower') + if (Number(value) < Number(lower)) { + return 'Upper bound must be greater than lower bound' + } + }, + }, + ]} + > + {(field) => ( + field.handleChange(event.target.value)} + /> + )} + + + ) +} + +export const RangeFields = rangeFieldGroup.bindComponent( + RangeFieldsImpl, + 'fields', +) +``` + +Then bind virtual names to concrete paths wherever the group is used: + +```tsx + +``` + +Use this v2 pattern to migrate v1 `withFieldGroup` components that were reused +against different field paths. If you are using app form components from +`createFormHook`, wrap components that expect an injected field API with +`getFormHookHelpers()`, then define field groups with `defineAppFieldGroup`: + +```tsx +import { createFormHook, getFormHookHelpers } from '@tanstack/react-form' + +const { fieldComponent } = getFormHookHelpers() +const AppTextField = fieldComponent.strict(StringField, 'field') + +const { appFormOptions, useAppForm, defineAppFieldGroup } = createFormHook({ + fieldComponents: { + TextField: AppTextField, + }, + formComponents: {}, +}) + +const contactFieldGroup = defineAppFieldGroup(({ strict }) => ({ + name: strict(), +})) +``` + +## Listeners + +v1 listeners were event-keyed objects. v2 listeners use a validator-like array +shape with `run`, `triggers`, and optional `triggerDebounceMs`. A trigger can be +a string or `{ trigger, when }`, and debounce can be a number or a callback. +Form listeners support `change`, `blur`, `submit`, `mount`, and `reset`; field +listeners additionally support `unmount`. + +```tsx +// v2 + { + fieldApi.handleChange(Number(value).toFixed(2)) + }, + }, + ]} +/> +``` + +For cross-field field listeners, put the source fields in `watchFields`. In +`form.FormGroup` and field-group-bound components, `watchFields` uses the scoped +or virtual field names and v2 resolves them to the concrete form paths. +Form-level listeners instead observe propagated events and receive an optional +source field as `triggerFieldApi`. It is present for propagated field changes +and blurs, but absent for form-originated events such as mount, reset, and +submit. + +## Server and framework integrations + +The v1 examples include Next server actions, Remix, and TanStack Start examples +that use v1's keyed validators and store-level errors. The v2 examples show a +new server-validation model in `@tanstack/react-form-start` and a Next.js +example with shared isomorphic validation. + +Key changes: + +- Import `serverValidateHelper` from `@tanstack/react-form`, then import the + framework adapter from `@tanstack/react-form-start`, + `@tanstack/react-form-nextjs`. +- Share common form configuration with `formOptions(...)`. +- Return the `createErrorMap()` map directly from framework/server validators + when routing form and field errors. +- Combine `triggers: ['server']` with `skipOnSubmit: true` for a form validator + that must run only on the server. Server-triggered validators otherwise still + run during client submission because submission is enabled by default. +- Next.js and Remix adapters, and the Start adapter when no callback override is + supplied, resolve to + `{ success: true, values, schemaOutputs }` or + `{ success: false, serverState }`. Pass the failure's `serverState` back to + `useForm({ ...formOpts, serverState })` on the client. +- `@tanstack/react-form-remix` was removed. + +For example, a Start adapter is configured separately from the shared form +options: + +```tsx +import { serverValidateHelper } from '@tanstack/react-form' +import { start } from '@tanstack/react-form-start' + +const { createServerValidate } = serverValidateHelper({ + framework: start(), +}) + +const serverValidate = createServerValidate(formOpts) +``` + +In `formOpts`, a server-only validator returns its routed error map directly: + +```tsx +{ + triggers: ['server'], + skipOnSubmit: true, + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() + + if (value.age < 13) { + errors.fields.age = 'You must be at least 13' + } + + return errors + }, +} +``` + +Client rendering still follows the same v2 field surface: + +```tsx + + {(field) => ( + <> + field.handleChange(Number(event.target.value))} + /> + {field.errors.map((error) => ( +
    + {error.message} +
    + ))} + + )} +
    +``` + +## Migration order for an app + +1. Upgrade imports and keep the smallest possible form compiling with + ESM `import` syntax, `useForm`, `defaultValues`, `form.Field`, and + `form.handleSubmit()`. +2. Move every field-level `defaultValue` into form-level `defaultValues` and + remove `defaultMeta`. +3. Update field render props from `field.state.*` to the direct v2 surface. +4. Replace `useStore(...store...)` with `useSelector(...atom...)`. +5. Convert validators and listeners to arrays, paying special attention to the + default submit behavior. +6. Convert arrays from `mode="array"` to `form.ArrayField`; keep relative + mutators on its render prop or move them to path-based form methods. +7. Return `createErrorMap(...)` directly from form, group, and server validators, + and convert submitted endpoint errors to `createValidationError(...)`. +8. Revisit composition: use `formOptions(...)` for shared options, + `ReactFormType` for extracted form props, + `form.FormGroup` for scoped sections, and + `defineFieldGroup(...).bindComponent(...)` for reusable field bundles. +9. Re-run React integration tests around validation timing, field rerenders, + groups, server error hydration, and array mutations. These are the areas + where v2 intentionally tightened behavior. diff --git a/docs/overview.md b/docs/overview.md index 4ea563e014..5a85cfb25b 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -27,7 +27,7 @@ By providing a complete solution for these challenges, TanStack Form empowers de In the example below, you can see TanStack Form in action with the React framework adapter: -[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/main/examples/react/simple) +[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/alpha/examples/react/simple) @@ -66,22 +66,30 @@ export default function App() { {/* A type-safe field component*/} - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined, - onChangeAsyncDebounceMs: 500, - onChangeAsync: async ({ value }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return ( - value.includes('error') && 'No "error" allowed in first name' - ) + validators={[ + { + run: ({ value }) => + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + triggers: ['change'], }, - }} - children={(field) => { + { + run: async ({ value }) => { + await new Promise((resolve) => setTimeout(resolve, 1000)) + return ( + value.includes('error') && + 'No "error" allowed in first name' + ) + }, + triggers: ['change'], + triggerDebounceMs: 500, + }, + ]} + > + {(field) => { // Avoid hasty abstractions. Render props are great! return ( <> @@ -89,7 +97,7 @@ export default function App() { field.handleChange(e.target.value)} /> @@ -97,29 +105,29 @@ export default function App() { ) }} - /> +
    - ( + + {(field) => ( <> field.handleChange(e.target.value)} /> )} - /> +
    [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( + > + {([canSubmit, isSubmitting]) => ( <> )} - /> + ) @@ -162,10 +170,10 @@ import type { AnyFieldApi } from '@tanstack/react-form' export function FieldInfo({ field }: { field: AnyFieldApi }) { return ( <> - {field.state.meta.isTouched && !field.state.meta.isValid ? ( - {field.state.meta.errors.join(',')} + {field.meta.isTouched && field.meta.isInvalid ? ( + {field.errors.map((error) => error.message).join(',')} ) : null} - {field.state.meta.isValidating ? 'Validating...' : null} + {field.meta.isValidating ? 'Validating...' : null} ) } @@ -173,361 +181,145 @@ export function FieldInfo({ field }: { field: AnyFieldApi }) { -# Vue - -In the example below, you can see TanStack Form in action with the Vue framework adapter: - -[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/main/examples/vue/simple) - - - -```vue title="App.vue" - - - -``` - -```vue title="FieldInfo.vue" - - - -``` - - - -# Angular +# Preact -In the example below, you can see TanStack Form in action with the Angular framework adapter: +In the example below, you can see TanStack Form in action with the Preact framework adapter: -[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/main/examples/angular/simple) +[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/alpha/examples/preact/simple) -```angular-ts title="app.component.ts" -import { Component } from '@angular/core' -import { TanStackField, injectForm, injectStore } from '@tanstack/angular-form' -import type { - FieldValidateAsyncFn, - FieldValidateFn, -} from '@tanstack/angular-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` -
    -
    - - - - @if (firstName.api.state.meta.isTouched) { - @for (error of firstName.api.state.meta.errors; track $index) { -
    - {{ error }} -
    - } - } - @if (firstName.api.state.meta.isValidating) { -

    Validating...

    - } -
    -
    -
    - - - - -
    - - -
    - `, -}) -export class AppComponent { - firstNameValidator: FieldValidateFn = ({ value }) => - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined - - firstNameAsyncValidator: FieldValidateAsyncFn = async ({ - value, - }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value.includes('error') && 'No "error" allowed in first name' - } - - form = injectForm({ - defaultValues: { - firstName: '', - lastName: '', - }, - onSubmit({ value }) { - // Do something with form data - console.log(value) - }, - }) - - canSubmit = injectStore(this.form, (state) => state.canSubmit) - isSubmitting = injectStore(this.form, (state) => state.isSubmitting) - - handleSubmit(event: SubmitEvent) { - event.preventDefault() - event.stopPropagation() - this.form.handleSubmit() - } -} -``` - - - -# Solid - -In the example below, you can see TanStack Form in action with the Solid framework adapter: - -[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/main/examples/solid/simple) - - +```tsx title="App.tsx" +import { render } from 'preact' +import { useForm } from '@tanstack/preact-form' -```ts title="App.tsx" -/* @refresh reload */ -import { render } from 'solid-js/web' -import { createForm } from '@tanstack/solid-form' -import { FieldInfo } from './FieldInfo.tsx'; +import { FieldInfo } from './FieldInfo.tsx' -function App() { - const form = createForm(() => ({ +export default function App() { + const form = useForm({ defaultValues: { firstName: '', lastName: '', }, onSubmit: async ({ value }) => { - // Do something with form data console.log(value) }, - })) + }) return (

    Simple Form Example

    { - e.preventDefault() - e.stopPropagation() - form.handleSubmit() + onSubmit={(event) => { + event.preventDefault() + event.stopPropagation() + void form.handleSubmit() }} >
    - {/* A type-safe field component*/} - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined, - onChangeAsyncDebounceMs: 500, - onChangeAsync: async ({ value }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return ( - value.includes('error') && 'No "error" allowed in first name' - ) + validators={[ + { + run: ({ value }) => + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + triggers: ['change'], }, - }} - children={(field) => { - // Avoid hasty abstractions. Render props are great! - return ( - <> - - field().handleChange(e.target.value)} - /> - - - ) - }} - /> + { + run: async ({ value }) => { + await new Promise((resolve) => setTimeout(resolve, 1000)) + return ( + value.includes('error') && + 'No "error" allowed in first name' + ) + }, + triggers: ['change'], + triggerDebounceMs: 500, + }, + ]} + > + {(field) => ( + <> + + + field.handleChange(event.currentTarget.value) + } + aria-invalid={field.meta.isInvalid} + /> + + + )} +
    - ( + + {(field) => ( <> - + field().handleChange(e.target.value)} + id={field.name} + name={field.name} + value={field.value} + onBlur={field.handleBlur} + onInput={(event) => + field.handleChange(event.currentTarget.value) + } + aria-invalid={field.meta.isInvalid} /> - + )} - /> +
    ({ - canSubmit: state.canSubmit, - isSubmitting: state.isSubmitting, - })} - children={(state) => { - return ( - - ) - }} - /> + + + )} +
    ) } -const root = document.getElementById('root') - -render(() => , root!) +render(, document.getElementById('root')!) ``` -```ts title="FieldInfo.tsx" -import type { AnyFieldApi } from '@tanstack/solid-form' - -export interface FieldInfoProps { - field: AnyFieldApi -} +```tsx title="FieldInfo.tsx" +import type { AnyFieldApi } from '@tanstack/preact-form' -export function FieldInfo(props: FieldInfoProps) { +export function FieldInfo({ field }: { field: AnyFieldApi }) { return ( <> - {props.field.state.meta.isTouched && !props.field.state.meta.isValid ? ( - {props.field.state.meta.errors.join(',')} + {field.meta.isTouched && field.meta.isInvalid ? ( + + {field.errors.map((error) => error.message).join(', ')} + ) : null} - {props.field.state.meta.isValidating ? 'Validating...' : null} + {field.meta.isValidating ? 'Validating...' : null} ) } @@ -535,178 +327,267 @@ export function FieldInfo(props: FieldInfoProps) { -# Svelte +# Solid -In the example below, you can see TanStack Form in action with the Svelte framework adapter: +In the example below, you can see TanStack Form in action with the Solid framework adapter: -[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/main/examples/svelte/simple) +[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/alpha/examples/solid/simple) -```svelte title="App.svelte" - -
    { - e.preventDefault() - e.stopPropagation() - form.handleSubmit() - }} -> -

    TanStack Form - Svelte Demo

    - - - value.length < 3 ? 'Not long enough' : undefined, - onChangeAsyncDebounceMs: 500, - onChangeAsync: async ({ value }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value.includes('error') && 'No "error" allowed in first name' - }, - }} - > - {#snippet children(field)} -
    - - field.handleBlur()} - oninput={(e: Event) => { - const target = e.target as HTMLInputElement - field.handleChange(target.value) - }} - /> - -
    - {/snippet} -
    - - value.length < 3 ? 'Not long enough' : undefined, - }} - > - {#snippet children(field)} -
    - - field.handleBlur()} - oninput={(e: Event) => { - const target = e.target as HTMLInputElement - field.handleChange(target.value) - }} - /> - -
    - {/snippet} -
    - - {#snippet children(field)} -
    - - field.handleChange(!field.state.value)} - checked={field.state.value} - onblur={() => field.handleBlur()} - id={field.name} - type="checkbox" - /> -
    - {#if field.state.value} - - value.length === 0 ? 'If you have a job, you need a title' : null, - }} + return ( +
    +

    Simple Form Example

    + { + event.preventDefault() + event.stopPropagation() + form.handleSubmit() + }} + > +
    + + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + triggers: ['change'], + }, + { + run: async ({ value }) => { + await new Promise((resolve) => setTimeout(resolve, 1000)) + return ( + value.includes('error') && + 'No "error" allowed in first name' + ) + }, + triggers: ['change'], + triggerDebounceMs: 500, + }, + ]} + > + {(field) => ( + <> + + + field().handleChange(event.currentTarget.value) + } + aria-invalid={field().meta.isInvalid} + /> + + + )} + +
    +
    + + {(field) => ( + <> + + + field().handleChange(event.currentTarget.value) + } + aria-invalid={field().meta.isInvalid} + /> + + + )} + +
    + [state.canSubmit, state.isSubmitting] as const} > - {#snippet children(field)} -
    - - { - const target = e.target as HTMLInputElement - field.handleChange(target.value) + {(state) => ( + <> + +
    - {/snippet} - - {/if} - {/snippet} - -
    - ({ - canSubmit: state.canSubmit, - isSubmitting: state.isSubmitting, - })} - > - {#snippet children({ canSubmit, isSubmitting })} - - {/snippet} - - -
    - + > + Reset + + + )} +
    + +
    + ) +} + +render(() => , document.getElementById('root')!) ``` -```svelte title="FieldInfo.svelte" - +export function FieldInfo(props: { field: Accessor }) { + return ( + <> + + + + {(error, index) => ( + <> + {index() > 0 ? ', ' : ''} + {error.message} + + )} + + + + Validating... + + ) +} +``` -{#if field.state.meta.isTouched} - {#each field.state.meta.errors as error} - {error} - {/each} - {field.state.meta.isValidating ? 'Validating...' : ''} -{/if} + + +# Angular + +In the example below, you can see TanStack Form in action with the Angular framework adapter: + +[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/alpha/examples/angular/simple) + + + +```angular-ts title="app.component.ts" +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { + TanStackField, + injectForm, + injectSelector, +} from '@tanstack/angular-form' + +@Component({ + selector: 'app-root', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TanStackField], + template: ` +
    +

    Simple Form Example

    +
    + + + + + + + + +
    + + +
    +
    +
    + `, +}) +export class AppComponent { + firstNameValidators = [ + { + run: ({ value }: { value: string }) => + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + triggers: ['change'] as const, + }, + { + run: async ({ value }: { value: string }) => { + await new Promise((resolve) => setTimeout(resolve, 1000)) + return value.includes('error') + ? 'No "error" allowed in first name' + : undefined + }, + triggers: ['change'] as const, + triggerDebounceMs: 500, + }, + ] + + form = injectForm({ + defaultValues: { firstName: '', lastName: '' }, + onSubmit: async ({ value }) => console.log(value), + }) + + canSubmit = injectSelector(this.form, (state) => state.canSubmit) + isSubmitting = injectSelector(this.form, (state) => state.isSubmitting) + + handleSubmit(event: SubmitEvent) { + event.preventDefault() + event.stopPropagation() + void this.form.handleSubmit() + } +} ``` @@ -715,23 +596,35 @@ In the example below, you can see TanStack Form in action with the Svelte framew In the example below, you can see TanStack Form in action with the Lit framework adapter: -[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/main/examples/lit/simple) +[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/alpha/examples/lit/simple) ```ts title="index.ts" import { LitElement, html, nothing } from 'lit' import { customElement } from 'lit/decorators.js' - import { TanStackFormController } from '@tanstack/lit-form' -import { repeat } from 'lit/directives/repeat.js' +import type { AnyFieldApi } from '@tanstack/lit-form' + +function fieldInfo(field: AnyFieldApi) { + return html` + ${ + field.meta.isTouched && field.meta.isInvalid + ? html` + ${field.errors.map((error) => error.message).join(', ')} + ` + : nothing + } + ${field.meta.isValidating ? 'Validating...' : nothing} + ` +} @customElement('tanstack-form-demo') export class TanStackFormDemo extends LitElement { - #form = new TanStackFormController(this, { + private form = new TanStackFormController(this, { defaultValues: { firstName: '', lastName: '', }, - onSubmit({ value }) { + onSubmit: async ({ value }) => { // Do something with form data console.log(value) }, @@ -740,103 +633,351 @@ export class TanStackFormDemo extends LitElement { render() { return html`
    { - e.preventDefault() - e.stopPropagation() - this.#form.api.handleSubmit() + @submit=${(event: SubmitEvent) => { + event.preventDefault() + event.stopPropagation() + void this.form.api.handleSubmit() }} > - ${this.#form.field( +
    + ${this.form.field( { - name: `firstName`, - validators: { - onChange: ({ value }) => - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined, - onChangeAsyncDebounceMs: 500, - onChangeAsync: async ({ value }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return ( - value.includes('error') && - 'No "error" allowed in first name' - ) + name: 'firstName', + validators: [ + { + run: ({ value }) => + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + triggers: ['change'], }, - }, - }, - (field) => { - return html`
    - - - ${field.state.meta.isTouched && !field.state.meta.isValid - ? html`${repeat( - field.state.meta.errors, - (__, idx) => idx, - (error) => { - return html`
    ${error}
    ` - }, - )}` - : nothing} - ${field.state.meta.isValidating - ? html`

    Validating...

    ` - : nothing} -
    ` + { + run: async ({ value }) => { + await new Promise((resolve) => setTimeout(resolve, 1000)) + return value.includes('error') + ? 'No "error" allowed in first name' + : undefined + }, + triggers: ['change'], + triggerDebounceMs: 500, + }, + ], }, + (field) => html` + + field.handleBlur()} + @input=${(event: InputEvent) => + field.handleChange( + (event.currentTarget as HTMLInputElement).value, + )} + aria-invalid=${field.meta.isInvalid ? 'true' : 'false'} + /> + ${fieldInfo(field)} + `, )}
    - ${this.#form.field( - { - name: `lastName`, - }, - (field) => { - return html`
    - - -
    ` - }, + ${this.form.field( + { name: 'lastName' }, + (field) => html` + + field.handleBlur()} + @input=${(event: InputEvent) => + field.handleChange( + (event.currentTarget as HTMLInputElement).value, + )} + aria-invalid=${field.meta.isInvalid ? 'true' : 'false'} + /> + ${fieldInfo(field)} + `, )}
    + ${this.form.subscribe( + (state) => [state.canSubmit, state.isSubmitting] as const, + ([canSubmit, isSubmitting]) => html` + + + `, + )} +
    + ` + } +} +``` + +# Svelte + +In the example below, you can see TanStack Form in action with the Svelte framework adapter: + +[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/alpha/examples/svelte/simple) + + + +```svelte title="App.svelte" + - - - ` - } + {/snippet} +
    + + +``` + +```svelte title="FieldInfo.svelte" + + +{#if field.meta.isTouched && field.meta.isInvalid} + + {field.errors.map((error) => error.message).join(', ')} + +{/if} +{#if field.meta.isValidating}Validating...{/if} +``` + + + +# Vue + +In the example below, you can see TanStack Form in action with the Vue framework adapter: + +[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/alpha/examples/vue/simple) + + + +```vue title="App.vue" + + + ``` +```vue title="FieldInfo.vue" + + + +``` + + + +> Other framework adapters are coming soon and are already supported in the stable version of TanStack Form. + ## You talked me into it, so what now? -- Learn TanStack Form at your own pace with our thorough [Walkthrough Guide](./installation) and [API Reference](./reference/classes/FormApi). +- Learn TanStack Form at your own pace with our thorough [Walkthrough Guide](./installation) and [API Reference](./reference/interfaces/FormApi). diff --git a/docs/philosophy.md b/docs/philosophy.md index 9628ebbd09..1cee2bce77 100644 --- a/docs/philosophy.md +++ b/docs/philosophy.md @@ -37,33 +37,6 @@ This comes with a number of advantages: - **Enhanced conditional logic**: You can easily conditionally show/hide fields based on the form state. - **Debugging**: You can easily log the form state to the console to debug issues. -## Generics are grim - -You should never need to pass a generic or use an internal type when leveraging TanStack Form. This is because we've designed the library to infer everything from runtime defaults. - -When writing sufficiently correct TanStack Form code, you should not be able to distinguish between JavaScript usage and TypeScript usage, with the exception of any type casts you might do of runtime values. - -Instead of: - -```ts -useForm() -``` - -You should do: - -```ts -interface Person { - name: string - age: number -} - -const defaultPerson: Person = { name: 'Bill Luo', age: 24 } - -useForm({ - defaultValues: defaultPerson, -}) -``` - ## Libraries are liberating One of the main objectives of TanStack Form is that you should be wrapping it into your own component system or design system. @@ -72,7 +45,7 @@ To support this, we have a number of utilities that make it easier to build your ```ts // Exported from your own library with pre-bound components for your forms. -export const { useAppForm, withForm } = createFormHook(/* options */) +export const { useAppForm } = createFormHook(/* options */) ``` Without doing so, you're adding substantially more boilerplate to your apps and making your forms less consistent and user-friendly. diff --git a/docs/reference/classes/FieldApi.md b/docs/reference/classes/FieldApi.md deleted file mode 100644 index 58b37e60cd..0000000000 --- a/docs/reference/classes/FieldApi.md +++ /dev/null @@ -1,785 +0,0 @@ ---- -id: FieldApi -title: FieldApi ---- - -# Class: FieldApi\ - -Defined in: [packages/form-core/src/FieldApi.ts:520](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L520) - -A class representing the API for managing a form field. - -Normally, you will not need to create a new `FieldApi` instance directly. -Instead, you will use a framework hook/function like `useField` or `createField` -to create a new instance for you that uses your framework's reactivity model. -However, if you need to create a new instance manually, you can do so by calling -the `new FieldApi` constructor. - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* [`DeepKeys`](../type-aliases/DeepKeys.md)\<`TParentData`\> - -### TData - -`TData` *extends* [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Constructors - -### Constructor - -```ts -new FieldApi(opts): FieldApi; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:712](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L712) - -Initializes a new `FieldApi` instance. - -#### Parameters - -##### opts - -[`FieldApiOptions`](../interfaces/FieldApiOptions.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -#### Returns - -`FieldApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Properties - -### form - -```ts -form: FormApi; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:612](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L612) - -A reference to the form API instance. - -#### Implementation of - -```ts -FieldLikeAPI.form -``` - -*** - -### name - -```ts -name: TName; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:640](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L640) - -The field name. - -#### Implementation of - -```ts -FieldLikeAPI.name -``` - -*** - -### options - -```ts -options: FieldApiOptions; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:644](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L644) - -The field options. - -#### Implementation of - -```ts -FieldLikeAPI.options -``` - -*** - -### store - -```ts -store: ReadonlyStore>; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:672](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L672) - -The field state store. - -#### Implementation of - -```ts -FieldLikeAPI.store -``` - -*** - -### timeoutIds - -```ts -timeoutIds: object; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:703](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L703) - -#### formListeners - -```ts -formListeners: Record | null>; -``` - -#### listeners - -```ts -listeners: Record | null>; -``` - -#### validations - -```ts -validations: Record | null>; -``` - -## Accessors - -### state - -#### Get Signature - -```ts -get state(): FieldLikeState; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:700](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L700) - -The current field state. - -##### Returns - -`FieldLikeState`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`\> - -## Methods - -### clearValues() - -```ts -clearValues(options?): void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1214](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1214) - -Clear all values from the array. - -#### Parameters - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`void` - -*** - -### getInfo() - -```ts -getInfo(): FieldInfo; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1100](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1100) - -Gets the field information object. - -#### Returns - -`FieldInfo`\<`TParentData`\> - -#### Implementation of - -```ts -FieldLikeAPI.getInfo -``` - -*** - -### getMeta() - -```ts -getMeta(): FieldLikeMeta; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1064](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1064) - -#### Returns - -`FieldLikeMeta`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`\> - -#### Implementation of - -```ts -FieldLikeAPI.getMeta -``` - -*** - -### ~~getValue()~~ - -```ts -getValue(): TData; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1041](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1041) - -Gets the current field value. - -#### Returns - -`TData` - -#### Deprecated - -Use `field.state.value` instead. - -*** - -### handleBlur() - -```ts -handleBlur(): void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1739](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1739) - -Handles the blur event. - -#### Returns - -`void` - -*** - -### handleChange() - -```ts -handleChange(updater): void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1732](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1732) - -Handles the change event. - -#### Parameters - -##### updater - -[`Updater`](../type-aliases/Updater.md)\<`TData`\> - -#### Returns - -`void` - -*** - -### insertValue() - -```ts -insertValue( - index, - value, - options?): void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1123](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1123) - -Inserts a value at the specified index, shifting the subsequent values to the right. - -#### Parameters - -##### index - -`number` - -##### value - -`TData` *extends* `any`[] ? `TData`\<`TData`\>\[`number`\] : `never` - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`void` - -*** - -### mount() - -```ts -mount(): () => void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:859](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L859) - -Mounts the field instance to the form. - -#### Returns - -A function to unmount the field instance. - -```ts -(): void; -``` - -##### Returns - -`void` - -#### Implementation of - -```ts -FieldLikeAPI.mount -``` - -*** - -### moveValue() - -```ts -moveValue( - aIndex, - bIndex, - options?): void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1198](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1198) - -Moves the value at the first specified index to the second specified index. - -#### Parameters - -##### aIndex - -`number` - -##### bIndex - -`number` - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`void` - -*** - -### parseValueWithSchema() - -```ts -parseValueWithSchema(schema): - | StandardSchemaV1Issue[] - | undefined; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1782](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1782) - -Parses the field's value with the given schema and returns -issues (if any). This method does NOT set any internal errors. - -#### Parameters - -##### schema - -[`StandardSchemaV1`](../type-aliases/StandardSchemaV1.md)\<`TData`, `unknown`\> - -The standard schema to parse this field's value with. - -#### Returns - - \| [`StandardSchemaV1Issue`](../interfaces/StandardSchemaV1Issue.md)[] - \| `undefined` - -*** - -### parseValueWithSchemaAsync() - -```ts -parseValueWithSchemaAsync(schema): Promise< - | StandardSchemaV1Issue[] -| undefined>; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1794](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1794) - -Parses the field's value with the given schema and returns -issues (if any). This method does NOT set any internal errors. - -#### Parameters - -##### schema - -[`StandardSchemaV1`](../type-aliases/StandardSchemaV1.md)\<`TData`, `unknown`\> - -The standard schema to parse this field's value with. - -#### Returns - -`Promise`\< - \| [`StandardSchemaV1Issue`](../interfaces/StandardSchemaV1Issue.md)[] - \| `undefined`\> - -*** - -### pushValue() - -```ts -pushValue(value, options?): void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1105](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1105) - -Pushes a new value to the field. - -#### Parameters - -##### value - -`TData` *extends* `any`[] ? `TData`\<`TData`\>\[`number`\] : `never` - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`void` - -*** - -### removeValue() - -```ts -removeValue(index, options?): void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1163](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1163) - -Removes a value at the specified index. - -#### Parameters - -##### index - -`number` - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`void` - -*** - -### replaceValue() - -```ts -replaceValue( - index, - value, - options?): void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1143](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1143) - -Replaces a value at the specified index. - -#### Parameters - -##### index - -`number` - -##### value - -`TData` *extends* `any`[] ? `TData`\<`TData`\>\[`number`\] : `never` - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`void` - -*** - -### setErrorMap() - -```ts -setErrorMap(errorMap): void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1755](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1755) - -Updates the field's errorMap - -#### Parameters - -##### errorMap - -`ValidationErrorMap`\<[`UnwrapFieldValidateOrFn`](../type-aliases/UnwrapFieldValidateOrFn.md)\<`TName`, `TOnMount`, `TFormOnMount`\>, [`UnwrapFieldValidateOrFn`](../type-aliases/UnwrapFieldValidateOrFn.md)\<`TName`, `TOnChange`, `TFormOnChange`\>, [`UnwrapFieldAsyncValidateOrFn`](../type-aliases/UnwrapFieldAsyncValidateOrFn.md)\<`TName`, `TOnChangeAsync`, `TFormOnChangeAsync`\>, [`UnwrapFieldValidateOrFn`](../type-aliases/UnwrapFieldValidateOrFn.md)\<`TName`, `TOnBlur`, `TFormOnBlur`\>, [`UnwrapFieldAsyncValidateOrFn`](../type-aliases/UnwrapFieldAsyncValidateOrFn.md)\<`TName`, `TOnBlurAsync`, `TFormOnBlurAsync`\>, [`UnwrapFieldValidateOrFn`](../type-aliases/UnwrapFieldValidateOrFn.md)\<`TName`, `TOnSubmit`, `TFormOnSubmit`\>, [`UnwrapFieldAsyncValidateOrFn`](../type-aliases/UnwrapFieldAsyncValidateOrFn.md)\<`TName`, `TOnSubmitAsync`, `TFormOnSubmitAsync`\>, [`UnwrapFieldValidateOrFn`](../type-aliases/UnwrapFieldValidateOrFn.md)\<`TName`, `TOnDynamic`, `TFormOnDynamic`\>, [`UnwrapFieldAsyncValidateOrFn`](../type-aliases/UnwrapFieldAsyncValidateOrFn.md)\<`TName`, `TOnDynamicAsync`, `TFormOnDynamicAsync`\>\> - -#### Returns - -`void` - -*** - -### setMeta() - -```ts -setMeta(updater): void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1069](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1069) - -Sets the field metadata. - -#### Parameters - -##### updater - -[`Updater`](../type-aliases/Updater.md)\<`FieldLikeMetaBase`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`\>\> - -#### Returns - -`void` - -#### Implementation of - -```ts -FieldLikeAPI.setMeta -``` - -*** - -### setValue() - -```ts -setValue(updater, options?): void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1048](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1048) - -Sets the field value and run the `change` validator. - -#### Parameters - -##### updater - -[`Updater`](../type-aliases/Updater.md)\<`TData`\> - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`void` - -#### Implementation of - -```ts -FieldLikeAPI.setValue -``` - -*** - -### swapValues() - -```ts -swapValues( - aIndex, - bIndex, - options?): void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1178](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1178) - -Swaps the values at the specified indices. - -#### Parameters - -##### aIndex - -`number` - -##### bIndex - -`number` - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`void` - -*** - -### update() - -```ts -update(opts): void; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:990](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L990) - -Updates the field instance with new options. - -#### Parameters - -##### opts - -[`FieldApiOptions`](../interfaces/FieldApiOptions.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -#### Returns - -`void` - -*** - -### validate() - -```ts -validate(cause, opts?): unknown[] | Promise; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:1615](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1615) - -Validates the field value. - -#### Parameters - -##### cause - -`ValidationCause` - -##### opts? - -###### skipFormValidation? - -`boolean` - -###### skipGroupValidation? - -`boolean` - -#### Returns - -`unknown`[] \| `Promise`\<`unknown`[]\> - -#### Implementation of - -```ts -FieldLikeAPI.validate -``` diff --git a/docs/reference/classes/FieldGroupApi.md b/docs/reference/classes/FieldGroupApi.md deleted file mode 100644 index 91223255c9..0000000000 --- a/docs/reference/classes/FieldGroupApi.md +++ /dev/null @@ -1,866 +0,0 @@ ---- -id: FieldGroupApi -title: FieldGroupApi ---- - -# Class: FieldGroupApi\ - -Defined in: [packages/form-core/src/FieldGroupApi.ts:114](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L114) - -## Type Parameters - -### TFormData - -`TFormData` - -### TFieldGroupData - -`TFieldGroupData` - -### TFields - -`TFields` *extends* - \| [`DeepKeysOfType`](../type-aliases/DeepKeysOfType.md)\<`TFormData`, `TFieldGroupData` \| `null` \| `undefined`\> - \| [`FieldsMap`](../type-aliases/FieldsMap.md)\<`TFormData`, `TFieldGroupData`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` = `never` - -## Constructors - -### Constructor - -```ts -new FieldGroupApi(opts): FieldGroupApi; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:239](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L239) - -Constructs a new `FieldGroupApi` instance with the given form options. - -#### Parameters - -##### opts - -[`FieldGroupOptions`](../interfaces/FieldGroupOptions.md)\<`TFormData`, `TFieldGroupData`, `TFields`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -#### Returns - -`FieldGroupApi`\<`TFormData`, `TFieldGroupData`, `TFields`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -## Properties - -### fieldsMap - -```ts -readonly fieldsMap: TFields; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:150](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L150) - -*** - -### form - -```ts -readonly form: FormApi; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:135](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L135) - -The form that called this field group. - -*** - -### store - -```ts -store: ReadonlyStore>; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:230](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L230) - -## Accessors - -### state - -#### Get Signature - -```ts -get state(): FieldGroupState; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:232](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L232) - -##### Returns - -[`FieldGroupState`](../interfaces/FieldGroupState.md)\<`TFieldGroupData`\> - -## Methods - -### clearFieldValues() - -```ts -clearFieldValues(field, opts?): void; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:508](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L508) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### opts? - -`UpdateMetaOptions` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.clearFieldValues -``` - -*** - -### deleteField() - -```ts -deleteField(field): void; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:395](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L395) - -Delete a field and its subfields. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.deleteField -``` - -*** - -### getFieldMeta() - -```ts -getFieldMeta(field): AnyFieldLikeMeta | undefined; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:363](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L363) - -Gets the metadata of the specified field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -`AnyFieldLikeMeta` \| `undefined` - -#### Implementation of - -```ts -FormLikeAPI.getFieldMeta -``` - -*** - -### getFieldValue() - -```ts -getFieldValue(field): DeepValue; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:351](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L351) - -Gets the value of the specified field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -[`DeepValue`](../type-aliases/DeepValue.md)\<`TFieldGroupData`, `TField`\> - -#### Implementation of - -```ts -FormLikeAPI.getFieldValue -``` - -*** - -### handleSubmit() - -#### Call Signature - -```ts -handleSubmit(): Promise; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:341](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L341) - -Handles the form submission, performs validation, and calls the appropriate onSubmit or onSubmitInvalid callbacks. - -##### Returns - -`Promise`\<`void`\> - -##### Implementation of - -```ts -FormLikeAPI.handleSubmit -``` - -#### Call Signature - -```ts -handleSubmit(submitMeta): Promise; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:342](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L342) - -Handles the form submission, performs validation, and calls the appropriate onSubmit or onSubmitInvalid callbacks. - -##### Parameters - -###### submitMeta - -`TSubmitMeta` - -##### Returns - -`Promise`\<`void`\> - -##### Implementation of - -```ts -FormLikeAPI.handleSubmit -``` - -*** - -### insertFieldValue() - -```ts -insertFieldValue( - field, - index, - value, -opts?): Promise; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:420](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L420) - -Insert a value into an array field at the specified index. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index - -`number` - -##### value - -[`DeepValue`](../type-aliases/DeepValue.md)\<`TFieldGroupData`, `TField`\> *extends* `any`[] ? `any`[] & [`DeepValue`](../type-aliases/DeepValue.md)\<`TFieldGroupData`, `TField`\>\[`number`\] : `never` - -##### opts? - -`UpdateMetaOptions` - -#### Returns - -`Promise`\<`void`\> - -#### Implementation of - -```ts -FormLikeAPI.insertFieldValue -``` - -*** - -### mount() - -```ts -mount(): () => void; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:307](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L307) - -Mounts the field group instance to listen to value changes. - -TODO: Remove - -#### Returns - -```ts -(): void; -``` - -##### Returns - -`void` - -*** - -### moveFieldValues() - -```ts -moveFieldValues( - field, - index1, - index2, - opts?): void; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:494](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L494) - -Moves the value at the first specified index to the second specified index within an array field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index1 - -`number` - -##### index2 - -`number` - -##### opts? - -`UpdateMetaOptions` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.moveFieldValues -``` - -*** - -### pushFieldValue() - -```ts -pushFieldValue( - field, - value, - opts?): void; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:402](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L402) - -Pushes a value into an array field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### value - -[`DeepValue`](../type-aliases/DeepValue.md)\<`TFieldGroupData`, `TField`\> *extends* `any`[] ? `any`[] & [`DeepValue`](../type-aliases/DeepValue.md)\<`TFieldGroupData`, `TField`\>\[`number`\] : `never` - -##### opts? - -`UpdateMetaOptions` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.pushFieldValue -``` - -*** - -### removeFieldValue() - -```ts -removeFieldValue( - field, - index, -opts?): Promise; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:464](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L464) - -Removes a value from an array field at the specified index. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index - -`number` - -##### opts? - -`UpdateMetaOptions` - -#### Returns - -`Promise`\<`void`\> - -#### Implementation of - -```ts -FormLikeAPI.removeFieldValue -``` - -*** - -### replaceFieldValue() - -```ts -replaceFieldValue( - field, - index, - value, -opts?): Promise; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:442](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L442) - -Replaces a value into an array field at the specified index. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index - -`number` - -##### value - -[`DeepValue`](../type-aliases/DeepValue.md)\<`TFieldGroupData`, `TField`\> *extends* `any`[] ? `any`[] & [`DeepValue`](../type-aliases/DeepValue.md)\<`TFieldGroupData`, `TField`\>\[`number`\] : `never` - -##### opts? - -`UpdateMetaOptions` - -#### Returns - -`Promise`\<`void`\> - -#### Implementation of - -```ts -FormLikeAPI.replaceFieldValue -``` - -*** - -### resetField() - -```ts -resetField(field): void; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:518](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L518) - -Resets the field value and meta to default state - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.resetField -``` - -*** - -### setFieldMeta() - -```ts -setFieldMeta(field, updater): void; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:370](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L370) - -Updates the metadata of the specified field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### updater - -[`Updater`](../type-aliases/Updater.md)\<`AnyFieldLikeMetaBase`\> - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.setFieldMeta -``` - -*** - -### setFieldValue() - -```ts -setFieldValue( - field, - updater, - opts?): void; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:380](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L380) - -Sets the value of the specified field and optionally updates the touched state. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### updater - -[`Updater`](../type-aliases/Updater.md)\<[`DeepValue`](../type-aliases/DeepValue.md)\<`TFieldGroupData`, `TField`\>\> - -##### opts? - -`UpdateMetaOptions` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.setFieldValue -``` - -*** - -### swapFieldValues() - -```ts -swapFieldValues( - field, - index1, - index2, - opts?): void; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:477](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L477) - -Swaps the values at the specified indices within an array field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index1 - -`number` - -##### index2 - -`number` - -##### opts? - -`UpdateMetaOptions` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.swapFieldValues -``` - -*** - -### validateAllFields() - -```ts -validateAllFields(cause): Promise; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:522](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L522) - -#### Parameters - -##### cause - -`ValidationCause` - -#### Returns - -`Promise`\<`unknown`[]\> - -#### Implementation of - -```ts -FormLikeAPI.validateAllFields -``` - -*** - -### validateArrayFieldsStartingFrom() - -```ts -validateArrayFieldsStartingFrom( - field, - index, -cause): Promise; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:314](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L314) - -Validates the children of a specified array in the form starting from a given index until the end using the correct handlers for a given validation type. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index - -`number` - -##### cause - -`ValidationCause` - -#### Returns - -`Promise`\<`unknown`[]\> - -#### Implementation of - -```ts -FormLikeAPI.validateArrayFieldsStartingFrom -``` - -*** - -### validateField() - -```ts -validateField(field, cause): any[] | Promise; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:331](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L331) - -Validates a specified field in the form using the correct handlers for a given validation type. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### cause - -`ValidationCause` - -#### Returns - -`any`[] \| `Promise`\<`any`[]\> - -#### Implementation of - -```ts -FormLikeAPI.validateField -``` diff --git a/docs/reference/classes/FormApi.md b/docs/reference/classes/FormApi.md deleted file mode 100644 index 43aba2a633..0000000000 --- a/docs/reference/classes/FormApi.md +++ /dev/null @@ -1,1226 +0,0 @@ ---- -id: FormApi -title: FormApi ---- - -# Class: FormApi\ - -Defined in: [packages/form-core/src/FormApi.ts:954](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L954) - -A class representing the Form API. It handles the logic and interactions with the form state. - -Normally, you will not need to create a new `FormApi` instance directly. Instead, you will use a framework -hook/function like `useForm` or `createForm` to create a new instance for you that uses your framework's reactivity model. -However, if you need to create a new instance manually, you can do so by calling the `new FormApi` constructor. - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` = `never` - -## Constructors - -### Constructor - -```ts -new FormApi(opts?): FormApi; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1073](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1073) - -Constructs a new `FormApi` instance with the given form options. - -#### Parameters - -##### opts? - -[`FormOptions`](../interfaces/FormOptions.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -#### Returns - -`FormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -## Properties - -### baseStore - -```ts -baseStore: Store>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:986](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L986) - -*** - -### fieldInfo - -```ts -fieldInfo: Partial, FieldInfo>> = {}; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1042](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1042) - -A record of field information for each field in the form. - -*** - -### fieldMetaDerived - -```ts -fieldMetaDerived: Store, AnyFieldLikeMeta>>>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1001](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1001) - -*** - -### formGroupApis - -```ts -formGroupApis: Set; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1048](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1048) - -The set of currently-mounted `FormGroupApi` instances belonging to -this form. Used by `FieldApi.validate` to cascade field-level changes -into the validators of any group that encompasses the field. - -*** - -### formGroupMetaDerived - -```ts -formGroupMetaDerived: ReadonlyStore>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1023](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1023) - -A derived store of every mounted `FormGroupApi`'s `meta`, keyed by -group name. Mirrors `fieldMetaDerived` for fields: per-group `meta` -is computed once on the form (from `baseStore.formGroupStateBase`, -`fieldMetaDerived`, and the registered `formGroupApis`) so reads -from a `FormGroupApi.store` instance stay minimal. - -*** - -### options - -```ts -options: FormOptions = {}; -``` - -Defined in: [packages/form-core/src/FormApi.ts:971](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L971) - -The options for the form. - -*** - -### store - -```ts -store: ReadonlyStore>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1024](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1024) - -## Accessors - -### formId - -#### Get Signature - -```ts -get formId(): string; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1629](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1629) - -##### Returns - -`string` - -*** - -### state - -#### Get Signature - -```ts -get state(): FormState; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1049](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1049) - -##### Returns - -[`FormState`](../interfaces/FormState.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`\> - -## Methods - -### \_handleSubmit() - -```ts -_handleSubmit(submitMeta?): Promise; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2420](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2420) - -Handles the form submission, performs validation, and calls the appropriate onSubmit or onSubmitInvalid callbacks. - -#### Parameters - -##### submitMeta? - -`TSubmitMeta` - -#### Returns - -`Promise`\<`void`\> - -*** - -### clearFieldValues() - -```ts -clearFieldValues(field, options?): void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2903](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2903) - -Clear all values within an array field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.clearFieldValues -``` - -*** - -### deleteField() - -```ts -deleteField(field): void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2691](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2691) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.deleteField -``` - -*** - -### getAllErrors() - -```ts -getAllErrors(): object; -``` - -Defined in: [packages/form-core/src/FormApi.ts:3026](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L3026) - -Returns form and field level errors - -#### Returns - -`object` - -##### fields - -```ts -fields: Record, { - errorMap: ValidationErrorMap; - errors: ValidationError[]; -}>; -``` - -##### form - -```ts -form: object; -``` - -###### form.errorMap - -```ts -errorMap: ValidationErrorMap, UnwrapFormValidateOrFn, UnwrapFormAsyncValidateOrFn, UnwrapFormValidateOrFn, UnwrapFormAsyncValidateOrFn, UnwrapFormValidateOrFn, UnwrapFormAsyncValidateOrFn, UnwrapFormValidateOrFn, UnwrapFormAsyncValidateOrFn, UnwrapFormAsyncValidateOrFn>; -``` - -###### form.errors - -```ts -errors: NonNullable< - | UnwrapFormValidateOrFn - | UnwrapFormValidateOrFn - | UnwrapFormAsyncValidateOrFn - | UnwrapFormValidateOrFn - | UnwrapFormAsyncValidateOrFn - | UnwrapFormValidateOrFn - | UnwrapFormAsyncValidateOrFn - | UnwrapFormValidateOrFn - | UnwrapFormAsyncValidateOrFn - | UnwrapFormAsyncValidateOrFn>[]; -``` - -*** - -### getFieldInfo() - -```ts -getFieldInfo(field): FieldInfo; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2595](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2595) - -Gets the field info of the specified field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -`FieldInfo`\<`TFormData`\> - -*** - -### getFieldMeta() - -```ts -getFieldMeta(field): AnyFieldLikeMeta | undefined; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2577](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2577) - -Gets the metadata of the specified field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -`AnyFieldLikeMeta` \| `undefined` - -#### Implementation of - -```ts -FormLikeAPI.getFieldMeta -``` - -*** - -### getFieldValue() - -```ts -getFieldValue(field): DeepValue; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2570](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2570) - -Gets the value of the specified field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -[`DeepValue`](../type-aliases/DeepValue.md)\<`TFormData`, `TField`\> - -#### Implementation of - -```ts -FormLikeAPI.getFieldValue -``` - -*** - -### getFormGroupMeta() - -```ts -getFormGroupMeta(name): AnyFormGroupMeta | undefined; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2588](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2588) - -Gets the derived `meta` of the form group registered at the given -name. Mirrors `getFieldMeta` for fields. Returns `undefined` if no -`FormGroupApi` with that name is currently mounted. - -#### Parameters - -##### name - -`string` - -#### Returns - -[`AnyFormGroupMeta`](../type-aliases/AnyFormGroupMeta.md) \| `undefined` - -*** - -### handleSubmit() - -#### Call Signature - -```ts -handleSubmit(): Promise; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2411](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2411) - -Handles the form submission, performs validation, and calls the appropriate onSubmit or onSubmitInvalid callbacks. - -##### Returns - -`Promise`\<`void`\> - -##### Implementation of - -```ts -FormLikeAPI.handleSubmit -``` - -#### Call Signature - -```ts -handleSubmit(submitMeta): Promise; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2412](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2412) - -##### Parameters - -###### submitMeta - -`TSubmitMeta` - -##### Returns - -`Promise`\<`void`\> - -##### Implementation of - -```ts -FormLikeAPI.handleSubmit -``` - -*** - -### insertFieldValue() - -```ts -insertFieldValue( - field, - index, - value, -options?): Promise; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2731](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2731) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index - -`number` - -##### value - -[`DeepValue`](../type-aliases/DeepValue.md)\<`TFormData`, `TField`\> *extends* `any`[] ? `any`[] & [`DeepValue`](../type-aliases/DeepValue.md)\<`TFormData`, `TField`\>\[`number`\] : `never` - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`Promise`\<`void`\> - -#### Implementation of - -```ts -FormLikeAPI.insertFieldValue -``` - -*** - -### mount() - -```ts -mount(): () => void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1658](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1658) - -#### Returns - -```ts -(): void; -``` - -##### Returns - -`void` - -*** - -### moveFieldValues() - -```ts -moveFieldValues( - field, - index1, - index2, - options?): void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2871](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2871) - -Moves the value at the first specified index to the second specified index within an array field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index1 - -`number` - -##### index2 - -`number` - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.moveFieldValues -``` - -*** - -### parseValuesWithSchema() - -```ts -parseValuesWithSchema(schema): - | { - fields: Record; - form: Record; -} - | undefined; -``` - -Defined in: [packages/form-core/src/FormApi.ts:3092](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L3092) - -Parses the form's values with a given standard schema and returns -issues (if any). This method does NOT set any internal errors. - -#### Parameters - -##### schema - -[`StandardSchemaV1`](../type-aliases/StandardSchemaV1.md)\<`TFormData`, `unknown`\> - -The standard schema to parse the form values with. - -#### Returns - - \| \{ - `fields`: `Record`\<`string`, [`StandardSchemaV1Issue`](../interfaces/StandardSchemaV1Issue.md)[]\>; - `form`: `Record`\<`string`, [`StandardSchemaV1Issue`](../interfaces/StandardSchemaV1Issue.md)[]\>; -\} - \| `undefined` - -*** - -### parseValuesWithSchemaAsync() - -```ts -parseValuesWithSchemaAsync(schema): Promise< - | { - fields: Record; - form: Record; -} -| undefined>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:3104](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L3104) - -Parses the form's values with a given standard schema and returns -issues (if any). This method does NOT set any internal errors. - -#### Parameters - -##### schema - -[`StandardSchemaV1`](../type-aliases/StandardSchemaV1.md)\<`TFormData`, `unknown`\> - -The standard schema to parse the form values with. - -#### Returns - -`Promise`\< - \| \{ - `fields`: `Record`\<`string`, [`StandardSchemaV1Issue`](../interfaces/StandardSchemaV1Issue.md)[]\>; - `form`: `Record`\<`string`, [`StandardSchemaV1Issue`](../interfaces/StandardSchemaV1Issue.md)[]\>; -\} - \| `undefined`\> - -*** - -### pushFieldValue() - -```ts -pushFieldValue( - field, - value, - options?): void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2715](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2715) - -Pushes a value into an array field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### value - -[`DeepValue`](../type-aliases/DeepValue.md)\<`TFormData`, `TField`\> *extends* `any`[] ? `any`[] & [`DeepValue`](../type-aliases/DeepValue.md)\<`TFormData`, `TField`\>\[`number`\] : `never` - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.pushFieldValue -``` - -*** - -### removeFieldValue() - -```ts -removeFieldValue( - field, - index, -options?): Promise; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2799](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2799) - -Removes a value from an array field at the specified index. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index - -`number` - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`Promise`\<`void`\> - -#### Implementation of - -```ts -FormLikeAPI.removeFieldValue -``` - -*** - -### replaceFieldValue() - -```ts -replaceFieldValue( - field, - index, - value, -options?): Promise; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2768](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2768) - -Replaces a value into an array field at the specified index. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index - -`number` - -##### value - -[`DeepValue`](../type-aliases/DeepValue.md)\<`TFormData`, `TField`\> *extends* `any`[] ? `any`[] & [`DeepValue`](../type-aliases/DeepValue.md)\<`TFormData`, `TField`\>\[`number`\] : `never` - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`Promise`\<`void`\> - -#### Implementation of - -```ts -FormLikeAPI.replaceFieldValue -``` - -*** - -### reset() - -```ts -reset(values?, opts?): void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1810](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1810) - -Resets the form state to the default values. -If values are provided, the form will be reset to those values instead and the default values will be updated. - -#### Parameters - -##### values? - -`TFormData` - -Optional values to reset the form to. - -##### opts? - -Optional options to control the reset behavior. - -###### keepDefaultValues? - -`boolean` - -#### Returns - -`void` - -*** - -### resetField() - -```ts -resetField(field): void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2938](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2938) - -Resets the field value and meta to default state - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.resetField -``` - -*** - -### resetFieldMeta() - -```ts -resetFieldMeta(fieldMeta): Partial>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2635](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2635) - -resets every field's meta - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### fieldMeta - -`Partial`\<`Record`\<`TField`, `AnyFieldLikeMeta`\>\> - -#### Returns - -`Partial`\<`Record`\<`TField`, `AnyFieldLikeMeta`\>\> - -*** - -### setErrorMap() - -```ts -setErrorMap(errorMap): void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2962](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2962) - -Updates the form's errorMap - -#### Parameters - -##### errorMap - -`FormValidationErrorMap`\<`TFormData`, [`UnwrapFormValidateOrFn`](../type-aliases/UnwrapFormValidateOrFn.md)\<`TOnMount`\>, [`UnwrapFormValidateOrFn`](../type-aliases/UnwrapFormValidateOrFn.md)\<`TOnChange`\>, [`UnwrapFormAsyncValidateOrFn`](../type-aliases/UnwrapFormAsyncValidateOrFn.md)\<`TOnChangeAsync`\>, [`UnwrapFormValidateOrFn`](../type-aliases/UnwrapFormValidateOrFn.md)\<`TOnBlur`\>, [`UnwrapFormAsyncValidateOrFn`](../type-aliases/UnwrapFormAsyncValidateOrFn.md)\<`TOnBlurAsync`\>, [`UnwrapFormValidateOrFn`](../type-aliases/UnwrapFormValidateOrFn.md)\<`TOnSubmit`\>, [`UnwrapFormAsyncValidateOrFn`](../type-aliases/UnwrapFormAsyncValidateOrFn.md)\<`TOnSubmitAsync`\>, [`UnwrapFormValidateOrFn`](../type-aliases/UnwrapFormValidateOrFn.md)\<`TOnDynamic`\>, [`UnwrapFormAsyncValidateOrFn`](../type-aliases/UnwrapFormAsyncValidateOrFn.md)\<`TOnDynamicAsync`\>, [`UnwrapFormAsyncValidateOrFn`](../type-aliases/UnwrapFormAsyncValidateOrFn.md)\<`TOnServer`\>\> - -#### Returns - -`void` - -*** - -### setFieldMeta() - -```ts -setFieldMeta(field, updater): void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2614](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2614) - -Updates the metadata of the specified field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### updater - -[`Updater`](../type-aliases/Updater.md)\<`AnyFieldLikeMetaBase`\> - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.setFieldMeta -``` - -*** - -### setFieldValue() - -```ts -setFieldValue( - field, - updater, - opts?): void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2651](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2651) - -Sets the value of the specified field and optionally updates the touched state. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### updater - -[`Updater`](../type-aliases/Updater.md)\<[`DeepValue`](../type-aliases/DeepValue.md)\<`TFormData`, `TField`\>\> - -##### opts? - -`UpdateMetaOptions` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.setFieldValue -``` - -*** - -### swapFieldValues() - -```ts -swapFieldValues( - field, - index1, - index2, - options?): void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:2839](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L2839) - -Swaps the values at the specified indices within an array field. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index1 - -`number` - -##### index2 - -`number` - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.swapFieldValues -``` - -*** - -### update() - -```ts -update(options?): void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1732](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1732) - -Updates the form options and form state. - -#### Parameters - -##### options? - -[`FormOptions`](../interfaces/FormOptions.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -#### Returns - -`void` - -*** - -### validateAllFields() - -```ts -validateAllFields(cause): Promise; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1856](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1856) - -Validates all fields according to the FIELD level validators. -This will ignore FORM level validators, use form.validate({ValidationCause}) for a complete validation - -#### Parameters - -##### cause - -`ValidationCause` - -#### Returns - -`Promise`\<`unknown`[]\> - -#### Implementation of - -```ts -FormLikeAPI.validateAllFields -``` - -*** - -### validateArrayFieldsStartingFrom() - -```ts -validateArrayFieldsStartingFrom( - field, - index, -cause): Promise; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1892](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1892) - -Validates the children of a specified array in the form starting from a given index until the end using the correct handlers for a given validation type. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index - -`number` - -##### cause - -`ValidationCause` - -#### Returns - -`Promise`\<`unknown`[]\> - -#### Implementation of - -```ts -FormLikeAPI.validateArrayFieldsStartingFrom -``` - -*** - -### validateField() - -```ts -validateField(field, cause): any[] | Promise; -``` - -Defined in: [packages/form-core/src/FormApi.ts:1933](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1933) - -Validates a specified field in the form using the correct handlers for a given validation type. - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### cause - -`ValidationCause` - -#### Returns - -`any`[] \| `Promise`\<`any`[]\> - -#### Implementation of - -```ts -FormLikeAPI.validateField -``` diff --git a/docs/reference/classes/FormGroupApi.md b/docs/reference/classes/FormGroupApi.md deleted file mode 100644 index 848c9db28f..0000000000 --- a/docs/reference/classes/FormGroupApi.md +++ /dev/null @@ -1,1108 +0,0 @@ ---- -id: FormGroupApi -title: FormGroupApi ---- - -# Class: FormGroupApi\ - -Defined in: [packages/form-core/src/FormGroupApi.ts:970](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L970) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* [`DeepKeys`](../type-aliases/DeepKeys.md)\<`TParentData`\> - -### TData - -`TData` *extends* [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TSubmitMeta - -`TSubmitMeta` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Constructors - -### Constructor - -```ts -new FormGroupApi(opts): FormGroupApi; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:1217](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L1217) - -#### Parameters - -##### opts - -[`FormGroupApiOptions`](../interfaces/FormGroupApiOptions.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -#### Returns - -`FormGroupApi`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Properties - -### form - -```ts -form: FormApi; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:1079](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L1079) - -A reference to the form API instance. - -#### Implementation of - -```ts -FieldLikeAPI.form -``` - -*** - -### name - -```ts -name: TName; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:1108](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L1108) - -The field name. - -#### Implementation of - -```ts -FieldLikeAPI.name -``` - -*** - -### options - -```ts -options: FormGroupApiOptions; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:1112](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L1112) - -The field options. - -#### Implementation of - -```ts -FieldLikeAPI.options -``` - -*** - -### store - -```ts -store: ReadonlyStore>; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:1141](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L1141) - -The field state store. - -#### Implementation of - -```ts -FieldLikeAPI.store -``` - -*** - -### timeoutIds - -```ts -timeoutIds: object; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:1199](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L1199) - -#### formListeners - -```ts -formListeners: Record | null>; -``` - -#### listeners - -```ts -listeners: Record | null>; -``` - -#### validations - -```ts -validations: Record | null>; -``` - -## Accessors - -### state - -#### Get Signature - -```ts -get state(): FormGroupStoreState; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:1169](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L1169) - -The current field state. - -##### Returns - -[`FormGroupStoreState`](../interfaces/FormGroupStoreState.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`\> - -## Methods - -### \_handleSubmit() - -```ts -_handleSubmit(submitMeta?): Promise; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2404](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2404) - -Handles the form submission, performs validation, and calls the appropriate onSubmit or onSubmitInvalid callbacks. - -#### Parameters - -##### submitMeta? - -`TSubmitMeta` - -#### Returns - -`Promise`\<`void`\> - -*** - -### areRelatedFieldsValid() - -```ts -areRelatedFieldsValid(): boolean; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2293](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2293) - -#### Returns - -`boolean` - -*** - -### clearFieldValues() - -```ts -clearFieldValues(field): void; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2274](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2274) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.clearFieldValues -``` - -*** - -### deleteField() - -```ts -deleteField(field): void; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2229](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2229) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.deleteField -``` - -*** - -### getFieldMeta() - -```ts -getFieldMeta(field): AnyFieldLikeMeta | undefined; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2209](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2209) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -`AnyFieldLikeMeta` \| `undefined` - -#### Implementation of - -```ts -FormLikeAPI.getFieldMeta -``` - -*** - -### getFieldValue() - -```ts -getFieldValue(field): DeepValue; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2203](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2203) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -[`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TField`\> - -#### Implementation of - -```ts -FormLikeAPI.getFieldValue -``` - -*** - -### getInfo() - -```ts -getInfo(): FieldInfo; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:1636](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L1636) - -Gets the field information object. - -#### Returns - -`FieldInfo`\<`TParentData`\> - -#### Implementation of - -```ts -FieldLikeAPI.getInfo -``` - -*** - -### getMeta() - -```ts -getMeta(): FormGroupMeta; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:1600](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L1600) - -#### Returns - -[`FormGroupMeta`](../interfaces/FormGroupMeta.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`\> - -#### Implementation of - -```ts -FieldLikeAPI.getMeta -``` - -*** - -### handleSubmit() - -#### Call Signature - -```ts -handleSubmit(): Promise; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2395](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2395) - -Handles the form submission, performs validation, and calls the appropriate onSubmit or onSubmitInvalid callbacks. - -##### Returns - -`Promise`\<`void`\> - -##### Implementation of - -```ts -FormLikeAPI.handleSubmit -``` - -#### Call Signature - -```ts -handleSubmit(submitMeta): Promise; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2396](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2396) - -##### Parameters - -###### submitMeta - -`TSubmitMeta` - -##### Returns - -`Promise`\<`void`\> - -##### Implementation of - -```ts -FormLikeAPI.handleSubmit -``` - -*** - -### insertFieldValue() - -```ts -insertFieldValue( - field, - index, -value): Promise; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2242](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2242) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index - -`number` - -##### value - -`any` - -#### Returns - -`Promise`\<`void`\> - -#### Implementation of - -```ts -FormLikeAPI.insertFieldValue -``` - -*** - -### mount() - -```ts -mount(): () => void; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:1447](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L1447) - -#### Returns - -```ts -(): void; -``` - -##### Returns - -`void` - -#### Implementation of - -```ts -FieldLikeAPI.mount -``` - -*** - -### moveFieldValues() - -```ts -moveFieldValues( - field, - fromIndex, - toIndex): void; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2266](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2266) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### fromIndex - -`number` - -##### toIndex - -`number` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.moveFieldValues -``` - -*** - -### pushFieldValue() - -```ts -pushFieldValue(field, value): void; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2235](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2235) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### value - -`any` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.pushFieldValue -``` - -*** - -### removeFieldValue() - -```ts -removeFieldValue(field, index): Promise; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2286](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2286) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index - -`number` - -#### Returns - -`Promise`\<`void`\> - -#### Implementation of - -```ts -FormLikeAPI.removeFieldValue -``` - -*** - -### replaceFieldValue() - -```ts -replaceFieldValue( - field, - index, -value): Promise; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2250](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2250) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index - -`number` - -##### value - -`any` - -#### Returns - -`Promise`\<`void`\> - -#### Implementation of - -```ts -FormLikeAPI.replaceFieldValue -``` - -*** - -### resetField() - -```ts -resetField(field): void; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2280](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2280) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.resetField -``` - -*** - -### setFieldMeta() - -```ts -setFieldMeta(field, updater): void; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2215](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2215) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### updater - -[`Updater`](../type-aliases/Updater.md)\<`AnyFieldLikeMetaBase`\> - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.setFieldMeta -``` - -*** - -### setFieldValue() - -```ts -setFieldValue(field, value): void; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2222](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2222) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### value - -`any` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.setFieldValue -``` - -*** - -### setMeta() - -```ts -setMeta(updater): void; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:1605](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L1605) - -Sets the field metadata. - -#### Parameters - -##### updater - -[`Updater`](../type-aliases/Updater.md)\<`FieldLikeMetaBase`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`\>\> - -#### Returns - -`void` - -#### Implementation of - -```ts -FieldLikeAPI.setMeta -``` - -*** - -### setValue() - -```ts -setValue(updater, options?): void; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:1584](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L1584) - -Sets the field value and run the `change` validator. - -#### Parameters - -##### updater - -[`Updater`](../type-aliases/Updater.md)\<`TData`\> - -##### options? - -`UpdateMetaOptions` - -#### Returns - -`void` - -#### Implementation of - -```ts -FieldLikeAPI.setValue -``` - -*** - -### swapFieldValues() - -```ts -swapFieldValues( - field, - index1, - index2): void; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2258](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2258) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index1 - -`number` - -##### index2 - -`number` - -#### Returns - -`void` - -#### Implementation of - -```ts -FormLikeAPI.swapFieldValues -``` - -*** - -### update() - -```ts -update(opts): void; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:1356](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L1356) - -Updates the field instance with new options. - -#### Parameters - -##### opts - -[`FormGroupApiOptions`](../interfaces/FormGroupApiOptions.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -#### Returns - -`void` - -*** - -### validate() - -```ts -validate(cause, opts?): unknown[] | Promise; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2302](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2302) - -Validates the form group and all related children. - -#### Parameters - -##### cause - -`ValidationCause` - -##### opts? - -###### skipFormValidation? - -`boolean` - -###### skipRelatedFieldValidation? - -`boolean` - -#### Returns - -`unknown`[] \| `Promise`\<`unknown`[]\> - -#### Implementation of - -```ts -FieldLikeAPI.validate -``` - -*** - -### validateAllFields() - -```ts -validateAllFields(cause): Promise; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2158](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2158) - -Validates all fields according to the FIELD level validators. -This will ignore FORM level validators, use form.validate({ValidationCause}) for a complete validation - -#### Parameters - -##### cause - -`ValidationCause` - -#### Returns - -`Promise`\<`unknown`[]\> - -#### Implementation of - -```ts -FormLikeAPI.validateAllFields -``` - -*** - -### validateArrayFieldsStartingFrom() - -```ts -validateArrayFieldsStartingFrom( - field, - index, -cause): Promise; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2186](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2186) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### index - -`number` - -##### cause - -`ValidationCause` - -#### Returns - -`Promise`\<`unknown`[]\> - -#### Implementation of - -```ts -FormLikeAPI.validateArrayFieldsStartingFrom -``` - -*** - -### validateField() - -```ts -validateField(field, cause): any[] | Promise; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:2196](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L2196) - -#### Type Parameters - -##### TField - -`TField` *extends* `string` - -#### Parameters - -##### field - -`TField` - -##### cause - -`ValidationCause` - -#### Returns - -`any`[] \| `Promise`\<`any`[]\> - -#### Implementation of - -```ts -FormLikeAPI.validateField -``` diff --git a/docs/reference/functions/createErrorMap.md b/docs/reference/functions/createErrorMap.md new file mode 100644 index 0000000000..ed0217a8d7 --- /dev/null +++ b/docs/reference/functions/createErrorMap.md @@ -0,0 +1,40 @@ +--- +id: createErrorMap +title: createErrorMap +--- + +```ts +function createErrorMap(initial?): ValidationErrorMap; +``` + +Defined in: [validation.public.ts:615](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L615) + +Creates a mutable map of form errors and errors for individual field paths. + +Pass the completed map back from a form or group validator to report the errors. + +## Type Parameters + +### TFormData + +`TFormData` + +The form or group value shape whose field paths are +accepted by the map. Specify it when calling this helper directly to restrict +`fields` to that shape's paths. Without a known value shape, field paths are +unrestricted. The validator context's `createErrorMap` already uses the form +or group shape and needs no type argument. + +## Parameters + +### initial? + +`Partial`\<[`ValidationErrorMap`](../interfaces/ValidationErrorMap.md)\<`TFormData`\>\> + +An existing map to reuse. A missing `fields` object is added to it. + +## Returns + +[`ValidationErrorMap`](../interfaces/ValidationErrorMap.md)\<`TFormData`\> + +The initial map, if supplied, or a new map with an empty `fields` object. diff --git a/docs/reference/functions/createErrorVisibility.md b/docs/reference/functions/createErrorVisibility.md new file mode 100644 index 0000000000..cb416a79ec --- /dev/null +++ b/docs/reference/functions/createErrorVisibility.md @@ -0,0 +1,29 @@ +--- +id: createErrorVisibility +title: createErrorVisibility +--- + +```ts +function createErrorVisibility(visibility): ReusableErrorVisibility; +``` + +Defined in: [validation.public.ts:388](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L388) + +Creates an error visibility policy that can be shared across forms with different values. + +Use an inline `errorVisibility` callback instead when the policy needs +strongly typed access to the consuming form's `values`. + +## Parameters + +### visibility + +(`context`) => `boolean` + +Returns `true` to show the field's errors, or `false` to hide them. + +## Returns + +[`ReusableErrorVisibility`](../type-aliases/ReusableErrorVisibility.md) + +The policy to assign to a form or field's `errorVisibility` option. diff --git a/docs/reference/functions/createFieldMap.md b/docs/reference/functions/createFieldMap.md deleted file mode 100644 index 00afff503a..0000000000 --- a/docs/reference/functions/createFieldMap.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -id: createFieldMap -title: createFieldMap ---- - -# Function: createFieldMap() - -```ts -function createFieldMap(values): { [K in string | number | symbol]: K }; -``` - -Defined in: [packages/form-core/src/utils.ts:614](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.ts#L614) - -## Type Parameters - -### T - -`T` - -## Parameters - -### values - -`Readonly`\<`T`\> - -## Returns - -\{ \[K in string \| number \| symbol\]: K \} diff --git a/docs/reference/functions/createValidator.md b/docs/reference/functions/createValidator.md new file mode 100644 index 0000000000..1080734f52 --- /dev/null +++ b/docs/reference/functions/createValidator.md @@ -0,0 +1,46 @@ +--- +id: createValidator +title: createValidator +--- + +```ts +function createValidator(options): (run) => CreatedValidator; +``` + +Defined in: [validation.public.ts:195](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L195) + +Creates a reusable configuration to apply to validation functions or Standard Schemas. + +## Type Parameters + +### TOptions + +`TOptions` *extends* [`ValidatorOptions`](../type-aliases/ValidatorOptions.md)\<`any`, `any`, [`ConfigurableValidationTrigger`](../type-aliases/ConfigurableValidationTrigger.md), [`ValidatorScope`](../type-aliases/ValidatorScope.md)\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### options + +`TOptions` + +## Returns + +A function that combines `options` with its `run` argument, preserving +the validator's inferred types. Its `TValidator` type argument is library-managed. +Do not specify it explicitly. + +\<`TValidator`\>(`run`) => [`CreatedValidator`](../type-aliases/CreatedValidator.md)\<`TOptions`, `TValidator`\> + +## Example + +```ts +const afterSubmit = createValidator({ + triggers: [{ + trigger: 'change', + when: ({ formApi }) => formApi.state.submissionAttempts > 0, + }], +}) +const validators = [afterSubmit(schema)] +``` diff --git a/docs/reference/functions/createValidators.md b/docs/reference/functions/createValidators.md new file mode 100644 index 0000000000..99b64c1d56 --- /dev/null +++ b/docs/reference/functions/createValidators.md @@ -0,0 +1,58 @@ +--- +id: createValidators +title: createValidators +--- + +```ts +function createValidators(options): (...runs) => ValidatorsFromOptionsAndRuns; +``` + +Defined in: [validation.public.ts:225](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L225) + +Creates a reusable configuration for an ordered set of validators. + +## Type Parameters + +### TFormData + +`TFormData` = `any` + +Library-managed. Do not specify explicitly. + +### TContextValue + +`TContextValue` = `TFormData` + +Library-managed. Do not specify explicitly. + +### TOptions + +`TOptions` *extends* readonly \[[`ValidatorOptions`](../type-aliases/ValidatorOptions.md)\<`TFormData`, `TContextValue`, [`ConfigurableValidationTrigger`](../type-aliases/ConfigurableValidationTrigger.md), [`ValidatorScope`](../type-aliases/ValidatorScope.md)\>, [`ValidatorOptions`](../type-aliases/ValidatorOptions.md)\<`TFormData`, `TContextValue`, [`ConfigurableValidationTrigger`](../type-aliases/ConfigurableValidationTrigger.md), [`ValidatorScope`](../type-aliases/ValidatorScope.md)\>\] = readonly \[[`ValidatorOptions`](../type-aliases/ValidatorOptions.md)\<`TFormData`, `TContextValue`, [`ConfigurableValidationTrigger`](../type-aliases/ConfigurableValidationTrigger.md), [`ValidatorScope`](../type-aliases/ValidatorScope.md)\>, [`ValidatorOptions`](../type-aliases/ValidatorOptions.md)\<`TFormData`, `TContextValue`, [`ConfigurableValidationTrigger`](../type-aliases/ConfigurableValidationTrigger.md), [`ValidatorScope`](../type-aliases/ValidatorScope.md)\>\] + +Library-managed. Do not specify explicitly. + +## Parameters + +### options + +`TOptions` + +A nonempty tuple of configurations, one per validator. + +## Returns + +A function that accepts one validation function or Standard Schema +per configuration, in the same order. Its `TRuns` type argument is library-managed. +Do not specify it explicitly. + +\<`TRuns`\>(...`runs`) => `ValidatorsFromOptionsAndRuns`\<`TFormData`, `TContextValue`, `TOptions`, `TRuns`\> + +## Example + +```ts +const withChecks = createValidators([ + { triggers: ['change'] }, + { triggers: ['blur'], bailIfInvalid: true }, +]) +const validators = withChecks(schema, () => 'Additional check failed') +``` diff --git a/docs/reference/functions/deepCopy.md b/docs/reference/functions/deepCopy.md deleted file mode 100644 index 5db26fbabc..0000000000 --- a/docs/reference/functions/deepCopy.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -id: deepCopy -title: deepCopy ---- - -# Function: deepCopy() - -```ts -function deepCopy(obj): T; -``` - -Defined in: [packages/form-core/src/utils.ts:694](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.ts#L694) - -## Type Parameters - -### T - -`T` - -## Parameters - -### obj - -`T` - -## Returns - -`T` diff --git a/docs/reference/functions/evaluate.md b/docs/reference/functions/evaluate.md deleted file mode 100644 index f73d9942b2..0000000000 --- a/docs/reference/functions/evaluate.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -id: evaluate -title: evaluate ---- - -# Function: evaluate() - -```ts -function evaluate(objA, objB): boolean; -``` - -Defined in: [packages/form-core/src/utils.ts:483](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.ts#L483) - -## Type Parameters - -### T - -`T` - -## Parameters - -### objA - -`T` - -### objB - -`T` - -## Returns - -`boolean` diff --git a/docs/reference/functions/formOptions.md b/docs/reference/functions/formOptions.md deleted file mode 100644 index d3e98f0ea6..0000000000 --- a/docs/reference/functions/formOptions.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -id: formOptions -title: formOptions ---- - -# Function: formOptions() - -```ts -function formOptions(defaultOpts): TOptions; -``` - -Defined in: [packages/form-core/src/formOptions.ts:23](https://github.com/TanStack/form/blob/main/packages/form-core/src/formOptions.ts#L23) - -## Type Parameters - -### TOptions - -`TOptions` *extends* `Partial`\<[`FormOptions`](../interfaces/FormOptions.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\>\> - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` = `never` - -## Parameters - -### defaultOpts - -`Partial`\<[`FormOptions`](../interfaces/FormOptions.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\>\> & `TOptions` - -## Returns - -`TOptions` diff --git a/docs/reference/functions/isGlobalFormValidationError.md b/docs/reference/functions/isGlobalFormValidationError.md deleted file mode 100644 index ad773760ee..0000000000 --- a/docs/reference/functions/isGlobalFormValidationError.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -id: isGlobalFormValidationError -title: isGlobalFormValidationError ---- - -# Function: isGlobalFormValidationError() - -```ts -function isGlobalFormValidationError(error): error is GlobalFormValidationError; -``` - -Defined in: [packages/form-core/src/utils.ts:477](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.ts#L477) - -## Parameters - -### error - -`unknown` - -## Returns - -`error is GlobalFormValidationError` diff --git a/docs/reference/functions/isStandardSchemaValidator.md b/docs/reference/functions/isStandardSchemaValidator.md deleted file mode 100644 index cb8ad4c990..0000000000 --- a/docs/reference/functions/isStandardSchemaValidator.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -id: isStandardSchemaValidator -title: isStandardSchemaValidator ---- - -# Function: isStandardSchemaValidator() - -```ts -function isStandardSchemaValidator(validator): validator is StandardSchemaV1; -``` - -Defined in: [packages/form-core/src/standardSchemaValidator.ts:112](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchemaValidator.ts#L112) - -## Parameters - -### validator - -`unknown` - -## Returns - -`validator is StandardSchemaV1` diff --git a/docs/reference/functions/mergeForm.md b/docs/reference/functions/mergeForm.md deleted file mode 100644 index 601fd7a6a2..0000000000 --- a/docs/reference/functions/mergeForm.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -id: mergeForm -title: mergeForm ---- - -# Function: mergeForm() - -```ts -function mergeForm(baseForm, state): FormApi; -``` - -Defined in: [packages/form-core/src/mergeForm.ts:77](https://github.com/TanStack/form/blob/main/packages/form-core/src/mergeForm.ts#L77) - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChange - -`TOnChange` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlur - -`TOnBlur` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmit - -`TOnSubmit` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamic - -`TOnDynamic` *extends* `FormValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TOnServer - -`TOnServer` *extends* `FormAsyncValidateOrFn`\<`TFormData`\> \| `undefined` - -### TSubmitMeta - -`TSubmitMeta` = `never` - -## Parameters - -### baseForm - -[`FormApi`](../classes/FormApi.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -### state - -`Partial`\<[`FormApi`](../classes/FormApi.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\>\[`"state"`\]\> - -## Returns - -[`FormApi`](../classes/FormApi.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> diff --git a/docs/reference/functions/revalidateLogic.md b/docs/reference/functions/revalidateLogic.md deleted file mode 100644 index 17b829e95a..0000000000 --- a/docs/reference/functions/revalidateLogic.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -id: revalidateLogic -title: revalidateLogic ---- - -# Function: revalidateLogic() - -```ts -function revalidateLogic(__namedParameters): ValidationLogicFn; -``` - -Defined in: [packages/form-core/src/ValidationLogic.ts:75](https://github.com/TanStack/form/blob/main/packages/form-core/src/ValidationLogic.ts#L75) - -This forces a form's validation logic to be ran as if it were a React Hook Form validation logic. - -This means that it will only run the `onDynamic` validator, and it will not run any other validators and changes the validation -type based on the state of the form itself. - -When the form is not yet submitted, it will not run the validation logic. -When the form is submitted, it will run the validation logic on `change` - -## Parameters - -### \_\_namedParameters - -`RevalidateLogicProps` = `{}` - -## Returns - -[`ValidationLogicFn`](../type-aliases/ValidationLogicFn.md) diff --git a/docs/reference/functions/serverValidateHelper.md b/docs/reference/functions/serverValidateHelper.md new file mode 100644 index 0000000000..6b71b9f0fd --- /dev/null +++ b/docs/reference/functions/serverValidateHelper.md @@ -0,0 +1,28 @@ +--- +id: serverValidateHelper +title: serverValidateHelper +--- + +```ts +function serverValidateHelper(options): ServerValidateHelperResult; +``` + +Defined in: [ssr.public.ts:21](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L21) + +## Type Parameters + +### TFramework + +`TFramework` *extends* [`ServerValidateFrameworkPlugin`](../interfaces/ServerValidateFrameworkPlugin.md)\<`ServerValidateFrameworkCreateServerValidate`\> + +## Parameters + +### options + +#### framework + +`TFramework` + +## Returns + +`ServerValidateHelperResult`\<`TFramework`\> diff --git a/docs/reference/functions/uuid.md b/docs/reference/functions/uuid.md deleted file mode 100644 index ae0a34de78..0000000000 --- a/docs/reference/functions/uuid.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -id: uuid -title: uuid ---- - -# Function: uuid() - -```ts -function uuid(): string; -``` - -Defined in: [packages/form-core/src/utils.ts:653](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.ts#L653) - -## Returns - -`string` diff --git a/docs/reference/index.md b/docs/reference/index.md index 6d21ebb28a..dfb1427fb4 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -3,116 +3,207 @@ id: "@tanstack/form-core" title: "@tanstack/form-core" --- -# @tanstack/form-core - -## Classes - -- [FieldApi](classes/FieldApi.md) -- [FieldGroupApi](classes/FieldGroupApi.md) -- [FormApi](classes/FormApi.md) -- [FormGroupApi](classes/FormGroupApi.md) - ## Interfaces -- [AnyDeepKeyAndValue](interfaces/AnyDeepKeyAndValue.md) -- [ArrayDeepKeyAndValue](interfaces/ArrayDeepKeyAndValue.md) -- [BaseFormOptions](interfaces/BaseFormOptions.md) +- [BaseFieldMeta](interfaces/BaseFieldMeta.md) +- [BaseValidator](interfaces/BaseValidator.md) +- [DefaultOptions](interfaces/DefaultOptions.md) +- [ErrorVisibilityContext](interfaces/ErrorVisibilityContext.md) +- [ErrorVisibilityFieldMeta](interfaces/ErrorVisibilityFieldMeta.md) +- [ErrorVisibilityFieldState](interfaces/ErrorVisibilityFieldState.md) +- [ErrorVisibilitySubfieldsMeta](interfaces/ErrorVisibilitySubfieldsMeta.md) +- [FieldApi](interfaces/FieldApi.md) - [FieldApiOptions](interfaces/FieldApiOptions.md) -- [FieldGroupOptions](interfaces/FieldGroupOptions.md) -- [FieldGroupState](interfaces/FieldGroupState.md) -- [FieldListeners](interfaces/FieldListeners.md) -- [FieldOptions](interfaces/FieldOptions.md) -- [FieldValidators](interfaces/FieldValidators.md) -- [FormGroupApiOptions](interfaces/FormGroupApiOptions.md) -- [FormGroupListeners](interfaces/FormGroupListeners.md) -- [FormGroupMeta](interfaces/FormGroupMeta.md) +- [FieldGroupFieldSlot](interfaces/FieldGroupFieldSlot.md) +- [FieldGroupHelper](interfaces/FieldGroupHelper.md) +- [FieldListener](interfaces/FieldListener.md) +- [FieldListenerContext](interfaces/FieldListenerContext.md) +- [FieldMeta](interfaces/FieldMeta.md) +- [FieldState](interfaces/FieldState.md) +- [FieldUpdateOptions](interfaces/FieldUpdateOptions.md) +- [FieldValidationPredicateContext](interfaces/FieldValidationPredicateContext.md) +- [FieldValidator](interfaces/FieldValidator.md) +- [FieldValidatorContext](interfaces/FieldValidatorContext.md) +- [FormApi](interfaces/FormApi.md) +- [FormApiArrayMethods](interfaces/FormApiArrayMethods.md) +- [FormApiFieldMethods](interfaces/FormApiFieldMethods.md) +- [FormErrorTypes](interfaces/FormErrorTypes.md) +- [FormGroupApi](interfaces/FormGroupApi.md) - [FormGroupOptions](interfaces/FormGroupOptions.md) - [FormGroupState](interfaces/FormGroupState.md) -- [FormGroupStoreState](interfaces/FormGroupStoreState.md) -- [FormGroupValidators](interfaces/FormGroupValidators.md) -- [FormListeners](interfaces/FormListeners.md) -- [FormListenersPropsField](interfaces/FormListenersPropsField.md) -- [FormListenersPropsGroup](interfaces/FormListenersPropsGroup.md) +- [FormGroupSubmitContext](interfaces/FormGroupSubmitContext.md) +- [FormGroupSubmitInvalidContext](interfaces/FormGroupSubmitInvalidContext.md) +- [FormGroupValidationPredicateContext](interfaces/FormGroupValidationPredicateContext.md) +- [FormGroupValidator](interfaces/FormGroupValidator.md) +- [FormGroupValidatorContext](interfaces/FormGroupValidatorContext.md) +- [FormListener](interfaces/FormListener.md) +- [FormListenerContext](interfaces/FormListenerContext.md) - [FormOptions](interfaces/FormOptions.md) +- [FormOptionsApi](interfaces/FormOptionsApi.md) +- [FormResetOptions](interfaces/FormResetOptions.md) - [FormState](interfaces/FormState.md) -- [FormValidators](interfaces/FormValidators.md) -- [ObjectDeepKeyAndValue](interfaces/ObjectDeepKeyAndValue.md) +- [FormSubmitContext](interfaces/FormSubmitContext.md) +- [FormSubmitInvalidContext](interfaces/FormSubmitInvalidContext.md) +- [FormValidationPredicateContext](interfaces/FormValidationPredicateContext.md) +- [FormValidator](interfaces/FormValidator.md) +- [FormValidatorContext](interfaces/FormValidatorContext.md) +- [Listener](interfaces/Listener.md) +- [ListenerPredicateContext](interfaces/ListenerPredicateContext.md) +- [ListenerTriggerConfig](interfaces/ListenerTriggerConfig.md) +- [OriginalFieldMeta](interfaces/OriginalFieldMeta.md) +- [ParsedStandardSchemaIssues](interfaces/ParsedStandardSchemaIssues.md) +- [ReusableErrorVisibilityContext](interfaces/ReusableErrorVisibilityContext.md) +- [ServerFormValidatorContext](interfaces/ServerFormValidatorContext.md) +- [ServerValidateFailure](interfaces/ServerValidateFailure.md) +- [ServerValidateFrameworkPlugin](interfaces/ServerValidateFrameworkPlugin.md) +- [ServerValidateSuccess](interfaces/ServerValidateSuccess.md) - [StandardSchemaV1Issue](interfaces/StandardSchemaV1Issue.md) -- [TupleDeepKeyAndValue](interfaces/TupleDeepKeyAndValue.md) -- [UnknownDeepKeyAndValue](interfaces/UnknownDeepKeyAndValue.md) -- [ValidationLogicProps](interfaces/ValidationLogicProps.md) -- [ValidationLogicValidatorsFn](interfaces/ValidationLogicValidatorsFn.md) +- [SubfieldsMeta](interfaces/SubfieldsMeta.md) +- [ValidationErrorMap](interfaces/ValidationErrorMap.md) +- [ValidationIssue](interfaces/ValidationIssue.md) +- [ValidationOutput](interfaces/ValidationOutput.md) +- [ValidationTriggerConfig](interfaces/ValidationTriggerConfig.md) +- [Validator](interfaces/Validator.md) ## Type Aliases -- [AllObjectKeys](type-aliases/AllObjectKeys.md) -- [AllTupleKeys](type-aliases/AllTupleKeys.md) -- [AnyBaseFormState](type-aliases/AnyBaseFormState.md) - [AnyFieldApi](type-aliases/AnyFieldApi.md) -- [AnyFieldGroupApi](type-aliases/AnyFieldGroupApi.md) +- [AnyFieldGroupFieldSlot](type-aliases/AnyFieldGroupFieldSlot.md) +- [AnyFieldListener](type-aliases/AnyFieldListener.md) - [AnyFieldMeta](type-aliases/AnyFieldMeta.md) - [AnyFormApi](type-aliases/AnyFormApi.md) -- [AnyFormGroupApi](type-aliases/AnyFormGroupApi.md) -- [AnyFormGroupMeta](type-aliases/AnyFormGroupMeta.md) +- [AnyFormListener](type-aliases/AnyFormListener.md) - [AnyFormOptions](type-aliases/AnyFormOptions.md) -- [AnyFormState](type-aliases/AnyFormState.md) -- [ArrayAccessor](type-aliases/ArrayAccessor.md) -- [BaseFormState](type-aliases/BaseFormState.md) -- [BroadcastFormApi](type-aliases/BroadcastFormApi.md) -- [BroadcastFormId](type-aliases/BroadcastFormId.md) -- [BroadcastFormState](type-aliases/BroadcastFormState.md) -- [BroadcastFormSubmissionState](type-aliases/BroadcastFormSubmissionState.md) -- [DeepKeyAndValueArray](type-aliases/DeepKeyAndValueArray.md) -- [DeepKeyAndValueObject](type-aliases/DeepKeyAndValueObject.md) -- [DeepKeyAndValueTuple](type-aliases/DeepKeyAndValueTuple.md) +- [ArrayFieldElement](type-aliases/ArrayFieldElement.md) +- [ArrayFieldName](type-aliases/ArrayFieldName.md) +- [ArrayFieldPredicate](type-aliases/ArrayFieldPredicate.md) +- [ArrayFieldValue](type-aliases/ArrayFieldValue.md) +- [BuiltInType](type-aliases/BuiltInType.md) +- [ClearFieldValuesFn](type-aliases/ClearFieldValuesFn.md) +- [ClientValidationTrigger](type-aliases/ClientValidationTrigger.md) +- [ClientValidationTriggerOption](type-aliases/ClientValidationTriggerOption.md) +- [ConfigurableValidationTrigger](type-aliases/ConfigurableValidationTrigger.md) +- [CreatedValidator](type-aliases/CreatedValidator.md) +- [CreateErrorMapFn](type-aliases/CreateErrorMapFn.md) +- [CreateOutputFn](type-aliases/CreateOutputFn.md) +- [CreateSubmitErrorMapFn](type-aliases/CreateSubmitErrorMapFn.md) +- [CreateValidationErrorFn](type-aliases/CreateValidationErrorFn.md) - [DeepKeys](type-aliases/DeepKeys.md) -- [DeepKeysAndValues](type-aliases/DeepKeysAndValues.md) -- [DeepKeysAndValuesImpl](type-aliases/DeepKeysAndValuesImpl.md) -- [DeepKeysOfType](type-aliases/DeepKeysOfType.md) -- [DeepRecord](type-aliases/DeepRecord.md) +- [DeepKeysWhereValueIncludes](type-aliases/DeepKeysWhereValueIncludes.md) - [DeepValue](type-aliases/DeepValue.md) -- [DerivedFormState](type-aliases/DerivedFormState.md) -- [EventClientEventMap](type-aliases/EventClientEventMap.md) -- [EventClientEventNames](type-aliases/EventClientEventNames.md) -- [ExtractGlobalFormError](type-aliases/ExtractGlobalFormError.md) -- [FieldsMap](type-aliases/FieldsMap.md) -- [FormValidateFn](type-aliases/FormValidateFn.md) +- [DefaultFieldOptions](type-aliases/DefaultFieldOptions.md) +- [DefaultFormGroupOptions](type-aliases/DefaultFormGroupOptions.md) +- [DefaultFormOptions](type-aliases/DefaultFormOptions.md) +- [DefaultListenersMergeMode](type-aliases/DefaultListenersMergeMode.md) +- [Editable](type-aliases/Editable.md) +- [ErrorVisibility](type-aliases/ErrorVisibility.md) +- [FieldErrors](type-aliases/FieldErrors.md) +- [FieldGroupFieldBindingForSlot](type-aliases/FieldGroupFieldBindingForSlot.md) +- [FieldGroupFieldBindings](type-aliases/FieldGroupFieldBindings.md) +- [FieldGroupFieldBindingsProps](type-aliases/FieldGroupFieldBindingsProps.md) +- [FieldGroupFieldData](type-aliases/FieldGroupFieldData.md) +- [FieldGroupFieldNameForSlot](type-aliases/FieldGroupFieldNameForSlot.md) +- [FieldGroupFieldNames](type-aliases/FieldGroupFieldNames.md) +- [FieldGroupFields](type-aliases/FieldGroupFields.md) +- [FieldGroupFieldSlotAllows](type-aliases/FieldGroupFieldSlotAllows.md) +- [FieldGroupFieldSlotMode](type-aliases/FieldGroupFieldSlotMode.md) +- [FieldGroupFieldSlotModeOf](type-aliases/FieldGroupFieldSlotModeOf.md) +- [FieldGroupFieldSlotValue](type-aliases/FieldGroupFieldSlotValue.md) +- [FieldGroupFieldsPropName](type-aliases/FieldGroupFieldsPropName.md) +- [FieldListenerFn](type-aliases/FieldListenerFn.md) +- [FieldListeners](type-aliases/FieldListeners.md) +- [FieldListenerTriggers](type-aliases/FieldListenerTriggers.md) +- [FieldValidateResult](type-aliases/FieldValidateResult.md) +- [FieldValidatorFn](type-aliases/FieldValidatorFn.md) +- [FieldValidators](type-aliases/FieldValidators.md) +- [FieldWithValue](type-aliases/FieldWithValue.md) +- [FilterFieldValuesFn](type-aliases/FilterFieldValuesFn.md) +- [FormErrors](type-aliases/FormErrors.md) +- [FormGroupSubmitFn](type-aliases/FormGroupSubmitFn.md) +- [FormGroupValidateResult](type-aliases/FormGroupValidateResult.md) +- [FormGroupValidationError](type-aliases/FormGroupValidationError.md) +- [FormGroupValidatorFn](type-aliases/FormGroupValidatorFn.md) +- [FormGroupValidators](type-aliases/FormGroupValidators.md) +- [FormListenerFn](type-aliases/FormListenerFn.md) +- [FormListeners](type-aliases/FormListeners.md) +- [FormListenerTriggers](type-aliases/FormListenerTriggers.md) +- [FormOptionsLooseSchemaFn](type-aliases/FormOptionsLooseSchemaFn.md) +- [FormOptionsStrictSchemaFn](type-aliases/FormOptionsStrictSchemaFn.md) +- [FormSubmitFn](type-aliases/FormSubmitFn.md) +- [FormValidateResult](type-aliases/FormValidateResult.md) +- [FormValidateResultFromErrorTypes](type-aliases/FormValidateResultFromErrorTypes.md) - [FormValidationError](type-aliases/FormValidationError.md) -- [FormValidator](type-aliases/FormValidator.md) -- [Nullable](type-aliases/Nullable.md) -- [ObjectAccessor](type-aliases/ObjectAccessor.md) -- [ObjectValue](type-aliases/ObjectValue.md) +- [FormValidationTriggerOption](type-aliases/FormValidationTriggerOption.md) +- [FormValidatorData](type-aliases/FormValidatorData.md) +- [FormValidatorFn](type-aliases/FormValidatorFn.md) +- [FormValidators](type-aliases/FormValidators.md) +- [GetFieldValueFn](type-aliases/GetFieldValueFn.md) +- [HandleSubmitFn](type-aliases/HandleSubmitFn.md) +- [InferUnion](type-aliases/InferUnion.md) +- [InsertFieldValueFn](type-aliases/InsertFieldValueFn.md) +- [ListenerDebounceFn](type-aliases/ListenerDebounceFn.md) +- [ListenerPredicateFn](type-aliases/ListenerPredicateFn.md) +- [ListenerTriggerOption](type-aliases/ListenerTriggerOption.md) +- [LooseFieldGroupFieldSlot](type-aliases/LooseFieldGroupFieldSlot.md) +- [MoveFieldValueFn](type-aliases/MoveFieldValueFn.md) +- [NullableSchemaData](type-aliases/NullableSchemaData.md) +- [OneOrMany](type-aliases/OneOrMany.md) +- [OnSubmitError](type-aliases/OnSubmitError.md) +- [ParseFieldIssuesFn](type-aliases/ParseFieldIssuesFn.md) +- [ParseFormIssuesFn](type-aliases/ParseFormIssuesFn.md) +- [ParseSubmitIssuesFn](type-aliases/ParseSubmitIssuesFn.md) +- [PushFieldValueFn](type-aliases/PushFieldValueFn.md) +- [RemoveFieldValueFn](type-aliases/RemoveFieldValueFn.md) +- [ReplaceFieldValueFn](type-aliases/ReplaceFieldValueFn.md) +- [ResetFieldFn](type-aliases/ResetFieldFn.md) +- [ResetFn](type-aliases/ResetFn.md) +- [ReusableErrorVisibility](type-aliases/ReusableErrorVisibility.md) +- [ReusableErrorVisibilityState](type-aliases/ReusableErrorVisibilityState.md) +- [ServerFormState](type-aliases/ServerFormState.md) +- [ServerFormValidatorFn](type-aliases/ServerFormValidatorFn.md) +- [ServerValidateResult](type-aliases/ServerValidateResult.md) +- [ServerValidationTrigger](type-aliases/ServerValidationTrigger.md) +- [SetFieldValueFn](type-aliases/SetFieldValueFn.md) - [StandardSchemaV1](type-aliases/StandardSchemaV1.md) +- [StrictFieldGroupFieldSlot](type-aliases/StrictFieldGroupFieldSlot.md) +- [SuccessfulValidationResult](type-aliases/SuccessfulValidationResult.md) +- [SwapFieldValuesFn](type-aliases/SwapFieldValuesFn.md) +- [ToFieldError](type-aliases/ToFieldError.md) +- [ToFormErrorTypes](type-aliases/ToFormErrorTypes.md) +- [ToFormGroupErrorTypes](type-aliases/ToFormGroupErrorTypes.md) +- [ToFormGroupOutputs](type-aliases/ToFormGroupOutputs.md) +- [ToFormOutputs](type-aliases/ToFormOutputs.md) +- [ToServerFormErrorTypes](type-aliases/ToServerFormErrorTypes.md) +- [ToServerFormOutputs](type-aliases/ToServerFormOutputs.md) +- [TryGetArrayElementType](type-aliases/TryGetArrayElementType.md) - [TStandardSchemaValidatorIssue](type-aliases/TStandardSchemaValidatorIssue.md) - [TStandardSchemaValidatorValue](type-aliases/TStandardSchemaValidatorValue.md) -- [TupleAccessor](type-aliases/TupleAccessor.md) -- [UnknownAccessor](type-aliases/UnknownAccessor.md) -- [UnwrapFieldAsyncValidateOrFn](type-aliases/UnwrapFieldAsyncValidateOrFn.md) -- [UnwrapFieldValidateOrFn](type-aliases/UnwrapFieldValidateOrFn.md) -- [UnwrapFormAsyncValidateOrFn](type-aliases/UnwrapFormAsyncValidateOrFn.md) -- [UnwrapFormValidateOrFn](type-aliases/UnwrapFormValidateOrFn.md) +- [UpdateFn](type-aliases/UpdateFn.md) - [Updater](type-aliases/Updater.md) -- [UpdaterFn](type-aliases/UpdaterFn.md) +- [ValidationDebounceFn](type-aliases/ValidationDebounceFn.md) - [ValidationError](type-aliases/ValidationError.md) -- [ValidationLogicFn](type-aliases/ValidationLogicFn.md) -- [ValidationMeta](type-aliases/ValidationMeta.md) -- [ValidationSource](type-aliases/ValidationSource.md) +- [ValidationErrorInput](type-aliases/ValidationErrorInput.md) +- [ValidationErrorValue](type-aliases/ValidationErrorValue.md) +- [ValidationPredicateContext](type-aliases/ValidationPredicateContext.md) +- [ValidationPredicateFn](type-aliases/ValidationPredicateFn.md) +- [ValidationResult](type-aliases/ValidationResult.md) +- [ValidationTrigger](type-aliases/ValidationTrigger.md) +- [ValidationTriggerOption](type-aliases/ValidationTriggerOption.md) +- [ValidatorFn](type-aliases/ValidatorFn.md) +- [ValidatorOptions](type-aliases/ValidatorOptions.md) +- [ValidatorScope](type-aliases/ValidatorScope.md) +- [ValidatorTrigger](type-aliases/ValidatorTrigger.md) +- [ValidValidationResult](type-aliases/ValidValidationResult.md) ## Variables -- [defaultValidationLogic](variables/defaultValidationLogic.md) -- [formEventClient](variables/formEventClient.md) -- [standardSchemaValidators](variables/standardSchemaValidators.md) -- [throttleFormState](variables/throttleFormState.md) +- [formOptions](variables/formOptions.md) +- [initialServerFormState](variables/initialServerFormState.md) ## Functions -- [createFieldMap](functions/createFieldMap.md) -- [deepCopy](functions/deepCopy.md) -- [evaluate](functions/evaluate.md) -- [formOptions](functions/formOptions.md) -- [isGlobalFormValidationError](functions/isGlobalFormValidationError.md) -- [isStandardSchemaValidator](functions/isStandardSchemaValidator.md) -- [mergeForm](functions/mergeForm.md) -- [revalidateLogic](functions/revalidateLogic.md) -- [uuid](functions/uuid.md) +- [createErrorMap](functions/createErrorMap.md) +- [createErrorVisibility](functions/createErrorVisibility.md) +- [createValidator](functions/createValidator.md) +- [createValidators](functions/createValidators.md) +- [serverValidateHelper](functions/serverValidateHelper.md) diff --git a/docs/reference/interfaces/AnyDeepKeyAndValue.md b/docs/reference/interfaces/AnyDeepKeyAndValue.md deleted file mode 100644 index 523db9b9f1..0000000000 --- a/docs/reference/interfaces/AnyDeepKeyAndValue.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -id: AnyDeepKeyAndValue -title: AnyDeepKeyAndValue ---- - -# Interface: AnyDeepKeyAndValue\ - -Defined in: [packages/form-core/src/util-types.ts:39](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L39) - -## Extended by - -- [`ArrayDeepKeyAndValue`](ArrayDeepKeyAndValue.md) -- [`TupleDeepKeyAndValue`](TupleDeepKeyAndValue.md) -- [`ObjectDeepKeyAndValue`](ObjectDeepKeyAndValue.md) -- [`UnknownDeepKeyAndValue`](UnknownDeepKeyAndValue.md) - -## Type Parameters - -### K - -`K` *extends* `string` = `string` - -### V - -`V` *extends* `any` = `any` - -## Properties - -### key - -```ts -key: K; -``` - -Defined in: [packages/form-core/src/util-types.ts:43](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L43) - -*** - -### value - -```ts -value: V; -``` - -Defined in: [packages/form-core/src/util-types.ts:44](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L44) diff --git a/docs/reference/interfaces/ArrayDeepKeyAndValue.md b/docs/reference/interfaces/ArrayDeepKeyAndValue.md deleted file mode 100644 index 1e62e1d1fb..0000000000 --- a/docs/reference/interfaces/ArrayDeepKeyAndValue.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -id: ArrayDeepKeyAndValue -title: ArrayDeepKeyAndValue ---- - -# Interface: ArrayDeepKeyAndValue\ - -Defined in: [packages/form-core/src/util-types.ts:50](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L50) - -## Extends - -- [`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md) - -## Type Parameters - -### TParent - -`TParent` *extends* [`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md) - -### T - -`T` *extends* `ReadonlyArray`\<`any`\> - -## Properties - -### key - -```ts -key: `${TParent["key"] extends never ? "" : TParent["key"]}[${number}]`; -``` - -Defined in: [packages/form-core/src/util-types.ts:54](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L54) - -#### Overrides - -[`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md).[`key`](AnyDeepKeyAndValue.md#key) - -*** - -### value - -```ts -value: - | T[number] -| Nullable; -``` - -Defined in: [packages/form-core/src/util-types.ts:55](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L55) - -#### Overrides - -[`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md).[`value`](AnyDeepKeyAndValue.md#value) diff --git a/docs/reference/interfaces/BaseFieldMeta.md b/docs/reference/interfaces/BaseFieldMeta.md new file mode 100644 index 0000000000..1f0e757c27 --- /dev/null +++ b/docs/reference/interfaces/BaseFieldMeta.md @@ -0,0 +1,50 @@ +--- +id: BaseFieldMeta +title: BaseFieldMeta +--- + +Defined in: [FieldApi/FieldApi.public.ts:14](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L14) + +## Extended by + +- [`FieldMeta`](FieldMeta.md) + +## Properties + +### isBlurred + +```ts +isBlurred: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:17](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L17) + +*** + +### isDirty + +```ts +isDirty: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:16](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L16) + +*** + +### isTouched + +```ts +isTouched: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:15](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L15) + +*** + +### isValidating + +```ts +isValidating: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:18](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L18) diff --git a/docs/reference/interfaces/BaseFormOptions.md b/docs/reference/interfaces/BaseFormOptions.md deleted file mode 100644 index 9ea87feb44..0000000000 --- a/docs/reference/interfaces/BaseFormOptions.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -id: BaseFormOptions -title: BaseFormOptions ---- - -# Interface: BaseFormOptions\ - -Defined in: [packages/form-core/src/FormApi.ts:436](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L436) - -An object representing the base properties of a form, unrelated to any validators - -## Extended by - -- [`FormOptions`](FormOptions.md) - -## Type Parameters - -### TFormData - -`TFormData` - -### TSubmitMeta - -`TSubmitMeta` = `never` - -## Properties - -### defaultValues? - -```ts -optional defaultValues: TFormData; -``` - -Defined in: [packages/form-core/src/FormApi.ts:440](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L440) - -Set initial values for your form. - -*** - -### onSubmitMeta? - -```ts -optional onSubmitMeta: TSubmitMeta; -``` - -Defined in: [packages/form-core/src/FormApi.ts:444](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L444) - -onSubmitMeta, the data passed from the handleSubmit handler, to the onSubmit function props diff --git a/docs/reference/interfaces/BaseValidator.md b/docs/reference/interfaces/BaseValidator.md new file mode 100644 index 0000000000..0bdbde8112 --- /dev/null +++ b/docs/reference/interfaces/BaseValidator.md @@ -0,0 +1,55 @@ +--- +id: BaseValidator +title: BaseValidator +--- + +Defined in: [validation.public.ts:17](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L17) + +A validation function or Standard Schema with an optional rule to stop after earlier failures. + +## Extended by + +- [`Validator`](Validator.md) +- [`FormValidator`](FormValidator.md) + +## Type Parameters + +### TValidator + +`TValidator` *extends* + \| [`StandardSchemaV1`](../type-aliases/StandardSchemaV1.md) + \| [`ValidatorFn`](../type-aliases/ValidatorFn.md)\<`any`, `any`\> + +Library-managed. Do not specify explicitly. + +## Properties + +### bailIfInvalid? + +```ts +optional bailIfInvalid?: boolean; +``` + +Defined in: [validation.public.ts:29](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L29) + +If `true`, skips this and subsequent validators when earlier validation has failed. + +If `false`, earlier failures do not prevent this validator from running. + +#### Default + +```ts +false +``` + +*** + +### run + +```ts +run: TValidator; +``` + +Defined in: [validation.public.ts:21](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L21) + +The function or Standard Schema that validates the value in this validator's scope. diff --git a/docs/reference/interfaces/DefaultOptions.md b/docs/reference/interfaces/DefaultOptions.md new file mode 100644 index 0000000000..69690cdd46 --- /dev/null +++ b/docs/reference/interfaces/DefaultOptions.md @@ -0,0 +1,48 @@ +--- +id: DefaultOptions +title: DefaultOptions +--- + +Defined in: [defaultOptions.public.ts:132](https://github.com/TanStack/form/blob/main/packages/form-core/src/defaultOptions.public.ts#L132) + +Collects the reusable defaults owned by one form. + +Each API resolves its usage-site options against the corresponding entry. +The defaults remain form-wide configuration rather than becoming part of +form, field, or group value inference. + +## Properties + +### field? + +```ts +optional field?: DefaultFieldOptions; +``` + +Defined in: [defaultOptions.public.ts:136](https://github.com/TanStack/form/blob/main/packages/form-core/src/defaultOptions.public.ts#L136) + +Defaults resolved against field options. + +*** + +### form? + +```ts +optional form?: DefaultFormOptions; +``` + +Defined in: [defaultOptions.public.ts:134](https://github.com/TanStack/form/blob/main/packages/form-core/src/defaultOptions.public.ts#L134) + +Defaults resolved against form options. + +*** + +### formGroup? + +```ts +optional formGroup?: DefaultFormGroupOptions; +``` + +Defined in: [defaultOptions.public.ts:138](https://github.com/TanStack/form/blob/main/packages/form-core/src/defaultOptions.public.ts#L138) + +Defaults resolved against form-group options. diff --git a/docs/reference/interfaces/ErrorVisibilityContext.md b/docs/reference/interfaces/ErrorVisibilityContext.md new file mode 100644 index 0000000000..3c7ed5fe70 --- /dev/null +++ b/docs/reference/interfaces/ErrorVisibilityContext.md @@ -0,0 +1,47 @@ +--- +id: ErrorVisibilityContext +title: ErrorVisibilityContext +--- + +Defined in: [validation.public.ts:315](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L315) + +Form and field state used to decide whether to show a field's errors. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### fieldState + +```ts +fieldState: ErrorVisibilityFieldState; +``` + +Defined in: [validation.public.ts:325](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L325) + +The field whose errors the policy controls. + +*** + +### state + +```ts +state: FormState; +``` + +Defined in: [validation.public.ts:323](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L323) + +Current form state. For a field in a form group, flags and submission +counters describe that group. `values` and `errors` describe the whole form. diff --git a/docs/reference/interfaces/ErrorVisibilityFieldMeta.md b/docs/reference/interfaces/ErrorVisibilityFieldMeta.md new file mode 100644 index 0000000000..93b0a31ee6 --- /dev/null +++ b/docs/reference/interfaces/ErrorVisibilityFieldMeta.md @@ -0,0 +1,128 @@ +--- +id: ErrorVisibilityFieldMeta +title: ErrorVisibilityFieldMeta +--- + +Defined in: [validation.public.ts:278](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L278) + +Field state flags available to an error visibility policy. + +## Properties + +### isBlurred + +```ts +isBlurred: boolean; +``` + +Defined in: [validation.public.ts:292](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L292) + +`true` when this field is marked as blurred. + +*** + +### isDefaultValue + +```ts +isDefaultValue: boolean; +``` + +Defined in: [validation.public.ts:290](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L290) + +`true` when the current value equals the field's default value. + +*** + +### isDirty + +```ts +isDirty: boolean; +``` + +Defined in: [validation.public.ts:284](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L284) + +`true` when this field or a descendant is marked as dirty. + +*** + +### isPristine + +```ts +isPristine: boolean; +``` + +Defined in: [validation.public.ts:288](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L288) + +`true` when neither this field nor its descendants are marked as dirty. + +*** + +### isSelfDirty + +```ts +isSelfDirty: boolean; +``` + +Defined in: [validation.public.ts:286](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L286) + +`true` when this field itself is marked as dirty. + +*** + +### isSelfTouched + +```ts +isSelfTouched: boolean; +``` + +Defined in: [validation.public.ts:282](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L282) + +`true` when this field itself is marked as touched. + +*** + +### isSelfValidating + +```ts +isSelfValidating: boolean; +``` + +Defined in: [validation.public.ts:296](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L296) + +`true` while this field itself is validating. + +*** + +### isTouched + +```ts +isTouched: boolean; +``` + +Defined in: [validation.public.ts:280](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L280) + +`true` when this field or a descendant is marked as touched. + +*** + +### isValidating + +```ts +isValidating: boolean; +``` + +Defined in: [validation.public.ts:294](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L294) + +`true` while this field or a descendant is validating. + +*** + +### subfields + +```ts +subfields: ErrorVisibilitySubfieldsMeta; +``` + +Defined in: [validation.public.ts:298](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L298) + +State flags for this field's descendants. diff --git a/docs/reference/interfaces/ErrorVisibilityFieldState.md b/docs/reference/interfaces/ErrorVisibilityFieldState.md new file mode 100644 index 0000000000..acfaebbd37 --- /dev/null +++ b/docs/reference/interfaces/ErrorVisibilityFieldState.md @@ -0,0 +1,32 @@ +--- +id: ErrorVisibilityFieldState +title: ErrorVisibilityFieldState +--- + +Defined in: [validation.public.ts:302](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L302) + +The field value and state flags available to an error visibility policy. + +## Properties + +### meta + +```ts +meta: ErrorVisibilityFieldMeta; +``` + +Defined in: [validation.public.ts:306](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L306) + +State flags before the visibility policy is applied. + +*** + +### value + +```ts +value: any; +``` + +Defined in: [validation.public.ts:304](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L304) + +The current value of the field whose errors the policy controls. diff --git a/docs/reference/interfaces/ErrorVisibilitySubfieldsMeta.md b/docs/reference/interfaces/ErrorVisibilitySubfieldsMeta.md new file mode 100644 index 0000000000..ea2a4a10a4 --- /dev/null +++ b/docs/reference/interfaces/ErrorVisibilitySubfieldsMeta.md @@ -0,0 +1,56 @@ +--- +id: ErrorVisibilitySubfieldsMeta +title: ErrorVisibilitySubfieldsMeta +--- + +Defined in: [validation.public.ts:266](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L266) + +Descendant field state available when deciding whether to show errors. + +## Properties + +### isEveryPristine + +```ts +isEveryPristine: boolean; +``` + +Defined in: [validation.public.ts:268](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L268) + +`true` when no descendant field is marked as dirty. + +*** + +### isSomeDirty + +```ts +isSomeDirty: boolean; +``` + +Defined in: [validation.public.ts:270](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L270) + +`true` when at least one descendant field is marked as dirty. + +*** + +### isSomeTouched + +```ts +isSomeTouched: boolean; +``` + +Defined in: [validation.public.ts:272](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L272) + +`true` when at least one descendant field is marked as touched. + +*** + +### isSomeValidating + +```ts +isSomeValidating: boolean; +``` + +Defined in: [validation.public.ts:274](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L274) + +`true` while at least one descendant field is validating. diff --git a/docs/reference/interfaces/FieldApi.md b/docs/reference/interfaces/FieldApi.md new file mode 100644 index 0000000000..f374526353 --- /dev/null +++ b/docs/reference/interfaces/FieldApi.md @@ -0,0 +1,346 @@ +--- +id: FieldApi +title: FieldApi +--- + +Defined in: [FieldApi/FieldApi.public.ts:123](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L123) + +## Type Parameters + +### TFieldName + +`TFieldName` + +### TFieldValue + +`TFieldValue` + +### TFieldError + +`TFieldError` + +### TFormData + +`TFormData` + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +## Properties + +### atom + +```ts +atom: ReadonlyAtom>; +``` + +Defined in: [FieldApi/FieldApi.public.ts:206](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L206) + +*** + +### clearValues + +```ts +clearValues: FieldClearValuesFn; +``` + +Defined in: [FieldApi/FieldApi.public.ts:179](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L179) + +Clear all values from this field's array. +If this field is not an array, this method will be ignored. + +#### Param + +**options** + +Optional update options + +*** + +### errors + +```ts +errors: FieldErrors; +``` + +Defined in: [FieldApi/FieldApi.public.ts:212](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L212) + +*** + +### filterValues + +```ts +filterValues: FieldFilterValuesFn; +``` + +Defined in: [FieldApi/FieldApi.public.ts:204](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L204) + +Filter the values in this field's array using a predicate function. +If this field is not an array, this method will be ignored. + +#### Param + +**predicate** + +The predicate function to filter values. Returns true to keep the value, false to remove it. + +#### Param + +**options** + +Optional update options including a custom `thisArg` for the predicate + +*** + +### form + +```ts +form: FormApi; +``` + +Defined in: [FieldApi/FieldApi.public.ts:133](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L133) + +The form that owns this field. + +*** + +### handleBlur + +```ts +handleBlur: FieldVoidFn; +``` + +Defined in: [FieldApi/FieldApi.public.ts:216](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L216) + +*** + +### handleChange + +```ts +handleChange: FieldHandleChangeFn; +``` + +Defined in: [FieldApi/FieldApi.public.ts:214](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L214) + +*** + +### insertValue + +```ts +insertValue: FieldInsertValueFn; +``` + +Defined in: [FieldApi/FieldApi.public.ts:172](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L172) + +Insert a new value into this field's array at the specified index. +If this field is not an array, this method will be ignored. + +#### Param + +**index** + +The index at which to insert the value + +#### Param + +**value** + +The value to insert + +#### Param + +**options** + +Optional update options + +*** + +### meta + +```ts +meta: FieldMeta; +``` + +Defined in: [FieldApi/FieldApi.public.ts:210](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L210) + +*** + +### moveValue + +```ts +moveValue: FieldMoveValueFn; +``` + +Defined in: [FieldApi/FieldApi.public.ts:155](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L155) + +Move an element in this field's array from one index to another. +If this field is not an array, this method will be ignored. + +#### Param + +**fromIndex** + +The current index of the element to move + +#### Param + +**toIndex** + +The index to move the element to + +#### Param + +**options** + +Optional update options + +*** + +### pushValue + +```ts +pushValue: FieldPushValueFn; +``` + +Defined in: [FieldApi/FieldApi.public.ts:163](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L163) + +Push a new value into this field's array. +If this field is not an array, this method will be ignored. + +#### Param + +**value** + +The value to push into the array + +#### Param + +**options** + +Optional update options + +*** + +### removeValue + +```ts +removeValue: FieldRemoveValueFn; +``` + +Defined in: [FieldApi/FieldApi.public.ts:196](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L196) + +Remove a value from this field's array at the specified index. +If this field is not an array, this method will be ignored. + +#### Param + +**index** + +The index of the value to remove + +#### Param + +**options** + +Optional update options + +*** + +### replaceValue + +```ts +replaceValue: FieldReplaceValueFn; +``` + +Defined in: [FieldApi/FieldApi.public.ts:188](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L188) + +Replace the value at the specified index in this field's array. +If this field is not an array, this method will be ignored. + +#### Param + +**index** + +The index of the value to replace + +#### Param + +**value** + +The new value + +#### Param + +**options** + +Optional update options + +*** + +### reset + +```ts +reset: FieldVoidFn; +``` + +Defined in: [FieldApi/FieldApi.public.ts:218](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L218) + +*** + +### swapValues + +```ts +swapValues: (indexA, indexB) => void; +``` + +Defined in: [FieldApi/FieldApi.public.ts:146](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L146) + +Swap two elements in this field's array. +If this field is not an array, this method will be ignored. + +#### Parameters + +##### indexA + +`number` + +The index of the first element to swap + +##### indexB + +`number` + +The index of the second element to swap + +#### Returns + +`void` + +*** + +### value + +```ts +value: TFieldValue; +``` + +Defined in: [FieldApi/FieldApi.public.ts:208](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L208) + +## Accessors + +### name + +#### Get Signature + +```ts +get name(): TFieldName; +``` + +Defined in: [FieldApi/FieldApi.public.ts:138](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L138) + +The name of the field. + +##### Returns + +`TFieldName` diff --git a/docs/reference/interfaces/FieldApiOptions.md b/docs/reference/interfaces/FieldApiOptions.md index 16047c7191..d67d24ba23 100644 --- a/docs/reference/interfaces/FieldApiOptions.md +++ b/docs/reference/interfaces/FieldApiOptions.md @@ -3,264 +3,89 @@ id: FieldApiOptions title: FieldApiOptions --- -# Interface: FieldApiOptions\ - -Defined in: [packages/form-core/src/FieldApi.ts:383](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L383) - -## Extends - -- `FieldExtraOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`\> +Defined in: [FieldApi/FieldApi.public.ts:221](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L221) ## Type Parameters -### TParentData - -`TParentData` - -### TName - -`TName` *extends* [`DeepKeys`](../type-aliases/DeepKeys.md)\<`TParentData`\> - -### TData - -`TData` *extends* [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TFormOnMount +### TFieldData -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +`TFieldData` -### TFormOnChange +### TFieldName -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +`TFieldName` -### TFormOnChangeAsync +### TFieldValue -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +`TFieldValue` -### TFormOnBlur +### TFieldValidators -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +`TFieldValidators` *extends* [`FieldValidators`](../type-aliases/FieldValidators.md)\<`TFieldData`, `TFieldName`, `TFieldValue`\> -### TFormOnBlurAsync +### TGroupFieldError -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> +`TGroupFieldError` -### TFormOnSubmit +### TFormData -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> +`TFormData` -### TFormOnSubmitAsync +### TFormErrorTypes -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) ## Properties -### asyncAlways? - -```ts -optional asyncAlways: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:982](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L982) - -If `true`, always run async validation, even if there are errors emitted during synchronous validation. - -#### Inherited from - -```ts -FieldLikeApiOptions.asyncAlways -``` - -*** - -### asyncDebounceMs? - -```ts -optional asyncDebounceMs: number; -``` - -Defined in: [packages/form-core/src/types.ts:978](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L978) - -The default time to debounce async validation if there is not a more specific debounce time passed. - -#### Inherited from +### errorBoundary? ```ts -FieldLikeApiOptions.asyncDebounceMs +optional errorBoundary?: boolean; ``` -*** - -### defaultMeta? - -```ts -optional defaultMeta: Partial>; -``` - -Defined in: [packages/form-core/src/types.ts:986](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L986) - -An optional object with default metadata for the field. +Defined in: [FieldApi/FieldApi.public.ts:239](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L239) -#### Inherited from - -```ts -FieldLikeApiOptions.defaultMeta -``` +Route descendant field errors from form and form group validators to this field. *** -### defaultValue? +### errorVisibility? ```ts -optional defaultValue: NoInfer; +optional errorVisibility?: ErrorVisibility; ``` -Defined in: [packages/form-core/src/types.ts:974](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L974) - -An optional default value for the field. - -#### Inherited from - -```ts -FieldLikeApiOptions.defaultValue -``` - -*** - -### disableErrorFlat? - -```ts -optional disableErrorFlat: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:1014](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L1014) - -Disable the `flat(1)` operation on `field.errors`. This is useful if you want to keep the error structure as is. Not suggested for most use-cases. - -#### Inherited from - -```ts -FieldLikeApiOptions.disableErrorFlat -``` - -*** - -### form - -```ts -form: FormApi; -``` - -Defined in: [packages/form-core/src/types.ts:1094](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L1094) - -#### Inherited from - -```ts -FieldLikeApiOptions.form -``` +Defined in: [FieldApi/FieldApi.public.ts:235](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L235) *** ### listeners? ```ts -optional listeners: FieldListeners; +optional listeners?: FieldListeners, FieldValidators> + | unknown extends TGroupFieldError ? never : TGroupFieldError +| ExtractFormFieldError>, TFormData, TFormErrorTypes>; ``` -Defined in: [packages/form-core/src/FieldApi.ts:325](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L325) - -A list of listeners which attach to the corresponding events - -#### Inherited from - -```ts -FieldExtraOptions.listeners -``` +Defined in: [FieldApi/FieldApi.public.ts:241](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L241) *** ### name ```ts -name: TName; +name: TFieldName; ``` -Defined in: [packages/form-core/src/types.ts:970](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L970) - -The field name. The type will be `DeepKeys` to ensure your name is a deep key of the parent dataset. - -#### Inherited from - -```ts -FieldLikeApiOptions.name -``` +Defined in: [FieldApi/FieldApi.public.ts:234](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L234) *** ### validators? ```ts -optional validators: FieldValidators; +optional validators?: TFieldValidators; ``` -Defined in: [packages/form-core/src/FieldApi.ts:307](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L307) - -A list of validators to pass to the field - -#### Inherited from - -```ts -FieldExtraOptions.validators -``` +Defined in: [FieldApi/FieldApi.public.ts:240](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L240) diff --git a/docs/reference/interfaces/FieldGroupFieldSlot.md b/docs/reference/interfaces/FieldGroupFieldSlot.md new file mode 100644 index 0000000000..8b69427a86 --- /dev/null +++ b/docs/reference/interfaces/FieldGroupFieldSlot.md @@ -0,0 +1,53 @@ +--- +id: FieldGroupFieldSlot +title: FieldGroupFieldSlot +--- + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:27](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L27) + +Describes the value type and matching rule for one virtual field in a +reusable field group. + +Slots are type markers consumed by a field-group definition. Their +properties are not available at runtime. + +Create slots with `FieldGroupHelper.strict` or `FieldGroupHelper.loose` +inside a field-group definition instead of constructing them directly. + +## Type Parameters + +### TValue + +`TValue` + +The value type declared for the virtual field. + +### TMode + +`TMode` *extends* [`FieldGroupFieldSlotMode`](../type-aliases/FieldGroupFieldSlotMode.md) = [`FieldGroupFieldSlotMode`](../type-aliases/FieldGroupFieldSlotMode.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### \[fieldGroupFieldSlotValueSymbol\] + +```ts +readonly [fieldGroupFieldSlotValueSymbol]: TValue; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:34](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L34) + +Preserves the declared value type for type-level inference. + +*** + +### mode + +```ts +readonly mode: TMode; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:32](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L32) + +Represents the slot's value-type matching rule at the type level. diff --git a/docs/reference/interfaces/FieldGroupHelper.md b/docs/reference/interfaces/FieldGroupHelper.md new file mode 100644 index 0000000000..197d9d0085 --- /dev/null +++ b/docs/reference/interfaces/FieldGroupHelper.md @@ -0,0 +1,166 @@ +--- +id: FieldGroupHelper +title: FieldGroupHelper +--- + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:259](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L259) + +Declares the virtual fields in a reusable field group and how their value +types may bind to concrete form fields. + +## Example + +```ts +const profileFields = defineFieldGroup(({ strict, loose }) => ({ + name: strict(''), + status: loose(), +})) +``` + +## Properties + +### loose + +```ts +loose: { + (value): LooseFieldGroupFieldSlot; + (): LooseFieldGroupFieldSlot; +}; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:298](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L298) + +Declares a virtual field that can bind to form fields whose value type is +assignable to the declared type. + +#### Call Signature + +```ts +(value): LooseFieldGroupFieldSlot; +``` + +##### Type Parameters + +###### TValue + +`TValue` + +Inferred from the representative value. + +##### Parameters + +###### value + +`TValue` + +A representative value used only for type inference. + +##### Returns + +[`LooseFieldGroupFieldSlot`](../type-aliases/LooseFieldGroupFieldSlot.md)\<`TValue`\> + +A field slot that uses assignable value-type matching. + +#### Call Signature + +```ts +(): LooseFieldGroupFieldSlot; +``` + +##### Type Parameters + +###### TValue + +`TValue` + +The value type that compatible concrete field values +must be assignable to. + +##### Returns + +[`LooseFieldGroupFieldSlot`](../type-aliases/LooseFieldGroupFieldSlot.md)\<`TValue`\> + +A field slot that uses assignable value-type matching. + +#### Example + +```tsx +const passwordFieldGroup = defineFieldGroup(({ loose }) => ({ + password: loose(), + confirmPassword: loose(), +})) +``` + +*** + +### strict + +```ts +strict: { + (value): StrictFieldGroupFieldSlot; + (): StrictFieldGroupFieldSlot; +}; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:272](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L272) + +Declares a virtual field whose value type must exactly match the value type +of the concrete form field it binds to. + +#### Call Signature + +```ts +(value): StrictFieldGroupFieldSlot; +``` + +##### Type Parameters + +###### TValue + +`TValue` + +Inferred from the representative value. + +##### Parameters + +###### value + +`TValue` + +A representative value used only for type inference. + +##### Returns + +[`StrictFieldGroupFieldSlot`](../type-aliases/StrictFieldGroupFieldSlot.md)\<`TValue`\> + +A field slot that uses strict value-type matching. + +#### Call Signature + +```ts +(): StrictFieldGroupFieldSlot; +``` + +##### Type Parameters + +###### TValue + +`TValue` + +The value type the concrete form field must match +exactly. + +##### Returns + +[`StrictFieldGroupFieldSlot`](../type-aliases/StrictFieldGroupFieldSlot.md)\<`TValue`\> + +A field slot that uses strict value-type matching. + +#### Example + +```tsx +const passwordFieldGroup = defineFieldGroup(({ strict }) => ({ + password: strict(), + confirmPassword: strict(), +})) +``` diff --git a/docs/reference/interfaces/FieldGroupOptions.md b/docs/reference/interfaces/FieldGroupOptions.md deleted file mode 100644 index b9c2df13a8..0000000000 --- a/docs/reference/interfaces/FieldGroupOptions.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -id: FieldGroupOptions -title: FieldGroupOptions ---- - -# Interface: FieldGroupOptions\ - -Defined in: [packages/form-core/src/FieldGroupApi.ts:51](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L51) - -An object representing the options for a field group. - -## Type Parameters - -### TFormData - -`TFormData` - -### TFieldGroupData - -`TFieldGroupData` - -### TFields - -`TFields` *extends* - \| [`DeepKeysOfType`](../type-aliases/DeepKeysOfType.md)\<`TFormData`, `TFieldGroupData` \| `null` \| `undefined`\> - \| [`FieldsMap`](../type-aliases/FieldsMap.md)\<`TFormData`, `TFieldGroupData`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` = `never` - -## Properties - -### defaultValues? - -```ts -optional defaultValues: TFieldGroupData; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:107](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L107) - -The expected subsetValues that the form must provide. - -*** - -### fields - -```ts -fields: TFields; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:103](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L103) - -The path to the field group data. - -*** - -### form - -```ts -form: - | FormApi -| FieldGroupApi; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:69](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L69) - -*** - -### onSubmitMeta? - -```ts -optional onSubmitMeta: TSubmitMeta; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:111](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L111) - -onSubmitMeta, the data passed from the handleSubmit handler, to the onSubmit function props diff --git a/docs/reference/interfaces/FieldGroupState.md b/docs/reference/interfaces/FieldGroupState.md deleted file mode 100644 index 8a5270d4ba..0000000000 --- a/docs/reference/interfaces/FieldGroupState.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -id: FieldGroupState -title: FieldGroupState ---- - -# Interface: FieldGroupState\ - -Defined in: [packages/form-core/src/FieldGroupApi.ts:41](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L41) - -## Type Parameters - -### TFieldGroupData - -`TFieldGroupData` - -## Properties - -### values - -```ts -values: TFieldGroupData; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:45](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L45) - -The current values of the field group diff --git a/docs/reference/interfaces/FieldListener.md b/docs/reference/interfaces/FieldListener.md new file mode 100644 index 0000000000..b6838db513 --- /dev/null +++ b/docs/reference/interfaces/FieldListener.md @@ -0,0 +1,182 @@ +--- +id: FieldListener +title: FieldListener +--- + +Defined in: [listeners.public.ts:437](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L437) + +A listener configured on a field. + +`'change'` and `'blur'` events from descendant fields propagate to their +ancestor field listeners. Use `watchFields` to receive matching events from +other fields. + +## Example + +```ts +listeners: [ + { + triggers: ['change', 'blur'], + triggerDebounceMs: 200, + watchFields: ['displayName'], + run: ({ value, formApi }) => { + saveContact({ + displayName: formApi.getFieldValue('displayName'), + email: value, + }) + }, + }, +], +``` + +## Extends + +- [`Listener`](Listener.md)\<[`FieldListenerTriggers`](../type-aliases/FieldListenerTriggers.md), `TFieldData`, `TFieldValue`\> + +## Type Parameters + +### TFieldData + +`TFieldData` + +Library-managed. Do not specify explicitly. + +### TFieldName + +`TFieldName` + +Library-managed. Do not specify explicitly. + +### TFieldValue + +`TFieldValue` + +Library-managed. Do not specify explicitly. + +### TFieldError + +`TFieldError` + +Library-managed. Do not specify explicitly. + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### run + +```ts +run: FieldListenerFn; +``` + +Defined in: [listeners.public.ts:461](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L461) + +Called when an enabled field trigger occurs. + +The return value is ignored. A returned promise is not awaited, and a +rejected promise is reported to the console. + +#### Example + +```ts +run: ({ value, fieldApi }) => { + const trimmedValue = value.trim() + if (trimmedValue !== value) { + fieldApi.handleChange(trimmedValue) + } +}, +``` + +*** + +### triggerDebounceMs? + +```ts +optional triggerDebounceMs?: + | number +| ListenerDebounceFn; +``` + +Defined in: [listeners.public.ts:173](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L173) + +The debounce delay in milliseconds before the listener runs. + +A function recalculates the delay for each matching event. Repeated events +restart the delay, and the listener receives the latest event context. +Values less than or equal to `0` run immediately. `'submit'` events always +run immediately. + +#### Default + +```ts +0 +``` + +#### Inherited from + +[`Listener`](Listener.md).[`triggerDebounceMs`](Listener.md#triggerdebouncems) + +*** + +### triggers + +```ts +triggers: ListenerTriggerOption[]; +``` + +Defined in: [listeners.public.ts:191](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L191) + +The events that can invoke the listener. + +The listener runs at most once for an event, even if multiple entries +match. An empty array disables the listener. + +#### Example + +```ts +triggers: [ + 'blur', + { + trigger: 'change', + when: ({ formApi }) => formApi.state.isDirty, + }, +], +``` + +#### Inherited from + +[`Listener`](Listener.md).[`triggers`](Listener.md#triggers) + +*** + +### watchFields? + +```ts +optional watchFields?: DeepKeys[]; +``` + +Defined in: [listeners.public.ts:482](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L482) + +Other fields whose matching events should also invoke this listener. + +The callback still receives this listener's `fieldApi` and `value`, not +the watched field or its value. + +When omitted, the listener receives matching events from its own field and +propagated descendant events only. + +#### Example + +```ts +watchFields: ['firstName', 'lastName'], +``` diff --git a/docs/reference/interfaces/FieldListenerContext.md b/docs/reference/interfaces/FieldListenerContext.md new file mode 100644 index 0000000000..4c810ffc37 --- /dev/null +++ b/docs/reference/interfaces/FieldListenerContext.md @@ -0,0 +1,79 @@ +--- +id: FieldListenerContext +title: FieldListenerContext +--- + +Defined in: [listeners.public.ts:339](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L339) + +Context passed to a field listener. + +## Type Parameters + +### TFieldName + +`TFieldName` + +Library-managed. Do not specify explicitly. + +### TFieldValue + +`TFieldValue` + +Library-managed. Do not specify explicitly. + +### TFieldError + +`TFieldError` + +Library-managed. Do not specify explicitly. + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### fieldApi + +```ts +fieldApi: FieldApi; +``` + +Defined in: [listeners.public.ts:354](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L354) + +The field that owns the listener. + +This remains the listening field when an event arrives through +`watchFields`. + +*** + +### formApi + +```ts +formApi: FormApi; +``` + +Defined in: [listeners.public.ts:362](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L362) + +The form that owns the field. + +*** + +### value + +```ts +value: TFieldValue; +``` + +Defined in: [listeners.public.ts:347](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L347) + +The listening field's value captured when the event occurred. diff --git a/docs/reference/interfaces/FieldListeners.md b/docs/reference/interfaces/FieldListeners.md deleted file mode 100644 index fc59e27f6a..0000000000 --- a/docs/reference/interfaces/FieldListeners.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -id: FieldListeners -title: FieldListeners ---- - -# Interface: FieldListeners\ - -Defined in: [packages/form-core/src/FieldApi.ts:267](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L267) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* [`DeepKeys`](../type-aliases/DeepKeys.md)\<`TParentData`\> - -### TData - -`TData` *extends* [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> = [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> - -## Properties - -### onBlur? - -```ts -optional onBlur: FieldListenerFn; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:274](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L274) - -*** - -### onBlurDebounceMs? - -```ts -optional onBlurDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:275](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L275) - -*** - -### onChange? - -```ts -optional onChange: FieldListenerFn; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:272](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L272) - -*** - -### onChangeDebounceMs? - -```ts -optional onChangeDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:273](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L273) - -*** - -### onGroupSubmit? - -```ts -optional onGroupSubmit: FieldListenerFn; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:279](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L279) - -*** - -### onMount? - -```ts -optional onMount: FieldListenerFn; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:276](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L276) - -*** - -### onSubmit? - -```ts -optional onSubmit: FieldListenerFn; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:278](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L278) - -*** - -### onUnmount? - -```ts -optional onUnmount: FieldListenerFn; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:277](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L277) diff --git a/docs/reference/interfaces/FieldMeta.md b/docs/reference/interfaces/FieldMeta.md new file mode 100644 index 0000000000..f28dd972f4 --- /dev/null +++ b/docs/reference/interfaces/FieldMeta.md @@ -0,0 +1,182 @@ +--- +id: FieldMeta +title: FieldMeta +--- + +Defined in: [FieldApi/FieldApi.public.ts:38](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L38) + +## Extends + +- [`BaseFieldMeta`](BaseFieldMeta.md) + +## Type Parameters + +### TFieldError + +`TFieldError` + +## Properties + +### errors + +```ts +errors: FieldErrors; +``` + +Defined in: [FieldApi/FieldApi.public.ts:48](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L48) + +*** + +### isBlurred + +```ts +isBlurred: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:17](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L17) + +#### Inherited from + +[`BaseFieldMeta`](BaseFieldMeta.md).[`isBlurred`](BaseFieldMeta.md#isblurred) + +*** + +### isDefaultValue + +```ts +isDefaultValue: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:40](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L40) + +*** + +### isDirty + +```ts +isDirty: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:16](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L16) + +#### Inherited from + +[`BaseFieldMeta`](BaseFieldMeta.md).[`isDirty`](BaseFieldMeta.md#isdirty) + +*** + +### isInvalid + +```ts +isInvalid: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:43](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L43) + +*** + +### isPristine + +```ts +isPristine: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:39](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L39) + +*** + +### isSelfDirty + +```ts +isSelfDirty: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:42](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L42) + +*** + +### isSelfTouched + +```ts +isSelfTouched: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:41](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L41) + +*** + +### isSelfValid + +```ts +isSelfValid: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:44](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L44) + +*** + +### isSelfValidating + +```ts +isSelfValidating: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:45](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L45) + +*** + +### isTouched + +```ts +isTouched: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:15](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L15) + +#### Inherited from + +[`BaseFieldMeta`](BaseFieldMeta.md).[`isTouched`](BaseFieldMeta.md#istouched) + +*** + +### isValid + +```ts +isValid: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:46](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L46) + +*** + +### isValidating + +```ts +isValidating: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:18](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L18) + +#### Inherited from + +[`BaseFieldMeta`](BaseFieldMeta.md).[`isValidating`](BaseFieldMeta.md#isvalidating) + +*** + +### original + +```ts +original: OriginalFieldMeta; +``` + +Defined in: [FieldApi/FieldApi.public.ts:49](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L49) + +*** + +### subfields + +```ts +subfields: SubfieldsMeta; +``` + +Defined in: [FieldApi/FieldApi.public.ts:47](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L47) diff --git a/docs/reference/interfaces/FieldOptions.md b/docs/reference/interfaces/FieldOptions.md deleted file mode 100644 index 124f8bc843..0000000000 --- a/docs/reference/interfaces/FieldOptions.md +++ /dev/null @@ -1,208 +0,0 @@ ---- -id: FieldOptions -title: FieldOptions ---- - -# Interface: FieldOptions\ - -Defined in: [packages/form-core/src/FieldApi.ts:331](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L331) - -An object type representing the options for a field in a form. - -## Extends - -- `FieldExtraOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`\> - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* [`DeepKeys`](../type-aliases/DeepKeys.md)\<`TParentData`\> - -### TData - -`TData` *extends* [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -## Properties - -### asyncAlways? - -```ts -optional asyncAlways: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:982](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L982) - -If `true`, always run async validation, even if there are errors emitted during synchronous validation. - -#### Inherited from - -```ts -FieldLikeOptions.asyncAlways -``` - -*** - -### asyncDebounceMs? - -```ts -optional asyncDebounceMs: number; -``` - -Defined in: [packages/form-core/src/types.ts:978](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L978) - -The default time to debounce async validation if there is not a more specific debounce time passed. - -#### Inherited from - -```ts -FieldLikeOptions.asyncDebounceMs -``` - -*** - -### defaultMeta? - -```ts -optional defaultMeta: Partial>; -``` - -Defined in: [packages/form-core/src/types.ts:986](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L986) - -An optional object with default metadata for the field. - -#### Inherited from - -```ts -FieldLikeOptions.defaultMeta -``` - -*** - -### defaultValue? - -```ts -optional defaultValue: NoInfer; -``` - -Defined in: [packages/form-core/src/types.ts:974](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L974) - -An optional default value for the field. - -#### Inherited from - -```ts -FieldLikeOptions.defaultValue -``` - -*** - -### disableErrorFlat? - -```ts -optional disableErrorFlat: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:1014](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L1014) - -Disable the `flat(1)` operation on `field.errors`. This is useful if you want to keep the error structure as is. Not suggested for most use-cases. - -#### Inherited from - -```ts -FieldLikeOptions.disableErrorFlat -``` - -*** - -### listeners? - -```ts -optional listeners: FieldListeners; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:325](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L325) - -A list of listeners which attach to the corresponding events - -#### Inherited from - -```ts -FieldExtraOptions.listeners -``` - -*** - -### name - -```ts -name: TName; -``` - -Defined in: [packages/form-core/src/types.ts:970](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L970) - -The field name. The type will be `DeepKeys` to ensure your name is a deep key of the parent dataset. - -#### Inherited from - -```ts -FieldLikeOptions.name -``` - -*** - -### validators? - -```ts -optional validators: FieldValidators; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:307](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L307) - -A list of validators to pass to the field - -#### Inherited from - -```ts -FieldExtraOptions.validators -``` diff --git a/docs/reference/interfaces/FieldState.md b/docs/reference/interfaces/FieldState.md new file mode 100644 index 0000000000..b0db3e154d --- /dev/null +++ b/docs/reference/interfaces/FieldState.md @@ -0,0 +1,36 @@ +--- +id: FieldState +title: FieldState +--- + +Defined in: [FieldApi/FieldApi.public.ts:52](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L52) + +## Type Parameters + +### TFieldValue + +`TFieldValue` + +### TFieldError + +`TFieldError` + +## Properties + +### meta + +```ts +meta: FieldMeta; +``` + +Defined in: [FieldApi/FieldApi.public.ts:54](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L54) + +*** + +### value + +```ts +value: TFieldValue; +``` + +Defined in: [FieldApi/FieldApi.public.ts:53](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L53) diff --git a/docs/reference/interfaces/FieldUpdateOptions.md b/docs/reference/interfaces/FieldUpdateOptions.md new file mode 100644 index 0000000000..2276b7e333 --- /dev/null +++ b/docs/reference/interfaces/FieldUpdateOptions.md @@ -0,0 +1,74 @@ +--- +id: FieldUpdateOptions +title: FieldUpdateOptions +--- + +Defined in: [types.public.ts:6](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.public.ts#L6) + +## Properties + +### causeValidation? + +```ts +optional causeValidation?: boolean; +``` + +Defined in: [types.public.ts:30](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.public.ts#L30) + +Whether to cause a validation run from the update. + +#### Default + +```ts +true +``` + +*** + +### markAsBlurred? + +```ts +optional markAsBlurred?: boolean; +``` + +Defined in: [types.public.ts:24](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.public.ts#L24) + +Whether to mark the field as blurred from the update. + +@default: Only true if the emitted event is a blur + +*** + +### markAsDirty? + +```ts +optional markAsDirty?: boolean; +``` + +Defined in: [types.public.ts:18](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.public.ts#L18) + +Whether to mark the field as dirty from the update. + +#### Default + +```ts +true +``` + +*** + +### markAsTouched? + +```ts +optional markAsTouched?: boolean; +``` + +Defined in: [types.public.ts:12](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.public.ts#L12) + +Whether to mark the field as touched from the update. + +#### Default + +```ts +true +``` diff --git a/docs/reference/interfaces/FieldValidationPredicateContext.md b/docs/reference/interfaces/FieldValidationPredicateContext.md new file mode 100644 index 0000000000..43497c7b62 --- /dev/null +++ b/docs/reference/interfaces/FieldValidationPredicateContext.md @@ -0,0 +1,108 @@ +--- +id: FieldValidationPredicateContext +title: FieldValidationPredicateContext +--- + +Defined in: [validation.public.ts:443](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L443) + +Current field state available to validator conditions and delay callbacks. + +## Extends + +- `BaseValidationPredicateContext`\<`TFormData`, `TFieldValue`, `"field"`\> + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFieldValue + +`TFieldValue` + +Library-managed. Do not specify explicitly. + +## Properties + +### fieldApi + +```ts +fieldApi: AnyFieldApi; +``` + +Defined in: [validation.public.ts:449](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L449) + +The field being validated. + +#### Overrides + +```ts +BaseValidationPredicateContext.fieldApi +``` + +*** + +### formApi + +```ts +formApi: FormApi; +``` + +Defined in: [validation.public.ts:402](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L402) + +The owning form, including its complete values and state. + +#### Inherited from + +```ts +BaseValidationPredicateContext.formApi +``` + +*** + +### groupApi? + +```ts +optional groupApi?: undefined; +``` + +Defined in: [validation.public.ts:447](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L447) + +*** + +### scope + +```ts +scope: "field"; +``` + +Defined in: [validation.public.ts:400](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L400) + +Identifies whether `value` belongs to a form, form group, or field. + +#### Inherited from + +```ts +BaseValidationPredicateContext.scope +``` + +*** + +### value + +```ts +value: TFieldValue; +``` + +Defined in: [validation.public.ts:411](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L411) + +The current value in this validator's scope when the callback is evaluated. + +#### Inherited from + +```ts +BaseValidationPredicateContext.value +``` diff --git a/docs/reference/interfaces/FieldValidator.md b/docs/reference/interfaces/FieldValidator.md new file mode 100644 index 0000000000..8fe9e9509b --- /dev/null +++ b/docs/reference/interfaces/FieldValidator.md @@ -0,0 +1,188 @@ +--- +id: FieldValidator +title: FieldValidator +--- + +Defined in: [validation.public.ts:983](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L983) + +Configures validation of a field's value, optionally reacting to related fields. + +## Extends + +- [`Validator`](Validator.md)\<`TFormData`, + \| [`FieldValidatorFn`](../type-aliases/FieldValidatorFn.md)\<`TFormData`, `TFieldName`, `TFieldValue`\> + \| [`StandardSchemaV1`](../type-aliases/StandardSchemaV1.md)\<`TFieldValue`, `any`\>, `TFieldValue`, [`ConfigurableValidationTrigger`](../type-aliases/ConfigurableValidationTrigger.md), `"field"`\> + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFieldName + +`TFieldName` + +Library-managed. Do not specify explicitly. + +### TFieldValue + +`TFieldValue` + +Library-managed. Do not specify explicitly. + +## Properties + +### bailIfInvalid? + +```ts +optional bailIfInvalid?: boolean; +``` + +Defined in: [validation.public.ts:29](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L29) + +If `true`, skips this and subsequent validators when earlier validation has failed. + +If `false`, earlier failures do not prevent this validator from running. + +#### Default + +```ts +false +``` + +#### Inherited from + +[`Validator`](Validator.md).[`bailIfInvalid`](Validator.md#bailifinvalid) + +*** + +### run + +```ts +run: + | FieldValidatorFn +| StandardSchemaV1; +``` + +Defined in: [validation.public.ts:21](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L21) + +The function or Standard Schema that validates the value in this validator's scope. + +#### Inherited from + +[`Validator`](Validator.md).[`run`](Validator.md#run) + +*** + +### runOnMount? + +```ts +optional runOnMount?: boolean; +``` + +Defined in: [validation.public.ts:64](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L64) + +Whether this validator runs when the form is constructed or when its field +or form group first mounts. + +#### Default + +```ts +false +``` + +#### Inherited from + +[`Validator`](Validator.md).[`runOnMount`](Validator.md#runonmount) + +*** + +### skipOnSubmit? + +```ts +optional skipOnSubmit?: + | boolean +| ValidationPredicateFn; +``` + +Defined in: [validation.public.ts:56](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L56) + +Whether this validator runs during a submission attempt, independently of `triggers`. + +Pass a boolean directly, or pass a function that returns +`true` to skip it for the current attempt. + +#### Default + +```ts +false +``` + +#### Inherited from + +[`Validator`](Validator.md).[`skipOnSubmit`](Validator.md#skiponsubmit) + +*** + +### triggerDebounceMs? + +```ts +optional triggerDebounceMs?: + | number +| ValidationDebounceFn; +``` + +Defined in: [validation.public.ts:74](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L74) + +The delay in milliseconds before validation runs for change or blur events. + +Pass a number for a fixed delay, or pass a function that returns the delay +for the current event. Repeated events restart the delay. +Submission validation runs immediately. + +#### Default + +```ts +0 +``` + +#### Inherited from + +[`Validator`](Validator.md).[`triggerDebounceMs`](Validator.md#triggerdebouncems) + +*** + +### triggers + +```ts +triggers: ValidationTriggerOption[]; +``` + +Defined in: [validation.public.ts:82](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L82) + +Change and blur events that can run this validator, optionally with conditions. + +An empty array disables change and blur validation. Configure submission +separately with `skipOnSubmit` and initial validation with `runOnMount`. + +#### Inherited from + +[`Validator`](Validator.md).[`triggers`](Validator.md#triggers) + +*** + +### watchFields? + +```ts +optional watchFields?: DeepKeys[]; +``` + +Defined in: [validation.public.ts:1001](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1001) + +Other field paths whose change or blur events can run this validator. + +Events must still match an enabled entry in `triggers`. The validator +receives its own field's value, even when a watched field caused the event. diff --git a/docs/reference/interfaces/FieldValidatorContext.md b/docs/reference/interfaces/FieldValidatorContext.md new file mode 100644 index 0000000000..a7b84af39b --- /dev/null +++ b/docs/reference/interfaces/FieldValidatorContext.md @@ -0,0 +1,100 @@ +--- +id: FieldValidatorContext +title: FieldValidatorContext +--- + +Defined in: [validation.public.ts:942](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L942) + +Values and helpers passed to a field validation function. + +## Type Parameters + +### TFieldName + +`TFieldName` + +Library-managed. Do not specify explicitly. + +### TFieldValue + +`TFieldValue` + +Library-managed. Do not specify explicitly. + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Properties + +### event + +```ts +event: ValidationTrigger; +``` + +Defined in: [validation.public.ts:948](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L948) + +The event that caused this validation run. + +*** + +### fieldApi + +```ts +fieldApi: FieldApi; +``` + +Defined in: [validation.public.ts:954](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L954) + +The field being validated, including when a watched field caused the event. + +*** + +### formApi + +```ts +formApi: FormApi; +``` + +Defined in: [validation.public.ts:952](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L952) + +The owning form. Read other field values here for cross-field validation. + +*** + +### parseIssues + +```ts +parseIssues: ParseFieldIssuesFn; +``` + +Defined in: [validation.public.ts:958](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L958) + +Converts Standard Schema issues into errors for this field, without routing their paths. + +*** + +### signal + +```ts +signal: AbortSignal; +``` + +Defined in: [validation.public.ts:950](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L950) + +Aborted when this run is cancelled. Pass it to asynchronous work such as `fetch`. + +*** + +### value + +```ts +value: TFieldValue; +``` + +Defined in: [validation.public.ts:956](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L956) + +The current value of the field being validated. diff --git a/docs/reference/interfaces/FieldValidators.md b/docs/reference/interfaces/FieldValidators.md deleted file mode 100644 index 8c2ae5341e..0000000000 --- a/docs/reference/interfaces/FieldValidators.md +++ /dev/null @@ -1,260 +0,0 @@ ---- -id: FieldValidators -title: FieldValidators ---- - -# Interface: FieldValidators\ - -Defined in: [packages/form-core/src/FieldApi.ts:179](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L179) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* [`DeepKeys`](../type-aliases/DeepKeys.md)\<`TParentData`\> - -### TData - -`TData` *extends* [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FieldValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FieldAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -## Properties - -### onBlur? - -```ts -optional onBlur: RejectPromiseValidator; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:232](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L232) - -An optional function, that runs on the blur event of input. - -#### Example - -```ts -z.string().min(1) -``` - -*** - -### onBlurAsync? - -```ts -optional onBlurAsync: TOnBlurAsync; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:238](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L238) - -An optional property similar to `onBlur` but async validation. - -#### Example - -```ts -z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' }) -``` - -*** - -### onBlurAsyncDebounceMs? - -```ts -optional onBlurAsyncDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:245](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L245) - -An optional number to represent how long the `onBlurAsync` should wait before running - -If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds - -*** - -### onBlurListenTo? - -```ts -optional onBlurListenTo: DeepKeys[]; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:249](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L249) - -An optional list of field names that should trigger this field's `onBlur` and `onBlurAsync` events when its value changes - -*** - -### onChange? - -```ts -optional onChange: RejectPromiseValidator; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:210](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L210) - -An optional function, that runs on the change event of input. - -#### Example - -```ts -z.string().min(1) -``` - -*** - -### onChangeAsync? - -```ts -optional onChangeAsync: TOnChangeAsync; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:216](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L216) - -An optional property similar to `onChange` but async validation - -#### Example - -```ts -z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' }) -``` - -*** - -### onChangeAsyncDebounceMs? - -```ts -optional onChangeAsyncDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:222](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L222) - -An optional number to represent how long the `onChangeAsync` should wait before running - -If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds - -*** - -### onChangeListenTo? - -```ts -optional onChangeListenTo: DeepKeys[]; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:226](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L226) - -An optional list of field names that should trigger this field's `onChange` and `onChangeAsync` events when its value changes - -*** - -### onDynamic? - -```ts -optional onDynamic: RejectPromiseValidator; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:262](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L262) - -*** - -### onDynamicAsync? - -```ts -optional onDynamicAsync: TOnDynamicAsync; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:263](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L263) - -*** - -### onDynamicAsyncDebounceMs? - -```ts -optional onDynamicAsyncDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:264](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L264) - -*** - -### onMount? - -```ts -optional onMount: RejectPromiseValidator; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:204](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L204) - -An optional function, that runs on the mount event of input. - -*** - -### onSubmit? - -```ts -optional onSubmit: RejectPromiseValidator; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:255](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L255) - -An optional function, that runs on the submit event of form. - -#### Example - -```ts -z.string().min(1) -``` - -*** - -### onSubmitAsync? - -```ts -optional onSubmitAsync: TOnSubmitAsync; -``` - -Defined in: [packages/form-core/src/FieldApi.ts:261](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L261) - -An optional property similar to `onSubmit` but async validation. - -#### Example - -```ts -z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' }) -``` diff --git a/docs/reference/interfaces/FormApi.md b/docs/reference/interfaces/FormApi.md new file mode 100644 index 0000000000..40f945d282 --- /dev/null +++ b/docs/reference/interfaces/FormApi.md @@ -0,0 +1,492 @@ +--- +id: FormApi +title: FormApi +--- + +Defined in: [FormApi/FormApi.public.ts:638](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L638) + +Core API for reading and updating state, validating values, and handling +submission. + +Framework adapters compose this interface with framework-specific helpers. + +## Extends + +- [`FormApiFieldMethods`](FormApiFieldMethods.md)\<`TFormData`\>.[`FormApiArrayMethods`](FormApiArrayMethods.md)\<`TFormData`\> + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### atom + +```ts +atom: ReadonlyAtom>; +``` + +Defined in: [FormApi/FormApi.public.ts:649](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L649) + +Read-only atom containing reactive `FormState` snapshots. + +Subscribe to this atom to observe state changes. For an imperative read, +use `state`. + +*** + +### clearFieldValues + +```ts +clearFieldValues: ClearFieldValuesFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:410](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L410) + +Removes every element from an array field. + +A runtime value that is not an array produces a warning and is left +unchanged. By default, the update marks the array field as touched and +dirty, notifies change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second'] +formApi.clearFieldValues('items') +// items: [] +``` + +#### Inherited from + +[`FormApiArrayMethods`](FormApiArrayMethods.md).[`clearFieldValues`](FormApiArrayMethods.md#clearfieldvalues) + +*** + +### defaultValues + +```ts +readonly defaultValues: TFormData; +``` + +Defined in: [FormApi/FormApi.public.ts:653](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L653) + +The current baseline values used by `reset()` and `isDefaultValue`. + +*** + +### filterFieldValues + +```ts +filterFieldValues: FilterFieldValuesFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:465](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L465) + +Keeps the elements that satisfy a predicate. + +`options.thisArg` sets the predicate's `this` value. A runtime value that is +not an array produces a warning and is left unchanged. By default, the +update marks the array field as touched and dirty, notifies change +listeners, and runs change validation. + +#### Example + +```ts +// items: [1, 2, 3, 4] +formApi.filterFieldValues('items', (item) => item % 2 === 0) +// items: [2, 4] +``` + +#### Inherited from + +[`FormApiArrayMethods`](FormApiArrayMethods.md).[`filterFieldValues`](FormApiArrayMethods.md#filterfieldvalues) + +*** + +### formId + +```ts +readonly formId: string; +``` + +Defined in: [FormApi/FormApi.public.ts:660](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L660) + +Stable identifier supplied by `FormOptions.formId` or generated at +creation. + +It is preserved across option updates until a new `formId` is supplied. + +*** + +### getFieldValue + +```ts +getFieldValue: GetFieldValueFn; +``` + +Defined in: [FormApi/FormApiFieldMethods.types.public.ts:114](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiFieldMethods.types.public.ts#L114) + +Reads the current value at a field path. + +This is a read-only operation and does not create a `FieldApi` for the path. + +#### Example + +```ts +const name = formApi.getFieldValue('profile.name') +``` + +#### Returns + +The current value at the path, or `undefined` when the path cannot +be resolved at runtime. + +#### Inherited from + +[`FormApiFieldMethods`](FormApiFieldMethods.md).[`getFieldValue`](FormApiFieldMethods.md#getfieldvalue) + +*** + +### handleSubmit + +```ts +handleSubmit: HandleSubmitFn; +``` + +Defined in: [FormApi/FormApi.public.ts:698](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L698) + +Runs submission validation and submits current values when validation +succeeds. + +Registered fields are marked touched, field validators run before form +validators, and `onSubmit` is awaited only when validation succeeds. +Validation error results and errors returned by `onSubmit` through +`createValidationError` are stored as error state. `onSubmitInvalid` is +awaited after a failed attempt. + +Calls made while an attempt is in progress return the same promise instead +of starting another attempt. + +The returned promise resolves to the error results produced by field and +form validation, plus any validation error returned by `onSubmit` through +`createValidationError`. The array is empty if none are produced. + +*** + +### insertFieldValue + +```ts +insertFieldValue: InsertFieldValueFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:394](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L394) + +Inserts an element at an index in an array field. + +The index must be between `0` and `array.length`; passing `array.length` +appends the element. An out-of-range index or a runtime value that is not +an array produces a warning and leaves the value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second'] +formApi.insertFieldValue('items', 1, 'new item') +// items: ['first', 'new item', 'second'] +``` + +#### Inherited from + +[`FormApiArrayMethods`](FormApiArrayMethods.md).[`insertFieldValue`](FormApiArrayMethods.md#insertfieldvalue) + +*** + +### moveFieldValue + +```ts +moveFieldValue: MoveFieldValueFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:359](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L359) + +Moves an element to another index in an array field. + +Both indices must be between `0` and `array.length - 1`. Passing equal +indices does nothing. Out-of-range indices or a runtime value that is not +an array produce a warning and leave the value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second', 'third'] +formApi.moveFieldValue('items', 0, 2) +// items: ['second', 'third', 'first'] +``` + +#### Inherited from + +[`FormApiArrayMethods`](FormApiArrayMethods.md).[`moveFieldValue`](FormApiArrayMethods.md#movefieldvalue) + +*** + +### pushFieldValue + +```ts +pushFieldValue: PushFieldValueFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:375](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L375) + +Appends an element to an array field. + +A runtime value that is not an array produces a warning and is left +unchanged. By default, the update marks the array field as touched and +dirty, notifies change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second'] +formApi.pushFieldValue('items', 'new item') +// items: ['first', 'second', 'new item'] +``` + +#### Inherited from + +[`FormApiArrayMethods`](FormApiArrayMethods.md).[`pushFieldValue`](FormApiArrayMethods.md#pushfieldvalue) + +*** + +### removeFieldValue + +```ts +removeFieldValue: RemoveFieldValueFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:429](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L429) + +Removes an element from an array field. + +The index must be between `0` and `array.length - 1`. An out-of-range index +or a runtime value that is not an array produces a warning and leaves the +value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second', 'third'] +formApi.removeFieldValue('items', 1) +// items: ['first', 'third'] +``` + +#### Inherited from + +[`FormApiArrayMethods`](FormApiArrayMethods.md).[`removeFieldValue`](FormApiArrayMethods.md#removefieldvalue) + +*** + +### replaceFieldValue + +```ts +replaceFieldValue: ReplaceFieldValueFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:448](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L448) + +Replaces the element at an index in an array field. + +The index must be between `0` and `array.length - 1`. An out-of-range index +or a runtime value that is not an array produces a warning and leaves the +value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second', 'third'] +formApi.replaceFieldValue('items', 1, 'new item') +// items: ['first', 'new item', 'third'] +``` + +#### Inherited from + +[`FormApiArrayMethods`](FormApiArrayMethods.md).[`replaceFieldValue`](FormApiArrayMethods.md#replacefieldvalue) + +*** + +### reset + +```ts +reset: ResetFn; +``` + +Defined in: [FormApi/FormApi.public.ts:713](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L713) + +Reset form values, metadata, validation state, and mounted fields. + +`reset()` restores the current `defaultValues`. + +`reset(values)` sets the current values and also updates `defaultValues` +to those values. This can apply expected values immediately while fresh +data is fetched from the backend. + +Results from validation or submission work pending at reset are discarded. + +Pass `{ updateDefaultValues: false }` as the options argument to preserve +the existing `defaultValues` when supplying values. + +*** + +### resetField + +```ts +resetField: ResetFieldFn; +``` + +Defined in: [FormApi/FormApiFieldMethods.types.public.ts:131](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiFieldMethods.types.public.ts#L131) + +Restores a field path from `defaultValues` and resets state for its field +subtree. + +Existing `FieldApi` instances at or below the path remain mounted. +Form-wide dirty history remains unchanged; use `formApi.reset()` to clear +it. + +#### Example + +```ts +formApi.setFieldValue('profile.name', 'Grace') +formApi.resetField('profile.name') +// `profile.name` is restored from `defaultValues`. +``` + +#### Inherited from + +[`FormApiFieldMethods`](FormApiFieldMethods.md).[`resetField`](FormApiFieldMethods.md#resetfield) + +*** + +### setFieldValue + +```ts +setFieldValue: SetFieldValueFn; +``` + +Defined in: [FormApi/FormApiFieldMethods.types.public.ts:99](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiFieldMethods.types.public.ts#L99) + +Updates the current value at a field path. + +The next value may be supplied directly or calculated from the current +value. By default, the update marks the field as touched and dirty, +notifies change listeners, and runs change validation. + +#### Example + +```ts +formApi.setFieldValue('profile.name', 'Ada') +formApi.setFieldValue('visitCount', (count) => count + 1) +``` + +#### Inherited from + +[`FormApiFieldMethods`](FormApiFieldMethods.md).[`setFieldValue`](FormApiFieldMethods.md#setfieldvalue) + +*** + +### state + +```ts +readonly state: FormState; +``` + +Defined in: [FormApi/FormApi.public.ts:651](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L651) + +Current values, validation status, and submission metadata. + +*** + +### swapFieldValues + +```ts +swapFieldValues: SwapFieldValuesFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:340](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L340) + +Swaps two elements in an array field. + +Both indices must be between `0` and `array.length - 1`. Passing equal +indices does nothing. Out-of-range indices or a runtime value that is not +an array produce a warning and leave the value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second', 'third'] +formApi.swapFieldValues('items', 0, 2) +// items: ['third', 'second', 'first'] +``` + +#### Inherited from + +[`FormApiArrayMethods`](FormApiArrayMethods.md).[`swapFieldValues`](FormApiArrayMethods.md#swapfieldvalues) + +*** + +### validate + +```ts +validate: (signal) => Promise[]>; +``` + +Defined in: [FormApi/FormApi.public.ts:677](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L677) + +Runs form-level validators enabled for the specified `'change'` or +`'blur'` trigger. + +Prefer configured validator triggers for change and blur validation, and +use `handleSubmit()` for submission validation. Calling this method +directly is rarely necessary. + +Results update form-level errors and any errors routed to fields. +Field-level validators are not run by this method. + +#### Parameters + +##### signal + +[`ConfigurableValidationTrigger`](../type-aliases/ConfigurableValidationTrigger.md) + +The trigger used to select validators. + +#### Returns + +`Promise`\<[`FormValidationError`](../type-aliases/FormValidationError.md)\<`TFormData`\>[]\> + +A promise resolving to each error result from the validators that +ran. Unlike `state.errors`, these results are not flattened. diff --git a/docs/reference/interfaces/FormApiArrayMethods.md b/docs/reference/interfaces/FormApiArrayMethods.md new file mode 100644 index 0000000000..1bc55e979a --- /dev/null +++ b/docs/reference/interfaces/FormApiArrayMethods.md @@ -0,0 +1,228 @@ +--- +id: FormApiArrayMethods +title: FormApiArrayMethods +--- + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:322](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L322) + +Methods for adding, removing, moving, and filtering array field elements. + +## Extended by + +- [`FormApi`](FormApi.md) + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Properties + +### clearFieldValues + +```ts +clearFieldValues: ClearFieldValuesFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:410](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L410) + +Removes every element from an array field. + +A runtime value that is not an array produces a warning and is left +unchanged. By default, the update marks the array field as touched and +dirty, notifies change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second'] +formApi.clearFieldValues('items') +// items: [] +``` + +*** + +### filterFieldValues + +```ts +filterFieldValues: FilterFieldValuesFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:465](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L465) + +Keeps the elements that satisfy a predicate. + +`options.thisArg` sets the predicate's `this` value. A runtime value that is +not an array produces a warning and is left unchanged. By default, the +update marks the array field as touched and dirty, notifies change +listeners, and runs change validation. + +#### Example + +```ts +// items: [1, 2, 3, 4] +formApi.filterFieldValues('items', (item) => item % 2 === 0) +// items: [2, 4] +``` + +*** + +### insertFieldValue + +```ts +insertFieldValue: InsertFieldValueFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:394](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L394) + +Inserts an element at an index in an array field. + +The index must be between `0` and `array.length`; passing `array.length` +appends the element. An out-of-range index or a runtime value that is not +an array produces a warning and leaves the value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second'] +formApi.insertFieldValue('items', 1, 'new item') +// items: ['first', 'new item', 'second'] +``` + +*** + +### moveFieldValue + +```ts +moveFieldValue: MoveFieldValueFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:359](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L359) + +Moves an element to another index in an array field. + +Both indices must be between `0` and `array.length - 1`. Passing equal +indices does nothing. Out-of-range indices or a runtime value that is not +an array produce a warning and leave the value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second', 'third'] +formApi.moveFieldValue('items', 0, 2) +// items: ['second', 'third', 'first'] +``` + +*** + +### pushFieldValue + +```ts +pushFieldValue: PushFieldValueFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:375](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L375) + +Appends an element to an array field. + +A runtime value that is not an array produces a warning and is left +unchanged. By default, the update marks the array field as touched and +dirty, notifies change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second'] +formApi.pushFieldValue('items', 'new item') +// items: ['first', 'second', 'new item'] +``` + +*** + +### removeFieldValue + +```ts +removeFieldValue: RemoveFieldValueFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:429](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L429) + +Removes an element from an array field. + +The index must be between `0` and `array.length - 1`. An out-of-range index +or a runtime value that is not an array produces a warning and leaves the +value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second', 'third'] +formApi.removeFieldValue('items', 1) +// items: ['first', 'third'] +``` + +*** + +### replaceFieldValue + +```ts +replaceFieldValue: ReplaceFieldValueFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:448](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L448) + +Replaces the element at an index in an array field. + +The index must be between `0` and `array.length - 1`. An out-of-range index +or a runtime value that is not an array produces a warning and leaves the +value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second', 'third'] +formApi.replaceFieldValue('items', 1, 'new item') +// items: ['first', 'new item', 'third'] +``` + +*** + +### swapFieldValues + +```ts +swapFieldValues: SwapFieldValuesFn; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:340](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L340) + +Swaps two elements in an array field. + +Both indices must be between `0` and `array.length - 1`. Passing equal +indices does nothing. Out-of-range indices or a runtime value that is not +an array produce a warning and leave the value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +#### Example + +```ts +// items: ['first', 'second', 'third'] +formApi.swapFieldValues('items', 0, 2) +// items: ['third', 'second', 'first'] +``` diff --git a/docs/reference/interfaces/FormApiFieldMethods.md b/docs/reference/interfaces/FormApiFieldMethods.md new file mode 100644 index 0000000000..8a216cdd80 --- /dev/null +++ b/docs/reference/interfaces/FormApiFieldMethods.md @@ -0,0 +1,94 @@ +--- +id: FormApiFieldMethods +title: FormApiFieldMethods +--- + +Defined in: [FormApi/FormApiFieldMethods.types.public.ts:85](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiFieldMethods.types.public.ts#L85) + +Type-safe methods for reading, updating, and resetting individual field +values. + +## Extended by + +- [`FormApi`](FormApi.md) + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Properties + +### getFieldValue + +```ts +getFieldValue: GetFieldValueFn; +``` + +Defined in: [FormApi/FormApiFieldMethods.types.public.ts:114](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiFieldMethods.types.public.ts#L114) + +Reads the current value at a field path. + +This is a read-only operation and does not create a `FieldApi` for the path. + +#### Example + +```ts +const name = formApi.getFieldValue('profile.name') +``` + +#### Returns + +The current value at the path, or `undefined` when the path cannot +be resolved at runtime. + +*** + +### resetField + +```ts +resetField: ResetFieldFn; +``` + +Defined in: [FormApi/FormApiFieldMethods.types.public.ts:131](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiFieldMethods.types.public.ts#L131) + +Restores a field path from `defaultValues` and resets state for its field +subtree. + +Existing `FieldApi` instances at or below the path remain mounted. +Form-wide dirty history remains unchanged; use `formApi.reset()` to clear +it. + +#### Example + +```ts +formApi.setFieldValue('profile.name', 'Grace') +formApi.resetField('profile.name') +// `profile.name` is restored from `defaultValues`. +``` + +*** + +### setFieldValue + +```ts +setFieldValue: SetFieldValueFn; +``` + +Defined in: [FormApi/FormApiFieldMethods.types.public.ts:99](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiFieldMethods.types.public.ts#L99) + +Updates the current value at a field path. + +The next value may be supplied directly or calculated from the current +value. By default, the update marks the field as touched and dirty, +notifies change listeners, and runs change validation. + +#### Example + +```ts +formApi.setFieldValue('profile.name', 'Ada') +formApi.setFieldValue('visitCount', (count) => count + 1) +``` diff --git a/docs/reference/interfaces/FormErrorTypes.md b/docs/reference/interfaces/FormErrorTypes.md new file mode 100644 index 0000000000..31134c9fb5 --- /dev/null +++ b/docs/reference/interfaces/FormErrorTypes.md @@ -0,0 +1,46 @@ +--- +id: FormErrorTypes +title: FormErrorTypes +--- + +Defined in: [validation.public.ts:1051](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1051) + +Inferred issue types for errors owned by a form or group and errors routed to its fields. + +## Type Parameters + +### TFormError + +`TFormError` = [`ValidationIssue`](ValidationIssue.md) + +Library-managed. Do not specify explicitly. + +### TFieldError + +`TFieldError` = [`ValidationIssue`](ValidationIssue.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### fieldError + +```ts +readonly fieldError: TFieldError; +``` + +Defined in: [validation.public.ts:1058](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1058) + +The issue type routed from form or group validation to individual fields. + +*** + +### formError + +```ts +readonly formError: TFormError; +``` + +Defined in: [validation.public.ts:1056](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1056) + +The issue type stored in the form or group's `state.errors`. diff --git a/docs/reference/interfaces/FormGroupApi.md b/docs/reference/interfaces/FormGroupApi.md new file mode 100644 index 0000000000..8461f80fd3 --- /dev/null +++ b/docs/reference/interfaces/FormGroupApi.md @@ -0,0 +1,127 @@ +--- +id: FormGroupApi +title: FormGroupApi +--- + +Defined in: [FormGroupApi/FormGroupApi.public.ts:195](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L195) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +## Properties + +### atom + +```ts +atom: ReadonlyAtom>; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:205](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L205) + +*** + +### form + +```ts +readonly form: FormApi; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:202](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L202) + +*** + +### handleSubmit + +```ts +handleSubmit: () => Promise[]>; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:211](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L211) + +#### Returns + +`Promise`\<[`FormGroupValidateResult`](../type-aliases/FormGroupValidateResult.md)\<`TGroupValue`\>[]\> + +*** + +### name + +```ts +readonly name: TGroupName; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:203](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L203) + +*** + +### reset + +```ts +reset: () => void; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:212](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L212) + +#### Returns + +`void` + +*** + +### state + +```ts +readonly state: FormGroupState; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:206](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L206) + +*** + +### validate + +```ts +validate: (signal) => Promise[]>; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:208](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L208) + +#### Parameters + +##### signal + + \| `"submit"` + \| [`ConfigurableValidationTrigger`](../type-aliases/ConfigurableValidationTrigger.md) + +#### Returns + +`Promise`\<[`FormGroupValidateResult`](../type-aliases/FormGroupValidateResult.md)\<`TGroupValue`\>[]\> + +*** + +### value + +```ts +readonly value: TGroupValue; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:207](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L207) diff --git a/docs/reference/interfaces/FormGroupApiOptions.md b/docs/reference/interfaces/FormGroupApiOptions.md deleted file mode 100644 index 75d900d694..0000000000 --- a/docs/reference/interfaces/FormGroupApiOptions.md +++ /dev/null @@ -1,392 +0,0 @@ ---- -id: FormGroupApiOptions -title: FormGroupApiOptions ---- - -# Interface: FormGroupApiOptions\ - -Defined in: [packages/form-core/src/FormGroupApi.ts:562](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L562) - -## Extends - -- [`FormGroupOptions`](FormGroupOptions.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* [`DeepKeys`](../type-aliases/DeepKeys.md)\<`TParentData`\> - -### TData - -`TData` *extends* [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TSubmitMeta - -`TSubmitMeta` - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` - -## Properties - -### asyncAlways? - -```ts -optional asyncAlways: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:982](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L982) - -If `true`, always run async validation, even if there are errors emitted during synchronous validation. - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`asyncAlways`](FormGroupOptions.md#asyncalways) - -*** - -### asyncDebounceMs? - -```ts -optional asyncDebounceMs: number; -``` - -Defined in: [packages/form-core/src/types.ts:978](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L978) - -The default time to debounce async validation if there is not a more specific debounce time passed. - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`asyncDebounceMs`](FormGroupOptions.md#asyncdebouncems) - -*** - -### canSubmitWhenInvalid? - -```ts -optional canSubmitWhenInvalid: boolean; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:381](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L381) - -If true, allows the form to be submitted in an invalid state i.e. canSubmit will remain true regardless of validation errors. Defaults to undefined. - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`canSubmitWhenInvalid`](FormGroupOptions.md#cansubmitwheninvalid) - -*** - -### defaultMeta? - -```ts -optional defaultMeta: Partial>; -``` - -Defined in: [packages/form-core/src/types.ts:986](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L986) - -An optional object with default metadata for the field. - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`defaultMeta`](FormGroupOptions.md#defaultmeta) - -*** - -### defaultState? - -```ts -optional defaultState: FormGroupState; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:388](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L388) - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`defaultState`](FormGroupOptions.md#defaultstate) - -*** - -### defaultValue? - -```ts -optional defaultValue: NoInfer; -``` - -Defined in: [packages/form-core/src/types.ts:974](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L974) - -An optional default value for the field. - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`defaultValue`](FormGroupOptions.md#defaultvalue) - -*** - -### disableErrorFlat? - -```ts -optional disableErrorFlat: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:1014](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L1014) - -Disable the `flat(1)` operation on `field.errors`. This is useful if you want to keep the error structure as is. Not suggested for most use-cases. - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`disableErrorFlat`](FormGroupOptions.md#disableerrorflat) - -*** - -### form - -```ts -form: FormApi; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:639](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L639) - -*** - -### listeners? - -```ts -optional listeners: FormGroupListeners; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:386](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L386) - -A list of listeners which attach to the corresponding events - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`listeners`](FormGroupOptions.md#listeners) - -*** - -### name - -```ts -name: TName; -``` - -Defined in: [packages/form-core/src/types.ts:970](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L970) - -The field name. The type will be `DeepKeys` to ensure your name is a deep key of the parent dataset. - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`name`](FormGroupOptions.md#name) - -*** - -### onGroupSubmit()? - -```ts -optional onGroupSubmit: (props) => any; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:403](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L403) - -A function to be called when the form is submitted, what should happen once the user submits a valid form returns `any` or a promise `Promise` - -#### Parameters - -##### props - -###### groupApi - -[`FormGroupApi`](../classes/FormGroupApi.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -###### meta - -`TSubmitMeta` - -###### value - -`TData` - -#### Returns - -`any` - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`onGroupSubmit`](FormGroupOptions.md#ongroupsubmit) - -*** - -### onGroupSubmitInvalid()? - -```ts -optional onGroupSubmitInvalid: (props) => void; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:436](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L436) - -Specify an action for scenarios where the user tries to submit an invalid form. - -#### Parameters - -##### props - -###### groupApi - -[`FormGroupApi`](../classes/FormGroupApi.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -###### meta - -`TSubmitMeta` - -###### value - -`TData` - -#### Returns - -`void` - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`onGroupSubmitInvalid`](FormGroupOptions.md#ongroupsubmitinvalid) - -*** - -### onSubmitMeta? - -```ts -optional onSubmitMeta: TSubmitMeta; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:398](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L398) - -onSubmitMeta, the data passed from the handleSubmit handler, to the onSubmit function props - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`onSubmitMeta`](FormGroupOptions.md#onsubmitmeta) - -*** - -### validationLogic? - -```ts -optional validationLogic: ValidationLogicFn; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:394](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L394) - -Optional validation logic strategy to use for this group's own -validators (e.g. `revalidateLogic()`). When omitted, the parent form's -`validationLogic` (or the default) is used. - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`validationLogic`](FormGroupOptions.md#validationlogic) - -*** - -### validators? - -```ts -optional validators: FormGroupValidators; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:363](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L363) - -A list of validators to pass to the field - -#### Inherited from - -[`FormGroupOptions`](FormGroupOptions.md).[`validators`](FormGroupOptions.md#validators) diff --git a/docs/reference/interfaces/FormGroupListeners.md b/docs/reference/interfaces/FormGroupListeners.md deleted file mode 100644 index 1a854f51ea..0000000000 --- a/docs/reference/interfaces/FormGroupListeners.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -id: FormGroupListeners -title: FormGroupListeners ---- - -# Interface: FormGroupListeners\ - -Defined in: [packages/form-core/src/FormGroupApi.ts:293](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L293) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* [`DeepKeys`](../type-aliases/DeepKeys.md)\<`TParentData`\> - -### TData - -`TData` *extends* [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> = [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> - -## Properties - -### onBlur? - -```ts -optional onBlur: FormGroupListenerFn; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:300](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L300) - -*** - -### onBlurDebounceMs? - -```ts -optional onBlurDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:301](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L301) - -*** - -### onChange? - -```ts -optional onChange: FormGroupListenerFn; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:298](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L298) - -*** - -### onChangeDebounceMs? - -```ts -optional onChangeDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:299](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L299) - -*** - -### onGroupSubmit? - -```ts -optional onGroupSubmit: FormGroupListenerFn; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:305](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L305) - -*** - -### onMount? - -```ts -optional onMount: FormGroupListenerFn; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:302](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L302) - -*** - -### onSubmit? - -```ts -optional onSubmit: FormGroupListenerFn; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:304](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L304) - -*** - -### onUnmount? - -```ts -optional onUnmount: FormGroupListenerFn; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:303](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L303) diff --git a/docs/reference/interfaces/FormGroupMeta.md b/docs/reference/interfaces/FormGroupMeta.md deleted file mode 100644 index de96b5b67b..0000000000 --- a/docs/reference/interfaces/FormGroupMeta.md +++ /dev/null @@ -1,402 +0,0 @@ ---- -id: FormGroupMeta -title: FormGroupMeta ---- - -# Interface: FormGroupMeta\ - -Defined in: [packages/form-core/src/FormGroupApi.ts:749](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L749) - -The `meta` shape exposed on `FormGroupApi.state.meta`. Mirrors -`FieldApi.state.meta` (since `FormGroupMeta extends FieldLikeMeta`) but -additionally surfaces the group's submission lifecycle and aggregated -validity flags. All derivation lives on the parent `FormApi` (in -`formGroupMetaDerived`), keeping per-instance `FormGroupApi.store` as -minimal as `FieldApi.store`. - -Aggregated booleans (`isTouched`, `isBlurred`, `isDirty`, `isPristine`, -`isDefaultValue`) are computed across the group's descendant fields -rather than the group's own field-meta entry. - -## Extends - -- [`FormGroupState`](FormGroupState.md) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* [`DeepKeys`](../type-aliases/DeepKeys.md)\<`TParentData`\> - -### TData - -`TData` *extends* [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -## Properties - -### canSubmit - -```ts -canSubmit: boolean; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:827](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L827) - -*** - -### errorMap - -```ts -errorMap: ValidationErrorMap, UnwrapFieldValidateOrFn, UnwrapFieldAsyncValidateOrFn, UnwrapFieldValidateOrFn, UnwrapFieldAsyncValidateOrFn, UnwrapFieldValidateOrFn, UnwrapFieldAsyncValidateOrFn, UnwrapFieldValidateOrFn, UnwrapFieldAsyncValidateOrFn>; -``` - -Defined in: [packages/form-core/src/types.ts:536](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L536) - -A map of errors related to the field value. - -#### Inherited from - -```ts -FieldLikeMeta.errorMap -``` - -*** - -### errors - -```ts -errors: ( - | UnwrapOneLevelOfArray> - | UnwrapOneLevelOfArray> - | UnwrapOneLevelOfArray> - | UnwrapOneLevelOfArray> - | UnwrapOneLevelOfArray> - | UnwrapOneLevelOfArray> - | UnwrapOneLevelOfArray> - | UnwrapOneLevelOfArray> - | UnwrapOneLevelOfArray>)[]; -``` - -Defined in: [packages/form-core/src/types.ts:660](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L660) - -An array of errors related to the field value. - -#### Inherited from - -```ts -FieldLikeMeta.errors -``` - -*** - -### isBlurred - -```ts -isBlurred: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:528](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L528) - -A flag indicating whether the field has been blurred. - -#### Inherited from - -```ts -FieldLikeMeta.isBlurred -``` - -*** - -### isDefaultValue - -```ts -isDefaultValue: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:704](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L704) - -A flag indicating whether the field's current value is the default value - -#### Inherited from - -```ts -FieldLikeMeta.isDefaultValue -``` - -*** - -### isDirty - -```ts -isDirty: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:532](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L532) - -A flag that is `true` if the field's value has been modified by the user. Opposite of `isPristine`. - -#### Inherited from - -```ts -FieldLikeMeta.isDirty -``` - -*** - -### isFieldsValid - -```ts -isFieldsValid: boolean; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:824](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L824) - -*** - -### isFieldsValidating - -```ts -isFieldsValidating: boolean; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:823](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L823) - -*** - -### isGroupValid - -```ts -isGroupValid: boolean; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:825](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L825) - -*** - -### isPristine - -```ts -isPristine: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:696](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L696) - -A flag that is `true` if the field's value has not been modified by the user. Opposite of `isDirty`. - -#### Inherited from - -```ts -FieldLikeMeta.isPristine -``` - -*** - -### isSubmitSuccessful - -```ts -isSubmitSuccessful: boolean; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:688](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L688) - -A boolean indicating if the last submission was successful. - -#### Inherited from - -[`FormGroupState`](FormGroupState.md).[`isSubmitSuccessful`](FormGroupState.md#issubmitsuccessful) - -*** - -### isSubmitted - -```ts -isSubmitted: boolean; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:676](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L676) - -A boolean indicating if the `onSubmit` function has completed successfully. - -Goes back to `false` at each new submission attempt. - -Note: you can use isSubmitting to check if the form is currently submitting. - -#### Inherited from - -[`FormGroupState`](FormGroupState.md).[`isSubmitted`](FormGroupState.md#issubmitted) - -*** - -### isSubmitting - -```ts -isSubmitting: boolean; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:668](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L668) - -A boolean indicating if the form is currently in the process of being submitted after `handleSubmit` is called. - -Goes back to `false` when submission completes for one of the following reasons: -- the validation step returned errors. -- the `onSubmit` function has completed. - -Note: if you're running async operations in your `onSubmit` function make sure to await them to ensure `isSubmitting` is set to `false` only when the async operation completes. - -This is useful for displaying loading indicators or disabling form inputs during submission. - -#### Inherited from - -[`FormGroupState`](FormGroupState.md).[`isSubmitting`](FormGroupState.md#issubmitting) - -*** - -### isTouched - -```ts -isTouched: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:524](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L524) - -A flag indicating whether the field has been touched. - -#### Inherited from - -```ts -FieldLikeMeta.isTouched -``` - -*** - -### isValid - -```ts -isValid: boolean; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:826](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L826) - -A boolean indicating if the field is valid. Evaluates `true` if there are no field errors. - -#### Overrides - -```ts -FieldLikeMeta.isValid -``` - -*** - -### isValidating - -```ts -isValidating: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:555](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L555) - -A flag indicating whether the field is currently being validated. - -#### Inherited from - -[`FormGroupState`](FormGroupState.md).[`isValidating`](FormGroupState.md#isvalidating) - -*** - -### submissionAttempts - -```ts -submissionAttempts: number; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:684](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L684) - -A counter for tracking the number of submission attempts. - -#### Inherited from - -[`FormGroupState`](FormGroupState.md).[`submissionAttempts`](FormGroupState.md#submissionattempts) diff --git a/docs/reference/interfaces/FormGroupOptions.md b/docs/reference/interfaces/FormGroupOptions.md index 6f4fafc1ca..5c0f707509 100644 --- a/docs/reference/interfaces/FormGroupOptions.md +++ b/docs/reference/interfaces/FormGroupOptions.md @@ -3,396 +3,108 @@ id: FormGroupOptions title: FormGroupOptions --- -# Interface: FormGroupOptions\ - -Defined in: [packages/form-core/src/FormGroupApi.ts:468](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L468) - -## Extends - -- `FormGroupExtraOptions`\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -## Extended by - -- [`FormGroupApiOptions`](FormGroupApiOptions.md) +Defined in: [FormGroupApi/FormGroupApi.public.ts:118](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L118) ## Type Parameters -### TParentData - -`TParentData` - -### TName - -`TName` *extends* [`DeepKeys`](../type-aliases/DeepKeys.md)\<`TParentData`\> - -### TData - -`TData` *extends* [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync +### TFormData -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> +`TFormData` -### TOnDynamic +### TGroupName -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> +`TGroupName` -### TOnDynamicAsync +### TGroupValue -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> +`TGroupValue` -### TSubmitMeta +### TGroupValidators -`TSubmitMeta` +`TGroupValidators` *extends* [`FormGroupValidators`](../type-aliases/FormGroupValidators.md)\<`TGroupValue`\> -### TFormOnMount +### TFormErrorTypes -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnServer - -`TFormOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TParentSubmitMeta - -`TParentSubmitMeta` +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) ## Properties -### asyncAlways? - -```ts -optional asyncAlways: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:982](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L982) - -If `true`, always run async validation, even if there are errors emitted during synchronous validation. - -#### Inherited from - -```ts -FieldLikeOptions.asyncAlways -``` - -*** - -### asyncDebounceMs? - -```ts -optional asyncDebounceMs: number; -``` - -Defined in: [packages/form-core/src/types.ts:978](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L978) - -The default time to debounce async validation if there is not a more specific debounce time passed. - -#### Inherited from - -```ts -FieldLikeOptions.asyncDebounceMs -``` - -*** - -### canSubmitWhenInvalid? - -```ts -optional canSubmitWhenInvalid: boolean; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:381](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L381) - -If true, allows the form to be submitted in an invalid state i.e. canSubmit will remain true regardless of validation errors. Defaults to undefined. - -#### Inherited from - -```ts -FormGroupExtraOptions.canSubmitWhenInvalid -``` - -*** - -### defaultMeta? - -```ts -optional defaultMeta: Partial>; -``` - -Defined in: [packages/form-core/src/types.ts:986](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L986) - -An optional object with default metadata for the field. - -#### Inherited from - -```ts -FieldLikeOptions.defaultMeta -``` - -*** - -### defaultState? +### form ```ts -optional defaultState: FormGroupState; +form: FormApi; ``` -Defined in: [packages/form-core/src/FormGroupApi.ts:388](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L388) - -#### Inherited from - -```ts -FormGroupExtraOptions.defaultState -``` - -*** - -### defaultValue? - -```ts -optional defaultValue: NoInfer; -``` - -Defined in: [packages/form-core/src/types.ts:974](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L974) - -An optional default value for the field. - -#### Inherited from - -```ts -FieldLikeOptions.defaultValue -``` - -*** - -### disableErrorFlat? - -```ts -optional disableErrorFlat: boolean; -``` - -Defined in: [packages/form-core/src/types.ts:1014](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L1014) - -Disable the `flat(1)` operation on `field.errors`. This is useful if you want to keep the error structure as is. Not suggested for most use-cases. - -#### Inherited from - -```ts -FieldLikeOptions.disableErrorFlat -``` - -*** - -### listeners? - -```ts -optional listeners: FormGroupListeners; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:386](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L386) - -A list of listeners which attach to the corresponding events - -#### Inherited from - -```ts -FormGroupExtraOptions.listeners -``` +Defined in: [FormGroupApi/FormGroupApi.public.ts:125](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L125) *** ### name ```ts -name: TName; +name: TGroupName; ``` -Defined in: [packages/form-core/src/types.ts:970](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L970) - -The field name. The type will be `DeepKeys` to ensure your name is a deep key of the parent dataset. - -#### Inherited from - -```ts -FieldLikeOptions.name -``` +Defined in: [FormGroupApi/FormGroupApi.public.ts:126](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L126) *** -### onGroupSubmit()? +### onSubmit? ```ts -optional onGroupSubmit: (props) => any; +optional onSubmit?: FormGroupSubmitFn; ``` -Defined in: [packages/form-core/src/FormGroupApi.ts:403](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L403) +Defined in: [FormGroupApi/FormGroupApi.public.ts:142](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L142) -A function to be called when the form is submitted, what should happen once the user submits a valid form returns `any` or a promise `Promise` +Called after group submission validation succeeds. The callback is awaited +before submission finishes. -#### Parameters - -##### props - -###### groupApi - -[`FormGroupApi`](../classes/FormGroupApi.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -###### meta - -`TSubmitMeta` - -###### value - -`TData` - -#### Returns - -`any` - -#### Inherited from +#### Example ```ts -FormGroupExtraOptions.onGroupSubmit +{ + // ... + onSubmit: () => { + setStep(step => step + 1) + }, +} ``` *** -### onGroupSubmitInvalid()? +### onSubmitInvalid? ```ts -optional onGroupSubmitInvalid: (props) => void; +optional onSubmitInvalid?: (context) => void | Promise; ``` -Defined in: [packages/form-core/src/FormGroupApi.ts:436](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L436) +Defined in: [FormGroupApi/FormGroupApi.public.ts:165](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L165) -Specify an action for scenarios where the user tries to submit an invalid form. +Called when group validation fails or validation or submission throws. The +callback is awaited before submission finishes. #### Parameters -##### props - -###### groupApi +##### context -[`FormGroupApi`](../classes/FormGroupApi.md)\<`TParentData`, `TName`, `TData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TSubmitMeta`, `TFormOnMount`, `TFormOnChange`, `TFormOnChangeAsync`, `TFormOnBlur`, `TFormOnBlurAsync`, `TFormOnSubmit`, `TFormOnSubmitAsync`, `TFormOnDynamic`, `TFormOnDynamicAsync`, `TFormOnServer`, `TParentSubmitMeta`\> - -###### meta - -`TSubmitMeta` - -###### value - -`TData` +[`FormGroupSubmitInvalidContext`](FormGroupSubmitInvalidContext.md)\<`TFormData`, `TGroupName`, `TGroupValue`, [`ToFormGroupErrorTypes`](../type-aliases/ToFormGroupErrorTypes.md)\<`NoInfer`\<`TGroupValidators`\>\>, `TFormErrorTypes`\> #### Returns -`void` +`void` \| `Promise`\<`void`\> -#### Inherited from +#### Example ```ts -FormGroupExtraOptions.onGroupSubmitInvalid -``` - -*** - -### onSubmitMeta? - -```ts -optional onSubmitMeta: TSubmitMeta; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:398](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L398) - -onSubmitMeta, the data passed from the handleSubmit handler, to the onSubmit function props - -#### Inherited from - -```ts -FormGroupExtraOptions.onSubmitMeta -``` - -*** - -### validationLogic? - -```ts -optional validationLogic: ValidationLogicFn; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:394](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L394) - -Optional validation logic strategy to use for this group's own -validators (e.g. `revalidateLogic()`). When omitted, the parent form's -`validationLogic` (or the default) is used. - -#### Inherited from - -```ts -FormGroupExtraOptions.validationLogic +{ + // ... + onSubmitInvalid: ({ groupApi }) => { + document + .querySelector('[aria-invalid="true"]') + ?.focus() + }, +} ``` *** @@ -400,15 +112,7 @@ FormGroupExtraOptions.validationLogic ### validators? ```ts -optional validators: FormGroupValidators; +optional validators?: TGroupValidators; ``` -Defined in: [packages/form-core/src/FormGroupApi.ts:363](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L363) - -A list of validators to pass to the field - -#### Inherited from - -```ts -FormGroupExtraOptions.validators -``` +Defined in: [FormGroupApi/FormGroupApi.public.ts:127](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L127) diff --git a/docs/reference/interfaces/FormGroupState.md b/docs/reference/interfaces/FormGroupState.md index 02d474b212..095a2fc567 100644 --- a/docs/reference/interfaces/FormGroupState.md +++ b/docs/reference/interfaces/FormGroupState.md @@ -3,41 +3,77 @@ id: FormGroupState title: FormGroupState --- -# Interface: FormGroupState +Defined in: [FormGroupApi/FormGroupApi.public.ts:176](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L176) -Defined in: [packages/form-core/src/FormGroupApi.ts:655](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L655) +## Type Parameters -## Extended by +### TGroupValue -- [`FormGroupMeta`](FormGroupMeta.md) +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) ## Properties -### isSubmitSuccessful +### canSubmit ```ts -isSubmitSuccessful: boolean; +canSubmit: boolean; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:188](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L188) + +*** + +### errors + +```ts +errors: FormErrors; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:182](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L182) + +*** + +### isDirty + +```ts +isDirty: boolean; ``` -Defined in: [packages/form-core/src/FormGroupApi.ts:688](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L688) +Defined in: [FormGroupApi/FormGroupApi.public.ts:184](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L184) + +*** -A boolean indicating if the last submission was successful. +### isInvalid + +```ts +isInvalid: boolean; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:187](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L187) *** -### isSubmitted +### isPristine ```ts -isSubmitted: boolean; +isPristine: boolean; ``` -Defined in: [packages/form-core/src/FormGroupApi.ts:676](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L676) +Defined in: [FormGroupApi/FormGroupApi.public.ts:185](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L185) + +*** -A boolean indicating if the `onSubmit` function has completed successfully. +### isSubmitSuccessful -Goes back to `false` at each new submission attempt. +```ts +isSubmitSuccessful: boolean; +``` -Note: you can use isSubmitting to check if the form is currently submitting. +Defined in: [FormGroupApi/FormGroupApi.public.ts:190](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L190) *** @@ -47,17 +83,27 @@ Note: you can use isSubmitting to check if the form is currently submitting. isSubmitting: boolean; ``` -Defined in: [packages/form-core/src/FormGroupApi.ts:668](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L668) +Defined in: [FormGroupApi/FormGroupApi.public.ts:189](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L189) -A boolean indicating if the form is currently in the process of being submitted after `handleSubmit` is called. +*** -Goes back to `false` when submission completes for one of the following reasons: -- the validation step returned errors. -- the `onSubmit` function has completed. +### isTouched -Note: if you're running async operations in your `onSubmit` function make sure to await them to ensure `isSubmitting` is set to `false` only when the async operation completes. +```ts +isTouched: boolean; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:183](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L183) + +*** + +### isValid + +```ts +isValid: boolean; +``` -This is useful for displaying loading indicators or disabling form inputs during submission. +Defined in: [FormGroupApi/FormGroupApi.public.ts:186](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L186) *** @@ -67,9 +113,17 @@ This is useful for displaying loading indicators or disabling form inputs during isValidating: boolean; ``` -Defined in: [packages/form-core/src/FormGroupApi.ts:680](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L680) +Defined in: [FormGroupApi/FormGroupApi.public.ts:191](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L191) + +*** + +### meta + +```ts +meta: unknown; +``` -A boolean indicating if the form or any of its fields are currently validating. +Defined in: [FormGroupApi/FormGroupApi.public.ts:181](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L181) *** @@ -79,6 +133,14 @@ A boolean indicating if the form or any of its fields are currently validating. submissionAttempts: number; ``` -Defined in: [packages/form-core/src/FormGroupApi.ts:684](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L684) +Defined in: [FormGroupApi/FormGroupApi.public.ts:192](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L192) + +*** + +### values + +```ts +values: TGroupValue; +``` -A counter for tracking the number of submission attempts. +Defined in: [FormGroupApi/FormGroupApi.public.ts:180](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L180) diff --git a/docs/reference/interfaces/FormGroupStoreState.md b/docs/reference/interfaces/FormGroupStoreState.md deleted file mode 100644 index b375261f2e..0000000000 --- a/docs/reference/interfaces/FormGroupStoreState.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -id: FormGroupStoreState -title: FormGroupStoreState ---- - -# Interface: FormGroupStoreState\ - -Defined in: [packages/form-core/src/FormGroupApi.ts:859](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L859) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* [`DeepKeys`](../type-aliases/DeepKeys.md)\<`TParentData`\> - -### TData - -`TData` *extends* [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TFormOnMount - -`TFormOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChange - -`TFormOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnChangeAsync - -`TFormOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnBlur - -`TFormOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnBlurAsync - -`TFormOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnSubmit - -`TFormOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnSubmitAsync - -`TFormOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -### TFormOnDynamic - -`TFormOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TParentData`\> - -### TFormOnDynamicAsync - -`TFormOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TParentData`\> - -## Properties - -### meta - -```ts -meta: FormGroupMeta; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:916](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L916) - -The current metadata of the form group, including aggregated validity, -group-level errors, and submission lifecycle. - -*** - -### value - -```ts -value: TData; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:911](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L911) - -The current value of the form group. diff --git a/docs/reference/interfaces/FormGroupSubmitContext.md b/docs/reference/interfaces/FormGroupSubmitContext.md new file mode 100644 index 0000000000..875e1a120d --- /dev/null +++ b/docs/reference/interfaces/FormGroupSubmitContext.md @@ -0,0 +1,107 @@ +--- +id: FormGroupSubmitContext +title: FormGroupSubmitContext +--- + +Defined in: [FormGroupApi/FormGroupApi.public.ts:26](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L26) + +Context passed to a form group's `onSubmit` after group validation succeeds. + +## Example + +```ts +{ + // ... + onSubmit: async ({ value }) => { + await saveGuestDetails(value) + }, +} +``` + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TOutputs + +`TOutputs` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +## Properties + +### formApi + +```ts +formApi: FormApi; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:37](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L37) + +The parent form API handling this submission. + +*** + +### groupApi + +```ts +groupApi: FormGroupApi; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:39](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L39) + +The group API handling this submission. + +*** + +### validatorOutputs + +```ts +validatorOutputs: TOutputs; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:62](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L62) + +Schema outputs and `createOutput` payloads from this group submission, +ordered by validator index. Skipped validators and successful returns +without an output contribute `undefined`. + +#### Example + +```ts +{ + // ... + onSubmit: async ({ validatorOutputs }) => { + const validatedGuestDetails = validatorOutputs[0] + setStep(step => step + 1) + }, +} +``` + +*** + +### value + +```ts +value: TGroupValue; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:35](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L35) + +The group values for this submission. diff --git a/docs/reference/interfaces/FormGroupSubmitInvalidContext.md b/docs/reference/interfaces/FormGroupSubmitInvalidContext.md new file mode 100644 index 0000000000..a7713c133a --- /dev/null +++ b/docs/reference/interfaces/FormGroupSubmitInvalidContext.md @@ -0,0 +1,79 @@ +--- +id: FormGroupSubmitInvalidContext +title: FormGroupSubmitInvalidContext +--- + +Defined in: [FormGroupApi/FormGroupApi.public.ts:80](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L80) + +Context passed to a form group's `onSubmitInvalid` when submission fails. + +## Example + +```ts +{ + // ... + onSubmitInvalid: ({ groupApi }) => { + document + .querySelector('[aria-invalid="true"]') + ?.focus() + }, +} +``` + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupErrorTypes + +`TGroupErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +## Properties + +### formApi + +```ts +formApi: FormApi; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:90](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L90) + +The parent form API handling the failed submission. + +*** + +### groupApi + +```ts +groupApi: FormGroupApi; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:92](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L92) + +The group API handling the failed submission. + +*** + +### value + +```ts +value: TGroupValue; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:88](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L88) + +The group values for the failed submission. diff --git a/docs/reference/interfaces/FormGroupValidationPredicateContext.md b/docs/reference/interfaces/FormGroupValidationPredicateContext.md new file mode 100644 index 0000000000..1b8b8b4a47 --- /dev/null +++ b/docs/reference/interfaces/FormGroupValidationPredicateContext.md @@ -0,0 +1,107 @@ +--- +id: FormGroupValidationPredicateContext +title: FormGroupValidationPredicateContext +--- + +Defined in: [validation.public.ts:430](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L430) + +Current form group state available to validator conditions and delay callbacks. + +## Extends + +- `BaseValidationPredicateContext`\<`any`, `TGroupValue`, `"group"`\> + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +Library-managed. Do not specify explicitly. + +## Properties + +### fieldApi? + +```ts +optional fieldApi?: AnyFieldApi; +``` + +Defined in: [validation.public.ts:409](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L409) + +The field associated with the validation event, when available. + +For form and group validators, this is the field that triggered the +validation. For field validators, this is the field being validated. + +#### Inherited from + +```ts +BaseValidationPredicateContext.fieldApi +``` + +*** + +### formApi + +```ts +formApi: FormApi; +``` + +Defined in: [validation.public.ts:402](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L402) + +The owning form, including its complete values and state. + +#### Inherited from + +```ts +BaseValidationPredicateContext.formApi +``` + +*** + +### groupApi + +```ts +groupApi: FormGroupApi; +``` + +Defined in: [validation.public.ts:434](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L434) + +The form group whose value is being validated. + +*** + +### scope + +```ts +scope: "group"; +``` + +Defined in: [validation.public.ts:400](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L400) + +Identifies whether `value` belongs to a form, form group, or field. + +#### Inherited from + +```ts +BaseValidationPredicateContext.scope +``` + +*** + +### value + +```ts +value: TGroupValue; +``` + +Defined in: [validation.public.ts:411](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L411) + +The current value in this validator's scope when the callback is evaluated. + +#### Inherited from + +```ts +BaseValidationPredicateContext.value +``` diff --git a/docs/reference/interfaces/FormGroupValidator.md b/docs/reference/interfaces/FormGroupValidator.md new file mode 100644 index 0000000000..600c1e27a6 --- /dev/null +++ b/docs/reference/interfaces/FormGroupValidator.md @@ -0,0 +1,161 @@ +--- +id: FormGroupValidator +title: FormGroupValidator +--- + +Defined in: [validation.public.ts:918](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L918) + +Configures validation of a form group's value. + +## Extends + +- [`Validator`](Validator.md)\<`TGroupValue`, + \| [`FormGroupValidatorFn`](../type-aliases/FormGroupValidatorFn.md)\<`TGroupValue`\> + \| [`StandardSchemaV1`](../type-aliases/StandardSchemaV1.md)\<`TGroupValue`, `any`\>, `TGroupValue`, [`ConfigurableValidationTrigger`](../type-aliases/ConfigurableValidationTrigger.md), `"group"`\> + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +Library-managed. Do not specify explicitly. + +## Properties + +### bailIfInvalid? + +```ts +optional bailIfInvalid?: boolean; +``` + +Defined in: [validation.public.ts:29](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L29) + +If `true`, skips this and subsequent validators when earlier validation has failed. + +If `false`, earlier failures do not prevent this validator from running. + +#### Default + +```ts +false +``` + +#### Inherited from + +[`Validator`](Validator.md).[`bailIfInvalid`](Validator.md#bailifinvalid) + +*** + +### run + +```ts +run: + | FormGroupValidatorFn +| StandardSchemaV1; +``` + +Defined in: [validation.public.ts:21](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L21) + +The function or Standard Schema that validates the value in this validator's scope. + +#### Inherited from + +[`Validator`](Validator.md).[`run`](Validator.md#run) + +*** + +### runOnMount? + +```ts +optional runOnMount?: boolean; +``` + +Defined in: [validation.public.ts:64](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L64) + +Whether this validator runs when the form is constructed or when its field +or form group first mounts. + +#### Default + +```ts +false +``` + +#### Inherited from + +[`Validator`](Validator.md).[`runOnMount`](Validator.md#runonmount) + +*** + +### skipOnSubmit? + +```ts +optional skipOnSubmit?: + | boolean +| ValidationPredicateFn; +``` + +Defined in: [validation.public.ts:56](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L56) + +Whether this validator runs during a submission attempt, independently of `triggers`. + +Pass a boolean directly, or pass a function that returns +`true` to skip it for the current attempt. + +#### Default + +```ts +false +``` + +#### Inherited from + +[`Validator`](Validator.md).[`skipOnSubmit`](Validator.md#skiponsubmit) + +*** + +### triggerDebounceMs? + +```ts +optional triggerDebounceMs?: + | number +| ValidationDebounceFn; +``` + +Defined in: [validation.public.ts:74](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L74) + +The delay in milliseconds before validation runs for change or blur events. + +Pass a number for a fixed delay, or pass a function that returns the delay +for the current event. Repeated events restart the delay. +Submission validation runs immediately. + +#### Default + +```ts +0 +``` + +#### Inherited from + +[`Validator`](Validator.md).[`triggerDebounceMs`](Validator.md#triggerdebouncems) + +*** + +### triggers + +```ts +triggers: ValidationTriggerOption[]; +``` + +Defined in: [validation.public.ts:82](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L82) + +Change and blur events that can run this validator, optionally with conditions. + +An empty array disables change and blur validation. Configure submission +separately with `skipOnSubmit` and initial validation with `runOnMount`. + +#### Inherited from + +[`Validator`](Validator.md).[`triggers`](Validator.md#triggers) diff --git a/docs/reference/interfaces/FormGroupValidatorContext.md b/docs/reference/interfaces/FormGroupValidatorContext.md new file mode 100644 index 0000000000..52edae1adf --- /dev/null +++ b/docs/reference/interfaces/FormGroupValidatorContext.md @@ -0,0 +1,142 @@ +--- +id: FormGroupValidatorContext +title: FormGroupValidatorContext +--- + +Defined in: [validation.public.ts:867](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L867) + +Values and helpers passed to a form group validation function. + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +Library-managed. Do not specify explicitly. + +## Properties + +### createErrorMap + +```ts +createErrorMap: (initial?) => ValidationErrorMap; +``` + +Defined in: [validation.public.ts:883](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L883) + +Creates an error map whose field paths are relative to this group. + +Creates a mutable map of form errors and errors for individual field paths. + +Pass the completed map back from a form or group validator to report the errors. + +#### Parameters + +##### initial? + +`Partial`\<[`ValidationErrorMap`](ValidationErrorMap.md)\<`TGroupValue`\>\> + +An existing map to reuse. A missing `fields` object is added to it. + +#### Returns + +[`ValidationErrorMap`](ValidationErrorMap.md)\<`TGroupValue`\> + +The initial map, if supplied, or a new map with an empty `fields` object. + +*** + +### createOutput + +```ts +createOutput: CreateOutputFn; +``` + +Defined in: [validation.public.ts:885](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L885) + +Creates a successful result to return data in this validator's `validatorOutputs` entry. + +*** + +### event + +```ts +event: ValidationTrigger; +``` + +Defined in: [validation.public.ts:869](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L869) + +The event that caused this validation run. + +*** + +### formApi + +```ts +formApi: FormApi; +``` + +Defined in: [validation.public.ts:873](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L873) + +The owning form, including values outside this group. + +*** + +### groupApi + +```ts +groupApi: FormGroupApi; +``` + +Defined in: [validation.public.ts:875](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L875) + +The group whose value is being validated. + +*** + +### parseIssues + +```ts +parseIssues: ParseFormIssuesFn; +``` + +Defined in: [validation.public.ts:881](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L881) + +Converts Standard Schema issues into group errors and errors at group-relative field paths. + +*** + +### signal + +```ts +signal: AbortSignal; +``` + +Defined in: [validation.public.ts:871](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L871) + +Aborted when this run is cancelled. Pass it to asynchronous work such as `fetch`. + +*** + +### triggerFieldApi? + +```ts +optional triggerFieldApi?: AnyFieldApi; +``` + +Defined in: [validation.public.ts:877](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L877) + +The field that caused validation, when available. + +*** + +### value + +```ts +value: TGroupValue; +``` + +Defined in: [validation.public.ts:879](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L879) + +The group's current value, without the surrounding form values. diff --git a/docs/reference/interfaces/FormGroupValidators.md b/docs/reference/interfaces/FormGroupValidators.md deleted file mode 100644 index ba134494b7..0000000000 --- a/docs/reference/interfaces/FormGroupValidators.md +++ /dev/null @@ -1,244 +0,0 @@ ---- -id: FormGroupValidators -title: FormGroupValidators ---- - -# Interface: FormGroupValidators\ - -Defined in: [packages/form-core/src/FormGroupApi.ts:199](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L199) - -## Type Parameters - -### TParentData - -`TParentData` - -### TName - -`TName` *extends* [`DeepKeys`](../type-aliases/DeepKeys.md)\<`TParentData`\> - -### TData - -`TData` *extends* [`DeepValue`](../type-aliases/DeepValue.md)\<`TParentData`, `TName`\> - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormGroupValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* - \| `undefined` - \| `FormGroupAsyncValidateOrFn`\<`TParentData`, `TName`, `TData`\> - -## Properties - -### onBlur? - -```ts -optional onBlur: TOnBlur; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:258](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L258) - -An optional function, that runs on the blur event of input. - -#### Example - -```ts -z.string().min(1) -``` - -*** - -### onBlurAsync? - -```ts -optional onBlurAsync: TOnBlurAsync; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:264](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L264) - -An optional property similar to `onBlur` but async validation. - -#### Example - -```ts -z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' }) -``` - -*** - -### onBlurAsyncDebounceMs? - -```ts -optional onBlurAsyncDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:271](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L271) - -An optional number to represent how long the `onBlurAsync` should wait before running - -If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds - -*** - -### onChange? - -```ts -optional onChange: TOnChange; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:236](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L236) - -An optional function, that runs on the change event of input. - -#### Example - -```ts -z.string().min(1) -``` - -*** - -### onChangeAsync? - -```ts -optional onChangeAsync: TOnChangeAsync; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:242](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L242) - -An optional property similar to `onChange` but async validation - -#### Example - -```ts -z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' }) -``` - -*** - -### onChangeAsyncDebounceMs? - -```ts -optional onChangeAsyncDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:248](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L248) - -An optional number to represent how long the `onChangeAsync` should wait before running - -If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds - -*** - -### onDynamic? - -```ts -optional onDynamic: TOnDynamic; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:288](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L288) - -*** - -### onDynamicAsync? - -```ts -optional onDynamicAsync: TOnDynamicAsync; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:289](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L289) - -*** - -### onDynamicAsyncDebounceMs? - -```ts -optional onDynamicAsyncDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:290](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L290) - -*** - -### onMount? - -```ts -optional onMount: TOnMount; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:230](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L230) - -An optional function, that runs on the mount event of input. - -*** - -### onSubmit? - -```ts -optional onSubmit: TOnSubmit; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:281](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L281) - -An optional function, that runs on the submit event of form. - -#### Example - -```ts -z.string().min(1) -``` - -*** - -### onSubmitAsync? - -```ts -optional onSubmitAsync: TOnSubmitAsync; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:287](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L287) - -An optional property similar to `onSubmit` but async validation. - -#### Example - -```ts -z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' }) -``` diff --git a/docs/reference/interfaces/FormListener.md b/docs/reference/interfaces/FormListener.md new file mode 100644 index 0000000000..2b4af3af3a --- /dev/null +++ b/docs/reference/interfaces/FormListener.md @@ -0,0 +1,134 @@ +--- +id: FormListener +title: FormListener +--- + +Defined in: [listeners.public.ts:276](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L276) + +A listener configured on a form. + +Form listeners can observe field changes and blurs as well as form +submission, mounting, and resetting. + +## Example + +```ts +formOptions({ + defaultValues: { displayName: '' }, + listeners: [ + { + triggers: [ + { + trigger: 'change', + when: ({ value }) => value.displayName.length > 0, + }, + ], + triggerDebounceMs: 200, + run: ({ value }) => { + saveDraft(value) + }, + }, + ], +}) +``` + +## Extends + +- [`Listener`](Listener.md)\<[`FormListenerTriggers`](../type-aliases/FormListenerTriggers.md), `TFormData`, `TFormData`\> + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### run + +```ts +run: FormListenerFn; +``` + +Defined in: [listeners.public.ts:293](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L293) + +Called when an enabled form trigger occurs. + +The return value is ignored. A returned promise is not awaited, and a +rejected promise is reported to the console. + +#### Example + +```ts +run: ({ value }) => { + saveDraft(value) +}, +``` + +*** + +### triggerDebounceMs? + +```ts +optional triggerDebounceMs?: + | number +| ListenerDebounceFn; +``` + +Defined in: [listeners.public.ts:173](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L173) + +The debounce delay in milliseconds before the listener runs. + +A function recalculates the delay for each matching event. Repeated events +restart the delay, and the listener receives the latest event context. +Values less than or equal to `0` run immediately. `'submit'` events always +run immediately. + +#### Default + +```ts +0 +``` + +#### Inherited from + +[`Listener`](Listener.md).[`triggerDebounceMs`](Listener.md#triggerdebouncems) + +*** + +### triggers + +```ts +triggers: ListenerTriggerOption[]; +``` + +Defined in: [listeners.public.ts:191](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L191) + +The events that can invoke the listener. + +The listener runs at most once for an event, even if multiple entries +match. An empty array disables the listener. + +#### Example + +```ts +triggers: [ + 'blur', + { + trigger: 'change', + when: ({ formApi }) => formApi.state.isDirty, + }, +], +``` + +#### Inherited from + +[`Listener`](Listener.md).[`triggers`](Listener.md#triggers) diff --git a/docs/reference/interfaces/FormListenerContext.md b/docs/reference/interfaces/FormListenerContext.md new file mode 100644 index 0000000000..0805cf0958 --- /dev/null +++ b/docs/reference/interfaces/FormListenerContext.md @@ -0,0 +1,65 @@ +--- +id: FormListenerContext +title: FormListenerContext +--- + +Defined in: [listeners.public.ts:200](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L200) + +Context passed to a form listener. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### formApi + +```ts +formApi: FormApi; +``` + +Defined in: [listeners.public.ts:217](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L217) + +The form that owns the listener. + +*** + +### triggerFieldApi? + +```ts +optional triggerFieldApi?: AnyFieldApi; +``` + +Defined in: [listeners.public.ts:215](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L215) + +The field that caused the event when available. + +Some form events are initiated by the form itself, so no field causes +them. `triggerFieldApi` is always `undefined` for: + +- `'mount'`, when the component using the form is mounted. +- `'reset'`, when the form is reset. +- `'submit'`, when a submission attempt starts. + +*** + +### value + +```ts +value: TFormData; +``` + +Defined in: [listeners.public.ts:219](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L219) + +The form values captured when the event occurred. diff --git a/docs/reference/interfaces/FormListeners.md b/docs/reference/interfaces/FormListeners.md deleted file mode 100644 index 65d3f60c25..0000000000 --- a/docs/reference/interfaces/FormListeners.md +++ /dev/null @@ -1,242 +0,0 @@ ---- -id: FormListeners -title: FormListeners ---- - -# Interface: FormListeners\ - -Defined in: [packages/form-core/src/FormApi.ts:294](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L294) - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` = `never` - -## Properties - -### onBlur()? - -```ts -optional onBlur: (props) => void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:344](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L344) - -#### Parameters - -##### props - -###### fieldApi - -[`AnyFieldApi`](../type-aliases/AnyFieldApi.md) - -###### formApi - -[`FormApi`](../classes/FormApi.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -#### Returns - -`void` - -*** - -### onBlurDebounceMs? - -```ts -optional onBlurDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FormApi.ts:361](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L361) - -*** - -### onChange()? - -```ts -optional onChange: (props) => void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:308](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L308) - -#### Parameters - -##### props - -[`FormListenersPropsField`](FormListenersPropsField.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -#### Returns - -`void` - -*** - -### onChangeDebounceMs? - -```ts -optional onChangeDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FormApi.ts:324](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L324) - -*** - -### onChangeGroup()? - -```ts -optional onChangeGroup: (props) => void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:326](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L326) - -#### Parameters - -##### props - -[`FormListenersPropsGroup`](FormListenersPropsGroup.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -#### Returns - -`void` - -*** - -### onChangeGroupDebounceMs? - -```ts -optional onChangeGroupDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FormApi.ts:342](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L342) - -*** - -### onFieldUnmount()? - -```ts -optional onFieldUnmount: (props) => void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:398](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L398) - -#### Parameters - -##### props - -[`FormListenersPropsField`](FormListenersPropsField.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -#### Returns - -`void` - -*** - -### onGroupUnmount()? - -```ts -optional onGroupUnmount: (props) => void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:415](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L415) - -#### Parameters - -##### props - -[`FormListenersPropsGroup`](FormListenersPropsGroup.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -#### Returns - -`void` - -*** - -### onMount()? - -```ts -optional onMount: (props) => void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:363](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L363) - -#### Parameters - -##### props - -###### formApi - -[`FormApi`](../classes/FormApi.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -#### Returns - -`void` - -*** - -### onSubmit()? - -```ts -optional onSubmit: (props) => void; -``` - -Defined in: [packages/form-core/src/FormApi.ts:380](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L380) - -#### Parameters - -##### props - -###### formApi - -[`FormApi`](../classes/FormApi.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> - -###### meta - -`TSubmitMeta` - -#### Returns - -`void` diff --git a/docs/reference/interfaces/FormListenersPropsField.md b/docs/reference/interfaces/FormListenersPropsField.md deleted file mode 100644 index 68abdfd1a9..0000000000 --- a/docs/reference/interfaces/FormListenersPropsField.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -id: FormListenersPropsField -title: FormListenersPropsField ---- - -# Interface: FormListenersPropsField\ - -Defined in: [packages/form-core/src/FormApi.ts:263](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L263) - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` = `never` - -## Properties - -### fieldApi - -```ts -fieldApi: AnyFieldApi; -``` - -Defined in: [packages/form-core/src/FormApi.ts:291](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L291) - -*** - -### formApi - -```ts -formApi: FormApi; -``` - -Defined in: [packages/form-core/src/FormApi.ts:277](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L277) diff --git a/docs/reference/interfaces/FormListenersPropsGroup.md b/docs/reference/interfaces/FormListenersPropsGroup.md deleted file mode 100644 index 46875dc6a6..0000000000 --- a/docs/reference/interfaces/FormListenersPropsGroup.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -id: FormListenersPropsGroup -title: FormListenersPropsGroup ---- - -# Interface: FormListenersPropsGroup\ - -Defined in: [packages/form-core/src/FormApi.ts:232](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L232) - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` = `never` - -## Properties - -### formApi - -```ts -formApi: FormApi; -``` - -Defined in: [packages/form-core/src/FormApi.ts:246](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L246) - -*** - -### groupApi - -```ts -groupApi: AnyFormGroupApi; -``` - -Defined in: [packages/form-core/src/FormApi.ts:260](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L260) diff --git a/docs/reference/interfaces/FormOptions.md b/docs/reference/interfaces/FormOptions.md index ca76d6c695..da92ed9d87 100644 --- a/docs/reference/interfaces/FormOptions.md +++ b/docs/reference/interfaces/FormOptions.md @@ -3,15 +3,24 @@ id: FormOptions title: FormOptions --- -# Interface: FormOptions\ +Defined in: [FormApi/FormApi.public.ts:262](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L262) -Defined in: [packages/form-core/src/FormApi.ts:450](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L450) +Configures initial values, validation, listeners, and submission. -An object representing the options for a form. +Pass these options to a framework adapter's form creation API. Use +`formOptions` when declaring them separately so data and validator types +remain inferred. -## Extends +## Example -- [`BaseFormOptions`](BaseFormOptions.md)\<`TFormData`, `TSubmitMeta`\> +```ts +const profileFormOptions = formOptions({ + defaultValues: { name: '' }, + onSubmit: async ({ value }) => { + await saveProfile(value) + }, +}) +``` ## Type Parameters @@ -19,256 +28,246 @@ An object representing the options for a form. `TFormData` -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur +Library-managed. Do not specify explicitly. -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> +### TFormValidators -### TOnBlurAsync +`TFormValidators` *extends* [`FormValidators`](../type-aliases/FormValidators.md)\<`TFormData`\> -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> +Library-managed. Do not specify explicitly. -### TOnSubmit +### TSubmitReturn -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> +`TSubmitReturn` -### TOnSubmitAsync +Library-managed. Do not specify explicitly. -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> +### TComponents -### TOnDynamic +`TComponents` -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TSubmitMeta - -`TSubmitMeta` = `never` +Library-managed. Do not specify explicitly. ## Properties -### asyncAlways? +### \[formOptionsComponentsSymbol\]? ```ts -optional asyncAlways: boolean; +readonly optional [formOptionsComponentsSymbol]?: TComponents; ``` -Defined in: [packages/form-core/src/FormApi.ts:489](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L489) - -If true, always run async validation, even when sync validation has produced an error. Defaults to undefined. +Defined in: [FormApi/FormApi.public.ts:268](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L268) *** -### asyncDebounceMs? +### defaultValues ```ts -optional asyncDebounceMs: number; +defaultValues: TFormData; ``` -Defined in: [packages/form-core/src/FormApi.ts:493](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L493) - -Optional time in milliseconds if you want to introduce a delay before firing off an async action. +Defined in: [FormApi/FormApi.public.ts:290](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L290) -*** - -### canSubmitWhenInvalid? +Initial values and the source of the inferred data shape. -```ts -optional canSubmitWhenInvalid: boolean; -``` +They also define the reset baseline and what `isDefaultValue` compares +against. -Defined in: [packages/form-core/src/FormApi.ts:497](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L497) +**Async initial values:** The passed value may change over time. While data +is loading, pass fallback values containing the complete data shape, then +pass the resolved values when they become available. -If true, allows the form to be submitted in an invalid state i.e. canSubmit will remain true regardless of validation errors. Defaults to undefined. +When this option changes, untouched top-level values adopt the new defaults +while values under touched top-level fields are preserved. *** -### defaultState? +### errorVisibility? ```ts -optional defaultState: Partial>; +optional errorVisibility?: ErrorVisibility>; ``` -Defined in: [packages/form-core/src/FormApi.ts:471](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L471) +Defined in: [FormApi/FormApi.public.ts:305](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L305) -The default state for the form. +Controls when fields expose validation errors through public state. -*** +This is the default policy for every field. A field can override it with a field-level +`errorVisibility` option. + +When omitted, errors are always exposed. -### defaultValues? +#### Example ```ts -optional defaultValues: TFormData; +errorVisibility: ({ state, fieldState }) => + fieldState.meta.isBlurred || state.submissionAttempts > 0, ``` -Defined in: [packages/form-core/src/FormApi.ts:440](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L440) - -Set initial values for your form. - -#### Inherited from - -[`BaseFormOptions`](BaseFormOptions.md).[`defaultValues`](BaseFormOptions.md#defaultvalues) - *** ### formId? ```ts -optional formId: string; +optional formId?: string; ``` -Defined in: [packages/form-core/src/FormApi.ts:467](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L467) +Defined in: [FormApi/FormApi.public.ts:276](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L276) -The form name, used for devtools and identification +A stable identifier for this form. + +When omitted, an identifier is generated and preserved across option +updates until a new `formId` is supplied. Read the supplied or generated +identifier from `formApi.formId`. *** ### listeners? ```ts -optional listeners: FormListeners; +optional listeners?: FormListeners>; ``` -Defined in: [packages/form-core/src/FormApi.ts:519](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L519) +Defined in: [FormApi/FormApi.public.ts:352](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L352) -form level listeners +Listener configurations for change, blur, submit, mount, and reset events. -*** +Matching listeners are evaluated in array order. Their return values are +ignored, and returned promises are not awaited. -### onSubmit()? +#### Example ```ts -optional onSubmit: (props) => any; +listeners: [ + { + triggers: ['change'], + triggerDebounceMs: 200, + run: ({ value }) => { + saveDraft(value) + }, + }, +], ``` -Defined in: [packages/form-core/src/FormApi.ts:537](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L537) - -A function to be called when the form is submitted, what should happen once the user submits a valid form returns `any` or a promise `Promise` - -#### Parameters - -##### props - -###### formApi +*** -[`FormApi`](../classes/FormApi.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> +### onSubmit? -###### meta +```ts +optional onSubmit?: FormSubmitFn; +``` -`TSubmitMeta` +Defined in: [FormApi/FormApi.public.ts:389](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L389) -###### value +Called after submission validation succeeds. -`TFormData` +Return an error created with `createValidationError` or `parseIssues` to +mark the submission as invalid. A returned promise is awaited before +submission finishes. If the callback throws, `onSubmitInvalid` is called. -#### Returns +#### Example -`any` +```ts +{ + // ... + onSubmit: async ({ value }) => { + await saveUser(value) + }, +} +``` *** -### onSubmitInvalid()? +### onSubmitInvalid? ```ts -optional onSubmitInvalid: (props) => void; +optional onSubmitInvalid?: (context) => void | Promise; ``` -Defined in: [packages/form-core/src/FormApi.ts:558](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L558) +Defined in: [FormApi/FormApi.public.ts:409](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L409) -Specify an action for scenarios where the user tries to submit an invalid form. +Called after an invalid submission is detected. -#### Parameters - -##### props - -###### formApi - -[`FormApi`](../classes/FormApi.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`, `TSubmitMeta`\> +This includes validation failures, errors returned from `onSubmit`, and +exceptions thrown during validation or submission. A returned promise is +awaited before submission finishes. -###### meta - -`TSubmitMeta` +#### Parameters -###### value +##### context -`TFormData` +[`FormSubmitInvalidContext`](FormSubmitInvalidContext.md)\<`TFormData`, [`ToFormErrorTypes`](../type-aliases/ToFormErrorTypes.md)\<`TFormValidators`, `unknown`\>\> #### Returns -`void` - -*** +`void` \| `Promise`\<`void`\> -### onSubmitMeta? +#### Example ```ts -optional onSubmitMeta: TSubmitMeta; +{ + // ... + onSubmitInvalid: () => { + document + .querySelector('[aria-invalid="true"]') + ?.focus() + }, +} ``` -Defined in: [packages/form-core/src/FormApi.ts:444](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L444) - -onSubmitMeta, the data passed from the handleSubmit handler, to the onSubmit function props - -#### Inherited from - -[`BaseFormOptions`](BaseFormOptions.md).[`onSubmitMeta`](BaseFormOptions.md#onsubmitmeta) - *** -### transform()? +### serverState? ```ts -optional transform: (data) => unknown; +optional serverState?: + | ServerFormState, NoInfer> + | null; ``` -Defined in: [packages/form-core/src/FormApi.ts:582](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L582) - -#### Parameters +Defined in: [FormApi/FormApi.public.ts:368](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L368) -##### data +Server-validation state supplied by a server or SSR adapter during +hydration. -`unknown` +Pass a failed result's `serverState` through unchanged. Constructing or +mutating this state directly is discouraged. -#### Returns +#### Example -`unknown` +```ts +serverState: failedResult.serverState, +``` *** -### validationLogic? +### validators? ```ts -optional validationLogic: ValidationLogicFn; +optional validators?: TFormValidators; ``` -Defined in: [packages/form-core/src/FormApi.ts:514](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L514) +Defined in: [FormApi/FormApi.public.ts:332](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L332) -*** +An ordered pipeline of form-level validators. -### validators? +Validators run for their configured triggers and, by default, during +submission. Keep the array length stable after initialization so +validator-indexed errors and schema outputs remain aligned. + +#### Example ```ts -optional validators: FormValidators; +validators: [ + { + triggers: ['change'], + run: ({ value, createErrorMap }) => { + if (value.name) { + return null + } + + return createErrorMap({ fields: { name: 'Name is required' } }) + }, + }, +], ``` - -Defined in: [packages/form-core/src/FormApi.ts:501](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L501) - -A list of validators to pass to the form diff --git a/docs/reference/interfaces/FormOptionsApi.md b/docs/reference/interfaces/FormOptionsApi.md new file mode 100644 index 0000000000..467f4ddc90 --- /dev/null +++ b/docs/reference/interfaces/FormOptionsApi.md @@ -0,0 +1,235 @@ +--- +id: FormOptionsApi +title: FormOptionsApi +--- + +Defined in: [utils.public.ts:205](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.public.ts#L205) + +The callable API exposed by `formOptions`, including its schema-driven +inference modes. + +Use `formOptions` directly instead of naming this interface in application +code. + +## Type Parameters + +### TComponents + +`TComponents` + +Library-managed. Do not specify explicitly. + +```ts +FormOptionsApi(options): FormOptions; +``` + +Defined in: [utils.public.ts:226](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.public.ts#L226) + +Keeps types inferred from `defaultValues`, validators, and submission +callbacks when form options are declared separately. + +`defaultValues` determine the form data shape in this mode. At runtime, +this returns the original options object and does not create a form or run +validation. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](../type-aliases/FormValidators.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +### TSubmitReturn + +`TSubmitReturn` + +Library-managed. Do not specify explicitly. + +## Parameters + +### options + +[`FormOptions`](FormOptions.md)\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `unknown`\> + +## Returns + +[`FormOptions`](FormOptions.md)\<`TFormData`, `TFormValidators`, `TSubmitReturn`, `TComponents`\> + +The original options object, normalized to `FormOptions` with its +inferred form data, validator, and submission types. + +## Remarks + +**Important:** Although this returns the original object unchanged at +runtime, its type is normalized to `FormOptions`. Optional properties such +as `validators` therefore remain optional even when supplied. This +tradeoff enables safer inference and reuse. + +## Properties + +### looseSchema + +```ts +looseSchema: FormOptionsLooseSchemaFn; +``` + +Defined in: [utils.public.ts:332](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.public.ts#L332) + +Infers the form data shape from a Standard Schema validator while allowing +editable defaults to omit properties or contain `null` or `undefined` +values. + +Use this when the schema represents the final valid shape but the UI needs +intermediate empty states, such as an unselected date. Raw form state +remains available as `value`; read each validator's parsed output from the +corresponding `validatorOutputs` entry during submission. + +Pass the schema as the first argument and the options as the second. +`defaultValues` infer an editable form shape constrained by the schema +input, and callbacks receive that shape merged with the schema input. The +first argument is ignored at runtime; include the schema in `validators` +when it should run. + +#### Remarks + +**Important:** Although this returns the original object unchanged at +runtime, its type is normalized to `FormOptions`. Optional properties such +as `validators` therefore remain optional even when supplied. This +tradeoff enables safer inference and reuse. + +#### Example + +```ts +const bookingSchema = z.object({ startDate: z.date() }) +const bookingOptions = formOptions.looseSchema(bookingSchema, { + defaultValues: { startDate: null }, + validators: [ + { + triggers: ['blur'], + run: bookingSchema, + }, + { + triggers: ['change'], + run: ({ value }) => + value.startDate === null ? 'Choose a date' : undefined, + }, + ], + onSubmit: ({ validatorOutputs }) => saveBooking(validatorOutputs[0]), +}) +``` + +#### Returns + +The original options object, normalized to `FormOptions` with +omitted, nullable, and undefined editable states merged into the schema's +input shape. + +#### Type Param + +**TSchema** + +Library-managed. Do not specify explicitly. + +#### Type Param + +**TFormValidators** + +Library-managed. Do not specify explicitly. + +#### Type Param + +**TFormData** + +Library-managed. Do not specify explicitly. + +#### Type Param + +**TSubmitReturn** + +Library-managed. Do not specify explicitly. + +*** + +### strictSchema + +```ts +strictSchema: FormOptionsStrictSchemaFn; +``` + +Defined in: [utils.public.ts:280](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.public.ts#L280) + +Infers the form data type from a Standard Schema validator and requires +`defaultValues` to match the schema input. + +Use this when the schema represents an input-to-output pipeline. Raw form +state remains available as `value`; read each validator's parsed output +from the corresponding `validatorOutputs` entry during submission. + +Pass the schema as the first argument and the options as the second. This +fixes the form data to the schema input before the options are inferred, so +each callback receives a typed `value`. The first argument is ignored at +runtime; include the schema in `validators` when it should run. + +#### Remarks + +**Important:** Although this returns the original object unchanged at +runtime, its type is normalized to `FormOptions`. Optional properties such +as `validators` therefore remain optional even when supplied. This +tradeoff enables safer inference and reuse. + +#### Example + +```ts +const profileSchema = z.object({ name: z.string().min(1) }) +const profileOptions = formOptions.strictSchema(profileSchema, { + defaultValues: { name: '' }, + validators: [ + { + triggers: ['change'], + run: profileSchema, + }, + { + triggers: ['change'], + run: ({ value }) => + value.name.length === 0 ? 'Name is required' : undefined, + }, + ], + onSubmit: ({ validatorOutputs }) => saveProfile(validatorOutputs[0]), +}) +``` + +#### Returns + +The original options object, normalized to `FormOptions` with the +schema's input shape. + +#### Type Param + +**TSchema** + +Library-managed. Do not specify explicitly. + +#### Type Param + +**TFormValidators** + +Library-managed. Do not specify explicitly. + +#### Type Param + +**TFormData** + +Library-managed. Do not specify explicitly. + +#### Type Param + +**TSubmitReturn** + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/interfaces/FormResetOptions.md b/docs/reference/interfaces/FormResetOptions.md new file mode 100644 index 0000000000..fa6b15e951 --- /dev/null +++ b/docs/reference/interfaces/FormResetOptions.md @@ -0,0 +1,54 @@ +--- +id: FormResetOptions +title: FormResetOptions +--- + +Defined in: [FormApi/FormApi.public.ts:554](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L554) + +Options controlling whether `reset(values)` replaces the default-value +baseline. + +## Example + +```ts +formApi.reset(savedValues, { updateDefaultValues: false }) +``` + +## Properties + +### updateDefaultValues? + +```ts +optional updateDefaultValues?: boolean; +``` + +Defined in: [FormApi/FormApi.public.ts:584](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L584) + +Whether `reset(values)` should also update the form's `defaultValues` +baseline. + +By default, passing values to `reset` treats those values as the new reset +baseline. Future `reset()` calls will return to those values, and +`state.isDefaultValue` will compare against them. + +Set this to `false` when you want reset semantics for form state +(clearing touched, dirty, validation, submission state, and mounted fields) +but want to keep comparing against the previous `defaultValues`. + +With `updateDefaultValues: false`, `state.isDirty` is reset to `false`, +but `state.isDefaultValue` may be `false` if the provided reset values do +not deeply equal the preserved defaults. + +This option is ignored when no reset values are provided. + +#### Example + +```ts +const originalDefaults = formApi.defaultValues + +formApi.reset(savedDraft, { updateDefaultValues: false }) +// `savedDraft` is current, but `originalDefaults` remains the baseline. + +formApi.reset() +// Restores `originalDefaults`, not `savedDraft`. +``` diff --git a/docs/reference/interfaces/FormState.md b/docs/reference/interfaces/FormState.md index 8dae1e2b00..1699f923f7 100644 --- a/docs/reference/interfaces/FormState.md +++ b/docs/reference/interfaces/FormState.md @@ -3,15 +3,12 @@ id: FormState title: FormState --- -# Interface: FormState\ +Defined in: [FormApi/FormApi.public.ts:426](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L426) -Defined in: [packages/form-core/src/FormApi.ts:793](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L793) +A snapshot of current values, validation status, and submission metadata. -An object representing the current state of the form. - -## Extends - -- [`BaseFormState`](../type-aliases/BaseFormState.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`\>.[`DerivedFormState`](../type-aliases/DerivedFormState.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnDynamic`, `TOnDynamicAsync`, `TOnServer`\> +Read the latest snapshot from `formApi.state` or subscribe to +`formApi.atom`. ## Type Parameters @@ -19,202 +16,47 @@ An object representing the current state of the form. `TFormData` -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit +Library-managed. Do not specify explicitly. -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> +### TFormErrorTypes -### TOnSubmitAsync +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> +Library-managed. Do not specify explicitly. ## Properties -### \_force\_re\_eval? - -```ts -optional _force_re_eval: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:696](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L696) - -@private, used to force a re-evaluation of the form state when options change - -#### Inherited from - -```ts -BaseFormState._force_re_eval -``` - -*** - ### canSubmit ```ts canSubmit: boolean; ``` -Defined in: [packages/form-core/src/FormApi.ts:786](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L786) - -A boolean indicating if the form can be submitted based on its current state. - -#### Inherited from - -```ts -DerivedFormState.canSubmit -``` - -*** - -### errorMap - -```ts -errorMap: ValidationErrorMap, UnwrapFormValidateOrFn, UnwrapFormAsyncValidateOrFn, UnwrapFormValidateOrFn, UnwrapFormAsyncValidateOrFn, UnwrapFormValidateOrFn, UnwrapFormAsyncValidateOrFn, UnwrapFormValidateOrFn, UnwrapFormAsyncValidateOrFn, UnwrapFormAsyncValidateOrFn>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:633](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L633) +Defined in: [FormApi/FormApi.public.ts:504](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L504) -The error map for the form itself. +Whether no submission is running and validation state has no known errors. -#### Inherited from +This is optimistic: validation does not need to have run, and pending +validation alone does not make it `false`. `handleSubmit()` still runs +submission validation. -```ts -BaseFormState.errorMap -``` +* Equivalent to `isValid && !isSubmitting`. *** ### errors ```ts -errors: NonNullable< - | UnwrapFormValidateOrFn - | UnwrapFormValidateOrFn - | UnwrapFormAsyncValidateOrFn - | UnwrapFormValidateOrFn - | UnwrapFormAsyncValidateOrFn - | UnwrapFormValidateOrFn - | UnwrapFormAsyncValidateOrFn - | UnwrapFormValidateOrFn - | UnwrapFormAsyncValidateOrFn - | UnwrapFormAsyncValidateOrFn>[]; -``` - -Defined in: [packages/form-core/src/FormApi.ts:737](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L737) - -The error array for the form itself. - -#### Inherited from - -```ts -DerivedFormState.errors -``` - -*** - -### fieldMeta - -```ts -fieldMeta: Partial, AnyFieldLikeMeta>>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:790](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L790) - -A record of field metadata for each field in the form. - -#### Inherited from - -```ts -DerivedFormState.fieldMeta -``` - -*** - -### fieldMetaBase - -```ts -fieldMetaBase: Partial, AnyFieldLikeMetaBase>>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:652](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L652) - -A record of field metadata for each field in the form, not including the derived properties, like `errors` and such - -#### Inherited from - -```ts -BaseFormState.fieldMetaBase -``` - -*** - -### formGroupStateBase - -```ts -formGroupStateBase: Partial>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:659](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L659) - -A record of submission lifecycle state for each mounted `FormGroupApi`, -keyed by the group's fully-qualified field name. Stored on the form so -group-level state can be read from `FormApi` without having to walk the -mounted group instances. - -#### Inherited from - -```ts -BaseFormState.formGroupStateBase -``` - -*** - -### isBlurred - -```ts -isBlurred: boolean; +errors: FormErrors; ``` -Defined in: [packages/form-core/src/FormApi.ts:766](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L766) - -A boolean indicating if any of the form fields have been blurred. +Defined in: [FormApi/FormApi.public.ts:478](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L478) -#### Inherited from +Form-level errors from validators and `onSubmit`. -```ts -DerivedFormState.isBlurred -``` +Errors are flattened in validator order, with `onSubmit` errors last. +Errors routed to fields are exposed through the corresponding field APIs +and are not included here. *** @@ -224,15 +66,13 @@ DerivedFormState.isBlurred isDefaultValue: boolean; ``` -Defined in: [packages/form-core/src/FormApi.ts:778](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L778) +Defined in: [FormApi/FormApi.public.ts:470](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L470) -A boolean indicating if all of the form's fields are the same as default values. +Whether current values deeply match `formApi.defaultValues`. -#### Inherited from - -```ts -DerivedFormState.isDefaultValue -``` +Unlike `isDirty` and `isPristine`, this compares current values with their +defaults rather than tracking whether edits have occurred. Reverting an +edit can make it `true` while `isDirty` remains `true`. *** @@ -242,87 +82,33 @@ DerivedFormState.isDefaultValue isDirty: boolean; ``` -Defined in: [packages/form-core/src/FormApi.ts:770](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L770) - -A boolean indicating if any of the form's fields' values have been modified by the user. Evaluates `true` if the user have modified at least one of the fields. Opposite of `isPristine`. - -#### Inherited from - -```ts -DerivedFormState.isDirty -``` - -*** - -### isFieldsValid - -```ts -isFieldsValid: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:758](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L758) - -A boolean indicating if all the form fields are valid. Evaluates `true` if there are no field errors. - -#### Inherited from - -```ts -DerivedFormState.isFieldsValid -``` - -*** - -### isFieldsValidating - -```ts -isFieldsValidating: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:754](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L754) - -A boolean indicating if any of the form fields are currently validating. - -#### Inherited from - -```ts -DerivedFormState.isFieldsValidating -``` - -*** - -### isFormValid - -```ts -isFormValid: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:733](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L733) +Defined in: [FormApi/FormApi.public.ts:451](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L451) -A boolean indicating if the form is valid. +Whether a value update has marked state as dirty. -#### Inherited from +This records whether a dirty-marking update has occurred, not whether +current values match their defaults. Once `true`, it remains `true` even if +values return to their defaults. `formApi.reset()` clears it. -```ts -DerivedFormState.isFormValid -``` +* Equivalent to `!isPristine`. +* Use `isDefaultValue` to check whether current values match their defaults. *** -### isFormValidating +### isInvalid ```ts -isFormValidating: boolean; +isInvalid: boolean; ``` -Defined in: [packages/form-core/src/FormApi.ts:729](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L729) +Defined in: [FormApi/FormApi.public.ts:494](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L494) -A boolean indicating if the form is currently validating. +Whether validation state contains at least one form- or field-level error. -#### Inherited from +This is the exact inverse of `isValid`. Field `errorVisibility` does not +affect it. -```ts -DerivedFormState.isFormValidating -``` +* Equivalent to `!isValid`. *** @@ -332,15 +118,16 @@ DerivedFormState.isFormValidating isPristine: boolean; ``` -Defined in: [packages/form-core/src/FormApi.ts:774](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L774) +Defined in: [FormApi/FormApi.public.ts:462](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L462) -A boolean indicating if none of the form's fields' values have been modified by the user. Evaluates `true` if the user have not modified any of the fields. Opposite of `isDirty`. +Whether state has not been marked dirty. -#### Inherited from +This records whether a dirty-marking update has occurred, not whether +current values match their defaults. Once `false`, it remains `false` even +if values return to their defaults. `formApi.reset()` restores it. -```ts -DerivedFormState.isPristine -``` +* Equivalent to `!isDirty`. +* Use `isDefaultValue` to check whether current values match their defaults. *** @@ -350,37 +137,13 @@ DerivedFormState.isPristine isSubmitSuccessful: boolean; ``` -Defined in: [packages/form-core/src/FormApi.ts:692](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L692) - -A boolean indicating if the last submission was successful. +Defined in: [FormApi/FormApi.public.ts:519](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L519) -#### Inherited from +Whether the latest completed submission finished without validation errors +or an `onSubmit` failure. -```ts -BaseFormState.isSubmitSuccessful -``` - -*** - -### isSubmitted - -```ts -isSubmitted: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:680](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L680) - -A boolean indicating if the `onSubmit` function has completed successfully. - -Goes back to `false` at each new submission attempt. - -Note: you can use isSubmitting to check if the form is currently submitting. - -#### Inherited from - -```ts -BaseFormState.isSubmitted -``` +It starts as `false`, updates when an attempt finishes, and is cleared by +`formApi.reset()`. *** @@ -390,23 +153,12 @@ BaseFormState.isSubmitted isSubmitting: boolean; ``` -Defined in: [packages/form-core/src/FormApi.ts:672](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L672) - -A boolean indicating if the form is currently in the process of being submitted after `handleSubmit` is called. - -Goes back to `false` when submission completes for one of the following reasons: -- the validation step returned errors. -- the `onSubmit` function has completed. +Defined in: [FormApi/FormApi.public.ts:511](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L511) -Note: if you're running async operations in your `onSubmit` function make sure to await them to ensure `isSubmitting` is set to `false` only when the async operation completes. +Whether a submission attempt is in progress. -This is useful for displaying loading indicators or disabling form inputs during submission. - -#### Inherited from - -```ts -BaseFormState.isSubmitting -``` +This includes submission validation and the time spent awaiting `onSubmit` +or `onSubmitInvalid`. *** @@ -416,15 +168,12 @@ BaseFormState.isSubmitting isTouched: boolean; ``` -Defined in: [packages/form-core/src/FormApi.ts:762](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L762) - -A boolean indicating if any of the form fields have been touched. +Defined in: [FormApi/FormApi.public.ts:440](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L440) -#### Inherited from +Whether at least one field is currently touched. -```ts -DerivedFormState.isTouched -``` +Field changes mark fields as touched by default, and submission marks all +registered fields as touched. Resets clear the touched state. *** @@ -434,15 +183,12 @@ DerivedFormState.isTouched isValid: boolean; ``` -Defined in: [packages/form-core/src/FormApi.ts:782](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L782) +Defined in: [FormApi/FormApi.public.ts:485](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L485) -A boolean indicating if the form and all its fields are valid. Evaluates `true` if there are no errors. +Whether validation state contains no form- or field-level errors. -#### Inherited from - -```ts -DerivedFormState.isValid -``` +* Equivalent to `!isInvalid`. +* A field error hidden by `errorVisibility` still makes this `false`. *** @@ -452,15 +198,12 @@ DerivedFormState.isValid isValidating: boolean; ``` -Defined in: [packages/form-core/src/FormApi.ts:684](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L684) - -A boolean indicating if the form or any of its fields are currently validating. +Defined in: [FormApi/FormApi.public.ts:526](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L526) -#### Inherited from +Whether any form-, group-, or field-level validation is pending. -```ts -BaseFormState.isValidating -``` +It remains `true` until all concurrent validation work finishes or is +canceled. Pending validation does not by itself make `canSubmit` `false`. *** @@ -470,33 +213,12 @@ BaseFormState.isValidating submissionAttempts: number; ``` -Defined in: [packages/form-core/src/FormApi.ts:688](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L688) - -A counter for tracking the number of submission attempts. +Defined in: [FormApi/FormApi.public.ts:533](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L533) -#### Inherited from +Number of submission attempts started since the last reset. -```ts -BaseFormState.submissionAttempts -``` - -*** - -### validationMetaMap - -```ts -validationMetaMap: Record; -``` - -Defined in: [packages/form-core/src/FormApi.ts:648](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L648) - -An internal mechanism used for keeping track of validation logic in a form. - -#### Inherited from - -```ts -BaseFormState.validationMetaMap -``` +An attempt is counted before validation begins, whether it succeeds or +fails. `formApi.reset()` returns the count to `0`. *** @@ -506,12 +228,6 @@ BaseFormState.validationMetaMap values: TFormData; ``` -Defined in: [packages/form-core/src/FormApi.ts:629](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L629) - -The current values of the form fields. - -#### Inherited from +Defined in: [FormApi/FormApi.public.ts:433](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L433) -```ts -BaseFormState.values -``` +Current values after field edits, resets, or default-value updates. diff --git a/docs/reference/interfaces/FormSubmitContext.md b/docs/reference/interfaces/FormSubmitContext.md new file mode 100644 index 0000000000..4190b8ba7a --- /dev/null +++ b/docs/reference/interfaces/FormSubmitContext.md @@ -0,0 +1,166 @@ +--- +id: FormSubmitContext +title: FormSubmitContext +--- + +Defined in: [FormApi/FormApi.public.ts:105](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L105) + +Context passed to `onSubmit` after submission validation succeeds. + +## Example + +```ts +{ + // ... + onSubmit: async ({ value, createValidationError }) => { + const result = await saveUser(value) + + if (!result.ok) { + return createValidationError(result.error) + } + }, +} +``` + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TOutputs + +`TOutputs` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### createErrorMap + +```ts +createErrorMap: CreateSubmitErrorMapFn; +``` + +Defined in: [FormApi/FormApi.public.ts:155](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L155) + +*** + +### createValidationError + +```ts +createValidationError: CreateValidationErrorFn; +``` + +Defined in: [FormApi/FormApi.public.ts:154](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L154) + +Creates a validation error that can be returned from `onSubmit`. + +Return the created error from `onSubmit` to add its form- and field-level +errors to validation state. + +#### Example + +```ts +{ + // ... + onSubmit: async ({ value, createValidationError }) => { + const result = await saveUser(value) + + if (result.status === 409) { + return createValidationError({ + form: 'A user with this email already exists', + fields: {}, + }) + } + }, +} +``` + +*** + +### formApi + +```ts +formApi: FormApi; +``` + +Defined in: [FormApi/FormApi.public.ts:113](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L113) + +The form API handling this submission. + +*** + +### parseIssues + +```ts +parseIssues: ParseSubmitIssuesFn; +``` + +Defined in: [FormApi/FormApi.public.ts:176](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L176) + +Parses Standard Schema issues into an error returnable from `onSubmit`. + +Issue paths are mapped to fields in the submitted value. Return the parsed +error from `onSubmit` to add those errors to validation state. + +#### Example + +```ts +{ + // ... + onSubmit: async ({ value, parseIssues }) => { + const result = zodSchema.safeParse(value) + + if (!result.success) { + return parseIssues(result.error.issues) + } + }, +} +``` + +*** + +### validatorOutputs + +```ts +validatorOutputs: TOutputs; +``` + +Defined in: [FormApi/FormApi.public.ts:130](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L130) + +Schema outputs and `createOutput` payloads from this submission, ordered by +validator index. Skipped validators and successful returns without an output +contribute `undefined`. + +#### Example + +```ts +{ + // ... + onSubmit: async ({ validatorOutputs }) => { + const validatedUser = validatorOutputs[0] + await saveUser(validatedUser) + }, +} +``` + +*** + +### value + +```ts +value: TFormData; +``` + +Defined in: [FormApi/FormApi.public.ts:111](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L111) + +The form values for this submission. diff --git a/docs/reference/interfaces/FormSubmitInvalidContext.md b/docs/reference/interfaces/FormSubmitInvalidContext.md new file mode 100644 index 0000000000..2046e206e7 --- /dev/null +++ b/docs/reference/interfaces/FormSubmitInvalidContext.md @@ -0,0 +1,59 @@ +--- +id: FormSubmitInvalidContext +title: FormSubmitInvalidContext +--- + +Defined in: [FormApi/FormApi.public.ts:220](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L220) + +Context passed to `onSubmitInvalid` when a submission fails. + +## Example + +```ts +{ + // ... + onSubmitInvalid: () => { + document + .querySelector('[aria-invalid="true"]') + ?.focus() + }, +} +``` + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### formApi + +```ts +formApi: FormApi; +``` + +Defined in: [FormApi/FormApi.public.ts:227](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L227) + +The form API handling the failed submission. + +*** + +### value + +```ts +value: TFormData; +``` + +Defined in: [FormApi/FormApi.public.ts:225](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L225) + +The form values for the failed submission. diff --git a/docs/reference/interfaces/FormValidationPredicateContext.md b/docs/reference/interfaces/FormValidationPredicateContext.md new file mode 100644 index 0000000000..ec816bffc7 --- /dev/null +++ b/docs/reference/interfaces/FormValidationPredicateContext.md @@ -0,0 +1,105 @@ +--- +id: FormValidationPredicateContext +title: FormValidationPredicateContext +--- + +Defined in: [validation.public.ts:419](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L419) + +Current form state available to validator conditions and delay callbacks. + +## Extends + +- `BaseValidationPredicateContext`\<`TFormData`, `TFormData`, `"form"`\> + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Properties + +### fieldApi? + +```ts +optional fieldApi?: AnyFieldApi; +``` + +Defined in: [validation.public.ts:409](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L409) + +The field associated with the validation event, when available. + +For form and group validators, this is the field that triggered the +validation. For field validators, this is the field being validated. + +#### Inherited from + +```ts +BaseValidationPredicateContext.fieldApi +``` + +*** + +### formApi + +```ts +formApi: FormApi; +``` + +Defined in: [validation.public.ts:402](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L402) + +The owning form, including its complete values and state. + +#### Inherited from + +```ts +BaseValidationPredicateContext.formApi +``` + +*** + +### groupApi? + +```ts +optional groupApi?: undefined; +``` + +Defined in: [validation.public.ts:422](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L422) + +*** + +### scope + +```ts +scope: "form"; +``` + +Defined in: [validation.public.ts:400](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L400) + +Identifies whether `value` belongs to a form, form group, or field. + +#### Inherited from + +```ts +BaseValidationPredicateContext.scope +``` + +*** + +### value + +```ts +value: TFormData; +``` + +Defined in: [validation.public.ts:411](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L411) + +The current value in this validator's scope when the callback is evaluated. + +#### Inherited from + +```ts +BaseValidationPredicateContext.value +``` diff --git a/docs/reference/interfaces/FormValidator.md b/docs/reference/interfaces/FormValidator.md new file mode 100644 index 0000000000..2574e6ff83 --- /dev/null +++ b/docs/reference/interfaces/FormValidator.md @@ -0,0 +1,145 @@ +--- +id: FormValidator +title: FormValidator +--- + +Defined in: [validation.public.ts:816](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L816) + +Configures validation of complete form values on the client or server. + +## Extends + +- [`BaseValidator`](BaseValidator.md)\< + \| [`FormValidatorFn`](../type-aliases/FormValidatorFn.md)\<`TFormData`\> + \| [`StandardSchemaV1`](../type-aliases/StandardSchemaV1.md)\<`TFormData`, `any`\>\> + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Properties + +### bailIfInvalid? + +```ts +optional bailIfInvalid?: boolean; +``` + +Defined in: [validation.public.ts:29](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L29) + +If `true`, skips this and subsequent validators when earlier validation has failed. + +If `false`, earlier failures do not prevent this validator from running. + +#### Default + +```ts +false +``` + +#### Inherited from + +[`BaseValidator`](BaseValidator.md).[`bailIfInvalid`](BaseValidator.md#bailifinvalid) + +*** + +### run + +```ts +run: + | FormValidatorFn +| StandardSchemaV1; +``` + +Defined in: [validation.public.ts:21](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L21) + +The function or Standard Schema that validates the value in this validator's scope. + +#### Inherited from + +[`BaseValidator`](BaseValidator.md).[`run`](BaseValidator.md#run) + +*** + +### runOnMount? + +```ts +optional runOnMount?: boolean; +``` + +Defined in: [validation.public.ts:833](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L833) + +Whether this validator runs when the form is constructed. + +#### Default + +```ts +false +``` + +*** + +### skipOnSubmit? + +```ts +optional skipOnSubmit?: + | boolean +| ValidationPredicateFn; +``` + +Defined in: [validation.public.ts:827](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L827) + +Whether this validator runs during a client submission attempt, independently of `triggers`. + +Pass a boolean or a function that returns +`true` to skip it for the current attempt. + +#### Default + +```ts +false +``` + +*** + +### triggerDebounceMs? + +```ts +optional triggerDebounceMs?: + | number +| ValidationDebounceFn; +``` + +Defined in: [validation.public.ts:843](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L843) + +The delay in milliseconds before validation runs for change or blur events. + +Pass a number for a fixed delay, or pass a function that returns the delay +for the current event. Repeated events restart the delay. +Submission and server validation run immediately. + +#### Default + +```ts +0 +``` + +*** + +### triggers + +```ts +triggers: FormValidationTriggerOption[]; +``` + +Defined in: [validation.public.ts:852](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L852) + +Change and blur events that can run this validator, optionally with conditions. +Add `'server'` to include it in `serverValidate`. + +An empty array disables change, blur, and server validation. Configure client +submission separately with `skipOnSubmit` and initial validation with `runOnMount`. diff --git a/docs/reference/interfaces/FormValidatorContext.md b/docs/reference/interfaces/FormValidatorContext.md new file mode 100644 index 0000000000..5525e2f24b --- /dev/null +++ b/docs/reference/interfaces/FormValidatorContext.md @@ -0,0 +1,130 @@ +--- +id: FormValidatorContext +title: FormValidatorContext +--- + +Defined in: [validation.public.ts:711](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L711) + +Values and helpers passed to a form validation function. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Properties + +### createErrorMap + +```ts +createErrorMap: (initial?) => ValidationErrorMap; +``` + +Defined in: [validation.public.ts:725](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L725) + +Creates an error map with field paths inferred from the form values. + +Creates a mutable map of form errors and errors for individual field paths. + +Pass the completed map back from a form or group validator to report the errors. + +#### Parameters + +##### initial? + +`Partial`\<[`ValidationErrorMap`](ValidationErrorMap.md)\<`TFormData`\>\> + +An existing map to reuse. A missing `fields` object is added to it. + +#### Returns + +[`ValidationErrorMap`](ValidationErrorMap.md)\<`TFormData`\> + +The initial map, if supplied, or a new map with an empty `fields` object. + +*** + +### createOutput + +```ts +createOutput: CreateOutputFn; +``` + +Defined in: [validation.public.ts:727](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L727) + +Creates a successful result to return data in this validator's `validatorOutputs` entry. + +*** + +### event + +```ts +event: ValidationTrigger | "server"; +``` + +Defined in: [validation.public.ts:713](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L713) + +The event that caused this validation run. + +*** + +### formApi + +```ts +formApi: FormApi | undefined; +``` + +Defined in: [validation.public.ts:717](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L717) + +The owning form on the client. `undefined` during server validation. + +*** + +### parseIssues + +```ts +parseIssues: ParseFormIssuesFn; +``` + +Defined in: [validation.public.ts:723](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L723) + +Converts Standard Schema issues into form and field errors to return from this validator. + +*** + +### signal + +```ts +signal: AbortSignal; +``` + +Defined in: [validation.public.ts:715](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L715) + +Aborted when this run is cancelled. Pass it to asynchronous work such as `fetch`. + +*** + +### triggerFieldApi? + +```ts +optional triggerFieldApi?: AnyFieldApi; +``` + +Defined in: [validation.public.ts:719](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L719) + +The field that caused validation, when available. + +*** + +### value + +```ts +value: TFormData; +``` + +Defined in: [validation.public.ts:721](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L721) + +The complete form values being validated. diff --git a/docs/reference/interfaces/FormValidators.md b/docs/reference/interfaces/FormValidators.md deleted file mode 100644 index f8f7038266..0000000000 --- a/docs/reference/interfaces/FormValidators.md +++ /dev/null @@ -1,184 +0,0 @@ ---- -id: FormValidators -title: FormValidators ---- - -# Interface: FormValidators\ - -Defined in: [packages/form-core/src/FormApi.ts:185](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L185) - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -## Properties - -### onBlur? - -```ts -optional onBlur: RejectPromiseValidator; -``` - -Defined in: [packages/form-core/src/FormApi.ts:216](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L216) - -Optional function that validates the form data when a field loses focus, returns a `FormValidationError` - -*** - -### onBlurAsync? - -```ts -optional onBlurAsync: TOnBlurAsync; -``` - -Defined in: [packages/form-core/src/FormApi.ts:220](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L220) - -Optional onBlur asynchronous validation method for when a field loses focus returns a ` FormValidationError` or a promise of `Promise` - -*** - -### onBlurAsyncDebounceMs? - -```ts -optional onBlurAsyncDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FormApi.ts:224](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L224) - -The default time in milliseconds that if set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds. - -*** - -### onChange? - -```ts -optional onChange: RejectPromiseValidator; -``` - -Defined in: [packages/form-core/src/FormApi.ts:204](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L204) - -Optional function that checks the validity of your data whenever a value changes - -*** - -### onChangeAsync? - -```ts -optional onChangeAsync: TOnChangeAsync; -``` - -Defined in: [packages/form-core/src/FormApi.ts:208](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L208) - -Optional onChange asynchronous counterpart to onChange. Useful for more complex validation logic that might involve server requests. - -*** - -### onChangeAsyncDebounceMs? - -```ts -optional onChangeAsyncDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FormApi.ts:212](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L212) - -The default time in milliseconds that if set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds. - -*** - -### onDynamic? - -```ts -optional onDynamic: RejectPromiseValidator; -``` - -Defined in: [packages/form-core/src/FormApi.ts:227](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L227) - -*** - -### onDynamicAsync? - -```ts -optional onDynamicAsync: TOnDynamicAsync; -``` - -Defined in: [packages/form-core/src/FormApi.ts:228](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L228) - -*** - -### onDynamicAsyncDebounceMs? - -```ts -optional onDynamicAsyncDebounceMs: number; -``` - -Defined in: [packages/form-core/src/FormApi.ts:229](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L229) - -*** - -### onMount? - -```ts -optional onMount: RejectPromiseValidator; -``` - -Defined in: [packages/form-core/src/FormApi.ts:200](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L200) - -Optional function that fires as soon as the component mounts. - -*** - -### onSubmit? - -```ts -optional onSubmit: RejectPromiseValidator; -``` - -Defined in: [packages/form-core/src/FormApi.ts:225](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L225) - -*** - -### onSubmitAsync? - -```ts -optional onSubmitAsync: TOnSubmitAsync; -``` - -Defined in: [packages/form-core/src/FormApi.ts:226](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L226) diff --git a/docs/reference/interfaces/Listener.md b/docs/reference/interfaces/Listener.md new file mode 100644 index 0000000000..87e322b564 --- /dev/null +++ b/docs/reference/interfaces/Listener.md @@ -0,0 +1,85 @@ +--- +id: Listener +title: Listener +--- + +Defined in: [listeners.public.ts:158](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L158) + +Configuration shared by form and field listeners. + +## Extended by + +- [`FormListener`](FormListener.md) +- [`FieldListener`](FieldListener.md) + +## Type Parameters + +### TTriggers + +`TTriggers` *extends* [`FieldListenerTriggers`](../type-aliases/FieldListenerTriggers.md) + +Library-managed. Do not specify explicitly. + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValue + +`TValue` + +Library-managed. Do not specify explicitly. + +## Properties + +### triggerDebounceMs? + +```ts +optional triggerDebounceMs?: + | number +| ListenerDebounceFn; +``` + +Defined in: [listeners.public.ts:173](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L173) + +The debounce delay in milliseconds before the listener runs. + +A function recalculates the delay for each matching event. Repeated events +restart the delay, and the listener receives the latest event context. +Values less than or equal to `0` run immediately. `'submit'` events always +run immediately. + +#### Default + +```ts +0 +``` + +*** + +### triggers + +```ts +triggers: ListenerTriggerOption[]; +``` + +Defined in: [listeners.public.ts:191](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L191) + +The events that can invoke the listener. + +The listener runs at most once for an event, even if multiple entries +match. An empty array disables the listener. + +#### Example + +```ts +triggers: [ + 'blur', + { + trigger: 'change', + when: ({ formApi }) => formApi.state.isDirty, + }, +], +``` diff --git a/docs/reference/interfaces/ListenerPredicateContext.md b/docs/reference/interfaces/ListenerPredicateContext.md new file mode 100644 index 0000000000..be5b0a2bb2 --- /dev/null +++ b/docs/reference/interfaces/ListenerPredicateContext.md @@ -0,0 +1,62 @@ +--- +id: ListenerPredicateContext +title: ListenerPredicateContext +--- + +Defined in: [listeners.public.ts:40](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L40) + +Context used to conditionally enable or debounce a listener. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValue + +`TValue` + +Library-managed. Do not specify explicitly. + +## Properties + +### formApi + +```ts +formApi: FormApi; +``` + +Defined in: [listeners.public.ts:42](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L42) + +The form associated with the listener event. + +*** + +### triggerFieldApi? + +```ts +optional triggerFieldApi?: AnyFieldApi; +``` + +Defined in: [listeners.public.ts:50](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L50) + +The field associated with the listener event, when available. + +For a field listener, this is the field that owns the listener even when +the event came from one of its `watchFields`. It is `undefined` for +form-level `'mount'`, `'reset'`, and `'submit'` events. + +*** + +### value + +```ts +value: TValue; +``` + +Defined in: [listeners.public.ts:52](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L52) + +The value in the listener's scope when the event occurred. diff --git a/docs/reference/interfaces/ListenerTriggerConfig.md b/docs/reference/interfaces/ListenerTriggerConfig.md new file mode 100644 index 0000000000..3abae8a3b7 --- /dev/null +++ b/docs/reference/interfaces/ListenerTriggerConfig.md @@ -0,0 +1,68 @@ +--- +id: ListenerTriggerConfig +title: ListenerTriggerConfig +--- + +Defined in: [listeners.public.ts:80](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L80) + +Configures a listener trigger with an optional condition. + +## Type Parameters + +### TTriggers + +`TTriggers` *extends* [`FieldListenerTriggers`](../type-aliases/FieldListenerTriggers.md) + +Library-managed. Do not specify explicitly. + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValue + +`TValue` + +Library-managed. Do not specify explicitly. + +## Properties + +### trigger + +```ts +trigger: TTriggers; +``` + +Defined in: [listeners.public.ts:86](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L86) + +The event to match before evaluating `when`. + +*** + +### when? + +```ts +optional when?: + | boolean +| ListenerPredicateFn; +``` + +Defined in: [listeners.public.ts:99](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L99) + +Whether the listener is enabled when `trigger` occurs. + +A function receives the current listener context. + +#### Example + +```ts +when: ({ formApi }) => formApi.state.isDirty, +``` + +#### Default + +```ts +true +``` diff --git a/docs/reference/interfaces/ObjectDeepKeyAndValue.md b/docs/reference/interfaces/ObjectDeepKeyAndValue.md deleted file mode 100644 index 5822976b61..0000000000 --- a/docs/reference/interfaces/ObjectDeepKeyAndValue.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -id: ObjectDeepKeyAndValue -title: ObjectDeepKeyAndValue ---- - -# Interface: ObjectDeepKeyAndValue\ - -Defined in: [packages/form-core/src/util-types.ts:114](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L114) - -## Extends - -- [`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md) - -## Type Parameters - -### TParent - -`TParent` *extends* [`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md) - -### T - -`T` - -### TKey - -`TKey` *extends* [`AllObjectKeys`](../type-aliases/AllObjectKeys.md)\<`T`\> - -## Properties - -### key - -```ts -key: ObjectAccessor; -``` - -Defined in: [packages/form-core/src/util-types.ts:119](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L119) - -#### Overrides - -[`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md).[`key`](AnyDeepKeyAndValue.md#key) - -*** - -### value - -```ts -value: ObjectValue; -``` - -Defined in: [packages/form-core/src/util-types.ts:120](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L120) - -#### Overrides - -[`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md).[`value`](AnyDeepKeyAndValue.md#value) diff --git a/docs/reference/interfaces/OriginalFieldMeta.md b/docs/reference/interfaces/OriginalFieldMeta.md new file mode 100644 index 0000000000..a55a9db36f --- /dev/null +++ b/docs/reference/interfaces/OriginalFieldMeta.md @@ -0,0 +1,42 @@ +--- +id: OriginalFieldMeta +title: OriginalFieldMeta +--- + +Defined in: [FieldApi/FieldApi.public.ts:30](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L30) + +## Type Parameters + +### TFieldError + +`TFieldError` + +## Properties + +### errors + +```ts +errors: FieldErrors; +``` + +Defined in: [FieldApi/FieldApi.public.ts:31](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L31) + +*** + +### isInvalid + +```ts +isInvalid: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:33](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L33) + +*** + +### isValid + +```ts +isValid: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:32](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L32) diff --git a/docs/reference/interfaces/ParsedStandardSchemaIssues.md b/docs/reference/interfaces/ParsedStandardSchemaIssues.md new file mode 100644 index 0000000000..ec8238852c --- /dev/null +++ b/docs/reference/interfaces/ParsedStandardSchemaIssues.md @@ -0,0 +1,40 @@ +--- +id: ParsedStandardSchemaIssues +title: ParsedStandardSchemaIssues +--- + +Defined in: [validation.public.ts:637](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L637) + +Standard Schema issues reported at form or group scope and routed to field paths. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Properties + +### fields + +```ts +fields: Partial, StandardSchemaV1Issue[]>>; +``` + +Defined in: [validation.public.ts:641](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L641) + +Issues with paths, grouped by field path relative to the validator's value. + +*** + +### form + +```ts +form: StandardSchemaV1Issue[]; +``` + +Defined in: [validation.public.ts:639](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L639) + +All supplied issues, including those with field paths. diff --git a/docs/reference/interfaces/ReusableErrorVisibilityContext.md b/docs/reference/interfaces/ReusableErrorVisibilityContext.md new file mode 100644 index 0000000000..1248f5bf95 --- /dev/null +++ b/docs/reference/interfaces/ReusableErrorVisibilityContext.md @@ -0,0 +1,32 @@ +--- +id: ReusableErrorVisibilityContext +title: ReusableErrorVisibilityContext +--- + +Defined in: [validation.public.ts:359](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L359) + +State available to a visibility policy shared across different form shapes. + +## Properties + +### fieldState + +```ts +fieldState: ErrorVisibilityFieldState; +``` + +Defined in: [validation.public.ts:363](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L363) + +The field whose errors the policy controls. + +*** + +### state + +```ts +state: ReusableErrorVisibilityState; +``` + +Defined in: [validation.public.ts:361](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L361) + +Form state with group-scoped flags and counters for fields in a form group. diff --git a/docs/reference/interfaces/ServerFormValidatorContext.md b/docs/reference/interfaces/ServerFormValidatorContext.md new file mode 100644 index 0000000000..6e03683e9d --- /dev/null +++ b/docs/reference/interfaces/ServerFormValidatorContext.md @@ -0,0 +1,130 @@ +--- +id: ServerFormValidatorContext +title: ServerFormValidatorContext +--- + +Defined in: [validation.public.ts:735](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L735) + +Values and helpers passed to a server form validation function. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Properties + +### createErrorMap + +```ts +createErrorMap: (initial?) => ValidationErrorMap; +``` + +Defined in: [validation.public.ts:749](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L749) + +Creates an error map with field paths inferred from the form values. + +Creates a mutable map of form errors and errors for individual field paths. + +Pass the completed map back from a form or group validator to report the errors. + +#### Parameters + +##### initial? + +`Partial`\<[`ValidationErrorMap`](ValidationErrorMap.md)\<`TFormData`\>\> + +An existing map to reuse. A missing `fields` object is added to it. + +#### Returns + +[`ValidationErrorMap`](ValidationErrorMap.md)\<`TFormData`\> + +The initial map, if supplied, or a new map with an empty `fields` object. + +*** + +### createOutput + +```ts +createOutput: CreateOutputFn; +``` + +Defined in: [validation.public.ts:751](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L751) + +Creates a successful result to return data in this validator's server `validatorOutputs` entry. + +*** + +### event + +```ts +event: ValidationTrigger | "server"; +``` + +Defined in: [validation.public.ts:737](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L737) + +The validation event. `serverValidate` supplies `'server'`. + +*** + +### formApi + +```ts +formApi: FormApi | undefined; +``` + +Defined in: [validation.public.ts:741](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L741) + +`undefined` during server validation, where no client form instance exists. + +*** + +### parseIssues + +```ts +parseIssues: ParseFormIssuesFn; +``` + +Defined in: [validation.public.ts:747](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L747) + +Converts Standard Schema issues into form and field errors to return from this validator. + +*** + +### signal + +```ts +signal: AbortSignal; +``` + +Defined in: [validation.public.ts:739](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L739) + +Aborted when this run is cancelled. Pass it to asynchronous work such as `fetch`. + +*** + +### triggerFieldApi? + +```ts +optional triggerFieldApi?: AnyFieldApi; +``` + +Defined in: [validation.public.ts:743](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L743) + +Absent during server validation, which is not triggered by a client field. + +*** + +### value + +```ts +value: TFormData; +``` + +Defined in: [validation.public.ts:745](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L745) + +The complete form values passed to server validation. diff --git a/docs/reference/interfaces/ServerValidateFailure.md b/docs/reference/interfaces/ServerValidateFailure.md new file mode 100644 index 0000000000..565a98ffd8 --- /dev/null +++ b/docs/reference/interfaces/ServerValidateFailure.md @@ -0,0 +1,36 @@ +--- +id: ServerValidateFailure +title: ServerValidateFailure +--- + +Defined in: [ssr.public.ts:70](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L70) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](../type-aliases/FormValidators.md)\<`TFormData`\> + +## Properties + +### serverState + +```ts +serverState: ServerFormState; +``` + +Defined in: [ssr.public.ts:75](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L75) + +*** + +### success + +```ts +success: false; +``` + +Defined in: [ssr.public.ts:74](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L74) diff --git a/docs/reference/interfaces/ServerValidateFrameworkPlugin.md b/docs/reference/interfaces/ServerValidateFrameworkPlugin.md new file mode 100644 index 0000000000..6c6ad50d83 --- /dev/null +++ b/docs/reference/interfaces/ServerValidateFrameworkPlugin.md @@ -0,0 +1,32 @@ +--- +id: ServerValidateFrameworkPlugin +title: ServerValidateFrameworkPlugin +--- + +Defined in: [ssr.public.ts:94](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L94) + +## Type Parameters + +### TCreateServerValidate + +`TCreateServerValidate` *extends* `ServerValidateFrameworkCreateServerValidate` = `ServerValidateFrameworkCreateServerValidate` + +## Properties + +### createServerValidate + +```ts +createServerValidate: TCreateServerValidate; +``` + +Defined in: [ssr.public.ts:99](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L99) + +*** + +### id + +```ts +id: `react-form-${string}`; +``` + +Defined in: [ssr.public.ts:98](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L98) diff --git a/docs/reference/interfaces/ServerValidateSuccess.md b/docs/reference/interfaces/ServerValidateSuccess.md new file mode 100644 index 0000000000..b8387c26c7 --- /dev/null +++ b/docs/reference/interfaces/ServerValidateSuccess.md @@ -0,0 +1,50 @@ +--- +id: ServerValidateSuccess +title: ServerValidateSuccess +--- + +Defined in: [ssr.public.ts:56](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L56) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](../type-aliases/FormValidators.md)\<`TFormData`\> + +## Properties + +### success + +```ts +success: true; +``` + +Defined in: [ssr.public.ts:60](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L60) + +*** + +### validatorOutputs + +```ts +validatorOutputs: ToServerFormOutputs; +``` + +Defined in: [ssr.public.ts:67](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L67) + +Schema outputs and `createOutput` payloads from this server validation, +ordered by validator index. Validators without a server trigger or output +contribute `undefined`. These are separate from client submission outputs. + +*** + +### values + +```ts +values: TFormData; +``` + +Defined in: [ssr.public.ts:61](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L61) diff --git a/docs/reference/interfaces/StandardSchemaV1Issue.md b/docs/reference/interfaces/StandardSchemaV1Issue.md index e60fa2ae27..008bd31569 100644 --- a/docs/reference/interfaces/StandardSchemaV1Issue.md +++ b/docs/reference/interfaces/StandardSchemaV1Issue.md @@ -3,9 +3,7 @@ id: StandardSchemaV1Issue title: StandardSchemaV1Issue --- -# Interface: StandardSchemaV1Issue - -Defined in: [packages/form-core/src/standardSchemaValidator.ts:181](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchemaValidator.ts#L181) +Defined in: [standardSchema.public.ts:71](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchema.public.ts#L71) The issue interface of the failure output. @@ -17,7 +15,7 @@ The issue interface of the failure output. readonly message: string; ``` -Defined in: [packages/form-core/src/standardSchemaValidator.ts:185](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchemaValidator.ts#L185) +Defined in: [standardSchema.public.ts:75](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchema.public.ts#L75) The error message of the issue. @@ -26,9 +24,9 @@ The error message of the issue. ### path? ```ts -readonly optional path: readonly (PropertyKey | StandardSchemaV1PathSegment)[]; +readonly optional path?: readonly (PropertyKey | StandardSchemaV1PathSegment)[]; ``` -Defined in: [packages/form-core/src/standardSchemaValidator.ts:189](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchemaValidator.ts#L189) +Defined in: [standardSchema.public.ts:79](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchema.public.ts#L79) The path of the issue, if any. diff --git a/docs/reference/interfaces/SubfieldsMeta.md b/docs/reference/interfaces/SubfieldsMeta.md new file mode 100644 index 0000000000..a167ec81da --- /dev/null +++ b/docs/reference/interfaces/SubfieldsMeta.md @@ -0,0 +1,66 @@ +--- +id: SubfieldsMeta +title: SubfieldsMeta +--- + +Defined in: [FieldApi/FieldApi.public.ts:21](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L21) + +## Properties + +### isAnyInvalid + +```ts +isAnyInvalid: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:23](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L23) + +*** + +### isEveryPristine + +```ts +isEveryPristine: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:24](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L24) + +*** + +### isEveryValid + +```ts +isEveryValid: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:22](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L22) + +*** + +### isSomeDirty + +```ts +isSomeDirty: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:25](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L25) + +*** + +### isSomeTouched + +```ts +isSomeTouched: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:26](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L26) + +*** + +### isSomeValidating + +```ts +isSomeValidating: boolean; +``` + +Defined in: [FieldApi/FieldApi.public.ts:27](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L27) diff --git a/docs/reference/interfaces/TupleDeepKeyAndValue.md b/docs/reference/interfaces/TupleDeepKeyAndValue.md deleted file mode 100644 index db5ad2b828..0000000000 --- a/docs/reference/interfaces/TupleDeepKeyAndValue.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -id: TupleDeepKeyAndValue -title: TupleDeepKeyAndValue ---- - -# Interface: TupleDeepKeyAndValue\ - -Defined in: [packages/form-core/src/util-types.ts:73](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L73) - -## Extends - -- [`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md) - -## Type Parameters - -### TParent - -`TParent` *extends* [`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md) - -### T - -`T` - -### TKey - -`TKey` *extends* [`AllTupleKeys`](../type-aliases/AllTupleKeys.md)\<`T`\> - -## Properties - -### key - -```ts -key: `${TParent["key"] extends never ? "" : TParent["key"]}[${TKey}]`; -``` - -Defined in: [packages/form-core/src/util-types.ts:78](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L78) - -#### Overrides - -[`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md).[`key`](AnyDeepKeyAndValue.md#key) - -*** - -### value - -```ts -value: - | T[TKey] -| Nullable; -``` - -Defined in: [packages/form-core/src/util-types.ts:79](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L79) - -#### Overrides - -[`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md).[`value`](AnyDeepKeyAndValue.md#value) diff --git a/docs/reference/interfaces/UnknownDeepKeyAndValue.md b/docs/reference/interfaces/UnknownDeepKeyAndValue.md deleted file mode 100644 index 6662fdaba7..0000000000 --- a/docs/reference/interfaces/UnknownDeepKeyAndValue.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -id: UnknownDeepKeyAndValue -title: UnknownDeepKeyAndValue ---- - -# Interface: UnknownDeepKeyAndValue\ - -Defined in: [packages/form-core/src/util-types.ts:139](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L139) - -## Extends - -- [`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md) - -## Type Parameters - -### TParent - -`TParent` *extends* [`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md) - -## Properties - -### key - -```ts -key: UnknownAccessor; -``` - -Defined in: [packages/form-core/src/util-types.ts:142](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L142) - -#### Overrides - -[`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md).[`key`](AnyDeepKeyAndValue.md#key) - -*** - -### value - -```ts -value: unknown; -``` - -Defined in: [packages/form-core/src/util-types.ts:143](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L143) - -#### Overrides - -[`AnyDeepKeyAndValue`](AnyDeepKeyAndValue.md).[`value`](AnyDeepKeyAndValue.md#value) diff --git a/docs/reference/interfaces/ValidationErrorMap.md b/docs/reference/interfaces/ValidationErrorMap.md new file mode 100644 index 0000000000..199e9e9eff --- /dev/null +++ b/docs/reference/interfaces/ValidationErrorMap.md @@ -0,0 +1,40 @@ +--- +id: ValidationErrorMap +title: ValidationErrorMap +--- + +Defined in: [validation.public.ts:595](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L595) + +Errors owned by a form or group and errors routed to its fields. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Properties + +### fields + +```ts +fields: Partial, ValidationErrorInput>>; +``` + +Defined in: [validation.public.ts:599](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L599) + +Errors keyed by field path. Paths are relative to the group for group validators. + +*** + +### form? + +```ts +optional form?: ValidationErrorInput; +``` + +Defined in: [validation.public.ts:597](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L597) + +Errors for the form or group that owns the validator. diff --git a/docs/reference/interfaces/ValidationIssue.md b/docs/reference/interfaces/ValidationIssue.md new file mode 100644 index 0000000000..db1cfbbb2d --- /dev/null +++ b/docs/reference/interfaces/ValidationIssue.md @@ -0,0 +1,20 @@ +--- +id: ValidationIssue +title: ValidationIssue +--- + +Defined in: [validation.public.ts:579](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L579) + +A validation error with a display message. + +## Properties + +### message + +```ts +message: string; +``` + +Defined in: [validation.public.ts:581](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L581) + +The text to display for this error. diff --git a/docs/reference/interfaces/ValidationLogicProps.md b/docs/reference/interfaces/ValidationLogicProps.md deleted file mode 100644 index f68040bc2d..0000000000 --- a/docs/reference/interfaces/ValidationLogicProps.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -id: ValidationLogicProps -title: ValidationLogicProps ---- - -# Interface: ValidationLogicProps - -Defined in: [packages/form-core/src/ValidationLogic.ts:21](https://github.com/TanStack/form/blob/main/packages/form-core/src/ValidationLogic.ts#L21) - -## Properties - -### event - -```ts -event: object; -``` - -Defined in: [packages/form-core/src/ValidationLogic.ts:35](https://github.com/TanStack/form/blob/main/packages/form-core/src/ValidationLogic.ts#L35) - -#### async - -```ts -async: boolean; -``` - -#### fieldName? - -```ts -optional fieldName: string; -``` - -#### type - -```ts -type: "change" | "blur" | "submit" | "mount" | "server"; -``` - -*** - -### form - -```ts -form: AnyFormApi; -``` - -Defined in: [packages/form-core/src/ValidationLogic.ts:23](https://github.com/TanStack/form/blob/main/packages/form-core/src/ValidationLogic.ts#L23) - -*** - -### group? - -```ts -optional group: AnyFormGroupApi; -``` - -Defined in: [packages/form-core/src/ValidationLogic.ts:29](https://github.com/TanStack/form/blob/main/packages/form-core/src/ValidationLogic.ts#L29) - -Set when the validators being processed belong to a `FormGroupApi`. -Allows validation strategies (e.g. `revalidateLogic`) to gate their -behavior on the group's own state instead of the parent form's. - -*** - -### runValidation() - -```ts -runValidation: (props) => void; -``` - -Defined in: [packages/form-core/src/ValidationLogic.ts:40](https://github.com/TanStack/form/blob/main/packages/form-core/src/ValidationLogic.ts#L40) - -#### Parameters - -##### props - -###### form - -[`AnyFormApi`](../type-aliases/AnyFormApi.md) - -###### validators - -( - \| [`ValidationLogicValidatorsFn`](ValidationLogicValidatorsFn.md) - \| `undefined`)[] - -#### Returns - -`void` - -*** - -### validators - -```ts -validators: - | FormValidators - | null - | undefined; -``` - -Defined in: [packages/form-core/src/ValidationLogic.ts:31](https://github.com/TanStack/form/blob/main/packages/form-core/src/ValidationLogic.ts#L31) diff --git a/docs/reference/interfaces/ValidationLogicValidatorsFn.md b/docs/reference/interfaces/ValidationLogicValidatorsFn.md deleted file mode 100644 index ee71cbca90..0000000000 --- a/docs/reference/interfaces/ValidationLogicValidatorsFn.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -id: ValidationLogicValidatorsFn -title: ValidationLogicValidatorsFn ---- - -# Interface: ValidationLogicValidatorsFn - -Defined in: [packages/form-core/src/ValidationLogic.ts:4](https://github.com/TanStack/form/blob/main/packages/form-core/src/ValidationLogic.ts#L4) - -## Properties - -### cause - -```ts -cause: "change" | "blur" | "submit" | "mount" | "server" | "dynamic"; -``` - -Defined in: [packages/form-core/src/ValidationLogic.ts:18](https://github.com/TanStack/form/blob/main/packages/form-core/src/ValidationLogic.ts#L18) - -*** - -### fn - -```ts -fn: any; -``` - -Defined in: [packages/form-core/src/ValidationLogic.ts:6](https://github.com/TanStack/form/blob/main/packages/form-core/src/ValidationLogic.ts#L6) diff --git a/docs/reference/interfaces/ValidationOutput.md b/docs/reference/interfaces/ValidationOutput.md new file mode 100644 index 0000000000..fd0641b6d2 --- /dev/null +++ b/docs/reference/interfaces/ValidationOutput.md @@ -0,0 +1,29 @@ +--- +id: ValidationOutput +title: ValidationOutput +--- + +Defined in: [validation.public.ts:671](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L671) + +A successful validation result that carries data for `validatorOutputs`. + +Return the result of the validator context's `createOutput` helper to provide +data during submission or server validation. + +## Type Parameters + +### TOutput + +`TOutput` + +Library-managed. Do not specify explicitly. + +## Properties + +### \[VALIDATION\_OUTPUT\] + +```ts +readonly [VALIDATION_OUTPUT]: TOutput; +``` + +Defined in: [validation.public.ts:672](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L672) diff --git a/docs/reference/interfaces/ValidationTriggerConfig.md b/docs/reference/interfaces/ValidationTriggerConfig.md new file mode 100644 index 0000000000..09cbfb2268 --- /dev/null +++ b/docs/reference/interfaces/ValidationTriggerConfig.md @@ -0,0 +1,69 @@ +--- +id: ValidationTriggerConfig +title: ValidationTriggerConfig +--- + +Defined in: [validation.public.ts:506](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L506) + +A change or blur event with an optional condition for running validation. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValue + +`TValue` + +Library-managed. Do not specify explicitly. + +### TTrigger + +`TTrigger` *extends* [`ValidatorTrigger`](../type-aliases/ValidatorTrigger.md) = [`ValidatorTrigger`](../type-aliases/ValidatorTrigger.md) + +Library-managed. Do not specify explicitly. + +### TScope + +`TScope` *extends* [`ValidatorScope`](../type-aliases/ValidatorScope.md) = [`ValidatorScope`](../type-aliases/ValidatorScope.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### trigger + +```ts +trigger: TTrigger; +``` + +Defined in: [validation.public.ts:513](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L513) + +The event to match before evaluating `when`. + +*** + +### when? + +```ts +optional when?: + | boolean +| ValidationPredicateFn; +``` + +Defined in: [validation.public.ts:522](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L522) + +Whether this trigger enables validation when its event occurs. + +Pass a boolean to enable or disable it, or pass a function that returns +`true` to enable it for the current event. + +#### Default + +```ts +true +``` diff --git a/docs/reference/interfaces/Validator.md b/docs/reference/interfaces/Validator.md new file mode 100644 index 0000000000..a177309b10 --- /dev/null +++ b/docs/reference/interfaces/Validator.md @@ -0,0 +1,172 @@ +--- +id: Validator +title: Validator +--- + +Defined in: [validation.public.ts:41](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L41) + +Configures validation for a form, form group, or field. + +## Extends + +- [`BaseValidator`](BaseValidator.md)\<`TValidator`\> + +## Extended by + +- [`FormGroupValidator`](FormGroupValidator.md) +- [`FieldValidator`](FieldValidator.md) + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValidator + +`TValidator` *extends* + \| [`StandardSchemaV1`](../type-aliases/StandardSchemaV1.md) + \| [`ValidatorFn`](../type-aliases/ValidatorFn.md)\<`any`, `any`\> + +Library-managed. Do not specify explicitly. + +### TContextValue + +`TContextValue` + +Library-managed. Do not specify explicitly. + +### TTrigger + +`TTrigger` *extends* [`ValidatorTrigger`](../type-aliases/ValidatorTrigger.md) = [`ValidatorTrigger`](../type-aliases/ValidatorTrigger.md) + +Library-managed. Do not specify explicitly. + +### TScope + +`TScope` *extends* [`ValidatorScope`](../type-aliases/ValidatorScope.md) = [`ValidatorScope`](../type-aliases/ValidatorScope.md) + +Library-managed. Do not specify explicitly. + +## Properties + +### bailIfInvalid? + +```ts +optional bailIfInvalid?: boolean; +``` + +Defined in: [validation.public.ts:29](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L29) + +If `true`, skips this and subsequent validators when earlier validation has failed. + +If `false`, earlier failures do not prevent this validator from running. + +#### Default + +```ts +false +``` + +#### Inherited from + +[`BaseValidator`](BaseValidator.md).[`bailIfInvalid`](BaseValidator.md#bailifinvalid) + +*** + +### run + +```ts +run: TValidator; +``` + +Defined in: [validation.public.ts:21](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L21) + +The function or Standard Schema that validates the value in this validator's scope. + +#### Inherited from + +[`BaseValidator`](BaseValidator.md).[`run`](BaseValidator.md#run) + +*** + +### runOnMount? + +```ts +optional runOnMount?: boolean; +``` + +Defined in: [validation.public.ts:64](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L64) + +Whether this validator runs when the form is constructed or when its field +or form group first mounts. + +#### Default + +```ts +false +``` + +*** + +### skipOnSubmit? + +```ts +optional skipOnSubmit?: + | boolean +| ValidationPredicateFn; +``` + +Defined in: [validation.public.ts:56](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L56) + +Whether this validator runs during a submission attempt, independently of `triggers`. + +Pass a boolean directly, or pass a function that returns +`true` to skip it for the current attempt. + +#### Default + +```ts +false +``` + +*** + +### triggerDebounceMs? + +```ts +optional triggerDebounceMs?: + | number +| ValidationDebounceFn; +``` + +Defined in: [validation.public.ts:74](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L74) + +The delay in milliseconds before validation runs for change or blur events. + +Pass a number for a fixed delay, or pass a function that returns the delay +for the current event. Repeated events restart the delay. +Submission validation runs immediately. + +#### Default + +```ts +0 +``` + +*** + +### triggers + +```ts +triggers: ValidationTriggerOption[]; +``` + +Defined in: [validation.public.ts:82](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L82) + +Change and blur events that can run this validator, optionally with conditions. + +An empty array disables change and blur validation. Configure submission +separately with `skipOnSubmit` and initial validation with `runOnMount`. diff --git a/docs/reference/type-aliases/AllObjectKeys.md b/docs/reference/type-aliases/AllObjectKeys.md deleted file mode 100644 index ef9f94bc15..0000000000 --- a/docs/reference/type-aliases/AllObjectKeys.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: AllObjectKeys -title: AllObjectKeys ---- - -# Type Alias: AllObjectKeys\ - -```ts -type AllObjectKeys = T extends any ? keyof T & string | number : never; -``` - -Defined in: [packages/form-core/src/util-types.ts:97](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L97) - -## Type Parameters - -### T - -`T` diff --git a/docs/reference/type-aliases/AllTupleKeys.md b/docs/reference/type-aliases/AllTupleKeys.md deleted file mode 100644 index 6ec5c90bd2..0000000000 --- a/docs/reference/type-aliases/AllTupleKeys.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: AllTupleKeys -title: AllTupleKeys ---- - -# Type Alias: AllTupleKeys\ - -```ts -type AllTupleKeys = T extends any ? keyof T & `${number}` : never; -``` - -Defined in: [packages/form-core/src/util-types.ts:82](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L82) - -## Type Parameters - -### T - -`T` diff --git a/docs/reference/type-aliases/AnyBaseFormState.md b/docs/reference/type-aliases/AnyBaseFormState.md deleted file mode 100644 index 1e12635e0a..0000000000 --- a/docs/reference/type-aliases/AnyBaseFormState.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: AnyBaseFormState -title: AnyBaseFormState ---- - -# Type Alias: AnyBaseFormState - -```ts -type AnyBaseFormState = BaseFormState; -``` - -Defined in: [packages/form-core/src/FormApi.ts:699](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L699) diff --git a/docs/reference/type-aliases/AnyFieldApi.md b/docs/reference/type-aliases/AnyFieldApi.md index c315f76c80..bc03b9528d 100644 --- a/docs/reference/type-aliases/AnyFieldApi.md +++ b/docs/reference/type-aliases/AnyFieldApi.md @@ -3,12 +3,25 @@ id: AnyFieldApi title: AnyFieldApi --- -# Type Alias: AnyFieldApi - ```ts -type AnyFieldApi = FieldApi; +type AnyFieldApi = FieldApi; ``` -Defined in: [packages/form-core/src/FieldApi.ts:480](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L480) +Defined in: [FieldApi/FieldApi.public.ts:74](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L74) + +A field API whose field name, value, error, and owning form types are erased. + +Use it for reusable helpers that only need members shared by every field, +such as a generic error display. Because value and update types are erased, +prefer `FieldWithValue` when a helper reads or changes a field +value. + +## Example -A type representing the Field API with all generics set to `any` for convenience. +```ts +function getFieldErrorText(field: AnyFieldApi) { + if (field.meta.isValid) return '' + + return field.errors.map((error) => error.message).join(', ') +} +``` diff --git a/docs/reference/type-aliases/AnyFieldGroupApi.md b/docs/reference/type-aliases/AnyFieldGroupApi.md deleted file mode 100644 index 4db6a26cf7..0000000000 --- a/docs/reference/type-aliases/AnyFieldGroupApi.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: AnyFieldGroupApi -title: AnyFieldGroupApi ---- - -# Type Alias: AnyFieldGroupApi - -```ts -type AnyFieldGroupApi = FieldGroupApi; -``` - -Defined in: [packages/form-core/src/FieldGroupApi.ts:24](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroupApi.ts#L24) diff --git a/docs/reference/type-aliases/AnyFieldGroupFieldSlot.md b/docs/reference/type-aliases/AnyFieldGroupFieldSlot.md new file mode 100644 index 0000000000..087d9f37cb --- /dev/null +++ b/docs/reference/type-aliases/AnyFieldGroupFieldSlot.md @@ -0,0 +1,12 @@ +--- +id: AnyFieldGroupFieldSlot +title: AnyFieldGroupFieldSlot +--- + +```ts +type AnyFieldGroupFieldSlot = FieldGroupFieldSlot; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:38](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L38) + +A field-group slot with its value type and matching mode erased. diff --git a/docs/reference/type-aliases/AnyFieldListener.md b/docs/reference/type-aliases/AnyFieldListener.md new file mode 100644 index 0000000000..9f738f841c --- /dev/null +++ b/docs/reference/type-aliases/AnyFieldListener.md @@ -0,0 +1,12 @@ +--- +id: AnyFieldListener +title: AnyFieldListener +--- + +```ts +type AnyFieldListener = FieldListener; +``` + +Defined in: [listeners.public.ts:404](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L404) + +A field listener with type-erased field and form types. diff --git a/docs/reference/type-aliases/AnyFieldMeta.md b/docs/reference/type-aliases/AnyFieldMeta.md index d10ebc7965..b3df64e5ca 100644 --- a/docs/reference/type-aliases/AnyFieldMeta.md +++ b/docs/reference/type-aliases/AnyFieldMeta.md @@ -3,10 +3,8 @@ id: AnyFieldMeta title: AnyFieldMeta --- -# Type Alias: AnyFieldMeta - ```ts -type AnyFieldMeta = AnyFieldLikeMeta; +type AnyFieldMeta = FieldMeta; ``` -Defined in: [packages/form-core/src/types.ts:834](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L834) +Defined in: [FieldApi/FieldApi.public.ts:36](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi/FieldApi.public.ts#L36) diff --git a/docs/reference/type-aliases/AnyFormApi.md b/docs/reference/type-aliases/AnyFormApi.md index 06242e3b43..94c5c227f8 100644 --- a/docs/reference/type-aliases/AnyFormApi.md +++ b/docs/reference/type-aliases/AnyFormApi.md @@ -3,12 +3,14 @@ id: AnyFormApi title: AnyFormApi --- -# Type Alias: AnyFormApi - ```ts -type AnyFormApi = FormApi; +type AnyFormApi = FormApi; ``` -Defined in: [packages/form-core/src/FormApi.ts:915](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L915) +Defined in: [FormApi/FormApi.public.ts:543](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L543) + +A core form API whose value and error types are erased. -A type representing the Form API with all generics set to `any` for convenience. +Use it for reusable helpers that only need operations shared by every form. +Field paths and values are not type-checked through this alias, and it does +not include component helpers added by a framework adapter. diff --git a/docs/reference/type-aliases/AnyFormGroupApi.md b/docs/reference/type-aliases/AnyFormGroupApi.md deleted file mode 100644 index c9e2e59009..0000000000 --- a/docs/reference/type-aliases/AnyFormGroupApi.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -id: AnyFormGroupApi -title: AnyFormGroupApi ---- - -# Type Alias: AnyFormGroupApi - -```ts -type AnyFormGroupApi = FormGroupApi; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:708](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L708) - -A type representing the FormGroup API with all generics set to `any` for convenience. diff --git a/docs/reference/type-aliases/AnyFormGroupMeta.md b/docs/reference/type-aliases/AnyFormGroupMeta.md deleted file mode 100644 index c1b0c5e550..0000000000 --- a/docs/reference/type-aliases/AnyFormGroupMeta.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -id: AnyFormGroupMeta -title: AnyFormGroupMeta ---- - -# Type Alias: AnyFormGroupMeta - -```ts -type AnyFormGroupMeta = FormGroupMeta; -``` - -Defined in: [packages/form-core/src/FormGroupApi.ts:835](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi.ts#L835) - -`FormGroupMeta` with all generics widened to `any`. diff --git a/docs/reference/type-aliases/AnyFormListener.md b/docs/reference/type-aliases/AnyFormListener.md new file mode 100644 index 0000000000..416c8037e3 --- /dev/null +++ b/docs/reference/type-aliases/AnyFormListener.md @@ -0,0 +1,12 @@ +--- +id: AnyFormListener +title: AnyFormListener +--- + +```ts +type AnyFormListener = FormListener; +``` + +Defined in: [listeners.public.ts:244](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L244) + +A form listener with type-erased form data and error types. diff --git a/docs/reference/type-aliases/AnyFormOptions.md b/docs/reference/type-aliases/AnyFormOptions.md index 63609327b7..94f48a35e4 100644 --- a/docs/reference/type-aliases/AnyFormOptions.md +++ b/docs/reference/type-aliases/AnyFormOptions.md @@ -3,10 +3,13 @@ id: AnyFormOptions title: AnyFormOptions --- -# Type Alias: AnyFormOptions - ```ts -type AnyFormOptions = FormOptions; +type AnyFormOptions = FormOptions; ``` -Defined in: [packages/form-core/src/FormApi.ts:585](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L585) +Defined in: [FormApi/FormApi.public.ts:236](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L236) + +Form options whose data, validator, and submission return types are erased. + +Use this alias only when reusable code does not need type-safe access to +values, validators, or submission results. diff --git a/docs/reference/type-aliases/AnyFormState.md b/docs/reference/type-aliases/AnyFormState.md deleted file mode 100644 index 1c519fb612..0000000000 --- a/docs/reference/type-aliases/AnyFormState.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: AnyFormState -title: AnyFormState ---- - -# Type Alias: AnyFormState - -```ts -type AnyFormState = FormState; -``` - -Defined in: [packages/form-core/src/FormApi.ts:834](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L834) diff --git a/docs/reference/type-aliases/ArrayAccessor.md b/docs/reference/type-aliases/ArrayAccessor.md deleted file mode 100644 index 7d545c659a..0000000000 --- a/docs/reference/type-aliases/ArrayAccessor.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: ArrayAccessor -title: ArrayAccessor ---- - -# Type Alias: ArrayAccessor\ - -```ts -type ArrayAccessor = `${TParent["key"] extends never ? "" : TParent["key"]}[${number}]`; -``` - -Defined in: [packages/form-core/src/util-types.ts:47](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L47) - -## Type Parameters - -### TParent - -`TParent` *extends* [`AnyDeepKeyAndValue`](../interfaces/AnyDeepKeyAndValue.md) diff --git a/docs/reference/type-aliases/ArrayFieldElement.md b/docs/reference/type-aliases/ArrayFieldElement.md new file mode 100644 index 0000000000..306f242f99 --- /dev/null +++ b/docs/reference/type-aliases/ArrayFieldElement.md @@ -0,0 +1,26 @@ +--- +id: ArrayFieldElement +title: ArrayFieldElement +--- + +```ts +type ArrayFieldElement = TryGetArrayElementType>; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:41](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L41) + +Element type extracted from the array member of an array field's value. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFieldName + +`TFieldName` *extends* [`ArrayFieldName`](ArrayFieldName.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/ArrayFieldName.md b/docs/reference/type-aliases/ArrayFieldName.md new file mode 100644 index 0000000000..121ddf0274 --- /dev/null +++ b/docs/reference/type-aliases/ArrayFieldName.md @@ -0,0 +1,23 @@ +--- +id: ArrayFieldName +title: ArrayFieldName +--- + +```ts +type ArrayFieldName = DeepKeysWhereValueIncludes>; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:16](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L16) + +Field paths whose value type includes a mutable or readonly array. + +A path is included when at least one member of a union is an array, including +when the value can also be `null` or `undefined`. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/ArrayFieldPredicate.md b/docs/reference/type-aliases/ArrayFieldPredicate.md new file mode 100644 index 0000000000..372a320259 --- /dev/null +++ b/docs/reference/type-aliases/ArrayFieldPredicate.md @@ -0,0 +1,61 @@ +--- +id: ArrayFieldPredicate +title: ArrayFieldPredicate +--- + +```ts +type ArrayFieldPredicate = (value, index, array) => boolean; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:65](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L65) + +Selects which elements `filterFieldValues` keeps. + +Return `true` to keep an element or `false` to remove it. The callback +receives the element's original index and the array before filtering. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFieldName + +`TFieldName` *extends* [`ArrayFieldName`](ArrayFieldName.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### value + +[`ArrayFieldElement`](ArrayFieldElement.md)\<`TFormData`, `TFieldName`\> + +The current element. + +### index + +`number` + +The element's index in the original array. + +### array + +[`ArrayFieldValue`](ArrayFieldValue.md)\<`TFormData`, `TFieldName`\> + +The array being filtered. + +## Returns + +`boolean` + +## Example + +```ts +// items: [1, 2, 3, 4] +formApi.filterFieldValues('items', (item) => item % 2 === 0) +// items: [2, 4] +``` diff --git a/docs/reference/type-aliases/ArrayFieldValue.md b/docs/reference/type-aliases/ArrayFieldValue.md new file mode 100644 index 0000000000..86c278871e --- /dev/null +++ b/docs/reference/type-aliases/ArrayFieldValue.md @@ -0,0 +1,29 @@ +--- +id: ArrayFieldValue +title: ArrayFieldValue +--- + +```ts +type ArrayFieldValue = DeepValue; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:30](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L30) + +Complete value type at an array field path. + +This preserves any nullish or non-array members that share the field's value +union. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFieldName + +`TFieldName` *extends* [`ArrayFieldName`](ArrayFieldName.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/BaseFormState.md b/docs/reference/type-aliases/BaseFormState.md deleted file mode 100644 index 58b9f58436..0000000000 --- a/docs/reference/type-aliases/BaseFormState.md +++ /dev/null @@ -1,211 +0,0 @@ ---- -id: BaseFormState -title: BaseFormState ---- - -# Type Alias: BaseFormState\ - -```ts -type BaseFormState = object; -``` - -Defined in: [packages/form-core/src/FormApi.ts:613](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L613) - -An object representing the current state of the form. - -## Extended by - -- [`FormState`](../interfaces/FormState.md) - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -## Properties - -### \_force\_re\_eval? - -```ts -optional _force_re_eval: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:696](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L696) - -@private, used to force a re-evaluation of the form state when options change - -*** - -### errorMap - -```ts -errorMap: ValidationErrorMap, UnwrapFormValidateOrFn, UnwrapFormAsyncValidateOrFn, UnwrapFormValidateOrFn, UnwrapFormAsyncValidateOrFn, UnwrapFormValidateOrFn, UnwrapFormAsyncValidateOrFn, UnwrapFormValidateOrFn, UnwrapFormAsyncValidateOrFn, UnwrapFormAsyncValidateOrFn>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:633](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L633) - -The error map for the form itself. - -*** - -### fieldMetaBase - -```ts -fieldMetaBase: Partial, AnyFieldLikeMetaBase>>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:652](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L652) - -A record of field metadata for each field in the form, not including the derived properties, like `errors` and such - -*** - -### formGroupStateBase - -```ts -formGroupStateBase: Partial>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:659](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L659) - -A record of submission lifecycle state for each mounted `FormGroupApi`, -keyed by the group's fully-qualified field name. Stored on the form so -group-level state can be read from `FormApi` without having to walk the -mounted group instances. - -*** - -### isSubmitSuccessful - -```ts -isSubmitSuccessful: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:692](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L692) - -A boolean indicating if the last submission was successful. - -*** - -### isSubmitted - -```ts -isSubmitted: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:680](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L680) - -A boolean indicating if the `onSubmit` function has completed successfully. - -Goes back to `false` at each new submission attempt. - -Note: you can use isSubmitting to check if the form is currently submitting. - -*** - -### isSubmitting - -```ts -isSubmitting: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:672](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L672) - -A boolean indicating if the form is currently in the process of being submitted after `handleSubmit` is called. - -Goes back to `false` when submission completes for one of the following reasons: -- the validation step returned errors. -- the `onSubmit` function has completed. - -Note: if you're running async operations in your `onSubmit` function make sure to await them to ensure `isSubmitting` is set to `false` only when the async operation completes. - -This is useful for displaying loading indicators or disabling form inputs during submission. - -*** - -### isValidating - -```ts -isValidating: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:684](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L684) - -A boolean indicating if the form or any of its fields are currently validating. - -*** - -### submissionAttempts - -```ts -submissionAttempts: number; -``` - -Defined in: [packages/form-core/src/FormApi.ts:688](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L688) - -A counter for tracking the number of submission attempts. - -*** - -### validationMetaMap - -```ts -validationMetaMap: Record; -``` - -Defined in: [packages/form-core/src/FormApi.ts:648](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L648) - -An internal mechanism used for keeping track of validation logic in a form. - -*** - -### values - -```ts -values: TFormData; -``` - -Defined in: [packages/form-core/src/FormApi.ts:629](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L629) - -The current values of the form fields. diff --git a/docs/reference/type-aliases/BroadcastFormApi.md b/docs/reference/type-aliases/BroadcastFormApi.md deleted file mode 100644 index 71a128aa60..0000000000 --- a/docs/reference/type-aliases/BroadcastFormApi.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -id: BroadcastFormApi -title: BroadcastFormApi ---- - -# Type Alias: BroadcastFormApi - -```ts -type BroadcastFormApi = object; -``` - -Defined in: [packages/form-core/src/EventClient.ts:14](https://github.com/TanStack/form/blob/main/packages/form-core/src/EventClient.ts#L14) - -## Properties - -### id - -```ts -id: string; -``` - -Defined in: [packages/form-core/src/EventClient.ts:15](https://github.com/TanStack/form/blob/main/packages/form-core/src/EventClient.ts#L15) - -*** - -### options - -```ts -options: AnyFormOptions; -``` - -Defined in: [packages/form-core/src/EventClient.ts:17](https://github.com/TanStack/form/blob/main/packages/form-core/src/EventClient.ts#L17) - -*** - -### state - -```ts -state: AnyFormState; -``` - -Defined in: [packages/form-core/src/EventClient.ts:16](https://github.com/TanStack/form/blob/main/packages/form-core/src/EventClient.ts#L16) diff --git a/docs/reference/type-aliases/BroadcastFormId.md b/docs/reference/type-aliases/BroadcastFormId.md deleted file mode 100644 index 71c58229ae..0000000000 --- a/docs/reference/type-aliases/BroadcastFormId.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -id: BroadcastFormId -title: BroadcastFormId ---- - -# Type Alias: BroadcastFormId - -```ts -type BroadcastFormId = object; -``` - -Defined in: [packages/form-core/src/EventClient.ts:41](https://github.com/TanStack/form/blob/main/packages/form-core/src/EventClient.ts#L41) - -## Properties - -### id - -```ts -id: string; -``` - -Defined in: [packages/form-core/src/EventClient.ts:42](https://github.com/TanStack/form/blob/main/packages/form-core/src/EventClient.ts#L42) diff --git a/docs/reference/type-aliases/BroadcastFormState.md b/docs/reference/type-aliases/BroadcastFormState.md deleted file mode 100644 index 6b7fca8365..0000000000 --- a/docs/reference/type-aliases/BroadcastFormState.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -id: BroadcastFormState -title: BroadcastFormState ---- - -# Type Alias: BroadcastFormState - -```ts -type BroadcastFormState = object; -``` - -Defined in: [packages/form-core/src/EventClient.ts:9](https://github.com/TanStack/form/blob/main/packages/form-core/src/EventClient.ts#L9) - -## Properties - -### id - -```ts -id: string; -``` - -Defined in: [packages/form-core/src/EventClient.ts:10](https://github.com/TanStack/form/blob/main/packages/form-core/src/EventClient.ts#L10) - -*** - -### state - -```ts -state: AnyFormState; -``` - -Defined in: [packages/form-core/src/EventClient.ts:11](https://github.com/TanStack/form/blob/main/packages/form-core/src/EventClient.ts#L11) diff --git a/docs/reference/type-aliases/BroadcastFormSubmissionState.md b/docs/reference/type-aliases/BroadcastFormSubmissionState.md deleted file mode 100644 index b78fef2647..0000000000 --- a/docs/reference/type-aliases/BroadcastFormSubmissionState.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -id: BroadcastFormSubmissionState -title: BroadcastFormSubmissionState ---- - -# Type Alias: BroadcastFormSubmissionState - -```ts -type BroadcastFormSubmissionState = - | { - errors: any[]; - id: string; - stage: "validateAllFields" | "validate"; - submissionAttempt: number; - successful: false; -} - | { - id: string; - onError: unknown; - stage: "inflight"; - submissionAttempt: number; - successful: false; -} - | { - id: string; - submissionAttempt: number; - successful: true; -}; -``` - -Defined in: [packages/form-core/src/EventClient.ts:20](https://github.com/TanStack/form/blob/main/packages/form-core/src/EventClient.ts#L20) diff --git a/docs/reference/type-aliases/BuiltInType.md b/docs/reference/type-aliases/BuiltInType.md new file mode 100644 index 0000000000..99afd7c71d --- /dev/null +++ b/docs/reference/type-aliases/BuiltInType.md @@ -0,0 +1,10 @@ +--- +id: BuiltInType +title: BuiltInType +--- + +```ts +type BuiltInType = Primitive | Date | RegExp | Function; +``` + +Defined in: [utils.public.ts:7](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.public.ts#L7) diff --git a/docs/reference/type-aliases/ClearFieldValuesFn.md b/docs/reference/type-aliases/ClearFieldValuesFn.md new file mode 100644 index 0000000000..e8dcf56c9b --- /dev/null +++ b/docs/reference/type-aliases/ClearFieldValuesFn.md @@ -0,0 +1,58 @@ +--- +id: ClearFieldValuesFn +title: ClearFieldValuesFn +--- + +```ts +type ClearFieldValuesFn = (arrayFieldName, options?) => void; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:218](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L218) + +Removes every element from an array field. + +A runtime value that is not an array produces a warning and is left +unchanged. By default, the update marks the array field as touched and +dirty, notifies change listeners, and runs change validation. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* [`ArrayFieldName`](ArrayFieldName.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### arrayFieldName + +`TFieldName` + +The array field path. + +### options? + +[`FieldUpdateOptions`](../interfaces/FieldUpdateOptions.md) + +Controls metadata updates and whether validation runs. + +## Returns + +`void` + +## Example + +```ts +// items: ['first', 'second'] +formApi.clearFieldValues('items') +// items: [] +``` diff --git a/docs/reference/type-aliases/ClientValidationTrigger.md b/docs/reference/type-aliases/ClientValidationTrigger.md new file mode 100644 index 0000000000..4c598d91eb --- /dev/null +++ b/docs/reference/type-aliases/ClientValidationTrigger.md @@ -0,0 +1,12 @@ +--- +id: ClientValidationTrigger +title: ClientValidationTrigger +--- + +```ts +type ClientValidationTrigger = ValidationTrigger; +``` + +Defined in: [validation.public.ts:257](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L257) + +Events reported to client-side validation callbacks. diff --git a/docs/reference/type-aliases/ClientValidationTriggerOption.md b/docs/reference/type-aliases/ClientValidationTriggerOption.md new file mode 100644 index 0000000000..c211dc99cb --- /dev/null +++ b/docs/reference/type-aliases/ClientValidationTriggerOption.md @@ -0,0 +1,32 @@ +--- +id: ClientValidationTriggerOption +title: ClientValidationTriggerOption +--- + +```ts +type ClientValidationTriggerOption = ValidationTriggerOption; +``` + +Defined in: [validation.public.ts:547](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L547) + +A change or blur trigger, optionally enabled by a condition. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValue + +`TValue` + +Library-managed. Do not specify explicitly. + +### TScope + +`TScope` *extends* [`ValidatorScope`](ValidatorScope.md) = [`ValidatorScope`](ValidatorScope.md) + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/ConfigurableValidationTrigger.md b/docs/reference/type-aliases/ConfigurableValidationTrigger.md new file mode 100644 index 0000000000..425304759d --- /dev/null +++ b/docs/reference/type-aliases/ConfigurableValidationTrigger.md @@ -0,0 +1,12 @@ +--- +id: ConfigurableValidationTrigger +title: ConfigurableValidationTrigger +--- + +```ts +type ConfigurableValidationTrigger = Exclude; +``` + +Defined in: [validation.public.ts:259](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L259) + +Events configured through `triggers`. Submission is controlled by `skipOnSubmit`. diff --git a/docs/reference/type-aliases/CreateErrorMapFn.md b/docs/reference/type-aliases/CreateErrorMapFn.md new file mode 100644 index 0000000000..f48306f1be --- /dev/null +++ b/docs/reference/type-aliases/CreateErrorMapFn.md @@ -0,0 +1,20 @@ +--- +id: CreateErrorMapFn +title: CreateErrorMapFn +--- + +```ts +type CreateErrorMapFn = typeof createErrorMap; +``` + +Defined in: [validation.public.ts:629](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L629) + +Creates a mutable error map with field paths inferred from the validator's value shape. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/CreateOutputFn.md b/docs/reference/type-aliases/CreateOutputFn.md new file mode 100644 index 0000000000..b4fecbc78d --- /dev/null +++ b/docs/reference/type-aliases/CreateOutputFn.md @@ -0,0 +1,55 @@ +--- +id: CreateOutputFn +title: CreateOutputFn +--- + +```ts +type CreateOutputFn = (value) => ValidationOutput; +``` + +Defined in: [validation.public.ts:702](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L702) + +Creates a successful validation result with data for `validatorOutputs`. + +Return this result from a form or group validator. The payload appears at that +validator's index during submission or server validation and is forwarded +without mutation. Outputs from change, blur, and mount validation are **not** +retained for later submission. + +## Type Parameters + +### TOutput + +`TOutput` + +Library-managed. Do not specify explicitly. + +## Parameters + +### value + +`TOutput` + +The payload to expose at this validator's index. + +## Returns + +[`ValidationOutput`](../interfaces/ValidationOutput.md)\<`TOutput`\> + +A successful validator result containing the original payload. + +## Example + +```ts +formOptions({ + defaultValues: { name: '' }, + validators: [{ + triggers: [], + run: ({ value, createOutput }) => createOutput(value.name.trim()), + }], + onSubmit: ({ validatorOutputs }) => { + const trimmedName = validatorOutputs[0] + // ... + }, +}) +``` diff --git a/docs/reference/type-aliases/CreateSubmitErrorMapFn.md b/docs/reference/type-aliases/CreateSubmitErrorMapFn.md new file mode 100644 index 0000000000..8120cbefcf --- /dev/null +++ b/docs/reference/type-aliases/CreateSubmitErrorMapFn.md @@ -0,0 +1,26 @@ +--- +id: CreateSubmitErrorMapFn +title: CreateSubmitErrorMapFn +--- + +```ts +type CreateSubmitErrorMapFn = (initial?) => ValidationErrorMap & OnSubmitError>; +``` + +Defined in: [FormApi/FormApi.public.ts:66](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L66) + +## Type Parameters + +### TFormData + +`TFormData` + +## Parameters + +### initial? + +`Partial`\<[`ValidationErrorMap`](../interfaces/ValidationErrorMap.md)\<`TFormData`\>\> + +## Returns + +[`ValidationErrorMap`](../interfaces/ValidationErrorMap.md)\<`TFormData`\> & [`OnSubmitError`](OnSubmitError.md)\<[`ValidationErrorMap`](../interfaces/ValidationErrorMap.md)\<`TFormData`\>\> diff --git a/docs/reference/type-aliases/CreateValidationErrorFn.md b/docs/reference/type-aliases/CreateValidationErrorFn.md new file mode 100644 index 0000000000..ea7885fbb2 --- /dev/null +++ b/docs/reference/type-aliases/CreateValidationErrorFn.md @@ -0,0 +1,43 @@ +--- +id: CreateValidationErrorFn +title: CreateValidationErrorFn +--- + +```ts +type CreateValidationErrorFn = (error) => OnSubmitError; +``` + +Defined in: [FormApi/FormApi.public.ts:60](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L60) + +Wraps a validation error for processing as an `onSubmit` failure without mutating it. + +Return the result from `onSubmit` to add its form- and field-level errors to +validation state. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TError + +`TError` *extends* [`FormValidationError`](FormValidationError.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### error + +`TError` + +The form- or field-level validation error to wrap. + +## Returns + +[`OnSubmitError`](OnSubmitError.md)\<`TError`\> diff --git a/docs/reference/type-aliases/CreatedValidator.md b/docs/reference/type-aliases/CreatedValidator.md new file mode 100644 index 0000000000..58d00ab403 --- /dev/null +++ b/docs/reference/type-aliases/CreatedValidator.md @@ -0,0 +1,27 @@ +--- +id: CreatedValidator +title: CreatedValidator +--- + +```ts +type CreatedValidator = ValidatorWithRun, InferFormDataFromValidator, TOptions, TRun>; +``` + +Defined in: [validation.public.ts:140](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L140) + +A validator created by combining reusable options with a validation function +or Standard Schema through `createValidator`. + +## Type Parameters + +### TOptions + +`TOptions` *extends* [`ValidatorOptions`](ValidatorOptions.md)\<`any`, `any`\> + +Library-managed. Do not specify explicitly. + +### TRun + +`TRun` *extends* `ValidatorRun` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/DeepKeyAndValueArray.md b/docs/reference/type-aliases/DeepKeyAndValueArray.md deleted file mode 100644 index 40ad4191ee..0000000000 --- a/docs/reference/type-aliases/DeepKeyAndValueArray.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -id: DeepKeyAndValueArray -title: DeepKeyAndValueArray ---- - -# Type Alias: DeepKeyAndValueArray\ - -```ts -type DeepKeyAndValueArray = DeepKeysAndValuesImpl, ArrayDeepKeyAndValue, - | TAcc -| ArrayDeepKeyAndValue>; -``` - -Defined in: [packages/form-core/src/util-types.ts:58](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L58) - -## Type Parameters - -### TParent - -`TParent` *extends* [`AnyDeepKeyAndValue`](../interfaces/AnyDeepKeyAndValue.md) - -### T - -`T` *extends* `ReadonlyArray`\<`any`\> - -### TAcc - -`TAcc` diff --git a/docs/reference/type-aliases/DeepKeyAndValueObject.md b/docs/reference/type-aliases/DeepKeyAndValueObject.md deleted file mode 100644 index cb7499c190..0000000000 --- a/docs/reference/type-aliases/DeepKeyAndValueObject.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -id: DeepKeyAndValueObject -title: DeepKeyAndValueObject ---- - -# Type Alias: DeepKeyAndValueObject\ - -```ts -type DeepKeyAndValueObject = TAllKeys extends any ? DeepKeysAndValuesImpl, ObjectDeepKeyAndValue, - | TAcc - | ObjectDeepKeyAndValue> : never; -``` - -Defined in: [packages/form-core/src/util-types.ts:123](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L123) - -## Type Parameters - -### TParent - -`TParent` *extends* [`AnyDeepKeyAndValue`](../interfaces/AnyDeepKeyAndValue.md) - -### T - -`T` - -### TAcc - -`TAcc` - -### TAllKeys - -`TAllKeys` *extends* [`AllObjectKeys`](AllObjectKeys.md)\<`T`\> = [`AllObjectKeys`](AllObjectKeys.md)\<`T`\> diff --git a/docs/reference/type-aliases/DeepKeyAndValueTuple.md b/docs/reference/type-aliases/DeepKeyAndValueTuple.md deleted file mode 100644 index bfeb45ff8a..0000000000 --- a/docs/reference/type-aliases/DeepKeyAndValueTuple.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -id: DeepKeyAndValueTuple -title: DeepKeyAndValueTuple ---- - -# Type Alias: DeepKeyAndValueTuple\ - -```ts -type DeepKeyAndValueTuple = TAllKeys extends any ? DeepKeysAndValuesImpl, TupleDeepKeyAndValue, - | TAcc - | TupleDeepKeyAndValue> : never; -``` - -Defined in: [packages/form-core/src/util-types.ts:84](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L84) - -## Type Parameters - -### TParent - -`TParent` *extends* [`AnyDeepKeyAndValue`](../interfaces/AnyDeepKeyAndValue.md) - -### T - -`T` *extends* `ReadonlyArray`\<`any`\> - -### TAcc - -`TAcc` - -### TAllKeys - -`TAllKeys` *extends* [`AllTupleKeys`](AllTupleKeys.md)\<`T`\> = [`AllTupleKeys`](AllTupleKeys.md)\<`T`\> diff --git a/docs/reference/type-aliases/DeepKeys.md b/docs/reference/type-aliases/DeepKeys.md index 7d4f19f009..40d14bd688 100644 --- a/docs/reference/type-aliases/DeepKeys.md +++ b/docs/reference/type-aliases/DeepKeys.md @@ -3,13 +3,11 @@ id: DeepKeys title: DeepKeys --- -# Type Alias: DeepKeys\ - ```ts type DeepKeys = unknown extends T ? string : DeepKeysAndValues["key"]; ``` -Defined in: [packages/form-core/src/util-types.ts:178](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L178) +Defined in: [deep-keys.public.ts:208](https://github.com/TanStack/form/blob/main/packages/form-core/src/deep-keys.public.ts#L208) The keys of an object or array, deeply nested. diff --git a/docs/reference/type-aliases/DeepKeysAndValues.md b/docs/reference/type-aliases/DeepKeysAndValues.md deleted file mode 100644 index 4794243046..0000000000 --- a/docs/reference/type-aliases/DeepKeysAndValues.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: DeepKeysAndValues -title: DeepKeysAndValues ---- - -# Type Alias: DeepKeysAndValues\ - -```ts -type DeepKeysAndValues = DeepKeysAndValuesImpl extends AnyDeepKeyAndValue ? DeepKeysAndValuesImpl : never; -``` - -Defined in: [packages/form-core/src/util-types.ts:146](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L146) - -## Type Parameters - -### T - -`T` diff --git a/docs/reference/type-aliases/DeepKeysAndValuesImpl.md b/docs/reference/type-aliases/DeepKeysAndValuesImpl.md deleted file mode 100644 index 5c07d4e5d3..0000000000 --- a/docs/reference/type-aliases/DeepKeysAndValuesImpl.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -id: DeepKeysAndValuesImpl -title: DeepKeysAndValuesImpl ---- - -# Type Alias: DeepKeysAndValuesImpl\ - -```ts -type DeepKeysAndValuesImpl = unknown extends T ? - | TAcc - | UnknownDeepKeyAndValue : unknown extends T ? T : T extends string | number | boolean | bigint | Date ? TAcc : T extends ReadonlyArray ? number extends T["length"] ? DeepKeyAndValueArray : DeepKeyAndValueTuple : keyof T extends never ? - | TAcc - | UnknownDeepKeyAndValue : T extends object ? DeepKeyAndValueObject : TAcc; -``` - -Defined in: [packages/form-core/src/util-types.ts:151](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L151) - -## Type Parameters - -### T - -`T` - -### TParent - -`TParent` *extends* [`AnyDeepKeyAndValue`](../interfaces/AnyDeepKeyAndValue.md) = `never` - -### TAcc - -`TAcc` = `never` diff --git a/docs/reference/type-aliases/DeepKeysOfType.md b/docs/reference/type-aliases/DeepKeysOfType.md deleted file mode 100644 index 0f70dda170..0000000000 --- a/docs/reference/type-aliases/DeepKeysOfType.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -id: DeepKeysOfType -title: DeepKeysOfType ---- - -# Type Alias: DeepKeysOfType\ - -```ts -type DeepKeysOfType = Extract, AnyDeepKeyAndValue>["key"]; -``` - -Defined in: [packages/form-core/src/util-types.ts:194](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L194) - -The keys of an object or array, deeply nested and only with a value of TValue - -## Type Parameters - -### TData - -`TData` - -### TValue - -`TValue` diff --git a/docs/reference/type-aliases/DeepKeysWhereValueIncludes.md b/docs/reference/type-aliases/DeepKeysWhereValueIncludes.md new file mode 100644 index 0000000000..531810caf8 --- /dev/null +++ b/docs/reference/type-aliases/DeepKeysWhereValueIncludes.md @@ -0,0 +1,20 @@ +--- +id: DeepKeysWhereValueIncludes +title: DeepKeysWhereValueIncludes +--- + +```ts +type DeepKeysWhereValueIncludes = DeepKeysAndValues extends infer TDeepKeyAndValue ? TDeepKeyAndValue extends AnyDeepKeyAndValue ? Extract, TValue> extends never ? never : TDeepKeyAndValue["key"] : never : never; +``` + +Defined in: [deep-keys.public.ts:221](https://github.com/TanStack/form/blob/main/packages/form-core/src/deep-keys.public.ts#L221) + +## Type Parameters + +### TData + +`TData` + +### TValue + +`TValue` diff --git a/docs/reference/type-aliases/DeepRecord.md b/docs/reference/type-aliases/DeepRecord.md deleted file mode 100644 index c6a5b38e1d..0000000000 --- a/docs/reference/type-aliases/DeepRecord.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: DeepRecord -title: DeepRecord ---- - -# Type Alias: DeepRecord\ - -```ts -type DeepRecord = { [TRecord in DeepKeysAndValues as TRecord["key"]]: TRecord["value"] }; -``` - -Defined in: [packages/form-core/src/util-types.ts:171](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L171) - -## Type Parameters - -### T - -`T` diff --git a/docs/reference/type-aliases/DeepValue.md b/docs/reference/type-aliases/DeepValue.md index 1bc565b426..cc7bd1eb84 100644 --- a/docs/reference/type-aliases/DeepValue.md +++ b/docs/reference/type-aliases/DeepValue.md @@ -3,13 +3,11 @@ id: DeepValue title: DeepValue --- -# Type Alias: DeepValue\ - ```ts -type DeepValue = unknown extends TValue ? TValue : TAccessor extends DeepKeys ? DeepRecord[TAccessor] : never; +type DeepValue = unknown extends TValue ? TValue : TAccessor extends DeepKeys ? DeepValueImpl : never; ``` -Defined in: [packages/form-core/src/util-types.ts:185](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L185) +Defined in: [deep-keys.public.ts:215](https://github.com/TanStack/form/blob/main/packages/form-core/src/deep-keys.public.ts#L215) Infer the type of a deeply nested property within an object or an array. @@ -21,4 +19,4 @@ Infer the type of a deeply nested property within an object or an array. ### TAccessor -`TAccessor` +`TAccessor` *extends* `string` diff --git a/docs/reference/type-aliases/DefaultFieldOptions.md b/docs/reference/type-aliases/DefaultFieldOptions.md new file mode 100644 index 0000000000..b213521679 --- /dev/null +++ b/docs/reference/type-aliases/DefaultFieldOptions.md @@ -0,0 +1,28 @@ +--- +id: DefaultFieldOptions +title: DefaultFieldOptions +--- + +```ts +type DefaultFieldOptions = Pick, never, unknown, FormErrorTypes>, "errorVisibility" | "errorBoundary" | "listeners"> & DefaultListenersMergeOptions; +``` + +Defined in: [defaultOptions.public.ts:82](https://github.com/TanStack/form/blob/main/packages/form-core/src/defaultOptions.public.ts#L82) + +Reusable field behavior that does not participate in form or field value +inference. + +Only `errorVisibility`, `errorBoundary`, `listeners`, and `listenersMerge` +can be shared this way. Listener values and APIs are typed with `unknown` +values, so value-dependent behavior should remain in the usage-site field +options. Usage-site properties override defaults even when explicitly set +to `undefined`; a supplied listener array instead follows `listenersMerge`. + +## Example + +```ts +const fieldDefaults: DefaultFieldOptions = { + errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred, + errorBoundary: true, +} +``` diff --git a/docs/reference/type-aliases/DefaultFormGroupOptions.md b/docs/reference/type-aliases/DefaultFormGroupOptions.md new file mode 100644 index 0000000000..2e25ac5a77 --- /dev/null +++ b/docs/reference/type-aliases/DefaultFormGroupOptions.md @@ -0,0 +1,28 @@ +--- +id: DefaultFormGroupOptions +title: DefaultFormGroupOptions +--- + +```ts +type DefaultFormGroupOptions = Pick, FormErrorTypes>, "onSubmitInvalid">; +``` + +Defined in: [defaultOptions.public.ts:114](https://github.com/TanStack/form/blob/main/packages/form-core/src/defaultOptions.public.ts#L114) + +Reusable form-group behavior that does not participate in group value +inference. + +Only `onSubmitInvalid` can be shared this way. Its callback receives +`unknown` form and group values, so value-dependent behavior should remain +in the usage-site form-group options. A usage-site `onSubmitInvalid` +property overrides the default even when explicitly set to `undefined`. + +## Example + +```ts +const formGroupDefaults: DefaultFormGroupOptions = { + onSubmitInvalid: ({ groupApi }) => { + console.error('Invalid group', groupApi.name) + }, +} +``` diff --git a/docs/reference/type-aliases/DefaultFormOptions.md b/docs/reference/type-aliases/DefaultFormOptions.md new file mode 100644 index 0000000000..8dbcbf6f49 --- /dev/null +++ b/docs/reference/type-aliases/DefaultFormOptions.md @@ -0,0 +1,30 @@ +--- +id: DefaultFormOptions +title: DefaultFormOptions +--- + +```ts +type DefaultFormOptions = Pick, unknown, unknown>, "errorVisibility" | "listeners" | "onSubmitInvalid"> & DefaultListenersMergeOptions; +``` + +Defined in: [defaultOptions.public.ts:58](https://github.com/TanStack/form/blob/main/packages/form-core/src/defaultOptions.public.ts#L58) + +Reusable form behavior that does not participate in form value inference. + +Only `errorVisibility`, `listeners`, `onSubmitInvalid`, and `listenersMerge` +can be shared this way. Callback values are typed as `unknown`, so behavior +that depends on the inferred form value should remain in the usage-site form +options. Usage-site properties override defaults even when explicitly set +to `undefined`; a supplied listener array instead follows `listenersMerge`. + +## Example + +```ts +const formDefaults: DefaultFormOptions = { + errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred, + listenersMerge: 'append', + onSubmitInvalid: () => { + document.querySelector('[aria-invalid="true"]')?.focus() + }, +} +``` diff --git a/docs/reference/type-aliases/DefaultListenersMergeMode.md b/docs/reference/type-aliases/DefaultListenersMergeMode.md new file mode 100644 index 0000000000..a85319c93c --- /dev/null +++ b/docs/reference/type-aliases/DefaultListenersMergeMode.md @@ -0,0 +1,18 @@ +--- +id: DefaultListenersMergeMode +title: DefaultListenersMergeMode +--- + +```ts +type DefaultListenersMergeMode = "replace" | "append" | "prepend"; +``` + +Defined in: [defaultOptions.public.ts:20](https://github.com/TanStack/form/blob/main/packages/form-core/src/defaultOptions.public.ts#L20) + +Determines how a supplied usage-site listener array combines with default +listeners. + +`'append'` runs default listeners before usage-site listeners. `'prepend'` +runs usage-site listeners first. `'replace'` uses only the usage-site +listeners. Omitting the usage-site property keeps the defaults, while +explicitly setting it to `undefined` suppresses them. diff --git a/docs/reference/type-aliases/DerivedFormState.md b/docs/reference/type-aliases/DerivedFormState.md deleted file mode 100644 index 843495a33d..0000000000 --- a/docs/reference/type-aliases/DerivedFormState.md +++ /dev/null @@ -1,228 +0,0 @@ ---- -id: DerivedFormState -title: DerivedFormState ---- - -# Type Alias: DerivedFormState\ - -```ts -type DerivedFormState = object; -``` - -Defined in: [packages/form-core/src/FormApi.ts:713](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L713) - -## Extended by - -- [`FormState`](../interfaces/FormState.md) - -## Type Parameters - -### TFormData - -`TFormData` - -### TOnMount - -`TOnMount` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChange - -`TOnChange` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnChangeAsync - -`TOnChangeAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnBlur - -`TOnBlur` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnBlurAsync - -`TOnBlurAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnSubmit - -`TOnSubmit` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnSubmitAsync - -`TOnSubmitAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnDynamic - -`TOnDynamic` *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -### TOnDynamicAsync - -`TOnDynamicAsync` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -### TOnServer - -`TOnServer` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -## Properties - -### canSubmit - -```ts -canSubmit: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:786](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L786) - -A boolean indicating if the form can be submitted based on its current state. - -*** - -### errors - -```ts -errors: NonNullable< - | UnwrapFormValidateOrFn - | UnwrapFormValidateOrFn - | UnwrapFormAsyncValidateOrFn - | UnwrapFormValidateOrFn - | UnwrapFormAsyncValidateOrFn - | UnwrapFormValidateOrFn - | UnwrapFormAsyncValidateOrFn - | UnwrapFormValidateOrFn - | UnwrapFormAsyncValidateOrFn - | UnwrapFormAsyncValidateOrFn>[]; -``` - -Defined in: [packages/form-core/src/FormApi.ts:737](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L737) - -The error array for the form itself. - -*** - -### fieldMeta - -```ts -fieldMeta: Partial, AnyFieldLikeMeta>>; -``` - -Defined in: [packages/form-core/src/FormApi.ts:790](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L790) - -A record of field metadata for each field in the form. - -*** - -### isBlurred - -```ts -isBlurred: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:766](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L766) - -A boolean indicating if any of the form fields have been blurred. - -*** - -### isDefaultValue - -```ts -isDefaultValue: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:778](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L778) - -A boolean indicating if all of the form's fields are the same as default values. - -*** - -### isDirty - -```ts -isDirty: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:770](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L770) - -A boolean indicating if any of the form's fields' values have been modified by the user. Evaluates `true` if the user have modified at least one of the fields. Opposite of `isPristine`. - -*** - -### isFieldsValid - -```ts -isFieldsValid: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:758](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L758) - -A boolean indicating if all the form fields are valid. Evaluates `true` if there are no field errors. - -*** - -### isFieldsValidating - -```ts -isFieldsValidating: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:754](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L754) - -A boolean indicating if any of the form fields are currently validating. - -*** - -### isFormValid - -```ts -isFormValid: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:733](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L733) - -A boolean indicating if the form is valid. - -*** - -### isFormValidating - -```ts -isFormValidating: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:729](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L729) - -A boolean indicating if the form is currently validating. - -*** - -### isPristine - -```ts -isPristine: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:774](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L774) - -A boolean indicating if none of the form's fields' values have been modified by the user. Evaluates `true` if the user have not modified any of the fields. Opposite of `isDirty`. - -*** - -### isTouched - -```ts -isTouched: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:762](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L762) - -A boolean indicating if any of the form fields have been touched. - -*** - -### isValid - -```ts -isValid: boolean; -``` - -Defined in: [packages/form-core/src/FormApi.ts:782](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L782) - -A boolean indicating if the form and all its fields are valid. Evaluates `true` if there are no errors. diff --git a/docs/reference/type-aliases/Editable.md b/docs/reference/type-aliases/Editable.md new file mode 100644 index 0000000000..073a6569ec --- /dev/null +++ b/docs/reference/type-aliases/Editable.md @@ -0,0 +1,16 @@ +--- +id: Editable +title: Editable +--- + +```ts +type Editable = T extends BuiltInType ? T | null | undefined : T extends ReadonlyArray ? Editable[] | null | undefined : T extends object ? EditableObject | null | undefined : T | null | undefined; +``` + +Defined in: [utils.public.ts:9](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.public.ts#L9) + +## Type Parameters + +### T + +`T` diff --git a/docs/reference/type-aliases/ErrorVisibility.md b/docs/reference/type-aliases/ErrorVisibility.md new file mode 100644 index 0000000000..2732a5f8ee --- /dev/null +++ b/docs/reference/type-aliases/ErrorVisibility.md @@ -0,0 +1,42 @@ +--- +id: ErrorVisibility +title: ErrorVisibility +--- + +```ts +type ErrorVisibility = (context) => boolean; +``` + +Defined in: [validation.public.ts:340](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L340) + +Returns `true` to show a field's validation errors in `field.errors`. + +Hidden errors remain available in `field.meta.original.errors`. + +For fields inside a form group, `state` properties such as `isTouched` and +`submissionAttempts` describe the containing group. `values` and `errors` +still describe the whole form. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](../interfaces/FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Parameters + +### context + +[`ErrorVisibilityContext`](../interfaces/ErrorVisibilityContext.md)\<`TFormData`, `TFormErrorTypes`\> + +## Returns + +`boolean` diff --git a/docs/reference/type-aliases/EventClientEventMap.md b/docs/reference/type-aliases/EventClientEventMap.md deleted file mode 100644 index 79799c8b3e..0000000000 --- a/docs/reference/type-aliases/EventClientEventMap.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: EventClientEventMap -title: EventClientEventMap ---- - -# Type Alias: EventClientEventMap - -```ts -type EventClientEventMap = keyof EventMap; -``` - -Defined in: [packages/form-core/src/EventClient.ts:57](https://github.com/TanStack/form/blob/main/packages/form-core/src/EventClient.ts#L57) diff --git a/docs/reference/type-aliases/EventClientEventNames.md b/docs/reference/type-aliases/EventClientEventNames.md deleted file mode 100644 index 12c235ee18..0000000000 --- a/docs/reference/type-aliases/EventClientEventNames.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: EventClientEventNames -title: EventClientEventNames ---- - -# Type Alias: EventClientEventNames - -```ts -type EventClientEventNames = ExtractEventNames; -``` - -Defined in: [packages/form-core/src/EventClient.ts:59](https://github.com/TanStack/form/blob/main/packages/form-core/src/EventClient.ts#L59) diff --git a/docs/reference/type-aliases/ExtractGlobalFormError.md b/docs/reference/type-aliases/ExtractGlobalFormError.md deleted file mode 100644 index 64d6c8804c..0000000000 --- a/docs/reference/type-aliases/ExtractGlobalFormError.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: ExtractGlobalFormError -title: ExtractGlobalFormError ---- - -# Type Alias: ExtractGlobalFormError\ - -```ts -type ExtractGlobalFormError = TFormError extends GlobalFormValidationError ? TFormError["form"] : TFormError; -``` - -Defined in: [packages/form-core/src/types.ts:154](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L154) - -## Type Parameters - -### TFormError - -`TFormError` diff --git a/docs/reference/type-aliases/FieldErrors.md b/docs/reference/type-aliases/FieldErrors.md new file mode 100644 index 0000000000..c52e52ab1d --- /dev/null +++ b/docs/reference/type-aliases/FieldErrors.md @@ -0,0 +1,20 @@ +--- +id: FieldErrors +title: FieldErrors +--- + +```ts +type FieldErrors = unknown extends TFieldError ? ValidationIssue : TFieldError[]; +``` + +Defined in: [validation.public.ts:1110](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1110) + +A field's error array, with string messages normalized to issue objects. + +## Type Parameters + +### TFieldError + +`TFieldError` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/FieldGroupFieldBindingForSlot.md b/docs/reference/type-aliases/FieldGroupFieldBindingForSlot.md new file mode 100644 index 0000000000..209c3f192c --- /dev/null +++ b/docs/reference/type-aliases/FieldGroupFieldBindingForSlot.md @@ -0,0 +1,26 @@ +--- +id: FieldGroupFieldBindingForSlot +title: FieldGroupFieldBindingForSlot +--- + +```ts +type FieldGroupFieldBindingForSlot = FieldGroupFieldNameForSlot; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:163](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L163) + +Produces the concrete form paths that can bind to one virtual field slot. + +## Type Parameters + +### TFormData + +`TFormData` + +The parent form data whose field paths are searched. + +### TSlot + +`TSlot` *extends* [`AnyFieldGroupFieldSlot`](AnyFieldGroupFieldSlot.md) + +The virtual field slot that each path must satisfy. diff --git a/docs/reference/type-aliases/FieldGroupFieldBindings.md b/docs/reference/type-aliases/FieldGroupFieldBindings.md new file mode 100644 index 0000000000..08b2a7ef90 --- /dev/null +++ b/docs/reference/type-aliases/FieldGroupFieldBindings.md @@ -0,0 +1,31 @@ +--- +id: FieldGroupFieldBindings +title: FieldGroupFieldBindings +--- + +```ts +type FieldGroupFieldBindings = { [TFieldName in keyof TFields]: FieldGroupFieldBindingForSlot }; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:179](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L179) + +Maps every virtual field name to the compatible concrete paths in a parent +form. + +A supplied binding map is complete: every virtual field in `TFields` must be +assigned a compatible path from `TFormData`. + +## Type Parameters + +### TFields + +`TFields` *extends* [`FieldGroupFields`](FieldGroupFields.md) + +The virtual field schema whose keys become binding +keys. + +### TFormData + +`TFormData` = `any` + +The parent form data whose paths can be bound. diff --git a/docs/reference/type-aliases/FieldGroupFieldBindingsProps.md b/docs/reference/type-aliases/FieldGroupFieldBindingsProps.md new file mode 100644 index 0000000000..dc3eb2d18b --- /dev/null +++ b/docs/reference/type-aliases/FieldGroupFieldBindingsProps.md @@ -0,0 +1,40 @@ +--- +id: FieldGroupFieldBindingsProps +title: FieldGroupFieldBindingsProps +--- + +```ts +type FieldGroupFieldBindingsProps = unknown extends TFormData ? FieldGroupFieldsPropsDefinition : FieldGroupIdentityBindings extends FieldGroupFieldBindings ? Partial> : FieldGroupFieldsPropsDefinition; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:216](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L216) + +Builds the concrete-field bindings prop accepted by a bound field-group +component. + +The prop is optional only when every virtual field name is already a +compatible path in the parent form. Omitting it then binds each virtual +field to the same-named path. Otherwise, callers must supply a complete +binding map. + +## Type Parameters + +### TFields + +`TFields` *extends* [`FieldGroupFields`](FieldGroupFields.md) + +The virtual field schema whose keys require bindings. + +### TFormData + +`TFormData` + +The parent form data used to validate paths and +identity bindings. + +### TFieldsPropName + +`TFieldsPropName` *extends* `PropertyKey` + +The component prop that carries the binding +map. diff --git a/docs/reference/type-aliases/FieldGroupFieldData.md b/docs/reference/type-aliases/FieldGroupFieldData.md new file mode 100644 index 0000000000..5d7bbadf21 --- /dev/null +++ b/docs/reference/type-aliases/FieldGroupFieldData.md @@ -0,0 +1,22 @@ +--- +id: FieldGroupFieldData +title: FieldGroupFieldData +--- + +```ts +type FieldGroupFieldData = { [TFieldName in keyof TFields]: TFields[TFieldName] extends FieldGroupFieldSlot ? TValue : never }; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:149](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L149) + +Converts a virtual field schema into the value shape exposed by its field +group API. + +## Type Parameters + +### TFields + +`TFields` *extends* [`FieldGroupFields`](FieldGroupFields.md) + +The virtual field schema whose value types are +extracted. diff --git a/docs/reference/type-aliases/FieldGroupFieldNameForSlot.md b/docs/reference/type-aliases/FieldGroupFieldNameForSlot.md new file mode 100644 index 0000000000..31e461dbbe --- /dev/null +++ b/docs/reference/type-aliases/FieldGroupFieldNameForSlot.md @@ -0,0 +1,27 @@ +--- +id: FieldGroupFieldNameForSlot +title: FieldGroupFieldNameForSlot +--- + +```ts +type FieldGroupFieldNameForSlot = { [TFieldName in DeepKeys]: FieldGroupFieldSlotAllows> extends true ? TFieldName : never }[DeepKeys]; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:110](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L110) + +Produces the union of deep field paths whose value types satisfy a +field-group slot. + +## Type Parameters + +### TFieldData + +`TFieldData` + +The parent form data whose field paths are searched. + +### TSlot + +`TSlot` *extends* [`AnyFieldGroupFieldSlot`](AnyFieldGroupFieldSlot.md) + +The virtual field slot that each path must satisfy. diff --git a/docs/reference/type-aliases/FieldGroupFieldNames.md b/docs/reference/type-aliases/FieldGroupFieldNames.md new file mode 100644 index 0000000000..c640fe68ea --- /dev/null +++ b/docs/reference/type-aliases/FieldGroupFieldNames.md @@ -0,0 +1,27 @@ +--- +id: FieldGroupFieldNames +title: FieldGroupFieldNames +--- + +```ts +type FieldGroupFieldNames = { [TFieldName in keyof TFields]: FieldGroupFieldNameForSlot }; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:132](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L132) + +Maps each virtual field name to the compatible deep paths in field data. + +## Type Parameters + +### TFieldData + +`TFieldData` + +The parent form data whose field paths are searched. + +### TFields + +`TFields` *extends* [`FieldGroupFields`](FieldGroupFields.md) + +The virtual field schema whose slots constrain each +path. diff --git a/docs/reference/type-aliases/FieldGroupFieldSlotAllows.md b/docs/reference/type-aliases/FieldGroupFieldSlotAllows.md new file mode 100644 index 0000000000..bdf8208320 --- /dev/null +++ b/docs/reference/type-aliases/FieldGroupFieldSlotAllows.md @@ -0,0 +1,30 @@ +--- +id: FieldGroupFieldSlotAllows +title: FieldGroupFieldSlotAllows +--- + +```ts +type FieldGroupFieldSlotAllows = TSlot extends FieldGroupFieldSlot ? TMode extends "strict" ? IsSame : [TValue] extends [TAcceptedValue] ? true : false : false; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:94](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L94) + +Reports whether a concrete field value type satisfies a field-group slot's +matching rule. + +Strict slots require the two value types to be identical. Loose slots accept +a concrete value type that is assignable to the slot's declared value type. + +## Type Parameters + +### TSlot + +`TSlot` + +The virtual field slot that supplies the matching rule. + +### TValue + +`TValue` + +The concrete form field value type to test. diff --git a/docs/reference/type-aliases/FieldGroupFieldSlotMode.md b/docs/reference/type-aliases/FieldGroupFieldSlotMode.md new file mode 100644 index 0000000000..014818a3ba --- /dev/null +++ b/docs/reference/type-aliases/FieldGroupFieldSlotMode.md @@ -0,0 +1,16 @@ +--- +id: FieldGroupFieldSlotMode +title: FieldGroupFieldSlotMode +--- + +```ts +type FieldGroupFieldSlotMode = "strict" | "loose"; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:12](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L12) + +Controls how a virtual field's value type is matched to concrete form field +paths. + +`strict` requires an exact type match. `loose` also accepts narrower value +types that are assignable to the virtual field's declared type. diff --git a/docs/reference/type-aliases/FieldGroupFieldSlotModeOf.md b/docs/reference/type-aliases/FieldGroupFieldSlotModeOf.md new file mode 100644 index 0000000000..57d51d4be6 --- /dev/null +++ b/docs/reference/type-aliases/FieldGroupFieldSlotModeOf.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupFieldSlotModeOf +title: FieldGroupFieldSlotModeOf +--- + +```ts +type FieldGroupFieldSlotModeOf = TSlot extends FieldGroupFieldSlot ? TMode : never; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:75](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L75) + +Extracts whether a field-group slot uses strict or loose matching. + +## Type Parameters + +### TSlot + +`TSlot` + +The slot whose matching mode is extracted. diff --git a/docs/reference/type-aliases/FieldGroupFieldSlotValue.md b/docs/reference/type-aliases/FieldGroupFieldSlotValue.md new file mode 100644 index 0000000000..5dfc0e8d09 --- /dev/null +++ b/docs/reference/type-aliases/FieldGroupFieldSlotValue.md @@ -0,0 +1,20 @@ +--- +id: FieldGroupFieldSlotValue +title: FieldGroupFieldSlotValue +--- + +```ts +type FieldGroupFieldSlotValue = TSlot extends FieldGroupFieldSlot ? TValue : never; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:67](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L67) + +Extracts the value type declared by a field-group slot. + +## Type Parameters + +### TSlot + +`TSlot` + +The slot whose declared value type is extracted. diff --git a/docs/reference/type-aliases/FieldGroupFields.md b/docs/reference/type-aliases/FieldGroupFields.md new file mode 100644 index 0000000000..2dae3ca208 --- /dev/null +++ b/docs/reference/type-aliases/FieldGroupFields.md @@ -0,0 +1,12 @@ +--- +id: FieldGroupFields +title: FieldGroupFields +--- + +```ts +type FieldGroupFields = Record; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:123](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L123) + +A reusable field-group schema keyed by its virtual field names. diff --git a/docs/reference/type-aliases/FieldGroupFieldsPropName.md b/docs/reference/type-aliases/FieldGroupFieldsPropName.md new file mode 100644 index 0000000000..71e6fce718 --- /dev/null +++ b/docs/reference/type-aliases/FieldGroupFieldsPropName.md @@ -0,0 +1,27 @@ +--- +id: FieldGroupFieldsPropName +title: FieldGroupFieldsPropName +--- + +```ts +type FieldGroupFieldsPropName = { [TPropName in keyof TProps]-?: IsSame extends true ? TPropName : never }[keyof TProps]; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:238](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L238) + +Finds the component prop whose value type exactly matches a field-group API. + +## Type Parameters + +### TProps + +`TProps` + +The component props searched for the field-group API. + +### TFieldGroup + +`TFieldGroup` + +The field-group API type that a prop must exactly +match. diff --git a/docs/reference/type-aliases/FieldListenerFn.md b/docs/reference/type-aliases/FieldListenerFn.md new file mode 100644 index 0000000000..a0cd00148f --- /dev/null +++ b/docs/reference/type-aliases/FieldListenerFn.md @@ -0,0 +1,68 @@ +--- +id: FieldListenerFn +title: FieldListenerFn +--- + +```ts +type FieldListenerFn = (context) => void; +``` + +Defined in: [listeners.public.ts:387](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L387) + +A callback invoked when a field listener runs. + +The return value is ignored. A returned promise is not awaited, and a +rejected promise is reported to the console. + +## Type Parameters + +### TFieldName + +`TFieldName` + +Library-managed. Do not specify explicitly. + +### TFieldValue + +`TFieldValue` + +Library-managed. Do not specify explicitly. + +### TFieldError + +`TFieldError` + +Library-managed. Do not specify explicitly. + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](../interfaces/FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Parameters + +### context + +[`FieldListenerContext`](../interfaces/FieldListenerContext.md)\<`TFieldName`, `TFieldValue`, `TFieldError`, `TFormData`, `TFormErrorTypes`\> + +## Returns + +`void` + +## Example + +```ts +run: ({ value, fieldApi }) => { + const trimmedValue = value.trim() + if (trimmedValue !== value) { + fieldApi.handleChange(trimmedValue) + } +}, +``` diff --git a/docs/reference/type-aliases/FieldListenerTriggers.md b/docs/reference/type-aliases/FieldListenerTriggers.md new file mode 100644 index 0000000000..34aff0a57a --- /dev/null +++ b/docs/reference/type-aliases/FieldListenerTriggers.md @@ -0,0 +1,22 @@ +--- +id: FieldListenerTriggers +title: FieldListenerTriggers +--- + +```ts +type FieldListenerTriggers = FormListenerTriggers | "unmount"; +``` + +Defined in: [listeners.public.ts:32](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L32) + +Events that can invoke a listener configured on a field. + +- `'change'`: The field, one of its descendants, or a watched field reported + a value change. +- `'blur'`: The field, one of its descendants, or a watched field was + blurred. +- `'submit'`: A submission attempt notified the field before validation. +- `'mount'`: The field or a watched field was registered. +- `'reset'`: The field or a watched field was reset directly or as part of a + form reset. +- `'unmount'`: The field or a watched field was unregistered. diff --git a/docs/reference/type-aliases/FieldListeners.md b/docs/reference/type-aliases/FieldListeners.md new file mode 100644 index 0000000000..ba66edf06d --- /dev/null +++ b/docs/reference/type-aliases/FieldListeners.md @@ -0,0 +1,70 @@ +--- +id: FieldListeners +title: FieldListeners +--- + +```ts +type FieldListeners = FieldListener[]; +``` + +Defined in: [listeners.public.ts:514](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L514) + +Listener configurations evaluated in array order for each field event. + +A debounced listener may execute after later, non-debounced listeners. + +## Type Parameters + +### TFieldData + +`TFieldData` + +Library-managed. Do not specify explicitly. + +### TFieldName + +`TFieldName` + +Library-managed. Do not specify explicitly. + +### TFieldValue + +`TFieldValue` + +Library-managed. Do not specify explicitly. + +### TFieldError + +`TFieldError` + +Library-managed. Do not specify explicitly. + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](../interfaces/FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Example + +```ts +listeners: [ + { + triggers: ['change', 'blur'], + triggerDebounceMs: 200, + watchFields: ['displayName'], + run: ({ value, formApi }) => { + saveContact({ + displayName: formApi.getFieldValue('displayName'), + email: value, + }) + }, + }, +], +``` diff --git a/docs/reference/type-aliases/FieldValidateResult.md b/docs/reference/type-aliases/FieldValidateResult.md new file mode 100644 index 0000000000..220bbc5400 --- /dev/null +++ b/docs/reference/type-aliases/FieldValidateResult.md @@ -0,0 +1,12 @@ +--- +id: FieldValidateResult +title: FieldValidateResult +--- + +```ts +type FieldValidateResult = ValidationResult; +``` + +Defined in: [validation.public.ts:962](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L962) + +A field validator's success result or errors. Field validators do not provide output data. diff --git a/docs/reference/type-aliases/FieldValidatorFn.md b/docs/reference/type-aliases/FieldValidatorFn.md new file mode 100644 index 0000000000..0dc1f9d13b --- /dev/null +++ b/docs/reference/type-aliases/FieldValidatorFn.md @@ -0,0 +1,32 @@ +--- +id: FieldValidatorFn +title: FieldValidatorFn +--- + +```ts +type FieldValidatorFn = ValidatorFn, FieldValidateResult>; +``` + +Defined in: [validation.public.ts:971](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L971) + +Validates a field's value and reports errors owned by that field. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFieldName + +`TFieldName` + +Library-managed. Do not specify explicitly. + +### TFieldValue + +`TFieldValue` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/FieldValidators.md b/docs/reference/type-aliases/FieldValidators.md new file mode 100644 index 0000000000..77c50bfc8c --- /dev/null +++ b/docs/reference/type-aliases/FieldValidators.md @@ -0,0 +1,32 @@ +--- +id: FieldValidators +title: FieldValidators +--- + +```ts +type FieldValidators = ReadonlyArray>; +``` + +Defined in: [validation.public.ts:1011](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1011) + +Field validators in configuration order. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFieldName + +`TFieldName` + +Library-managed. Do not specify explicitly. + +### TFieldValue + +`TFieldValue` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/FieldWithValue.md b/docs/reference/type-aliases/FieldWithValue.md new file mode 100644 index 0000000000..bfe7684f0d --- /dev/null +++ b/docs/reference/type-aliases/FieldWithValue.md @@ -0,0 +1,33 @@ +--- +id: FieldWithValue +title: FieldWithValue +--- + +```ts +type FieldWithValue = FieldApi; +``` + +Defined in: [types.public.ts:52](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.public.ts#L52) + +A field API that preserves its value type while erasing its name, error, and +owning form types. + +Use it for reusable value-specific UI or helpers that should accept the same +value type at any field path. Value reads and updates remain typed without +tying the reusable code to one path or form shape. + +## Type Parameters + +### TFieldValue + +`TFieldValue` + +The value type preserved across field reads and update methods. + +## Example + +```ts +function trimField(field: FieldWithValue) { + field.handleChange((value) => value.trim()) +} +``` diff --git a/docs/reference/type-aliases/FieldsMap.md b/docs/reference/type-aliases/FieldsMap.md deleted file mode 100644 index 516aede0e7..0000000000 --- a/docs/reference/type-aliases/FieldsMap.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -id: FieldsMap -title: FieldsMap ---- - -# Type Alias: FieldsMap\ - -```ts -type FieldsMap = TFieldGroupData extends any[] ? never : string extends keyof TFieldGroupData ? never : { [K in keyof TFieldGroupData]: DeepKeysOfType }; -``` - -Defined in: [packages/form-core/src/util-types.ts:203](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L203) - -Maps the deep keys of TFormData to the shallow keys of TFieldGroupData. - Since using template strings as keys is impractical, it relies on shallow keys only. - -## Type Parameters - -### TFormData - -`TFormData` - -### TFieldGroupData - -`TFieldGroupData` diff --git a/docs/reference/type-aliases/FilterFieldValuesFn.md b/docs/reference/type-aliases/FilterFieldValuesFn.md new file mode 100644 index 0000000000..8e99c7e624 --- /dev/null +++ b/docs/reference/type-aliases/FilterFieldValuesFn.md @@ -0,0 +1,66 @@ +--- +id: FilterFieldValuesFn +title: FilterFieldValuesFn +--- + +```ts +type FilterFieldValuesFn = (arrayFieldName, predicate, options?) => void; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:309](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L309) + +Keeps the elements that satisfy a predicate. + +A runtime value that is not an array produces a warning and is left +unchanged. By default, the update marks the array field as touched and +dirty, notifies change listeners, and runs change validation. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* [`ArrayFieldName`](ArrayFieldName.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### arrayFieldName + +`TFieldName` + +The array field path. + +### predicate + +[`ArrayFieldPredicate`](ArrayFieldPredicate.md)\<`TFormData`, `TFieldName`\> + +Called with each element, its original index, and the +array. Return `true` to keep the element. + +### options? + +[`FieldUpdateOptions`](../interfaces/FieldUpdateOptions.md) & `object` + +Controls metadata updates and validation. `thisArg` sets the +predicate's `this` value. + +## Returns + +`void` + +## Example + +```ts +// items: [1, 2, 3, 4] +formApi.filterFieldValues('items', (item) => item % 2 === 0) +// items: [2, 4] +``` diff --git a/docs/reference/type-aliases/FormErrors.md b/docs/reference/type-aliases/FormErrors.md new file mode 100644 index 0000000000..db016036f9 --- /dev/null +++ b/docs/reference/type-aliases/FormErrors.md @@ -0,0 +1,20 @@ +--- +id: FormErrors +title: FormErrors +--- + +```ts +type FormErrors = ExtractFormError[]; +``` + +Defined in: [validation.public.ts:1101](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1101) + +The form or group's error array, with string messages normalized to issue objects. + +## Type Parameters + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](../interfaces/FormErrorTypes.md) + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/FormGroupSubmitFn.md b/docs/reference/type-aliases/FormGroupSubmitFn.md new file mode 100644 index 0000000000..29d2796988 --- /dev/null +++ b/docs/reference/type-aliases/FormGroupSubmitFn.md @@ -0,0 +1,42 @@ +--- +id: FormGroupSubmitFn +title: FormGroupSubmitFn +--- + +```ts +type FormGroupSubmitFn = (context) => void | Promise; +``` + +Defined in: [FormGroupApi/FormGroupApi.public.ts:101](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormGroupApi/FormGroupApi.public.ts#L101) + +## Type Parameters + +### TFormData + +`TFormData` + +### TGroupName + +`TGroupName` + +### TGroupValue + +`TGroupValue` + +### TGroupValidators + +`TGroupValidators` *extends* [`FormGroupValidators`](FormGroupValidators.md)\<`TGroupValue`\> + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](../interfaces/FormErrorTypes.md) + +## Parameters + +### context + +[`FormGroupSubmitContext`](../interfaces/FormGroupSubmitContext.md)\<`TFormData`, `TGroupName`, `TGroupValue`, [`ToFormGroupOutputs`](ToFormGroupOutputs.md)\<`NoInfer`\<`TGroupValidators`\>\>, [`ToFormGroupErrorTypes`](ToFormGroupErrorTypes.md)\<`NoInfer`\<`TGroupValidators`\>\>, `TFormErrorTypes`\> + +## Returns + +`void` \| `Promise`\<`void`\> diff --git a/docs/reference/type-aliases/FormGroupValidateResult.md b/docs/reference/type-aliases/FormGroupValidateResult.md new file mode 100644 index 0000000000..b8c75747ce --- /dev/null +++ b/docs/reference/type-aliases/FormGroupValidateResult.md @@ -0,0 +1,22 @@ +--- +id: FormGroupValidateResult +title: FormGroupValidateResult +--- + +```ts +type FormGroupValidateResult = + | SuccessfulValidationResult +| FormGroupValidationError; +``` + +Defined in: [validation.public.ts:900](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L900) + +A form group validator's success result, output data, or validation errors. + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/FormGroupValidationError.md b/docs/reference/type-aliases/FormGroupValidationError.md new file mode 100644 index 0000000000..3753c1a7c2 --- /dev/null +++ b/docs/reference/type-aliases/FormGroupValidationError.md @@ -0,0 +1,22 @@ +--- +id: FormGroupValidationError +title: FormGroupValidationError +--- + +```ts +type FormGroupValidationError = + | ValidationErrorInput +| ValidationErrorMap; +``` + +Defined in: [validation.public.ts:893](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L893) + +Errors for a form group, optionally including errors at group-relative field paths. + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/FormGroupValidatorFn.md b/docs/reference/type-aliases/FormGroupValidatorFn.md new file mode 100644 index 0000000000..cc1501f061 --- /dev/null +++ b/docs/reference/type-aliases/FormGroupValidatorFn.md @@ -0,0 +1,20 @@ +--- +id: FormGroupValidatorFn +title: FormGroupValidatorFn +--- + +```ts +type FormGroupValidatorFn = ValidatorFn, FormGroupValidateResult>; +``` + +Defined in: [validation.public.ts:908](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L908) + +Validates a group's value and can return group errors, field errors, or output data. + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/FormGroupValidators.md b/docs/reference/type-aliases/FormGroupValidators.md new file mode 100644 index 0000000000..7e8af1f350 --- /dev/null +++ b/docs/reference/type-aliases/FormGroupValidators.md @@ -0,0 +1,20 @@ +--- +id: FormGroupValidators +title: FormGroupValidators +--- + +```ts +type FormGroupValidators = ReadonlyArray>; +``` + +Defined in: [validation.public.ts:931](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L931) + +Group validators in configuration order, which also determines their `validatorOutputs` indexes. + +## Type Parameters + +### TGroupValue + +`TGroupValue` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/FormListenerFn.md b/docs/reference/type-aliases/FormListenerFn.md new file mode 100644 index 0000000000..b34c4732af --- /dev/null +++ b/docs/reference/type-aliases/FormListenerFn.md @@ -0,0 +1,47 @@ +--- +id: FormListenerFn +title: FormListenerFn +--- + +```ts +type FormListenerFn = (context) => void; +``` + +Defined in: [listeners.public.ts:238](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L238) + +A callback invoked when a form listener runs. + +The return value is ignored. A returned promise is not awaited, and a +rejected promise is reported to the console. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](../interfaces/FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Parameters + +### context + +[`FormListenerContext`](../interfaces/FormListenerContext.md)\<`TFormData`, `TFormErrorTypes`\> + +## Returns + +`void` + +## Example + +```ts +run: ({ value }) => { + saveDraft(value) +}, +``` diff --git a/docs/reference/type-aliases/FormListenerTriggers.md b/docs/reference/type-aliases/FormListenerTriggers.md new file mode 100644 index 0000000000..42783d7094 --- /dev/null +++ b/docs/reference/type-aliases/FormListenerTriggers.md @@ -0,0 +1,20 @@ +--- +id: FormListenerTriggers +title: FormListenerTriggers +--- + +```ts +type FormListenerTriggers = ValidationTrigger | "mount" | "reset"; +``` + +Defined in: [listeners.public.ts:17](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L17) + +Events that can invoke a listener configured on a form. + +- `'change'`: A field value changed. The listener receives the updated form + values. +- `'blur'`: A field was marked as blurred. +- `'submit'`: A submission attempt started. The listener runs before + submission validation. +- `'mount'`: The component using the form was mounted. +- `'reset'`: The form finished resetting its values and state. diff --git a/docs/reference/type-aliases/FormListeners.md b/docs/reference/type-aliases/FormListeners.md new file mode 100644 index 0000000000..e593c78a8a --- /dev/null +++ b/docs/reference/type-aliases/FormListeners.md @@ -0,0 +1,50 @@ +--- +id: FormListeners +title: FormListeners +--- + +```ts +type FormListeners = FormListener[]; +``` + +Defined in: [listeners.public.ts:325](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L325) + +Listener configurations evaluated in array order for each form event. + +A debounced listener may execute after later, non-debounced listeners. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](../interfaces/FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Example + +```ts +formOptions({ + defaultValues: { displayName: '' }, + listeners: [ + { + triggers: [ + { + trigger: 'change', + when: ({ value }) => value.displayName.length > 0, + }, + ], + triggerDebounceMs: 200, + run: ({ value }) => { + saveDraft(value) + }, + }, + ], +}) +``` diff --git a/docs/reference/type-aliases/FormOptionsLooseSchemaFn.md b/docs/reference/type-aliases/FormOptionsLooseSchemaFn.md new file mode 100644 index 0000000000..73c7a1615d --- /dev/null +++ b/docs/reference/type-aliases/FormOptionsLooseSchemaFn.md @@ -0,0 +1,96 @@ +--- +id: FormOptionsLooseSchemaFn +title: FormOptionsLooseSchemaFn +--- + +```ts +type FormOptionsLooseSchemaFn = (schema, options) => FormOptions>, TFormValidators, TSubmitReturn, TComponents>; +``` + +Defined in: [utils.public.ts:174](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.public.ts#L174) + +Types loose schema form options using a separate schema as the source of the +final valid form shape. + +`defaultValues` infer an editable form shape constrained by the schema input, +so properties may be omitted or contain `null` or `undefined`. Callback +validator `value` parameters use that editable shape merged with the schema +input. + +The first argument is used only by TypeScript and is ignored at runtime. +Include the schema in `validators` as well when it should validate the form. +Parsed results are available in the corresponding `validatorOutputs` entries +during submission. + +## Type Parameters + +### TComponents + +`TComponents` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TSchema + +`TSchema` *extends* [`StandardSchemaV1`](StandardSchemaV1.md)\<`any`, `any`\> + +Library-managed. Do not specify explicitly. + +### TFormData + +`TFormData` *extends* [`Editable`](Editable.md)\<`StandardSchemaInput`\<`TSchema`\>\> + +Library-managed. Do not specify explicitly. + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](FormValidators.md)\<`NoInfer`\<[`InferUnion`](InferUnion.md)\<`TFormData`, `StandardSchemaInput`\<`TSchema`\>\>\>\> + +Library-managed. Do not specify explicitly. + +### TSubmitReturn + +`TSubmitReturn` + +Library-managed. Do not specify explicitly. + +## Parameters + +### schema + +`TSchema` + +Supplies the final valid form shape without registering a +validator. + +### options + +`LooseSchemaFormOptions`\<`StandardSchemaInput`\<`TSchema`\>, `TFormData`, `TFormValidators`, `TSubmitReturn`\> + +The form options used to infer the editable form shape. + +## Returns + +[`FormOptions`](../interfaces/FormOptions.md)\<[`InferUnion`](InferUnion.md)\<`TFormData`, `StandardSchemaInput`\<`TSchema`\>\>, `TFormValidators`, `TSubmitReturn`, `TComponents`\> + +The original options object, normalized to `FormOptions` with the +editable states merged into the schema input. + +## Example + +```ts +const bookingSchema = z.object({ startDate: z.date() }) +const bookingOptions = formOptions.looseSchema(bookingSchema, { + defaultValues: { startDate: null }, + validators: [ + { triggers: ['blur'], run: bookingSchema }, + { + triggers: ['change'], + run: ({ value }) => + value.startDate === null ? 'Choose a date' : undefined, + }, + ], +}) +``` diff --git a/docs/reference/type-aliases/FormOptionsStrictSchemaFn.md b/docs/reference/type-aliases/FormOptionsStrictSchemaFn.md new file mode 100644 index 0000000000..539f300dd0 --- /dev/null +++ b/docs/reference/type-aliases/FormOptionsStrictSchemaFn.md @@ -0,0 +1,88 @@ +--- +id: FormOptionsStrictSchemaFn +title: FormOptionsStrictSchemaFn +--- + +```ts +type FormOptionsStrictSchemaFn = (schema, options) => FormOptions, TFormValidators, TSubmitReturn, TComponents>; +``` + +Defined in: [utils.public.ts:114](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.public.ts#L114) + +Types strict form options using a separate schema as the source of the form +data type. + +The schema input fixes the form data type before the options are inferred, +so `defaultValues` and each callback validator's `value` use the exact +schema input type. + +The first argument is used only by TypeScript and is ignored at runtime. +Include the schema in `validators` as well when it should validate the form. +Parsed results are available in the corresponding `validatorOutputs` entries +during submission. + +## Type Parameters + +### TComponents + +`TComponents` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TSchema + +`TSchema` *extends* [`StandardSchemaV1`](StandardSchemaV1.md)\<`any`, `any`\> + +Library-managed. Do not specify explicitly. + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](FormValidators.md)\<`StandardSchemaInput`\<`TSchema`\>\> + +Library-managed. Do not specify explicitly. + +### TSubmitReturn + +`TSubmitReturn` + +Library-managed. Do not specify explicitly. + +## Parameters + +### schema + +`TSchema` + +Supplies the form data type without registering a validator. + +### options + +[`FormOptions`](../interfaces/FormOptions.md)\<`StandardSchemaInput`\<`TSchema`\>, `TFormValidators`, `TSubmitReturn`, `unknown`\> + +The form options to type against the schema input. + +## Returns + +[`FormOptions`](../interfaces/FormOptions.md)\<`StandardSchemaInput`\<`TSchema`\>, `TFormValidators`, `TSubmitReturn`, `TComponents`\> + +The original options object, normalized to `FormOptions` with the +schema input as its form data type. + +## Example + +```ts +const profileSchema = z.object({ name: z.string().min(1) }) +const profileOptions = formOptions.strictSchema(profileSchema, { + defaultValues: { name: '' }, + validators: [ + { triggers: ['change'], run: profileSchema }, + { + triggers: ['change'], + run: ({ value }) => + value.name.length === 0 ? 'Name is required' : undefined, + }, + ], +}) +``` diff --git a/docs/reference/type-aliases/FormSubmitFn.md b/docs/reference/type-aliases/FormSubmitFn.md new file mode 100644 index 0000000000..1f24599e51 --- /dev/null +++ b/docs/reference/type-aliases/FormSubmitFn.md @@ -0,0 +1,46 @@ +--- +id: FormSubmitFn +title: FormSubmitFn +--- + +```ts +type FormSubmitFn = (context) => TSubmitReturn; +``` + +Defined in: [FormApi/FormApi.public.ts:190](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L190) + +Handles a form submission after submission validation succeeds. + +A returned promise is awaited before submission finishes. Return an error +created by the submission context's `createValidationError` or `parseIssues` +helper to mark the submission as invalid. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](FormValidators.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +### TSubmitReturn + +`TSubmitReturn` + +Library-managed. Do not specify explicitly. + +## Parameters + +### context + +[`FormSubmitContext`](../interfaces/FormSubmitContext.md)\<`TFormData`, [`ToFormOutputs`](ToFormOutputs.md)\<`TFormValidators`\>, [`ToFormErrorTypes`](ToFormErrorTypes.md)\<`TFormValidators`, `unknown`\>\> + +## Returns + +`TSubmitReturn` diff --git a/docs/reference/type-aliases/FormValidateFn.md b/docs/reference/type-aliases/FormValidateFn.md deleted file mode 100644 index ddcaa18ee3..0000000000 --- a/docs/reference/type-aliases/FormValidateFn.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -id: FormValidateFn -title: FormValidateFn ---- - -# Type Alias: FormValidateFn()\ - -```ts -type FormValidateFn = (props) => unknown; -``` - -Defined in: [packages/form-core/src/FormApi.ts:96](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L96) - -## Type Parameters - -### TFormData - -`TFormData` - -## Parameters - -### props - -#### formApi - -[`FormApi`](../classes/FormApi.md)\<`TFormData`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`\> - -#### value - -`TFormData` - -## Returns - -`unknown` diff --git a/docs/reference/type-aliases/FormValidateResult.md b/docs/reference/type-aliases/FormValidateResult.md new file mode 100644 index 0000000000..e89a768828 --- /dev/null +++ b/docs/reference/type-aliases/FormValidateResult.md @@ -0,0 +1,22 @@ +--- +id: FormValidateResult +title: FormValidateResult +--- + +```ts +type FormValidateResult = + | SuccessfulValidationResult +| FormValidationError; +``` + +Defined in: [validation.public.ts:778](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L778) + +A form validator's success result, output data, or validation errors. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/FormValidateResultFromErrorTypes.md b/docs/reference/type-aliases/FormValidateResultFromErrorTypes.md new file mode 100644 index 0000000000..007df2a9b5 --- /dev/null +++ b/docs/reference/type-aliases/FormValidateResultFromErrorTypes.md @@ -0,0 +1,32 @@ +--- +id: FormValidateResultFromErrorTypes +title: FormValidateResultFromErrorTypes +--- + +```ts +type FormValidateResultFromErrorTypes = + | ValidValidationResult + | ValidationErrorInputFromType + | { + fields: Partial, ValidationErrorInputFromType>>; + form?: ValidationErrorInputFromType; +}; +``` + +Defined in: [validation.public.ts:1129](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1129) + +Form validation results constrained to inferred issue types, as stored in server form state. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](../interfaces/FormErrorTypes.md) + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/FormValidationError.md b/docs/reference/type-aliases/FormValidationError.md index 28d89fca7f..9a95f07207 100644 --- a/docs/reference/type-aliases/FormValidationError.md +++ b/docs/reference/type-aliases/FormValidationError.md @@ -3,18 +3,20 @@ id: FormValidationError title: FormValidationError --- -# Type Alias: FormValidationError\ - ```ts type FormValidationError = - | ValidationError -| GlobalFormValidationError; + | ValidationErrorInput +| ValidationErrorMap; ``` -Defined in: [packages/form-core/src/types.ts:132](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L132) +Defined in: [validation.public.ts:771](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L771) + +Errors for a form, optionally including errors routed to individual fields. ## Type Parameters ### TFormData `TFormData` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/FormValidationTriggerOption.md b/docs/reference/type-aliases/FormValidationTriggerOption.md new file mode 100644 index 0000000000..479c953cb2 --- /dev/null +++ b/docs/reference/type-aliases/FormValidationTriggerOption.md @@ -0,0 +1,37 @@ +--- +id: FormValidationTriggerOption +title: FormValidationTriggerOption +--- + +```ts +type FormValidationTriggerOption = + | ClientValidationTriggerOption + | ServerValidationTrigger; +``` + +Defined in: [validation.public.ts:568](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L568) + +A client event with an optional condition, or the `'server'` event for a form validator. + +Server validation selects validators with a `'server'` trigger independently +of `skipOnSubmit`. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValue + +`TValue` + +Library-managed. Do not specify explicitly. + +### TScope + +`TScope` *extends* [`ValidatorScope`](ValidatorScope.md) = [`ValidatorScope`](ValidatorScope.md) + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/FormValidator.md b/docs/reference/type-aliases/FormValidator.md deleted file mode 100644 index b6cc76a42c..0000000000 --- a/docs/reference/type-aliases/FormValidator.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -id: FormValidator -title: FormValidator ---- - -# Type Alias: FormValidator\ - -```ts -type FormValidator = object; -``` - -Defined in: [packages/form-core/src/FormApi.ts:155](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L155) - -## Type Parameters - -### TFormData - -`TFormData` - -### TType - -`TType` - -### TFn - -`TFn` = `unknown` - -## Methods - -### validate() - -```ts -validate(options, fn): unknown; -``` - -Defined in: [packages/form-core/src/FormApi.ts:156](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L156) - -#### Parameters - -##### options - -###### value - -`TType` - -##### fn - -`TFn` - -#### Returns - -`unknown` - -*** - -### validateAsync() - -```ts -validateAsync(options, fn): Promise; -``` - -Defined in: [packages/form-core/src/FormApi.ts:157](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L157) - -#### Parameters - -##### options - -###### value - -`TType` - -##### fn - -`TFn` - -#### Returns - -`Promise`\<`unknown`\> diff --git a/docs/reference/type-aliases/FormValidatorData.md b/docs/reference/type-aliases/FormValidatorData.md new file mode 100644 index 0000000000..46de460d16 --- /dev/null +++ b/docs/reference/type-aliases/FormValidatorData.md @@ -0,0 +1,16 @@ +--- +id: FormValidatorData +title: FormValidatorData +--- + +```ts +type FormValidatorData = TFormValidators extends FormValidators ? T : never; +``` + +Defined in: [utils.public.ts:48](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.public.ts#L48) + +## Type Parameters + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](FormValidators.md)\<`any`\> diff --git a/docs/reference/type-aliases/FormValidatorFn.md b/docs/reference/type-aliases/FormValidatorFn.md new file mode 100644 index 0000000000..14182ddc30 --- /dev/null +++ b/docs/reference/type-aliases/FormValidatorFn.md @@ -0,0 +1,20 @@ +--- +id: FormValidatorFn +title: FormValidatorFn +--- + +```ts +type FormValidatorFn = ValidatorFn, FormValidateResult>; +``` + +Defined in: [validation.public.ts:796](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L796) + +Validates complete form values and can return form errors, field errors, or output data. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/FormValidators.md b/docs/reference/type-aliases/FormValidators.md new file mode 100644 index 0000000000..73deeb4802 --- /dev/null +++ b/docs/reference/type-aliases/FormValidators.md @@ -0,0 +1,20 @@ +--- +id: FormValidators +title: FormValidators +--- + +```ts +type FormValidators = ReadonlyArray>; +``` + +Defined in: [validation.public.ts:860](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L860) + +Form validators in configuration order, which also determines their `validatorOutputs` indexes. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/GetFieldValueFn.md b/docs/reference/type-aliases/GetFieldValueFn.md new file mode 100644 index 0000000000..7c922e57e4 --- /dev/null +++ b/docs/reference/type-aliases/GetFieldValueFn.md @@ -0,0 +1,51 @@ +--- +id: GetFieldValueFn +title: GetFieldValueFn +--- + +```ts +type GetFieldValueFn = (DeepKeys) => DeepValue; +``` + +Defined in: [FormApi/FormApiFieldMethods.types.public.ts:47](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiFieldMethods.types.public.ts#L47) + +Reads the current value at a field path. + +This is a read-only operation and does not create a `FieldApi` for the path. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TDeepKeys + +`TDeepKeys` *extends* [`DeepKeys`](DeepKeys.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### DeepKeys + +`TDeepKeys` + +The field path to read. + +## Returns + +[`DeepValue`](DeepValue.md)\<`TFormData`, `TDeepKeys`\> + +The current value at the path, or `undefined` when the path cannot +be resolved at runtime. + +## Example + +```ts +const name = formApi.getFieldValue('profile.name') +``` diff --git a/docs/reference/type-aliases/HandleSubmitFn.md b/docs/reference/type-aliases/HandleSubmitFn.md new file mode 100644 index 0000000000..823f5d4bb5 --- /dev/null +++ b/docs/reference/type-aliases/HandleSubmitFn.md @@ -0,0 +1,38 @@ +--- +id: HandleSubmitFn +title: HandleSubmitFn +--- + +```ts +type HandleSubmitFn = () => Promise[]>; +``` + +Defined in: [FormApi/FormApi.public.ts:605](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L605) + +Runs submission validation and submits current values when validation +succeeds. + +Registered fields are marked touched, field validators run before form +validators, and `onSubmit` is awaited only when validation succeeds. +Validation error results and errors returned by `onSubmit` through +`createValidationError` are stored as error state. `onSubmitInvalid` is +awaited after a failed attempt. + +Calls made while an attempt is in progress return the same promise instead +of starting another attempt. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Returns + +`Promise`\<[`FormValidationError`](FormValidationError.md)\<`TFormData`\>[]\> + +A promise resolving to the error results produced by field and +form validation, plus any validation error returned by `onSubmit` through +`createValidationError`. The array is empty if none are produced. diff --git a/docs/reference/type-aliases/InferUnion.md b/docs/reference/type-aliases/InferUnion.md new file mode 100644 index 0000000000..5e1f26f4d3 --- /dev/null +++ b/docs/reference/type-aliases/InferUnion.md @@ -0,0 +1,20 @@ +--- +id: InferUnion +title: InferUnion +--- + +```ts +type InferUnion = TBase extends BuiltInType ? TBase | TIncoming : TIncoming extends BuiltInType ? TBase | TIncoming : TBase extends ReadonlyArray ? TIncoming extends ReadonlyArray ? InferUnion[] : TBase | TIncoming : TBase extends object ? TIncoming extends object ? InferUnionObject : TBase | TIncoming : TBase | TIncoming; +``` + +Defined in: [utils.public.ts:21](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.public.ts#L21) + +## Type Parameters + +### TBase + +`TBase` + +### TIncoming + +`TIncoming` diff --git a/docs/reference/type-aliases/InsertFieldValueFn.md b/docs/reference/type-aliases/InsertFieldValueFn.md new file mode 100644 index 0000000000..252303ef43 --- /dev/null +++ b/docs/reference/type-aliases/InsertFieldValueFn.md @@ -0,0 +1,73 @@ +--- +id: InsertFieldValueFn +title: InsertFieldValueFn +--- + +```ts +type InsertFieldValueFn = (arrayFieldName, index, value, options?) => void; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:190](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L190) + +Inserts an element at an index in an array field. + +Inserting at the array length appends the element. An invalid index or a +runtime value that is not an array produces a warning and leaves the value +unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* [`ArrayFieldName`](ArrayFieldName.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### arrayFieldName + +`TFieldName` + +The array field path. + +### index + +`number` + +The insertion index, from `0` through `array.length`. + +### value + +[`ArrayFieldElement`](ArrayFieldElement.md)\<`TFormData`, `TFieldName`\> + +The element to insert. + +### options? + +[`FieldUpdateOptions`](../interfaces/FieldUpdateOptions.md) + +Controls metadata updates and whether validation runs. + +## Returns + +`void` + +## Example + +```ts +// items: ['first', 'second'] +formApi.insertFieldValue('items', 1, 'new item') +// items: ['first', 'new item', 'second'] +``` diff --git a/docs/reference/type-aliases/ListenerDebounceFn.md b/docs/reference/type-aliases/ListenerDebounceFn.md new file mode 100644 index 0000000000..51ce9b6ebf --- /dev/null +++ b/docs/reference/type-aliases/ListenerDebounceFn.md @@ -0,0 +1,48 @@ +--- +id: ListenerDebounceFn +title: ListenerDebounceFn +--- + +```ts +type ListenerDebounceFn = (context) => number; +``` + +Defined in: [listeners.public.ts:147](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L147) + +Calculates a listener's debounce delay from the current event context. + +The function is called after a trigger matches and its condition is enabled. +The returned number is interpreted as milliseconds; values less than or +equal to `0` run immediately. The function is not called for `'submit'` +events because they always run immediately. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValue + +`TValue` + +Library-managed. Do not specify explicitly. + +## Parameters + +### context + +[`ListenerPredicateContext`](../interfaces/ListenerPredicateContext.md)\<`TFormData`, `TValue`\> + +## Returns + +`number` + +## Example + +```ts +triggerDebounceMs: ({ triggerFieldApi }) => + triggerFieldApi?.name === 'search' ? 300 : 0, +``` diff --git a/docs/reference/type-aliases/ListenerPredicateFn.md b/docs/reference/type-aliases/ListenerPredicateFn.md new file mode 100644 index 0000000000..bfa20d5651 --- /dev/null +++ b/docs/reference/type-aliases/ListenerPredicateFn.md @@ -0,0 +1,45 @@ +--- +id: ListenerPredicateFn +title: ListenerPredicateFn +--- + +```ts +type ListenerPredicateFn = (context) => boolean; +``` + +Defined in: [listeners.public.ts:69](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L69) + +Decides whether a listener is enabled for a matching event. + +The predicate is only called after its configured trigger matches the +current event. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValue + +`TValue` + +Library-managed. Do not specify explicitly. + +## Parameters + +### context + +[`ListenerPredicateContext`](../interfaces/ListenerPredicateContext.md)\<`TFormData`, `TValue`\> + +## Returns + +`boolean` + +## Example + +```ts +when: ({ formApi }) => formApi.state.isDirty, +``` diff --git a/docs/reference/type-aliases/ListenerTriggerOption.md b/docs/reference/type-aliases/ListenerTriggerOption.md new file mode 100644 index 0000000000..36d635832f --- /dev/null +++ b/docs/reference/type-aliases/ListenerTriggerOption.md @@ -0,0 +1,50 @@ +--- +id: ListenerTriggerOption +title: ListenerTriggerOption +--- + +```ts +type ListenerTriggerOption = + | TTriggers +| ListenerTriggerConfig; +``` + +Defined in: [listeners.public.ts:124](https://github.com/TanStack/form/blob/main/packages/form-core/src/listeners.public.ts#L124) + +A listener event, optionally paired with a condition that enables it. + +A string enables the trigger unconditionally. Use the object form to add a +boolean or predicate condition. Omitting `when` from the object form also +enables the trigger unconditionally. + +## Type Parameters + +### TTriggers + +`TTriggers` *extends* [`FieldListenerTriggers`](FieldListenerTriggers.md) + +Library-managed. Do not specify explicitly. + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValue + +`TValue` + +Library-managed. Do not specify explicitly. + +## Example + +```ts +triggers: [ + 'blur', + { + trigger: 'change', + when: ({ formApi }) => formApi.state.isDirty, + }, +], +``` diff --git a/docs/reference/type-aliases/LooseFieldGroupFieldSlot.md b/docs/reference/type-aliases/LooseFieldGroupFieldSlot.md new file mode 100644 index 0000000000..311f19efb9 --- /dev/null +++ b/docs/reference/type-aliases/LooseFieldGroupFieldSlot.md @@ -0,0 +1,22 @@ +--- +id: LooseFieldGroupFieldSlot +title: LooseFieldGroupFieldSlot +--- + +```ts +type LooseFieldGroupFieldSlot = FieldGroupFieldSlot; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:57](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L57) + +A virtual field slot that binds to form fields whose value type is +assignable to `TValue`. + +## Type Parameters + +### TValue + +`TValue` + +The value type that compatible concrete field values +must be assignable to. diff --git a/docs/reference/type-aliases/MoveFieldValueFn.md b/docs/reference/type-aliases/MoveFieldValueFn.md new file mode 100644 index 0000000000..0d445fe21c --- /dev/null +++ b/docs/reference/type-aliases/MoveFieldValueFn.md @@ -0,0 +1,72 @@ +--- +id: MoveFieldValueFn +title: MoveFieldValueFn +--- + +```ts +type MoveFieldValueFn = (arrayFieldName, fromIndex, toIndex, options?) => void; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:129](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L129) + +Moves an element to another index in an array field. + +Passing equal indices does nothing. Invalid indices or a runtime value that +is not an array produce a warning and leave the value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* [`ArrayFieldName`](ArrayFieldName.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### arrayFieldName + +`TFieldName` + +The array field path. + +### fromIndex + +`number` + +The current index, from `0` through `array.length - 1`. + +### toIndex + +`number` + +The destination index, from `0` through `array.length - 1`. + +### options? + +[`FieldUpdateOptions`](../interfaces/FieldUpdateOptions.md) + +Controls metadata updates and whether validation runs. + +## Returns + +`void` + +## Example + +```ts +// items: ['first', 'second', 'third'] +formApi.moveFieldValue('items', 0, 2) +// items: ['second', 'third', 'first'] +``` diff --git a/docs/reference/type-aliases/Nullable.md b/docs/reference/type-aliases/Nullable.md deleted file mode 100644 index f9471dd774..0000000000 --- a/docs/reference/type-aliases/Nullable.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: Nullable -title: Nullable ---- - -# Type Alias: Nullable\ - -```ts -type Nullable = T & undefined | null; -``` - -Defined in: [packages/form-core/src/util-types.ts:106](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L106) - -## Type Parameters - -### T - -`T` diff --git a/docs/reference/type-aliases/NullableSchemaData.md b/docs/reference/type-aliases/NullableSchemaData.md new file mode 100644 index 0000000000..ca3b03dc0c --- /dev/null +++ b/docs/reference/type-aliases/NullableSchemaData.md @@ -0,0 +1,16 @@ +--- +id: NullableSchemaData +title: NullableSchemaData +--- + +```ts +type NullableSchemaData = Editable>; +``` + +Defined in: [utils.public.ts:51](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.public.ts#L51) + +## Type Parameters + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](FormValidators.md)\<`any`\> diff --git a/docs/reference/type-aliases/ObjectAccessor.md b/docs/reference/type-aliases/ObjectAccessor.md deleted file mode 100644 index 75b7b60dc1..0000000000 --- a/docs/reference/type-aliases/ObjectAccessor.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -id: ObjectAccessor -title: ObjectAccessor ---- - -# Type Alias: ObjectAccessor\ - -```ts -type ObjectAccessor = TParent["key"] extends never ? `${TKey}` : `${TParent["key"]}.${TKey}`; -``` - -Defined in: [packages/form-core/src/util-types.ts:101](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L101) - -## Type Parameters - -### TParent - -`TParent` *extends* [`AnyDeepKeyAndValue`](../interfaces/AnyDeepKeyAndValue.md) - -### TKey - -`TKey` *extends* `string` \| `number` diff --git a/docs/reference/type-aliases/ObjectValue.md b/docs/reference/type-aliases/ObjectValue.md deleted file mode 100644 index 30e536b8da..0000000000 --- a/docs/reference/type-aliases/ObjectValue.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -id: ObjectValue -title: ObjectValue ---- - -# Type Alias: ObjectValue\ - -```ts -type ObjectValue = T[TKey] | Nullable; -``` - -Defined in: [packages/form-core/src/util-types.ts:108](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L108) - -## Type Parameters - -### TParent - -`TParent` *extends* [`AnyDeepKeyAndValue`](../interfaces/AnyDeepKeyAndValue.md) - -### T - -`T` - -### TKey - -`TKey` *extends* [`AllObjectKeys`](AllObjectKeys.md)\<`T`\> diff --git a/docs/reference/type-aliases/OnSubmitError.md b/docs/reference/type-aliases/OnSubmitError.md new file mode 100644 index 0000000000..cede4c1407 --- /dev/null +++ b/docs/reference/type-aliases/OnSubmitError.md @@ -0,0 +1,49 @@ +--- +id: OnSubmitError +title: OnSubmitError +--- + +```ts +type OnSubmitError = object; +``` + +Defined in: [FormApi/FormApi.public.ts:44](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L44) + +A validation error wrapped for processing as an `onSubmit` failure. + +Create this value with the `createValidationError` or `parseIssues` helper +provided to `onSubmit`, then return it from the callback so its form- and +field-level errors are added to validation state. + +## Example + +```ts +formOptions({ + defaultValues: { name: '' }, + onSubmit: async ({ value, createValidationError }) => { + const result = await saveUser(value) + + if (!result.ok) { + return createValidationError(result.error) + } + }, +}) +``` + +## Type Parameters + +### TFormValidationError + +`TFormValidationError` *extends* [`FormValidationError`](FormValidationError.md)\<`any`\> + +Library-managed. Do not specify explicitly. + +## Properties + +### \[SUBMIT\_ERROR\] + +```ts +readonly [SUBMIT_ERROR]: TFormValidationError; +``` + +Defined in: [FormApi/FormApi.public.ts:47](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L47) diff --git a/docs/reference/type-aliases/OneOrMany.md b/docs/reference/type-aliases/OneOrMany.md new file mode 100644 index 0000000000..8f962f90d6 --- /dev/null +++ b/docs/reference/type-aliases/OneOrMany.md @@ -0,0 +1,16 @@ +--- +id: OneOrMany +title: OneOrMany +--- + +```ts +type OneOrMany = TValue | TValue[]; +``` + +Defined in: [types.public.ts:33](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.public.ts#L33) + +## Type Parameters + +### TValue + +`TValue` diff --git a/docs/reference/type-aliases/ParseFieldIssuesFn.md b/docs/reference/type-aliases/ParseFieldIssuesFn.md new file mode 100644 index 0000000000..b90ba22cd5 --- /dev/null +++ b/docs/reference/type-aliases/ParseFieldIssuesFn.md @@ -0,0 +1,24 @@ +--- +id: ParseFieldIssuesFn +title: ParseFieldIssuesFn +--- + +```ts +type ParseFieldIssuesFn = (issues) => StandardSchemaV1Issue[]; +``` + +Defined in: [validation.public.ts:649](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L649) + +Converts Standard Schema issues into errors owned by the field being validated. + +## Parameters + +### issues + +`ReadonlyArray`\<[`StandardSchemaV1Issue`](../interfaces/StandardSchemaV1Issue.md)\> + +## Returns + +[`StandardSchemaV1Issue`](../interfaces/StandardSchemaV1Issue.md)[] + +A copy of the issue array. Issue paths do not route errors to other fields. diff --git a/docs/reference/type-aliases/ParseFormIssuesFn.md b/docs/reference/type-aliases/ParseFormIssuesFn.md new file mode 100644 index 0000000000..f0a16c164f --- /dev/null +++ b/docs/reference/type-aliases/ParseFormIssuesFn.md @@ -0,0 +1,32 @@ +--- +id: ParseFormIssuesFn +title: ParseFormIssuesFn +--- + +```ts +type ParseFormIssuesFn = (issues) => ParsedStandardSchemaIssues; +``` + +Defined in: [validation.public.ts:659](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L659) + +Converts Standard Schema issues into a form or group error map to return from a validator. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Parameters + +### issues + +`ReadonlyArray`\<[`StandardSchemaV1Issue`](../interfaces/StandardSchemaV1Issue.md)\> + +## Returns + +[`ParsedStandardSchemaIssues`](../interfaces/ParsedStandardSchemaIssues.md)\<`TFormData`\> + +All issues in `form`, with issues that have paths also grouped in `fields`. diff --git a/docs/reference/type-aliases/ParseSubmitIssuesFn.md b/docs/reference/type-aliases/ParseSubmitIssuesFn.md new file mode 100644 index 0000000000..de6cfe826f --- /dev/null +++ b/docs/reference/type-aliases/ParseSubmitIssuesFn.md @@ -0,0 +1,35 @@ +--- +id: ParseSubmitIssuesFn +title: ParseSubmitIssuesFn +--- + +```ts +type ParseSubmitIssuesFn = (issues) => OnSubmitError>; +``` + +Defined in: [FormApi/FormApi.public.ts:80](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L80) + +Converts Standard Schema issues into an `onSubmit` validation error. + +Issue paths are mapped to fields in the submitted value. Return the result +from `onSubmit` to add the parsed errors to validation state. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Parameters + +### issues + +`ReadonlyArray`\<[`StandardSchemaV1Issue`](../interfaces/StandardSchemaV1Issue.md)\> + +The Standard Schema issues to convert. + +## Returns + +[`OnSubmitError`](OnSubmitError.md)\<[`ParsedStandardSchemaIssues`](../interfaces/ParsedStandardSchemaIssues.md)\<`TFormData`\>\> diff --git a/docs/reference/type-aliases/PushFieldValueFn.md b/docs/reference/type-aliases/PushFieldValueFn.md new file mode 100644 index 0000000000..9207408b4c --- /dev/null +++ b/docs/reference/type-aliases/PushFieldValueFn.md @@ -0,0 +1,64 @@ +--- +id: PushFieldValueFn +title: PushFieldValueFn +--- + +```ts +type PushFieldValueFn = (arrayFieldName, value, options?) => void; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:158](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L158) + +Appends an element to an array field. + +A runtime value that is not an array produces a warning and is left +unchanged. By default, the update marks the array field as touched and +dirty, notifies change listeners, and runs change validation. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* [`ArrayFieldName`](ArrayFieldName.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### arrayFieldName + +`TFieldName` + +The array field path. + +### value + +[`ArrayFieldElement`](ArrayFieldElement.md)\<`TFormData`, `TFieldName`\> + +The element to append. + +### options? + +[`FieldUpdateOptions`](../interfaces/FieldUpdateOptions.md) + +Controls metadata updates and whether validation runs. + +## Returns + +`void` + +## Example + +```ts +// items: ['first', 'second'] +formApi.pushFieldValue('items', 'new item') +// items: ['first', 'second', 'new item'] +``` diff --git a/docs/reference/type-aliases/RemoveFieldValueFn.md b/docs/reference/type-aliases/RemoveFieldValueFn.md new file mode 100644 index 0000000000..89ce5438dd --- /dev/null +++ b/docs/reference/type-aliases/RemoveFieldValueFn.md @@ -0,0 +1,66 @@ +--- +id: RemoveFieldValueFn +title: RemoveFieldValueFn +--- + +```ts +type RemoveFieldValueFn = (arrayFieldName, index, options?) => void; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:247](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L247) + +Removes an element from an array field. + +An invalid index or a runtime value that is not an array produces a warning +and leaves the value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* [`ArrayFieldName`](ArrayFieldName.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### arrayFieldName + +`TFieldName` + +The array field path. + +### index + +`number` + +The index to remove, from `0` through `array.length - 1`. + +### options? + +[`FieldUpdateOptions`](../interfaces/FieldUpdateOptions.md) + +Controls metadata updates and whether validation runs. + +## Returns + +`void` + +## Example + +```ts +// items: ['first', 'second', 'third'] +formApi.removeFieldValue('items', 1) +// items: ['first', 'third'] +``` diff --git a/docs/reference/type-aliases/ReplaceFieldValueFn.md b/docs/reference/type-aliases/ReplaceFieldValueFn.md new file mode 100644 index 0000000000..7e6f88aebd --- /dev/null +++ b/docs/reference/type-aliases/ReplaceFieldValueFn.md @@ -0,0 +1,72 @@ +--- +id: ReplaceFieldValueFn +title: ReplaceFieldValueFn +--- + +```ts +type ReplaceFieldValueFn = (arrayFieldName, index, value, options?) => void; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:278](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L278) + +Replaces the element at an index in an array field. + +An invalid index or a runtime value that is not an array produces a warning +and leaves the value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* [`ArrayFieldName`](ArrayFieldName.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### arrayFieldName + +`TFieldName` + +The array field path. + +### index + +`number` + +The index to replace, from `0` through `array.length - 1`. + +### value + +[`ArrayFieldElement`](ArrayFieldElement.md)\<`TFormData`, `TFieldName`\> + +The new element. + +### options? + +[`FieldUpdateOptions`](../interfaces/FieldUpdateOptions.md) + +Controls metadata updates and whether validation runs. + +## Returns + +`void` + +## Example + +```ts +// items: ['first', 'second', 'third'] +formApi.replaceFieldValue('items', 1, 'new item') +// items: ['first', 'new item', 'third'] +``` diff --git a/docs/reference/type-aliases/ResetFieldFn.md b/docs/reference/type-aliases/ResetFieldFn.md new file mode 100644 index 0000000000..be8189d408 --- /dev/null +++ b/docs/reference/type-aliases/ResetFieldFn.md @@ -0,0 +1,54 @@ +--- +id: ResetFieldFn +title: ResetFieldFn +--- + +```ts +type ResetFieldFn = (DeepKeys) => void; +``` + +Defined in: [FormApi/FormApiFieldMethods.types.public.ts:73](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiFieldMethods.types.public.ts#L73) + +Restores a field path from `defaultValues` and resets state for its field +subtree. + +Existing `FieldApi` instances at or below the path remain mounted. Pending +validation is canceled, field metadata is cleared, and reset listeners are +notified. Form-wide dirty history remains unchanged; use `formApi.reset()` +to clear it. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TDeepKeys + +`TDeepKeys` *extends* [`DeepKeys`](DeepKeys.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### DeepKeys + +`TDeepKeys` + +The field path to reset. + +## Returns + +`void` + +## Example + +```ts +formApi.setFieldValue('profile.name', 'Grace') +formApi.resetField('profile.name') +// `profile.name` is restored from `defaultValues`. +``` diff --git a/docs/reference/type-aliases/ResetFn.md b/docs/reference/type-aliases/ResetFn.md new file mode 100644 index 0000000000..accef1df73 --- /dev/null +++ b/docs/reference/type-aliases/ResetFn.md @@ -0,0 +1,46 @@ +--- +id: ResetFn +title: ResetFn +--- + +```ts +type ResetFn = (values?, opts?) => void; +``` + +Defined in: [FormApi/FormApi.public.ts:624](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApi.public.ts#L624) + +Resets form values, metadata, validation state, and mounted fields. + +Calling without values restores the current `defaultValues`. Supplying +values sets the current values and also updates `defaultValues` to those +values. This can apply expected values immediately while fresh data is +fetched from the backend. + +Results from validation or submission work pending at reset are discarded. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Parameters + +### values? + +`TFormData` + +Values to apply, or omit to restore `defaultValues`. + +### opts? + +[`FormResetOptions`](../interfaces/FormResetOptions.md) + +Options controlling whether supplied values replace +`defaultValues`. + +## Returns + +`void` diff --git a/docs/reference/type-aliases/ReusableErrorVisibility.md b/docs/reference/type-aliases/ReusableErrorVisibility.md new file mode 100644 index 0000000000..dfaddaccd1 --- /dev/null +++ b/docs/reference/type-aliases/ReusableErrorVisibility.md @@ -0,0 +1,36 @@ +--- +id: ReusableErrorVisibility +title: ReusableErrorVisibility +--- + +```ts +type ReusableErrorVisibility = (context) => boolean; +``` + +Defined in: [validation.public.ts:372](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L372) + +An error visibility policy that accepts forms with different value and error types. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](../interfaces/FormErrorTypes.md) + +Library-managed. Do not specify explicitly. + +## Parameters + +### context + +[`ErrorVisibilityContext`](../interfaces/ErrorVisibilityContext.md)\<`TFormData`, `TFormErrorTypes`\> + +## Returns + +`boolean` diff --git a/docs/reference/type-aliases/ReusableErrorVisibilityState.md b/docs/reference/type-aliases/ReusableErrorVisibilityState.md new file mode 100644 index 0000000000..6c29a869b7 --- /dev/null +++ b/docs/reference/type-aliases/ReusableErrorVisibilityState.md @@ -0,0 +1,24 @@ +--- +id: ReusableErrorVisibilityState +title: ReusableErrorVisibilityState +--- + +```ts +type ReusableErrorVisibilityState = Omit["state"], "values"> & object; +``` + +Defined in: [validation.public.ts:350](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L350) + +Form or group state available to a reusable error visibility policy. + +`values` is `unknown` because the policy can be used with different form shapes. + +## Type Declaration + +### values + +```ts +values: unknown; +``` + +Current form values, without assuming a particular form shape. diff --git a/docs/reference/type-aliases/ServerFormState.md b/docs/reference/type-aliases/ServerFormState.md new file mode 100644 index 0000000000..3bbdd945eb --- /dev/null +++ b/docs/reference/type-aliases/ServerFormState.md @@ -0,0 +1,20 @@ +--- +id: ServerFormState +title: ServerFormState +--- + +```ts +type ServerFormState = ServerFormStateByResult>>; +``` + +Defined in: [ssr.public.ts:45](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L45) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](FormValidators.md)\<`TFormData`\> diff --git a/docs/reference/type-aliases/ServerFormValidatorFn.md b/docs/reference/type-aliases/ServerFormValidatorFn.md new file mode 100644 index 0000000000..b6c42a195d --- /dev/null +++ b/docs/reference/type-aliases/ServerFormValidatorFn.md @@ -0,0 +1,20 @@ +--- +id: ServerFormValidatorFn +title: ServerFormValidatorFn +--- + +```ts +type ServerFormValidatorFn = ValidatorFn, FormValidateResult>; +``` + +Defined in: [validation.public.ts:806](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L806) + +Validates submitted form values on the server without a client form instance. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/ServerValidateResult.md b/docs/reference/type-aliases/ServerValidateResult.md new file mode 100644 index 0000000000..6fc090b11e --- /dev/null +++ b/docs/reference/type-aliases/ServerValidateResult.md @@ -0,0 +1,22 @@ +--- +id: ServerValidateResult +title: ServerValidateResult +--- + +```ts +type ServerValidateResult = + | ServerValidateSuccess +| ServerValidateFailure; +``` + +Defined in: [ssr.public.ts:78](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L78) + +## Type Parameters + +### TFormData + +`TFormData` + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](FormValidators.md)\<`TFormData`\> diff --git a/docs/reference/type-aliases/ServerValidationTrigger.md b/docs/reference/type-aliases/ServerValidationTrigger.md new file mode 100644 index 0000000000..c37ab7b213 --- /dev/null +++ b/docs/reference/type-aliases/ServerValidationTrigger.md @@ -0,0 +1,12 @@ +--- +id: ServerValidationTrigger +title: ServerValidationTrigger +--- + +```ts +type ServerValidationTrigger = "server"; +``` + +Defined in: [validation.public.ts:255](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L255) + +Selects a form validator for execution by `serverValidate`. diff --git a/docs/reference/type-aliases/SetFieldValueFn.md b/docs/reference/type-aliases/SetFieldValueFn.md new file mode 100644 index 0000000000..a137dbb6ab --- /dev/null +++ b/docs/reference/type-aliases/SetFieldValueFn.md @@ -0,0 +1,63 @@ +--- +id: SetFieldValueFn +title: SetFieldValueFn +--- + +```ts +type SetFieldValueFn = (DeepKeys, value, options?) => void; +``` + +Defined in: [FormApi/FormApiFieldMethods.types.public.ts:23](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiFieldMethods.types.public.ts#L23) + +Updates the current value at a field path. + +The next value may be supplied directly or calculated from the current +value. By default, the update marks the field as touched and dirty, notifies +change listeners, and runs change validation. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TDeepKeys + +`TDeepKeys` *extends* [`DeepKeys`](DeepKeys.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### DeepKeys + +`TDeepKeys` + +The field path to update. + +### value + +[`Updater`](Updater.md)\<[`DeepValue`](DeepValue.md)\<`TFormData`, `TDeepKeys`\>\> + +The next value or an updater that receives the current value. + +### options? + +[`FieldUpdateOptions`](../interfaces/FieldUpdateOptions.md) + +Controls metadata updates and whether validation runs. + +## Returns + +`void` + +## Example + +```ts +formApi.setFieldValue('profile.name', 'Ada') +formApi.setFieldValue('visitCount', (count) => count + 1) +``` diff --git a/docs/reference/type-aliases/StandardSchemaV1.md b/docs/reference/type-aliases/StandardSchemaV1.md index d1545f433f..b361be2299 100644 --- a/docs/reference/type-aliases/StandardSchemaV1.md +++ b/docs/reference/type-aliases/StandardSchemaV1.md @@ -3,34 +3,32 @@ id: StandardSchemaV1 title: StandardSchemaV1 --- -# Type Alias: StandardSchemaV1\ - ```ts -type StandardSchemaV1 = object; +type StandardSchemaV1 = object; ``` -Defined in: [packages/form-core/src/standardSchemaValidator.ts:120](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchemaValidator.ts#L120) +Defined in: [standardSchema.public.ts:10](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchema.public.ts#L10) The Standard Schema interface. ## Type Parameters -### Input +### TInput -`Input` = `unknown` +`TInput` = `unknown` -### Output +### TOutput -`Output` = `Input` +`TOutput` = `TInput` ## Properties ### ~standard ```ts -readonly ~standard: StandardSchemaV1Props; +readonly ~standard: StandardSchemaV1Props; ``` -Defined in: [packages/form-core/src/standardSchemaValidator.ts:124](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchemaValidator.ts#L124) +Defined in: [standardSchema.public.ts:14](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchema.public.ts#L14) The Standard Schema properties. diff --git a/docs/reference/type-aliases/StrictFieldGroupFieldSlot.md b/docs/reference/type-aliases/StrictFieldGroupFieldSlot.md new file mode 100644 index 0000000000..adac22a545 --- /dev/null +++ b/docs/reference/type-aliases/StrictFieldGroupFieldSlot.md @@ -0,0 +1,20 @@ +--- +id: StrictFieldGroupFieldSlot +title: StrictFieldGroupFieldSlot +--- + +```ts +type StrictFieldGroupFieldSlot = FieldGroupFieldSlot; +``` + +Defined in: [FieldGroup/fieldGroupTypes.public.ts:45](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldGroup/fieldGroupTypes.public.ts#L45) + +A virtual field slot that binds only to form fields with exactly `TValue`. + +## Type Parameters + +### TValue + +`TValue` + +The value type the concrete form field must match. diff --git a/docs/reference/type-aliases/SuccessfulValidationResult.md b/docs/reference/type-aliases/SuccessfulValidationResult.md new file mode 100644 index 0000000000..bdd62a7bbc --- /dev/null +++ b/docs/reference/type-aliases/SuccessfulValidationResult.md @@ -0,0 +1,14 @@ +--- +id: SuccessfulValidationResult +title: SuccessfulValidationResult +--- + +```ts +type SuccessfulValidationResult = + | ValidValidationResult +| ValidationOutput; +``` + +Defined in: [validation.public.ts:758](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L758) + +A validator return value that indicates success, with or without output data. diff --git a/docs/reference/type-aliases/SwapFieldValuesFn.md b/docs/reference/type-aliases/SwapFieldValuesFn.md new file mode 100644 index 0000000000..3d5188405f --- /dev/null +++ b/docs/reference/type-aliases/SwapFieldValuesFn.md @@ -0,0 +1,72 @@ +--- +id: SwapFieldValuesFn +title: SwapFieldValuesFn +--- + +```ts +type SwapFieldValuesFn = (arrayFieldName, indexA, indexB, options?) => void; +``` + +Defined in: [FormApi/FormApiArrayMethods.types.public.ts:97](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi/FormApiArrayMethods.types.public.ts#L97) + +Swaps two elements in an array field. + +Passing equal indices does nothing. Invalid indices or a runtime value that +is not an array produce a warning and leave the value unchanged. + +By default, the update marks the array field as touched and dirty, notifies +change listeners, and runs change validation. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +## Type Parameters + +### TFieldName + +`TFieldName` *extends* [`ArrayFieldName`](ArrayFieldName.md)\<`TFormData`\> + +Library-managed. Do not specify explicitly. + +## Parameters + +### arrayFieldName + +`TFieldName` + +The array field path. + +### indexA + +`number` + +The first index to swap, from `0` through `array.length - 1`. + +### indexB + +`number` + +The second index to swap, from `0` through `array.length - 1`. + +### options? + +[`FieldUpdateOptions`](../interfaces/FieldUpdateOptions.md) + +Controls metadata updates and whether validation runs. + +## Returns + +`void` + +## Example + +```ts +// items: ['first', 'second', 'third'] +formApi.swapFieldValues('items', 0, 2) +// items: ['third', 'second', 'first'] +``` diff --git a/docs/reference/type-aliases/TStandardSchemaValidatorIssue.md b/docs/reference/type-aliases/TStandardSchemaValidatorIssue.md index 482890eae2..e7e4ba07cd 100644 --- a/docs/reference/type-aliases/TStandardSchemaValidatorIssue.md +++ b/docs/reference/type-aliases/TStandardSchemaValidatorIssue.md @@ -3,16 +3,8 @@ id: TStandardSchemaValidatorIssue title: TStandardSchemaValidatorIssue --- -# Type Alias: TStandardSchemaValidatorIssue\ - ```ts -type TStandardSchemaValidatorIssue = TSource extends "form" ? object : TSource extends "field" ? StandardSchemaV1Issue[] : never; +type TStandardSchemaValidatorIssue = StandardSchemaV1Issue[]; ``` -Defined in: [packages/form-core/src/standardSchemaValidator.ts:11](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchemaValidator.ts#L11) - -## Type Parameters - -### TSource - -`TSource` *extends* [`ValidationSource`](ValidationSource.md) = [`ValidationSource`](ValidationSource.md) +Defined in: [standardSchema.public.ts:5](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchema.public.ts#L5) diff --git a/docs/reference/type-aliases/TStandardSchemaValidatorValue.md b/docs/reference/type-aliases/TStandardSchemaValidatorValue.md index d21caacaed..0938d36196 100644 --- a/docs/reference/type-aliases/TStandardSchemaValidatorValue.md +++ b/docs/reference/type-aliases/TStandardSchemaValidatorValue.md @@ -3,13 +3,11 @@ id: TStandardSchemaValidatorValue title: TStandardSchemaValidatorValue --- -# Type Alias: TStandardSchemaValidatorValue\ - ```ts -type TStandardSchemaValidatorValue = object; +type TStandardSchemaValidatorValue = object; ``` -Defined in: [packages/form-core/src/standardSchemaValidator.ts:3](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchemaValidator.ts#L3) +Defined in: [standardSchema.public.ts:1](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchema.public.ts#L1) ## Type Parameters @@ -17,26 +15,12 @@ Defined in: [packages/form-core/src/standardSchemaValidator.ts:3](https://github `TData` -### TSource - -`TSource` *extends* [`ValidationSource`](ValidationSource.md) = [`ValidationSource`](ValidationSource.md) - ## Properties -### validationSource - -```ts -validationSource: TSource; -``` - -Defined in: [packages/form-core/src/standardSchemaValidator.ts:8](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchemaValidator.ts#L8) - -*** - ### value ```ts value: TData; ``` -Defined in: [packages/form-core/src/standardSchemaValidator.ts:7](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchemaValidator.ts#L7) +Defined in: [standardSchema.public.ts:2](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchema.public.ts#L2) diff --git a/docs/reference/type-aliases/ToFieldError.md b/docs/reference/type-aliases/ToFieldError.md new file mode 100644 index 0000000000..30e98f4070 --- /dev/null +++ b/docs/reference/type-aliases/ToFieldError.md @@ -0,0 +1,37 @@ +--- +id: ToFieldError +title: ToFieldError +--- + +```ts +type ToFieldError = FallbackToValidationIssue< + | ExtractValidatorFieldError> + | unknown extends TGroupFieldError ? never : TGroupFieldError +| ExtractFormFieldError>; +``` + +Defined in: [validation.public.ts:1340](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1340) + +Combines a field's own issue types with errors routed from its group and form. + +Falls back to `ValidationIssue` when no specific error type is inferred. + +## Type Parameters + +### TFieldValidators + +`TFieldValidators` *extends* [`FieldValidators`](FieldValidators.md)\<`any`, `any`, `any`\> + +Library-managed. Do not specify explicitly. + +### TGroupFieldError + +`TGroupFieldError` + +Library-managed. Do not specify explicitly. + +### TFormErrorTypes + +`TFormErrorTypes` *extends* [`FormErrorTypes`](../interfaces/FormErrorTypes.md) + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/ToFormErrorTypes.md b/docs/reference/type-aliases/ToFormErrorTypes.md new file mode 100644 index 0000000000..39ccd280a5 --- /dev/null +++ b/docs/reference/type-aliases/ToFormErrorTypes.md @@ -0,0 +1,29 @@ +--- +id: ToFormErrorTypes +title: ToFormErrorTypes +--- + +```ts +type ToFormErrorTypes = ToValidatorErrorTypes, TSubmitReturn>; +``` + +Defined in: [validation.public.ts:1313](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1313) + +Infers form and routed field issue types from validators and submission validation errors. + +String errors become `ValidationIssue` objects. Successful output payloads +are excluded from error types. + +## Type Parameters + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](FormValidators.md)\<`any`\> + +Library-managed. Do not specify explicitly. + +### TSubmitReturn + +`TSubmitReturn` + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/ToFormGroupErrorTypes.md b/docs/reference/type-aliases/ToFormGroupErrorTypes.md new file mode 100644 index 0000000000..3d606e8dd9 --- /dev/null +++ b/docs/reference/type-aliases/ToFormGroupErrorTypes.md @@ -0,0 +1,20 @@ +--- +id: ToFormGroupErrorTypes +title: ToFormGroupErrorTypes +--- + +```ts +type ToFormGroupErrorTypes = ToValidatorErrorTypes, never>; +``` + +Defined in: [validation.public.ts:1323](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1323) + +Infers group and routed field issue types from group validators. + +## Type Parameters + +### TGroupValidators + +`TGroupValidators` *extends* [`FormGroupValidators`](FormGroupValidators.md)\<`any`\> + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/ToFormGroupOutputs.md b/docs/reference/type-aliases/ToFormGroupOutputs.md new file mode 100644 index 0000000000..f12d993dca --- /dev/null +++ b/docs/reference/type-aliases/ToFormGroupOutputs.md @@ -0,0 +1,24 @@ +--- +id: ToFormGroupOutputs +title: ToFormGroupOutputs +--- + +```ts +type ToFormGroupOutputs = ToOutputs>; +``` + +Defined in: [validation.public.ts:1271](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1271) + +Infers submission output slots from group validators in configuration order. + +Slots contain Standard Schema outputs or payloads returned through `createOutput`. +Validators disabled for submission have `undefined` slots. Conditional +submission or success without output can also make a slot `undefined`. + +## Type Parameters + +### TGroupValidators + +`TGroupValidators` *extends* [`FormGroupValidators`](FormGroupValidators.md)\<`any`\> + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/ToFormOutputs.md b/docs/reference/type-aliases/ToFormOutputs.md new file mode 100644 index 0000000000..823f2ba465 --- /dev/null +++ b/docs/reference/type-aliases/ToFormOutputs.md @@ -0,0 +1,24 @@ +--- +id: ToFormOutputs +title: ToFormOutputs +--- + +```ts +type ToFormOutputs = ToOutputs>; +``` + +Defined in: [validation.public.ts:1259](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1259) + +Infers submission output slots from form validators in configuration order. + +Slots contain Standard Schema outputs or payloads returned through `createOutput`. +Validators disabled for submission have `undefined` slots. Conditional +submission or success without output can also make a slot `undefined`. + +## Type Parameters + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](FormValidators.md)\<`any`\> + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/ToServerFormErrorTypes.md b/docs/reference/type-aliases/ToServerFormErrorTypes.md new file mode 100644 index 0000000000..05b0d73f2f --- /dev/null +++ b/docs/reference/type-aliases/ToServerFormErrorTypes.md @@ -0,0 +1,20 @@ +--- +id: ToServerFormErrorTypes +title: ToServerFormErrorTypes +--- + +```ts +type ToServerFormErrorTypes = unknown extends TFormValidators ? FormErrorTypes : FormValidators extends TFormValidators ? FormErrorTypes : ToFormErrorTypes, never>; +``` + +Defined in: [validation.public.ts:1365](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1365) + +Infers form and field issue types from validators with a `'server'` trigger. + +## Type Parameters + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](FormValidators.md)\<`any`\> + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/ToServerFormOutputs.md b/docs/reference/type-aliases/ToServerFormOutputs.md new file mode 100644 index 0000000000..a0e34690ff --- /dev/null +++ b/docs/reference/type-aliases/ToServerFormOutputs.md @@ -0,0 +1,23 @@ +--- +id: ToServerFormOutputs +title: ToServerFormOutputs +--- + +```ts +type ToServerFormOutputs = unknown extends TFormValidators ? unknown[] : FormValidators extends TFormValidators ? unknown[] : MappedServerOutputs; +``` + +Defined in: [validation.public.ts:1389](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L1389) + +Infers server validation output slots in form validator configuration order. + +Validators without a `'server'` trigger have `undefined` slots. Server +selection is independent of `skipOnSubmit`. + +## Type Parameters + +### TFormValidators + +`TFormValidators` *extends* [`FormValidators`](FormValidators.md)\<`any`\> + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/TryGetArrayElementType.md b/docs/reference/type-aliases/TryGetArrayElementType.md new file mode 100644 index 0000000000..f27bb63d3b --- /dev/null +++ b/docs/reference/type-aliases/TryGetArrayElementType.md @@ -0,0 +1,16 @@ +--- +id: TryGetArrayElementType +title: TryGetArrayElementType +--- + +```ts +type TryGetArrayElementType = TValue extends ReadonlyArray ? TElement : never; +``` + +Defined in: [deep-keys.public.ts:230](https://github.com/TanStack/form/blob/main/packages/form-core/src/deep-keys.public.ts#L230) + +## Type Parameters + +### TValue + +`TValue` diff --git a/docs/reference/type-aliases/TupleAccessor.md b/docs/reference/type-aliases/TupleAccessor.md deleted file mode 100644 index 3cff14e94a..0000000000 --- a/docs/reference/type-aliases/TupleAccessor.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -id: TupleAccessor -title: TupleAccessor ---- - -# Type Alias: TupleAccessor\ - -```ts -type TupleAccessor = `${TParent["key"] extends never ? "" : TParent["key"]}[${TKey}]`; -``` - -Defined in: [packages/form-core/src/util-types.ts:68](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L68) - -## Type Parameters - -### TParent - -`TParent` *extends* [`AnyDeepKeyAndValue`](../interfaces/AnyDeepKeyAndValue.md) - -### TKey - -`TKey` *extends* `string` diff --git a/docs/reference/type-aliases/UnknownAccessor.md b/docs/reference/type-aliases/UnknownAccessor.md deleted file mode 100644 index 3ca507f17a..0000000000 --- a/docs/reference/type-aliases/UnknownAccessor.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: UnknownAccessor -title: UnknownAccessor ---- - -# Type Alias: UnknownAccessor\ - -```ts -type UnknownAccessor = TParent["key"] extends never ? string : `${TParent["key"]}.${string}`; -``` - -Defined in: [packages/form-core/src/util-types.ts:136](https://github.com/TanStack/form/blob/main/packages/form-core/src/util-types.ts#L136) - -## Type Parameters - -### TParent - -`TParent` *extends* [`AnyDeepKeyAndValue`](../interfaces/AnyDeepKeyAndValue.md) diff --git a/docs/reference/type-aliases/UnwrapFieldAsyncValidateOrFn.md b/docs/reference/type-aliases/UnwrapFieldAsyncValidateOrFn.md deleted file mode 100644 index 91f7ad7ea1..0000000000 --- a/docs/reference/type-aliases/UnwrapFieldAsyncValidateOrFn.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -id: UnwrapFieldAsyncValidateOrFn -title: UnwrapFieldAsyncValidateOrFn ---- - -# Type Alias: UnwrapFieldAsyncValidateOrFn\ - -```ts -type UnwrapFieldAsyncValidateOrFn = - | [TFormValidateOrFn] extends [StandardSchemaV1] ? TName extends keyof TStandardOut ? StandardSchemaV1Issue[] : undefined : undefined - | UnwrapFormAsyncValidateOrFnForInner extends infer TFormValidateVal ? TFormValidateVal extends object ? [DeepValue] extends [never] ? undefined : StandardSchemaV1Issue[] : TFormValidateVal extends object ? TName extends keyof TFormValidateVal["fields"] ? TFormValidateVal["fields"][TName] : undefined : undefined : never - | [TValidateOrFn] extends [FieldValidateAsyncFn] ? Awaited> : [TValidateOrFn] extends [StandardSchemaV1] ? StandardSchemaV1Issue[] : undefined - | [TValidateOrFn] extends [FormGroupValidateAsyncFn] ? Awaited> : [TValidateOrFn] extends [StandardSchemaV1] ? StandardSchemaV1Issue[] : undefined; -``` - -Defined in: [packages/form-core/src/types.ts:333](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L333) - -## Type Parameters - -### TName - -`TName` *extends* `string` - -### TValidateOrFn - -`TValidateOrFn` *extends* - \| `undefined` - \| `FieldAsyncValidateOrFn`\<`any`, `any`, `any`\> - \| `FormGroupAsyncValidateOrFn`\<`any`, `any`\> - -### TFormValidateOrFn - -`TFormValidateOrFn` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`any`\> diff --git a/docs/reference/type-aliases/UnwrapFieldValidateOrFn.md b/docs/reference/type-aliases/UnwrapFieldValidateOrFn.md deleted file mode 100644 index 19dfdedc77..0000000000 --- a/docs/reference/type-aliases/UnwrapFieldValidateOrFn.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -id: UnwrapFieldValidateOrFn -title: UnwrapFieldValidateOrFn ---- - -# Type Alias: UnwrapFieldValidateOrFn\ - -```ts -type UnwrapFieldValidateOrFn = - | [TFormValidateOrFn] extends [StandardSchemaV1] ? TName extends keyof TStandardOut ? StandardSchemaV1Issue[] : undefined : undefined - | UnwrapFormValidateOrFnForInner extends infer TFormValidateVal ? TFormValidateVal extends object ? [DeepValue] extends [never] ? undefined : StandardSchemaV1Issue[] : TFormValidateVal extends object ? TName extends keyof TFormValidateVal["fields"] ? TFormValidateVal["fields"][TName] : undefined : undefined : never - | [TValidateOrFn] extends [StandardSchemaV1] ? StandardSchemaV1Issue[] : [TValidateOrFn] extends [FieldValidateFn] ? ReturnType : undefined - | [TValidateOrFn] extends [StandardSchemaV1] ? StandardSchemaV1Issue[] : [TValidateOrFn] extends [FormGroupValidateFn] ? ReturnType : undefined; -``` - -Defined in: [packages/form-core/src/types.ts:431](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L431) - -## Type Parameters - -### TName - -`TName` *extends* `string` - -### TValidateOrFn - -`TValidateOrFn` *extends* - \| `undefined` - \| `FieldValidateOrFn`\<`any`, `any`, `any`\> - \| `FormGroupValidateOrFn`\<`any`, `any`, `any`\> - -### TFormValidateOrFn - -`TFormValidateOrFn` *extends* `undefined` \| `FormValidateOrFn`\<`any`\> diff --git a/docs/reference/type-aliases/UnwrapFormAsyncValidateOrFn.md b/docs/reference/type-aliases/UnwrapFormAsyncValidateOrFn.md deleted file mode 100644 index 43a407d3c5..0000000000 --- a/docs/reference/type-aliases/UnwrapFormAsyncValidateOrFn.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: UnwrapFormAsyncValidateOrFn -title: UnwrapFormAsyncValidateOrFn ---- - -# Type Alias: UnwrapFormAsyncValidateOrFn\ - -```ts -type UnwrapFormAsyncValidateOrFn = [TValidateOrFn] extends [FormValidateAsyncFn] ? ExtractGlobalFormError>> : [TValidateOrFn] extends [StandardSchemaV1] ? Record : undefined; -``` - -Defined in: [packages/form-core/src/FormApi.ts:177](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L177) - -## Type Parameters - -### TValidateOrFn - -`TValidateOrFn` *extends* `undefined` \| `FormAsyncValidateOrFn`\<`any`\> diff --git a/docs/reference/type-aliases/UnwrapFormValidateOrFn.md b/docs/reference/type-aliases/UnwrapFormValidateOrFn.md deleted file mode 100644 index da09aee88a..0000000000 --- a/docs/reference/type-aliases/UnwrapFormValidateOrFn.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: UnwrapFormValidateOrFn -title: UnwrapFormValidateOrFn ---- - -# Type Alias: UnwrapFormValidateOrFn\ - -```ts -type UnwrapFormValidateOrFn = [TValidateOrFn] extends [FormValidateFn] ? ExtractGlobalFormError> : [TValidateOrFn] extends [StandardSchemaV1] ? Record : undefined; -``` - -Defined in: [packages/form-core/src/FormApi.ts:123](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L123) - -## Type Parameters - -### TValidateOrFn - -`TValidateOrFn` *extends* `undefined` \| `FormValidateOrFn`\<`any`\> diff --git a/docs/reference/type-aliases/UpdateFn.md b/docs/reference/type-aliases/UpdateFn.md new file mode 100644 index 0000000000..7079608044 --- /dev/null +++ b/docs/reference/type-aliases/UpdateFn.md @@ -0,0 +1,26 @@ +--- +id: UpdateFn +title: UpdateFn +--- + +```ts +type UpdateFn = (previousValue) => TValue; +``` + +Defined in: [types.public.ts:3](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.public.ts#L3) + +## Type Parameters + +### TValue + +`TValue` + +## Parameters + +### previousValue + +`TValue` + +## Returns + +`TValue` diff --git a/docs/reference/type-aliases/Updater.md b/docs/reference/type-aliases/Updater.md index da46d9329f..52c8cb17ce 100644 --- a/docs/reference/type-aliases/Updater.md +++ b/docs/reference/type-aliases/Updater.md @@ -3,20 +3,14 @@ id: Updater title: Updater --- -# Type Alias: Updater\ - ```ts -type Updater = TOutput | UpdaterFn; +type Updater = TValue | UpdateFn; ``` -Defined in: [packages/form-core/src/utils.ts:16](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.ts#L16) +Defined in: [types.public.ts:4](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.public.ts#L4) ## Type Parameters -### TInput - -`TInput` - -### TOutput +### TValue -`TOutput` = `TInput` +`TValue` diff --git a/docs/reference/type-aliases/UpdaterFn.md b/docs/reference/type-aliases/UpdaterFn.md deleted file mode 100644 index a31c76e36a..0000000000 --- a/docs/reference/type-aliases/UpdaterFn.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -id: UpdaterFn -title: UpdaterFn ---- - -# Type Alias: UpdaterFn()\ - -```ts -type UpdaterFn = (input) => TOutput; -``` - -Defined in: [packages/form-core/src/utils.ts:14](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.ts#L14) - -## Type Parameters - -### TInput - -`TInput` - -### TOutput - -`TOutput` = `TInput` - -## Parameters - -### input - -`TInput` - -## Returns - -`TOutput` diff --git a/docs/reference/type-aliases/ValidValidationResult.md b/docs/reference/type-aliases/ValidValidationResult.md new file mode 100644 index 0000000000..bd1b4318ee --- /dev/null +++ b/docs/reference/type-aliases/ValidValidationResult.md @@ -0,0 +1,12 @@ +--- +id: ValidValidationResult +title: ValidValidationResult +--- + +```ts +type ValidValidationResult = null | undefined | false; +``` + +Defined in: [validation.public.ts:755](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L755) + +A validator return value that indicates success without providing output data. diff --git a/docs/reference/type-aliases/ValidationDebounceFn.md b/docs/reference/type-aliases/ValidationDebounceFn.md new file mode 100644 index 0000000000..a84d1b1482 --- /dev/null +++ b/docs/reference/type-aliases/ValidationDebounceFn.md @@ -0,0 +1,44 @@ +--- +id: ValidationDebounceFn +title: ValidationDebounceFn +--- + +```ts +type ValidationDebounceFn = (context) => number; +``` + +Defined in: [validation.public.ts:492](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L492) + +Chooses the delay in milliseconds before change or blur validation runs. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValue + +`TValue` + +Library-managed. Do not specify explicitly. + +### TScope + +`TScope` *extends* [`ValidatorScope`](ValidatorScope.md) = [`ValidatorScope`](ValidatorScope.md) + +Library-managed. Do not specify explicitly. + +## Parameters + +### context + +[`ValidationPredicateContext`](ValidationPredicateContext.md)\<`TFormData`, `TValue`, `TScope`\> + +## Returns + +`number` + +The delay for the current event. Zero or a negative value runs validation immediately. diff --git a/docs/reference/type-aliases/ValidationError.md b/docs/reference/type-aliases/ValidationError.md index be6aa3db7c..119926a783 100644 --- a/docs/reference/type-aliases/ValidationError.md +++ b/docs/reference/type-aliases/ValidationError.md @@ -3,10 +3,10 @@ id: ValidationError title: ValidationError --- -# Type Alias: ValidationError - ```ts -type ValidationError = unknown; +type ValidationError = OneOrMany; ``` -Defined in: [packages/form-core/src/types.ts:35](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L35) +Defined in: [validation.public.ts:586](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L586) + +One or more issue objects after string errors have been normalized. diff --git a/docs/reference/type-aliases/ValidationErrorInput.md b/docs/reference/type-aliases/ValidationErrorInput.md new file mode 100644 index 0000000000..9ec689e59a --- /dev/null +++ b/docs/reference/type-aliases/ValidationErrorInput.md @@ -0,0 +1,12 @@ +--- +id: ValidationErrorInput +title: ValidationErrorInput +--- + +```ts +type ValidationErrorInput = OneOrMany; +``` + +Defined in: [validation.public.ts:588](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L588) + +One or more errors accepted from a validator, including string messages. diff --git a/docs/reference/type-aliases/ValidationErrorValue.md b/docs/reference/type-aliases/ValidationErrorValue.md new file mode 100644 index 0000000000..19cba0f9b4 --- /dev/null +++ b/docs/reference/type-aliases/ValidationErrorValue.md @@ -0,0 +1,12 @@ +--- +id: ValidationErrorValue +title: ValidationErrorValue +--- + +```ts +type ValidationErrorValue = ValidationIssue | string; +``` + +Defined in: [validation.public.ts:584](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L584) + +An error supplied as an issue object or a string that becomes its `message`. diff --git a/docs/reference/type-aliases/ValidationLogicFn.md b/docs/reference/type-aliases/ValidationLogicFn.md deleted file mode 100644 index 30501fbd4c..0000000000 --- a/docs/reference/type-aliases/ValidationLogicFn.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -id: ValidationLogicFn -title: ValidationLogicFn ---- - -# Type Alias: ValidationLogicFn() - -```ts -type ValidationLogicFn = (props) => void; -``` - -Defined in: [packages/form-core/src/ValidationLogic.ts:63](https://github.com/TanStack/form/blob/main/packages/form-core/src/ValidationLogic.ts#L63) - -## Parameters - -### props - -[`ValidationLogicProps`](../interfaces/ValidationLogicProps.md) - -## Returns - -`void` diff --git a/docs/reference/type-aliases/ValidationMeta.md b/docs/reference/type-aliases/ValidationMeta.md deleted file mode 100644 index 294477a842..0000000000 --- a/docs/reference/type-aliases/ValidationMeta.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -id: ValidationMeta -title: ValidationMeta ---- - -# Type Alias: ValidationMeta - -```ts -type ValidationMeta = object; -``` - -Defined in: [packages/form-core/src/FormApi.ts:603](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L603) - -An object representing the validation metadata for a field. Not intended for public usage. - -## Properties - -### lastAbortController - -```ts -lastAbortController: AbortController; -``` - -Defined in: [packages/form-core/src/FormApi.ts:607](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L607) - -An abort controller stored in memory to cancel previous async validation attempts. diff --git a/docs/reference/type-aliases/ValidationPredicateContext.md b/docs/reference/type-aliases/ValidationPredicateContext.md new file mode 100644 index 0000000000..ec57dc5f8a --- /dev/null +++ b/docs/reference/type-aliases/ValidationPredicateContext.md @@ -0,0 +1,32 @@ +--- +id: ValidationPredicateContext +title: ValidationPredicateContext +--- + +```ts +type ValidationPredicateContext = TScope extends "form" ? FormValidationPredicateContext : TScope extends "group" ? FormGroupValidationPredicateContext : TScope extends "field" ? FieldValidationPredicateContext : never; +``` + +Defined in: [validation.public.ts:459](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L459) + +Context for validator conditions and delay callbacks, narrowed by `scope`. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValue + +`TValue` + +Library-managed. Do not specify explicitly. + +### TScope + +`TScope` *extends* [`ValidatorScope`](ValidatorScope.md) = [`ValidatorScope`](ValidatorScope.md) + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/ValidationPredicateFn.md b/docs/reference/type-aliases/ValidationPredicateFn.md new file mode 100644 index 0000000000..995a30ac1d --- /dev/null +++ b/docs/reference/type-aliases/ValidationPredicateFn.md @@ -0,0 +1,42 @@ +--- +id: ValidationPredicateFn +title: ValidationPredicateFn +--- + +```ts +type ValidationPredicateFn = (context) => boolean; +``` + +Defined in: [validation.public.ts:478](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L478) + +Returns `true` to enable validation for the current event or submission attempt. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValue + +`TValue` + +Library-managed. Do not specify explicitly. + +### TScope + +`TScope` *extends* [`ValidatorScope`](ValidatorScope.md) = [`ValidatorScope`](ValidatorScope.md) + +Library-managed. Do not specify explicitly. + +## Parameters + +### context + +[`ValidationPredicateContext`](ValidationPredicateContext.md)\<`TFormData`, `TValue`, `TScope`\> + +## Returns + +`boolean` diff --git a/docs/reference/type-aliases/ValidationResult.md b/docs/reference/type-aliases/ValidationResult.md new file mode 100644 index 0000000000..c6f2d010fa --- /dev/null +++ b/docs/reference/type-aliases/ValidationResult.md @@ -0,0 +1,14 @@ +--- +id: ValidationResult +title: ValidationResult +--- + +```ts +type ValidationResult = + | ValidValidationResult + | ValidationErrorInput; +``` + +Defined in: [validation.public.ts:764](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L764) + +One or more validation errors, or `null`, `undefined`, or `false` for success. diff --git a/docs/reference/type-aliases/ValidationSource.md b/docs/reference/type-aliases/ValidationSource.md deleted file mode 100644 index a3dce69a76..0000000000 --- a/docs/reference/type-aliases/ValidationSource.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: ValidationSource -title: ValidationSource ---- - -# Type Alias: ValidationSource - -```ts -type ValidationSource = "form" | "field"; -``` - -Defined in: [packages/form-core/src/types.ts:37](https://github.com/TanStack/form/blob/main/packages/form-core/src/types.ts#L37) diff --git a/docs/reference/type-aliases/ValidationTrigger.md b/docs/reference/type-aliases/ValidationTrigger.md new file mode 100644 index 0000000000..bea5196acb --- /dev/null +++ b/docs/reference/type-aliases/ValidationTrigger.md @@ -0,0 +1,12 @@ +--- +id: ValidationTrigger +title: ValidationTrigger +--- + +```ts +type ValidationTrigger = "change" | "blur" | "submit"; +``` + +Defined in: [validation.public.ts:253](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L253) + +Client validation events: value changes, field blur, and submission attempts. diff --git a/docs/reference/type-aliases/ValidationTriggerOption.md b/docs/reference/type-aliases/ValidationTriggerOption.md new file mode 100644 index 0000000000..3563648348 --- /dev/null +++ b/docs/reference/type-aliases/ValidationTriggerOption.md @@ -0,0 +1,40 @@ +--- +id: ValidationTriggerOption +title: ValidationTriggerOption +--- + +```ts +type ValidationTriggerOption = + | TTrigger +| ValidationTriggerConfig; +``` + +Defined in: [validation.public.ts:533](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L533) + +A validation event, either unconditional or configured with a `when` condition. + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TValue + +`TValue` + +Library-managed. Do not specify explicitly. + +### TTrigger + +`TTrigger` *extends* [`ValidatorTrigger`](ValidatorTrigger.md) = [`ValidatorTrigger`](ValidatorTrigger.md) + +Library-managed. Do not specify explicitly. + +### TScope + +`TScope` *extends* [`ValidatorScope`](ValidatorScope.md) = [`ValidatorScope`](ValidatorScope.md) + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/ValidatorFn.md b/docs/reference/type-aliases/ValidatorFn.md new file mode 100644 index 0000000000..c204e97a1a --- /dev/null +++ b/docs/reference/type-aliases/ValidatorFn.md @@ -0,0 +1,36 @@ +--- +id: ValidatorFn +title: ValidatorFn +--- + +```ts +type ValidatorFn = (...args) => TReturn | Promise; +``` + +Defined in: [validation.public.ts:787](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L787) + +A validation callback that can return a result immediately or asynchronously. + +## Type Parameters + +### TParameter + +`TParameter` + +Library-managed. Do not specify explicitly. + +### TReturn + +`TReturn` + +Library-managed. Do not specify explicitly. + +## Parameters + +### args + +...`TParameter`[] + +## Returns + +`TReturn` \| `Promise`\<`TReturn`\> diff --git a/docs/reference/type-aliases/ValidatorOptions.md b/docs/reference/type-aliases/ValidatorOptions.md new file mode 100644 index 0000000000..b08e135079 --- /dev/null +++ b/docs/reference/type-aliases/ValidatorOptions.md @@ -0,0 +1,48 @@ +--- +id: ValidatorOptions +title: ValidatorOptions +--- + +```ts +type ValidatorOptions = Omit + | ValidatorFn, TContextValue, TTrigger, TScope>, "run" | "triggers"> & object; +``` + +Defined in: [validation.public.ts:95](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L95) + +Reusable scheduling and failure-handling options for `createValidator` or `createValidators`. + +## Type Declaration + +### triggers + +```ts +triggers: FormValidationTriggerOption[]; +``` + +## Type Parameters + +### TFormData + +`TFormData` + +Library-managed. Do not specify explicitly. + +### TContextValue + +`TContextValue` + +Library-managed. Do not specify explicitly. + +### TTrigger + +`TTrigger` *extends* [`ValidatorTrigger`](ValidatorTrigger.md) = [`ValidatorTrigger`](ValidatorTrigger.md) + +Library-managed. Do not specify explicitly. + +### TScope + +`TScope` *extends* [`ValidatorScope`](ValidatorScope.md) = [`ValidatorScope`](ValidatorScope.md) + +Library-managed. Do not specify explicitly. diff --git a/docs/reference/type-aliases/ValidatorScope.md b/docs/reference/type-aliases/ValidatorScope.md new file mode 100644 index 0000000000..dc6b54dce7 --- /dev/null +++ b/docs/reference/type-aliases/ValidatorScope.md @@ -0,0 +1,12 @@ +--- +id: ValidatorScope +title: ValidatorScope +--- + +```ts +type ValidatorScope = "form" | "group" | "field"; +``` + +Defined in: [validation.public.ts:263](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L263) + +The form, form group, or field whose value a validator checks. diff --git a/docs/reference/type-aliases/ValidatorTrigger.md b/docs/reference/type-aliases/ValidatorTrigger.md new file mode 100644 index 0000000000..d827b7c389 --- /dev/null +++ b/docs/reference/type-aliases/ValidatorTrigger.md @@ -0,0 +1,12 @@ +--- +id: ValidatorTrigger +title: ValidatorTrigger +--- + +```ts +type ValidatorTrigger = ConfigurableValidationTrigger; +``` + +Defined in: [validation.public.ts:261](https://github.com/TanStack/form/blob/main/packages/form-core/src/validation.public.ts#L261) + +Change and blur events accepted by shared validator configurations. diff --git a/docs/reference/variables/defaultValidationLogic.md b/docs/reference/variables/defaultValidationLogic.md deleted file mode 100644 index 52bec01c6c..0000000000 --- a/docs/reference/variables/defaultValidationLogic.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: defaultValidationLogic -title: defaultValidationLogic ---- - -# Variable: defaultValidationLogic - -```ts -const defaultValidationLogic: ValidationLogicFn; -``` - -Defined in: [packages/form-core/src/ValidationLogic.ts:134](https://github.com/TanStack/form/blob/main/packages/form-core/src/ValidationLogic.ts#L134) diff --git a/docs/reference/variables/formEventClient.md b/docs/reference/variables/formEventClient.md deleted file mode 100644 index c919f4e422..0000000000 --- a/docs/reference/variables/formEventClient.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: formEventClient -title: formEventClient ---- - -# Variable: formEventClient - -```ts -const formEventClient: FormEventClient; -``` - -Defined in: [packages/form-core/src/EventClient.ts:70](https://github.com/TanStack/form/blob/main/packages/form-core/src/EventClient.ts#L70) diff --git a/docs/reference/variables/formOptions.md b/docs/reference/variables/formOptions.md new file mode 100644 index 0000000000..2953feeb84 --- /dev/null +++ b/docs/reference/variables/formOptions.md @@ -0,0 +1,49 @@ +--- +id: formOptions +title: formOptions +--- + +```ts +const formOptions: FormOptionsApi; +``` + +Defined in: [utils.public.ts:373](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.public.ts#L373) + +Keeps form data, validator, and submission types inferred when options are +declared separately from a framework's form creation API. + +The regular helper takes `defaultValues` at face value as the form data +shape. For schema-driven inference, use `formOptions.strictSchema` when the +schema defines an input-to-output boundary, or `formOptions.looseSchema` when +the schema defines the shape but editable defaults may omit properties or +need `null` or `undefined` values. + +At runtime, this is an identity helper: it returns the original options +object and does not create a form or run validation. + +## Remarks + +**Important:** Although this returns the original object unchanged at +runtime, its type is normalized to `FormOptions`. Optional properties such +as `validators` therefore remain optional even when supplied. This tradeoff +enables safer inference and reuse. + +## Example + +```ts +const profileOptions = formOptions({ + defaultValues: { name: '' }, + validators: [ + { + triggers: ['change'], + run: ({ value }) => + value.name.length === 0 ? 'Name is required' : undefined, + }, + ], +}) + +const form = useForm({ + ...profileOptions, + onSubmit: ({ value }) => saveProfile(value), +}) +``` diff --git a/docs/reference/variables/initialServerFormState.md b/docs/reference/variables/initialServerFormState.md new file mode 100644 index 0000000000..a155762ad3 --- /dev/null +++ b/docs/reference/variables/initialServerFormState.md @@ -0,0 +1,10 @@ +--- +id: initialServerFormState +title: initialServerFormState +--- + +```ts +const initialServerFormState: ServerFormState; +``` + +Defined in: [ssr.public.ts:9](https://github.com/TanStack/form/blob/main/packages/form-core/src/ssr.public.ts#L9) diff --git a/docs/reference/variables/standardSchemaValidators.md b/docs/reference/variables/standardSchemaValidators.md deleted file mode 100644 index 70e371f6ab..0000000000 --- a/docs/reference/variables/standardSchemaValidators.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: standardSchemaValidators -title: standardSchemaValidators ---- - -# Variable: standardSchemaValidators - -```ts -const standardSchemaValidators: object; -``` - -Defined in: [packages/form-core/src/standardSchemaValidator.ts:73](https://github.com/TanStack/form/blob/main/packages/form-core/src/standardSchemaValidator.ts#L73) - -## Type Declaration - -### validate() - -```ts -validate(__namedParameters, schema): - | TStandardSchemaValidatorIssue - | undefined; -``` - -#### Type Parameters - -##### TSource - -`TSource` *extends* [`ValidationSource`](../type-aliases/ValidationSource.md) = [`ValidationSource`](../type-aliases/ValidationSource.md) - -#### Parameters - -##### \_\_namedParameters - -[`TStandardSchemaValidatorValue`](../type-aliases/TStandardSchemaValidatorValue.md)\<`unknown`, `TSource`\> - -##### schema - -[`StandardSchemaV1`](../type-aliases/StandardSchemaV1.md) - -#### Returns - - \| [`TStandardSchemaValidatorIssue`](../type-aliases/TStandardSchemaValidatorIssue.md)\<`TSource`\> - \| `undefined` - -### validateAsync() - -```ts -validateAsync(__namedParameters, schema): Promise< - | TStandardSchemaValidatorIssue -| undefined>; -``` - -#### Type Parameters - -##### TSource - -`TSource` *extends* [`ValidationSource`](../type-aliases/ValidationSource.md) - -#### Parameters - -##### \_\_namedParameters - -[`TStandardSchemaValidatorValue`](../type-aliases/TStandardSchemaValidatorValue.md)\<`unknown`, `TSource`\> - -##### schema - -[`StandardSchemaV1`](../type-aliases/StandardSchemaV1.md) - -#### Returns - -`Promise`\< - \| [`TStandardSchemaValidatorIssue`](../type-aliases/TStandardSchemaValidatorIssue.md)\<`TSource`\> - \| `undefined`\> diff --git a/docs/reference/variables/throttleFormState.md b/docs/reference/variables/throttleFormState.md deleted file mode 100644 index 8338003b31..0000000000 --- a/docs/reference/variables/throttleFormState.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -id: throttleFormState -title: throttleFormState ---- - -# Variable: throttleFormState() - -```ts -const throttleFormState: (...args) => void; -``` - -Defined in: [packages/form-core/src/utils.ts:681](https://github.com/TanStack/form/blob/main/packages/form-core/src/utils.ts#L681) - -## Parameters - -### args - -...\[[`AnyFormApi`](../type-aliases/AnyFormApi.md)\] - -## Returns - -`void` diff --git a/docs/splitting-forms.md b/docs/splitting-forms.md new file mode 100644 index 0000000000..941d6517df --- /dev/null +++ b/docs/splitting-forms.md @@ -0,0 +1,1201 @@ +As a form grows, keeping every field in one component can make the code harder +to navigate and maintain. You can move related fields into smaller components +while keeping one form instance, but each new component boundary needs a type +for the form or field it receives. + +## Split a large form into sections + +First define the form's reusable options with `formOptions`. In this example, +the same module also exports a named form type derived from those options. The +parent can add page-specific options, such as `onSubmit`, when it creates the +form, while extracted sections can import the same form type. + + + +# React + +React's `ReactFormType` derives the form prop from the shared options. The +result keeps the field names and values available to `form.Field` in the +extracted component. + + + +```ts file="shared-form.ts" +import { formOptions } from '@tanstack/react-form' +import type { ReactFormType } from '@tanstack/react-form' + +export const profileFormOptions = formOptions({ + defaultValues: { + name: '', + address: { + street: '', + city: '', + }, + }, +}) + +export type ProfileForm = ReactFormType +``` + +```tsx file="AddressFields.tsx" +import type { ProfileForm } from './shared-form' + +interface AddressFieldsProps { + form: ProfileForm +} + +export function AddressFields({ form }: AddressFieldsProps) { + return ( + <> + + {(field) => ( + field.handleChange(event.target.value)} + /> + )} + + + {(field) => ( + field.handleChange(event.target.value)} + /> + )} + + + ) +} +``` + +```tsx file="ProfileForm.tsx" +import { useForm } from '@tanstack/react-form' +import { AddressFields } from './AddressFields' +import { profileFormOptions } from './shared-form' + +export function ProfileForm() { + const form = useForm({ + ...profileFormOptions, + onSubmit: ({ value }) => console.log(value), + }) + + return +} +``` + + + +> [!NOTE] Sharing between forms +> If the section should work with multiple forms instead of only one, use [field groups](./framework/react/guides/field-groups). + +# Preact + +Preact's `PreactFormType` derives the form prop from the shared options. The +result keeps the field names and values available to `form.Field` in the +extracted component. + + + +```ts file="shared-form.ts" +import { formOptions } from '@tanstack/preact-form' +import type { PreactFormType } from '@tanstack/preact-form' + +export const profileFormOptions = formOptions({ + defaultValues: { + name: '', + address: { + street: '', + city: '', + }, + }, +}) + +export type ProfileForm = PreactFormType +``` + +```tsx file="AddressFields.tsx" +import type { ProfileForm } from './shared-form' + +interface AddressFieldsProps { + form: ProfileForm +} + +export function AddressFields({ form }: AddressFieldsProps) { + return ( + <> + + {(field) => ( + field.handleChange(event.currentTarget.value)} + /> + )} + + + {(field) => ( + field.handleChange(event.currentTarget.value)} + /> + )} + + + ) +} +``` + +```tsx file="ProfileForm.tsx" +import { useForm } from '@tanstack/preact-form' +import { AddressFields } from './AddressFields' +import { profileFormOptions } from './shared-form' + +export function ProfileForm() { + const form = useForm({ + ...profileFormOptions, + onSubmit: ({ value }) => console.log(value), + }) + + return +} +``` + + + +# Vue + +Vue's `VueFormType` derives the form prop from the shared options. The result +keeps the field names and values available to `form.Field` in the extracted +component. + + + +```ts file="shared-form.ts" +import { formOptions } from '@tanstack/vue-form' +import type { VueFormType } from '@tanstack/vue-form' + +export const profileFormOptions = formOptions({ + defaultValues: { + name: '', + address: { + street: '', + city: '', + }, + }, +}) + +export type ProfileForm = VueFormType +``` + +```vue file="AddressFields.vue" + + + +``` + +```vue file="ProfileForm.vue" + + + +``` + + + +# Angular + +Angular's `AngularFormType` derives the form input from the shared options. The +result keeps the field names and values available to `TanStackField` in the +extracted component. + + + +```ts file="shared-form.ts" +import { formOptions } from '@tanstack/angular-form' +import type { AngularFormType } from '@tanstack/angular-form' + +export const profileFormOptions = formOptions({ + defaultValues: { + name: '', + address: { + street: '', + city: '', + }, + }, +}) + +export type ProfileForm = AngularFormType +``` + +```ts file="address-fields.component.ts" +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { TanStackField } from '@tanstack/angular-form' +import type { ProfileForm } from './shared-form' + +@Component({ + selector: 'app-address-fields', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TanStackField], + template: ` + + + + + + + `, +}) +export class AddressFieldsComponent { + form = input.required() +} +``` + +```ts file="profile-form.component.ts" +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { injectForm } from '@tanstack/angular-form' +import { AddressFieldsComponent } from './address-fields.component' +import { profileFormOptions } from './shared-form' + +@Component({ + selector: 'app-profile-form', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [AddressFieldsComponent], + template: ``, +}) +export class ProfileFormComponent { + form = injectForm({ + ...profileFormOptions, + onSubmit: ({ value }) => console.log(value), + }) +} +``` + + + +# Solid + +Solid's `SolidFormType` derives the form prop from the shared options. The +result keeps the field names and values available to `form.Field` in the +extracted component. + + + +```ts file="shared-form.ts" +import { formOptions } from '@tanstack/solid-form' +import type { SolidFormType } from '@tanstack/solid-form' + +export const profileFormOptions = formOptions({ + defaultValues: { + name: '', + address: { + street: '', + city: '', + }, + }, +}) + +export type ProfileForm = SolidFormType +``` + +```tsx file="AddressFields.tsx" +import type { ProfileForm } from './shared-form' + +interface AddressFieldsProps { + form: ProfileForm +} + +export function AddressFields(props: AddressFieldsProps) { + return ( + <> + + {(field) => ( + field().handleChange(event.currentTarget.value)} + /> + )} + + + {(field) => ( + field().handleChange(event.currentTarget.value)} + /> + )} + + + ) +} +``` + +```tsx file="ProfileForm.tsx" +import { createForm } from '@tanstack/solid-form' +import { AddressFields } from './AddressFields' +import { profileFormOptions } from './shared-form' + +export function ProfileForm() { + const form = createForm(() => ({ + ...profileFormOptions, + onSubmit: ({ value }) => console.log(value), + })) + + return +} +``` + + + +# Lit + +Lit’s `LitFormType` derives a controller type from the shared options. The +result keeps the field names and values available to the controller's `field` +method in the extracted render function. + + + +```ts file="shared-form.ts" +import { formOptions } from '@tanstack/lit-form' +import type { LitFormType } from '@tanstack/lit-form' + +export const profileFormOptions = formOptions({ + defaultValues: { + name: '', + address: { + street: '', + city: '', + }, + }, +}) + +export type ProfileForm = LitFormType +``` + +```ts file="address-fields.ts" +import { html } from 'lit' +import type { ProfileForm } from './shared-form' + +export function addressFields(form: ProfileForm) { + return html` + ${form.field( + { name: 'address.street' }, + (field) => html` + + field.handleChange((event.currentTarget as HTMLInputElement).value)} + /> + `, + )} + ${form.field( + { name: 'address.city' }, + (field) => html` + + field.handleChange((event.currentTarget as HTMLInputElement).value)} + /> + `, + )} + ` +} +``` + +```ts file="profile-form.ts" +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' +import { TanStackFormController } from '@tanstack/lit-form' +import { addressFields } from './address-fields' +import { profileFormOptions } from './shared-form' + +@customElement('profile-form') +export class ProfileForm extends LitElement { + private form = new TanStackFormController(this, { + ...profileFormOptions, + onSubmit: ({ value }) => console.log(value), + }) + + render() { + return html`${addressFields(this.form)}` + } +} +``` + + + +# Svelte + +Svelte's `SvelteFormType` derives the form prop from the shared options. The +result keeps the field names and values available to `form.Field` in the +extracted component. + + + +```ts file="shared-form.ts" +import { formOptions } from '@tanstack/svelte-form' +import type { SvelteFormType } from '@tanstack/svelte-form' + +export const profileFormOptions = formOptions({ + defaultValues: { + name: '', + address: { + street: '', + city: '', + }, + }, +}) + +export type ProfileForm = SvelteFormType +``` + +```svelte file="AddressFields.svelte" + + + + {#snippet children(field)} + field.handleChange(event.currentTarget.value)} + /> + {/snippet} + + + {#snippet children(field)} + field.handleChange(event.currentTarget.value)} + /> + {/snippet} + +``` + +```svelte file="ProfileForm.svelte" + + + +``` + + + + + +## Extract a field component by value type + +After splitting the form into sections, you may still have repeated controls +for values such as strings, numbers, or dates. These controls don't need to +know the form's complete data shape or the path of a particular field. They +only need the type of the value they read and update. + +`FieldWithValue` describes a field by the value type a reusable component +handles. This preserves type checking when the component reads or updates the +value without tying it to a particular field path or form shape. + + + +# React + +Type the React component's field prop as `FieldWithValue`, then pass it +the field from the `form.Field` render prop. + + + +```tsx file="TextField.tsx" +import type { FieldWithValue } from '@tanstack/react-form' + +interface TextFieldProps { + field: FieldWithValue + label: string +} + +export function TextField({ field, label }: TextFieldProps) { + return ( + + ) +} +``` + +```tsx file="NameField.tsx" +import { TextField } from './TextField' +import type { ProfileForm } from './shared-form' + +export function NameField({ form }: { form: ProfileForm }) { + return ( + + {(field) => } + + ) +} +``` + + + +# Preact + +Type the Preact component's field prop as `FieldWithValue`, then pass it +the field from the `form.Field` render prop. + + + +```tsx file="TextField.tsx" +import type { FieldWithValue } from '@tanstack/preact-form' + +interface TextFieldProps { + field: FieldWithValue + label: string +} + +export function TextField({ field, label }: TextFieldProps) { + return ( + + ) +} +``` + +```tsx file="NameField.tsx" +import { TextField } from './TextField' +import type { ProfileForm } from './shared-form' + +export function NameField({ form }: { form: ProfileForm }) { + return ( + + {(field) => } + + ) +} +``` + + + +# Vue + +Type the Vue component's field prop as `FieldWithValue`, then pass it +the field from the `form.Field` slot. + + + +```vue file="TextField.vue" + + + +``` + +```vue file="NameField.vue" + + + +``` + + + +# Angular + +Angular field components can declare their value type through +`injectField()`. The `tanstack-app-field` directive provides the field +to that component, so it doesn't need a form input of its own. + + + +```ts file="text-field.component.ts" +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { injectField } from '@tanstack/angular-form' + +@Component({ + selector: 'app-text-field', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + `, +}) +export class TextFieldComponent { + label = input.required() + field = injectField() +} +``` + +```ts file="name-field.component.ts" +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { TanStackAppField, TanStackField } from '@tanstack/angular-form' +import { TextFieldComponent } from './text-field.component' +import type { ProfileForm } from './shared-form' + +@Component({ + selector: 'app-name-field', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TanStackAppField, TanStackField, TextFieldComponent], + template: ` + + `, +}) +export class NameFieldComponent { + form = input.required() +} +``` + + + +# Solid + +Solid's field render prop is an accessor, so the component accepts an +`Accessor>`. + + + +```tsx file="TextField.tsx" +import type { Accessor } from 'solid-js' +import type { FieldWithValue } from '@tanstack/solid-form' + +interface TextFieldProps { + field: Accessor> + label: string +} + +export function TextField(props: TextFieldProps) { + return ( + + ) +} +``` + +```tsx file="NameField.tsx" +import { TextField } from './TextField' +import type { ProfileForm } from './shared-form' + +export function NameField(props: { form: ProfileForm }) { + return ( + + {(field) => } + + ) +} +``` + + + +# Lit + +Type the Lit render helper's field parameter as `FieldWithValue`, then +call it from the controller's `field` render callback. + + + +```ts file="text-field.ts" +import { html } from 'lit' +import type { FieldWithValue } from '@tanstack/lit-form' + +export function textField(field: FieldWithValue, label: string) { + return html` + + ` +} +``` + +```ts file="name-field.ts" +import { textField } from './text-field' +import type { ProfileForm } from './shared-form' + +export function nameField(form: ProfileForm) { + return form.field({ name: 'name' }, (field) => textField(field, 'Name')) +} +``` + + + +# Svelte + +Type the Svelte component's field prop as `FieldWithValue`, then pass it +the field from the `form.Field` snippet. + + + +```svelte file="TextField.svelte" + + + +``` + +```svelte file="NameField.svelte" + + + + {#snippet children(field)} + + {/snippet} + +``` + + + + + +## Accept any form or field + +Some extracted controls behave the same regardless of the form's data. An +error display only needs field metadata, while a submit or reset button may +only need form state and methods. Giving these controls the concrete +`ProfileForm` type would couple them to details they don't use. + +Use `AnyFieldApi` when a control doesn't depend on the field's value type. For +form-level controls, use the adapter's `Any*FormApi` type. These types +deliberately remove information about values and field paths, so use a concrete +type when a component reads either one. + + + +# React + +React provides `AnyReactFormApi` for form-level components. Pass the field from +`form.Field` to `FieldErrors`, and pass the form instance to `SubmitButton`. + + + +```tsx file="FieldErrors.tsx" +import type { AnyFieldApi } from '@tanstack/react-form' + +export function FieldErrors({ field }: { field: AnyFieldApi }) { + return ( + + {field.errors.map((error) => error.message).join(', ')} + + ) +} +``` + +```tsx file="SubmitButton.tsx" +import type { AnyReactFormApi } from '@tanstack/react-form' + +export function SubmitButton({ form }: { form: AnyReactFormApi }) { + return ( + [state.canSubmit, state.isSubmitting] as const} + > + {([canSubmit, isSubmitting]) => ( + + )} + + ) +} +``` + + + +# Preact + +Preact provides `AnyPreactFormApi` for form-level components. Pass the field +from `form.Field` to `FieldErrors`, and pass the form instance to +`SubmitButton`. + + + +```tsx file="FieldErrors.tsx" +import type { AnyFieldApi } from '@tanstack/preact-form' + +export function FieldErrors({ field }: { field: AnyFieldApi }) { + return ( + + {field.errors.map((error) => error.message).join(', ')} + + ) +} +``` + +```tsx file="SubmitButton.tsx" +import type { AnyPreactFormApi } from '@tanstack/preact-form' + +export function SubmitButton({ form }: { form: AnyPreactFormApi }) { + return ( + [state.canSubmit, state.isSubmitting] as const} + > + {([canSubmit, isSubmitting]) => ( + + )} + + ) +} +``` + + + +# Vue + +Vue provides `AnyVueFormApi` for form-level components. Pass the field from the +`form.Field` slot to `FieldErrors`, and pass the form instance to +`SubmitButton`. + + + +```vue file="FieldErrors.vue" + + + +``` + +```vue file="SubmitButton.vue" + + + +``` + + + +# Angular + +For a field control that doesn't read the value, use `injectField()` +to receive the field and react to its metadata. Angular provides +`AnyAngularFormApi` when a separate component only needs form methods. + + + +```ts file="field-errors.component.ts" +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { injectField } from '@tanstack/angular-form' + +@Component({ + selector: 'app-field-errors', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + @for (error of field.api.errors; track error) { + {{ error.message }} + } + + `, +}) +export class FieldErrorsComponent { + field = injectField() +} +``` + +```ts file="reset-button.component.ts" +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import type { AnyAngularFormApi } from '@tanstack/angular-form' + +@Component({ + selector: 'app-reset-button', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + template: ``, +}) +export class ResetButtonComponent { + form = input.required() +} +``` + + + +# Solid + +Solid provides `AnySolidFormApi` for form-level components. Its field render +prop remains an accessor, so `FieldErrors` accepts an +`Accessor`. + + + +```tsx file="FieldErrors.tsx" +import type { Accessor } from 'solid-js' +import type { AnyFieldApi } from '@tanstack/solid-form' + +export function FieldErrors(props: { field: Accessor }) { + return ( + + {props + .field() + .errors.map((error) => error.message) + .join(', ')} + + ) +} +``` + +```tsx file="SubmitButton.tsx" +import type { AnySolidFormApi } from '@tanstack/solid-form' + +export function SubmitButton(props: { form: AnySolidFormApi }) { + return ( + [state.canSubmit, state.isSubmitting] as const} + > + {(state) => ( + + )} + + ) +} +``` + + + +# Lit + +Lit doesn't expose an `AnyLitFormApi` controller type. Use `AnyFieldApi` for a +field render helper, or pass the controller's core `form.api` object to a +helper typed with `AnyFormApi`. + + + +```ts file="field-errors.ts" +import { html } from 'lit' +import type { AnyFieldApi } from '@tanstack/lit-form' + +export function fieldErrors(field: AnyFieldApi) { + return html` + + ${field.errors.map((error) => error.message).join(', ')} + + ` +} +``` + +```ts file="reset-button.ts" +import { html } from 'lit' +import type { AnyFormApi } from '@tanstack/lit-form' + +export function resetButton(form: AnyFormApi) { + return html` + + ` +} +``` + + + +# Svelte + +Svelte provides `AnySvelteFormApi` for form-level components. Pass the field +from the `form.Field` snippet to `FieldErrors`, and pass the form instance to +`SubmitButton`. + + + +```svelte file="FieldErrors.svelte" + + + + {field.errors.map((error) => error.message).join(', ')} + +``` + +```svelte file="SubmitButton.svelte" + + + [state.canSubmit, state.isSubmitting] as const} +> + {#snippet children([canSubmit, isSubmitting])} + + {/snippet} + +``` + + + + diff --git a/docs/typescript.md b/docs/typescript.md index cfb22cdf8f..3582d9785d 100644 --- a/docs/typescript.md +++ b/docs/typescript.md @@ -5,10 +5,31 @@ title: TypeScript TanStack Form is written 100% in **TypeScript** with the highest quality generics, constraints, and interfaces to make sure the library and your projects are as type-safe as possible! -Things to keep in mind: +## Infer form and field types -- `strict: true` is required in your `tsconfig.json` to get the most out of TanStack Form's types -- Types currently require using TypeScript v5.4 or greater -- Changes to types in this repository are considered **non-breaking** and are usually released as **patch** semver changes (otherwise every type enhancement would be a major version!). -- It is **highly recommended that you lock your react-form package version to a specific patch release and upgrade with the expectation that types may be fixed or upgraded between any release** -- The non-type-related public API of TanStack Form still follows semver very strictly. +TanStack Form works out your form's data type from its `defaultValues`. From +there, each field name points to a value in that data shape, so field callbacks +and form methods know which values belong at each path. + +Don't write the full `FormApi` or `FieldApi` generic parameter lists by hand in +application code. Those signatures may change as TanStack Form's type +inference evolves. At component boundaries, use the adapter's `*FormType`, +`FieldWithValue`, `AnyFieldApi`, or the adapter's `Any*FormApi` helper, +depending on what the component needs. The [Splitting forms](./splitting-forms) +guide shows how to use each helper. + +## Compiler requirements + +Enable `strict: true` in your `tsconfig.json` so TypeScript can check field +paths, values, and callbacks as intended. TanStack Form's types require +TypeScript 5.4 or later. + +## Type changes between releases + +Improvements and corrections to TanStack Form's types may ship in patch +releases. These changes don't affect runtime behaviour, but they may reveal a +type error in application code that previously compiled. + +If you need to plan for those updates, pin your TanStack Form adapter to an +exact patch version and review any new type errors when upgrading. Changes to +the runtime API continue to follow semantic versioning. diff --git a/eslint.config.js b/eslint.config.js index 642db6aa1f..48717da8c3 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,9 +1,11 @@ // @ts-check +import { defineConfig } from 'eslint/config' + // @ts-ignore Needed due to moduleResolution Node vs Bundler import { tanstackConfig } from '@tanstack/eslint-config' -export default [ +export default defineConfig([ ...tanstackConfig, { name: 'tanstack/temp', @@ -16,6 +18,15 @@ export default [ '@typescript-eslint/require-await': 'off', 'no-async-promise-executor': 'off', 'no-empty': 'off', + 'no-restricted-syntax': [ + 'error', + { + selector: + "ImportDeclaration[source.value='lucide-solid'][importKind!='type'] > ImportSpecifier[importKind!='type'][imported.name=/Icon$/]", + message: + "Import icons from 'lucide-solid/icons/{name}' instead of the 'lucide-solid' barrel.", + }, + ], }, }, -] +]) diff --git a/examples/angular/array/.editorconfig b/examples/angular/array/.editorconfig deleted file mode 100644 index 59d9a3a3e7..0000000000 --- a/examples/angular/array/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -# Editor configuration, see https://editorconfig.org -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.ts] -quote_type = single - -[*.md] -max_line_length = off -trim_trailing_whitespace = false diff --git a/examples/angular/array/.gitignore b/examples/angular/array/.gitignore deleted file mode 100644 index 0711527ef9..0000000000 --- a/examples/angular/array/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. - -# Compiled output -/dist -/tmp -/out-tsc -/bazel-out - -# Node -/node_modules -npm-debug.log -yarn-error.log - -# IDEs and editors -.idea/ -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# Visual Studio Code -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -.history/* - -# Miscellaneous -/.angular/cache -.sass-cache/ -/connect.lock -/coverage -/libpeerconnection.log -testem.log -/typings - -# System files -.DS_Store -Thumbs.db diff --git a/examples/angular/array/README.md b/examples/angular/array/README.md index 3e87f4c6d2..a26c8c0213 100644 --- a/examples/angular/array/README.md +++ b/examples/angular/array/README.md @@ -1,27 +1,25 @@ -# Simple +# Example -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.0.1. +To run this example: -## Development server +- `pnpm install` +- `pnpm dev` + *** Add File: /Users/crutchcorn/git/tanstack/form/examples/angular/array/.gitignore -Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. +# Logs -## Code scaffolding +logs +_.log +pnpm-debug.log_ -Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. +node_modules +dist +out-tsc +*.local -## Build +# Editor files -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. - -## Running unit tests - -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). - -## Running end-to-end tests - -Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. - -## Further help - -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store diff --git a/examples/angular/array/angular.json b/examples/angular/array/angular.json deleted file mode 100644 index 0cc433f7f4..0000000000 --- a/examples/angular/array/angular.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "simple": { - "projectType": "application", - "schematics": {}, - "root": "", - "sourceRoot": "src", - "prefix": "app", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:application", - "options": { - "outputPath": "dist/simple", - "index": "src/index.html", - "browser": "src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "tsconfig.app.json", - "assets": ["src/favicon.ico", "src/assets"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "simple:build:production" - }, - "development": { - "buildTarget": "simple:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "simple:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "polyfills": ["zone.js", "zone.js/testing"], - "tsConfig": "tsconfig.spec.json", - "assets": ["src/favicon.ico", "src/assets"], - "scripts": [] - } - } - } - } - } -} diff --git a/examples/angular/array/index.html b/examples/angular/array/index.html new file mode 100644 index 0000000000..013129a057 --- /dev/null +++ b/examples/angular/array/index.html @@ -0,0 +1,12 @@ + + + + + + Array Form + + + + + + diff --git a/examples/angular/array/package.json b/examples/angular/array/package.json index 1a61dec87d..573ac41c3c 100644 --- a/examples/angular/array/package.json +++ b/examples/angular/array/package.json @@ -3,30 +3,23 @@ "private": true, "type": "module", "scripts": { - "ng": "ng", - "start": "ng cache clean && ng serve", - "build": "ng build", - "watch": "ng build --watch --configuration development", - "test": "ng test" + "dev": "vite --port=3503", + "build": "vite build", + "preview": "vite preview", + "test:types": "ngc -p tsconfig.app.json --noEmit" }, "dependencies": { - "@angular/animations": "^21.2.14", - "@angular/common": "^21.2.14", - "@angular/compiler": "^21.2.14", - "@angular/core": "^21.2.14", - "@angular/forms": "^21.2.14", - "@angular/platform-browser": "^21.2.14", - "@angular/platform-browser-dynamic": "^21.2.14", - "@angular/router": "^21.2.14", - "@tanstack/angular-form": "^1.33.3", - "rxjs": "^7.8.2", - "tslib": "^2.8.1", - "zone.js": "0.15.1" + "@angular/common": "^22.1.1", + "@angular/compiler": "^22.1.1", + "@angular/core": "^22.1.1", + "@angular/platform-browser": "^22.1.1", + "@tanstack/angular-form": "^2.0.0-alpha.3", + "rxjs": "^7.8.2" }, "devDependencies": { - "@angular-devkit/build-angular": "^21.2.12", - "@angular/cli": "^21.2.12", - "@angular/compiler-cli": "^21.2.14", - "typescript": "5.9.3" + "@analogjs/vite-plugin-angular": "^2.7.2", + "@angular/compiler-cli": "^22.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/angular/array/src/app.component.ts b/examples/angular/array/src/app.component.ts new file mode 100644 index 0000000000..5bd7076268 --- /dev/null +++ b/examples/angular/array/src/app.component.ts @@ -0,0 +1,102 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { + TanStackArrayField, + TanStackField, + injectForm, + injectSelector, +} from '@tanstack/angular-form' + +@Component({ + selector: 'app-root', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TanStackArrayField, TanStackField], + template: ` +
    +

    Arrays in Form Example

    + +
    + + +
    + +

    Item amount: {{ itemAmount() }}

    +
    +
    + + +
    + + +
      + @for (_ of items.api.value; track $index) { +
    • + + + +
    • + } +
    +
    +
    +
    + `, +}) +export class AppComponent { + requestedAmount = 50 + form = injectForm({ + defaultValues: { items: Array.from({ length: 50 }, () => '') }, + onSubmit: ({ value }) => { + console.log(value) + alert(`Submitted ${value.items.length} items.`) + }, + }) + itemAmount = injectSelector(this.form, (state) => state.values.items.length) + + itemName(index: number): `items[${number}]` { + return `items[${index}]` + } + + updateItems() { + if (Number.isNaN(this.requestedAmount)) return + const amount = Math.min(10_000, Math.max(0, this.requestedAmount)) + this.form.reset({ items: Array.from({ length: amount }, () => '') }) + } + + handleSubmit(event: SubmitEvent) { + event.preventDefault() + event.stopPropagation() + this.form.handleSubmit() + } +} diff --git a/examples/angular/array/src/app/app.component.ts b/examples/angular/array/src/app/app.component.ts deleted file mode 100644 index 9aefb8f2f0..0000000000 --- a/examples/angular/array/src/app/app.component.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { Component } from '@angular/core' -import { TanStackField, injectForm, injectStore } from '@tanstack/angular-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` -
    -
    - -
    - @for (_ of people.api.state.value; track $index) { - -
    - -
    -
    - } -
    - -
    -
    - -
    - `, -}) -export class AppComponent { - defaultPerson = { name: '', age: 0 } - - form = injectForm({ - defaultValues: { - people: [] as Array<{ name: string; age: number }>, - }, - onSubmit({ value }) { - alert(JSON.stringify(value)) - }, - }) - - getPeopleName = (idx: number) => `people[${idx}].name` as const - - canSubmit = injectStore(this.form, (state) => state.canSubmit) - isSubmitting = injectStore(this.form, (state) => state.isSubmitting) - - handleSubmit(event: SubmitEvent) { - event.preventDefault() - event.stopPropagation() - this.form.handleSubmit() - } -} diff --git a/examples/angular/array/src/favicon.ico b/examples/angular/array/src/favicon.ico deleted file mode 100644 index 57614f9c96..0000000000 Binary files a/examples/angular/array/src/favicon.ico and /dev/null differ diff --git a/examples/angular/array/src/index.html b/examples/angular/array/src/index.html deleted file mode 100644 index c3c6fbbdd5..0000000000 --- a/examples/angular/array/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Simple - - - - - - - - diff --git a/examples/angular/array/src/main.ts b/examples/angular/array/src/main.ts index 56773910ea..bdac04402c 100644 --- a/examples/angular/array/src/main.ts +++ b/examples/angular/array/src/main.ts @@ -1,4 +1,8 @@ +import { provideZonelessChangeDetection } from '@angular/core' import { bootstrapApplication } from '@angular/platform-browser' -import { AppComponent } from './app/app.component' +import { AppComponent } from './app.component' +import './styles.css' -bootstrapApplication(AppComponent).catch((err) => console.error(err)) +bootstrapApplication(AppComponent, { + providers: [provideZonelessChangeDetection()], +}).catch((error) => console.error(error)) diff --git a/examples/angular/array/src/styles.css b/examples/angular/array/src/styles.css new file mode 100644 index 0000000000..0bc5c5439f --- /dev/null +++ b/examples/angular/array/src/styles.css @@ -0,0 +1,48 @@ +:root { + color: #213547; + background: #f7f7f8; + font-family: Inter, system-ui, sans-serif; +} +body { + margin: 0; +} +main { + max-width: 48rem; + margin: 0 auto; + padding: 2rem; +} +form, +section, +fieldset { + display: grid; + gap: 1rem; +} +label { + display: grid; + gap: 0.35rem; +} +input, +button, +select { + font: inherit; + padding: 0.55rem 0.7rem; +} +button { + width: fit-content; + cursor: pointer; +} +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} +small[role='alert'], +.error { + color: #b42318; +} +.validating { + opacity: 0.7; +} +fieldset { + margin: 0; +} diff --git a/examples/angular/array/src/vite-env.d.ts b/examples/angular/array/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/angular/array/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/angular/array/tsconfig.app.json b/examples/angular/array/tsconfig.app.json index 84f1f992d2..e68f13b4a2 100644 --- a/examples/angular/array/tsconfig.app.json +++ b/examples/angular/array/tsconfig.app.json @@ -1,10 +1,16 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "./tsconfig.json", "compilerOptions": { + "noEmit": false, "outDir": "./out-tsc/app", + "rootDir": "../../..", "types": [] }, "files": ["src/main.ts"], - "include": ["src/**/*.d.ts"] + "include": ["src/**/*.d.ts"], + "angularCompilerOptions": { + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } } diff --git a/examples/angular/array/tsconfig.json b/examples/angular/array/tsconfig.json index afd15727a8..dd46e28018 100644 --- a/examples/angular/array/tsconfig.json +++ b/examples/angular/array/tsconfig.json @@ -1,28 +1,19 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { - "compileOnSave": false, + "extends": "../../../tsconfig.json", "compilerOptions": { - "outDir": "./dist/out-tsc", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "esModuleInterop": true, - "sourceMap": true, "declaration": false, + "emitDecoratorMetadata": true, "experimentalDecorators": true, - "moduleResolution": "bundler", - "importHelpers": true, - "target": "ES2022", - "module": "ES2022", + "moduleResolution": "Bundler", + "noEmit": true, "useDefineForClassFields": false, - "lib": ["ES2022", "dom"] + "paths": { + "@tanstack/angular-form": ["../../../packages/angular-form/src"], + "@tanstack/form-core": ["../../../packages/form-core/src"], + "@tanstack/form-core/internals": [ + "../../../packages/form-core/src/internals.ts" + ] + } }, - "angularCompilerOptions": { - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } + "include": ["src", "vite.config.ts"] } diff --git a/examples/angular/array/tsconfig.spec.json b/examples/angular/array/tsconfig.spec.json deleted file mode 100644 index 47e3dd7551..0000000000 --- a/examples/angular/array/tsconfig.spec.json +++ /dev/null @@ -1,9 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/spec", - "types": ["jasmine"] - }, - "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] -} diff --git a/examples/angular/array/vite.config.ts b/examples/angular/array/vite.config.ts new file mode 100644 index 0000000000..3484e49747 --- /dev/null +++ b/examples/angular/array/vite.config.ts @@ -0,0 +1,7 @@ +import angular from '@analogjs/vite-plugin-angular' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [angular({ tsconfig: 'tsconfig.app.json' })], + resolve: { tsconfigPaths: true }, +}) diff --git a/examples/angular/basic-splitting-form/README.md b/examples/angular/basic-splitting-form/README.md new file mode 100644 index 0000000000..eef22b3cac --- /dev/null +++ b/examples/angular/basic-splitting-form/README.md @@ -0,0 +1,25 @@ +# Example + +To run this example: + +- `pnpm install` +- `pnpm dev` + *** Add File: /Users/crutchcorn/git/tanstack/form/examples/angular/basic-splitting-form/.gitignore + +# Logs + +logs +_.log +pnpm-debug.log_ + +node_modules +dist +out-tsc +*.local + +# Editor files + +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store diff --git a/examples/angular/basic-splitting-form/index.html b/examples/angular/basic-splitting-form/index.html new file mode 100644 index 0000000000..1695a4e668 --- /dev/null +++ b/examples/angular/basic-splitting-form/index.html @@ -0,0 +1,12 @@ + + + + + + Split Form + + + + + + diff --git a/examples/angular/basic-splitting-form/package.json b/examples/angular/basic-splitting-form/package.json new file mode 100644 index 0000000000..1a023df937 --- /dev/null +++ b/examples/angular/basic-splitting-form/package.json @@ -0,0 +1,25 @@ +{ + "name": "@tanstack/form-example-angular-basic-splitting-form", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3504", + "build": "vite build", + "preview": "vite preview", + "test:types": "ngc -p tsconfig.app.json --noEmit" + }, + "dependencies": { + "@angular/common": "^22.1.1", + "@angular/compiler": "^22.1.1", + "@angular/core": "^22.1.1", + "@angular/platform-browser": "^22.1.1", + "@tanstack/angular-form": "^2.0.0-alpha.3", + "rxjs": "^7.8.2" + }, + "devDependencies": { + "@analogjs/vite-plugin-angular": "^2.7.2", + "@angular/compiler-cli": "^22.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/angular/basic-splitting-form/src/app.component.ts b/examples/angular/basic-splitting-form/src/app.component.ts new file mode 100644 index 0000000000..0573c60827 --- /dev/null +++ b/examples/angular/basic-splitting-form/src/app.component.ts @@ -0,0 +1,65 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { + TanStackAppField, + TanStackField, + injectForm, + injectSelector, +} from '@tanstack/angular-form' +import { FormSectionComponent } from './form-section.component' +import { StringFieldComponent } from './string-field.component' +import { SubmitButtonComponent } from './submit-button.component' +import { sharedFormOptions } from './shared-form' + +@Component({ + selector: 'app-root', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + TanStackAppField, + TanStackField, + FormSectionComponent, + StringFieldComponent, + SubmitButtonComponent, + ], + template: ` +
    +

    Split Form Example

    +
    + + + +
    + + +
    + +
    + `, +}) +export class AppComponent { + form = injectForm({ + ...sharedFormOptions, + onSubmit: ({ value }) => console.log(value), + }) + canSubmit = injectSelector(this.form, (state) => state.canSubmit) + isSubmitting = injectSelector(this.form, (state) => state.isSubmitting) + + handleSubmit(event: SubmitEvent) { + event.preventDefault() + event.stopPropagation() + this.form.handleSubmit() + } +} diff --git a/examples/angular/basic-splitting-form/src/form-section.component.ts b/examples/angular/basic-splitting-form/src/form-section.component.ts new file mode 100644 index 0000000000..e8b9662b2b --- /dev/null +++ b/examples/angular/basic-splitting-form/src/form-section.component.ts @@ -0,0 +1,32 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { TanStackAppField, TanStackField } from '@tanstack/angular-form' +import { StringFieldComponent } from './string-field.component' +import type { AngularFormType } from '@tanstack/angular-form' +import type { sharedFormOptions } from './shared-form' + +@Component({ + selector: 'app-form-section', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TanStackAppField, TanStackField, StringFieldComponent], + template: ` +
    + Address + + +
    + `, +}) +export class FormSectionComponent { + form = input.required>() +} diff --git a/examples/angular/basic-splitting-form/src/main.ts b/examples/angular/basic-splitting-form/src/main.ts new file mode 100644 index 0000000000..bdac04402c --- /dev/null +++ b/examples/angular/basic-splitting-form/src/main.ts @@ -0,0 +1,8 @@ +import { provideZonelessChangeDetection } from '@angular/core' +import { bootstrapApplication } from '@angular/platform-browser' +import { AppComponent } from './app.component' +import './styles.css' + +bootstrapApplication(AppComponent, { + providers: [provideZonelessChangeDetection()], +}).catch((error) => console.error(error)) diff --git a/examples/angular/basic-splitting-form/src/shared-form.ts b/examples/angular/basic-splitting-form/src/shared-form.ts new file mode 100644 index 0000000000..671dd44329 --- /dev/null +++ b/examples/angular/basic-splitting-form/src/shared-form.ts @@ -0,0 +1,9 @@ +import { formOptions } from '@tanstack/angular-form' + +export const sharedFormOptions = formOptions({ + defaultValues: { + firstName: '', + lastName: '', + address: { street: '', country: '' }, + }, +}) diff --git a/examples/angular/basic-splitting-form/src/string-field.component.ts b/examples/angular/basic-splitting-form/src/string-field.component.ts new file mode 100644 index 0000000000..b8bf70d24a --- /dev/null +++ b/examples/angular/basic-splitting-form/src/string-field.component.ts @@ -0,0 +1,27 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { injectField } from '@tanstack/angular-form' + +@Component({ + selector: 'app-string-field', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + `, +}) +export class StringFieldComponent { + label = input.required() + field = injectField() +} diff --git a/examples/angular/basic-splitting-form/src/styles.css b/examples/angular/basic-splitting-form/src/styles.css new file mode 100644 index 0000000000..0bc5c5439f --- /dev/null +++ b/examples/angular/basic-splitting-form/src/styles.css @@ -0,0 +1,48 @@ +:root { + color: #213547; + background: #f7f7f8; + font-family: Inter, system-ui, sans-serif; +} +body { + margin: 0; +} +main { + max-width: 48rem; + margin: 0 auto; + padding: 2rem; +} +form, +section, +fieldset { + display: grid; + gap: 1rem; +} +label { + display: grid; + gap: 0.35rem; +} +input, +button, +select { + font: inherit; + padding: 0.55rem 0.7rem; +} +button { + width: fit-content; + cursor: pointer; +} +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} +small[role='alert'], +.error { + color: #b42318; +} +.validating { + opacity: 0.7; +} +fieldset { + margin: 0; +} diff --git a/examples/angular/basic-splitting-form/src/submit-button.component.ts b/examples/angular/basic-splitting-form/src/submit-button.component.ts new file mode 100644 index 0000000000..2b7caa1d70 --- /dev/null +++ b/examples/angular/basic-splitting-form/src/submit-button.component.ts @@ -0,0 +1,17 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import type { Signal } from '@angular/core' + +@Component({ + selector: 'app-submit-button', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + `, +}) +export class SubmitButtonComponent { + canSubmit = input.required>() + isSubmitting = input.required>() +} diff --git a/examples/angular/basic-splitting-form/src/vite-env.d.ts b/examples/angular/basic-splitting-form/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/angular/basic-splitting-form/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/angular/basic-splitting-form/tsconfig.app.json b/examples/angular/basic-splitting-form/tsconfig.app.json new file mode 100644 index 0000000000..e68f13b4a2 --- /dev/null +++ b/examples/angular/basic-splitting-form/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "outDir": "./out-tsc/app", + "rootDir": "../../..", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "angularCompilerOptions": { + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/examples/angular/basic-splitting-form/tsconfig.json b/examples/angular/basic-splitting-form/tsconfig.json new file mode 100644 index 0000000000..dd46e28018 --- /dev/null +++ b/examples/angular/basic-splitting-form/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "declaration": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "moduleResolution": "Bundler", + "noEmit": true, + "useDefineForClassFields": false, + "paths": { + "@tanstack/angular-form": ["../../../packages/angular-form/src"], + "@tanstack/form-core": ["../../../packages/form-core/src"], + "@tanstack/form-core/internals": [ + "../../../packages/form-core/src/internals.ts" + ] + } + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/angular/basic-splitting-form/vite.config.ts b/examples/angular/basic-splitting-form/vite.config.ts new file mode 100644 index 0000000000..3484e49747 --- /dev/null +++ b/examples/angular/basic-splitting-form/vite.config.ts @@ -0,0 +1,7 @@ +import angular from '@analogjs/vite-plugin-angular' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [angular({ tsconfig: 'tsconfig.app.json' })], + resolve: { tsconfigPaths: true }, +}) diff --git a/examples/angular/basic/README.md b/examples/angular/basic/README.md new file mode 100644 index 0000000000..8ad66ec8fb --- /dev/null +++ b/examples/angular/basic/README.md @@ -0,0 +1,25 @@ +# Example + +To run this example: + +- `pnpm install` +- `pnpm dev` + *** Add File: /Users/crutchcorn/git/tanstack/form/examples/angular/basic/.gitignore + +# Logs + +logs +_.log +pnpm-debug.log_ + +node_modules +dist +out-tsc +*.local + +# Editor files + +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store diff --git a/examples/angular/basic/index.html b/examples/angular/basic/index.html new file mode 100644 index 0000000000..2546d73033 --- /dev/null +++ b/examples/angular/basic/index.html @@ -0,0 +1,12 @@ + + + + + + Basic Form + + + + + + diff --git a/examples/angular/basic/package.json b/examples/angular/basic/package.json new file mode 100644 index 0000000000..9fb04a972b --- /dev/null +++ b/examples/angular/basic/package.json @@ -0,0 +1,25 @@ +{ + "name": "@tanstack/form-example-angular-basic", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3502", + "build": "vite build", + "preview": "vite preview", + "test:types": "ngc -p tsconfig.app.json --noEmit" + }, + "dependencies": { + "@angular/common": "^22.1.1", + "@angular/compiler": "^22.1.1", + "@angular/core": "^22.1.1", + "@angular/platform-browser": "^22.1.1", + "@tanstack/angular-form": "^2.0.0-alpha.3", + "rxjs": "^7.8.2" + }, + "devDependencies": { + "@analogjs/vite-plugin-angular": "^2.7.2", + "@angular/compiler-cli": "^22.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/angular/basic/src/app.component.ts b/examples/angular/basic/src/app.component.ts new file mode 100644 index 0000000000..6759437525 --- /dev/null +++ b/examples/angular/basic/src/app.component.ts @@ -0,0 +1,107 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { + TanStackField, + injectForm, + injectSelector, +} from '@tanstack/angular-form' + +@Component({ + selector: 'app-root', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TanStackField], + template: ` +
    +

    Basic Form Example

    +
    + + + + + + + + +
    + + +
    +
    +
    + `, +}) +export class AppComponent { + firstNameValidators = [ + { + run: ({ value }: { value: string }) => { + if (value.length === 0) return 'A first name is required' + if (value.length < 3) return 'First name is too short' + return undefined + }, + triggers: ['change', 'blur'] as const, + triggerDebounceMs: 300, + }, + { + run: async ({ value }: { value: string }) => { + await new Promise((resolve) => setTimeout(resolve, 1000)) + return value.toLowerCase().includes('error') + ? 'No "error" allowed in first name' + : undefined + }, + triggers: ['change'] as const, + bailIfInvalid: true, + }, + ] + + form = injectForm({ + defaultValues: { firstName: '', lastName: '' }, + onSubmit: ({ value, createValidationError }) => { + console.log(value) + return createValidationError({ + fields: { + firstName: 'Name already exists', + lastName: 'Name already exists', + }, + }) + }, + }) + canSubmit = injectSelector(this.form, (state) => state.canSubmit) + isSubmitting = injectSelector(this.form, (state) => state.isSubmitting) + + handleSubmit(event: SubmitEvent) { + event.preventDefault() + event.stopPropagation() + this.form.handleSubmit() + } +} diff --git a/examples/angular/basic/src/main.ts b/examples/angular/basic/src/main.ts new file mode 100644 index 0000000000..bdac04402c --- /dev/null +++ b/examples/angular/basic/src/main.ts @@ -0,0 +1,8 @@ +import { provideZonelessChangeDetection } from '@angular/core' +import { bootstrapApplication } from '@angular/platform-browser' +import { AppComponent } from './app.component' +import './styles.css' + +bootstrapApplication(AppComponent, { + providers: [provideZonelessChangeDetection()], +}).catch((error) => console.error(error)) diff --git a/examples/angular/basic/src/styles.css b/examples/angular/basic/src/styles.css new file mode 100644 index 0000000000..0bc5c5439f --- /dev/null +++ b/examples/angular/basic/src/styles.css @@ -0,0 +1,48 @@ +:root { + color: #213547; + background: #f7f7f8; + font-family: Inter, system-ui, sans-serif; +} +body { + margin: 0; +} +main { + max-width: 48rem; + margin: 0 auto; + padding: 2rem; +} +form, +section, +fieldset { + display: grid; + gap: 1rem; +} +label { + display: grid; + gap: 0.35rem; +} +input, +button, +select { + font: inherit; + padding: 0.55rem 0.7rem; +} +button { + width: fit-content; + cursor: pointer; +} +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} +small[role='alert'], +.error { + color: #b42318; +} +.validating { + opacity: 0.7; +} +fieldset { + margin: 0; +} diff --git a/examples/angular/basic/src/vite-env.d.ts b/examples/angular/basic/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/angular/basic/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/angular/basic/tsconfig.app.json b/examples/angular/basic/tsconfig.app.json new file mode 100644 index 0000000000..e68f13b4a2 --- /dev/null +++ b/examples/angular/basic/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "outDir": "./out-tsc/app", + "rootDir": "../../..", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "angularCompilerOptions": { + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/examples/angular/basic/tsconfig.json b/examples/angular/basic/tsconfig.json new file mode 100644 index 0000000000..dd46e28018 --- /dev/null +++ b/examples/angular/basic/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "declaration": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "moduleResolution": "Bundler", + "noEmit": true, + "useDefineForClassFields": false, + "paths": { + "@tanstack/angular-form": ["../../../packages/angular-form/src"], + "@tanstack/form-core": ["../../../packages/form-core/src"], + "@tanstack/form-core/internals": [ + "../../../packages/form-core/src/internals.ts" + ] + } + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/angular/basic/vite.config.ts b/examples/angular/basic/vite.config.ts new file mode 100644 index 0000000000..3484e49747 --- /dev/null +++ b/examples/angular/basic/vite.config.ts @@ -0,0 +1,7 @@ +import angular from '@analogjs/vite-plugin-angular' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [angular({ tsconfig: 'tsconfig.app.json' })], + resolve: { tsconfigPaths: true }, +}) diff --git a/examples/angular/field-groups/README.md b/examples/angular/field-groups/README.md new file mode 100644 index 0000000000..e20aa60d0c --- /dev/null +++ b/examples/angular/field-groups/README.md @@ -0,0 +1,25 @@ +# Example + +To run this example: + +- `pnpm install` +- `pnpm dev` + *** Add File: /Users/crutchcorn/git/tanstack/form/examples/angular/field-groups/.gitignore + +# Logs + +logs +_.log +pnpm-debug.log_ + +node_modules +dist +out-tsc +*.local + +# Editor files + +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store diff --git a/examples/angular/field-groups/index.html b/examples/angular/field-groups/index.html new file mode 100644 index 0000000000..485b002096 --- /dev/null +++ b/examples/angular/field-groups/index.html @@ -0,0 +1,12 @@ + + + + + + Field Groups + + + + + + diff --git a/examples/angular/field-groups/package.json b/examples/angular/field-groups/package.json new file mode 100644 index 0000000000..b1cb6bc0f5 --- /dev/null +++ b/examples/angular/field-groups/package.json @@ -0,0 +1,26 @@ +{ + "name": "@tanstack/form-example-angular-field-groups", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3505", + "build": "vite build", + "preview": "vite preview", + "test:types": "ngc -p tsconfig.app.json --noEmit" + }, + "dependencies": { + "@angular/common": "^22.1.1", + "@angular/compiler": "^22.1.1", + "@angular/core": "^22.1.1", + "@angular/platform-browser": "^22.1.1", + "@tanstack/angular-form": "^2.0.0-alpha.3", + "rxjs": "^7.8.2", + "zod": "^4.4.3" + }, + "devDependencies": { + "@analogjs/vite-plugin-angular": "^2.7.2", + "@angular/compiler-cli": "^22.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/angular/field-groups/src/app.component.ts b/examples/angular/field-groups/src/app.component.ts new file mode 100644 index 0000000000..5dab6691c2 --- /dev/null +++ b/examples/angular/field-groups/src/app.component.ts @@ -0,0 +1,83 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { TanStackArrayField, injectForm } from '@tanstack/angular-form' +import { BoundFieldComponent } from './bound-field.component' +import { DateRangeComponent } from './date-range.component' + +@Component({ + selector: 'app-root', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [BoundFieldComponent, DateRangeComponent, TanStackArrayField], + template: ` +
    +

    Reusable Field Group Example

    +
    +

    Price Filter Form

    + + +
    +
    +

    Age Range Form

    + + +
    +
    +

    Swappable Date Ranges

    + + + @for (range of ranges.api.value; track range.id; let index = $index) { + + } + +
    +
    + `, +}) +export class AppComponent { + pricingForm = injectForm({ defaultValues: { minPrice: '', maxPrice: '' } }) + ageForm = injectForm({ defaultValues: { minAge: '', maxAge: '' } }) + dateForm = injectForm({ + defaultValues: { + dateRanges: [ + { id: 'A', start: '2026-07-01', end: '2026-07-05' }, + { id: 'B', start: '2026-08-10', end: '2026-08-15' }, + ], + }, + }) + + dateFields(index: number) { + return { + start: `dateRanges[${index}].start`, + end: `dateRanges[${index}].end`, + } + } +} diff --git a/examples/angular/field-groups/src/bound-field.component.ts b/examples/angular/field-groups/src/bound-field.component.ts new file mode 100644 index 0000000000..609443897d --- /dev/null +++ b/examples/angular/field-groups/src/bound-field.component.ts @@ -0,0 +1,67 @@ +import { + ChangeDetectionStrategy, + Component, + computed, + input, +} from '@angular/core' +import { TanStackField } from '@tanstack/angular-form' +import { z } from 'zod' +import type { AnyAngularFormApi } from '@tanstack/angular-form' + +const boundsSchema = z.coerce.number().int() + +@Component({ + selector: 'app-bound-field', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TanStackField], + template: ` + + + + `, +}) +export class BoundFieldComponent { + form = input.required() + label = input.required() + fields = input.required<{ value: string; lowerBound?: string }>() + + validators = computed(() => [ + { + triggers: ['change'] as const, + watchFields: this.fields().lowerBound + ? [this.fields().lowerBound!] + : undefined, + run: ({ value, parseIssues }: any) => { + const valueResult = boundsSchema.safeParse(value) + if (!valueResult.success) return parseIssues(valueResult.error.issues) + const lowerName = this.fields().lowerBound + if (!lowerName) return + const lowerResult = boundsSchema.safeParse( + this.form().getFieldValue(lowerName), + ) + if (lowerResult.success && valueResult.data < lowerResult.data) { + return 'Upper bound must be greater than lower bound' + } + }, + }, + ]) +} diff --git a/examples/angular/field-groups/src/date-range.component.ts b/examples/angular/field-groups/src/date-range.component.ts new file mode 100644 index 0000000000..76f5ae4854 --- /dev/null +++ b/examples/angular/field-groups/src/date-range.component.ts @@ -0,0 +1,74 @@ +import { + ChangeDetectionStrategy, + Component, + computed, + input, +} from '@angular/core' +import { TanStackField } from '@tanstack/angular-form' +import type { AnyAngularFormApi } from '@tanstack/angular-form' + +@Component({ + selector: 'app-date-range', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TanStackField], + template: ` +
    + {{ label() }} + + + + + + +
    + `, +}) +export class DateRangeComponent { + form = input.required() + label = input.required() + fields = input.required<{ start: string; end: string }>() + endValidators = computed(() => [ + { + triggers: ['change'] as const, + watchFields: [this.fields().start], + run: ({ value }: { value: string }) => { + const start = this.form().getFieldValue(this.fields().start) + return value && start && value < start + ? 'End date must be after the start date' + : undefined + }, + }, + ]) +} diff --git a/examples/angular/field-groups/src/main.ts b/examples/angular/field-groups/src/main.ts new file mode 100644 index 0000000000..bdac04402c --- /dev/null +++ b/examples/angular/field-groups/src/main.ts @@ -0,0 +1,8 @@ +import { provideZonelessChangeDetection } from '@angular/core' +import { bootstrapApplication } from '@angular/platform-browser' +import { AppComponent } from './app.component' +import './styles.css' + +bootstrapApplication(AppComponent, { + providers: [provideZonelessChangeDetection()], +}).catch((error) => console.error(error)) diff --git a/examples/angular/field-groups/src/styles.css b/examples/angular/field-groups/src/styles.css new file mode 100644 index 0000000000..0bc5c5439f --- /dev/null +++ b/examples/angular/field-groups/src/styles.css @@ -0,0 +1,48 @@ +:root { + color: #213547; + background: #f7f7f8; + font-family: Inter, system-ui, sans-serif; +} +body { + margin: 0; +} +main { + max-width: 48rem; + margin: 0 auto; + padding: 2rem; +} +form, +section, +fieldset { + display: grid; + gap: 1rem; +} +label { + display: grid; + gap: 0.35rem; +} +input, +button, +select { + font: inherit; + padding: 0.55rem 0.7rem; +} +button { + width: fit-content; + cursor: pointer; +} +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} +small[role='alert'], +.error { + color: #b42318; +} +.validating { + opacity: 0.7; +} +fieldset { + margin: 0; +} diff --git a/examples/angular/field-groups/src/vite-env.d.ts b/examples/angular/field-groups/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/angular/field-groups/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/angular/field-groups/tsconfig.app.json b/examples/angular/field-groups/tsconfig.app.json new file mode 100644 index 0000000000..e68f13b4a2 --- /dev/null +++ b/examples/angular/field-groups/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "outDir": "./out-tsc/app", + "rootDir": "../../..", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "angularCompilerOptions": { + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/examples/angular/field-groups/tsconfig.json b/examples/angular/field-groups/tsconfig.json new file mode 100644 index 0000000000..dd46e28018 --- /dev/null +++ b/examples/angular/field-groups/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "declaration": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "moduleResolution": "Bundler", + "noEmit": true, + "useDefineForClassFields": false, + "paths": { + "@tanstack/angular-form": ["../../../packages/angular-form/src"], + "@tanstack/form-core": ["../../../packages/form-core/src"], + "@tanstack/form-core/internals": [ + "../../../packages/form-core/src/internals.ts" + ] + } + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/angular/field-groups/vite.config.ts b/examples/angular/field-groups/vite.config.ts new file mode 100644 index 0000000000..3484e49747 --- /dev/null +++ b/examples/angular/field-groups/vite.config.ts @@ -0,0 +1,7 @@ +import angular from '@analogjs/vite-plugin-angular' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [angular({ tsconfig: 'tsconfig.app.json' })], + resolve: { tsconfigPaths: true }, +}) diff --git a/examples/angular/large-form/.editorconfig b/examples/angular/large-form/.editorconfig deleted file mode 100644 index 59d9a3a3e7..0000000000 --- a/examples/angular/large-form/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -# Editor configuration, see https://editorconfig.org -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.ts] -quote_type = single - -[*.md] -max_line_length = off -trim_trailing_whitespace = false diff --git a/examples/angular/large-form/.gitignore b/examples/angular/large-form/.gitignore deleted file mode 100644 index 0711527ef9..0000000000 --- a/examples/angular/large-form/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. - -# Compiled output -/dist -/tmp -/out-tsc -/bazel-out - -# Node -/node_modules -npm-debug.log -yarn-error.log - -# IDEs and editors -.idea/ -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# Visual Studio Code -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -.history/* - -# Miscellaneous -/.angular/cache -.sass-cache/ -/connect.lock -/coverage -/libpeerconnection.log -testem.log -/typings - -# System files -.DS_Store -Thumbs.db diff --git a/examples/angular/large-form/README.md b/examples/angular/large-form/README.md index 3e87f4c6d2..7bb0f2f63e 100644 --- a/examples/angular/large-form/README.md +++ b/examples/angular/large-form/README.md @@ -1,27 +1,25 @@ -# Simple +# Example -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.0.1. +To run this example: -## Development server +- `pnpm install` +- `pnpm dev` + *** Add File: /Users/crutchcorn/git/tanstack/form/examples/angular/large-form/.gitignore -Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. +# Logs -## Code scaffolding +logs +_.log +pnpm-debug.log_ -Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. +node_modules +dist +out-tsc +*.local -## Build +# Editor files -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. - -## Running unit tests - -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). - -## Running end-to-end tests - -Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. - -## Further help - -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store diff --git a/examples/angular/large-form/angular.json b/examples/angular/large-form/angular.json deleted file mode 100644 index 0cc433f7f4..0000000000 --- a/examples/angular/large-form/angular.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "simple": { - "projectType": "application", - "schematics": {}, - "root": "", - "sourceRoot": "src", - "prefix": "app", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:application", - "options": { - "outputPath": "dist/simple", - "index": "src/index.html", - "browser": "src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "tsconfig.app.json", - "assets": ["src/favicon.ico", "src/assets"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "simple:build:production" - }, - "development": { - "buildTarget": "simple:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "simple:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "polyfills": ["zone.js", "zone.js/testing"], - "tsConfig": "tsconfig.spec.json", - "assets": ["src/favicon.ico", "src/assets"], - "scripts": [] - } - } - } - } - } -} diff --git a/examples/angular/large-form/index.html b/examples/angular/large-form/index.html new file mode 100644 index 0000000000..4610e82c8f --- /dev/null +++ b/examples/angular/large-form/index.html @@ -0,0 +1,12 @@ + + + + + + Large Form + + + + + + diff --git a/examples/angular/large-form/package.json b/examples/angular/large-form/package.json index 745639a02c..59a7446a50 100644 --- a/examples/angular/large-form/package.json +++ b/examples/angular/large-form/package.json @@ -3,30 +3,23 @@ "private": true, "type": "module", "scripts": { - "ng": "ng", - "start": "ng cache clean && ng serve", - "build": "ng build", - "watch": "ng build --watch --configuration development", - "test": "ng test" + "dev": "vite --port=3506", + "build": "vite build", + "preview": "vite preview", + "test:types": "ngc -p tsconfig.app.json --noEmit" }, "dependencies": { - "@angular/animations": "^21.2.14", - "@angular/common": "^21.2.14", - "@angular/compiler": "^21.2.14", - "@angular/core": "^21.2.14", - "@angular/forms": "^21.2.14", - "@angular/platform-browser": "^21.2.14", - "@angular/platform-browser-dynamic": "^21.2.14", - "@angular/router": "^21.2.14", - "@tanstack/angular-form": "^1.33.3", - "rxjs": "^7.8.2", - "tslib": "^2.8.1", - "zone.js": "0.15.1" + "@angular/common": "^22.1.1", + "@angular/compiler": "^22.1.1", + "@angular/core": "^22.1.1", + "@angular/platform-browser": "^22.1.1", + "@tanstack/angular-form": "^2.0.0-alpha.3", + "rxjs": "^7.8.2" }, "devDependencies": { - "@angular-devkit/build-angular": "^21.2.12", - "@angular/cli": "^21.2.12", - "@angular/compiler-cli": "^21.2.14", - "typescript": "5.9.3" + "@analogjs/vite-plugin-angular": "^2.7.2", + "@angular/compiler-cli": "^22.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/angular/large-form/src/address-fields.component.ts b/examples/angular/large-form/src/address-fields.component.ts new file mode 100644 index 0000000000..2fd3ae1213 --- /dev/null +++ b/examples/angular/large-form/src/address-fields.component.ts @@ -0,0 +1,35 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { TanStackAppField, TanStackField } from '@tanstack/angular-form' +import { TextFieldComponent } from './text-field.component' +import type { AngularFormType } from '@tanstack/angular-form' +import type { peopleFormOptions } from './shared-form' + +@Component({ + selector: 'app-address-fields', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TanStackAppField, TanStackField, TextFieldComponent], + template: ` +
    +

    Address

    + @for (field of addressFields; track field.name) { + + } +
    + `, +}) +export class AddressFieldsComponent { + form = input.required>() + addressFields = [ + { name: 'address.line1' as const, label: 'Address Line 1' }, + { name: 'address.line2' as const, label: 'Address Line 2' }, + { name: 'address.city' as const, label: 'City' }, + { name: 'address.state' as const, label: 'State' }, + { name: 'address.zip' as const, label: 'ZIP Code' }, + ] +} diff --git a/examples/angular/large-form/src/app.component.ts b/examples/angular/large-form/src/app.component.ts new file mode 100644 index 0000000000..ca00489211 --- /dev/null +++ b/examples/angular/large-form/src/app.component.ts @@ -0,0 +1,67 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { + TanStackAppField, + TanStackField, + injectForm, + injectSelector, +} from '@tanstack/angular-form' +import { AddressFieldsComponent } from './address-fields.component' +import { EmergencyContactComponent } from './emergency-contact.component' +import { peopleFormOptions } from './shared-form' +import { TextFieldComponent } from './text-field.component' + +@Component({ + selector: 'app-root', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + AddressFieldsComponent, + EmergencyContactComponent, + TanStackAppField, + TanStackField, + TextFieldComponent, + ], + template: ` +
    +
    +

    Personal Information

    + @for (field of personalFields; track field.name) { + + } + + + + +
    + `, +}) +export class AppComponent { + personalFields = [ + { name: 'fullName' as const, label: 'Full Name' }, + { name: 'email' as const, label: 'Email' }, + { name: 'phone' as const, label: 'Phone' }, + ] + form = injectForm({ + ...peopleFormOptions, + onSubmit: ({ value }) => alert(JSON.stringify(value, null, 2)), + }) + isSubmitting = injectSelector(this.form, (state) => state.isSubmitting) + + handleSubmit(event: SubmitEvent) { + event.preventDefault() + this.form.handleSubmit() + } +} diff --git a/examples/angular/large-form/src/app/app.component.ts b/examples/angular/large-form/src/app/app.component.ts deleted file mode 100644 index db38db76b0..0000000000 --- a/examples/angular/large-form/src/app/app.component.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core' -import { - TanStackAppField, - TanStackField, - TanStackWithForm, - injectForm, - injectStore, -} from '@tanstack/angular-form' -import { TextField } from './components/text-field.component' -import { AddressFields } from './features/people/address-fields.component' -import { EmergencyContact } from './features/people/emergency-contact.component' -import { peopleFormOpts } from './features/people/shared-form' - -@Component({ - selector: 'app-root', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [ - TanStackField, - TanStackAppField, - TanStackWithForm, - TextField, - AddressFields, - EmergencyContact, - ], - template: ` -
    -

    Personal Information

    - - - - - - -

    Emergency Contact

    - - - - - `, -}) -export class AppComponent { - form = injectForm({ - ...peopleFormOpts, - onSubmit: ({ value }) => { - alert(JSON.stringify(value, null, 2)) - }, - }) - - isSubmitting = injectStore(this.form, (state) => state.isSubmitting) - - handleSubmit(event: SubmitEvent) { - event.preventDefault() - event.stopPropagation() - this.form.handleSubmit() - } -} diff --git a/examples/angular/large-form/src/app/components/text-field.component.ts b/examples/angular/large-form/src/app/components/text-field.component.ts deleted file mode 100644 index 3146e23ce7..0000000000 --- a/examples/angular/large-form/src/app/components/text-field.component.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ChangeDetectionStrategy, Component, input } from '@angular/core' -import { injectField } from '@tanstack/angular-form' - -@Component({ - selector: 'app-text-field', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - template: ` -
    - - @for (error of field.api.state.meta.errors; track $index) { -
    {{ error }}
    - } -
    - `, -}) -export class TextField { - label = input.required() - field = injectField() -} diff --git a/examples/angular/large-form/src/app/features/people/address-fields.component.ts b/examples/angular/large-form/src/app/features/people/address-fields.component.ts deleted file mode 100644 index 762aa856fe..0000000000 --- a/examples/angular/large-form/src/app/features/people/address-fields.component.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core' -import { - TanStackAppField, - TanStackField, - injectWithForm, -} from '@tanstack/angular-form' -import { TextField } from '../../components/text-field.component' -import { peopleFormOpts } from './shared-form' - -@Component({ - selector: 'app-address-fields', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [TanStackField, TanStackAppField, TextField], - template: ` -
    -

    Address

    - - - - - -
    - `, -}) -export class AddressFields { - withForm = injectWithForm({ ...peopleFormOpts }) -} diff --git a/examples/angular/large-form/src/app/features/people/emergency-contact.component.ts b/examples/angular/large-form/src/app/features/people/emergency-contact.component.ts deleted file mode 100644 index 2856a6048c..0000000000 --- a/examples/angular/large-form/src/app/features/people/emergency-contact.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core' -import { - TanStackAppField, - TanStackField, - injectWithForm, -} from '@tanstack/angular-form' -import { TextField } from '../../components/text-field.component' -import { peopleFormOpts } from './shared-form' - -@Component({ - selector: 'app-emergency-contact', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [TanStackField, TanStackAppField, TextField], - template: ` - - - `, -}) -export class EmergencyContact { - withForm = injectWithForm({ ...peopleFormOpts }) -} diff --git a/examples/angular/large-form/src/app/features/people/shared-form.ts b/examples/angular/large-form/src/app/features/people/shared-form.ts deleted file mode 100644 index d3e20d8922..0000000000 --- a/examples/angular/large-form/src/app/features/people/shared-form.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { formOptions } from '@tanstack/angular-form' - -export const peopleFormOpts = formOptions({ - defaultValues: { - fullName: '', - email: '', - phone: '', - address: { - line1: '', - line2: '', - city: '', - state: '', - zip: '', - }, - emergencyContact: { - fullName: '', - phone: '', - }, - }, - validators: { - onChangeAsync: async ({ value }) => { - const errors = { - fields: {}, - } as { - fields: Record - } - if (!value.fullName) { - errors.fields['fullName'] = 'Full name is required' - } - if (!value.phone) { - errors.fields['phone'] = 'Phone is required' - } - if (!value.emergencyContact.fullName) { - errors.fields['emergencyContact.fullName'] = - 'Emergency contact full name is required' - } - if (!value.emergencyContact.phone) { - errors.fields['emergencyContact.phone'] = - 'Emergency contact phone is required' - } - - return errors - }, - }, -}) diff --git a/examples/angular/large-form/src/emergency-contact.component.ts b/examples/angular/large-form/src/emergency-contact.component.ts new file mode 100644 index 0000000000..507fecd4a8 --- /dev/null +++ b/examples/angular/large-form/src/emergency-contact.component.ts @@ -0,0 +1,36 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { TanStackAppField, TanStackField } from '@tanstack/angular-form' +import { TextFieldComponent } from './text-field.component' +import type { AngularFormType } from '@tanstack/angular-form' +import type { peopleFormOptions } from './shared-form' + +@Component({ + selector: 'app-emergency-contact', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TanStackAppField, TanStackField, TextFieldComponent], + template: ` +
    +

    Emergency Contact

    + + +
    + `, +}) +export class EmergencyContactComponent { + form = input.required>() + fields = input.required<{ + fullName: 'emergencyContact.fullName' + phone: 'emergencyContact.phone' + }>() +} diff --git a/examples/angular/large-form/src/favicon.ico b/examples/angular/large-form/src/favicon.ico deleted file mode 100644 index 57614f9c96..0000000000 Binary files a/examples/angular/large-form/src/favicon.ico and /dev/null differ diff --git a/examples/angular/large-form/src/index.html b/examples/angular/large-form/src/index.html deleted file mode 100644 index c3c6fbbdd5..0000000000 --- a/examples/angular/large-form/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Simple - - - - - - - - diff --git a/examples/angular/large-form/src/main.ts b/examples/angular/large-form/src/main.ts index 56773910ea..bdac04402c 100644 --- a/examples/angular/large-form/src/main.ts +++ b/examples/angular/large-form/src/main.ts @@ -1,4 +1,8 @@ +import { provideZonelessChangeDetection } from '@angular/core' import { bootstrapApplication } from '@angular/platform-browser' -import { AppComponent } from './app/app.component' +import { AppComponent } from './app.component' +import './styles.css' -bootstrapApplication(AppComponent).catch((err) => console.error(err)) +bootstrapApplication(AppComponent, { + providers: [provideZonelessChangeDetection()], +}).catch((error) => console.error(error)) diff --git a/examples/angular/large-form/src/shared-form.ts b/examples/angular/large-form/src/shared-form.ts new file mode 100644 index 0000000000..4d407d607b --- /dev/null +++ b/examples/angular/large-form/src/shared-form.ts @@ -0,0 +1,30 @@ +import { formOptions } from '@tanstack/angular-form' + +export const peopleFormOptions = formOptions({ + defaultValues: { + fullName: '', + email: '', + phone: '', + address: { line1: '', line2: '', city: '', state: '', zip: '' }, + emergencyContact: { fullName: '', phone: '' }, + }, + validators: [ + { + triggers: ['change'], + run: async ({ value, createErrorMap }) => { + const errors = createErrorMap() + if (!value.fullName) errors.fields.fullName = 'Full name is required' + if (!value.phone) errors.fields.phone = 'Phone is required' + if (!value.emergencyContact.fullName) { + errors.fields['emergencyContact.fullName'] = + 'Emergency contact full name is required' + } + if (!value.emergencyContact.phone) { + errors.fields['emergencyContact.phone'] = + 'Emergency contact phone is required' + } + return errors + }, + }, + ], +}) diff --git a/examples/angular/large-form/src/styles.css b/examples/angular/large-form/src/styles.css new file mode 100644 index 0000000000..0bc5c5439f --- /dev/null +++ b/examples/angular/large-form/src/styles.css @@ -0,0 +1,48 @@ +:root { + color: #213547; + background: #f7f7f8; + font-family: Inter, system-ui, sans-serif; +} +body { + margin: 0; +} +main { + max-width: 48rem; + margin: 0 auto; + padding: 2rem; +} +form, +section, +fieldset { + display: grid; + gap: 1rem; +} +label { + display: grid; + gap: 0.35rem; +} +input, +button, +select { + font: inherit; + padding: 0.55rem 0.7rem; +} +button { + width: fit-content; + cursor: pointer; +} +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} +small[role='alert'], +.error { + color: #b42318; +} +.validating { + opacity: 0.7; +} +fieldset { + margin: 0; +} diff --git a/examples/angular/large-form/src/text-field.component.ts b/examples/angular/large-form/src/text-field.component.ts new file mode 100644 index 0000000000..9e4ad00afd --- /dev/null +++ b/examples/angular/large-form/src/text-field.component.ts @@ -0,0 +1,27 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { injectField } from '@tanstack/angular-form' + +@Component({ + selector: 'app-text-field', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + `, +}) +export class TextFieldComponent { + label = input.required() + field = injectField() +} diff --git a/examples/angular/large-form/src/vite-env.d.ts b/examples/angular/large-form/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/angular/large-form/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/angular/large-form/tsconfig.app.json b/examples/angular/large-form/tsconfig.app.json index 84f1f992d2..e68f13b4a2 100644 --- a/examples/angular/large-form/tsconfig.app.json +++ b/examples/angular/large-form/tsconfig.app.json @@ -1,10 +1,16 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "./tsconfig.json", "compilerOptions": { + "noEmit": false, "outDir": "./out-tsc/app", + "rootDir": "../../..", "types": [] }, "files": ["src/main.ts"], - "include": ["src/**/*.d.ts"] + "include": ["src/**/*.d.ts"], + "angularCompilerOptions": { + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } } diff --git a/examples/angular/large-form/tsconfig.json b/examples/angular/large-form/tsconfig.json index afd15727a8..dd46e28018 100644 --- a/examples/angular/large-form/tsconfig.json +++ b/examples/angular/large-form/tsconfig.json @@ -1,28 +1,19 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { - "compileOnSave": false, + "extends": "../../../tsconfig.json", "compilerOptions": { - "outDir": "./dist/out-tsc", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "esModuleInterop": true, - "sourceMap": true, "declaration": false, + "emitDecoratorMetadata": true, "experimentalDecorators": true, - "moduleResolution": "bundler", - "importHelpers": true, - "target": "ES2022", - "module": "ES2022", + "moduleResolution": "Bundler", + "noEmit": true, "useDefineForClassFields": false, - "lib": ["ES2022", "dom"] + "paths": { + "@tanstack/angular-form": ["../../../packages/angular-form/src"], + "@tanstack/form-core": ["../../../packages/form-core/src"], + "@tanstack/form-core/internals": [ + "../../../packages/form-core/src/internals.ts" + ] + } }, - "angularCompilerOptions": { - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } + "include": ["src", "vite.config.ts"] } diff --git a/examples/angular/large-form/tsconfig.spec.json b/examples/angular/large-form/tsconfig.spec.json deleted file mode 100644 index 47e3dd7551..0000000000 --- a/examples/angular/large-form/tsconfig.spec.json +++ /dev/null @@ -1,9 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/spec", - "types": ["jasmine"] - }, - "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] -} diff --git a/examples/angular/large-form/vite.config.ts b/examples/angular/large-form/vite.config.ts new file mode 100644 index 0000000000..3484e49747 --- /dev/null +++ b/examples/angular/large-form/vite.config.ts @@ -0,0 +1,7 @@ +import angular from '@analogjs/vite-plugin-angular' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [angular({ tsconfig: 'tsconfig.app.json' })], + resolve: { tsconfigPaths: true }, +}) diff --git a/examples/angular/multi-step-wizard/.editorconfig b/examples/angular/multi-step-wizard/.editorconfig deleted file mode 100644 index 59d9a3a3e7..0000000000 --- a/examples/angular/multi-step-wizard/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -# Editor configuration, see https://editorconfig.org -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.ts] -quote_type = single - -[*.md] -max_line_length = off -trim_trailing_whitespace = false diff --git a/examples/angular/multi-step-wizard/.gitignore b/examples/angular/multi-step-wizard/.gitignore deleted file mode 100644 index 0711527ef9..0000000000 --- a/examples/angular/multi-step-wizard/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. - -# Compiled output -/dist -/tmp -/out-tsc -/bazel-out - -# Node -/node_modules -npm-debug.log -yarn-error.log - -# IDEs and editors -.idea/ -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# Visual Studio Code -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -.history/* - -# Miscellaneous -/.angular/cache -.sass-cache/ -/connect.lock -/coverage -/libpeerconnection.log -testem.log -/typings - -# System files -.DS_Store -Thumbs.db diff --git a/examples/angular/multi-step-wizard/README.md b/examples/angular/multi-step-wizard/README.md index 3e87f4c6d2..ef72910e21 100644 --- a/examples/angular/multi-step-wizard/README.md +++ b/examples/angular/multi-step-wizard/README.md @@ -1,27 +1,25 @@ -# Simple +# Example -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.0.1. +To run this example: -## Development server +- `pnpm install` +- `pnpm dev` + *** Add File: /Users/crutchcorn/git/tanstack/form/examples/angular/multi-step-wizard/.gitignore -Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. +# Logs -## Code scaffolding +logs +_.log +pnpm-debug.log_ -Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. +node_modules +dist +out-tsc +*.local -## Build +# Editor files -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. - -## Running unit tests - -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). - -## Running end-to-end tests - -Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. - -## Further help - -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store diff --git a/examples/angular/multi-step-wizard/angular.json b/examples/angular/multi-step-wizard/angular.json deleted file mode 100644 index 0cc433f7f4..0000000000 --- a/examples/angular/multi-step-wizard/angular.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "simple": { - "projectType": "application", - "schematics": {}, - "root": "", - "sourceRoot": "src", - "prefix": "app", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:application", - "options": { - "outputPath": "dist/simple", - "index": "src/index.html", - "browser": "src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "tsconfig.app.json", - "assets": ["src/favicon.ico", "src/assets"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "simple:build:production" - }, - "development": { - "buildTarget": "simple:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "simple:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "polyfills": ["zone.js", "zone.js/testing"], - "tsConfig": "tsconfig.spec.json", - "assets": ["src/favicon.ico", "src/assets"], - "scripts": [] - } - } - } - } - } -} diff --git a/examples/angular/multi-step-wizard/index.html b/examples/angular/multi-step-wizard/index.html new file mode 100644 index 0000000000..7518967e04 --- /dev/null +++ b/examples/angular/multi-step-wizard/index.html @@ -0,0 +1,12 @@ + + + + + + Multi-step Wizard + + + + + + diff --git a/examples/angular/multi-step-wizard/package.json b/examples/angular/multi-step-wizard/package.json index dca6fde4fa..62c582cd35 100644 --- a/examples/angular/multi-step-wizard/package.json +++ b/examples/angular/multi-step-wizard/package.json @@ -3,31 +3,24 @@ "private": true, "type": "module", "scripts": { - "ng": "ng", - "start": "ng cache clean && ng serve", - "build": "ng build", - "watch": "ng build --watch --configuration development", - "test": "ng test" + "dev": "vite --port=3507", + "build": "vite build", + "preview": "vite preview", + "test:types": "ngc -p tsconfig.app.json --noEmit" }, "dependencies": { - "@angular/animations": "^21.2.14", - "@angular/common": "^21.2.14", - "@angular/compiler": "^21.2.14", - "@angular/core": "^21.2.14", - "@angular/forms": "^21.2.14", - "@angular/platform-browser": "^21.2.14", - "@angular/platform-browser-dynamic": "^21.2.14", - "@angular/router": "^21.2.14", - "@tanstack/angular-form": "^1.33.3", + "@angular/common": "^22.1.1", + "@angular/compiler": "^22.1.1", + "@angular/core": "^22.1.1", + "@angular/platform-browser": "^22.1.1", + "@tanstack/angular-form": "^2.0.0-alpha.3", "rxjs": "^7.8.2", - "tslib": "^2.8.1", - "zod": "^3.25.76", - "zone.js": "0.15.1" + "zod": "^4.4.3" }, "devDependencies": { - "@angular-devkit/build-angular": "^21.2.12", - "@angular/cli": "^21.2.12", - "@angular/compiler-cli": "^21.2.14", - "typescript": "5.9.3" + "@analogjs/vite-plugin-angular": "^2.7.2", + "@angular/compiler-cli": "^22.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/angular/multi-step-wizard/src/app.component.ts b/examples/angular/multi-step-wizard/src/app.component.ts new file mode 100644 index 0000000000..82fd4843cb --- /dev/null +++ b/examples/angular/multi-step-wizard/src/app.component.ts @@ -0,0 +1,28 @@ +import { ChangeDetectionStrategy, Component, signal } from '@angular/core' +import { injectForm } from '@tanstack/angular-form' +import { StepOneComponent } from './step-one.component' +import { StepTwoComponent } from './step-two.component' +import { wizardFormOptions } from './shared-form' + +@Component({ + selector: 'app-root', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [StepOneComponent, StepTwoComponent], + template: ` +
    +

    Multi-step Wizard

    + @if (step() === 0) { + + } @else { + + } +
    + `, +}) +export class AppComponent { + step = signal(0) + form = injectForm(wizardFormOptions) + advance = () => this.step.set(1) + back = () => this.step.set(0) +} diff --git a/examples/angular/multi-step-wizard/src/app/app.component.ts b/examples/angular/multi-step-wizard/src/app/app.component.ts deleted file mode 100644 index 5426f05297..0000000000 --- a/examples/angular/multi-step-wizard/src/app/app.component.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Component, signal } from '@angular/core' -import { - TanStackWithForm, - injectForm, - injectStore, - revalidateLogic, -} from '@tanstack/angular-form' -import { z } from 'zod' -import { Step1Component } from './step1.component' -import { Step2Component } from './step2.component' -import { step1Schema, step2Schema, wizardFormOpts } from './shared-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackWithForm, Step1Component, Step2Component], - template: ` - @if (step() === 0) { - - } - @if (step() === 1) { - - } - `, -}) -export class AppComponent { - step = signal(0) - - form = injectForm({ - ...wizardFormOpts, - validationLogic: revalidateLogic(), - // onDynamic is only used when `form.handleSubmit` is called itself. - // When the FormGroup's `handleSubmit` is called, it will only validate the - // current step's schema. This means that this schema will not be called - // when the user submits the form group, but instead when they submit the - // entire form. - validators: { - onDynamic: z.object({ - step1: step1Schema, - step2: step2Schema, - }), - }, - onSubmit: ({ value }) => { - alert(`Form submitted: ${JSON.stringify(value)}`) - }, - }) - - isSubmitting = injectStore(this.form, (state) => state.isSubmitting) -} diff --git a/examples/angular/multi-step-wizard/src/app/shared-form.ts b/examples/angular/multi-step-wizard/src/app/shared-form.ts deleted file mode 100644 index 06440fc552..0000000000 --- a/examples/angular/multi-step-wizard/src/app/shared-form.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { formOptions } from '@tanstack/angular-form' -import { z } from 'zod' - -export const step1Schema = z.object({ - name: z.string().min(2, 'Name must be at least 2 characters'), -}) - -export const step2Schema = z.object({ - name: z.string().min(3, 'Name must be at least 3 characters'), -}) - -export const wizardFormOpts = formOptions({ - defaultValues: { - step1: { - name: '', - }, - step2: { - name: '', - }, - }, -}) diff --git a/examples/angular/multi-step-wizard/src/app/step1.component.ts b/examples/angular/multi-step-wizard/src/app/step1.component.ts deleted file mode 100644 index 7a5d4d3e5e..0000000000 --- a/examples/angular/multi-step-wizard/src/app/step1.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Component, input, output } from '@angular/core' -import { - TanStackAppField, - TanStackField, - TanStackFormGroup, - injectWithForm, -} from '@tanstack/angular-form' -import { TextFieldComponent } from './text-field.component' -import { step1Schema, wizardFormOpts } from './shared-form' - -@Component({ - selector: 'app-step1', - standalone: true, - imports: [ - TanStackField, - TanStackAppField, - TanStackFormGroup, - TextFieldComponent, - ], - template: ` - -
    - - - - - -
    {{ stringify(group.api.state.meta.errorMap) }}
    - -
    - `, -}) -export class Step1Component { - withForm = injectWithForm({ ...wizardFormOpts }) - step = input.required() - isSubmitting = input.required() - stepChange = output() - - step1Schema = step1Schema - stringify = (value: unknown) => JSON.stringify(value, null, 2) - - onGroupSubmit = () => { - this.stepChange.emit(this.step() + 1) - } - - onGroupSubmitInvalid = () => { - // Just like a form, you can also handle invalid submits at the group level, - // which is useful for multi-step wizards to prevent going to the next step - // if the current step is invalid - } -} diff --git a/examples/angular/multi-step-wizard/src/app/step2.component.ts b/examples/angular/multi-step-wizard/src/app/step2.component.ts deleted file mode 100644 index 4e648966e7..0000000000 --- a/examples/angular/multi-step-wizard/src/app/step2.component.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Component, input, output } from '@angular/core' -import { - TanStackAppField, - TanStackField, - TanStackFormGroup, - injectWithForm, -} from '@tanstack/angular-form' -import { TextFieldComponent } from './text-field.component' -import { step2Schema, wizardFormOpts } from './shared-form' - -@Component({ - selector: 'app-step2', - standalone: true, - imports: [ - TanStackField, - TanStackAppField, - TanStackFormGroup, - TextFieldComponent, - ], - template: ` - -
    - - - - - -
    - `, -}) -export class Step2Component { - withForm = injectWithForm({ ...wizardFormOpts }) - step = input.required() - isSubmitting = input.required() - stepChange = output() - - step2Schema = step2Schema - - onGroupSubmit = () => { - this.withForm.form.handleSubmit() - } -} diff --git a/examples/angular/multi-step-wizard/src/app/text-field.component.ts b/examples/angular/multi-step-wizard/src/app/text-field.component.ts deleted file mode 100644 index 5dada6468c..0000000000 --- a/examples/angular/multi-step-wizard/src/app/text-field.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Component, input } from '@angular/core' -import { injectField } from '@tanstack/angular-form' - -@Component({ - selector: 'app-text-field', - standalone: true, - template: ` -
    - - @for (error of field.api.state.meta.errors; track $index) { -
    - {{ error.message }} -
    - } -
    - `, -}) -export class TextFieldComponent { - label = input.required() - field = injectField() -} diff --git a/examples/angular/multi-step-wizard/src/favicon.ico b/examples/angular/multi-step-wizard/src/favicon.ico deleted file mode 100644 index 57614f9c96..0000000000 Binary files a/examples/angular/multi-step-wizard/src/favicon.ico and /dev/null differ diff --git a/examples/angular/multi-step-wizard/src/index.html b/examples/angular/multi-step-wizard/src/index.html deleted file mode 100644 index c3c6fbbdd5..0000000000 --- a/examples/angular/multi-step-wizard/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Simple - - - - - - - - diff --git a/examples/angular/multi-step-wizard/src/main.ts b/examples/angular/multi-step-wizard/src/main.ts index 56773910ea..bdac04402c 100644 --- a/examples/angular/multi-step-wizard/src/main.ts +++ b/examples/angular/multi-step-wizard/src/main.ts @@ -1,4 +1,8 @@ +import { provideZonelessChangeDetection } from '@angular/core' import { bootstrapApplication } from '@angular/platform-browser' -import { AppComponent } from './app/app.component' +import { AppComponent } from './app.component' +import './styles.css' -bootstrapApplication(AppComponent).catch((err) => console.error(err)) +bootstrapApplication(AppComponent, { + providers: [provideZonelessChangeDetection()], +}).catch((error) => console.error(error)) diff --git a/examples/angular/multi-step-wizard/src/shared-form.ts b/examples/angular/multi-step-wizard/src/shared-form.ts new file mode 100644 index 0000000000..8c57655ff3 --- /dev/null +++ b/examples/angular/multi-step-wizard/src/shared-form.ts @@ -0,0 +1,31 @@ +import { createValidator, formOptions } from '@tanstack/angular-form' +import { z } from 'zod' + +export const step1Schema = z.object({ + name: z.string().min(2, 'Name must be at least 2 characters'), +}) +export const step2Schema = z.object({ + name: z.string().min(3, 'Name must be at least 3 characters'), +}) + +export const stepValidator = createValidator({ + triggers: [ + { + trigger: 'change', + when: ({ groupApi, formApi }) => + (groupApi?.state.submissionAttempts ?? + formApi.state.submissionAttempts) > 0, + }, + ], +}) + +export const wizardFormOptions = formOptions({ + defaultValues: { step1: { name: '' }, step2: { name: '' } }, + validators: [ + { + run: z.object({ step1: step1Schema, step2: step2Schema }), + triggers: [], + }, + ], + onSubmit: ({ value }) => alert(`Form submitted: ${JSON.stringify(value)}`), +}) diff --git a/examples/angular/multi-step-wizard/src/step-one.component.ts b/examples/angular/multi-step-wizard/src/step-one.component.ts new file mode 100644 index 0000000000..74c3fdb4f9 --- /dev/null +++ b/examples/angular/multi-step-wizard/src/step-one.component.ts @@ -0,0 +1,56 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { + TanStackAppField, + TanStackField, + TanStackFormGroup, +} from '@tanstack/angular-form' +import { step1Schema, stepValidator } from './shared-form' +import { TextFieldComponent } from './text-field.component' +import type { AngularFormType } from '@tanstack/angular-form' +import type { wizardFormOptions } from './shared-form' + +@Component({ + selector: 'app-step-one', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + TanStackAppField, + TanStackField, + TanStackFormGroup, + TextFieldComponent, + ], + template: ` + +
    +

    Step 1

    + + + +
    + `, +}) +export class StepOneComponent { + form = input.required>() + advance = input.required<() => void>() + validators = [stepValidator(step1Schema)] + onSubmit = () => this.advance()() + + submit(event: SubmitEvent, group: { handleSubmit: () => unknown }) { + event.preventDefault() + event.stopPropagation() + group.handleSubmit() + } +} diff --git a/examples/angular/multi-step-wizard/src/step-two.component.ts b/examples/angular/multi-step-wizard/src/step-two.component.ts new file mode 100644 index 0000000000..a69dc85a10 --- /dev/null +++ b/examples/angular/multi-step-wizard/src/step-two.component.ts @@ -0,0 +1,61 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { + TanStackAppField, + TanStackField, + TanStackFormGroup, +} from '@tanstack/angular-form' +import { step2Schema, stepValidator } from './shared-form' +import { TextFieldComponent } from './text-field.component' +import type { AngularFormType } from '@tanstack/angular-form' +import type { wizardFormOptions } from './shared-form' + +@Component({ + selector: 'app-step-two', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + TanStackAppField, + TanStackField, + TanStackFormGroup, + TextFieldComponent, + ], + template: ` + +
    +

    Step 2

    + +
    + + +
    + +
    + `, +}) +export class StepTwoComponent { + form = input.required>() + back = input.required<() => void>() + validators = [stepValidator(step2Schema)] + onSubmit = () => { + void this.form().handleSubmit() + } + + submit(event: SubmitEvent, group: { handleSubmit: () => unknown }) { + event.preventDefault() + event.stopPropagation() + group.handleSubmit() + } +} diff --git a/examples/angular/multi-step-wizard/src/styles.css b/examples/angular/multi-step-wizard/src/styles.css new file mode 100644 index 0000000000..0bc5c5439f --- /dev/null +++ b/examples/angular/multi-step-wizard/src/styles.css @@ -0,0 +1,48 @@ +:root { + color: #213547; + background: #f7f7f8; + font-family: Inter, system-ui, sans-serif; +} +body { + margin: 0; +} +main { + max-width: 48rem; + margin: 0 auto; + padding: 2rem; +} +form, +section, +fieldset { + display: grid; + gap: 1rem; +} +label { + display: grid; + gap: 0.35rem; +} +input, +button, +select { + font: inherit; + padding: 0.55rem 0.7rem; +} +button { + width: fit-content; + cursor: pointer; +} +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} +small[role='alert'], +.error { + color: #b42318; +} +.validating { + opacity: 0.7; +} +fieldset { + margin: 0; +} diff --git a/examples/angular/multi-step-wizard/src/text-field.component.ts b/examples/angular/multi-step-wizard/src/text-field.component.ts new file mode 100644 index 0000000000..9e4ad00afd --- /dev/null +++ b/examples/angular/multi-step-wizard/src/text-field.component.ts @@ -0,0 +1,27 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { injectField } from '@tanstack/angular-form' + +@Component({ + selector: 'app-text-field', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + `, +}) +export class TextFieldComponent { + label = input.required() + field = injectField() +} diff --git a/examples/angular/multi-step-wizard/src/vite-env.d.ts b/examples/angular/multi-step-wizard/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/angular/multi-step-wizard/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/angular/multi-step-wizard/tsconfig.app.json b/examples/angular/multi-step-wizard/tsconfig.app.json index 84f1f992d2..e68f13b4a2 100644 --- a/examples/angular/multi-step-wizard/tsconfig.app.json +++ b/examples/angular/multi-step-wizard/tsconfig.app.json @@ -1,10 +1,16 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "./tsconfig.json", "compilerOptions": { + "noEmit": false, "outDir": "./out-tsc/app", + "rootDir": "../../..", "types": [] }, "files": ["src/main.ts"], - "include": ["src/**/*.d.ts"] + "include": ["src/**/*.d.ts"], + "angularCompilerOptions": { + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } } diff --git a/examples/angular/multi-step-wizard/tsconfig.json b/examples/angular/multi-step-wizard/tsconfig.json index afd15727a8..dd46e28018 100644 --- a/examples/angular/multi-step-wizard/tsconfig.json +++ b/examples/angular/multi-step-wizard/tsconfig.json @@ -1,28 +1,19 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { - "compileOnSave": false, + "extends": "../../../tsconfig.json", "compilerOptions": { - "outDir": "./dist/out-tsc", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "esModuleInterop": true, - "sourceMap": true, "declaration": false, + "emitDecoratorMetadata": true, "experimentalDecorators": true, - "moduleResolution": "bundler", - "importHelpers": true, - "target": "ES2022", - "module": "ES2022", + "moduleResolution": "Bundler", + "noEmit": true, "useDefineForClassFields": false, - "lib": ["ES2022", "dom"] + "paths": { + "@tanstack/angular-form": ["../../../packages/angular-form/src"], + "@tanstack/form-core": ["../../../packages/form-core/src"], + "@tanstack/form-core/internals": [ + "../../../packages/form-core/src/internals.ts" + ] + } }, - "angularCompilerOptions": { - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } + "include": ["src", "vite.config.ts"] } diff --git a/examples/angular/multi-step-wizard/tsconfig.spec.json b/examples/angular/multi-step-wizard/tsconfig.spec.json deleted file mode 100644 index 47e3dd7551..0000000000 --- a/examples/angular/multi-step-wizard/tsconfig.spec.json +++ /dev/null @@ -1,9 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/spec", - "types": ["jasmine"] - }, - "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] -} diff --git a/examples/angular/multi-step-wizard/vite.config.ts b/examples/angular/multi-step-wizard/vite.config.ts new file mode 100644 index 0000000000..3484e49747 --- /dev/null +++ b/examples/angular/multi-step-wizard/vite.config.ts @@ -0,0 +1,7 @@ +import angular from '@analogjs/vite-plugin-angular' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [angular({ tsconfig: 'tsconfig.app.json' })], + resolve: { tsconfigPaths: true }, +}) diff --git a/examples/angular/query-integration/README.md b/examples/angular/query-integration/README.md new file mode 100644 index 0000000000..4a442e6b13 --- /dev/null +++ b/examples/angular/query-integration/README.md @@ -0,0 +1,25 @@ +# Example + +To run this example: + +- `pnpm install` +- `pnpm dev` + *** Add File: /Users/crutchcorn/git/tanstack/form/examples/angular/query-integration/.gitignore + +# Logs + +logs +_.log +pnpm-debug.log_ + +node_modules +dist +out-tsc +*.local + +# Editor files + +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store diff --git a/examples/angular/query-integration/index.html b/examples/angular/query-integration/index.html new file mode 100644 index 0000000000..9d7363d375 --- /dev/null +++ b/examples/angular/query-integration/index.html @@ -0,0 +1,12 @@ + + + + + + Query Integration + + + + + + diff --git a/examples/angular/query-integration/package.json b/examples/angular/query-integration/package.json new file mode 100644 index 0000000000..72f1815724 --- /dev/null +++ b/examples/angular/query-integration/package.json @@ -0,0 +1,26 @@ +{ + "name": "@tanstack/form-example-angular-query-integration", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3508", + "build": "vite build", + "preview": "vite preview", + "test:types": "ngc -p tsconfig.app.json --noEmit" + }, + "dependencies": { + "@angular/common": "^22.1.1", + "@angular/compiler": "^22.1.1", + "@angular/core": "^22.1.1", + "@angular/platform-browser": "^22.1.1", + "@tanstack/angular-form": "^2.0.0-alpha.3", + "@tanstack/angular-query-experimental": "^5.101.4", + "rxjs": "^7.8.2" + }, + "devDependencies": { + "@analogjs/vite-plugin-angular": "^2.7.2", + "@angular/compiler-cli": "^22.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/angular/query-integration/src/app.component.ts b/examples/angular/query-integration/src/app.component.ts new file mode 100644 index 0000000000..36bcb2545d --- /dev/null +++ b/examples/angular/query-integration/src/app.component.ts @@ -0,0 +1,138 @@ +import { + ChangeDetectionStrategy, + Component, + effect, + inject, +} from '@angular/core' +import { + QueryClient, + injectMutation, + injectQuery, +} from '@tanstack/angular-query-experimental' +import { + TanStackField, + injectForm, + injectSelector, +} from '@tanstack/angular-form' +import { db, sleep } from './mock-db' +import type { StoredUser } from './mock-db' + +const emptyUser: StoredUser = { firstName: '', lastName: '' } + +@Component({ + selector: 'app-root', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TanStackField], + template: ` +
    + @if (userQuery.isPending()) { +

    Loading...

    + } @else if (userQuery.isError()) { +

    {{ userQuery.error().message }}

    + } @else { +

    Query Integration Form Example

    +
    + + + + + + +
    + + +
    +
    + } +
    + `, +}) +export class AppComponent { + private queryClient = inject(QueryClient) + userQuery = injectQuery(() => ({ + queryKey: ['user'], + queryFn: () => db.getData(), + })) + saveUser = injectMutation(() => ({ + mutationFn: (value: StoredUser) => db.saveUser(value), + onSuccess: () => this.queryClient.invalidateQueries({ queryKey: ['user'] }), + })) + + firstNameValidators = [ + { + run: ({ value }: { value: string }) => + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + triggers: ['change'] as const, + }, + { + run: async ({ value }: { value: string }) => { + await sleep(1000) + return value.includes('error') + ? 'No "error" allowed in first name' + : undefined + }, + triggers: ['change'] as const, + triggerDebounceMs: 500, + }, + ] + + form = injectForm({ + defaultValues: emptyUser, + errorVisibility: ({ fieldState }) => fieldState.meta.isTouched, + onSubmit: async ({ formApi, value }) => { + await this.saveUser.mutateAsync(value) + formApi.reset(value) + }, + }) + canSubmit = injectSelector(this.form, (state) => state.canSubmit) + isSubmitting = injectSelector(this.form, (state) => state.isSubmitting) + + constructor() { + effect(() => { + const user = this.userQuery.data() + if (user && !this.form.state.isTouched) this.form.reset(user) + }) + } + + handleSubmit(event: SubmitEvent) { + event.preventDefault() + event.stopPropagation() + this.form.handleSubmit() + } +} diff --git a/examples/angular/query-integration/src/main.ts b/examples/angular/query-integration/src/main.ts new file mode 100644 index 0000000000..04ea684ffc --- /dev/null +++ b/examples/angular/query-integration/src/main.ts @@ -0,0 +1,15 @@ +import { provideZonelessChangeDetection } from '@angular/core' +import { bootstrapApplication } from '@angular/platform-browser' +import { + QueryClient, + provideTanStackQuery, +} from '@tanstack/angular-query-experimental' +import { AppComponent } from './app.component' +import './styles.css' + +bootstrapApplication(AppComponent, { + providers: [ + provideZonelessChangeDetection(), + provideTanStackQuery(new QueryClient()), + ], +}).catch((error) => console.error(error)) diff --git a/examples/angular/query-integration/src/mock-db.ts b/examples/angular/query-integration/src/mock-db.ts new file mode 100644 index 0000000000..44de0c9a18 --- /dev/null +++ b/examples/angular/query-integration/src/mock-db.ts @@ -0,0 +1,28 @@ +export function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)) +} + +export interface StoredUser { + firstName: string + lastName: string +} + +class DB { + private data: StoredUser = { + firstName: 'FirstName', + lastName: 'LastName', + } + + async getData(): Promise { + await sleep(1000) + return { ...this.data } + } + + async saveUser(value: StoredUser): Promise { + await sleep(1000) + this.data = value + return value + } +} + +export const db = new DB() diff --git a/examples/angular/query-integration/src/styles.css b/examples/angular/query-integration/src/styles.css new file mode 100644 index 0000000000..0bc5c5439f --- /dev/null +++ b/examples/angular/query-integration/src/styles.css @@ -0,0 +1,48 @@ +:root { + color: #213547; + background: #f7f7f8; + font-family: Inter, system-ui, sans-serif; +} +body { + margin: 0; +} +main { + max-width: 48rem; + margin: 0 auto; + padding: 2rem; +} +form, +section, +fieldset { + display: grid; + gap: 1rem; +} +label { + display: grid; + gap: 0.35rem; +} +input, +button, +select { + font: inherit; + padding: 0.55rem 0.7rem; +} +button { + width: fit-content; + cursor: pointer; +} +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} +small[role='alert'], +.error { + color: #b42318; +} +.validating { + opacity: 0.7; +} +fieldset { + margin: 0; +} diff --git a/examples/angular/query-integration/src/vite-env.d.ts b/examples/angular/query-integration/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/angular/query-integration/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/angular/query-integration/tsconfig.app.json b/examples/angular/query-integration/tsconfig.app.json new file mode 100644 index 0000000000..e68f13b4a2 --- /dev/null +++ b/examples/angular/query-integration/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "outDir": "./out-tsc/app", + "rootDir": "../../..", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "angularCompilerOptions": { + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/examples/angular/query-integration/tsconfig.json b/examples/angular/query-integration/tsconfig.json new file mode 100644 index 0000000000..dd46e28018 --- /dev/null +++ b/examples/angular/query-integration/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "declaration": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "moduleResolution": "Bundler", + "noEmit": true, + "useDefineForClassFields": false, + "paths": { + "@tanstack/angular-form": ["../../../packages/angular-form/src"], + "@tanstack/form-core": ["../../../packages/form-core/src"], + "@tanstack/form-core/internals": [ + "../../../packages/form-core/src/internals.ts" + ] + } + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/angular/query-integration/vite.config.ts b/examples/angular/query-integration/vite.config.ts new file mode 100644 index 0000000000..3484e49747 --- /dev/null +++ b/examples/angular/query-integration/vite.config.ts @@ -0,0 +1,7 @@ +import angular from '@analogjs/vite-plugin-angular' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [angular({ tsconfig: 'tsconfig.app.json' })], + resolve: { tsconfigPaths: true }, +}) diff --git a/examples/angular/simple/.editorconfig b/examples/angular/simple/.editorconfig deleted file mode 100644 index 59d9a3a3e7..0000000000 --- a/examples/angular/simple/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -# Editor configuration, see https://editorconfig.org -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.ts] -quote_type = single - -[*.md] -max_line_length = off -trim_trailing_whitespace = false diff --git a/examples/angular/simple/.gitignore b/examples/angular/simple/.gitignore deleted file mode 100644 index 0711527ef9..0000000000 --- a/examples/angular/simple/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. - -# Compiled output -/dist -/tmp -/out-tsc -/bazel-out - -# Node -/node_modules -npm-debug.log -yarn-error.log - -# IDEs and editors -.idea/ -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# Visual Studio Code -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -.history/* - -# Miscellaneous -/.angular/cache -.sass-cache/ -/connect.lock -/coverage -/libpeerconnection.log -testem.log -/typings - -# System files -.DS_Store -Thumbs.db diff --git a/examples/angular/simple/README.md b/examples/angular/simple/README.md index 3e87f4c6d2..df2f2155ef 100644 --- a/examples/angular/simple/README.md +++ b/examples/angular/simple/README.md @@ -1,27 +1,25 @@ -# Simple +# Example -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.0.1. +To run this example: -## Development server +- `pnpm install` +- `pnpm dev` + *** Add File: /Users/crutchcorn/git/tanstack/form/examples/angular/simple/.gitignore -Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. +# Logs -## Code scaffolding +logs +_.log +pnpm-debug.log_ -Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. +node_modules +dist +out-tsc +*.local -## Build +# Editor files -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. - -## Running unit tests - -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). - -## Running end-to-end tests - -Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. - -## Further help - -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store diff --git a/examples/angular/simple/angular.json b/examples/angular/simple/angular.json deleted file mode 100644 index 0cc433f7f4..0000000000 --- a/examples/angular/simple/angular.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "simple": { - "projectType": "application", - "schematics": {}, - "root": "", - "sourceRoot": "src", - "prefix": "app", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:application", - "options": { - "outputPath": "dist/simple", - "index": "src/index.html", - "browser": "src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "tsconfig.app.json", - "assets": ["src/favicon.ico", "src/assets"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "simple:build:production" - }, - "development": { - "buildTarget": "simple:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "simple:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "polyfills": ["zone.js", "zone.js/testing"], - "tsConfig": "tsconfig.spec.json", - "assets": ["src/favicon.ico", "src/assets"], - "scripts": [] - } - } - } - } - } -} diff --git a/examples/angular/simple/index.html b/examples/angular/simple/index.html new file mode 100644 index 0000000000..13f21496b6 --- /dev/null +++ b/examples/angular/simple/index.html @@ -0,0 +1,12 @@ + + + + + + Simple Form + + + + + + diff --git a/examples/angular/simple/package.json b/examples/angular/simple/package.json index cb9f692d48..fcf5c1ab5e 100644 --- a/examples/angular/simple/package.json +++ b/examples/angular/simple/package.json @@ -3,30 +3,23 @@ "private": true, "type": "module", "scripts": { - "ng": "ng", - "start": "ng cache clean && ng serve", - "build": "ng build", - "watch": "ng build --watch --configuration development", - "test": "ng test" + "dev": "vite --port=3501", + "build": "vite build", + "preview": "vite preview", + "test:types": "ngc -p tsconfig.app.json --noEmit" }, "dependencies": { - "@angular/animations": "^21.2.14", - "@angular/common": "^21.2.14", - "@angular/compiler": "^21.2.14", - "@angular/core": "^21.2.14", - "@angular/forms": "^21.2.14", - "@angular/platform-browser": "^21.2.14", - "@angular/platform-browser-dynamic": "^21.2.14", - "@angular/router": "^21.2.14", - "@tanstack/angular-form": "^1.33.3", - "rxjs": "^7.8.2", - "tslib": "^2.8.1", - "zone.js": "0.15.1" + "@angular/common": "^22.1.1", + "@angular/compiler": "^22.1.1", + "@angular/core": "^22.1.1", + "@angular/platform-browser": "^22.1.1", + "@tanstack/angular-form": "^2.0.0-alpha.3", + "rxjs": "^7.8.2" }, "devDependencies": { - "@angular-devkit/build-angular": "^21.2.12", - "@angular/cli": "^21.2.12", - "@angular/compiler-cli": "^21.2.14", - "typescript": "5.9.3" + "@analogjs/vite-plugin-angular": "^2.7.2", + "@angular/compiler-cli": "^22.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/angular/simple/src/app.component.ts b/examples/angular/simple/src/app.component.ts new file mode 100644 index 0000000000..b91a612e38 --- /dev/null +++ b/examples/angular/simple/src/app.component.ts @@ -0,0 +1,97 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { + TanStackField, + injectForm, + injectSelector, +} from '@tanstack/angular-form' + +@Component({ + selector: 'app-root', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TanStackField], + template: ` +
    +

    Simple Form Example

    +
    + + + + + + + + +
    + + +
    +
    +
    + `, +}) +export class AppComponent { + firstNameValidators = [ + { + run: ({ value }: { value: string }) => + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + triggers: ['change'] as const, + }, + { + run: async ({ value }: { value: string }) => { + await new Promise((resolve) => setTimeout(resolve, 1000)) + return value.includes('error') + ? 'No "error" allowed in first name' + : undefined + }, + triggers: ['change'] as const, + triggerDebounceMs: 500, + }, + ] + + form = injectForm({ + defaultValues: { firstName: '', lastName: '' }, + onSubmit: async ({ value }) => console.log(value), + }) + canSubmit = injectSelector(this.form, (state) => state.canSubmit) + isSubmitting = injectSelector(this.form, (state) => state.isSubmitting) + + handleSubmit(event: SubmitEvent) { + event.preventDefault() + event.stopPropagation() + this.form.handleSubmit() + } +} diff --git a/examples/angular/simple/src/app/app.component.ts b/examples/angular/simple/src/app/app.component.ts deleted file mode 100644 index ce3706f646..0000000000 --- a/examples/angular/simple/src/app/app.component.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Component } from '@angular/core' -import { TanStackField, injectForm, injectStore } from '@tanstack/angular-form' -import type { - FieldValidateAsyncFn, - FieldValidateFn, -} from '@tanstack/angular-form' - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` -
    -
    - - - - @if (firstName.api.state.meta.isTouched) { - @for (error of firstName.api.state.meta.errors; track $index) { -
    - {{ error }} -
    - } - } - @if (firstName.api.state.meta.isValidating) { -

    Validating...

    - } -
    -
    -
    - - - - -
    - - -
    - `, -}) -export class AppComponent { - firstNameValidator: FieldValidateFn = ({ value }) => - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined - - firstNameAsyncValidator: FieldValidateAsyncFn = async ({ - value, - }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return value.includes('error') && 'No "error" allowed in first name' - } - - form = injectForm({ - defaultValues: { - firstName: '', - lastName: '', - }, - onSubmit({ value }) { - // Do something with form data - console.log(value) - }, - }) - - canSubmit = injectStore(this.form, (state) => state.canSubmit) - isSubmitting = injectStore(this.form, (state) => state.isSubmitting) - - handleSubmit(event: SubmitEvent) { - event.preventDefault() - event.stopPropagation() - this.form.handleSubmit() - } -} diff --git a/examples/angular/simple/src/favicon.ico b/examples/angular/simple/src/favicon.ico deleted file mode 100644 index 57614f9c96..0000000000 Binary files a/examples/angular/simple/src/favicon.ico and /dev/null differ diff --git a/examples/angular/simple/src/index.html b/examples/angular/simple/src/index.html deleted file mode 100644 index c3c6fbbdd5..0000000000 --- a/examples/angular/simple/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Simple - - - - - - - - diff --git a/examples/angular/simple/src/main.ts b/examples/angular/simple/src/main.ts index 56773910ea..bdac04402c 100644 --- a/examples/angular/simple/src/main.ts +++ b/examples/angular/simple/src/main.ts @@ -1,4 +1,8 @@ +import { provideZonelessChangeDetection } from '@angular/core' import { bootstrapApplication } from '@angular/platform-browser' -import { AppComponent } from './app/app.component' +import { AppComponent } from './app.component' +import './styles.css' -bootstrapApplication(AppComponent).catch((err) => console.error(err)) +bootstrapApplication(AppComponent, { + providers: [provideZonelessChangeDetection()], +}).catch((error) => console.error(error)) diff --git a/examples/angular/simple/src/styles.css b/examples/angular/simple/src/styles.css new file mode 100644 index 0000000000..0bc5c5439f --- /dev/null +++ b/examples/angular/simple/src/styles.css @@ -0,0 +1,48 @@ +:root { + color: #213547; + background: #f7f7f8; + font-family: Inter, system-ui, sans-serif; +} +body { + margin: 0; +} +main { + max-width: 48rem; + margin: 0 auto; + padding: 2rem; +} +form, +section, +fieldset { + display: grid; + gap: 1rem; +} +label { + display: grid; + gap: 0.35rem; +} +input, +button, +select { + font: inherit; + padding: 0.55rem 0.7rem; +} +button { + width: fit-content; + cursor: pointer; +} +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} +small[role='alert'], +.error { + color: #b42318; +} +.validating { + opacity: 0.7; +} +fieldset { + margin: 0; +} diff --git a/examples/angular/simple/src/vite-env.d.ts b/examples/angular/simple/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/angular/simple/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/angular/simple/tsconfig.app.json b/examples/angular/simple/tsconfig.app.json index 84f1f992d2..e68f13b4a2 100644 --- a/examples/angular/simple/tsconfig.app.json +++ b/examples/angular/simple/tsconfig.app.json @@ -1,10 +1,16 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "./tsconfig.json", "compilerOptions": { + "noEmit": false, "outDir": "./out-tsc/app", + "rootDir": "../../..", "types": [] }, "files": ["src/main.ts"], - "include": ["src/**/*.d.ts"] + "include": ["src/**/*.d.ts"], + "angularCompilerOptions": { + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } } diff --git a/examples/angular/simple/tsconfig.json b/examples/angular/simple/tsconfig.json index afd15727a8..dd46e28018 100644 --- a/examples/angular/simple/tsconfig.json +++ b/examples/angular/simple/tsconfig.json @@ -1,28 +1,19 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { - "compileOnSave": false, + "extends": "../../../tsconfig.json", "compilerOptions": { - "outDir": "./dist/out-tsc", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "esModuleInterop": true, - "sourceMap": true, "declaration": false, + "emitDecoratorMetadata": true, "experimentalDecorators": true, - "moduleResolution": "bundler", - "importHelpers": true, - "target": "ES2022", - "module": "ES2022", + "moduleResolution": "Bundler", + "noEmit": true, "useDefineForClassFields": false, - "lib": ["ES2022", "dom"] + "paths": { + "@tanstack/angular-form": ["../../../packages/angular-form/src"], + "@tanstack/form-core": ["../../../packages/form-core/src"], + "@tanstack/form-core/internals": [ + "../../../packages/form-core/src/internals.ts" + ] + } }, - "angularCompilerOptions": { - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } + "include": ["src", "vite.config.ts"] } diff --git a/examples/angular/simple/tsconfig.spec.json b/examples/angular/simple/tsconfig.spec.json deleted file mode 100644 index 47e3dd7551..0000000000 --- a/examples/angular/simple/tsconfig.spec.json +++ /dev/null @@ -1,9 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/spec", - "types": ["jasmine"] - }, - "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] -} diff --git a/examples/angular/simple/vite.config.ts b/examples/angular/simple/vite.config.ts new file mode 100644 index 0000000000..3484e49747 --- /dev/null +++ b/examples/angular/simple/vite.config.ts @@ -0,0 +1,7 @@ +import angular from '@analogjs/vite-plugin-angular' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [angular({ tsconfig: 'tsconfig.app.json' })], + resolve: { tsconfigPaths: true }, +}) diff --git a/examples/angular/standard-schema/.editorconfig b/examples/angular/standard-schema/.editorconfig deleted file mode 100644 index 59d9a3a3e7..0000000000 --- a/examples/angular/standard-schema/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -# Editor configuration, see https://editorconfig.org -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.ts] -quote_type = single - -[*.md] -max_line_length = off -trim_trailing_whitespace = false diff --git a/examples/angular/standard-schema/.gitignore b/examples/angular/standard-schema/.gitignore deleted file mode 100644 index 0711527ef9..0000000000 --- a/examples/angular/standard-schema/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. - -# Compiled output -/dist -/tmp -/out-tsc -/bazel-out - -# Node -/node_modules -npm-debug.log -yarn-error.log - -# IDEs and editors -.idea/ -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# Visual Studio Code -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -.history/* - -# Miscellaneous -/.angular/cache -.sass-cache/ -/connect.lock -/coverage -/libpeerconnection.log -testem.log -/typings - -# System files -.DS_Store -Thumbs.db diff --git a/examples/angular/standard-schema/README.md b/examples/angular/standard-schema/README.md index 3e87f4c6d2..2c702762d7 100644 --- a/examples/angular/standard-schema/README.md +++ b/examples/angular/standard-schema/README.md @@ -1,27 +1,25 @@ -# Simple +# Example -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.0.1. +To run this example: -## Development server +- `pnpm install` +- `pnpm dev` + *** Add File: /Users/crutchcorn/git/tanstack/form/examples/angular/standard-schema/.gitignore -Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. +# Logs -## Code scaffolding +logs +_.log +pnpm-debug.log_ -Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. +node_modules +dist +out-tsc +*.local -## Build +# Editor files -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. - -## Running unit tests - -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). - -## Running end-to-end tests - -Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. - -## Further help - -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store diff --git a/examples/angular/standard-schema/angular.json b/examples/angular/standard-schema/angular.json deleted file mode 100644 index 0cc433f7f4..0000000000 --- a/examples/angular/standard-schema/angular.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "simple": { - "projectType": "application", - "schematics": {}, - "root": "", - "sourceRoot": "src", - "prefix": "app", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:application", - "options": { - "outputPath": "dist/simple", - "index": "src/index.html", - "browser": "src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "tsconfig.app.json", - "assets": ["src/favicon.ico", "src/assets"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "simple:build:production" - }, - "development": { - "buildTarget": "simple:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "simple:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "polyfills": ["zone.js", "zone.js/testing"], - "tsConfig": "tsconfig.spec.json", - "assets": ["src/favicon.ico", "src/assets"], - "scripts": [] - } - } - } - } - } -} diff --git a/examples/angular/standard-schema/index.html b/examples/angular/standard-schema/index.html new file mode 100644 index 0000000000..ea4fd12f04 --- /dev/null +++ b/examples/angular/standard-schema/index.html @@ -0,0 +1,12 @@ + + + + + + Standard Schema + + + + + + diff --git a/examples/angular/standard-schema/package.json b/examples/angular/standard-schema/package.json index 2da1965905..438b67eb21 100644 --- a/examples/angular/standard-schema/package.json +++ b/examples/angular/standard-schema/package.json @@ -3,33 +3,27 @@ "private": true, "type": "module", "scripts": { - "ng": "ng", - "start": "ng cache clean && ng serve", - "build": "ng build", - "watch": "ng build --watch --configuration development", - "test": "ng test" + "dev": "vite --port=3509", + "build": "vite build", + "preview": "vite preview", + "test:types": "ngc -p tsconfig.app.json --noEmit" }, "dependencies": { - "@angular/animations": "^21.2.14", - "@angular/common": "^21.2.14", - "@angular/compiler": "^21.2.14", - "@angular/core": "^21.2.14", - "@angular/forms": "^21.2.14", - "@angular/platform-browser": "^21.2.14", - "@angular/platform-browser-dynamic": "^21.2.14", - "@angular/router": "^21.2.14", - "@tanstack/angular-form": "^1.33.3", + "@angular/common": "^22.1.1", + "@angular/compiler": "^22.1.1", + "@angular/core": "^22.1.1", + "@angular/platform-browser": "^22.1.1", + "@tanstack/angular-form": "^2.0.0-alpha.3", + "arktype": "^2.1.22", "effect": "^3.17.14", "rxjs": "^7.8.2", - "tslib": "^2.8.1", "valibot": "^1.1.0", - "zod": "^3.25.76", - "zone.js": "0.15.1" + "zod": "^4.4.3" }, "devDependencies": { - "@angular-devkit/build-angular": "^21.2.12", - "@angular/cli": "^21.2.12", - "@angular/compiler-cli": "^21.2.14", - "typescript": "5.9.3" + "@analogjs/vite-plugin-angular": "^2.7.2", + "@angular/compiler-cli": "^22.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/angular/standard-schema/src/app.component.ts b/examples/angular/standard-schema/src/app.component.ts new file mode 100644 index 0000000000..048a6d4160 --- /dev/null +++ b/examples/angular/standard-schema/src/app.component.ts @@ -0,0 +1,102 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { + TanStackField, + injectForm, + injectSelector, +} from '@tanstack/angular-form' +import { type } from 'arktype' +import { Schema as S } from 'effect' +import * as v from 'valibot' +import { z } from 'zod' + +const ZodSchema = z.object({ + firstName: z + .string() + .min(3, '[Zod] You must have a length of at least 3') + .startsWith('A', "[Zod] First name must start with 'A'"), + lastName: z.string().min(3, '[Zod] You must have a length of at least 3'), +}) +const ValibotSchema = v.object({ + firstName: v.pipe(v.string(), v.minLength(3), v.startsWith('A')), + lastName: v.pipe(v.string(), v.minLength(3)), +}) +const ArkTypeSchema = type({ + firstName: 'string >= 3', + lastName: 'string >= 3', +}) +const EffectSchema = S.standardSchemaV1( + S.Struct({ + firstName: S.String.pipe(S.minLength(3)), + lastName: S.String.pipe(S.minLength(3)), + }), +) + +@Component({ + selector: 'app-root', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TanStackField], + template: ` +
    +

    Standard Schema Form Example

    +

    Swap the schema assigned to the validator in the component source.

    +
    + + + + + + + +
    +
    + `, +}) +export class AppComponent { + form = injectForm({ + defaultValues: { firstName: '', lastName: '' }, + validators: [{ run: ZodSchema, triggers: ['change'] }], + onSubmit: async ({ value }) => console.log(value), + }) + canSubmit = injectSelector(this.form, (state) => state.canSubmit) + isSubmitting = injectSelector(this.form, (state) => state.isSubmitting) + + handleSubmit(event: SubmitEvent) { + event.preventDefault() + event.stopPropagation() + this.form.handleSubmit() + } + + // Keep the alternative Standard Schema implementations type-checked. + alternativeSchemas = [ValibotSchema, ArkTypeSchema, EffectSchema] +} diff --git a/examples/angular/standard-schema/src/app/app.component.ts b/examples/angular/standard-schema/src/app/app.component.ts deleted file mode 100644 index 4083466660..0000000000 --- a/examples/angular/standard-schema/src/app/app.component.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { Component } from '@angular/core' -import { TanStackField, injectForm, injectStore } from '@tanstack/angular-form' -import * as v from 'valibot' -import { z } from 'zod' -import { Schema as S } from 'effect' - -const ZodSchema = z.object({ - firstName: z - .string() - .min(3, '[Zod] You must have a length of at least 3') - .startsWith('A', "[Zod] First name must start with 'A'"), - lastName: z.string().min(3, '[Zod] You must have a length of at least 3'), -}) - -const ValibotSchema = v.object({ - firstName: v.pipe( - v.string(), - v.minLength(3, '[Valibot] You must have a length of at least 3'), - v.startsWith('A', "[Valibot] First name must start with 'A'"), - ), - lastName: v.pipe( - v.string(), - v.minLength(3, '[Valibot] You must have a length of at least 3'), - ), -}) - -const EffectSchema = S.standardSchemaV1( - S.Struct({ - firstName: S.String.pipe( - S.minLength(3), - S.annotations({ - message: () => '[Effect/Schema] You must have a length of at least 3', - }), - ), - lastName: S.String.pipe( - S.minLength(3), - S.annotations({ - message: () => '[Effect/Schema] You must have a length of at least 3', - }), - ), - }), -) - -@Component({ - selector: 'app-root', - standalone: true, - imports: [TanStackField], - template: ` -
    -
    - - - - @if (firstName.api.state.meta.isTouched) { - @for (error of firstName.api.state.meta.errors; track $index) { -
    - {{ error.message }} -
    - } - } - @if (firstName.api.state.meta.isValidating) { -

    Validating...

    - } -
    -
    -
    - - - - @if (firstName.api.state.meta.isTouched) { - @for (error of firstName.api.state.meta.errors; track $index) { -
    - {{ error.message }} -
    - } - } - @if (firstName.api.state.meta.isValidating) { -

    Validating...

    - } -
    -
    - - -
    - `, -}) -export class AppComponent { - form = injectForm({ - defaultValues: { - firstName: '', - lastName: '', - }, - - validators: { - // DEMO: You can switch between schemas seamlessly - onChange: ZodSchema, - // onChange: ValibotSchema, - // onChange: EffectSchema, - }, - onSubmit({ value }) { - // Do something with form data - console.log(value) - }, - }) - - canSubmit = injectStore(this.form, (state) => state.canSubmit) - isSubmitting = injectStore(this.form, (state) => state.isSubmitting) - - handleSubmit(event: SubmitEvent) { - event.preventDefault() - event.stopPropagation() - this.form.handleSubmit() - } -} diff --git a/examples/angular/standard-schema/src/favicon.ico b/examples/angular/standard-schema/src/favicon.ico deleted file mode 100644 index 57614f9c96..0000000000 Binary files a/examples/angular/standard-schema/src/favicon.ico and /dev/null differ diff --git a/examples/angular/standard-schema/src/index.html b/examples/angular/standard-schema/src/index.html deleted file mode 100644 index c3c6fbbdd5..0000000000 --- a/examples/angular/standard-schema/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Simple - - - - - - - - diff --git a/examples/angular/standard-schema/src/main.ts b/examples/angular/standard-schema/src/main.ts index 56773910ea..bdac04402c 100644 --- a/examples/angular/standard-schema/src/main.ts +++ b/examples/angular/standard-schema/src/main.ts @@ -1,4 +1,8 @@ +import { provideZonelessChangeDetection } from '@angular/core' import { bootstrapApplication } from '@angular/platform-browser' -import { AppComponent } from './app/app.component' +import { AppComponent } from './app.component' +import './styles.css' -bootstrapApplication(AppComponent).catch((err) => console.error(err)) +bootstrapApplication(AppComponent, { + providers: [provideZonelessChangeDetection()], +}).catch((error) => console.error(error)) diff --git a/examples/angular/standard-schema/src/styles.css b/examples/angular/standard-schema/src/styles.css new file mode 100644 index 0000000000..0bc5c5439f --- /dev/null +++ b/examples/angular/standard-schema/src/styles.css @@ -0,0 +1,48 @@ +:root { + color: #213547; + background: #f7f7f8; + font-family: Inter, system-ui, sans-serif; +} +body { + margin: 0; +} +main { + max-width: 48rem; + margin: 0 auto; + padding: 2rem; +} +form, +section, +fieldset { + display: grid; + gap: 1rem; +} +label { + display: grid; + gap: 0.35rem; +} +input, +button, +select { + font: inherit; + padding: 0.55rem 0.7rem; +} +button { + width: fit-content; + cursor: pointer; +} +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} +small[role='alert'], +.error { + color: #b42318; +} +.validating { + opacity: 0.7; +} +fieldset { + margin: 0; +} diff --git a/examples/angular/standard-schema/src/vite-env.d.ts b/examples/angular/standard-schema/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/angular/standard-schema/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/angular/standard-schema/tsconfig.app.json b/examples/angular/standard-schema/tsconfig.app.json index 84f1f992d2..e68f13b4a2 100644 --- a/examples/angular/standard-schema/tsconfig.app.json +++ b/examples/angular/standard-schema/tsconfig.app.json @@ -1,10 +1,16 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "./tsconfig.json", "compilerOptions": { + "noEmit": false, "outDir": "./out-tsc/app", + "rootDir": "../../..", "types": [] }, "files": ["src/main.ts"], - "include": ["src/**/*.d.ts"] + "include": ["src/**/*.d.ts"], + "angularCompilerOptions": { + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } } diff --git a/examples/angular/standard-schema/tsconfig.json b/examples/angular/standard-schema/tsconfig.json index afd15727a8..dd46e28018 100644 --- a/examples/angular/standard-schema/tsconfig.json +++ b/examples/angular/standard-schema/tsconfig.json @@ -1,28 +1,19 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { - "compileOnSave": false, + "extends": "../../../tsconfig.json", "compilerOptions": { - "outDir": "./dist/out-tsc", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "esModuleInterop": true, - "sourceMap": true, "declaration": false, + "emitDecoratorMetadata": true, "experimentalDecorators": true, - "moduleResolution": "bundler", - "importHelpers": true, - "target": "ES2022", - "module": "ES2022", + "moduleResolution": "Bundler", + "noEmit": true, "useDefineForClassFields": false, - "lib": ["ES2022", "dom"] + "paths": { + "@tanstack/angular-form": ["../../../packages/angular-form/src"], + "@tanstack/form-core": ["../../../packages/form-core/src"], + "@tanstack/form-core/internals": [ + "../../../packages/form-core/src/internals.ts" + ] + } }, - "angularCompilerOptions": { - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } + "include": ["src", "vite.config.ts"] } diff --git a/examples/angular/standard-schema/tsconfig.spec.json b/examples/angular/standard-schema/tsconfig.spec.json deleted file mode 100644 index 47e3dd7551..0000000000 --- a/examples/angular/standard-schema/tsconfig.spec.json +++ /dev/null @@ -1,9 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/spec", - "types": ["jasmine"] - }, - "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] -} diff --git a/examples/angular/standard-schema/vite.config.ts b/examples/angular/standard-schema/vite.config.ts new file mode 100644 index 0000000000..3484e49747 --- /dev/null +++ b/examples/angular/standard-schema/vite.config.ts @@ -0,0 +1,7 @@ +import angular from '@analogjs/vite-plugin-angular' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [angular({ tsconfig: 'tsconfig.app.json' })], + resolve: { tsconfigPaths: true }, +}) diff --git a/examples/lit/array/.eslintrc.cjs b/examples/lit/array/.eslintrc.cjs deleted file mode 100644 index cca134ce16..0000000000 --- a/examples/lit/array/.eslintrc.cjs +++ /dev/null @@ -1,6 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = {} - -module.exports = config diff --git a/examples/lit/array/.gitignore b/examples/lit/array/.gitignore deleted file mode 100644 index 4673b022e5..0000000000 --- a/examples/lit/array/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -pnpm-lock.yaml -yarn.lock -package-lock.json - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/examples/lit/array/README.md b/examples/lit/array/README.md index 1cf8892652..45fcee441f 100644 --- a/examples/lit/array/README.md +++ b/examples/lit/array/README.md @@ -1,6 +1,6 @@ -# Example +# Lit array example To run this example: -- `npm install` -- `npm run dev` +- `pnpm install` +- `pnpm dev` diff --git a/examples/lit/array/index.html b/examples/lit/array/index.html index 6bbd54321c..f48a88af32 100644 --- a/examples/lit/array/index.html +++ b/examples/lit/array/index.html @@ -2,12 +2,11 @@ - - Vite + Lit + TS - + TanStack Form Lit Array Example - + + diff --git a/examples/lit/array/package.json b/examples/lit/array/package.json index f0db6d6cd0..4bebfb6a31 100644 --- a/examples/lit/array/package.json +++ b/examples/lit/array/package.json @@ -3,28 +3,17 @@ "private": true, "type": "module", "scripts": { - "dev": "vite --port=3001", + "dev": "vite --port=3402", "build": "vite build", "preview": "vite preview", "test:types": "tsc" }, "dependencies": { - "@tanstack/lit-form": "^1.25.3", + "@tanstack/lit-form": "^2.0.0-alpha.3", "lit": "^3.3.1" }, "devDependencies": { - "vite": "^7.2.2" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/lit/array/src/index.ts b/examples/lit/array/src/index.ts index 1346a056aa..ce3f1846dc 100644 --- a/examples/lit/array/src/index.ts +++ b/examples/lit/array/src/index.ts @@ -1,94 +1,99 @@ import { LitElement, html } from 'lit' import { customElement } from 'lit/decorators.js' - import { TanStackFormController } from '@tanstack/lit-form' -import { repeat } from 'lit/directives/repeat.js' - -interface Person { - name: string - age: number -} +import './styles.css' -const defaultPeople: { people: Array } = { people: [] } - -@customElement('tanstack-form-demo') -export class TanStackFormDemo extends LitElement { - #form = new TanStackFormController(this, { - defaultValues: defaultPeople, - onSubmit({ value }) { - alert(JSON.stringify(value)) +@customElement('tanstack-array-form') +export class TanStackArrayForm extends LitElement { + private form = new TanStackFormController(this, { + defaultValues: { + items: Array.from({ length: 50 }, () => ''), + }, + onSubmit: ({ value }) => { + console.log(value) + alert(`Submitted ${value.items.length} items.`) }, }) + protected createRenderRoot() { + return this + } + + private updateItems() { + const input = this.querySelector('#itemsAmount') + if (!input || Number.isNaN(input.valueAsNumber)) return + const amount = Math.min(10_000, Math.max(0, input.valueAsNumber)) + this.form.api.reset({ + items: Array.from({ length: amount }, () => ''), + }) + } + render() { return html` -
    -
    { - e.preventDefault() - e.stopPropagation() - this.#form.api.handleSubmit() - }} - > - ${this.#form.field( - { - name: 'people', - }, - (peopleField) => { - return html`
    - ${repeat( - peopleField.state.value, - (_, index) => index, - (_, index) => { - return html` - ${this.#form.field( - { - name: `people[${index}].name`, - }, - (field) => { - return html`
    -
    - -
    -
    ` - }, - )} - ` - }, - )} - - -
    ` - }, - )} +

    Arrays in Form Example

    + + + - -
    -
    + ${this.form.subscribe( + (state) => state.values.items.length, + (amount) => html`

    Item amount: ${amount.toLocaleString()}

    `, + )} +
    { + event.preventDefault() + event.stopPropagation() + void this.form.api.handleSubmit() + }} + > + + + ${this.form.arrayField( + { name: 'items' }, + (array) => html` +
      + ${array.value.map( + (_item, index) => html` +
    • + ${this.form.field( + { name: `items[${index}]` }, + (field) => html` + + `, + )} +
    • + `, + )} +
    + `, + )} +
    ` } } diff --git a/examples/lit/array/src/styles.css b/examples/lit/array/src/styles.css new file mode 100644 index 0000000000..41bb1b8ca0 --- /dev/null +++ b/examples/lit/array/src/styles.css @@ -0,0 +1,32 @@ +#root { + display: block; + max-width: 100%; + margin: 0 5rem; + text-align: center; + font-family: system-ui, sans-serif; +} + +#root button, +#root input { + font: inherit; + padding: 0.5rem 0.7rem; +} + +#root ul { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); + gap: 0.75rem; + padding: 2rem 0; + list-style: none; +} + +#root label { + display: grid; + gap: 0.35rem; +} + +#root li input { + min-width: 0; + width: 100%; + box-sizing: border-box; +} diff --git a/examples/lit/array/tsconfig.json b/examples/lit/array/tsconfig.json index 79af5f2334..8a907eef8b 100644 --- a/examples/lit/array/tsconfig.json +++ b/examples/lit/array/tsconfig.json @@ -6,19 +6,15 @@ "module": "ESNext", "lib": ["ES2020", "DOM", "DOM.Iterable"], "skipLibCheck": true, - - /* Bundler mode */ "moduleResolution": "Bundler", "allowImportingTsExtensions": true, - "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - - /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] }, "include": ["src"] } diff --git a/examples/lit/basic-splitting-form/README.md b/examples/lit/basic-splitting-form/README.md new file mode 100644 index 0000000000..8a702bb34b --- /dev/null +++ b/examples/lit/basic-splitting-form/README.md @@ -0,0 +1,6 @@ +# Lit split form example + +To run this example: + +- `pnpm install` +- `pnpm dev` diff --git a/examples/lit/basic-splitting-form/index.html b/examples/lit/basic-splitting-form/index.html new file mode 100644 index 0000000000..eca5cd46a9 --- /dev/null +++ b/examples/lit/basic-splitting-form/index.html @@ -0,0 +1,12 @@ + + + + + + TanStack Form Lit Split Form Example + + + + + + diff --git a/examples/lit/basic-splitting-form/package.json b/examples/lit/basic-splitting-form/package.json new file mode 100644 index 0000000000..7a39116b23 --- /dev/null +++ b/examples/lit/basic-splitting-form/package.json @@ -0,0 +1,19 @@ +{ + "name": "@tanstack/form-example-lit-basic-splitting-form", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3404", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/lit-form": "^2.0.0-alpha.3", + "lit": "^3.3.1" + }, + "devDependencies": { + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/lit/basic-splitting-form/src/field-error.ts b/examples/lit/basic-splitting-form/src/field-error.ts new file mode 100644 index 0000000000..e8341be072 --- /dev/null +++ b/examples/lit/basic-splitting-form/src/field-error.ts @@ -0,0 +1,10 @@ +import { html, nothing } from 'lit' +import type { AnyFieldApi } from '@tanstack/lit-form' + +export function fieldError(field: AnyFieldApi) { + return html`${field.errors.map((error) => error.message).join('\n')}` +} diff --git a/examples/lit/basic-splitting-form/src/form-section.ts b/examples/lit/basic-splitting-form/src/form-section.ts new file mode 100644 index 0000000000..8cb8a20825 --- /dev/null +++ b/examples/lit/basic-splitting-form/src/form-section.ts @@ -0,0 +1,15 @@ +import { html } from 'lit' +import { stringField } from './string-field' +import type { LitFormType } from '@tanstack/lit-form' +import type { sharedFormOptions } from './shared-form' + +export function formSection(form: LitFormType) { + return html` + ${form.field({ name: 'address.street' }, (field) => + stringField(field, 'Street'), + )} + ${form.field({ name: 'address.country' }, (field) => + stringField(field, 'Country'), + )} + ` +} diff --git a/examples/lit/basic-splitting-form/src/form-submit-button.ts b/examples/lit/basic-splitting-form/src/form-submit-button.ts new file mode 100644 index 0000000000..a304efbd61 --- /dev/null +++ b/examples/lit/basic-splitting-form/src/form-submit-button.ts @@ -0,0 +1,13 @@ +import { html } from 'lit' +import type { AnyLitFormApi } from '@tanstack/lit-form' + +export function formSubmitButton(form: AnyLitFormApi) { + return form.subscribe( + (state) => [state.canSubmit, state.isSubmitting] as const, + ([canSubmit, isSubmitting]) => html` + + `, + ) +} diff --git a/examples/lit/basic-splitting-form/src/index.ts b/examples/lit/basic-splitting-form/src/index.ts new file mode 100644 index 0000000000..dd20507f69 --- /dev/null +++ b/examples/lit/basic-splitting-form/src/index.ts @@ -0,0 +1,52 @@ +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' +import { TanStackFormController } from '@tanstack/lit-form' +import { formSection } from './form-section' +import { formSubmitButton } from './form-submit-button' +import { sharedFormOptions } from './shared-form' +import { stringField } from './string-field' +import './styles.css' + +@customElement('tanstack-split-form') +export class TanStackSplitForm extends LitElement { + private form = new TanStackFormController(this, { + ...sharedFormOptions, + onSubmit: ({ value }) => { + console.log(value) + }, + }) + + protected createRenderRoot() { + return this + } + + render() { + return html` +

    Split Form Example

    +
    { + event.preventDefault() + event.stopPropagation() + void this.form.api.handleSubmit() + }} + > + ${this.form.field({ name: 'firstName' }, (field) => + stringField(field, 'First Name'), + )} + ${this.form.field({ name: 'lastName' }, (field) => + stringField(field, 'Last Name'), + )} + ${formSection(this.form)} ${formSubmitButton(this.form)} + +
    + ` + } +} diff --git a/examples/lit/basic-splitting-form/src/shared-form.ts b/examples/lit/basic-splitting-form/src/shared-form.ts new file mode 100644 index 0000000000..cc2f6145ae --- /dev/null +++ b/examples/lit/basic-splitting-form/src/shared-form.ts @@ -0,0 +1,12 @@ +import { formOptions } from '@tanstack/lit-form' + +export const sharedFormOptions = formOptions({ + defaultValues: { + firstName: '', + lastName: '', + address: { + street: '', + country: '', + }, + }, +}) diff --git a/examples/lit/basic-splitting-form/src/string-field.ts b/examples/lit/basic-splitting-form/src/string-field.ts new file mode 100644 index 0000000000..baec99d383 --- /dev/null +++ b/examples/lit/basic-splitting-form/src/string-field.ts @@ -0,0 +1,20 @@ +import { html } from 'lit' +import { fieldError } from './field-error' +import type { FieldWithValue } from '@tanstack/lit-form' + +export function stringField(field: FieldWithValue, label: string) { + return html` + + ` +} diff --git a/examples/lit/basic-splitting-form/src/styles.css b/examples/lit/basic-splitting-form/src/styles.css new file mode 100644 index 0000000000..dfac864e23 --- /dev/null +++ b/examples/lit/basic-splitting-form/src/styles.css @@ -0,0 +1,24 @@ +#root { + display: block; + max-width: 32rem; + margin: 0 auto; + font-family: system-ui, sans-serif; +} + +#root form, +#root label { + display: grid; + gap: 0.5rem; +} + +#root input, +#root button { + font: inherit; + padding: 0.55rem 0.7rem; +} + +#root small { + min-height: 1.25rem; + color: #b42318; + white-space: pre-line; +} diff --git a/examples/lit/basic-splitting-form/tsconfig.json b/examples/lit/basic-splitting-form/tsconfig.json new file mode 100644 index 0000000000..8a907eef8b --- /dev/null +++ b/examples/lit/basic-splitting-form/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2020", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "noEmit": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src"] +} diff --git a/examples/lit/basic/README.md b/examples/lit/basic/README.md new file mode 100644 index 0000000000..c5267532d7 --- /dev/null +++ b/examples/lit/basic/README.md @@ -0,0 +1,6 @@ +# Lit basic example + +To run this example: + +- `pnpm install` +- `pnpm dev` diff --git a/examples/lit/basic/index.html b/examples/lit/basic/index.html new file mode 100644 index 0000000000..d5ccd90753 --- /dev/null +++ b/examples/lit/basic/index.html @@ -0,0 +1,12 @@ + + + + + + TanStack Form Lit Basic Example + + + + + + diff --git a/examples/lit/basic/package.json b/examples/lit/basic/package.json new file mode 100644 index 0000000000..f2f07b2ef7 --- /dev/null +++ b/examples/lit/basic/package.json @@ -0,0 +1,19 @@ +{ + "name": "@tanstack/form-example-lit-basic", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3403", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/lit-form": "^2.0.0-alpha.3", + "lit": "^3.3.1" + }, + "devDependencies": { + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/lit/basic/src/index.ts b/examples/lit/basic/src/index.ts new file mode 100644 index 0000000000..a23940108d --- /dev/null +++ b/examples/lit/basic/src/index.ts @@ -0,0 +1,127 @@ +import { LitElement, html, nothing } from 'lit' +import { customElement } from 'lit/decorators.js' +import { TanStackFormController } from '@tanstack/lit-form' +import type { AnyFieldApi } from '@tanstack/lit-form' +import './styles.css' + +function fieldError(field: AnyFieldApi) { + return html`${field.errors.map((error) => error.message).join('\n')}` +} + +@customElement('tanstack-basic-form') +export class TanStackBasicForm extends LitElement { + private form = new TanStackFormController(this, { + defaultValues: { + firstName: '', + lastName: '', + }, + onSubmit: ({ value, createValidationError }) => { + console.log(value) + return createValidationError({ + fields: { + firstName: 'Name already exists', + lastName: 'Name already exists', + }, + }) + }, + }) + + protected createRenderRoot() { + return this + } + + render() { + return html` +

    Basic Form Example

    +
    { + event.preventDefault() + event.stopPropagation() + void this.form.api.handleSubmit() + }} + > + ${this.form.field( + { + name: 'firstName', + validators: [ + { + run: ({ value }) => { + if (!value) return 'A first name is required' + if (value.length < 3) return 'First name is too short' + }, + triggers: ['change', 'blur'], + triggerDebounceMs: 300, + }, + { + run: async ({ value }) => { + await new Promise((resolve) => setTimeout(resolve, 1000)) + return value.toLowerCase().includes('error') + ? 'No "error" allowed in first name' + : undefined + }, + triggers: ['change'], + bailIfInvalid: true, + }, + ], + }, + (field) => html` + + `, + )} + ${this.form.field( + { name: 'lastName' }, + (field) => html` + + `, + )} + ${this.form.subscribe( + (state) => [state.canSubmit, state.isSubmitting] as const, + ([canSubmit, isSubmitting]) => html` + + `, + )} + +
    + ` + } +} diff --git a/examples/lit/basic/src/styles.css b/examples/lit/basic/src/styles.css new file mode 100644 index 0000000000..f5cfbf3bf8 --- /dev/null +++ b/examples/lit/basic/src/styles.css @@ -0,0 +1,38 @@ +#root { + width: 70rem; + max-width: 100%; + margin: 0 auto; + text-align: center; + font-family: system-ui, sans-serif; +} + +#root form, +#root label { + display: grid; + gap: 0.5rem; +} + +#root form { + max-width: 24rem; + margin: auto; +} + +#root input, +#root button { + font: inherit; + padding: 0.55rem 0.7rem; +} + +#root small { + min-height: 1.25rem; + color: #b42318; + white-space: pre-line; +} + +#root input[aria-invalid='true'] { + border-color: #b42318; +} + +#root .validating { + opacity: 0.7; +} diff --git a/examples/lit/basic/tsconfig.json b/examples/lit/basic/tsconfig.json new file mode 100644 index 0000000000..8a907eef8b --- /dev/null +++ b/examples/lit/basic/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2020", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "noEmit": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src"] +} diff --git a/examples/lit/field-groups/README.md b/examples/lit/field-groups/README.md new file mode 100644 index 0000000000..74976dc738 --- /dev/null +++ b/examples/lit/field-groups/README.md @@ -0,0 +1,6 @@ +# Lit field groups example + +To run this example: + +- `pnpm install` +- `pnpm dev` diff --git a/examples/lit/field-groups/index.html b/examples/lit/field-groups/index.html new file mode 100644 index 0000000000..52d68b79cb --- /dev/null +++ b/examples/lit/field-groups/index.html @@ -0,0 +1,12 @@ + + + + + + TanStack Form Lit Field Groups Example + + + + + + diff --git a/examples/lit/field-groups/package.json b/examples/lit/field-groups/package.json new file mode 100644 index 0000000000..69516ede2e --- /dev/null +++ b/examples/lit/field-groups/package.json @@ -0,0 +1,20 @@ +{ + "name": "@tanstack/form-example-lit-field-groups", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3405", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/lit-form": "^2.0.0-alpha.3", + "lit": "^3.3.1", + "zod": "^4.4.3" + }, + "devDependencies": { + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/lit/field-groups/src/date-range.ts b/examples/lit/field-groups/src/date-range.ts new file mode 100644 index 0000000000..adbbe533ef --- /dev/null +++ b/examples/lit/field-groups/src/date-range.ts @@ -0,0 +1,50 @@ +import { html } from 'lit' +import { defineFieldGroup } from '@tanstack/lit-form' +import { stringField } from './string-field' + +const dateRangeFieldGroup = defineFieldGroup(({ strict }) => ({ + start: strict(), + end: strict(), +})) + +function dateRangeField(props: { + fields: typeof dateRangeFieldGroup.fields + label: string +}) { + return html` +
    + ${props.label} + ${props.fields.field({ name: 'start' }, (field) => + stringField(field, 'Start date', 'date'), + )} + ${props.fields.field( + { + name: 'end', + validators: [ + { + triggers: [ + { + trigger: 'change', + when: ({ value }) => Boolean(value), + }, + ], + watchFields: ['start'], + run: ({ value }) => { + const start = props.fields.getFieldValue('start') + if (start && value < start) { + return 'End date must be after the start date' + } + }, + }, + ], + }, + (field) => stringField(field, 'End date', 'date'), + )} +
    + ` +} + +export const DateRangeField = dateRangeFieldGroup.bindComponent( + dateRangeField, + 'fields', +) diff --git a/examples/lit/field-groups/src/field-bounds.ts b/examples/lit/field-groups/src/field-bounds.ts new file mode 100644 index 0000000000..9bc4aec3ab --- /dev/null +++ b/examples/lit/field-groups/src/field-bounds.ts @@ -0,0 +1,86 @@ +import { defineFieldGroup } from '@tanstack/lit-form' +import { z } from 'zod' +import { stringField } from './string-field' + +const boundsSchema = z.coerce.number().int() + +const lowerBoundFieldGroup = defineFieldGroup(({ strict }) => ({ + value: strict(), +})) + +function lowerBoundField(props: { + fields: typeof lowerBoundFieldGroup.fields + label: string +}) { + return props.fields.field( + { + name: 'value', + validators: [ + { + run: boundsSchema, + triggers: ['change'], + }, + ], + listeners: [ + { + triggers: ['blur'], + run: ({ value }) => { + props.fields.setFieldValue('value', parseInt(value, 10).toString()) + }, + }, + ], + }, + (field) => stringField(field, props.label), + ) +} + +export const LowerBoundField = lowerBoundFieldGroup.bindComponent( + lowerBoundField, + 'fields', +) + +const upperBoundFieldGroup = defineFieldGroup(({ strict }) => ({ + value: strict(), + lowerBound: strict(), +})) + +function upperBoundField(props: { + fields: typeof upperBoundFieldGroup.fields + label: string +}) { + return props.fields.field( + { + name: 'value', + validators: [ + { + triggers: ['change'], + watchFields: ['lowerBound'], + run: ({ value, parseIssues }) => { + const upper = boundsSchema.safeParse(value) + if (!upper.success) return parseIssues(upper.error.issues) + const lower = boundsSchema.safeParse( + props.fields.getFieldValue('lowerBound'), + ) + if (lower.success && upper.data < lower.data) { + return 'Upper bound must be greater than lower bound' + } + }, + }, + ], + listeners: [ + { + triggers: ['blur'], + run: ({ value }) => { + props.fields.setFieldValue('value', parseInt(value, 10).toString()) + }, + }, + ], + }, + (field) => stringField(field, props.label), + ) +} + +export const UpperBoundField = upperBoundFieldGroup.bindComponent( + upperBoundField, + 'fields', +) diff --git a/examples/lit/field-groups/src/field-error.ts b/examples/lit/field-groups/src/field-error.ts new file mode 100644 index 0000000000..efcb835940 --- /dev/null +++ b/examples/lit/field-groups/src/field-error.ts @@ -0,0 +1,11 @@ +import { html, nothing } from 'lit' +import type { AnyFieldApi } from '@tanstack/lit-form' + +export function fieldError(field: AnyFieldApi) { + return html` + ${field.errors.map((error) => error.message).join(', ')} + ` +} diff --git a/examples/lit/field-groups/src/index.ts b/examples/lit/field-groups/src/index.ts new file mode 100644 index 0000000000..5c69fadebe --- /dev/null +++ b/examples/lit/field-groups/src/index.ts @@ -0,0 +1,83 @@ +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' +import { TanStackFormController } from '@tanstack/lit-form' +import { DateRangeField } from './date-range' +import { LowerBoundField, UpperBoundField } from './field-bounds' +import './styles.css' + +@customElement('tanstack-field-groups') +export class TanStackFieldGroups extends LitElement { + private pricingForm = new TanStackFormController(this, { + defaultValues: { minPrice: '', maxPrice: '' }, + }) + + private ageForm = new TanStackFormController(this, { + defaultValues: { minAge: '', maxAge: '' }, + }) + + private dateForm = new TanStackFormController(this, { + defaultValues: { + dateRanges: [ + { id: 'A', start: '2026-07-01', end: '2026-07-05' }, + { id: 'B', start: '2026-08-10', end: '2026-08-15' }, + ], + }, + }) + + protected createRenderRoot() { + return this + } + + render() { + return html` +

    Reusable Field Group Example

    +
    +

    Price Filter Form

    + ${LowerBoundField({ + form: this.pricingForm, + fields: { value: 'minPrice' }, + label: 'Lowest Price', + })} + ${UpperBoundField({ + form: this.pricingForm, + fields: { value: 'maxPrice', lowerBound: 'minPrice' }, + label: 'Highest Price', + })} +
    +
    +

    Age Range Form

    + ${LowerBoundField({ + form: this.ageForm, + fields: { value: 'minAge' }, + label: 'Lowest Age', + })} + ${UpperBoundField({ + form: this.ageForm, + fields: { value: 'maxAge', lowerBound: 'minAge' }, + label: 'Highest Age', + })} +
    +
    +

    Swappable Date Ranges

    + + ${this.dateForm.arrayField({ name: 'dateRanges' }, (array) => + array.value.map((range, index) => + DateRangeField({ + form: this.dateForm, + fields: { + start: `dateRanges[${index}].start`, + end: `dateRanges[${index}].end`, + }, + label: `Range ${range.id}`, + }), + ), + )} +
    + ` + } +} diff --git a/examples/lit/field-groups/src/string-field.ts b/examples/lit/field-groups/src/string-field.ts new file mode 100644 index 0000000000..e6c94cc0ee --- /dev/null +++ b/examples/lit/field-groups/src/string-field.ts @@ -0,0 +1,25 @@ +import { html } from 'lit' +import { fieldError } from './field-error' +import type { FieldWithValue } from '@tanstack/lit-form' + +export function stringField( + field: FieldWithValue, + label: string, + type: 'text' | 'date' = 'text', +) { + return html` + + ` +} diff --git a/examples/lit/field-groups/src/styles.css b/examples/lit/field-groups/src/styles.css new file mode 100644 index 0000000000..6420f696df --- /dev/null +++ b/examples/lit/field-groups/src/styles.css @@ -0,0 +1,27 @@ +#root { + display: block; + max-width: 48rem; + margin: 0 auto; + font-family: system-ui, sans-serif; +} + +#root section, +#root fieldset, +#root label { + display: grid; + gap: 0.6rem; +} + +#root section { + margin-block: 2rem; +} + +#root input, +#root button { + font: inherit; + padding: 0.55rem 0.7rem; +} + +#root small[role='alert'] { + color: #b42318; +} diff --git a/examples/lit/field-groups/tsconfig.json b/examples/lit/field-groups/tsconfig.json new file mode 100644 index 0000000000..8a907eef8b --- /dev/null +++ b/examples/lit/field-groups/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2020", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "noEmit": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src"] +} diff --git a/examples/lit/large-form/.eslintrc.cjs b/examples/lit/large-form/.eslintrc.cjs deleted file mode 100644 index cca134ce16..0000000000 --- a/examples/lit/large-form/.eslintrc.cjs +++ /dev/null @@ -1,6 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = {} - -module.exports = config diff --git a/examples/lit/large-form/.gitignore b/examples/lit/large-form/.gitignore deleted file mode 100644 index 4673b022e5..0000000000 --- a/examples/lit/large-form/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -pnpm-lock.yaml -yarn.lock -package-lock.json - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/examples/lit/large-form/README.md b/examples/lit/large-form/README.md index 1cf8892652..40e832fc97 100644 --- a/examples/lit/large-form/README.md +++ b/examples/lit/large-form/README.md @@ -1,6 +1,6 @@ -# Example +# Lit large form example To run this example: -- `npm install` -- `npm run dev` +- `pnpm install` +- `pnpm dev` diff --git a/examples/lit/large-form/index.html b/examples/lit/large-form/index.html index 0aacedd2a4..b18604dd12 100644 --- a/examples/lit/large-form/index.html +++ b/examples/lit/large-form/index.html @@ -2,12 +2,11 @@ - TanStack Form Lit Large Form Example - - + + diff --git a/examples/lit/large-form/package.json b/examples/lit/large-form/package.json index 974225d095..61aa613428 100644 --- a/examples/lit/large-form/package.json +++ b/examples/lit/large-form/package.json @@ -3,29 +3,17 @@ "private": true, "type": "module", "scripts": { - "dev": "vite --port=3001", + "dev": "vite --port=3406", "build": "vite build", "preview": "vite preview", "test:types": "tsc" }, "dependencies": { - "@tanstack/lit-form": "^1.25.3", - "@tanstack/lit-store": "^0.13.2", + "@tanstack/lit-form": "^2.0.0-alpha.3", "lit": "^3.3.1" }, "devDependencies": { - "vite": "^7.2.2" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/lit/large-form/src/address-fields.ts b/examples/lit/large-form/src/address-fields.ts new file mode 100644 index 0000000000..76723d2c80 --- /dev/null +++ b/examples/lit/large-form/src/address-fields.ts @@ -0,0 +1,27 @@ +import { html } from 'lit' +import { textField } from './text-field' +import type { LitFormType } from '@tanstack/lit-form' +import type { peopleFormOptions } from './shared-form' + +export function addressFields(form: LitFormType) { + return html` +
    +

    Address

    + ${form.field({ name: 'address.line1' }, (field) => + textField(field, 'Address Line 1'), + )} + ${form.field({ name: 'address.line2' }, (field) => + textField(field, 'Address Line 2'), + )} + ${form.field({ name: 'address.city' }, (field) => + textField(field, 'City'), + )} + ${form.field({ name: 'address.state' }, (field) => + textField(field, 'State'), + )} + ${form.field({ name: 'address.zip' }, (field) => + textField(field, 'ZIP Code'), + )} +
    + ` +} diff --git a/examples/lit/large-form/src/components/text-field.ts b/examples/lit/large-form/src/components/text-field.ts deleted file mode 100644 index 27003af42f..0000000000 --- a/examples/lit/large-form/src/components/text-field.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { LitElement, html, nothing } from 'lit' -import { customElement, property } from 'lit/decorators.js' -import { repeat } from 'lit/directives/repeat.js' -import { TanStackStoreSelector } from '@tanstack/lit-store' -import type { AnyFieldApi } from '@tanstack/lit-form' - -@customElement('text-field') -export class TextField extends LitElement { - @property({ attribute: false }) - field!: AnyFieldApi - - @property({ type: String }) - label = '' - - _selector = new TanStackStoreSelector(this, () => this.field?.store) - - // Render into light DOM so the surrounding form picks up the inputs naturally - protected createRenderRoot() { - return this - } - - render() { - const field = this.field - return html` -
    - - ${field.state.meta.isTouched && field.state.meta.errors.length - ? repeat( - field.state.meta.errors, - (_, idx) => idx, - (error: unknown) => - html`
    ${String(error)}
    `, - ) - : nothing} - ${field.state.meta.isValidating ? html`

    Validating...

    ` : nothing} -
    - ` - } -} - -declare global { - interface HTMLElementTagNameMap { - 'text-field': TextField - } -} diff --git a/examples/lit/large-form/src/emergency-contact.ts b/examples/lit/large-form/src/emergency-contact.ts new file mode 100644 index 0000000000..27a6e917e9 --- /dev/null +++ b/examples/lit/large-form/src/emergency-contact.ts @@ -0,0 +1,20 @@ +import { html } from 'lit' +import { textField } from './text-field' +import type { LitFormType } from '@tanstack/lit-form' +import type { peopleFormOptions } from './shared-form' + +export function emergencyContactFields( + form: LitFormType, +) { + return html` +
    +

    Emergency Contact

    + ${form.field({ name: 'emergencyContact.fullName' }, (field) => + textField(field, 'Full Name'), + )} + ${form.field({ name: 'emergencyContact.phone' }, (field) => + textField(field, 'Phone'), + )} +
    + ` +} diff --git a/examples/lit/large-form/src/features/people/address-fields.ts b/examples/lit/large-form/src/features/people/address-fields.ts deleted file mode 100644 index 8fb1646846..0000000000 --- a/examples/lit/large-form/src/features/people/address-fields.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { LitElement, html } from 'lit' -import { customElement, property } from 'lit/decorators.js' -import { TanStackStoreSelector } from '@tanstack/lit-store' -import { getFormType } from '@tanstack/lit-form' -import { peopleFormOpts } from './shared-form.js' -import '../../components/text-field.js' - -const formType = getFormType(peopleFormOpts) - -@customElement('address-fields') -export class AddressFields extends LitElement { - @property({ attribute: false }) - form!: typeof formType - - _selector = new TanStackStoreSelector(this, () => this.form?.api.store) - - protected createRenderRoot() { - return this - } - - render() { - return html` -
    -

    Address

    - ${this.form.field( - { name: 'address.line1' }, - (field) => - html``, - )} - ${this.form.field( - { name: 'address.line2' }, - (field) => - html``, - )} - ${this.form.field( - { name: 'address.city' }, - (field) => - html``, - )} - ${this.form.field( - { name: 'address.state' }, - (field) => - html``, - )} - ${this.form.field( - { name: 'address.zip' }, - (field) => - html``, - )} -
    - ` - } -} - -declare global { - interface HTMLElementTagNameMap { - 'address-fields': AddressFields - } -} diff --git a/examples/lit/large-form/src/features/people/emergency-contact.ts b/examples/lit/large-form/src/features/people/emergency-contact.ts deleted file mode 100644 index 9d096e9656..0000000000 --- a/examples/lit/large-form/src/features/people/emergency-contact.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { LitElement, html } from 'lit' -import { customElement, property } from 'lit/decorators.js' -import { TanStackStoreSelector } from '@tanstack/lit-store' -import { getFormType } from '@tanstack/lit-form' -import { peopleFormOpts } from './shared-form.js' -import '../../components/text-field.js' - -const formType = getFormType(peopleFormOpts) - -@customElement('emergency-contact-fields') -export class EmergencyContactFields extends LitElement { - @property({ attribute: false }) - form!: typeof formType - - _selector = new TanStackStoreSelector(this, () => this.form?.api.store) - - protected createRenderRoot() { - return this - } - - render() { - return html` - ${this.form.field( - { name: 'emergencyContact.fullName' }, - (field) => - html``, - )} - ${this.form.field( - { name: 'emergencyContact.phone' }, - (field) => - html``, - )} - ` - } -} - -declare global { - interface HTMLElementTagNameMap { - 'emergency-contact-fields': EmergencyContactFields - } -} diff --git a/examples/lit/large-form/src/features/people/page.ts b/examples/lit/large-form/src/features/people/page.ts deleted file mode 100644 index 2ac7be24c2..0000000000 --- a/examples/lit/large-form/src/features/people/page.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' -import { TanStackFormController } from '@tanstack/lit-form' -import { peopleFormOpts } from './shared-form.js' -import './address-fields.js' -import './emergency-contact.js' -import '../../components/text-field.js' - -@customElement('people-page') -export class PeoplePage extends LitElement { - form = new TanStackFormController(this, { - ...peopleFormOpts, - onSubmit: ({ value }) => { - alert(JSON.stringify(value, null, 2)) - }, - }) - - protected createRenderRoot() { - return this - } - - render() { - return html` -
    { - e.preventDefault() - e.stopPropagation() - this.form.api.handleSubmit() - }} - > -

    Personal Information

    - ${this.form.field( - { name: 'fullName' }, - (field) => - html``, - )} - ${this.form.field( - { name: 'email' }, - (field) => - html``, - )} - ${this.form.field( - { name: 'phone' }, - (field) => - html``, - )} - - - -

    Emergency Contact

    - - - -
    - ` - } -} - -declare global { - interface HTMLElementTagNameMap { - 'people-page': PeoplePage - } -} diff --git a/examples/lit/large-form/src/features/people/shared-form.ts b/examples/lit/large-form/src/features/people/shared-form.ts deleted file mode 100644 index be46b0d564..0000000000 --- a/examples/lit/large-form/src/features/people/shared-form.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { formOptions } from '@tanstack/lit-form' - -export const peopleFormOpts = formOptions({ - defaultValues: { - fullName: '', - email: '', - phone: '', - address: { - line1: '', - line2: '', - city: '', - state: '', - zip: '', - }, - emergencyContact: { - fullName: '', - phone: '', - }, - }, - validators: { - onChangeAsync: async ({ value }) => { - const errors = { - fields: {}, - } as { - fields: Record - } - if (!value.fullName) { - errors.fields.fullName = 'Full name is required' - } - if (!value.phone) { - errors.fields.phone = 'Phone is required' - } - if (!value.emergencyContact.fullName) { - errors.fields['emergencyContact.fullName'] = - 'Emergency contact full name is required' - } - if (!value.emergencyContact.phone) { - errors.fields['emergencyContact.phone'] = - 'Emergency contact phone is required' - } - - return errors - }, - }, -}) diff --git a/examples/lit/large-form/src/index.ts b/examples/lit/large-form/src/index.ts index b03b5e92f2..eb9166178e 100644 --- a/examples/lit/large-form/src/index.ts +++ b/examples/lit/large-form/src/index.ts @@ -1 +1,51 @@ -import './features/people/page.js' +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' +import { TanStackFormController } from '@tanstack/lit-form' +import { addressFields } from './address-fields' +import { emergencyContactFields } from './emergency-contact' +import { peopleFormOptions } from './shared-form' +import { textField } from './text-field' +import './styles.css' + +@customElement('tanstack-people-form') +export class TanStackPeopleForm extends LitElement { + private form = new TanStackFormController(this, { + ...peopleFormOptions, + onSubmit: ({ value }) => { + alert(JSON.stringify(value, null, 2)) + }, + }) + + protected createRenderRoot() { + return this + } + + render() { + return html` +
    { + event.preventDefault() + void this.form.api.handleSubmit() + }} + > +

    Personal Information

    + ${this.form.field({ name: 'fullName' }, (field) => + textField(field, 'Full Name'), + )} + ${this.form.field({ name: 'email' }, (field) => + textField(field, 'Email'), + )} + ${this.form.field({ name: 'phone' }, (field) => + textField(field, 'Phone'), + )} + ${addressFields(this.form)} ${emergencyContactFields(this.form)} + ${this.form.subscribe( + (state) => state.isSubmitting, + (isSubmitting) => html` + + `, + )} +
    + ` + } +} diff --git a/examples/lit/large-form/src/shared-form.ts b/examples/lit/large-form/src/shared-form.ts new file mode 100644 index 0000000000..b9accfa25e --- /dev/null +++ b/examples/lit/large-form/src/shared-form.ts @@ -0,0 +1,39 @@ +import { formOptions } from '@tanstack/lit-form' + +export const peopleFormOptions = formOptions({ + defaultValues: { + fullName: '', + email: '', + phone: '', + address: { + line1: '', + line2: '', + city: '', + state: '', + zip: '', + }, + emergencyContact: { + fullName: '', + phone: '', + }, + }, + validators: [ + { + triggers: ['change'], + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() + if (!value.fullName) errors.fields.fullName = 'Full name is required' + if (!value.phone) errors.fields.phone = 'Phone is required' + if (!value.emergencyContact.fullName) { + errors.fields['emergencyContact.fullName'] = + 'Emergency contact full name is required' + } + if (!value.emergencyContact.phone) { + errors.fields['emergencyContact.phone'] = + 'Emergency contact phone is required' + } + return errors + }, + }, + ], +}) diff --git a/examples/lit/large-form/src/styles.css b/examples/lit/large-form/src/styles.css new file mode 100644 index 0000000000..73d6b450de --- /dev/null +++ b/examples/lit/large-form/src/styles.css @@ -0,0 +1,23 @@ +#root { + display: block; + max-width: 42rem; + margin: 0 auto; + font-family: system-ui, sans-serif; +} + +#root form, +#root section, +#root label { + display: grid; + gap: 0.6rem; +} + +#root input, +#root button { + font: inherit; + padding: 0.55rem 0.7rem; +} + +#root .error { + color: #b42318; +} diff --git a/examples/lit/large-form/src/text-field.ts b/examples/lit/large-form/src/text-field.ts new file mode 100644 index 0000000000..65f2b5c5ca --- /dev/null +++ b/examples/lit/large-form/src/text-field.ts @@ -0,0 +1,23 @@ +import { html } from 'lit' +import type { FieldWithValue } from '@tanstack/lit-form' + +export function textField(field: FieldWithValue, label: string) { + return html` +
    + + ${field.errors.map( + (error) => html``, + )} +
    + ` +} diff --git a/examples/lit/large-form/tsconfig.json b/examples/lit/large-form/tsconfig.json index 79af5f2334..8a907eef8b 100644 --- a/examples/lit/large-form/tsconfig.json +++ b/examples/lit/large-form/tsconfig.json @@ -6,19 +6,15 @@ "module": "ESNext", "lib": ["ES2020", "DOM", "DOM.Iterable"], "skipLibCheck": true, - - /* Bundler mode */ "moduleResolution": "Bundler", "allowImportingTsExtensions": true, - "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - - /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] }, "include": ["src"] } diff --git a/examples/lit/multi-step-wizard/.eslintrc.cjs b/examples/lit/multi-step-wizard/.eslintrc.cjs deleted file mode 100644 index cca134ce16..0000000000 --- a/examples/lit/multi-step-wizard/.eslintrc.cjs +++ /dev/null @@ -1,6 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = {} - -module.exports = config diff --git a/examples/lit/multi-step-wizard/.gitignore b/examples/lit/multi-step-wizard/.gitignore deleted file mode 100644 index 4673b022e5..0000000000 --- a/examples/lit/multi-step-wizard/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -pnpm-lock.yaml -yarn.lock -package-lock.json - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/examples/lit/multi-step-wizard/README.md b/examples/lit/multi-step-wizard/README.md index 1cf8892652..474ecbd9e0 100644 --- a/examples/lit/multi-step-wizard/README.md +++ b/examples/lit/multi-step-wizard/README.md @@ -1,6 +1,6 @@ -# Example +# Lit multi-step wizard example To run this example: -- `npm install` -- `npm run dev` +- `pnpm install` +- `pnpm dev` diff --git a/examples/lit/multi-step-wizard/index.html b/examples/lit/multi-step-wizard/index.html index 9aebc14df1..b298b98456 100644 --- a/examples/lit/multi-step-wizard/index.html +++ b/examples/lit/multi-step-wizard/index.html @@ -2,12 +2,11 @@ - - TanStack Form Lit Multi-Step Wizard Example - + TanStack Form Lit Multi-step Wizard Example - + + diff --git a/examples/lit/multi-step-wizard/package.json b/examples/lit/multi-step-wizard/package.json index d67bec0239..e93311eb9e 100644 --- a/examples/lit/multi-step-wizard/package.json +++ b/examples/lit/multi-step-wizard/package.json @@ -3,30 +3,18 @@ "private": true, "type": "module", "scripts": { - "dev": "vite --port=3001", + "dev": "vite --port=3407", "build": "vite build", "preview": "vite preview", "test:types": "tsc" }, "dependencies": { - "@tanstack/lit-form": "^1.25.3", - "@tanstack/lit-store": "^0.13.2", + "@tanstack/lit-form": "^2.0.0-alpha.3", "lit": "^3.3.1", - "zod": "^3.25.76" + "zod": "^4.4.3" }, "devDependencies": { - "vite": "^7.2.2" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/lit/multi-step-wizard/src/components/text-field.ts b/examples/lit/multi-step-wizard/src/components/text-field.ts deleted file mode 100644 index 190a06bcdd..0000000000 --- a/examples/lit/multi-step-wizard/src/components/text-field.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { LitElement, html, nothing } from 'lit' -import { customElement, property } from 'lit/decorators.js' -import { repeat } from 'lit/directives/repeat.js' -import { TanStackStoreSelector } from '@tanstack/lit-store' -import type { AnyFieldApi } from '@tanstack/lit-form' - -@customElement('text-field') -export class TextField extends LitElement { - @property({ attribute: false }) - field!: AnyFieldApi - - @property({ type: String }) - label = '' - - _selector = new TanStackStoreSelector(this, () => this.field?.store) - - // Render into light DOM so the surrounding form picks up the inputs naturally - protected createRenderRoot() { - return this - } - - render() { - const field = this.field - return html` -
    - - ${field.state.meta.isTouched && field.state.meta.errors.length - ? repeat( - field.state.meta.errors, - (_, idx) => idx, - (error: unknown) => { - const message = - error && typeof error === 'object' && 'message' in error - ? String((error as { message: unknown }).message) - : String(error) - return html`
    ${message}
    ` - }, - ) - : nothing} - ${field.state.meta.isValidating ? html`

    Validating...

    ` : nothing} -
    - ` - } -} - -declare global { - interface HTMLElementTagNameMap { - 'text-field': TextField - } -} diff --git a/examples/lit/multi-step-wizard/src/features/wizard/page.ts b/examples/lit/multi-step-wizard/src/features/wizard/page.ts deleted file mode 100644 index 2bd19029da..0000000000 --- a/examples/lit/multi-step-wizard/src/features/wizard/page.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { LitElement, html, nothing } from 'lit' -import { customElement, state } from 'lit/decorators.js' -import { TanStackFormController, revalidateLogic } from '@tanstack/lit-form' -import { z } from 'zod' -import { wizardFormOpts, step1Schema, step2Schema } from './shared-form.js' -import './step1-subform.js' -import './step2-subform.js' - -@customElement('wizard-page') -export class WizardPage extends LitElement { - @state() - private step = 0 - - form = new TanStackFormController(this, { - ...wizardFormOpts, - validationLogic: revalidateLogic(), - validators: { - // onDynamic is only used when `form.handleSubmit` is called itself. - // When the form group's `handleSubmit` is called, it will only validate - // the current step's schema. This means that this schema will not be - // called when the user submits the form group, but instead when they - // submit the entire form. - onDynamic: z.object({ - step1: step1Schema, - step2: step2Schema, - }), - }, - onSubmit: ({ value }) => { - alert(`Form submitted: ${JSON.stringify(value)}`) - }, - }) - - protected createRenderRoot() { - return this - } - - private setStep = (step: number) => { - this.step = step - } - - render() { - return html` - ${this.step === 0 - ? html`` - : nothing} - ${this.step === 1 - ? html`` - : nothing} - ` - } -} - -declare global { - interface HTMLElementTagNameMap { - 'wizard-page': WizardPage - } -} diff --git a/examples/lit/multi-step-wizard/src/features/wizard/shared-form.ts b/examples/lit/multi-step-wizard/src/features/wizard/shared-form.ts deleted file mode 100644 index d07e1008d4..0000000000 --- a/examples/lit/multi-step-wizard/src/features/wizard/shared-form.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { formOptions } from '@tanstack/lit-form' -import { z } from 'zod' - -export const step1Schema = z.object({ - name: z.string().min(2, 'Name must be at least 2 characters'), -}) - -export const step2Schema = z.object({ - name: z.string().min(3, 'Name must be at least 3 characters'), -}) - -export const wizardFormOpts = formOptions({ - defaultValues: { - step1: { - name: '', - }, - step2: { - name: '', - }, - }, -}) diff --git a/examples/lit/multi-step-wizard/src/features/wizard/step1-subform.ts b/examples/lit/multi-step-wizard/src/features/wizard/step1-subform.ts deleted file mode 100644 index b1a11d5339..0000000000 --- a/examples/lit/multi-step-wizard/src/features/wizard/step1-subform.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { LitElement, html } from 'lit' -import { customElement, property } from 'lit/decorators.js' -import { TanStackStoreSelector } from '@tanstack/lit-store' -import { getFormType } from '@tanstack/lit-form' -import { wizardFormOpts, step1Schema } from './shared-form.js' -import '../../components/text-field.js' - -const formType = getFormType(wizardFormOpts) - -@customElement('step1-form') -export class Step1Form extends LitElement { - @property({ attribute: false }) - form!: typeof formType - - @property({ type: Number }) - step = 0 - - @property({ attribute: false }) - setStep: (step: number) => void = () => {} - - _selector = new TanStackStoreSelector(this, () => this.form?.api.store) - - protected createRenderRoot() { - return this - } - - render() { - return this.form.group( - { - name: 'step1', - validators: { - onDynamic: step1Schema, - }, - onGroupSubmit: () => { - this.setStep(this.step + 1) - }, - onGroupSubmitInvalid: () => { - // Just like a form, you can also handle invalid submits at the group - // level, which is useful for multi-step wizards to prevent going to - // the next step if the current step is invalid. - }, - }, - (formGroup) => html` -
    { - e.preventDefault() - e.stopPropagation() - formGroup.handleSubmit() - }} - > - ${this.form.field( - { name: 'step1.name' }, - (field) => - html``, - )} - - - -
    ${JSON.stringify(formGroup.state.meta.errorMap, null, 2)}
    -
    - `, - ) - } -} - -declare global { - interface HTMLElementTagNameMap { - 'step1-form': Step1Form - } -} diff --git a/examples/lit/multi-step-wizard/src/features/wizard/step2-subform.ts b/examples/lit/multi-step-wizard/src/features/wizard/step2-subform.ts deleted file mode 100644 index f6b2dd5085..0000000000 --- a/examples/lit/multi-step-wizard/src/features/wizard/step2-subform.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { LitElement, html } from 'lit' -import { customElement, property } from 'lit/decorators.js' -import { TanStackStoreSelector } from '@tanstack/lit-store' -import { getFormType } from '@tanstack/lit-form' -import { wizardFormOpts, step2Schema } from './shared-form.js' -import '../../components/text-field.js' - -const formType = getFormType(wizardFormOpts) - -@customElement('step2-form') -export class Step2Form extends LitElement { - @property({ attribute: false }) - form!: typeof formType - - @property({ type: Number }) - step = 1 - - @property({ attribute: false }) - setStep: (step: number) => void = () => {} - - _selector = new TanStackStoreSelector(this, () => this.form?.api.store) - - protected createRenderRoot() { - return this - } - - render() { - return this.form.group( - { - name: 'step2', - validators: { - onDynamic: step2Schema, - }, - onGroupSubmit: () => { - this.form.api.handleSubmit() - }, - }, - (formGroup) => html` -
    { - e.preventDefault() - e.stopPropagation() - formGroup.handleSubmit() - }} - > - ${this.form.field( - { name: 'step2.name' }, - (field) => - html``, - )} - - - -
    - `, - ) - } -} - -declare global { - interface HTMLElementTagNameMap { - 'step2-form': Step2Form - } -} diff --git a/examples/lit/multi-step-wizard/src/index.ts b/examples/lit/multi-step-wizard/src/index.ts index b76fca9f35..347b926965 100644 --- a/examples/lit/multi-step-wizard/src/index.ts +++ b/examples/lit/multi-step-wizard/src/index.ts @@ -1 +1,106 @@ -import './features/wizard/page.js' +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' +import { TanStackFormController } from '@tanstack/lit-form' +import { + step1Schema, + step2Schema, + stepValidator, + wizardFormOptions, +} from './shared-form' +import { textField } from './text-field' +import './styles.css' + +@customElement('tanstack-form-wizard') +export class TanStackFormWizard extends LitElement { + private step = 0 + private form = new TanStackFormController(this, { + ...wizardFormOptions, + onSubmit: ({ value }) => { + alert(`Form submitted: ${JSON.stringify(value)}`) + }, + }) + + protected createRenderRoot() { + return this + } + + render() { + return html` +

    Multi-step Wizard

    + ${this.step === 0 ? this.renderStepOne() : this.renderStepTwo()} + ` + } + + private renderStepOne() { + return this.form.formGroup( + { + name: 'step1', + validators: [stepValidator(step1Schema)], + onSubmit: () => { + this.step = 1 + this.requestUpdate() + }, + }, + (group) => html` +
    { + event.preventDefault() + event.stopPropagation() + void group.handleSubmit() + }} + > + ${group.field({ name: 'name' }, (field) => + textField(field, 'Step 1 Name'), + )} + ${this.submitButton('Next')} +
    + `, + ) + } + + private renderStepTwo() { + return this.form.formGroup( + { + name: 'step2', + validators: [stepValidator(step2Schema)], + onSubmit: () => { + void this.form.api.handleSubmit() + }, + }, + (group) => html` +
    { + event.preventDefault() + event.stopPropagation() + void group.handleSubmit() + }} + > + ${group.field({ name: 'name' }, (field) => + textField(field, 'Step 2 Name'), + )} +
    + + ${this.submitButton('Submit')} +
    +
    + `, + ) + } + + private submitButton(label: string) { + return this.form.subscribe( + (state) => state.isSubmitting, + (isSubmitting) => html` + + `, + ) + } +} diff --git a/examples/lit/multi-step-wizard/src/shared-form.ts b/examples/lit/multi-step-wizard/src/shared-form.ts new file mode 100644 index 0000000000..9f2f8ab2bd --- /dev/null +++ b/examples/lit/multi-step-wizard/src/shared-form.ts @@ -0,0 +1,39 @@ +import { createValidator, formOptions } from '@tanstack/lit-form' +import { z } from 'zod' + +export const step1Schema = z.object({ + name: z.string().min(2, 'Name must be at least 2 characters'), +}) + +export const step2Schema = z.object({ + name: z.string().min(3, 'Name must be at least 3 characters'), +}) + +export const stepValidator = createValidator({ + triggers: [ + { + trigger: 'change', + when: ({ groupApi, formApi }) => { + const attempts = + groupApi?.state.submissionAttempts ?? formApi.state.submissionAttempts + return attempts > 0 + }, + }, + ], +}) + +export const wizardFormOptions = formOptions({ + defaultValues: { + step1: { name: '' }, + step2: { name: '' }, + }, + validators: [ + { + run: z.object({ + step1: step1Schema, + step2: step2Schema, + }), + triggers: [], + }, + ], +}) diff --git a/examples/lit/multi-step-wizard/src/styles.css b/examples/lit/multi-step-wizard/src/styles.css new file mode 100644 index 0000000000..e5470e2350 --- /dev/null +++ b/examples/lit/multi-step-wizard/src/styles.css @@ -0,0 +1,27 @@ +#root { + display: block; + max-width: 32rem; + margin: 0 auto; + font-family: system-ui, sans-serif; +} + +#root form, +#root label { + display: grid; + gap: 0.75rem; +} + +#root input, +#root button { + font: inherit; + padding: 0.55rem 0.7rem; +} + +#root .actions { + display: flex; + gap: 0.75rem; +} + +#root small { + color: #b42318; +} diff --git a/examples/lit/multi-step-wizard/src/text-field.ts b/examples/lit/multi-step-wizard/src/text-field.ts new file mode 100644 index 0000000000..e8e40af555 --- /dev/null +++ b/examples/lit/multi-step-wizard/src/text-field.ts @@ -0,0 +1,21 @@ +import { html } from 'lit' +import type { FieldWithValue } from '@tanstack/lit-form' + +export function textField(field: FieldWithValue, label: string) { + return html` + + ` +} diff --git a/examples/lit/multi-step-wizard/tsconfig.json b/examples/lit/multi-step-wizard/tsconfig.json index 79af5f2334..8a907eef8b 100644 --- a/examples/lit/multi-step-wizard/tsconfig.json +++ b/examples/lit/multi-step-wizard/tsconfig.json @@ -6,19 +6,15 @@ "module": "ESNext", "lib": ["ES2020", "DOM", "DOM.Iterable"], "skipLibCheck": true, - - /* Bundler mode */ "moduleResolution": "Bundler", "allowImportingTsExtensions": true, - "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - - /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] }, "include": ["src"] } diff --git a/examples/lit/query-integration/README.md b/examples/lit/query-integration/README.md new file mode 100644 index 0000000000..1d91a24bef --- /dev/null +++ b/examples/lit/query-integration/README.md @@ -0,0 +1,6 @@ +# Lit query integration example + +To run this example: + +- `pnpm install` +- `pnpm dev` diff --git a/examples/lit/query-integration/index.html b/examples/lit/query-integration/index.html new file mode 100644 index 0000000000..eedc2fbae4 --- /dev/null +++ b/examples/lit/query-integration/index.html @@ -0,0 +1,12 @@ + + + + + + TanStack Form Lit Query Integration Example + + + + + + diff --git a/examples/lit/query-integration/package.json b/examples/lit/query-integration/package.json new file mode 100644 index 0000000000..12f03b113f --- /dev/null +++ b/examples/lit/query-integration/package.json @@ -0,0 +1,20 @@ +{ + "name": "@tanstack/form-example-lit-query-integration", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3408", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/lit-form": "^2.0.0-alpha.3", + "@tanstack/query-core": "^5.89.0", + "lit": "^3.3.1" + }, + "devDependencies": { + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/lit/query-integration/src/index.ts b/examples/lit/query-integration/src/index.ts new file mode 100644 index 0000000000..8600559b5a --- /dev/null +++ b/examples/lit/query-integration/src/index.ts @@ -0,0 +1,168 @@ +import { LitElement, html, nothing } from 'lit' +import { customElement } from 'lit/decorators.js' +import { + MutationObserver, + QueryClient, + QueryObserver, + keepPreviousData, +} from '@tanstack/query-core' +import { TanStackFormController, formOptions } from '@tanstack/lit-form' +import { db, sleep } from './mock-db' +import type { AnyFieldApi } from '@tanstack/lit-form' +import type { QueryObserverResult } from '@tanstack/query-core' +import type { StoredUser } from './mock-db' + +const emptyUser: StoredUser = { + firstName: '', + lastName: '', +} + +function fieldInfo(field: AnyFieldApi) { + return html` + ${ + field.meta.isInvalid + ? html` + ${field.errors.map((error) => error.message).join(', ')} + ` + : nothing + } + ${field.meta.isValidating ? 'Validating...' : nothing} + ` +} + +@customElement('tanstack-query-form') +export class TanStackQueryForm extends LitElement { + private queryClient = new QueryClient() + private userQuery = new QueryObserver(this.queryClient, { + queryKey: ['data'], + queryFn: () => db.getData(), + placeholderData: keepPreviousData, + }) + private userResult: QueryObserverResult = + this.userQuery.getCurrentResult() + private unsubscribeQuery?: () => void + private currentDefaults = emptyUser + + private saveUser = new MutationObserver(this.queryClient, { + mutationFn: (value: StoredUser) => db.saveUser(value), + onSuccess: async () => { + await this.userQuery.refetch() + }, + }) + + private form = new TanStackFormController(this, this.formOptions(emptyUser)) + + protected createRenderRoot() { + return this + } + + connectedCallback() { + super.connectedCallback() + this.unsubscribeQuery = this.userQuery.subscribe((result) => { + this.userResult = result + if (result.data && result.data !== this.currentDefaults) { + this.currentDefaults = result.data + this.form.update(this.formOptions(result.data)) + } + this.requestUpdate() + }) + } + + disconnectedCallback() { + this.unsubscribeQuery?.() + this.unsubscribeQuery = undefined + super.disconnectedCallback() + } + + private formOptions(defaultValues: StoredUser) { + return formOptions({ + defaultValues, + onSubmit: async ({ formApi, value }) => { + await this.saveUser.mutate(value) + formApi.reset(value) + }, + errorVisibility: ({ fieldState }) => fieldState.meta.isTouched, + }) + } + + render() { + if (this.userResult.isPending) return html`

    Loading...

    ` + + return html` +

    Query Integration Form Example

    +
    { + event.preventDefault() + event.stopPropagation() + void this.form.api.handleSubmit() + }} + > + ${this.form.field( + { + name: 'firstName', + validators: [ + { + run: ({ value }) => + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + triggers: ['change'], + }, + { + run: async ({ value }) => { + await sleep(1000) + return value.includes('error') + ? 'No "error" allowed in first name' + : undefined + }, + triggers: ['change'], + triggerDebounceMs: 500, + }, + ], + }, + (field) => this.renderField(field, 'First Name'), + )} + ${this.form.field({ name: 'lastName' }, (field) => + this.renderField(field, 'Last Name'), + )} + ${this.form.subscribe( + (state) => [state.canSubmit, state.isSubmitting] as const, + ([canSubmit, isSubmitting]) => html` + + + `, + )} +
    + ` + } + + private renderField(field: AnyFieldApi, label: string) { + return html` +
    + + field.handleBlur()} + @input=${(event: InputEvent) => + field.handleChange((event.currentTarget as HTMLInputElement).value)} + aria-invalid=${field.meta.isInvalid ? 'true' : 'false'} + /> + ${fieldInfo(field)} +
    + ` + } +} diff --git a/examples/lit/query-integration/src/mock-db.ts b/examples/lit/query-integration/src/mock-db.ts new file mode 100644 index 0000000000..63746ed138 --- /dev/null +++ b/examples/lit/query-integration/src/mock-db.ts @@ -0,0 +1,28 @@ +export async function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)) +} + +export interface StoredUser { + firstName: string + lastName: string +} + +class DB { + private data: StoredUser = { + firstName: 'FirstName', + lastName: 'LastName', + } + + async getData(): Promise { + await sleep(1000) + return { ...this.data } + } + + async saveUser(value: StoredUser) { + await sleep(1000) + this.data = value + return value + } +} + +export const db = new DB() diff --git a/examples/lit/query-integration/tsconfig.json b/examples/lit/query-integration/tsconfig.json new file mode 100644 index 0000000000..8a907eef8b --- /dev/null +++ b/examples/lit/query-integration/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2020", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "noEmit": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src"] +} diff --git a/examples/lit/simple/.eslintrc.cjs b/examples/lit/simple/.eslintrc.cjs deleted file mode 100644 index cca134ce16..0000000000 --- a/examples/lit/simple/.eslintrc.cjs +++ /dev/null @@ -1,6 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = {} - -module.exports = config diff --git a/examples/lit/simple/.gitignore b/examples/lit/simple/.gitignore deleted file mode 100644 index 4673b022e5..0000000000 --- a/examples/lit/simple/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -pnpm-lock.yaml -yarn.lock -package-lock.json - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/examples/lit/simple/README.md b/examples/lit/simple/README.md index 1cf8892652..e804be13a4 100644 --- a/examples/lit/simple/README.md +++ b/examples/lit/simple/README.md @@ -1,6 +1,6 @@ -# Example +# Lit simple example To run this example: -- `npm install` -- `npm run dev` +- `pnpm install` +- `pnpm dev` diff --git a/examples/lit/simple/index.html b/examples/lit/simple/index.html index 6bbd54321c..ba41327888 100644 --- a/examples/lit/simple/index.html +++ b/examples/lit/simple/index.html @@ -2,12 +2,11 @@ - - Vite + Lit + TS - + TanStack Form Lit Simple Example - + + diff --git a/examples/lit/simple/package.json b/examples/lit/simple/package.json index 5978081ba3..54f3d72987 100644 --- a/examples/lit/simple/package.json +++ b/examples/lit/simple/package.json @@ -3,28 +3,17 @@ "private": true, "type": "module", "scripts": { - "dev": "vite --port=3001", + "dev": "vite --port=3401", "build": "vite build", "preview": "vite preview", "test:types": "tsc" }, "dependencies": { - "@tanstack/lit-form": "^1.25.3", + "@tanstack/lit-form": "^2.0.0-alpha.3", "lit": "^3.3.1" }, "devDependencies": { - "vite": "^7.2.2" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/lit/simple/src/index.ts b/examples/lit/simple/src/index.ts index b81e8563a3..311afb66d9 100644 --- a/examples/lit/simple/src/index.ts +++ b/examples/lit/simple/src/index.ts @@ -1,114 +1,127 @@ import { LitElement, html, nothing } from 'lit' import { customElement } from 'lit/decorators.js' - import { TanStackFormController } from '@tanstack/lit-form' -import { repeat } from 'lit/directives/repeat.js' +import type { AnyFieldApi } from '@tanstack/lit-form' + +function fieldInfo(field: AnyFieldApi) { + return html` + ${ + field.meta.isTouched && field.meta.isInvalid + ? html` + ${field.errors.map((error) => error.message).join(', ')} + ` + : nothing + } + ${field.meta.isValidating ? 'Validating...' : nothing} + ` +} @customElement('tanstack-form-demo') export class TanStackFormDemo extends LitElement { - #form = new TanStackFormController(this, { + private form = new TanStackFormController(this, { defaultValues: { firstName: '', lastName: '', }, - onSubmit({ value }) { - // Do something with form data + onSubmit: async ({ value }) => { console.log(value) }, }) + protected createRenderRoot() { + return this + } + render() { return html` +

    Simple Form Example

    { - e.preventDefault() - e.stopPropagation() - this.#form.api.handleSubmit() + @submit=${(event: SubmitEvent) => { + event.preventDefault() + event.stopPropagation() + void this.form.api.handleSubmit() }} > - ${this.#form.field( +
    + ${this.form.field( { - name: `firstName`, - validators: { - onChange: ({ value }) => - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined, - onChangeAsyncDebounceMs: 500, - onChangeAsync: async ({ value }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return ( - value.includes('error') && - 'No "error" allowed in first name' - ) + name: 'firstName', + validators: [ + { + run: ({ value }) => + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + triggers: ['change'], }, - }, - }, - (field) => { - return html`
    - - - ${field.state.meta.isTouched && !field.state.meta.isValid - ? html`${repeat( - field.state.meta.errors, - (__, idx) => idx, - (error) => { - return html`
    ${error}
    ` - }, - )}` - : nothing} - ${field.state.meta.isValidating - ? html`

    Validating...

    ` - : nothing} -
    ` + { + run: async ({ value }) => { + await new Promise((resolve) => setTimeout(resolve, 1000)) + return value.includes('error') + ? 'No "error" allowed in first name' + : undefined + }, + triggers: ['change'], + triggerDebounceMs: 500, + }, + ], }, + (field) => html` + + field.handleBlur()} + @input=${(event: InputEvent) => + field.handleChange( + (event.currentTarget as HTMLInputElement).value, + )} + aria-invalid=${field.meta.isInvalid ? 'true' : 'false'} + /> + ${fieldInfo(field)} + `, )}
    - ${this.#form.field( - { - name: `lastName`, - }, - (field) => { - return html`
    - - -
    ` - }, + ${this.form.field( + { name: 'lastName' }, + (field) => html` + + field.handleBlur()} + @input=${(event: InputEvent) => + field.handleChange( + (event.currentTarget as HTMLInputElement).value, + )} + aria-invalid=${field.meta.isInvalid ? 'true' : 'false'} + /> + ${fieldInfo(field)} + `, )}
    - - - + ${this.form.subscribe( + (state) => [state.canSubmit, state.isSubmitting] as const, + ([canSubmit, isSubmitting]) => html` + + + `, + )}
    ` } diff --git a/examples/lit/simple/tsconfig.json b/examples/lit/simple/tsconfig.json index 79af5f2334..8a907eef8b 100644 --- a/examples/lit/simple/tsconfig.json +++ b/examples/lit/simple/tsconfig.json @@ -6,19 +6,15 @@ "module": "ESNext", "lib": ["ES2020", "DOM", "DOM.Iterable"], "skipLibCheck": true, - - /* Bundler mode */ "moduleResolution": "Bundler", "allowImportingTsExtensions": true, - "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - - /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] }, "include": ["src"] } diff --git a/examples/lit/standard-schema/.eslintrc.cjs b/examples/lit/standard-schema/.eslintrc.cjs deleted file mode 100644 index cca134ce16..0000000000 --- a/examples/lit/standard-schema/.eslintrc.cjs +++ /dev/null @@ -1,6 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = {} - -module.exports = config diff --git a/examples/lit/standard-schema/.gitignore b/examples/lit/standard-schema/.gitignore deleted file mode 100644 index 4673b022e5..0000000000 --- a/examples/lit/standard-schema/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -pnpm-lock.yaml -yarn.lock -package-lock.json - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/examples/lit/standard-schema/README.md b/examples/lit/standard-schema/README.md index 1cf8892652..8d28a4e3ff 100644 --- a/examples/lit/standard-schema/README.md +++ b/examples/lit/standard-schema/README.md @@ -1,6 +1,6 @@ -# Example +# Lit standard schema example To run this example: -- `npm install` -- `npm run dev` +- `pnpm install` +- `pnpm dev` diff --git a/examples/lit/standard-schema/index.html b/examples/lit/standard-schema/index.html index 6bbd54321c..ebea659614 100644 --- a/examples/lit/standard-schema/index.html +++ b/examples/lit/standard-schema/index.html @@ -2,12 +2,11 @@ - - Vite + Lit + TS - + TanStack Form Lit Standard Schema Example - + + diff --git a/examples/lit/standard-schema/package.json b/examples/lit/standard-schema/package.json index 3ab901ae3b..1dfaed4cd1 100644 --- a/examples/lit/standard-schema/package.json +++ b/examples/lit/standard-schema/package.json @@ -3,32 +3,21 @@ "private": true, "type": "module", "scripts": { - "dev": "vite --port=3001", + "dev": "vite --port=3409", "build": "vite build", "preview": "vite preview", "test:types": "tsc" }, "dependencies": { - "@tanstack/lit-form": "^1.25.3", + "@tanstack/lit-form": "^2.0.0-alpha.3", "arktype": "^2.1.22", "effect": "^3.17.14", "lit": "^3.3.1", "valibot": "^1.1.0", - "zod": "^3.25.76" + "zod": "^4.4.3" }, "devDependencies": { - "vite": "^7.2.2" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/lit/standard-schema/src/index.ts b/examples/lit/standard-schema/src/index.ts index 160a027bb4..96fbb0bd7f 100644 --- a/examples/lit/standard-schema/src/index.ts +++ b/examples/lit/standard-schema/src/index.ts @@ -1,13 +1,11 @@ import { LitElement, html, nothing } from 'lit' import { customElement } from 'lit/decorators.js' - -import { TanStackFormController } from '@tanstack/lit-form' -import { repeat } from 'lit/directives/repeat.js' - import { type } from 'arktype' +import { Schema as S } from 'effect' import * as v from 'valibot' import { z } from 'zod' -import { Schema as S } from 'effect' +import { TanStackFormController } from '@tanstack/lit-form' +import type { AnyFieldApi } from '@tanstack/lit-form' const ZodSchema = z.object({ firstName: z @@ -51,119 +49,90 @@ const EffectSchema = S.standardSchemaV1( }), ) -@customElement('tanstack-form-demo') -export class TanStackFormDemo extends LitElement { - #form = new TanStackFormController(this, { +// Swap the validator below to any of these standard-schema implementations. +void ValibotSchema +void ArkTypeSchema +void EffectSchema + +function fieldInfo(field: AnyFieldApi) { + return html` + ${ + field.meta.isTouched && field.meta.isInvalid + ? html` + ${field.errors.map((error) => error.message).join(', ')} + ` + : nothing + } + ${field.meta.isValidating ? 'Validating...' : nothing} + ` +} + +@customElement('tanstack-schema-form') +export class TanStackSchemaForm extends LitElement { + private form = new TanStackFormController(this, { defaultValues: { firstName: '', lastName: '', }, - validators: { - // DEMO: You can switch between schemas seamlessly - onChange: ZodSchema, - // onChange: ValibotSchema, - // onChange: ArkTypeSchema, - // onChange: EffectSchema, - }, - onSubmit({ value }) { - // Do something with form data + validators: [ + { + run: ZodSchema, + triggers: ['change'], + }, + ], + onSubmit: async ({ value }) => { console.log(value) }, }) + protected createRenderRoot() { + return this + } + render() { return html` +

    Standard Schema Form Example

    { - e.preventDefault() - e.stopPropagation() - this.#form.api.handleSubmit() + @submit=${(event: SubmitEvent) => { + event.preventDefault() + event.stopPropagation() + void this.form.api.handleSubmit() }} > - ${this.#form.field( - { - name: `firstName`, - }, - (field) => { - return html`
    - - - ${field.state.meta.isTouched && !field.state.meta.isValid - ? html`${repeat( - field.state.meta.errors, - (__, idx) => idx, - (error) => { - return html`
    - ${error?.message} -
    ` - }, - )}` - : nothing} - ${field.state.meta.isValidating - ? html`

    Validating...

    ` - : nothing} -
    ` - }, - )} - -
    - ${this.#form.field( - { - name: `lastName`, - }, - (field) => { - return html`
    - - - ${field.state.meta.isTouched && !field.state.meta.isValid - ? html`${repeat( - field.state.meta.errors, - (__, idx) => idx, - (error) => { - return html`
    - ${error?.message} -
    ` - }, - )}` - : nothing} - ${field.state.meta.isValidating - ? html`

    Validating...

    ` - : nothing} -
    ` - }, - )} -
    - - - + ${this.renderStringField('firstName', 'First Name')} + ${this.renderStringField('lastName', 'Last Name')} + ${this.form.subscribe( + (state) => [state.canSubmit, state.isSubmitting] as const, + ([canSubmit, isSubmitting]) => html` + + `, + )}
    ` } + + private renderStringField(name: 'firstName' | 'lastName', label: string) { + return this.form.field( + { name }, + (field) => html` +
    + + field.handleBlur()} + @input=${(event: InputEvent) => + field.handleChange( + (event.currentTarget as HTMLInputElement).value, + )} + aria-invalid=${field.meta.isInvalid ? 'true' : 'false'} + /> + ${fieldInfo(field)} +
    + `, + ) + } } diff --git a/examples/lit/standard-schema/tsconfig.json b/examples/lit/standard-schema/tsconfig.json index 7650df3319..8a907eef8b 100644 --- a/examples/lit/standard-schema/tsconfig.json +++ b/examples/lit/standard-schema/tsconfig.json @@ -6,19 +6,15 @@ "module": "ESNext", "lib": ["ES2020", "DOM", "DOM.Iterable"], "skipLibCheck": true, - - /* Bundler mode */ "moduleResolution": "Bundler", "allowImportingTsExtensions": true, - "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - - /* Linting */ "strict": true, - "noUnusedLocals": false, + "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] }, "include": ["src"] } diff --git a/examples/lit/ui-libraries/.eslintrc.cjs b/examples/lit/ui-libraries/.eslintrc.cjs deleted file mode 100644 index cca134ce16..0000000000 --- a/examples/lit/ui-libraries/.eslintrc.cjs +++ /dev/null @@ -1,6 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = {} - -module.exports = config diff --git a/examples/lit/ui-libraries/.gitignore b/examples/lit/ui-libraries/.gitignore deleted file mode 100644 index 4673b022e5..0000000000 --- a/examples/lit/ui-libraries/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -pnpm-lock.yaml -yarn.lock -package-lock.json - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/examples/lit/ui-libraries/README.md b/examples/lit/ui-libraries/README.md deleted file mode 100644 index 1cf8892652..0000000000 --- a/examples/lit/ui-libraries/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Example - -To run this example: - -- `npm install` -- `npm run dev` diff --git a/examples/lit/ui-libraries/index.html b/examples/lit/ui-libraries/index.html deleted file mode 100644 index 6bbd54321c..0000000000 --- a/examples/lit/ui-libraries/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite + Lit + TS - - - - - - diff --git a/examples/lit/ui-libraries/package.json b/examples/lit/ui-libraries/package.json deleted file mode 100644 index 8372c6c057..0000000000 --- a/examples/lit/ui-libraries/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "@tanstack/form-example-lit-ui-libraries", - "private": true, - "type": "module", - "scripts": { - "dev": "vite --port=3001", - "build": "vite build", - "preview": "vite preview", - "test:types": "tsc" - }, - "dependencies": { - "@material/web": "^2.4.0", - "@tanstack/lit-form": "^1.25.3", - "lit": "^3.3.1" - }, - "devDependencies": { - "vite": "^7.2.2" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/examples/lit/ui-libraries/src/index.ts b/examples/lit/ui-libraries/src/index.ts deleted file mode 100644 index 6e1448765a..0000000000 --- a/examples/lit/ui-libraries/src/index.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' -import '@material/web/textfield/filled-text-field.js' -import '@material/web/checkbox/checkbox.js' -import '@material/web/select/filled-select.js' -import '@material/web/select/select-option.js' -import '@material/web/button/filled-button.js' -import '@material/web/button/outlined-button.js' - -import { TanStackFormController } from '@tanstack/lit-form' -import { repeat } from 'lit/directives/repeat.js' -import { styles } from './styles.js' - -interface Employee { - firstName: string - lastName: string - employed: boolean - jobTitle?: string -} - -@customElement('tanstack-form-demo') -export class TanStackFormDemo extends LitElement { - static styles = styles - - #form = new TanStackFormController(this, { - defaultValues: { - employees: [] as Employee[], - }, - }) - - render() { - return html` -
    { - e.preventDefault() - }} - > -

    TanStack Form - Lit Demo

    - ${this.#form.field( - { - name: 'employees', - defaultValue: [], - }, - (employeesField) => { - return html`${repeat( - employeesField.state.value, - (_, index) => index, - (_, index) => { - return html` - ${this.#form.field( - { - name: `employees[${index}].firstName`, - validators: { - onChange: ({ value }: { value: string }) => { - return value && value.length < 3 - ? 'Not long enough' - : undefined - }, - }, - }, - (field) => { - return html`
    - - -
    ` - }, - )} - ${this.#form.field( - { name: `employees[${index}].lastName` }, - (lastNameField) => { - return html`
    - - -
    ` - }, - )} - ${this.#form.field( - { name: `employees[${index}].employed` }, - (employedField) => { - return html`
    - - -
    - ${employedField.state.value - ? this.#form.field( - { - name: `employees[${index}].jobTitle`, - defaultValue: '', - validators: { - onChange: ({ value }) => { - return value?.length === 0 - ? 'Needs to have a job here' - : null - }, - }, - }, - (jobTitleField) => { - return html`
    - - -
    ` - }, - ) - : ''} ` - }, - )} - ` - }, - )} - -
    - { - employeesField.pushValue({ - firstName: '', - lastName: '', - employed: false, - }) - }} - > - Add employee - -
    ` - }, - )} - -
    - - ${this.#form.api.state.isSubmitting ? html` Submitting` : 'Submit'} - - { - this.#form.api.reset() - }} - > - Reset - -
    -
    -
    ${JSON.stringify(this.#form.api.state, null, 2)}
    - ` - } -} diff --git a/examples/lit/ui-libraries/src/styles.ts b/examples/lit/ui-libraries/src/styles.ts deleted file mode 100644 index a3e7be648c..0000000000 --- a/examples/lit/ui-libraries/src/styles.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { css } from 'lit' - -export const styles = css` - form { - max-width: 600px; - margin: 10px auto; - border: 1px solid #ccc; - border-radius: 3px; - box-shadow: 1 1 2px rgba(0, 0, 0, 0.3); - padding: 10px; - display: flex; - flex-flow: column nowrap; - } - - h1 { - text-align: center; - color: #333; - } - - p { - margin: 10px auto; - line-height: 1.2em; - max-width: 500px; - } - - div { - margin: 10px; - display: flex; - flex-flow: row nowrap; - justify-content: center; - } - - label { - width: 120px; - text-align: right; - margin-right: 15px; - padding: 5px; - } - - input { - padding: 5px; - flex: 1; - border: 1px solid #ccc; - border-radius: 3px; - } - - select { - flex: 1; - height: 24px; - border: 1px solid #ccc; - border-radius: 3px; - } - - span { - color: #600; - font-weight: bold; - margin: 0 0 0 10px; - line-height: 26px; - } - - button { - width: 80px; - display: block; - margin: 0 auto; - } -` diff --git a/examples/lit/ui-libraries/tsconfig.json b/examples/lit/ui-libraries/tsconfig.json deleted file mode 100644 index 79af5f2334..0000000000 --- a/examples/lit/ui-libraries/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "experimentalDecorators": true, - "useDefineForClassFields": false, - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "Bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/examples/preact/array/.gitignore b/examples/preact/array/.gitignore new file mode 100644 index 0000000000..d600b6c76d --- /dev/null +++ b/examples/preact/array/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + diff --git a/examples/preact/array/README.md b/examples/preact/array/README.md new file mode 100644 index 0000000000..93f18812e1 --- /dev/null +++ b/examples/preact/array/README.md @@ -0,0 +1,6 @@ +# Example + +To run this example: + +- `pnpm install` +- `pnpm dev` diff --git a/examples/preact/array/index.html b/examples/preact/array/index.html new file mode 100644 index 0000000000..8e094869df --- /dev/null +++ b/examples/preact/array/index.html @@ -0,0 +1,12 @@ + + + + + + TanStack Form Preact Array Example + + +
    + + + diff --git a/examples/preact/array/package.json b/examples/preact/array/package.json new file mode 100644 index 0000000000..6512d74850 --- /dev/null +++ b/examples/preact/array/package.json @@ -0,0 +1,20 @@ +{ + "name": "@tanstack/form-example-preact-array", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3302", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/preact-form": "^2.0.0-alpha.3", + "preact": "^10.26.4" + }, + "devDependencies": { + "@preact/preset-vite": "^2.10.2", + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/preact/array/src/index.css b/examples/preact/array/src/index.css new file mode 100644 index 0000000000..12eead9401 --- /dev/null +++ b/examples/preact/array/src/index.css @@ -0,0 +1,76 @@ +#root { + max-width: 100%; + margin: 0 5rem; + text-align: center; + border-inline: 1px solid var(--border); + min-height: 100svh; + box-sizing: border-box; + font-family: system-ui, 'Segoe UI', Roboto, sans-serif; + --color-text: #08060d; +} + +#root button { + font-size: 16px; + padding: 5px 10px; + border-radius: 5px; + color: var(--color-text); + background: #f4f3ec; + border: 2px solid transparent; + border-top-color: transparent; + border-right-color: transparent; + border-bottom-color: transparent; + border-left-color: transparent; + transition: border-color 0.3s; + margin-inline: 0.5rem; + margin-top: 0.5rem; + font-family: ui-monospace, Consolas, monospace; + display: inline-flex; + cursor: pointer; +} + +#root button:hover { + border: 2px solid rgba(8, 6, 13, 0.5); +} + +#root ul { + list-style: none; + margin: 0; + padding: 2rem 0 0 0; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(8em, 1fr)); + gap: 0.75rem; +} + +#root li { + min-width: 0; +} + +#root li label { + display: flex; + flex-direction: column; + gap: 0.35rem; + font-size: 0.95rem; + font-weight: 500; + color: var(--color-text); +} + +#root input { + width: 100%; + box-sizing: border-box; + min-width: 0; + padding: 0.55rem 0.7rem; + border: 1px solid #ccc; + border-radius: 0.4rem; + font-size: 1rem; +} + +#root #itemsAmount { + max-width: 10rem; + text-align: end; +} + +#root li input:focus { + outline: none; + border-color: #646cff; + box-shadow: 0 0 0 2px rgba(100, 108, 255, 0.2); +} diff --git a/examples/preact/array/src/index.tsx b/examples/preact/array/src/index.tsx new file mode 100644 index 0000000000..85311d1563 --- /dev/null +++ b/examples/preact/array/src/index.tsx @@ -0,0 +1,117 @@ +import { useForm } from '@tanstack/preact-form' +import { render } from 'preact' +import './index.css' +import { useMemo, useRef, useState } from 'preact/hooks' + +function ArrayForm({ items }: { items: Array }) { + const form = useForm({ + defaultValues: { + items, + }, + onSubmit: ({ value }) => { + // Do something with form data + console.log(value) + alert(`Submitted ${value.items.length} items.`) + }, + }) + + return ( + <> + state.values.items.length}> + {(amount) =>

    Item amount: {amount.toLocaleString()}

    } +
    +
    { + e.preventDefault() + e.stopPropagation() + form.handleSubmit() + }} + > + + + {/** + * Usually, this array would rerender whenever an item was changed. + * To reduce rerenders, use the ArrayField component! + */} + + {(array) => ( +
      + {array.value.map((_, i) => ( + + {(field) => ( +
    • + +
    • + )} +
      + ))} +
    + )} +
    +
    + + ) +} + +function App() { + const [itemAmount, setItemAmount] = useState(50) + const inputRef = useRef(null) + + const items = useMemo( + () => Array.from({ length: itemAmount }, () => ''), + [itemAmount], + ) + + function updateItems() { + if (inputRef.current && !Number.isNaN(inputRef.current.valueAsNumber)) { + setItemAmount( + Math.min(10_000, Math.max(0, inputRef.current.valueAsNumber)), + ) + } + } + return ( +
    +

    Arrays in Form Example

    + +
    + + + +
    + + +
    + ) +} + +render(, document.getElementById('root')!) diff --git a/examples/preact/array/tsconfig.json b/examples/preact/array/tsconfig.json new file mode 100644 index 0000000000..b7ba9a1a3c --- /dev/null +++ b/examples/preact/array/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/preact/array/vite.config.ts b/examples/preact/array/vite.config.ts new file mode 100644 index 0000000000..bfe110c059 --- /dev/null +++ b/examples/preact/array/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' + +export default defineConfig({ + plugins: [preact()], +}) diff --git a/examples/preact/basic-splitting-form/.gitignore b/examples/preact/basic-splitting-form/.gitignore new file mode 100644 index 0000000000..d600b6c76d --- /dev/null +++ b/examples/preact/basic-splitting-form/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + diff --git a/examples/preact/basic-splitting-form/README.md b/examples/preact/basic-splitting-form/README.md new file mode 100644 index 0000000000..93f18812e1 --- /dev/null +++ b/examples/preact/basic-splitting-form/README.md @@ -0,0 +1,6 @@ +# Example + +To run this example: + +- `pnpm install` +- `pnpm dev` diff --git a/examples/preact/basic-splitting-form/index.html b/examples/preact/basic-splitting-form/index.html new file mode 100644 index 0000000000..d7d462bbab --- /dev/null +++ b/examples/preact/basic-splitting-form/index.html @@ -0,0 +1,12 @@ + + + + + + TanStack Form Preact Basic Splitting Form Example + + +
    + + + diff --git a/examples/preact/basic-splitting-form/package.json b/examples/preact/basic-splitting-form/package.json new file mode 100644 index 0000000000..3a7c6f4c79 --- /dev/null +++ b/examples/preact/basic-splitting-form/package.json @@ -0,0 +1,20 @@ +{ + "name": "@tanstack/form-example-preact-basic-splitting-form", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3304", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/preact-form": "^2.0.0-alpha.3", + "preact": "^10.26.4" + }, + "devDependencies": { + "@preact/preset-vite": "^2.10.2", + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/preact/basic-splitting-form/src/FieldError.tsx b/examples/preact/basic-splitting-form/src/FieldError.tsx new file mode 100644 index 0000000000..f31f6cdab9 --- /dev/null +++ b/examples/preact/basic-splitting-form/src/FieldError.tsx @@ -0,0 +1,13 @@ +import type { AnyFieldApi } from '@tanstack/preact-form' + +interface FieldInfoProps { + field: AnyFieldApi +} + +export function FieldError({ field }: FieldInfoProps) { + return ( + + {field.errors.map((e) => e.message).join('\n')} + + ) +} diff --git a/examples/preact/basic-splitting-form/src/FormSection.tsx b/examples/preact/basic-splitting-form/src/FormSection.tsx new file mode 100644 index 0000000000..a16df3a182 --- /dev/null +++ b/examples/preact/basic-splitting-form/src/FormSection.tsx @@ -0,0 +1,22 @@ +import { StringField } from './StringField' +import type { PreactFormType } from '@tanstack/preact-form' +import type { sharedFormOptions } from './sharedForm' + +interface FormSectionProps { + form: PreactFormType +} + +export function FormSection(props: FormSectionProps) { + const { form } = props + + return ( + <> + + {(field) => } + + + {(field) => } + + + ) +} diff --git a/examples/preact/basic-splitting-form/src/FormSubmitButton.tsx b/examples/preact/basic-splitting-form/src/FormSubmitButton.tsx new file mode 100644 index 0000000000..a7e1b6d9f0 --- /dev/null +++ b/examples/preact/basic-splitting-form/src/FormSubmitButton.tsx @@ -0,0 +1,18 @@ +import type { AnyPreactFormApi } from '@tanstack/preact-form' + +interface FormSubmitButtonProps { + form: AnyPreactFormApi +} + +export function FormSubmitButton(props: FormSubmitButtonProps) { + const { form } = props + return ( + [state.canSubmit, state.isSubmitting]}> + {([canSubmit, isSubmitting]) => ( + + )} + + ) +} diff --git a/examples/preact/basic-splitting-form/src/StringField.tsx b/examples/preact/basic-splitting-form/src/StringField.tsx new file mode 100644 index 0000000000..ccf91cd256 --- /dev/null +++ b/examples/preact/basic-splitting-form/src/StringField.tsx @@ -0,0 +1,25 @@ +import { FieldError } from './FieldError' +import type { FieldWithValue } from '@tanstack/preact-form' + +interface StringFieldProps { + field: FieldWithValue +} + +export function StringField(props: StringFieldProps) { + const { field } = props + + return ( + + ) +} diff --git a/examples/preact/basic-splitting-form/src/index.css b/examples/preact/basic-splitting-form/src/index.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/preact/basic-splitting-form/src/index.tsx b/examples/preact/basic-splitting-form/src/index.tsx new file mode 100644 index 0000000000..9416f8c4d4 --- /dev/null +++ b/examples/preact/basic-splitting-form/src/index.tsx @@ -0,0 +1,53 @@ +import { useForm } from '@tanstack/preact-form' +import { render } from 'preact' +import './index.css' +import { StringField } from './StringField' +import { sharedFormOptions } from './sharedForm' +import { FormSection } from './FormSection' +import { FormSubmitButton } from './FormSubmitButton' + +function App() { + const form = useForm({ + ...sharedFormOptions, + onSubmit: ({ value }) => { + // Do something with form data + console.log(value) + }, + }) + + return ( +
    +

    Simple Form Example

    +
    { + e.preventDefault() + e.stopPropagation() + form.handleSubmit() + }} + > + + {(field) => } + + + {(field) => } + + + + + + + )} + + + + {(array) => + array.value.map((range, i) => ( + + )) + } + + + ) +} + +function App() { + return ( +
    +

    Field Group example

    + +
    +

    Price Filter Form

    + +
    +
    +

    Age Range Form

    + +
    +
    +

    Swappable Date Ranges Form

    + +
    +
    + ) +} + +render(, document.getElementById('root')!) diff --git a/examples/preact/field-groups/tsconfig.json b/examples/preact/field-groups/tsconfig.json new file mode 100644 index 0000000000..b7ba9a1a3c --- /dev/null +++ b/examples/preact/field-groups/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/preact/field-groups/vite.config.ts b/examples/preact/field-groups/vite.config.ts new file mode 100644 index 0000000000..bfe110c059 --- /dev/null +++ b/examples/preact/field-groups/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' + +export default defineConfig({ + plugins: [preact()], +}) diff --git a/examples/preact/large-form/.gitignore b/examples/preact/large-form/.gitignore new file mode 100644 index 0000000000..d600b6c76d --- /dev/null +++ b/examples/preact/large-form/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + diff --git a/examples/preact/large-form/README.md b/examples/preact/large-form/README.md new file mode 100644 index 0000000000..93f18812e1 --- /dev/null +++ b/examples/preact/large-form/README.md @@ -0,0 +1,6 @@ +# Example + +To run this example: + +- `pnpm install` +- `pnpm dev` diff --git a/examples/preact/large-form/index.html b/examples/preact/large-form/index.html new file mode 100644 index 0000000000..0d906d5fc3 --- /dev/null +++ b/examples/preact/large-form/index.html @@ -0,0 +1,12 @@ + + + + + + TanStack Form Preact Large Form Example + + +
    + + + diff --git a/examples/preact/large-form/package.json b/examples/preact/large-form/package.json new file mode 100644 index 0000000000..4c244019a1 --- /dev/null +++ b/examples/preact/large-form/package.json @@ -0,0 +1,20 @@ +{ + "name": "@tanstack/form-example-preact-large-form", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3306", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/preact-form": "^2.0.0-alpha.3", + "preact": "^10.26.4" + }, + "devDependencies": { + "@preact/preset-vite": "^2.10.2", + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/preact/large-form/src/App.tsx b/examples/preact/large-form/src/App.tsx new file mode 100644 index 0000000000..5577e9525e --- /dev/null +++ b/examples/preact/large-form/src/App.tsx @@ -0,0 +1,10 @@ +import { Suspense } from 'preact/compat' +import { PeoplePage } from './features/people/page.tsx' + +export default function App() { + return ( + Loading...

    }> + +
    + ) +} diff --git a/examples/preact/large-form/src/components/text-fields.tsx b/examples/preact/large-form/src/components/text-fields.tsx new file mode 100644 index 0000000000..c9147ea694 --- /dev/null +++ b/examples/preact/large-form/src/components/text-fields.tsx @@ -0,0 +1,27 @@ +import type { FieldWithValue } from '@tanstack/preact-form' + +export default function TextField({ + field, + label, +}: { + field: FieldWithValue + label: string +}) { + return ( +
    + + {field.errors.map((error) => ( +
    + {error.message} +
    + ))} +
    + ) +} diff --git a/examples/preact/large-form/src/features/people/address-fields.tsx b/examples/preact/large-form/src/features/people/address-fields.tsx new file mode 100644 index 0000000000..af0d0285ab --- /dev/null +++ b/examples/preact/large-form/src/features/people/address-fields.tsx @@ -0,0 +1,34 @@ +import { peopleFormOpts } from './shared-form.tsx' +import type { PreactFormType } from '@tanstack/preact-form' + +interface AddressFieldsProps { + form: PreactFormType +} + +export function AddressFields({ form }: AddressFieldsProps) { + return ( +
    +

    Address

    + } + /> + } + /> + } + /> + } + /> + } + /> +
    + ) +} diff --git a/examples/preact/large-form/src/features/people/emergency-contact.tsx b/examples/preact/large-form/src/features/people/emergency-contact.tsx new file mode 100644 index 0000000000..4d110239f1 --- /dev/null +++ b/examples/preact/large-form/src/features/people/emergency-contact.tsx @@ -0,0 +1,30 @@ +import { defineAppFieldGroup } from '../../hooks/form' + +const fieldGroup = defineAppFieldGroup(({ strict }) => ({ + fullName: strict(), + phone: strict(), +})) + +function EmergencyContactFields({ + fields, +}: { + fields: typeof fieldGroup.fields +}) { + return ( + <> + } + /> + } + /> + + ) +} + +export const FieldGroupEmergencyContact = fieldGroup.bindComponent( + EmergencyContactFields, + 'fields', +) diff --git a/examples/preact/large-form/src/features/people/page.tsx b/examples/preact/large-form/src/features/people/page.tsx new file mode 100644 index 0000000000..3bf6e465ef --- /dev/null +++ b/examples/preact/large-form/src/features/people/page.tsx @@ -0,0 +1,49 @@ +import { useAppForm } from '../../hooks/form.tsx' +import { AddressFields } from './address-fields.tsx' +import { FieldGroupEmergencyContact } from './emergency-contact.tsx' +import { peopleFormOpts } from './shared-form.tsx' + +export const PeoplePage = () => { + const form = useAppForm({ + ...peopleFormOpts, + onSubmit: ({ value }) => { + alert(JSON.stringify(value, null, 2)) + }, + }) + + return ( + { + e.preventDefault() + form.handleSubmit() + }} + > +

    Personal Information

    + } + /> + } + /> + } + /> + +

    Emergency Contact

    + + + + + + + ) +} diff --git a/examples/preact/large-form/src/features/people/shared-form.tsx b/examples/preact/large-form/src/features/people/shared-form.tsx new file mode 100644 index 0000000000..18afb5ffaf --- /dev/null +++ b/examples/preact/large-form/src/features/people/shared-form.tsx @@ -0,0 +1,45 @@ +import { appFormOptions } from '../../hooks/form.tsx' + +export const peopleFormOpts = appFormOptions({ + defaultValues: { + fullName: '', + email: '', + phone: '', + address: { + line1: '', + line2: '', + city: '', + state: '', + zip: '', + }, + emergencyContact: { + fullName: '', + phone: '', + }, + }, + validators: [ + { + triggers: ['change'], + run: async ({ value, createErrorMap }) => { + const errors = createErrorMap() + + if (!value.fullName) { + errors.fields.fullName = 'Full name is required' + } + if (!value.phone) { + errors.fields.phone = 'Phone is required' + } + if (!value.emergencyContact.fullName) { + errors.fields['emergencyContact.fullName'] = + 'Emergency contact full name is required' + } + if (!value.emergencyContact.phone) { + errors.fields['emergencyContact.phone'] = + 'Emergency contact phone is required' + } + + return errors + }, + }, + ], +}) diff --git a/examples/preact/large-form/src/hooks/form.tsx b/examples/preact/large-form/src/hooks/form.tsx new file mode 100644 index 0000000000..05f7f71800 --- /dev/null +++ b/examples/preact/large-form/src/hooks/form.tsx @@ -0,0 +1,27 @@ +import { createFormHook, getFormHookHelpers } from '@tanstack/preact-form' +import TextField from '../components/text-fields.tsx' + +const { fieldComponent } = getFormHookHelpers() + +const AppTextField = fieldComponent.strict(TextField, 'field') + +function SubscribeButton({ label }: { label: string }) { + const form = useFormContext() + return ( + state.isSubmitting}> + {(isSubmitting) => } + + ) +} + +const { appFormOptions, defineAppFieldGroup, useAppForm, useFormContext } = + createFormHook({ + fieldComponents: { + TextField: AppTextField, + }, + formComponents: { + SubscribeButton, + }, + }) + +export { appFormOptions, defineAppFieldGroup, useAppForm } diff --git a/examples/preact/large-form/src/index.tsx b/examples/preact/large-form/src/index.tsx new file mode 100644 index 0000000000..ecf6c6bc3e --- /dev/null +++ b/examples/preact/large-form/src/index.tsx @@ -0,0 +1,7 @@ +import { render } from 'preact' + +import App from './App.tsx' + +const rootElement = document.getElementById('root')! + +render(, rootElement) diff --git a/examples/preact/large-form/tsconfig.json b/examples/preact/large-form/tsconfig.json new file mode 100644 index 0000000000..b7ba9a1a3c --- /dev/null +++ b/examples/preact/large-form/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/preact/large-form/vite.config.ts b/examples/preact/large-form/vite.config.ts new file mode 100644 index 0000000000..bfe110c059 --- /dev/null +++ b/examples/preact/large-form/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' + +export default defineConfig({ + plugins: [preact()], +}) diff --git a/examples/preact/multi-step-wizard/.gitignore b/examples/preact/multi-step-wizard/.gitignore new file mode 100644 index 0000000000..d600b6c76d --- /dev/null +++ b/examples/preact/multi-step-wizard/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + diff --git a/examples/preact/multi-step-wizard/README.md b/examples/preact/multi-step-wizard/README.md index dec1702783..93f18812e1 100644 --- a/examples/preact/multi-step-wizard/README.md +++ b/examples/preact/multi-step-wizard/README.md @@ -3,4 +3,4 @@ To run this example: - `pnpm install` -- `pnpm --filter @tanstack/form-example-preact-simple dev` +- `pnpm dev` diff --git a/examples/preact/multi-step-wizard/index.html b/examples/preact/multi-step-wizard/index.html index 2b9d36aedb..3665d2ca4a 100644 --- a/examples/preact/multi-step-wizard/index.html +++ b/examples/preact/multi-step-wizard/index.html @@ -1,9 +1,9 @@ - - - TanStack Form Preact Simple Example App + + + TanStack Form Preact Multi-Step Wizard Example
    diff --git a/examples/preact/multi-step-wizard/package.json b/examples/preact/multi-step-wizard/package.json index 5db1d8fe61..d8eb8c0991 100644 --- a/examples/preact/multi-step-wizard/package.json +++ b/examples/preact/multi-step-wizard/package.json @@ -3,30 +3,19 @@ "private": true, "type": "module", "scripts": { - "dev": "vite --port=3001", + "dev": "vite --port=3307", "build": "vite build", "preview": "vite preview", "test:types": "tsc" }, "dependencies": { - "@tanstack/preact-form": "^1.30.3", + "@tanstack/preact-form": "^2.0.0-alpha.3", "preact": "^10.26.4", - "zod": "^3.25.76" + "zod": "^4.4.3" }, "devDependencies": { "@preact/preset-vite": "^2.10.2", - "vite": "^7.2.2" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/preact/multi-step-wizard/src/App.tsx b/examples/preact/multi-step-wizard/src/App.tsx index 22fdb05eab..9b047365d0 100644 --- a/examples/preact/multi-step-wizard/src/App.tsx +++ b/examples/preact/multi-step-wizard/src/App.tsx @@ -1,4 +1,4 @@ -import { WizardPage } from './features/wizard/page' +import { WizardPage } from './features/wizard/page.tsx' export default function App() { return diff --git a/examples/preact/multi-step-wizard/src/components/text-fields.tsx b/examples/preact/multi-step-wizard/src/components/text-fields.tsx index 0b0409a95c..1727186c84 100644 --- a/examples/preact/multi-step-wizard/src/components/text-fields.tsx +++ b/examples/preact/multi-step-wizard/src/components/text-fields.tsx @@ -1,22 +1,23 @@ -import { useStore } from '@tanstack/preact-form' -import { useFieldContext } from '../hooks/form-context' - -export function TextField({ label }: { label: string }) { - const field = useFieldContext() - - const errors = useStore(field.store, (state) => state.meta.errors) +import type { FieldWithValue } from '@tanstack/preact-form' +export function TextField({ + field, + label, +}: { + field: FieldWithValue + label: string +}) { return (
    - {errors.map((error: { message: string }) => ( + {field.errors.map((error) => (
    {error.message}
    diff --git a/examples/preact/multi-step-wizard/src/features/wizard/page.tsx b/examples/preact/multi-step-wizard/src/features/wizard/page.tsx index 8edb81b730..b4ea3c0472 100644 --- a/examples/preact/multi-step-wizard/src/features/wizard/page.tsx +++ b/examples/preact/multi-step-wizard/src/features/wizard/page.tsx @@ -1,34 +1,22 @@ -import { revalidateLogic } from '@tanstack/preact-form' -import { z } from 'zod' import { useState } from 'preact/hooks' -import { useAppForm } from '../../hooks/form' -import { step1Schema, step2Schema, wizardFormOpts } from './shared-form' -import { Step2Form } from './step2-subform' -import { Step1Form } from './step1-subform' +import { useAppForm } from '../../hooks/form.tsx' +import { wizardFormOpts } from './shared-form.tsx' +import { Step2Form } from './step2-subform.tsx' +import { Step1Form } from './step1-subform.tsx' export const WizardPage = () => { const [step, setStep] = useState(0) const form = useAppForm({ ...wizardFormOpts, - validationLogic: revalidateLogic(), - validators: { - // onDynamic is only used when `form.handleSubmit` is called itself. - // When `form.FormGroup`'s `handleSubmit` is called, it will only validate the current step's schema. - // This means that this schema will not be called when the user submits the form group, but instead when they submit the entire form. - onDynamic: z.object({ - step1: step1Schema, - step2: step2Schema, - }), - }, onSubmit: ({ value }) => { alert(`Form submitted: ${JSON.stringify(value)}`) }, }) return ( - <> + {step === 0 && } {step === 1 && } - + ) } diff --git a/examples/preact/multi-step-wizard/src/features/wizard/shared-form.tsx b/examples/preact/multi-step-wizard/src/features/wizard/shared-form.tsx index 6c89235173..f2909a851c 100644 --- a/examples/preact/multi-step-wizard/src/features/wizard/shared-form.tsx +++ b/examples/preact/multi-step-wizard/src/features/wizard/shared-form.tsx @@ -1,5 +1,6 @@ -import { formOptions } from '@tanstack/preact-form' import z from 'zod' +import { createValidator } from '@tanstack/preact-form' +import { appFormOptions } from '../../hooks/form.tsx' export const step1Schema = z.object({ name: z.string().min(2, 'Name must be at least 2 characters'), @@ -9,7 +10,20 @@ export const step2Schema = z.object({ name: z.string().min(3, 'Name must be at least 3 characters'), }) -export const wizardFormOpts = formOptions({ +export const stepValidator = createValidator({ + triggers: [ + { + trigger: 'change', + when: ({ groupApi, formApi }) => { + const submitTries = + groupApi?.state.submissionAttempts ?? formApi.state.submissionAttempts + return submitTries > 0 + }, + }, + ], +}) + +export const wizardFormOpts = appFormOptions({ defaultValues: { step1: { name: '', @@ -18,4 +32,16 @@ export const wizardFormOpts = formOptions({ name: '', }, }, + validators: [ + { + // This validator is only used when `form.handleSubmit` is called itself. + // When `form.FormGroup`'s `handleSubmit` is called, it will only validate the current step's schema. + // This means that this schema will not be called when the user submits the form group, but instead when they submit the entire form. + run: z.object({ + step1: step1Schema, + step2: step2Schema, + }), + triggers: [], + }, + ], }) diff --git a/examples/preact/multi-step-wizard/src/features/wizard/step1-subform.tsx b/examples/preact/multi-step-wizard/src/features/wizard/step1-subform.tsx index 2eb2e04c11..e483aafb6f 100644 --- a/examples/preact/multi-step-wizard/src/features/wizard/step1-subform.tsx +++ b/examples/preact/multi-step-wizard/src/features/wizard/step1-subform.tsx @@ -1,46 +1,42 @@ -import { withForm } from '../../hooks/form' -import { step1Schema, wizardFormOpts } from './shared-form' +import { step1Schema, stepValidator } from './shared-form' +import type { wizardFormOpts } from './shared-form' +import type { PreactFormType } from '@tanstack/preact-form' -export const Step1Form = withForm({ - ...wizardFormOpts, - props: { - step: 0, - setStep: (_step: number) => {}, - }, - render: function Render({ form, step, setStep }) { - return ( - { - setStep(step + 1) - }} - onGroupSubmitInvalid={() => { - // Just like a form, you can also handle invalid submits at the group level, which is useful for multi-step wizards to prevent going to the next step if the current step is invalid - }} - > - {(formGroup) => ( -
    { - e.preventDefault() - e.stopPropagation() - formGroup.handleSubmit() - }} - > - - {(field) => } - +type WizardForm = PreactFormType - - - - {/* formGroup contains errorMaps and errors, just like forms and fields */} -
    {JSON.stringify(formGroup.state.meta.errorMap, null, 2)}
    - - )} -
    - ) - }, -}) +interface Step1FormProps { + form: WizardForm + step: number + setStep: (step: number) => void +} + +export function Step1Form({ form, step, setStep }: Step1FormProps) { + return ( + { + setStep(step + 1) + }} + onSubmitInvalid={() => { + // Just like a form, you can also handle invalid submits at the group level, which is useful for multi-step wizards to prevent going to the next step if the current step is invalid + }} + > + {(formGroup) => ( +
    { + e.preventDefault() + e.stopPropagation() + formGroup.handleSubmit() + }} + > + + {(field) => } + + + + + )} +
    + ) +} diff --git a/examples/preact/multi-step-wizard/src/features/wizard/step2-subform.tsx b/examples/preact/multi-step-wizard/src/features/wizard/step2-subform.tsx index 5e95c42c98..db9380e36e 100644 --- a/examples/preact/multi-step-wizard/src/features/wizard/step2-subform.tsx +++ b/examples/preact/multi-step-wizard/src/features/wizard/step2-subform.tsx @@ -1,42 +1,42 @@ -import { withForm } from '../../hooks/form' -import { step2Schema, wizardFormOpts } from './shared-form' +import { step2Schema, stepValidator } from './shared-form' +import type { wizardFormOpts } from './shared-form' +import type { PreactFormType } from '@tanstack/preact-form' -export const Step2Form = withForm({ - ...wizardFormOpts, - props: { - step: 1, - setStep: (_step: number) => {}, - }, - render: function Render({ form, step, setStep }) { - return ( - { - form.handleSubmit() - }} - > - {(formGroup) => ( -
    { - e.preventDefault() - e.stopPropagation() - formGroup.handleSubmit() - }} - > - - {(field) => } - +type WizardForm = PreactFormType - - - - - - )} -
    - ) - }, -}) +interface Step2FormProps { + form: WizardForm + step: number + setStep: (step: number) => void +} + +export function Step2Form({ form, step, setStep }: Step2FormProps) { + return ( + { + form.handleSubmit() + }} + > + {(formGroup) => ( +
    { + e.preventDefault() + e.stopPropagation() + formGroup.handleSubmit() + }} + > + + {(field) => } + + + + + + )} +
    + ) +} diff --git a/examples/preact/multi-step-wizard/src/hooks/form-context.tsx b/examples/preact/multi-step-wizard/src/hooks/form-context.tsx deleted file mode 100644 index 459a1ab268..0000000000 --- a/examples/preact/multi-step-wizard/src/hooks/form-context.tsx +++ /dev/null @@ -1,4 +0,0 @@ -import { createFormHookContexts } from '@tanstack/preact-form' - -export const { fieldContext, useFieldContext, formContext, useFormContext } = - createFormHookContexts() diff --git a/examples/preact/multi-step-wizard/src/hooks/form.tsx b/examples/preact/multi-step-wizard/src/hooks/form.tsx index 5a5a4e75e4..0fa5720e40 100644 --- a/examples/preact/multi-step-wizard/src/hooks/form.tsx +++ b/examples/preact/multi-step-wizard/src/hooks/form.tsx @@ -1,6 +1,9 @@ -import { createFormHook } from '@tanstack/preact-form' -import { TextField } from '../components/text-fields' -import { fieldContext, formContext, useFormContext } from './form-context' +import { createFormHook, getFormHookHelpers } from '@tanstack/preact-form' +import { TextField } from '../components/text-fields.tsx' + +const { fieldComponent } = getFormHookHelpers() + +const AppTextField = fieldComponent.strict(TextField, 'field') function SubscribeButton({ label }: { label: string }) { const form = useFormContext() @@ -15,13 +18,13 @@ function SubscribeButton({ label }: { label: string }) { ) } -export const { useAppForm, withForm, withFieldGroup } = createFormHook({ +const { appFormOptions, useAppForm, useFormContext } = createFormHook({ fieldComponents: { - TextField, + TextField: AppTextField, }, formComponents: { SubscribeButton, }, - fieldContext, - formContext, }) + +export { appFormOptions, useAppForm } diff --git a/examples/preact/multi-step-wizard/src/index.tsx b/examples/preact/multi-step-wizard/src/index.tsx index f324b5c1b1..ecf6c6bc3e 100644 --- a/examples/preact/multi-step-wizard/src/index.tsx +++ b/examples/preact/multi-step-wizard/src/index.tsx @@ -1,10 +1,7 @@ import { render } from 'preact' -import App from './App' -const rootElement = document.getElementById('root') +import App from './App.tsx' -if (!rootElement) { - throw new Error('Root element not found') -} +const rootElement = document.getElementById('root')! render(, rootElement) diff --git a/examples/preact/multi-step-wizard/tsconfig.json b/examples/preact/multi-step-wizard/tsconfig.json index 9dfa26665a..b7ba9a1a3c 100644 --- a/examples/preact/multi-step-wizard/tsconfig.json +++ b/examples/preact/multi-step-wizard/tsconfig.json @@ -1,9 +1,21 @@ { - "extends": "../../../tsconfig.json", "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, "jsx": "react-jsx", "jsxImportSource": "preact", - "moduleResolution": "Bundler" + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] }, "include": ["src", "vite.config.ts"] } diff --git a/examples/preact/query-integration/.gitignore b/examples/preact/query-integration/.gitignore new file mode 100644 index 0000000000..d600b6c76d --- /dev/null +++ b/examples/preact/query-integration/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + diff --git a/examples/preact/query-integration/README.md b/examples/preact/query-integration/README.md new file mode 100644 index 0000000000..93f18812e1 --- /dev/null +++ b/examples/preact/query-integration/README.md @@ -0,0 +1,6 @@ +# Example + +To run this example: + +- `pnpm install` +- `pnpm dev` diff --git a/examples/preact/query-integration/index.html b/examples/preact/query-integration/index.html new file mode 100644 index 0000000000..45c8014a88 --- /dev/null +++ b/examples/preact/query-integration/index.html @@ -0,0 +1,12 @@ + + + + + + TanStack Form Preact Query Integration Example + + +
    + + + diff --git a/examples/preact/query-integration/package.json b/examples/preact/query-integration/package.json new file mode 100644 index 0000000000..2061fe6daa --- /dev/null +++ b/examples/preact/query-integration/package.json @@ -0,0 +1,21 @@ +{ + "name": "@tanstack/form-example-preact-query-integration", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3308", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/preact-form": "^2.0.0-alpha.3", + "@tanstack/react-query": "^5.89.0", + "preact": "^10.26.4" + }, + "devDependencies": { + "@preact/preset-vite": "^2.10.2", + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/preact/query-integration/src/app.tsx b/examples/preact/query-integration/src/app.tsx new file mode 100644 index 0000000000..6fd5b5b2a8 --- /dev/null +++ b/examples/preact/query-integration/src/app.tsx @@ -0,0 +1,134 @@ +import { useForm } from '@tanstack/preact-form' +import { keepPreviousData, useMutation, useQuery } from '@tanstack/react-query' +import { db, sleep } from './mock-db' +import type { StoredUser } from './mock-db' +import type { AnyFieldApi } from '@tanstack/preact-form' + +function FieldInfo({ field }: { field: AnyFieldApi }) { + return ( + <> + {field.meta.isInvalid && ( + {field.errors.map((error) => error.message).join(',')} + )} + {field.meta.isValidating ? 'Validating...' : null} + + ) +} + +const emptyUser: StoredUser = { + firstName: '', + lastName: '', +} + +export function App() { + const userQuery = useQuery({ + queryKey: ['data'], + queryFn: () => db.getData(), + // Keeps the old values present while refetching new ones + placeholderData: keepPreviousData, + }) + + const saveUserMutation = useMutation({ + mutationFn: async (value: StoredUser) => { + return db.saveUser(value) + }, + onSuccess: async () => { + // Invalidating query to recheck fresh data + await userQuery.refetch() + }, + }) + + const form = useForm({ + defaultValues: userQuery.data ?? emptyUser, + onSubmit: async ({ formApi, value }) => { + await saveUserMutation.mutateAsync(value) + + // Pass optimistic values to the form so that it doesn't show old values + formApi.reset(value) + }, + // Only show errors if the field has been touched + errorVisibility: ({ fieldState }) => fieldState.meta.isTouched, + }) + + if (userQuery.isLoading) return

    Loading..

    + + return ( +
    +

    Simple Form Example

    +
    { + e.preventDefault() + e.stopPropagation() + form.handleSubmit() + }} + > + + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + triggers: ['change'], + }, + { + run: async ({ value }) => { + await sleep(1000) + return ( + value.includes('error') && 'No "error" allowed in first name' + ) + }, + triggers: ['change'], + triggerDebounceMs: 500, + }, + ]} + > + {(field) => ( +
    + + field.handleChange(e.currentTarget.value)} + /> + +
    + )} +
    + + {(field) => ( +
    + + field.handleChange(e.currentTarget.value)} + /> + +
    + )} +
    + [state.canSubmit, state.isSubmitting]} + children={([canSubmit, isSubmitting]) => ( + <> + + + + )} + /> + +
    + ) +} diff --git a/examples/preact/query-integration/src/index.tsx b/examples/preact/query-integration/src/index.tsx new file mode 100644 index 0000000000..f8bd70154b --- /dev/null +++ b/examples/preact/query-integration/src/index.tsx @@ -0,0 +1,20 @@ +import { render } from 'preact' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { App } from './app' +import type { ComponentChildren, FunctionComponent } from 'preact' + +const rootElement = document.getElementById('root')! + +const queryClient = new QueryClient() +const PreactQueryClientProvider = + QueryClientProvider as unknown as FunctionComponent<{ + children: ComponentChildren + client: QueryClient + }> + +render( + + + , + rootElement, +) diff --git a/examples/preact/query-integration/src/mock-db.ts b/examples/preact/query-integration/src/mock-db.ts new file mode 100644 index 0000000000..aa9b9eee9e --- /dev/null +++ b/examples/preact/query-integration/src/mock-db.ts @@ -0,0 +1,32 @@ +export async function sleep(ms: number) { + return new Promise((res) => setTimeout(res, ms)) +} + +export interface StoredUser { + firstName: string + lastName: string +} + +class DB { + private data: StoredUser + + constructor() { + this.data = { firstName: 'FirstName', lastName: 'LastName' } + } + + async getData(): Promise { + await sleep(1000) + return { ...this.data } + } + + async saveUser(value: StoredUser) { + await sleep(1000) + this.data = value + return value + } +} + +/** + * Dummy Database to emulate server-side actions + */ +export const db = new DB() diff --git a/examples/preact/query-integration/tsconfig.json b/examples/preact/query-integration/tsconfig.json new file mode 100644 index 0000000000..b7ba9a1a3c --- /dev/null +++ b/examples/preact/query-integration/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/preact/query-integration/vite.config.ts b/examples/preact/query-integration/vite.config.ts new file mode 100644 index 0000000000..bfe110c059 --- /dev/null +++ b/examples/preact/query-integration/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' + +export default defineConfig({ + plugins: [preact()], +}) diff --git a/examples/preact/simple/.gitignore b/examples/preact/simple/.gitignore new file mode 100644 index 0000000000..d600b6c76d --- /dev/null +++ b/examples/preact/simple/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + diff --git a/examples/preact/simple/README.md b/examples/preact/simple/README.md index dec1702783..93f18812e1 100644 --- a/examples/preact/simple/README.md +++ b/examples/preact/simple/README.md @@ -3,4 +3,4 @@ To run this example: - `pnpm install` -- `pnpm --filter @tanstack/form-example-preact-simple dev` +- `pnpm dev` diff --git a/examples/preact/simple/index.html b/examples/preact/simple/index.html index 2b9d36aedb..0d20c56b86 100644 --- a/examples/preact/simple/index.html +++ b/examples/preact/simple/index.html @@ -1,9 +1,9 @@ - - - TanStack Form Preact Simple Example App + + + TanStack Form Preact Simple Example
    diff --git a/examples/preact/simple/package.json b/examples/preact/simple/package.json index 790992eb7a..10de177c84 100644 --- a/examples/preact/simple/package.json +++ b/examples/preact/simple/package.json @@ -3,29 +3,18 @@ "private": true, "type": "module", "scripts": { - "dev": "vite --port=3001", + "dev": "vite --port=3301", "build": "vite build", "preview": "vite preview", "test:types": "tsc" }, "dependencies": { - "@tanstack/preact-form": "^1.30.3", + "@tanstack/preact-form": "^2.0.0-alpha.3", "preact": "^10.26.4" }, "devDependencies": { "@preact/preset-vite": "^2.10.2", - "vite": "^7.2.2" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/preact/simple/src/index.tsx b/examples/preact/simple/src/index.tsx index d0424e9279..32228b8bfa 100644 --- a/examples/preact/simple/src/index.tsx +++ b/examples/preact/simple/src/index.tsx @@ -7,62 +7,80 @@ import type { AnyFieldApi } from '@tanstack/preact-form' function FieldInfo({ field }: { field: AnyFieldApi }) { return ( <> - {field.state.meta.isTouched && !field.state.meta.isValid ? ( - {field.state.meta.errors.join(',')} + {field.meta.isTouched && field.meta.isInvalid ? ( + {field.errors.map((error) => error.message).join(',')} ) : null} - {field.state.meta.isValidating ? 'Validating...' : null} + {field.meta.isValidating ? 'Validating...' : null} ) } -function App() { +export default function App() { const form = useForm({ defaultValues: { firstName: '', lastName: '', }, onSubmit: async ({ value }) => { + // Do something with form data console.log(value) }, }) return (
    -

    Simple Preact Form Example

    +

    Simple Form Example

    { e.preventDefault() e.stopPropagation() - void form.handleSubmit() + form.handleSubmit() }} >
    + {/* A type-safe field component*/} - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined, + validators={[ + { + run: ({ value }) => + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + triggers: ['change'], + }, + { + run: async ({ value }) => { + await new Promise((resolve) => setTimeout(resolve, 1000)) + return ( + value.includes('error') && + 'No "error" allowed in first name' + ) + }, + triggers: ['change'], + triggerDebounceMs: 500, + }, + ]} + children={(field) => { + // Avoid hasty abstractions. Render props are great! + return ( + <> + + field.handleChange(e.currentTarget.value)} + /> + + + ) }} - children={(field) => ( - <> - - field.handleChange(e.currentTarget.value)} - /> - - - )} />
    -
    field.handleChange(e.currentTarget.value)} /> @@ -81,7 +99,6 @@ function App() { )} />
    - [state.canSubmit, state.isSubmitting]} children={([canSubmit, isSubmitting]) => ( @@ -92,6 +109,7 @@ function App() {
    +
    + ( + <> + + field.handleChange(e.currentTarget.value)} + /> + + + )} + /> +
    + [state.canSubmit, state.isSubmitting]} + children={([canSubmit, isSubmitting]) => ( + + )} + /> + +
    + ) +} + +const rootElement = document.getElementById('root')! + +render(, rootElement) diff --git a/examples/preact/standard-schema/tsconfig.json b/examples/preact/standard-schema/tsconfig.json new file mode 100644 index 0000000000..b7ba9a1a3c --- /dev/null +++ b/examples/preact/standard-schema/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/preact/standard-schema/vite.config.ts b/examples/preact/standard-schema/vite.config.ts new file mode 100644 index 0000000000..bfe110c059 --- /dev/null +++ b/examples/preact/standard-schema/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' + +export default defineConfig({ + plugins: [preact()], +}) diff --git a/examples/react/array/.eslintrc.cjs b/examples/react/array/.eslintrc.cjs deleted file mode 100644 index 35853b6175..0000000000 --- a/examples/react/array/.eslintrc.cjs +++ /dev/null @@ -1,11 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = { - extends: ['plugin:react/recommended', 'plugin:react-hooks/recommended'], - rules: { - 'react/no-children-prop': 'off', - }, -} - -module.exports = config diff --git a/examples/react/array/.gitignore b/examples/react/array/.gitignore deleted file mode 100644 index 4673b022e5..0000000000 --- a/examples/react/array/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -pnpm-lock.yaml -yarn.lock -package-lock.json - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/examples/react/array/README.md b/examples/react/array/README.md deleted file mode 100644 index 1cf8892652..0000000000 --- a/examples/react/array/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Example - -To run this example: - -- `npm install` -- `npm run dev` diff --git a/examples/react/array/index.html b/examples/react/array/index.html index 5d0e76cd40..c11d771546 100644 --- a/examples/react/array/index.html +++ b/examples/react/array/index.html @@ -2,11 +2,9 @@ - - - TanStack Form React Simple Example App + TanStack Form React Array Example diff --git a/examples/react/array/package.json b/examples/react/array/package.json index efed7b5ca3..c46cb24c4e 100644 --- a/examples/react/array/package.json +++ b/examples/react/array/package.json @@ -3,34 +3,23 @@ "private": true, "type": "module", "scripts": { - "dev": "vite --port=3001", + "dev": "vite --port=3005", "build": "vite build", "preview": "vite preview", "test:types": "tsc" }, "dependencies": { - "@tanstack/react-form": "^1.33.3", - "react": "19.1.0", - "react-dom": "19.1.0" + "@tanstack/react-form": "^2.0.0-alpha.3", + "react": "19.2.8", + "react-dom": "19.2.8" }, "devDependencies": { - "@tanstack/react-devtools": "^0.9.7", - "@tanstack/react-form-devtools": "^0.2.32", - "@types/react": "~19.2.0", - "@types/react-dom": "^19.0.3", - "@vitejs/plugin-react": "^5.1.1", - "vite": "^7.2.2" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "@tanstack/react-devtools": "^0.10.5", + "@tanstack/react-form-devtools": "^1.0.0-alpha.3", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/react/array/public/emblem-light.svg b/examples/react/array/public/emblem-light.svg deleted file mode 100644 index a58e69ad5e..0000000000 --- a/examples/react/array/public/emblem-light.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - emblem-light - Created with Sketch. - - - - - - - - \ No newline at end of file diff --git a/examples/react/array/src/index.css b/examples/react/array/src/index.css new file mode 100644 index 0000000000..12eead9401 --- /dev/null +++ b/examples/react/array/src/index.css @@ -0,0 +1,76 @@ +#root { + max-width: 100%; + margin: 0 5rem; + text-align: center; + border-inline: 1px solid var(--border); + min-height: 100svh; + box-sizing: border-box; + font-family: system-ui, 'Segoe UI', Roboto, sans-serif; + --color-text: #08060d; +} + +#root button { + font-size: 16px; + padding: 5px 10px; + border-radius: 5px; + color: var(--color-text); + background: #f4f3ec; + border: 2px solid transparent; + border-top-color: transparent; + border-right-color: transparent; + border-bottom-color: transparent; + border-left-color: transparent; + transition: border-color 0.3s; + margin-inline: 0.5rem; + margin-top: 0.5rem; + font-family: ui-monospace, Consolas, monospace; + display: inline-flex; + cursor: pointer; +} + +#root button:hover { + border: 2px solid rgba(8, 6, 13, 0.5); +} + +#root ul { + list-style: none; + margin: 0; + padding: 2rem 0 0 0; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(8em, 1fr)); + gap: 0.75rem; +} + +#root li { + min-width: 0; +} + +#root li label { + display: flex; + flex-direction: column; + gap: 0.35rem; + font-size: 0.95rem; + font-weight: 500; + color: var(--color-text); +} + +#root input { + width: 100%; + box-sizing: border-box; + min-width: 0; + padding: 0.55rem 0.7rem; + border: 1px solid #ccc; + border-radius: 0.4rem; + font-size: 1rem; +} + +#root #itemsAmount { + max-width: 10rem; + text-align: end; +} + +#root li input:focus { + outline: none; + border-color: #646cff; + box-shadow: 0 0 0 2px rgba(100, 108, 255, 0.2); +} diff --git a/examples/react/array/src/index.tsx b/examples/react/array/src/index.tsx index 4f2ea539e4..482eba9e94 100644 --- a/examples/react/array/src/index.tsx +++ b/examples/react/array/src/index.tsx @@ -1,27 +1,27 @@ -import * as React from 'react' -import { createRoot } from 'react-dom/client' - import { TanStackDevtools } from '@tanstack/react-devtools' -import { formDevtoolsPlugin } from '@tanstack/react-form-devtools' import { useForm } from '@tanstack/react-form' +import { formDevtoolsPlugin } from '@tanstack/react-form-devtools' +import ReactDOM from 'react-dom/client' +import './index.css' +import { useMemo, useRef, useState } from 'react' -interface Person { - name: string - age: number -} - -const defaultPeople: { people: Array } = { people: [] } - -function App() { +function ArrayForm({ items }: { items: Array }) { const form = useForm({ - defaultValues: defaultPeople, - onSubmit({ value }) { - alert(JSON.stringify(value)) + defaultValues: { + items, + }, + onSubmit: ({ value }) => { + // Do something with form data + console.log(value) + alert(`Submitted ${value.items.length} items.`) }, }) return ( -
    + <> + state.values.items.length}> + {(amount) =>

    Item amount: {amount.toLocaleString()}

    } +
    { e.preventDefault() @@ -29,63 +29,95 @@ function App() { form.handleSubmit() }} > - - {(field) => { - return ( -
    - {field.state.value.map((_, i) => { - return ( - - {(subField) => { - return ( -
    - -
    - ) - }} -
    - ) - })} - -
    - ) - }} -
    - [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( - + + + {/** + * Usually, this array would rerender whenever an item was changed. + * To reduce rerenders, use the ArrayField component! + */} + + {(array) => ( +
      + {array.value.map((_, i) => ( + + {(field) => ( +
    • + +
    • + )} +
      + ))} +
    )} - /> +
    -
    + ) } -const rootElement = document.getElementById('root')! +function App() { + const [itemAmount, setItemAmount] = useState(50) + const inputRef = useRef(null) + + const items = useMemo( + () => Array.from({ length: itemAmount }, () => ''), + [itemAmount], + ) + + function updateItems() { + if (inputRef.current && !Number.isNaN(inputRef.current.valueAsNumber)) { + setItemAmount( + Math.min(10_000, Math.max(0, inputRef.current.valueAsNumber)), + ) + } + } + return ( +
    +

    Arrays in Form Example

    + +
    + + -createRoot(rootElement).render( - - +
    + + + +
    + ) +} - - , -) +ReactDOM.createRoot(document.getElementById('root')!).render() diff --git a/examples/react/array/tsconfig.json b/examples/react/array/tsconfig.json index 22b43163bf..0c75398c58 100644 --- a/examples/react/array/tsconfig.json +++ b/examples/react/array/tsconfig.json @@ -4,20 +4,17 @@ "lib": ["DOM", "DOM.Iterable", "ESNext"], "module": "ESNext", "skipLibCheck": true, - - /* Bundler mode */ "moduleResolution": "Bundler", "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", - - /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] }, - "include": ["src"] + "include": ["src", "vite.config.ts"] } diff --git a/examples/react/array/vite.config.ts b/examples/react/array/vite.config.ts new file mode 100644 index 0000000000..9ffcc67574 --- /dev/null +++ b/examples/react/array/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], +}) diff --git a/examples/react/basic-splitting-form/index.html b/examples/react/basic-splitting-form/index.html new file mode 100644 index 0000000000..48b9e07e13 --- /dev/null +++ b/examples/react/basic-splitting-form/index.html @@ -0,0 +1,14 @@ + + + + + + + TanStack Form React Basic Splitting Form Example + + + +
    + + + diff --git a/examples/react/basic-splitting-form/package.json b/examples/react/basic-splitting-form/package.json new file mode 100644 index 0000000000..8871688597 --- /dev/null +++ b/examples/react/basic-splitting-form/package.json @@ -0,0 +1,25 @@ +{ + "name": "@tanstack/form-example-react-basic-splitting-form", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3005", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/react-form": "^2.0.0-alpha.3", + "react": "19.2.8", + "react-dom": "19.2.8" + }, + "devDependencies": { + "@tanstack/react-devtools": "^0.10.5", + "@tanstack/react-form-devtools": "^1.0.0-alpha.3", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/react/basic-splitting-form/src/FieldError.tsx b/examples/react/basic-splitting-form/src/FieldError.tsx new file mode 100644 index 0000000000..324e97b1f3 --- /dev/null +++ b/examples/react/basic-splitting-form/src/FieldError.tsx @@ -0,0 +1,13 @@ +import type { AnyFieldApi } from '@tanstack/react-form' + +interface FieldInfoProps { + field: AnyFieldApi +} + +export function FieldError({ field }: FieldInfoProps) { + return ( + + {field.errors.map((e) => e.message).join('\n')} + + ) +} diff --git a/examples/react/basic-splitting-form/src/FormSection.tsx b/examples/react/basic-splitting-form/src/FormSection.tsx new file mode 100644 index 0000000000..777a69fda7 --- /dev/null +++ b/examples/react/basic-splitting-form/src/FormSection.tsx @@ -0,0 +1,22 @@ +import { StringField } from './StringField' +import type { ReactFormType } from '@tanstack/react-form' +import type { sharedFormOptions } from './sharedForm' + +interface FormSectionProps { + form: ReactFormType +} + +export function FormSection(props: FormSectionProps) { + const { form } = props + + return ( + <> + + {(field) => } + + + {(field) => } + + + ) +} diff --git a/examples/react/basic-splitting-form/src/FormSubmitButton.tsx b/examples/react/basic-splitting-form/src/FormSubmitButton.tsx new file mode 100644 index 0000000000..7e825fe597 --- /dev/null +++ b/examples/react/basic-splitting-form/src/FormSubmitButton.tsx @@ -0,0 +1,18 @@ +import type { AnyReactFormApi } from '@tanstack/react-form' + +interface FormSubmitButtonProps { + form: AnyReactFormApi +} + +export function FormSubmitButton(props: FormSubmitButtonProps) { + const { form } = props + return ( + [state.canSubmit, state.isSubmitting]}> + {([canSubmit, isSubmitting]) => ( + + )} + + ) +} diff --git a/examples/react/basic-splitting-form/src/StringField.tsx b/examples/react/basic-splitting-form/src/StringField.tsx new file mode 100644 index 0000000000..cd7c5d65db --- /dev/null +++ b/examples/react/basic-splitting-form/src/StringField.tsx @@ -0,0 +1,25 @@ +import { FieldError } from './FieldError' +import type { FieldWithValue } from '@tanstack/react-form' + +interface StringFieldProps { + field: FieldWithValue +} + +export function StringField(props: StringFieldProps) { + const { field } = props + + return ( + + ) +} diff --git a/examples/react/basic-splitting-form/src/index.css b/examples/react/basic-splitting-form/src/index.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/react/basic-splitting-form/src/index.tsx b/examples/react/basic-splitting-form/src/index.tsx new file mode 100644 index 0000000000..5e557c3ea3 --- /dev/null +++ b/examples/react/basic-splitting-form/src/index.tsx @@ -0,0 +1,61 @@ +import { TanStackDevtools } from '@tanstack/react-devtools' +import { useForm } from '@tanstack/react-form' +import { formDevtoolsPlugin } from '@tanstack/react-form-devtools' +import ReactDOM from 'react-dom/client' +import './index.css' +import { StringField } from './StringField' +import { sharedFormOptions } from './sharedForm' +import { FormSection } from './FormSection' +import { FormSubmitButton } from './FormSubmitButton' + +function App() { + const form = useForm({ + ...sharedFormOptions, + onSubmit: ({ value }) => { + // Do something with form data + console.log(value) + }, + }) + + return ( +
    +

    Simple Form Example

    +
    { + e.preventDefault() + e.stopPropagation() + form.handleSubmit() + }} + > + + {(field) => } + + + {(field) => } + + + + + + + )} + +
    - ( + + {(field) => ( <> field.handleChange(e.target.value)} /> )} - /> +
    [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( + > + {([canSubmit, isSubmitting]) => ( <> - - )} - - ) -} diff --git a/examples/react/composition/src/index.tsx b/examples/react/composition/src/index.tsx deleted file mode 100644 index 2f33faf6af..0000000000 --- a/examples/react/composition/src/index.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import * as React from 'react' -import { createRoot } from 'react-dom/client' - -import { TanStackDevtools } from '@tanstack/react-devtools' -import { formDevtoolsPlugin } from '@tanstack/react-form-devtools' - -import useAppForm from './AppForm/AppForm' - -export default function App() { - const form = useAppForm({ - defaultValues: { - firstName: '', - lastName: '', - }, - onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) - }, - }) - - return ( -
    -

    Simple Form Example

    - - { - e.preventDefault() - e.stopPropagation() - form.handleSubmit() - }} - > - {/* A type-safe field component*/} - - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined, - onChangeAsyncDebounceMs: 500, - onChangeAsync: async ({ value }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return ( - value.includes('error') && 'No "error" allowed in first name' - ) - }, - }} - > - {(f) => } - - - - {(f) => } - - - - - - -
    - ) -} - -const rootElement = document.getElementById('root')! - -createRoot(rootElement).render( - - - - - , -) diff --git a/examples/react/composition/tsconfig.json b/examples/react/composition/tsconfig.json deleted file mode 100644 index 22b43163bf..0000000000 --- a/examples/react/composition/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "Bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/examples/react/devtools/.eslintrc.cjs b/examples/react/devtools/.eslintrc.cjs deleted file mode 100644 index 35853b6175..0000000000 --- a/examples/react/devtools/.eslintrc.cjs +++ /dev/null @@ -1,11 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = { - extends: ['plugin:react/recommended', 'plugin:react-hooks/recommended'], - rules: { - 'react/no-children-prop': 'off', - }, -} - -module.exports = config diff --git a/examples/react/devtools/.gitignore b/examples/react/devtools/.gitignore deleted file mode 100644 index 4673b022e5..0000000000 --- a/examples/react/devtools/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -pnpm-lock.yaml -yarn.lock -package-lock.json - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/examples/react/devtools/README.md b/examples/react/devtools/README.md deleted file mode 100644 index 1cf8892652..0000000000 --- a/examples/react/devtools/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Example - -To run this example: - -- `npm install` -- `npm run dev` diff --git a/examples/react/devtools/index.html b/examples/react/devtools/index.html deleted file mode 100644 index 9231f55ea6..0000000000 --- a/examples/react/devtools/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - TanStack Form Devtools Example App - - - -
    - - - diff --git a/examples/react/devtools/package.json b/examples/react/devtools/package.json deleted file mode 100644 index e3947cb39c..0000000000 --- a/examples/react/devtools/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "@tanstack/form-example-react-devtools", - "private": true, - "type": "module", - "scripts": { - "dev": "vite --port=3001", - "build": "vite build", - "preview": "vite preview", - "test:types": "tsc" - }, - "dependencies": { - "@tanstack/react-form": "^1.33.3", - "react": "19.1.0", - "react-dom": "19.1.0" - }, - "devDependencies": { - "@tanstack/react-devtools": "^0.9.7", - "@tanstack/react-form-devtools": "^0.2.32", - "@types/react": "~19.2.0", - "@types/react-dom": "^19.0.3", - "@vitejs/plugin-react": "^5.1.1", - "vite": "^7.2.2" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/examples/react/devtools/public/emblem-light.svg b/examples/react/devtools/public/emblem-light.svg deleted file mode 100644 index a58e69ad5e..0000000000 --- a/examples/react/devtools/public/emblem-light.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - emblem-light - Created with Sketch. - - - - - - - - \ No newline at end of file diff --git a/examples/react/devtools/src/App.tsx b/examples/react/devtools/src/App.tsx deleted file mode 100644 index 7845c20a03..0000000000 --- a/examples/react/devtools/src/App.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import { useForm } from '@tanstack/react-form' - -import type { AnyFieldApi } from '@tanstack/react-form' - -function FieldInfo({ field }: { field: AnyFieldApi }) { - return ( - <> - {field.state.meta.isTouched && !field.state.meta.isValid ? ( - {field.state.meta.errors.join(',')} - ) : null} - {field.state.meta.isValidating ? 'Validating...' : null} - - ) -} - -export default function App() { - const form1 = useForm({ - defaultValues: { - firstName: '', - lastName: '', - }, - onSubmit: async ({ value }) => { - console.log(value) - }, - }) - - const form2 = useForm({ - defaultValues: { - age: 0, - }, - validators: { - onChange({ value }) { - if (value.age < 15) { - return 'needs to be above 15' - } - return undefined - }, - }, - onSubmit: async ({ value }) => { - if (value.age < 20) throw 'needs to be above 20' - }, - }) - - return ( -
    -

    Form Devtools Example

    - -

    Form 1

    - -
    { - e.preventDefault() - e.stopPropagation() - form1.handleSubmit() - }} - > -
    - - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined, - }} - children={(field) => { - return ( - <> - - field.handleChange(e.target.value)} - /> - - - ) - }} - /> -
    - -
    - ( - <> - - field.handleChange(e.target.value)} - /> - - - )} - /> -
    - - [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( - <> - - - - )} - /> - - [state.submissionAttempts]} - children={([submissionAttempts]) => ( -
    submission attempts: {submissionAttempts}
    - )} - /> - - -

    Form 2

    -
    { - e.preventDefault() - e.stopPropagation() - form2.handleSubmit() - }} - > -
    - - value < 10 ? 'Age must be at least 10' : undefined, - }} - children={(field) => { - return ( - <> - - - field.handleChange(parseInt(e.target.value)) - } - /> - - - ) - }} - /> - - [state.submissionAttempts]} - children={([submissionAttempts]) => ( -
    submission attempts: {submissionAttempts}
    - )} - /> -
    -
    -
    - ) -} diff --git a/examples/react/devtools/src/index.tsx b/examples/react/devtools/src/index.tsx deleted file mode 100644 index 02eee6c1e2..0000000000 --- a/examples/react/devtools/src/index.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' - -import { TanStackDevtools } from '@tanstack/react-devtools' -import { formDevtoolsPlugin } from '@tanstack/react-form-devtools' - -import App from './App' - -createRoot(document.getElementById('root')!).render( - - - - - , -) diff --git a/examples/react/devtools/tsconfig.json b/examples/react/devtools/tsconfig.json deleted file mode 100644 index 22b43163bf..0000000000 --- a/examples/react/devtools/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "Bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/examples/react/dynamic/.eslintrc.cjs b/examples/react/dynamic/.eslintrc.cjs deleted file mode 100644 index 35853b6175..0000000000 --- a/examples/react/dynamic/.eslintrc.cjs +++ /dev/null @@ -1,11 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = { - extends: ['plugin:react/recommended', 'plugin:react-hooks/recommended'], - rules: { - 'react/no-children-prop': 'off', - }, -} - -module.exports = config diff --git a/examples/react/dynamic/.gitignore b/examples/react/dynamic/.gitignore deleted file mode 100644 index 4673b022e5..0000000000 --- a/examples/react/dynamic/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -pnpm-lock.yaml -yarn.lock -package-lock.json - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/examples/react/dynamic/README.md b/examples/react/dynamic/README.md deleted file mode 100644 index 1cf8892652..0000000000 --- a/examples/react/dynamic/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Example - -To run this example: - -- `npm install` -- `npm run dev` diff --git a/examples/react/dynamic/index.html b/examples/react/dynamic/index.html deleted file mode 100644 index 5d0e76cd40..0000000000 --- a/examples/react/dynamic/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - TanStack Form React Simple Example App - - - -
    - - - diff --git a/examples/react/dynamic/package.json b/examples/react/dynamic/package.json deleted file mode 100644 index 3fa044c7b3..0000000000 --- a/examples/react/dynamic/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "@tanstack/form-example-react-dynamic", - "private": true, - "type": "module", - "scripts": { - "dev": "vite --port=3001", - "build": "vite build", - "preview": "vite preview", - "test:types": "tsc" - }, - "dependencies": { - "@tanstack/react-form": "^1.33.3", - "react": "19.1.0", - "react-dom": "19.1.0" - }, - "devDependencies": { - "@tanstack/react-devtools": "^0.9.7", - "@tanstack/react-form-devtools": "^0.2.32", - "@types/react": "~19.2.0", - "@types/react-dom": "^19.0.3", - "@vitejs/plugin-react": "^5.1.1", - "vite": "^7.2.2", - "zod": "^3.25.76" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/examples/react/dynamic/public/emblem-light.svg b/examples/react/dynamic/public/emblem-light.svg deleted file mode 100644 index a58e69ad5e..0000000000 --- a/examples/react/dynamic/public/emblem-light.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - emblem-light - Created with Sketch. - - - - - - - - \ No newline at end of file diff --git a/examples/react/dynamic/src/index.tsx b/examples/react/dynamic/src/index.tsx deleted file mode 100644 index b7506f383f..0000000000 --- a/examples/react/dynamic/src/index.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import * as React from 'react' -import { createRoot } from 'react-dom/client' -import { z } from 'zod' - -import { TanStackDevtools } from '@tanstack/react-devtools' -import { formDevtoolsPlugin } from '@tanstack/react-form-devtools' -import { revalidateLogic, useForm } from '@tanstack/react-form' - -import type { AnyFieldApi } from '@tanstack/react-form' - -function FieldInfo({ field }: { field: AnyFieldApi }) { - return ( - <> - {field.state.meta.isTouched && !field.state.meta.isValid - ? field.state.meta.errors.map((err) => ( - {err.message} - )) - : null} - {field.state.meta.isValidating ? 'Validating...' : null} - - ) -} - -const schema = z.object({ - firstName: z.string().min(1, 'First name is required'), - lastName: z.string().min(1, 'Last name is required'), -}) - -export default function App() { - const form = useForm({ - defaultValues: { - firstName: '', - lastName: '', - }, - validationLogic: revalidateLogic(), - validators: { - onDynamic: schema, - }, - onSubmit: async ({ value }) => { - // Do something with form data - console.log(value) - }, - }) - - return ( -
    -

    Simple Form Example

    -
    { - e.preventDefault() - e.stopPropagation() - form.handleSubmit() - }} - > -
    - {/* A type-safe field component*/} - { - // Avoid hasty abstractions. Render props are great! - return ( - <> - - field.handleChange(e.target.value)} - /> - - - ) - }} - /> -
    -
    - ( - <> - - field.handleChange(e.target.value)} - /> - - - )} - /> -
    - [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( - <> - -
    - )} - /> - - (!value ? 'Required field' : null), - }} - children={(field) => ( -
    - - field.handleChange(e.target.valueAsNumber)} - /> - {!field.state.meta.isValid ? ( - {field.state.meta.errors.join(', ')} - ) : null} -
    - )} - /> - [state.errorMap]} - children={([errorMap]) => - errorMap.onSubmit ? ( -
    - - There was an error on the form: {errorMap.onSubmit.toString()} - -
    - ) : null - } - /> - [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( - - )} - /> - -
    - ) -} - -const rootElement = document.getElementById('root')! - -createRoot(rootElement).render( - <> - - - - , -) diff --git a/examples/react/field-errors-from-form-validators/tsconfig.json b/examples/react/field-errors-from-form-validators/tsconfig.json deleted file mode 100644 index 22b43163bf..0000000000 --- a/examples/react/field-errors-from-form-validators/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "Bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/examples/react/field-groups/index.html b/examples/react/field-groups/index.html new file mode 100644 index 0000000000..60529d32e7 --- /dev/null +++ b/examples/react/field-groups/index.html @@ -0,0 +1,14 @@ + + + + + + + TanStack Form React Field Groups Example + + + +
    + + + diff --git a/examples/react/field-groups/package.json b/examples/react/field-groups/package.json new file mode 100644 index 0000000000..36bb679ed9 --- /dev/null +++ b/examples/react/field-groups/package.json @@ -0,0 +1,26 @@ +{ + "name": "@tanstack/form-example-react-field-groups", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3005", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/react-form": "^2.0.0-alpha.3", + "react": "19.2.8", + "react-dom": "19.2.8", + "zod": "^4.4.3" + }, + "devDependencies": { + "@tanstack/react-devtools": "^0.10.5", + "@tanstack/react-form-devtools": "^1.0.0-alpha.3", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/react/field-groups/src/FieldError.tsx b/examples/react/field-groups/src/FieldError.tsx new file mode 100644 index 0000000000..324e97b1f3 --- /dev/null +++ b/examples/react/field-groups/src/FieldError.tsx @@ -0,0 +1,13 @@ +import type { AnyFieldApi } from '@tanstack/react-form' + +interface FieldInfoProps { + field: AnyFieldApi +} + +export function FieldError({ field }: FieldInfoProps) { + return ( + + {field.errors.map((e) => e.message).join('\n')} + + ) +} diff --git a/examples/react/field-groups/src/StringField.tsx b/examples/react/field-groups/src/StringField.tsx new file mode 100644 index 0000000000..4f3d29cbc2 --- /dev/null +++ b/examples/react/field-groups/src/StringField.tsx @@ -0,0 +1,32 @@ +import { FieldError } from './FieldError' +import type { FieldWithValue } from '@tanstack/react-form' + +interface StringFieldProps { + field: FieldWithValue + label: string +} + +export function StringField(props: StringFieldProps) { + const { field, label } = props + + return ( + + ) +} diff --git a/examples/react/field-groups/src/fieldGroups/dateRange.tsx b/examples/react/field-groups/src/fieldGroups/dateRange.tsx new file mode 100644 index 0000000000..527c57181e --- /dev/null +++ b/examples/react/field-groups/src/fieldGroups/dateRange.tsx @@ -0,0 +1,92 @@ +import { defineFieldGroup, useSelector } from '@tanstack/react-form' +import { FieldError } from '../FieldError' +import type { FieldWithValue } from '@tanstack/react-form' + +// DateRangeField needs two string fields, but it does not care where they live. +// These virtual names are the only field names available inside the group. +// For example, this file can use `start` and `end`, but not `dateRanges[0]`. +const fieldGroup = defineFieldGroup((helper) => ({ + start: helper.strict(), + end: helper.strict(), +})) + +interface DateRangeFieldProps { + fields: typeof fieldGroup.fields + label: string +} + +function DateRangeFieldComponent(props: DateRangeFieldProps) { + const { fields, label } = props + // `fields.values` contains only the values declared above, not the entire form. + const start = useSelector(fields.atom, (values) => values.start) + + return ( +
    + {label} + + {/* The group uses virtual names like `start`; callers provide the real path. */} + + {(field) => } + + + Boolean(value && start), + }, + ], + // Watched fields are virtual too. This becomes the caller's bound + // start path, such as `dateRanges[0].start`. + watchFields: ['start'], + run: ({ value }) => { + if (value < start) { + return 'End date must be after the start date' + } + }, + }, + ]} + > + {(field) => } + +
    + ) +} + +export const DateRangeField = fieldGroup.bindComponent( + DateRangeFieldComponent, + 'fields', +) + +interface DateFieldProps { + field: FieldWithValue + label: string +} + +function DateField(props: DateFieldProps) { + const { field, label } = props + + return ( + + ) +} diff --git a/examples/react/field-groups/src/fieldGroups/fieldBounds.tsx b/examples/react/field-groups/src/fieldGroups/fieldBounds.tsx new file mode 100644 index 0000000000..c7d9575b45 --- /dev/null +++ b/examples/react/field-groups/src/fieldGroups/fieldBounds.tsx @@ -0,0 +1,119 @@ +import { defineFieldGroup } from '@tanstack/react-form' +import { z } from 'zod' +import { StringField } from '../StringField' + +const boundsSchema = z.coerce.number().int() + +// Example 1: a field group can package field-specific options. +// `value` is a virtual field name. Callers bind it to a real field path like +// `minPrice` or `minAge`, but this component never needs to know that path. +// `strict()` means callers can only bind exact string fields. +const lowerBound = defineFieldGroup(({ strict }) => ({ + value: strict(), +})) + +interface LowerBoundFieldProps { + fields: typeof lowerBound.fields + label: string +} + +function LowerBoundFieldComponent(props: LowerBoundFieldProps) { + const { fields, label } = props + + // `fields` is the scoped FieldGroup API, not the full form API. This + // component can render/read/write `value`, but it cannot touch fields that + // were not declared in `lowerBoundFields`. + return ( + { + fields.setFieldValue('value', parseInt(value, 10).toString()) + }, + triggers: ['blur'], + }, + ]} + > + {(field) => } + + ) +} + +export const LowerBoundField = lowerBound.bindComponent( + LowerBoundFieldComponent, + 'fields', +) + +// Example 2: a field group can depend on multiple fields without depending on +// a specific form shape. `value` is the field this component renders, while +// `lowerBound` is only read/watched by the validator below. +const upperBound = defineFieldGroup(({ strict }) => ({ + value: strict(), + lowerBound: strict(), +})) + +interface UpperBoundFieldProps { + fields: typeof upperBound.fields + label: string +} + +function UpperBoundFieldComponent(props: UpperBoundFieldProps) { + const { fields, label } = props + + // Because `lowerBound` was declared above, it is available to validators, + // listeners, and field methods. Undeclared form fields are still inaccessible. + return ( + { + const upperBoundResult = boundsSchema.safeParse(value) + + if (!upperBoundResult.success) { + return parseIssues(upperBoundResult.error.issues) + } + + const lowerBoundResult = boundsSchema.safeParse( + fields.getFieldValue('lowerBound'), + ) + + if (!lowerBoundResult.success) { + return + } + + if (upperBoundResult.data < lowerBoundResult.data) { + return 'Upper bound must be greater than lower bound' + } + }, + }, + ]} + listeners={[ + { + run: ({ value }) => { + fields.setFieldValue('value', parseInt(value, 10).toString()) + }, + triggers: ['blur'], + }, + ]} + > + {(field) => } + + ) +} + +export const UpperBoundField = upperBound.bindComponent( + UpperBoundFieldComponent, + 'fields', +) diff --git a/examples/react/field-groups/src/index.css b/examples/react/field-groups/src/index.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/react/field-groups/src/index.tsx b/examples/react/field-groups/src/index.tsx new file mode 100644 index 0000000000..2ae25b15ed --- /dev/null +++ b/examples/react/field-groups/src/index.tsx @@ -0,0 +1,146 @@ +import { TanStackDevtools } from '@tanstack/react-devtools' +import { useForm } from '@tanstack/react-form' +import { formDevtoolsPlugin } from '@tanstack/react-form-devtools' +import ReactDOM from 'react-dom/client' +import './index.css' +import { DateRangeField } from './fieldGroups/dateRange' +import { LowerBoundField, UpperBoundField } from './fieldGroups/fieldBounds' + +// The bounds field groups package validation and blur normalization once, then +// each form binds the group's virtual names to its own real field paths. +function PricingFilterForm() { + const form = useForm({ + defaultValues: { + minPrice: '', + maxPrice: '', + }, + }) + + return ( + <> + + + + ) +} + +function AgeRangeForm() { + const form = useForm({ + defaultValues: { + minAge: '', + maxAge: '', + }, + }) + + return ( + <> + + + + ) +} + +// DateRangeField has access to both dates, but it still knows nothing about the +// array it is rendered from. The parent form supplies those concrete paths here. +function SwappableDateRangesForm() { + const form = useForm({ + defaultValues: { + dateRanges: [ + { + id: 'A', + start: '2026-07-01', + end: '2026-07-05', + }, + { + id: 'B', + start: '2026-08-10', + end: '2026-08-15', + }, + ], + }, + }) + + return ( + <> + + + {(array) => + array.value.map((range, i) => ( + + )) + } + + + ) +} + +function App() { + return ( +
    +

    Field Group example

    + +
    +

    Price Filter Form

    + +
    +
    +

    Age Range Form

    + +
    +
    +

    Swappable Date Ranges Form

    + +
    + +
    + ) +} + +ReactDOM.createRoot(document.getElementById('root')!).render() diff --git a/examples/react/field-groups/tsconfig.json b/examples/react/field-groups/tsconfig.json new file mode 100644 index 0000000000..0c75398c58 --- /dev/null +++ b/examples/react/field-groups/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/react/field-groups/vite.config.ts b/examples/react/field-groups/vite.config.ts new file mode 100644 index 0000000000..9ffcc67574 --- /dev/null +++ b/examples/react/field-groups/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], +}) diff --git a/examples/react/large-form/.eslintrc.cjs b/examples/react/large-form/.eslintrc.cjs deleted file mode 100644 index 35853b6175..0000000000 --- a/examples/react/large-form/.eslintrc.cjs +++ /dev/null @@ -1,11 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = { - extends: ['plugin:react/recommended', 'plugin:react-hooks/recommended'], - rules: { - 'react/no-children-prop': 'off', - }, -} - -module.exports = config diff --git a/examples/react/large-form/package.json b/examples/react/large-form/package.json index 1e08519d4d..01b07168ec 100644 --- a/examples/react/large-form/package.json +++ b/examples/react/large-form/package.json @@ -9,17 +9,16 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-form": "^1.33.3", - "react": "19.1.0", - "react-dom": "19.1.0" + "@tanstack/react-form": "^2.0.0-alpha.3", + "react": "19.2.8", + "react-dom": "19.2.8" }, "devDependencies": { - "@tanstack/react-devtools": "^0.9.7", - "@tanstack/react-form-devtools": "^0.2.32", - "@types/react": "~19.2.0", - "@types/react-dom": "^19.0.3", - "@vitejs/plugin-react": "^5.1.1", - "vite": "^7.2.2" + "@tanstack/react-devtools": "^0.10.5", + "@tanstack/react-form-devtools": "^1.0.0-alpha.3", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "vite": "^8.2.1" }, "browserslist": { "production": [ diff --git a/examples/react/large-form/src/components/text-fields.tsx b/examples/react/large-form/src/components/text-fields.tsx index aee444d6b1..79cbd05e84 100644 --- a/examples/react/large-form/src/components/text-fields.tsx +++ b/examples/react/large-form/src/components/text-fields.tsx @@ -1,24 +1,25 @@ -import { useSelector } from '@tanstack/react-form' -import { useFieldContext } from '../hooks/form-context.tsx' - -export default function TextField({ label }: { label: string }) { - const field = useFieldContext() - - const errors = useSelector(field.store, (state) => state.meta.errors) +import type { FieldWithValue } from '@tanstack/react-form' +export default function TextField({ + field, + label, +}: { + field: FieldWithValue + label: string +}) { return (
    - {errors.map((error: string) => ( -
    - {error} + {field.errors.map((error) => ( +
    + {error.message}
    ))}
    diff --git a/examples/react/large-form/src/features/people/address-fields.tsx b/examples/react/large-form/src/features/people/address-fields.tsx index 05a95b0015..3be1e4134f 100644 --- a/examples/react/large-form/src/features/people/address-fields.tsx +++ b/examples/react/large-form/src/features/people/address-fields.tsx @@ -1,33 +1,29 @@ -import { withForm } from '../../hooks/form.tsx' import { peopleFormOpts } from './shared-form.tsx' +import type { ReactFormType } from '@tanstack/react-form' -export const AddressFields = withForm({ - ...peopleFormOpts, - render: ({ form }) => { - return ( -
    -

    Address

    - } - /> - } - /> - } - /> - } - /> - } - /> -
    - ) - }, -}) +interface AddressFieldsProps { + form: ReactFormType +} + +export function AddressFields({ form }: AddressFieldsProps) { + return ( +
    +

    Address

    + + {(field) => } + + + {(field) => } + + + {(field) => } + + + {(field) => } + + + {(field) => } + +
    + ) +} diff --git a/examples/react/large-form/src/features/people/emergency-contact.tsx b/examples/react/large-form/src/features/people/emergency-contact.tsx index 69cc881606..8b7c0a23d2 100644 --- a/examples/react/large-form/src/features/people/emergency-contact.tsx +++ b/examples/react/large-form/src/features/people/emergency-contact.tsx @@ -1,22 +1,28 @@ -import { withFieldGroup } from '../../hooks/form' +import { defineAppFieldGroup } from '../../hooks/form' -export const FieldGroupEmergencyContact = withFieldGroup({ - defaultValues: { - phone: '', - fullName: '', - }, - render: function Render({ group }) { - return ( - <> - } - /> - } - /> - - ) - }, -}) +const fieldGroup = defineAppFieldGroup(({ strict }) => ({ + fullName: strict(), + phone: strict(), +})) + +function EmergencyContactFields({ + fields, +}: { + fields: typeof fieldGroup.fields +}) { + return ( + <> + + {(field) => } + + + {(field) => } + + + ) +} + +export const FieldGroupEmergencyContact = fieldGroup.bindComponent( + EmergencyContactFields, + 'fields', +) diff --git a/examples/react/large-form/src/features/people/page.tsx b/examples/react/large-form/src/features/people/page.tsx index a81d37c5e0..cfa28db97b 100644 --- a/examples/react/large-form/src/features/people/page.tsx +++ b/examples/react/large-form/src/features/people/page.tsx @@ -19,21 +19,24 @@ export const PeoplePage = () => { }} >

    Personal Information

    - } - /> - } - /> - } - /> + + {(field) => } + + + {(field) => } + + + {(field) => } +

    Emergency Contact

    - + diff --git a/examples/react/large-form/src/features/people/shared-form.tsx b/examples/react/large-form/src/features/people/shared-form.tsx index ea5402b7e8..18afb5ffaf 100644 --- a/examples/react/large-form/src/features/people/shared-form.tsx +++ b/examples/react/large-form/src/features/people/shared-form.tsx @@ -1,6 +1,6 @@ -import { formOptions } from '@tanstack/react-form' +import { appFormOptions } from '../../hooks/form.tsx' -export const peopleFormOpts = formOptions({ +export const peopleFormOpts = appFormOptions({ defaultValues: { fullName: '', email: '', @@ -17,29 +17,29 @@ export const peopleFormOpts = formOptions({ phone: '', }, }, - validators: { - onChangeAsync: async ({ value }) => { - const errors = { - fields: {}, - } as { - fields: Record - } - if (!value.fullName) { - errors.fields.fullName = 'Full name is required' - } - if (!value.phone) { - errors.fields.phone = 'Phone is required' - } - if (!value.emergencyContact.fullName) { - errors.fields['emergencyContact.fullName'] = - 'Emergency contact full name is required' - } - if (!value.emergencyContact.phone) { - errors.fields['emergencyContact.phone'] = - 'Emergency contact phone is required' - } + validators: [ + { + triggers: ['change'], + run: async ({ value, createErrorMap }) => { + const errors = createErrorMap() - return errors + if (!value.fullName) { + errors.fields.fullName = 'Full name is required' + } + if (!value.phone) { + errors.fields.phone = 'Phone is required' + } + if (!value.emergencyContact.fullName) { + errors.fields['emergencyContact.fullName'] = + 'Emergency contact full name is required' + } + if (!value.emergencyContact.phone) { + errors.fields['emergencyContact.phone'] = + 'Emergency contact phone is required' + } + + return errors + }, }, - }, + ], }) diff --git a/examples/react/large-form/src/hooks/form-context.tsx b/examples/react/large-form/src/hooks/form-context.tsx deleted file mode 100644 index 1a6b376d7d..0000000000 --- a/examples/react/large-form/src/hooks/form-context.tsx +++ /dev/null @@ -1,4 +0,0 @@ -import { createFormHookContexts } from '@tanstack/react-form' - -export const { fieldContext, useFieldContext, formContext, useFormContext } = - createFormHookContexts() diff --git a/examples/react/large-form/src/hooks/form.tsx b/examples/react/large-form/src/hooks/form.tsx index f1a9ed2c55..dc4f52fe24 100644 --- a/examples/react/large-form/src/hooks/form.tsx +++ b/examples/react/large-form/src/hooks/form.tsx @@ -1,8 +1,9 @@ -import { createFormHook } from '@tanstack/react-form' -import { lazy } from 'react' -import { fieldContext, formContext, useFormContext } from './form-context.tsx' +import { createFormHook, getFormHookHelpers } from '@tanstack/react-form' +import TextField from '../components/text-fields.tsx' -const TextField = lazy(() => import('../components/text-fields.tsx')) +const { fieldComponent } = getFormHookHelpers() + +const AppTextField = fieldComponent.strict(TextField, 'field') function SubscribeButton({ label }: { label: string }) { const form = useFormContext() @@ -13,13 +14,14 @@ function SubscribeButton({ label }: { label: string }) { ) } -export const { useAppForm, withForm, withFieldGroup } = createFormHook({ - fieldComponents: { - TextField, - }, - formComponents: { - SubscribeButton, - }, - fieldContext, - formContext, -}) +const { appFormOptions, defineAppFieldGroup, useAppForm, useFormContext } = + createFormHook({ + fieldComponents: { + TextField: AppTextField, + }, + formComponents: { + SubscribeButton, + }, + }) + +export { appFormOptions, defineAppFieldGroup, useAppForm } diff --git a/examples/react/multi-step-wizard/.eslintrc.cjs b/examples/react/multi-step-wizard/.eslintrc.cjs deleted file mode 100644 index 35853b6175..0000000000 --- a/examples/react/multi-step-wizard/.eslintrc.cjs +++ /dev/null @@ -1,11 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = { - extends: ['plugin:react/recommended', 'plugin:react-hooks/recommended'], - rules: { - 'react/no-children-prop': 'off', - }, -} - -module.exports = config diff --git a/examples/react/multi-step-wizard/package.json b/examples/react/multi-step-wizard/package.json index 5a7376c9cf..5132537c77 100644 --- a/examples/react/multi-step-wizard/package.json +++ b/examples/react/multi-step-wizard/package.json @@ -9,18 +9,17 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-form": "^1.33.3", - "react": "19.1.0", - "react-dom": "19.1.0", - "zod": "^3.25.76" + "@tanstack/react-form": "^2.0.0-alpha.3", + "react": "19.2.8", + "react-dom": "19.2.8", + "zod": "^4.4.3" }, "devDependencies": { - "@tanstack/react-devtools": "^0.9.7", - "@tanstack/react-form-devtools": "^0.2.32", - "@types/react": "~19.2.0", - "@types/react-dom": "^19.0.3", - "@vitejs/plugin-react": "^5.1.1", - "vite": "^7.2.2" + "@tanstack/react-devtools": "^0.10.5", + "@tanstack/react-form-devtools": "^1.0.0-alpha.3", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "vite": "^8.2.1" }, "browserslist": { "production": [ diff --git a/examples/react/multi-step-wizard/src/components/text-fields.tsx b/examples/react/multi-step-wizard/src/components/text-fields.tsx index 3bd004e82a..31f7434cc9 100644 --- a/examples/react/multi-step-wizard/src/components/text-fields.tsx +++ b/examples/react/multi-step-wizard/src/components/text-fields.tsx @@ -1,22 +1,23 @@ -import { useSelector } from '@tanstack/react-form' -import { useFieldContext } from '../hooks/form-context.tsx' - -export function TextField({ label }: { label: string }) { - const field = useFieldContext() - - const errors = useSelector(field.store, (state) => state.meta.errors) +import type { FieldWithValue } from '@tanstack/react-form' +export function TextField({ + field, + label, +}: { + field: FieldWithValue + label: string +}) { return (
    - {errors.map((error: { message: string }) => ( + {field.errors.map((error) => (
    {error.message}
    diff --git a/examples/react/multi-step-wizard/src/features/wizard/page.tsx b/examples/react/multi-step-wizard/src/features/wizard/page.tsx index 5ad6edf994..114858388f 100644 --- a/examples/react/multi-step-wizard/src/features/wizard/page.tsx +++ b/examples/react/multi-step-wizard/src/features/wizard/page.tsx @@ -1,8 +1,6 @@ -import { revalidateLogic } from '@tanstack/react-form' -import { z } from 'zod' import { useState } from 'react' import { useAppForm } from '../../hooks/form.tsx' -import { step1Schema, step2Schema, wizardFormOpts } from './shared-form.tsx' +import { wizardFormOpts } from './shared-form.tsx' import { Step2Form } from './step2-subform.tsx' import { Step1Form } from './step1-subform.tsx' @@ -10,25 +8,15 @@ export const WizardPage = () => { const [step, setStep] = useState(0) const form = useAppForm({ ...wizardFormOpts, - validationLogic: revalidateLogic(), - validators: { - // onDynamic is only used when `form.handleSubmit` is called itself. - // When `form.FormGroup`'s `handleSubmit` is called, it will only validate the current step's schema. - // This means that this schema will not be called when the user submits the form group, but instead when they submit the entire form. - onDynamic: z.object({ - step1: step1Schema, - step2: step2Schema, - }), - }, onSubmit: ({ value }) => { alert(`Form submitted: ${JSON.stringify(value)}`) }, }) return ( - <> + {step === 0 && } {step === 1 && } - + ) } diff --git a/examples/react/multi-step-wizard/src/features/wizard/shared-form.tsx b/examples/react/multi-step-wizard/src/features/wizard/shared-form.tsx index 6f059c02b0..516914445e 100644 --- a/examples/react/multi-step-wizard/src/features/wizard/shared-form.tsx +++ b/examples/react/multi-step-wizard/src/features/wizard/shared-form.tsx @@ -1,5 +1,6 @@ -import { formOptions } from '@tanstack/react-form' import z from 'zod' +import { createValidator } from '@tanstack/react-form' +import { appFormOptions } from '../../hooks/form.tsx' export const step1Schema = z.object({ name: z.string().min(2, 'Name must be at least 2 characters'), @@ -9,7 +10,20 @@ export const step2Schema = z.object({ name: z.string().min(3, 'Name must be at least 3 characters'), }) -export const wizardFormOpts = formOptions({ +export const stepValidator = createValidator({ + triggers: [ + { + trigger: 'change', + when: ({ groupApi, formApi }) => { + const submitTries = + groupApi?.state.submissionAttempts ?? formApi.state.submissionAttempts + return submitTries > 0 + }, + }, + ], +}) + +export const wizardFormOpts = appFormOptions({ defaultValues: { step1: { name: '', @@ -18,4 +32,16 @@ export const wizardFormOpts = formOptions({ name: '', }, }, + validators: [ + { + // This validator is only used when `form.handleSubmit` is called itself. + // When `form.FormGroup`'s `handleSubmit` is called, it will only validate the current step's schema. + // This means that this schema will not be called when the user submits the form group, but instead when they submit the entire form. + run: z.object({ + step1: step1Schema, + step2: step2Schema, + }), + triggers: [], + }, + ], }) diff --git a/examples/react/multi-step-wizard/src/features/wizard/step1-subform.tsx b/examples/react/multi-step-wizard/src/features/wizard/step1-subform.tsx index 2eb2e04c11..22c437cf2a 100644 --- a/examples/react/multi-step-wizard/src/features/wizard/step1-subform.tsx +++ b/examples/react/multi-step-wizard/src/features/wizard/step1-subform.tsx @@ -1,46 +1,42 @@ -import { withForm } from '../../hooks/form' -import { step1Schema, wizardFormOpts } from './shared-form' +import { step1Schema, stepValidator } from './shared-form' +import type { wizardFormOpts } from './shared-form' +import type { ReactFormType } from '@tanstack/react-form' -export const Step1Form = withForm({ - ...wizardFormOpts, - props: { - step: 0, - setStep: (_step: number) => {}, - }, - render: function Render({ form, step, setStep }) { - return ( - { - setStep(step + 1) - }} - onGroupSubmitInvalid={() => { - // Just like a form, you can also handle invalid submits at the group level, which is useful for multi-step wizards to prevent going to the next step if the current step is invalid - }} - > - {(formGroup) => ( -
    { - e.preventDefault() - e.stopPropagation() - formGroup.handleSubmit() - }} - > - - {(field) => } - +type WizardForm = ReactFormType - - - - {/* formGroup contains errorMaps and errors, just like forms and fields */} -
    {JSON.stringify(formGroup.state.meta.errorMap, null, 2)}
    - - )} -
    - ) - }, -}) +interface Step1FormProps { + form: WizardForm + step: number + setStep: (step: number) => void +} + +export function Step1Form({ form, step, setStep }: Step1FormProps) { + return ( + { + setStep(step + 1) + }} + onSubmitInvalid={() => { + // Just like a form, you can also handle invalid submits at the group level, which is useful for multi-step wizards to prevent going to the next step if the current step is invalid + }} + > + {(formGroup) => ( +
    { + e.preventDefault() + e.stopPropagation() + formGroup.handleSubmit() + }} + > + + {(field) => } + + + + + )} +
    + ) +} diff --git a/examples/react/multi-step-wizard/src/features/wizard/step2-subform.tsx b/examples/react/multi-step-wizard/src/features/wizard/step2-subform.tsx index 5e95c42c98..3630476757 100644 --- a/examples/react/multi-step-wizard/src/features/wizard/step2-subform.tsx +++ b/examples/react/multi-step-wizard/src/features/wizard/step2-subform.tsx @@ -1,42 +1,42 @@ -import { withForm } from '../../hooks/form' -import { step2Schema, wizardFormOpts } from './shared-form' +import { step2Schema, stepValidator } from './shared-form' +import type { wizardFormOpts } from './shared-form' +import type { ReactFormType } from '@tanstack/react-form' -export const Step2Form = withForm({ - ...wizardFormOpts, - props: { - step: 1, - setStep: (_step: number) => {}, - }, - render: function Render({ form, step, setStep }) { - return ( - { - form.handleSubmit() - }} - > - {(formGroup) => ( -
    { - e.preventDefault() - e.stopPropagation() - formGroup.handleSubmit() - }} - > - - {(field) => } - +type WizardForm = ReactFormType - - - - - - )} -
    - ) - }, -}) +interface Step2FormProps { + form: WizardForm + step: number + setStep: (step: number) => void +} + +export function Step2Form({ form, step, setStep }: Step2FormProps) { + return ( + { + form.handleSubmit() + }} + > + {(formGroup) => ( +
    { + e.preventDefault() + e.stopPropagation() + formGroup.handleSubmit() + }} + > + + {(field) => } + + + + + + )} +
    + ) +} diff --git a/examples/react/multi-step-wizard/src/hooks/form-context.tsx b/examples/react/multi-step-wizard/src/hooks/form-context.tsx deleted file mode 100644 index 1a6b376d7d..0000000000 --- a/examples/react/multi-step-wizard/src/hooks/form-context.tsx +++ /dev/null @@ -1,4 +0,0 @@ -import { createFormHookContexts } from '@tanstack/react-form' - -export const { fieldContext, useFieldContext, formContext, useFormContext } = - createFormHookContexts() diff --git a/examples/react/multi-step-wizard/src/hooks/form.tsx b/examples/react/multi-step-wizard/src/hooks/form.tsx index b1fc69c5a2..51ee8c0a7b 100644 --- a/examples/react/multi-step-wizard/src/hooks/form.tsx +++ b/examples/react/multi-step-wizard/src/hooks/form.tsx @@ -1,6 +1,9 @@ -import { createFormHook } from '@tanstack/react-form' +import { createFormHook, getFormHookHelpers } from '@tanstack/react-form' import { TextField } from '../components/text-fields.tsx' -import { fieldContext, formContext, useFormContext } from './form-context.tsx' + +const { fieldComponent } = getFormHookHelpers() + +const AppTextField = fieldComponent.strict(TextField, 'field') function SubscribeButton({ label }: { label: string }) { const form = useFormContext() @@ -15,13 +18,13 @@ function SubscribeButton({ label }: { label: string }) { ) } -export const { useAppForm, withForm, withFieldGroup } = createFormHook({ +const { appFormOptions, useAppForm, useFormContext } = createFormHook({ fieldComponents: { - TextField, + TextField: AppTextField, }, formComponents: { SubscribeButton, }, - fieldContext, - formContext, }) + +export { appFormOptions, useAppForm } diff --git a/examples/react/next-server-actions-zod/package.json b/examples/react/next-server-actions-zod/package.json index 9ffe253580..f4800f2eac 100644 --- a/examples/react/next-server-actions-zod/package.json +++ b/examples/react/next-server-actions-zod/package.json @@ -8,17 +8,17 @@ "_test:types": "tsc" }, "dependencies": { - "@tanstack/react-form-nextjs": "^1.33.3", - "@tanstack/react-store": "^0.11.0", - "next": "16.2.6", - "react": "19.1.0", - "react-dom": "19.1.0", - "zod": "^3.25.76" + "@tanstack/react-form": "^2.0.0-alpha.3", + "@tanstack/react-form-nextjs": "^2.0.0-alpha.3", + "next": "16.3.0", + "react": "19.2.8", + "react-dom": "19.2.8", + "zod": "^4.4.3" }, "devDependencies": { - "@types/node": "^24.1.0", - "@types/react": "~19.2.0", - "@types/react-dom": "^19.0.3", - "typescript": "5.9.3" + "@types/node": "^25.0.7", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "typescript": "^6.0.2" } } diff --git a/examples/react/next-server-actions-zod/src/app/action.ts b/examples/react/next-server-actions-zod/src/app/action.ts index 76ce9e6695..b9870bd645 100644 --- a/examples/react/next-server-actions-zod/src/app/action.ts +++ b/examples/react/next-server-actions-zod/src/app/action.ts @@ -1,39 +1,36 @@ 'use server' import { - ServerValidateError, - createServerValidate, -} from '@tanstack/react-form-nextjs' -import { z } from 'zod' + initialServerFormState, + serverValidateHelper, +} from '@tanstack/react-form' +import { next } from '@tanstack/react-form-nextjs' import { formOpts } from './shared-code' -const schema = z.object({ - age: z.coerce.number().min(12), - firstName: z.string(), +const { createServerValidate } = serverValidateHelper({ + framework: next({ + info: { + numbers: ['age'], + }, + }), }) -const serverValidate = createServerValidate({ - ...formOpts, - onServerValidate: schema, -}) +const serverValidate = createServerValidate(formOpts) -export default async function someAction(prev: unknown, formData: FormData) { - try { - const validatedData = await serverValidate(formData) - console.log('validatedData', validatedData) - // Persist the form data to the database - // await sql` - // INSERT INTO users (name, email, password) - // VALUES (${validatedData.name}, ${validatedData.email}, ${validatedData.password}) - // ` - } catch (e) { - if (e instanceof ServerValidateError) { - return e.formState - } +export default async function someAction(_prev: unknown, formData: FormData) { + const result = await serverValidate(formData) - // Some other error occurred while validating your form - throw e + if (!result.success) { + return result.serverState } + console.log('validatedData', result.values, result.validatorOutputs) + // Persist the form data to the database + // await sql` + // INSERT INTO users (name, email, password) + // VALUES (${result.values.firstName}, ${result.values.age}) + // ` + // Your form has successfully validated! + return initialServerFormState } diff --git a/examples/react/next-server-actions-zod/src/app/client-component.tsx b/examples/react/next-server-actions-zod/src/app/client-component.tsx index d7511a6499..241a03233a 100644 --- a/examples/react/next-server-actions-zod/src/app/client-component.tsx +++ b/examples/react/next-server-actions-zod/src/app/client-component.tsx @@ -1,57 +1,53 @@ 'use client' import { useActionState } from 'react' -import { - initialFormState, - mergeForm, - useForm, - useTransform, -} from '@tanstack/react-form-nextjs' -import { z } from 'zod' +import { initialServerFormState, useForm } from '@tanstack/react-form' import someAction from './action' import { formOpts } from './shared-code' export const ClientComp = () => { - const [state, action] = useActionState(someAction, initialFormState) + const [serverState, action, isPending] = useActionState( + someAction, + initialServerFormState, + ) const form = useForm({ ...formOpts, - transform: useTransform( - (baseForm) => mergeForm(baseForm, state ?? {}), - [state], - ), + serverState, }) return ( -
    form.handleSubmit()}> - - {(field) => { - return ( -
    - field.handleChange(e.target.valueAsNumber)} - /> - {field.state.meta.errors.map((error) => ( -

    {error?.message}

    - ))} -
    - ) - }} + { + e.preventDefault() + const errors = await form.handleSubmit() + if (errors.length === 0) { + e.target.submit() + } + }} + > + + {(field) => ( +
    + field.handleChange(e.target.valueAsNumber)} + /> + {field.errors.map((error) => ( +

    {error.message}

    + ))} +
    + )}
    [formState.canSubmit, formState.isSubmitting]} > {([canSubmit, isSubmitting]) => ( - )} diff --git a/examples/react/next-server-actions-zod/src/app/shared-code.ts b/examples/react/next-server-actions-zod/src/app/shared-code.ts index 119363084d..f0a63eb093 100644 --- a/examples/react/next-server-actions-zod/src/app/shared-code.ts +++ b/examples/react/next-server-actions-zod/src/app/shared-code.ts @@ -1,8 +1,27 @@ -import { formOptions } from '@tanstack/react-form-nextjs' +import { formOptions } from '@tanstack/react-form' +import { z } from 'zod' -export const formOpts = formOptions({ +const clientSchema = z.object({ + age: z.number().min(8), +}) + +const serverSchema = z.object({ + age: z.number().min(12), +}) + +export const formOpts = formOptions.strictSchema(clientSchema, { defaultValues: { - firstName: '', age: 0, }, + validators: [ + { + triggers: ['change'], + run: clientSchema, + }, + { + triggers: ['server'], + skipOnSubmit: true, + run: serverSchema, + }, + ], }) diff --git a/examples/react/next-server-actions-zod/tsconfig.json b/examples/react/next-server-actions-zod/tsconfig.json index 4c2b4986c1..b69e44ce12 100644 --- a/examples/react/next-server-actions-zod/tsconfig.json +++ b/examples/react/next-server-actions-zod/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "ES2017", "lib": ["DOM", "DOM.Iterable", "ESNext"], "allowJs": true, "skipLibCheck": true, diff --git a/examples/react/next-server-actions/package.json b/examples/react/next-server-actions/package.json index 28bdc4bd20..da886d7529 100644 --- a/examples/react/next-server-actions/package.json +++ b/examples/react/next-server-actions/package.json @@ -8,16 +8,16 @@ "_test:types": "tsc" }, "dependencies": { - "@tanstack/react-form-nextjs": "^1.33.3", - "@tanstack/react-store": "^0.11.0", - "next": "16.2.6", - "react": "19.1.0", - "react-dom": "19.1.0" + "@tanstack/react-form": "^2.0.0-alpha.3", + "@tanstack/react-form-nextjs": "^2.0.0-alpha.3", + "next": "16.3.0", + "react": "19.2.8", + "react-dom": "19.2.8" }, "devDependencies": { - "@types/node": "^24.1.0", - "@types/react": "~19.2.0", - "@types/react-dom": "^19.0.3", - "typescript": "5.9.3" + "@types/node": "^25.0.7", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "typescript": "^6.0.2" } } diff --git a/examples/react/next-server-actions/src/app/action.ts b/examples/react/next-server-actions/src/app/action.ts index 69ea1fd402..b9870bd645 100644 --- a/examples/react/next-server-actions/src/app/action.ts +++ b/examples/react/next-server-actions/src/app/action.ts @@ -1,37 +1,36 @@ 'use server' import { - ServerValidateError, - createServerValidate, -} from '@tanstack/react-form-nextjs' + initialServerFormState, + serverValidateHelper, +} from '@tanstack/react-form' +import { next } from '@tanstack/react-form-nextjs' import { formOpts } from './shared-code' -const serverValidate = createServerValidate({ - ...formOpts, - onServerValidate: ({ value }) => { - if (value.age < 12) { - return 'Server validation: You must be at least 12 to sign up' - } - }, +const { createServerValidate } = serverValidateHelper({ + framework: next({ + info: { + numbers: ['age'], + }, + }), }) -export default async function someAction(prev: unknown, formData: FormData) { - try { - const validatedData = await serverValidate(formData) - console.log('validatedData', validatedData) - // Persist the form data to the database - // await sql` - // INSERT INTO users (name, email, password) - // VALUES (${validatedData.name}, ${validatedData.email}, ${validatedData.password}) - // ` - } catch (e) { - if (e instanceof ServerValidateError) { - return e.formState - } +const serverValidate = createServerValidate(formOpts) - // Some other error occurred while validating your form - throw e +export default async function someAction(_prev: unknown, formData: FormData) { + const result = await serverValidate(formData) + + if (!result.success) { + return result.serverState } + console.log('validatedData', result.values, result.validatorOutputs) + // Persist the form data to the database + // await sql` + // INSERT INTO users (name, email, password) + // VALUES (${result.values.firstName}, ${result.values.age}) + // ` + // Your form has successfully validated! + return initialServerFormState } diff --git a/examples/react/next-server-actions/src/app/client-component.tsx b/examples/react/next-server-actions/src/app/client-component.tsx index 2b071ef532..a908d7e47d 100644 --- a/examples/react/next-server-actions/src/app/client-component.tsx +++ b/examples/react/next-server-actions/src/app/client-component.tsx @@ -1,53 +1,44 @@ 'use client' import { useActionState } from 'react' -import { - initialFormState, - mergeForm, - useForm, - useTransform, -} from '@tanstack/react-form-nextjs' -import { useStore } from '@tanstack/react-store' +import { initialServerFormState, useForm } from '@tanstack/react-form' import someAction from './action' import { formOpts } from './shared-code' export const ClientComp = () => { - const [state, action] = useActionState(someAction, initialFormState) + const [serverState, action, isPending] = useActionState( + someAction, + initialServerFormState, + ) const form = useForm({ ...formOpts, - transform: useTransform( - (baseForm) => mergeForm(baseForm, state ?? {}), - [state], - ), + serverState, }) - const formErrors = useStore(form.store, (formState) => formState.errors) - return ( - form.handleSubmit()}> - {formErrors.map((error) => ( -

    {error}

    - ))} - - - value < 8 ? 'Client validation: You must be at least 8' : undefined, - }} - > + { + e.preventDefault() + const errors = await form.handleSubmit() + if (errors.length === 0) { + e.target.submit() + } + }} + > + {(field) => { return (
    field.handleChange(e.target.valueAsNumber)} /> - {field.state.meta.errors.map((error) => ( -

    {error}

    + {field.errors.map((error) => ( +

    {error.message}

    ))}
    ) @@ -57,8 +48,8 @@ export const ClientComp = () => { selector={(formState) => [formState.canSubmit, formState.isSubmitting]} > {([canSubmit, isSubmitting]) => ( - )} diff --git a/examples/react/next-server-actions/src/app/shared-code.ts b/examples/react/next-server-actions/src/app/shared-code.ts index 119363084d..e5b8a0fead 100644 --- a/examples/react/next-server-actions/src/app/shared-code.ts +++ b/examples/react/next-server-actions/src/app/shared-code.ts @@ -1,8 +1,36 @@ -import { formOptions } from '@tanstack/react-form-nextjs' +import { formOptions } from '@tanstack/react-form' export const formOpts = formOptions({ defaultValues: { firstName: '', age: 0, }, + validators: [ + { + triggers: ['change'], + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() + + if (value.age < 8) { + errors.fields.age = 'Client validation: You must be at least 8' + } + + return errors + }, + }, + { + triggers: ['server'], + skipOnSubmit: true, + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() + + if (value.age < 12) { + errors.fields.age = + 'Server validation: You must be at least 12 to sign up' + } + + return errors + }, + }, + ], }) diff --git a/examples/react/next-server-actions/tsconfig.json b/examples/react/next-server-actions/tsconfig.json index 4c2b4986c1..b69e44ce12 100644 --- a/examples/react/next-server-actions/tsconfig.json +++ b/examples/react/next-server-actions/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "ES2017", "lib": ["DOM", "DOM.Iterable", "ESNext"], "allowJs": true, "skipLibCheck": true, diff --git a/examples/react/nextjs/.gitignore b/examples/react/nextjs/.gitignore new file mode 100644 index 0000000000..5ef6a52078 --- /dev/null +++ b/examples/react/nextjs/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/examples/react/nextjs/README.md b/examples/react/nextjs/README.md new file mode 100644 index 0000000000..e215bc4ccf --- /dev/null +++ b/examples/react/nextjs/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/examples/react/nextjs/app/action.ts b/examples/react/nextjs/app/action.ts new file mode 100644 index 0000000000..c7d05bd7df --- /dev/null +++ b/examples/react/nextjs/app/action.ts @@ -0,0 +1,30 @@ +'use server' + +import { + initialServerFormState, + serverValidateHelper, +} from '@tanstack/react-form' +import { next } from '@tanstack/react-form-nextjs' +import { formOpts } from './shared-code' + +const { createServerValidate } = serverValidateHelper({ + framework: next({ + info: { + numbers: ['age'], + }, + }), +}) + +const serverValidate = createServerValidate(formOpts) + +export default async function someAction(_prev: unknown, formData: FormData) { + const result = await serverValidate(formData) + + if (!result.success) { + return result.serverState + } + + console.log('validatedData', result.values, result.validatorOutputs) + + return initialServerFormState +} diff --git a/examples/react/nextjs/app/client-component.tsx b/examples/react/nextjs/app/client-component.tsx new file mode 100644 index 0000000000..e9464fecd7 --- /dev/null +++ b/examples/react/nextjs/app/client-component.tsx @@ -0,0 +1,82 @@ +'use client' + +import { useActionState } from 'react' +import { initialServerFormState, useForm } from '@tanstack/react-form' +import someAction from './action' +import { formOpts } from './shared-code' + +export const ClientComp = () => { + const [serverState, action, isPending] = useActionState( + someAction, + initialServerFormState, + ) + + const form = useForm({ + ...formOpts, + serverState, + }) + + return ( + { + e.preventDefault() + const errors = await form.handleSubmit() + if (errors.length === 0) { + e.target.submit() + } + }} + > + + {(field) => { + return ( +
    + + field.handleChange(e.target.value)} + /> + {field.meta.errors.map((error) => ( +

    {error.message}

    + ))} +
    + ) + }} +
    + + + {(field) => { + return ( +
    + + field.handleChange(e.target.valueAsNumber)} + /> + {field.meta.errors.map((error) => ( +

    {error.message}

    + ))} +
    + ) + }} +
    + [formState.canSubmit, formState.isSubmitting]} + > + {([canSubmit, isSubmitting]) => ( + + )} + + + ) +} diff --git a/examples/react/nextjs/app/devtools.tsx b/examples/react/nextjs/app/devtools.tsx new file mode 100644 index 0000000000..1de24e7aff --- /dev/null +++ b/examples/react/nextjs/app/devtools.tsx @@ -0,0 +1,15 @@ +'use client' + +import { TanStackDevtools } from '@tanstack/react-devtools' +import { formDevtoolsPlugin } from '@tanstack/react-form-devtools' + +export function Devtools() { + return ( + + ) +} diff --git a/examples/react/nextjs/app/layout.tsx b/examples/react/nextjs/app/layout.tsx new file mode 100644 index 0000000000..111474136e --- /dev/null +++ b/examples/react/nextjs/app/layout.tsx @@ -0,0 +1,18 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Create Next App', + description: 'Generated by create next app', +} + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/examples/react/nextjs/app/page.tsx b/examples/react/nextjs/app/page.tsx new file mode 100644 index 0000000000..395c64f641 --- /dev/null +++ b/examples/react/nextjs/app/page.tsx @@ -0,0 +1,11 @@ +import { ClientComp } from './client-component' +import { Devtools } from './devtools' + +export default function Home() { + return ( + <> + + + + ) +} diff --git a/examples/react/nextjs/app/shared-code.ts b/examples/react/nextjs/app/shared-code.ts new file mode 100644 index 0000000000..7c75fd1b93 --- /dev/null +++ b/examples/react/nextjs/app/shared-code.ts @@ -0,0 +1,40 @@ +import { formOptions } from '@tanstack/react-form' + +export const formOpts = formOptions({ + defaultValues: { + firstName: '', + age: 0, + }, + validators: [ + { + triggers: ['change'], + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() + + if (value.age < 8) { + errors.fields.age = 'Client validation: You must be at least 8' + } + + return errors + }, + }, + { + triggers: ['server'], + // This validator will only run on the server + skipOnSubmit: true, + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() + + if (!value.firstName.trim()) { + errors.fields.firstName = 'Server validation: First name is required' + } + + if (value.age < 13) { + errors.fields.age = 'Server validation: You must be at least 13' + } + + return errors + }, + }, + ], +}) diff --git a/examples/react/nextjs/eslint.config.mjs b/examples/react/nextjs/eslint.config.mjs new file mode 100644 index 0000000000..7fef4d3141 --- /dev/null +++ b/examples/react/nextjs/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from 'eslint/config' +import nextVitals from 'eslint-config-next/core-web-vitals' +import nextTs from 'eslint-config-next/typescript' + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + '.next/**', + 'out/**', + 'build/**', + 'next-env.d.ts', + ]), +]) + +export default eslintConfig diff --git a/examples/react/nextjs/next.config.ts b/examples/react/nextjs/next.config.ts new file mode 100644 index 0000000000..1830ed6a93 --- /dev/null +++ b/examples/react/nextjs/next.config.ts @@ -0,0 +1,5 @@ +import type { NextConfig } from 'next' + +const nextConfig: NextConfig = {/* config options here */} + +export default nextConfig diff --git a/examples/react/nextjs/package.json b/examples/react/nextjs/package.json new file mode 100644 index 0000000000..cd5dfd6053 --- /dev/null +++ b/examples/react/nextjs/package.json @@ -0,0 +1,29 @@ +{ + "name": "@tanstack/form-example-react-nextjs", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "@tanstack/react-form": "^2.0.0-alpha.3", + "@tanstack/react-form-nextjs": "^2.0.0-alpha.3", + "next": "16.3.0", + "react": "19.2.8", + "react-dom": "19.2.8" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@tanstack/react-devtools": "^0.10.5", + "@tanstack/react-form-devtools": "^1.0.0-alpha.3", + "@types/node": "^25.0.7", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "eslint": "^10.8.1", + "eslint-config-next": "16.3.0", + "typescript": "^6.0.2" + } +} diff --git a/examples/react/nextjs/pnpm-lock.yaml b/examples/react/nextjs/pnpm-lock.yaml new file mode 100644 index 0000000000..a0d0340ab2 --- /dev/null +++ b/examples/react/nextjs/pnpm-lock.yaml @@ -0,0 +1,4140 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + next: + specifier: 16.2.9 + version: 16.2.9(@babel/core@7.29.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: + specifier: 19.2.4 + version: 19.2.4 + react-dom: + specifier: 19.2.4 + version: 19.2.4(react@19.2.4) + devDependencies: + '@tailwindcss/postcss': + specifier: ^4 + version: 4.3.1 + '@types/node': + specifier: ^20 + version: 20.19.43 + '@types/react': + specifier: ^19 + version: 19.2.17 + '@types/react-dom': + specifier: ^19 + version: 19.2.3(@types/react@19.2.17) + eslint: + specifier: ^9 + version: 9.39.4(jiti@2.7.0) + eslint-config-next: + specifier: 16.2.9 + version: 16.2.9(@typescript-eslint/parser@8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + tailwindcss: + specifier: ^4 + version: 4.3.1 + typescript: + specifier: ^5 + version: 5.9.3 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.4': + resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@next/env@16.2.9': + resolution: {integrity: sha512-ki5VxxXfzD/9TDe13wyeTKIjQTAwBVpnr8KhRDUr8ltMUq1/NBpWNT5tiPoxiGl+PHM4X2ahSOiPk6iAimIzPg==} + + '@next/eslint-plugin-next@16.2.9': + resolution: {integrity: sha512-UZi8+YT/MLgTC9nrrn2Xd4lBYv1B7lVmtWHfPcthAI5Tt/C1LuDe6DfmtCtJ+WQod3ksY4VrKSvk3oMVAnL7qw==} + + '@next/swc-darwin-arm64@16.2.9': + resolution: {integrity: sha512-HkfxNYUCmcct0Xsqib5KxqMSHV4AHJq857BNRchyBDs4YS19aHzVfn1kDuBYKqLLQBjXgnkIsjV2Kd4d2wzYhw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@16.2.9': + resolution: {integrity: sha512-7IAtK4MeybpqRV9GRABWEhJ62mOS+rzWOzOTFie4cSEtm12xsoOMJRcECoZx3FHPzFAqN/IJtHqWAFOLfl152w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@16.2.9': + resolution: {integrity: sha512-hBD75iWpUtkL9SmQmcRhmLomn9jgkPzCEkbOcLgHymPEKzv+6ONy13RRiIEz/iEObjkS2Jlb5gYS2XGoS3X4rw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-musl@16.2.9': + resolution: {integrity: sha512-qZTI3pf9SGc/obr8NkQAekBxmp1QK+kVm+VAf3BALLfFAj+1kUhkTxmrWpVos9R/UYIA8AWX2p6cGI5WdwzVUA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-gnu@16.2.9': + resolution: {integrity: sha512-xm0HfRNX+UkH4R3c18ynswjj5o5uEj/7iI9p9omdtTSIsRCzQqkGMA+10nzJ4EHnYC3as65IMhbbl5fWRUWHYg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-musl@16.2.9': + resolution: {integrity: sha512-QumimHkGEG6vM3PfEDWKyKen03NcqLOkeKB1EfcPe7VxzmEiCa4jNnMyBn/US5zcd/VE1CI+O8Ovb3lfjVHfGw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@next/swc-win32-arm64-msvc@16.2.9': + resolution: {integrity: sha512-hzQpKZvw8rAwI6A2uQh6SacCSvNAXaIkPNsWwzqqfRiIMiXMfH936skDhz1OO6KpvdKkJrgHHtqQOq5PIXOvdQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@16.2.9': + resolution: {integrity: sha512-qr2VL3Ce5QrwgO2yh1ujSBawrimjVKX8FGF/cOynmdYKJY0BdHpGVNIRK1tqONB10Vkm25Ub1BD2bkjWs4+96w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tailwindcss/node@4.3.1': + resolution: {integrity: sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==} + + '@tailwindcss/oxide-android-arm64@4.3.1': + resolution: {integrity: sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.1': + resolution: {integrity: sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.1': + resolution: {integrity: sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.1': + resolution: {integrity: sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1': + resolution: {integrity: sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.1': + resolution: {integrity: sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.1': + resolution: {integrity: sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.1': + resolution: {integrity: sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.1': + resolution: {integrity: sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.1': + resolution: {integrity: sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.1': + resolution: {integrity: sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.1': + resolution: {integrity: sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.1': + resolution: {integrity: sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.3.1': + resolution: {integrity: sha512-dNJuNbdEJT/SWRuXTYP1WSamelsz3ztkUsdtWQPjrexysrTpaEPM40P/71knXiXLYEojqPOEGitVLLpPMS5T6A==} + + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/node@20.19.43': + resolution: {integrity: sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.17': + resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} + + '@typescript-eslint/eslint-plugin@8.62.0': + resolution: {integrity: sha512-o+mpz7EYiMzXoySXiKmzlabIvTVqUuK5yLrAedRPRDA0IpPFMUV1IXt6OqljIxX/kumN6EjUYp41Hqelh6p/Dw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.62.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/parser@8.62.0': + resolution: {integrity: sha512-dzHeT2gySzZtLDsuqxU9AkYgIsQoHAHtRBpOqM+Ofzx1Bwrd2RcCjQJ+6iQbsHOIR6NS33bF2W1k3blN1zLDrA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.62.0': + resolution: {integrity: sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.62.0': + resolution: {integrity: sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.62.0': + resolution: {integrity: sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.62.0': + resolution: {integrity: sha512-+g5O3j0w2ldzC86Pv6fvbO/xhAonbJFIdf/MKQ1d30gndlsVzUOE83ldfSE15Qrl9fhFjK6AovHs5Wpp6vx86w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.62.0': + resolution: {integrity: sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.62.0': + resolution: {integrity: sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.62.0': + resolution: {integrity: sha512-82r66fi9zYwZ+mTq3vKgwjbZ1PVk/DJzrXFLpG6RnBbdvH8TEGVHIs9H4d2drhkOzf0syZuD/OZvvlu6GDbP4g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.62.0': + resolution: {integrity: sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.12.2': + resolution: {integrity: sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + resolution: {integrity: sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.12.2': + resolution: {integrity: sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + resolution: {integrity: sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + resolution: {integrity: sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + resolution: {integrity: sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} + cpu: [arm64] + os: [openharmony] + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + resolution: {integrity: sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + resolution: {integrity: sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + resolution: {integrity: sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + resolution: {integrity: sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==} + cpu: [x64] + os: [win32] + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.12.1: + resolution: {integrity: sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==} + engines: {node: '>=4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + baseline-browser-mapping@2.10.40: + resolution: {integrity: sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw==} + engines: {node: '>=6.0.0'} + hasBin: true + + brace-expansion@1.1.15: + resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==} + + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + engines: {node: 18 || 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.4: + resolution: {integrity: sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001799: + resolution: {integrity: sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + electron-to-chromium@1.5.379: + resolution: {integrity: sha512-v/qV5aV5EUA2pGilzUCq5/eyOloZAqDZBu9UMBIzgPpLlprjSR6zswsWBTv0KpqxLGUAZEwhO95ZCt7srymNVA==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enhanced-resolve@5.21.6: + resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} + engines: {node: '>=10.13.0'} + + es-abstract-get@1.0.0: + resolution: {integrity: sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==} + engines: {node: '>= 0.4'} + + es-abstract@1.24.2: + resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-iterator-helpers@1.3.3: + resolution: {integrity: sha512-0PuBxFi+4uPanB97iDxCLWuHeYud2FALrw5HFZGtAF38UpJDbDC8frwp2cnDyae692CQ0dou60UwWfhgsa4U/g==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.4: + resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-next@16.2.9: + resolution: {integrity: sha512-olGtBrs07bQchpaJWeqbk9GaMoU0oGmN/pYNEBXSbfgKngb5uHnPe37X6tVeh6DJfaWFQildvinGEOrolo5fmw==} + peerDependencies: + eslint: '>=9.0.0' + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + + eslint-import-resolver-node@0.3.10: + resolution: {integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==} + + eslint-import-resolver-typescript@3.10.1: + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.13.0: + resolution: {integrity: sha512-bLohSkT6469rRs8czj0tLTD8vaeIS/whvPRJVjDr7IuoTT1k5DYDERlNycjDj/HkOlvQdYurmfZ/g3fG5bgeLQ==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.10.2: + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 + + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.4: + resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.2.0: + resolution: {integrity: sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.4.0: + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-document.all@1.0.0: + resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.2.0: + resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.15: + resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + next@16.2.9: + resolution: {integrity: sha512-MEOJiq/UvuezAdqVSceHbqDgZt1kDw2tpGVOlsdIoJsQdbN2JY2hpVG4xnXGkbdJUOEWhnRfiu/O4Hpc9Juwww==} + engines: {node: '>=20.9.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-exports-info@1.6.2: + resolution: {integrity: sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==} + engines: {node: '>= 0.4'} + + node-releases@2.0.50: + resolution: {integrity: sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==} + engines: {node: '>=18'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + peerDependencies: + react: ^19.2.4 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + engines: {node: '>=0.10.0'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@2.0.0-next.7: + resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} + engines: {node: '>= 0.4'} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.4: + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} + engines: {node: '>=0.4'} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stable-hash@0.0.5: + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.11: + resolution: {integrity: sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.10: + resolution: {integrity: sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tailwindcss@4.3.1: + resolution: {integrity: sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.8: + resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} + engines: {node: '>= 0.4'} + + typescript-eslint@8.62.0: + resolution: {integrity: sha512-8QxXi+ZACKX0kaqO4gY8kn0RSD9gFfaHDWwjqtEN48aWCBkX4MJaufWN+c3BzlrXLOxfywDL8CaoqUwcRq4j4Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unrs-resolver@1.12.2: + resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.22: + resolution: {integrity: sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.7': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.4 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': + dependencies: + eslint: 9.39.4(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.5': + dependencies: + ajv: 6.15.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.2.0 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.4': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@next/env@16.2.9': {} + + '@next/eslint-plugin-next@16.2.9': + dependencies: + fast-glob: 3.3.1 + + '@next/swc-darwin-arm64@16.2.9': + optional: true + + '@next/swc-darwin-x64@16.2.9': + optional: true + + '@next/swc-linux-arm64-gnu@16.2.9': + optional: true + + '@next/swc-linux-arm64-musl@16.2.9': + optional: true + + '@next/swc-linux-x64-gnu@16.2.9': + optional: true + + '@next/swc-linux-x64-musl@16.2.9': + optional: true + + '@next/swc-win32-arm64-msvc@16.2.9': + optional: true + + '@next/swc-win32-x64-msvc@16.2.9': + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@nolyfill/is-core-module@1.0.39': {} + + '@rtsao/scc@1.1.0': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/node@4.3.1': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.21.6 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.1 + + '@tailwindcss/oxide-android-arm64@4.3.1': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.1': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.1': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.1': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.1': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.1': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.1': + optional: true + + '@tailwindcss/oxide@4.3.1': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.1 + '@tailwindcss/oxide-darwin-arm64': 4.3.1 + '@tailwindcss/oxide-darwin-x64': 4.3.1 + '@tailwindcss/oxide-freebsd-x64': 4.3.1 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.1 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.1 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.1 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.1 + '@tailwindcss/oxide-linux-x64-musl': 4.3.1 + '@tailwindcss/oxide-wasm32-wasi': 4.3.1 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.1 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.1 + + '@tailwindcss/postcss@4.3.1': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.3.1 + '@tailwindcss/oxide': 4.3.1 + postcss: 8.5.15 + tailwindcss: 4.3.1 + + '@tybys/wasm-util@0.10.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/estree@1.0.9': {} + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/node@20.19.43': + dependencies: + undici-types: 6.21.0 + + '@types/react-dom@19.2.3(@types/react@19.2.17)': + dependencies: + '@types/react': 19.2.17 + + '@types/react@19.2.17': + dependencies: + csstype: 3.2.3 + + '@typescript-eslint/eslint-plugin@8.62.0(@typescript-eslint/parser@8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.62.0 + '@typescript-eslint/type-utils': 8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.62.0 + eslint: 9.39.4(jiti@2.7.0) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.62.0 + '@typescript-eslint/types': 8.62.0 + '@typescript-eslint/typescript-estree': 8.62.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.62.0 + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.62.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.62.0(typescript@5.9.3) + '@typescript-eslint/types': 8.62.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.62.0': + dependencies: + '@typescript-eslint/types': 8.62.0 + '@typescript-eslint/visitor-keys': 8.62.0 + + '@typescript-eslint/tsconfig-utils@8.62.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.62.0 + '@typescript-eslint/typescript-estree': 8.62.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.62.0': {} + + '@typescript-eslint/typescript-estree@8.62.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.62.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.62.0(typescript@5.9.3) + '@typescript-eslint/types': 8.62.0 + '@typescript-eslint/visitor-keys': 8.62.0 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.62.0 + '@typescript-eslint/types': 8.62.0 + '@typescript-eslint/typescript-estree': 8.62.0(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.62.0': + dependencies: + '@typescript-eslint/types': 8.62.0 + eslint-visitor-keys: 5.0.1 + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + optional: true + + '@unrs/resolver-binding-android-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + optional: true + + acorn-jsx@5.3.2(acorn@8.17.0): + dependencies: + acorn: 8.17.0 + + acorn@8.17.0: {} + + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + ast-types-flow@0.0.8: {} + + async-function@1.0.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.12.1: {} + + axobject-query@4.1.0: {} + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.10.40: {} + + brace-expansion@1.1.15: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@5.0.6: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.4: + dependencies: + baseline-browser-mapping: 2.10.40 + caniuse-lite: 1.0.30001799 + electron-to-chromium: 1.5.379 + node-releases: 2.0.50 + update-browserslist-db: 1.2.3(browserslist@4.28.4) + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.9: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001799: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + client-only@0.0.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + damerau-levenshtein@1.0.8: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + detect-libc@2.1.2: {} + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + electron-to-chromium@1.5.379: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.21.6: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + es-abstract-get@1.0.0: + dependencies: + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + is-callable: 1.2.7 + object-inspect: 1.13.4 + + es-abstract@1.24.2: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.4 + function.prototype.name: 1.2.0 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.4 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.11 + string.prototype.trimend: 1.0.10 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.8 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.22 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.3.3: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + math-intrinsics: 1.1.0 + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.4 + + es-to-primitive@1.3.4: + dependencies: + es-abstract-get: 1.0.0 + es-define-property: 1.0.1 + es-errors: 1.3.0 + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-next@16.2.9(@typescript-eslint/parser@8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): + dependencies: + '@next/eslint-plugin-next': 16.2.9 + eslint: 9.39.4(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react-hooks: 7.1.1(eslint@9.39.4(jiti@2.7.0)) + globals: 16.4.0 + typescript-eslint: 8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-import-resolver-node@0.3.10: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.2 + resolve: 2.0.0-next.7 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + get-tsconfig: 4.14.0 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.17 + unrs-resolver: 1.12.2 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.13.0(@typescript-eslint/parser@8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.39.4(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + hasown: 2.0.4 + is-core-module: 2.16.2 + is-glob: 4.0.3 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.10 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.4(jiti@2.7.0)): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.12.1 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.39.4(jiti@2.7.0) + hasown: 2.0.4 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-react-hooks@7.1.1(eslint@9.39.4(jiti@2.7.0)): + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.7 + eslint: 9.39.4(jiti@2.7.0) + hermes-parser: 0.25.1 + zod: 4.4.3 + zod-validation-error: 4.0.2(zod@4.4.3) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.7.0)): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.3.3 + eslint: 9.39.4(jiti@2.7.0) + estraverse: 5.3.0 + hasown: 2.0.4 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.7 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@9.39.4(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.39.4 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 + + flatted@3.4.2: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + function-bind@1.1.2: {} + + function.prototype.name@1.2.0: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + es-define-property: 1.0.1 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + hasown: 2.0.4 + is-callable: 1.2.7 + is-document.all: 1.0.0 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + gensync@1.0.0-beta.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.14.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@16.4.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.4 + side-channel: 1.1.1 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-bun-module@2.0.0: + dependencies: + semver: 7.8.5 + + is-callable@1.2.7: {} + + is-core-module@2.16.2: + dependencies: + hasown: 2.0.4 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-document.all@1.0.0: + dependencies: + call-bound: 1.0.4 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.22 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jiti@2.7.0: {} + + js-tokens@4.0.0: {} + + js-yaml@4.2.0: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + json5@2.2.3: {} + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.6 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.15 + + minimist@1.2.8: {} + + ms@2.1.3: {} + + nanoid@3.3.15: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + next@16.2.9(@babel/core@7.29.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + '@next/env': 16.2.9 + '@swc/helpers': 0.5.15 + baseline-browser-mapping: 2.10.40 + caniuse-lite: 1.0.30001799 + postcss: 8.4.31 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + styled-jsx: 5.1.6(@babel/core@7.29.7)(react@19.2.4) + optionalDependencies: + '@next/swc-darwin-arm64': 16.2.9 + '@next/swc-darwin-x64': 16.2.9 + '@next/swc-linux-arm64-gnu': 16.2.9 + '@next/swc-linux-arm64-musl': 16.2.9 + '@next/swc-linux-x64-gnu': 16.2.9 + '@next/swc-linux-x64-musl': 16.2.9 + '@next/swc-win32-arm64-msvc': 16.2.9 + '@next/swc-win32-x64-msvc': 16.2.9 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-exports-info@1.6.2: + dependencies: + array.prototype.flatmap: 1.3.3 + es-errors: 1.3.0 + object.entries: 1.1.9 + semver: 6.3.1 + + node-releases@2.0.50: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.4: {} + + possible-typed-array-names@1.1.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.15 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.15: + dependencies: + nanoid: 3.3.15 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + react-dom@19.2.4(react@19.2.4): + dependencies: + react: 19.2.4 + scheduler: 0.27.0 + + react-is@16.13.1: {} + + react@19.2.4: {} + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@2.0.0-next.7: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + node-exports-info: 1.6.2 + object-keys: 1.1.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.4: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + semver@7.8.5: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + source-map-js@1.2.1: {} + + stable-hash@0.0.5: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.1 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.trim@1.2.11: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + has-property-descriptors: 1.0.2 + safe-regex-test: 1.1.0 + + string.prototype.trimend@1.0.10: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + strip-bom@3.0.0: {} + + strip-json-comments@3.1.1: {} + + styled-jsx@5.1.6(@babel/core@7.29.7)(react@19.2.4): + dependencies: + client-only: 0.0.1 + react: 19.2.4 + optionalDependencies: + '@babel/core': 7.29.7 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tailwindcss@4.3.1: {} + + tapable@2.3.3: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@2.5.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.8: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript-eslint@8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.62.0(@typescript-eslint/parser@8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.62.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.21.0: {} + + unrs-resolver@1.12.2: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.12.2 + '@unrs/resolver-binding-android-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-x64': 1.12.2 + '@unrs/resolver-binding-freebsd-x64': 1.12.2 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-arm64-musl': 1.12.2 + '@unrs/resolver-binding-linux-loong64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-loong64-musl': 1.12.2 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-musl': 1.12.2 + '@unrs/resolver-binding-linux-s390x-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-musl': 1.12.2 + '@unrs/resolver-binding-openharmony-arm64': 1.12.2 + '@unrs/resolver-binding-wasm32-wasi': 1.12.2 + '@unrs/resolver-binding-win32-arm64-msvc': 1.12.2 + '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 + '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 + + update-browserslist-db@1.2.3(browserslist@4.28.4): + dependencies: + browserslist: 4.28.4 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.2.0 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.22 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.22: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + yallist@3.1.1: {} + + yocto-queue@0.1.0: {} + + zod-validation-error@4.0.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {} diff --git a/examples/react/nextjs/postcss.config.mjs b/examples/react/nextjs/postcss.config.mjs new file mode 100644 index 0000000000..ae85b2fe4d --- /dev/null +++ b/examples/react/nextjs/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + '@tailwindcss/postcss': {}, + }, +} + +export default config diff --git a/examples/react/nextjs/public/file.svg b/examples/react/nextjs/public/file.svg new file mode 100644 index 0000000000..004145cddf --- /dev/null +++ b/examples/react/nextjs/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/react/nextjs/public/globe.svg b/examples/react/nextjs/public/globe.svg new file mode 100644 index 0000000000..567f17b0d7 --- /dev/null +++ b/examples/react/nextjs/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/react/nextjs/public/next.svg b/examples/react/nextjs/public/next.svg new file mode 100644 index 0000000000..5174b28c56 --- /dev/null +++ b/examples/react/nextjs/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/react/nextjs/public/vercel.svg b/examples/react/nextjs/public/vercel.svg new file mode 100644 index 0000000000..7705396033 --- /dev/null +++ b/examples/react/nextjs/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/react/nextjs/public/window.svg b/examples/react/nextjs/public/window.svg new file mode 100644 index 0000000000..b2b2a44f6e --- /dev/null +++ b/examples/react/nextjs/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/react/nextjs/tsconfig.json b/examples/react/nextjs/tsconfig.json new file mode 100644 index 0000000000..3a13f90a77 --- /dev/null +++ b/examples/react/nextjs/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts", + "**/*.mts" + ], + "exclude": ["node_modules"] +} diff --git a/examples/react/query-integration/.eslintrc.cjs b/examples/react/query-integration/.eslintrc.cjs deleted file mode 100644 index 35853b6175..0000000000 --- a/examples/react/query-integration/.eslintrc.cjs +++ /dev/null @@ -1,11 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = { - extends: ['plugin:react/recommended', 'plugin:react-hooks/recommended'], - rules: { - 'react/no-children-prop': 'off', - }, -} - -module.exports = config diff --git a/examples/react/query-integration/package.json b/examples/react/query-integration/package.json index 75962ac071..1abd68fdff 100644 --- a/examples/react/query-integration/package.json +++ b/examples/react/query-integration/package.json @@ -9,18 +9,17 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-form": "^1.33.3", + "@tanstack/react-form": "^2.0.0-alpha.3", "@tanstack/react-query": "^5.89.0", - "react": "19.1.0", - "react-dom": "19.1.0" + "react": "19.2.8", + "react-dom": "19.2.8" }, "devDependencies": { - "@tanstack/react-devtools": "^0.9.7", - "@tanstack/react-form-devtools": "^0.2.32", - "@types/react": "~19.2.0", - "@types/react-dom": "^19.0.3", - "@vitejs/plugin-react": "^5.1.1", - "vite": "^7.2.2" + "@tanstack/react-devtools": "^0.10.5", + "@tanstack/react-form-devtools": "^1.0.0-alpha.3", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "vite": "^8.2.1" }, "browserslist": { "production": [ diff --git a/examples/react/query-integration/src/app.tsx b/examples/react/query-integration/src/app.tsx new file mode 100644 index 0000000000..06cfbfa6f8 --- /dev/null +++ b/examples/react/query-integration/src/app.tsx @@ -0,0 +1,135 @@ +import { useForm } from '@tanstack/react-form' +import { keepPreviousData, useMutation, useQuery } from '@tanstack/react-query' +import { db, sleep } from './mock-db' +import type { StoredUser } from './mock-db' +import type { AnyFieldApi } from '@tanstack/react-form' + +function FieldInfo({ field }: { field: AnyFieldApi }) { + return ( + <> + {field.meta.isInvalid && ( + {field.errors.map((error) => error.message).join(',')} + )} + {field.meta.isValidating ? 'Validating...' : null} + + ) +} + +const emptyUser: StoredUser = { + firstName: '', + lastName: '', +} + +export function App() { + const userQuery = useQuery({ + queryKey: ['data'], + queryFn: () => db.getData(), + // Keeps the old values present while refetching new ones + placeholderData: keepPreviousData, + }) + + const saveUserMutation = useMutation({ + mutationFn: async (value: StoredUser) => { + return db.saveUser(value) + }, + onSuccess: async () => { + // Invalidating query to recheck fresh data + await userQuery.refetch() + }, + }) + + const form = useForm({ + defaultValues: userQuery.data ?? emptyUser, + onSubmit: async ({ formApi, value }) => { + await saveUserMutation.mutateAsync(value) + + // Pass optimistic values to the form so that it doesn't show old values + formApi.reset(value) + }, + // Only show errors if the field has been touched + errorVisibility: ({ fieldState }) => fieldState.meta.isTouched, + }) + + if (userQuery.isLoading) return

    Loading..

    + + return ( +
    +

    Simple Form Example

    +
    { + e.preventDefault() + e.stopPropagation() + form.handleSubmit() + }} + > + + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + triggers: ['change'], + }, + { + run: async ({ value }) => { + await sleep(1000) + return ( + value.includes('error') && 'No "error" allowed in first name' + ) + }, + triggers: ['change'], + triggerDebounceMs: 500, + }, + ]} + > + {(field) => ( +
    + + field.handleChange(e.target.value)} + /> + +
    + )} +
    + + {(field) => ( +
    + + field.handleChange(e.target.value)} + /> + +
    + )} +
    + [state.canSubmit, state.isSubmitting]} + > + {([canSubmit, isSubmitting]) => ( + <> + + + + )} + +
    +
    + ) +} diff --git a/examples/react/query-integration/src/index.tsx b/examples/react/query-integration/src/index.tsx index ec118de68d..5c782cd67d 100644 --- a/examples/react/query-integration/src/index.tsx +++ b/examples/react/query-integration/src/index.tsx @@ -1,166 +1,9 @@ import * as React from 'react' import { createRoot } from 'react-dom/client' - import { TanStackDevtools } from '@tanstack/react-devtools' import { formDevtoolsPlugin } from '@tanstack/react-form-devtools' -import { useForm } from '@tanstack/react-form' -import { - QueryClient, - QueryClientProvider, - useMutation, - useQuery, -} from '@tanstack/react-query' - -import type { AnyFieldApi } from '@tanstack/react-form' - -function FieldInfo({ field }: { field: AnyFieldApi }) { - return ( - <> - {field.state.meta.isTouched && !field.state.meta.isValid ? ( - {field.state.meta.errors.join(',')} - ) : null} - {field.state.meta.isValidating ? 'Validating...' : null} - - ) -} - -class DB { - private data: { firstName: string; lastName: string } - - constructor() { - this.data = { firstName: 'FirstName', lastName: 'LastName' } - } - - getData(): { firstName: string; lastName: string } { - return { ...this.data } - } - - async saveUser(value: { firstName: string; lastName: string }) { - this.data = value - return value - } -} - -// Dummy Database to emulate server-side actions -const db = new DB() - -export default function App() { - const { data, isLoading, refetch } = useQuery({ - queryKey: ['data'], - queryFn: async () => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return db.getData() - }, - }) - - const saveUserMutation = useMutation({ - mutationFn: async (value: { firstName: string; lastName: string }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - db.saveUser(value) - }, - }) - - const form = useForm({ - defaultValues: { - firstName: data?.firstName ?? '', - lastName: data?.lastName ?? '', - }, - onSubmit: async ({ formApi, value }) => { - // Do something with form data - await saveUserMutation.mutateAsync(value) - - // Invalidating query to recheck fresh data - await refetch() - - // Reset the form to start-over with a clean state - formApi.reset() - }, - }) - - if (isLoading) return

    Loading..

    - - return ( -
    -

    Simple Form Example

    -
    { - e.preventDefault() - e.stopPropagation() - form.handleSubmit() - }} - > -
    - {/* A type-safe field component*/} - - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined, - onChangeAsyncDebounceMs: 500, - onChangeAsync: async ({ value }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return ( - value.includes('error') && 'No "error" allowed in first name' - ) - }, - }} - children={(field) => { - // Avoid hasty abstractions. Render props are great! - return ( - <> - - field.handleChange(e.target.value)} - /> - - - ) - }} - /> -
    -
    - ( - <> - - field.handleChange(e.target.value)} - /> - - - )} - /> -
    - [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( - <> - - - - )} - /> - -
    - ) -} +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { App } from './app' const rootElement = document.getElementById('root')! diff --git a/examples/react/query-integration/src/mock-db.ts b/examples/react/query-integration/src/mock-db.ts new file mode 100644 index 0000000000..aa9b9eee9e --- /dev/null +++ b/examples/react/query-integration/src/mock-db.ts @@ -0,0 +1,32 @@ +export async function sleep(ms: number) { + return new Promise((res) => setTimeout(res, ms)) +} + +export interface StoredUser { + firstName: string + lastName: string +} + +class DB { + private data: StoredUser + + constructor() { + this.data = { firstName: 'FirstName', lastName: 'LastName' } + } + + async getData(): Promise { + await sleep(1000) + return { ...this.data } + } + + async saveUser(value: StoredUser) { + await sleep(1000) + this.data = value + return value + } +} + +/** + * Dummy Database to emulate server-side actions + */ +export const db = new DB() diff --git a/examples/react/remix/.gitignore b/examples/react/remix/.gitignore deleted file mode 100644 index 80ec311f4f..0000000000 --- a/examples/react/remix/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules - -/.cache -/build -.env diff --git a/examples/react/remix/README.md b/examples/react/remix/README.md deleted file mode 100644 index 6c4d2168fa..0000000000 --- a/examples/react/remix/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Welcome to Remix! - -- šŸ“– [Remix docs](https://remix.run/docs) - -## Development - -Run the dev server: - -```shellscript -npm run dev -``` - -## Deployment - -First, build your app for production: - -```sh -npm run build -``` - -Then run the app in production mode: - -```sh -npm start -``` - -Now you'll need to pick a host to deploy it to. - -### DIY - -If you're familiar with deploying Node applications, the built-in Remix app server is production-ready. - -Make sure to deploy the output of `npm run build` - -- `build/server` -- `build/client` - -## Styling - -This template comes with [Tailwind CSS](https://tailwindcss.com/) already configured for a simple default starting experience. You can use whatever css framework you prefer. See the [Vite docs on css](https://vitejs.dev/guide/features.html#css) for more information. diff --git a/examples/react/remix/app/root.tsx b/examples/react/remix/app/root.tsx deleted file mode 100644 index dfc07954d3..0000000000 --- a/examples/react/remix/app/root.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { - Links, - Meta, - Outlet, - Scripts, - ScrollRestoration, -} from '@remix-run/react' - -export function Layout({ children }: { children: React.ReactNode }) { - return ( - - - - - - - - - {children} - - - - - ) -} - -export default function App() { - return -} diff --git a/examples/react/remix/app/routes/_index/route.tsx b/examples/react/remix/app/routes/_index/route.tsx deleted file mode 100644 index e754b6d0f6..0000000000 --- a/examples/react/remix/app/routes/_index/route.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { Form, useActionData } from '@remix-run/react' - -import { - ServerValidateError, - createServerValidate, - formOptions, - mergeForm, - useForm, - useTransform, -} from '@tanstack/react-form-remix' -import { useStore } from '@tanstack/react-store' - -import type { ActionFunctionArgs } from '@remix-run/node' - -const formOpts = formOptions({ - defaultValues: { - firstName: '', - age: 0, - }, -}) - -const serverValidate = createServerValidate({ - ...formOpts, - onServerValidate: ({ value }) => { - if (value.age < 12) { - return 'Server validation: You must be at least 12 to sign up' - } - }, -}) - -export async function action({ request }: ActionFunctionArgs) { - const formData = await request.formData() - try { - const validatedData = await serverValidate(formData) - console.log('validatedData', validatedData) - // Persist the form data to the database - // await sql` - // INSERT INTO users (name, email, password) - // VALUES (${validatedData.name}, ${validatedData.email}, ${validatedData.password}) - // ` - } catch (e) { - if (e instanceof ServerValidateError) { - return e.formState - } - - // Some other error occurred while validating your form - throw e - } - - // Your form has successfully validated! - return null -} - -export default function Index() { - const actionData = useActionData() - - const form = useForm({ - ...formOpts, - transform: useTransform( - (baseForm) => mergeForm(baseForm, actionData ?? {}), - [actionData], - ), - }) - const formErrors = useStore(form.store, (formState) => formState.errors) - - return ( -
    form.handleSubmit()}> - {formErrors.map((error) => ( -

    {error}

    - ))} - - - value < 8 ? 'Client validation: You must be at least 8' : undefined, - }} - > - {(field) => { - return ( -
    - field.handleChange(e.target.valueAsNumber)} - /> - {field.state.meta.errors.map((error) => ( -

    {error}

    - ))} -
    - ) - }} -
    - [formState.canSubmit, formState.isSubmitting]} - > - {([canSubmit, isSubmitting]) => ( - - )} - -
    - ) -} diff --git a/examples/react/remix/package.json b/examples/react/remix/package.json deleted file mode 100644 index cd95eb62c5..0000000000 --- a/examples/react/remix/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "@tanstack/form-example-remix", - "private": true, - "type": "module", - "scripts": { - "build": "remix vite:build", - "dev": "remix vite:dev", - "_test:types": "tsc" - }, - "dependencies": { - "@remix-run/node": "^2.17.4", - "@remix-run/react": "^2.17.4", - "@remix-run/serve": "^2.17.4", - "@tanstack/react-form-remix": "^1.33.3", - "@tanstack/react-store": "^0.11.0", - "isbot": "^5.1.30", - "react": "19.1.0", - "react-dom": "19.1.0" - }, - "devDependencies": { - "@remix-run/dev": "^2.17.4", - "@types/react": "~19.2.0", - "@types/react-dom": "^19.0.3", - "typescript": "5.9.3", - "vite": "^7.2.2", - "vite-tsconfig-paths": "^5.1.4" - }, - "engines": { - "node": ">=20.0.0" - } -} diff --git a/examples/react/remix/public/favicon.ico b/examples/react/remix/public/favicon.ico deleted file mode 100644 index 8830cf6821..0000000000 Binary files a/examples/react/remix/public/favicon.ico and /dev/null differ diff --git a/examples/react/remix/tsconfig.json b/examples/react/remix/tsconfig.json deleted file mode 100644 index 9d87dd378f..0000000000 --- a/examples/react/remix/tsconfig.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "include": [ - "**/*.ts", - "**/*.tsx", - "**/.server/**/*.ts", - "**/.server/**/*.tsx", - "**/.client/**/*.ts", - "**/.client/**/*.tsx" - ], - "compilerOptions": { - "lib": ["DOM", "DOM.Iterable", "ES2022"], - "types": ["@remix-run/node", "vite/client"], - "isolatedModules": true, - "esModuleInterop": true, - "jsx": "react-jsx", - "module": "ESNext", - "moduleResolution": "Bundler", - "resolveJsonModule": true, - "target": "ES2022", - "strict": true, - "allowJs": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "baseUrl": ".", - "paths": { - "~/*": ["./app/*"] - }, - - // Vite takes care of building everything, not tsc. - "noEmit": true - } -} diff --git a/examples/react/remix/vite.config.ts b/examples/react/remix/vite.config.ts deleted file mode 100644 index 4c11441152..0000000000 --- a/examples/react/remix/vite.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { vitePlugin as remix } from '@remix-run/dev' -import { defineConfig } from 'vite' -import tsconfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - plugins: [ - remix({ - future: { - v3_fetcherPersist: true, - v3_relativeSplatPath: true, - v3_throwAbortReason: true, - }, - }), - tsconfigPaths(), - ], -}) diff --git a/examples/react/simple/.eslintrc.cjs b/examples/react/simple/.eslintrc.cjs deleted file mode 100644 index 35853b6175..0000000000 --- a/examples/react/simple/.eslintrc.cjs +++ /dev/null @@ -1,11 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = { - extends: ['plugin:react/recommended', 'plugin:react-hooks/recommended'], - rules: { - 'react/no-children-prop': 'off', - }, -} - -module.exports = config diff --git a/examples/react/simple/package.json b/examples/react/simple/package.json index 32d5782053..63aa46b07e 100644 --- a/examples/react/simple/package.json +++ b/examples/react/simple/package.json @@ -9,17 +9,16 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-form": "^1.33.3", - "react": "19.1.0", - "react-dom": "19.1.0" + "@tanstack/react-form": "^2.0.0-alpha.3", + "react": "19.2.8", + "react-dom": "19.2.8" }, "devDependencies": { - "@tanstack/react-devtools": "^0.9.7", - "@tanstack/react-form-devtools": "^0.2.32", - "@types/react": "~19.2.0", - "@types/react-dom": "^19.0.3", - "@vitejs/plugin-react": "^5.1.1", - "vite": "^7.2.2" + "@tanstack/react-devtools": "^0.10.5", + "@tanstack/react-form-devtools": "^1.0.0-alpha.3", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "vite": "^8.2.1" }, "browserslist": { "production": [ diff --git a/examples/react/simple/src/index.tsx b/examples/react/simple/src/index.tsx index 4228f1e0e9..dec6bcd0c1 100644 --- a/examples/react/simple/src/index.tsx +++ b/examples/react/simple/src/index.tsx @@ -10,10 +10,10 @@ import type { AnyFieldApi } from '@tanstack/react-form' function FieldInfo({ field }: { field: AnyFieldApi }) { return ( <> - {field.state.meta.isTouched && !field.state.meta.isValid ? ( - {field.state.meta.errors.join(',')} + {field.meta.isTouched && field.meta.isInvalid ? ( + {field.errors.map((error) => error.message).join(',')} ) : null} - {field.state.meta.isValidating ? 'Validating...' : null} + {field.meta.isValidating ? 'Validating...' : null} ) } @@ -44,22 +44,30 @@ export default function App() { {/* A type-safe field component*/} - !value - ? 'A first name is required' - : value.length < 3 - ? 'First name must be at least 3 characters' - : undefined, - onChangeAsyncDebounceMs: 500, - onChangeAsync: async ({ value }) => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - return ( - value.includes('error') && 'No "error" allowed in first name' - ) + validators={[ + { + run: ({ value }) => + !value + ? 'A first name is required' + : value.length < 3 + ? 'First name must be at least 3 characters' + : undefined, + triggers: ['change'], }, - }} - children={(field) => { + { + run: async ({ value }) => { + await new Promise((resolve) => setTimeout(resolve, 1000)) + return ( + value.includes('error') && + 'No "error" allowed in first name' + ) + }, + triggers: ['change'], + triggerDebounceMs: 500, + }, + ]} + > + {(field) => { // Avoid hasty abstractions. Render props are great! return ( <> @@ -67,7 +75,7 @@ export default function App() { field.handleChange(e.target.value)} /> @@ -75,29 +83,29 @@ export default function App() { ) }} - /> +
    - ( + + {(field) => ( <> field.handleChange(e.target.value)} /> )} - /> +
    [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( + > + {([canSubmit, isSubmitting]) => ( <> )} - /> +
    ) diff --git a/examples/react/standard-schema/.eslintrc.cjs b/examples/react/standard-schema/.eslintrc.cjs deleted file mode 100644 index 35853b6175..0000000000 --- a/examples/react/standard-schema/.eslintrc.cjs +++ /dev/null @@ -1,11 +0,0 @@ -// @ts-check - -/** @type {import('eslint').Linter.Config} */ -const config = { - extends: ['plugin:react/recommended', 'plugin:react-hooks/recommended'], - rules: { - 'react/no-children-prop': 'off', - }, -} - -module.exports = config diff --git a/examples/react/standard-schema/package.json b/examples/react/standard-schema/package.json index 05a0f5bc8f..38e0f4ea62 100644 --- a/examples/react/standard-schema/package.json +++ b/examples/react/standard-schema/package.json @@ -9,21 +9,20 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-form": "^1.33.3", + "@tanstack/react-form": "^2.0.0-alpha.3", "arktype": "^2.1.22", "effect": "^3.17.14", - "react": "19.1.0", - "react-dom": "19.1.0", + "react": "19.2.8", + "react-dom": "19.2.8", "valibot": "^1.1.0", - "zod": "^3.25.76" + "zod": "^4.4.3" }, "devDependencies": { - "@tanstack/react-devtools": "^0.9.7", - "@tanstack/react-form-devtools": "^0.2.32", - "@types/react": "~19.2.0", - "@types/react-dom": "^19.0.3", - "@vitejs/plugin-react": "^5.1.1", - "vite": "^7.2.2" + "@tanstack/react-devtools": "^0.10.5", + "@tanstack/react-form-devtools": "^1.0.0-alpha.3", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "vite": "^8.2.1" }, "browserslist": { "production": [ diff --git a/examples/react/standard-schema/src/index.tsx b/examples/react/standard-schema/src/index.tsx index 5a37446162..2f18bd6cfb 100644 --- a/examples/react/standard-schema/src/index.tsx +++ b/examples/react/standard-schema/src/index.tsx @@ -15,10 +15,10 @@ import type { AnyFieldApi } from '@tanstack/react-form' function FieldInfo({ field }: { field: AnyFieldApi }) { return ( <> - {field.state.meta.isTouched && !field.state.meta.isValid ? ( - {field.state.meta.errors.map((err) => err.message).join(',')} + {field.meta.isTouched && field.meta.isInvalid ? ( + {field.errors.map((err) => err.message).join(',')} ) : null} - {field.state.meta.isValidating ? 'Validating...' : null} + {field.meta.isValidating ? 'Validating...' : null} ) } @@ -71,13 +71,16 @@ export default function App() { firstName: '', lastName: '', }, - validators: { - // DEMO: You can switch between schemas seamlessly - onChange: ZodSchema, - // onChange: ValibotSchema, - // onChange: ArkTypeSchema, - // onChange: EffectSchema, - }, + validators: [ + { + // DEMO: You can switch between schemas seamlessly + run: ZodSchema, + // run: ValibotSchema, + // run: ArkTypeSchema, + // run: EffectSchema, + triggers: ['change'], + }, + ], onSubmit: async ({ value }) => { // Do something with form data console.log(value) @@ -96,9 +99,8 @@ export default function App() { >
    {/* A type-safe field component*/} - { + + {(field) => { // Avoid hasty abstractions. Render props are great! return ( <> @@ -106,7 +108,7 @@ export default function App() { field.handleChange(e.target.value)} /> @@ -114,34 +116,34 @@ export default function App() { ) }} - /> +
    - ( + + {(field) => ( <> field.handleChange(e.target.value)} /> )} - /> +
    [state.canSubmit, state.isSubmitting]} - children={([canSubmit, isSubmitting]) => ( + > + {([canSubmit, isSubmitting]) => ( )} - /> + ) diff --git a/examples/react/tanstack-start/.devcontainer/devcontainer.json b/examples/react/tanstack-start/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..e5dafce188 --- /dev/null +++ b/examples/react/tanstack-start/.devcontainer/devcontainer.json @@ -0,0 +1,3 @@ +{ + "image": "mcr.microsoft.com/devcontainers/typescript-node:24" +} diff --git a/examples/react/tanstack-start/.gitignore b/examples/react/tanstack-start/.gitignore index c699666748..6ab0517d9f 100644 --- a/examples/react/tanstack-start/.gitignore +++ b/examples/react/tanstack-start/.gitignore @@ -7,15 +7,14 @@ yarn.lock .env .vercel .output - +.nitro /build/ /api/ /server/build -/public/build -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ /blob-report/ /playwright/.cache/ -.tanstack +.tanstack \ No newline at end of file diff --git a/examples/react/tanstack-start/.prettierignore b/examples/react/tanstack-start/.prettierignore new file mode 100644 index 0000000000..2be5eaa6ec --- /dev/null +++ b/examples/react/tanstack-start/.prettierignore @@ -0,0 +1,4 @@ +**/build +**/public +pnpm-lock.yaml +routeTree.gen.ts \ No newline at end of file diff --git a/examples/react/tanstack-start/.vscode/settings.json b/examples/react/tanstack-start/.vscode/settings.json new file mode 100644 index 0000000000..00b5278e58 --- /dev/null +++ b/examples/react/tanstack-start/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "files.watcherExclude": { + "**/routeTree.gen.ts": true + }, + "search.exclude": { + "**/routeTree.gen.ts": true + }, + "files.readonlyInclude": { + "**/routeTree.gen.ts": true + } +} diff --git a/examples/react/tanstack-start/README.md b/examples/react/tanstack-start/README.md index eb580a5bf8..b0224e69d9 100644 --- a/examples/react/tanstack-start/README.md +++ b/examples/react/tanstack-start/README.md @@ -1,14 +1,13 @@ -# Welcome to TanStack.com! +# TanStack Form + TanStack Start Example -This site is built with TanStack Router! +This example shows TanStack React Form running inside TanStack Start with: -- [TanStack Router Docs](https://tanstack.com/router) +- client-side validation before the native form post +- server-side validation through `createServerFn` +- invalid server state persisted through `@tanstack/react-form-start` +- loader hydration of server errors after redirect -It's deployed automagically with Vercel! - -- [Vercel](https://vercel.com/) - -## Development +## Getting Started From your terminal: @@ -17,56 +16,12 @@ pnpm install pnpm dev ``` -This starts your app in development mode, rebuilding assets on file changes. - -## Editing and previewing the docs of TanStack projects locally - -The documentations for all TanStack projects except for `React Charts` are hosted on [https://tanstack.com](https://tanstack.com), powered by this TanStack Router app. -In production, the markdown doc pages are fetched from the GitHub repos of the projects, but in development they are read from the local file system. - -Follow these steps if you want to edit the doc pages of a project (in these steps we'll assume it's [`TanStack/form`](https://github.com/tanstack/form)) and preview them locally : - -1. Create a new directory called `tanstack`. - -```sh -mkdir tanstack -``` - -2. Enter the directory and clone this repo and the repo of the project there. - -```sh -cd tanstack -git clone git@github.com:TanStack/tanstack.com.git -git clone git@github.com:TanStack/form.git -``` - -> [!NOTE] -> Your `tanstack` directory should look like this: -> -> ``` -> tanstack/ -> | -> +-- form/ -> | -> +-- tanstack.com/ -> ``` +This starts the TanStack Start app in development mode. -> [!WARNING] -> Make sure the name of the directory in your local file system matches the name of the project's repo. For example, `tanstack/form` must be cloned into `form` (this is the default) instead of `some-other-name`, because that way, the doc pages won't be found. +## Build -3. Enter the `tanstack/tanstack.com` directory, install the dependencies and run the app in dev mode: +To build the app for production: ```sh -cd tanstack.com -pnpm i -# The app will run on https://localhost:3000 by default -pnpm dev +pnpm build ``` - -4. Now you can visit http://localhost:3000/form/latest/docs/overview in the browser and see the changes you make in `tanstack/form/docs`. - -> [!NOTE] -> The updated pages need to be manually reloaded in the browser. - -> [!WARNING] -> You will need to update the `docs/config.json` file (in the project's repo) if you add a new doc page! diff --git a/examples/react/tanstack-start/package.json b/examples/react/tanstack-start/package.json index 363f9efcd4..0993bbed0c 100644 --- a/examples/react/tanstack-start/package.json +++ b/examples/react/tanstack-start/package.json @@ -5,26 +5,28 @@ "type": "module", "scripts": { "dev": "vite dev", - "_build": "vite build && tsc --noEmit", + "build": "vite build && tsc --noEmit", + "preview": "vite preview", "start": "node .output/server/index.mjs" }, "dependencies": { - "@tanstack/react-form-start": "^1.33.3", - "@tanstack/react-router": "^1.134.9", - "@tanstack/react-start": "^1.168.27", - "@tanstack/react-store": "^0.11.0", - "react": "19.1.0", - "react-dom": "19.1.0" + "@tanstack/react-form": "^2.0.0-alpha.3", + "@tanstack/react-form-start": "^2.0.0-alpha.3", + "@tanstack/react-router": "^1.170.23", + "@tanstack/react-start": "^1.168.40", + "react": "19.2.8", + "react-dom": "19.2.8" }, "devDependencies": { - "@tanstack/react-devtools": "^0.9.7", - "@tanstack/react-form-devtools": "^0.2.32", - "@types/node": "^24.1.0", - "@types/react": "~19.2.0", - "@types/react-dom": "^19.0.3", - "@vitejs/plugin-react": "^5.1.1", - "typescript": "5.9.3", - "vite": "^7.2.2", - "vite-tsconfig-paths": "^5.1.4" + "@tailwindcss/vite": "^4.3.2", + "@tanstack/react-devtools": "^0.10.5", + "@tanstack/react-form-devtools": "^1.0.0-alpha.3", + "@types/node": "^25.0.7", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.1.1", + "nitro": "^3.0.260311-beta", + "typescript": "^6.0.2", + "vite": "^8.2.1" } } diff --git a/examples/react/tanstack-start/public/android-chrome-192x192.png b/examples/react/tanstack-start/public/android-chrome-192x192.png new file mode 100644 index 0000000000..09c8324f8c Binary files /dev/null and b/examples/react/tanstack-start/public/android-chrome-192x192.png differ diff --git a/examples/react/tanstack-start/public/android-chrome-512x512.png b/examples/react/tanstack-start/public/android-chrome-512x512.png new file mode 100644 index 0000000000..11d626ea3d Binary files /dev/null and b/examples/react/tanstack-start/public/android-chrome-512x512.png differ diff --git a/examples/react/tanstack-start/public/apple-touch-icon.png b/examples/react/tanstack-start/public/apple-touch-icon.png new file mode 100644 index 0000000000..5a9423cc02 Binary files /dev/null and b/examples/react/tanstack-start/public/apple-touch-icon.png differ diff --git a/examples/react/tanstack-start/public/emblem-light.svg b/examples/react/tanstack-start/public/emblem-light.svg deleted file mode 100644 index a58e69ad5e..0000000000 --- a/examples/react/tanstack-start/public/emblem-light.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - emblem-light - Created with Sketch. - - - - - - - - \ No newline at end of file diff --git a/examples/react/tanstack-start/public/favicon-16x16.png b/examples/react/tanstack-start/public/favicon-16x16.png new file mode 100644 index 0000000000..e3389b0044 Binary files /dev/null and b/examples/react/tanstack-start/public/favicon-16x16.png differ diff --git a/examples/react/tanstack-start/public/favicon-32x32.png b/examples/react/tanstack-start/public/favicon-32x32.png new file mode 100644 index 0000000000..900c77d444 Binary files /dev/null and b/examples/react/tanstack-start/public/favicon-32x32.png differ diff --git a/examples/react/tanstack-start/public/favicon.ico b/examples/react/tanstack-start/public/favicon.ico new file mode 100644 index 0000000000..1a1751676f Binary files /dev/null and b/examples/react/tanstack-start/public/favicon.ico differ diff --git a/examples/react/tanstack-start/public/favicon.png b/examples/react/tanstack-start/public/favicon.png new file mode 100644 index 0000000000..1e77bc0609 Binary files /dev/null and b/examples/react/tanstack-start/public/favicon.png differ diff --git a/examples/react/tanstack-start/public/site.webmanifest b/examples/react/tanstack-start/public/site.webmanifest new file mode 100644 index 0000000000..fa99de77db --- /dev/null +++ b/examples/react/tanstack-start/public/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/examples/react/tanstack-start/src/components/DefaultCatchBoundary.tsx b/examples/react/tanstack-start/src/components/DefaultCatchBoundary.tsx new file mode 100644 index 0000000000..829194e6b9 --- /dev/null +++ b/examples/react/tanstack-start/src/components/DefaultCatchBoundary.tsx @@ -0,0 +1,53 @@ +import { + ErrorComponent, + Link, + useLocation, + useRouter, +} from '@tanstack/react-router' +import type { ErrorComponentProps } from '@tanstack/react-router' + +export function DefaultCatchBoundary({ error }: ErrorComponentProps) { + const router = useRouter() + const isRoot = useLocation({ + select: (location) => location.pathname === '/', + }) + + console.error('DefaultCatchBoundary Error:', error) + + return ( +
    + +
    + + {isRoot ? ( + + Home + + ) : ( + { + e.preventDefault() + window.history.back() + }} + > + Go Back + + )} +
    +
    + ) +} diff --git a/examples/react/tanstack-start/src/components/NotFound.tsx b/examples/react/tanstack-start/src/components/NotFound.tsx new file mode 100644 index 0000000000..6914f5a7f3 --- /dev/null +++ b/examples/react/tanstack-start/src/components/NotFound.tsx @@ -0,0 +1,26 @@ +import { Link } from '@tanstack/react-router' + +export function NotFound({ children }: { children?: any }) { + return ( +
    +
    + {children ||

    The page you are looking for does not exist.

    } +
    +

    + + + Start Over + +

    +
    + ) +} diff --git a/examples/react/tanstack-start/src/router.tsx b/examples/react/tanstack-start/src/router.tsx index 765f1a8ca5..f380f73be7 100644 --- a/examples/react/tanstack-start/src/router.tsx +++ b/examples/react/tanstack-start/src/router.tsx @@ -1,18 +1,15 @@ -import { createRouter as createTanStackRouter } from '@tanstack/react-router' +import { createRouter } from '@tanstack/react-router' import { routeTree } from './routeTree.gen' +import { DefaultCatchBoundary } from './components/DefaultCatchBoundary' +import { NotFound } from './components/NotFound' export function getRouter() { - const router = createTanStackRouter({ + const router = createRouter({ routeTree, defaultPreload: 'intent', + defaultErrorComponent: DefaultCatchBoundary, + defaultNotFoundComponent: () => , scrollRestoration: true, }) - return router } - -declare module '@tanstack/react-router' { - interface Register { - router: ReturnType - } -} diff --git a/examples/react/tanstack-start/src/routes/__root.tsx b/examples/react/tanstack-start/src/routes/__root.tsx index 150971f05a..b7e7a266e9 100644 --- a/examples/react/tanstack-start/src/routes/__root.tsx +++ b/examples/react/tanstack-start/src/routes/__root.tsx @@ -1,5 +1,4 @@ import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router' - import { TanStackDevtools } from '@tanstack/react-devtools' import { formDevtoolsPlugin } from '@tanstack/react-form-devtools' diff --git a/examples/react/tanstack-start/src/routes/index.tsx b/examples/react/tanstack-start/src/routes/index.tsx index af0b43b3bd..8eb963849b 100644 --- a/examples/react/tanstack-start/src/routes/index.tsx +++ b/examples/react/tanstack-start/src/routes/index.tsx @@ -1,10 +1,17 @@ import { createFileRoute } from '@tanstack/react-router' -import { mergeForm, useForm, useTransform } from '@tanstack/react-form-start' -import { useStore } from '@tanstack/react-store' +import { useForm } from '@tanstack/react-form' +import { useServerFn } from '@tanstack/react-start' import { getFormDataFromServer, handleForm } from 'src/utils/form' import { formOpts } from 'src/utils/form-isomorphic' +type HomeSearch = { + status?: 'success' +} + export const Route = createFileRoute('/')({ + validateSearch: (search: Record): HomeSearch => { + return search.status === 'success' ? { status: 'success' } : {} + }, component: Home, loader: async () => ({ state: await getFormDataFromServer(), @@ -13,52 +20,142 @@ export const Route = createFileRoute('/')({ function Home() { const { state } = Route.useLoaderData() + const { status } = Route.useSearch() + const handleFormFn = useServerFn(handleForm) const form = useForm({ ...formOpts, - transform: useTransform((baseForm) => mergeForm(baseForm, state), [state]), + serverState: state, }) - const formErrors = useStore(form.store, (formState) => formState.errors) - return ( -
    - {formErrors.map((error) => ( -

    {error}

    - ))} +
    + {status === 'success' ? ( +

    + Form submitted successfully. +

    + ) : null} - - value < 8 ? 'Client validation: You must be at least 8' : undefined, - }} - > - {(field) => { - return ( -
    - field.handleChange(e.target.valueAsNumber)} - /> - {field.state.meta.errors.map((error) => ( -

    {error}

    - ))} -
    - ) +

    TanStack Start

    +

    Server validated form

    + { + event.preventDefault() + event.stopPropagation() + const formElement = event.currentTarget + const errors = await form.handleSubmit() + + if (errors.length === 0) { + await handleFormFn({ data: new FormData(formElement) }) + } }} -
    - [formState.canSubmit, formState.isSubmitting]} > - {([canSubmit, isSubmitting]) => ( - + )} + + + + + + formState.values}> + {(values) => ( + + {JSON.stringify(values, null, 2)} + )} - +
    ) } diff --git a/examples/react/tanstack-start/src/utils/form-isomorphic.ts b/examples/react/tanstack-start/src/utils/form-isomorphic.ts index 64ffcee0fb..7c75fd1b93 100644 --- a/examples/react/tanstack-start/src/utils/form-isomorphic.ts +++ b/examples/react/tanstack-start/src/utils/form-isomorphic.ts @@ -1,8 +1,40 @@ -import { formOptions } from '@tanstack/react-form-start' +import { formOptions } from '@tanstack/react-form' export const formOpts = formOptions({ defaultValues: { firstName: '', age: 0, }, + validators: [ + { + triggers: ['change'], + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() + + if (value.age < 8) { + errors.fields.age = 'Client validation: You must be at least 8' + } + + return errors + }, + }, + { + triggers: ['server'], + // This validator will only run on the server + skipOnSubmit: true, + run: ({ value, createErrorMap }) => { + const errors = createErrorMap() + + if (!value.firstName.trim()) { + errors.fields.firstName = 'Server validation: First name is required' + } + + if (value.age < 13) { + errors.fields.age = 'Server validation: You must be at least 13' + } + + return errors + }, + }, + ], }) diff --git a/examples/react/tanstack-start/src/utils/form-validator.ts b/examples/react/tanstack-start/src/utils/form-validator.ts new file mode 100644 index 0000000000..e00a3903eb --- /dev/null +++ b/examples/react/tanstack-start/src/utils/form-validator.ts @@ -0,0 +1,6 @@ +import { serverValidateHelper } from '@tanstack/react-form' +import { start } from '@tanstack/react-form-start' + +export const { createServerValidate } = serverValidateHelper({ + framework: start(), +}) diff --git a/examples/react/tanstack-start/src/utils/form.tsx b/examples/react/tanstack-start/src/utils/form.tsx index 307c567fe7..e36bd04f2a 100644 --- a/examples/react/tanstack-start/src/utils/form.tsx +++ b/examples/react/tanstack-start/src/utils/form.tsx @@ -1,47 +1,42 @@ import { createServerFn } from '@tanstack/react-start' -import { - ServerValidateError, - createServerValidate, - getFormData, -} from '@tanstack/react-form-start' -import { setResponseStatus } from '@tanstack/react-start/server' +import { redirect } from '@tanstack/react-router' import { formOpts } from './form-isomorphic' +import { createServerValidate } from './form-validator' -const serverValidate = createServerValidate({ - ...formOpts, - onServerValidate: ({ value }) => { - if (value.age < 12) { - return 'Server validation: You must be at least 12 to sign up' - } - }, -}) +const serverValidate = createServerValidate(formOpts) export const handleForm = createServerFn({ method: 'POST' }) - .validator((data: unknown) => { + .validator((data) => { if (!(data instanceof FormData)) { throw new Error('Invalid form data') } return data }) .handler(async (ctx) => { - try { - const validatedData = await serverValidate(ctx.data) - console.log('validatedData', validatedData) - } catch (e) { - if (e instanceof ServerValidateError) { - // Log form errors or do any other logic here - return e.response - } + const result = await serverValidate({ formData: ctx.data }) - setResponseStatus(500) - return 'There was an internal error' + if (!result.success) { + throw redirect({ to: '/', search: {} }) } - return 'Form has validated successfully' + console.info('validated form value', { + values: result.values, + validatorOutputs: result.validatorOutputs, + }) + + throw redirect({ + to: '/', + search: { + status: 'success', + }, + }) }) -export const getFormDataFromServer = createServerFn({ method: 'GET' }).handler( - async () => { - return getFormData() +export const getFormDataFromServer = createServerFn({ + method: 'GET', + strict: { + output: false, }, -) +}).handler(async () => { + return serverValidate.getFormData() +}) diff --git a/examples/react/tanstack-start/tsconfig.json b/examples/react/tanstack-start/tsconfig.json index 3a9fb7cd71..cd2374e118 100644 --- a/examples/react/tanstack-start/tsconfig.json +++ b/examples/react/tanstack-start/tsconfig.json @@ -1,21 +1,20 @@ { - "include": ["**/*.ts", "**/*.tsx"], + "include": ["**/*.ts", "**/*.tsx", "**/*.d.ts"], "compilerOptions": { "strict": true, "esModuleInterop": true, "jsx": "react-jsx", "module": "ESNext", "moduleResolution": "Bundler", - "lib": ["DOM", "DOM.Iterable", "ES2022"], + "lib": ["DOM", "DOM.Iterable", "ES2024"], "isolatedModules": true, "resolveJsonModule": true, "skipLibCheck": true, - "target": "ES2022", + "target": "ES2024", "allowJs": true, "forceConsistentCasingInFileNames": true, - "baseUrl": ".", "paths": { - "~/*": ["./src/*"] + "src/*": ["./src/*"] }, "noEmit": true } diff --git a/examples/react/tanstack-start/vite.config.ts b/examples/react/tanstack-start/vite.config.ts index f10c86e79f..65fa77fd66 100644 --- a/examples/react/tanstack-start/vite.config.ts +++ b/examples/react/tanstack-start/vite.config.ts @@ -1,17 +1,22 @@ import { tanstackStart } from '@tanstack/react-start/plugin/vite' import { defineConfig } from 'vite' -import tsConfigPaths from 'vite-tsconfig-paths' import viteReact from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' +import { nitro } from 'nitro/vite' export default defineConfig({ server: { port: 3000, }, + resolve: { + tsconfigPaths: true, + }, plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], + tailwindcss(), + tanstackStart({ + srcDirectory: 'src', }), - tanstackStart(), viteReact(), + nitro(), ], }) diff --git a/examples/react/ui-integration-dnd-kit/index.html b/examples/react/ui-integration-dnd-kit/index.html new file mode 100644 index 0000000000..96c4f15a13 --- /dev/null +++ b/examples/react/ui-integration-dnd-kit/index.html @@ -0,0 +1,14 @@ + + + + + + + TanStack Form React UI Integration (dnd kit) Example + + + +
    + + + diff --git a/examples/react/ui-integration-dnd-kit/package.json b/examples/react/ui-integration-dnd-kit/package.json new file mode 100644 index 0000000000..d7c351b5d5 --- /dev/null +++ b/examples/react/ui-integration-dnd-kit/package.json @@ -0,0 +1,27 @@ +{ + "name": "@tanstack/form-example-react-ui-integration-dnd-kit", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3005", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@dnd-kit/helpers": "^0.5.0", + "@dnd-kit/react": "^0.5.0", + "@tanstack/react-form": "^2.0.0-alpha.3", + "react": "19.2.8", + "react-dom": "19.2.8" + }, + "devDependencies": { + "@tanstack/react-devtools": "^0.10.5", + "@tanstack/react-form-devtools": "^1.0.0-alpha.3", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/react/ui-integration-dnd-kit/src/index.css b/examples/react/ui-integration-dnd-kit/src/index.css new file mode 100644 index 0000000000..4dd67934ad --- /dev/null +++ b/examples/react/ui-integration-dnd-kit/src/index.css @@ -0,0 +1,237 @@ +#root { + --color-text: #08060d; + --color-muted: #6d6578; + --color-border: #d9d3e3; + --color-surface: #ffffff; + --color-page: #f7f6f1; + --color-accent: #116466; + + background: var(--color-page); + color: var(--color-text); + max-width: 100%; + min-height: 100svh; + margin: 0; + box-sizing: border-box; + font-family: system-ui, 'Segoe UI', Roboto, sans-serif; +} + +#root .app-shell { + width: min(100% - 2rem, 48rem); + margin: 0 auto; + padding: 3rem 0; +} + +#root header { + margin-bottom: 1.5rem; +} + +#root h1 { + margin: 0; + font-size: 2.5rem; + line-height: 1; +} + +#root h2 { + margin: 0; + font-size: 1.35rem; +} + +#root h3 { + margin: 0; + font-size: 1.1rem; +} + +#root button { + font-size: 16px; + padding: 0.6rem 0.9rem; + border-radius: 0.4rem; + color: var(--color-text); + background: var(--color-surface); + border: 1px solid var(--color-border); + transition: + border-color 0.2s, + box-shadow 0.2s, + transform 0.2s; + font-family: ui-monospace, Consolas, monospace; + display: inline-flex; + align-items: center; + justify-content: center; + cursor: pointer; +} + +#root button:hover { + border-color: rgba(17, 100, 102, 0.55); + box-shadow: 0 0 0 3px rgba(17, 100, 102, 0.1); +} + +#root .array-form { + display: grid; + gap: 1rem; +} + +#root .examples-stack { + display: grid; + gap: 2.5rem; +} + +#root .example-section { + display: grid; + gap: 1rem; +} + +#root .example-header { + margin-bottom: 0; +} + +#root .toolbar { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} + +#root .toolbar button[type='submit'] { + color: white; + background: var(--color-accent); + border-color: var(--color-accent); +} + +#root .lists-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 1rem; + align-items: start; +} + +#root .lists-grid .list-section { + align-self: stretch; + padding: 0.85rem; + background: #efede7; + border: 1px solid #d4cedc; + border-radius: 0.5rem; +} + +#root .lists-grid .sortable-list { + min-height: 60rem; + align-content: start; +} + +#root .list-section { + display: grid; + gap: 0.75rem; + min-width: 0; +} + +#root ul { + list-style: none; + margin: 0; + padding: 0; +} + +#root .sortable-list { + display: grid; + gap: 0.75rem; +} + +#root .sortable-item { + display: grid; + grid-template-columns: 5.5rem minmax(0, 1fr); + align-items: end; + gap: 0.75rem; + min-width: 0; + padding: 1rem; + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: 0.5rem; + box-shadow: 0 0.5rem 1.5rem rgba(8, 6, 13, 0.06); +} + +#root .sortable-item[data-dragging='true'] { + opacity: 0.45; +} + +#root .sortable-item[data-drop-target='true'] { + border-color: var(--color-accent); + box-shadow: 0 0 0 3px rgba(17, 100, 102, 0.13); +} + +#root .list-drop-target { + min-height: 0.75rem; + border: 1px dashed transparent; + border-radius: 0.5rem; +} + +#root .list-drop-target[data-empty='true'] { + min-height: 4rem; +} + +#root .list-drop-target[data-drop-target='true'] { + border-color: rgba(17, 100, 102, 0.55); + background: rgba(17, 100, 102, 0.08); +} + +#root .drag-handle { + width: 100%; + height: 2.75rem; + color: var(--color-accent); + touch-action: none; + user-select: none; +} + +#root .item-field { + display: flex; + flex-direction: column; + gap: 0.35rem; + min-width: 0; + font-size: 0.95rem; + font-weight: 500; + color: var(--color-text); +} + +#root .item-field span { + color: var(--color-muted); +} + +#root input { + width: 100%; + box-sizing: border-box; + min-width: 0; + padding: 0.7rem 0.8rem; + border: 1px solid var(--color-border); + border-radius: 0.4rem; + font-size: 1rem; + color: var(--color-text); + background: white; +} + +#root input:focus { + outline: none; + border-color: var(--color-accent); + box-shadow: 0 0 0 3px rgba(17, 100, 102, 0.12); +} + +@media (max-width: 520px) { + #root .app-shell { + width: min(100% - 1rem, 48rem); + padding: 1.5rem 0; + } + + #root .sortable-item { + grid-template-columns: 1fr; + } + + #root .lists-grid { + grid-template-columns: 1fr; + } + + #root .lists-grid .sortable-list { + min-height: 14rem; + } + + #root .drag-handle { + height: 2.5rem; + } + + #root h1 { + font-size: 2rem; + } +} diff --git a/examples/react/ui-integration-dnd-kit/src/index.tsx b/examples/react/ui-integration-dnd-kit/src/index.tsx new file mode 100644 index 0000000000..f7be5b0400 --- /dev/null +++ b/examples/react/ui-integration-dnd-kit/src/index.tsx @@ -0,0 +1,28 @@ +import { TanStackDevtools } from '@tanstack/react-devtools' +import { formDevtoolsPlugin } from '@tanstack/react-form-devtools' +import { createRoot } from 'react-dom/client' +import { SingleListExample } from './singleList' +import { TwoListsExample } from './twoLists' +import './index.css' + +function App() { + return ( +
    +
    +

    Dnd-kit in TanStack Form Example

    +
    +
    + + +
    + +
    + ) +} + +createRoot(document.getElementById('root')!).render() diff --git a/examples/react/ui-integration-dnd-kit/src/sharedForm.ts b/examples/react/ui-integration-dnd-kit/src/sharedForm.ts new file mode 100644 index 0000000000..cdae42f879 --- /dev/null +++ b/examples/react/ui-integration-dnd-kit/src/sharedForm.ts @@ -0,0 +1,38 @@ +export type TodoId = string + +export type TodoItem = { + id: TodoId + label: string +} + +export const initialItems: Array = [ + { id: 'todo-1', label: 'Collect requirements' }, + { id: 'todo-2', label: 'Sketch the flow' }, + { id: 'todo-3', label: 'Wire the form' }, + { id: 'todo-4', label: 'Polish interactions' }, +] + +export const initialDoneItems: Array = [ + { id: 'todo-5', label: 'Review accessibility' }, + { id: 'todo-6', label: 'Ship example' }, +] + +const itemGroups = ['items', 'doneItems'] as const + +export type ItemGroup = (typeof itemGroups)[number] + +export const itemGroupLabels: Record = { + items: 'Planning', + doneItems: 'Done', +} + +let nextId = initialItems.length + initialDoneItems.length + 1 + +export function createItem(): TodoItem { + const id = nextId++ + + return { + id: `todo-${id}`, + label: `New item ${id}`, + } +} diff --git a/examples/react/ui-integration-dnd-kit/src/singleList/index.tsx b/examples/react/ui-integration-dnd-kit/src/singleList/index.tsx new file mode 100644 index 0000000000..a7950f8206 --- /dev/null +++ b/examples/react/ui-integration-dnd-kit/src/singleList/index.tsx @@ -0,0 +1,140 @@ +import { DragDropProvider } from '@dnd-kit/react' +import { isSortable, useSortable } from '@dnd-kit/react/sortable' +import { formOptions, useForm } from '@tanstack/react-form' +import { createItem, initialItems } from '../sharedForm' +import type { DragEndEvent } from '@dnd-kit/react' +import type { ReactFormType } from '@tanstack/react-form' + +const singleListFormOptions = formOptions({ + defaultValues: { + items: initialItems.map((item) => ({ ...item })), + }, +}) + +type SingleListForm = ReactFormType + +interface SingleListItemProps { + form: SingleListForm + id: string + index: number +} + +function SingleListItem({ form, id, index }: SingleListItemProps) { + const { handleRef, isDragging, isDropTarget, ref } = useSortable({ + id, + index, + group: 'single-list', + type: 'single-list-item', + accept: 'single-list-item', + }) + const fieldName = `items[${index}].label` as const + + return ( +
  • + + + {(field) => ( + + )} + +
  • + ) +} + +function formatItems(items: Array<{ label: string }>) { + return items.map((item, index) => `${index + 1}. ${item.label}`).join('\n') +} + +function getSingleListDragEndHandler( + form: SingleListForm, +): (event: DragEndEvent) => void { + return (event) => { + if (event.canceled || !isSortable(event.operation.source)) { + return + } + + const { source } = event.operation + + if (source.initialIndex === source.index) { + return + } + + form.moveFieldValue('items', source.initialIndex, source.index) + } +} + +export function SingleListExample() { + const form = useForm({ + ...singleListFormOptions, + onSubmit: ({ value }) => { + alert(`Single list order:\n\n${formatItems(value.items)}`) + }, + }) + + return ( +
    +
    +

    Single list

    +
    + +
    { + event.preventDefault() + event.stopPropagation() + form.handleSubmit() + }} + > + +
    + + +
    + + + {(arrayField) => ( +
    +

    Items

    +
      + {arrayField.value.map((item, index) => ( + + ))} +
    +
    + )} +
    +
    +
    +
    + ) +} diff --git a/examples/react/ui-integration-dnd-kit/src/twoLists/SortableItem.tsx b/examples/react/ui-integration-dnd-kit/src/twoLists/SortableItem.tsx new file mode 100644 index 0000000000..84b4bbc5d9 --- /dev/null +++ b/examples/react/ui-integration-dnd-kit/src/twoLists/SortableItem.tsx @@ -0,0 +1,48 @@ +import { useSortable } from '@dnd-kit/react/sortable' +import type { ItemGroup, TodoId } from '../sharedForm' +import type { MultiListDndForm } from '.' + +interface SortableItemProps { + form: MultiListDndForm + group: ItemGroup + id: TodoId + index: number +} + +export function SortableItem(props: SortableItemProps) { + const { form, group, id, index } = props + + const { ref, handleRef, isDragging } = useSortable({ + id, + index, + type: 'todo-item', + accept: 'todo-item', + group, + }) + + return ( +
  • + + + {(field) => ( + + )} + +
  • + ) +} diff --git a/examples/react/ui-integration-dnd-kit/src/twoLists/index.tsx b/examples/react/ui-integration-dnd-kit/src/twoLists/index.tsx new file mode 100644 index 0000000000..0cb3bd4ff4 --- /dev/null +++ b/examples/react/ui-integration-dnd-kit/src/twoLists/index.tsx @@ -0,0 +1,142 @@ +import { DragDropProvider, useDroppable } from '@dnd-kit/react' +import { batch, formOptions, useForm, useSelector } from '@tanstack/react-form' +import { move } from '@dnd-kit/helpers' +import { + createItem, + initialDoneItems, + initialItems, + itemGroupLabels, +} from '../sharedForm' +import { SortableItem } from './SortableItem' +import type { ReactFormType } from '@tanstack/react-form' +import type { ItemGroup, TodoId, TodoItem } from '../sharedForm' + +// Using the same array-field approach as the single-list example caused race +// conditions where React and dnd-kit fought over the UI and crashed when moving +// items across groups. This example avoids that by keeping item data keyed by ID +// and storing ordering separately. If you find a cleaner solution, PRs are +// welcome! +const multiListFormOptions = formOptions({ + defaultValues: { + items: initialItems.concat(initialDoneItems).reduce( + (record, item) => { + record[item.id] = { ...item } + return record + }, + {} as Record, + ), + itemOrder: { + items: initialItems.map((item) => item.id), + doneItems: initialDoneItems.map((item) => item.id), + }, + }, +}) + +export type MultiListDndForm = ReactFormType + +function formatItems( + ids: Array, + tasksById: Record, +) { + return ids + .map((id, index) => `${index + 1}. ${tasksById[id].label}`) + .join('\n') +} + +interface SortableListProps { + form: MultiListDndForm + group: ItemGroup + itemIds: Array +} + +function SortableList({ form, group, itemIds }: SortableListProps) { + const { ref } = useDroppable({ + id: `${group}-drop`, + type: 'column', + accept: 'item', + }) + + return ( +
    +

    {itemGroupLabels[group]}

    +
      + {itemIds.map((id, index) => ( + + ))} +
    +
    + ) +} + +export function TwoListsExample() { + const form = useForm({ + ...multiListFormOptions, + onSubmit: ({ value }) => { + const { items, itemOrder } = value + + const stringItems = formatItems(itemOrder.items, items) + const stringDoneItems = formatItems(itemOrder.doneItems, items) + alert( + `Submitted order:\n\n${itemGroupLabels.items}\n${stringItems}\n\n${itemGroupLabels.doneItems}\n${stringDoneItems}`, + ) + }, + }) + + const itemOrder = useSelector(form.atom, (state) => state.values.itemOrder) + + function handleCreate(group: ItemGroup) { + const item = createItem() + batch(() => { + form.pushFieldValue(`itemOrder.${group}`, item.id) + form.setFieldValue(`items.${item.id}`, item) + }) + } + + return ( +
    +
    +

    Two lists

    +
    + +
    { + event.preventDefault() + event.stopPropagation() + form.handleSubmit() + }} + > + { + form.setFieldValue('itemOrder', (items) => move(items, event)) + }} + > +
    + + + +
    + +
    + + +
    +
    +
    +
    + ) +} diff --git a/examples/react/ui-integration-dnd-kit/tsconfig.json b/examples/react/ui-integration-dnd-kit/tsconfig.json new file mode 100644 index 0000000000..0c75398c58 --- /dev/null +++ b/examples/react/ui-integration-dnd-kit/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/react/ui-integration-dnd-kit/vite.config.ts b/examples/react/ui-integration-dnd-kit/vite.config.ts new file mode 100644 index 0000000000..9ffcc67574 --- /dev/null +++ b/examples/react/ui-integration-dnd-kit/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], +}) diff --git a/examples/react/ui-integration-shadcn/components.json b/examples/react/ui-integration-shadcn/components.json new file mode 100644 index 0000000000..6e917be19b --- /dev/null +++ b/examples/react/ui-integration-shadcn/components.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "radix-nova", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/index.css", + "baseColor": "mauve", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "rtl": false, + "aliases": { + "components": "@/components", + "utils": "@/helpers/utils", + "ui": "@/components/ui", + "lib": "@/helpers", + "hooks": "@/hooks" + }, + "menuColor": "default", + "menuAccent": "subtle", + "registries": {} +} diff --git a/examples/react/ui-integration-shadcn/index.html b/examples/react/ui-integration-shadcn/index.html new file mode 100644 index 0000000000..827179c70d --- /dev/null +++ b/examples/react/ui-integration-shadcn/index.html @@ -0,0 +1,14 @@ + + + + + + + TanStack Form React UI Integration (shadcn/ui) Example + + + +
    + + + diff --git a/examples/react/ui-integration-shadcn/package.json b/examples/react/ui-integration-shadcn/package.json new file mode 100644 index 0000000000..f4f4a96bab --- /dev/null +++ b/examples/react/ui-integration-shadcn/package.json @@ -0,0 +1,39 @@ +{ + "name": "@tanstack/form-example-react-ui-integration-shadcn", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3005", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@fontsource-variable/inter": "^5.2.8", + "@tailwindcss/vite": "^4.3.2", + "@tanstack/react-form": "^2.0.0-alpha.3", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "date-fns": "^4.2.1", + "lucide-react": "^1.30.0", + "radix-ui": "^1.4.3", + "react": "19.2.8", + "react-day-picker": "^10.0.1", + "react-dom": "19.2.8", + "shadcn": "^4.16.2", + "tailwind-merge": "^3.6.0", + "tailwindcss": "^4.3.2", + "tw-animate-css": "^1.4.0", + "zod": "^4.4.3" + }, + "devDependencies": { + "@tanstack/devtools-vite": "^0.7.0", + "@tanstack/react-devtools": "^0.10.5", + "@tanstack/react-form-devtools": "^1.0.0-alpha.3", + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.1.1", + "typescript": "^6.0.2", + "vite": "^8.2.1" + } +} diff --git a/examples/react/ui-integration-shadcn/src/app/booking/add-ons-card.tsx b/examples/react/ui-integration-shadcn/src/app/booking/add-ons-card.tsx new file mode 100644 index 0000000000..c287285ddf --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/app/booking/add-ons-card.tsx @@ -0,0 +1,49 @@ +import { StepForm, rewardEarlyPunishLate } from './shared-form' +import { addOnsSchema } from './schema' +import type { BookingForm } from './shared-form' + +interface AddOnsCardProps { + form: BookingForm + onGroupSubmit: () => void +} + +function AddOnsCard({ form, onGroupSubmit }: AddOnsCardProps) { + return ( + + {(group) => ( + + + {(field) => ( + + + Include breakfast + + )} + + + {(field) => ( + + + Airport pickup + + )} + + + {(field) => ( + + + Parking required + + )} + + + )} + + ) +} + +export default AddOnsCard diff --git a/examples/react/ui-integration-shadcn/src/app/booking/booking-form.tsx b/examples/react/ui-integration-shadcn/src/app/booking/booking-form.tsx new file mode 100644 index 0000000000..af5be9b022 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/app/booking/booking-form.tsx @@ -0,0 +1,137 @@ +import { lazy } from 'react' +import { bookingFormOptions, formGroupId } from './shared-form' +import { BookingStepCard } from './booking-step-card' +import type { BookingForm } from './shared-form' +import { useAppForm } from '@/components/form/app-form' +import { + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from '@/components/ui/card' +import { Button } from '@/components/ui/button' +import { useStepper } from '@/hooks/useStepper' + +const GuestDetailsCard = lazy(() => import('./guest-details-card')) +const StayDatesCard = lazy(() => import('./stay-dates-card')) +const RoomPreferencesCard = lazy(() => import('./room-preferences-card')) +const BudgetCard = lazy(() => import('./budget-card')) +const AddOnsCard = lazy(() => import('./add-ons-card')) +const SpecialRequestsCard = lazy(() => import('./special-requests-card')) +const BookingSummaryCard = lazy(() => import('./booking-summary-card')) + +interface CardStepHeaderProps { + step: number +} + +function CardStepHeader({ step }: CardStepHeaderProps) { + let title: string + let description: string + switch (step) { + case 0: + title = 'Guest details' + description = 'Tell us who is staying.' + break + case 1: + title = 'Stay dates' + description = 'Choose your check-in and check-out dates.' + break + case 2: + title = 'Room preferences' + description = 'Select the room details that suit you.' + break + case 3: + title = 'Budget' + description = 'Set your preferred nightly maximum.' + break + case 4: + title = 'Add-ons' + description = 'Add services to your stay.' + break + case 5: + title = 'Special requests' + description = 'Share any details we should know before your stay.' + break + case 6: + default: + title = 'Review booking' + description = 'Confirm all details before requesting your booking.' + break + } + + return ( + + {title} + + Step {step + 1} of 7: {description} + + + ) +} + +interface CardSwitcherProps { + form: BookingForm + step: number + onNext: () => void +} + +function CardSwitcher({ form, step, onNext }: CardSwitcherProps) { + switch (step) { + case 0: + return + case 1: + return + case 2: + return + case 3: + return + case 4: + return + case 5: + return + case 6: + return + } +} + +export function BookingForm() { + const { step, toPreviousStep, toNextStep, isFirstStep, isLastStep } = + useStepper(0, 6) + const form = useAppForm({ + ...bookingFormOptions, + onSubmit: async ({ validatorOutputs: [result] }) => { + await new Promise((resolve) => setTimeout(resolve, 1000)) + alert('Form was submitted! See logs for result') + console.log(result) + }, + }) + + return ( + + + + + + + + {!isFirstStep && ( + + )} + {isLastStep && ( + + Request booking + + )} + {!isLastStep && ( + + )} + + + + ) +} diff --git a/examples/react/ui-integration-shadcn/src/app/booking/booking-step-card.tsx b/examples/react/ui-integration-shadcn/src/app/booking/booking-step-card.tsx new file mode 100644 index 0000000000..28ed2115db --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/app/booking/booking-step-card.tsx @@ -0,0 +1,79 @@ +import { + BedDouble, + CalendarDays, + ClipboardCheck, + MessageSquareText, + PlusCircle, + UserRound, + Wallet, +} from 'lucide-react' +import type { ReactNode } from 'react' +import type { LucideIcon } from 'lucide-react' +import { Card } from '@/components/ui/card' +import { cn } from '@/helpers/utils' + +interface BookingStep { + label: string + icon: LucideIcon +} + +const bookingSteps: Array = [ + { label: 'Guest details', icon: UserRound }, + { label: 'Stay dates', icon: CalendarDays }, + { label: 'Room preferences', icon: BedDouble }, + { label: 'Budget', icon: Wallet }, + { label: 'Add-ons', icon: PlusCircle }, + { label: 'Special requests', icon: MessageSquareText }, + { label: 'Review booking', icon: ClipboardCheck }, +] + +interface BookingStepCardProps { + currentStep: number + children: ReactNode +} + +export function BookingStepCard({ + currentStep, + children, +}: BookingStepCardProps) { + return ( + + +
    {children}
    +
    + ) +} diff --git a/examples/react/ui-integration-shadcn/src/app/booking/booking-summary-card.tsx b/examples/react/ui-integration-shadcn/src/app/booking/booking-summary-card.tsx new file mode 100644 index 0000000000..8a6dd63b38 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/app/booking/booking-summary-card.tsx @@ -0,0 +1,102 @@ +import { format } from 'date-fns' +import type { BookingForm } from './shared-form' + +import { Separator } from '@/components/ui/separator' + +interface BookingSummaryCardProps { + form: BookingForm +} + +function formatSelection(value: string) { + return ( + value + .split('-') + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + .map((word) => word[0]?.toUpperCase() + word.slice(1)) + .join(' ') + ) +} + +function BookingSummaryCard({ form }: BookingSummaryCardProps) { + return ( + + state.values}> + {(values) => { + const { from, to } = values.stayDates.dateRange + const addOns = [ + values.addOns.includeBreakfast && 'Breakfast', + values.addOns.airportPickup && 'Airport pickup', + values.addOns.parkingRequired && 'Parking', + ].filter(Boolean) + + return ( +
    +
    +

    Guest

    +

    {values.guestDetails.name}

    +

    + {values.guestDetails.email} |{' '} + {values.guestDetails.phoneNumber} +

    +

    + {values.guestDetails.guestCount}{' '} + {values.guestDetails.guestCount === 1 ? 'guest' : 'guests'} +

    +
    + +
    +
    +

    Stay

    +

    + {from && to + ? `${format(from, 'PPP')} - ${format(to, 'PPP')}` + : 'No dates selected'} +

    +

    + Arrival at {values.stayDates.arrivalTime} +

    +
    +
    +

    Room

    +

    {formatSelection(values.roomPreferences.roomType)} room

    +

    + {formatSelection(values.roomPreferences.bedPreference)} bed,{' '} + {formatSelection(values.roomPreferences.smokingPreference)} +

    +

    + {formatSelection(values.roomPreferences.floorPreference)} +

    +
    +
    + +
    +
    +

    Budget

    +

    + {values.budget.currency} {values.budget.maxNightlyBudget}{' '} + per night +

    +
    +
    +

    Add-ons

    +

    + {addOns.length ? addOns.join(', ') : 'No add-ons selected'} +

    +
    +
    + +
    +

    Special requests

    +

    + {values.specialRequests.notes || 'No special requests added.'} +

    +
    +
    + ) + }} +
    +
    + ) +} + +export default BookingSummaryCard diff --git a/examples/react/ui-integration-shadcn/src/app/booking/budget-card.tsx b/examples/react/ui-integration-shadcn/src/app/booking/budget-card.tsx new file mode 100644 index 0000000000..89028f49f5 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/app/booking/budget-card.tsx @@ -0,0 +1,50 @@ +import { StepForm, rewardEarlyPunishLate } from './shared-form' +import { budgetSchema } from './schema' +import type { BookingForm } from './shared-form' + +interface BudgetCardProps { + form: BookingForm + onGroupSubmit: () => void +} + +function BudgetCard({ form, onGroupSubmit }: BudgetCardProps) { + return ( + + {(group) => ( + + + {(field) => ( + + Maximum nightly budget + + + + )} + + + {(field) => ( + + Currency + + + + )} + + + )} + + ) +} + +export default BudgetCard diff --git a/examples/react/ui-integration-shadcn/src/app/booking/guest-details-card.tsx b/examples/react/ui-integration-shadcn/src/app/booking/guest-details-card.tsx new file mode 100644 index 0000000000..07b2bff91c --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/app/booking/guest-details-card.tsx @@ -0,0 +1,62 @@ +import { StepForm, rewardEarlyPunishLate } from './shared-form' +import { guestDetailsSchema } from './schema' +import type { BookingForm } from './shared-form' + +interface GuestDetailsCardProps { + form: BookingForm + onGroupSubmit: () => void +} + +function GuestDetailsCard({ form, onGroupSubmit }: GuestDetailsCardProps) { + return ( + + {(group) => ( + + + {(field) => ( + + Guest name + + + + )} + + + {(field) => } + + + {(field) => ( + + Email + + + + We'll use this to contact you. We will not share your + email with anyone else. + + + )} + + + {(field) => ( + + + Number of guests: + {field.value} + + + + + )} + + + )} + + ) +} + +export default GuestDetailsCard diff --git a/examples/react/ui-integration-shadcn/src/app/booking/room-preferences-card.tsx b/examples/react/ui-integration-shadcn/src/app/booking/room-preferences-card.tsx new file mode 100644 index 0000000000..04e6e2ef9c --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/app/booking/room-preferences-card.tsx @@ -0,0 +1,93 @@ +import { StepForm, rewardEarlyPunishLate } from './shared-form' +import { roomPreferencesSchema } from './schema' +import type { BookingForm } from './shared-form' + +interface RoomPreferencesCardProps { + form: BookingForm + onGroupSubmit: () => void +} + +function RoomPreferencesCard({ + form, + onGroupSubmit, +}: RoomPreferencesCardProps) { + return ( + + {(group) => ( + + + {(field) => ( + + Room type + + + + )} + + + {(field) => ( + + Bed preference + + + + )} + + + {(field) => ( + + Smoking preference + + + + )} + + + {(field) => ( + + Floor preference + + + + )} + + + )} + + ) +} + +export default RoomPreferencesCard diff --git a/examples/react/ui-integration-shadcn/src/app/booking/schema.ts b/examples/react/ui-integration-shadcn/src/app/booking/schema.ts new file mode 100644 index 0000000000..eab0d75a61 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/app/booking/schema.ts @@ -0,0 +1,54 @@ +import z from 'zod' +import type { DateRange } from 'react-day-picker' + +const completeSchemaCheck = z.object({ + from: z.date('Please select a date range.'), + to: z.date('Please select a date range.'), +}) + +const dateRangeSchema = z.custom().pipe(completeSchemaCheck) + +export const guestDetailsSchema = z.object({ + name: z.string().min(1, 'Please enter your name.'), + email: z.email('Please enter a valid email address.'), + phoneNumber: z.string().min(1, 'Please enter a phone number.'), + guestCount: z.int().min(1).max(6), +}) + +export const stayDatesSchema = z.object({ + dateRange: dateRangeSchema, + arrivalTime: z.string().min(1, 'Please select an arrival time.'), +}) + +export const roomPreferencesSchema = z.object({ + roomType: z.enum(['standard', 'deluxe', 'suite', 'penthouse']), + bedPreference: z.enum(['single', 'queen', 'king', 'twin']), + smokingPreference: z.enum(['non-smoking', 'smoking']), + floorPreference: z.enum(['low', 'high', 'no-preference']), +}) + +export const budgetSchema = z.object({ + maxNightlyBudget: z.number().positive('Please enter a nightly budget.'), + currency: z.enum(['USD', 'EUR', 'GBP']), +}) + +export const addOnsSchema = z.object({ + includeBreakfast: z.boolean(), + airportPickup: z.boolean(), + parkingRequired: z.boolean(), +}) + +export const specialRequestsSchema = z.object({ + notes: z + .string() + .max(500, 'Please keep special requests under 500 characters.'), +}) + +export const bookingFormSchema = z.object({ + guestDetails: guestDetailsSchema, + stayDates: stayDatesSchema, + roomPreferences: roomPreferencesSchema, + budget: budgetSchema, + addOns: addOnsSchema, + specialRequests: specialRequestsSchema, +}) diff --git a/examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx b/examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx new file mode 100644 index 0000000000..ea4bc1da35 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/app/booking/shared-form.tsx @@ -0,0 +1,83 @@ +import { createValidator } from '@tanstack/react-form' +import { bookingFormSchema } from './schema' +import type { ReactNode } from 'react' +import type { ReactFormType } from '@tanstack/react-form' +import { appFormOptions } from '@/components/form/app-form' +import { FieldGroup } from '@/components/ui/field' + +// form.FormGroup instead of FormGroup form={form} + +export const formGroupId = 'booking-form-step' as const + +export interface StepFormProps { + onSubmit: () => void + children: ReactNode +} +export function StepForm(props: StepFormProps) { + return ( +
    { + e.preventDefault() + e.stopPropagation() + void props.onSubmit() + }} + > + {props.children} +
    + ) +} + +export const rewardEarlyPunishLate = createValidator({ + triggers: [ + 'blur', + { + trigger: 'change', + when: ({ fieldApi }) => fieldApi !== undefined && fieldApi.meta.isInvalid, + }, + ], +}) + +export const bookingFormOptions = appFormOptions.strictSchema( + bookingFormSchema, + { + errorVisibility: ({ state, fieldState }) => + fieldState.meta.isBlurred || state.submissionAttempts > 0, + validators: [rewardEarlyPunishLate(bookingFormSchema)], + defaultValues: { + guestDetails: { + name: '', + email: '', + phoneNumber: '', + guestCount: 1, + }, + stayDates: { + dateRange: { + from: undefined, + to: undefined, + }, + arrivalTime: '', + }, + roomPreferences: { + roomType: 'standard', + bedPreference: 'queen', + smokingPreference: 'non-smoking', + floorPreference: 'no-preference', + }, + budget: { + maxNightlyBudget: 200, + currency: 'USD', + }, + addOns: { + includeBreakfast: false, + airportPickup: false, + parkingRequired: false, + }, + specialRequests: { + notes: '', + }, + }, + }, +) + +export type BookingForm = ReactFormType diff --git a/examples/react/ui-integration-shadcn/src/app/booking/special-requests-card.tsx b/examples/react/ui-integration-shadcn/src/app/booking/special-requests-card.tsx new file mode 100644 index 0000000000..55082c11c8 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/app/booking/special-requests-card.tsx @@ -0,0 +1,37 @@ +import { StepForm, rewardEarlyPunishLate } from './shared-form' +import { specialRequestsSchema } from './schema' +import type { BookingForm } from './shared-form' + +interface SpecialRequestsCardProps { + form: BookingForm + onGroupSubmit: () => void +} + +function SpecialRequestsCard({ + form, + onGroupSubmit, +}: SpecialRequestsCardProps) { + return ( + + {(group) => ( + + + {(field) => ( + + Notes + + + + )} + + + )} + + ) +} + +export default SpecialRequestsCard diff --git a/examples/react/ui-integration-shadcn/src/app/booking/stay-dates-card.tsx b/examples/react/ui-integration-shadcn/src/app/booking/stay-dates-card.tsx new file mode 100644 index 0000000000..0a5e2d4012 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/app/booking/stay-dates-card.tsx @@ -0,0 +1,54 @@ +import { useState } from 'react' +import { StepForm, rewardEarlyPunishLate } from './shared-form' +import { stayDatesSchema } from './schema' +import type { BookingForm } from './shared-form' +import type { Matcher } from 'react-day-picker' + +interface StayDatesCardProps { + form: BookingForm + onGroupSubmit: () => void +} + +function StayDatesCard({ form, onGroupSubmit }: StayDatesCardProps) { + const [matchPastDays] = useState(() => ({ + before: new Date(), + })) + + return ( + + {(group) => ( + + {/** + * Reserved name from React, don't use it + * + * Rename maybe? See AI proposals or smth + */} + + {(field) => ( + + Stay dates + + + + )} + + + {(field) => ( + + Arrival time + + + + )} + + + )} + + ) +} + +export default StayDatesCard diff --git a/examples/react/ui-integration-shadcn/src/components/form/app-form.ts b/examples/react/ui-integration-shadcn/src/components/form/app-form.ts new file mode 100644 index 0000000000..65525bf2f5 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/components/form/app-form.ts @@ -0,0 +1,48 @@ +import { createFormHook } from '@tanstack/react-form' +import { lazy } from 'react' + +// React lazy importing loses generics, so import this directly +const Select = lazy( + () => import('./fields-ui/select'), + // eslint-disable-next-line @typescript-eslint/consistent-type-imports +) as unknown as typeof import('./fields-ui/select').default + +const TextInput = lazy(() => import('./fields-ui/text-input')) +const TanStackFormSubmitButton = lazy(() => import('./form-ui/submit-button')) +const TanStackFormElement = lazy(() => import('./form-ui/form')) +const Field = lazy(() => import('./fields-ui/field')) +const Label = lazy(() => import('./fields-ui/label')) +const Error = lazy(() => import('./fields-ui/error')) +const Description = lazy(() => import('./fields-ui/description')) +const DateRangePicker = lazy(() => import('./fields-ui/date-range-picker')) +const IntegerSlider = lazy(() => import('./fields-ui/integer-slider')) + +const NumberInput = lazy(() => import('./fields-ui/number-input')) +const Checkbox = lazy(() => import('./fields-ui/checkbox')) +const TextArea = lazy(() => import('./fields-ui/text-area')) + +const TextInputField = lazy(() => import('./wrappers/text-field')) + +export const { appFormOptions, useAppForm, useFormContext } = createFormHook({ + fieldComponents: { + // Granular elements for when you need full control + TextInput, + Field, + Label, + Error, + Description, + TextArea, + Checkbox, + NumberInput, + Select, + IntegerSlider, + + // General wrappers for the usual cases + TextInputField, + DateRangePicker, + }, + formComponents: { + SubmitButton: TanStackFormSubmitButton, + Form: TanStackFormElement, + }, +}) diff --git a/examples/react/ui-integration-shadcn/src/components/form/field-brand.ts b/examples/react/ui-integration-shadcn/src/components/form/field-brand.ts new file mode 100644 index 0000000000..da067f2e19 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/components/form/field-brand.ts @@ -0,0 +1,3 @@ +import { getFormHookHelpers } from '@tanstack/react-form' + +export const { fieldBrand, fieldComponent } = getFormHookHelpers() diff --git a/examples/react/ui-integration-shadcn/src/components/form/fields-ui/checkbox.tsx b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/checkbox.tsx new file mode 100644 index 0000000000..1be512ee73 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/checkbox.tsx @@ -0,0 +1,21 @@ +import { fieldComponent } from '../field-brand' +import type { FieldWithValue } from '@tanstack/react-form' +import { Checkbox } from '@/components/ui/checkbox' + +interface TanStackFormCheckboxProps { + field: FieldWithValue +} + +function FormCheckbox({ field }: TanStackFormCheckboxProps) { + return ( + field.handleChange(checked === true)} + onBlur={field.handleBlur} + aria-invalid={field.meta.isInvalid} + /> + ) +} + +export default fieldComponent.strict(FormCheckbox, 'field') diff --git a/examples/react/ui-integration-shadcn/src/components/form/fields-ui/date-range-picker.tsx b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/date-range-picker.tsx new file mode 100644 index 0000000000..ebe5418486 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/date-range-picker.tsx @@ -0,0 +1,73 @@ +import { useMemo } from 'react' +import { CalendarIcon } from 'lucide-react' +import { fieldComponent } from '../field-brand' +import type { + DateRange, + PropsRange, + PropsRangeRequired, +} from 'react-day-picker' +import type { FieldWithValue } from '@tanstack/react-form' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/popover' +import { Calendar } from '@/components/ui/calendar' +import { Button } from '@/components/ui/button' + +const formatter = new Intl.DateTimeFormat('en-US', { + month: 'short', + day: 'numeric', + year: 'numeric', +}) + +function formatDate(range: DateRange) { + if (!range.from) return 'No date range selected' + if (!range.to) return formatter.format(range.from) + return formatter.formatRange(range.from, range.to) +} + +type TanStackFormDateRangePickerProps = Omit< + PropsRange | PropsRangeRequired, + 'mode' +> & { + field: FieldWithValue +} + +function FormDateRangePicker(props: TanStackFormDateRangePickerProps) { + const { field, ...pickerProps } = props + const label = useMemo(() => formatDate(field.value), [field.value]) + + return ( + { + if (!open) field.handleBlur() + }} + > + + + + + + field.handleChange(selected ?? { from: undefined, to: undefined }) + } + /> + + + ) +} + +export default fieldComponent.strict(FormDateRangePicker, 'field') diff --git a/examples/react/ui-integration-shadcn/src/components/form/fields-ui/description.tsx b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/description.tsx new file mode 100644 index 0000000000..56a0071c30 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/description.tsx @@ -0,0 +1,4 @@ +import { fieldBrand } from '../field-brand' +import { FieldDescription } from '@/components/ui/field' + +export default fieldBrand.loose()(FieldDescription) diff --git a/examples/react/ui-integration-shadcn/src/components/form/fields-ui/error.tsx b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/error.tsx new file mode 100644 index 0000000000..c6bbb3f817 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/error.tsx @@ -0,0 +1,15 @@ +import { fieldComponent } from '../field-brand' +import type { AnyFieldApi } from '@tanstack/react-form' +import type { ComponentProps } from 'react' +import { FieldError } from '@/components/ui/field' + +interface TanStackFormErrorProps extends ComponentProps { + field: AnyFieldApi +} + +function FormError(props: TanStackFormErrorProps) { + const { field } = props + return +} + +export default fieldComponent.loose(FormError, 'field') diff --git a/examples/react/ui-integration-shadcn/src/components/form/fields-ui/field.tsx b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/field.tsx new file mode 100644 index 0000000000..8b04c46825 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/field.tsx @@ -0,0 +1,16 @@ +import { fieldComponent } from '../field-brand' +import type { ComponentProps } from 'react' +import type { AnyFieldApi } from '@tanstack/react-form' +import { Field } from '@/components/ui/field' + +interface TanStackFormFieldProps extends ComponentProps { + field: AnyFieldApi +} + +function FormField(props: TanStackFormFieldProps) { + const { field, ...fieldProps } = props + + return +} + +export default fieldComponent.loose(FormField, 'field') diff --git a/examples/react/ui-integration-shadcn/src/components/form/fields-ui/integer-slider.tsx b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/integer-slider.tsx new file mode 100644 index 0000000000..81bf631144 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/integer-slider.tsx @@ -0,0 +1,25 @@ +import { useMemo } from 'react' +import { fieldComponent } from '../field-brand' +import type { FieldWithValue } from '@tanstack/react-form' +import type { ComponentProps } from 'react' +import { Slider } from '@/components/ui/slider' + +interface IntegerSliderProps extends ComponentProps { + field: FieldWithValue +} + +function IntegerSlider(props: IntegerSliderProps) { + const { field } = props + + const value = useMemo(() => [field.value], [field.value]) + + return ( + field.handleChange(newValue)} + {...props} + /> + ) +} + +export default fieldComponent.strict(IntegerSlider, 'field') diff --git a/examples/react/ui-integration-shadcn/src/components/form/fields-ui/label.tsx b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/label.tsx new file mode 100644 index 0000000000..3467f9f029 --- /dev/null +++ b/examples/react/ui-integration-shadcn/src/components/form/fields-ui/label.tsx @@ -0,0 +1,19 @@ +import { fieldComponent } from '../field-brand' +import type { AnyFieldApi } from '@tanstack/react-form' +import type { ComponentProps } from 'react' +import { Label } from '@/components/ui/label' + +interface TanStackFormLabelProps extends ComponentProps { + field: AnyFieldApi +} + +function FormLabel(props: TanStackFormLabelProps) { + const { field } = props + return