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