11import * as React from 'react' ;
22import { Converter } from 'showdown' ;
33import { QuickStartContext , QuickStartContextValues } from '../../utils/quick-start-context' ;
4- // import _truncate from 'lodash-es/truncate.js';
5- // import _uniqueId from 'lodash-es/uniqueId.js';
64import cx from 'classnames' ;
5+ import { useForceRender } from '@console/shared' ;
76
87import './_markdown-view.scss' ;
98
@@ -97,18 +96,11 @@ export const SyncMarkdownView: React.FC<SyncMarkdownProps> = ({
9796} ) => {
9897 const { getResource } = React . useContext < QuickStartContextValues > ( QuickStartContext ) ;
9998 const markup = React . useMemo ( ( ) => {
100- const truncatedContent = /*truncateContent
101- ? _truncate(content, {
102- length: 256,
103- separator: ' ',
104- omission: '\u2026',
105- })
106- : */ content ;
10799 return markdownConvert (
108- truncatedContent || emptyMsg || getResource ( 'Not available' ) ,
100+ content || emptyMsg || getResource ( 'Not available' ) ,
109101 extensions ,
110102 ) ;
111- } , [ content , emptyMsg , extensions , getResource /*, truncateContent*/ ] ) ;
103+ } , [ content , emptyMsg , extensions , getResource ] ) ;
112104 const innerProps : InnerSyncMarkdownProps = {
113105 renderExtension : extensions ?. length > 0 ? renderExtension : undefined ,
114106 exactHeight,
@@ -128,6 +120,43 @@ const uniqueId = (function () {
128120 } ;
129121} ) ( ) ;
130122
123+ type RenderExtensionProps = {
124+ renderExtension : ( contentDocument : HTMLDocument , rootSelector : string ) => React . ReactNode ;
125+ selector : string ;
126+ markup : string ;
127+ docContext ?: HTMLDocument ;
128+ } ;
129+
130+ const RenderExtension : React . FC < RenderExtensionProps > = ( {
131+ renderExtension,
132+ selector,
133+ markup,
134+ docContext,
135+ } ) => {
136+ const forceRender = useForceRender ( ) ;
137+ const markupRef = React . useRef < string > ( null ) ;
138+ const shouldRenderExtension = React . useCallback ( ( ) => {
139+ if ( markupRef . current === markup ) {
140+ return true ;
141+ }
142+ markupRef . current = markup ;
143+ return false ;
144+ } , [ markup ] ) ;
145+ /**
146+ * During a render cycle in which markup changes, renderExtension receives an old copy of document
147+ * because react is still updating the dom using `dangerouslySetInnerHTML` with latest markdown markup
148+ * which causes the component rendered by renderExtension to receive old copy of document
149+ * use forceRender to delay the rendering of extension by one render cycle
150+ */
151+ React . useEffect ( ( ) => {
152+ renderExtension && forceRender ( ) ;
153+ // eslint-disable-next-line react-hooks/exhaustive-deps
154+ } , [ markup ] ) ;
155+ return (
156+ < > { shouldRenderExtension ( ) ? renderExtension ?.( docContext ?? document , selector ) : null } </ >
157+ ) ;
158+ } ;
159+
131160const InlineMarkdownView : React . FC < InnerSyncMarkdownProps > = ( {
132161 markup,
133162 isEmpty,
@@ -138,7 +167,7 @@ const InlineMarkdownView: React.FC<InnerSyncMarkdownProps> = ({
138167 return (
139168 < div className = { cx ( 'co-markdown-view' , { [ 'is-empty' ] : isEmpty } , className ) } id = { id } >
140169 < div dangerouslySetInnerHTML = { { __html : markup } } />
141- { renderExtension && renderExtension ( document , `#${ id } ` ) }
170+ { renderExtension && < RenderExtension renderExtension = { renderExtension } selector = { `#${ id } ` } markup = { markup } /> }
142171 </ div >
143172 ) ;
144173} ;
@@ -232,7 +261,14 @@ const IFrameMarkdownView: React.FC<InnerSyncMarkdownProps> = ({
232261 onLoad = { ( ) => onLoad ( ) }
233262 className = { className }
234263 />
235- { loaded && frame && renderExtension && renderExtension ( frame . contentDocument , '' ) }
264+ { loaded && frame && renderExtension && (
265+ < RenderExtension
266+ markup = { markup }
267+ selector = { '' }
268+ renderExtension = { renderExtension }
269+ docContext = { frame . contentDocument }
270+ />
271+ ) }
236272 </ >
237273 ) ;
238274} ;
0 commit comments