PluginProbe
Gutenberg / 22.2.0
Gutenberg v22.2.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 / scripts / patterns / index.js

index.js in Gutenberg 22.2.0, at build/scripts/patterns/index.js

1,522 lines 57.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 var wp;
2 (wp ||= {}).patterns = (() => {
3 var __create = Object.create;
4 var __defProp = Object.defineProperty;
5 var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6 var __getOwnPropNames = Object.getOwnPropertyNames;
7 var __getProtoOf = Object.getPrototypeOf;
8 var __hasOwnProp = Object.prototype.hasOwnProperty;
9 var __commonJS = (cb, mod) => function __require() {
10 return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11 };
12 var __export = (target, all) => {
13 for (var name in all)
14 __defProp(target, name, { get: all[name], enumerable: true });
15 };
16 var __copyProps = (to, from, except, desc) => {
17 if (from && typeof from === "object" || typeof from === "function") {
18 for (let key of __getOwnPropNames(from))
19 if (!__hasOwnProp.call(to, key) && key !== except)
20 __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21 }
22 return to;
23 };
24 var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25 // If the importer is in node compatibility mode or this is not an ESM
26 // file that has been converted to a CommonJS file using a Babel-
27 // compatible transform (i.e. "__esModule" has not been set), then set
28 // "default" to the CommonJS "module.exports" for node compatibility.
29 isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30 mod
31 ));
32 var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
34 // package-external:@wordpress/data
35 var require_data = __commonJS({
36 "package-external:@wordpress/data"(exports, module) {
37 module.exports = window.wp.data;
38 }
39 });
40
41 // package-external:@wordpress/blocks
42 var require_blocks = __commonJS({
43 "package-external:@wordpress/blocks"(exports, module) {
44 module.exports = window.wp.blocks;
45 }
46 });
47
48 // package-external:@wordpress/core-data
49 var require_core_data = __commonJS({
50 "package-external:@wordpress/core-data"(exports, module) {
51 module.exports = window.wp.coreData;
52 }
53 });
54
55 // package-external:@wordpress/block-editor
56 var require_block_editor = __commonJS({
57 "package-external:@wordpress/block-editor"(exports, module) {
58 module.exports = window.wp.blockEditor;
59 }
60 });
61
62 // package-external:@wordpress/private-apis
63 var require_private_apis = __commonJS({
64 "package-external:@wordpress/private-apis"(exports, module) {
65 module.exports = window.wp.privateApis;
66 }
67 });
68
69 // package-external:@wordpress/components
70 var require_components = __commonJS({
71 "package-external:@wordpress/components"(exports, module) {
72 module.exports = window.wp.components;
73 }
74 });
75
76 // package-external:@wordpress/element
77 var require_element = __commonJS({
78 "package-external:@wordpress/element"(exports, module) {
79 module.exports = window.wp.element;
80 }
81 });
82
83 // package-external:@wordpress/i18n
84 var require_i18n = __commonJS({
85 "package-external:@wordpress/i18n"(exports, module) {
86 module.exports = window.wp.i18n;
87 }
88 });
89
90 // vendor-external:react/jsx-runtime
91 var require_jsx_runtime = __commonJS({
92 "vendor-external:react/jsx-runtime"(exports, module) {
93 module.exports = window.ReactJSXRuntime;
94 }
95 });
96
97 // package-external:@wordpress/notices
98 var require_notices = __commonJS({
99 "package-external:@wordpress/notices"(exports, module) {
100 module.exports = window.wp.notices;
101 }
102 });
103
104 // package-external:@wordpress/compose
105 var require_compose = __commonJS({
106 "package-external:@wordpress/compose"(exports, module) {
107 module.exports = window.wp.compose;
108 }
109 });
110
111 // package-external:@wordpress/html-entities
112 var require_html_entities = __commonJS({
113 "package-external:@wordpress/html-entities"(exports, module) {
114 module.exports = window.wp.htmlEntities;
115 }
116 });
117
118 // package-external:@wordpress/primitives
119 var require_primitives = __commonJS({
120 "package-external:@wordpress/primitives"(exports, module) {
121 module.exports = window.wp.primitives;
122 }
123 });
124
125 // package-external:@wordpress/url
126 var require_url = __commonJS({
127 "package-external:@wordpress/url"(exports, module) {
128 module.exports = window.wp.url;
129 }
130 });
131
132 // package-external:@wordpress/a11y
133 var require_a11y = __commonJS({
134 "package-external:@wordpress/a11y"(exports, module) {
135 module.exports = window.wp.a11y;
136 }
137 });
138
139 // packages/patterns/build-module/index.js
140 var index_exports = {};
141 __export(index_exports, {
142 privateApis: () => privateApis,
143 store: () => store
144 });
145
146 // packages/patterns/build-module/store/index.js
147 var import_data2 = __toESM(require_data());
148
149 // packages/patterns/build-module/store/reducer.js
150 var import_data = __toESM(require_data());
151 function isEditingPattern(state = {}, action) {
152 if (action?.type === "SET_EDITING_PATTERN") {
153 return {
154 ...state,
155 [action.clientId]: action.isEditing
156 };
157 }
158 return state;
159 }
160 var reducer_default = (0, import_data.combineReducers)({
161 isEditingPattern
162 });
163
164 // packages/patterns/build-module/store/actions.js
165 var actions_exports = {};
166 __export(actions_exports, {
167 convertSyncedPatternToStatic: () => convertSyncedPatternToStatic,
168 createPattern: () => createPattern,
169 createPatternFromFile: () => createPatternFromFile,
170 setEditingPattern: () => setEditingPattern
171 });
172 var import_blocks = __toESM(require_blocks());
173 var import_core_data = __toESM(require_core_data());
174 var import_block_editor = __toESM(require_block_editor());
175
176 // packages/patterns/build-module/constants.js
177 var PATTERN_TYPES = {
178 theme: "pattern",
179 user: "wp_block"
180 };
181 var PATTERN_DEFAULT_CATEGORY = "all-patterns";
182 var PATTERN_USER_CATEGORY = "my-patterns";
183 var EXCLUDED_PATTERN_SOURCES = [
184 "core",
185 "pattern-directory/core",
186 "pattern-directory/featured"
187 ];
188 var PATTERN_SYNC_TYPES = {
189 full: "fully",
190 unsynced: "unsynced"
191 };
192 var PARTIAL_SYNCING_SUPPORTED_BLOCKS = {
193 "core/paragraph": ["content"],
194 "core/heading": ["content"],
195 "core/button": ["text", "url", "linkTarget", "rel"],
196 "core/image": ["id", "url", "title", "alt", "caption"]
197 };
198 var PATTERN_OVERRIDES_BINDING_SOURCE = "core/pattern-overrides";
199
200 // packages/patterns/build-module/store/actions.js
201 var createPattern = (title, syncType, content, categories) => async ({ registry }) => {
202 const meta = syncType === PATTERN_SYNC_TYPES.unsynced ? {
203 wp_pattern_sync_status: syncType
204 } : void 0;
205 const reusableBlock = {
206 title,
207 content,
208 status: "publish",
209 meta,
210 wp_pattern_category: categories
211 };
212 const updatedRecord = await registry.dispatch(import_core_data.store).saveEntityRecord("postType", "wp_block", reusableBlock);
213 return updatedRecord;
214 };
215 var createPatternFromFile = (file, categories) => async ({ dispatch }) => {
216 const fileContent = await file.text();
217 let parsedContent;
218 try {
219 parsedContent = JSON.parse(fileContent);
220 } catch (e) {
221 throw new Error("Invalid JSON file");
222 }
223 if (parsedContent.__file !== "wp_block" || !parsedContent.title || !parsedContent.content || typeof parsedContent.title !== "string" || typeof parsedContent.content !== "string" || parsedContent.syncStatus && typeof parsedContent.syncStatus !== "string") {
224 throw new Error("Invalid pattern JSON file");
225 }
226 const pattern = await dispatch.createPattern(
227 parsedContent.title,
228 parsedContent.syncStatus,
229 parsedContent.content,
230 categories
231 );
232 return pattern;
233 };
234 var convertSyncedPatternToStatic = (clientId) => ({ registry }) => {
235 const patternBlock = registry.select(import_block_editor.store).getBlock(clientId);
236 const existingOverrides = patternBlock.attributes?.content;
237 function cloneBlocksAndRemoveBindings(blocks) {
238 return blocks.map((block) => {
239 let metadata = block.attributes.metadata;
240 if (metadata) {
241 metadata = { ...metadata };
242 delete metadata.id;
243 delete metadata.bindings;
244 if (existingOverrides?.[metadata.name]) {
245 for (const [attributeName, value] of Object.entries(
246 existingOverrides[metadata.name]
247 )) {
248 if (!(0, import_blocks.getBlockType)(block.name)?.attributes[attributeName]) {
249 continue;
250 }
251 block.attributes[attributeName] = value;
252 }
253 }
254 }
255 return (0, import_blocks.cloneBlock)(
256 block,
257 {
258 metadata: metadata && Object.keys(metadata).length > 0 ? metadata : void 0
259 },
260 cloneBlocksAndRemoveBindings(block.innerBlocks)
261 );
262 });
263 }
264 const patternInnerBlocks = registry.select(import_block_editor.store).getBlocks(patternBlock.clientId);
265 registry.dispatch(import_block_editor.store).replaceBlocks(
266 patternBlock.clientId,
267 cloneBlocksAndRemoveBindings(patternInnerBlocks)
268 );
269 };
270 function setEditingPattern(clientId, isEditing) {
271 return {
272 type: "SET_EDITING_PATTERN",
273 clientId,
274 isEditing
275 };
276 }
277
278 // packages/patterns/build-module/store/constants.js
279 var STORE_NAME = "core/patterns";
280
281 // packages/patterns/build-module/store/selectors.js
282 var selectors_exports = {};
283 __export(selectors_exports, {
284 isEditingPattern: () => isEditingPattern2
285 });
286 function isEditingPattern2(state, clientId) {
287 return state.isEditingPattern[clientId];
288 }
289
290 // packages/patterns/build-module/lock-unlock.js
291 var import_private_apis = __toESM(require_private_apis());
292 var { lock, unlock } = (0, import_private_apis.__dangerousOptInToUnstableAPIsOnlyForCoreModules)(
293 "I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.",
294 "@wordpress/patterns"
295 );
296
297 // packages/patterns/build-module/store/index.js
298 var storeConfig = {
299 reducer: reducer_default
300 };
301 var store = (0, import_data2.createReduxStore)(STORE_NAME, {
302 ...storeConfig
303 });
304 (0, import_data2.register)(store);
305 unlock(store).registerPrivateActions(actions_exports);
306 unlock(store).registerPrivateSelectors(selectors_exports);
307
308 // packages/patterns/build-module/components/overrides-panel.js
309 var import_block_editor2 = __toESM(require_block_editor());
310 var import_components = __toESM(require_components());
311 var import_data3 = __toESM(require_data());
312 var import_element = __toESM(require_element());
313 var import_i18n = __toESM(require_i18n());
314
315 // packages/patterns/build-module/api/index.js
316 function isOverridableBlock(block) {
317 return Object.keys(PARTIAL_SYNCING_SUPPORTED_BLOCKS).includes(
318 block.name
319 ) && !!block.attributes.metadata?.name && !!block.attributes.metadata?.bindings && Object.values(block.attributes.metadata.bindings).some(
320 (binding) => binding.source === "core/pattern-overrides"
321 );
322 }
323 function hasOverridableBlocks(blocks) {
324 return blocks.some((block) => {
325 if (isOverridableBlock(block)) {
326 return true;
327 }
328 return hasOverridableBlocks(block.innerBlocks);
329 });
330 }
331
332 // packages/patterns/build-module/components/overrides-panel.js
333 var import_jsx_runtime = __toESM(require_jsx_runtime());
334 var { BlockQuickNavigation } = unlock(import_block_editor2.privateApis);
335 function OverridesPanel() {
336 const allClientIds = (0, import_data3.useSelect)(
337 (select) => select(import_block_editor2.store).getClientIdsWithDescendants(),
338 []
339 );
340 const { getBlock } = (0, import_data3.useSelect)(import_block_editor2.store);
341 const clientIdsWithOverrides = (0, import_element.useMemo)(
342 () => allClientIds.filter((clientId) => {
343 const block = getBlock(clientId);
344 return isOverridableBlock(block);
345 }),
346 [allClientIds, getBlock]
347 );
348 if (!clientIdsWithOverrides?.length) {
349 return null;
350 }
351 return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.PanelBody, { title: (0, import_i18n.__)("Overrides"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BlockQuickNavigation, { clientIds: clientIdsWithOverrides }) });
352 }
353
354 // packages/patterns/build-module/components/create-pattern-modal.js
355 var import_components3 = __toESM(require_components());
356 var import_i18n3 = __toESM(require_i18n());
357 var import_element4 = __toESM(require_element());
358 var import_data5 = __toESM(require_data());
359 var import_notices = __toESM(require_notices());
360 var import_core_data3 = __toESM(require_core_data());
361
362 // packages/patterns/build-module/components/category-selector.js
363 var import_i18n2 = __toESM(require_i18n());
364 var import_element2 = __toESM(require_element());
365 var import_components2 = __toESM(require_components());
366 var import_compose = __toESM(require_compose());
367 var import_html_entities = __toESM(require_html_entities());
368 var import_jsx_runtime2 = __toESM(require_jsx_runtime());
369 var unescapeString = (arg) => {
370 return (0, import_html_entities.decodeEntities)(arg);
371 };
372 var CATEGORY_SLUG = "wp_pattern_category";
373 function CategorySelector({
374 categoryTerms,
375 onChange,
376 categoryMap
377 }) {
378 const [search, setSearch] = (0, import_element2.useState)("");
379 const debouncedSearch = (0, import_compose.useDebounce)(setSearch, 500);
380 const suggestions = (0, import_element2.useMemo)(() => {
381 return Array.from(categoryMap.values()).map((category) => unescapeString(category.label)).filter((category) => {
382 if (search !== "") {
383 return category.toLowerCase().includes(search.toLowerCase());
384 }
385 return true;
386 }).sort((a, b) => a.localeCompare(b));
387 }, [search, categoryMap]);
388 function handleChange(termNames) {
389 const uniqueTerms = termNames.reduce((terms, newTerm) => {
390 if (!terms.some(
391 (term) => term.toLowerCase() === newTerm.toLowerCase()
392 )) {
393 terms.push(newTerm);
394 }
395 return terms;
396 }, []);
397 onChange(uniqueTerms);
398 }
399 return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
400 import_components2.FormTokenField,
401 {
402 className: "patterns-menu-items__convert-modal-categories",
403 value: categoryTerms,
404 suggestions,
405 onChange: handleChange,
406 onInputChange: debouncedSearch,
407 label: (0, import_i18n2.__)("Categories"),
408 tokenizeOnBlur: true,
409 __experimentalExpandOnFocus: true,
410 __next40pxDefaultSize: true,
411 __nextHasNoMarginBottom: true
412 }
413 );
414 }
415
416 // packages/patterns/build-module/private-hooks.js
417 var import_data4 = __toESM(require_data());
418 var import_core_data2 = __toESM(require_core_data());
419 var import_element3 = __toESM(require_element());
420 function useAddPatternCategory() {
421 const { saveEntityRecord, invalidateResolution } = (0, import_data4.useDispatch)(import_core_data2.store);
422 const { corePatternCategories, userPatternCategories } = (0, import_data4.useSelect)(
423 (select) => {
424 const { getUserPatternCategories, getBlockPatternCategories } = select(import_core_data2.store);
425 return {
426 corePatternCategories: getBlockPatternCategories(),
427 userPatternCategories: getUserPatternCategories()
428 };
429 },
430 []
431 );
432 const categoryMap = (0, import_element3.useMemo)(() => {
433 const uniqueCategories = /* @__PURE__ */ new Map();
434 userPatternCategories.forEach((category) => {
435 uniqueCategories.set(category.label.toLowerCase(), {
436 label: category.label,
437 name: category.name,
438 id: category.id
439 });
440 });
441 corePatternCategories.forEach((category) => {
442 if (!uniqueCategories.has(category.label.toLowerCase()) && // There are two core categories with `Post` label so explicitly remove the one with
443 // the `query` slug to avoid any confusion.
444 category.name !== "query") {
445 uniqueCategories.set(category.label.toLowerCase(), {
446 label: category.label,
447 name: category.name
448 });
449 }
450 });
451 return uniqueCategories;
452 }, [userPatternCategories, corePatternCategories]);
453 async function findOrCreateTerm(term) {
454 try {
455 const existingTerm = categoryMap.get(term.toLowerCase());
456 if (existingTerm?.id) {
457 return existingTerm.id;
458 }
459 const termData = existingTerm ? { name: existingTerm.label, slug: existingTerm.name } : { name: term };
460 const newTerm = await saveEntityRecord(
461 "taxonomy",
462 CATEGORY_SLUG,
463 termData,
464 { throwOnError: true }
465 );
466 invalidateResolution("getUserPatternCategories");
467 return newTerm.id;
468 } catch (error) {
469 if (error.code !== "term_exists") {
470 throw error;
471 }
472 return error.data.term_id;
473 }
474 }
475 return { categoryMap, findOrCreateTerm };
476 }
477
478 // packages/patterns/build-module/components/create-pattern-modal.js
479 var import_jsx_runtime3 = __toESM(require_jsx_runtime());
480 function CreatePatternModal({
481 className = "patterns-menu-items__convert-modal",
482 modalTitle,
483 ...restProps
484 }) {
485 const defaultModalTitle = (0, import_data5.useSelect)(
486 (select) => select(import_core_data3.store).getPostType(PATTERN_TYPES.user)?.labels?.add_new_item,
487 []
488 );
489 return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
490 import_components3.Modal,
491 {
492 title: modalTitle || defaultModalTitle,
493 onRequestClose: restProps.onClose,
494 overlayClassName: className,
495 focusOnMount: "firstContentElement",
496 size: "small",
497 children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CreatePatternModalContents, { ...restProps })
498 }
499 );
500 }
501 function CreatePatternModalContents({
502 confirmLabel = (0, import_i18n3.__)("Add"),
503 defaultCategories = [],
504 content,
505 onClose,
506 onError,
507 onSuccess,
508 defaultSyncType = PATTERN_SYNC_TYPES.full,
509 defaultTitle = ""
510 }) {
511 const [syncType, setSyncType] = (0, import_element4.useState)(defaultSyncType);
512 const [categoryTerms, setCategoryTerms] = (0, import_element4.useState)(defaultCategories);
513 const [title, setTitle] = (0, import_element4.useState)(defaultTitle);
514 const [isSaving, setIsSaving] = (0, import_element4.useState)(false);
515 const { createPattern: createPattern2 } = unlock((0, import_data5.useDispatch)(store));
516 const { createErrorNotice } = (0, import_data5.useDispatch)(import_notices.store);
517 const { categoryMap, findOrCreateTerm } = useAddPatternCategory();
518 async function onCreate(patternTitle, sync) {
519 if (!title || isSaving) {
520 return;
521 }
522 try {
523 setIsSaving(true);
524 const categories = await Promise.all(
525 categoryTerms.map(
526 (termName) => findOrCreateTerm(termName)
527 )
528 );
529 const newPattern = await createPattern2(
530 patternTitle,
531 sync,
532 typeof content === "function" ? content() : content,
533 categories
534 );
535 onSuccess({
536 pattern: newPattern,
537 categoryId: PATTERN_DEFAULT_CATEGORY
538 });
539 } catch (error) {
540 createErrorNotice(error.message, {
541 type: "snackbar",
542 id: "pattern-create"
543 });
544 onError?.();
545 } finally {
546 setIsSaving(false);
547 setCategoryTerms([]);
548 setTitle("");
549 }
550 }
551 return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
552 "form",
553 {
554 onSubmit: (event) => {
555 event.preventDefault();
556 onCreate(title, syncType);
557 },
558 children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_components3.__experimentalVStack, { spacing: "5", children: [
559 /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
560 import_components3.TextControl,
561 {
562 label: (0, import_i18n3.__)("Name"),
563 value: title,
564 onChange: setTitle,
565 placeholder: (0, import_i18n3.__)("My pattern"),
566 className: "patterns-create-modal__name-input",
567 __nextHasNoMarginBottom: true,
568 __next40pxDefaultSize: true
569 }
570 ),
571 /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
572 CategorySelector,
573 {
574 categoryTerms,
575 onChange: setCategoryTerms,
576 categoryMap
577 }
578 ),
579 /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
580 import_components3.ToggleControl,
581 {
582 __nextHasNoMarginBottom: true,
583 label: (0, import_i18n3._x)("Synced", "pattern (singular)"),
584 help: (0, import_i18n3.__)(
585 "Sync this pattern across multiple locations."
586 ),
587 checked: syncType === PATTERN_SYNC_TYPES.full,
588 onChange: () => {
589 setSyncType(
590 syncType === PATTERN_SYNC_TYPES.full ? PATTERN_SYNC_TYPES.unsynced : PATTERN_SYNC_TYPES.full
591 );
592 }
593 }
594 ),
595 /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_components3.__experimentalHStack, { justify: "right", children: [
596 /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
597 import_components3.Button,
598 {
599 __next40pxDefaultSize: true,
600 variant: "tertiary",
601 onClick: () => {
602 onClose();
603 setTitle("");
604 },
605 children: (0, import_i18n3.__)("Cancel")
606 }
607 ),
608 /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
609 import_components3.Button,
610 {
611 __next40pxDefaultSize: true,
612 variant: "primary",
613 type: "submit",
614 "aria-disabled": !title || isSaving,
615 isBusy: isSaving,
616 children: confirmLabel
617 }
618 )
619 ] })
620 ] })
621 }
622 );
623 }
624
625 // packages/patterns/build-module/components/duplicate-pattern-modal.js
626 var import_core_data4 = __toESM(require_core_data());
627 var import_data6 = __toESM(require_data());
628 var import_i18n4 = __toESM(require_i18n());
629 var import_notices2 = __toESM(require_notices());
630 var import_jsx_runtime4 = __toESM(require_jsx_runtime());
631 function getTermLabels(pattern, categories) {
632 if (pattern.type !== PATTERN_TYPES.user) {
633 return categories.core?.filter(
634 (category) => pattern.categories?.includes(category.name)
635 ).map((category) => category.label);
636 }
637 return categories.user?.filter(
638 (category) => pattern.wp_pattern_category?.includes(category.id)
639 ).map((category) => category.label);
640 }
641 function useDuplicatePatternProps({ pattern, onSuccess }) {
642 const { createSuccessNotice } = (0, import_data6.useDispatch)(import_notices2.store);
643 const categories = (0, import_data6.useSelect)((select) => {
644 const { getUserPatternCategories, getBlockPatternCategories } = select(import_core_data4.store);
645 return {
646 core: getBlockPatternCategories(),
647 user: getUserPatternCategories()
648 };
649 });
650 if (!pattern) {
651 return null;
652 }
653 return {
654 content: pattern.content,
655 defaultCategories: getTermLabels(pattern, categories),
656 defaultSyncType: pattern.type !== PATTERN_TYPES.user ? PATTERN_SYNC_TYPES.unsynced : pattern.wp_pattern_sync_status || PATTERN_SYNC_TYPES.full,
657 defaultTitle: (0, import_i18n4.sprintf)(
658 /* translators: %s: Existing pattern title */
659 (0, import_i18n4._x)("%s (Copy)", "pattern"),
660 typeof pattern.title === "string" ? pattern.title : pattern.title.raw
661 ),
662 onSuccess: ({ pattern: newPattern }) => {
663 createSuccessNotice(
664 (0, import_i18n4.sprintf)(
665 // translators: %s: The new pattern's title e.g. 'Call to action (copy)'.
666 (0, import_i18n4._x)('"%s" duplicated.', "pattern"),
667 newPattern.title.raw
668 ),
669 {
670 type: "snackbar",
671 id: "patterns-create"
672 }
673 );
674 onSuccess?.({ pattern: newPattern });
675 }
676 };
677 }
678 function DuplicatePatternModal({
679 pattern,
680 onClose,
681 onSuccess
682 }) {
683 const duplicatedProps = useDuplicatePatternProps({ pattern, onSuccess });
684 if (!pattern) {
685 return null;
686 }
687 return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
688 CreatePatternModal,
689 {
690 modalTitle: (0, import_i18n4.__)("Duplicate pattern"),
691 confirmLabel: (0, import_i18n4.__)("Duplicate"),
692 onClose,
693 onError: onClose,
694 ...duplicatedProps
695 }
696 );
697 }
698
699 // packages/patterns/build-module/components/rename-pattern-modal.js
700 var import_components4 = __toESM(require_components());
701 var import_core_data5 = __toESM(require_core_data());
702 var import_data7 = __toESM(require_data());
703 var import_element5 = __toESM(require_element());
704 var import_html_entities2 = __toESM(require_html_entities());
705 var import_i18n5 = __toESM(require_i18n());
706 var import_notices3 = __toESM(require_notices());
707 var import_jsx_runtime5 = __toESM(require_jsx_runtime());
708 function RenamePatternModal({
709 onClose,
710 onError,
711 onSuccess,
712 pattern,
713 ...props
714 }) {
715 const originalName = (0, import_html_entities2.decodeEntities)(pattern.title);
716 const [name, setName] = (0, import_element5.useState)(originalName);
717 const [isSaving, setIsSaving] = (0, import_element5.useState)(false);
718 const {
719 editEntityRecord,
720 __experimentalSaveSpecifiedEntityEdits: saveSpecifiedEntityEdits
721 } = (0, import_data7.useDispatch)(import_core_data5.store);
722 const { createSuccessNotice, createErrorNotice } = (0, import_data7.useDispatch)(import_notices3.store);
723 const onRename = async (event) => {
724 event.preventDefault();
725 if (!name || name === pattern.title || isSaving) {
726 return;
727 }
728 try {
729 await editEntityRecord("postType", pattern.type, pattern.id, {
730 title: name
731 });
732 setIsSaving(true);
733 setName("");
734 onClose?.();
735 const savedRecord = await saveSpecifiedEntityEdits(
736 "postType",
737 pattern.type,
738 pattern.id,
739 ["title"],
740 { throwOnError: true }
741 );
742 onSuccess?.(savedRecord);
743 createSuccessNotice((0, import_i18n5.__)("Pattern renamed"), {
744 type: "snackbar",
745 id: "pattern-update"
746 });
747 } catch (error) {
748 onError?.();
749 const errorMessage = error.message && error.code !== "unknown_error" ? error.message : (0, import_i18n5.__)("An error occurred while renaming the pattern.");
750 createErrorNotice(errorMessage, {
751 type: "snackbar",
752 id: "pattern-update"
753 });
754 } finally {
755 setIsSaving(false);
756 setName("");
757 }
758 };
759 const onRequestClose = () => {
760 onClose?.();
761 setName("");
762 };
763 return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
764 import_components4.Modal,
765 {
766 title: (0, import_i18n5.__)("Rename"),
767 ...props,
768 onRequestClose: onClose,
769 focusOnMount: "firstContentElement",
770 size: "small",
771 children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("form", { onSubmit: onRename, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_components4.__experimentalVStack, { spacing: "5", children: [
772 /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
773 import_components4.TextControl,
774 {
775 __nextHasNoMarginBottom: true,
776 __next40pxDefaultSize: true,
777 label: (0, import_i18n5.__)("Name"),
778 value: name,
779 onChange: setName,
780 required: true
781 }
782 ),
783 /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_components4.__experimentalHStack, { justify: "right", children: [
784 /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
785 import_components4.Button,
786 {
787 __next40pxDefaultSize: true,
788 variant: "tertiary",
789 onClick: onRequestClose,
790 children: (0, import_i18n5.__)("Cancel")
791 }
792 ),
793 /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
794 import_components4.Button,
795 {
796 __next40pxDefaultSize: true,
797 variant: "primary",
798 type: "submit",
799 children: (0, import_i18n5.__)("Save")
800 }
801 )
802 ] })
803 ] }) })
804 }
805 );
806 }
807
808 // packages/patterns/build-module/components/index.js
809 var import_block_editor5 = __toESM(require_block_editor());
810
811 // packages/patterns/build-module/components/pattern-convert-button.js
812 var import_blocks2 = __toESM(require_blocks());
813 var import_block_editor3 = __toESM(require_block_editor());
814 var import_element6 = __toESM(require_element());
815 var import_components5 = __toESM(require_components());
816
817 // packages/icons/build-module/library/symbol.js
818 var import_primitives = __toESM(require_primitives());
819 var import_jsx_runtime6 = __toESM(require_jsx_runtime());
820 var symbol_default = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_primitives.SVG, { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_primitives.Path, { 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" }) });
821
822 // packages/patterns/build-module/components/pattern-convert-button.js
823 var import_data8 = __toESM(require_data());
824 var import_core_data6 = __toESM(require_core_data());
825 var import_i18n6 = __toESM(require_i18n());
826 var import_notices4 = __toESM(require_notices());
827 var import_jsx_runtime7 = __toESM(require_jsx_runtime());
828 function PatternConvertButton({
829 clientIds,
830 rootClientId,
831 closeBlockSettingsMenu
832 }) {
833 const { createSuccessNotice } = (0, import_data8.useDispatch)(import_notices4.store);
834 const { replaceBlocks, updateBlockAttributes } = (0, import_data8.useDispatch)(import_block_editor3.store);
835 const { setEditingPattern: setEditingPattern2 } = unlock((0, import_data8.useDispatch)(store));
836 const [isModalOpen, setIsModalOpen] = (0, import_element6.useState)(false);
837 const { getBlockAttributes } = (0, import_data8.useSelect)(import_block_editor3.store);
838 const canConvert = (0, import_data8.useSelect)(
839 (select) => {
840 const { canUser } = select(import_core_data6.store);
841 const {
842 getBlocksByClientId: getBlocksByClientId2,
843 canInsertBlockType,
844 getBlockRootClientId
845 } = select(import_block_editor3.store);
846 const rootId = rootClientId || (clientIds.length > 0 ? getBlockRootClientId(clientIds[0]) : void 0);
847 const blocks = getBlocksByClientId2(clientIds) ?? [];
848 const hasReusableBlockSupport = (blockName) => {
849 const blockType = (0, import_blocks2.getBlockType)(blockName);
850 const hasParent = blockType && "parent" in blockType;
851 return (0, import_blocks2.hasBlockSupport)(blockName, "reusable", !hasParent);
852 };
853 const isSyncedPattern = blocks.length === 1 && blocks[0] && (0, import_blocks2.isReusableBlock)(blocks[0]) && !!select(import_core_data6.store).getEntityRecord(
854 "postType",
855 "wp_block",
856 blocks[0].attributes.ref
857 );
858 const isUnsyncedPattern = window?.__experimentalContentOnlyPatternInsertion && blocks.length === 1 && blocks?.[0]?.attributes?.metadata?.patternName;
859 const _canConvert = (
860 // Hide when this is already a pattern.
861 !isUnsyncedPattern && !isSyncedPattern && // Hide when patterns are disabled.
862 canInsertBlockType("core/block", rootId) && blocks.every(
863 (block) => (
864 // Guard against the case where a regular block has *just* been converted.
865 !!block && // Hide on invalid blocks.
866 block.isValid && // Hide when block doesn't support being made into a pattern.
867 hasReusableBlockSupport(block.name)
868 )
869 ) && // Hide when current doesn't have permission to do that.
870 // Blocks refers to the wp_block post type, this checks the ability to create a post of that type.
871 !!canUser("create", {
872 kind: "postType",
873 name: "wp_block"
874 })
875 );
876 return _canConvert;
877 },
878 [clientIds, rootClientId]
879 );
880 const { getBlocksByClientId } = (0, import_data8.useSelect)(import_block_editor3.store);
881 const getContent = (0, import_element6.useCallback)(
882 () => (0, import_blocks2.serialize)(getBlocksByClientId(clientIds)),
883 [getBlocksByClientId, clientIds]
884 );
885 if (!canConvert) {
886 return null;
887 }
888 const handleSuccess = ({ pattern }) => {
889 if (pattern.wp_pattern_sync_status === PATTERN_SYNC_TYPES.unsynced) {
890 if (clientIds?.length === 1) {
891 const existingAttributes = getBlockAttributes(clientIds[0]);
892 updateBlockAttributes(clientIds[0], {
893 metadata: {
894 ...existingAttributes?.metadata ? existingAttributes.metadata : {},
895 patternName: `core/block/${pattern.id}`,
896 name: pattern.title.raw
897 }
898 });
899 }
900 } else {
901 const newBlock = (0, import_blocks2.createBlock)("core/block", {
902 ref: pattern.id
903 });
904 replaceBlocks(clientIds, newBlock);
905 setEditingPattern2(newBlock.clientId, true);
906 closeBlockSettingsMenu();
907 }
908 createSuccessNotice(
909 pattern.wp_pattern_sync_status === PATTERN_SYNC_TYPES.unsynced ? (0, import_i18n6.sprintf)(
910 // translators: %s: the name the user has given to the pattern.
911 (0, import_i18n6.__)("Unsynced pattern created: %s"),
912 pattern.title.raw
913 ) : (0, import_i18n6.sprintf)(
914 // translators: %s: the name the user has given to the pattern.
915 (0, import_i18n6.__)("Synced pattern created: %s"),
916 pattern.title.raw
917 ),
918 {
919 type: "snackbar",
920 id: "convert-to-pattern-success"
921 }
922 );
923 setIsModalOpen(false);
924 };
925 return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
926 /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
927 import_components5.MenuItem,
928 {
929 icon: symbol_default,
930 onClick: () => setIsModalOpen(true),
931 "aria-expanded": isModalOpen,
932 "aria-haspopup": "dialog",
933 children: (0, import_i18n6.__)("Create pattern")
934 }
935 ),
936 isModalOpen && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
937 CreatePatternModal,
938 {
939 content: getContent,
940 onSuccess: (pattern) => {
941 handleSuccess(pattern);
942 },
943 onError: () => {
944 setIsModalOpen(false);
945 },
946 onClose: () => {
947 setIsModalOpen(false);
948 }
949 }
950 )
951 ] });
952 }
953
954 // packages/patterns/build-module/components/patterns-manage-button.js
955 var import_components6 = __toESM(require_components());
956 var import_i18n7 = __toESM(require_i18n());
957 var import_blocks3 = __toESM(require_blocks());
958 var import_data9 = __toESM(require_data());
959 var import_block_editor4 = __toESM(require_block_editor());
960 var import_url = __toESM(require_url());
961 var import_core_data7 = __toESM(require_core_data());
962 var import_jsx_runtime8 = __toESM(require_jsx_runtime());
963 function PatternsManageButton({ clientId }) {
964 const {
965 attributes,
966 canDetach,
967 isVisible,
968 managePatternsUrl,
969 isSyncedPattern,
970 isUnsyncedPattern
971 } = (0, import_data9.useSelect)(
972 (select) => {
973 const { canRemoveBlock, getBlock } = select(import_block_editor4.store);
974 const { canUser } = select(import_core_data7.store);
975 const block = getBlock(clientId);
976 const _isUnsyncedPattern = window?.__experimentalContentOnlyPatternInsertion && !!block?.attributes?.metadata?.patternName;
977 const _isSyncedPattern = !!block && (0, import_blocks3.isReusableBlock)(block) && !!canUser("update", {
978 kind: "postType",
979 name: "wp_block",
980 id: block.attributes.ref
981 });
982 return {
983 attributes: block.attributes,
984 // For unsynced patterns, detaching is simply removing the `patternName` attribute.
985 // For synced patterns, the `core:block` block is replaced with its inner blocks,
986 // so checking whether `canRemoveBlock` is possible is required.
987 canDetach: _isUnsyncedPattern || _isSyncedPattern && canRemoveBlock(clientId),
988 isUnsyncedPattern: _isUnsyncedPattern,
989 isSyncedPattern: _isSyncedPattern,
990 isVisible: _isUnsyncedPattern || _isSyncedPattern,
991 // The site editor and templates both check whether the user
992 // has edit_theme_options capabilities. We can leverage that here
993 // and omit the manage patterns link if the user can't access it.
994 managePatternsUrl: canUser("create", {
995 kind: "postType",
996 name: "wp_template"
997 }) ? (0, import_url.addQueryArgs)("site-editor.php", {
998 p: "/pattern"
999 }) : (0, import_url.addQueryArgs)("edit.php", {
1000 post_type: "wp_block"
1001 })
1002 };
1003 },
1004 [clientId]
1005 );
1006 const { updateBlockAttributes } = (0, import_data9.useDispatch)(import_block_editor4.store);
1007 const { convertSyncedPatternToStatic: convertSyncedPatternToStatic2 } = unlock(
1008 (0, import_data9.useDispatch)(store)
1009 );
1010 if (!isVisible) {
1011 return null;
1012 }
1013 return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1014 canDetach && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1015 import_components6.MenuItem,
1016 {
1017 onClick: () => {
1018 if (isSyncedPattern) {
1019 convertSyncedPatternToStatic2(clientId);
1020 }
1021 if (isUnsyncedPattern) {
1022 const {
1023 patternName,
1024 ...attributesWithoutPatternName
1025 } = attributes?.metadata ?? {};
1026 updateBlockAttributes(clientId, {
1027 metadata: attributesWithoutPatternName
1028 });
1029 }
1030 },
1031 children: (0, import_i18n7.__)("Disconnect pattern")
1032 }
1033 ),
1034 /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_components6.MenuItem, { href: managePatternsUrl, children: (0, import_i18n7.__)("Manage patterns") })
1035 ] });
1036 }
1037 var patterns_manage_button_default = PatternsManageButton;
1038
1039 // packages/patterns/build-module/components/index.js
1040 var import_jsx_runtime9 = __toESM(require_jsx_runtime());
1041 function PatternsMenuItems({ rootClientId }) {
1042 return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_block_editor5.BlockSettingsMenuControls, { children: ({ selectedClientIds, onClose }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1043 /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1044 PatternConvertButton,
1045 {
1046 clientIds: selectedClientIds,
1047 rootClientId,
1048 closeBlockSettingsMenu: onClose
1049 }
1050 ),
1051 selectedClientIds.length === 1 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1052 patterns_manage_button_default,
1053 {
1054 clientId: selectedClientIds[0]
1055 }
1056 )
1057 ] }) });
1058 }
1059
1060 // packages/patterns/build-module/components/rename-pattern-category-modal.js
1061 var import_components7 = __toESM(require_components());
1062 var import_core_data8 = __toESM(require_core_data());
1063 var import_data10 = __toESM(require_data());
1064 var import_element7 = __toESM(require_element());
1065 var import_html_entities3 = __toESM(require_html_entities());
1066 var import_i18n8 = __toESM(require_i18n());
1067 var import_notices5 = __toESM(require_notices());
1068 var import_a11y = __toESM(require_a11y());
1069 var import_jsx_runtime10 = __toESM(require_jsx_runtime());
1070 function RenamePatternCategoryModal({
1071 category,
1072 existingCategories,
1073 onClose,
1074 onError,
1075 onSuccess,
1076 ...props
1077 }) {
1078 const id = (0, import_element7.useId)();
1079 const textControlRef = (0, import_element7.useRef)();
1080 const [name, setName] = (0, import_element7.useState)((0, import_html_entities3.decodeEntities)(category.name));
1081 const [isSaving, setIsSaving] = (0, import_element7.useState)(false);
1082 const [validationMessage, setValidationMessage] = (0, import_element7.useState)(false);
1083 const validationMessageId = validationMessage ? `patterns-rename-pattern-category-modal__validation-message-${id}` : void 0;
1084 const { saveEntityRecord, invalidateResolution } = (0, import_data10.useDispatch)(import_core_data8.store);
1085 const { createErrorNotice, createSuccessNotice } = (0, import_data10.useDispatch)(import_notices5.store);
1086 const onChange = (newName) => {
1087 if (validationMessage) {
1088 setValidationMessage(void 0);
1089 }
1090 setName(newName);
1091 };
1092 const onSave = async (event) => {
1093 event.preventDefault();
1094 if (isSaving) {
1095 return;
1096 }
1097 if (!name || name === category.name) {
1098 const message = (0, import_i18n8.__)("Please enter a new name for this category.");
1099 (0, import_a11y.speak)(message, "assertive");
1100 setValidationMessage(message);
1101 textControlRef.current?.focus();
1102 return;
1103 }
1104 if (existingCategories.patternCategories.find((existingCategory) => {
1105 return existingCategory.id !== category.id && existingCategory.label.toLowerCase() === name.toLowerCase();
1106 })) {
1107 const message = (0, import_i18n8.__)(
1108 "This category already exists. Please use a different name."
1109 );
1110 (0, import_a11y.speak)(message, "assertive");
1111 setValidationMessage(message);
1112 textControlRef.current?.focus();
1113 return;
1114 }
1115 try {
1116 setIsSaving(true);
1117 const savedRecord = await saveEntityRecord(
1118 "taxonomy",
1119 CATEGORY_SLUG,
1120 {
1121 id: category.id,
1122 slug: category.slug,
1123 name
1124 }
1125 );
1126 invalidateResolution("getUserPatternCategories");
1127 onSuccess?.(savedRecord);
1128 onClose();
1129 createSuccessNotice((0, import_i18n8.__)("Pattern category renamed."), {
1130 type: "snackbar",
1131 id: "pattern-category-update"
1132 });
1133 } catch (error) {
1134 onError?.();
1135 createErrorNotice(error.message, {
1136 type: "snackbar",
1137 id: "pattern-category-update"
1138 });
1139 } finally {
1140 setIsSaving(false);
1141 setName("");
1142 }
1143 };
1144 const onRequestClose = () => {
1145 onClose();
1146 setName("");
1147 };
1148 return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1149 import_components7.Modal,
1150 {
1151 title: (0, import_i18n8.__)("Rename"),
1152 onRequestClose,
1153 ...props,
1154 children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("form", { onSubmit: onSave, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_components7.__experimentalVStack, { spacing: "5", children: [
1155 /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_components7.__experimentalVStack, { spacing: "2", children: [
1156 /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1157 import_components7.TextControl,
1158 {
1159 ref: textControlRef,
1160 __nextHasNoMarginBottom: true,
1161 __next40pxDefaultSize: true,
1162 label: (0, import_i18n8.__)("Name"),
1163 value: name,
1164 onChange,
1165 "aria-describedby": validationMessageId,
1166 required: true
1167 }
1168 ),
1169 validationMessage && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1170 "span",
1171 {
1172 className: "patterns-rename-pattern-category-modal__validation-message",
1173 id: validationMessageId,
1174 children: validationMessage
1175 }
1176 )
1177 ] }),
1178 /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_components7.__experimentalHStack, { justify: "right", children: [
1179 /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1180 import_components7.Button,
1181 {
1182 __next40pxDefaultSize: true,
1183 variant: "tertiary",
1184 onClick: onRequestClose,
1185 children: (0, import_i18n8.__)("Cancel")
1186 }
1187 ),
1188 /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1189 import_components7.Button,
1190 {
1191 __next40pxDefaultSize: true,
1192 variant: "primary",
1193 type: "submit",
1194 "aria-disabled": !name || name === category.name || isSaving,
1195 isBusy: isSaving,
1196 children: (0, import_i18n8.__)("Save")
1197 }
1198 )
1199 ] })
1200 ] }) })
1201 }
1202 );
1203 }
1204
1205 // packages/patterns/build-module/components/pattern-overrides-controls.js
1206 var import_element9 = __toESM(require_element());
1207 var import_block_editor6 = __toESM(require_block_editor());
1208 var import_components9 = __toESM(require_components());
1209 var import_i18n10 = __toESM(require_i18n());
1210
1211 // packages/patterns/build-module/components/allow-overrides-modal.js
1212 var import_components8 = __toESM(require_components());
1213 var import_i18n9 = __toESM(require_i18n());
1214 var import_element8 = __toESM(require_element());
1215 var import_a11y2 = __toESM(require_a11y());
1216 var import_jsx_runtime11 = __toESM(require_jsx_runtime());
1217 function AllowOverridesModal({
1218 placeholder,
1219 initialName = "",
1220 onClose,
1221 onSave
1222 }) {
1223 const [editedBlockName, setEditedBlockName] = (0, import_element8.useState)(initialName);
1224 const descriptionId = (0, import_element8.useId)();
1225 const isNameValid = !!editedBlockName.trim();
1226 const handleSubmit = () => {
1227 if (editedBlockName !== initialName) {
1228 const message = (0, import_i18n9.sprintf)(
1229 /* translators: %s: new name/label for the block */
1230 (0, import_i18n9.__)('Block name changed to: "%s".'),
1231 editedBlockName
1232 );
1233 (0, import_a11y2.speak)(message, "assertive");
1234 }
1235 onSave(editedBlockName);
1236 onClose();
1237 };
1238 return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1239 import_components8.Modal,
1240 {
1241 title: (0, import_i18n9.__)("Enable overrides"),
1242 onRequestClose: onClose,
1243 focusOnMount: "firstContentElement",
1244 aria: { describedby: descriptionId },
1245 size: "small",
1246 children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1247 "form",
1248 {
1249 onSubmit: (event) => {
1250 event.preventDefault();
1251 if (!isNameValid) {
1252 return;
1253 }
1254 handleSubmit();
1255 },
1256 children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_components8.__experimentalVStack, { spacing: "6", children: [
1257 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_components8.__experimentalText, { id: descriptionId, children: (0, import_i18n9.__)(
1258 "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."
1259 ) }),
1260 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1261 import_components8.TextControl,
1262 {
1263 __nextHasNoMarginBottom: true,
1264 __next40pxDefaultSize: true,
1265 value: editedBlockName,
1266 label: (0, import_i18n9.__)("Name"),
1267 help: (0, import_i18n9.__)(
1268 'For example, if you are creating a recipe pattern, you use "Recipe Title", "Recipe Description", etc.'
1269 ),
1270 placeholder,
1271 onChange: setEditedBlockName
1272 }
1273 ),
1274 /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_components8.__experimentalHStack, { justify: "right", children: [
1275 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1276 import_components8.Button,
1277 {
1278 __next40pxDefaultSize: true,
1279 variant: "tertiary",
1280 onClick: onClose,
1281 children: (0, import_i18n9.__)("Cancel")
1282 }
1283 ),
1284 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1285 import_components8.Button,
1286 {
1287 __next40pxDefaultSize: true,
1288 "aria-disabled": !isNameValid,
1289 variant: "primary",
1290 type: "submit",
1291 children: (0, import_i18n9.__)("Enable")
1292 }
1293 )
1294 ] })
1295 ] })
1296 }
1297 )
1298 }
1299 );
1300 }
1301 function DisallowOverridesModal({ onClose, onSave }) {
1302 const descriptionId = (0, import_element8.useId)();
1303 return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1304 import_components8.Modal,
1305 {
1306 title: (0, import_i18n9.__)("Disable overrides"),
1307 onRequestClose: onClose,
1308 aria: { describedby: descriptionId },
1309 size: "small",
1310 children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1311 "form",
1312 {
1313 onSubmit: (event) => {
1314 event.preventDefault();
1315 onSave();
1316 onClose();
1317 },
1318 children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_components8.__experimentalVStack, { spacing: "6", children: [
1319 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_components8.__experimentalText, { id: descriptionId, children: (0, import_i18n9.__)(
1320 "Are you sure you want to disable overrides? Disabling overrides will revert all applied overrides for this block throughout instances of this pattern."
1321 ) }),
1322 /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_components8.__experimentalHStack, { justify: "right", children: [
1323 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1324 import_components8.Button,
1325 {
1326 __next40pxDefaultSize: true,
1327 variant: "tertiary",
1328 onClick: onClose,
1329 children: (0, import_i18n9.__)("Cancel")
1330 }
1331 ),
1332 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1333 import_components8.Button,
1334 {
1335 __next40pxDefaultSize: true,
1336 variant: "primary",
1337 type: "submit",
1338 children: (0, import_i18n9.__)("Disable")
1339 }
1340 )
1341 ] })
1342 ] })
1343 }
1344 )
1345 }
1346 );
1347 }
1348
1349 // packages/patterns/build-module/components/pattern-overrides-controls.js
1350 var import_jsx_runtime12 = __toESM(require_jsx_runtime());
1351 function PatternOverridesControls({
1352 attributes,
1353 setAttributes,
1354 name: blockName
1355 }) {
1356 const controlId = (0, import_element9.useId)();
1357 const [showAllowOverridesModal, setShowAllowOverridesModal] = (0, import_element9.useState)(false);
1358 const [showDisallowOverridesModal, setShowDisallowOverridesModal] = (0, import_element9.useState)(false);
1359 const hasName = !!attributes.metadata?.name;
1360 const defaultBindings = attributes.metadata?.bindings?.__default;
1361 const hasOverrides = hasName && defaultBindings?.source === PATTERN_OVERRIDES_BINDING_SOURCE;
1362 const isConnectedToOtherSources = defaultBindings?.source && defaultBindings.source !== PATTERN_OVERRIDES_BINDING_SOURCE;
1363 const { updateBlockBindings } = (0, import_block_editor6.useBlockBindingsUtils)();
1364 function updateBindings(isChecked, customName) {
1365 if (customName) {
1366 setAttributes({
1367 metadata: {
1368 ...attributes.metadata,
1369 name: customName
1370 }
1371 });
1372 }
1373 updateBlockBindings({
1374 __default: isChecked ? { source: PATTERN_OVERRIDES_BINDING_SOURCE } : void 0
1375 });
1376 }
1377 if (isConnectedToOtherSources) {
1378 return null;
1379 }
1380 const hasUnsupportedImageAttributes = blockName === "core/image" && !!attributes.href?.length;
1381 const helpText = !hasOverrides && hasUnsupportedImageAttributes ? (0, import_i18n10.__)(
1382 `Overrides currently don't support image links. Remove the link first before enabling overrides.`
1383 ) : (0, import_i18n10.__)(
1384 "Allow changes to this block throughout instances of this pattern."
1385 );
1386 return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1387 /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_block_editor6.InspectorControls, { group: "advanced", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1388 import_components9.BaseControl,
1389 {
1390 __nextHasNoMarginBottom: true,
1391 id: controlId,
1392 label: (0, import_i18n10.__)("Overrides"),
1393 help: helpText,
1394 children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1395 import_components9.Button,
1396 {
1397 __next40pxDefaultSize: true,
1398 className: "pattern-overrides-control__allow-overrides-button",
1399 variant: "secondary",
1400 "aria-haspopup": "dialog",
1401 onClick: () => {
1402 if (hasOverrides) {
1403 setShowDisallowOverridesModal(true);
1404 } else {
1405 setShowAllowOverridesModal(true);
1406 }
1407 },
1408 disabled: !hasOverrides && hasUnsupportedImageAttributes,
1409 accessibleWhenDisabled: true,
1410 children: hasOverrides ? (0, import_i18n10.__)("Disable overrides") : (0, import_i18n10.__)("Enable overrides")
1411 }
1412 )
1413 }
1414 ) }),
1415 showAllowOverridesModal && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1416 AllowOverridesModal,
1417 {
1418 initialName: attributes.metadata?.name,
1419 onClose: () => setShowAllowOverridesModal(false),
1420 onSave: (newName) => {
1421 updateBindings(true, newName);
1422 }
1423 }
1424 ),
1425 showDisallowOverridesModal && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1426 DisallowOverridesModal,
1427 {
1428 onClose: () => setShowDisallowOverridesModal(false),
1429 onSave: () => updateBindings(false)
1430 }
1431 )
1432 ] });
1433 }
1434 var pattern_overrides_controls_default = PatternOverridesControls;
1435
1436 // packages/patterns/build-module/components/reset-overrides-control.js
1437 var import_block_editor7 = __toESM(require_block_editor());
1438 var import_components10 = __toESM(require_components());
1439 var import_data11 = __toESM(require_data());
1440 var import_i18n11 = __toESM(require_i18n());
1441 var import_jsx_runtime13 = __toESM(require_jsx_runtime());
1442 var CONTENT = "content";
1443 function ResetOverridesControl(props) {
1444 const name = props.attributes.metadata?.name;
1445 const registry = (0, import_data11.useRegistry)();
1446 const isOverridden = (0, import_data11.useSelect)(
1447 (select) => {
1448 if (!name) {
1449 return;
1450 }
1451 const { getBlockAttributes, getBlockParentsByBlockName } = select(import_block_editor7.store);
1452 const [patternClientId] = getBlockParentsByBlockName(
1453 props.clientId,
1454 "core/block",
1455 true
1456 );
1457 if (!patternClientId) {
1458 return;
1459 }
1460 const overrides = getBlockAttributes(patternClientId)[CONTENT];
1461 if (!overrides) {
1462 return;
1463 }
1464 return overrides.hasOwnProperty(name);
1465 },
1466 [props.clientId, name]
1467 );
1468 function onClick() {
1469 const { getBlockAttributes, getBlockParentsByBlockName } = registry.select(import_block_editor7.store);
1470 const [patternClientId] = getBlockParentsByBlockName(
1471 props.clientId,
1472 "core/block",
1473 true
1474 );
1475 if (!patternClientId) {
1476 return;
1477 }
1478 const overrides = getBlockAttributes(patternClientId)[CONTENT];
1479 if (!overrides.hasOwnProperty(name)) {
1480 return;
1481 }
1482 const { updateBlockAttributes, __unstableMarkLastChangeAsPersistent } = registry.dispatch(import_block_editor7.store);
1483 __unstableMarkLastChangeAsPersistent();
1484 let newOverrides = { ...overrides };
1485 delete newOverrides[name];
1486 if (!Object.keys(newOverrides).length) {
1487 newOverrides = void 0;
1488 }
1489 updateBlockAttributes(patternClientId, {
1490 [CONTENT]: newOverrides
1491 });
1492 }
1493 return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_block_editor7.__unstableBlockToolbarLastItem, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_components10.ToolbarGroup, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_components10.ToolbarButton, { onClick, disabled: !isOverridden, children: (0, import_i18n11.__)("Reset") }) }) });
1494 }
1495
1496 // packages/patterns/build-module/private-apis.js
1497 var privateApis = {};
1498 lock(privateApis, {
1499 OverridesPanel,
1500 CreatePatternModal,
1501 CreatePatternModalContents,
1502 DuplicatePatternModal,
1503 isOverridableBlock,
1504 hasOverridableBlocks,
1505 useDuplicatePatternProps,
1506 RenamePatternModal,
1507 PatternsMenuItems,
1508 RenamePatternCategoryModal,
1509 PatternOverridesControls: pattern_overrides_controls_default,
1510 ResetOverridesControl,
1511 useAddPatternCategory,
1512 PATTERN_TYPES,
1513 PATTERN_DEFAULT_CATEGORY,
1514 PATTERN_USER_CATEGORY,
1515 EXCLUDED_PATTERN_SOURCES,
1516 PATTERN_SYNC_TYPES,
1517 PARTIAL_SYNCING_SUPPORTED_BLOCKS
1518 });
1519 return __toCommonJS(index_exports);
1520 })();
1521 //# sourceMappingURL=index.js.map
1522