11import { tcls } from '@/lib/tailwind' ;
22import { type DocumentBlockColumns , type Length , VerticalAlignment } from '@gitbook/api' ;
3+ import React from 'react' ;
34import type { BlockProps } from '../Block' ;
45import { Blocks } from '../Blocks' ;
56
67export function Columns ( props : BlockProps < DocumentBlockColumns > ) {
78 const { block, style, ancestorBlocks, document, context } = props ;
9+
10+ const columnWidths = React . useMemo ( ( ) => {
11+ const widths = block . nodes . map ( ( block ) => {
12+ const width = block . data . width ;
13+ return width ? getFractionalWidth ( width ) : 0 ;
14+ } ) ;
15+
16+ const totalWidth = widths . reduce < number > ( ( acc , width ) => acc + width , 0 ) ;
17+ // If not all columns widths are set, distribute the remaining widths as equally as we can
18+ if ( totalWidth < 1.0 && widths . some ( ( width ) => width === 0 ) ) {
19+ const unsetWidths = widths . filter ( ( width ) => width === 0 ) ;
20+ let remainingWidth = 1.0 - totalWidth ;
21+ let unsetWidthsLength = unsetWidths . length ;
22+ widths . forEach ( ( width , index ) => {
23+ if ( width === 0 ) {
24+ const calculatedWidth =
25+ Math . round ( ( remainingWidth / unsetWidthsLength ) * COLUMN_DIVISIONS ) /
26+ COLUMN_DIVISIONS ;
27+ widths [ index ] = calculatedWidth ; // Assign width to empty columns
28+ unsetWidthsLength -- ;
29+ remainingWidth -= calculatedWidth ;
30+ }
31+ } ) ;
32+ }
33+ return widths ;
34+ } , [ block . nodes ] ) ;
35+
836 return (
9- < div className = { tcls ( 'flex flex-col gap-x-8 md:flex-row' , style ) } >
10- { block . nodes . map ( ( columnBlock ) => {
37+ < div
38+ className = { tcls (
39+ 'grid w-full grid-cols-1 gap-x-8 gap-y-4 md:grid-flow-col md:grid-cols-[repeat(var(--grid-slices),minmax(0,1fr))] md:grid-rows-1' ,
40+ style
41+ ) }
42+ style = { { '--grid-slices' : COLUMN_DIVISIONS } as React . CSSProperties }
43+ >
44+ { block . nodes . map ( ( columnBlock , index ) => {
45+ const columnWidth = columnWidths [ index ] ;
1146 return (
1247 < Column
1348 key = { columnBlock . key }
14- width = { columnBlock . data . width }
49+ width = {
50+ columnBlock . data . width ??
51+ ( columnWidth
52+ ? { value : columnWidth * 100 , unit : '%' }
53+ : { value : 0 , unit : '%' } )
54+ }
1555 verticalAlignment = { columnBlock . data . verticalAlignment }
1656 >
1757 < Blocks
@@ -31,11 +71,11 @@ export function Columns(props: BlockProps<DocumentBlockColumns>) {
3171
3272export function Column ( props : {
3373 children ?: React . ReactNode ;
34- width ? : Length ;
74+ width : Length ;
3575 verticalAlignment ?: VerticalAlignment ;
3676} ) {
3777 const { width, verticalAlignment } = props ;
38- const { className, style } = transformLengthToCSS ( width ) ;
78+ const { className, style } = transformLengthToCSS ( width ) ?? { } ;
3979 return (
4080 < div
4181 className = { tcls (
@@ -53,41 +93,25 @@ export function Column(props: {
5393 ) ;
5494}
5595
56- function transformLengthToCSS ( length : Length | undefined ) {
57- if ( ! length ) {
58- return { className : [ 'md:w-full' ] } ; // default to full width if no length is specified
59- }
96+ const COLUMN_DIVISIONS = 12 ;
6097
98+ export function transformLengthToCSS ( length : Length ) {
6199 if ( typeof length === 'number' ) {
62- return { style : undefined } ; // not implemented yet with non-percentage lengths
100+ return ; // not implemented yet with non-percentage lengths
63101 }
64-
65102 if ( length . unit === '%' ) {
66103 return {
67- className : [
68- 'md:shrink-0' ,
69- COLUMN_WIDTHS [ Math . round ( length . value * 0.01 * ( COLUMN_WIDTHS . length - 1 ) ) ] ,
70- ] ,
104+ className : 'md:flex-shrink-0 md:[grid-column:var(--grid-col)]' ,
105+ style : {
106+ '--grid-col' : `auto / span ${ Math . round ( length . value * 0.01 * COLUMN_DIVISIONS ) } ` ,
107+ } as React . CSSProperties ,
71108 } ;
72109 }
73-
74- return { style : undefined } ; // not implemented yet with non-percentage lengths
75110}
76111
77- // Tailwind CSS classes for column widths.
78- // The index of the array corresponds to the percentage width of the column.
79- const COLUMN_WIDTHS = [
80- 'md:w-0' ,
81- 'md:w-1/12' ,
82- 'md:w-2/12' ,
83- 'md:w-3/12' ,
84- 'md:w-4/12' ,
85- 'md:w-5/12' ,
86- 'md:w-6/12' ,
87- 'md:w-7/12' ,
88- 'md:w-8/12' ,
89- 'md:w-9/12' ,
90- 'md:w-10/12' ,
91- 'md:w-11/12' ,
92- 'md:w-full' ,
93- ] ;
112+ function getFractionalWidth ( length : Length ) {
113+ if ( typeof length === 'number' ) {
114+ return 0 ;
115+ }
116+ return length . value / 100 ;
117+ }
0 commit comments