@@ -8,6 +8,8 @@ import { DescriptionRenderer } from './DescriptionRenderer.js';
88import { canSubmit } from './canSubmit.js' ;
99import { SubmitButton } from './SubmitButton.js' ;
1010import { Button } from './Button.js' ;
11+ import { ScrollArea } from './ScrollArea.js' ;
12+ import { FullScreen } from './FullScreen.js' ;
1113
1214export const Form : React . FC < FormProps > = props => {
1315 const isControlled = props . value !== undefined ;
@@ -18,6 +20,7 @@ export const Form: React.FC<FormProps> = props => {
1820 const [ editingField , setEditingField ] = useState < string > ( ) ;
1921 const canSubmitForm = useMemo ( ( ) => canSubmit ( props . form , value ) , [ value , props . form ] ) ;
2022 const focusManager = useFocusManager ( ) ;
23+ const [ focusedElement , setFocusedElement ] = useState ( 0 ) ;
2124
2225 useEffect ( ( ) => {
2326 focusManager . enableFocus ( ) ;
@@ -37,21 +40,15 @@ export const Form: React.FC<FormProps> = props => {
3740 . map ( field => ( field . initialValue !== undefined ? { [ field . name ] : field . initialValue } : { } ) )
3841 . reduce ( ( obj1 , obj2 ) => ( { ...obj1 , ...obj2 } ) , { } ) ) ;
3942 } )
40-
41-
42- // setValueAndPropagate({
43- // ...value,
44- // ...props.form.sections
45- // .map(section =>
46- // section.fields
47- // .map(field => (field.initialValue !== undefined ? { [field.name]: field.initialValue } : {}))
48- // .reduce((obj1, obj2) => ({ ...obj1, ...obj2 }), {})
49- // )
50- // .reduce((obj1, obj2) => ({ ...obj1, ...obj2 }), {}),
51- // });
5243 }
5344 } , [ ] ) ;
5445
46+ const onChangeTab = ( tab ) => {
47+ setCurrentTab ( tab ) ;
48+ focusManager . focus ( '0' ) ;
49+ setFocusedElement ( 0 )
50+ }
51+
5552 const setValueAndPropagate = ( index : number , newValue : Record < string , unknown > ) => {
5653 value [ index ] = newValue
5754 setValue ( structuredClone ( value ) ) ;
@@ -61,8 +58,18 @@ export const Form: React.FC<FormProps> = props => {
6158 useInput (
6259 ( input , key ) => {
6360 if ( key . upArrow ) {
61+ if ( focusedElement - 1 <= 0 ) {
62+ return ;
63+ }
64+
65+ setFocusedElement ( ( focusedElement ) => focusedElement - 1 ) ;
6466 focusManager . focusPrevious ( ) ;
6567 } else if ( key . downArrow ) {
68+ if ( focusedElement + 1 > sections [ currentTab ] . fields . length + 2 ) {
69+ return ;
70+ }
71+
72+ setFocusedElement ( ( focusedElement ) => focusedElement + 1 ) ;
6673 focusManager . focusNext ( ) ;
6774 }
6875 } ,
@@ -89,44 +96,69 @@ export const Form: React.FC<FormProps> = props => {
8996 setValue ( [ ...value ] ) ;
9097 }
9198
99+ const [ size , setSize ] = useState ( {
100+ columns : process . stdout . columns ,
101+ rows : process . stdout . rows ,
102+ } ) ;
103+
104+ useEffect ( ( ) => {
105+ function onResize ( ) {
106+ setSize ( {
107+ columns : process . stdout . columns ,
108+ rows : process . stdout . rows ,
109+ } ) ;
110+ }
111+
112+ process . stdout . on ( "resize" , onResize ) ;
113+ return ( ) => {
114+ process . stdout . off ( "resize" , onResize ) ;
115+ } ;
116+ } , [ ] ) ;
117+
92118 return (
93- ! isSubmitted && < Box width = "100%" height = "90%" flexDirection = "column" overflowY = "hidden" >
94- < FormHeader { ...props } form = { { ...props . form , sections } } currentTab = { currentTab } onChangeTab = { setCurrentTab } editingField = { editingField } />
95- { ! editingField && sections [ currentTab ] . description && (
96- < Box marginX = { 4 } >
97- < DescriptionRenderer description = { props . form . sections [ currentTab ] ?. description } />
98- </ Box >
99- ) }
100- < Box flexDirection = "column" >
101- { currentTab > props . form . sections . length - 1
102- ? null
103- : sections [ currentTab ] . fields . map ( ( field , index ) => (
104- < FormFieldRenderer
105- field = { field }
106- key = { field . name + currentTab }
107- form = { props . form }
108- value = { value [ currentTab ] [ field . name ] }
109- onChange = { v => setValueAndPropagate ( currentTab , { ...value [ currentTab ] , [ field . name ] : v } ) }
110- onSetEditingField = { setEditingField }
111- editingField = { editingField }
112- customManagers = { props . customManagers }
113- />
114- ) ) }
115- < Box flexDirection = "row-reverse" >
116- < Button label = "Add Item (duplicate)" onClicked = { ( ) => duplicateCurrentItem ( ) } />
117- </ Box >
118- < Box flexDirection = "row-reverse" >
119- < Button label = "Remove" onClicked = { ( ) => removeCurrentItem ( ) } />
120- </ Box >
119+ < FullScreen >
120+ < Box width = "100%" height = "90%" flexDirection = "column" overflowY = "hidden" >
121+ < FormHeader { ...props } form = { { ...props . form , sections } } currentTab = { currentTab } onChangeTab = { onChangeTab } editingField = { editingField } />
122+ < ScrollArea height = { size . rows - 6 } key = { currentTab } isStart = { focusedElement === 0 } >
123+ { ! editingField && sections [ currentTab ] . description && (
124+ < Box marginX = { 4 } >
125+ < DescriptionRenderer description = { props . form . sections [ currentTab ] ?. description } />
126+ </ Box >
127+ ) }
128+ < Box flexDirection = "column" >
129+ { currentTab > props . form . sections . length - 1
130+ ? null
131+ : sections [ currentTab ] . fields . map ( ( field , index ) => (
132+ < FormFieldRenderer
133+ id = { index + '' }
134+ field = { field }
135+ key = { field . name + currentTab }
136+ form = { props . form }
137+ value = { value [ currentTab ] [ field . name ] }
138+ onChange = { v => setValueAndPropagate ( currentTab , { ...value [ currentTab ] , [ field . name ] : v } ) }
139+ onSetEditingField = { setEditingField }
140+ editingField = { editingField }
141+ customManagers = { props . customManagers }
142+ />
143+ ) ) }
144+ < Box flexDirection = "row-reverse" >
145+ < Button label = "Add Item (duplicate)" onClicked = { ( ) => duplicateCurrentItem ( ) } />
146+ </ Box >
147+ < Box flexDirection = "row-reverse" >
148+ < Button label = "Remove" onClicked = { ( ) => removeCurrentItem ( ) } />
149+ </ Box >
150+ </ Box >
151+ { ! editingField && (
152+ < Box flexDirection = "row-reverse" >
153+ < SubmitButton canSubmit = { canSubmitForm } onSubmit = { ( ) => {
154+ props . onSubmit ?.( value )
155+ setIsSubmitted ( true ) ;
156+ } } />
157+ </ Box >
158+ ) }
159+ </ ScrollArea >
121160 </ Box >
122- { ! editingField && (
123- < Box flexDirection = "row-reverse" >
124- < SubmitButton canSubmit = { canSubmitForm } onSubmit = { ( ) => {
125- props . onSubmit ?.( value )
126- setIsSubmitted ( true ) ;
127- } } />
128- </ Box >
129- ) }
130- </ Box >
161+ </ FullScreen >
162+
131163 ) ;
132164} ;
0 commit comments