@@ -7,11 +7,14 @@ import { FormFieldRenderer } from './FormFieldRenderer.js';
77import { DescriptionRenderer } from './DescriptionRenderer.js' ;
88import { canSubmit } from './canSubmit.js' ;
99import { SubmitButton } from './SubmitButton.js' ;
10+ import { Button } from './Button.js' ;
1011
1112export const Form : React . FC < FormProps > = props => {
1213 const isControlled = props . value !== undefined ;
1314 const [ currentTab , setCurrentTab ] = useState ( 0 ) ;
14- const [ value , setValue ] = useState < object > ( props . value ?? { } ) ;
15+ const [ isSubmitted , setIsSubmitted ] = useState ( false ) ;
16+ const [ sections , setSections ] = useState ( props . form . sections ) ;
17+ const [ value , setValue ] = useState < Array < Record < string , unknown > > > ( props . value ?? Array . from ( { length : sections . length } , ( ) => ( { } ) ) ) ;
1518 const [ editingField , setEditingField ] = useState < string > ( ) ;
1619 const canSubmitForm = useMemo ( ( ) => canSubmit ( props . form , value ) , [ value , props . form ] ) ;
1720 const focusManager = useFocusManager ( ) ;
@@ -29,21 +32,25 @@ export const Form: React.FC<FormProps> = props => {
2932 useEffect ( ( ) => {
3033 // Set initial values
3134 if ( ! isControlled ) {
32- setValueAndPropagate ( {
33- ...value ,
34- ...props . form . sections
35- . map ( section =>
36- section . fields
37- . map ( field => ( field . initialValue !== undefined ? { [ field . name ] : field . initialValue } : { } ) )
38- . reduce ( ( obj1 , obj2 ) => ( { ...obj1 , ...obj2 } ) , { } )
39- )
40- . reduce ( ( obj1 , obj2 ) => ( { ...obj1 , ...obj2 } ) , { } ) ,
41- } ) ;
35+ setValue ( Array . from ( { length : sections . length } , ( ) => ( { } ) ) ) ;
36+
37+
38+ // setValueAndPropagate({
39+ // ...value,
40+ // ...props.form.sections
41+ // .map(section =>
42+ // section.fields
43+ // .map(field => (field.initialValue !== undefined ? { [field.name]: field.initialValue } : {}))
44+ // .reduce((obj1, obj2) => ({ ...obj1, ...obj2 }), {})
45+ // )
46+ // .reduce((obj1, obj2) => ({ ...obj1, ...obj2 }), {}),
47+ // });
4248 }
4349 } , [ ] ) ;
4450
45- const setValueAndPropagate = ( value : object ) => {
46- setValue ( value ) ;
51+ const setValueAndPropagate = ( index : number , newValue : Record < string , unknown > ) => {
52+ value [ index ] = newValue
53+ setValue ( structuredClone ( value ) ) ;
4754 props . onChange ?.( value ) ;
4855 } ;
4956
@@ -58,33 +65,62 @@ export const Form: React.FC<FormProps> = props => {
5865 { isActive : ! editingField }
5966 ) ;
6067
68+ const duplicateCurrentItem = ( ) => {
69+ const newTabs = [ ...sections ]
70+ newTabs . splice ( currentTab + 1 , 0 , sections [ currentTab ] )
71+
72+ const newValue = { ...value [ currentTab ] } ;
73+ value . splice ( currentTab + 1 , 0 , newValue ) ;
74+
75+ setSections ( newTabs ) ;
76+ setValue ( [ ...value ] ) ;
77+ }
78+
79+ const removeCurrentItem = ( ) => {
80+ const newTabs = [ ...sections ]
81+ newTabs . splice ( currentTab , 1 ) ;
82+ value . splice ( currentTab , 1 )
83+
84+ setSections ( newTabs ) ;
85+ setValue ( [ ...value ] ) ;
86+ }
87+
6188 return (
62- < Box width = "100%" height = "100 %" flexDirection = "column" >
63- < FormHeader { ...props } currentTab = { currentTab } onChangeTab = { setCurrentTab } editingField = { editingField } />
64- { ! editingField && props . form . sections [ currentTab ] . description && (
89+ ! isSubmitted && < Box width = "100%" height = "90 %" flexDirection = "column" overflowY = "hidden ">
90+ < FormHeader { ...props } form = { { ... props . form , sections } } currentTab = { currentTab } onChangeTab = { setCurrentTab } editingField = { editingField } />
91+ { ! editingField && sections [ currentTab ] . description && (
6592 < Box marginX = { 4 } >
66- < DescriptionRenderer description = { props . form . sections [ currentTab ] . description } />
93+ < DescriptionRenderer description = { props . form . sections [ currentTab ] ? .description } />
6794 </ Box >
6895 ) }
6996 < Box flexDirection = "column" >
7097 { currentTab > props . form . sections . length - 1
7198 ? null
72- : props . form . sections [ currentTab ] . fields . map ( field => (
73- < FormFieldRenderer
74- field = { field }
75- key = { field . name }
76- form = { props . form }
77- value = { value [ field . name ] }
78- onChange = { v => setValueAndPropagate ( { ...value , [ field . name ] : v } ) }
79- onSetEditingField = { setEditingField }
80- editingField = { editingField }
81- customManagers = { props . customManagers }
82- />
83- ) ) }
99+ : sections [ currentTab ] . fields . map ( ( field , index ) => (
100+ < FormFieldRenderer
101+ field = { field }
102+ key = { field . name + currentTab }
103+ form = { props . form }
104+ value = { value [ currentTab ] [ field . name ] }
105+ onChange = { v => setValueAndPropagate ( currentTab , { ...value [ currentTab ] , [ field . name ] : v } ) }
106+ onSetEditingField = { setEditingField }
107+ editingField = { editingField }
108+ customManagers = { props . customManagers }
109+ />
110+ ) ) }
111+ < Box flexDirection = "row-reverse" >
112+ < Button label = "Add Item (duplicate)" onClicked = { ( ) => duplicateCurrentItem ( ) } />
113+ </ Box >
114+ < Box flexDirection = "row-reverse" >
115+ < Button label = "Remove" onClicked = { ( ) => removeCurrentItem ( ) } />
116+ </ Box >
84117 </ Box >
85118 { ! editingField && (
86119 < Box flexDirection = "row-reverse" >
87- < SubmitButton canSubmit = { canSubmitForm } onSubmit = { ( ) => props . onSubmit ?.( value ) } />
120+ < SubmitButton canSubmit = { canSubmitForm } onSubmit = { ( ) => {
121+ props . onSubmit ?.( value )
122+ setIsSubmitted ( true ) ;
123+ } } />
88124 </ Box >
89125 ) }
90126 </ Box >
0 commit comments