@faasjs/react 3.7.0-beta.5 → 3.7.0-beta.7
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.d.mts +53 -15
- package/dist/index.d.ts +53 -15
- package/dist/index.js +87 -38
- package/dist/index.mjs +88 -39
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -124,7 +124,7 @@ declare function createSplittingContext<T extends Record<string, any>>(defaultVa
|
|
|
124
124
|
* ```
|
|
125
125
|
*/
|
|
126
126
|
Provider<NewT extends T = T>(props: {
|
|
127
|
-
value?: NewT
|
|
127
|
+
value?: Partial<NewT>;
|
|
128
128
|
children: ReactNode;
|
|
129
129
|
/**
|
|
130
130
|
* Whether to use memoization for the children.
|
|
@@ -135,6 +135,20 @@ declare function createSplittingContext<T extends Record<string, any>>(defaultVa
|
|
|
135
135
|
* `any[]`: memoize the children with specific dependencies.
|
|
136
136
|
*/
|
|
137
137
|
memo?: true | any[];
|
|
138
|
+
/**
|
|
139
|
+
* An object containing initial values that will be automatically converted into state variables using {@link useSplittingState} hook. Each property will create both a state value and its setter following the pattern: value/setValue.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```tsx
|
|
143
|
+
* <Provider
|
|
144
|
+
* initializeStates={{
|
|
145
|
+
* value: 0,
|
|
146
|
+
* }}
|
|
147
|
+
* >
|
|
148
|
+
* // Children will have access to: value, setValue
|
|
149
|
+
* </Provider>
|
|
150
|
+
*/
|
|
151
|
+
initializeStates?: Partial<NewT>;
|
|
138
152
|
}): ReactNode;
|
|
139
153
|
/**
|
|
140
154
|
* The hook to use the splitting context.
|
|
@@ -264,6 +278,14 @@ type FaasReactClientOptions = {
|
|
|
264
278
|
/** @default `/` */
|
|
265
279
|
baseUrl?: BaseUrl;
|
|
266
280
|
options?: Options;
|
|
281
|
+
/**
|
|
282
|
+
* @example
|
|
283
|
+
* ```ts
|
|
284
|
+
* onError: (action, params) => async (res) => {
|
|
285
|
+
* console.error(action, params, res)
|
|
286
|
+
* }
|
|
287
|
+
* ```
|
|
288
|
+
*/
|
|
267
289
|
onError?: OnError;
|
|
268
290
|
};
|
|
269
291
|
type FaasReactClientInstance = {
|
|
@@ -386,14 +408,25 @@ type FormInputElementProps = {
|
|
|
386
408
|
onChange: (value: any) => void;
|
|
387
409
|
};
|
|
388
410
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
required
|
|
392
|
-
|
|
411
|
+
declare const FormDefaultLang: {
|
|
412
|
+
submit: string;
|
|
413
|
+
required: string;
|
|
414
|
+
string: string;
|
|
415
|
+
number: string;
|
|
393
416
|
};
|
|
417
|
+
type FormLang = typeof FormDefaultLang;
|
|
418
|
+
|
|
394
419
|
type FormError = {
|
|
395
420
|
message: string;
|
|
396
421
|
};
|
|
422
|
+
type FormRule<Options = any> = (value: any, options?: Options, lang?: FormLang) => Promise<FormError | undefined>;
|
|
423
|
+
type InferRuleOption<T> = T extends (value: any, options: infer O, lang?: FormLang) => Promise<FormError | undefined> ? O : never;
|
|
424
|
+
type FormRules = Record<string, FormRule>;
|
|
425
|
+
type InferFormRulesOptions<T> = {
|
|
426
|
+
[K in keyof T]: InferRuleOption<T[K]>;
|
|
427
|
+
};
|
|
428
|
+
declare const FormDefaultRules: FormRules;
|
|
429
|
+
type FormDefaultRulesOptions = InferFormRulesOptions<typeof FormDefaultRules>;
|
|
397
430
|
|
|
398
431
|
type InferFormInputProps<T extends ComponentType<FormInputElementProps> | JSXElementConstructor<any>> = T extends ComponentType<FormInputElementProps> ? Omit<ComponentProps<T>, 'name' | 'value' | 'onChange'> : Omit<ComponentProps<T>, 'name' | 'value'>;
|
|
399
432
|
type FormInputProps<FormElements extends FormElementTypes = FormElementTypes> = {
|
|
@@ -401,9 +434,9 @@ type FormInputProps<FormElements extends FormElementTypes = FormElementTypes> =
|
|
|
401
434
|
props?: InferFormInputProps<FormElements['Input']>;
|
|
402
435
|
};
|
|
403
436
|
|
|
404
|
-
type FormLabelElementProps<FormElements extends FormElementTypes = FormElementTypes> = {
|
|
437
|
+
type FormLabelElementProps<FormElements extends FormElementTypes = FormElementTypes, FormRulesOptions extends Record<string, any> = FormDefaultRulesOptions> = {
|
|
405
438
|
name: string;
|
|
406
|
-
rules?:
|
|
439
|
+
rules?: FormRulesOptions;
|
|
407
440
|
title?: ReactNode;
|
|
408
441
|
description?: ReactNode;
|
|
409
442
|
Label?: FormElements['Label'];
|
|
@@ -417,22 +450,26 @@ type FormElementTypes = {
|
|
|
417
450
|
};
|
|
418
451
|
declare const FormDefaultElements: FormElementTypes;
|
|
419
452
|
|
|
420
|
-
type FormProps<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes> = {
|
|
421
|
-
items: FormLabelElementProps<FormElements
|
|
453
|
+
type FormProps<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes, Rules extends FormRules = typeof FormDefaultRules> = {
|
|
454
|
+
items: FormLabelElementProps<FormElements, InferFormRulesOptions<Rules>>[];
|
|
422
455
|
onSubmit?: (values: Values) => Promise<void>;
|
|
423
|
-
|
|
456
|
+
Elements?: Partial<FormElements>;
|
|
457
|
+
lang?: Partial<FormLang>;
|
|
424
458
|
defaultValues?: Values;
|
|
459
|
+
rules?: typeof FormDefaultRules & Rules;
|
|
425
460
|
};
|
|
426
|
-
declare function FormContainer<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes>({ defaultValues,
|
|
461
|
+
declare function FormContainer<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes, Rules extends FormRules = typeof FormDefaultRules>({ defaultValues, Elements, rules, lang, ...props }: FormProps<Values, FormElements, Rules>): react_jsx_runtime.JSX.Element;
|
|
427
462
|
declare namespace FormContainer {
|
|
428
463
|
var displayName: string;
|
|
429
464
|
var whyDidYouRender: boolean;
|
|
430
465
|
}
|
|
431
466
|
|
|
432
|
-
type FormContextProps<Values extends Record<string, any> = Record<string, any
|
|
467
|
+
type FormContextProps<Values extends Record<string, any> = Record<string, any>, Rules extends FormRules = typeof FormDefaultRules> = {
|
|
433
468
|
items: FormLabelElementProps[];
|
|
434
469
|
onSubmit: (values: Values) => Promise<void>;
|
|
435
470
|
Elements: FormElementTypes;
|
|
471
|
+
lang: FormLang;
|
|
472
|
+
rules: typeof FormDefaultRules & Rules;
|
|
436
473
|
submitting: boolean;
|
|
437
474
|
setSubmitting: Dispatch<SetStateAction<boolean>>;
|
|
438
475
|
values: Values;
|
|
@@ -440,11 +477,12 @@ type FormContextProps<Values extends Record<string, any> = Record<string, any>>
|
|
|
440
477
|
errors: Record<string, FormError>;
|
|
441
478
|
setErrors: Dispatch<SetStateAction<Record<string, FormError>>>;
|
|
442
479
|
};
|
|
443
|
-
declare const FormContextProvider: <NewT extends FormContextProps<Record<string, any
|
|
444
|
-
value?: NewT
|
|
480
|
+
declare const FormContextProvider: <NewT extends FormContextProps<Record<string, any>, FormRules> = FormContextProps<Record<string, any>, FormRules>>(props: {
|
|
481
|
+
value?: Partial<NewT>;
|
|
445
482
|
children: react.ReactNode;
|
|
446
483
|
memo?: true | any[];
|
|
484
|
+
initializeStates?: Partial<NewT>;
|
|
447
485
|
}) => react.ReactNode;
|
|
448
|
-
declare const useFormContext: <NewT extends FormContextProps<Record<string, any
|
|
486
|
+
declare const useFormContext: <NewT extends FormContextProps<Record<string, any>, FormRules> = FormContextProps<Record<string, any>, FormRules>>() => Readonly<NewT>;
|
|
449
487
|
|
|
450
488
|
export { ErrorBoundary, type ErrorBoundaryProps, type ErrorChildrenProps, type FaasDataInjection, FaasDataWrapper, type FaasDataWrapperProps, FaasReactClient, type FaasReactClientInstance, type FaasReactClientOptions, FormContainer as Form, type FormButtonElementProps, type FormContextProps, FormContextProvider, FormDefaultElements, type FormElementTypes, type FormInputElementProps, type FormLabelElementProps, type FormProps, type OnError, OptionalWrapper, type OptionalWrapperProps, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, type useFaasOptions, useFormContext, useSplittingState, withFaasData };
|
package/dist/index.d.ts
CHANGED
|
@@ -124,7 +124,7 @@ declare function createSplittingContext<T extends Record<string, any>>(defaultVa
|
|
|
124
124
|
* ```
|
|
125
125
|
*/
|
|
126
126
|
Provider<NewT extends T = T>(props: {
|
|
127
|
-
value?: NewT
|
|
127
|
+
value?: Partial<NewT>;
|
|
128
128
|
children: ReactNode;
|
|
129
129
|
/**
|
|
130
130
|
* Whether to use memoization for the children.
|
|
@@ -135,6 +135,20 @@ declare function createSplittingContext<T extends Record<string, any>>(defaultVa
|
|
|
135
135
|
* `any[]`: memoize the children with specific dependencies.
|
|
136
136
|
*/
|
|
137
137
|
memo?: true | any[];
|
|
138
|
+
/**
|
|
139
|
+
* An object containing initial values that will be automatically converted into state variables using {@link useSplittingState} hook. Each property will create both a state value and its setter following the pattern: value/setValue.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```tsx
|
|
143
|
+
* <Provider
|
|
144
|
+
* initializeStates={{
|
|
145
|
+
* value: 0,
|
|
146
|
+
* }}
|
|
147
|
+
* >
|
|
148
|
+
* // Children will have access to: value, setValue
|
|
149
|
+
* </Provider>
|
|
150
|
+
*/
|
|
151
|
+
initializeStates?: Partial<NewT>;
|
|
138
152
|
}): ReactNode;
|
|
139
153
|
/**
|
|
140
154
|
* The hook to use the splitting context.
|
|
@@ -264,6 +278,14 @@ type FaasReactClientOptions = {
|
|
|
264
278
|
/** @default `/` */
|
|
265
279
|
baseUrl?: BaseUrl;
|
|
266
280
|
options?: Options;
|
|
281
|
+
/**
|
|
282
|
+
* @example
|
|
283
|
+
* ```ts
|
|
284
|
+
* onError: (action, params) => async (res) => {
|
|
285
|
+
* console.error(action, params, res)
|
|
286
|
+
* }
|
|
287
|
+
* ```
|
|
288
|
+
*/
|
|
267
289
|
onError?: OnError;
|
|
268
290
|
};
|
|
269
291
|
type FaasReactClientInstance = {
|
|
@@ -386,14 +408,25 @@ type FormInputElementProps = {
|
|
|
386
408
|
onChange: (value: any) => void;
|
|
387
409
|
};
|
|
388
410
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
required
|
|
392
|
-
|
|
411
|
+
declare const FormDefaultLang: {
|
|
412
|
+
submit: string;
|
|
413
|
+
required: string;
|
|
414
|
+
string: string;
|
|
415
|
+
number: string;
|
|
393
416
|
};
|
|
417
|
+
type FormLang = typeof FormDefaultLang;
|
|
418
|
+
|
|
394
419
|
type FormError = {
|
|
395
420
|
message: string;
|
|
396
421
|
};
|
|
422
|
+
type FormRule<Options = any> = (value: any, options?: Options, lang?: FormLang) => Promise<FormError | undefined>;
|
|
423
|
+
type InferRuleOption<T> = T extends (value: any, options: infer O, lang?: FormLang) => Promise<FormError | undefined> ? O : never;
|
|
424
|
+
type FormRules = Record<string, FormRule>;
|
|
425
|
+
type InferFormRulesOptions<T> = {
|
|
426
|
+
[K in keyof T]: InferRuleOption<T[K]>;
|
|
427
|
+
};
|
|
428
|
+
declare const FormDefaultRules: FormRules;
|
|
429
|
+
type FormDefaultRulesOptions = InferFormRulesOptions<typeof FormDefaultRules>;
|
|
397
430
|
|
|
398
431
|
type InferFormInputProps<T extends ComponentType<FormInputElementProps> | JSXElementConstructor<any>> = T extends ComponentType<FormInputElementProps> ? Omit<ComponentProps<T>, 'name' | 'value' | 'onChange'> : Omit<ComponentProps<T>, 'name' | 'value'>;
|
|
399
432
|
type FormInputProps<FormElements extends FormElementTypes = FormElementTypes> = {
|
|
@@ -401,9 +434,9 @@ type FormInputProps<FormElements extends FormElementTypes = FormElementTypes> =
|
|
|
401
434
|
props?: InferFormInputProps<FormElements['Input']>;
|
|
402
435
|
};
|
|
403
436
|
|
|
404
|
-
type FormLabelElementProps<FormElements extends FormElementTypes = FormElementTypes> = {
|
|
437
|
+
type FormLabelElementProps<FormElements extends FormElementTypes = FormElementTypes, FormRulesOptions extends Record<string, any> = FormDefaultRulesOptions> = {
|
|
405
438
|
name: string;
|
|
406
|
-
rules?:
|
|
439
|
+
rules?: FormRulesOptions;
|
|
407
440
|
title?: ReactNode;
|
|
408
441
|
description?: ReactNode;
|
|
409
442
|
Label?: FormElements['Label'];
|
|
@@ -417,22 +450,26 @@ type FormElementTypes = {
|
|
|
417
450
|
};
|
|
418
451
|
declare const FormDefaultElements: FormElementTypes;
|
|
419
452
|
|
|
420
|
-
type FormProps<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes> = {
|
|
421
|
-
items: FormLabelElementProps<FormElements
|
|
453
|
+
type FormProps<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes, Rules extends FormRules = typeof FormDefaultRules> = {
|
|
454
|
+
items: FormLabelElementProps<FormElements, InferFormRulesOptions<Rules>>[];
|
|
422
455
|
onSubmit?: (values: Values) => Promise<void>;
|
|
423
|
-
|
|
456
|
+
Elements?: Partial<FormElements>;
|
|
457
|
+
lang?: Partial<FormLang>;
|
|
424
458
|
defaultValues?: Values;
|
|
459
|
+
rules?: typeof FormDefaultRules & Rules;
|
|
425
460
|
};
|
|
426
|
-
declare function FormContainer<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes>({ defaultValues,
|
|
461
|
+
declare function FormContainer<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes, Rules extends FormRules = typeof FormDefaultRules>({ defaultValues, Elements, rules, lang, ...props }: FormProps<Values, FormElements, Rules>): react_jsx_runtime.JSX.Element;
|
|
427
462
|
declare namespace FormContainer {
|
|
428
463
|
var displayName: string;
|
|
429
464
|
var whyDidYouRender: boolean;
|
|
430
465
|
}
|
|
431
466
|
|
|
432
|
-
type FormContextProps<Values extends Record<string, any> = Record<string, any
|
|
467
|
+
type FormContextProps<Values extends Record<string, any> = Record<string, any>, Rules extends FormRules = typeof FormDefaultRules> = {
|
|
433
468
|
items: FormLabelElementProps[];
|
|
434
469
|
onSubmit: (values: Values) => Promise<void>;
|
|
435
470
|
Elements: FormElementTypes;
|
|
471
|
+
lang: FormLang;
|
|
472
|
+
rules: typeof FormDefaultRules & Rules;
|
|
436
473
|
submitting: boolean;
|
|
437
474
|
setSubmitting: Dispatch<SetStateAction<boolean>>;
|
|
438
475
|
values: Values;
|
|
@@ -440,11 +477,12 @@ type FormContextProps<Values extends Record<string, any> = Record<string, any>>
|
|
|
440
477
|
errors: Record<string, FormError>;
|
|
441
478
|
setErrors: Dispatch<SetStateAction<Record<string, FormError>>>;
|
|
442
479
|
};
|
|
443
|
-
declare const FormContextProvider: <NewT extends FormContextProps<Record<string, any
|
|
444
|
-
value?: NewT
|
|
480
|
+
declare const FormContextProvider: <NewT extends FormContextProps<Record<string, any>, FormRules> = FormContextProps<Record<string, any>, FormRules>>(props: {
|
|
481
|
+
value?: Partial<NewT>;
|
|
445
482
|
children: react.ReactNode;
|
|
446
483
|
memo?: true | any[];
|
|
484
|
+
initializeStates?: Partial<NewT>;
|
|
447
485
|
}) => react.ReactNode;
|
|
448
|
-
declare const useFormContext: <NewT extends FormContextProps<Record<string, any
|
|
486
|
+
declare const useFormContext: <NewT extends FormContextProps<Record<string, any>, FormRules> = FormContextProps<Record<string, any>, FormRules>>() => Readonly<NewT>;
|
|
449
487
|
|
|
450
488
|
export { ErrorBoundary, type ErrorBoundaryProps, type ErrorChildrenProps, type FaasDataInjection, FaasDataWrapper, type FaasDataWrapperProps, FaasReactClient, type FaasReactClientInstance, type FaasReactClientOptions, FormContainer as Form, type FormButtonElementProps, type FormContextProps, FormContextProvider, FormDefaultElements, type FormElementTypes, type FormInputElementProps, type FormLabelElementProps, type FormProps, type OnError, OptionalWrapper, type OptionalWrapperProps, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, type useFaasOptions, useFormContext, useSplittingState, withFaasData };
|
package/dist/index.js
CHANGED
|
@@ -20,6 +20,7 @@ function equal(a, b) {
|
|
|
20
20
|
if ((a === null || a === void 0) && (b === null || b === void 0))
|
|
21
21
|
return true;
|
|
22
22
|
if (typeof a !== typeof b) return false;
|
|
23
|
+
if (b === null || b === void 0) return false;
|
|
23
24
|
const ctor = a.constructor;
|
|
24
25
|
if (ctor !== b.constructor) return false;
|
|
25
26
|
switch (ctor) {
|
|
@@ -79,6 +80,17 @@ function useEqualCallback(callback, dependencies) {
|
|
|
79
80
|
useEqualMemoize(dependencies)
|
|
80
81
|
);
|
|
81
82
|
}
|
|
83
|
+
function useSplittingState(initialStates) {
|
|
84
|
+
const states = {};
|
|
85
|
+
for (const key of Object.keys(initialStates)) {
|
|
86
|
+
const state = react.useState(initialStates[key]);
|
|
87
|
+
Object.assign(states, {
|
|
88
|
+
[key]: state[0],
|
|
89
|
+
[`set${String(key).charAt(0).toUpperCase()}${String(key).slice(1)}`]: state[1]
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return states;
|
|
93
|
+
}
|
|
82
94
|
function createSplittingContext(defaultValue) {
|
|
83
95
|
const keys = Array.isArray(defaultValue) ? defaultValue : Object.keys(defaultValue);
|
|
84
96
|
const defaultValues = Array.isArray(defaultValue) ? keys.reduce((prev, cur) => {
|
|
@@ -88,13 +100,14 @@ function createSplittingContext(defaultValue) {
|
|
|
88
100
|
const contexts = {};
|
|
89
101
|
for (const key of keys) contexts[key] = react.createContext(defaultValues[key]);
|
|
90
102
|
function Provider(props) {
|
|
103
|
+
const states = props.initializeStates ? useSplittingState(props.initializeStates) : {};
|
|
91
104
|
let children = props.memo ? useEqualMemo(
|
|
92
105
|
() => props.children,
|
|
93
106
|
props.memo === true ? [] : props.memo
|
|
94
107
|
) : props.children;
|
|
95
108
|
for (const key of keys) {
|
|
96
109
|
const Context = contexts[key];
|
|
97
|
-
const value = props.value?.[key] ?? defaultValues[key];
|
|
110
|
+
const value = props.value?.[key] ?? states[key] ?? defaultValues[key];
|
|
98
111
|
children = /* @__PURE__ */ jsxRuntime.jsx(Context.Provider, { value, children });
|
|
99
112
|
}
|
|
100
113
|
return children;
|
|
@@ -118,17 +131,6 @@ function createSplittingContext(defaultValue) {
|
|
|
118
131
|
use
|
|
119
132
|
};
|
|
120
133
|
}
|
|
121
|
-
function useSplittingState(initialStates) {
|
|
122
|
-
const states = {};
|
|
123
|
-
for (const key of Object.keys(initialStates)) {
|
|
124
|
-
const state = react.useState(initialStates[key]);
|
|
125
|
-
Object.assign(states, {
|
|
126
|
-
[key]: state[0],
|
|
127
|
-
[`set${String(key).charAt(0).toUpperCase()}${String(key).slice(1)}`]: state[1]
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
return states;
|
|
131
|
-
}
|
|
132
134
|
function FaasDataWrapper(props) {
|
|
133
135
|
const request = getClient(props.baseUrl).useFaas(
|
|
134
136
|
props.action,
|
|
@@ -347,12 +349,14 @@ var FormContext = createSplittingContext([
|
|
|
347
349
|
"items",
|
|
348
350
|
"onSubmit",
|
|
349
351
|
"Elements",
|
|
352
|
+
"lang",
|
|
350
353
|
"submitting",
|
|
351
354
|
"setSubmitting",
|
|
352
355
|
"values",
|
|
353
356
|
"setValues",
|
|
354
357
|
"errors",
|
|
355
|
-
"setErrors"
|
|
358
|
+
"setErrors",
|
|
359
|
+
"rules"
|
|
356
360
|
]);
|
|
357
361
|
var FormContextProvider = FormContext.Provider;
|
|
358
362
|
var useFormContext = FormContext.use;
|
|
@@ -371,21 +375,48 @@ FormBody.displayName = "FormBody";
|
|
|
371
375
|
FormBody.whyDidYouRender = true;
|
|
372
376
|
|
|
373
377
|
// src/Form/rules.ts
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
378
|
+
var FormDefaultRules = {
|
|
379
|
+
required: async (value, _, lang) => {
|
|
380
|
+
if (value === null || value === void 0 || value === "" || Number.isNaN(value)) {
|
|
381
|
+
return { message: lang?.required };
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
type: async (value, options, lang) => {
|
|
385
|
+
switch (options) {
|
|
386
|
+
case "string":
|
|
387
|
+
if (typeof value !== "string") {
|
|
388
|
+
return { message: lang?.string };
|
|
389
|
+
}
|
|
390
|
+
break;
|
|
391
|
+
case "number":
|
|
392
|
+
if (Number.isNaN(Number(value))) {
|
|
393
|
+
return { message: lang?.number };
|
|
394
|
+
}
|
|
395
|
+
break;
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
custom: async (value, options) => {
|
|
399
|
+
return options(value);
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
async function validValues(rules, items, values, lang) {
|
|
382
403
|
const errors = {};
|
|
383
404
|
for (const item of items) {
|
|
384
405
|
const value = values[item.name];
|
|
385
|
-
const
|
|
386
|
-
if (
|
|
387
|
-
const
|
|
388
|
-
|
|
406
|
+
const rulesOptions = item.rules;
|
|
407
|
+
if (rulesOptions) {
|
|
408
|
+
for (const [name, options] of Object.entries(rulesOptions)) {
|
|
409
|
+
const handler = rules[name];
|
|
410
|
+
if (!handler) {
|
|
411
|
+
console.warn(`Rule "${name}" is not defined`);
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
const error = await handler(value, options, lang);
|
|
415
|
+
if (error) {
|
|
416
|
+
errors[item.name] = error;
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
389
420
|
}
|
|
390
421
|
}
|
|
391
422
|
return errors;
|
|
@@ -398,7 +429,9 @@ function FormFooter() {
|
|
|
398
429
|
values,
|
|
399
430
|
Elements,
|
|
400
431
|
items,
|
|
401
|
-
setErrors
|
|
432
|
+
setErrors,
|
|
433
|
+
lang,
|
|
434
|
+
rules
|
|
402
435
|
} = useFormContext();
|
|
403
436
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
404
437
|
Elements.Button,
|
|
@@ -406,7 +439,7 @@ function FormFooter() {
|
|
|
406
439
|
disabled: submitting,
|
|
407
440
|
submit: async () => {
|
|
408
441
|
setSubmitting(true);
|
|
409
|
-
const errors = await validValues(items, values);
|
|
442
|
+
const errors = await validValues(rules, items, values, lang);
|
|
410
443
|
if (Object.keys(errors).length) {
|
|
411
444
|
setErrors(errors);
|
|
412
445
|
setSubmitting(false);
|
|
@@ -414,7 +447,7 @@ function FormFooter() {
|
|
|
414
447
|
}
|
|
415
448
|
onSubmit(values).finally(() => setSubmitting(false));
|
|
416
449
|
},
|
|
417
|
-
children:
|
|
450
|
+
children: lang.submit
|
|
418
451
|
}
|
|
419
452
|
);
|
|
420
453
|
}
|
|
@@ -490,26 +523,42 @@ var FormDefaultElements = {
|
|
|
490
523
|
Input: FormInputElement,
|
|
491
524
|
Button: FormButtonElement
|
|
492
525
|
};
|
|
526
|
+
|
|
527
|
+
// src/Form/lang.ts
|
|
528
|
+
var FormDefaultLang = {
|
|
529
|
+
submit: "Submit",
|
|
530
|
+
required: "This field is required",
|
|
531
|
+
string: "This field must be a string",
|
|
532
|
+
number: "This field must be a number"
|
|
533
|
+
};
|
|
493
534
|
function mergeValues(items, defaultValues = {}) {
|
|
494
535
|
const values = {};
|
|
495
536
|
for (const item of items)
|
|
496
537
|
values[item.name] = defaultValues[item.name] ?? "";
|
|
497
538
|
return values;
|
|
498
539
|
}
|
|
499
|
-
function FormContainer({
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
540
|
+
function FormContainer({
|
|
541
|
+
defaultValues,
|
|
542
|
+
Elements,
|
|
543
|
+
rules,
|
|
544
|
+
lang,
|
|
545
|
+
...props
|
|
546
|
+
}) {
|
|
506
547
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
507
548
|
FormContextProvider,
|
|
508
549
|
{
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
550
|
+
initializeStates: {
|
|
551
|
+
values: mergeValues(props.items, defaultValues),
|
|
552
|
+
errors: {},
|
|
553
|
+
submitting: false,
|
|
554
|
+
Elements: Object.assign(
|
|
555
|
+
FormDefaultElements,
|
|
556
|
+
Elements
|
|
557
|
+
),
|
|
558
|
+
lang: Object.assign(FormDefaultLang, lang),
|
|
559
|
+
rules: Object.assign(FormDefaultRules, rules)
|
|
512
560
|
},
|
|
561
|
+
value: props,
|
|
513
562
|
memo: true,
|
|
514
563
|
children: [
|
|
515
564
|
/* @__PURE__ */ jsxRuntime.jsx(FormBody, {}),
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { forwardRef, useRef, useMemo, useEffect, useCallback,
|
|
1
|
+
import { forwardRef, useRef, useMemo, useEffect, useCallback, useState, createContext, cloneElement, Component, useContext } from 'react';
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import { FaasBrowserClient } from '@faasjs/browser';
|
|
4
4
|
|
|
@@ -18,6 +18,7 @@ function equal(a, b) {
|
|
|
18
18
|
if ((a === null || a === void 0) && (b === null || b === void 0))
|
|
19
19
|
return true;
|
|
20
20
|
if (typeof a !== typeof b) return false;
|
|
21
|
+
if (b === null || b === void 0) return false;
|
|
21
22
|
const ctor = a.constructor;
|
|
22
23
|
if (ctor !== b.constructor) return false;
|
|
23
24
|
switch (ctor) {
|
|
@@ -77,6 +78,17 @@ function useEqualCallback(callback, dependencies) {
|
|
|
77
78
|
useEqualMemoize(dependencies)
|
|
78
79
|
);
|
|
79
80
|
}
|
|
81
|
+
function useSplittingState(initialStates) {
|
|
82
|
+
const states = {};
|
|
83
|
+
for (const key of Object.keys(initialStates)) {
|
|
84
|
+
const state = useState(initialStates[key]);
|
|
85
|
+
Object.assign(states, {
|
|
86
|
+
[key]: state[0],
|
|
87
|
+
[`set${String(key).charAt(0).toUpperCase()}${String(key).slice(1)}`]: state[1]
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return states;
|
|
91
|
+
}
|
|
80
92
|
function createSplittingContext(defaultValue) {
|
|
81
93
|
const keys = Array.isArray(defaultValue) ? defaultValue : Object.keys(defaultValue);
|
|
82
94
|
const defaultValues = Array.isArray(defaultValue) ? keys.reduce((prev, cur) => {
|
|
@@ -86,13 +98,14 @@ function createSplittingContext(defaultValue) {
|
|
|
86
98
|
const contexts = {};
|
|
87
99
|
for (const key of keys) contexts[key] = createContext(defaultValues[key]);
|
|
88
100
|
function Provider(props) {
|
|
101
|
+
const states = props.initializeStates ? useSplittingState(props.initializeStates) : {};
|
|
89
102
|
let children = props.memo ? useEqualMemo(
|
|
90
103
|
() => props.children,
|
|
91
104
|
props.memo === true ? [] : props.memo
|
|
92
105
|
) : props.children;
|
|
93
106
|
for (const key of keys) {
|
|
94
107
|
const Context = contexts[key];
|
|
95
|
-
const value = props.value?.[key] ?? defaultValues[key];
|
|
108
|
+
const value = props.value?.[key] ?? states[key] ?? defaultValues[key];
|
|
96
109
|
children = /* @__PURE__ */ jsx(Context.Provider, { value, children });
|
|
97
110
|
}
|
|
98
111
|
return children;
|
|
@@ -116,17 +129,6 @@ function createSplittingContext(defaultValue) {
|
|
|
116
129
|
use
|
|
117
130
|
};
|
|
118
131
|
}
|
|
119
|
-
function useSplittingState(initialStates) {
|
|
120
|
-
const states = {};
|
|
121
|
-
for (const key of Object.keys(initialStates)) {
|
|
122
|
-
const state = useState(initialStates[key]);
|
|
123
|
-
Object.assign(states, {
|
|
124
|
-
[key]: state[0],
|
|
125
|
-
[`set${String(key).charAt(0).toUpperCase()}${String(key).slice(1)}`]: state[1]
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
return states;
|
|
129
|
-
}
|
|
130
132
|
function FaasDataWrapper(props) {
|
|
131
133
|
const request = getClient(props.baseUrl).useFaas(
|
|
132
134
|
props.action,
|
|
@@ -345,12 +347,14 @@ var FormContext = createSplittingContext([
|
|
|
345
347
|
"items",
|
|
346
348
|
"onSubmit",
|
|
347
349
|
"Elements",
|
|
350
|
+
"lang",
|
|
348
351
|
"submitting",
|
|
349
352
|
"setSubmitting",
|
|
350
353
|
"values",
|
|
351
354
|
"setValues",
|
|
352
355
|
"errors",
|
|
353
|
-
"setErrors"
|
|
356
|
+
"setErrors",
|
|
357
|
+
"rules"
|
|
354
358
|
]);
|
|
355
359
|
var FormContextProvider = FormContext.Provider;
|
|
356
360
|
var useFormContext = FormContext.use;
|
|
@@ -369,21 +373,48 @@ FormBody.displayName = "FormBody";
|
|
|
369
373
|
FormBody.whyDidYouRender = true;
|
|
370
374
|
|
|
371
375
|
// src/Form/rules.ts
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
376
|
+
var FormDefaultRules = {
|
|
377
|
+
required: async (value, _, lang) => {
|
|
378
|
+
if (value === null || value === void 0 || value === "" || Number.isNaN(value)) {
|
|
379
|
+
return { message: lang?.required };
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
type: async (value, options, lang) => {
|
|
383
|
+
switch (options) {
|
|
384
|
+
case "string":
|
|
385
|
+
if (typeof value !== "string") {
|
|
386
|
+
return { message: lang?.string };
|
|
387
|
+
}
|
|
388
|
+
break;
|
|
389
|
+
case "number":
|
|
390
|
+
if (Number.isNaN(Number(value))) {
|
|
391
|
+
return { message: lang?.number };
|
|
392
|
+
}
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
custom: async (value, options) => {
|
|
397
|
+
return options(value);
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
async function validValues(rules, items, values, lang) {
|
|
380
401
|
const errors = {};
|
|
381
402
|
for (const item of items) {
|
|
382
403
|
const value = values[item.name];
|
|
383
|
-
const
|
|
384
|
-
if (
|
|
385
|
-
const
|
|
386
|
-
|
|
404
|
+
const rulesOptions = item.rules;
|
|
405
|
+
if (rulesOptions) {
|
|
406
|
+
for (const [name, options] of Object.entries(rulesOptions)) {
|
|
407
|
+
const handler = rules[name];
|
|
408
|
+
if (!handler) {
|
|
409
|
+
console.warn(`Rule "${name}" is not defined`);
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
const error = await handler(value, options, lang);
|
|
413
|
+
if (error) {
|
|
414
|
+
errors[item.name] = error;
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
387
418
|
}
|
|
388
419
|
}
|
|
389
420
|
return errors;
|
|
@@ -396,7 +427,9 @@ function FormFooter() {
|
|
|
396
427
|
values,
|
|
397
428
|
Elements,
|
|
398
429
|
items,
|
|
399
|
-
setErrors
|
|
430
|
+
setErrors,
|
|
431
|
+
lang,
|
|
432
|
+
rules
|
|
400
433
|
} = useFormContext();
|
|
401
434
|
return /* @__PURE__ */ jsx(
|
|
402
435
|
Elements.Button,
|
|
@@ -404,7 +437,7 @@ function FormFooter() {
|
|
|
404
437
|
disabled: submitting,
|
|
405
438
|
submit: async () => {
|
|
406
439
|
setSubmitting(true);
|
|
407
|
-
const errors = await validValues(items, values);
|
|
440
|
+
const errors = await validValues(rules, items, values, lang);
|
|
408
441
|
if (Object.keys(errors).length) {
|
|
409
442
|
setErrors(errors);
|
|
410
443
|
setSubmitting(false);
|
|
@@ -412,7 +445,7 @@ function FormFooter() {
|
|
|
412
445
|
}
|
|
413
446
|
onSubmit(values).finally(() => setSubmitting(false));
|
|
414
447
|
},
|
|
415
|
-
children:
|
|
448
|
+
children: lang.submit
|
|
416
449
|
}
|
|
417
450
|
);
|
|
418
451
|
}
|
|
@@ -488,26 +521,42 @@ var FormDefaultElements = {
|
|
|
488
521
|
Input: FormInputElement,
|
|
489
522
|
Button: FormButtonElement
|
|
490
523
|
};
|
|
524
|
+
|
|
525
|
+
// src/Form/lang.ts
|
|
526
|
+
var FormDefaultLang = {
|
|
527
|
+
submit: "Submit",
|
|
528
|
+
required: "This field is required",
|
|
529
|
+
string: "This field must be a string",
|
|
530
|
+
number: "This field must be a number"
|
|
531
|
+
};
|
|
491
532
|
function mergeValues(items, defaultValues = {}) {
|
|
492
533
|
const values = {};
|
|
493
534
|
for (const item of items)
|
|
494
535
|
values[item.name] = defaultValues[item.name] ?? "";
|
|
495
536
|
return values;
|
|
496
537
|
}
|
|
497
|
-
function FormContainer({
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
538
|
+
function FormContainer({
|
|
539
|
+
defaultValues,
|
|
540
|
+
Elements,
|
|
541
|
+
rules,
|
|
542
|
+
lang,
|
|
543
|
+
...props
|
|
544
|
+
}) {
|
|
504
545
|
return /* @__PURE__ */ jsxs(
|
|
505
546
|
FormContextProvider,
|
|
506
547
|
{
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
548
|
+
initializeStates: {
|
|
549
|
+
values: mergeValues(props.items, defaultValues),
|
|
550
|
+
errors: {},
|
|
551
|
+
submitting: false,
|
|
552
|
+
Elements: Object.assign(
|
|
553
|
+
FormDefaultElements,
|
|
554
|
+
Elements
|
|
555
|
+
),
|
|
556
|
+
lang: Object.assign(FormDefaultLang, lang),
|
|
557
|
+
rules: Object.assign(FormDefaultRules, rules)
|
|
510
558
|
},
|
|
559
|
+
value: props,
|
|
511
560
|
memo: true,
|
|
512
561
|
children: [
|
|
513
562
|
/* @__PURE__ */ jsx(FormBody, {}),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faasjs/react",
|
|
3
|
-
"version": "3.7.0-beta.
|
|
3
|
+
"version": "3.7.0-beta.7",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"dist"
|
|
35
35
|
],
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@faasjs/browser": "3.7.0-beta.
|
|
37
|
+
"@faasjs/browser": "3.7.0-beta.7"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@faasjs/browser": "3.7.0-beta.
|
|
40
|
+
"@faasjs/browser": "3.7.0-beta.7",
|
|
41
41
|
"@types/react": "*",
|
|
42
42
|
"react": "*"
|
|
43
43
|
},
|