PluginProbe
Gutenberg / 19.6.0
Gutenberg v19.6.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 12.6.0 All 403 releases
gutenberg / build / patterns / index.js

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

1,738 lines 61.8 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 ;// external ["wp","data"]
64 const external_wp_data_namespaceObject = window["wp"]["data"];
65 ;// ./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 ;// external ["wp","blocks"]
84 const external_wp_blocks_namespaceObject = window["wp"]["blocks"];
85 ;// external ["wp","coreData"]
86 const external_wp_coreData_namespaceObject = window["wp"]["coreData"];
87 ;// external ["wp","blockEditor"]
88 const external_wp_blockEditor_namespaceObject = window["wp"]["blockEditor"];
89 ;// ./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 ;// ./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 ;// ./packages/patterns/build-module/store/constants.js
230 /**
231 * Module Constants
232 */
233 const STORE_NAME = 'core/patterns';
234
235 ;// ./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 ;// external ["wp","privateApis"]
248 const external_wp_privateApis_namespaceObject = window["wp"]["privateApis"];
249 ;// ./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 acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.', '@wordpress/patterns');
258
259 ;// ./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 ;// external ["wp","components"]
300 const external_wp_components_namespaceObject = window["wp"]["components"];
301 ;// external ["wp","element"]
302 const external_wp_element_namespaceObject = window["wp"]["element"];
303 ;// external ["wp","i18n"]
304 const external_wp_i18n_namespaceObject = window["wp"]["i18n"];
305 ;// ./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 ;// external "ReactJSXRuntime"
339 const external_ReactJSXRuntime_namespaceObject = window["ReactJSXRuntime"];
340 ;// ./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 ;// external ["wp","notices"]
380 const external_wp_notices_namespaceObject = window["wp"]["notices"];
381 ;// external ["wp","compose"]
382 const external_wp_compose_namespaceObject = window["wp"]["compose"];
383 ;// external ["wp","htmlEntities"]
384 const external_wp_htmlEntities_namespaceObject = window["wp"]["htmlEntities"];
385 ;// ./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 ;// ./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 ;// ./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 function CreatePatternModal({
553 className = 'patterns-menu-items__convert-modal',
554 modalTitle,
555 ...restProps
556 }) {
557 const defaultModalTitle = (0,external_wp_data_namespaceObject.useSelect)(select => select(external_wp_coreData_namespaceObject.store).getPostType(PATTERN_TYPES.user)?.labels?.add_new_item, []);
558 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Modal, {
559 title: modalTitle || defaultModalTitle,
560 onRequestClose: restProps.onClose,
561 overlayClassName: className,
562 focusOnMount: "firstContentElement",
563 size: "small",
564 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(CreatePatternModalContents, {
565 ...restProps
566 })
567 });
568 }
569 function CreatePatternModalContents({
570 confirmLabel = (0,external_wp_i18n_namespaceObject.__)('Add'),
571 defaultCategories = [],
572 content,
573 onClose,
574 onError,
575 onSuccess,
576 defaultSyncType = PATTERN_SYNC_TYPES.full,
577 defaultTitle = ''
578 }) {
579 const [syncType, setSyncType] = (0,external_wp_element_namespaceObject.useState)(defaultSyncType);
580 const [categoryTerms, setCategoryTerms] = (0,external_wp_element_namespaceObject.useState)(defaultCategories);
581 const [title, setTitle] = (0,external_wp_element_namespaceObject.useState)(defaultTitle);
582 const [isSaving, setIsSaving] = (0,external_wp_element_namespaceObject.useState)(false);
583 const {
584 createPattern
585 } = unlock((0,external_wp_data_namespaceObject.useDispatch)(store));
586 const {
587 createErrorNotice
588 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_notices_namespaceObject.store);
589 const {
590 categoryMap,
591 findOrCreateTerm
592 } = useAddPatternCategory();
593 async function onCreate(patternTitle, sync) {
594 if (!title || isSaving) {
595 return;
596 }
597 try {
598 setIsSaving(true);
599 const categories = await Promise.all(categoryTerms.map(termName => findOrCreateTerm(termName)));
600 const newPattern = await createPattern(patternTitle, sync, typeof content === 'function' ? content() : content, categories);
601 onSuccess({
602 pattern: newPattern,
603 categoryId: PATTERN_DEFAULT_CATEGORY
604 });
605 } catch (error) {
606 createErrorNotice(error.message, {
607 type: 'snackbar',
608 id: 'pattern-create'
609 });
610 onError?.();
611 } finally {
612 setIsSaving(false);
613 setCategoryTerms([]);
614 setTitle('');
615 }
616 }
617 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("form", {
618 onSubmit: event => {
619 event.preventDefault();
620 onCreate(title, syncType);
621 },
622 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalVStack, {
623 spacing: "5",
624 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.TextControl, {
625 label: (0,external_wp_i18n_namespaceObject.__)('Name'),
626 value: title,
627 onChange: setTitle,
628 placeholder: (0,external_wp_i18n_namespaceObject.__)('My pattern'),
629 className: "patterns-create-modal__name-input",
630 __nextHasNoMarginBottom: true,
631 __next40pxDefaultSize: true
632 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(CategorySelector, {
633 categoryTerms: categoryTerms,
634 onChange: setCategoryTerms,
635 categoryMap: categoryMap
636 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.ToggleControl, {
637 __nextHasNoMarginBottom: true,
638 label: (0,external_wp_i18n_namespaceObject._x)('Synced', 'pattern (singular)'),
639 help: (0,external_wp_i18n_namespaceObject.__)('Sync this pattern across multiple locations.'),
640 checked: syncType === PATTERN_SYNC_TYPES.full,
641 onChange: () => {
642 setSyncType(syncType === PATTERN_SYNC_TYPES.full ? PATTERN_SYNC_TYPES.unsynced : PATTERN_SYNC_TYPES.full);
643 }
644 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalHStack, {
645 justify: "right",
646 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
647 __next40pxDefaultSize: true,
648 variant: "tertiary",
649 onClick: () => {
650 onClose();
651 setTitle('');
652 },
653 children: (0,external_wp_i18n_namespaceObject.__)('Cancel')
654 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
655 __next40pxDefaultSize: true,
656 variant: "primary",
657 type: "submit",
658 "aria-disabled": !title || isSaving,
659 isBusy: isSaving,
660 children: confirmLabel
661 })]
662 })]
663 })
664 });
665 }
666
667 ;// ./packages/patterns/build-module/components/duplicate-pattern-modal.js
668 /**
669 * WordPress dependencies
670 */
671
672
673
674
675
676 /**
677 * Internal dependencies
678 */
679
680
681
682 function getTermLabels(pattern, categories) {
683 // Theme patterns rely on core pattern categories.
684 if (pattern.type !== PATTERN_TYPES.user) {
685 return categories.core?.filter(category => pattern.categories.includes(category.name)).map(category => category.label);
686 }
687 return categories.user?.filter(category => pattern.wp_pattern_category.includes(category.id)).map(category => category.label);
688 }
689 function useDuplicatePatternProps({
690 pattern,
691 onSuccess
692 }) {
693 const {
694 createSuccessNotice
695 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_notices_namespaceObject.store);
696 const categories = (0,external_wp_data_namespaceObject.useSelect)(select => {
697 const {
698 getUserPatternCategories,
699 getBlockPatternCategories
700 } = select(external_wp_coreData_namespaceObject.store);
701 return {
702 core: getBlockPatternCategories(),
703 user: getUserPatternCategories()
704 };
705 });
706 if (!pattern) {
707 return null;
708 }
709 return {
710 content: pattern.content,
711 defaultCategories: getTermLabels(pattern, categories),
712 defaultSyncType: pattern.type !== PATTERN_TYPES.user // Theme patterns are unsynced by default.
713 ? PATTERN_SYNC_TYPES.unsynced : pattern.wp_pattern_sync_status || PATTERN_SYNC_TYPES.full,
714 defaultTitle: (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %s: Existing pattern title */
715 (0,external_wp_i18n_namespaceObject._x)('%s (Copy)', 'pattern'), typeof pattern.title === 'string' ? pattern.title : pattern.title.raw),
716 onSuccess: ({
717 pattern: newPattern
718 }) => {
719 createSuccessNotice((0,external_wp_i18n_namespaceObject.sprintf)(
720 // translators: %s: The new pattern's title e.g. 'Call to action (copy)'.
721 (0,external_wp_i18n_namespaceObject._x)('"%s" duplicated.', 'pattern'), newPattern.title.raw), {
722 type: 'snackbar',
723 id: 'patterns-create'
724 });
725 onSuccess?.({
726 pattern: newPattern
727 });
728 }
729 };
730 }
731 function DuplicatePatternModal({
732 pattern,
733 onClose,
734 onSuccess
735 }) {
736 const duplicatedProps = useDuplicatePatternProps({
737 pattern,
738 onSuccess
739 });
740 if (!pattern) {
741 return null;
742 }
743 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(CreatePatternModal, {
744 modalTitle: (0,external_wp_i18n_namespaceObject.__)('Duplicate pattern'),
745 confirmLabel: (0,external_wp_i18n_namespaceObject.__)('Duplicate'),
746 onClose: onClose,
747 onError: onClose,
748 ...duplicatedProps
749 });
750 }
751
752 ;// ./packages/patterns/build-module/components/rename-pattern-modal.js
753 /**
754 * WordPress dependencies
755 */
756
757
758
759
760
761
762
763
764 function RenamePatternModal({
765 onClose,
766 onError,
767 onSuccess,
768 pattern,
769 ...props
770 }) {
771 const originalName = (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(pattern.title);
772 const [name, setName] = (0,external_wp_element_namespaceObject.useState)(originalName);
773 const [isSaving, setIsSaving] = (0,external_wp_element_namespaceObject.useState)(false);
774 const {
775 editEntityRecord,
776 __experimentalSaveSpecifiedEntityEdits: saveSpecifiedEntityEdits
777 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_coreData_namespaceObject.store);
778 const {
779 createSuccessNotice,
780 createErrorNotice
781 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_notices_namespaceObject.store);
782 const onRename = async event => {
783 event.preventDefault();
784 if (!name || name === pattern.title || isSaving) {
785 return;
786 }
787 try {
788 await editEntityRecord('postType', pattern.type, pattern.id, {
789 title: name
790 });
791 setIsSaving(true);
792 setName('');
793 onClose?.();
794 const savedRecord = await saveSpecifiedEntityEdits('postType', pattern.type, pattern.id, ['title'], {
795 throwOnError: true
796 });
797 onSuccess?.(savedRecord);
798 createSuccessNotice((0,external_wp_i18n_namespaceObject.__)('Pattern renamed'), {
799 type: 'snackbar',
800 id: 'pattern-update'
801 });
802 } catch (error) {
803 onError?.();
804 const errorMessage = error.message && error.code !== 'unknown_error' ? error.message : (0,external_wp_i18n_namespaceObject.__)('An error occurred while renaming the pattern.');
805 createErrorNotice(errorMessage, {
806 type: 'snackbar',
807 id: 'pattern-update'
808 });
809 } finally {
810 setIsSaving(false);
811 setName('');
812 }
813 };
814 const onRequestClose = () => {
815 onClose?.();
816 setName('');
817 };
818 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Modal, {
819 title: (0,external_wp_i18n_namespaceObject.__)('Rename'),
820 ...props,
821 onRequestClose: onClose,
822 focusOnMount: "firstContentElement",
823 size: "small",
824 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("form", {
825 onSubmit: onRename,
826 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalVStack, {
827 spacing: "5",
828 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.TextControl, {
829 __nextHasNoMarginBottom: true,
830 __next40pxDefaultSize: true,
831 label: (0,external_wp_i18n_namespaceObject.__)('Name'),
832 value: name,
833 onChange: setName,
834 required: true
835 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalHStack, {
836 justify: "right",
837 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
838 __next40pxDefaultSize: true,
839 variant: "tertiary",
840 onClick: onRequestClose,
841 children: (0,external_wp_i18n_namespaceObject.__)('Cancel')
842 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
843 __next40pxDefaultSize: true,
844 variant: "primary",
845 type: "submit",
846 children: (0,external_wp_i18n_namespaceObject.__)('Save')
847 })]
848 })]
849 })
850 })
851 });
852 }
853
854 ;// external ["wp","primitives"]
855 const external_wp_primitives_namespaceObject = window["wp"]["primitives"];
856 ;// ./packages/icons/build-module/library/symbol.js
857 /**
858 * WordPress dependencies
859 */
860
861
862 const symbol = /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.SVG, {
863 xmlns: "http://www.w3.org/2000/svg",
864 viewBox: "0 0 24 24",
865 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.Path, {
866 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"
867 })
868 });
869 /* harmony default export */ const library_symbol = (symbol);
870
871 ;// ./packages/patterns/build-module/components/pattern-convert-button.js
872 /**
873 * WordPress dependencies
874 */
875
876
877
878
879
880
881
882
883
884 /**
885 * Internal dependencies
886 */
887
888
889
890
891
892 /**
893 * Menu control to convert block(s) to a pattern block.
894 *
895 * @param {Object} props Component props.
896 * @param {string[]} props.clientIds Client ids of selected blocks.
897 * @param {string} props.rootClientId ID of the currently selected top-level block.
898 * @param {()=>void} props.closeBlockSettingsMenu Callback to close the block settings menu dropdown.
899 * @return {import('react').ComponentType} The menu control or null.
900 */
901
902 function PatternConvertButton({
903 clientIds,
904 rootClientId,
905 closeBlockSettingsMenu
906 }) {
907 const {
908 createSuccessNotice
909 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_notices_namespaceObject.store);
910 const {
911 replaceBlocks
912 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_blockEditor_namespaceObject.store);
913 // Ignore reason: false positive of the lint rule.
914 // eslint-disable-next-line @wordpress/no-unused-vars-before-return
915 const {
916 setEditingPattern
917 } = unlock((0,external_wp_data_namespaceObject.useDispatch)(store));
918 const [isModalOpen, setIsModalOpen] = (0,external_wp_element_namespaceObject.useState)(false);
919 const canConvert = (0,external_wp_data_namespaceObject.useSelect)(select => {
920 var _getBlocksByClientId;
921 const {
922 canUser
923 } = select(external_wp_coreData_namespaceObject.store);
924 const {
925 getBlocksByClientId,
926 canInsertBlockType,
927 getBlockRootClientId
928 } = select(external_wp_blockEditor_namespaceObject.store);
929 const rootId = rootClientId || (clientIds.length > 0 ? getBlockRootClientId(clientIds[0]) : undefined);
930 const blocks = (_getBlocksByClientId = getBlocksByClientId(clientIds)) !== null && _getBlocksByClientId !== void 0 ? _getBlocksByClientId : [];
931 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);
932 const _canConvert =
933 // Hide when this is already a synced pattern.
934 !isReusable &&
935 // Hide when patterns are disabled.
936 canInsertBlockType('core/block', rootId) && blocks.every(block =>
937 // Guard against the case where a regular block has *just* been converted.
938 !!block &&
939 // Hide on invalid blocks.
940 block.isValid &&
941 // Hide when block doesn't support being made into a pattern.
942 (0,external_wp_blocks_namespaceObject.hasBlockSupport)(block.name, 'reusable', true)) &&
943 // Hide when current doesn't have permission to do that.
944 // Blocks refers to the wp_block post type, this checks the ability to create a post of that type.
945 !!canUser('create', {
946 kind: 'postType',
947 name: 'wp_block'
948 });
949 return _canConvert;
950 }, [clientIds, rootClientId]);
951 const {
952 getBlocksByClientId
953 } = (0,external_wp_data_namespaceObject.useSelect)(external_wp_blockEditor_namespaceObject.store);
954 const getContent = (0,external_wp_element_namespaceObject.useCallback)(() => (0,external_wp_blocks_namespaceObject.serialize)(getBlocksByClientId(clientIds)), [getBlocksByClientId, clientIds]);
955 if (!canConvert) {
956 return null;
957 }
958 const handleSuccess = ({
959 pattern
960 }) => {
961 if (pattern.wp_pattern_sync_status !== PATTERN_SYNC_TYPES.unsynced) {
962 const newBlock = (0,external_wp_blocks_namespaceObject.createBlock)('core/block', {
963 ref: pattern.id
964 });
965 replaceBlocks(clientIds, newBlock);
966 setEditingPattern(newBlock.clientId, true);
967 closeBlockSettingsMenu();
968 }
969 createSuccessNotice(pattern.wp_pattern_sync_status === PATTERN_SYNC_TYPES.unsynced ? (0,external_wp_i18n_namespaceObject.sprintf)(
970 // translators: %s: the name the user has given to the pattern.
971 (0,external_wp_i18n_namespaceObject.__)('Unsynced pattern created: %s'), pattern.title.raw) : (0,external_wp_i18n_namespaceObject.sprintf)(
972 // translators: %s: the name the user has given to the pattern.
973 (0,external_wp_i18n_namespaceObject.__)('Synced pattern created: %s'), pattern.title.raw), {
974 type: 'snackbar',
975 id: 'convert-to-pattern-success'
976 });
977 setIsModalOpen(false);
978 };
979 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_ReactJSXRuntime_namespaceObject.Fragment, {
980 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.MenuItem, {
981 icon: library_symbol,
982 onClick: () => setIsModalOpen(true),
983 "aria-expanded": isModalOpen,
984 "aria-haspopup": "dialog",
985 children: (0,external_wp_i18n_namespaceObject.__)('Create pattern')
986 }), isModalOpen && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(CreatePatternModal, {
987 content: getContent,
988 onSuccess: pattern => {
989 handleSuccess(pattern);
990 },
991 onError: () => {
992 setIsModalOpen(false);
993 },
994 onClose: () => {
995 setIsModalOpen(false);
996 }
997 })]
998 });
999 }
1000
1001 ;// external ["wp","url"]
1002 const external_wp_url_namespaceObject = window["wp"]["url"];
1003 ;// ./packages/patterns/build-module/components/patterns-manage-button.js
1004 /**
1005 * WordPress dependencies
1006 */
1007
1008
1009
1010
1011
1012
1013
1014
1015 /**
1016 * Internal dependencies
1017 */
1018
1019
1020
1021 function PatternsManageButton({
1022 clientId
1023 }) {
1024 const {
1025 canRemove,
1026 isVisible,
1027 managePatternsUrl
1028 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
1029 const {
1030 getBlock,
1031 canRemoveBlock,
1032 getBlockCount
1033 } = select(external_wp_blockEditor_namespaceObject.store);
1034 const {
1035 canUser
1036 } = select(external_wp_coreData_namespaceObject.store);
1037 const reusableBlock = getBlock(clientId);
1038 return {
1039 canRemove: canRemoveBlock(clientId),
1040 isVisible: !!reusableBlock && (0,external_wp_blocks_namespaceObject.isReusableBlock)(reusableBlock) && !!canUser('update', {
1041 kind: 'postType',
1042 name: 'wp_block',
1043 id: reusableBlock.attributes.ref
1044 }),
1045 innerBlockCount: getBlockCount(clientId),
1046 // The site editor and templates both check whether the user
1047 // has edit_theme_options capabilities. We can leverage that here
1048 // and omit the manage patterns link if the user can't access it.
1049 managePatternsUrl: canUser('create', {
1050 kind: 'postType',
1051 name: 'wp_template'
1052 }) ? (0,external_wp_url_namespaceObject.addQueryArgs)('site-editor.php', {
1053 path: '/patterns'
1054 }) : (0,external_wp_url_namespaceObject.addQueryArgs)('edit.php', {
1055 post_type: 'wp_block'
1056 })
1057 };
1058 }, [clientId]);
1059
1060 // Ignore reason: false positive of the lint rule.
1061 // eslint-disable-next-line @wordpress/no-unused-vars-before-return
1062 const {
1063 convertSyncedPatternToStatic
1064 } = unlock((0,external_wp_data_namespaceObject.useDispatch)(store));
1065 if (!isVisible) {
1066 return null;
1067 }
1068 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_ReactJSXRuntime_namespaceObject.Fragment, {
1069 children: [canRemove && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.MenuItem, {
1070 onClick: () => convertSyncedPatternToStatic(clientId),
1071 children: (0,external_wp_i18n_namespaceObject.__)('Detach')
1072 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.MenuItem, {
1073 href: managePatternsUrl,
1074 children: (0,external_wp_i18n_namespaceObject.__)('Manage patterns')
1075 })]
1076 });
1077 }
1078 /* harmony default export */ const patterns_manage_button = (PatternsManageButton);
1079
1080 ;// ./packages/patterns/build-module/components/index.js
1081 /**
1082 * WordPress dependencies
1083 */
1084
1085
1086 /**
1087 * Internal dependencies
1088 */
1089
1090
1091
1092 function PatternsMenuItems({
1093 rootClientId
1094 }) {
1095 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_blockEditor_namespaceObject.BlockSettingsMenuControls, {
1096 children: ({
1097 selectedClientIds,
1098 onClose
1099 }) => /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_ReactJSXRuntime_namespaceObject.Fragment, {
1100 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(PatternConvertButton, {
1101 clientIds: selectedClientIds,
1102 rootClientId: rootClientId,
1103 closeBlockSettingsMenu: onClose
1104 }), selectedClientIds.length === 1 && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(patterns_manage_button, {
1105 clientId: selectedClientIds[0]
1106 })]
1107 })
1108 });
1109 }
1110
1111 ;// external ["wp","a11y"]
1112 const external_wp_a11y_namespaceObject = window["wp"]["a11y"];
1113 ;// ./packages/patterns/build-module/components/rename-pattern-category-modal.js
1114 /**
1115 * WordPress dependencies
1116 */
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126 /**
1127 * Internal dependencies
1128 */
1129
1130
1131 function RenamePatternCategoryModal({
1132 category,
1133 existingCategories,
1134 onClose,
1135 onError,
1136 onSuccess,
1137 ...props
1138 }) {
1139 const id = (0,external_wp_element_namespaceObject.useId)();
1140 const textControlRef = (0,external_wp_element_namespaceObject.useRef)();
1141 const [name, setName] = (0,external_wp_element_namespaceObject.useState)((0,external_wp_htmlEntities_namespaceObject.decodeEntities)(category.name));
1142 const [isSaving, setIsSaving] = (0,external_wp_element_namespaceObject.useState)(false);
1143 const [validationMessage, setValidationMessage] = (0,external_wp_element_namespaceObject.useState)(false);
1144 const validationMessageId = validationMessage ? `patterns-rename-pattern-category-modal__validation-message-${id}` : undefined;
1145 const {
1146 saveEntityRecord,
1147 invalidateResolution
1148 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_coreData_namespaceObject.store);
1149 const {
1150 createErrorNotice,
1151 createSuccessNotice
1152 } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_notices_namespaceObject.store);
1153 const onChange = newName => {
1154 if (validationMessage) {
1155 setValidationMessage(undefined);
1156 }
1157 setName(newName);
1158 };
1159 const onSave = async event => {
1160 event.preventDefault();
1161 if (isSaving) {
1162 return;
1163 }
1164 if (!name || name === category.name) {
1165 const message = (0,external_wp_i18n_namespaceObject.__)('Please enter a new name for this category.');
1166 (0,external_wp_a11y_namespaceObject.speak)(message, 'assertive');
1167 setValidationMessage(message);
1168 textControlRef.current?.focus();
1169 return;
1170 }
1171
1172 // Check existing categories to avoid creating duplicates.
1173 if (existingCategories.patternCategories.find(existingCategory => {
1174 // Compare the id so that the we don't disallow the user changing the case of their current category
1175 // (i.e. renaming 'test' to 'Test').
1176 return existingCategory.id !== category.id && existingCategory.label.toLowerCase() === name.toLowerCase();
1177 })) {
1178 const message = (0,external_wp_i18n_namespaceObject.__)('This category already exists. Please use a different name.');
1179 (0,external_wp_a11y_namespaceObject.speak)(message, 'assertive');
1180 setValidationMessage(message);
1181 textControlRef.current?.focus();
1182 return;
1183 }
1184 try {
1185 setIsSaving(true);
1186
1187 // User pattern category properties may differ as they can be
1188 // normalized for use alongside template part areas, core pattern
1189 // categories etc. As a result we won't just destructure the passed
1190 // category object.
1191 const savedRecord = await saveEntityRecord('taxonomy', CATEGORY_SLUG, {
1192 id: category.id,
1193 slug: category.slug,
1194 name
1195 });
1196 invalidateResolution('getUserPatternCategories');
1197 onSuccess?.(savedRecord);
1198 onClose();
1199 createSuccessNotice((0,external_wp_i18n_namespaceObject.__)('Pattern category renamed.'), {
1200 type: 'snackbar',
1201 id: 'pattern-category-update'
1202 });
1203 } catch (error) {
1204 onError?.();
1205 createErrorNotice(error.message, {
1206 type: 'snackbar',
1207 id: 'pattern-category-update'
1208 });
1209 } finally {
1210 setIsSaving(false);
1211 setName('');
1212 }
1213 };
1214 const onRequestClose = () => {
1215 onClose();
1216 setName('');
1217 };
1218 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Modal, {
1219 title: (0,external_wp_i18n_namespaceObject.__)('Rename'),
1220 onRequestClose: onRequestClose,
1221 ...props,
1222 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("form", {
1223 onSubmit: onSave,
1224 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalVStack, {
1225 spacing: "5",
1226 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalVStack, {
1227 spacing: "2",
1228 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.TextControl, {
1229 ref: textControlRef,
1230 __nextHasNoMarginBottom: true,
1231 __next40pxDefaultSize: true,
1232 label: (0,external_wp_i18n_namespaceObject.__)('Name'),
1233 value: name,
1234 onChange: onChange,
1235 "aria-describedby": validationMessageId,
1236 required: true
1237 }), validationMessage && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("span", {
1238 className: "patterns-rename-pattern-category-modal__validation-message",
1239 id: validationMessageId,
1240 children: validationMessage
1241 })]
1242 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalHStack, {
1243 justify: "right",
1244 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1245 __next40pxDefaultSize: true,
1246 variant: "tertiary",
1247 onClick: onRequestClose,
1248 children: (0,external_wp_i18n_namespaceObject.__)('Cancel')
1249 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1250 __next40pxDefaultSize: true,
1251 variant: "primary",
1252 type: "submit",
1253 "aria-disabled": !name || name === category.name || isSaving,
1254 isBusy: isSaving,
1255 children: (0,external_wp_i18n_namespaceObject.__)('Save')
1256 })]
1257 })]
1258 })
1259 })
1260 });
1261 }
1262
1263 ;// ./packages/patterns/build-module/components/allow-overrides-modal.js
1264 /**
1265 * WordPress dependencies
1266 */
1267
1268
1269
1270
1271
1272 function AllowOverridesModal({
1273 placeholder,
1274 initialName = '',
1275 onClose,
1276 onSave
1277 }) {
1278 const [editedBlockName, setEditedBlockName] = (0,external_wp_element_namespaceObject.useState)(initialName);
1279 const descriptionId = (0,external_wp_element_namespaceObject.useId)();
1280 const isNameValid = !!editedBlockName.trim();
1281 const handleSubmit = () => {
1282 if (editedBlockName !== initialName) {
1283 const message = (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %s: new name/label for the block */
1284 (0,external_wp_i18n_namespaceObject.__)('Block name changed to: "%s".'), editedBlockName);
1285
1286 // Must be assertive to immediately announce change.
1287 (0,external_wp_a11y_namespaceObject.speak)(message, 'assertive');
1288 }
1289 onSave(editedBlockName);
1290
1291 // Immediate close avoids ability to hit save multiple times.
1292 onClose();
1293 };
1294 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Modal, {
1295 title: (0,external_wp_i18n_namespaceObject.__)('Enable overrides'),
1296 onRequestClose: onClose,
1297 focusOnMount: "firstContentElement",
1298 aria: {
1299 describedby: descriptionId
1300 },
1301 size: "small",
1302 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("form", {
1303 onSubmit: event => {
1304 event.preventDefault();
1305 if (!isNameValid) {
1306 return;
1307 }
1308 handleSubmit();
1309 },
1310 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalVStack, {
1311 spacing: "6",
1312 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.__experimentalText, {
1313 id: descriptionId,
1314 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.')
1315 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.TextControl, {
1316 __nextHasNoMarginBottom: true,
1317 __next40pxDefaultSize: true,
1318 value: editedBlockName,
1319 label: (0,external_wp_i18n_namespaceObject.__)('Name'),
1320 help: (0,external_wp_i18n_namespaceObject.__)('For example, if you are creating a recipe pattern, you use "Recipe Title", "Recipe Description", etc.'),
1321 placeholder: placeholder,
1322 onChange: setEditedBlockName
1323 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalHStack, {
1324 justify: "right",
1325 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1326 __next40pxDefaultSize: true,
1327 variant: "tertiary",
1328 onClick: onClose,
1329 children: (0,external_wp_i18n_namespaceObject.__)('Cancel')
1330 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1331 __next40pxDefaultSize: true,
1332 "aria-disabled": !isNameValid,
1333 variant: "primary",
1334 type: "submit",
1335 children: (0,external_wp_i18n_namespaceObject.__)('Enable')
1336 })]
1337 })]
1338 })
1339 })
1340 });
1341 }
1342 function DisallowOverridesModal({
1343 onClose,
1344 onSave
1345 }) {
1346 const descriptionId = (0,external_wp_element_namespaceObject.useId)();
1347 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Modal, {
1348 title: (0,external_wp_i18n_namespaceObject.__)('Disable overrides'),
1349 onRequestClose: onClose,
1350 aria: {
1351 describedby: descriptionId
1352 },
1353 size: "small",
1354 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("form", {
1355 onSubmit: event => {
1356 event.preventDefault();
1357 onSave();
1358 onClose();
1359 },
1360 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalVStack, {
1361 spacing: "6",
1362 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.__experimentalText, {
1363 id: descriptionId,
1364 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.')
1365 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalHStack, {
1366 justify: "right",
1367 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1368 __next40pxDefaultSize: true,
1369 variant: "tertiary",
1370 onClick: onClose,
1371 children: (0,external_wp_i18n_namespaceObject.__)('Cancel')
1372 }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1373 __next40pxDefaultSize: true,
1374 variant: "primary",
1375 type: "submit",
1376 children: (0,external_wp_i18n_namespaceObject.__)('Disable')
1377 })]
1378 })]
1379 })
1380 })
1381 });
1382 }
1383
1384 ;// ./packages/patterns/build-module/components/pattern-overrides-controls.js
1385 /**
1386 * WordPress dependencies
1387 */
1388
1389
1390
1391
1392
1393 /**
1394 * Internal dependencies
1395 */
1396
1397
1398
1399 function PatternOverridesControls({
1400 attributes,
1401 setAttributes,
1402 name: blockName
1403 }) {
1404 const controlId = (0,external_wp_element_namespaceObject.useId)();
1405 const [showAllowOverridesModal, setShowAllowOverridesModal] = (0,external_wp_element_namespaceObject.useState)(false);
1406 const [showDisallowOverridesModal, setShowDisallowOverridesModal] = (0,external_wp_element_namespaceObject.useState)(false);
1407 const hasName = !!attributes.metadata?.name;
1408 const defaultBindings = attributes.metadata?.bindings?.__default;
1409 const hasOverrides = hasName && defaultBindings?.source === PATTERN_OVERRIDES_BINDING_SOURCE;
1410 const isConnectedToOtherSources = defaultBindings?.source && defaultBindings.source !== PATTERN_OVERRIDES_BINDING_SOURCE;
1411 const {
1412 updateBlockBindings
1413 } = (0,external_wp_blockEditor_namespaceObject.useBlockBindingsUtils)();
1414 function updateBindings(isChecked, customName) {
1415 if (customName) {
1416 setAttributes({
1417 metadata: {
1418 ...attributes.metadata,
1419 name: customName
1420 }
1421 });
1422 }
1423 updateBlockBindings({
1424 __default: isChecked ? {
1425 source: PATTERN_OVERRIDES_BINDING_SOURCE
1426 } : undefined
1427 });
1428 }
1429
1430 // Avoid overwriting other (e.g. meta) bindings.
1431 if (isConnectedToOtherSources) {
1432 return null;
1433 }
1434 const hasUnsupportedImageAttributes = blockName === 'core/image' && (!!attributes.caption?.length || !!attributes.href?.length);
1435 const helpText = !hasOverrides && hasUnsupportedImageAttributes ? (0,external_wp_i18n_namespaceObject.__)(`Overrides currently don't support image captions or links. Remove the caption or link first before enabling overrides.`) : (0,external_wp_i18n_namespaceObject.__)('Allow changes to this block throughout instances of this pattern.');
1436 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_ReactJSXRuntime_namespaceObject.Fragment, {
1437 children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_blockEditor_namespaceObject.InspectorControls, {
1438 group: "advanced",
1439 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.BaseControl, {
1440 __nextHasNoMarginBottom: true,
1441 id: controlId,
1442 label: (0,external_wp_i18n_namespaceObject.__)('Overrides'),
1443 help: helpText,
1444 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
1445 __next40pxDefaultSize: true,
1446 className: "pattern-overrides-control__allow-overrides-button",
1447 variant: "secondary",
1448 "aria-haspopup": "dialog",
1449 onClick: () => {
1450 if (hasOverrides) {
1451 setShowDisallowOverridesModal(true);
1452 } else {
1453 setShowAllowOverridesModal(true);
1454 }
1455 },
1456 disabled: !hasOverrides && hasUnsupportedImageAttributes,
1457 accessibleWhenDisabled: true,
1458 children: hasOverrides ? (0,external_wp_i18n_namespaceObject.__)('Disable overrides') : (0,external_wp_i18n_namespaceObject.__)('Enable overrides')
1459 })
1460 })
1461 }), showAllowOverridesModal && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(AllowOverridesModal, {
1462 initialName: attributes.metadata?.name,
1463 onClose: () => setShowAllowOverridesModal(false),
1464 onSave: newName => {
1465 updateBindings(true, newName);
1466 }
1467 }), showDisallowOverridesModal && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(DisallowOverridesModal, {
1468 onClose: () => setShowDisallowOverridesModal(false),
1469 onSave: () => updateBindings(false)
1470 })]
1471 });
1472 }
1473 /* harmony default export */ const pattern_overrides_controls = (PatternOverridesControls);
1474
1475 ;// ./packages/patterns/build-module/components/reset-overrides-control.js
1476 /**
1477 * WordPress dependencies
1478 */
1479
1480
1481
1482
1483
1484 const CONTENT = 'content';
1485 function ResetOverridesControl(props) {
1486 const name = props.attributes.metadata?.name;
1487 const registry = (0,external_wp_data_namespaceObject.useRegistry)();
1488 const isOverriden = (0,external_wp_data_namespaceObject.useSelect)(select => {
1489 if (!name) {
1490 return;
1491 }
1492 const {
1493 getBlockAttributes,
1494 getBlockParentsByBlockName
1495 } = select(external_wp_blockEditor_namespaceObject.store);
1496 const [patternClientId] = getBlockParentsByBlockName(props.clientId, 'core/block', true);
1497 if (!patternClientId) {
1498 return;
1499 }
1500 const overrides = getBlockAttributes(patternClientId)[CONTENT];
1501 if (!overrides) {
1502 return;
1503 }
1504 return overrides.hasOwnProperty(name);
1505 }, [props.clientId, name]);
1506 function onClick() {
1507 const {
1508 getBlockAttributes,
1509 getBlockParentsByBlockName
1510 } = registry.select(external_wp_blockEditor_namespaceObject.store);
1511 const [patternClientId] = getBlockParentsByBlockName(props.clientId, 'core/block', true);
1512 if (!patternClientId) {
1513 return;
1514 }
1515 const overrides = getBlockAttributes(patternClientId)[CONTENT];
1516 if (!overrides.hasOwnProperty(name)) {
1517 return;
1518 }
1519 const {
1520 updateBlockAttributes,
1521 __unstableMarkLastChangeAsPersistent
1522 } = registry.dispatch(external_wp_blockEditor_namespaceObject.store);
1523 __unstableMarkLastChangeAsPersistent();
1524 let newOverrides = {
1525 ...overrides
1526 };
1527 delete newOverrides[name];
1528 if (!Object.keys(newOverrides).length) {
1529 newOverrides = undefined;
1530 }
1531 updateBlockAttributes(patternClientId, {
1532 [CONTENT]: newOverrides
1533 });
1534 }
1535 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_blockEditor_namespaceObject.__unstableBlockToolbarLastItem, {
1536 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.ToolbarGroup, {
1537 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.ToolbarButton, {
1538 onClick: onClick,
1539 disabled: !isOverriden,
1540 children: (0,external_wp_i18n_namespaceObject.__)('Reset')
1541 })
1542 })
1543 });
1544 }
1545
1546 ;// ./packages/icons/build-module/library/copy.js
1547 /**
1548 * WordPress dependencies
1549 */
1550
1551
1552 const copy = /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.SVG, {
1553 xmlns: "http://www.w3.org/2000/svg",
1554 viewBox: "0 0 24 24",
1555 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.Path, {
1556 fillRule: "evenodd",
1557 clipRule: "evenodd",
1558 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"
1559 })
1560 });
1561 /* harmony default export */ const library_copy = (copy);
1562
1563 ;// ./packages/patterns/build-module/components/pattern-overrides-block-controls.js
1564 /* wp:polyfill */
1565 /**
1566 * WordPress dependencies
1567 */
1568
1569
1570
1571
1572
1573
1574
1575
1576 /**
1577 * Internal dependencies
1578 */
1579
1580
1581
1582 const {
1583 useBlockDisplayTitle
1584 } = unlock(external_wp_blockEditor_namespaceObject.privateApis);
1585 function PatternOverridesToolbarIndicator({
1586 clientIds
1587 }) {
1588 const isSingleBlockSelected = clientIds.length === 1;
1589 const {
1590 icon,
1591 firstBlockName
1592 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
1593 const {
1594 getBlockAttributes,
1595 getBlockNamesByClientId
1596 } = select(external_wp_blockEditor_namespaceObject.store);
1597 const {
1598 getBlockType,
1599 getActiveBlockVariation
1600 } = select(external_wp_blocks_namespaceObject.store);
1601 const blockTypeNames = getBlockNamesByClientId(clientIds);
1602 const _firstBlockTypeName = blockTypeNames[0];
1603 const firstBlockType = getBlockType(_firstBlockTypeName);
1604 let _icon;
1605 if (isSingleBlockSelected) {
1606 const match = getActiveBlockVariation(_firstBlockTypeName, getBlockAttributes(clientIds[0]));
1607 // Take into account active block variations.
1608 _icon = match?.icon || firstBlockType.icon;
1609 } else {
1610 const isSelectionOfSameType = new Set(blockTypeNames).size === 1;
1611 // When selection consists of blocks of multiple types, display an
1612 // appropriate icon to communicate the non-uniformity.
1613 _icon = isSelectionOfSameType ? firstBlockType.icon : library_copy;
1614 }
1615 return {
1616 icon: _icon,
1617 firstBlockName: getBlockAttributes(clientIds[0]).metadata.name
1618 };
1619 }, [clientIds, isSingleBlockSelected]);
1620 const firstBlockTitle = useBlockDisplayTitle({
1621 clientId: clientIds[0],
1622 maximumLength: 35
1623 });
1624 const blockDescription = isSingleBlockSelected ? (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: 1: The block type's name. 2: The block's user-provided name (the same as the override name). */
1625 (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.');
1626 const descriptionId = (0,external_wp_element_namespaceObject.useId)();
1627 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.ToolbarItem, {
1628 children: toggleProps => /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.DropdownMenu, {
1629 className: "patterns-pattern-overrides-toolbar-indicator",
1630 label: firstBlockTitle,
1631 popoverProps: {
1632 placement: 'bottom-start',
1633 className: 'patterns-pattern-overrides-toolbar-indicator__popover'
1634 },
1635 icon: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_ReactJSXRuntime_namespaceObject.Fragment, {
1636 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_blockEditor_namespaceObject.BlockIcon, {
1637 icon: icon,
1638 className: "patterns-pattern-overrides-toolbar-indicator-icon",
1639 showColors: true
1640 })
1641 }),
1642 toggleProps: {
1643 description: blockDescription,
1644 ...toggleProps
1645 },
1646 menuProps: {
1647 orientation: 'both',
1648 'aria-describedby': descriptionId
1649 },
1650 children: () => /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.__experimentalText, {
1651 id: descriptionId,
1652 children: blockDescription
1653 })
1654 })
1655 });
1656 }
1657 function PatternOverridesBlockControls() {
1658 const {
1659 clientIds,
1660 hasPatternOverrides,
1661 hasParentPattern
1662 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
1663 const {
1664 getBlockAttributes,
1665 getSelectedBlockClientIds,
1666 getBlockParentsByBlockName
1667 } = select(external_wp_blockEditor_namespaceObject.store);
1668 const selectedClientIds = getSelectedBlockClientIds();
1669 const _hasPatternOverrides = selectedClientIds.every(clientId => {
1670 var _getBlockAttributes$m;
1671 return Object.values((_getBlockAttributes$m = getBlockAttributes(clientId)?.metadata?.bindings) !== null && _getBlockAttributes$m !== void 0 ? _getBlockAttributes$m : {}).some(binding => binding?.source === PATTERN_OVERRIDES_BINDING_SOURCE);
1672 });
1673 const _hasParentPattern = selectedClientIds.every(clientId => getBlockParentsByBlockName(clientId, 'core/block', true).length > 0);
1674 return {
1675 clientIds: selectedClientIds,
1676 hasPatternOverrides: _hasPatternOverrides,
1677 hasParentPattern: _hasParentPattern
1678 };
1679 }, []);
1680 return hasPatternOverrides && hasParentPattern ? /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_blockEditor_namespaceObject.BlockControls, {
1681 group: "parent",
1682 children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(PatternOverridesToolbarIndicator, {
1683 clientIds: clientIds
1684 })
1685 }) : null;
1686 }
1687
1688 ;// ./packages/patterns/build-module/private-apis.js
1689 /**
1690 * Internal dependencies
1691 */
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705 const privateApis = {};
1706 lock(privateApis, {
1707 OverridesPanel: OverridesPanel,
1708 CreatePatternModal: CreatePatternModal,
1709 CreatePatternModalContents: CreatePatternModalContents,
1710 DuplicatePatternModal: DuplicatePatternModal,
1711 isOverridableBlock: isOverridableBlock,
1712 hasOverridableBlocks: hasOverridableBlocks,
1713 useDuplicatePatternProps: useDuplicatePatternProps,
1714 RenamePatternModal: RenamePatternModal,
1715 PatternsMenuItems: PatternsMenuItems,
1716 RenamePatternCategoryModal: RenamePatternCategoryModal,
1717 PatternOverridesControls: pattern_overrides_controls,
1718 ResetOverridesControl: ResetOverridesControl,
1719 PatternOverridesBlockControls: PatternOverridesBlockControls,
1720 useAddPatternCategory: useAddPatternCategory,
1721 PATTERN_TYPES: PATTERN_TYPES,
1722 PATTERN_DEFAULT_CATEGORY: PATTERN_DEFAULT_CATEGORY,
1723 PATTERN_USER_CATEGORY: PATTERN_USER_CATEGORY,
1724 EXCLUDED_PATTERN_SOURCES: EXCLUDED_PATTERN_SOURCES,
1725 PATTERN_SYNC_TYPES: PATTERN_SYNC_TYPES,
1726 PARTIAL_SYNCING_SUPPORTED_BLOCKS: PARTIAL_SYNCING_SUPPORTED_BLOCKS
1727 });
1728
1729 ;// ./packages/patterns/build-module/index.js
1730 /**
1731 * Internal dependencies
1732 */
1733
1734
1735
1736 (window.wp = window.wp || {}).patterns = __webpack_exports__;
1737 /******/ })()
1738 ;