@applica-software-guru/react-admin 1.5.282 → 1.5.284

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.
Files changed (46) hide show
  1. package/dist/components/ra-forms/LongForm/Tab.d.ts.map +1 -1
  2. package/dist/components/ra-forms/WizardForm/Content.d.ts +15 -0
  3. package/dist/components/ra-forms/WizardForm/Content.d.ts.map +1 -0
  4. package/dist/components/ra-forms/WizardForm/Form.d.ts +38 -0
  5. package/dist/components/ra-forms/WizardForm/Form.d.ts.map +1 -0
  6. package/dist/components/ra-forms/WizardForm/Provider.d.ts +48 -0
  7. package/dist/components/ra-forms/WizardForm/Provider.d.ts.map +1 -0
  8. package/dist/components/ra-forms/WizardForm/Stepper.d.ts +18 -0
  9. package/dist/components/ra-forms/WizardForm/Stepper.d.ts.map +1 -0
  10. package/dist/components/ra-forms/WizardForm/Toolbar.d.ts +20 -0
  11. package/dist/components/ra-forms/WizardForm/Toolbar.d.ts.map +1 -0
  12. package/dist/components/ra-forms/WizardForm/index.d.ts +4 -0
  13. package/dist/components/ra-forms/WizardForm/index.d.ts.map +1 -0
  14. package/dist/components/ra-forms/index.d.ts +1 -0
  15. package/dist/components/ra-forms/index.d.ts.map +1 -1
  16. package/dist/react-admin.cjs.js +54 -54
  17. package/dist/react-admin.cjs.js.gz +0 -0
  18. package/dist/react-admin.cjs.js.map +1 -1
  19. package/dist/react-admin.es.js +8609 -8403
  20. package/dist/react-admin.es.js.gz +0 -0
  21. package/dist/react-admin.es.js.map +1 -1
  22. package/dist/react-admin.umd.js +54 -54
  23. package/dist/react-admin.umd.js.gz +0 -0
  24. package/dist/react-admin.umd.js.map +1 -1
  25. package/dist/utils/index.d.ts +1 -0
  26. package/dist/utils/index.d.ts.map +1 -1
  27. package/dist/utils/react.d.ts +14 -0
  28. package/dist/utils/react.d.ts.map +1 -0
  29. package/package.json +1 -1
  30. package/src/components/ra-forms/LongForm/Tab.tsx +2 -11
  31. package/src/components/ra-forms/WizardForm/Content.tsx +94 -0
  32. package/src/components/ra-forms/WizardForm/Form.tsx +107 -0
  33. package/src/components/ra-forms/WizardForm/Provider.tsx +62 -0
  34. package/src/components/ra-forms/WizardForm/Stepper.tsx +113 -0
  35. package/src/components/ra-forms/WizardForm/Toolbar.tsx +58 -0
  36. package/src/components/ra-forms/WizardForm/index.ts +4 -0
  37. package/src/components/ra-forms/index.ts +1 -0
  38. package/src/playground/App.jsx +2 -1
  39. package/src/playground/components/ra-forms/TestWizardForm/AdvancedUsage.jsx +176 -0
  40. package/src/playground/components/ra-forms/TestWizardForm/BaseUsage.jsx +115 -0
  41. package/src/playground/components/ra-forms/TestWizardForm/TestWizardForm.jsx +27 -0
  42. package/src/playground/components/ra-forms/TestWizardForm/index.jsx +1 -0
  43. package/src/playground/components/ra-forms/index.jsx +1 -0
  44. package/src/playground/menu.jsx +8 -0
  45. package/src/utils/index.ts +1 -0
  46. package/src/utils/react.ts +25 -0
@@ -1,5 +1,6 @@
1
1
  export * from './lang';
2
2
  export * from './localStorage';
3
3
  export * from './localizedValue';
4
+ export * from './react';
4
5
  export * from './time';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { ReactElement, ReactNode } from 'react';
2
+ /**
3
+ * This file contains utility functions that can be reused across the project.
4
+ */
5
+ /**
6
+ * Originally made for LongForm component to find sources.
7
+ * Walks the children of a React element and calls a callback function for each child.
8
+ *
9
+ * @param {ReactNode} children - The children of a React element.
10
+ * @param {Function} callback - The callback function to call for each child.
11
+ */
12
+ declare function walkChildren(children: ReactNode, callback: (el: ReactElement) => void): void;
13
+ export { walkChildren };
14
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../../src/utils/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAkB,MAAM,OAAO,CAAC;AAGhE;;GAEG;AAEH;;;;;;GAMG;AACH,iBAAS,YAAY,CAAC,QAAQ,WAAgB,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,YAAY,KAAK,IAAI,QAQnF;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
package/package.json CHANGED
@@ -106,5 +106,5 @@
106
106
  "type": "module",
