Explorar o código

Update implementation and tests

Caleb Porzio %!s(int64=3) %!d(string=hai) anos
pai
achega
03c52eea8d

+ 1 - 0
packages/alpinejs/src/directives.js

@@ -160,6 +160,7 @@ let directiveOrder = [
     'ignore',
     'ref',
     'data',
+    'id',
     'bind',
     'init',
     'for',

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

@@ -12,4 +12,5 @@ import './x-show'
 import './x-for'
 import './x-ref'
 import './x-if'
+import './x-id'
 import './x-on'

+ 8 - 0
packages/alpinejs/src/directives/x-id.js

@@ -0,0 +1,8 @@
+import { directive } from "../directives"
+import { findAndIncrementId, setIdRoot } from '../ids'
+
+directive('id', (el, { expression }, { evaluate }) => {
+    let names = evaluate(expression)
+    
+    names.forEach(name => setIdRoot(el, name))
+})

+ 20 - 0
packages/alpinejs/src/ids.js

@@ -0,0 +1,20 @@
+import { findClosest } from './lifecycle'
+
+let globalIdMemo = {}
+
+export function findAndIncrementId(name) {
+    if (! globalIdMemo[name]) globalIdMemo[name] = 0
+
+    return ++globalIdMemo[name]
+}
+
+export function closestIdRoot(el, name) {
+    return findClosest(el, element => {
+        if (element._x_ids && element._x_ids[name]) return true
+    })
+}
+
+export function setIdRoot(el, name) {
+    if (! el._x_ids) el._x_ids = {}
+    if (! el._x_ids[name]) el._x_ids[name] = findAndIncrementId(name) 
+}

+ 17 - 47
packages/alpinejs/src/magics/$id.js

@@ -1,55 +1,25 @@
 import { magic } from '../magics'
-import { directive } from '../directives'
-import { findClosest, closestRoot } from '../lifecycle'
+import { closestIdRoot, findAndIncrementId } from '../ids'
 
-let globalIdMemo = {}
+magic('id', el => (name, key = null) => {
+    let root = closestIdRoot(el, name)
 
-function generateIdMagicFunction(el) {
-    function idMagic(name, key = null) {
-        if (! globalIdMemo[name]) globalIdMemo[name] = 0
-    
-        let id = getId(el, name)
-    
-        return key
-            ? new HtmlId(el, `${name}-${id}-${key}`)
-            : new HtmlId(el, `${name}-${id}`)
-    }
-
-    idMagic.scope = function () {
-        el._x_new_scope = true
-    }
-
-    return idMagic
-}
-
-magic('id', el => generateIdMagicFunction(el))
-
-function getId(el, name) {
-    let root = closestIdRoot(el, name) || closestRoot(el)
+    let id = root
+        ? root._x_ids[name]
+        : findAndIncrementId(name)
 
-    initRoot(root, name)
-        
-    return root._x_ids[name]
-}
-
-class HtmlId {
-    constructor(el, id) { this.id = id }
-    toString() { return this.id }
-}
-
-export function closestIdRoot(el, name) {
-    return findClosest(el, element => {
-        if (element._x_new_scope) {
-            initRoot(element, name)
+    return key
+        ? new AlpineId(`${name}-${id}-${key}`)
+        : new AlpineId(`${name}-${id}`)
+})
 
-            return true
-        }
+class AlpineId {
+    constructor(id) {
+        this.id = id
+    }
 
-        if (element._x_ids && element._x_ids[name]) return true
-    })
+    toString() {
+        return this.id
+    }
 }
 
-function initRoot(el, name) {
-    if (! el._x_ids) el._x_ids = {}
-    if (! el._x_ids[name]) el._x_ids[name] = ++globalIdMemo[name]
-}

+ 22 - 9
tests/cypress/integration/magics/$id.spec.js

@@ -2,7 +2,7 @@ import { haveAttribute, haveText, html, test } from '../../utils'
 
 test('$id generates a unique id',
     html`
-        <div x-data id="1">
+        <div x-data x-id="['foo']" id="1">
             <div>
                 <h1 :id="$id('foo')"></h1>
             </div>
@@ -10,7 +10,7 @@ test('$id generates a unique id',
             <span :aria-labelledby="$id('foo')"></span>
         </div>
 
-        <div x-data id="2">
+        <div x-data x-id="['foo']" id="2">
             <div>
                 <h1 :id="$id('foo')"></h1>
             </div>
@@ -28,7 +28,7 @@ test('$id generates a unique id',
 
 test('$id works with keys and nested data scopes',
     html`
-        <div x-data id="1">
+        <div x-data x-id="['foo']" id="1">
             <!-- foo-1-3 -->
             <span :aria-activedescendant="$id('foo', 3)"></span>
 
@@ -39,7 +39,7 @@ test('$id works with keys and nested data scopes',
             </ul>
         </div>
 
-        <div x-data id="2">
+        <div x-data x-id="['foo']" id="2">
             <!-- foo-2-3 -->
             <span :aria-activedescendant="$id('foo', 3)"></span>
 
@@ -64,13 +64,13 @@ test('$id works with keys and nested data scopes',
 
 test('$id scopes are grouped by name',
     html`
-        <div x-data>
+        <div x-data x-id="['foo']">
             <!-- foo-1 -->
             <span :aria-activedescendant="$id('foo')"></span>
 
             <ul>
-                <li x-data :id="$id('bar')"></li> <!-- bar-1 -->
-                <li x-data :id="$id('bar')"></li> <!-- bar-2 -->
+                <li x-data x-id="['bar']" :id="$id('bar')"></li> <!-- bar-1 -->
+                <li x-data x-id="['bar']" :id="$id('bar')"></li> <!-- bar-2 -->
             </ul>
         </div>
     `,
@@ -81,9 +81,22 @@ test('$id scopes are grouped by name',
     }
 )
 
-test('$id scopes can be reset',
+test('$ids are globally unique when outside x-id',
     html`
         <div x-data>
+            <h1 :id="$id('foo')"></h1>
+            <h2 :id="$id('foo')"></h2>
+        </div>
+    `,
+    ({ get }) => {
+        get('h1').should(haveAttribute('id', 'foo-1'))
+        get('h2').should(haveAttribute('id', 'foo-2'))
+    }
+)
+
+test('$id scopes can be reset',
+    html`
+        <div x-data x-id="['foo', 'bar']">
             <!-- foo-1 -->
             <span :aria-labelledby="$id('foo')"></span>
 
@@ -91,7 +104,7 @@ test('$id scopes can be reset',
                 <h1 :id="$id('foo')"></h1>
                 <h5 :id="$id('bar')"></h5>
                 
-                <div x-init="$id.scope('foo')">
+                <div x-id="['foo']">
                     <h2 :aria-labelledby="$id('foo')"></h2>
                     <h6 :aria-labelledby="$id('bar')"></h6>