diff --git a/resources/js/components/dropdown.js b/resources/js/components/dropdown.js index 22402d483..f761ecf01 100644 --- a/resources/js/components/dropdown.js +++ b/resources/js/components/dropdown.js @@ -12,6 +12,7 @@ class DropDown { this.menu = this.$refs.menu; this.toggle = this.$refs.toggle; this.moveMenu = this.$opts.moveMenu; + this.bubbleEscapes = this.$opts.bubbleEscapes === 'true'; this.direction = (document.dir === 'rtl') ? 'right' : 'left'; this.body = document.body; @@ -137,7 +138,9 @@ class DropDown { } else if (event.key === 'Escape') { this.hide(); this.toggle.focus(); - event.stopPropagation(); + if (!this.bubbleEscapes) { + event.stopPropagation(); + } } }; this.container.addEventListener('keydown', keyboardNavigation); diff --git a/resources/js/components/header-mobile-toggle.js b/resources/js/components/header-mobile-toggle.js index eccd4b8f0..99737bfb8 100644 --- a/resources/js/components/header-mobile-toggle.js +++ b/resources/js/components/header-mobile-toggle.js @@ -1,31 +1,41 @@ class HeaderMobileToggle { - constructor(elem) { - this.elem = elem; - this.toggleButton = elem.querySelector('.mobile-menu-toggle'); - this.menu = elem.querySelector('.header-links'); - this.open = false; + setup() { + this.elem = this.$el; + this.toggleButton = this.$refs.toggle; + this.menu = this.$refs.menu; + this.open = false; this.toggleButton.addEventListener('click', this.onToggle.bind(this)); this.onWindowClick = this.onWindowClick.bind(this); + this.onKeyDown = this.onKeyDown.bind(this); } onToggle(event) { this.open = !this.open; this.menu.classList.toggle('show', this.open); + this.toggleButton.setAttribute('aria-expanded', this.open ? 'true' : 'false'); if (this.open) { + this.elem.addEventListener('keydown', this.onKeyDown); window.addEventListener('click', this.onWindowClick) } else { + this.elem.removeEventListener('keydown', this.onKeyDown); window.removeEventListener('click', this.onWindowClick) } event.stopPropagation(); } + onKeyDown(event) { + if (event.code === 'Escape') { + this.onToggle(event); + } + } + onWindowClick(event) { this.onToggle(event); } } -module.exports = HeaderMobileToggle; \ No newline at end of file +export default HeaderMobileToggle; \ No newline at end of file diff --git a/resources/js/components/tri-layout.js b/resources/js/components/tri-layout.js index 905ca03b1..f801e52a1 100644 --- a/resources/js/components/tri-layout.js +++ b/resources/js/components/tri-layout.js @@ -1,8 +1,9 @@ class TriLayout { - constructor(elem) { - this.elem = elem; + setup() { + this.container = this.$refs.container; + this.tabs = this.$manyRefs.tab; this.lastLayoutType = 'none'; this.onDestroy = null; @@ -43,13 +44,12 @@ class TriLayout { } setupMobile() { - const layoutTabs = document.querySelectorAll('[tri-layout-mobile-tab]'); - for (let tab of layoutTabs) { + for (const tab of this.tabs) { tab.addEventListener('click', this.mobileTabClick); } this.onDestroy = () => { - for (let tab of layoutTabs) { + for (const tab of this.tabs) { tab.removeEventListener('click', this.mobileTabClick); } } @@ -65,7 +65,7 @@ class TriLayout { * @param event */ mobileTabClick(event) { - const tab = event.target.getAttribute('tri-layout-mobile-tab'); + const tab = event.target.dataset.tab; this.showTab(tab); } @@ -79,21 +79,21 @@ class TriLayout { /** * Show the given tab - * @param tabName + * @param {String} tabName + * @param {Boolean }scroll */ showTab(tabName, scroll = true) { this.scrollCache[this.lastTabShown] = document.documentElement.scrollTop; // Set tab status - const tabs = document.querySelectorAll('.tri-layout-mobile-tab'); - for (let tab of tabs) { - const isActive = (tab.getAttribute('tri-layout-mobile-tab') === tabName); - tab.classList.toggle('active', isActive); + for (const tab of this.tabs) { + const isActive = (tab.dataset.tab === tabName); + tab.setAttribute('aria-selected', isActive ? 'true' : 'false'); } // Toggle section const showInfo = (tabName === 'info'); - this.elem.classList.toggle('show-info', showInfo); + this.container.classList.toggle('show-info', showInfo); // Set the scroll position from cache if (scroll) { diff --git a/resources/lang/en/common.php b/resources/lang/en/common.php index 3b003c64a..855c1c807 100644 --- a/resources/lang/en/common.php +++ b/resources/lang/en/common.php @@ -65,6 +65,7 @@ return [ 'breadcrumb' => 'Breadcrumb', // Header + 'header_menu_expand' => 'Expand Header Menu', 'profile_menu' => 'Profile Menu', 'view_profile' => 'View Profile', 'edit_profile' => 'Edit Profile', @@ -73,7 +74,9 @@ return [ // Layout tabs 'tab_info' => 'Info', + 'tab_info_label' => 'Tab: Show Secondary Information', 'tab_content' => 'Content', + 'tab_content_label' => 'Tab: Show Primary Content', // Email Content 'email_action_help' => 'If you’re having trouble clicking the ":actionText" button, copy and paste the URL below into your web browser:', diff --git a/resources/sass/_header.scss b/resources/sass/_header.scss index f371e0410..e06dcde6f 100644 --- a/resources/sass/_header.scss +++ b/resources/sass/_header.scss @@ -191,6 +191,11 @@ header .search-box { @include lightDark(color, #000, #fff); text-decoration: none; } + &:focus { + @include lightDark(background-color, #eee, #333); + outline-color: var(--color-primary); + color: var(--color-primary); + } } header .dropdown-container { display: block; @@ -225,7 +230,7 @@ header .search-box { &:first-child { border-inline-end: 1px solid #DDD; } - &.active { + &[aria-selected="true"] { border-bottom-color: currentColor; } } diff --git a/resources/views/base.blade.php b/resources/views/base.blade.php index 29e4acee7..66604345f 100644 --- a/resources/views/base.blade.php +++ b/resources/views/base.blade.php @@ -31,7 +31,7 @@ @include('partials.notifications') @include('common.header') -
+
@yield('content')
diff --git a/resources/views/common/header.blade.php b/resources/views/common/header.blade.php index 52f6b8cbb..4799aba24 100644 --- a/resources/views/common/header.blade.php +++ b/resources/views/common/header.blade.php @@ -1,4 +1,4 @@ -