PluginProbe ʕ •ᴥ•ʔ
GenerateBlocks / 1.9.0
GenerateBlocks v1.9.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 / pattern-library / components / pattern-list.js
generateblocks / src / pattern-library / components Last commit date
add-library.js 2 years ago category-list.js 2 years ago insert-pattern.js 2 years ago library-cache.js 2 years ago library-layout.js 2 years ago library-provider.js 2 years ago library-selector.js 2 years ago manage-libraries.js 2 years ago pattern-details-header.js 2 years ago pattern-details.js 2 years ago pattern-list.js 2 years ago pattern-search.js 2 years ago pattern.js 2 years ago selected-patterns.js 2 years ago
pattern-list.js
200 lines
1 import Pattern from './pattern';
2 import { useLibrary } from './library-provider';
3 import { useMemo, useRef, useState, useEffect, memo } from '@wordpress/element';
4 import { Button, Spinner } from '@wordpress/components';
5 import { __ } from '@wordpress/i18n';
6 import { PatternDetails } from './pattern-details';
7 import classnames from 'classnames';
8
9 export default function PatternList( {
10 bulkInsertEnabled = false,
11 patterns = [],
12 closeModal,
13 globalStyleCSS,
14 globalStyleData,
15 } ) {
16 const ref = useRef();
17 const loadMoreRef = useRef();
18 const {
19 activePatternId,
20 loading,
21 itemsPerPage,
22 itemCount,
23 setItemCount,
24 scrollPosition,
25 selectedPatterns,
26 selectedPatternsDispatch,
27 } = useLibrary();
28
29 const activePattern = useMemo( () => {
30 const found = patterns.filter( ( pattern ) => ( pattern.id === activePatternId ) );
31 return found[ 0 ] || undefined;
32 }, [ activePatternId ] );
33
34 const hide = loading ? { opacity: 0 } : {};
35 const [ visiblePatterns, setVisiblePatterns ] = useState( [] );
36 const [ loadMore, setLoadMore ] = useState( false );
37
38 useEffect( () => {
39 setVisiblePatterns( patterns.slice( 0, itemCount ) );
40 }, [ itemCount, patterns ] );
41
42 /**
43 * Set up our infinite scroll.
44 */
45 useEffect( () => {
46 const intersectionObserver = new IntersectionObserver(
47 ( entries ) => {
48 entries.forEach( ( entry ) => {
49 if ( entry.isIntersecting ) {
50 setLoadMore( true );
51 }
52 } );
53 },
54 {
55 root: null,
56 rootMargin: '0px',
57 threshold: 0.01,
58 }
59 );
60
61 if ( loadMoreRef.current ) {
62 intersectionObserver.observe( loadMoreRef.current );
63 }
64
65 return () => {
66 if ( intersectionObserver ) {
67 intersectionObserver.disconnect();
68 }
69 };
70 }, [] );
71
72 /**
73 * Load more patterns when we reach the bottom.
74 */
75 useEffect( () => {
76 if ( ! loadMore ) {
77 return;
78 }
79
80 if ( activePattern ) {
81 setLoadMore( false );
82 return;
83 }
84
85 setItemCount( itemCount + itemsPerPage );
86 setLoadMore( false );
87 }, [ loadMore ] );
88
89 /**
90 * Scroll to the last remembered scroll position.
91 * This is used to remember where we were if we preview a pattern and return to the list.
92 */
93 useEffect( () => {
94 if ( ref.current && ! activePattern ) {
95 const patternContent = ref.current.closest( '.gb-pattern-library__content' );
96
97 if ( patternContent ) {
98 patternContent.scrollTop = scrollPosition;
99 }
100 }
101 }, [ scrollPosition, activePattern ] );
102
103 const PatternDetailsMemo = memo( PatternDetails );
104
105 return (
106 <>
107 { loading && ! activePatternId &&
108 <div className="loading-library"><Spinner />
109 { __( 'Loading library', 'generateblocks' ) }
110 </div>
111 }
112
113 { ! loading && ! patterns.length && ! activePatternId &&
114 <div className="loading-library">
115 { __( 'No patterns found.', 'generateblocks' ) }
116 </div>
117 }
118
119 { !! activePattern &&
120 <Pattern
121 isLoading={ loading }
122 isActive={ true }
123 pattern={ activePattern }
124 globalStyleCSS={ globalStyleCSS }
125 />
126 }
127
128 <ul
129 ref={ ref }
130 className={ classnames( 'patterns-wrapper', bulkInsertEnabled && 'gb-bulk-insert' ) }
131 style={ {
132 ...hide,
133 display: !! activePattern ? 'none' : '',
134 } }
135 >
136 { visiblePatterns.map( ( pattern ) => {
137 const isSelected = selectedPatterns.some( ( { id } ) => id === pattern.id ) ?? false;
138
139 return (
140 <li
141 key={ pattern.id }
142 className={ classnames( 'gb-pattern-wrapper', 'gb-selectable', isSelected && bulkInsertEnabled && 'is-selected' ) }
143 >
144 { bulkInsertEnabled && (
145 <Button
146 className="gb-selectable__toggle"
147 label={ isSelected
148 ? __( 'Deselect this pattern', 'generateblocks' )
149 : __( 'Select this pattern', 'generate-blocks' )
150 }
151 onClick={ ( e ) => {
152 e.stopPropagation();
153 const type = isSelected ? 'REMOVE' : 'ADD';
154 selectedPatternsDispatch( { type, pattern } );
155 } }
156 />
157 ) }
158 { ( bulkInsertEnabled || isSelected ) && (
159 <Button
160 className="check"
161 onClick={ ( e ) => {
162 e.stopPropagation();
163 selectedPatternsDispatch( { type: 'REMOVE', pattern } );
164 } }
165 onBlur={ ( e ) => e.stopPropagation() }
166 tabIndex="-1"
167 >
168 <span className="media-modal-icon"></span>
169 <span className="screen-reader-text">
170 { __( 'Deselect', 'generateblocks' ) }
171 </span>
172 </Button>
173 ) }
174 <Pattern
175 isLoading={ loading }
176 pattern={ pattern }
177 globalStyleCSS={ globalStyleCSS }
178 />
179
180 <PatternDetailsMemo
181 pattern={ pattern }
182 patternRef={ ref }
183 bulkInsertEnabled={ bulkInsertEnabled }
184 globalStyleData={ globalStyleData }
185 closeModal={ closeModal }
186 />
187 </li>
188 );
189 } ) }
190 </ul>
191
192 <div
193 ref={ loadMoreRef }
194 style={ { marginTop: '10px' } }
195 className="gblocks-patterns-load-more"
196 />
197 </>
198 );
199 }
200