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