piral-forms 1.9.2 → 1.10.0-beta.22286977124

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2019 - 2025 smapiot
3
+ Copyright (c) 2019 - 2026 smapiot
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -37,6 +37,17 @@ Returns a higher-order component for providing the form-related props such as `e
37
37
 
38
38
  ## Usage
39
39
 
40
+ When creating a new form the following options are relevant:
41
+
42
+ - `allowSubmitUnchanged` allows you to disable the default behavior of not submitting forms when the form's data is unchanged
43
+ - `silent` will prevent dialogs to show up when the user is to navigate away from the form containing changed data
44
+ - Setting `wait` to `false` will not immediately navigate away from forms upon submission
45
+ - The data loss message (in case of navigations when the form has changed data) can be set via `message`
46
+ - `loadData` is an optional function that can be set to define how the initial form data is loaded
47
+ - `emptyData` is the initial form data
48
+ - `onSubmit` is the callback to use when a form has been submitted
49
+ - `onChange` is the callback to use when the form data has changed
50
+
40
51
  ::: summary: For pilet authors
41
52
 
42
53
  You can use the `createForm` function from the Pilet API to create a global state container managed form inside the Piral instance.
@@ -58,11 +69,37 @@ export function setup(piral: PiletApi) {
58
69
  // return promise with data
59
70
  },
60
71
  });
61
- piral.registerPage('/sample-form', withSimpleForm(MyPage));
72
+ piral.registerPage('/sample-form', withSimpleForm(MyPage)); // changes <MyPage /> to <form><MyPage /></form>
62
73
  }
63
74
  ```
64
75
 
65
- Calling `createForm` returns a higher-order component that injects new props from the `FormProps<TFormData>` interface into the component. These props contain among others a `formData` record and a `submit` function.
76
+ Calling `createForm` returns a higher-order component that
77
+
78
+ 1. injects new props from the `FormProps<TFormData>` interface into the component and
79
+ 2. wraps the component into a `<form>` element.
80
+
81
+ The injected props contain - among the originally defined props - a `formData` record and a `submit` function.
82
+
83
+ If you wish to avoid the `<form>` element wrapping then provide an argument `skipForm` such as:
84
+
85
+ ```ts
86
+ import { PiletApi } from '<name-of-piral-instance>';
87
+ import { MyPage } from './MyPage';
88
+
89
+ export function setup(piral: PiletApi) {
90
+ const withSimpleForm = piral.createForm({
91
+ message: `Really lose the data?`,
92
+ emptyData: {
93
+ firstName: '',
94
+ lastName: '',
95
+ },
96
+ onSubmit(data) {
97
+ // return promise with data
98
+ },
99
+ });
100
+ piral.registerPage('/sample-form', withSimpleForm(MyPage, { skipForm: true })); // does not change <MyPage />
101
+ }
102
+ ```
66
103
 
67
104
  :::
68
105
 
@@ -88,6 +125,12 @@ const instance = createInstance({
88
125
 
89
126
  There are no options available.
90
127
 
128
+ Using the library directly also allows you to use the provided hooks direcly:
129
+
130
+ - `useForm` is used implicitly in the higher-order component to create the dynamic form handler data
131
+ - `withForm` creates an higher-order component for the provided component using the given options - this HOC still wraps the provided component in a `<form>`
132
+ - `withFormHandler` creates an higher-order component for the provided component using the given options - without wrapping the provided component in a `<form>`
133
+
91
134
  :::
92
135
 
93
136
  ## License
package/lib/actions.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { GlobalStateContext } from 'piral-core';
2
- import { FormDataState } from './types';
2
+ import type { FormDataState } from './types';
3
3
  export declare function updateFormState(ctx: GlobalStateContext, id: string, initial: FormDataState, patch: Partial<FormDataState>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"actions.js","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAsB,MAAM,YAAY,CAAC;AAG5E,SAAS,eAAe,CAAC,QAAuB,EAAE,KAA6B;IAC7E,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;QACnD,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,OAAO,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC;AACjG,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,GAAuB,EACvB,EAAU,EACV,OAAsB,EACtB,KAA6B;IAE7B,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE;QACrB,MAAM,QAAQ,GAAG;YACf,GAAG,OAAO;YACV,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;YAC1B,GAAG,KAAK;SACT,CAAC;QACF,MAAM,YAAY,GAAG,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACtD,OAAO;YACL,GAAG,KAAK;YACR,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,YAAY,CAAC;SAChD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAsB,MAAM,YAAY,CAAC;AAI5E,SAAS,eAAe,CAAC,QAAuB,EAAE,KAA6B;IAC7E,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;QACnD,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,OAAO,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC;AACjG,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,GAAuB,EACvB,EAAU,EACV,OAAsB,EACtB,KAA6B;IAE7B,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE;QACrB,MAAM,QAAQ,GAAG;YACf,GAAG,OAAO;YACV,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;YAC1B,GAAG,KAAK;SACT,CAAC;QACF,MAAM,YAAY,GAAG,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACtD,OAAO;YACL,GAAG,KAAK;YACR,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,YAAY,CAAC;SAChD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
package/lib/create.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PiralPlugin } from 'piral-core';
2
- import { PiletFormsApi } from './types';
2
+ import type { PiletFormsApi } from './types';
3
3
  /**
4
4
  * Available configuration options for the forms plugin.
5
5
  */
package/lib/create.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as actions from './actions';
2
2
  import { withForm } from './withForm';
3
+ import { withFormHandler } from './withFormHandler';
3
4
  /**
4
5
  * Creates new Pilet API extensions for enhancing forms.
5
6
  */
@@ -12,7 +13,10 @@ export function createFormsApi(config = {}) {
12
13
  }));
