@skopon-cool/form-sdk 0.3.0 → 0.3.1
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/dist/index.js +265 -259
- package/dist/runtime/formAutoControl.d.ts +1 -0
- package/dist/runtime/formAutoControl.d.ts.map +1 -1
- package/dist/runtime/formRuntimeContext.d.ts +4 -0
- package/dist/runtime/formRuntimeContext.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/runtime/formAutoControl.test.ts +56 -0
- package/src/runtime/formAutoControl.ts +3 -2
- package/src/runtime/formRuntimeContext.tsx +24 -2
|
@@ -8,6 +8,7 @@ export interface FormAutoControlTargets {
|
|
|
8
8
|
}
|
|
9
9
|
export interface FormAutoControlHelpers {
|
|
10
10
|
reportEvent: (event: FormRuntimeEventData) => void;
|
|
11
|
+
/** 支持同步或返回 Promise(async submit 期间保持 autoControlDepth) */
|
|
11
12
|
runAutoControl: <T>(fn: () => T) => T;
|
|
12
13
|
}
|
|
13
14
|
/** 执行下行 form_auto_control_event;缺参或未知 action 时 warn 并忽略。 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formAutoControl.d.ts","sourceRoot":"","sources":["../../src/runtime/formAutoControl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAE7E,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IACpD,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7D,MAAM,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAClC,yCAAyC;IACzC,WAAW,EAAE,WAAW,GAAG,IAAI,CAAA;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAClD,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;CACtC;AAiCD,4DAA4D;AAC5D,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,wBAAwB,EAC9B,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,sBAAsB,GAC9B,IAAI,CAyDN"}
|
|
1
|
+
{"version":3,"file":"formAutoControl.d.ts","sourceRoot":"","sources":["../../src/runtime/formAutoControl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAE7E,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IACpD,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7D,MAAM,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAClC,yCAAyC;IACzC,WAAW,EAAE,WAAW,GAAG,IAAI,CAAA;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAClD,0DAA0D;IAC1D,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;CACtC;AAiCD,4DAA4D;AAC5D,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,wBAAwB,EAC9B,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,sBAAsB,GAC9B,IAAI,CAyDN"}
|
|
@@ -4,6 +4,10 @@ import type { FormRuntimeEventData } from './types';
|
|
|
4
4
|
export interface FormRuntimeContextValue {
|
|
5
5
|
reportEvent: (event: FormRuntimeEventData) => void;
|
|
6
6
|
reportData: (values: Record<string, unknown>) => void;
|
|
7
|
+
/**
|
|
8
|
+
* 在自动控上下文中执行 fn。若 fn 返回 Promise,depth 保持到 settle,
|
|
9
|
+
* 使异步 submit 内的 reportEvent 仍为 form_auto_control_bac_event。
|
|
10
|
+
*/
|
|
7
11
|
runAutoControl: <T>(fn: () => T) => T;
|
|
8
12
|
isAutoControl: () => boolean;
|
|
9
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formRuntimeContext.d.ts","sourceRoot":"","sources":["../../src/runtime/formRuntimeContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AACd,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAEnD,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAClD,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IACrD,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IACrC,aAAa,EAAE,MAAM,OAAO,CAAA;CAC7B;
|
|
1
|
+
{"version":3,"file":"formRuntimeContext.d.ts","sourceRoot":"","sources":["../../src/runtime/formRuntimeContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AACd,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAEnD,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAClD,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IACrD;;;OAGG;IACH,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IACrC,aAAa,EAAE,MAAM,OAAO,CAAA;CAC7B;AA6BD,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAA;IAClC,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,QAAQ,GACT,EAAE,wBAAwB,+BAkE1B;AAED,uCAAuC;AACvC,wBAAgB,cAAc,IAAI,uBAAuB,CAExD"}
|
package/package.json
CHANGED
|
@@ -5,6 +5,32 @@ import { describe, it, expect, vi } from 'vitest'
|
|
|
5
5
|
import { executeFormAutoControl } from './formAutoControl'
|
|
6
6
|
import type { FormAutoControlEventData } from './types'
|
|
7
7
|
|
|
8
|
+
/** 模拟 FormRuntimeProvider.runAutoControl:Promise settle 前保持 depth。 */
|
|
9
|
+
function createDepthTrackingRunAutoControl(depthRef: { current: number }) {
|
|
10
|
+
return <T,>(fn: () => T): T => {
|
|
11
|
+
depthRef.current += 1
|
|
12
|
+
let syncResult: T
|
|
13
|
+
try {
|
|
14
|
+
syncResult = fn()
|
|
15
|
+
} catch (error) {
|
|
16
|
+
depthRef.current = Math.max(0, depthRef.current - 1)
|
|
17
|
+
throw error
|
|
18
|
+
}
|
|
19
|
+
if (
|
|
20
|
+
syncResult != null &&
|
|
21
|
+
(typeof syncResult === 'object' || typeof syncResult === 'function') &&
|
|
22
|
+
typeof (syncResult as PromiseLike<unknown>).then === 'function'
|
|
23
|
+
) {
|
|
24
|
+
const promise = Promise.resolve(syncResult).finally(() => {
|
|
25
|
+
depthRef.current = Math.max(0, depthRef.current - 1)
|
|
26
|
+
})
|
|
27
|
+
return promise as T
|
|
28
|
+
}
|
|
29
|
+
depthRef.current = Math.max(0, depthRef.current - 1)
|
|
30
|
+
return syncResult
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
8
34
|
describe('executeFormAutoControl', () => {
|
|
9
35
|
it('writes values and reports bac change event', () => {
|
|
10
36
|
const setValues = vi.fn()
|
|
@@ -68,4 +94,34 @@ describe('executeFormAutoControl', () => {
|
|
|
68
94
|
)
|
|
69
95
|
expect(submit).toHaveBeenCalled()
|
|
70
96
|
})
|
|
97
|
+
|
|
98
|
+
it('keeps autoControl depth until async submit settles', async () => {
|
|
99
|
+
const depthRef = { current: 0 }
|
|
100
|
+
const runAutoControl = createDepthTrackingRunAutoControl(depthRef)
|
|
101
|
+
let resolveSubmit!: () => void
|
|
102
|
+
const submit = vi.fn(
|
|
103
|
+
() =>
|
|
104
|
+
new Promise<void>((resolve) => {
|
|
105
|
+
resolveSubmit = resolve
|
|
106
|
+
}),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
executeFormAutoControl(
|
|
110
|
+
{ action: 'submit' },
|
|
111
|
+
{
|
|
112
|
+
setValues: vi.fn(),
|
|
113
|
+
getValues: () => ({}),
|
|
114
|
+
submit,
|
|
115
|
+
rootElement: null,
|
|
116
|
+
},
|
|
117
|
+
{ reportEvent: vi.fn(), runAutoControl },
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
expect(submit).toHaveBeenCalled()
|
|
121
|
+
expect(depthRef.current).toBe(1)
|
|
122
|
+
resolveSubmit()
|
|
123
|
+
await Promise.resolve()
|
|
124
|
+
await Promise.resolve()
|
|
125
|
+
expect(depthRef.current).toBe(0)
|
|
126
|
+
})
|
|
71
127
|
})
|
|
@@ -10,6 +10,7 @@ export interface FormAutoControlTargets {
|
|
|
10
10
|
|
|
11
11
|
export interface FormAutoControlHelpers {
|
|
12
12
|
reportEvent: (event: FormRuntimeEventData) => void
|
|
13
|
+
/** 支持同步或返回 Promise(async submit 期间保持 autoControlDepth) */
|
|
13
14
|
runAutoControl: <T>(fn: () => T) => T
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -64,8 +65,8 @@ export function executeFormAutoControl(
|
|
|
64
65
|
|
|
65
66
|
helpers.runAutoControl(() => {
|
|
66
67
|
if (action === 'submit') {
|
|
67
|
-
|
|
68
|
-
return
|
|
68
|
+
// 返回 Promise,使 runAutoControl 在 settle 前保持 depth
|
|
69
|
+
return targets.submit()
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
const field = typeof data.field === 'string' ? data.field.trim() : ''
|
|
@@ -12,12 +12,24 @@ import type { FormRuntimeEventData } from './types'
|
|
|
12
12
|
export interface FormRuntimeContextValue {
|
|
13
13
|
reportEvent: (event: FormRuntimeEventData) => void
|
|
14
14
|
reportData: (values: Record<string, unknown>) => void
|
|
15
|
+
/**
|
|
16
|
+
* 在自动控上下文中执行 fn。若 fn 返回 Promise,depth 保持到 settle,
|
|
17
|
+
* 使异步 submit 内的 reportEvent 仍为 form_auto_control_bac_event。
|
|
18
|
+
*/
|
|
15
19
|
runAutoControl: <T>(fn: () => T) => T
|
|
16
20
|
isAutoControl: () => boolean
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
const FormRuntimeContext = createContext<FormRuntimeContextValue | null>(null)
|
|
20
24
|
|
|
25
|
+
function isThenable(value: unknown): value is PromiseLike<unknown> {
|
|
26
|
+
return (
|
|
27
|
+
value != null &&
|
|
28
|
+
(typeof value === 'object' || typeof value === 'function') &&
|
|
29
|
+
typeof (value as PromiseLike<unknown>).then === 'function'
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
21
33
|
const noopRuntime: FormRuntimeContextValue = {
|
|
22
34
|
reportEvent: () => {},
|
|
23
35
|
reportData: () => {},
|
|
@@ -72,11 +84,21 @@ export function FormRuntimeProvider({
|
|
|
72
84
|
|
|
73
85
|
const runAutoControl = useCallback(<T,>(fn: () => T): T => {
|
|
74
86
|
autoControlDepthRef.current += 1
|
|
87
|
+
let syncResult: T
|
|
75
88
|
try {
|
|
76
|
-
|
|
77
|
-
}
|
|
89
|
+
syncResult = fn()
|
|
90
|
+
} catch (error) {
|
|
78
91
|
autoControlDepthRef.current = Math.max(0, autoControlDepthRef.current - 1)
|
|
92
|
+
throw error
|
|
93
|
+
}
|
|
94
|
+
if (isThenable(syncResult)) {
|
|
95
|
+
const promise = Promise.resolve(syncResult).finally(() => {
|
|
96
|
+
autoControlDepthRef.current = Math.max(0, autoControlDepthRef.current - 1)
|
|
97
|
+
})
|
|
98
|
+
return promise as T
|
|
79
99
|
}
|
|
100
|
+
autoControlDepthRef.current = Math.max(0, autoControlDepthRef.current - 1)
|
|
101
|
+
return syncResult
|
|
80
102
|
}, [])
|
|
81
103
|
|
|
82
104
|
const isAutoControl = useCallback(
|