@@ -5,7 +5,6 @@ import { Button } from '@/components/ui/button'
55import {
66 Card ,
77 CardContent ,
8- CardDescription ,
98 CardHeader ,
109 CardTitle ,
1110} from '@/components/ui/card'
@@ -31,20 +30,10 @@ function buildFieldPath(basePath: string, fieldName: string) {
3130 return basePath ? `${ basePath } .${ fieldName } ` : fieldName
3231}
3332
34- function hasTopLevelAdvancedFields ( schema : ConfigSchema ) {
35- return schema . fields . some ( ( field ) => field . advanced && ! schema . nested ?. [ field . name ] )
36- }
37-
3833function resolveSectionTitle ( schema : ConfigSchema ) {
3934 return schema . uiLabel || schema . classDoc || schema . className
4035}
4136
42- function resolveSectionDescription ( schema : ConfigSchema , sectionTitle : string ) {
43- return schema . classDoc && schema . classDoc !== sectionTitle
44- ? schema . classDoc
45- : undefined
46- }
47-
4837function SectionIcon ( { iconName } : { iconName ?: string } ) {
4938 if ( ! iconName ) return null
5039 const IconComponent = LucideIcons [ iconName as keyof typeof LucideIcons ] as
@@ -54,7 +43,7 @@ function SectionIcon({ iconName }: { iconName?: string }) {
5443 return < IconComponent className = "h-5 w-5 text-muted-foreground" />
5544}
5645
57- function AdvancedSettingsButton ( {
46+ export function AdvancedSettingsButton ( {
5847 active,
5948 onClick,
6049} : {
@@ -74,59 +63,47 @@ function AdvancedSettingsButton({
7463}
7564
7665function DynamicConfigSection ( {
66+ advancedVisible,
7767 basePath,
7868 hooks,
7969 level,
8070 nestedSchema,
8171 onChange,
82- sectionDescription,
8372 sectionKey,
8473 sectionTitle,
8574 values,
8675} : {
76+ advancedVisible : boolean
8777 basePath : string
8878 hooks : FieldHookRegistry
8979 level : number
9080 nestedSchema : ConfigSchema
9181 onChange : ( field : string , value : unknown ) => void
92- sectionDescription ?: string
9382 sectionKey : string
9483 sectionTitle : string
9584 values : Record < string , unknown >
9685} ) {
97- const [ advancedVisible , setAdvancedVisible ] = React . useState ( false )
98- const hasAdvanced = hasTopLevelAdvancedFields ( nestedSchema )
99-
10086 return (
101- < Card >
102- < CardHeader className = "pb-4" >
87+ < Card className = "min-w-0" >
88+ < CardHeader className = "border-b border-border/50 pb-4" >
10389 < div className = "flex items-start justify-between gap-4" >
10490 < div className = "space-y-1" >
10591 < div className = "flex items-center gap-2" >
10692 < SectionIcon iconName = { nestedSchema . uiIcon } />
107- < CardTitle className = "text-lg" > { sectionTitle } </ CardTitle >
93+ < CardTitle className = "text-lg text-primary " > { sectionTitle } </ CardTitle >
10894 </ div >
109- { sectionDescription && (
110- < CardDescription > { sectionDescription } </ CardDescription >
111- ) }
11295 </ div >
113- { hasAdvanced && (
114- < AdvancedSettingsButton
115- active = { advancedVisible }
116- onClick = { ( ) => setAdvancedVisible ( ( current ) => ! current ) }
117- />
118- ) }
11996 </ div >
12097 </ CardHeader >
121- < CardContent >
98+ < CardContent className = "pt-4" >
12299 < DynamicConfigForm
123100 schema = { nestedSchema }
124101 values = { values }
125102 onChange = { ( field , value ) => onChange ( `${ sectionKey } .${ field } ` , value ) }
126103 basePath = { basePath }
127104 hooks = { hooks }
128105 level = { level }
129- advancedVisible = { hasAdvanced ? advancedVisible : undefined }
106+ advancedVisible = { advancedVisible }
130107 sectionColumns = { 1 }
131108 />
132109 </ CardContent >
@@ -154,8 +131,7 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
154131 advancedVisible,
155132 sectionColumns = 1 ,
156133} ) => {
157- const [ localAdvancedVisible , setLocalAdvancedVisible ] = React . useState ( false )
158- const resolvedAdvancedVisible = advancedVisible ?? localAdvancedVisible
134+ const resolvedAdvancedVisible = advancedVisible ?? false
159135
160136 const fieldMap = React . useMemo (
161137 ( ) => new Map ( schema . fields . map ( ( field ) => [ field . name , field ] ) ) ,
@@ -230,6 +206,51 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
230206 return hooks . get ( fieldPath ) ?. type === 'replace'
231207 }
232208
209+ const schemaHasVisibleContent = React . useCallback (
210+ ( targetSchema : ConfigSchema , targetBasePath : string ) : boolean => {
211+ const targetFields = targetSchema . fields ?? [ ]
212+ const hasVisibleInlineField = targetFields . some ( ( field ) => {
213+ const fieldPath = buildFieldPath ( targetBasePath , field . name )
214+ const hookEntry = hooks . get ( fieldPath )
215+
216+ if ( hookEntry ?. type === 'hidden' ) {
217+ return false
218+ }
219+
220+ if ( targetSchema . nested ?. [ field . name ] && hookEntry ?. type !== 'replace' ) {
221+ return false
222+ }
223+
224+ return resolvedAdvancedVisible || ! field . advanced
225+ } )
226+
227+ if ( hasVisibleInlineField ) {
228+ return true
229+ }
230+
231+ return Object . entries ( targetSchema . nested ?? { } ) . some ( ( [ key , nestedSchema ] ) => {
232+ const nestedField = targetFields . find ( ( field ) => field . name === key )
233+ const nestedFieldPath = buildFieldPath ( targetBasePath , key )
234+ const hookEntry = hooks . get ( nestedFieldPath )
235+
236+ if ( hookEntry ?. type === 'hidden' ) {
237+ return false
238+ }
239+
240+ if ( nestedField ?. advanced && ! resolvedAdvancedVisible ) {
241+ return false
242+ }
243+
244+ if ( hookEntry ?. type === 'replace' ) {
245+ return true
246+ }
247+
248+ return schemaHasVisibleContent ( nestedSchema , nestedFieldPath )
249+ } )
250+ } ,
251+ [ hooks , resolvedAdvancedVisible ] ,
252+ )
253+
233254 const inlineFields = schema . fields . filter ( shouldRenderFieldInline )
234255 const inlineNestedFieldNames = new Set (
235256 inlineFields
@@ -275,15 +296,15 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
275296 row . length > 1 ? (
276297 < div
277298 key = { row . map ( ( field ) => field . name ) . join ( '|' ) }
278- className = "grid gap-4 py-1 md:grid-cols-[repeat(var(--field-row-count),minmax(0,1fr))]"
299+ className = "grid min-w-0 gap-4 py-1 md:grid-cols-[repeat(var(--field-row-count),minmax(0,1fr))]"
279300 style = { { '--field-row-count' : row . length } as React . CSSProperties }
280301 >
281302 { row . map ( ( field ) => (
282- < div key = { field . name } > { renderField ( field ) } </ div >
303+ < div key = { field . name } className = "min-w-0" > { renderField ( field ) } </ div >
283304 ) ) }
284305 </ div >
285306 ) : (
286- < div key = { row [ 0 ] . name } className = "py-1" > { renderField ( row [ 0 ] ) } </ div >
307+ < div key = { row [ 0 ] . name } className = "min-w-0 py-1" > { renderField ( row [ 0 ] ) } </ div >
287308 )
288309 ) ) }
289310 </ >
@@ -301,17 +322,9 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
301322 )
302323
303324 return (
304- < div className = "space-y-6" >
305- { inlineFields . length > 0 && (
325+ < div className = "min-w-0 space-y-6" >
326+ { visibleFields . length > 0 && (
306327 < div >
307- { advancedVisible === undefined && advancedFields . length > 0 && (
308- < div className = "flex justify-end pb-2" >
309- < AdvancedSettingsButton
310- active = { localAdvancedVisible }
311- onClick = { ( ) => setLocalAdvancedVisible ( ( current ) => ! current ) }
312- />
313- </ div >
314- ) }
315328 { renderFieldList ( visibleFields ) }
316329 </ div >
317330 ) }
@@ -327,11 +340,20 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
327340 if ( hooks . has ( nestedFieldPath ) ) {
328341 const hookEntry = hooks . get ( nestedFieldPath )
329342 if ( ! hookEntry ) return null
343+ if ( hookEntry . type === 'hidden' ) return null
344+ if ( nestedField ?. advanced && ! resolvedAdvancedVisible ) return null
345+ if (
346+ hookEntry . type !== 'replace' &&
347+ nestedSchema &&
348+ ! schemaHasVisibleContent ( nestedSchema , nestedFieldPath )
349+ ) {
350+ return null
351+ }
330352
331353 const HookComponent = hookEntry . component
332354 if ( hookEntry . type === 'replace' ) {
333355 return (
334- < div key = { key } >
356+ < div key = { key } className = "min-w-0" >
335357 < HookComponent
336358 fieldPath = { nestedFieldPath }
337359 value = { values [ key ] }
@@ -346,7 +368,7 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
346368 }
347369
348370 return (
349- < div key = { key } >
371+ < div key = { key } className = "min-w-0" >
350372 < HookComponent
351373 fieldPath = { nestedFieldPath }
352374 value = { values [ key ] }
@@ -363,6 +385,7 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
363385 basePath = { nestedFieldPath }
364386 hooks = { hooks }
365387 level = { level + 1 }
388+ advancedVisible = { resolvedAdvancedVisible }
366389 sectionColumns = { 1 }
367390 />
368391 </ HookComponent >
@@ -371,12 +394,15 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
371394 }
372395
373396 const sectionTitle = resolveSectionTitle ( nestedSchema )
374- const sectionDescription = resolveSectionDescription ( nestedSchema , sectionTitle )
397+ if ( ! schemaHasVisibleContent ( nestedSchema , nestedFieldPath ) ) {
398+ return null
399+ }
375400
376401 if ( level === 0 ) {
377402 return (
378403 < DynamicConfigSection
379404 key = { key }
405+ advancedVisible = { resolvedAdvancedVisible }
380406 nestedSchema = { nestedSchema }
381407 values = { ( values [ key ] as Record < string , unknown > ) || { } }
382408 onChange = { onChange }
@@ -385,36 +411,31 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
385411 level = { level + 1 }
386412 sectionKey = { key }
387413 sectionTitle = { sectionTitle }
388- sectionDescription = { sectionDescription }
389414 />
390415 )
391416 }
392417
393418 return (
394- < Card key = { key } className = "border-border/70 bg-muted/20 shadow-none" >
395- < CardHeader className = "px-4 py-3" >
419+ < Card key = { key } className = "min-w-0 border-border/70 bg-muted/20 shadow-none" >
420+ < CardHeader className = "border-b border-border/50 px-4 py-3" >
396421 < div className = "flex items-start justify-between gap-4" >
397422 < div className = "space-y-1" >
398423 < div className = "flex items-center gap-2" >
399424 < SectionIcon iconName = { nestedSchema . uiIcon } />
400- < CardTitle className = "text-sm" > { sectionTitle } </ CardTitle >
425+ < CardTitle className = "text-sm text-primary " > { sectionTitle } </ CardTitle >
401426 </ div >
402- { sectionDescription && (
403- < CardDescription className = "text-xs" >
404- { sectionDescription }
405- </ CardDescription >
406- ) }
407427 </ div >
408428 </ div >
409429 </ CardHeader >
410- < CardContent className = "px-4 pb-4 pt-0 " >
430+ < CardContent className = "px-4 pb-4 pt-4 " >
411431 < DynamicConfigForm
412432 schema = { nestedSchema }
413433 values = { ( values [ key ] as Record < string , unknown > ) || { } }
414434 onChange = { ( field , value ) => onChange ( `${ key } .${ field } ` , value ) }
415435 basePath = { nestedFieldPath }
416436 hooks = { hooks }
417437 level = { level + 1 }
438+ advancedVisible = { resolvedAdvancedVisible }
418439 sectionColumns = { 1 }
419440 />
420441 </ CardContent >
@@ -428,7 +449,7 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
428449
429450 if ( level === 0 && sectionColumns === 2 && visibleNestedSections . length > 1 ) {
430451 return (
431- < div className = "grid gap-4 md:grid-cols-2" >
452+ < div className = "grid min-w-0 gap-4 md:grid-cols-2" >
432453 { visibleNestedSections }
433454 </ div >
434455 )
0 commit comments