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
gutenberg / build / modules / block-library / navigation / view.js

view.js in Gutenberg trunk, at build/modules/block-library/navigation/view.js

182 lines 5.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // packages/block-library/build-module/navigation/view.mjs
2 import {
3 store,
4 getContext,
5 getElement,
6 withSyncEvent
7 } from "@wordpress/interactivity";
8 var focusableSelectors = [
9 "a[href]",
10 'input:not([disabled]):not([type="hidden"]):not([aria-hidden])',
11 "select:not([disabled]):not([aria-hidden])",
12 "textarea:not([disabled]):not([aria-hidden])",
13 "button:not([disabled]):not([aria-hidden])",
14 "[contenteditable]",
15 '[tabindex]:not([tabindex^="-"])'
16 ];
17 function getFocusableElements(ref) {
18 const focusableElements = ref.querySelectorAll(focusableSelectors);
19 return Array.from(focusableElements).filter((element) => {
20 if (typeof element.checkVisibility === "function") {
21 return element.checkVisibility({
22 checkOpacity: false,
23 checkVisibilityCSS: true
24 });
25 }
26 return element.offsetParent !== null;
27 });
28 }
29 document.addEventListener("click", () => {
30 });
31 var { state, actions } = store(
32 "core/navigation",
33 {
34 state: {
35 get roleAttribute() {
36 const ctx = getContext();
37 return ctx.type === "overlay" && state.isMenuOpen ? "dialog" : null;
38 },
39 get ariaModal() {
40 const ctx = getContext();
41 return ctx.type === "overlay" && state.isMenuOpen ? "true" : null;
42 },
43 get ariaLabel() {
44 const ctx = getContext();
45 return ctx.type === "overlay" && state.isMenuOpen ? ctx.ariaLabel : null;
46 },
47 get isMenuOpen() {
48 return Object.values(state.menuOpenedBy).filter(Boolean).length > 0;
49 },
50 get menuOpenedBy() {
51 const ctx = getContext();
52 return ctx.type === "overlay" ? ctx.overlayOpenedBy : ctx.submenuOpenedBy;
53 },
54 get isSubmenuOpen() {
55 const ctx = getContext();
56 const isDefaultOverlayOpen = !ctx.hasCustomOverlay && Object.values(ctx.overlayOpenedBy || {}).filter(Boolean).length > 0;
57 return isDefaultOverlayOpen || state.isMenuOpen;
58 }
59 },
60 actions: {
61 openMenuOnHover(event) {
62 if (event?.pointerType === "touch") {
63 return;
64 }
65 const { type } = getContext();
66 if (type === "submenu") {
67 actions.openMenu("hover");
68 }
69 },
70 closeMenuOnHover(event) {
71 if (event?.pointerType === "touch") {
72 return;
73 }
74 const { type } = getContext();
75 if (type === "submenu") {
76 actions.closeMenu("hover");
77 }
78 },
79 openMenuOnClick() {
80 const ctx = getContext();
81 const { ref } = getElement();
82 ctx.previousFocus = ref;
83 actions.openMenu("click");
84 },
85 closeMenuOnClick() {
86 actions.closeMenu("click");
87 actions.closeMenu("focus");
88 },
89 openMenuOnFocus() {
90 actions.openMenu("focus");
91 },
92 toggleMenuOnClick() {
93 const ctx = getContext();
94 const { ref } = getElement();
95 if (window.document.activeElement !== ref) {
96 ref.focus();
97 }
98 const { menuOpenedBy } = state;
99 if (menuOpenedBy.click || menuOpenedBy.focus) {
100 actions.closeMenu("click");
101 actions.closeMenu("focus");
102 actions.closeMenu("hover");
103 } else {
104 ctx.previousFocus = ref;
105 actions.openMenu("click");
106 }
107 },
108 handleMenuKeydown: withSyncEvent((event) => {
109 const { type, firstFocusableElement, lastFocusableElement } = getContext();
110 if (state.menuOpenedBy.click) {
111 if (event.key === "Escape") {
112 event.stopPropagation();
113 actions.closeMenu("click");
114 actions.closeMenu("focus");
115 return;
116 }
117 if (type === "overlay" && event.key === "Tab") {
118 if (event.shiftKey && window.document.activeElement === firstFocusableElement) {
119 event.preventDefault();
120 lastFocusableElement.focus();
121 } else if (!event.shiftKey && window.document.activeElement === lastFocusableElement) {
122 event.preventDefault();
123 firstFocusableElement.focus();
124 }
125 }
126 }
127 }),
128 handleMenuFocusout: withSyncEvent((event) => {
129 const { modal, type } = getContext();
130 if (event.relatedTarget === null || !modal?.contains(event.relatedTarget) && event.target !== window.document.activeElement && type === "submenu") {
131 actions.closeMenu("click");
132 actions.closeMenu("focus");
133 }
134 }),
135 openMenu(menuOpenedOn = "click") {
136 const { type } = getContext();
137 state.menuOpenedBy[menuOpenedOn] = true;
138 if (type === "overlay") {
139 document.documentElement.classList.add("has-modal-open");
140 }
141 },
142 closeMenu(menuClosedOn = "click") {
143 const ctx = getContext();
144 state.menuOpenedBy[menuClosedOn] = false;
145 if (!state.isMenuOpen) {
146 if (ctx.modal?.contains(window.document.activeElement)) {
147 ctx.previousFocus?.focus();
148 }
149 ctx.modal = null;
150 ctx.previousFocus = null;
151 if (ctx.type === "overlay") {
152 document.documentElement.classList.remove(
153 "has-modal-open"
154 );
155 }
156 }
157 }
158 },
159 callbacks: {
160 initMenu() {
161 const ctx = getContext();
162 const { ref } = getElement();
163 if (state.isMenuOpen) {
164 const focusableElements = getFocusableElements(ref);
165 ctx.modal = ref;
166 ctx.firstFocusableElement = focusableElements[0];
167 ctx.lastFocusableElement = focusableElements[focusableElements.length - 1];
168 }
169 },
170 focusFirstElement() {
171 const { ref } = getElement();
172 if (state.isMenuOpen) {
173 const focusableElements = getFocusableElements(ref);
174 focusableElements?.[0]?.focus();
175 }
176 }
177 }
178 },
179 { lock: true }
180 );
181 //# sourceMappingURL=view.js.map
182