FormLayout.tsx217 lines · main
1import React from 'react'
2
3// @ts-ignore
4import defaultTheme from '../../theme/defaultTheme'
5import { cn } from '../../utils'
6
7// @ts-ignore
8// import FormLayoutStyles from './FormLayout.module.css'
9
10type Props = {
11 align?: 'left' | 'right'
12 children?: any
13 className?: string
14 descriptionText?: string | React.ReactNode
15 error?: string | React.ReactNode
16 id?: string
17 label?: string | React.ReactNode
18 labelOptional?: string | React.ReactNode
19 layout?: 'horizontal' | 'vertical' | 'flex'
20 style?: React.CSSProperties
21 // flex?: boolean
22 responsive?: boolean
23 size?: 'tiny' | 'small' | 'medium' | 'large' | 'xlarge'
24 beforeLabel?: string
25 afterLabel?: string | React.ReactNode
26 nonBoxInput?: boolean
27 labelLayout?: 'horizontal' | 'vertical'
28}
29
30export function FormLayout({
31 align = 'left',
32 children,
33 className,
34 descriptionText,
35 error,
36 id,
37 label,
38 labelOptional,
39 layout = 'vertical',
40 style,
41 // flex = false,
42 labelLayout,
43 responsive = true,
44 size = 'medium',
45 beforeLabel,
46 afterLabel,
47 nonBoxInput = label ? false : true,
48}: Props) {
49 // _error is used label && to delay the error string beind removed too soon
50 // once it has animated out, the string will be removed
51 // const [_error, _setError] = useState(error)
52
53 // useEffect(() => {
54 // if (!error) {
55 // console.log('no error')
56 // setTimeout(function () {
57 // _setError(error)
58 // }, 500)
59 // } else {
60 // console.log('has error')
61 // _setError(error)
62 // }
63 // // Update the document title using the browser API
64 // }, [error])
65
66 const __styles = defaultTheme.form_layout
67
68 const flex = layout === 'flex'
69
70 let containerClasses: Array<string> = []
71
72 containerClasses.push(__styles.size[size])
73
74 let labelContainerClasses: Array<string> = []
75 let dataInputContainerClasses: Array<string> = []
76
77 if (layout !== 'horizontal' && !labelLayout && !flex) {
78 labelContainerClasses.push(__styles.labels_horizontal_layout)
79 } else if (labelLayout === 'horizontal') {
80 labelContainerClasses.push(__styles.labels_horizontal_layout)
81 } else if (labelLayout === 'vertical') {
82 labelContainerClasses.push(__styles.labels_vertical_layout)
83 } else {
84 labelContainerClasses.push(__styles.labels_vertical_layout)
85 }
86
87 if (layout !== 'horizontal') {
88 dataInputContainerClasses.push(__styles.data_input_horizontal_layout)
89 } else {
90 dataInputContainerClasses.push(__styles.data_input_vertical_layout)
91 if (align === 'right') {
92 dataInputContainerClasses.push(__styles.data_input_vertical_layout__align_right)
93 }
94 }
95
96 if (flex) {
97 containerClasses.push(__styles.flex[align].base)
98 if (align === 'left') {
99 labelContainerClasses.push(__styles.flex.left.labels)
100 dataInputContainerClasses.push(__styles.flex.left.data_input)
101 }
102 if (align === 'right') {
103 labelContainerClasses.push(__styles.flex.right.labels)
104 dataInputContainerClasses.push(__styles.flex.right.data_input)
105 }
106 } else {
107 containerClasses.push(
108 __styles.container,
109 responsive ? __styles.responsive : __styles.non_responsive
110 )
111 }
112
113 if (className) {
114 containerClasses.push(className)
115 }
116
117 const labelled = Boolean(label || beforeLabel || afterLabel)
118
119 // console.log('error', error)
120
121 const renderError = error && (
122 <p
123 data-state={error ? 'show' : 'hide'}
124 className={[__styles.error.base, __styles.error.size[size]].join(' ')}
125 >
126 {error}
127 </p>
128 )
129
130 const renderDescription = descriptionText && (
131 <div
132 className={[__styles.description.base, __styles.description.size[size]].join(' ')}
133 id={id + '-description'}
134 >
135 {descriptionText}
136 </div>
137 )
138
139 return (
140 <div className={containerClasses.join(' ')}>
141 {flex && <div className={__styles.flex[align].content}>{children}</div>}
142 {labelled || labelOptional || layout === 'horizontal' ? (
143 <div
144 // direction={
145 // (layout && layout === 'horizontal') ||
146 // (flex && layout && layout === 'vertical')
147 // ? 'vertical'
148 // : 'horizontal'
149 // }
150 className={labelContainerClasses.join(' ')}
151 >
152 {labelled && (
153 <label
154 className={cn(__styles.label.base, __styles.label.size[size], 'break-all')}
155 htmlFor={id}
156 >
157 {beforeLabel && (
158 <span
159 className={[__styles.label_before.base, __styles.label_before.size[size]].join(
160 ' '
161 )}
162 id={id + '-before'}
163 >
164 {beforeLabel}
165 </span>
166 )}
167 {label}
168 {afterLabel && (
169 <span
170 className={[__styles.label_after.base, __styles.label_after.size[size]].join(' ')}
171 id={id + '-after'}
172 >
173 {afterLabel}
174 </span>
175 )}
176 </label>
177 )}
178 {labelOptional && (
179 <span
180 className={[__styles.label_optional.base, __styles.label_optional.size[size]].join(
181 ' '
182 )}
183 id={id + '-optional'}
184 >
185 {labelOptional}
186 </span>
187 )}
188 {flex && (
189 <>
190 {renderDescription}
191 {renderError}
192 </>
193 )}
194 </div>
195 ) : null}
196 {!flex && (
197 <div className={dataInputContainerClasses.join(' ')} style={style}>
198 <>
199 <div
200 className={
201 nonBoxInput && label && layout === 'vertical'
202 ? __styles.non_box_data_input_spacing_vertical
203 : nonBoxInput && label && layout === 'horizontal'
204 ? __styles.non_box_data_input_spacing_horizontal
205 : ''
206 }
207 >
208 {children}
209 </div>
210 {renderError}
211 {renderDescription}
212 </>
213 </div>
214 )}
215 </div>
216 )
217}