PluginProbe ʕ •ᴥ•ʔ
GenerateBlocks / 2.0.0
GenerateBlocks v2.0.0
trunk 1.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.7.0 1.7.1 1.7.2 1.7.3 1.8.0 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 2.0.0 2.0.1 2.0.2 2.1.0 2.1.1 2.1.2 2.2.0 2.2.1 2.3.0
generateblocks / src / blocks / query-loop / components / LoopRenderer.js
generateblocks / src / blocks / query-loop / components Last commit date
inspector-controls 3 years ago BlockControls.js 3 years ago InspectorAdvancedControls.js 2 years ago InspectorControls.js 3 years ago LayoutSelector.js 3 years ago LoopRenderer.js 3 years ago QueryLoopRenderer.js 2 years ago utils.js 3 years ago
LoopRenderer.js
138 lines
1 import {
2 BlockContextProvider,
3 InnerBlocks,
4 __experimentalUseBlockPreview as useBlockPreview, // eslint-disable-line @wordpress/no-unsafe-wp-apis
5 store as blockEditorStore,
6 } from '@wordpress/block-editor';
7 import { Spinner } from '@wordpress/components';
8 import { __ } from '@wordpress/i18n';
9 import { memo, useEffect, useMemo, useState } from '@wordpress/element';
10 import { useSelect } from '@wordpress/data';
11 import { useDebouncedCallback } from 'use-debounce';
12
13 function BlockPreview( {
14 blocks,
15 contextId,
16 setActiveContextId,
17 isHidden,
18 } ) {
19 const blockPreviewProps = useBlockPreview( {
20 blocks,
21 } );
22
23 const handleOnClick = () => setActiveContextId( contextId );
24
25 const style = {
26 display: isHidden ? 'none' : undefined,
27 };
28
29 return (
30 <div
31 { ...blockPreviewProps }
32 className={ 'block-editor-inner-blocks gb-query-loop-block-preview' }
33 tabIndex={ 0 }
34 // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
35 role={ 'button' }
36 onClick={ handleOnClick }
37 onKeyPress={ handleOnClick }
38 style={ style }
39 />
40 );
41 }
42
43 const MemoizedBlockPreview = memo( BlockPreview );
44
45 function setIsBlockPreview( innerBlocks ) {
46 return innerBlocks.map( ( block ) => {
47 const newInnerBlocks = setIsBlockPreview( block.innerBlocks );
48 const attributes = Object.assign( {}, block.attributes, { isBlockPreview: true } );
49
50 return Object.assign( {}, block, { attributes, innerBlocks: newInnerBlocks } );
51 } );
52 }
53
54 export default function LoopRenderer( props ) {
55 const {
56 clientId,
57 data,
58 hasData,
59 isResolvingData,
60 hasResolvedData,
61 templateLock,
62 contextCallback,
63 } = props;
64
65 const innerBlocks = useSelect( ( select ) => {
66 return select( 'core/block-editor' )?.getBlocks( clientId );
67 }, [] );
68
69 const { getSelectedBlock } = useSelect( blockEditorStore );
70 const [ innerBlockData, setInnerBlockData ] = useState( [] );
71 const [ activeContextId, setActiveContextId ] = useState();
72
73 useEffect( () => {
74 setInnerBlockData( setIsBlockPreview( innerBlocks ) );
75 }, [] );
76
77 const debounced = useDebouncedCallback( () => {
78 setInnerBlockData( setIsBlockPreview( innerBlocks ) );
79 }, 10 );
80
81 const debounceBlocks = [
82 'core/paragraph',
83 'core/heading',
84 'core/button',
85 'generateblocks/headline',
86 'generateblocks/button',
87 ];
88
89 useEffect( () => {
90 const selectedBlock = getSelectedBlock();
91
92 if (
93 debounceBlocks.includes( selectedBlock?.name ) &&
94 ! selectedBlock?.attributes?.useDynamicData &&
95 ! selectedBlock?.attributes?.dynamicContentType
96 ) {
97 // Only debounce if we're using a RichText component.
98 debounced();
99 } else {
100 setInnerBlockData( setIsBlockPreview( innerBlocks ) );
101 }
102 }, [ JSON.stringify( innerBlocks ) ] );
103
104 const dataContexts = useMemo(
105 () =>
106 hasData && data.map( ( item ) => ( contextCallback( item ) ) ),
107 [ data, hasData ]
108 );
109
110 if ( isResolvingData ) {
111 return ( <Spinner /> );
112 }
113
114 if ( hasResolvedData && ! hasData ) {
115 return ( <h5>{ __( 'No results found.', 'generateblocks' ) }</h5> );
116 }
117
118 return (
119 dataContexts &&
120 dataContexts.map( ( postContext ) => (
121 <BlockContextProvider key={ postContext.postId } value={ postContext }>
122
123 { postContext.postId === ( activeContextId || dataContexts[ 0 ]?.postId )
124 ? ( <InnerBlocks { ...props } templateLock={ templateLock } /> )
125 : null
126 }
127
128 <MemoizedBlockPreview
129 blocks={ innerBlockData }
130 contextId={ postContext.postId }
131 setActiveContextId={ setActiveContextId }
132 isHidden={ postContext.postId === ( activeContextId || dataContexts[ 0 ]?.postId ) }
133 />
134
135 </BlockContextProvider>
136 ) ) );
137 }
138