@faasjs/react 3.7.0-beta.1 → 3.7.0-beta.10

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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { forwardRef, useRef, useMemo, useEffect, useCallback, createContext, useState, cloneElement, Component, useContext } from 'react';
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) {
@@ -45,11 +46,8 @@ function equal(a, b) {
45
46
  case Promise:
46
47
  return a === b;
47
48
  case Object: {
48
- const keys = Object.keys(a);
49
- if (keys.length !== Object.keys(b).length) return false;
50
- for (const key of keys) {
49
+ for (const key of /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]))
51
50
  if (!equal(a[key], b[key])) return false;
52
- }
53
51
  return true;
54
52
  }
55
53
  default:
@@ -77,6 +75,24 @@ function useEqualCallback(callback, dependencies) {
77
75
  useEqualMemoize(dependencies)
78
76
  );
79
77
  }
78
+ function usePrevious(value) {
79
+ const ref = useRef();
80
+ useEffect(() => {
81
+ ref.current = value;
82
+ });
83
+ return ref.current;
84
+ }
85
+ function useSplittingState(initialStates) {
86
+ const states = {};
87
+ for (const key of Object.keys(initialStates)) {
88
+ const state = useState(initialStates[key]);
89
+ Object.assign(states, {
90
+ [key]: state[0],
91
+ [`set${String(key).charAt(0).toUpperCase()}${String(key).slice(1)}`]: state[1]
92
+ });
93
+ }
94
+ return states;
95
+ }
80
96
  function createSplittingContext(defaultValue) {
81
97
  const keys = Array.isArray(defaultValue) ? defaultValue : Object.keys(defaultValue);
82
98
  const defaultValues = Array.isArray(defaultValue) ? keys.reduce((prev, cur) => {
@@ -86,17 +102,20 @@ function createSplittingContext(defaultValue) {
86
102
  const contexts = {};
87
103
  for (const key of keys) contexts[key] = createContext(defaultValues[key]);
88
104
  function Provider(props) {
105
+ const states = props.initializeStates ? useSplittingState(props.initializeStates) : {};
89
106
  let children = props.memo ? useEqualMemo(
90
107
  () => props.children,
91
108
  props.memo === true ? [] : props.memo
92
109
  ) : props.children;
93
110
  for (const key of keys) {
94
111
  const Context = contexts[key];
95
- const value = props.value?.[key] ?? defaultValues[key];
112
+ const value = props.value?.[key] ?? states[key] ?? defaultValues[key];
96
113
  children = /* @__PURE__ */ jsx(Context.Provider, { value, children });
97
114
  }
98
115
  return children;
99
116
  }
117
+ Provider.displayName = "SplittingContextProvider";
118
+ Provider.whyDidYouRender = true;
100
119
  function use() {
101
120
  return useConstant(() => {
102
121
  const obj = /* @__PURE__ */ Object.create(null);
@@ -108,19 +127,12 @@ function createSplittingContext(defaultValue) {
108
127
  return Object.freeze(obj);
109
128
  });
110
129
  }
130
+ use.whyDidYouRender = true;
111
131
  return {
112
132
  Provider,
113
133
  use
114
134
  };
115
135
  }
116
- function useSplittingState(initialStates) {
117
- const states = {};
118
- for (const key of Object.keys(initialStates)) {
119
- const state = useState(initialStates[key]);
120
- Object.assign(states, { [key]: state[0], [`set${String(key).charAt(0).toUpperCase()}${String(key).slice(1)}`]: state[1] });
121
- }
122
- return states;
123
- }
124
136
  function FaasDataWrapper(props) {
125
137
  const request = getClient(props.baseUrl).useFaas(
126
138
  props.action,
@@ -153,10 +165,22 @@ function FaasDataWrapper(props) {
153
165
  ]);
154
166
  return child;
155
167
  }
168
+ FaasDataWrapper.displayName = "FaasDataWrapper";
156
169
  FaasDataWrapper.whyDidYouRender = true;
157
170
  function withFaasData(Component2, faasProps) {
158
171
  return (props) => /* @__PURE__ */ jsx(FaasDataWrapper, { ...faasProps, children: /* @__PURE__ */ jsx(Component2, { ...props }) });
159
172
  }
173
+
174
+ // src/faas.ts
175
+ async function faas(action, params, options) {
176
+ const client = getClient(options?.baseUrl);
177
+ if (client.onError)
178
+ return client.browserClient.action(action, params, options).catch(async (res) => {
179
+ await client.onError(action, params)(res);
180
+ return Promise.reject(res);
181
+ });
182
+ return client.browserClient.action(action, params, options);
183
+ }
160
184
  function useFaas(action, defaultParams, options = {}) {
161
185
  const [loading, setLoading] = useState(true);
162
186
  const [data, setData] = useState();
@@ -255,17 +279,6 @@ function useFaas(action, defaultParams, options = {}) {
255
279
  };
256
280
  }
257
281
  useFaas.whyDidYouRender = true;
258
-
259
- // src/faas.ts
260
- async function faas(action, params, options) {
261
- const client = getClient(options?.baseUrl);
262
- if (client.onError)
263
- return client.browserClient.action(action, params, options).catch(async (res) => {
264
- await client.onError(action, params)(res);
265
- return Promise.reject(res);
266
- });
267
- return client.browserClient.action(action, params, options);
268
- }
269
282
  var clients = {};
270
283
  function FaasReactClient({ baseUrl, options, onError } = {
271
284
  baseUrl: "/"
@@ -291,6 +304,7 @@ function getClient(host) {
291
304
  return client;
292
305
  }
293
306
  var ErrorBoundary = class extends Component {
307
+ static displayName = "ErrorBoundary";
294
308
  static whyDidYouRender = true;
295
309
  constructor(props) {
296
310
  super(props);
@@ -326,72 +340,156 @@ var ErrorBoundary = class extends Component {
326
340
  return this.props.children;
327
341
  }
328
342
  };
329
- ErrorBoundary.whyDidYouRender = true;
330
343
  var OptionalWrapper = ({ condition, Wrapper, wrapperProps, children }) => {
331
344
  return condition ? /* @__PURE__ */ jsx(Wrapper, { ...wrapperProps, children }) : /* @__PURE__ */ jsx(Fragment, { children });
332
345
  };
346
+ OptionalWrapper.displayName = "OptionalWrapper";
333
347
  OptionalWrapper.whyDidYouRender = true;
334
348
 
335
349
  // src/Form/context.tsx
336
- var FormContext = createSplittingContext(["items", "onSubmit", "Elements", "submitting", "setSubmitting", "values", "setValues"]);
350
+ var FormContext = createSplittingContext([
351
+ "items",
352
+ "onSubmit",
353
+ "Elements",
354
+ "lang",
355
+ "submitting",
356
+ "setSubmitting",
357
+ "values",
358
+ "setValues",
359
+ "errors",
360
+ "setErrors",
361
+ "rules"
362
+ ]);
337
363
  var FormContextProvider = FormContext.Provider;
338
364
  var useFormContext = FormContext.use;
339
- function FormLabel(props) {
340
- const { Elements } = useFormContext();
341
- if (props.Label) return /* @__PURE__ */ jsx(props.Label, { ...props });
342
- return /* @__PURE__ */ jsx(Elements.Label, { ...props });
365
+ function FormItem(props) {
366
+ const { Elements, values, setValues, errors } = useFormContext();
367
+ const Label = props.label?.Label ?? Elements.Label;
368
+ const Input = props.input?.Input ?? Elements.Input;
369
+ return /* @__PURE__ */ jsx(Label, { name: props.name, ...props.label, error: errors[props.name], children: /* @__PURE__ */ jsx(
370
+ Input,
371
+ {
372
+ name: props.name,
373
+ value: values[props.name],
374
+ onChange: (v) => setValues((prev) => ({
375
+ ...prev,
376
+ [props.name]: v
377
+ }))
378
+ }
379
+ ) });
343
380
  }
381
+ FormItem.displayName = "FormItem";
382
+ FormItem.whyDidYouRender = true;
344
383
  function FormBody() {
345
384
  const { items } = useFormContext();
346
- return items.map((item) => /* @__PURE__ */ jsx(FormLabel, { ...item }, item.name));
385
+ return items.map((item) => /* @__PURE__ */ jsx(FormItem, { ...item }, item.name));
347
386
  }
348
- var FormInputElement = forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsx("input", { ...props, onChange: (e) => onChange(e.target.value), ref }));
349
- var FormLabelElement = ({
350
- name,
351
- title,
352
- description,
353
- Label,
354
- input
355
- }) => {
356
- const { values, setValues } = useFormContext();
357
- if (Label) return /* @__PURE__ */ jsx(Label, { name, title, description, input });
358
- return /* @__PURE__ */ jsxs("label", { children: [
359
- title ?? name,
360
- input?.Input ? /* @__PURE__ */ jsx(
361
- input.Input,
362
- {
363
- name,
364
- value: values[name],
365
- onChange: (v) => setValues((prev) => ({
366
- ...prev,
367
- [name]: v
368
- }))
369
- }
370
- ) : /* @__PURE__ */ jsx(
371
- FormInputElement,
372
- {
373
- name,
374
- value: values[name],
375
- onChange: (v) => setValues((prev) => ({
376
- ...prev,
377
- [name]: v
378
- }))
379
- }
380
- ),
381
- description
382
- ] });
387
+ FormBody.displayName = "FormBody";
388
+ FormBody.whyDidYouRender = true;
389
+
390
+ // src/Form/rules.ts
391
+ var FormDefaultRules = {
392
+ required: async (value, _, lang) => {
393
+ if (value === null || value === void 0 || value === "" || Number.isNaN(value)) {
394
+ throw Error(lang?.required);
395
+ }
396
+ },
397
+ type: async (value, options, lang) => {
398
+ switch (options) {
399
+ case "string":
400
+ if (typeof value !== "string") throw Error(lang?.string);
401
+ break;
402
+ case "number":
403
+ if (Number.isNaN(Number(value))) throw Error(lang?.number);
404
+ break;
405
+ }
406
+ },
407
+ custom: async (value, options) => {
408
+ return options(value);
409
+ }
383
410
  };
384
- var FormButtonElement = forwardRef(({ disabled, children, onClick, ...props }, ref) => /* @__PURE__ */ jsx(
411
+ async function validValues(rules, items, values, lang) {
412
+ const errors = {};
413
+ for (const item of items) {
414
+ const value = values[item.name];
415
+ const rulesOptions = item.rules;
416
+ if (rulesOptions) {
417
+ for (const [name, options] of Object.entries(rulesOptions)) {
418
+ try {
419
+ await rules[name](value, options, lang);
420
+ } catch (error) {
421
+ errors[item.name] = error;
422
+ break;
423
+ }
424
+ }
425
+ }
426
+ }
427
+ return errors;
428
+ }
429
+ function FormFooter() {
430
+ const {
431
+ submitting,
432
+ setSubmitting,
433
+ onSubmit,
434
+ values,
435
+ Elements,
436
+ items,
437
+ setErrors,
438
+ lang,
439
+ rules
440
+ } = useFormContext();
441
+ return /* @__PURE__ */ jsx(
442
+ Elements.Button,
443
+ {
444
+ disabled: submitting,
445
+ submit: async () => {
446
+ setSubmitting(true);
447
+ const errors = await validValues(rules, items, values, lang);
448
+ if (Object.keys(errors).length) {
449
+ setErrors(errors);
450
+ setSubmitting(false);
451
+ return;
452
+ }
453
+ onSubmit(values).finally(() => setSubmitting(false));
454
+ },
455
+ children: lang.submit
456
+ }
457
+ );
458
+ }
459
+ FormFooter.displayName = "FormFooter";
460
+ FormFooter.whyDidYouRender = true;
461
+ var FormButtonElement = forwardRef(({ disabled, children, submit, ...props }, ref) => /* @__PURE__ */ jsx(
385
462
  "button",
386
463
  {
387
464
  type: "button",
388
465
  disabled,
389
- onClick,
466
+ onClick: submit,
390
467
  ...props,
391
468
  ref,
392
469
  children
393
470
  }
394
471
  ));
472
+ FormButtonElement.displayName = "FormButtonElement";
473
+ FormButtonElement.whyDidYouRender = true;
474
+ var FormInputElement = forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsx("input", { ...props, onChange: (e) => onChange(e.target.value), ref }));
475
+ FormInputElement.displayName = "FormInputElement";
476
+ FormInputElement.whyDidYouRender = true;
477
+ var FormLabelElement = ({
478
+ name,
479
+ title,
480
+ description,
481
+ error,
482
+ children
483
+ }) => {
484
+ return /* @__PURE__ */ jsxs("label", { children: [
485
+ title ?? name,
486
+ children,
487
+ description,
488
+ error && /* @__PURE__ */ jsx("div", { style: { color: "red" }, children: error.message })
489
+ ] });
490
+ };
491
+ FormLabelElement.displayName = "FormLabelElement";
492
+ FormLabelElement.whyDidYouRender = true;
395
493
 
396
494
  // src/Form/elements/index.ts
397
495
  var FormDefaultElements = {
@@ -399,39 +497,43 @@ var FormDefaultElements = {
399
497
  Input: FormInputElement,
400
498
  Button: FormButtonElement
401
499
  };
402
- function FormFooter() {
403
- const { submitting, setSubmitting, onSubmit, values, Elements } = useFormContext();
404
- return /* @__PURE__ */ jsx(
405
- Elements.Button,
406
- {
407
- disabled: submitting,
408
- onClick: () => {
409
- setSubmitting(true);
410
- onSubmit(values).finally(() => setSubmitting(false));
411
- },
412
- children: "Submit"
413
- }
414
- );
415
- }
500
+
501
+ // src/Form/lang.ts
502
+ var FormDefaultLang = {
503
+ submit: "Submit",
504
+ required: "This field is required",
505
+ string: "This field must be a string",
506
+ number: "This field must be a number"
507
+ };
416
508
  function mergeValues(items, defaultValues = {}) {
417
509
  const values = {};
418
510
  for (const item of items)
419
511
  values[item.name] = defaultValues[item.name] ?? "";
420
512
  return values;
421
513
  }
422
- function FormContainer({ defaultValues, elements, ...props }) {
423
- const states = useSplittingState({
424
- values: mergeValues(props.items, defaultValues),
425
- submitting: false,
426
- Elements: Object.assign(FormDefaultElements, elements)
427
- });
514
+ function FormContainer({
515
+ defaultValues,
516
+ Elements,
517
+ rules,
518
+ lang,
519
+ ...props
520
+ }) {
428
521
  return /* @__PURE__ */ jsxs(
429
522
  FormContextProvider,
430
523
  {
431
- value: {
432
- ...states,
433
- ...props
524
+ initializeStates: {
525
+ values: mergeValues(props.items, defaultValues),
526
+ errors: {},
527
+ submitting: false,
528
+ Elements: Object.assign(
529
+ FormDefaultElements,
530
+ Elements
531
+ ),
532
+ lang: Object.assign(FormDefaultLang, lang),
533
+ rules: Object.assign(FormDefaultRules, rules)
434
534
  },
535
+ value: props,
536
+ memo: true,
435
537
  children: [
436
538
  /* @__PURE__ */ jsx(FormBody, {}),
437
539
  /* @__PURE__ */ jsx(FormFooter, {})
@@ -439,5 +541,7 @@ function FormContainer({ defaultValues, elements, ...props }) {
439
541
  }
440
542
  );
441
543
  }
544
+ FormContainer.displayName = "FormContainer";
545
+ FormContainer.whyDidYouRender = true;
442
546
 
443
- export { ErrorBoundary, FaasDataWrapper, FaasReactClient, FormContainer as Form, FormContextProvider, FormDefaultElements, OptionalWrapper, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, useFormContext, useSplittingState, withFaasData };
547
+ 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, validValues, withFaasData };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faasjs/react",
3
- "version": "3.7.0-beta.1",
3
+ "version": "3.7.0-beta.10",
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.1"
37
+ "@faasjs/browser": "3.7.0-beta.10"
38
38
  },
39
39
  "devDependencies": {
40
- "@faasjs/browser": "3.7.0-beta.1",
40
+ "@faasjs/browser": "3.7.0-beta.10",
41
41
  "@types/react": "*",
42
42
  "react": "*"
43
43
  },