| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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 } 412 ); 413 } 414 415 // packages/patterns/build-module/private-hooks.js 416 var import_data4 = __toESM(require_data()); 417 var import_core_data2 = __toESM(require_core_data()); 418 var import_element3 = __toESM(require_element()); 419 function useAddPatternCategory() { 420 const { saveEntityRecord, invalidateResolution } = (0, import_data4.useDispatch)(import_core_data2.store); 421 const { corePatternCategories, userPatternCategories } = (0, import_data4.useSelect)( 422 (select) => { 423 const { getUserPatternCategories, getBlockPatternCategories } = select(import_core_data2.store); 424 return { 425 corePatternCategories: getBlockPatternCategories(), 426 userPatternCategories: getUserPatternCategories() 427 }; 428 }, 429 [] 430 ); 431 const categoryMap = (0, import_element3.useMemo)(() => { 432 const uniqueCategories = /* @__PURE__ */ new Map(); 433 userPatternCategories.forEach((category) => { 434 uniqueCategories.set(category.label.toLowerCase(), { 435 label: category.label, 436 name: category.name, 437 id: category.id 438 }); 439 }); 440 corePatternCategories.forEach((category) => { 441 if (!uniqueCategories.has(category.label.toLowerCase()) && // There are two core categories with `Post` label so explicitly remove the one with 442 // the `query` slug to avoid any confusion. 443 category.name !== "query") { 444 uniqueCategories.set(category.label.toLowerCase(), { 445 label: category.label, 446 name: category.name 447 }); 448 } 449 }); 450 return uniqueCategories; 451 }, [userPatternCategories, corePatternCategories]); 452 async function findOrCreateTerm(term) { 453 try { 454 const existingTerm = categoryMap.get(term.toLowerCase()); 455 if (existingTerm?.id) { 456 return existingTerm.id; 457 } 458 const termData = existingTerm ? { name: existingTerm.label, slug: existingTerm.name } : { name: term }; 459 const newTerm = await saveEntityRecord( 460 "taxonomy", 461 CATEGORY_SLUG, 462 termData, 463 { throwOnError: true } 464 ); 465 invalidateResolution("getUserPatternCategories"); 466 return newTerm.id; 467 } catch (error) { 468 if (error.code !== "term_exists") { 469 throw error; 470 } 471 return error.data.term_id; 472 } 473 } 474 return { categoryMap, findOrCreateTerm }; 475 } 476 477 // packages/patterns/build-module/components/create-pattern-modal.js 478 var import_jsx_runtime3 = __toESM(require_jsx_runtime()); 479 function CreatePatternModal({ 480 className = "patterns-menu-items__convert-modal", 481 modalTitle, 482 ...restProps 483 }) { 484 const defaultModalTitle = (0, import_data5.useSelect)( 485 (select) => select(import_core_data3.store).getPostType(PATTERN_TYPES.user)?.labels?.add_new_item, 486 [] 487 ); 488 return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)( 489 import_components3.Modal, 490 { 491 title: modalTitle || defaultModalTitle, 492 onRequestClose: restProps.onClose, 493 overlayClassName: className, 494 focusOnMount: "firstContentElement", 495 size: "small", 496 children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CreatePatternModalContents, { ...restProps }) 497 } 498 ); 499 } 500 function CreatePatternModalContents({ 501 confirmLabel = (0, import_i18n3.__)("Add"), 502 defaultCategories = [], 503 content, 504 onClose, 505 onError, 506 onSuccess, 507 defaultSyncType = PATTERN_SYNC_TYPES.full, 508 defaultTitle = "" 509 }) { 510 const [syncType, setSyncType] = (0, import_element4.useState)(defaultSyncType); 511 const [categoryTerms, setCategoryTerms] = (0, import_element4.useState)(defaultCategories); 512 const [title, setTitle] = (0, import_element4.useState)(defaultTitle); 513 const [isSaving, setIsSaving] = (0, import_element4.useState)(false); 514 const { createPattern: createPattern2 } = unlock((0, import_data5.useDispatch)(store)); 515 const { createErrorNotice } = (0, import_data5.useDispatch)(import_notices.store); 516 const { categoryMap, findOrCreateTerm } = useAddPatternCategory(); 517 async function onCreate(patternTitle, sync) { 518 if (!title || isSaving) { 519 return; 520 } 521 try { 522 setIsSaving(true); 523 const categories = await Promise.all( 524 categoryTerms.map( 525 (termName) => findOrCreateTerm(termName) 526 ) 527 ); 528 const newPattern = await createPattern2( 529 patternTitle, 530 sync, 531 typeof content === "function" ? content() : content, 532 categories 533 ); 534 onSuccess({ 535 pattern: newPattern, 536 categoryId: PATTERN_DEFAULT_CATEGORY 537 }); 538 } catch (error) { 539 createErrorNotice(error.message, { 540 type: "snackbar", 541 id: "pattern-create" 542 }); 543 onError?.(); 544 } finally { 545 setIsSaving(false); 546 setCategoryTerms([]); 547 setTitle(""); 548 } 549 } 550 return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)( 551 "form", 552 { 553 onSubmit: (event) => { 554 event.preventDefault(); 555 onCreate(title, syncType); 556 }, 557 children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_components3.__experimentalVStack, { spacing: "5", children: [ 558 /* @__PURE__ */ (0, import_jsx_runtime3.jsx)( 559 import_components3.TextControl, 560 { 561 label: (0, import_i18n3.__)("Name"), 562 value: title, 563 onChange: setTitle, 564 placeholder: (0, import_i18n3.__)("My pattern"), 565 className: "patterns-create-modal__name-input", 566 __next40pxDefaultSize: true 567 } 568 ), 569 /* @__PURE__ */ (0, import_jsx_runtime3.jsx)( 570 CategorySelector, 571 { 572 categoryTerms, 573 onChange: setCategoryTerms, 574 categoryMap 575 } 576 ), 577 /* @__PURE__ */ (0, import_jsx_runtime3.jsx)( 578 import_components3.ToggleControl, 579 { 580 label: (0, import_i18n3._x)("Synced", "pattern (singular)"), 581 help: (0, import_i18n3.__)( 582 "Sync this pattern across multiple locations." 583 ), 584 checked: syncType === PATTERN_SYNC_TYPES.full, 585 onChange: () => { 586 setSyncType( 587 syncType === PATTERN_SYNC_TYPES.full ? PATTERN_SYNC_TYPES.unsynced : PATTERN_SYNC_TYPES.full 588 ); 589 } 590 } 591 ), 592 /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_components3.__experimentalHStack, { justify: "right", children: [ 593 /* @__PURE__ */ (0, import_jsx_runtime3.jsx)( 594 import_components3.Button, 595 { 596 __next40pxDefaultSize: true, 597 variant: "tertiary", 598 onClick: () => { 599 onClose(); 600 setTitle(""); 601 }, 602 children: (0, import_i18n3.__)("Cancel") 603 } 604 ), 605 /* @__PURE__ */ (0, import_jsx_runtime3.jsx)( 606 import_components3.Button, 607 { 608 __next40pxDefaultSize: true, 609 variant: "primary", 610 type: "submit", 611 "aria-disabled": !title || isSaving, 612 isBusy: isSaving, 613 children: confirmLabel 614 } 615 ) 616 ] }) 617 ] }) 618 } 619 ); 620 } 621 622 // packages/patterns/build-module/components/duplicate-pattern-modal.js 623 var import_core_data4 = __toESM(require_core_data()); 624 var import_data6 = __toESM(require_data()); 625 var import_i18n4 = __toESM(require_i18n()); 626 var import_notices2 = __toESM(require_notices()); 627 var import_jsx_runtime4 = __toESM(require_jsx_runtime()); 628 function getTermLabels(pattern, categories) { 629 if (pattern.type !== PATTERN_TYPES.user) { 630 return categories.core?.filter( 631 (category) => pattern.categories?.includes(category.name) 632 ).map((category) => category.label); 633 } 634 return categories.user?.filter( 635 (category) => pattern.wp_pattern_category?.includes(category.id) 636 ).map((category) => category.label); 637 } 638 function useDuplicatePatternProps({ pattern, onSuccess }) { 639 const { createSuccessNotice } = (0, import_data6.useDispatch)(import_notices2.store); 640 const categories = (0, import_data6.useSelect)((select) => { 641 const { getUserPatternCategories, getBlockPatternCategories } = select(import_core_data4.store); 642 return { 643 core: getBlockPatternCategories(), 644 user: getUserPatternCategories() 645 }; 646 }); 647 if (!pattern) { 648 return null; 649 } 650 return { 651 content: pattern.content, 652 defaultCategories: getTermLabels(pattern, categories), 653 defaultSyncType: pattern.type !== PATTERN_TYPES.user ? PATTERN_SYNC_TYPES.unsynced : pattern.wp_pattern_sync_status || PATTERN_SYNC_TYPES.full, 654 defaultTitle: (0, import_i18n4.sprintf)( 655 /* translators: %s: Existing pattern title */ 656 (0, import_i18n4._x)("%s (Copy)", "pattern"), 657 typeof pattern.title === "string" ? pattern.title : pattern.title.raw 658 ), 659 onSuccess: ({ pattern: newPattern }) => { 660 createSuccessNotice( 661 (0, import_i18n4.sprintf)( 662 // translators: %s: The new pattern's title e.g. 'Call to action (copy)'. 663 (0, import_i18n4._x)('"%s" duplicated.', "pattern"), 664 newPattern.title.raw 665 ), 666 { 667 type: "snackbar", 668 id: "patterns-create" 669 } 670 ); 671 onSuccess?.({ pattern: newPattern }); 672 } 673 }; 674 } 675 function DuplicatePatternModal({ 676 pattern, 677 onClose, 678 onSuccess 679 }) { 680 const duplicatedProps = useDuplicatePatternProps({ pattern, onSuccess }); 681 if (!pattern) { 682 return null; 683 } 684 return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( 685 CreatePatternModal, 686 { 687 modalTitle: (0, import_i18n4.__)("Duplicate pattern"), 688 confirmLabel: (0, import_i18n4.__)("Duplicate"), 689 onClose, 690 onError: onClose, 691 ...duplicatedProps 692 } 693 ); 694 } 695 696 // packages/patterns/build-module/components/rename-pattern-modal.js 697 var import_components4 = __toESM(require_components()); 698 var import_core_data5 = __toESM(require_core_data()); 699 var import_data7 = __toESM(require_data()); 700 var import_element5 = __toESM(require_element()); 701 var import_html_entities2 = __toESM(require_html_entities()); 702 var import_i18n5 = __toESM(require_i18n()); 703 var import_notices3 = __toESM(require_notices()); 704 var import_jsx_runtime5 = __toESM(require_jsx_runtime()); 705 function RenamePatternModal({ 706 onClose, 707 onError, 708 onSuccess, 709 pattern, 710 ...props 711 }) { 712 const originalName = (0, import_html_entities2.decodeEntities)(pattern.title); 713 const [name, setName] = (0, import_element5.useState)(originalName); 714 const [isSaving, setIsSaving] = (0, import_element5.useState)(false); 715 const { 716 editEntityRecord, 717 __experimentalSaveSpecifiedEntityEdits: saveSpecifiedEntityEdits 718 } = (0, import_data7.useDispatch)(import_core_data5.store); 719 const { createSuccessNotice, createErrorNotice } = (0, import_data7.useDispatch)(import_notices3.store); 720 const onRename = async (event) => { 721 event.preventDefault(); 722 if (!name || name === pattern.title || isSaving) { 723 return; 724 } 725 try { 726 await editEntityRecord("postType", pattern.type, pattern.id, { 727 title: name 728 }); 729 setIsSaving(true); 730 setName(""); 731 onClose?.(); 732 const savedRecord = await saveSpecifiedEntityEdits( 733 "postType", 734 pattern.type, 735 pattern.id, 736 ["title"], 737 { throwOnError: true } 738 ); 739 onSuccess?.(savedRecord); 740 createSuccessNotice((0, import_i18n5.__)("Pattern renamed"), { 741 type: "snackbar", 742 id: "pattern-update" 743 }); 744 } catch (error) { 745 onError?.(); 746 const errorMessage = error.message && error.code !== "unknown_error" ? error.message : (0, import_i18n5.__)("An error occurred while renaming the pattern."); 747 createErrorNotice(errorMessage, { 748 type: "snackbar", 749 id: "pattern-update" 750 }); 751 } finally { 752 setIsSaving(false); 753 setName(""); 754 } 755 }; 756 const onRequestClose = () => { 757 onClose?.(); 758 setName(""); 759 }; 760 return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( 761 import_components4.Modal, 762 { 763 title: (0, import_i18n5.__)("Rename"), 764 ...props, 765 onRequestClose: onClose, 766 focusOnMount: "firstContentElement", 767 size: "small", 768 children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("form", { onSubmit: onRename, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_components4.__experimentalVStack, { spacing: "5", children: [ 769 /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( 770 import_components4.TextControl, 771 { 772 __next40pxDefaultSize: true, 773 label: (0, import_i18n5.__)("Name"), 774 value: name, 775 onChange: setName, 776 required: true 777 } 778 ), 779 /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_components4.__experimentalHStack, { justify: "right", children: [ 780 /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( 781 import_components4.Button, 782 { 783 __next40pxDefaultSize: true, 784 variant: "tertiary", 785 onClick: onRequestClose, 786 children: (0, import_i18n5.__)("Cancel") 787 } 788 ), 789 /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( 790 import_components4.Button, 791 { 792 __next40pxDefaultSize: true, 793 variant: "primary", 794 type: "submit", 795 children: (0, import_i18n5.__)("Save") 796 } 797 ) 798 ] }) 799 ] }) }) 800 } 801 ); 802 } 803 804 // packages/patterns/build-module/components/index.js 805 var import_block_editor5 = __toESM(require_block_editor()); 806 807 // packages/patterns/build-module/components/pattern-convert-button.js 808 var import_blocks2 = __toESM(require_blocks()); 809 var import_block_editor3 = __toESM(require_block_editor()); 810 var import_element6 = __toESM(require_element()); 811 var import_components5 = __toESM(require_components()); 812 813 // packages/icons/build-module/library/symbol.js 814 var import_primitives = __toESM(require_primitives()); 815 var import_jsx_runtime6 = __toESM(require_jsx_runtime()); 816 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" }) }); 817 818 // packages/patterns/build-module/components/pattern-convert-button.js 819 var import_data8 = __toESM(require_data()); 820 var import_core_data6 = __toESM(require_core_data()); 821 var import_i18n6 = __toESM(require_i18n()); 822 var import_notices4 = __toESM(require_notices()); 823 var import_jsx_runtime7 = __toESM(require_jsx_runtime()); 824 function PatternConvertButton({ 825 clientIds, 826 rootClientId, 827 closeBlockSettingsMenu 828 }) { 829 const { createSuccessNotice } = (0, import_data8.useDispatch)(import_notices4.store); 830 const { replaceBlocks, updateBlockAttributes } = (0, import_data8.useDispatch)(import_block_editor3.store); 831 const { setEditingPattern: setEditingPattern2 } = unlock((0, import_data8.useDispatch)(store)); 832 const [isModalOpen, setIsModalOpen] = (0, import_element6.useState)(false); 833 const { getBlockAttributes } = (0, import_data8.useSelect)(import_block_editor3.store); 834 const canConvert = (0, import_data8.useSelect)( 835 (select) => { 836 const { canUser } = select(import_core_data6.store); 837 const { 838 getBlocksByClientId: getBlocksByClientId2, 839 canInsertBlockType, 840 getBlockRootClientId 841 } = select(import_block_editor3.store); 842 const rootId = rootClientId || (clientIds.length > 0 ? getBlockRootClientId(clientIds[0]) : void 0); 843 const blocks = getBlocksByClientId2(clientIds) ?? []; 844 const hasReusableBlockSupport = (blockName) => { 845 const blockType = (0, import_blocks2.getBlockType)(blockName); 846 const hasParent = blockType && "parent" in blockType; 847 return (0, import_blocks2.hasBlockSupport)(blockName, "reusable", !hasParent); 848 }; 849 const isSyncedPattern = blocks.length === 1 && blocks[0] && (0, import_blocks2.isReusableBlock)(blocks[0]) && !!select(import_core_data6.store).getEntityRecord( 850 "postType", 851 "wp_block", 852 blocks[0].attributes.ref 853 ); 854 const isUnsyncedPattern = window?.__experimentalContentOnlyPatternInsertion && blocks.length === 1 && blocks?.[0]?.attributes?.metadata?.patternName; 855 const _canConvert = ( 856 // Hide when this is already a pattern. 857 !isUnsyncedPattern && !isSyncedPattern && // Hide when patterns are disabled. 858 canInsertBlockType("core/block", rootId) && blocks.every( 859 (block) => ( 860 // Guard against the case where a regular block has *just* been converted. 861 !!block && // Hide on invalid blocks. 862 block.isValid && // Hide when block doesn't support being made into a pattern. 863 hasReusableBlockSupport(block.name) 864 ) 865 ) && // Hide when current doesn't have permission to do that. 866 // Blocks refers to the wp_block post type, this checks the ability to create a post of that type. 867 !!canUser("create", { 868 kind: "postType", 869 name: "wp_block" 870 }) 871 ); 872 return _canConvert; 873 }, 874 [clientIds, rootClientId] 875 ); 876 const { getBlocksByClientId } = (0, import_data8.useSelect)(import_block_editor3.store); 877 const getContent = (0, import_element6.useCallback)( 878 () => (0, import_blocks2.serialize)(getBlocksByClientId(clientIds)), 879 [getBlocksByClientId, clientIds] 880 ); 881 if (!canConvert) { 882 return null; 883 } 884 const handleSuccess = ({ pattern }) => { 885 if (pattern.wp_pattern_sync_status === PATTERN_SYNC_TYPES.unsynced) { 886 if (clientIds?.length === 1) { 887 const existingAttributes = getBlockAttributes(clientIds[0]); 888 updateBlockAttributes(clientIds[0], { 889 metadata: { 890 ...existingAttributes?.metadata ? existingAttributes.metadata : {}, 891 patternName: `core/block/$pattern.id}`, 892 name: pattern.title.raw 893 } 894 }); 895 } 896 } else { 897 const newBlock = (0, import_blocks2.createBlock)("core/block", { 898 ref: pattern.id 899 }); 900 replaceBlocks(clientIds, newBlock); 901 setEditingPattern2(newBlock.clientId, true); 902 closeBlockSettingsMenu(); 903 } 904 createSuccessNotice( 905 pattern.wp_pattern_sync_status === PATTERN_SYNC_TYPES.unsynced ? (0, import_i18n6.sprintf)( 906 // translators: %s: the name the user has given to the pattern. 907 (0, import_i18n6.__)("Unsynced pattern created: %s"), 908 pattern.title.raw 909 ) : (0, import_i18n6.sprintf)( 910 // translators: %s: the name the user has given to the pattern. 911 (0, import_i18n6.__)("Synced pattern created: %s"), 912 pattern.title.raw 913 ), 914 { 915 type: "snackbar", 916 id: "convert-to-pattern-success" 917 } 918 ); 919 setIsModalOpen(false); 920 }; 921 return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [ 922 /* @__PURE__ */ (0, import_jsx_runtime7.jsx)( 923 import_components5.MenuItem, 924 { 925 icon: symbol_default, 926 onClick: () => setIsModalOpen(true), 927 "aria-expanded": isModalOpen, 928 "aria-haspopup": "dialog", 929 children: (0, import_i18n6.__)("Create pattern") 930 } 931 ), 932 isModalOpen && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)( 933 CreatePatternModal, 934 { 935 content: getContent, 936 onSuccess: (pattern) => { 937 handleSuccess(pattern); 938 }, 939 onError: () => { 940 setIsModalOpen(false); 941 }, 942 onClose: () => { 943 setIsModalOpen(false); 944 } 945 } 946 ) 947 ] }); 948 } 949 950 // packages/patterns/build-module/components/patterns-manage-button.js 951 var import_components6 = __toESM(require_components()); 952 var import_i18n7 = __toESM(require_i18n()); 953 var import_blocks3 = __toESM(require_blocks()); 954 var import_data9 = __toESM(require_data()); 955 var import_block_editor4 = __toESM(require_block_editor()); 956 var import_url = __toESM(require_url()); 957 var import_core_data7 = __toESM(require_core_data()); 958 var import_jsx_runtime8 = __toESM(require_jsx_runtime()); 959 function PatternsManageButton({ clientId }) { 960 const { 961 attributes, 962 canDetach, 963 isVisible, 964 managePatternsUrl, 965 isSyncedPattern, 966 isUnsyncedPattern 967 } = (0, import_data9.useSelect)( 968 (select) => { 969 const { canRemoveBlock, getBlock } = select(import_block_editor4.store); 970 const { canUser } = select(import_core_data7.store); 971 const block = getBlock(clientId); 972 const _isUnsyncedPattern = window?.__experimentalContentOnlyPatternInsertion && !!block?.attributes?.metadata?.patternName; 973 const _isSyncedPattern = !!block && (0, import_blocks3.isReusableBlock)(block) && !!canUser("update", { 974 kind: "postType", 975 name: "wp_block", 976 id: block.attributes.ref 977 }); 978 return { 979 attributes: block.attributes, 980 // For unsynced patterns, detaching is simply removing the `patternName` attribute. 981 // For synced patterns, the `core:block` block is replaced with its inner blocks, 982 // so checking whether `canRemoveBlock` is possible is required. 983 canDetach: _isUnsyncedPattern || _isSyncedPattern && canRemoveBlock(clientId), 984 isUnsyncedPattern: _isUnsyncedPattern, 985 isSyncedPattern: _isSyncedPattern, 986 isVisible: _isUnsyncedPattern || _isSyncedPattern, 987 // The site editor and templates both check whether the user 988 // has edit_theme_options capabilities. We can leverage that here 989 // and omit the manage patterns link if the user can't access it. 990 managePatternsUrl: canUser("create", { 991 kind: "postType", 992 name: "wp_template" 993 }) ? (0, import_url.addQueryArgs)("site-editor.php", { 994 p: "/pattern" 995 }) : (0, import_url.addQueryArgs)("edit.php", { 996 post_type: "wp_block" 997 }) 998 }; 999 }, 1000 [clientId] 1001 ); 1002 const { updateBlockAttributes } = (0, import_data9.useDispatch)(import_block_editor4.store); 1003 const { convertSyncedPatternToStatic: convertSyncedPatternToStatic2 } = unlock( 1004 (0, import_data9.useDispatch)(store) 1005 ); 1006 if (!isVisible) { 1007 return null; 1008 } 1009 return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [ 1010 canDetach && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)( 1011 import_components6.MenuItem, 1012 { 1013 onClick: () => { 1014 if (isSyncedPattern) { 1015 convertSyncedPatternToStatic2(clientId); 1016 } 1017 if (isUnsyncedPattern) { 1018 const { 1019 patternName, 1020 ...attributesWithoutPatternName 1021 } = attributes?.metadata ?? {}; 1022 updateBlockAttributes(clientId, { 1023 metadata: attributesWithoutPatternName 1024 }); 1025 } 1026 }, 1027 children: (0, import_i18n7.__)("Disconnect pattern") 1028 } 1029 ), 1030 /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_components6.MenuItem, { href: managePatternsUrl, children: (0, import_i18n7.__)("Manage patterns") }) 1031 ] }); 1032 } 1033 var patterns_manage_button_default = PatternsManageButton; 1034 1035 // packages/patterns/build-module/components/index.js 1036 var import_jsx_runtime9 = __toESM(require_jsx_runtime()); 1037 function PatternsMenuItems({ rootClientId }) { 1038 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: [ 1039 /* @__PURE__ */ (0, import_jsx_runtime9.jsx)( 1040 PatternConvertButton, 1041 { 1042 clientIds: selectedClientIds, 1043 rootClientId, 1044 closeBlockSettingsMenu: onClose 1045 } 1046 ), 1047 selectedClientIds.length === 1 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)( 1048 patterns_manage_button_default, 1049 { 1050 clientId: selectedClientIds[0] 1051 } 1052 ) 1053 ] }) }); 1054 } 1055 1056 // packages/patterns/build-module/components/rename-pattern-category-modal.js 1057 var import_components7 = __toESM(require_components()); 1058 var import_core_data8 = __toESM(require_core_data()); 1059 var import_data10 = __toESM(require_data()); 1060 var import_element7 = __toESM(require_element()); 1061 var import_html_entities3 = __toESM(require_html_entities()); 1062 var import_i18n8 = __toESM(require_i18n()); 1063 var import_notices5 = __toESM(require_notices()); 1064 var import_a11y = __toESM(require_a11y()); 1065 var import_jsx_runtime10 = __toESM(require_jsx_runtime()); 1066 function RenamePatternCategoryModal({ 1067 category, 1068 existingCategories, 1069 onClose, 1070 onError, 1071 onSuccess, 1072 ...props 1073 }) { 1074 const id = (0, import_element7.useId)(); 1075 const textControlRef = (0, import_element7.useRef)(); 1076 const [name, setName] = (0, import_element7.useState)((0, import_html_entities3.decodeEntities)(category.name)); 1077 const [isSaving, setIsSaving] = (0, import_element7.useState)(false); 1078 const [validationMessage, setValidationMessage] = (0, import_element7.useState)(false); 1079 const validationMessageId = validationMessage ? `patterns-rename-pattern-category-modal__validation-message-$id}` : void 0; 1080 const { saveEntityRecord, invalidateResolution } = (0, import_data10.useDispatch)(import_core_data8.store); 1081 const { createErrorNotice, createSuccessNotice } = (0, import_data10.useDispatch)(import_notices5.store); 1082 const onChange = (newName) => { 1083 if (validationMessage) { 1084 setValidationMessage(void 0); 1085 } 1086 setName(newName); 1087 }; 1088 const onSave = async (event) => { 1089 event.preventDefault(); 1090 if (isSaving) { 1091 return; 1092 } 1093 if (!name || name === category.name) { 1094 const message = (0, import_i18n8.__)("Please enter a new name for this category."); 1095 (0, import_a11y.speak)(message, "assertive"); 1096 setValidationMessage(message); 1097 textControlRef.current?.focus(); 1098 return; 1099 } 1100 if (existingCategories.patternCategories.find((existingCategory) => { 1101 return existingCategory.id !== category.id && existingCategory.label.toLowerCase() === name.toLowerCase(); 1102 })) { 1103 const message = (0, import_i18n8.__)( 1104 "This category already exists. Please use a different name." 1105 ); 1106 (0, import_a11y.speak)(message, "assertive"); 1107 setValidationMessage(message); 1108 textControlRef.current?.focus(); 1109 return; 1110 } 1111 try { 1112 setIsSaving(true); 1113 const savedRecord = await saveEntityRecord( 1114 "taxonomy", 1115 CATEGORY_SLUG, 1116 { 1117 id: category.id, 1118 slug: category.slug, 1119 name 1120 } 1121 ); 1122 invalidateResolution("getUserPatternCategories"); 1123 onSuccess?.(savedRecord); 1124 onClose(); 1125 createSuccessNotice((0, import_i18n8.__)("Pattern category renamed."), { 1126 type: "snackbar", 1127 id: "pattern-category-update" 1128 }); 1129 } catch (error) { 1130 onError?.(); 1131 createErrorNotice(error.message, { 1132 type: "snackbar", 1133 id: "pattern-category-update" 1134 }); 1135 } finally { 1136 setIsSaving(false); 1137 setName(""); 1138 } 1139 }; 1140 const onRequestClose = () => { 1141 onClose(); 1142 setName(""); 1143 }; 1144 return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)( 1145 import_components7.Modal, 1146 { 1147 title: (0, import_i18n8.__)("Rename"), 1148 onRequestClose, 1149 ...props, 1150 children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("form", { onSubmit: onSave, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_components7.__experimentalVStack, { spacing: "5", children: [ 1151 /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_components7.__experimentalVStack, { spacing: "2", children: [ 1152 /* @__PURE__ */ (0, import_jsx_runtime10.jsx)( 1153 import_components7.TextControl, 1154 { 1155 ref: textControlRef, 1156 __next40pxDefaultSize: true, 1157 label: (0, import_i18n8.__)("Name"), 1158 value: name, 1159 onChange, 1160 "aria-describedby": validationMessageId, 1161 required: true 1162 } 1163 ), 1164 validationMessage && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)( 1165 "span", 1166 { 1167 className: "patterns-rename-pattern-category-modal__validation-message", 1168 id: validationMessageId, 1169 children: validationMessage 1170 } 1171 ) 1172 ] }), 1173 /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_components7.__experimentalHStack, { justify: "right", children: [ 1174 /* @__PURE__ */ (0, import_jsx_runtime10.jsx)( 1175 import_components7.Button, 1176 { 1177 __next40pxDefaultSize: true, 1178 variant: "tertiary", 1179 onClick: onRequestClose, 1180 children: (0, import_i18n8.__)("Cancel") 1181 } 1182 ), 1183 /* @__PURE__ */ (0, import_jsx_runtime10.jsx)( 1184 import_components7.Button, 1185 { 1186 __next40pxDefaultSize: true, 1187 variant: "primary", 1188 type: "submit", 1189 "aria-disabled": !name || name === category.name || isSaving, 1190 isBusy: isSaving, 1191 children: (0, import_i18n8.__)("Save") 1192 } 1193 ) 1194 ] }) 1195 ] }) }) 1196 } 1197 ); 1198 } 1199 1200 // packages/patterns/build-module/components/pattern-overrides-controls.js 1201 var import_element9 = __toESM(require_element()); 1202 var import_block_editor6 = __toESM(require_block_editor()); 1203 var import_components9 = __toESM(require_components()); 1204 var import_i18n10 = __toESM(require_i18n()); 1205 1206 // packages/patterns/build-module/components/allow-overrides-modal.js 1207 var import_components8 = __toESM(require_components()); 1208 var import_i18n9 = __toESM(require_i18n()); 1209 var import_element8 = __toESM(require_element()); 1210 var import_a11y2 = __toESM(require_a11y()); 1211 var import_jsx_runtime11 = __toESM(require_jsx_runtime()); 1212 function AllowOverridesModal({ 1213 placeholder, 1214 initialName = "", 1215 onClose, 1216 onSave 1217 }) { 1218 const [editedBlockName, setEditedBlockName] = (0, import_element8.useState)(initialName); 1219 const descriptionId = (0, import_element8.useId)(); 1220 const isNameValid = !!editedBlockName.trim(); 1221 const handleSubmit = () => { 1222 if (editedBlockName !== initialName) { 1223 const message = (0, import_i18n9.sprintf)( 1224 /* translators: %s: new name/label for the block */ 1225 (0, import_i18n9.__)('Block name changed to: "%s".'), 1226 editedBlockName 1227 ); 1228 (0, import_a11y2.speak)(message, "assertive"); 1229 } 1230 onSave(editedBlockName); 1231 onClose(); 1232 }; 1233 return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)( 1234 import_components8.Modal, 1235 { 1236 title: (0, import_i18n9.__)("Enable overrides"), 1237 onRequestClose: onClose, 1238 focusOnMount: "firstContentElement", 1239 aria: { describedby: descriptionId }, 1240 size: "small", 1241 children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)( 1242 "form", 1243 { 1244 onSubmit: (event) => { 1245 event.preventDefault(); 1246 if (!isNameValid) { 1247 return; 1248 } 1249 handleSubmit(); 1250 }, 1251 children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_components8.__experimentalVStack, { spacing: "6", children: [ 1252 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_components8.__experimentalText, { id: descriptionId, children: (0, import_i18n9.__)( 1253 "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." 1254 ) }), 1255 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)( 1256 import_components8.TextControl, 1257 { 1258 __next40pxDefaultSize: true, 1259 value: editedBlockName, 1260 label: (0, import_i18n9.__)("Name"), 1261 help: (0, import_i18n9.__)( 1262 'For example, if you are creating a recipe pattern, you use "Recipe Title", "Recipe Description", etc.' 1263 ), 1264 placeholder, 1265 onChange: setEditedBlockName 1266 } 1267 ), 1268 /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_components8.__experimentalHStack, { justify: "right", children: [ 1269 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)( 1270 import_components8.Button, 1271 { 1272 __next40pxDefaultSize: true, 1273 variant: "tertiary", 1274 onClick: onClose, 1275 children: (0, import_i18n9.__)("Cancel") 1276 } 1277 ), 1278 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)( 1279 import_components8.Button, 1280 { 1281 __next40pxDefaultSize: true, 1282 "aria-disabled": !isNameValid, 1283 variant: "primary", 1284 type: "submit", 1285 children: (0, import_i18n9.__)("Enable") 1286 } 1287 ) 1288 ] }) 1289 ] }) 1290 } 1291 ) 1292 } 1293 ); 1294 } 1295 function DisallowOverridesModal({ onClose, onSave }) { 1296 const descriptionId = (0, import_element8.useId)(); 1297 return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)( 1298 import_components8.Modal, 1299 { 1300 title: (0, import_i18n9.__)("Disable overrides"), 1301 onRequestClose: onClose, 1302 aria: { describedby: descriptionId }, 1303 size: "small", 1304 children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)( 1305 "form", 1306 { 1307 onSubmit: (event) => { 1308 event.preventDefault(); 1309 onSave(); 1310 onClose(); 1311 }, 1312 children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_components8.__experimentalVStack, { spacing: "6", children: [ 1313 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_components8.__experimentalText, { id: descriptionId, children: (0, import_i18n9.__)( 1314 "Are you sure you want to disable overrides? Disabling overrides will revert all applied overrides for this block throughout instances of this pattern." 1315 ) }), 1316 /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_components8.__experimentalHStack, { justify: "right", children: [ 1317 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)( 1318 import_components8.Button, 1319 { 1320 __next40pxDefaultSize: true, 1321 variant: "tertiary", 1322 onClick: onClose, 1323 children: (0, import_i18n9.__)("Cancel") 1324 } 1325 ), 1326 /* @__PURE__ */ (0, import_jsx_runtime11.jsx)( 1327 import_components8.Button, 1328 { 1329 __next40pxDefaultSize: true, 1330 variant: "primary", 1331 type: "submit", 1332 children: (0, import_i18n9.__)("Disable") 1333 } 1334 ) 1335 ] }) 1336 ] }) 1337 } 1338 ) 1339 } 1340 ); 1341 } 1342 1343 // packages/patterns/build-module/components/pattern-overrides-controls.js 1344 var import_jsx_runtime12 = __toESM(require_jsx_runtime()); 1345 function PatternOverridesControls({ 1346 attributes, 1347 setAttributes, 1348 name: blockName 1349 }) { 1350 const controlId = (0, import_element9.useId)(); 1351 const [showAllowOverridesModal, setShowAllowOverridesModal] = (0, import_element9.useState)(false); 1352 const [showDisallowOverridesModal, setShowDisallowOverridesModal] = (0, import_element9.useState)(false); 1353 const hasName = !!attributes.metadata?.name; 1354 const defaultBindings = attributes.metadata?.bindings?.__default; 1355 const hasOverrides = hasName && defaultBindings?.source === PATTERN_OVERRIDES_BINDING_SOURCE; 1356 const isConnectedToOtherSources = defaultBindings?.source && defaultBindings.source !== PATTERN_OVERRIDES_BINDING_SOURCE; 1357 const { updateBlockBindings } = (0, import_block_editor6.useBlockBindingsUtils)(); 1358 function updateBindings(isChecked, customName) { 1359 if (customName) { 1360 setAttributes({ 1361 metadata: { 1362 ...attributes.metadata, 1363 name: customName 1364 } 1365 }); 1366 } 1367 updateBlockBindings({ 1368 __default: isChecked ? { source: PATTERN_OVERRIDES_BINDING_SOURCE } : void 0 1369 }); 1370 } 1371 if (isConnectedToOtherSources) { 1372 return null; 1373 } 1374 const hasUnsupportedImageAttributes = blockName === "core/image" && !!attributes.href?.length; 1375 const helpText = !hasOverrides && hasUnsupportedImageAttributes ? (0, import_i18n10.__)( 1376 `Overrides currently don't support image links. Remove the link first before enabling overrides.` 1377 ) : (0, import_i18n10.__)( 1378 "Allow changes to this block throughout instances of this pattern." 1379 ); 1380 return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [ 1381 /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_block_editor6.InspectorControls, { group: "advanced", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)( 1382 import_components9.BaseControl, 1383 { 1384 id: controlId, 1385 label: (0, import_i18n10.__)("Overrides"), 1386 help: helpText, 1387 children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)( 1388 import_components9.Button, 1389 { 1390 __next40pxDefaultSize: true, 1391 className: "pattern-overrides-control__allow-overrides-button", 1392 variant: "secondary", 1393 "aria-haspopup": "dialog", 1394 onClick: () => { 1395 if (hasOverrides) { 1396 setShowDisallowOverridesModal(true); 1397 } else { 1398 setShowAllowOverridesModal(true); 1399 } 1400 }, 1401 disabled: !hasOverrides && hasUnsupportedImageAttributes, 1402 accessibleWhenDisabled: true, 1403 children: hasOverrides ? (0, import_i18n10.__)("Disable overrides") : (0, import_i18n10.__)("Enable overrides") 1404 } 1405 ) 1406 } 1407 ) }), 1408 showAllowOverridesModal && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)( 1409 AllowOverridesModal, 1410 { 1411 initialName: attributes.metadata?.name, 1412 onClose: () => setShowAllowOverridesModal(false), 1413 onSave: (newName) => { 1414 updateBindings(true, newName); 1415 } 1416 } 1417 ), 1418 showDisallowOverridesModal && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)( 1419 DisallowOverridesModal, 1420 { 1421 onClose: () => setShowDisallowOverridesModal(false), 1422 onSave: () => updateBindings(false) 1423 } 1424 ) 1425 ] }); 1426 } 1427 var pattern_overrides_controls_default = PatternOverridesControls; 1428 1429 // packages/patterns/build-module/components/reset-overrides-control.js 1430 var import_block_editor7 = __toESM(require_block_editor()); 1431 var import_components10 = __toESM(require_components()); 1432 var import_data11 = __toESM(require_data()); 1433 var import_i18n11 = __toESM(require_i18n()); 1434 var import_jsx_runtime13 = __toESM(require_jsx_runtime()); 1435 var CONTENT = "content"; 1436 function ResetOverridesControl(props) { 1437 const name = props.attributes.metadata?.name; 1438 const registry = (0, import_data11.useRegistry)(); 1439 const isOverridden = (0, import_data11.useSelect)( 1440 (select) => { 1441 if (!name) { 1442 return; 1443 } 1444 const { getBlockAttributes, getBlockParentsByBlockName } = select(import_block_editor7.store); 1445 const [patternClientId] = getBlockParentsByBlockName( 1446 props.clientId, 1447 "core/block", 1448 true 1449 ); 1450 if (!patternClientId) { 1451 return; 1452 } 1453 const overrides = getBlockAttributes(patternClientId)[CONTENT]; 1454 if (!overrides) { 1455 return; 1456 } 1457 return overrides.hasOwnProperty(name); 1458 }, 1459 [props.clientId, name] 1460 ); 1461 function onClick() { 1462 const { getBlockAttributes, getBlockParentsByBlockName } = registry.select(import_block_editor7.store); 1463 const [patternClientId] = getBlockParentsByBlockName( 1464 props.clientId, 1465 "core/block", 1466 true 1467 ); 1468 if (!patternClientId) { 1469 return; 1470 } 1471 const overrides = getBlockAttributes(patternClientId)[CONTENT]; 1472 if (!overrides.hasOwnProperty(name)) { 1473 return; 1474 } 1475 const { updateBlockAttributes, __unstableMarkLastChangeAsPersistent } = registry.dispatch(import_block_editor7.store); 1476 __unstableMarkLastChangeAsPersistent(); 1477 let newOverrides = { ...overrides }; 1478 delete newOverrides[name]; 1479 if (!Object.keys(newOverrides).length) { 1480 newOverrides = void 0; 1481 } 1482 updateBlockAttributes(patternClientId, { 1483 [CONTENT]: newOverrides 1484 }); 1485 } 1486 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") }) }) }); 1487 } 1488 1489 // packages/patterns/build-module/private-apis.js 1490 var privateApis = {}; 1491 lock(privateApis, { 1492 OverridesPanel, 1493 CreatePatternModal, 1494 CreatePatternModalContents, 1495 DuplicatePatternModal, 1496 isOverridableBlock, 1497 hasOverridableBlocks, 1498 useDuplicatePatternProps, 1499 RenamePatternModal, 1500 PatternsMenuItems, 1501 RenamePatternCategoryModal, 1502 PatternOverridesControls: pattern_overrides_controls_default, 1503 ResetOverridesControl, 1504 useAddPatternCategory, 1505 PATTERN_TYPES, 1506 PATTERN_DEFAULT_CATEGORY, 1507 PATTERN_USER_CATEGORY, 1508 EXCLUDED_PATTERN_SOURCES, 1509 PATTERN_SYNC_TYPES, 1510 PARTIAL_SYNCING_SUPPORTED_BLOCKS 1511 }); 1512 return __toCommonJS(index_exports); 1513 })();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sat Apr 18 08:20:10 2026 | Cross-referenced by PHPXref |