13
14
  return {
14
15
  createForm(options) {
15
- return (component) => withForm(component, options);
16
+ return (component, config) => {
17
+ const hoc = config?.skipForm ? withFormHandler : withForm;
18
+ return hoc(component, options);
19
+ };
16
20
  },
17
21
  };
18
22
  };
package/lib/create.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAQtC;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,SAAsB,EAAE;IACrD,OAAO,CAAC,OAAO,EAAE,EAAE;QACjB,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAE/B,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC3B,GAAG,KAAK;YACR,KAAK,EAAE,EAAE;SACV,CAAC,CAAC,CAAC;QAEJ,OAAO;YACL,UAAU,CAAC,OAAO;gBAChB,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YACrD,CAAC;SACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,WAAW,CAAC;AAGrC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAQpD;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,SAAsB,EAAE;IACrD,OAAO,CAAC,OAAO,EAAE,EAAE;QACjB,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAE/B,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC3B,GAAG,KAAK;YACR,KAAK,EAAE,EAAE;SACV,CAAC,CAAC,CAAC;QAEJ,OAAO;YACL,UAAU,CAAC,OAAO;gBAChB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE;oBAC3B,MAAM,GAAG,GAAG,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC;oBAC1D,OAAO,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBACjC,CAAC,CAAC;YACJ,CAAC;SACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
package/lib/index.d.ts CHANGED
@@ -2,4 +2,5 @@ export * from './create';
2
2
  export * from './types';
3
3
  export * from './useForm';
4
4
  export * from './usePrompt';
5
+ export * from './withFormHandler';
5
6
  export * from './withForm';
package/lib/index.js CHANGED
@@ -2,5 +2,6 @@ export * from './create';
2
2
  export * from './types';
3
3
  export * from './useForm';
4
4
  export * from './usePrompt';
5
+ export * from './withFormHandler';
5
6
  export * from './withForm';
6
7
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC"}
package/lib/types.d.ts CHANGED
@@ -118,13 +118,22 @@ export interface FormCreator<TFormData, TRequiredProps> {
118
118
  /**
119
119
  * Form function for wrapping a component.
120
120
  */
121
- <TProps extends TRequiredProps>(component: ComponentType<TProps & FormProps<TFormData>>): FC<TProps>;
121
+ <TProps extends TRequiredProps>(component: ComponentType<TProps & FormProps<TFormData>>, config?: {
122
+ /**
123
+ * Indicates if the wrapping `<form>` element should be omitted.
124
+ */
125
+ skipForm?: boolean;
126
+ }): FC<TProps>;
122
127
  }
123
128
  /**
124
129
  * Potential value types for defining a prompt message.
125
130
  */
126
131
  export type PromptMessage = string | (() => string);