107
107
  "types": "dist/index.d.ts",
108
108
  "typings": "dist/index.d.ts",
109
- "version": "1.5.282"
109
+ "version": "1.5.284"
110
110
  }
@@ -3,25 +3,16 @@ import { useIsActive } from '@/components/ra-forms/LongForm/hooks';
3
3
  import { IItem } from '@/components/ra-forms/LongForm/types';
4
4
  import { getId } from '@/components/ra-forms/LongForm/utils';
5
5
  import { Optional } from '@/types';
6
+ import { walkChildren } from '@/utils';
6
7
  import { Box } from '@mui/material';
7
8
  import _ from 'lodash';
8
- import React, { Children, ReactElement, ReactNode, cloneElement, isValidElement, useEffect, useMemo } from 'react';
9
+ import React, { Children, cloneElement, isValidElement, useEffect, useMemo } from 'react';
9
10
  import { useFormState } from 'react-hook-form';
10
11
 
11
12
  type IBaseItemProps = React.PropsWithChildren<Optional<IItem, 'id' | 'index'> & { sources: Array<string> }>;
12
13
  type ITabProps = IBaseItemProps;
13
14
  type IGroupProps = IBaseItemProps;
14
15
 
15
- function walkChildren(children: ReactNode = [], callback: (el: ReactElement) => void) {
16
- const _children = _.isArray(children) ? children : [children];
17
- const validChildren = _.filter(_children, (child) => isValidElement(child));
18
- _.each(validChildren, (child) => {
19
- callback(child);
20
- // @ts-ignore @ts-expect-error Property 'children' does not exist on type '{}'.
21
- walkChildren(child?.props?.children ?? [], callback);
22
- });
23
- }
24
-
25
16
  function BaseItem(props: IBaseItemProps) {
26
17
  const { errors } = useFormState();
27
18
  const countErrors = useErrorCount();
@@ -0,0 +1,94 @@
1
+ import { Children, ReactElement, ReactNode, isValidElement, useMemo } from 'react';
2
+ import { Box, Button, Divider, Grid, useTheme } from '@mui/material';
3
+ import { MainCard } from '@/components/MainCard';
4
+ import { Toolbar } from './Toolbar';
5
+ import { useTranslate } from 'react-admin';
6
+ import _ from 'lodash';
7
+ import { useWizardFormContext } from './Provider';
8
+ import { Stepper } from './Stepper';
9
+ import { walkChildren } from '@/utils';
10
+
11
+ interface ContentProps {
12
+ title?: ReactNode | string;
13
+ subheader?: ReactNode | string;
14
+ secondary?: ReactNode | string;
15
+ toolbar?: ReactElement;
16
+ progress?: ReactNode;
17
+ isSmall: boolean;
18
+ modal: boolean;
19
+ sx?: any;
20
+ setCurrentStep: (step: number) => void;
21
+ }
22
+
23
+ function Content({ title, subheader, secondary, toolbar, progress, isSmall, modal, sx, setCurrentStep }: ContentProps) {
24
+ const { currentStep, steps } = useWizardFormContext();
25
+ const translate = useTranslate();
26
+ const theme = useTheme();
27
+ const isHorizontal = isSmall || modal;
28
+
29
+ const cancelButton = useMemo(() => {
30
+ if (!toolbar) return null;
31
+
32
+ return Children.toArray(toolbar.props.children).find(
33
+ (child) =>
34
+ isValidElement(child) && child.type === Button && child.props?.children === translate('ra.action.cancel')
35
+ );
36
+ }, [toolbar, translate]);
37
+
38
+ const stepFields: Array<Array<string>> = steps.map((step: ReactElement) => {
39
+ const fields: Array<string> = [];
40
+ const { sources } = step.props;
41
+ if (sources !== undefined) {
42
+ fields.push(...sources);
43
+ } else {
44
+ walkChildren(step, (el) => {
45
+ if (el?.props?.source !== undefined) {
46
+ fields.push(el.props.source);
47
+ }
48
+ });
49
+ }
50
+ return fields;
51
+ });
52
+
53
+ return (
54
+ <Grid container spacing={2} sx={sx}>
55
+ <Grid item xl={modal ? 12 : 2} lg={modal ? 12 : 3} md={modal ? 12 : 3} sm={modal ? 12 : 4} xs={12}>
56
+ {progress || <Stepper isHorizontal={isHorizontal} setCurrentStep={setCurrentStep} stepFields={stepFields} />}
57
+ </Grid>
58
+ {modal ? <Divider sx={{ width: '100%' }} /> : null}
59
+ <Grid
60
+ item
61
+ xl={modal ? 12 : 10}
62
+ lg={modal ? 12 : 9}
63
+ md={modal ? 12 : 9}
64
+ sm={modal ? 12 : 8}
65
+ xs={12}
66
+ sx={{ paddingTop: modal ? '0 !important' : null }}
67
+ >
68
+ <MainCard
69
+ title={title || steps[currentStep].props.label}
70
+ subheader={subheader}
71
+ secondary={secondary}
72
+ border={!modal}
73
+ divider
74
+ >
75
+ <Box>{steps[currentStep]}</Box>
76
+ <Box
77
+ sx={{
78
+ '& .MuiToolbar-root': {
79
+ paddingLeft: 0,
80
+ paddingRight: 0,
81
+ paddingBottom: 0,
82
+ paddingTop: theme.spacing(2)
83
+ }
84
+ }}
85
+ >
86
+ {toolbar && !cancelButton ? toolbar : <Toolbar cancelButton={cancelButton} />}
87
+ </Box>
88
+ </MainCard>
89
+ </Grid>
90
+ </Grid>
91
+ );
92
+ }
93
+
94
+ export { Content };
@@ -0,0 +1,107 @@
1
+ import { Children, ReactElement, ReactNode, useState } from 'react';
2
+ import { Theme, styled, useMediaQuery } from '@mui/material';
3
+ import { FormProps, Form as RaForm } from 'react-admin';
4
+ import { Provider } from './Provider';
5
+ import { Content } from './Content';
6
+
7
+ type WizardFormProps = FormProps & {
8
+ toolbar?: ReactElement;
9
+ progress?: ReactElement;
10
+ title?: ReactNode | string;
11
+ subheader?: ReactNode | string;
12
+ secondary?: ReactNode | string;
13
+ sx?: any;
14
+ modal?: boolean;
15
+ };
16
+
17
+ const StyledForm = styled(RaForm, {
18
+ shouldForwardProp: (prop) => prop !== 'modal'
19
+ })<{ modal: boolean }>(({ theme, modal }) => ({
20
+ [theme.breakpoints.down('sm')]: !modal
21
+ ? {
22
+ paddingBottom: `${theme.spacing(2.5)}`
23
+ }
24
+ : {}
25
+ }));
26
+
27
+ /**
28
+ * Form component for handling wizard-style forms with multiple steps.
29
+ *
30
+ * @param {object} props - The properties object.
31
+ * @param {React.ReactNode} props.children - The child components representing each step of the wizard.
32
+ * @param {React.ReactNode} props.toolbar - The toolbar component to be displayed.
33
+ * @param {React.ReactNode} props.progress - The progress indicator component.
34
+ * @param {string} props.title - The title of the form.
35
+ * @param {string | null} [props.subheader=null] - The subheader text of the form.
36
+ * @param {React.ReactNode | null} [props.secondary=null] - The secondary content of the form.
37
+ * @param {object} props.sx - The style object for custom styling.
38
+ * @param {boolean} [props.modal=false] - Flag indicating if the form is displayed in a modal.
39
+ * @param {object} props.rest - Additional properties passed to the form.
40
+ *
41
+ * @returns {JSX.Element | null} The rendered form component.
42
+ */
43
+ function Form({
44
+ children,
45
+ toolbar,
46
+ progress,
47
+ title,
48
+ subheader = null,
49
+ secondary = null,
50
+ sx,
51
+ modal = false,
52
+ ...props
53
+ }: WizardFormProps): JSX.Element | null {
54
+ const [currentStep, setCurrentStep] = useState(0);
55
+ const steps = Children.toArray(children) as Array<ReactElement>;
56
+ const isSmall = useMediaQuery((theme: Theme) => theme.breakpoints.down('sm'));
57
+
58
+ function hasNextStep(): boolean {
59
+ return currentStep < steps.length - 1;
60
+ }
61
+ function hasPreviousStep(): boolean {
62
+ return currentStep > 0;
63
+ }
64
+
65
+ function goToNextStep(): void {
66
+ setCurrentStep((prev) => Math.min(prev + 1, steps.length - 1));
67
+ }
68
+
69
+ function goToPreviousStep(): void {
70
+ setCurrentStep((prev) => Math.max(prev - 1, 0));
71
+ }
72
+
73
+ const wizardFormContextValue = {
74
+ currentStep,
75
+ steps,
76
+ hasNextStep,
77
+ hasPreviousStep,
78
+ goToNextStep,
79
+ goToPreviousStep
80
+ };
81
+
82
+ return (
83
+ <Provider value={wizardFormContextValue}>
84
+ <StyledForm {...props} modal={modal}>
85
+ <Content
86
+ title={title}
87
+ subheader={subheader}
88
+ secondary={secondary}
89
+ modal={modal}
90
+ sx={sx}
91
+ toolbar={toolbar}
92
+ progress={progress}
93
+ isSmall={isSmall}
94
+ setCurrentStep={setCurrentStep}
95
+ />
96
+ </StyledForm>
97
+ </Provider>
98
+ );
99
+ }
100
+
101
+ function Step({ children }: { children: ReactNode; label: string; icon?: ReactNode; sources?: Array<string> }) {
102
+ return <>{children}</>;
103
+ }
104
+
105
+ Form.Step = Step;
106
+
107
+ export { Form };
@@ -0,0 +1,62 @@
1
+ import { ReactElement, ReactNode, createContext, useContext } from 'react';
2
+
3
+ interface WizardFormContextValue {
4
+ currentStep: number;
5
+ steps: Array<ReactElement>;
6
+ hasNextStep: () => boolean;
7
+ hasPreviousStep: () => boolean;
8
+ goToNextStep: () => void;
9
+ goToPreviousStep: () => void;
10
+ }
11
+
12
+ const WizardFormContext = createContext<WizardFormContextValue | undefined>(undefined);
13
+
14
+ /**
15
+ * Custom hook to access the wizard form context.
16
+ * This hook provides access to the current step, steps, and navigation methods
17
+ * for a wizard form.
18
+ *
19
+ * @throws Will throw an error if used outside of a `WizardFormProvider`.
20
+ *
21
+ * @property {number} currentStep - The index of the current step in the wizard form.
22
+ * @property {Array<ReactElement>} steps - An array of React elements representing the steps of the wizard form.
23
+ *
24
+ * @method hasNextStep
25
+ * @returns {boolean} - Returns true if there is a next step available, otherwise false.
26
+ *
27
+ * @method hasPreviousStep
28
+ * @returns {boolean} - Returns true if there is a previous step available, otherwise false.
29
+ *
30
+ * @method goToNextStep
31
+ * @returns {void} - Advances to the next step in the wizard form.
32
+ *
33
+ * @method goToPreviousStep
34
+ * @returns {void} - Goes back to the previous step in the wizard form.
35
+ *
36
+ *
37
+ * @example
38
+ * const { hasNextStep, goToNextStep } = useWizardFormContext();
39
+ * return (
40
+ * <Button disabled={!hasNextStep} onClick={goToNextStep}>
41
+ * Next
42
+ * </Button>
43
+ * );
44
+ */
45
+ function useWizardFormContext() {
46
+ const context = useContext(WizardFormContext);
47
+ if (!context) {
48
+ throw new Error('useWizardFormContext must be used within a WizardFormProvider');
49
+ }
50
+ return context;
51
+ }
52
+
53
+ interface WizardFormProviderProps {
54
+ value: WizardFormContextValue;
55
+ children: ReactNode;
56
+ }
57
+
58
+ function Provider({ value, children }: WizardFormProviderProps) {
59
+ return <WizardFormContext.Provider value={value}>{children}</WizardFormContext.Provider>;
60
+ }
61
+
62
+ export { Provider, useWizardFormContext };
@@ -0,0 +1,113 @@
1
+ import { ReactElement } from 'react';
2
+ import { Box, Stepper as MuiStepper, Step, StepIconProps, StepLabel, styled } from '@mui/material';
3
+ import { useWizardFormContext } from './Provider';
4
+ import { useFormState } from 'react-hook-form';
5
+ import _ from 'lodash';
6
+
7
+ interface WizardStepperProps {
8
+ isHorizontal: boolean;
9
+ setCurrentStep: (step: number) => void;
10
+ stepFields: Array<Array<string>>;
11
+ }
12
+
13
+ const StyledStepper = styled(MuiStepper, {
14
+ shouldForwardProp: (prop) => prop !== 'isHorizontal'
15
+ })<{ isHorizontal: boolean }>(({ theme, isHorizontal }) => ({
16
+ paddingBottom: theme.spacing(2),
17
+ display: 'flex',
18
+ justifyContent: isHorizontal ? 'space-between' : 'flex-start',
19
+ '.MuiStep-root': {
20
+ flex: isHorizontal ? 1 : 'none',
21
+ maxWidth: isHorizontal ? 'none' : '100%',
22
+ display: 'flex',
23
+ justifyContent: isHorizontal ? 'center' : 'flex-start'
24
+ },
25
+ '.MuiStepConnector-line.MuiStepConnector-lineVertical': {
26
+ minHeight: 12
27
+ },
28
+ '.MuiStepConnector-vertical': {
29
+ marginLeft: 14.5
30
+ },
31
+ '.MuiStepConnector-horizontal': {
32
+ marginLeft: -10
33
+ }
34
+ }));
35
+
36
+ const StyledStepIconRoot = styled(Box)<{
37
+ ownerState: { completed?: boolean; active?: boolean; error?: boolean };
38
+ }>(({ theme, ownerState }) => ({
39
+ backgroundColor: ownerState.error
40
+ ? theme.palette.error.main
41
+ : ownerState.completed || ownerState.active
42
+ ? theme.palette.primary.main
43
+ : theme.palette.mode === 'dark'
44
+ ? theme.palette.grey[200]
45
+ : theme.palette.grey[400],
46
+ zIndex: 1,
47
+ color: theme.palette.common.white,
48
+ width: 30,
49
+ height: 30,
50
+ display: 'flex',
51
+ borderRadius: '50%',
52
+ justifyContent: 'center',
53
+ alignItems: 'center'
54
+ }));
55
+
56
+ function StyledStepIcon({ completed, active, error, icon, className }: StepIconProps) {
57
+ return (
58
+ <StyledStepIconRoot ownerState={{ completed, active, error }} className={className}>
59
+ {error ? '!' : icon}
60
+ </StyledStepIconRoot>
61
+ );
62
+ }
63
+
64
+ /**
65
+ * Stepper component for rendering a step-by-step navigation UI.
66
+ *
67
+ * @param {Object} props - The properties object.
68
+ * @param {boolean} props.isHorizontal - Determines the orientation of the stepper (horizontal or vertical).
69
+ * @param {function} props.setCurrentStep - Function to set the current step index.
70
+ * @param {Array} props.stepFields - Array of fields associated with each step.
71
+ *
72
+ * @returns {JSX.Element} The rendered Stepper component.
73
+ */
74
+ function Stepper({ isHorizontal, setCurrentStep, stepFields }: WizardStepperProps) {
75
+ const { currentStep, steps } = useWizardFormContext();
76
+ const { errors } = useFormState();
77
+
78
+ function handleClick(index: number) {
79
+ if (index <= currentStep) {
80
+ setCurrentStep(index);
81
+ }
82
+ }
83
+
84
+ return (
85
+ <StyledStepper
86
+ activeStep={currentStep}
87
+ orientation={isHorizontal ? 'horizontal' : 'vertical'}
88
+ isHorizontal={isHorizontal}
89
+ sx={{ p: 3, mt: 1 }}
90
+ >
91
+ {steps.map((step: ReactElement, index: number) => {
92
+ const stepHasError = stepFields[index].some((field) => _.get(errors, field));
93
+ const { label, icon } = step.props;
94
+
95
+ return (
96
+ <Step key={index}>
97
+ <StepLabel
98
+ StepIconComponent={StyledStepIcon}
99
+ error={stepHasError}
100
+ icon={icon}
101
+ onClick={() => handleClick(index)}
102
+ style={{ cursor: index <= currentStep ? 'pointer' : 'default' }}
103
+ >
104
+ {isHorizontal ? null : label}
105
+ </StepLabel>
106
+ </Step>
107
+ );
108
+ })}
109
+ </StyledStepper>
110
+ );
111
+ }
112
+
113
+ export { Stepper };
@@ -0,0 +1,58 @@
1
+ import { ReactNode, cloneElement, useCallback } from 'react';
2
+ import { Box, Button } from '@mui/material';
3
+ import { Toolbar as RaToolbar, ToolbarProps } from '@/components/ra-forms/Toolbar';
4
+ import { SaveButton } from 'react-admin';
5
+ import { useTranslate } from 'ra-core';
6
+ import { useFormContext } from 'react-hook-form';
7
+ import { useWizardFormContext } from './Provider';
8
+
9
+ interface WizardToolbarProps extends ToolbarProps {
10
+ cancelButton?: ReactNode;
11
+ }
12
+
13
+ /**
14
+ * Toolbar component for the WizardForm.
15
+ *
16
+ * This component renders a toolbar with navigation buttons for a multi-step form.
17
+ * It includes buttons to navigate to the previous and next steps, as well as a cancel button.
18
+ *
19
+ * @param {WizardToolbarProps} props - The properties for the Toolbar component.
20
+ * @param {React.ReactElement} props.cancelButton - An optional cancel button element.
21
+ * @param {object} props.toolbarProps - Additional properties to pass to the RaToolbar component.
22
+ *
23
+ * @returns {JSX.Element} The rendered Toolbar component.
24
+ */
25
+ function Toolbar({ cancelButton, ...props }: WizardToolbarProps) {
26
+ const { hasNextStep, hasPreviousStep, goToNextStep, goToPreviousStep } = useWizardFormContext();
27
+ const translate = useTranslate();
28
+ const { handleSubmit } = useFormContext();
29
+ const onSubmit = useCallback(() => {
30
+ goToNextStep();
31
+ }, [goToNextStep]);
32
+
33
+ return (
34
+ <RaToolbar {...props}>
35
+ <Box sx={{ '& .MuiButtonBase-root': { ml: 0 } }}>
36
+ {
37
+ //@ts-ignore
38
+ cancelButton ? cloneElement(cancelButton) : null
39
+ }
40
+ </Box>
41
+ <Box sx={{ flex: '1 1 auto' }} />
42
+ {hasPreviousStep() && (
43
+ <Button variant="text" color="primary" onClick={goToPreviousStep}>
44
+ {translate('ra.action.back')}
45
+ </Button>
46
+ )}
47
+ {hasNextStep() ? (
48
+ <Button variant="contained" color="primary" onClick={handleSubmit(onSubmit)}>
49
+ {translate('ra.action.next')}
50
+ </Button>
51
+ ) : (
52
+ <SaveButton />
53
+ )}
54
+ </RaToolbar>
55
+ );
56
+ }
57
+
58
+ export { Toolbar };
@@ -0,0 +1,4 @@
1
+ import { Form } from './Form';
2
+ import { useWizardFormContext } from './Provider';
3
+
4
+ export { Form as WizardForm, useWizardFormContext };
@@ -10,3 +10,4 @@ export * from './SimpleFormIterator';
10
10
  export * from './TabbedForm';
11
11
  export * from './TableForm';
12
12
  export * from './Toolbar';
13
+ export * from './WizardForm';
@@ -3,7 +3,7 @@ import { menu } from './menu';
3
3
  import { theme } from './theme';
4
4
  import { ActivatePage, ApplicaAdmin, HttpError, RecoverPage, RegisterPage, Resource } from '@/';
5
5
  import build from '@/playground/build.json';
6
- import { CustomPage } from '@/playground/components';
6
+ import { CustomPage, TestWizardForm } from '@/playground/components';
7
7
  import { API_URL, APP_NAME } from '@/playground/config';
8
8
  import { ApplicaDataProvider, createAttachmentsParser } from '@applica-software-guru/crud-client';
9
9
  import { ApplicaAuthProvider, LocalStorage } from '@applica-software-guru/iam-client';
@@ -44,6 +44,7 @@ function App() {
44
44
  >
45
45
  <CustomRoutes>
46
46
  <Route path="/custom-page" element={<CustomPage />} />
47
+ <Route path="/wizard-form" element={<TestWizardForm />} />
47
48
  </CustomRoutes>
48
49
  <Resource name="entities/notification" {...entities.notification} />
49
50
  <Resource name="entities/user" {...entities.user} />