[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/dist/ -> patterns.js (source)

   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  })();


Generated : Thu Jul 2 08:20:12 2026 Cross-referenced by PHPXref