127
132
  export interface InputFormOptions<TFormData, TProps> {
133
+ /**
134
+ * If enabled does not prevent submission of unchanged forms.
135
+ */
136
+ allowSubmitUnchanged?: boolean;
128
137
  /**
129
138
  * If enabled does not notify the user that form data could be lost on page transitions.
130
139
  */
package/lib/useForm.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { NavigationApi } from 'piral-core';
2
- import { FormProps, InputFormOptions } from './types';
2
+ import type { FormProps, InputFormOptions } from './types';
3
3
  /**
4
4
  * Hook for using a form locally that blocks if a transition is performed.
5
5
  * @param initialData The initial data of the form.
package/lib/useForm.js CHANGED
@@ -61,7 +61,7 @@ function createProps(id, state, updateState, options) {
61
61
  error: state.error,
62
62
  submit(e) {
63
63
  e && e.preventDefault();
64
- if (state.changed) {
64
+ if (options.allowSubmitUnchanged || state.changed) {
65
65
  submitData(id, state, updateState, options);
66
66
  }
67
67
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"useForm.js","sourceRoot":"","sources":["../src/useForm.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useForm.js","sourceRoot":"","sources":["../src/useForm.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { NavigationApi, NavigationListener } from 'piral-core';
2
- import { PromptMessage } from './types';
2
+ import type { PromptMessage } from './types';
3
3
  /**
4
4
  * Hook to notify the user in case of potential data loss when
5
5
  * performing a page transition (internal or external).
@@ -1 +1 @@
1
- {"version":3,"file":"usePrompt.js","sourceRoot":"","sources":["../src/usePrompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,MAAM,EAAwD,MAAM,YAAY,CAAC;AAG1F;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CACvB,MAAe,EACf,UAAyB,EACzB,OAAsB,EACtB,YAAiC;IAEjC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,YAAY,GAAG,CAAC,EAAqB,EAAE,EAAE;gBAC7C,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;gBAClD,EAAE,CAAC,WAAW,GAAG,GAAG,CAAC;gBACrB,OAAO,GAAG,CAAC;YACb,CAAC,CAAC;YACF,MAAM,QAAQ,GAAG,YAAY,IAAI,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YACjE,MAAM,OAAO,GAAG,OAAO,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;YACxE,MAAM,OAAO,GAAG,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACrD,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;YACtD,OAAO,GAAG,EAAE;gBACV,QAAQ,IAAI,QAAQ,EAAE,CAAC;gBACvB,OAAO,IAAI,OAAO,EAAE,CAAC;gBACrB,MAAM,CAAC,mBAAmB,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;YAC3D,CAAC,CAAC;QACJ,CAAC;QAED,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;IAClB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AACxB,CAAC"}
1
+ {"version":3,"file":"usePrompt.js","sourceRoot":"","sources":["../src/usePrompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,MAAM,EAAwD,MAAM,YAAY,CAAC;AAI1F;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CACvB,MAAe,EACf,UAAyB,EACzB,OAAsB,EACtB,YAAiC;IAEjC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,YAAY,GAAG,CAAC,EAAqB,EAAE,EAAE;gBAC7C,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;gBAClD,EAAE,CAAC,WAAW,GAAG,GAAG,CAAC;gBACrB,OAAO,GAAG,CAAC;YACb,CAAC,CAAC;YACF,MAAM,QAAQ,GAAG,YAAY,IAAI,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YACjE,MAAM,OAAO,GAAG,OAAO,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;YACxE,MAAM,OAAO,GAAG,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACrD,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;YACtD,OAAO,GAAG,EAAE;gBACV,QAAQ,IAAI,QAAQ,EAAE,CAAC;gBACvB,OAAO,IAAI,OAAO,EAAE,CAAC;gBACrB,MAAM,CAAC,mBAAmB,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;YAC3D,CAAC,CAAC;QACJ,CAAC;QAED,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;IAClB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AACxB,CAAC"}
package/lib/withForm.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import * as React from 'react';
2
- import { InputFormOptions, FormProps } from './types';
2
+ import type { InputFormOptions, FormProps } from './types';
3
3
  export declare function withForm<TFormData, TRequiredProps, TProps extends TRequiredProps>(Component: React.ComponentType<TProps & FormProps<TFormData>>, options: InputFormOptions<TFormData, TRequiredProps>): React.FC<TProps>;
package/lib/withForm.js CHANGED
@@ -1,28 +1,9 @@
1
1
  import * as React from 'react';
2
- import { RegisteredLoadingIndicator, RegisteredErrorInfo, useGlobalStateContext } from 'piral-core';
3
- import { useForm } from './useForm';
4
- import { usePromise } from './usePromise';
2
+ import { withFormHandler } from './withFormHandler';
5
3
  export function withForm(Component, options) {
6
- const FormView = (props) => {
7
- const { navigation } = useGlobalStateContext();
8
- const formProps = useForm(props.initialData, navigation, options);
9
- return (React.createElement("form", { onSubmit: formProps.submit },
10
- React.createElement(Component, { ...props, ...formProps })));
11
- };
12
- const FormLoader = (props) => {
13
- const { loadData, emptyData } = options;
14
- const { loading, data, error } = usePromise(() => typeof loadData !== 'function' ? Promise.resolve(emptyData) : loadData(props));
15
- if (loading) {
16
- return React.createElement(RegisteredLoadingIndicator, null);
17
- }
18
- else if (data) {
19
- return React.createElement(FormView, { ...props, initialData: data });
20
- }
21
- else {
22
- return React.createElement(RegisteredErrorInfo, { type: "form", error: error });
23
- }
24
- };
25
- FormLoader.displayName = `withForm(${Component.displayName ?? 'Component'})`;
26
- return FormLoader;
4
+ const WrappedComponent = withFormHandler((props) => (React.createElement("form", { onSubmit: props.submit },
5
+ React.createElement(Component, { ...props }))), options);
6
+ WrappedComponent.displayName = `withForm(${Component.displayName ?? 'Component'})`;
7
+ return WrappedComponent;
27
8
  }
28
9
  //# sourceMappingURL=withForm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"withForm.js","sourceRoot":"","sources":["../src/withForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACpG,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,MAAM,UAAU,QAAQ,CACtB,SAA6D,EAC7D,OAAoD;IAEpD,MAAM,QAAQ,GAAkD,CAAC,KAAK,EAAE,EAAE;QACxE,MAAM,EAAE,UAAU,EAAE,GAAG,qBAAqB,EAAE,CAAC;QAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QAClE,OAAO,CACL,8BAAM,QAAQ,EAAE,SAAS,CAAC,MAAM;YAC9B,oBAAC,SAAS,OAAK,KAAK,KAAM,SAAS,GAAI,CAClC,CACR,CAAC;IACJ,CAAC,CAAC;IACF,MAAM,UAAU,GAAqB,CAAC,KAAK,EAAE,EAAE;QAC7C,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;QACxC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAC/C,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAC9E,CAAC;QAEF,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,oBAAC,0BAA0B,OAAG,CAAC;QACxC,CAAC;aAAM,IAAI,IAAI,EAAE,CAAC;YAChB,OAAO,oBAAC,QAAQ,OAAK,KAAK,EAAE,WAAW,EAAE,IAAI,GAAI,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,OAAO,oBAAC,mBAAmB,IAAC,IAAI,EAAC,MAAM,EAAC,KAAK,EAAE,KAAK,GAAI,CAAC;QAC3D,CAAC;IACH,CAAC,CAAC;IACF,UAAU,CAAC,WAAW,GAAG,YAAY,SAAS,CAAC,WAAW,IAAI,WAAW,GAAG,CAAC;IAE7E,OAAO,UAAU,CAAC;AACpB,CAAC"}
1
+ {"version":3,"file":"withForm.js","sourceRoot":"","sources":["../src/withForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD,MAAM,UAAU,QAAQ,CACtB,SAA6D,EAC7D,OAAoD;IAEpD,MAAM,gBAAgB,GAAG,eAAe,CACtC,CAAC,KAAK,EAAE,EAAE,CAAC,CACT,8BAAM,QAAQ,EAAE,KAAK,CAAC,MAAM;QAC1B,oBAAC,SAAS,OAAK,KAAK,GAAI,CACnB,CACR,EACD,OAAO,CACR,CAAC;IACF,gBAAgB,CAAC,WAAW,GAAG,YAAY,SAAS,CAAC,WAAW,IAAI,WAAW,GAAG,CAAC;IACnF,OAAO,gBAAgB,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import * as React from 'react';
2
+ import type { InputFormOptions, FormProps } from './types';
3
+ export declare function withFormHandler<TFormData, TRequiredProps, TProps extends TRequiredProps>(Component: React.ComponentType<TProps & FormProps<TFormData>>, options: InputFormOptions<TFormData, TRequiredProps>): React.FC<TProps>;
@@ -0,0 +1,27 @@
1
+ import * as React from 'react';
2
+ import { RegisteredLoadingIndicator, RegisteredErrorInfo, useGlobalStateContext } from 'piral-core';
3
+ import { useForm } from './useForm';
4
+ import { usePromise } from './usePromise';
5
+ export function withFormHandler(Component, options) {
6
+ const FormView = (props) => {
7
+ const { navigation } = useGlobalStateContext();
8
+ const formProps = useForm(props.initialData, navigation, options);
9
+ return React.createElement(Component, { ...props, ...formProps });
10
+ };
11
+ const FormLoader = (props) => {
12
+ const { loadData, emptyData } = options;
13
+ const { loading, data, error } = usePromise(() => typeof loadData !== 'function' ? Promise.resolve(emptyData) : loadData(props));
14
+ if (loading) {
15
+ return React.createElement(RegisteredLoadingIndicator, null);
16
+ }
17
+ else if (data) {
18
+ return React.createElement(FormView, { ...props, initialData: data });
19
+ }
20
+ else {
21
+ return React.createElement(RegisteredErrorInfo, { type: "form", error: error });
22
+ }
23
+ };
24
+ FormLoader.displayName = `withFormHandler(${Component.displayName ?? 'Component'})`;
25
+ return FormLoader;
26
+ }
27
+ //# sourceMappingURL=withFormHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"withFormHandler.js","sourceRoot":"","sources":["../src/withFormHandler.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEpG,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,MAAM,UAAU,eAAe,CAC7B,SAA6D,EAC7D,OAAoD;IAEpD,MAAM,QAAQ,GAAkD,CAAC,KAAK,EAAE,EAAE;QACxE,MAAM,EAAE,UAAU,EAAE,GAAG,qBAAqB,EAAE,CAAC;QAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QAClE,OAAO,oBAAC,SAAS,OAAK,KAAK,KAAM,SAAS,GAAI,CAAC;IACjD,CAAC,CAAC;IACF,MAAM,UAAU,GAAqB,CAAC,KAAK,EAAE,EAAE;QAC7C,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;QACxC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAC/C,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAC9E,CAAC;QAEF,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,oBAAC,0BAA0B,OAAG,CAAC;QACxC,CAAC;aAAM,IAAI,IAAI,EAAE,CAAC;YAChB,OAAO,oBAAC,QAAQ,OAAK,KAAK,EAAE,WAAW,EAAE,IAAI,GAAI,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,OAAO,oBAAC,mBAAmB,IAAC,IAAI,EAAC,MAAM,EAAC,KAAK,EAAE,KAAK,GAAI,CAAC;QAC3D,CAAC;IACH,CAAC,CAAC;IACF,UAAU,CAAC,WAAW,GAAG,mBAAmB,SAAS,CAAC,WAAW,IAAI,WAAW,GAAG,CAAC;IAEpF,OAAO,UAAU,CAAC;AACpB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "piral-forms",
3
- "version": "1.9.2",
3
+ "version": "1.10.0-beta.22286977124",
4
4
  "description": "Plugin for providing advanced form support in Piral.",
5
5
  "keywords": [
6
6
  "piral",
@@ -52,8 +52,8 @@
52
52
  "@types/history": "^4.7.8",
53
53
  "@types/react": "^18.0.0",
54
54
  "@types/react-router-dom": "^5.1.6",
55
- "piral-core": "^1.9.2",
55
+ "piral-core": "1.10.0-beta.22286977124",
56
56
  "react": "^18.0.0"
57
57
  },
58
- "gitHead": "3adb702cbb788889a05a30d2a7ee657ad713a468"
58
+ "gitHead": "5680202f7c708e9f728e8eb7bc8da368d668eba9"
59
59
  }
@@ -1 +1 @@
1
- var piralForms=(()=>{var A=Object.create;var F=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var E=Object.getPrototypeOf,U=Object.prototype.hasOwnProperty;var f=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(r,o)=>(typeof require<"u"?require:r)[o]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var v=(t,r)=>{for(var o in r)F(t,o,{get:r[o],enumerable:!0})},S=(t,r,o,a)=>{if(r&&typeof r=="object"||typeof r=="function")for(let e of N(r))!U.call(t,e)&&e!==o&&F(t,e,{get:()=>r[e],enumerable:!(a=C(r,e))||a.enumerable});return t};var O=(t,r,o)=>(o=t!=null?A(E(t)):{},S(r||!t||!t.__esModule?F(o,"default",{value:t,enumerable:!0}):o,t)),L=t=>S(F({},"__esModule",{value:!0}),t);var K={};v(K,{createFormsApi:()=>V,useForm:()=>b,usePrompt:()=>T,withForm:()=>h});var P={};v(P,{updateFormState:()=>k});var d=f("piral-core");function w(t,r){return r.active===!1&&!t.submitting?d.removeIndicator:t.active||t.submitting||t.changed?t:d.removeIndicator}function k(t,r,o,a){t.dispatch(e=>{let i={...o,...e.forms[r]||{},...a},n=w(i,a);return{...e,forms:(0,d.updateKey)(e.forms,r,n)}})}var p=O(f("react")),l=f("piral-core");var D=f("react"),u=f("piral-core");var x=f("react"),y=f("piral-core");function T(t,r,o,a){(0,x.useEffect)(()=>{if(t){let e=s=>{let c=(0,y.isfunc)(o)?o():o;return s.returnValue=c,c},i=a&&r.listen(a),n=typeof o=="function"?o:()=>o,m=o&&r.block(n);return window.addEventListener("beforeunload",e),()=>{i&&i(),m&&m(),window.removeEventListener("beforeunload",e)}}return()=>{}},[t,o])}var G="Are you sure you want to discard the form data?";function q(t){return{active:!0,currentData:t,initialData:t,changed:!1,submitting:!1,error:void 0}}function R(t,r,o,a,e){let{onChange:i}=e;o(t,r,{currentData:a,changed:!(0,u.isSame)(a,r.initialData),error:void 0}),(0,u.isfunc)(i)&&Promise.resolve(i(a)).then(n=>{let m={...a,...n};o(t,r,{currentData:m,changed:!(0,u.isSame)(m,r.initialData),error:void 0})}).catch(n=>o(t,r,{error:n}))}function M(t,r,o,a){let{onSubmit:e,wait:i}=a;o(t,r,{changed:!!i,submitting:!0}),(0,u.isfunc)(e)&&Promise.resolve(e(r.currentData)).then(()=>o(t,r,{initialData:r.currentData,changed:!1,submitting:!1})).catch(n=>o(t,r,{error:n,changed:!0,submitting:!1}))}function B(t,r,o,a){return{changed:r.changed,formData:r.currentData,error:r.error,submit(e){return e&&e.preventDefault(),r.changed&&M(t,r,o,a),!1},submitting:r.submitting,reset(){o(t,r,{currentData:r.initialData,changed:!1,error:void 0})},setFormData(e){R(t,r,o,{...r.currentData,...e},a)},changeForm(e){let{name:i,value:n}=e.target;R(t,r,o,{...r.currentData,[i]:n},a)}}}function b(t,r,o,a){let{silent:e,message:i=G}=o,[n]=(0,D.useState)(a||u.generateId),m=(0,u.useGlobalState)(c=>c.forms[n]||q(t)),s=(0,u.useAction)("updateFormState");return T(!e&&m.changed,r,i),(0,D.useEffect)(()=>(s(n,m,{active:!0}),()=>s(n,m,{active:!1})),[m.submitting]),B(n,m,s,o)}var g=f("react");function I(t){let[r,o]=(0,g.useState)({loading:!0,data:void 0,error:void 0});return(0,g.useEffect)(()=>{let a=!1;return t().then(e=>!a&&o({data:e,error:void 0,loading:!1}),e=>!a&&o({data:void 0,error:e,loading:!1})),()=>{a=!0}},[]),r}function h(t,r){let o=e=>{let{navigation:i}=(0,l.useGlobalStateContext)(),n=b(e.initialData,i,r);return p.createElement("form",{onSubmit:n.submit},p.createElement(t,{...e,...n}))},a=e=>{let{loadData:i,emptyData:n}=r,{loading:m,data:s,error:c}=I(()=>typeof i!="function"?Promise.resolve(n):i(e));return m?p.createElement(l.RegisteredLoadingIndicator,null):s?p.createElement(o,{...e,initialData:s}):p.createElement(l.RegisteredErrorInfo,{type:"form",error:c})};return a.displayName=`withForm(${t.displayName??"Component"})`,a}function V(t={}){return r=>(r.defineActions(P),r.dispatch(o=>({...o,forms:{}})),{createForm(o){return a=>h(a,o)}})}return L(K);})();
1
+ var piralForms=(()=>{var A=Object.create;var D=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var U=Object.getPrototypeOf,q=Object.prototype.hasOwnProperty;var u=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(r,o)=>(typeof require<"u"?require:r)[o]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var S=(t,r)=>{for(var o in r)D(t,o,{get:r[o],enumerable:!0})},R=(t,r,o,a)=>{if(r&&typeof r=="object"||typeof r=="function")for(let e of O(r))!q.call(t,e)&&e!==o&&D(t,e,{get:()=>r[e],enumerable:!(a=E(r,e))||a.enumerable});return t};var x=(t,r,o)=>(o=t!=null?A(U(t)):{},R(r||!t||!t.__esModule?D(o,"default",{value:t,enumerable:!0}):o,t)),L=t=>R(D({},"__esModule",{value:!0}),t);var K={};S(K,{createFormsApi:()=>$,useForm:()=>y,usePrompt:()=>h,withForm:()=>v,withFormHandler:()=>F});var T={};S(T,{updateFormState:()=>G});var l=u("piral-core");function k(t,r){return r.active===!1&&!t.submitting?l.removeIndicator:t.active||t.submitting||t.changed?t:l.removeIndicator}function G(t,r,o,a){t.dispatch(e=>{let i={...o,...e.forms[r]||{},...a},n=k(i,a);return{...e,forms:(0,l.updateKey)(e.forms,r,n)}})}var b=x(u("react"));var d=x(u("react")),f=u("piral-core");var g=u("react"),s=u("piral-core");var C=u("react"),I=u("piral-core");function h(t,r,o,a){(0,C.useEffect)(()=>{if(t){let e=p=>{let c=(0,I.isfunc)(o)?o():o;return p.returnValue=c,c},i=a&&r.listen(a),n=typeof o=="function"?o:()=>o,m=o&&r.block(n);return window.addEventListener("beforeunload",e),()=>{i&&i(),m&&m(),window.removeEventListener("beforeunload",e)}}return()=>{}},[t,o])}var H="Are you sure you want to discard the form data?";function M(t){return{active:!0,currentData:t,initialData:t,changed:!1,submitting:!1,error:void 0}}function N(t,r,o,a,e){let{onChange:i}=e;o(t,r,{currentData:a,changed:!(0,s.isSame)(a,r.initialData),error:void 0}),(0,s.isfunc)(i)&&Promise.resolve(i(a)).then(n=>{let m={...a,...n};o(t,r,{currentData:m,changed:!(0,s.isSame)(m,r.initialData),error:void 0})}).catch(n=>o(t,r,{error:n}))}function B(t,r,o,a){let{onSubmit:e,wait:i}=a;o(t,r,{changed:!!i,submitting:!0}),(0,s.isfunc)(e)&&Promise.resolve(e(r.currentData)).then(()=>o(t,r,{initialData:r.currentData,changed:!1,submitting:!1})).catch(n=>o(t,r,{error:n,changed:!0,submitting:!1}))}function V(t,r,o,a){return{changed:r.changed,formData:r.currentData,error:r.error,submit(e){return e&&e.preventDefault(),(a.allowSubmitUnchanged||r.changed)&&B(t,r,o,a),!1},submitting:r.submitting,reset(){o(t,r,{currentData:r.initialData,changed:!1,error:void 0})},setFormData(e){N(t,r,o,{...r.currentData,...e},a)},changeForm(e){let{name:i,value:n}=e.target;N(t,r,o,{...r.currentData,[i]:n},a)}}}function y(t,r,o,a){let{silent:e,message:i=H}=o,[n]=(0,g.useState)(a||s.generateId),m=(0,s.useGlobalState)(c=>c.forms[n]||M(t)),p=(0,s.useAction)("updateFormState");return h(!e&&m.changed,r,i),(0,g.useEffect)(()=>(p(n,m,{active:!0}),()=>p(n,m,{active:!1})),[m.submitting]),V(n,m,p,o)}var P=u("react");function w(t){let[r,o]=(0,P.useState)({loading:!0,data:void 0,error:void 0});return(0,P.useEffect)(()=>{let a=!1;return t().then(e=>!a&&o({data:e,error:void 0,loading:!1}),e=>!a&&o({data:void 0,error:e,loading:!1})),()=>{a=!0}},[]),r}function F(t,r){let o=e=>{let{navigation:i}=(0,f.useGlobalStateContext)(),n=y(e.initialData,i,r);return d.createElement(t,{...e,...n})},a=e=>{let{loadData:i,emptyData:n}=r,{loading:m,data:p,error:c}=w(()=>typeof i!="function"?Promise.resolve(n):i(e));return m?d.createElement(f.RegisteredLoadingIndicator,null):p?d.createElement(o,{...e,initialData:p}):d.createElement(f.RegisteredErrorInfo,{type:"form",error:c})};return a.displayName=`withFormHandler(${t.displayName??"Component"})`,a}function v(t,r){let o=F(a=>b.createElement("form",{onSubmit:a.submit},b.createElement(t,{...a})),r);return o.displayName=`withForm(${t.displayName??"Component"})`,o}function $(t={}){return r=>(r.defineActions(T),r.dispatch(o=>({...o,forms:{}})),{createForm(o){return(a,e)=>(e?.skipForm?F:v)(a,o)}})}return L(K);})();
package/src/actions.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { updateKey, removeIndicator, GlobalStateContext } from 'piral-core';
2
- import { FormDataState } from './types';
2
+
3
+ import type { FormDataState } from './types';
3
4
 
4
5
  function getNewFormState(newState: FormDataState, patch: Partial<FormDataState>) {
5
6
  if (patch.active === false && !newState.submitting) {
@@ -40,4 +40,18 @@ describe('Create Forms API Extensions', () => {
40
40
  const NewComponent = create(StubComponent);
41
41
  expect(NewComponent.displayName).toBe('withForm(StubComponent)');
42
42
  });
43
+
44
+ it('createCoreApi can also avoid wrapping in a form', () => {
45
+ const container = createMockContainer();
46
+ container.context.updateFormState = vitest.fn();
47
+ const api = createFormsApi()(container.context) as any;
48
+ const create = api.createForm({
49
+ emptyData: {},
50
+ onSubmit() {
51
+ return Promise.resolve();
52
+ },
53
+ });
54
+ const NewComponent = create(StubComponent, { skipForm: true });
55
+ expect(NewComponent.displayName).toBe('withFormHandler(StubComponent)');
56
+ });
43
57
  });
package/src/create.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import * as actions from './actions';
2
2
  import { PiralPlugin } from 'piral-core';
3
+
3
4
  import { withForm } from './withForm';
4
- import { PiletFormsApi } from './types';
5
+ import { withFormHandler } from './withFormHandler';
6
+ import type { PiletFormsApi } from './types';
5
7
 
6
8
  /**
7
9
  * Available configuration options for the forms plugin.
@@ -22,7 +24,10 @@ export function createFormsApi(config: FormsConfig = {}): PiralPlugin<PiletForms
22
24
 
23
25
  return {
24
26
  createForm(options) {
25
- return (component) => withForm(component, options);
27
+ return (component, config) => {
28
+ const hoc = config?.skipForm ? withFormHandler : withForm;
29
+ return hoc(component, options);
30
+ };
26
31
  },
27
32
  };
28
33
  };
package/src/index.ts CHANGED
@@ -2,4 +2,5 @@ export * from './create';
2
2
  export * from './types';
3
3
  export * from './useForm';
4
4
  export * from './usePrompt';
5
+ export * from './withFormHandler';
5
6
  export * from './withForm';
package/src/types.ts CHANGED
@@ -127,7 +127,15 @@ export interface FormCreator<TFormData, TRequiredProps> {
127
127
  /**
128
128
  * Form function for wrapping a component.
129
129
  */
130
- <TProps extends TRequiredProps>(component: ComponentType<TProps & FormProps<TFormData>>): FC<TProps>;
130
+ <TProps extends TRequiredProps>(
131
+ component: ComponentType<TProps & FormProps<TFormData>>,
132
+ config?: {
133
+ /**
134
+ * Indicates if the wrapping `<form>` element should be omitted.
135
+ */
136
+ skipForm?: boolean;
137
+ },
138
+ ): FC<TProps>;
131
139
  }
