Skip to content

Commit 29593e9

Browse files
authored
Merge pull request #1045 from rvsia/addExampleForCustomWizard
Add example for custom wizard
2 parents 2964628 + 589cea3 commit 29593e9

File tree

3 files changed

+189
-0
lines changed

3 files changed

+189
-0
lines changed

packages/react-renderer-demo/src/components/navigation/schemas/custom-examples.schema.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ const customExamplesSchema = [
1414
{
1515
component: 'resolve-props-db',
1616
linkText: 'ResolveProps stored in DB'
17+
},
18+
{
19+
component: 'custom-wizard',
20+
linkText: 'Custom wizard'
1721
}
1822
];
1923

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import React, { useContext, useState } from 'react';
2+
3+
import FormRenderer from '@data-driven-forms/react-form-renderer/form-renderer';
4+
import WizardContext from '@data-driven-forms/react-form-renderer/wizard-context';
5+
import FormSpy from '@data-driven-forms/react-form-renderer/form-spy';
6+
7+
import Wizard from '@data-driven-forms/common/wizard';
8+
import selectNext from '@data-driven-forms/common/wizard/select-next';
9+
10+
import FormTemplate from '@data-driven-forms/mui-component-mapper/form-template';
11+
import Select from '@data-driven-forms/mui-component-mapper/select';
12+
import TextField from '@data-driven-forms/mui-component-mapper/text-field';
13+
14+
const schema = {
15+
fields: [
16+
{
17+
component: 'wizard',
18+
name: 'custom-wizard',
19+
fields: [
20+
{
21+
name: 'first-step',
22+
title: 'Select step',
23+
nextStep: ({ values }) => values['selected-step'],
24+
fields: [
25+
{
26+
component: 'select',
27+
name: 'selected-step',
28+
label: 'Select next step',
29+
isRequired: true,
30+
validate: [{ type: 'required' }],
31+
options: [
32+
{ label: 'Step a', value: 'step-a' },
33+
{ label: 'Step b', value: 'step-b' }
34+
]
35+
}
36+
]
37+
},
38+
{
39+
name: 'step-a',
40+
title: 'Step A',
41+
fields: [
42+
{
43+
component: 'text-field',
44+
name: 'a-value',
45+
isRequired: true,
46+
validate: [{ type: 'required' }],
47+
label: 'A value'
48+
}
49+
]
50+
},
51+
{
52+
name: 'step-b',
53+
title: 'Step B',
54+
fields: [
55+
{
56+
component: 'text-field',
57+
name: 'b-value',
58+
isRequired: true,
59+
validate: [{ type: 'required' }],
60+
label: 'B value'
61+
}
62+
]
63+
}
64+
]
65+
}
66+
]
67+
};
68+
69+
const WizardInternal = (props) => {
70+
const { formOptions, currentStep, handlePrev, onKeyDown, handleNext, activeStepIndex } = useContext(WizardContext);
71+
72+
return (
73+
<div onKeyDown={onKeyDown} style={{ width: '100%' }}>
74+
{currentStep.title}
75+
{formOptions.renderForm(currentStep.fields)}
76+
<FormSpy>
77+
{() => (
78+
<React.Fragment>
79+
{currentStep.nextStep && (
80+
<button disabled={!formOptions.getState().valid} onClick={() => handleNext(selectNext(currentStep.nextStep, formOptions.getState))}>
81+
Next
82+
</button>
83+
)}
84+
{!currentStep.nextStep && (
85+
<button disabled={!formOptions.getState().valid} onClick={() => formOptions.handleSubmit()}>
86+
Submit
87+
</button>
88+
)}
89+
<button onClick={handlePrev} disabled={activeStepIndex === 0}>
90+
Back
91+
</button>
92+
</React.Fragment>
93+
)}
94+
</FormSpy>
95+
</div>
96+
);
97+
};
98+
99+
const WrappedWizard = (props) => <Wizard Wizard={WizardInternal} {...props} />;
100+
101+
const CustomWizard = () => {
102+
const [values, setValues] = useState();
103+
104+
return (
105+
<React.Fragment>
106+
<FormRenderer
107+
schema={schema}
108+
componentMapper={{ 'text-field': TextField, select: Select, wizard: WrappedWizard }}
109+
FormTemplate={(props) => <FormTemplate {...props} showFormControls={false} />}
110+
onSubmit={(values) => setValues(values)}
111+
/>
112+
{values && <pre>{JSON.stringify(values, null, 2)}</pre>}
113+
</React.Fragment>
114+
);
115+
};
116+
117+
export default CustomWizard;
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import DocPage from '@docs/doc-page';
2+
import CodeExample from '@docs/code-example';
3+
import Wizard from '../../doc-components/examples-texts/wizard.md';
4+
5+
<DocPage>
6+
7+
# Custom wizard
8+
9+
## Common wizard
10+
11+
To implement a custom wizard form, you can use the common wizard component. This component provides basic functionality such as branching, submitting only visited values, etc. Also, this wizard is used in all of our provided mappers.
12+
13+
When implementing custom wizard, please keep it under `wizard` component key so the schema validator won't expect that nested fields (=wizard steps definitions) have a component property. If this is not possible, you can implement a mock component that will be used as a component for wizard steps.
14+
15+
To use the component import it from the common package:
16+
17+
```jsx
18+
--- { "switchable": false } ---
19+
import Wizard from '@data-driven-forms/common/wizard';
20+
```
21+
22+
And use your wizard component as `Wizard` prop:
23+
24+
```jsx
25+
const CustomWizard = (props) => { ... }
26+
27+
const WrappedWizard = (props) => <Wizard Wizard={CustomWizard} {...props} />
28+
```
29+
30+
Custom wizard (and all other nested components) then can access the wizard api via `WizardContext`:
31+
32+
```jsx
33+
--- { "switchable": false } ---
34+
import WizardContext from '@data-driven-forms/react-form-renderer/wizard-context';
35+
36+
const CustomWizard = (props) => {
37+
const {
38+
crossroads,
39+
formOptions,
40+
currentStep,
41+
handlePrev,
42+
onKeyDown,
43+
jumpToStep,
44+
setPrevSteps,
45+
handleNext,
46+
navSchema,
47+
activeStepIndex,
48+
maxStepIndex,
49+
isDynamic
50+
} = useContext(WizardContext);
51+
52+
...
53+
}
54+
```
55+
56+
You can notice that this context also contains `formOptions`. It contains the same functions as the [regular one](/hooks/use-form-api), however, some of the functions are enhanced to support wizard functionality.
57+
58+
## Common documentation
59+
60+
<Wizard />
61+
62+
## Preview
63+
64+
Following example shows only the basic custom implementation. To see other functionality as a dynamic navigation, check implementation in one of our mappers. (The [PF4 wizard](/provided-mappers/wizard?mapper=pf4) provides the most complex functionality.)
65+
66+
<CodeExample source="components/examples/custom-wizard" mode="preview" />
67+
68+
</DocPage>

0 commit comments

Comments
 (0)