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