Преглед на файлове

Add noreturn modifier to x-trap (#2603)

* added x-trap.noreturn modifier

avoids re-focusing trigger element

* Added documentation for x-trap.noreturn modifier
Andrew преди 3 години
родител
ревизия
8b4e68a5b6
променени са 3 файла, в които са добавени 69 реда и са изтрити 2 реда
  1. 47 0
      packages/docs/src/en/plugins/focus.md
  2. 4 2
      packages/focus/src/index.js
  3. 18 0
      tests/cypress/integration/plugins/focus.spec.js

+ 47 - 0
packages/docs/src/en/plugins/focus.md

@@ -254,6 +254,53 @@ For example:
 </div>
 <!-- END_VERBATIM -->
 
+<a name="noreturn"></a>
+#### .noreturn
+
+Sometimes you may not want focus to be returned to where it was previously. Consider a dropdown that's triggered upon focusing an input, returning focus to the input on close will just trigger the dropdown to open again.
+
+`x-trap` allows you to disable this behavior with the `.noreturn` modifier.
+
+By adding `.noreturn`, Alpine will not return focus upon x-trap evaluating to false.
+
+For example:
+
+```alpine
+<div x-data="{ open: false }" x-trap.noreturn="open">
+    <input type="search" placeholder="search for something" />
+
+    <div x-show="open">
+        Search results
+
+        <button @click="open = false">Close</button>
+    </div>
+</div>
+```
+
+<!-- START_VERBATIM -->
+<div class="demo">
+    <div
+        x-data="{ open: false }" 
+        x-trap.noreturn="open"
+        @click.outside="open = false"
+        @keyup.escape.prevent.stop="open = false"
+    >
+        <input type="search" placeholder="search for something"
+            @focus="open = true"
+            @keyup.escape.prevent="$el.blur()"
+        />
+
+        <div x-show="open">
+            <div class="mb-4 text-bold">Search results</div>
+
+            <p class="mb-4 text-gray-600 text-sm">Notice when closing this dropdown, focus is not returned to the input.</p>
+
+            <button class="mt-4" @click="open = false">Close Dialog</button>
+        </div>
+    </div>
+</div>
+<!-- END_VERBATIM -->
+
 <a name="focus-magic"></a>
 ## $focus
 

+ 4 - 2
packages/focus/src/index.js

@@ -102,7 +102,7 @@ export default function (Alpine) {
 
             let oldValue = false
 
-            let trap = createFocusTrap(el, { 
+            let trap = createFocusTrap(el, {
                 escapeDeactivates: false,
                 allowOutsideClick: true,
                 fallbackFocus: () => el,
@@ -132,7 +132,9 @@ export default function (Alpine) {
                     undoDisableScrolling()
                     undoDisableScrolling = () => {}
 
-                    trap.deactivate()
+                    trap.deactivate({
+                        returnFocus: !modifiers.includes('noreturn')
+                    })
                 }
 
                 oldValue = !! value

+ 18 - 0
tests/cypress/integration/plugins/focus.spec.js

@@ -101,6 +101,24 @@ test('can trap focus with noscroll',
     },
 )
 
+test('can trap focus with noreturn',
+    [html`
+        <div x-data="{ open: false }" x-trap.noreturn="open">
+            <input id="input" @focus="open = true" />
+
+            <div x-show="open">
+                <button @click="open = false" id="close">close</button>
+            </div>
+        </div>
+    `],
+    ({ get }) => {
+        get('#input').focus()
+        get('#close')
+        get('#close').click()
+        get('#input').should(notHaveFocus())
+    },
+)
+
 test('$focus.focus',
     [html`
         <div x-data>