diff --git a/examples/solid/array/package.json b/examples/solid/array/package.json index cf1369b1b..c6197cb64 100644 --- a/examples/solid/array/package.json +++ b/examples/solid/array/package.json @@ -10,11 +10,12 @@ }, "dependencies": { "@tanstack/solid-form": "^1.33.0", - "solid-js": "^1.9.9" + "solid-js": "2.0.0-beta.15" }, "devDependencies": { + "@solidjs/web": "2.0.0-beta.15", "typescript": "5.9.3", "vite": "^7.2.2", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "3.0.0-next.5" } } diff --git a/examples/solid/array/src/index.tsx b/examples/solid/array/src/index.tsx index e930e712c..9dae886fb 100644 --- a/examples/solid/array/src/index.tsx +++ b/examples/solid/array/src/index.tsx @@ -1,8 +1,8 @@ /* @refresh reload */ -import { render } from 'solid-js/web' +import { render } from '@solidjs/web' import { createForm } from '@tanstack/solid-form' -import { Index, Show } from 'solid-js' +import { Repeat, Show } from 'solid-js' function App() { const form = createForm(() => ({ @@ -26,8 +26,8 @@ function App() {
0}> {/* Do not change this to For or the test will fail */} - - {(_, i) => ( + + {(i) => ( {(subField) => (
@@ -44,7 +44,7 @@ function App() { )} )} - +
) diff --git a/examples/solid/large-form/src/index.tsx b/examples/solid/large-form/src/index.tsx index f764172a5..6813299d3 100644 --- a/examples/solid/large-form/src/index.tsx +++ b/examples/solid/large-form/src/index.tsx @@ -1,4 +1,4 @@ -import { render } from 'solid-js/web' +import { render } from '@solidjs/web' import App from './App.tsx' const root = document.getElementById('root') diff --git a/examples/solid/large-form/tsconfig.json b/examples/solid/large-form/tsconfig.json index 5e559e80f..2d91c4727 100644 --- a/examples/solid/large-form/tsconfig.json +++ b/examples/solid/large-form/tsconfig.json @@ -12,7 +12,7 @@ "isolatedModules": true, "noEmit": true, "jsx": "preserve", - "jsxImportSource": "solid-js", + "jsxImportSource": "@solidjs/web", /* Linting */ "strict": true, "noUnusedLocals": true, diff --git a/examples/solid/multi-step-wizard/package.json b/examples/solid/multi-step-wizard/package.json index 61eef3612..487180e81 100644 --- a/examples/solid/multi-step-wizard/package.json +++ b/examples/solid/multi-step-wizard/package.json @@ -10,12 +10,13 @@ }, "dependencies": { "@tanstack/solid-form": "^1.33.0", - "solid-js": "^1.9.9", + "solid-js": "2.0.0-beta.15", "zod": "^3.25.76" }, "devDependencies": { + "@solidjs/web": "2.0.0-beta.15", "typescript": "5.9.3", "vite": "^7.2.2", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "3.0.0-next.5" } } diff --git a/examples/solid/multi-step-wizard/src/index.tsx b/examples/solid/multi-step-wizard/src/index.tsx index 88bb10c6c..0743af72c 100644 --- a/examples/solid/multi-step-wizard/src/index.tsx +++ b/examples/solid/multi-step-wizard/src/index.tsx @@ -1,5 +1,5 @@ /* @refresh reload */ -import { render } from 'solid-js/web' +import { render } from '@solidjs/web' import { WizardPage } from './features/wizard/page.tsx' function App() { diff --git a/examples/solid/multi-step-wizard/tsconfig.json b/examples/solid/multi-step-wizard/tsconfig.json index 576a7f010..26e9875fe 100644 --- a/examples/solid/multi-step-wizard/tsconfig.json +++ b/examples/solid/multi-step-wizard/tsconfig.json @@ -13,7 +13,7 @@ "isolatedModules": true, "noEmit": true, "jsx": "preserve", - "jsxImportSource": "solid-js", + "jsxImportSource": "@solidjs/web", /* Linting */ "strict": true, diff --git a/examples/solid/simple/package.json b/examples/solid/simple/package.json index 0b2220400..99de44841 100644 --- a/examples/solid/simple/package.json +++ b/examples/solid/simple/package.json @@ -10,11 +10,12 @@ }, "dependencies": { "@tanstack/solid-form": "^1.33.0", - "solid-js": "^1.9.9" + "solid-js": "2.0.0-beta.15" }, "devDependencies": { + "@solidjs/web": "2.0.0-beta.15", "typescript": "5.9.3", "vite": "^7.2.2", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "3.0.0-next.5" } } diff --git a/examples/solid/simple/src/index.tsx b/examples/solid/simple/src/index.tsx index e74faded7..68308a771 100644 --- a/examples/solid/simple/src/index.tsx +++ b/examples/solid/simple/src/index.tsx @@ -1,5 +1,5 @@ /* @refresh reload */ -import { render } from 'solid-js/web' +import { render } from '@solidjs/web' import { createForm } from '@tanstack/solid-form' import type { AnyFieldApi } from '@tanstack/solid-form' diff --git a/examples/solid/simple/tsconfig.json b/examples/solid/simple/tsconfig.json index 576a7f010..26e9875fe 100644 --- a/examples/solid/simple/tsconfig.json +++ b/examples/solid/simple/tsconfig.json @@ -13,7 +13,7 @@ "isolatedModules": true, "noEmit": true, "jsx": "preserve", - "jsxImportSource": "solid-js", + "jsxImportSource": "@solidjs/web", /* Linting */ "strict": true, diff --git a/examples/solid/standard-schema/package.json b/examples/solid/standard-schema/package.json index ea0b81ed9..ab5dcbfcc 100644 --- a/examples/solid/standard-schema/package.json +++ b/examples/solid/standard-schema/package.json @@ -14,13 +14,14 @@ "effect": "^3.17.14", "react": "19.1.0", "react-dom": "19.1.0", - "solid-js": "^1.9.9", + "solid-js": "2.0.0-beta.15", "valibot": "^1.1.0", "zod": "^3.25.76" }, "devDependencies": { + "@solidjs/web": "2.0.0-beta.15", "typescript": "5.9.3", "vite": "^7.2.2", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "3.0.0-next.5" } } diff --git a/examples/solid/standard-schema/src/index.tsx b/examples/solid/standard-schema/src/index.tsx index db7533c6f..659bd445d 100644 --- a/examples/solid/standard-schema/src/index.tsx +++ b/examples/solid/standard-schema/src/index.tsx @@ -1,5 +1,5 @@ /* @refresh reload */ -import { render } from 'solid-js/web' +import { render } from '@solidjs/web' import { createForm } from '@tanstack/solid-form' diff --git a/examples/solid/standard-schema/tsconfig.json b/examples/solid/standard-schema/tsconfig.json index 850d4bf2e..36a794c18 100644 --- a/examples/solid/standard-schema/tsconfig.json +++ b/examples/solid/standard-schema/tsconfig.json @@ -13,7 +13,7 @@ "isolatedModules": true, "noEmit": true, "jsx": "preserve", - "jsxImportSource": "solid-js", + "jsxImportSource": "@solidjs/web", /* Linting */ "strict": true, diff --git a/package.json b/package.json index 190c8dc88..02c172e64 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "test:pr": "nx affected --targets=test:sherif,test:knip,test:docs,test:eslint,test:lib,test:types,test:build,build", "test:ci": "nx run-many --targets=test:sherif,test:knip,test:docs,test:eslint,test:lib,test:types,test:build,build", "test:eslint": "nx affected --target=test:eslint", - "test:sherif": "sherif", + "test:sherif": "sherif --ignore-dependency solid-js --ignore-dependency vite-plugin-solid", "test:lib": "nx affected --target=test:lib --exclude=examples/**", "test:lib:dev": "pnpm run test:lib && nx watch --all -- pnpm run test:lib", "test:build": "nx affected --target=test:build --exclude=examples/**", @@ -44,7 +44,6 @@ "@changesets/changelog-github": "^0.7.0", "@changesets/cli": "^2.29.8", "@eslint-react/eslint-plugin": "^1.53.1", - "@solidjs/testing-library": "^0.8.10", "@tanstack/eslint-config": "0.3.2", "@tanstack/typedoc-config": "0.3.1", "@tanstack/vite-config": "0.4.1", diff --git a/packages/solid-form-devtools/package.json b/packages/solid-form-devtools/package.json index 0994030d3..4e3bf6c1a 100644 --- a/packages/solid-form-devtools/package.json +++ b/packages/solid-form-devtools/package.json @@ -58,6 +58,7 @@ "@tanstack/form-devtools": "workspace:*" }, "devDependencies": { + "solid-js": "^1.9.9", "vite-plugin-solid": "^2.11.8" } } diff --git a/packages/solid-form/package.json b/packages/solid-form/package.json index 253789745..636db7e00 100644 --- a/packages/solid-form/package.json +++ b/packages/solid-form/package.json @@ -31,21 +31,21 @@ }, "type": "module", "types": "dist/esm/index.d.ts", - "main": "dist/cjs/index.cjs", - "module": "dist/esm/index.js", + "main": "dist/cjs/packages/solid-form/src/index.cjs", + "module": "dist/esm/packages/solid-form/src/index.js", "exports": { ".": { "solid": { - "types": "./dist/source/index.d.ts", - "default": "./dist/source/index.jsx" + "types": "./dist/source/solid-form/src/index.d.ts", + "default": "./dist/source/solid-form/src/index.jsx" }, "import": { "types": "./dist/esm/index.d.ts", - "default": "./dist/esm/index.js" + "default": "./dist/esm/packages/solid-form/src/index.js" }, "require": { "types": "./dist/cjs/index.d.cts", - "default": "./dist/cjs/index.cjs" + "default": "./dist/cjs/packages/solid-form/src/index.cjs" } }, "./package.json": "./package.json" @@ -57,14 +57,16 @@ ], "dependencies": { "@tanstack/form-core": "workspace:*", - "@tanstack/solid-store": "^0.11.0" + "@tanstack/solid-store": "^0.9.1" }, "devDependencies": { - "solid-js": "^1.9.9", + "@solidjs/testing-library": "1.0.0-beta.2", + "@solidjs/web": "2.0.0-beta.15", + "solid-js": "2.0.0-beta.15", "vite": "^7.2.2", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "3.0.0-next.5" }, "peerDependencies": { - "solid-js": ">=1.9.9" + "solid-js": ">=2.0.0-beta.15 <2.0.0-experimental.0" } } diff --git a/packages/solid-form/src/createField.tsx b/packages/solid-form/src/createField.tsx index 373146864..f7f397c62 100644 --- a/packages/solid-form/src/createField.tsx +++ b/packages/solid-form/src/createField.tsx @@ -1,10 +1,10 @@ import { FieldApi } from '@tanstack/form-core' import { createComponent, - createComputed, - createSignal, - onCleanup, - onMount, + createMemo, + createRenderEffect, + omit, + onSettled, } from 'solid-js' import { useStore } from '@tanstack/solid-store' import type { @@ -15,9 +15,11 @@ import type { FieldValidators, FormAsyncValidateOrFn, FormValidateOrFn, + Narrow, } from '@tanstack/form-core' -import type { Accessor, JSX, JSXElement } from 'solid-js' +import type { Accessor } from 'solid-js' +import type { JSX } from '@solidjs/web' import type { CreateFieldOptions, CreateFieldOptionsBound, @@ -54,6 +56,94 @@ interface SolidFieldApi< > } +export type CreateField< + TParentData, + TFormOnMount extends undefined | FormValidateOrFn, + TFormOnChange extends undefined | FormValidateOrFn, + TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn, + TFormOnBlur extends undefined | FormValidateOrFn, + TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn, + TFormOnSubmit extends undefined | FormValidateOrFn, + TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn, + TFormOnDynamic extends undefined | FormValidateOrFn, + TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn, + TFormOnServer extends undefined | FormAsyncValidateOrFn, + TParentSubmitMeta, +> = < + TName extends DeepKeys, + TData extends DeepValue, + TOnMount extends undefined | FieldValidateOrFn, + TOnChange extends undefined | FieldValidateOrFn, + TOnChangeAsync extends + | undefined + | FieldAsyncValidateOrFn, + TOnBlur extends undefined | FieldValidateOrFn, + TOnBlurAsync extends + | undefined + | FieldAsyncValidateOrFn, + TOnSubmit extends undefined | FieldValidateOrFn, + TOnSubmitAsync extends + | undefined + | FieldAsyncValidateOrFn, + TOnDynamic extends undefined | FieldValidateOrFn, + TOnDynamicAsync extends + | undefined + | FieldAsyncValidateOrFn, +>( + opts: () => { name: Narrow } & CreateFieldOptionsBound< + TParentData, + TName, + TData, + TOnMount, + TOnChange, + TOnChangeAsync, + TOnBlur, + TOnBlurAsync, + TOnSubmit, + TOnSubmitAsync, + TOnDynamic, + TOnDynamicAsync + >, +) => () => 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 + > + // ugly way to trick solid into triggering updates for changes on the fieldApi function makeFieldReactive< TParentData, @@ -167,11 +257,10 @@ function makeFieldReactive< TFormOnServer, TParentSubmitMeta > { - const [field, setField] = createSignal(fieldApi, { equals: false }) // Subscribe to the pieces of state that should trigger a re-render of the - // field. For array mode, we only track the length of the array value to - // avoid re-renders when child properties change. Meta is tracked piece by - // piece so that consumers re-render when any meta property updates. + // field. For array mode, we only track the array version to avoid re-renders + // when child properties change. Meta is tracked piece by piece so that + // consumers re-render when any meta property updates. // See: https://github.com/TanStack/form/issues/1961 const reactiveStateValue = useStore(fieldApi.store, (state) => mode === 'array' ? state.meta._arrayVersion || 0 : state.value, @@ -200,19 +289,20 @@ function makeFieldReactive< fieldApi.store, (state) => state.meta.isValidating, ) - // Run before initial render - createComputed(() => { - // Read all reactive sources to track them as dependencies - reactiveStateValue() - reactiveMetaIsTouched() - reactiveMetaIsBlurred() - reactiveMetaIsDirty() - reactiveMetaErrorMap() - reactiveMetaErrorSourceMap() - reactiveMetaIsValidating() - setField(fieldApi) - }) - return field + return createMemo( + () => { + // Read all reactive sources to track them as dependencies + reactiveStateValue() + reactiveMetaIsTouched() + reactiveMetaIsBlurred() + reactiveMetaIsDirty() + reactiveMetaErrorMap() + reactiveMetaErrorSourceMap() + reactiveMetaIsValidating() + return fieldApi + }, + { equals: false }, + ) } export function createField< @@ -282,25 +372,35 @@ export function createField< let mounted = false // Instantiates field meta and removes it when unrendered - onMount(() => { + onSettled(() => { + api.update(opts()) const cleanupFn = api.mount() mounted = true - onCleanup(() => { - cleanupFn() + return () => { mounted = false - }) + cleanupFn() + } }) /** * fieldApi.update should not have any side effects. Think of it like a `useRef` * that we need to keep updated every render with the most up-to-date information. * - * createComputed to make sure this effect runs before render effects + * createRenderEffect keeps the api options in sync before user effects run. */ - createComputed(() => { - if (!mounted) return - api.update(opts()) - }) + createRenderEffect( + () => { + const nextOptions = opts() + return mounted ? nextOptions : undefined + }, + (options) => { + if (options) { + api.update(options) + } + + return undefined + }, + ) return makeFieldReactive< TParentData, @@ -566,7 +666,7 @@ interface FieldComponentProps< TFormOnServer, TParentSubmitMeta >, - ) => JSXElement + ) => JSX.Element } /** @@ -741,8 +841,7 @@ export function Field< TFormOnServer, TParentSubmitMeta >(() => { - const { children, ...fieldOptions } = props - return fieldOptions + return omit(props, 'children') }) return <>{createComponent(() => props.children(fieldApi), {})} diff --git a/packages/solid-form/src/createFieldGroup.tsx b/packages/solid-form/src/createFieldGroup.tsx index 0310dd9d9..de9cd4d84 100644 --- a/packages/solid-form/src/createFieldGroup.tsx +++ b/packages/solid-form/src/createFieldGroup.tsx @@ -1,7 +1,8 @@ import { FieldGroupApi, functionalUpdate } from '@tanstack/form-core' import { useStore } from '@tanstack/solid-store' -import { onCleanup, onMount } from 'solid-js' -import type { Component, JSX, ParentProps } from 'solid-js' +import { onSettled } from 'solid-js' +import type { Component, ParentProps } from 'solid-js' +import type { JSX } from '@solidjs/web' import type { DeepKeysOfType, FieldGroupState, @@ -193,27 +194,28 @@ export function createFieldGroup< TFormComponents > = api as never - extendedApi.AppForm = (appFormProps) => - extendedApi.AppField = (props) => ( - + extendedApi.AppForm = (appFormProps: any) => ( + ) - extendedApi.Field = (props) => ( - - ) - extendedApi.Subscribe = (props) => { + extendedApi.AppField = (props: any) => { + const fieldOptions = () => api.getFormFieldOptions(props) + return + } + extendedApi.Field = (props: any) => { + const fieldOptions = () => api.getFormFieldOptions(props) + return + } + extendedApi.Subscribe = (props: any) => { const data = useStore(api.store, props.selector) return functionalUpdate(props.children, data()) as Element } - let mounted = false - onMount(() => { + onSettled(() => { const cleanupFn = api.mount() - mounted = true - onCleanup(() => { + return () => { cleanupFn() - mounted = false - }) + } }) return Object.assign(extendedApi, { diff --git a/packages/solid-form/src/createForm.tsx b/packages/solid-form/src/createForm.tsx index 844dfa833..e7bf5ad7f 100644 --- a/packages/solid-form/src/createForm.tsx +++ b/packages/solid-form/src/createForm.tsx @@ -1,5 +1,5 @@ import { FormApi, functionalUpdate } from '@tanstack/form-core' -import { createComputed, onMount } from 'solid-js' +import { createRenderEffect, onSettled } from 'solid-js' import { useStore } from '@tanstack/solid-store' import { Field, createField } from './createField' import { FormGroup } from './createFormGroup' @@ -9,8 +9,8 @@ import type { FormState, FormValidateOrFn, } from '@tanstack/form-core' -import type { JSXElement } from 'solid-js' -import type { FieldComponent } from './createField' +import type { JSX } from '@solidjs/web' +import type { CreateField, FieldComponent } from './createField' import type { FormGroupComponent } from './createFormGroup' export interface SolidFormApi< @@ -41,6 +41,20 @@ export interface SolidFormApi< TFormOnServer, TSubmitMeta > + createField: CreateField< + TParentData, + TFormOnMount, + TFormOnChange, + TFormOnChangeAsync, + TFormOnBlur, + TFormOnBlurAsync, + TFormOnSubmit, + TFormOnSubmitAsync, + TFormOnDynamic, + TFormOnDynamicAsync, + TFormOnServer, + TSubmitMeta + > FormGroup: FormGroupComponent< TParentData, TFormOnMount, @@ -124,8 +138,8 @@ export interface SolidFormApi< > >, ) => TSelected - children: ((state: () => NoInfer) => JSXElement) | JSXElement - }) => JSXElement + children: ((state: () => NoInfer) => JSX.Element) | JSX.Element + }) => JSX.Element } /** @@ -232,19 +246,29 @@ export function createForm< TSubmitMeta > = api as never - extendedApi.Field = (props) => - extendedApi.FormGroup = (props) => - extendedApi.useStore = (selector) => useStore(api.store, selector) - extendedApi.Subscribe = (props) => + extendedApi.Field = (props: any) => + extendedApi.createField = (props: any) => + createField(() => { + return { ...props(), form: api } + }) as never + extendedApi.FormGroup = (props: any) => + extendedApi.useStore = (selector: any) => useStore(api.store, selector) + extendedApi.Subscribe = (props: any) => functionalUpdate(props.children, useStore(api.store, props.selector)) - onMount(api.mount) + onSettled(api.mount) /** * formApi.update should not have any side effects. Think of it like a `useRef` * that we need to keep updated every render with the most up-to-date information. */ - createComputed(() => api.update(opts?.())) + createRenderEffect( + () => opts?.(), + (options) => { + api.update(options) + return undefined + }, + ) return extendedApi } diff --git a/packages/solid-form/src/createFormGroup.tsx b/packages/solid-form/src/createFormGroup.tsx index 47467a88a..ba7f77c20 100644 --- a/packages/solid-form/src/createFormGroup.tsx +++ b/packages/solid-form/src/createFormGroup.tsx @@ -1,10 +1,9 @@ import { FormGroupApi, functionalUpdate } from '@tanstack/form-core' import { createComponent, - createComputed, - createSignal, - onCleanup, - onMount, + createMemo, + createRenderEffect, + onSettled, } from 'solid-js' import { useStore } from '@tanstack/solid-store' import type { @@ -17,7 +16,8 @@ import type { FormGroupValidateOrFn, FormValidateOrFn, } from '@tanstack/form-core' -import type { Accessor, JSX, JSXElement } from 'solid-js' +import type { Accessor } from 'solid-js' +import type { JSX } from '@solidjs/web' // ugly way to trick solid into triggering updates for changes on the formGroupApi function makeFormGroupReactive< @@ -112,16 +112,16 @@ function makeFormGroupReactive< TFormOnServer, TParentSubmitMeta > { - const [group, setGroup] = createSignal(formGroupApi, { equals: false }) // Handle shallow comparison to make sure that Derived doesn't create a new setGroup call every time const store = useStore(formGroupApi.store, (store) => store) - // Run before initial render - createComputed(() => { - // Use the store to track dependencies - store() - setGroup(formGroupApi) - }) - return group + return createMemo( + () => { + // Use the store to track dependencies + store() + return formGroupApi + }, + { equals: false }, + ) } export function createFormGroup< @@ -197,25 +197,29 @@ export function createFormGroup< let mounted = false // Instantiates form group meta and removes it when unrendered - onMount(() => { + onSettled(() => { const cleanupFn = api.mount() mounted = true - onCleanup(() => { + return () => { cleanupFn() mounted = false - }) + } }) /** * formGroupApi.update should not have any side effects. Think of it like a `useRef` * that we need to keep updated every render with the most up-to-date information. * - * createComputed to make sure this effect runs before render effects + * createRenderEffect to make sure this effect runs before render effects */ - createComputed(() => { - if (!mounted) return - api.update(opts()) - }) + createRenderEffect( + () => opts(), + (options) => { + if (!mounted) return undefined + api.update(options) + return undefined + }, + ) return makeFormGroupReactive< TParentData, @@ -424,7 +428,7 @@ export type FormGroupComponent< TParentSubmitMeta, ExtendedApi >, -) => JSXElement +) => JSX.Element interface FormGroupComponentProps< TParentData, @@ -518,7 +522,7 @@ interface FormGroupComponentProps< TFormOnServer, TParentSubmitMeta >, - ) => JSXElement + ) => JSX.Element } export function FormGroup< diff --git a/packages/solid-form/src/createFormHook.tsx b/packages/solid-form/src/createFormHook.tsx index a86afab24..ad6a68e71 100644 --- a/packages/solid-form/src/createFormHook.tsx +++ b/packages/solid-form/src/createFormHook.tsx @@ -1,8 +1,8 @@ import { createComponent, createContext, - mergeProps, - splitProps, + merge, + omit, useContext, } from 'solid-js' import { createFieldGroup } from './createFieldGroup' @@ -18,13 +18,8 @@ import type { FormOptions, FormValidateOrFn, } from '@tanstack/form-core' -import type { - Accessor, - Component, - Context, - JSXElement, - ParentProps, -} from 'solid-js' +import type { Accessor, Component, Context, ParentProps } from 'solid-js' +import type { JSX } from '@solidjs/web' import type { FieldComponent } from './createField' import type { AppFieldExtendedSolidFieldGroupApi } from './createFieldGroup' import type { SolidFormExtendedApi } from './createForm' @@ -257,7 +252,7 @@ export interface WithFormProps< > } >, - ) => JSXElement + ) => JSX.Element } export interface WithFieldGroupProps< @@ -294,7 +289,7 @@ export interface WithFieldGroupProps< > } >, - ) => JSXElement + ) => JSX.Element } export function createFormHook< @@ -351,26 +346,18 @@ export function createFormHook< const AppForm = ((formProps) => { return ( - - {formProps.children} - + {formProps.children} ) }) as Component const AppField = ((_props) => { - const [childProps, fieldProps] = splitProps(_props, ['children']) + const fieldProps = omit(_props, 'children') return ( - {(field) => ( - - {createComponent( - () => - childProps.children( - Object.assign(field, opts.fieldComponents), - ), - {}, - )} - + {(field: any) => ( + + {_props.children(Object.assign(field, opts.fieldComponents))} + )} ) @@ -472,7 +459,7 @@ export function createFormHook< return (innerProps) => createComponent( render as Component, - mergeProps(props ?? {}, innerProps), + props ? merge(props, innerProps) : innerProps, ) } @@ -549,7 +536,7 @@ export function createFormHook< fields: TFields } >, - ) => JSXElement { + ) => JSX.Element { return function Render(innerProps) { const fieldGroupProps = { form: innerProps.form, @@ -560,7 +547,7 @@ export function createFormHook< const fieldGroupApi = createFieldGroup(() => fieldGroupProps) return createComponent( render as Component, - mergeProps(props ?? {}, innerProps, { group: fieldGroupApi as any }), + merge(props ?? {}, innerProps, { group: fieldGroupApi as any }), ) } } diff --git a/packages/solid-form/tests/createField.test.tsx b/packages/solid-form/tests/createField.test.tsx index 00395ee31..d68ce16f1 100644 --- a/packages/solid-form/tests/createField.test.tsx +++ b/packages/solid-form/tests/createField.test.tsx @@ -1,7 +1,7 @@ import { describe, expect, it, vi } from 'vitest' import { render, waitFor } from '@solidjs/testing-library' import { userEvent } from '@testing-library/user-event' -import { Index, Show } from 'solid-js' +import { Repeat, Show } from 'solid-js' import { createForm } from '../src/index' import { sleep } from './utils' @@ -402,8 +402,8 @@ describe('createField', () => {
0}> {/* Do not change this to For or the test will fail */} - - {(_, i) => { + + {(i) => { return ( {(subField) => ( @@ -430,7 +430,7 @@ describe('createField', () => { ) }} - +
- - {(_, index) => ( + + {(index) => ( {(field) => (
@@ -573,7 +573,7 @@ describe('createForm', () => { )} )} - +
)} @@ -610,10 +610,9 @@ describe('createForm', () => { {(arrayField) => ( // This unit test provides different result based on - // using For vs. Index. Unit test both - // once that's fixed. - - {(_, i) => ( + // Keep index-based array field rendering covered. + + {(i) => ( {(field) => { expect(field().name).toBe(`foo[${i}].name`) @@ -622,7 +621,7 @@ describe('createForm', () => { }} )} - + )}