@@ -418,6 +418,7 @@ function buildHeading(
418418
419419function projectTable ( pmNode : ProseMirrorNode ) : SDTable {
420420 const attrs = pmNode . attrs as TableAttrs | undefined ;
421+ const pmAttrs = pmNode . attrs as Record < string , unknown > ;
421422 const rows : SDTableRow [ ] = [ ] ;
422423
423424 pmNode . forEach ( ( child ) => {
@@ -432,14 +433,31 @@ function projectTable(pmNode: ProseMirrorNode): SDTable {
432433 table : { rows } ,
433434 } ;
434435
435- const styleRef = attrs ?. tableProperties ?. tableStyleId ?? ( pmNode . attrs as any ) ?. tableStyleId ;
436+ const styleRef = attrs ?. tableProperties ?. tableStyleId ?? ( pmAttrs as any ) ?. tableStyleId ;
436437 if ( styleRef ) result . table . styleRef = styleRef ;
437438
438- const gridModel = ( pmNode . attrs as any ) ?. tableGridModel ?? attrs ?. tableGrid ?. colWidths ;
439+ const props = extractTableProps ( attrs , pmAttrs ) ;
440+ if ( props ) result . table . props = props ;
441+
442+ const gridModel = ( pmAttrs as any ) ?. grid ?? ( pmAttrs as any ) ?. tableGridModel ?? attrs ?. tableGrid ?. colWidths ;
439443 if ( gridModel && Array . isArray ( gridModel ) ) {
440- result . table . columns = gridModel . map ( ( item : any ) => ( {
441- width : typeof item === 'number' ? item : ( item ?. col ?? item ?. width ) ,
442- } ) ) ;
444+ const columns = gridModel
445+ . map ( ( item : any ) => ( typeof item === 'number' ? item : ( item ?. col ?? item ?. width ) ) )
446+ . filter ( ( width : unknown ) : width is number => typeof width === 'number' && Number . isFinite ( width ) )
447+ . map ( ( width : number ) => ( { width } ) ) ;
448+ if ( columns . length > 0 ) {
449+ result . table . columns = columns ;
450+ }
451+ }
452+
453+ if ( ( pmAttrs as any ) ?. needsTableStyleNormalization === true ) {
454+ const ext = isRecord ( result . ext ) ? { ...result . ext } : { } ;
455+ const superdocExt = isRecord ( ext . superdoc ) ? { ...( ext . superdoc as Record < string , unknown > ) } : { } ;
456+ superdocExt . needsTableStyleNormalization = true ;
457+ result . ext = {
458+ ...ext ,
459+ superdoc : superdocExt ,
460+ } ;
443461 }
444462
445463 return result ;
@@ -986,6 +1004,82 @@ function resolveNodeId(pmNode: ProseMirrorNode): string | undefined {
9861004 return typeof id === 'string' && id . length > 0 ? id : undefined ;
9871005}
9881006
1007+ function isRecord ( value : unknown ) : value is Record < string , unknown > {
1008+ return value !== null && typeof value === 'object' && ! Array . isArray ( value ) ;
1009+ }
1010+
1011+ function extractTableProps (
1012+ attrs : TableAttrs | undefined ,
1013+ pmAttrs : Record < string , unknown > ,
1014+ ) : SDTable [ 'table' ] [ 'props' ] | undefined {
1015+ const tableProps = attrs ?. tableProperties as Record < string , unknown > | null | undefined ;
1016+ const props : NonNullable < SDTable [ 'table' ] [ 'props' ] > = { } ;
1017+ let hasProps = false ;
1018+
1019+ const width = extractTableWidth ( ( tableProps as any ) ?. tableWidth ?? ( pmAttrs as any ) ?. tableWidth ) ;
1020+ if ( width ) {
1021+ props . width = width ;
1022+ hasProps = true ;
1023+ }
1024+
1025+ const layout = ( tableProps as any ) ?. tableLayout ?? ( pmAttrs as any ) ?. tableLayout ;
1026+ if ( layout === 'fixed' || layout === 'autofit' ) {
1027+ props . layout = layout ;
1028+ hasProps = true ;
1029+ }
1030+
1031+ const alignment = mapTableAlignmentToSD ( ( tableProps as any ) ?. justification ?? ( pmAttrs as any ) ?. justification ) ;
1032+ if ( alignment ) {
1033+ props . alignment = alignment ;
1034+ hasProps = true ;
1035+ }
1036+
1037+ return hasProps ? props : undefined ;
1038+ }
1039+
1040+ function mapTableAlignmentToSD ( value : unknown ) : NonNullable < SDTable [ 'table' ] [ 'props' ] > [ 'alignment' ] | undefined {
1041+ if ( typeof value !== 'string' ) return undefined ;
1042+ switch ( value ) {
1043+ case 'start' :
1044+ case 'left' :
1045+ return 'left' ;
1046+ case 'end' :
1047+ case 'right' :
1048+ return 'right' ;
1049+ case 'center' :
1050+ case 'inside' :
1051+ case 'outside' :
1052+ return value ;
1053+ default :
1054+ return undefined ;
1055+ }
1056+ }
1057+
1058+ function extractTableWidth ( width : unknown ) : NonNullable < SDTable [ 'table' ] [ 'props' ] > [ 'width' ] | undefined {
1059+ if ( ! isRecord ( width ) ) return undefined ;
1060+
1061+ const type = typeof width . type === 'string' ? width . type . toLowerCase ( ) : undefined ;
1062+ const value =
1063+ typeof width . value === 'number' ? width . value : typeof width . width === 'number' ? width . width : undefined ;
1064+
1065+ if ( type === 'auto' ) {
1066+ return { kind : 'auto' } ;
1067+ }
1068+ if ( type === 'nil' || type === 'none' ) {
1069+ return { kind : 'none' } ;
1070+ }
1071+ if ( type === 'pct' && typeof value === 'number' && Number . isFinite ( value ) ) {
1072+ return { kind : 'percent' , value } ;
1073+ }
1074+ if ( type === 'dxa' && typeof value === 'number' && Number . isFinite ( value ) ) {
1075+ return { kind : 'points' , value : value / 20 } ;
1076+ }
1077+ if ( typeof value === 'number' && Number . isFinite ( value ) ) {
1078+ return { kind : 'points' , value } ;
1079+ }
1080+ return undefined ;
1081+ }
1082+
9891083// ---------------------------------------------------------------------------
9901084// Helpers: paragraph properties extraction
9911085// ---------------------------------------------------------------------------
0 commit comments