11import { DocumentBlock , JSONDocument } from '@gitbook/api' ;
2- import assertNever from 'assert-never' ;
32import React from 'react' ;
43
54import {
@@ -42,6 +41,9 @@ export interface BlockProps<Block extends DocumentBlock> extends DocumentContext
4241 block : Block ;
4342 document : JSONDocument ;
4443 ancestorBlocks : DocumentBlock [ ] ;
44+ /** If true, we estimate that the block will be outside the initial viewport */
45+ isEstimatedOffscreen : boolean ;
46+ /** Class names to be passed to the underlying DOM element */
4547 style ?: ClassValue ;
4648}
4749
@@ -53,79 +55,88 @@ function nullIfNever(value: never): null {
5355}
5456
5557export function Block < T extends DocumentBlock > ( props : BlockProps < T > ) {
56- const { block, style, ... contextProps } = props ;
58+ const { block, style, isEstimatedOffscreen , context } = props ;
5759
5860 const content = ( ( ) => {
5961 switch ( block . type ) {
6062 case 'paragraph' :
61- return < Paragraph { ...props } { ... contextProps } block = { block } /> ;
63+ return < Paragraph { ...props } block = { block } /> ;
6264 case 'heading-1' :
6365 case 'heading-2' :
6466 case 'heading-3' :
65- return < Heading { ...props } { ... contextProps } block = { block } /> ;
67+ return < Heading { ...props } block = { block } /> ;
6668 case 'list-ordered' :
67- return < ListOrdered { ...props } { ... contextProps } block = { block } /> ;
69+ return < ListOrdered { ...props } block = { block } /> ;
6870 case 'list-unordered' :
69- return < ListUnordered { ...props } { ... contextProps } block = { block } /> ;
71+ return < ListUnordered { ...props } block = { block } /> ;
7072 case 'list-tasks' :
71- return < ListTasks { ...props } { ... contextProps } block = { block } /> ;
73+ return < ListTasks { ...props } block = { block } /> ;
7274 case 'list-item' :
73- return < ListItem { ...props } { ... contextProps } block = { block } /> ;
75+ return < ListItem { ...props } block = { block } /> ;
7476 case 'code' :
75- return < CodeBlock { ...props } { ... contextProps } block = { block } /> ;
77+ return < CodeBlock { ...props } block = { block } /> ;
7678 case 'hint' :
77- return < Hint { ...props } { ... contextProps } block = { block } /> ;
79+ return < Hint { ...props } block = { block } /> ;
7880 case 'images' :
79- return < Images { ...props } { ... contextProps } block = { block } /> ;
81+ return < Images { ...props } block = { block } /> ;
8082 case 'tabs' :
81- return < Tabs { ...props } { ... contextProps } block = { block } /> ;
83+ return < Tabs { ...props } block = { block } /> ;
8284 case 'expandable' :
83- return < Expandable { ...props } { ... contextProps } block = { block } /> ;
85+ return < Expandable { ...props } block = { block } /> ;
8486 case 'table' :
85- return < Table { ...props } { ... contextProps } block = { block } /> ;
87+ return < Table { ...props } block = { block } /> ;
8688 case 'swagger' :
87- return < OpenAPI { ...props } { ... contextProps } block = { block } /> ;
89+ return < OpenAPI { ...props } block = { block } /> ;
8890 case 'embed' :
89- return < Embed { ...props } { ... contextProps } block = { block } /> ;
91+ return < Embed { ...props } block = { block } /> ;
9092 case 'blockquote' :
91- return < Quote { ...props } { ... contextProps } block = { block } /> ;
93+ return < Quote { ...props } block = { block } /> ;
9294 case 'math' :
93- return < BlockMath { ...props } { ... contextProps } block = { block } /> ;
95+ return < BlockMath { ...props } block = { block } /> ;
9496 case 'file' :
95- return < File { ...props } { ... contextProps } block = { block } /> ;
97+ return < File { ...props } block = { block } /> ;
9698 case 'divider' :
97- return < Divider { ...props } { ... contextProps } block = { block } /> ;
99+ return < Divider { ...props } block = { block } /> ;
98100 case 'drawing' :
99- return < Drawing { ...props } { ... contextProps } block = { block } /> ;
101+ return < Drawing { ...props } block = { block } /> ;
100102 case 'content-ref' :
101- return < BlockContentRef { ...props } { ... contextProps } block = { block } /> ;
103+ return < BlockContentRef { ...props } block = { block } /> ;
102104 case 'image' :
103105 case 'code-line' :
104106 case 'tabs-item' :
105107 throw new Error ( 'Blocks should be directly rendered by parent' ) ;
106108 case 'integration' :
107- return < IntegrationBlock { ...props } { ... contextProps } block = { block } /> ;
109+ return < IntegrationBlock { ...props } block = { block } /> ;
108110 case 'synced-block' :
109- return < BlockSyncedBlock { ...props } { ... contextProps } block = { block } /> ;
111+ return < BlockSyncedBlock { ...props } block = { block } /> ;
110112 case 'reusable-content' :
111- return < ReusableContent { ...props } { ... contextProps } block = { block } /> ;
113+ return < ReusableContent { ...props } block = { block } /> ;
112114 case 'stepper' :
113- return < Stepper { ...props } { ... contextProps } block = { block } /> ;
115+ return < Stepper { ...props } block = { block } /> ;
114116 case 'stepper-step' :
115- return < StepperStep { ...props } { ... contextProps } block = { block } /> ;
117+ return < StepperStep { ...props } block = { block } /> ;
116118 default :
117119 return nullIfNever ( block ) ;
118120 }
119121 } ) ( ) ;
120122
123+ if ( ! isEstimatedOffscreen || context . wrapBlocksInSuspense === false ) {
124+ // When blocks are estimated to be on the initial viewport, we render them immediately
125+ // to avoid a flash of a loading skeleton.
126+ return content ;
127+ }
128+
121129 return (
122- < React . Suspense fallback = { < BlockPlaceholder block = { block } style = { style } /> } >
130+ < React . Suspense fallback = { < BlockSkeleton block = { block } style = { style } /> } >
123131 { content }
124132 </ React . Suspense >
125133 ) ;
126134}
127135
128- function BlockPlaceholder ( props : { block : DocumentBlock ; style : ClassValue } ) {
136+ /**
137+ * Skeleton for a block while it is being loaded.
138+ */
139+ export function BlockSkeleton ( props : { block : DocumentBlock ; style : ClassValue } ) {
129140 const { block, style } = props ;
130141 const id = 'meta' in block && block . meta && 'id' in block . meta ? block . meta . id : undefined ;
131142
0 commit comments