PluginProbe
Gutenberg / 23.3.2
Gutenberg v23.3.2
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 12.6.0 7.4.0 All 402 releases
gutenberg / build / modules / block-library / tabs / view.js

view.js in Gutenberg 23.3.2, at build/modules/block-library/tabs/view.js

248 lines 6.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 });
247 //# sourceMappingURL=view.js.map
248