| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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 }, 55 actions: { 56 openMenuOnHover(event) { 57 if (event?.pointerType === "touch") { 58 return; 59 } 60 const { type, overlayOpenedBy } = getContext(); 61 if (type === "submenu" && // Only open on hover if the overlay is closed. 62 Object.values(overlayOpenedBy || {}).filter(Boolean).length === 0) { 63 actions.openMenu("hover"); 64 } 65 }, 66 closeMenuOnHover(event) { 67 if (event?.pointerType === "touch") { 68 return; 69 } 70 const { type, overlayOpenedBy } = getContext(); 71 if (type === "submenu" && // Only close on hover if the overlay is closed. 72 Object.values(overlayOpenedBy || {}).filter(Boolean).length === 0) { 73 actions.closeMenu("hover"); 74 } 75 }, 76 openMenuOnClick() { 77 const ctx = getContext(); 78 const { ref } = getElement(); 79 ctx.previousFocus = ref; 80 actions.openMenu("click"); 81 }, 82 closeMenuOnClick() { 83 actions.closeMenu("click"); 84 actions.closeMenu("focus"); 85 }, 86 openMenuOnFocus() { 87 actions.openMenu("focus"); 88 }, 89 toggleMenuOnClick() { 90 const ctx = getContext(); 91 const { ref } = getElement(); 92 if (window.document.activeElement !== ref) { 93 ref.focus(); 94 } 95 const { menuOpenedBy } = state; 96 if (menuOpenedBy.click || menuOpenedBy.focus) { 97 actions.closeMenu("click"); 98 actions.closeMenu("focus"); 99 actions.closeMenu("hover"); 100 } else { 101 ctx.previousFocus = ref; 102 actions.openMenu("click"); 103 } 104 }, 105 handleMenuKeydown: withSyncEvent((event) => { 106 const { type, firstFocusableElement, lastFocusableElement } = getContext(); 107 if (state.menuOpenedBy.click) { 108 if (event.key === "Escape") { 109 event.stopPropagation(); 110 actions.closeMenu("click"); 111 actions.closeMenu("focus"); 112 return; 113 } 114 if (type === "overlay" && event.key === "Tab") { 115 if (event.shiftKey && window.document.activeElement === firstFocusableElement) { 116 event.preventDefault(); 117 lastFocusableElement.focus(); 118 } else if (!event.shiftKey && window.document.activeElement === lastFocusableElement) { 119 event.preventDefault(); 120 firstFocusableElement.focus(); 121 } 122 } 123 } 124 }), 125 handleMenuFocusout: withSyncEvent((event) => { 126 const { modal, type } = getContext(); 127 if (event.relatedTarget === null || !modal?.contains(event.relatedTarget) && event.target !== window.document.activeElement && type === "submenu") { 128 actions.closeMenu("click"); 129 actions.closeMenu("focus"); 130 } 131 }), 132 openMenu(menuOpenedOn = "click") { 133 const { type } = getContext(); 134 state.menuOpenedBy[menuOpenedOn] = true; 135 if (type === "overlay") { 136 document.documentElement.classList.add("has-modal-open"); 137 } 138 }, 139 closeMenu(menuClosedOn = "click") { 140 const ctx = getContext(); 141 state.menuOpenedBy[menuClosedOn] = false; 142 if (!state.isMenuOpen) { 143 if (ctx.modal?.contains(window.document.activeElement)) { 144 ctx.previousFocus?.focus(); 145 } 146 ctx.modal = null; 147 ctx.previousFocus = null; 148 if (ctx.type === "overlay") { 149 document.documentElement.classList.remove( 150 "has-modal-open" 151 ); 152 } 153 } 154 } 155 }, 156 callbacks: { 157 initMenu() { 158 const ctx = getContext(); 159 const { ref } = getElement(); 160 if (state.isMenuOpen) { 161 const focusableElements = getFocusableElements(ref); 162 ctx.modal = ref; 163 ctx.firstFocusableElement = focusableElements[0]; 164 ctx.lastFocusableElement = focusableElements[focusableElements.length - 1]; 165 } 166 }, 167 focusFirstElement() { 168 const { ref } = getElement(); 169 if (state.isMenuOpen) { 170 const focusableElements = getFocusableElements(ref); 171 focusableElements?.[0]?.focus(); 172 } 173 } 174 } 175 }, 176 { lock: true } 177 );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sat Jun 20 08:20:11 2026 | Cross-referenced by PHPXref |