Caleb Porzio hace 2 años
padre
commit
4291ccbaef
Se han modificado 2 ficheros con 55 adiciones y 3 borrados
  1. 10 3
      packages/ui/src/menu.js
  2. 45 0
      tests/cypress/integration/plugins/ui/menu.spec.js

+ 10 - 3
packages/ui/src/menu.js

@@ -38,13 +38,21 @@ function handleRoot(el, Alpine) {
 
                     nextTick(() => this.$refs.__items.focus({ preventScroll: true }))
                 },
-                __close() {
+                __close(focusAfter = true) {
                     this.__isOpen = false
 
-                    this.$nextTick(() => this.$refs.__button.focus({ preventScroll: true }))
+                    focusAfter && this.$nextTick(() => this.$refs.__button.focus({ preventScroll: true }))
+                },
+                __contains(outer, inner) {
+                    return !! Alpine.findClosest(inner, el => el.isSameNode(outer))
                 }
             }
         },
+        '@focusin.window'() {
+            if (! this.$data.__contains(this.$el, document.activeElement)) {
+                this.$data.__close(false)
+            }
+        },
     })
 }
 
@@ -74,7 +82,6 @@ function handleItems(el, Alpine) {
         ':aria-labelledby'() { return this.$id('alpine-menu-button') },
         ':aria-activedescendant'() { return this.$data.__activeEl && this.$data.__activeEl.id },
         'x-show'() { return this.$data.__isOpen },
-        'x-trap'() { return this.$data.__isOpen },
         'tabindex': '0',
         '@click.outside'() { this.$data.__close() },
         '@keydown'(e) { dom.search(Alpine, this.$refs.__items, e.key, el => el.__activate()) },

+ 45 - 0
tests/cypress/integration/plugins/ui/menu.spec.js

@@ -43,6 +43,51 @@ test('it works',
     },
 )
 
+test('focusing away closes menu',
+    [html`
+    <div>
+        <div x-data x-menu>
+            <span>
+                <button x-menu:button trigger>
+                    <span>Options</span>
+                </button>
+            </span>
+            <div x-menu:items items>
+                <div>
+                    <p>Signed in as</p>
+                    <p>tom@example.com</p>
+                </div>
+                <div>
+                    <a x-menu:item href="#account-settings">
+                        Account settings
+                    </a>
+                    <a x-menu:item href="#support">
+                        Support
+                    </a>
+                    <a x-menu:item href="#license">
+                        License
+                    </a>
+                </div>
+                <div>
+                    <a x-menu:item href="#sign-out">
+                        Sign out
+                    </a>
+                </div>
+            </div>
+        </div>
+
+        <button>Focus away</button>
+    </div>
+    `],
+    ({ get }) => {
+        get('[items]').should(notBeVisible())
+        get('[trigger]').click()
+        get('[items]').should(beVisible())
+        cy.focused().tab()
+        get('[items]').should(notBeVisible())
+    },
+)
+
 test('it works with x-model',
     [html`
         <div x-data="{ open: false }" x-menu x-model="open">