Caleb Porzio 3 سال پیش
والد
کامیت
ab72e86238
4فایلهای تغییر یافته به همراه126 افزوده شده و 0 حذف شده
  1. 26 0
      index.html
  2. 40 0
      packages/alpinejs/src/magics/$id.js
  3. 1 0
      packages/alpinejs/src/magics/index.js
  4. 59 0
      tests/cypress/integration/magics/$id.spec.js

+ 26 - 0
index.html

@@ -7,6 +7,32 @@
     <script src="./packages/alpinejs/dist/cdn.js" defer></script>
     <!-- <script src="https://unpkg.com/alpinejs@3.0.0/dist/cdn.min.js" defer></script> -->
 
+
+    <!-- Add aria-hidden="true" to all other elements. -->
+    <div x-trap.inert="open">...</div>
+
+    <!-- Disabled scrolling when a dialog is open. -->
+    <div x-trap.noscroll="open">...</div>
+
+    <!-- Easily perist global store data in localStorage. -->
+    <script>
+        Alpine.store('config', {
+            darkMode: Alpine.$persist(false),
+        })
+    </script>
+
+    <!-- You can now pass around Alpine scope as an object with the new $data magic. -->
+    <div @click="doSomething($data)"></div>
+
+    <!-- x-model data can now be programmatically "get" and "set" (with reactivity). -->
+    <div
+        x-model="open"
+        x-text="$el._x_model.get()"
+        @click="$el._x_model.set('...')"
+    >...</div>
+     
+
+
     <!-- Play around. -->
     <div x-data="{ open: false }">
         <button @click="open = !open">Toggle</button>

+ 40 - 0
packages/alpinejs/src/magics/$id.js

@@ -0,0 +1,40 @@
+import { closestDataStack, mergeProxies } from '../scope'
+import { magic } from '../magics'
+import { closestRoot } from '../lifecycle'
+
+let memo = {}
+
+magic('id', el => (name, key = null) => {
+    if (! memo[name]) memo[name] = 0
+
+    let root = closestRoot(el)
+    let id = getId(root, el, name)
+
+    if (key) {
+        return `${name}-${id}-${key}`
+    }
+
+    return `${name}-${id}`
+})
+
+function getId(root, el, name) {
+    if (! root._x_ids) root._x_ids = []
+
+    if (root._x_ids.includes(name)) {
+        return memo[name]
+    } else {
+        root._x_ids.push(name) 
+        
+        return ++memo[name]
+    }
+}
+
+export function closestIdRoot(el) {
+    if (! el) return
+
+    if (el._x_ids) return el
+
+    if (! el.parentElement) return
+
+    return closestIdRoot(el.parentElement)
+}

+ 1 - 0
packages/alpinejs/src/magics/index.js

@@ -5,4 +5,5 @@ import './$store'
 import './$data'
 import './$root'
 import './$refs'
+import './$id'
 import './$el'

+ 59 - 0
tests/cypress/integration/magics/$id.spec.js

@@ -0,0 +1,59 @@
+import { haveAttribute, haveText, html, test } from '../../utils'
+
+test('$id generates a unique id',
+    html`
+        <div x-data id="1">
+            <span :aria-labelledby="$id('foo')"></span>
+
+            <div>
+                <h1 :id="$id('foo')"></h1>
+            </div>
+        </div>
+
+        <div x-data id="2">
+            <div>
+                <h1 :id="$id('foo')"></h1>
+            </div>
+
+            <span :aria-labelledby="$id('foo')"></span>
+        </div>
+    `,
+    ({ get }) => {
+        get('#1 h1').should(haveAttribute('id', 'foo-1'))
+        get('#1 span').should(haveAttribute('aria-labelledby', 'foo-1'))
+        get('#2 h1').should(haveAttribute('id', 'foo-2'))
+        get('#2 span').should(haveAttribute('aria-labelledby', 'foo-2'))
+    }
+)
+
+test('$id works with keys and nested data scopes',
+    html`
+        <div x-data id="1">
+            <!-- foo-1-3 -->
+            <span :aria-activedescendant="$id('foo', 3)"></span>
+
+            <ul>
+                <li x-data :id="$id('foo', 1)"></li> <!-- foo-1-1 -->
+                <li x-data :id="$id('foo', 2)"></li> <!-- foo-1-2 -->
+                <li x-data :id="$id('foo', 3)"></li> <!-- foo-1-3 -->
+            </ul>
+        </div>
+
+        <div x-data id="2">
+            <!-- foo-2-3 -->
+            <span :aria-activedescendant="$id('foo', 3)"></span>
+
+            <ul>
+                <li x-data :id="$id('foo', 1)"></li> <!-- foo-2-1 -->
+                <li x-data :id="$id('foo', 2)"></li> <!-- foo-2-2 -->
+                <li x-data :id="$id('foo', 3)"></li> <!-- foo-2-3 -->
+            </ul>
+        </div>
+    `,
+    ({ get }) => {
+        get('#1 span').should(haveAttribute('aria-activedescendant', 'foo-1-3'))
+        get('#1 li:nth-child(1)').should(haveAttribute('id', 'foo-1-1'))
+        get('#1 li:nth-child(2)').should(haveAttribute('id', 'foo-1-2'))
+        get('#1 li:nth-child(3)').should(haveAttribute('id', 'foo-1-3'))
+    }
+)