PluginProbe
Gutenberg / trunk
Gutenberg vtrunk
24.1.0 24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 All 404 releases
← All changes | build/modules/block-library/tabs/view.js +57 -13 23.8.0 → trunk View file →
@@ -46,11 +46,29 @@
46 46 const { tabIndex } = state;
47 47 return activeTabIndex === tabIndex;
48 48 },
49 49 /**
50 - * The value of the tabindex attribute for tab buttons.
51 - * Only the active tab should be in the tab sequence.
50 + * The value of the hidden attribute for tab panels.
52 51 *
52 + * Inactive panels use the `until-found` state rather than being
53 + * hidden outright, so their content stays reachable by the
54 + * browser's find-in-page and by fragment navigation. The browser
55 + * fires `beforematch` on the panel before revealing it, which is
56 + * where the matching tab gets activated.
57 + *
58 + * @type {string|null}
59 + */
60 + get isHidden() {
61 + return state.isActiveTab ? null : "until-found";
62 + },
63 + /**
64 + * The value of the tabindex attribute for tab buttons and tab
65 + * panels. Only the active tab should be in the tab sequence.
66 + *
67 + * An inactive panel is hidden with `until-found`, which leaves it
68 + * in the layout, so it stays focusable unless it is taken out of
69 + * the tab sequence here.
70 + *
53 71 * @type {number}
54 72 */
55 73 get tabIndexAttribute() {
56 74 return state.isActiveTab ? 0 : -1;
@@ -93,8 +111,20 @@
93 111 actions.setActiveTab(tabIndex);
94 112 }
95 113 }),
96 114 /**
115 + * Activates the tab whose panel the browser is about to reveal.
116 + *
117 + * Fired on a panel hidden with `until-found` when find-in-page or
118 + * a fragment navigation matches content inside it.
119 + */
120 + handleBeforeMatch: () => {
121 + const { tabIndex } = state;
122 + if (tabIndex !== null) {
123 + actions.setActiveTab(tabIndex);
124 + }
125 + },
126 + /**
97 127 * Moves focus to a specific tab without activating it.
98 128 *
99 129 * @param {number} tabIndex The index to move focus to.
100 130 */
@@ -145,23 +175,37 @@
145 175 }
146 176 }
147 177 },
148 178 callbacks: {
149 - /**
150 - * 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.
151 - *
152 - */
153 - onTabsInit: () => {
179 + activateTabByHash: () => {
154 180 const { tabsList } = state;
155 - if (tabsList.length === 0) {
181 + if (!tabsList || tabsList.length === 0) {
156 182 return;
157 183 }
158 - const { hash } = window.location;
159 - const tabId = hash.replace("#", "");
160 - const tabIndex = tabsList.findIndex((t) => t === tabId);
161 - if (tabIndex >= 0) {
162 - actions.setActiveTab(tabIndex, true);
184 + const targetElement = document.querySelector(":target");
185 + if (!targetElement) {
186 + return;
163 187 }
188 + const panelIndex = tabsList.findIndex(
189 + (t) => t === targetElement.id
190 + );
191 + if (panelIndex >= 0) {
192 + actions.setActiveTab(panelIndex, true);
193 + return;
194 + }
195 + let panel = targetElement.closest(".wp-block-tab-panel");
196 + let tabIndex = -1;
197 + while (panel && tabIndex < 0) {
198 + tabIndex = tabsList.findIndex((t) => t === panel.id);
199 + panel = panel.parentElement?.closest(".wp-block-tab-panel") ?? null;
200 + }
201 + if (tabIndex < 0) {
202 + return;
203 + }
204 + actions.setActiveTab(tabIndex);
205 + window.setTimeout(() => {
206 + targetElement.scrollIntoView();
207 + }, 0);
164 208 }
165 209 }
166 210 },
167 211 {