Caleb Porzio %!s(int64=2) %!d(string=hai) anos
pai
achega
1c38653f03

+ 12 - 5
index.html

@@ -5,15 +5,22 @@
     <script src="./packages/persist/dist/cdn.js"></script>
     <script src="./packages/focus/dist/cdn.js"></script>
     <script src="./packages/mask/dist/cdn.js"></script>
+    <script src="./packages/ui/dist/cdn.js" defer></script>
     <script src="./packages/alpinejs/dist/cdn.js" defer></script>
     <!-- <script src="https://unpkg.com/alpinejs@3.0.0/dist/cdn.min.js" defer></script> -->
 
     <!-- Play around. -->
-    <div x-data="{ open: false }">
-        <button @click="open = !open">Toggle</button>
+    <div x-data x-tabs>
+        <div x-tabs:list>
+            <button x-tabs:tab button-1>First</button>
+            <button x-tabs:tab button-2 disabled :class="$tab.isDisabled && 'disabled'">Second</button>
+            <button x-tabs:tab button-3>Third</button>
+        </div>
 
-        <span x-show="open">
-            Content...
-        </span>
+        <div x-tabs:panels>
+            <div x-tabs:panel panel-1>First Panel</div>
+            <div x-tabs:panel panel-2>Second Panel</div>
+            <div x-tabs:panel panel-3>Third Panel</div>
+        </div>
     </div>
 </html>

+ 3 - 3
packages/alpinejs/src/utils/bind.js

@@ -138,12 +138,12 @@ export function getBinding(el, name, fallback) {
     // Nothing bound:
     if (attr === null) return typeof fallback === 'function' ? fallback() : fallback
 
+    // The case of a custom attribute with no value. Ex: <div manual>
+    if (attr === '') return true
+
     if (isBooleanAttr(name)) {
         return !! [name, 'true'].includes(attr)
     }
 
-    // The case of a custom attribute with no value. Ex: <div manual>
-    if (attr === '') return true
-
     return attr
 }

+ 14 - 5
packages/ui/src/tabs.js

@@ -14,11 +14,20 @@ export default function (Alpine) {
         return {
             get isSelected() {
                 return $data.__selectedIndex === $data.__tabs.indexOf($data.__tabEl)
+            },
+            get isDisabled() {
+                console.log($data.__isDisabled)
+                return true
+                return 'ey'
+                setTimeout(() => {
+                    console.log(($data.__isDisabled))
+                })
+                return $data.__isDisabled
             }
         }
     })
 