132
140
 
133
141
  /**
@@ -136,6 +144,10 @@ export interface FormCreator<TFormData, TRequiredProps> {
136
144
  export type PromptMessage = string | (() => string);
137
145
 
138
146
  export interface InputFormOptions<TFormData, TProps> {
147
+ /**
148
+ * If enabled does not prevent submission of unchanged forms.
149
+ */
150
+ allowSubmitUnchanged?: boolean;
139
151
  /**
140
152
  * If enabled does not notify the user that form data could be lost on page transitions.
141
153
  */
@@ -127,6 +127,37 @@ describe('Form Hook Module', () => {
127
127
  testOptions,
128
128
  );
129
129
 
130
+ it(
131
+ 'Submit with no changed data does something with allowSubmitUnchanged is on',
132
+ async () => {
133
+ const { useForm } = await import('./useForm');
134
+ const onSubmit = vitest.fn(() => Promise.resolve());
135
+
136
+ useGlobalState.mockImplementation((select: any) =>
137
+ select({
138
+ forms: {},
139
+ }),
140
+ );
141
+ const options = {
142
+ allowSubmitUnchanged: true,
143
+ wait: false,
144
+ silent: false,
145
+ message: '',
146
+ onSubmit,
147
+ onChange: undefined,
148
+ emptyData: {},
149
+ };
150
+ const { changed, submitting, formData, submit } = useForm({}, undefined as any, options);
151
+ submit();
152
+ expect(changed).toBeFalsy();
153
+ expect(submitting).toBeFalsy();
154
+ expect(onSubmit).toHaveBeenCalled();
155
+ expect(formData).toEqual({});
156
+ expect(setStateFake.mock.calls[0][0].length).toBe(36);
157
+ },
158
+ testOptions,
159
+ );
160
+
130
161
  it(
131
162
  'Submit with changed data submits successfully',
132
163
  async () => {
package/src/useForm.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { useState, useEffect, FormEvent } from 'react';
2
2
  import { isfunc, useAction, useGlobalState, isSame, generateId, NavigationApi } from 'piral-core';
3
+
3
4
  import { usePrompt } from './usePrompt';
4
- import { FormProps, InputFormOptions, FormDataState } from './types';
5
+ import type { FormProps, InputFormOptions, FormDataState } from './types';
5
6
 
6
7
  const defaultMessage = 'Are you sure you want to discard the form data?';
7
8
 
@@ -96,7 +97,7 @@ function createProps<TFormData>(
96
97
  submit(e?: FormEvent) {
97
98
  e && e.preventDefault();
98
99
 
99
- if (state.changed) {
100
+ if (options.allowSubmitUnchanged || state.changed) {
100
101
  submitData(id, state, updateState, options);
101
102
  }
102
103
 
package/src/usePrompt.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { useEffect } from 'react';
2
2
  import { isfunc, NavigationApi, NavigationListener, NavigationBlocker } from 'piral-core';
3
- import { PromptMessage } from './types';
3
+
4
+ import type { PromptMessage } from './types';
4
5
 
5
6
  /**
6
7
  * Hook to notify the user in case of potential data loss when
package/src/withForm.tsx CHANGED
@@ -1,37 +1,20 @@
1
1
  import * as React from 'react';
2
- import { RegisteredLoadingIndicator, RegisteredErrorInfo, useGlobalStateContext } from 'piral-core';
3
- import { useForm } from './useForm';
4
- import { usePromise } from './usePromise';
5
- import { InputFormOptions, FormProps } from './types';
2
+
3
+ import { withFormHandler } from './withFormHandler';
4
+ import type { InputFormOptions, FormProps } from './types';
6
5
 
7
6
  export function withForm<TFormData, TRequiredProps, TProps extends TRequiredProps>(
8
7
  Component: React.ComponentType<TProps & FormProps<TFormData>>,
9
8
  options: InputFormOptions<TFormData, TRequiredProps>,
10
9
  ): React.FC<TProps> {
11
- const FormView: React.FC<TProps & { initialData: TFormData }> = (props) => {
12
- const { navigation } = useGlobalStateContext();
13
- const formProps = useForm(props.initialData, navigation, options);
14
- return (
15
- <form onSubmit={formProps.submit}>
16
- <Component {...props} {...formProps} />
10
+ const WrappedComponent = withFormHandler<TFormData, TRequiredProps, TProps>(
11
+ (props) => (
12
+ <form onSubmit={props.submit}>
13
+ <Component {...props} />
17
14
  </form>
18
- );
19
- };
20
- const FormLoader: React.FC<TProps> = (props) => {
21
- const { loadData, emptyData } = options;
22
- const { loading, data, error } = usePromise(() =>
23
- typeof loadData !== 'function' ? Promise.resolve(emptyData) : loadData(props),
24
- );
25
-
26
- if (loading) {
27
- return <RegisteredLoadingIndicator />;
28
- } else if (data) {
29
- return <FormView {...props} initialData={data} />;
30
- } else {
31
- return <RegisteredErrorInfo type="form" error={error} />;
32
- }
33
- };
34
- FormLoader.displayName = `withForm(${Component.displayName ?? 'Component'})`;
35
-
36
- return FormLoader;
15
+ ),
16
+ options,
17
+ );
18
+ WrappedComponent.displayName = `withForm(${Component.displayName ?? 'Component'})`;
19
+ return WrappedComponent;
37
20
  }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * @vitest-environment jsdom
3
+ */
4
+ import * as React from 'react';
5
+ import * as piralCore from 'piral-core';
6
+ import * as useForm from './useForm';
7
+ import * as usePromise from './usePromise';
8
+ import { describe, it, expect, vitest } from 'vitest';
9
+ import { render } from '@testing-library/react';
10
+ import { withFormHandler } from './withFormHandler';
11
+
12
+ vitest.mock('piral-core');
13
+ vitest.mock('./useForm');
14
+ vitest.mock('./usePromise');
15
+
16
+ const StubComponent: React.FC<{ data: any }> = () => <div role="component" />;
17
+ StubComponent.displayName = 'StubComponent';
18
+
19
+ const LoaderComponent: React.FC<{ data: any }> = () => <div role="loader" />;
20
+ LoaderComponent.displayName = 'LoaderComponent';
21
+
22
+ const ErrorComponent: React.FC<{ data: any }> = () => <div role="error" />;
23
+ ErrorComponent.displayName = 'ErrorComponent';
24
+
25
+ (piralCore as any).RegisteredErrorInfo = ErrorComponent;
26
+ (piralCore as any).RegisteredLoadingIndicator = LoaderComponent;
27
+ (piralCore as any).useGlobalStateContext = vitest.fn(() => ({
28
+ navigation: {},
29
+ }));
30
+
31
+ describe('withForm Module', () => {
32
+ it('shows error component if nothing is loading and no data is available', () => {
33
+ const options: any = { emptyData: {} };
34
+ const usedForm = vitest.fn(() => ({
35
+ submit() {},
36
+ }));
37
+ const usedPromise = vitest.fn(() => ({
38
+ loading: false,
39
+ data: undefined,
40
+ error: undefined,
41
+ }));
42
+ (useForm as any).useForm = usedForm;
43
+ (usePromise as any).usePromise = usedPromise;
44
+ const Component: any = withFormHandler(StubComponent, options);
45
+ const node = render(<Component />);
46
+ expect(node.getAllByRole('error').length).toBe(1);
47
+ });
48
+
49
+ it('shows data component if nothing is loading and data is available', () => {
50
+ const options: any = { emptyData: {} };
51
+ const usedForm = vitest.fn(() => ({
52
+ submit() {},
53
+ }));
54
+ const usedPromise = vitest.fn(() => ({
55
+ loading: false,
56
+ data: {},
57
+ error: undefined,
58
+ }));
59
+ (useForm as any).useForm = usedForm;
60
+ (usePromise as any).usePromise = usedPromise;
61
+ const Component: any = withFormHandler(StubComponent, options);
62
+ const node = render(<Component />);
63
+ expect(node.getAllByRole('component').length).toBe(1);
64
+ });
65
+
66
+ it('shows loading component if it is loading', () => {
67
+ const options: any = { emptyData: {} };
68
+ const usedForm = vitest.fn(() => ({
69
+ submit() {},
70
+ }));
71
+ const usedPromise = vitest.fn(() => ({
72
+ loading: true,
73
+ data: undefined,
74
+ error: undefined,
75
+ }));
76
+ (useForm as any).useForm = usedForm;
77
+ (usePromise as any).usePromise = usedPromise;
78
+ const Component: any = withFormHandler(StubComponent, options);
79
+ const node = render(<Component />);
80
+ expect(node.getAllByRole('loader').length).toBe(1);
81
+ });
82
+
83
+ it('calls load data if its there', () => {
84
+ const loadData = vitest.fn(() => () => Promise.resolve({}));
85
+ const usedForm = vitest.fn(() => ({
86
+ submit() {},
87
+ }));
88
+ const usedPromise = vitest.fn((fn) => {
89
+ fn();
90
+ return {
91
+ loading: false,
92
+ data: undefined,
93
+ error: undefined,
94
+ };
95
+ });
96
+ (useForm as any).useForm = usedForm;
97
+ (usePromise as any).usePromise = usedPromise;
98
+ const options: any = { emptyData: {}, loadData };
99
+ const Component: any = withFormHandler(StubComponent, options);
100
+ render(<Component />);
101
+ expect(usedPromise).toHaveBeenCalledTimes(1);
102
+ expect(loadData).toHaveBeenCalledTimes(1);
103
+ });
104
+
105
+ it('does not call load data if its missing', () => {
106
+ const loadData = undefined;
107
+ const usedForm = vitest.fn(() => ({
108
+ submit() {},
109
+ }));
110
+ const usedPromise = vitest.fn((fn) => {
111
+ const data = fn();
112
+ return {
113
+ loading: false,
114
+ data,
115
+ error: undefined,
116
+ };
117
+ });
118
+ (useForm as any).useForm = usedForm;
119
+ (usePromise as any).usePromise = usedPromise;
120
+ const options: any = { emptyData: {}, loadData };
121
+ const Component: any = withFormHandler(StubComponent, options);
122
+ render(<Component />);
123
+ expect(usedPromise).toHaveBeenCalledTimes(1);
124
+ });
125
+ });
@@ -0,0 +1,34 @@
1
+ import * as React from 'react';
2
+ import { RegisteredLoadingIndicator, RegisteredErrorInfo, useGlobalStateContext } from 'piral-core';
3
+
4
+ import { useForm } from './useForm';
5
+ import { usePromise } from './usePromise';
6
+ import type { InputFormOptions, FormProps } from './types';
7
+
8
+ export function withFormHandler<TFormData, TRequiredProps, TProps extends TRequiredProps>(
9
+ Component: React.ComponentType<TProps & FormProps<TFormData>>,
10
+ options: InputFormOptions<TFormData, TRequiredProps>,
11
+ ): React.FC<TProps> {
12
+ const FormView: React.FC<TProps & { initialData: TFormData }> = (props) => {
13
+ const { navigation } = useGlobalStateContext();
14
+ const formProps = useForm(props.initialData, navigation, options);
15
+ return <Component {...props} {...formProps} />;
16
+ };
17
+ const FormLoader: React.FC<TProps> = (props) => {
18
+ const { loadData, emptyData } = options;
19
+ const { loading, data, error } = usePromise(() =>
20
+ typeof loadData !== 'function' ? Promise.resolve(emptyData) : loadData(props),
21
+ );
22
+
23
+ if (loading) {
24
+ return <RegisteredLoadingIndicator />;
25
+ } else if (data) {
26
+ return <FormView {...props} initialData={data} />;
27
+ } else {
28
+ return <RegisteredErrorInfo type="form" error={error} />;
29
+ }
30
+ };
31
+ FormLoader.displayName = `withFormHandler(${Component.displayName ?? 'Component'})`;
32
+
33
+ return FormLoader;
34
+ }