Skip to content

Commit 36749f4

Browse files
committed
Merge branch 'main' into preact-integration
2 parents 2d89d08 + 704fefa commit 36749f4

File tree

11 files changed

+182
-10
lines changed

11 files changed

+182
-10
lines changed

.changeset/new-cameras-itch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/react-form': patch
3+
---
4+
5+
Reimplement fallback selector for Subscribe component

.changeset/polite-wombats-send.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/react-form': patch
3+
---
4+
5+
Use a named function for the `withForm` HOC return to enable Fast Refresh.

docs/framework/react/guides/ssr.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ Finally, we'll use `getFormDataFromServer` in our loader to get the state from o
106106

107107
```tsx
108108
// app/routes/index.tsx
109+
import { createFileRoute } from '@tanstack/react-router'
109110
import {
110-
createFileRoute
111111
mergeForm,
112112
useForm,
113113
useStore,

docs/framework/vue/guides/arrays.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ TanStack Form supports arrays as values in a form, including sub-object values i
77

88
## Basic Usage
99

10-
To use an array, you can use `field.state.value` on an array value in conjunction
11-
with [`Index` from `solid-js`](https://www.solidjs.com/tutorial/flow_index):
10+
To use an array, you can use `field.state.value` on an array value in conjunction with `v-for`:
1211

1312
```vue
1413
<script setup lang="ts">

docs/framework/vue/guides/async-initial-values.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ As such, this guide shows you how you can mix-n-match TanStack Form with TanStac
2121
<script setup lang="ts">
2222
import { useForm } from '@tanstack/vue-form'
2323
import { useQuery } from '@tanstack/vue-query'
24-
import { watchEffect, reactive } from 'vue'
24+
import { watchEffect, reactive, computed } from 'vue'
2525
2626
const { data, isLoading } = useQuery({
2727
queryKey: ['data'],

packages/form-core/tests/utils.spec.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,67 @@ describe('evaluate', () => {
692692
const dateObjectFalse = evaluate({ date: date1 }, { date: date3 })
693693
expect(dateObjectFalse).toEqual(false)
694694
})
695+
696+
it('should test equality between Map objects', () => {
697+
const map1 = new Map([
698+
['a', 1],
699+
['b', 2],
700+
])
701+
const map2 = new Map([
702+
['a', 1],
703+
['b', 2],
704+
])
705+
expect(evaluate(map1, map2)).toEqual(true)
706+
707+
const emptyMap1 = new Map()
708+
const emptyMap2 = new Map()
709+
expect(evaluate(emptyMap1, emptyMap2)).toEqual(true)
710+
711+
const mapSmall = new Map([['a', 1]])
712+
const mapLarge = new Map([
713+
['a', 1],
714+
['b', 2],
715+
])
716+
expect(evaluate(mapSmall, mapLarge)).toEqual(false)
717+
718+
const mapA = new Map([
719+
['a', 1],
720+
['b', 2],
721+
])
722+
const mapC = new Map([
723+
['a', 1],
724+
['c', 2],
725+
])
726+
expect(evaluate(mapA, mapC)).toEqual(false)
727+
728+
const mapVal1 = new Map([
729+
['a', 1],
730+
['b', 2],
731+
])
732+
const mapVal2 = new Map([
733+
['a', 1],
734+
['b', 3],
735+
])
736+
expect(evaluate(mapVal1, mapVal2)).toEqual(false)
737+
})
738+
739+
it('should test equality between Set objects', () => {
740+
const set1 = new Set([1, 2, 3])
741+
const set2 = new Set([1, 2, 3])
742+
expect(evaluate(set1, set2)).toEqual(true)
743+
744+
const emptySet1 = new Set()
745+
const emptySet2 = new Set()
746+
expect(evaluate(emptySet1, emptySet2)).toEqual(true)
747+
748+
const setSmall = new Set([1, 2])
749+
const setLarge = new Set([1, 2, 3])
750+
expect(evaluate(setSmall, setLarge)).toEqual(false)
751+
752+
const setA = new Set([1, 2, 3])
753+
const setB = new Set([1, 2, 4])
754+
expect(evaluate(setA, setB)).toEqual(false)
755+
})
695756
})
696757