-    Alpine.magic('tabPanel', el => {
+    Alpine.magic('panel', el => {
         let $data = Alpine.$data(el)
 
         return {
@@ -71,16 +80,16 @@ function handleList(el, Alpine) {
 }
 
 function handleTab(el, Alpine) {
-    let options = {}
     Alpine.bind(el, {
         'x-init'() { if (this.$el.tagName.toLowerCase() === 'button' && !this.$el.hasAttribute('type')) this.$el.type = 'button' },
         'x-data'() { return {
             init() {
                 this.__tabEl = this.$el
                 this.$data.__addTab(this.$el)
-                this.$el.__disabled = options.disabled
+                // this.__tabEl.__disabled = this.__isDisabled = Alpine.bound(this.$el, 'disabled', false)
             },
             __tabEl: undefined,
+            __isDisabled: 'hey',
         }},
         '@click'() {
             if (this.$el.__disabled) return
@@ -122,7 +131,7 @@ function handlePanels(el, Alpine) {
 
 function handlePanel(el, Alpine) {
     Alpine.bind(el, {
-        ':tabindex'() { return this.$tabPanel.isSelected ? 0 : -1 },
+        ':tabindex'() { return this.$panel.isSelected ? 0 : -1 },
         'x-data'() { return {
             init() {
                 this.__panelEl = this.$el
@@ -130,7 +139,7 @@ function handlePanel(el, Alpine) {
             },
             __panelEl: undefined,
         }},
-        'x-show'() { return this.$tabPanel.isSelected },
+        'x-show'() { return this.$panel.isSelected },
     })
 }
 

+ 6 - 4
tests/cypress/integration/directives/x-bind.spec.js

@@ -439,14 +439,16 @@ test('Can retrieve Alpine bound data with global bound method',
         <div id="1" x-data foo="bar" x-text="Alpine.bound($el, 'foo')"></div>
         <div id="2" x-data :foo="'bar'" x-text="Alpine.bound($el, 'foo')"></div>
         <div id="3" x-data foo x-text="Alpine.bound($el, 'foo')"></div>
-        <div id="4" x-data x-text="Alpine.bound($el, 'foo')"></div>
-        <div id="5" x-data x-text="Alpine.bound($el, 'foo', 'bar')"></div>
+        <div id="4" x-data disabled x-text="Alpine.bound($el, 'disabled')"></div>
+        <div id="5" x-data x-text="Alpine.bound($el, 'foo')"></div>
+        <div id="6" x-data x-text="Alpine.bound($el, 'foo', 'bar')"></div>
     `,
     ({ get }) => {
         get('#1').should(haveText('bar'))
         get('#2').should(haveText('bar'))
         get('#3').should(haveText('true'))
-        get('#4').should(haveText(''))
-        get('#5').should(haveText('bar'))
+        get('#4').should(haveText('true'))
+        get('#5').should(haveText(''))
+        get('#6').should(haveText('bar'))
     }
 )

+ 63 - 1
tests/cypress/integration/plugins/ui/tabs.spec.js

@@ -1,4 +1,4 @@
-import { beVisible, haveFocus, html, notBeVisible, test } from '../../../utils'
+import { beVisible, haveClasses, haveFocus, html, notBeVisible, notHaveClasses, test } from '../../../utils'
 
 test('can use tabs to toggle panels',
     [html`
@@ -83,3 +83,65 @@ test('cant tab through tabs, can only use arrows',
         get('[button-4]').should(haveFocus())
     },
 )
+
+test('can detect the selected tab & panel',
+    [html`
+        <div x-data x-tabs>
+            <div x-tabs:list>
+                <button x-tabs:tab button-1 :class="$tab.isSelected && 'active'">First</button>
+                <button x-tabs:tab button-2 :class="$tab.isSelected && 'active'">Second</button>
+            </div>
+
+            <div x-tabs:panels>
+                <div x-tabs:panel panel-1 :class="$panel.isSelected && 'active'">First Panel</div>
+                <div x-tabs:panel panel-2 :class="$panel.isSelected && 'active'">Second Panel</div>
+            </div>
+        </div>
+    `],
+    ({ get }) => {
+        get('[panel-1]').should(beVisible())
+        get('[panel-2]').should(notBeVisible())
+        get('[button-1]').should(haveClasses(['active']))
+        get('[panel-1]').should(haveClasses(['active']))
+        get('[button-2]').should(notHaveClasses(['active']))
+        get('[panel-2]').should(notHaveClasses(['active']))
+        get('[button-2]').click()
+        get('[button-1]').should(notHaveClasses(['active']))
+        get('[panel-1]').should(notHaveClasses(['active']))
+        get('[button-2]').should(haveClasses(['active']))
+        get('[panel-2]').should(haveClasses(['active']))
+        get('[panel-1]').should(notBeVisible())
+        get('[panel-2]').should(beVisible())
+    },
+)
+
+test.only('can disable a tab',
+    [html`
+        <div x-data x-tabs>
+            <div x-tabs:list>
+                <button x-tabs:tab button-1>First</button>
+                <button x-tabs:tab button-2 disabled :class="$tab.isDisabled && 'disabled'">Second</button>
+                <button x-tabs:tab button-3>Third</button>
+            </div>
+
+            <div x-tabs:panels>
+                <div x-tabs:panel panel-1>First Panel</div>
+                <div x-tabs:panel panel-2>Second Panel</div>
+                <div x-tabs:panel panel-3>Third Panel</div>
+            </div>
+        </div>
+    `],
+    ({ get }) => {
+        get('[button-2]').should(haveClasses(['disabled']))
+        get('[button-1]').click()
+        get('[button-1]').should(haveFocus())
+        get('[panel-1]').should(beVisible())
+        get('[panel-2]').should(notBeVisible())
+        get('[button-1]').type('{rightArrow}')
+        get('[panel-1]').should(notBeVisible())
+        get('[panel-3]').should(beVisible())
+        get('[button-1]').type('{rightArrow}')
+        get('[panel-3]').should(notBeVisible())
+        get('[panel-1]').should(beVisible())
+    },
+)