@@ -14,6 +14,7 @@ import {
1414 Display ,
1515 Edge ,
1616 FlexDirection ,
17+ GridTrackType ,
1718 Gutter ,
1819 Justify ,
1920 Overflow ,
@@ -63,7 +64,7 @@ export type FlexStyle = {
6364 bottom ?: number | `${number } %`;
6465 boxSizing ?: 'border-box' | 'content-box' ;
6566 direction ?: 'ltr' | 'rtl' ;
66- display ?: 'none' | 'flex' | 'contents' ;
67+ display ?: 'none' | 'flex' | 'contents' | 'grid' ;
6768 end ?: number | `${number } %`;
6869 flex ?: number ;
6970 flexBasis ?: number | 'auto' | `${number } %`;
@@ -108,6 +109,15 @@ export type FlexStyle = {
108109 insetBlock ?: number | `${number } %`;
109110 inset ?: number | `${number } %`;
110111 width ?: number | 'auto' | `${number } %`;
112+ // Grid properties
113+ gridTemplateColumns ?: string ;
114+ gridTemplateRows ?: string ;
115+ gridAutoColumns ?: string ;
116+ gridAutoRows ?: string ;
117+ gridColumnStart ?: number | `span ${number } `;
118+ gridColumnEnd ?: number | `span ${number } `;
119+ gridRowStart ?: number | `span ${number } `;
120+ gridRowEnd ?: number | `span ${number } `;
111121} ;
112122
113123export function applyStyle ( node : YogaNode , style : FlexStyle = { } ) : void {
@@ -297,6 +307,64 @@ export function applyStyle(node: YogaNode, style: FlexStyle = {}): void {
297307 case 'width' :
298308 node . setWidth ( style . width ) ;
299309 break ;
310+ case 'gridTemplateColumns' :
311+ node . setGridTemplateColumns (
312+ parseGridTemplate ( style . gridTemplateColumns ) ,
313+ ) ;
314+ break ;
315+ case 'gridTemplateRows' :
316+ node . setGridTemplateRows ( parseGridTemplate ( style . gridTemplateRows ) ) ;
317+ break ;
318+ case 'gridAutoColumns' :
319+ node . setGridAutoColumns ( parseGridTemplate ( style . gridAutoColumns ) ) ;
320+ break ;
321+ case 'gridAutoRows' :
322+ node . setGridAutoRows ( parseGridTemplate ( style . gridAutoRows ) ) ;
323+ break ;
324+ case 'gridColumnStart' :
325+ if (
326+ typeof style . gridColumnStart === 'string' &&
327+ style . gridColumnStart . startsWith ( 'span ' )
328+ ) {
329+ node . setGridColumnStartSpan (
330+ parseInt ( style . gridColumnStart . slice ( 5 ) , 10 ) ,
331+ ) ;
332+ } else {
333+ node . setGridColumnStart ( style . gridColumnStart as number ) ;
334+ }
335+ break ;
336+ case 'gridColumnEnd' :
337+ if (
338+ typeof style . gridColumnEnd === 'string' &&
339+ style . gridColumnEnd . startsWith ( 'span ' )
340+ ) {
341+ node . setGridColumnEndSpan (
342+ parseInt ( style . gridColumnEnd . slice ( 5 ) , 10 ) ,
343+ ) ;
344+ } else {
345+ node . setGridColumnEnd ( style . gridColumnEnd as number ) ;
346+ }
347+ break ;
348+ case 'gridRowStart' :
349+ if (
350+ typeof style . gridRowStart === 'string' &&
351+ style . gridRowStart . startsWith ( 'span ' )
352+ ) {
353+ node . setGridRowStartSpan ( parseInt ( style . gridRowStart . slice ( 5 ) , 10 ) ) ;
354+ } else {
355+ node . setGridRowStart ( style . gridRowStart as number ) ;
356+ }
357+ break ;
358+ case 'gridRowEnd' :
359+ if (
360+ typeof style . gridRowEnd === 'string' &&
361+ style . gridRowEnd . startsWith ( 'span ' )
362+ ) {
363+ node . setGridRowEndSpan ( parseInt ( style . gridRowEnd . slice ( 5 ) , 10 ) ) ;
364+ } else {
365+ node . setGridRowEnd ( style . gridRowEnd as number ) ;
366+ }
367+ break ;
300368 }
301369 } catch ( e ) {
302370 // Fail gracefully
@@ -360,14 +428,16 @@ function direction(str?: 'ltr' | 'rtl'): Direction {
360428 throw new Error ( `"${ str } " is not a valid value for direction` ) ;
361429}
362430
363- function display ( str ?: 'none' | 'flex' | 'contents' ) : Display {
431+ function display ( str ?: 'none' | 'flex' | 'contents' | 'grid' ) : Display {
364432 switch ( str ) {
365433 case 'none' :
366434 return Display . None ;
367435 case 'flex' :
368436 return Display . Flex ;
369437 case 'contents' :
370438 return Display . Contents ;
439+ case 'grid' :
440+ return Display . Grid ;
371441 }
372442 throw new Error ( `"${ str } " is not a valid value for display` ) ;
373443}
@@ -441,3 +511,75 @@ function position(str?: 'absolute' | 'relative' | 'static'): PositionType {
441511 }
442512 throw new Error ( `"${ str } " is not a valid value for position` ) ;
443513}
514+
515+ type GridTrackValue = {
516+ type : GridTrackType ;
517+ value ?: number ;
518+ min ?: GridTrackValue ;
519+ max ?: GridTrackValue ;
520+ } ;
521+
522+ function parseGridTrackValue ( track : string ) : GridTrackValue {
523+ track = track . trim ( ) ;
524+
525+ if ( track === 'auto' ) {
526+ return { type : GridTrackType . Auto } ;
527+ }
528+
529+ if ( track . endsWith ( 'fr' ) ) {
530+ return { type : GridTrackType . Fr , value : parseFloat ( track ) } ;
531+ }
532+
533+ if ( track . endsWith ( '%' ) ) {
534+ return { type : GridTrackType . Percent , value : parseFloat ( track ) } ;
535+ }
536+
537+ if ( track . endsWith ( 'px' ) ) {
538+ return { type : GridTrackType . Points , value : parseFloat ( track ) } ;
539+ }
540+
541+ if ( track . startsWith ( 'minmax(' ) && track . endsWith ( ')' ) ) {
542+ const inner = track . slice ( 7 , - 1 ) ;
543+ const commaIndex = findTopLevelComma ( inner ) ;
544+ if ( commaIndex === - 1 ) {
545+ throw new Error ( `Invalid minmax syntax: ${ track } ` ) ;
546+ }
547+ const minPart = inner . slice ( 0 , commaIndex ) . trim ( ) ;
548+ const maxPart = inner . slice ( commaIndex + 1 ) . trim ( ) ;
549+ return {
550+ type : GridTrackType . Minmax ,
551+ min : parseGridTrackValue ( minPart ) ,
552+ max : parseGridTrackValue ( maxPart ) ,
553+ } ;
554+ }
555+
556+ const num = parseFloat ( track ) ;
557+ if ( ! isNaN ( num ) ) {
558+ return { type : GridTrackType . Points , value : num } ;
559+ }
560+
561+ throw new Error ( `Invalid grid track value: ${ track } ` ) ;
562+ }
563+
564+ function findTopLevelComma ( str : string ) : number {
565+ let depth = 0 ;
566+ for ( let i = 0 ; i < str . length ; i ++ ) {
567+ if ( str [ i ] === '(' ) depth ++ ;
568+ else if ( str [ i ] === ')' ) depth -- ;
569+ else if ( str [ i ] === ',' && depth === 0 ) return i ;
570+ }
571+ return - 1 ;
572+ }
573+
574+ function parseGridTemplate ( template ?: string ) : GridTrackValue [ ] {
575+ if ( ! template ) return [ ] ;
576+
577+ const tracks : GridTrackValue [ ] = [ ] ;
578+ const parts = template . trim ( ) . split ( / \s + / ) ;
579+
580+ for ( const part of parts ) {
581+ tracks . push ( parseGridTrackValue ( part ) ) ;
582+ }
583+
584+ return tracks ;
585+ }
0 commit comments