@faasjs/react 3.7.0-beta.0 → 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,5 +1,5 @@
1
- import { forwardRef, useRef, useMemo, useEffect, useCallback, createContext, useState, cloneElement, Component, useContext } from 'react';
2
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
1
+ import { forwardRef, useRef, useMemo, useEffect, useCallback, useState, createContext, cloneElement, Component, useContext } from 'react';
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import { FaasBrowserClient } from '@faasjs/browser';
4
4
 
5
5
  // src/constant.ts
@@ -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,146 +340,200 @@ 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?.Label) return /* @__PURE__ */ jsx(props.label.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
- function processValue(input, rules) {
349
- let value = input;
350
- if (typeof input === "object" && "target" in input) {
351
- value = input.target.value;
352
- }
353
- switch (rules?.type) {
354
- case "number":
355
- return Number(value);
356
- case "string":
357
- return String(value);
358
- default:
359
- return value;
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);
360
409
  }
361
- }
362
- function FormInput({
363
- name,
364
- rules,
365
- ...rest
366
- }) {
367
- const { elements, values, setValues } = useFormContext();
368
- const value = values?.[name];
369
- if ("Input" in rest && rest.Input) {
370
- return /* @__PURE__ */ jsx(
371
- rest.Input,
372
- {
373
- name,
374
- value,
375
- onChange: (v) => setValues((prev) => ({
376
- ...prev,
377
- [name]: v
378
- }))
410
+ };
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
+ }
379
424
  }
380
- );
381
- }
382
- if ("type" in rest || "props" in rest) {
383
- switch (rest.type) {
384
- case "select":
385
- return /* @__PURE__ */ jsx(
386
- elements.select,
387
- {
388
- name,
389
- value,
390
- onChange: (v) => setValues((prev) => ({
391
- ...prev,
392
- [name]: processValue(v, rules)
393
- })),
394
- ...rest.props
395
- }
396
- );
397
- default:
398
- return /* @__PURE__ */ jsx(
399
- elements.input,
400
- {
401
- name,
402
- value,
403
- onChange: (v) => setValues((prev) => ({
404
- ...prev,
405
- [name]: processValue(v, rules)
406
- })),
407
- ...rest.props
408
- }
409
- );
410
425
  }
411
426
  }
412
- return /* @__PURE__ */ jsx(
413
- elements.input,
414
- {
415
- name,
416
- value,
417
- onChange: (v) => setValues((prev) => ({
418
- ...prev,
419
- [name]: processValue(v, rules)
420
- }))
421
- }
422
- );
427
+ return errors;
423
428
  }
424
- var FormElements = {
425
- label: forwardRef(({ name, label, input, rules }, ref) => /* @__PURE__ */ jsxs("label", { ref, children: [
426
- label?.title ?? name,
427
- /* @__PURE__ */ jsx(FormInput, { name, rules, ...input }),
428
- label?.description
429
- ] })),
430
- input: forwardRef(
431
- (props, ref) => /* @__PURE__ */ jsx("input", { ...props, ref })
432
- ),
433
- select: forwardRef(({ options, ...props }, ref) => /* @__PURE__ */ jsx("select", { ...props, ref, children: options?.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value)) })),
434
- button: forwardRef(({ disabled, children, onClick, ...props }, ref) => /* @__PURE__ */ jsx("button", { type: "button", disabled, onClick, ...props, ref, children }))
435
- };
436
429
  function FormFooter() {
437
- const { submitting, setSubmitting, onSubmit, values, elements } = useFormContext();
430
+ const {
431
+ submitting,
432
+ setSubmitting,
433
+ onSubmit,
434
+ values,
435
+ Elements,
436
+ items,
437
+ setErrors,
438
+ lang,
439
+ rules
440
+ } = useFormContext();
438
441
  return /* @__PURE__ */ jsx(
439
- elements.button,
442
+ Elements.Button,
440
443
  {
441
444
  disabled: submitting,
442
- onClick: () => {
445
+ submit: async () => {
443
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
+ }
444
453
  onSubmit(values).finally(() => setSubmitting(false));
445
454
  },
446
- children: "Submit"
455
+ children: lang.submit
447
456
  }
448
457
  );
449
458
  }
459
+ FormFooter.displayName = "FormFooter";
460
+ FormFooter.whyDidYouRender = true;
461
+ var FormButtonElement = forwardRef(({ disabled, children, submit, ...props }, ref) => /* @__PURE__ */ jsx(
462
+ "button",
463
+ {
464
+ type: "button",
465
+ disabled,
466
+ onClick: submit,
467
+ ...props,
468
+ ref,
469
+ children
470
+ }
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;
493
+
494
+ // src/Form/elements/index.ts
495
+ var FormDefaultElements = {
496
+ Label: FormLabelElement,
497
+ Input: FormInputElement,
498
+ Button: FormButtonElement
499
+ };
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
+ };
450
508
  function mergeValues(items, defaultValues = {}) {
451
509
  const values = {};
452
510
  for (const item of items)
453
511
  values[item.name] = defaultValues[item.name] ?? "";
454
512
  return values;
455
513
  }
456
- function FormContainer({ defaultValues, elements, ...props }) {
457
- const states = useSplittingState({
458
- values: mergeValues(props.items, defaultValues),
459
- submitting: false,
460
- elements: Object.assign(FormElements, elements)
461
- });
514
+ function FormContainer({
515
+ defaultValues,
516
+ Elements,
517
+ rules,
518
+ lang,
519
+ ...props
520
+ }) {
462
521
  return /* @__PURE__ */ jsxs(
463
522
  FormContextProvider,
464
523
  {
465
- value: {
466
- ...states,
467
- ...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)
468
534
  },
535
+ value: props,
536
+ memo: true,
469
537
  children: [
470
538
  /* @__PURE__ */ jsx(FormBody, {}),
471
539
  /* @__PURE__ */ jsx(FormFooter, {})
@@ -473,5 +541,7 @@ function FormContainer({ defaultValues, elements, ...props }) {
473
541
  }
474
542
  );
475
543
  }
544
+ FormContainer.displayName = "FormContainer";
545
+ FormContainer.whyDidYouRender = true;
476
546
 
477
- export { ErrorBoundary, FaasDataWrapper, FaasReactClient, FormContainer as Form, OptionalWrapper, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, 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.0",
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.0"
37
+ "@faasjs/browser": "3.7.0-beta.10"
38
38
  },
39
39
  "devDependencies": {
40
- "@faasjs/browser": "3.7.0-beta.0",
40
+ "@faasjs/browser": "3.7.0-beta.10",
41
41
  "@types/react": "*",
42
42
  "react": "*"
43
43
  },