@faasjs/react 8.0.0-beta.2 → 8.0.0-beta.4
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 +5 -5
- package/dist/index.cjs +135 -18
- package/dist/index.d.ts +56 -10
- package/dist/index.mjs +136 -20
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -31,6 +31,7 @@ React plugin for FaasJS.
|
|
|
31
31
|
- Fetch Data:
|
|
32
32
|
- [faas](functions/faas.md): Fetch data from FaasJS.
|
|
33
33
|
- [useFaas](functions/useFaas.md): Fetch data from FaasJS with hooks.
|
|
34
|
+
- [useFaasStream](functions/useFaasStream.md): Fetch streaming data from FaasJS with hooks.
|
|
34
35
|
- [FaasDataWrapper](functions/FaasDataWrapper.md): Fetch data from FaasJS with a wrapper component.
|
|
35
36
|
- [withFaasData](functions/withFaasData.md): Fetch data from FaasJS using a higher-order component (HOC).
|
|
36
37
|
|
|
@@ -49,12 +50,14 @@ npm install @faasjs/react react
|
|
|
49
50
|
- [Form](functions/Form.md)
|
|
50
51
|
- [FormItem](functions/FormItem.md)
|
|
51
52
|
- [getClient](functions/getClient.md)
|
|
53
|
+
- [OptionalWrapper](functions/OptionalWrapper.md)
|
|
52
54
|
- [useConstant](functions/useConstant.md)
|
|
53
55
|
- [useEqualCallback](functions/useEqualCallback.md)
|
|
54
56
|
- [useEqualEffect](functions/useEqualEffect.md)
|
|
55
57
|
- [useEqualMemo](functions/useEqualMemo.md)
|
|
56
58
|
- [useEqualMemoize](functions/useEqualMemoize.md)
|
|
57
59
|
- [useFaas](functions/useFaas.md)
|
|
60
|
+
- [useFaasStream](functions/useFaasStream.md)
|
|
58
61
|
- [usePrevious](functions/usePrevious.md)
|
|
59
62
|
- [useSplittingState](functions/useSplittingState.md)
|
|
60
63
|
- [useStateRef](functions/useStateRef.md)
|
|
@@ -71,10 +74,6 @@ npm install @faasjs/react react
|
|
|
71
74
|
- [Response](interfaces/Response.md)
|
|
72
75
|
- [ResponseError](interfaces/ResponseError.md)
|
|
73
76
|
|
|
74
|
-
## Namespaces
|
|
75
|
-
|
|
76
|
-
- [OptionalWrapper](@faasjs/namespaces/OptionalWrapper/README.md)
|
|
77
|
-
|
|
78
77
|
## Type Aliases
|
|
79
78
|
|
|
80
79
|
- [ErrorChildrenProps](type-aliases/ErrorChildrenProps.md)
|
|
@@ -105,6 +104,8 @@ npm install @faasjs/react react
|
|
|
105
104
|
- [Options](type-aliases/Options.md)
|
|
106
105
|
- [ResponseHeaders](type-aliases/ResponseHeaders.md)
|
|
107
106
|
- [useFaasOptions](type-aliases/useFaasOptions.md)
|
|
107
|
+
- [UseFaasStreamOptions](type-aliases/UseFaasStreamOptions.md)
|
|
108
|
+
- [UseFaasStreamResult](type-aliases/UseFaasStreamResult.md)
|
|
108
109
|
|
|
109
110
|
## Variables
|
|
110
111
|
|
|
@@ -113,5 +114,4 @@ npm install @faasjs/react react
|
|
|
113
114
|
- [FormDefaultElements](variables/FormDefaultElements.md)
|
|
114
115
|
- [FormDefaultLang](variables/FormDefaultLang.md)
|
|
115
116
|
- [FormDefaultRules](variables/FormDefaultRules.md)
|
|
116
|
-
- [OptionalWrapper](variables/OptionalWrapper.md)
|
|
117
117
|
- [useFormContext](variables/useFormContext.md)
|
package/dist/index.cjs
CHANGED
|
@@ -107,8 +107,7 @@ var FaasDataWrapper = fixedForwardRef(
|
|
|
107
107
|
}
|
|
108
108
|
);
|
|
109
109
|
Object.assign(FaasDataWrapper, {
|
|
110
|
-
displayName: "FaasDataWrapper"
|
|
111
|
-
whyDidYouRender: true
|
|
110
|
+
displayName: "FaasDataWrapper"
|
|
112
111
|
});
|
|
113
112
|
function withFaasData(Component2, faasProps) {
|
|
114
113
|
return (props) => /* @__PURE__ */ jsxRuntime.jsx(FaasDataWrapper, { ...faasProps, children: /* @__PURE__ */ jsxRuntime.jsx(Component2, { ...props }) });
|
|
@@ -267,10 +266,8 @@ function useConstant(fn) {
|
|
|
267
266
|
}
|
|
268
267
|
return ref.current.v;
|
|
269
268
|
}
|
|
270
|
-
useConstant.whyDidYouRender = true;
|
|
271
269
|
var ErrorBoundary = class extends react.Component {
|
|
272
270
|
static displayName = "ErrorBoundary";
|
|
273
|
-
static whyDidYouRender = true;
|
|
274
271
|
constructor(props) {
|
|
275
272
|
super(props);
|
|
276
273
|
this.state = {
|
|
@@ -349,7 +346,6 @@ function createSplittingContext(defaultValue) {
|
|
|
349
346
|
return children;
|
|
350
347
|
}
|
|
351
348
|
Provider.displayName = "SplittingContextProvider";
|
|
352
|
-
Provider.whyDidYouRender = true;
|
|
353
349
|
function use() {
|
|
354
350
|
return useConstant(() => {
|
|
355
351
|
const obj = /* @__PURE__ */ Object.create(null);
|
|
@@ -366,7 +362,6 @@ function createSplittingContext(defaultValue) {
|
|
|
366
362
|
return Object.freeze(obj);
|
|
367
363
|
});
|
|
368
364
|
}
|
|
369
|
-
use.whyDidYouRender = true;
|
|
370
365
|
return {
|
|
371
366
|
Provider,
|
|
372
367
|
use
|
|
@@ -435,20 +430,17 @@ function FormInput({
|
|
|
435
430
|
);
|
|
436
431
|
}
|
|
437
432
|
FormInput.displayName = "FormInput";
|
|
438
|
-
FormInput.whyDidYouRender = true;
|
|
439
433
|
function FormItem(props) {
|
|
440
434
|
const { Elements, errors } = useFormContext();
|
|
441
435
|
const Label = props.label?.Label ?? Elements.Label;
|
|
442
436
|
return /* @__PURE__ */ jsxRuntime.jsx(Label, { name: props.name, ...props.label, error: errors[props.name], children: /* @__PURE__ */ jsxRuntime.jsx(FormInput, { name: props.name, rules: props.rules, ...props.input }) });
|
|
443
437
|
}
|
|
444
438
|
FormItem.displayName = "FormItem";
|
|
445
|
-
FormItem.whyDidYouRender = true;
|
|
446
439
|
function FormBody() {
|
|
447
440
|
const { items } = useFormContext();
|
|
448
441
|
return items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(FormItem, { ...item }, item.name));
|
|
449
442
|
}
|
|
450
443
|
FormBody.displayName = "FormBody";
|
|
451
|
-
FormBody.whyDidYouRender = true;
|
|
452
444
|
var FormButtonElement = react.forwardRef(({ children, submit, submitting, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
453
445
|
"button",
|
|
454
446
|
{
|
|
@@ -461,10 +453,8 @@ var FormButtonElement = react.forwardRef(({ children, submit, submitting, ...pro
|
|
|
461
453
|
}
|
|
462
454
|
));
|
|
463
455
|
FormButtonElement.displayName = "FormButtonElement";
|
|
464
|
-
Object.assign(FormButtonElement, { whyDidYouRender: true });
|
|
465
456
|
var FormInputElement = react.forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("input", { ...props, onChange: (e) => onChange(e.target.value), ref }));
|
|
466
457
|
FormInputElement.displayName = "FormInputElement";
|
|
467
|
-
Object.assign(FormInputElement, { whyDidYouRender: true });
|
|
468
458
|
var FormLabelElement = ({
|
|
469
459
|
name,
|
|
470
460
|
title,
|
|
@@ -480,7 +470,6 @@ var FormLabelElement = ({
|
|
|
480
470
|
] });
|
|
481
471
|
};
|
|
482
472
|
FormLabelElement.displayName = "FormLabelElement";
|
|
483
|
-
FormLabelElement.whyDidYouRender = true;
|
|
484
473
|
|
|
485
474
|
// src/Form/elements/index.ts
|
|
486
475
|
var FormDefaultElements = {
|
|
@@ -558,7 +547,6 @@ function FormFooter() {
|
|
|
558
547
|
return MemoizedButton;
|
|
559
548
|
}
|
|
560
549
|
FormFooter.displayName = "FormFooter";
|
|
561
|
-
FormFooter.whyDidYouRender = true;
|
|
562
550
|
|
|
563
551
|
// src/Form/lang.ts
|
|
564
552
|
var FormDefaultLang = {
|
|
@@ -610,12 +598,140 @@ function FormContainer({
|
|
|
610
598
|
);
|
|
611
599
|
}
|
|
612
600
|
FormContainer.displayName = "FormContainer";
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
601
|
+
function OptionalWrapper({
|
|
602
|
+
condition,
|
|
603
|
+
Wrapper,
|
|
604
|
+
wrapperProps,
|
|
605
|
+
children
|
|
606
|
+
}) {
|
|
607
|
+
if (condition) return /* @__PURE__ */ jsxRuntime.jsx(Wrapper, { ...wrapperProps, children });
|
|
608
|
+
return children;
|
|
609
|
+
}
|
|
617
610
|
OptionalWrapper.displayName = "OptionalWrapper";
|
|
618
|
-
|
|
611
|
+
function useFaasStream(action, defaultParams, options = {}) {
|
|
612
|
+
const [loading, setLoading] = react.useState(true);
|
|
613
|
+
const [data, setData] = react.useState(options.data || "");
|
|
614
|
+
const [error, setError] = react.useState();
|
|
615
|
+
const [params, setParams] = react.useState(defaultParams);
|
|
616
|
+
const [reloadTimes, setReloadTimes] = react.useState(0);
|
|
617
|
+
const [fails, setFails] = react.useState(0);
|
|
618
|
+
const [skip, setSkip] = react.useState(
|
|
619
|
+
typeof options.skip === "function" ? options.skip(defaultParams) : options.skip
|
|
620
|
+
);
|
|
621
|
+
const controllerRef = react.useRef(null);
|
|
622
|
+
const pendingReloadsRef = react.useRef(/* @__PURE__ */ new Map());
|
|
623
|
+
const reloadCounterRef = react.useRef(0);
|
|
624
|
+
useEqualEffect(() => {
|
|
625
|
+
setSkip(
|
|
626
|
+
typeof options.skip === "function" ? options.skip(params) : options.skip
|
|
627
|
+
);
|
|
628
|
+
}, [typeof options.skip === "function" ? params : options.skip]);
|
|
629
|
+
useEqualEffect(() => {
|
|
630
|
+
if (!equal(defaultParams, params)) {
|
|
631
|
+
setParams(defaultParams);
|
|
632
|
+
}
|
|
633
|
+
}, [defaultParams]);
|
|
634
|
+
useEqualEffect(() => {
|
|
635
|
+
if (!action || skip) {
|
|
636
|
+
setLoading(false);
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
setLoading(true);
|
|
640
|
+
setData("");
|
|
641
|
+
controllerRef.current = new AbortController();
|
|
642
|
+
const client = getClient(options.baseUrl);
|
|
643
|
+
function send() {
|
|
644
|
+
client.browserClient.action(action, options.params || params, {
|
|
645
|
+
signal: controllerRef.current.signal,
|
|
646
|
+
stream: true
|
|
647
|
+
}).then(async (response) => {
|
|
648
|
+
if (!response.body) {
|
|
649
|
+
setError(new Error("Response body is null"));
|
|
650
|
+
setLoading(false);
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
const reader = response.body.getReader();
|
|
654
|
+
const decoder = new TextDecoder();
|
|
655
|
+
let accumulatedText = "";
|
|
656
|
+
try {
|
|
657
|
+
while (true) {
|
|
658
|
+
const { done, value } = await reader.read();
|
|
659
|
+
if (done) break;
|
|
660
|
+
accumulatedText += decoder.decode(value, { stream: true });
|
|
661
|
+
setData(accumulatedText);
|
|
662
|
+
}
|
|
663
|
+
setFails(0);
|
|
664
|
+
setError(null);
|
|
665
|
+
setLoading(false);
|
|
666
|
+
for (const { resolve } of pendingReloadsRef.current.values())
|
|
667
|
+
resolve(accumulatedText);
|
|
668
|
+
pendingReloadsRef.current.clear();
|
|
669
|
+
} catch (readError) {
|
|
670
|
+
reader.releaseLock();
|
|
671
|
+
throw readError;
|
|
672
|
+
}
|
|
673
|
+
}).catch(async (e) => {
|
|
674
|
+
if (typeof e?.message === "string" && e.message.toLowerCase().indexOf("aborted") >= 0)
|
|
675
|
+
return;
|
|
676
|
+
if (!fails && typeof e?.message === "string" && e.message.indexOf("Failed to fetch") >= 0) {
|
|
677
|
+
console.warn(`FaasReactClient: ${e.message} retry...`);
|
|
678
|
+
setFails(1);
|
|
679
|
+
return send();
|
|
680
|
+
}
|
|
681
|
+
let error2 = e;
|
|
682
|
+
if (client.onError)
|
|
683
|
+
try {
|
|
684
|
+
await client.onError(action, params)(e);
|
|
685
|
+
} catch (newError) {
|
|
686
|
+
error2 = newError;
|
|
687
|
+
}
|
|
688
|
+
setError(error2);
|
|
689
|
+
setLoading(false);
|
|
690
|
+
for (const { reject } of pendingReloadsRef.current.values())
|
|
691
|
+
reject(error2);
|
|
692
|
+
pendingReloadsRef.current.clear();
|
|
693
|
+
return;
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
if (options.debounce) {
|
|
697
|
+
const timeout = setTimeout(send, options.debounce);
|
|
698
|
+
return () => {
|
|
699
|
+
clearTimeout(timeout);
|
|
700
|
+
controllerRef.current?.abort();
|
|
701
|
+
setLoading(false);
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
send();
|
|
705
|
+
return () => {
|
|
706
|
+
controllerRef.current?.abort();
|
|
707
|
+
setLoading(false);
|
|
708
|
+
};
|
|
709
|
+
}, [action, options.params || params, reloadTimes, skip]);
|
|
710
|
+
const reload = useEqualCallback(
|
|
711
|
+
(params2) => {
|
|
712
|
+
if (skip) setSkip(false);
|
|
713
|
+
if (params2) setParams(params2);
|
|
714
|
+
const reloadCounter = ++reloadCounterRef.current;
|
|
715
|
+
return new Promise((resolve, reject) => {
|
|
716
|
+
pendingReloadsRef.current.set(reloadCounter, { resolve, reject });
|
|
717
|
+
setReloadTimes((prev) => prev + 1);
|
|
718
|
+
});
|
|
719
|
+
},
|
|
720
|
+
[params, skip]
|
|
721
|
+
);
|
|
722
|
+
return {
|
|
723
|
+
action,
|
|
724
|
+
params,
|
|
725
|
+
loading,
|
|
726
|
+
data: options.data || data,
|
|
727
|
+
reloadTimes,
|
|
728
|
+
error,
|
|
729
|
+
reload,
|
|
730
|
+
setData: options.setData || setData,
|
|
731
|
+
setLoading,
|
|
732
|
+
setError
|
|
733
|
+
};
|
|
734
|
+
}
|
|
619
735
|
function usePrevious(value) {
|
|
620
736
|
const ref = react.useRef(void 0);
|
|
621
737
|
react.useEffect(() => {
|
|
@@ -644,6 +760,7 @@ exports.useEqualEffect = useEqualEffect;
|
|
|
644
760
|
exports.useEqualMemo = useEqualMemo;
|
|
645
761
|
exports.useEqualMemoize = useEqualMemoize;
|
|
646
762
|
exports.useFaas = useFaas;
|
|
763
|
+
exports.useFaasStream = useFaasStream;
|
|
647
764
|
exports.useFormContext = useFormContext;
|
|
648
765
|
exports.usePrevious = usePrevious;
|
|
649
766
|
exports.useSplittingState = useSplittingState;
|
package/dist/index.d.ts
CHANGED
|
@@ -158,9 +158,6 @@ declare function getClient(host?: string): FaasReactClientInstance;
|
|
|
158
158
|
* Returns a constant value that is created by the given function.
|
|
159
159
|
*/
|
|
160
160
|
declare function useConstant<T>(fn: () => T): T;
|
|
161
|
-
declare namespace useConstant {
|
|
162
|
-
var whyDidYouRender: boolean;
|
|
163
|
-
}
|
|
164
161
|
|
|
165
162
|
interface ErrorBoundaryProps {
|
|
166
163
|
children?: ReactNode;
|
|
@@ -180,7 +177,6 @@ declare class ErrorBoundary extends Component<ErrorBoundaryProps, {
|
|
|
180
177
|
};
|
|
181
178
|
}> {
|
|
182
179
|
static displayName: string;
|
|
183
|
-
static whyDidYouRender: boolean;
|
|
184
180
|
constructor(props: ErrorBoundaryProps);
|
|
185
181
|
componentDidCatch(error: Error | null, info: any): void;
|
|
186
182
|
render(): string | number | bigint | boolean | react_jsx_runtime.JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode>>;
|
|
@@ -358,7 +354,6 @@ type FormItemProps<FormElements extends FormElementTypes = FormElementTypes, For
|
|
|
358
354
|
declare function FormItem(props: FormItemProps): react_jsx_runtime.JSX.Element;
|
|
359
355
|
declare namespace FormItem {
|
|
360
356
|
var displayName: string;
|
|
361
|
-
var whyDidYouRender: boolean;
|
|
362
357
|
}
|
|
363
358
|
|
|
364
359
|
type FormProps<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes, Rules extends FormRules = typeof FormDefaultRules> = {
|
|
@@ -402,7 +397,6 @@ type FormProps<Values extends Record<string, any> = Record<string, any>, FormEle
|
|
|
402
397
|
declare function FormContainer<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes, Rules extends FormRules = typeof FormDefaultRules>({ defaultValues, Elements, rules, lang, items, ...props }: FormProps<Values, FormElements, Rules>): react_jsx_runtime.JSX.Element;
|
|
403
398
|
declare namespace FormContainer {
|
|
404
399
|
var displayName: string;
|
|
405
|
-
var whyDidYouRender: boolean;
|
|
406
400
|
}
|
|
407
401
|
|
|
408
402
|
type FormContextProps<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes, Rules extends FormRules = typeof FormDefaultRules> = {
|
|
@@ -453,9 +447,10 @@ type OptionalWrapperProps<TWrapper extends ComponentType<{
|
|
|
453
447
|
* )
|
|
454
448
|
* ```
|
|
455
449
|
*/
|
|
456
|
-
declare
|
|
457
|
-
|
|
458
|
-
|
|
450
|
+
declare function OptionalWrapper({ condition, Wrapper, wrapperProps, children, }: OptionalWrapperProps): string | number | bigint | boolean | react_jsx_runtime.JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode>>;
|
|
451
|
+
declare namespace OptionalWrapper {
|
|
452
|
+
var displayName: string;
|
|
453
|
+
}
|
|
459
454
|
|
|
460
455
|
/**
|
|
461
456
|
* Creates a splitting context with the given default value.
|
|
@@ -588,6 +583,57 @@ type StatesWithSetters<T> = T & StateSetters<T>;
|
|
|
588
583
|
*/
|
|
589
584
|
declare function useSplittingState<T extends Record<string, unknown>>(initialStates: T): StatesWithSetters<T>;
|
|
590
585
|
|
|
586
|
+
type UseFaasStreamOptions = {
|
|
587
|
+
params?: Record<string, any>;
|
|
588
|
+
data?: string;
|
|
589
|
+
setData?: React.Dispatch<React.SetStateAction<string>>;
|
|
590
|
+
/**
|
|
591
|
+
* If skip is true, the request will not be sent.
|
|
592
|
+
*
|
|
593
|
+
* However, you can still use reload to send the request.
|
|
594
|
+
*/
|
|
595
|
+
skip?: boolean | ((params: Record<string, any>) => boolean);
|
|
596
|
+
/** Send the last request after milliseconds */
|
|
597
|
+
debounce?: number;
|
|
598
|
+
baseUrl?: BaseUrl;
|
|
599
|
+
};
|
|
600
|
+
type UseFaasStreamResult = {
|
|
601
|
+
action: string;
|
|
602
|
+
params: Record<string, any>;
|
|
603
|
+
loading: boolean;
|
|
604
|
+
reloadTimes: number;
|
|
605
|
+
data: string;
|
|
606
|
+
error: any;
|
|
607
|
+
reload: (params?: Record<string, any>) => Promise<string>;
|
|
608
|
+
setData: React.Dispatch<React.SetStateAction<string>>;
|
|
609
|
+
setLoading: React.Dispatch<React.SetStateAction<boolean>>;
|
|
610
|
+
setError: React.Dispatch<React.SetStateAction<any>>;
|
|
611
|
+
};
|
|
612
|
+
/**
|
|
613
|
+
* Stream faas server response with React hook
|
|
614
|
+
*
|
|
615
|
+
* @param action {string} action name
|
|
616
|
+
* @param defaultParams {object} initial action params
|
|
617
|
+
* @returns {UseFaasStreamResult}
|
|
618
|
+
*
|
|
619
|
+
* @example
|
|
620
|
+
* ```tsx
|
|
621
|
+
* function Chat() {
|
|
622
|
+
* const [prompt, setPrompt] = useState('')
|
|
623
|
+
* const { data, loading, reload } = useFaasStream('chat', { prompt })
|
|
624
|
+
*
|
|
625
|
+
* return (
|
|
626
|
+
* <div>
|
|
627
|
+
* <textarea value={prompt} onChange={e => setPrompt(e.target.value)} />
|
|
628
|
+
* <button onClick={reload} disabled={loading}>Send</button>
|
|
629
|
+
* <div>{data}</div>
|
|
630
|
+
* </div>
|
|
631
|
+
* )
|
|
632
|
+
* }
|
|
633
|
+
* ```
|
|
634
|
+
*/
|
|
635
|
+
declare function useFaasStream(action: string, defaultParams: Record<string, any>, options?: UseFaasStreamOptions): UseFaasStreamResult;
|
|
636
|
+
|
|
591
637
|
/**
|
|
592
638
|
* Hook to store the previous value of a state or prop.
|
|
593
639
|
*
|
|
@@ -621,4 +667,4 @@ declare function usePrevious<T = any>(value: T): T | undefined;
|
|
|
621
667
|
*/
|
|
622
668
|
declare function useStateRef<T = any>(initialValue?: T): [T, Dispatch<SetStateAction<T>>, RefObject<T>];
|
|
623
669
|
|
|
624
|
-
export { ErrorBoundary, type ErrorBoundaryProps, type ErrorChildrenProps, type FaasDataInjection, FaasDataWrapper, type FaasDataWrapperProps, type FaasDataWrapperRef, FaasReactClient, type FaasReactClientInstance, type FaasReactClientOptions, FormContainer as Form, type FormButtonElementProps, type FormContextProps, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, type FormDefaultRulesOptions, type FormElementTypes, type FormInputElementProps, FormItem, type FormItemName, type FormItemProps, type FormLabelElementProps, type FormLang, type FormProps, type FormRule, type FormRules, type InferFormRulesOptions, type OnError, OptionalWrapper, type OptionalWrapperProps, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, type useFaasOptions, useFormContext, usePrevious, useSplittingState, useStateRef, validValues, withFaasData };
|
|
670
|
+
export { ErrorBoundary, type ErrorBoundaryProps, type ErrorChildrenProps, type FaasDataInjection, FaasDataWrapper, type FaasDataWrapperProps, type FaasDataWrapperRef, FaasReactClient, type FaasReactClientInstance, type FaasReactClientOptions, FormContainer as Form, type FormButtonElementProps, type FormContextProps, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, type FormDefaultRulesOptions, type FormElementTypes, type FormInputElementProps, FormItem, type FormItemName, type FormItemProps, type FormLabelElementProps, type FormLang, type FormProps, type FormRule, type FormRules, type InferFormRulesOptions, type OnError, OptionalWrapper, type OptionalWrapperProps, type UseFaasStreamOptions, type UseFaasStreamResult, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, type useFaasOptions, useFaasStream, useFormContext, usePrevious, useSplittingState, useStateRef, validValues, withFaasData };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FaasBrowserClient } from '@faasjs/browser';
|
|
2
2
|
import { useState, useImperativeHandle, cloneElement, forwardRef, useEffect, useMemo, createContext, useRef, useCallback, Component, useContext } from 'react';
|
|
3
|
-
import { jsx, jsxs
|
|
3
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
4
|
|
|
5
5
|
// src/client.tsx
|
|
6
6
|
var AsyncFunction = (async () => {
|
|
@@ -105,8 +105,7 @@ var FaasDataWrapper = fixedForwardRef(
|
|
|
105
105
|
}
|
|
106
106
|
);
|
|
107
107
|
Object.assign(FaasDataWrapper, {
|
|
108
|
-
displayName: "FaasDataWrapper"
|
|
109
|
-
whyDidYouRender: true
|
|
108
|
+
displayName: "FaasDataWrapper"
|
|
110
109
|
});
|
|
111
110
|
function withFaasData(Component2, faasProps) {
|
|
112
111
|
return (props) => /* @__PURE__ */ jsx(FaasDataWrapper, { ...faasProps, children: /* @__PURE__ */ jsx(Component2, { ...props }) });
|
|
@@ -265,10 +264,8 @@ function useConstant(fn) {
|
|
|
265
264
|
}
|
|
266
265
|
return ref.current.v;
|
|
267
266
|
}
|
|
268
|
-
useConstant.whyDidYouRender = true;
|
|
269
267
|
var ErrorBoundary = class extends Component {
|
|
270
268
|
static displayName = "ErrorBoundary";
|
|
271
|
-
static whyDidYouRender = true;
|
|
272
269
|
constructor(props) {
|
|
273
270
|
super(props);
|
|
274
271
|
this.state = {
|
|
@@ -347,7 +344,6 @@ function createSplittingContext(defaultValue) {
|
|
|
347
344
|
return children;
|
|
348
345
|
}
|
|
349
346
|
Provider.displayName = "SplittingContextProvider";
|
|
350
|
-
Provider.whyDidYouRender = true;
|
|
351
347
|
function use() {
|
|
352
348
|
return useConstant(() => {
|
|
353
349
|
const obj = /* @__PURE__ */ Object.create(null);
|
|
@@ -364,7 +360,6 @@ function createSplittingContext(defaultValue) {
|
|
|
364
360
|
return Object.freeze(obj);
|
|
365
361
|
});
|
|
366
362
|
}
|
|
367
|
-
use.whyDidYouRender = true;
|
|
368
363
|
return {
|
|
369
364
|
Provider,
|
|
370
365
|
use
|
|
@@ -433,20 +428,17 @@ function FormInput({
|
|
|
433
428
|
);
|
|
434
429
|
}
|
|
435
430
|
FormInput.displayName = "FormInput";
|
|
436
|
-
FormInput.whyDidYouRender = true;
|
|
437
431
|
function FormItem(props) {
|
|
438
432
|
const { Elements, errors } = useFormContext();
|
|
439
433
|
const Label = props.label?.Label ?? Elements.Label;
|
|
440
434
|
return /* @__PURE__ */ jsx(Label, { name: props.name, ...props.label, error: errors[props.name], children: /* @__PURE__ */ jsx(FormInput, { name: props.name, rules: props.rules, ...props.input }) });
|
|
441
435
|
}
|
|
442
436
|
FormItem.displayName = "FormItem";
|
|
443
|
-
FormItem.whyDidYouRender = true;
|
|
444
437
|
function FormBody() {
|
|
445
438
|
const { items } = useFormContext();
|
|
446
439
|
return items.map((item) => /* @__PURE__ */ jsx(FormItem, { ...item }, item.name));
|
|
447
440
|
}
|
|
448
441
|
FormBody.displayName = "FormBody";
|
|
449
|
-
FormBody.whyDidYouRender = true;
|
|
450
442
|
var FormButtonElement = forwardRef(({ children, submit, submitting, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
451
443
|
"button",
|
|
452
444
|
{
|
|
@@ -459,10 +451,8 @@ var FormButtonElement = forwardRef(({ children, submit, submitting, ...props },
|
|
|
459
451
|
}
|
|
460
452
|
));
|
|
461
453
|
FormButtonElement.displayName = "FormButtonElement";
|
|
462
|
-
Object.assign(FormButtonElement, { whyDidYouRender: true });
|
|
463
454
|
var FormInputElement = forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsx("input", { ...props, onChange: (e) => onChange(e.target.value), ref }));
|
|
464
455
|
FormInputElement.displayName = "FormInputElement";
|
|
465
|
-
Object.assign(FormInputElement, { whyDidYouRender: true });
|
|
466
456
|
var FormLabelElement = ({
|
|
467
457
|
name,
|
|
468
458
|
title,
|
|
@@ -478,7 +468,6 @@ var FormLabelElement = ({
|
|
|
478
468
|
] });
|
|
479
469
|
};
|
|
480
470
|
FormLabelElement.displayName = "FormLabelElement";
|
|
481
|
-
FormLabelElement.whyDidYouRender = true;
|
|
482
471
|
|
|
483
472
|
// src/Form/elements/index.ts
|
|
484
473
|
var FormDefaultElements = {
|
|
@@ -556,7 +545,6 @@ function FormFooter() {
|
|
|
556
545
|
return MemoizedButton;
|
|
557
546
|
}
|
|
558
547
|
FormFooter.displayName = "FormFooter";
|
|
559
|
-
FormFooter.whyDidYouRender = true;
|
|
560
548
|
|
|
561
549
|
// src/Form/lang.ts
|
|
562
550
|
var FormDefaultLang = {
|
|
@@ -608,12 +596,140 @@ function FormContainer({
|
|
|
608
596
|
);
|
|
609
597
|
}
|
|
610
598
|
FormContainer.displayName = "FormContainer";
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
599
|
+
function OptionalWrapper({
|
|
600
|
+
condition,
|
|
601
|
+
Wrapper,
|
|
602
|
+
wrapperProps,
|
|
603
|
+
children
|
|
604
|
+
}) {
|
|
605
|
+
if (condition) return /* @__PURE__ */ jsx(Wrapper, { ...wrapperProps, children });
|
|
606
|
+
return children;
|
|
607
|
+
}
|
|
615
608
|
OptionalWrapper.displayName = "OptionalWrapper";
|
|
616
|
-
|
|
609
|
+
function useFaasStream(action, defaultParams, options = {}) {
|
|
610
|
+
const [loading, setLoading] = useState(true);
|
|
611
|
+
const [data, setData] = useState(options.data || "");
|
|
612
|
+
const [error, setError] = useState();
|
|
613
|
+
const [params, setParams] = useState(defaultParams);
|
|
614
|
+
const [reloadTimes, setReloadTimes] = useState(0);
|
|
615
|
+
const [fails, setFails] = useState(0);
|
|
616
|
+
const [skip, setSkip] = useState(
|
|
617
|
+
typeof options.skip === "function" ? options.skip(defaultParams) : options.skip
|
|
618
|
+
);
|
|
619
|
+
const controllerRef = useRef(null);
|
|
620
|
+
const pendingReloadsRef = useRef(/* @__PURE__ */ new Map());
|
|
621
|
+
const reloadCounterRef = useRef(0);
|
|
622
|
+
useEqualEffect(() => {
|
|
623
|
+
setSkip(
|
|
624
|
+
typeof options.skip === "function" ? options.skip(params) : options.skip
|
|
625
|
+
);
|
|
626
|
+
}, [typeof options.skip === "function" ? params : options.skip]);
|
|
627
|
+
useEqualEffect(() => {
|
|
628
|
+
if (!equal(defaultParams, params)) {
|
|
629
|
+
setParams(defaultParams);
|
|
630
|
+
}
|
|
631
|
+
}, [defaultParams]);
|
|
632
|
+
useEqualEffect(() => {
|
|
633
|
+
if (!action || skip) {
|
|
634
|
+
setLoading(false);
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
setLoading(true);
|
|
638
|
+
setData("");
|
|
639
|
+
controllerRef.current = new AbortController();
|
|
640
|
+
const client = getClient(options.baseUrl);
|
|
641
|
+
function send() {
|
|
642
|
+
client.browserClient.action(action, options.params || params, {
|
|
643
|
+
signal: controllerRef.current.signal,
|
|
644
|
+
stream: true
|
|
645
|
+
}).then(async (response) => {
|
|
646
|
+
if (!response.body) {
|
|
647
|
+
setError(new Error("Response body is null"));
|
|
648
|
+
setLoading(false);
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
const reader = response.body.getReader();
|
|
652
|
+
const decoder = new TextDecoder();
|
|
653
|
+
let accumulatedText = "";
|
|
654
|
+
try {
|
|
655
|
+
while (true) {
|
|
656
|
+
const { done, value } = await reader.read();
|
|
657
|
+
if (done) break;
|
|
658
|
+
accumulatedText += decoder.decode(value, { stream: true });
|
|
659
|
+
setData(accumulatedText);
|
|
660
|
+
}
|
|
661
|
+
setFails(0);
|
|
662
|
+
setError(null);
|
|
663
|
+
setLoading(false);
|
|
664
|
+
for (const { resolve } of pendingReloadsRef.current.values())
|
|
665
|
+
resolve(accumulatedText);
|
|
666
|
+
pendingReloadsRef.current.clear();
|
|
667
|
+
} catch (readError) {
|
|
668
|
+
reader.releaseLock();
|
|
669
|
+
throw readError;
|
|
670
|
+
}
|
|
671
|
+
}).catch(async (e) => {
|
|
672
|
+
if (typeof e?.message === "string" && e.message.toLowerCase().indexOf("aborted") >= 0)
|
|
673
|
+
return;
|
|
674
|
+
if (!fails && typeof e?.message === "string" && e.message.indexOf("Failed to fetch") >= 0) {
|
|
675
|
+
console.warn(`FaasReactClient: ${e.message} retry...`);
|
|
676
|
+
setFails(1);
|
|
677
|
+
return send();
|
|
678
|
+
}
|
|
679
|
+
let error2 = e;
|
|
680
|
+
if (client.onError)
|
|
681
|
+
try {
|
|
682
|
+
await client.onError(action, params)(e);
|
|
683
|
+
} catch (newError) {
|
|
684
|
+
error2 = newError;
|
|
685
|
+
}
|
|
686
|
+
setError(error2);
|
|
687
|
+
setLoading(false);
|
|
688
|
+
for (const { reject } of pendingReloadsRef.current.values())
|
|
689
|
+
reject(error2);
|
|
690
|
+
pendingReloadsRef.current.clear();
|
|
691
|
+
return;
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
if (options.debounce) {
|
|
695
|
+
const timeout = setTimeout(send, options.debounce);
|
|
696
|
+
return () => {
|
|
697
|
+
clearTimeout(timeout);
|
|
698
|
+
controllerRef.current?.abort();
|
|
699
|
+
setLoading(false);
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
send();
|
|
703
|
+
return () => {
|
|
704
|
+
controllerRef.current?.abort();
|
|
705
|
+
setLoading(false);
|
|
706
|
+
};
|
|
707
|
+
}, [action, options.params || params, reloadTimes, skip]);
|
|
708
|
+
const reload = useEqualCallback(
|
|
709
|
+
(params2) => {
|
|
710
|
+
if (skip) setSkip(false);
|
|
711
|
+
if (params2) setParams(params2);
|
|
712
|
+
const reloadCounter = ++reloadCounterRef.current;
|
|
713
|
+
return new Promise((resolve, reject) => {
|
|
714
|
+
pendingReloadsRef.current.set(reloadCounter, { resolve, reject });
|
|
715
|
+
setReloadTimes((prev) => prev + 1);
|
|
716
|
+
});
|
|
717
|
+
},
|
|
718
|
+
[params, skip]
|
|
719
|
+
);
|
|
720
|
+
return {
|
|
721
|
+
action,
|
|
722
|
+
params,
|
|
723
|
+
loading,
|
|
724
|
+
data: options.data || data,
|
|
725
|
+
reloadTimes,
|
|
726
|
+
error,
|
|
727
|
+
reload,
|
|
728
|
+
setData: options.setData || setData,
|
|
729
|
+
setLoading,
|
|
730
|
+
setError
|
|
731
|
+
};
|
|
732
|
+
}
|
|
617
733
|
function usePrevious(value) {
|
|
618
734
|
const ref = useRef(void 0);
|
|
619
735
|
useEffect(() => {
|
|
@@ -622,4 +738,4 @@ function usePrevious(value) {
|
|
|
622
738
|
return ref.current;
|
|
623
739
|
}
|
|
624
740
|
|
|
625
|
-
export { ErrorBoundary, FaasDataWrapper, FaasReactClient, FormContainer as Form, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, FormItem, OptionalWrapper, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, useFormContext, usePrevious, useSplittingState, useStateRef, validValues, withFaasData };
|
|
741
|
+
export { ErrorBoundary, FaasDataWrapper, FaasReactClient, FormContainer as Form, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, FormItem, OptionalWrapper, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, useFaasStream, useFormContext, usePrevious, useSplittingState, useStateRef, validValues, withFaasData };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faasjs/react",
|
|
3
|
-
"version": "v8.0.0-beta.
|
|
3
|
+
"version": "v8.0.0-beta.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"dist"
|
|
31
31
|
],
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@faasjs/browser": ">=v8.0.0-beta.
|
|
33
|
+
"@faasjs/browser": ">=v8.0.0-beta.4"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@faasjs/browser": ">=v8.0.0-beta.
|
|
36
|
+
"@faasjs/browser": ">=v8.0.0-beta.4",
|
|
37
37
|
"@types/react": "^19.0.0",
|
|
38
38
|
"react": "^19.0.0"
|
|
39
39
|
},
|