[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/dist/script-modules/block-library/tabs/ -> view.js (source)

   1  // packages/block-library/build-module/tabs/view.mjs
   2  import {
   3    store,
   4    getContext,
   5    getElement,
   6    withSyncEvent
   7  } from "@wordpress/interactivity";
   8  function createReadOnlyProxy(obj) {
   9    const arrayMutationMethods = /* @__PURE__ */ new Set([
  10      "push",
  11      "pop",
  12      "shift",
  13      "unshift",
  14      "splice",
  15      "sort",
  16      "reverse",
  17      "copyWithin",
  18      "fill"
  19    ]);
  20    return new Proxy(obj, {
  21      get(target, prop) {
  22        if (Array.isArray(target) && arrayMutationMethods.has(prop)) {
  23          return () => {
  24          };
  25        }
  26        const value = target[prop];
  27        if (typeof value === "object" && value !== null) {
  28          return createReadOnlyProxy(value);
  29        }
  30        return value;
  31      },
  32      set() {
  33        return false;
  34      },
  35      deleteProperty() {
  36        return false;
  37      }
  38    });
  39  }
  40  var { actions: privateActions, state: privateState } = store(
  41    "core/tabs/private",
  42    {
  43      state: {
  44        /**
  45         * Gets a contextually aware list of tabs for the current tabs block.
  46         *
  47         * @type {Array}
  48         */
  49        get tabsList() {
  50          const context = getContext();
  51          const tabsId = context?.tabsId;
  52          const tabsList = privateState[tabsId];
  53          return tabsList;
  54        },
  55        /**
  56         * Gets the index of the active tab element whether it
  57         * is a tab label or tab panel.
  58         *
  59         * @type {number|null}
  60         */
  61        get tabIndex() {
  62          const { attributes } = getElement();
  63          const tabId = attributes?.id?.replace("tab__", "") || null;
  64          if (!tabId) {
  65            return null;
  66          }
  67          const { tabsList } = privateState;
  68          const tabIndex = tabsList.findIndex((t) => t.id === tabId);
  69          return tabIndex;
  70        },
  71        /**
  72         * Whether the tab panel or tab label is the active tab.
  73         *
  74         * @type {boolean}
  75         */
  76        get isActiveTab() {
  77          const { activeTabIndex } = getContext();
  78          const { tabIndex } = privateState;
  79          return activeTabIndex === tabIndex;
  80        },
  81        /**
  82         * The value of the tabindex attribute for tab buttons.
  83         * Only the active tab should be in the tab sequence.
  84         *
  85         * @type {number}
  86         */
  87        get tabIndexAttribute() {
  88          return privateState.isActiveTab ? 0 : -1;
  89        }
  90      },
  91      actions: {
  92        /**
  93         * Handles the keydown events for the tab label and tabs controller.
  94         *
  95         * @param {KeyboardEvent} event The keydown event.
  96         */
  97        handleTabKeyDown: withSyncEvent((event) => {
  98          const context = getContext();
  99          const { isVertical } = context;
 100          const { tabIndex } = privateState;
 101          if (tabIndex === null) {
 102            return;
 103          }
 104          if (event.key === "ArrowRight" && !isVertical) {
 105            event.preventDefault();
 106            privateActions.moveFocus(tabIndex + 1);
 107          } else if (event.key === "ArrowLeft" && !isVertical) {
 108            event.preventDefault();
 109            privateActions.moveFocus(tabIndex - 1);
 110          } else if (event.key === "ArrowDown" && isVertical) {
 111            event.preventDefault();
 112            privateActions.moveFocus(tabIndex + 1);
 113          } else if (event.key === "ArrowUp" && isVertical) {
 114            event.preventDefault();
 115            privateActions.moveFocus(tabIndex - 1);
 116          }
 117        }),
 118        /**
 119         * Handles the click event for the tab label.
 120         *
 121         * @param {MouseEvent} event The click event.
 122         */
 123        handleTabClick: withSyncEvent((event) => {
 124          event.preventDefault();
 125          const { tabIndex } = privateState;
 126          if (tabIndex !== null) {
 127            privateActions.setActiveTab(tabIndex);
 128          }
 129        }),
 130        /**
 131         * Moves focus to a specific tab without activating it.
 132         *
 133         * @param {number} tabIndex The index to move focus to.
 134         */
 135        moveFocus: (tabIndex) => {
 136          const { tabsList } = privateState;
 137          if (!tabsList || tabsList.length === 0) {
 138            return;
 139          }
 140          let newIndex = tabIndex;
 141          if (newIndex < 0) {
 142            newIndex = tabsList.length - 1;
 143          } else if (newIndex >= tabsList.length) {
 144            newIndex = 0;
 145          }
 146          const tabId = tabsList[newIndex].id;
 147          const tabElement = document.getElementById("tab__" + tabId);
 148          if (tabElement) {
 149            tabElement.focus();
 150          }
 151        },
 152        /**
 153         * Sets the active tab index (internal implementation).
 154         *
 155         * @param {number}  tabIndex    The index of the active tab.
 156         * @param {boolean} scrollToTab Whether to scroll to the tab element.
 157         */
 158        setActiveTab: (tabIndex, scrollToTab = false) => {
 159          const { tabsList } = privateState;
 160          if (!tabsList || tabsList.length === 0) {
 161            return;
 162          }
 163          let newIndex = tabIndex;
 164          if (newIndex < 0) {
 165            newIndex = 0;
 166          } else if (newIndex >= tabsList.length) {
 167            newIndex = tabsList.length - 1;
 168          }
 169          const context = getContext();
 170          context.activeTabIndex = newIndex;
 171          if (scrollToTab) {
 172            const tabId = tabsList[newIndex].id;
 173            const tabElement = document.getElementById(tabId);
 174            if (tabElement) {
 175              setTimeout(() => {
 176                tabElement.scrollIntoView({ behavior: "smooth" });
 177              }, 100);
 178            }
 179          }
 180        }
 181      },
 182      callbacks: {
 183        /**
 184         * When the tabs are initialized, we need to check if there is a hash in the url and if so if it exists in the current tabsList, set the active tab to that index.
 185         *
 186         */
 187        onTabsInit: () => {
 188          const { tabsList } = privateState;
 189          if (tabsList.length === 0) {
 190            return;
 191          }
 192          const { hash } = window.location;
 193          const tabId = hash.replace("#", "");
 194          const tabIndex = tabsList.findIndex((t) => t.id === tabId);
 195          if (tabIndex >= 0) {
 196            privateActions.setActiveTab(tabIndex, true);
 197          }
 198        }
 199      }
 200    },
 201    {
 202      lock: true
 203    }
 204  );
 205  store("core/tabs", {
 206    state: {
 207      /**
 208       * Gets a contextually aware list of tabs for the current tabs block.
 209       * Public API for third-party access.
 210       *
 211       * @type {Array}
 212       */
 213      get tabsList() {
 214        return createReadOnlyProxy(privateState.tabsList);
 215      },
 216      /**
 217       * Gets the index of the active tab element whether it
 218       * is a tab label or tab panel.
 219       *
 220       * @type {number|null}
 221       */
 222      get tabIndex() {
 223        return privateState.tabIndex;
 224      },
 225      /**
 226       * Whether the tab panel or tab label is the active tab.
 227       *
 228       * @type {boolean}
 229       */
 230      get isActiveTab() {
 231        return privateState.isActiveTab;
 232      }
 233    },
 234    actions: {
 235      /**
 236       * Sets the active tab index.
 237       * Public API for third-party programmatic tab activation.
 238       *
 239       * @param {number}  tabIndex    The index of the active tab.
 240       * @param {boolean} scrollToTab Whether to scroll to the tab element.
 241       */
 242      setActiveTab: (tabIndex, scrollToTab = false) => {
 243        privateActions.setActiveTab(tabIndex, scrollToTab);
 244      }
 245    }
 246  });


Generated : Mon Jun 15 08:20:09 2026 Cross-referenced by PHPXref