PluginProbe
Gutenberg / 18.6.1
Gutenberg v18.6.1
24.1.0 24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 All 404 releases
gutenberg / build / patterns / index.js

index.js in Gutenberg 18.6.1, at build/patterns/index.js

1,744 lines 62.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /******/ (() => { // webpackBootstrap
2 /******/ "use strict";
3 /******/ // The require scope
4 /******/ var __webpack_require__ = {};
5 /******/
6 /************************************************************************/
7 /******/ /* webpack/runtime/define property getters */
8 /******/ (() => {
9 /******/ // define getter functions for harmony exports
10 /******/ __webpack_require__.d = (exports, definition) => {
11 /******/ for(var key in definition) {
12 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
13 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
14 /******/ }
15 /******/ }
16 /******/ };
17 /******/ })();
18 /******/
19 /******/ /* webpack/runtime/hasOwnProperty shorthand */
20 /******/ (() => {
21 /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
22 /******/ })();
23 /******/
24 /******/ /* webpack/runtime/make namespace object */
25 /******/ (() => {
26 /******/ // define __esModule on exports
27 /******/ __webpack_require__.r = (exports) => {
28 /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
29 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
30 /******/ }
31 /******/ Object.defineProperty(exports, '__esModule', { value: true });
32 /******/ };
33 /******/ })();
34 /******/
35 /************************************************************************/
36 var __webpack_exports__ = {};
37 // ESM COMPAT FLAG
38 __webpack_require__.r(__webpack_exports__);
39
40 // EXPORTS
41 __webpack_require__.d(__webpack_exports__, {
42 privateApis: () => (/* reexport */ privateApis),
43 store: () => (/* reexport */ store)
44 });
45
46 // NAMESPACE OBJECT: ./packages/patterns/build-module/store/actions.js
47 var actions_namespaceObject = {};
48 __webpack_require__.r(actions_namespaceObject);
49 __webpack_require__.d(actions_namespaceObject, {
50 convertSyncedPatternToStatic: () => (convertSyncedPatternToStatic),
51 createPattern: () => (createPattern),
52 createPatternFromFile: () => (createPatternFromFile),
53 setEditingPattern: () => (setEditingPattern)
54 });
55
56 // NAMESPACE OBJECT: ./packages/patterns/build-module/store/selectors.js
57 var selectors_namespaceObject = {};
58 __webpack_require__.r(selectors_namespaceObject);
59 __webpack_require__.d(selectors_namespaceObject, {
60 isEditingPattern: () => (selectors_isEditingPattern)
61 });
62
63 ;// CONCATENATED MODULE: external ["wp","data"]
64 const external_wp_data_namespaceObject = window["wp"]["data"];
65 ;// CONCATENATED MODULE: ./packages/patterns/build-module/store/reducer.js
66 /**
67 * WordPress dependencies
68 */
69
70 function isEditingPattern(state = {}, action) {
71 if (action?.type === 'SET_EDITING_PATTERN') {
72 return {
73 ...state,
74 [action.clientId]: action.isEditing
75 };
76 }
77 return state;
78 }
79 /* harmony default export */ const reducer = ((0,external_wp_data_namespaceObject.combineReducers)({
80 isEditingPattern
81 }));
82
83 ;// CONCATENATED MODULE: external ["wp","blocks"]
84 const external_wp_blocks_namespaceObject = window["wp"]["blocks"];
85 ;// CONCATENATED MODULE: external ["wp","coreData"]
86 const external_wp_coreData_namespaceObject = window["wp"]["coreData"];
87 ;// CONCATENATED MODULE: external ["wp","blockEditor"]
88 const external_wp_blockEditor_namespaceObject = window["wp"]["blockEditor"];
89 ;// CONCATENATED MODULE: ./packages/patterns/build-module/constants.js
90 const PATTERN_TYPES = {
91 theme: 'pattern',
92 user: 'wp_block'
93 };
94 const PATTERN_DEFAULT_CATEGORY = 'all-patterns';
95 const PATTERN_USER_CATEGORY = 'my-patterns';
96 const EXCLUDED_PATTERN_SOURCES = ['core', 'pattern-directory/core', 'pattern-directory/featured'];
97 const PATTERN_SYNC_TYPES = {
98 full: 'fully',
99 unsynced: 'unsynced'
100 };
101
102 // TODO: This should not be hardcoded. Maybe there should be a config and/or an UI.
103 const PARTIAL_SYNCING_SUPPORTED_BLOCKS = {
104 'core/paragraph': ['content'],
105 'core/heading': ['content'],
106 'core/button': ['text', 'url', 'linkTarget', 'rel'],
107 'core/image': ['id', 'url', 'title', 'alt']
108 };
109 const PATTERN_OVERRIDES_BINDING_SOURCE = 'core/pattern-overrides';
110
111 ;// CONCATENATED MODULE: ./packages/patterns/build-module/store/actions.js
112 /**
113 * WordPress dependencies
114 */
115
116
117
118
119
120 /**
121 * Internal dependencies
122 */
123
124
125 /**
126 * Returns a generator converting one or more static blocks into a pattern, or creating a new empty pattern.
127 *
128 * @param {string} title Pattern title.
129 * @param {'full'|'unsynced'} syncType They way block is synced, 'full' or 'unsynced'.
130 * @param {string|undefined} [content] Optional serialized content of blocks to convert to pattern.
131 * @param {number[]|undefined} [categories] Ids of any selected categories.
132 */
133 const createPattern = (title, syncType, content, categories) => async ({
134 registry
135 }) => {
136 const meta = syncType === PATTERN_SYNC_TYPES.unsynced ? {
137 wp_pattern_sync_status: syncType
138 } : undefined;
139 const reusableBlock = {
140 title,
141 content,
142 status: 'publish',
143 meta,
144 wp_pattern_category: categories
145 };
146 const updatedRecord = await registry.dispatch(external_wp_coreData_namespaceObject.store).saveEntityRecord('postType', 'wp_block', reusableBlock);
147 return updatedRecord;
148 };
149
150 /**
151 * Create a pattern from a JSON file.
152 * @param {File} file The JSON file instance of the pattern.
153 * @param {number[]|undefined} [categories] Ids of any selected categories.
154 */
155 const createPatternFromFile = (file, categories) => async ({
156 dispatch
157 }) => {
158 const fileContent = await file.text();
159 /** @type {import('./types').PatternJSON} */
160 let parsedContent;
161 try {
162 parsedContent = JSON.parse(fileContent);
163 } catch (e) {
164 throw new Error('Invalid JSON file');
165 }
166 if (parsedContent.__file !== 'wp_block' || !parsedContent.title || !parsedContent.content || typeof parsedContent.title !== 'string' || typeof parsedContent.content !== 'string' || parsedContent.syncStatus && typeof parsedContent.syncStatus !== 'string') {
167 throw new Error('Invalid pattern JSON file');
168 }
169 const pattern = await dispatch.createPattern(parsedContent.title, parsedContent.syncStatus, parsedContent.content, categories);
170 return pattern;
171 };
172
173 /**
174 * Returns a generator converting a synced pattern block into a static block.
175 *
176 * @param {string} clientId The client ID of the block to attach.
177 */
178 const convertSyncedPatternToStatic = clientId => ({
179 registry
180 }) => {
181 const patternBlock = registry.select(external_wp_blockEditor_namespaceObject.store).getBlock(clientId);
182 const existingOverrides = patternBlock.attributes?.content;
183 function cloneBlocksAndRemoveBindings(blocks) {
184 return blocks.map(block => {
185 let metadata = block.attributes.metadata;
186 if (metadata) {
187 metadata = {
188 ...metadata
189 };
190 delete metadata.id;
191 delete metadata.bindings;
192 // Use overridden values of the pattern block if they exist.
193 if (existingOverrides?.[metadata.name]) {
194 // Iterate over each overriden attribute.
195 for (const [attributeName, value] of Object.entries(existingOverrides[metadata.name])) {
196 // Skip if the attribute does not exist in the block type.
197 if (!(0,external_wp_blocks_namespaceObject.getBlockType)(block.name)?.attributes[attributeName]) {
198 continue;
199 }
200 // Update the block attribute with the override value.
201 block.attributes[attributeName] = value;
202 }
203 }
204 }
205 return (0,external_wp_blocks_namespaceObject.cloneBlock)(block, {
206 metadata: metadata && Object.keys(metadata).length > 0 ? metadata : undefined
207 }, cloneBlocksAndRemoveBindings(block.innerBlocks));
208 });
209 }
210 const patternInnerBlocks = registry.select(external_wp_blockEditor_namespaceObject.store).getBlocks(patternBlock.clientId);
211 registry.dispatch(external_wp_blockEditor_namespaceObject.store).replaceBlocks(patternBlock.clientId, cloneBlocksAndRemoveBindings(patternInnerBlocks));
212 };
213
214 /**
215 * Returns an action descriptor for SET_EDITING_PATTERN action.
216 *
217 * @param {string} clientId The clientID of the pattern to target.
218 * @param {boolean} isEditing Whether the block should be in editing state.
219 * @return {Object} Action descriptor.
220 */
221 function setEditingPattern(clientId, isEditing) {
222 return {
223 type: 'SET_EDITING_PATTERN',
224 clientId,
225 isEditing
226 };
227 }
228
229 ;// CONCATENATED MODULE: ./packages/patterns/build-module/store/constants.js
230 /**
231 * Module Constants
232 */
233 const STORE_NAME = 'core/patterns';
234
235 ;// CONCATENATED MODULE: ./packages/patterns/build-module/store/selectors.js
236 /**
237 * Returns true if pattern is in the editing state.
238 *
239 * @param {Object} state Global application state.
240 * @param {number} clientId the clientID of the block.
241 * @return {boolean} Whether the pattern is in the editing state.
242 */
243 function selectors_isEditingPattern(state, clientId) {
244 return state.isEditingPattern[clientId];
245 }
246
247 ;// CONCATENATED MODULE: external ["wp","privateApis"]
248 const external_wp_privateApis_namespaceObject = window["wp"]["privateApis"];
249 ;// CONCATENATED MODULE: ./packages/patterns/build-module/lock-unlock.js
250 /**
251 * WordPress dependencies
252 */
253
254 const {
255 lock,
256 unlock
257 } = (0,external_wp_privateApis_namespaceObject.__dangerousOptInToUnstableAPIsOnlyForCoreModules)('I know using unstable features means my theme or plugin will inevitably break in the next version of WordPress.', '@wordpress/patterns');
258
259 ;// CONCATENATED MODULE: ./packages/patterns/build-module/store/index.js
260 /**
261 * WordPress dependencies
262 */
263
264
265 /**
266 * Internal dependencies
267 */
268
269
270
271
272
273
274 /**
275 * Post editor data store configuration.
276 *
277 * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#registerStore
278 *
279 * @type {Object}
280 */
281 const storeConfig = {
282 reducer: reducer
283 };
284
285 /**
286 * Store definition for the editor namespace.
287 *
288 * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore
289 *
290 * @type {Object}
291 */
292 const store = (0,external_wp_data_namespaceObject.createReduxStore)(STORE_NAME, {
293 ...storeConfig
294 });
295 (0,external_wp_data_namespaceObject.register)(store);
296 unlock(store).registerPrivateActions(actions_namespaceObject);
297 unlock(store).registerPrivateSelectors(selectors_namespaceObject);
298
299 ;// CONCATENATED MODULE: external ["wp","components"]
300 const external_wp_components_namespaceObject = window["wp"]["components"];
301 ;// CONCATENATED MODULE: external ["wp","element"]
302 const external_wp_element_namespaceObject = window["wp"]["element"];
303 ;// CONCATENATED MODULE: external ["wp","i18n"]
304 const external_wp_i18n_namespaceObject = window["wp"]["i18n"];
305 ;// CONCATENATED MODULE: ./packages/patterns/build-module/api/index.js
306 /**
307 * Internal dependencies
308 */
309
310
311 /**
312 * Determines whether a block is overridable.
313 *
314 * @param {WPBlock} block The block to test.
315 *
316 * @return {boolean} `true` if a block is overridable, `false` otherwise.
317 */
318 function isOverridableBlock(block) {
319 return Object.keys(PARTIAL_SYNCING_SUPPORTED_BLOCKS).includes(block.name) && !!block.attributes.metadata?.name && !!block.attributes.metadata?.bindings && Object.values(block.attributes.metadata.bindings).some(binding => binding.source === 'core/pattern-overrides');
320 }
321
322 /**
323 * Determines whether the blocks list has overridable blocks.
324 *
325 * @param {WPBlock[]} blocks The blocks list.
326 *
327 * @return {boolean} `true` if the list has overridable blocks, `false` otherwise.
328 */
329 function hasOverridableBlocks(blocks) {
330 return blocks.some(block => {
331 if (isOverridableBlock(block)) {
332 return true;
333 }
334 return hasOverridableBlocks(block.innerBlocks);
335 });
336 }
337
338 ;// CONCATENATED MODULE: external "ReactJSXRuntime"
339 const external_ReactJSXRuntime_namespaceObject = window["ReactJSXRuntime"];
340 ;// CONCATENATED MODULE: ./packages/patterns/build-module/components/overrides-panel.js
341 /**
342 * WordPress dependencies
343 */
344
345
346
347
348
349
350 /**
351 * Internal dependencies
352 */
353
354
355
356 const {
357 BlockQuickNavigation
358 } = unlock(external_wp_blockEditor_namespaceObject.privateApis);
359 function OverridesPanel() {
360 const allClientIds = (0,external_wp_data_namespaceObject.useSelect)(select => select(external_wp_blockEditor_namespaceObject.store).getClientIdsWithDescendants(), []);
361 const {
362 getBlock
363 } = (0,external_wp_data_namespaceObject.useSelect)(external_wp_blockEditor_namespaceObject.store);
364 const clientIdsWithOverrides = (0,external_wp_element_namespaceObject.useMemo)(() => allClientIds.filter(clientId => {
365 const block = getBlock(clientId);
366 return isOverridableBlock(block);
367 }), [allClientIds, getBlock]);
368 if (!clientIdsWithOverrides?.length) {
369 return null;
370 }
371 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.PanelBody, {
372 title: (0,external_wp_i18n_namespaceObject.__)('Overrides'),
373 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(BlockQuickNavigation, {
374 clientIds: clientIdsWithOverrides
375 })
376 });
377 }
378
379 ;// CONCATENATED MODULE: external ["wp","notices"]
380 const external_wp_notices_namespaceObject = window["wp"]["notices"];
381 ;// CONCATENATED MODULE: external ["wp","compose"]
382 const external_wp_compose_namespaceObject = window["wp"]["compose"];
383 ;// CONCATENATED MODULE: external ["wp","htmlEntities"]
384 const external_wp_htmlEntities_namespaceObject = window["wp"]["htmlEntities"];
385 ;// CONCATENATED MODULE: ./packages/patterns/build-module/components/category-selector.js
386 /**
387 * WordPress dependencies
388 */
389
390
391
392
393
394
395 const unescapeString = arg => {
396 return (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(arg);
397 };
398 const CATEGORY_SLUG = 'wp_pattern_category';
399 function CategorySelector({
400 categoryTerms,
401 onChange,
402 categoryMap
403 }) {
404 const [search, setSearch] = (0,external_wp_element_namespaceObject.useState)('');
405 const debouncedSearch = (0,external_wp_compose_namespaceObject.useDebounce)(setSearch, 500);
406 const suggestions = (0,external_wp_element_namespaceObject.useMemo)(() => {
407 return Array.from(categoryMap.values()).map(category => unescapeString(category.label)).filter(category => {
408 if (search !== '') {
409 return category.toLowerCase().includes(search.toLowerCase());
410 }
411 return true;
412 }).sort((a, b) => a.localeCompare(b));
413 }, [search, categoryMap]);
414 function handleChange(termNames) {
415 const uniqueTerms = termNames.reduce((terms, newTerm) => {
416 if (!terms.some(term => term.toLowerCase() === newTerm.toLowerCase())) {
417 terms.push(newTerm);
418 }
419 return terms;
420 }, []);
421 onChange(uniqueTerms);
422 }
423 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.FormTokenField, {
424 className: "patterns-menu-items__convert-modal-categories",
425 value: categoryTerms,
426 suggestions: suggestions,
427 onChange: handleChange,
428 onInputChange: debouncedSearch,
429 label: (0,external_wp_i18n_namespaceObject.__)('Categories'),
430 tokenizeOnBlur: true,
431 __experimentalExpandOnFocus: true,
432 __next40pxDefaultSize: true,
433 __nextHasNoMarginBottom: true
434 });
435 }
436
437 ;// CONCATENATED MODULE: ./packages/patterns/build-module/private-hooks.js
438 /**
439 * WordPress dependencies
440 */
441
442
443
444
445 /**
446 * Internal dependencies
447 */
448
449
450 /**
451 * Helper hook that creates a Map with the core and user patterns categories
452 * and removes any duplicates. It's used when we need to create new user
453 * categories when creating or importing patterns.
454 * This hook also provides a function to find or create a pattern category.
455 *
456 * @return {Object} The merged categories map and the callback function to find or create a category.
457 */
458 function useAddPatternCategory() {
459 const {
460 saveEntityRecord,
461 invalidateResolution
462 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_coreData_namespaceObject.store);
463 const {
464 corePatternCategories,
465 userPatternCategories
466 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
467 const {
468 getUserPatternCategories,
469 getBlockPatternCategories
470 } = select(external_wp_coreData_namespaceObject.store);
471 return {
472 corePatternCategories: getBlockPatternCategories(),
473 userPatternCategories: getUserPatternCategories()
474 };
475 }, []);
476 const categoryMap = (0,external_wp_element_namespaceObject.useMemo)(() => {
477 // Merge the user and core pattern categories and remove any duplicates.
478 const uniqueCategories = new Map();
479 userPatternCategories.forEach(category => {
480 uniqueCategories.set(category.label.toLowerCase(), {
481 label: category.label,
482 name: category.name,
483 id: category.id
484 });
485 });
486 corePatternCategories.forEach(category => {
487 if (!uniqueCategories.has(category.label.toLowerCase()) &&
488 // There are two core categories with `Post` label so explicitly remove the one with
489 // the `query` slug to avoid any confusion.
490 category.name !== 'query') {
491 uniqueCategories.set(category.label.toLowerCase(), {
492 label: category.label,
493 name: category.name
494 });
495 }
496 });
497 return uniqueCategories;
498 }, [userPatternCategories, corePatternCategories]);
499 async function findOrCreateTerm(term) {
500 try {
501 const existingTerm = categoryMap.get(term.toLowerCase());
502 if (existingTerm?.id) {
503 return existingTerm.id;
504 }
505 // If we have an existing core category we need to match the new user category to the
506 // correct slug rather than autogenerating it to prevent duplicates, eg. the core `Headers`
507 // category uses the singular `header` as the slug.
508 const termData = existingTerm ? {
509 name: existingTerm.label,
510 slug: existingTerm.name
511 } : {
512 name: term
513 };
514 const newTerm = await saveEntityRecord('taxonomy', CATEGORY_SLUG, termData, {
515 throwOnError: true
516 });
517 invalidateResolution('getUserPatternCategories');
518 return newTerm.id;
519 } catch (error) {
520 if (error.code !== 'term_exists') {
521 throw error;
522 }
523 return error.data.term_id;
524 }
525 }
526 return {
527 categoryMap,
528 findOrCreateTerm
529 };
530 }
531
532 ;// CONCATENATED MODULE: ./packages/patterns/build-module/components/create-pattern-modal.js
533 /**
534 * WordPress dependencies
535 */
536
537
538
539
540
541
542
543 /**
544 * Internal dependencies
545 */
546
547
548
549
550
551
552
553 function CreatePatternModal({
554 className = 'patterns-menu-items__convert-modal',
555 modalTitle,
556 ...restProps
557 }) {
558 const defaultModalTitle = (0,external_wp_data_namespaceObject.useSelect)(select => select(external_wp_coreData_namespaceObject.store).getPostType(PATTERN_TYPES.user)?.labels?.add_new_item, []);
559 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Modal, {
560 title: modalTitle || defaultModalTitle,
561 onRequestClose: restProps.onClose,
562 overlayClassName: className,
563 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(CreatePatternModalContents, {
564 ...restProps
565 })
566 });
567 }
568 function CreatePatternModalContents({
569 confirmLabel = (0,external_wp_i18n_namespaceObject.__)('Add'),
570 defaultCategories = [],
571 content,
572 onClose,
573 onError,
574 onSuccess,
575 defaultSyncType = PATTERN_SYNC_TYPES.full,
576 defaultTitle = ''
577 }) {
578 const [syncType, setSyncType] = (0,external_wp_element_namespaceObject.useState)(defaultSyncType);
579 const [categoryTerms, setCategoryTerms] = (0,external_wp_element_namespaceObject.useState)(defaultCategories);
580 const [title, setTitle] = (0,external_wp_element_namespaceObject.useState)(defaultTitle);
581 const [isSaving, setIsSaving] = (0,external_wp_element_namespaceObject.useState)(false);
582 const {
583 createPattern
584 } = unlock((0,external_wp_data_namespaceObject.useDispatch)(store));
585 const {
586 createErrorNotice
587 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_notices_namespaceObject.store);
588 const {
589 categoryMap,
590 findOrCreateTerm
591 } = useAddPatternCategory();
592 async function onCreate(patternTitle, sync) {
593 if (!title || isSaving) {
594 return;
595 }
596 try {
597 setIsSaving(true);
598 const categories = await Promise.all(categoryTerms.map(termName => findOrCreateTerm(termName)));
599 const newPattern = await createPattern(patternTitle, sync, typeof content === 'function' ? content() : content, categories);
600 onSuccess({
601 pattern: newPattern,
602 categoryId: PATTERN_DEFAULT_CATEGORY
603 });
604 } catch (error) {
605 createErrorNotice(error.message, {
606 type: 'snackbar',
607 id: 'pattern-create'
608 });
609 onError?.();
610 } finally {
611 setIsSaving(false);
612 setCategoryTerms([]);
613 setTitle('');
614 }
615 }
616 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("form", {
617 onSubmit: event => {
618 event.preventDefault();
619 onCreate(title, syncType);
620 },
621 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalVStack, {
622 spacing: "5",
623 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.TextControl, {
624 label: (0,external_wp_i18n_namespaceObject.__)('Name'),
625 value: title,
626 onChange: setTitle,
627 placeholder: (0,external_wp_i18n_namespaceObject.__)('My pattern'),
628 className: "patterns-create-modal__name-input",
629 __nextHasNoMarginBottom: true,
630 __next40pxDefaultSize: true
631 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(CategorySelector, {
632 categoryTerms: categoryTerms,
633 onChange: setCategoryTerms,
634 categoryMap: categoryMap
635 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.ToggleControl, {
636 label: (0,external_wp_i18n_namespaceObject._x)('Synced', 'pattern (singular)'),
637 help: (0,external_wp_i18n_namespaceObject.__)('Sync this pattern across multiple locations.'),
638 checked: syncType === PATTERN_SYNC_TYPES.full,
639 onChange: () => {
640 setSyncType(syncType === PATTERN_SYNC_TYPES.full ? PATTERN_SYNC_TYPES.unsynced : PATTERN_SYNC_TYPES.full);
641 }
642 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalHStack, {
643 justify: "right",
644 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
645 __next40pxDefaultSize: true,
646 variant: "tertiary",
647 onClick: () => {
648 onClose();
649 setTitle('');
650 },
651 children: (0,external_wp_i18n_namespaceObject.__)('Cancel')
652 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
653 __next40pxDefaultSize: true,
654 variant: "primary",
655 type: "submit",
656 "aria-disabled": !title || isSaving,
657 isBusy: isSaving,
658 children: confirmLabel
659 })]
660 })]
661 })
662 });
663 }
664
665 ;// CONCATENATED MODULE: ./packages/patterns/build-module/components/duplicate-pattern-modal.js
666 /**
667 * WordPress dependencies
668 */
669
670
671
672
673
674 /**
675 * Internal dependencies
676 */
677
678
679
680 function getTermLabels(pattern, categories) {
681 // Theme patterns rely on core pattern categories.
682 if (pattern.type !== PATTERN_TYPES.user) {
683 return categories.core?.filter(category => pattern.categories.includes(category.name)).map(category => category.label);
684 }
685 return categories.user?.filter(category => pattern.wp_pattern_category.includes(category.id)).map(category => category.label);
686 }
687 function useDuplicatePatternProps({
688 pattern,
689 onSuccess
690 }) {
691 const {
692 createSuccessNotice
693 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_notices_namespaceObject.store);
694 const categories = (0,external_wp_data_namespaceObject.useSelect)(select => {
695 const {
696 getUserPatternCategories,
697 getBlockPatternCategories
698 } = select(external_wp_coreData_namespaceObject.store);
699 return {
700 core: getBlockPatternCategories(),
701 user: getUserPatternCategories()
702 };
703 });
704 if (!pattern) {
705 return null;
706 }
707 return {
708 content: pattern.content,
709 defaultCategories: getTermLabels(pattern, categories),
710 defaultSyncType: pattern.type !== PATTERN_TYPES.user // Theme patterns are unsynced by default.
711 ? PATTERN_SYNC_TYPES.unsynced : pattern.wp_pattern_sync_status || PATTERN_SYNC_TYPES.full,
712 defaultTitle: (0,external_wp_i18n_namespaceObject.sprintf)( /* translators: %s: Existing pattern title */
713 (0,external_wp_i18n_namespaceObject.__)('%s (Copy)'), typeof pattern.title === 'string' ? pattern.title : pattern.title.raw),
714 onSuccess: ({
715 pattern: newPattern
716 }) => {
717 createSuccessNotice((0,external_wp_i18n_namespaceObject.sprintf)(
718 // translators: %s: The new pattern's title e.g. 'Call to action (copy)'.
719 (0,external_wp_i18n_namespaceObject.__)('"%s" duplicated.'), newPattern.title.raw), {
720 type: 'snackbar',
721 id: 'patterns-create'
722 });
723 onSuccess?.({
724 pattern: newPattern
725 });
726 }
727 };
728 }
729 function DuplicatePatternModal({
730 pattern,
731 onClose,
732 onSuccess
733 }) {
734 const duplicatedProps = useDuplicatePatternProps({
735 pattern,
736 onSuccess
737 });
738 if (!pattern) {
739 return null;
740 }
741 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(CreatePatternModal, {
742 modalTitle: (0,external_wp_i18n_namespaceObject.__)('Duplicate pattern'),
743 confirmLabel: (0,external_wp_i18n_namespaceObject.__)('Duplicate'),
744 onClose: onClose,
745 onError: onClose,
746 ...duplicatedProps
747 });
748 }
749
750 ;// CONCATENATED MODULE: ./packages/patterns/build-module/components/rename-pattern-modal.js
751 /**
752 * WordPress dependencies
753 */
754
755
756
757
758
759
760
761
762
763 function RenamePatternModal({
764 onClose,
765 onError,
766 onSuccess,
767 pattern,
768 ...props
769 }) {
770 const originalName = (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(pattern.title);
771 const [name, setName] = (0,external_wp_element_namespaceObject.useState)(originalName);
772 const [isSaving, setIsSaving] = (0,external_wp_element_namespaceObject.useState)(false);
773 const {
774 editEntityRecord,
775 __experimentalSaveSpecifiedEntityEdits: saveSpecifiedEntityEdits
776 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_coreData_namespaceObject.store);
777 const {
778 createSuccessNotice,
779 createErrorNotice
780 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_notices_namespaceObject.store);
781 const onRename = async event => {
782 event.preventDefault();
783 if (!name || name === pattern.title || isSaving) {
784 return;
785 }
786 try {
787 await editEntityRecord('postType', pattern.type, pattern.id, {
788 title: name
789 });
790 setIsSaving(true);
791 setName('');
792 onClose?.();
793 const savedRecord = await saveSpecifiedEntityEdits('postType', pattern.type, pattern.id, ['title'], {
794 throwOnError: true
795 });
796 onSuccess?.(savedRecord);
797 createSuccessNotice((0,external_wp_i18n_namespaceObject.__)('Pattern renamed'), {
798 type: 'snackbar',
799 id: 'pattern-update'
800 });
801 } catch (error) {
802 onError?.();
803 const errorMessage = error.message && error.code !== 'unknown_error' ? error.message : (0,external_wp_i18n_namespaceObject.__)('An error occurred while renaming the pattern.');
804 createErrorNotice(errorMessage, {
805 type: 'snackbar',
806 id: 'pattern-update'
807 });
808 } finally {
809 setIsSaving(false);
810 setName('');
811 }
812 };
813 const onRequestClose = () => {
814 onClose?.();
815 setName('');
816 };
817 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Modal, {
818 title: (0,external_wp_i18n_namespaceObject.__)('Rename'),
819 ...props,
820 onRequestClose: onClose,
821 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("form", {
822 onSubmit: onRename,
823 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalVStack, {
824 spacing: "5",
825 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.TextControl, {
826 __nextHasNoMarginBottom: true,
827 __next40pxDefaultSize: true,
828 label: (0,external_wp_i18n_namespaceObject.__)('Name'),
829 value: name,
830 onChange: setName,
831 required: true
832 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalHStack, {
833 justify: "right",
834 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
835 __next40pxDefaultSize: true,
836 variant: "tertiary",
837 onClick: onRequestClose,
838 children: (0,external_wp_i18n_namespaceObject.__)('Cancel')
839 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
840 __next40pxDefaultSize: true,
841 variant: "primary",
842 type: "submit",
843 children: (0,external_wp_i18n_namespaceObject.__)('Save')
844 })]
845 })]
846 })
847 })
848 });
849 }
850
851 ;// CONCATENATED MODULE: external ["wp","primitives"]
852 const external_wp_primitives_namespaceObject = window["wp"]["primitives"];
853 ;// CONCATENATED MODULE: ./packages/icons/build-module/library/symbol.js
854 /**
855 * WordPress dependencies
856 */
857
858
859 const symbol = /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.SVG, {
860 xmlns: "http://www.w3.org/2000/svg",
861 viewBox: "0 0 24 24",
862 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.Path, {
863 d: "M21.3 10.8l-5.6-5.6c-.7-.7-1.8-.7-2.5 0l-5.6 5.6c-.7.7-.7 1.8 0 2.5l5.6 5.6c.3.3.8.5 1.2.5s.9-.2 1.2-.5l5.6-5.6c.8-.7.8-1.9.1-2.5zm-1 1.4l-5.6 5.6c-.1.1-.3.1-.4 0l-5.6-5.6c-.1-.1-.1-.3 0-.4l5.6-5.6s.1-.1.2-.1.1 0 .2.1l5.6 5.6c.1.1.1.3 0 .4zm-16.6-.4L10 5.5l-1-1-6.3 6.3c-.7.7-.7 1.8 0 2.5L9 19.5l1.1-1.1-6.3-6.3c-.2 0-.2-.2-.1-.3z"
864 })
865 });
866 /* harmony default export */ const library_symbol = (symbol);
867
868 ;// CONCATENATED MODULE: ./packages/patterns/build-module/components/pattern-convert-button.js
869 /**
870 * WordPress dependencies
871 */
872
873
874
875
876
877
878
879
880
881 /**
882 * Internal dependencies
883 */
884
885
886
887
888
889 /**
890 * Menu control to convert block(s) to a pattern block.
891 *
892 * @param {Object} props Component props.
893 * @param {string[]} props.clientIds Client ids of selected blocks.
894 * @param {string} props.rootClientId ID of the currently selected top-level block.
895 * @param {()=>void} props.closeBlockSettingsMenu Callback to close the block settings menu dropdown.
896 * @return {import('react').ComponentType} The menu control or null.
897 */
898
899
900
901 function PatternConvertButton({
902 clientIds,
903 rootClientId,
904 closeBlockSettingsMenu
905 }) {
906 const {
907 createSuccessNotice
908 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_notices_namespaceObject.store);
909 const {
910 replaceBlocks
911 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_blockEditor_namespaceObject.store);
912 // Ignore reason: false positive of the lint rule.
913 // eslint-disable-next-line @wordpress/no-unused-vars-before-return
914 const {
915 setEditingPattern
916 } = unlock((0,external_wp_data_namespaceObject.useDispatch)(store));
917 const [isModalOpen, setIsModalOpen] = (0,external_wp_element_namespaceObject.useState)(false);
918 const canConvert = (0,external_wp_data_namespaceObject.useSelect)(select => {
919 var _getBlocksByClientId;
920 const {
921 canUser
922 } = select(external_wp_coreData_namespaceObject.store);
923 const {
924 getBlocksByClientId,
925 canInsertBlockType,
926 getBlockRootClientId
927 } = select(external_wp_blockEditor_namespaceObject.store);
928 const rootId = rootClientId || (clientIds.length > 0 ? getBlockRootClientId(clientIds[0]) : undefined);
929 const blocks = (_getBlocksByClientId = getBlocksByClientId(clientIds)) !== null && _getBlocksByClientId !== void 0 ? _getBlocksByClientId : [];
930 const isReusable = blocks.length === 1 && blocks[0] && (0,external_wp_blocks_namespaceObject.isReusableBlock)(blocks[0]) && !!select(external_wp_coreData_namespaceObject.store).getEntityRecord('postType', 'wp_block', blocks[0].attributes.ref);
931 const _canConvert =
932 // Hide when this is already a synced pattern.
933 !isReusable &&
934 // Hide when patterns are disabled.
935 canInsertBlockType('core/block', rootId) && blocks.every(block =>
936 // Guard against the case where a regular block has *just* been converted.
937 !!block &&
938 // Hide on invalid blocks.
939 block.isValid &&
940 // Hide when block doesn't support being made into a pattern.
941 (0,external_wp_blocks_namespaceObject.hasBlockSupport)(block.name, 'reusable', true)) &&
942 // Hide when current doesn't have permission to do that.
943 !!canUser('create', 'blocks');
944 return _canConvert;
945 }, [clientIds, rootClientId]);
946 const {
947 getBlocksByClientId
948 } = (0,external_wp_data_namespaceObject.useSelect)(external_wp_blockEditor_namespaceObject.store);
949 const getContent = (0,external_wp_element_namespaceObject.useCallback)(() => (0,external_wp_blocks_namespaceObject.serialize)(getBlocksByClientId(clientIds)), [getBlocksByClientId, clientIds]);
950 if (!canConvert) {
951 return null;
952 }
953 const handleSuccess = ({
954 pattern
955 }) => {
956 if (pattern.wp_pattern_sync_status !== PATTERN_SYNC_TYPES.unsynced) {
957 const newBlock = (0,external_wp_blocks_namespaceObject.createBlock)('core/block', {
958 ref: pattern.id
959 });
960 replaceBlocks(clientIds, newBlock);
961 setEditingPattern(newBlock.clientId, true);
962 closeBlockSettingsMenu();
963 }
964 createSuccessNotice(pattern.wp_pattern_sync_status === PATTERN_SYNC_TYPES.unsynced ? (0,external_wp_i18n_namespaceObject.sprintf)(
965 // translators: %s: the name the user has given to the pattern.
966 (0,external_wp_i18n_namespaceObject.__)('Unsynced pattern created: %s'), pattern.title.raw) : (0,external_wp_i18n_namespaceObject.sprintf)(
967 // translators: %s: the name the user has given to the pattern.
968 (0,external_wp_i18n_namespaceObject.__)('Synced pattern created: %s'), pattern.title.raw), {
969 type: 'snackbar',
970 id: 'convert-to-pattern-success'
971 });
972 setIsModalOpen(false);
973 };
974 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_ReactJSXRuntime_namespaceObject.Fragment, {
975 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.MenuItem, {
976 icon: library_symbol,
977 onClick: () => setIsModalOpen(true),
978 "aria-expanded": isModalOpen,
979 "aria-haspopup": "dialog",
980 children: (0,external_wp_i18n_namespaceObject.__)('Create pattern')
981 }), isModalOpen && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(CreatePatternModal, {
982 content: getContent,
983 onSuccess: pattern => {
984 handleSuccess(pattern);
985 },
986 onError: () => {
987 setIsModalOpen(false);
988 },
989 onClose: () => {
990 setIsModalOpen(false);
991 }
992 })]
993 });
994 }
995
996 ;// CONCATENATED MODULE: external ["wp","url"]
997 const external_wp_url_namespaceObject = window["wp"]["url"];
998 ;// CONCATENATED MODULE: ./packages/patterns/build-module/components/patterns-manage-button.js
999 /**
1000 * WordPress dependencies
1001 */
1002
1003
1004
1005
1006
1007
1008
1009
1010 /**
1011 * Internal dependencies
1012 */
1013
1014
1015
1016
1017
1018 function PatternsManageButton({
1019 clientId
1020 }) {
1021 const {
1022 canRemove,
1023 isVisible,
1024 managePatternsUrl
1025 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
1026 const {
1027 getBlock,
1028 canRemoveBlock,
1029 getBlockCount
1030 } = select(external_wp_blockEditor_namespaceObject.store);
1031 const {
1032 canUser
1033 } = select(external_wp_coreData_namespaceObject.store);
1034 const reusableBlock = getBlock(clientId);
1035 return {
1036 canRemove: canRemoveBlock(clientId),
1037 isVisible: !!reusableBlock && (0,external_wp_blocks_namespaceObject.isReusableBlock)(reusableBlock) && !!canUser('update', 'blocks', reusableBlock.attributes.ref),
1038 innerBlockCount: getBlockCount(clientId),
1039 // The site editor and templates both check whether the user
1040 // has edit_theme_options capabilities. We can leverage that here
1041 // and omit the manage patterns link if the user can't access it.
1042 managePatternsUrl: canUser('create', 'templates') ? (0,external_wp_url_namespaceObject.addQueryArgs)('site-editor.php', {
1043 path: '/patterns'
1044 }) : (0,external_wp_url_namespaceObject.addQueryArgs)('edit.php', {
1045 post_type: 'wp_block'
1046 })
1047 };
1048 }, [clientId]);
1049
1050 // Ignore reason: false positive of the lint rule.
1051 // eslint-disable-next-line @wordpress/no-unused-vars-before-return
1052 const {
1053 convertSyncedPatternToStatic
1054 } = unlock((0,external_wp_data_namespaceObject.useDispatch)(store));
1055 if (!isVisible) {
1056 return null;
1057 }
1058 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_ReactJSXRuntime_namespaceObject.Fragment, {
1059 children: [canRemove && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.MenuItem, {
1060 onClick: () => convertSyncedPatternToStatic(clientId),
1061 children: (0,external_wp_i18n_namespaceObject.__)('Detach')
1062 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.MenuItem, {
1063 href: managePatternsUrl,
1064 children: (0,external_wp_i18n_namespaceObject.__)('Manage patterns')
1065 })]
1066 });
1067 }
1068 /* harmony default export */ const patterns_manage_button = (PatternsManageButton);
1069
1070 ;// CONCATENATED MODULE: ./packages/patterns/build-module/components/index.js
1071 /**
1072 * WordPress dependencies
1073 */
1074
1075
1076 /**
1077 * Internal dependencies
1078 */
1079
1080
1081
1082
1083
1084 function PatternsMenuItems({
1085 rootClientId
1086 }) {
1087 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_blockEditor_namespaceObject.BlockSettingsMenuControls, {
1088 children: ({
1089 selectedClientIds,
1090 onClose
1091 }) => /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_ReactJSXRuntime_namespaceObject.Fragment, {
1092 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(PatternConvertButton, {
1093 clientIds: selectedClientIds,
1094 rootClientId: rootClientId,
1095 closeBlockSettingsMenu: onClose
1096 }), selectedClientIds.length === 1 && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(patterns_manage_button, {
1097 clientId: selectedClientIds[0]
1098 })]
1099 })
1100 });
1101 }
1102
1103 ;// CONCATENATED MODULE: external ["wp","a11y"]
1104 const external_wp_a11y_namespaceObject = window["wp"]["a11y"];
1105 ;// CONCATENATED MODULE: ./packages/patterns/build-module/components/rename-pattern-category-modal.js
1106 /**
1107 * WordPress dependencies
1108 */
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118 /**
1119 * Internal dependencies
1120 */
1121
1122
1123
1124 function RenamePatternCategoryModal({
1125 category,
1126 existingCategories,
1127 onClose,
1128 onError,
1129 onSuccess,
1130 ...props
1131 }) {
1132 const id = (0,external_wp_element_namespaceObject.useId)();
1133 const textControlRef = (0,external_wp_element_namespaceObject.useRef)();
1134 const [name, setName] = (0,external_wp_element_namespaceObject.useState)((0,external_wp_htmlEntities_namespaceObject.decodeEntities)(category.name));
1135 const [isSaving, setIsSaving] = (0,external_wp_element_namespaceObject.useState)(false);
1136 const [validationMessage, setValidationMessage] = (0,external_wp_element_namespaceObject.useState)(false);
1137 const validationMessageId = validationMessage ? `patterns-rename-pattern-category-modal__validation-message-${id}` : undefined;
1138 const {
1139 saveEntityRecord,
1140 invalidateResolution
1141 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_coreData_namespaceObject.store);
1142 const {
1143 createErrorNotice,
1144 createSuccessNotice
1145 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_notices_namespaceObject.store);
1146 const onChange = newName => {
1147 if (validationMessage) {
1148 setValidationMessage(undefined);
1149 }
1150 setName(newName);
1151 };
1152 const onSave = async event => {
1153 event.preventDefault();
1154 if (isSaving) {
1155 return;
1156 }
1157 if (!name || name === category.name) {
1158 const message = (0,external_wp_i18n_namespaceObject.__)('Please enter a new name for this category.');
1159 (0,external_wp_a11y_namespaceObject.speak)(message, 'assertive');
1160 setValidationMessage(message);
1161 textControlRef.current?.focus();
1162 return;
1163 }
1164
1165 // Check existing categories to avoid creating duplicates.
1166 if (existingCategories.patternCategories.find(existingCategory => {
1167 // Compare the id so that the we don't disallow the user changing the case of their current category
1168 // (i.e. renaming 'test' to 'Test').
1169 return existingCategory.id !== category.id && existingCategory.label.toLowerCase() === name.toLowerCase();
1170 })) {
1171 const message = (0,external_wp_i18n_namespaceObject.__)('This category already exists. Please use a different name.');
1172 (0,external_wp_a11y_namespaceObject.speak)(message, 'assertive');
1173 setValidationMessage(message);
1174 textControlRef.current?.focus();
1175 return;
1176 }
1177 try {
1178 setIsSaving(true);
1179
1180 // User pattern category properties may differ as they can be
1181 // normalized for use alongside template part areas, core pattern
1182 // categories etc. As a result we won't just destructure the passed
1183 // category object.
1184 const savedRecord = await saveEntityRecord('taxonomy', CATEGORY_SLUG, {
1185 id: category.id,
1186 slug: category.slug,
1187 name
1188 });
1189 invalidateResolution('getUserPatternCategories');
1190 onSuccess?.(savedRecord);
1191 onClose();
1192 createSuccessNotice((0,external_wp_i18n_namespaceObject.__)('Pattern category renamed.'), {
1193 type: 'snackbar',
1194 id: 'pattern-category-update'
1195 });
1196 } catch (error) {
1197 onError?.();
1198 createErrorNotice(error.message, {
1199 type: 'snackbar',
1200 id: 'pattern-category-update'
1201 });
1202 } finally {
1203 setIsSaving(false);
1204 setName('');
1205 }
1206 };
1207 const onRequestClose = () => {
1208 onClose();
1209 setName('');
1210 };
1211 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Modal, {
1212 title: (0,external_wp_i18n_namespaceObject.__)('Rename'),
1213 onRequestClose: onRequestClose,
1214 ...props,
1215 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("form", {
1216 onSubmit: onSave,
1217 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalVStack, {
1218 spacing: "5",
1219 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalVStack, {
1220 spacing: "2",
1221 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.TextControl, {
1222 ref: textControlRef,
1223 __nextHasNoMarginBottom: true,
1224 __next40pxDefaultSize: true,
1225 label: (0,external_wp_i18n_namespaceObject.__)('Name'),
1226 value: name,
1227 onChange: onChange,
1228 "aria-describedby": validationMessageId,
1229 required: true
1230 }), validationMessage && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("span", {
1231 className: "patterns-rename-pattern-category-modal__validation-message",
1232 id: validationMessageId,
1233 children: validationMessage
1234 })]
1235 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalHStack, {
1236 justify: "right",
1237 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1238 __next40pxDefaultSize: true,
1239 variant: "tertiary",
1240 onClick: onRequestClose,
1241 children: (0,external_wp_i18n_namespaceObject.__)('Cancel')
1242 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1243 __next40pxDefaultSize: true,
1244 variant: "primary",
1245 type: "submit",
1246 "aria-disabled": !name || name === category.name || isSaving,
1247 isBusy: isSaving,
1248 children: (0,external_wp_i18n_namespaceObject.__)('Save')
1249 })]
1250 })]
1251 })
1252 })
1253 });
1254 }
1255
1256 ;// CONCATENATED MODULE: ./packages/patterns/build-module/components/allow-overrides-modal.js
1257 /**
1258 * WordPress dependencies
1259 */
1260
1261
1262
1263
1264
1265
1266 function AllowOverridesModal({
1267 placeholder,
1268 initialName = '',
1269 onClose,
1270 onSave
1271 }) {
1272 const [editedBlockName, setEditedBlockName] = (0,external_wp_element_namespaceObject.useState)(initialName);
1273 const descriptionId = (0,external_wp_element_namespaceObject.useId)();
1274 const isNameValid = !!editedBlockName.trim();
1275 const handleSubmit = () => {
1276 if (editedBlockName !== initialName) {
1277 const message = (0,external_wp_i18n_namespaceObject.sprintf)( /* translators: %s: new name/label for the block */
1278 (0,external_wp_i18n_namespaceObject.__)('Block name changed to: "%s".'), editedBlockName);
1279
1280 // Must be assertive to immediately announce change.
1281 (0,external_wp_a11y_namespaceObject.speak)(message, 'assertive');
1282 }
1283 onSave(editedBlockName);
1284
1285 // Immediate close avoids ability to hit save multiple times.
1286 onClose();
1287 };
1288 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Modal, {
1289 title: (0,external_wp_i18n_namespaceObject.__)('Enable overrides'),
1290 onRequestClose: onClose,
1291 focusOnMount: "firstContentElement",
1292 aria: {
1293 describedby: descriptionId
1294 },
1295 size: "small",
1296 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("form", {
1297 onSubmit: event => {
1298 event.preventDefault();
1299 if (!isNameValid) {
1300 return;
1301 }
1302 handleSubmit();
1303 },
1304 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalVStack, {
1305 spacing: "6",
1306 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.__experimentalText, {
1307 id: descriptionId,
1308 children: (0,external_wp_i18n_namespaceObject.__)('Overrides are changes you make to a block within a synced pattern instance. Use overrides to customize a synced pattern instance to suit its new context. Name this block to specify an override.')
1309 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.TextControl, {
1310 __nextHasNoMarginBottom: true,
1311 __next40pxDefaultSize: true,
1312 value: editedBlockName,
1313 label: (0,external_wp_i18n_namespaceObject.__)('Name'),
1314 help: (0,external_wp_i18n_namespaceObject.__)('For example, if you are creating a recipe pattern, you use "Recipe Title", "Recipe Description", etc.'),
1315 placeholder: placeholder,
1316 onChange: setEditedBlockName
1317 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalHStack, {
1318 justify: "right",
1319 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1320 __next40pxDefaultSize: true,
1321 variant: "tertiary",
1322 onClick: onClose,
1323 children: (0,external_wp_i18n_namespaceObject.__)('Cancel')
1324 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1325 __next40pxDefaultSize: true,
1326 "aria-disabled": !isNameValid,
1327 variant: "primary",
1328 type: "submit",
1329 children: (0,external_wp_i18n_namespaceObject.__)('Enable')
1330 })]
1331 })]
1332 })
1333 })
1334 });
1335 }
1336 function DisallowOverridesModal({
1337 onClose,
1338 onSave
1339 }) {
1340 const descriptionId = (0,external_wp_element_namespaceObject.useId)();
1341 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Modal, {
1342 title: (0,external_wp_i18n_namespaceObject.__)('Disable overrides'),
1343 onRequestClose: onClose,
1344 aria: {
1345 describedby: descriptionId
1346 },
1347 size: "small",
1348 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("form", {
1349 onSubmit: event => {
1350 event.preventDefault();
1351 onSave();
1352 onClose();
1353 },
1354 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalVStack, {
1355 spacing: "6",
1356 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.__experimentalText, {
1357 id: descriptionId,
1358 children: (0,external_wp_i18n_namespaceObject.__)('Are you sure you want to disable overrides? Disabling overrides will revert all applied overrides for this block throughout instances of this pattern.')
1359 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalHStack, {
1360 justify: "right",
1361 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1362 __next40pxDefaultSize: true,
1363 variant: "tertiary",
1364 onClick: onClose,
1365 children: (0,external_wp_i18n_namespaceObject.__)('Cancel')
1366 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1367 __next40pxDefaultSize: true,
1368 variant: "primary",
1369 type: "submit",
1370 children: (0,external_wp_i18n_namespaceObject.__)('Disable')
1371 })]
1372 })]
1373 })
1374 })
1375 });
1376 }
1377
1378 ;// CONCATENATED MODULE: ./packages/patterns/build-module/components/pattern-overrides-controls.js
1379 /**
1380 * WordPress dependencies
1381 */
1382
1383
1384
1385
1386
1387 /**
1388 * Internal dependencies
1389 */
1390
1391
1392
1393
1394
1395 function removeBindings(bindings) {
1396 let updatedBindings = {
1397 ...bindings
1398 };
1399 delete updatedBindings.__default;
1400 if (!Object.keys(updatedBindings).length) {
1401 updatedBindings = undefined;
1402 }
1403 return updatedBindings;
1404 }
1405 function addBindings(bindings) {
1406 return {
1407 ...bindings,
1408 __default: {
1409 source: PATTERN_OVERRIDES_BINDING_SOURCE
1410 }
1411 };
1412 }
1413 function PatternOverridesControls({
1414 attributes,
1415 setAttributes
1416 }) {
1417 const controlId = (0,external_wp_element_namespaceObject.useId)();
1418 const [showAllowOverridesModal, setShowAllowOverridesModal] = (0,external_wp_element_namespaceObject.useState)(false);
1419 const [showDisallowOverridesModal, setShowDisallowOverridesModal] = (0,external_wp_element_namespaceObject.useState)(false);
1420 const hasName = !!attributes.metadata?.name;
1421 const defaultBindings = attributes.metadata?.bindings?.__default;
1422 const allowOverrides = hasName && defaultBindings?.source === PATTERN_OVERRIDES_BINDING_SOURCE;
1423 const isConnectedToOtherSources = defaultBindings?.source && defaultBindings.source !== PATTERN_OVERRIDES_BINDING_SOURCE;
1424 function updateBindings(isChecked, customName) {
1425 const prevBindings = attributes?.metadata?.bindings;
1426 const updatedBindings = isChecked ? addBindings(prevBindings) : removeBindings(prevBindings);
1427 const updatedMetadata = {
1428 ...attributes.metadata,
1429 bindings: updatedBindings
1430 };
1431 if (customName) {
1432 updatedMetadata.name = customName;
1433 }
1434 setAttributes({
1435 metadata: updatedMetadata
1436 });
1437 }
1438
1439 // Avoid overwriting other (e.g. meta) bindings.
1440 if (isConnectedToOtherSources) {
1441 return null;
1442 }
1443 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_ReactJSXRuntime_namespaceObject.Fragment, {
1444 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_blockEditor_namespaceObject.InspectorControls, {
1445 group: "advanced",
1446 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.BaseControl, {
1447 id: controlId,
1448 label: (0,external_wp_i18n_namespaceObject.__)('Overrides'),
1449 help: (0,external_wp_i18n_namespaceObject.__)('Allow changes to this block throughout instances of this pattern.'),
1450 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1451 __next40pxDefaultSize: true,
1452 className: "pattern-overrides-control__allow-overrides-button",
1453 variant: "secondary",
1454 "aria-haspopup": "dialog",
1455 onClick: () => {
1456 if (allowOverrides) {
1457 setShowDisallowOverridesModal(true);
1458 } else {
1459 setShowAllowOverridesModal(true);
1460 }
1461 },
1462 children: allowOverrides ? (0,external_wp_i18n_namespaceObject.__)('Disable overrides') : (0,external_wp_i18n_namespaceObject.__)('Enable overrides')
1463 })
1464 })
1465 }), showAllowOverridesModal && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(AllowOverridesModal, {
1466 initialName: attributes.metadata?.name,
1467 onClose: () => setShowAllowOverridesModal(false),
1468 onSave: newName => {
1469 updateBindings(true, newName);
1470 }
1471 }), showDisallowOverridesModal && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(DisallowOverridesModal, {
1472 onClose: () => setShowDisallowOverridesModal(false),
1473 onSave: () => updateBindings(false)
1474 })]
1475 });
1476 }
1477 /* harmony default export */ const pattern_overrides_controls = (PatternOverridesControls);
1478
1479 ;// CONCATENATED MODULE: ./packages/patterns/build-module/components/reset-overrides-control.js
1480 /**
1481 * WordPress dependencies
1482 */
1483
1484
1485
1486
1487
1488 const CONTENT = 'content';
1489 function ResetOverridesControl(props) {
1490 const name = props.attributes.metadata?.name;
1491 const registry = (0,external_wp_data_namespaceObject.useRegistry)();
1492 const isOverriden = (0,external_wp_data_namespaceObject.useSelect)(select => {
1493 if (!name) {
1494 return;
1495 }
1496 const {
1497 getBlockAttributes,
1498 getBlockParentsByBlockName
1499 } = select(external_wp_blockEditor_namespaceObject.store);
1500 const [patternClientId] = getBlockParentsByBlockName(props.clientId, 'core/block', true);
1501 if (!patternClientId) {
1502 return;
1503 }
1504 const overrides = getBlockAttributes(patternClientId)[CONTENT];
1505 if (!overrides) {
1506 return;
1507 }
1508 return overrides.hasOwnProperty(name);
1509 }, [props.clientId, name]);
1510 function onClick() {
1511 const {
1512 getBlockAttributes,
1513 getBlockParentsByBlockName
1514 } = registry.select(external_wp_blockEditor_namespaceObject.store);
1515 const [patternClientId] = getBlockParentsByBlockName(props.clientId, 'core/block', true);
1516 if (!patternClientId) {
1517 return;
1518 }
1519 const overrides = getBlockAttributes(patternClientId)[CONTENT];
1520 if (!overrides.hasOwnProperty(name)) {
1521 return;
1522 }
1523 const {
1524 updateBlockAttributes,
1525 __unstableMarkLastChangeAsPersistent
1526 } = registry.dispatch(external_wp_blockEditor_namespaceObject.store);
1527 __unstableMarkLastChangeAsPersistent();
1528 let newOverrides = {
1529 ...overrides
1530 };
1531 delete newOverrides[name];
1532 if (!Object.keys(newOverrides).length) {
1533 newOverrides = undefined;
1534 }
1535 updateBlockAttributes(patternClientId, {
1536 [CONTENT]: newOverrides
1537 });
1538 }
1539 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_blockEditor_namespaceObject.BlockControls, {
1540 group: "other",
1541 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.ToolbarGroup, {
1542 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.ToolbarButton, {
1543 onClick: onClick,
1544 disabled: !isOverriden,
1545 __experimentalIsFocusable: true,
1546 children: (0,external_wp_i18n_namespaceObject.__)('Reset')
1547 })
1548 })
1549 });
1550 }
1551
1552 ;// CONCATENATED MODULE: ./packages/icons/build-module/library/copy.js
1553 /**
1554 * WordPress dependencies
1555 */
1556
1557
1558 const copy = /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.SVG, {
1559 xmlns: "http://www.w3.org/2000/svg",
1560 viewBox: "0 0 24 24",
1561 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.Path, {
1562 fillRule: "evenodd",
1563 clipRule: "evenodd",
1564 d: "M5 4.5h11a.5.5 0 0 1 .5.5v11a.5.5 0 0 1-.5.5H5a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5ZM3 5a2 2 0 0 1 2-2h11a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5Zm17 3v10.75c0 .69-.56 1.25-1.25 1.25H6v1.5h12.75a2.75 2.75 0 0 0 2.75-2.75V8H20Z"
1565 })
1566 });
1567 /* harmony default export */ const library_copy = (copy);
1568
1569 ;// CONCATENATED MODULE: ./packages/patterns/build-module/components/pattern-overrides-block-controls.js
1570 /**
1571 * WordPress dependencies
1572 */
1573
1574
1575
1576
1577
1578
1579
1580
1581 /**
1582 * Internal dependencies
1583 */
1584
1585
1586
1587
1588 const {
1589 useBlockDisplayTitle
1590 } = unlock(external_wp_blockEditor_namespaceObject.privateApis);
1591 function PatternOverridesToolbarIndicator({
1592 clientIds
1593 }) {
1594 const isSingleBlockSelected = clientIds.length === 1;
1595 const {
1596 icon,
1597 firstBlockName
1598 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
1599 const {
1600 getBlockAttributes,
1601 getBlockNamesByClientId
1602 } = select(external_wp_blockEditor_namespaceObject.store);
1603 const {
1604 getBlockType,
1605 getActiveBlockVariation
1606 } = select(external_wp_blocks_namespaceObject.store);
1607 const blockTypeNames = getBlockNamesByClientId(clientIds);
1608 const _firstBlockTypeName = blockTypeNames[0];
1609 const firstBlockType = getBlockType(_firstBlockTypeName);
1610 let _icon;
1611 if (isSingleBlockSelected) {
1612 const match = getActiveBlockVariation(_firstBlockTypeName, getBlockAttributes(clientIds[0]));
1613 // Take into account active block variations.
1614 _icon = match?.icon || firstBlockType.icon;
1615 } else {
1616 const isSelectionOfSameType = new Set(blockTypeNames).size === 1;
1617 // When selection consists of blocks of multiple types, display an
1618 // appropriate icon to communicate the non-uniformity.
1619 _icon = isSelectionOfSameType ? firstBlockType.icon : library_copy;
1620 }
1621 return {
1622 icon: _icon,
1623 firstBlockName: getBlockAttributes(clientIds[0]).metadata.name
1624 };
1625 }, [clientIds, isSingleBlockSelected]);
1626 const firstBlockTitle = useBlockDisplayTitle({
1627 clientId: clientIds[0],
1628 maximumLength: 35
1629 });
1630 const blockDescription = isSingleBlockSelected ? (0,external_wp_i18n_namespaceObject.sprintf)( /* translators: %1s: The block type's name; %2s: The block's user-provided name (the same as the override name). */
1631 (0,external_wp_i18n_namespaceObject.__)('This %1$s is editable using the "%2$s" override.'), firstBlockTitle.toLowerCase(), firstBlockName) : (0,external_wp_i18n_namespaceObject.__)('These blocks are editable using overrides.');
1632 const descriptionId = (0,external_wp_element_namespaceObject.useId)();
1633 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.ToolbarItem, {
1634 children: toggleProps => /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.DropdownMenu, {
1635 className: "patterns-pattern-overrides-toolbar-indicator",
1636 label: firstBlockTitle,
1637 popoverProps: {
1638 placement: 'bottom-start',
1639 className: 'patterns-pattern-overrides-toolbar-indicator__popover'
1640 },
1641 icon: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_ReactJSXRuntime_namespaceObject.Fragment, {
1642 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_blockEditor_namespaceObject.BlockIcon, {
1643 icon: icon,
1644 className: "patterns-pattern-overrides-toolbar-indicator-icon",
1645 showColors: true
1646 })
1647 }),
1648 toggleProps: {
1649 describedBy: blockDescription,
1650 ...toggleProps
1651 },
1652 menuProps: {
1653 orientation: 'both',
1654 'aria-describedby': descriptionId
1655 },
1656 children: () => /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.__experimentalText, {
1657 id: descriptionId,
1658 children: blockDescription
1659 })
1660 })
1661 });
1662 }
1663 function PatternOverridesBlockControls() {
1664 const {
1665 clientIds,
1666 hasPatternOverrides,
1667 hasParentPattern
1668 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
1669 const {
1670 getBlockAttributes,
1671 getSelectedBlockClientIds,
1672 getBlockParentsByBlockName
1673 } = select(external_wp_blockEditor_namespaceObject.store);
1674 const selectedClientIds = getSelectedBlockClientIds();
1675 const _hasPatternOverrides = selectedClientIds.every(clientId => {
1676 var _getBlockAttributes$m;
1677 return Object.values((_getBlockAttributes$m = getBlockAttributes(clientId)?.metadata?.bindings) !== null && _getBlockAttributes$m !== void 0 ? _getBlockAttributes$m : {}).some(binding => binding?.source === PATTERN_OVERRIDES_BINDING_SOURCE);
1678 });
1679 const _hasParentPattern = selectedClientIds.every(clientId => getBlockParentsByBlockName(clientId, 'core/block', true).length > 0);
1680 return {
1681 clientIds: selectedClientIds,
1682 hasPatternOverrides: _hasPatternOverrides,
1683 hasParentPattern: _hasParentPattern
1684 };
1685 }, []);
1686 return hasPatternOverrides && hasParentPattern ? /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_blockEditor_namespaceObject.BlockControls, {
1687 group: "parent",
1688 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(PatternOverridesToolbarIndicator, {
1689 clientIds: clientIds
1690 })
1691 }) : null;
1692 }
1693
1694 ;// CONCATENATED MODULE: ./packages/patterns/build-module/private-apis.js
1695 /**
1696 * Internal dependencies
1697 */
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711 const privateApis = {};
1712 lock(privateApis, {
1713 OverridesPanel: OverridesPanel,
1714 CreatePatternModal: CreatePatternModal,
1715 CreatePatternModalContents: CreatePatternModalContents,
1716 DuplicatePatternModal: DuplicatePatternModal,
1717 isOverridableBlock: isOverridableBlock,
1718 hasOverridableBlocks: hasOverridableBlocks,
1719 useDuplicatePatternProps: useDuplicatePatternProps,
1720 RenamePatternModal: RenamePatternModal,
1721 PatternsMenuItems: PatternsMenuItems,
1722 RenamePatternCategoryModal: RenamePatternCategoryModal,
1723 PatternOverridesControls: pattern_overrides_controls,
1724 ResetOverridesControl: ResetOverridesControl,
1725 PatternOverridesBlockControls: PatternOverridesBlockControls,
1726 useAddPatternCategory: useAddPatternCategory,
1727 PATTERN_TYPES: PATTERN_TYPES,
1728 PATTERN_DEFAULT_CATEGORY: PATTERN_DEFAULT_CATEGORY,
1729 PATTERN_USER_CATEGORY: PATTERN_USER_CATEGORY,
1730 EXCLUDED_PATTERN_SOURCES: EXCLUDED_PATTERN_SOURCES,
1731 PATTERN_SYNC_TYPES: PATTERN_SYNC_TYPES,
1732 PARTIAL_SYNCING_SUPPORTED_BLOCKS: PARTIAL_SYNCING_SUPPORTED_BLOCKS
1733 });
1734
1735 ;// CONCATENATED MODULE: ./packages/patterns/build-module/index.js
1736 /**
1737 * Internal dependencies
1738 */
1739
1740
1741
1742 (window.wp = window.wp || {}).patterns = __webpack_exports__;
1743 /******/ })()
1744 ;