697758
describe('concatenatePaths', () => {

packages/react-form/src/createFormHook.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,9 @@ export function createFormHook<
448448
UnwrapOrAny<TFormComponents>,
449449
UnwrapOrAny<TRenderProps>
450450
>['render'] {
451-
return (innerProps) => render({ ...props, ...innerProps })
451+
return function Render(innerProps) {
452+
return render({ ...props, ...innerProps })
453+
}
452454
}
453455

454456
function withFieldGroup<

packages/react-form/src/useFieldGroup.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ import type { LensFieldComponent } from './useField'
2323

2424
function LocalSubscribe({
2525
lens,
26-
selector,
26+
selector = (state) => state,
2727
children,
2828
}: PropsWithChildren<{
2929
lens: AnyFieldGroupApi
30-
selector: (state: FieldGroupState<any>) => FieldGroupState<any>
30+
selector?: (state: FieldGroupState<any>) => FieldGroupState<any>
3131
}>): ReturnType<FunctionComponent> {
3232
const data = useStore(lens.store, selector)
3333

packages/react-form/src/useForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,11 @@ export type ReactFormExtendedApi<
139139

140140
function LocalSubscribe({
141141
form,
142-
selector,
142+
selector = (state) => state,
143143
children,
144144
}: PropsWithChildren<{
145145
form: AnyFormApi
146-
selector: (state: AnyFormState) => AnyFormState
146+
selector?: (state: AnyFormState) => AnyFormState
147147
}>): ReturnType<FunctionComponent> {
148148
const data = useStore(form.store, selector)
149149

packages/react-form/tests/createFormHook.test.tsx

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it } from 'vitest'
2-
import { render } from '@testing-library/react'
2+
import { render, waitFor } from '@testing-library/react'
33
import { formOptions } from '@tanstack/form-core'
44
import userEvent from '@testing-library/user-event'
55
import { createFormHook, createFormHookContexts, useStore } from '../src'
@@ -699,4 +699,63 @@ describe('createFormHook', () => {
699699
const button = getByText('Testing')
700700
expect(button).toBeInTheDocument()
701701
})
702+
703+
it('should render FieldGroup Subscribe without selector (default identity)', async () => {
704+
const formOpts = formOptions({
705+
defaultValues: {
706+
person: {
707+
firstName: 'FirstName',
708+
lastName: 'LastName',
709+
},
710+
},
711+
})
712+
713+
const ChildFormAsField = withFieldGroup({
714+
defaultValues: formOpts.defaultValues.person,
715+
render: ({ group }) => {
716+
return (
717+
<div>
718+
<group.Field
719+
name="lastName"
720+
children={(field) => (
721+
<label>
722+
Last Name:
723+
<input
724+
data-testid="lastName"
725+
value={field.state.value}
726+
onBlur={field.handleBlur}
727+
onChange={(e) => field.handleChange(e.target.value)}
728+
/>
729+
</label>
730+
)}
731+
/>
732+
<group.Subscribe
733+
children={(state) => (
734+
<span data-testid="state-lastName">
735+
{state.values.lastName}
736+
</span>
737+
)}
738+
/>
739+
</div>
740+
)
741+
},
742+
})
743+
744+
const Parent = () => {
745+
const form = useAppForm({
746+
...formOpts,
747+
})
748+
return <ChildFormAsField form={form} fields="person" />
749+
}
750+
751+
const { getByTestId } = render(<Parent />)
752+
const input = getByTestId('lastName')
753+
const stateLastName = getByTestId('state-lastName')
754+
755+
expect(stateLastName).toHaveTextContent('LastName')
756+
757+
await user.clear(input)
758+
await user.type(input, 'Updated')
759+
await waitFor(() => expect(stateLastName).toHaveTextContent('Updated'))
760+
})
702761
})

0 commit comments

Comments
 (0)