@pyreon/form 0.11.4 → 0.11.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -89
- package/lib/devtools.js.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/types/index.d.ts +3 -3
- package/package.json +16 -16
- package/src/context.ts +5 -5
- package/src/devtools.ts +6 -6
- package/src/index.ts +10 -13
- package/src/tests/devtools.test.ts +53 -53
- package/src/tests/form-additional.test.tsx +117 -117
- package/src/tests/form.test.tsx +374 -374
- package/src/types.ts +3 -3
- package/src/use-field-array.ts +2 -2
- package/src/use-field.ts +4 -4
- package/src/use-form-state.ts +3 -3
- package/src/use-form.ts +16 -16
- package/src/use-watch.ts +3 -3
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { FormProvider, useFormContext } from
|
|
1
|
+
export { FormProvider, useFormContext } from './context'
|
|
2
2
|
export type {
|
|
3
3
|
Accessor,
|
|
4
4
|
FieldRegisterProps,
|
|
@@ -8,15 +8,12 @@ export type {
|
|
|
8
8
|
UseFormOptions,
|
|
9
9
|
ValidateFn,
|
|
10
10
|
ValidationError,
|
|
11
|
-
} from
|
|
12
|
-
export type { UseFieldResult } from
|
|
13
|
-
export { useField } from
|
|
14
|
-
export type {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
} from
|
|
18
|
-
export {
|
|
19
|
-
export {
|
|
20
|
-
export type { FormStateSummary } from "./use-form-state"
|
|
21
|
-
export { useFormState } from "./use-form-state"
|
|
22
|
-
export { useWatch } from "./use-watch"
|
|
11
|
+
} from './types'
|
|
12
|
+
export type { UseFieldResult } from './use-field'
|
|
13
|
+
export { useField } from './use-field'
|
|
14
|
+
export type { FieldArrayItem, UseFieldArrayResult } from './use-field-array'
|
|
15
|
+
export { useFieldArray } from './use-field-array'
|
|
16
|
+
export { useForm } from './use-form'
|
|
17
|
+
export type { FormStateSummary } from './use-form-state'
|
|
18
|
+
export { useFormState } from './use-form-state'
|
|
19
|
+
export { useWatch } from './use-watch'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computed, signal } from
|
|
1
|
+
import { computed, signal } from '@pyreon/reactivity'
|
|
2
2
|
import {
|
|
3
3
|
_resetDevtools,
|
|
4
4
|
getActiveForms,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
onFormChange,
|
|
8
8
|
registerForm,
|
|
9
9
|
unregisterForm,
|
|
10
|
-
} from
|
|
10
|
+
} from '../devtools'
|
|
11
11
|
|
|
12
12
|
// Minimal form-like object for testing (avoids needing the full useForm + DOM)
|
|
13
13
|
function createMockForm(values: Record<string, unknown>) {
|
|
@@ -28,40 +28,40 @@ function createMockForm(values: Record<string, unknown>) {
|
|
|
28
28
|
|
|
29
29
|
afterEach(() => _resetDevtools())
|
|
30
30
|
|
|
31
|
-
describe(
|
|
32
|
-
test(
|
|
31
|
+
describe('form devtools', () => {
|
|
32
|
+
test('getActiveForms returns empty initially', () => {
|
|
33
33
|
expect(getActiveForms()).toEqual([])
|
|
34
34
|
})
|
|
35
35
|
|
|
36
|
-
test(
|
|
37
|
-
const form = createMockForm({ email:
|
|
38
|
-
registerForm(
|
|
39
|
-
expect(getActiveForms()).toEqual([
|
|
36
|
+
test('registerForm makes form visible', () => {
|
|
37
|
+
const form = createMockForm({ email: '' })
|
|
38
|
+
registerForm('login', form)
|
|
39
|
+
expect(getActiveForms()).toEqual(['login'])
|
|
40
40
|
})
|
|
41
41
|
|
|
42
|
-
test(
|
|
43
|
-
const form = createMockForm({ email:
|
|
44
|
-
registerForm(
|
|
45
|
-
expect(getFormInstance(
|
|
42
|
+
test('getFormInstance returns the registered form', () => {
|
|
43
|
+
const form = createMockForm({ email: '' })
|
|
44
|
+
registerForm('login', form)
|
|
45
|
+
expect(getFormInstance('login')).toBe(form)
|
|
46
46
|
})
|
|
47
47
|
|
|
48
|
-
test(
|
|
49
|
-
expect(getFormInstance(
|
|
48
|
+
test('getFormInstance returns undefined for unregistered name', () => {
|
|
49
|
+
expect(getFormInstance('nope')).toBeUndefined()
|
|
50
50
|
})
|
|
51
51
|
|
|
52
|
-
test(
|
|
53
|
-
const form = createMockForm({ email:
|
|
54
|
-
registerForm(
|
|
55
|
-
unregisterForm(
|
|
52
|
+
test('unregisterForm removes the form', () => {
|
|
53
|
+
const form = createMockForm({ email: '' })
|
|
54
|
+
registerForm('login', form)
|
|
55
|
+
unregisterForm('login')
|
|
56
56
|
expect(getActiveForms()).toEqual([])
|
|
57
57
|
})
|
|
58
58
|
|
|
59
|
-
test(
|
|
60
|
-
const form = createMockForm({ email:
|
|
61
|
-
registerForm(
|
|
62
|
-
const snapshot = getFormSnapshot(
|
|
59
|
+
test('getFormSnapshot returns current form state', () => {
|
|
60
|
+
const form = createMockForm({ email: 'test@test.com' })
|
|
61
|
+
registerForm('login', form)
|
|
62
|
+
const snapshot = getFormSnapshot('login')
|
|
63
63
|
expect(snapshot).toBeDefined()
|
|
64
|
-
expect(snapshot!.values).toEqual({ email:
|
|
64
|
+
expect(snapshot!.values).toEqual({ email: 'test@test.com' })
|
|
65
65
|
expect(snapshot!.errors).toEqual({})
|
|
66
66
|
expect(snapshot!.isSubmitting).toBe(false)
|
|
67
67
|
expect(snapshot!.isValid).toBe(true)
|
|
@@ -69,19 +69,19 @@ describe("form devtools", () => {
|
|
|
69
69
|
expect(snapshot!.submitCount).toBe(0)
|
|
70
70
|
})
|
|
71
71
|
|
|
72
|
-
test(
|
|
72
|
+
test('getFormSnapshot handles form with non-function properties', () => {
|
|
73
73
|
// Register a plain object where properties are NOT functions
|
|
74
74
|
// This covers the false branches of typeof checks in getFormSnapshot
|
|
75
75
|
const plainForm = {
|
|
76
|
-
values:
|
|
76
|
+
values: 'not-a-function',
|
|
77
77
|
errors: 42,
|
|
78
78
|
isSubmitting: true,
|
|
79
79
|
isValid: null,
|
|
80
80
|
isDirty: undefined,
|
|
81
|
-
submitCount:
|
|
81
|
+
submitCount: 'five',
|
|
82
82
|
}
|
|
83
|
-
registerForm(
|
|
84
|
-
const snapshot = getFormSnapshot(
|
|
83
|
+
registerForm('plain', plainForm)
|
|
84
|
+
const snapshot = getFormSnapshot('plain')
|
|
85
85
|
expect(snapshot).toBeDefined()
|
|
86
86
|
expect(snapshot!.values).toBeUndefined()
|
|
87
87
|
expect(snapshot!.errors).toBeUndefined()
|
|
@@ -91,51 +91,51 @@ describe("form devtools", () => {
|
|
|
91
91
|
expect(snapshot!.submitCount).toBeUndefined()
|
|
92
92
|
})
|
|
93
93
|
|
|
94
|
-
test(
|
|
95
|
-
expect(getFormSnapshot(
|
|
94
|
+
test('getFormSnapshot returns undefined for unregistered name', () => {
|
|
95
|
+
expect(getFormSnapshot('nope')).toBeUndefined()
|
|
96
96
|
})
|
|
97
97
|
|
|
98
|
-
test(
|
|
98
|
+
test('onFormChange fires on register', () => {
|
|
99
99
|
const calls: number[] = []
|
|
100
100
|
const unsub = onFormChange(() => calls.push(1))
|
|
101
101
|
|
|
102
|
-
registerForm(
|
|
102
|
+
registerForm('login', createMockForm({}))
|
|
103
103
|
expect(calls.length).toBe(1)
|
|
104
104
|
|
|
105
105
|
unsub()
|
|
106
106
|
})
|
|
107
107
|
|
|
108
|
-
test(
|
|
109
|
-
registerForm(
|
|
108
|
+
test('onFormChange fires on unregister', () => {
|
|
109
|
+
registerForm('login', createMockForm({}))
|
|
110
110
|
|
|
111
111
|
const calls: number[] = []
|
|
112
112
|
const unsub = onFormChange(() => calls.push(1))
|
|
113
|
-
unregisterForm(
|
|
113
|
+
unregisterForm('login')
|
|
114
114
|
expect(calls.length).toBe(1)
|
|
115
115
|
|
|
116
116
|
unsub()
|
|
117
117
|
})
|
|
118
118
|
|
|
119
|
-
test(
|
|
119
|
+
test('onFormChange unsubscribe stops notifications', () => {
|
|
120
120
|
const calls: number[] = []
|
|
121
121
|
const unsub = onFormChange(() => calls.push(1))
|
|
122
122
|
unsub()
|
|
123
123
|
|
|
124
|
-
registerForm(
|
|
124
|
+
registerForm('login', createMockForm({}))
|
|
125
125
|
expect(calls.length).toBe(0)
|
|
126
126
|
})
|
|
127
127
|
|
|
128
|
-
test(
|
|
129
|
-
registerForm(
|
|
130
|
-
registerForm(
|
|
131
|
-
expect(getActiveForms().sort()).toEqual([
|
|
128
|
+
test('multiple forms are tracked', () => {
|
|
129
|
+
registerForm('login', createMockForm({}))
|
|
130
|
+
registerForm('signup', createMockForm({}))
|
|
131
|
+
expect(getActiveForms().sort()).toEqual(['login', 'signup'])
|
|
132
132
|
})
|
|
133
133
|
|
|
134
|
-
test(
|
|
134
|
+
test('getActiveForms cleans up garbage-collected WeakRefs', () => {
|
|
135
135
|
// Simulate a WeakRef whose target has been GC'd by replacing
|
|
136
136
|
// the internal map entry with a WeakRef that returns undefined from deref()
|
|
137
|
-
registerForm(
|
|
138
|
-
expect(getActiveForms()).toEqual([
|
|
137
|
+
registerForm('gc-form', createMockForm({}))
|
|
138
|
+
expect(getActiveForms()).toEqual(['gc-form'])
|
|
139
139
|
|
|
140
140
|
// Overwrite with a WeakRef-like object that always returns undefined (simulates GC)
|
|
141
141
|
// We do this by registering and then manipulating the internal state
|
|
@@ -150,7 +150,7 @@ describe("form devtools", () => {
|
|
|
150
150
|
// the WeakRef naturally. Instead, let's create a real WeakRef to a short-lived object:
|
|
151
151
|
;(() => {
|
|
152
152
|
let tempObj: object | null = { tmp: true }
|
|
153
|
-
registerForm(
|
|
153
|
+
registerForm('temp-form', tempObj)
|
|
154
154
|
tempObj = null // Allow GC
|
|
155
155
|
})()
|
|
156
156
|
|
|
@@ -165,11 +165,11 @@ describe("form devtools", () => {
|
|
|
165
165
|
_resetDevtools()
|
|
166
166
|
})
|
|
167
167
|
|
|
168
|
-
test(
|
|
168
|
+
test('getFormInstance cleans up and returns undefined when WeakRef is dead', () => {
|
|
169
169
|
// Register a form, then simulate GC by replacing the map entry
|
|
170
|
-
const form = createMockForm({ email:
|
|
171
|
-
registerForm(
|
|
172
|
-
expect(getFormInstance(
|
|
170
|
+
const form = createMockForm({ email: '' })
|
|
171
|
+
registerForm('dying-form', form)
|
|
172
|
+
expect(getFormInstance('dying-form')).toBe(form)
|
|
173
173
|
|
|
174
174
|
// Now we need to make the WeakRef deref return undefined.
|
|
175
175
|
// We can't directly access _activeForms, but we can test the
|
|
@@ -189,15 +189,15 @@ describe("form devtools", () => {
|
|
|
189
189
|
globalThis.WeakRef = MockWeakRef as any
|
|
190
190
|
|
|
191
191
|
_resetDevtools()
|
|
192
|
-
registerForm(
|
|
193
|
-
expect(getFormInstance(
|
|
192
|
+
registerForm('mock-form', form)
|
|
193
|
+
expect(getFormInstance('mock-form')).toBe(form)
|
|
194
194
|
|
|
195
195
|
// Now simulate GC
|
|
196
196
|
mockDerefResult = undefined
|
|
197
|
-
expect(getFormInstance(
|
|
197
|
+
expect(getFormInstance('mock-form')).toBeUndefined()
|
|
198
198
|
|
|
199
199
|
// getActiveForms should also clean it up
|
|
200
|
-
registerForm(
|
|
200
|
+
registerForm('mock-form2', form)
|
|
201
201
|
mockDerefResult = undefined
|
|
202
202
|
expect(getActiveForms()).toEqual([])
|
|
203
203
|
|