@@ -334,11 +334,77 @@ ComponentRegistry.register('form',
334334 // Resolve the component type: prefer widget override, fallback to field type
335335 const resolvedType = widget || type ;
336336
337- // colSpan classes for grid layout
337+ // colSpan classes for grid layout.
338+ //
339+ // When the container uses container-query-based grid classes
340+ // (e.g. `@md:grid-cols-2`), the grid's base is `grid-cols-1`
341+ // on narrow containers. Applying a bare `col-span-2` in that
342+ // state causes CSS grid to synthesize an implicit 2nd column
343+ // track, distorting column widths. We must mirror the same
344+ // container-query prefix on the col-span utilities so they
345+ // only engage once the grid is actually multi-column.
346+ // The effective container is whatever wraps the fields: either
347+ // `fieldContainerClass` (overrides, typically container-query based)
348+ // or the locally-computed `gridClass` (viewport-based).
349+ const containerClass = schema . fieldContainerClass || gridClass ;
350+ // Match both container-query (`@md:`) and viewport (`md:`) prefixes.
351+ // Return an explicit, statically-detectable class so Tailwind JIT
352+ // can scan and include it.
353+ const pickSpanClass = ( targetCols : number ) : string => {
354+ const re = / ( @ ) ? ( s m | m d | l g | x l | 2 x l | 3 x l | 4 x l | 5 x l | 6 x l | 7 x l ) : g r i d - c o l s - ( \d + ) / g;
355+ const matches = Array . from ( containerClass . matchAll ( re ) ) . map ( m => ( {
356+ at : m [ 1 ] || '' ,
357+ bp : m [ 2 ] ,
358+ cols : Number ( m [ 3 ] ) ,
359+ } ) ) ;
360+ if ( ! matches . length ) {
361+ // No responsive/container prefix found — bare class is safe
362+ // because the grid is already multi-column at all widths.
363+ if ( targetCols === 2 ) return 'col-span-2' ;
364+ if ( targetCols === 3 ) return 'col-span-3' ;
365+ return 'col-span-4' ;
366+ }
367+ const hit = matches . find ( m => m . cols >= targetCols ) || matches [ matches . length - 1 ] ;
368+ const key = `${ hit . at } ${ hit . bp } :${ targetCols } ` ;
369+ // Explicit literal map so Tailwind JIT discovers these classes.
370+ const table : Record < string , string > = {
371+ '@sm:2' : '@sm:col-span-2' ,
372+ '@md:2' : '@md:col-span-2' ,
373+ '@lg:2' : '@lg:col-span-2' ,
374+ '@xl:2' : '@xl:col-span-2' ,
375+ '@2xl:2' : '@2xl:col-span-2' ,
376+ '@sm:3' : '@sm:col-span-3' ,
377+ '@md:3' : '@md:col-span-3' ,
378+ '@lg:3' : '@lg:col-span-3' ,
379+ '@xl:3' : '@xl:col-span-3' ,
380+ '@2xl:3' : '@2xl:col-span-3' ,
381+ '@4xl:3' : '@4xl:col-span-3' ,
382+ '@sm:4' : '@sm:col-span-4' ,
383+ '@md:4' : '@md:col-span-4' ,
384+ '@lg:4' : '@lg:col-span-4' ,
385+ '@xl:4' : '@xl:col-span-4' ,
386+ '@2xl:4' : '@2xl:col-span-4' ,
387+ '@4xl:4' : '@4xl:col-span-4' ,
388+ 'sm:2' : 'sm:col-span-2' ,
389+ 'md:2' : 'md:col-span-2' ,
390+ 'lg:2' : 'lg:col-span-2' ,
391+ 'xl:2' : 'xl:col-span-2' ,
392+ 'sm:3' : 'sm:col-span-3' ,
393+ 'md:3' : 'md:col-span-3' ,
394+ 'lg:3' : 'lg:col-span-3' ,
395+ 'xl:3' : 'xl:col-span-3' ,
396+ 'sm:4' : 'sm:col-span-4' ,
397+ 'md:4' : 'md:col-span-4' ,
398+ 'lg:4' : 'lg:col-span-4' ,
399+ 'xl:4' : 'xl:col-span-4' ,
400+ } ;
401+ return table [ key ] || ( targetCols === 2 ? 'col-span-2' : targetCols === 3 ? 'col-span-3' : 'col-span-4' ) ;
402+ } ;
403+
338404 const colSpanClass = colSpan && colSpan > 1
339- ? colSpan === 2 ? 'col-span-2'
340- : colSpan === 3 ? 'col-span-3'
341- : colSpan >= 4 ? 'col-span-4'
405+ ? colSpan === 2 ? pickSpanClass ( 2 )
406+ : colSpan === 3 ? pickSpanClass ( 3 )
407+ : colSpan >= 4 ? pickSpanClass ( 4 )
342408 : ''
343409 : '' ;
344410
0 commit comments