Ver Fonte

Merge branch 'main' into add-focus

Caleb Porzio há 3 anos atrás
pai
commit
f858774bb0

+ 1 - 1
packages/alpinejs/package.json

@@ -1,6 +1,6 @@
 {
     "name": "alpinejs",
-    "version": "3.7.0",
+    "version": "3.7.1",
     "description": "The rugged, minimal JavaScript framework",
     "author": "Caleb Porzio",
     "license": "MIT",

+ 1 - 1
packages/alpinejs/src/directives/x-on.js

@@ -8,7 +8,7 @@ mapAttributes(startingWith('@', into(prefix('on:'))))
 directive('on', skipDuringClone((el, { value, modifiers, expression }, { cleanup }) => {
     let evaluate = expression ? evaluateLater(el, expression) : () => {}
    
-    // Forward events liseners on portals.
+    // Forward event listeners on portals.
     if (el.tagName.toLowerCase() === 'template') {
         if (! el._x_forwardEvents) el._x_forwardEvents = []
         if (! el._x_forwardEvents.includes(value)) el._x_forwardEvents.push(value)

+ 2 - 3
packages/alpinejs/src/magics/$watch.js

@@ -10,9 +10,8 @@ magic('watch', el => (key, callback) => {
     let oldValue
 
     effect(() => evaluate(value => {
-        // This is a hack to force deep reactivity for things like "items.push()".
-        let div = document.createElement('div')
-        div.dataset.throwAway = value
+        // JSON.stringify touches every single property at any level enabling deep watching
+        JSON.stringify(value)
 
         if (! firstTime) {
             // We have to queue this watcher as a microtask so that

+ 1 - 1
packages/collapse/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@alpinejs/collapse",
-    "version": "3.7.0",
+    "version": "3.7.1",
     "description": "Collapse and expand elements with robust animations",
     "author": "Caleb Porzio",
     "license": "MIT",

+ 11 - 19
packages/collapse/src/index.js

@@ -17,11 +17,10 @@ export default function (Alpine) {
         let setFunction = (el, styles) => {
             let revertFunction = Alpine.setStyles(el, styles);
 
-           return styles.height ? () => {} : revertFunction
+            return styles.height ? () => {} : revertFunction
         }
 
         let transitionStyles = {
-            overflow: 'hidden',
             transitionProperty: 'height',
             transitionDuration: `${duration}s`,
             transitionTimingFunction: 'cubic-bezier(0.4, 0.0, 0.2, 1)',
@@ -30,27 +29,25 @@ export default function (Alpine) {
         el._x_transition = {
             in(before = () => {}, after = () => {}) {
                 el.hidden = false;
+                el.style.display = null
 
                 let current = el.getBoundingClientRect().height
 
-                Alpine.setStyles(el, {
-                    display: null,
-                    height: 'auto',
-                })
+                el.style.height = 'auto'
 
                 let full = el.getBoundingClientRect().height
 
-                Alpine.setStyles(el, {
-                    overflow: null
-                })
-
                 if (current === full) { current = floor }
 
                 Alpine.transition(el, Alpine.setStyles, {
                     during: transitionStyles,
                     start: { height: current+'px' },
                     end: { height: full+'px' },
-                }, () => el._x_isShown = true, () => {})
+                }, () => el._x_isShown = true, () => {
+                    if (el.style.height == `${full}px`) {
+                        el.style.overflow = null
+                    }
+                })
             },
 
             out(before = () => {}, after = () => {}) {
@@ -60,18 +57,13 @@ export default function (Alpine) {
                     during: transitionStyles,
                     start: { height: full+'px' },
                     end: { height: floor+'px' },
-                }, () => {}, () => {
+                }, () => el.style.overflow = 'hidden', () => {
                     el._x_isShown = false
 
                     // check if element is fully collapsed
                     if (el.style.height == `${floor}px`) {
-                        Alpine.nextTick(() => {
-                            Alpine.setStyles(el, {
-                                display: 'none',
-                                overflow: 'hidden'
-                            })
-                            el.hidden = true;
-                        })
+                        el.style.display = 'none'
+                        el.hidden = true
                     }
                 })
             },

+ 1 - 1
packages/docs/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@alpinejs/docs",
-    "version": "3.7.0-revision.3",
+    "version": "3.7.1-revision.1",
     "description": "The documentation for Alpine",
     "author": "Caleb Porzio",
     "license": "MIT"

+ 4 - 2
packages/docs/src/en/directives/teleport.md

@@ -18,7 +18,9 @@ This is useful for things like modals (especially nesting them), where it's help
 
 By attaching `x-teleport` to a `<template>` element, you are telling Alpine to "append" that element to the provided selector.
 
-> The `x-template` selector can be any string you would normally pass into something like `document.querySelector`
+> The `x-template` selector can be any string you would normally pass into something like `document.querySelector`. It will find the first element that matches, be it a tag name (`body`), class name (`.my-class`), ID (`#my-id`), or any other valid CSS selector.
+
+[→ Read more about `document.querySelector`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)
 
 Here's a contrived modal example:
 
@@ -63,7 +65,7 @@ Notice how when toggling the modal, the actual modal contents show up AFTER the
 <a name="forwarding-events"></a>
 ## Forwarding events
 
-Alpine tries it's best to make the experience of teleporting seamless. Anything you would normally do in a template, you should be able to do inside an `x-teleport` template. Teleported content can access the normal Alpine scope of the component as well as other features like `$refs`, `$root`, etc...
+Alpine tries its best to make the experience of teleporting seamless. Anything you would normally do in a template, you should be able to do inside an `x-teleport` template. Teleported content can access the normal Alpine scope of the component as well as other features like `$refs`, `$root`, etc...
 
 However, native DOM events have no concept of teleportation, so if, for example, you trigger a "click" event from inside a teleported element, that event will bubble up the DOM tree as it normally would.
 

+ 4 - 4
packages/docs/src/en/directives/transition.md

@@ -138,11 +138,11 @@ For direct control over exactly what goes into your transitions, you can apply C
     <div
         x-show="open"
         x-transition:enter="transition ease-out duration-300"
-        x-transition:enter-start="opacity-0 transform scale-90"
-        x-transition:enter-end="opacity-100 transform scale-100"
+        x-transition:enter-start="opacity-0 scale-90"
+        x-transition:enter-end="opacity-100 scale-100"
         x-transition:leave="transition ease-in duration-300"
-        x-transition:leave-start="opacity-100 transform scale-100"
-        x-transition:leave-end="opacity-0 transform scale-90"
+        x-transition:leave-start="opacity-100 scale-100"
+        x-transition:leave-end="opacity-0 scale-90"
     >Hello 👋</div>
 </div>
 ```

+ 1 - 1
packages/docs/src/en/essentials/installation.md

@@ -33,7 +33,7 @@ This is by far the simplest way to get started with Alpine. Include the followin
 Notice the `@3.x.x` in the provided CDN link. This will pull the latest version of Alpine version 3. For stability in production, it's recommended that you hardcode the latest version in the CDN link.
 
 ```alpine
-<script defer src="https://unpkg.com/alpinejs@3.7.0/dist/cdn.min.js"></script>
+<script defer src="https://unpkg.com/alpinejs@3.7.1/dist/cdn.min.js"></script>
 ```
 
 That's it! Alpine is now available for use inside your page.

+ 22 - 0
packages/docs/src/en/magics/watch.md

@@ -35,3 +35,25 @@ When the `<button>` is pressed, `foo.bar` will be set to "bob", and "bob" will b
     <button @click="open = ! open">Toggle Open</button>
 </div>
 ```
+
+<a name="deep-watching"></a>
+### Deep watching
+
+`$watch` will automatically watches from changes at any level but you should keep in mind that, when a change is detected, the watcher will return the value of the observed property, not the value of the subproperty that has changed.
+
+```alpine
+<div x-data="{ foo: { bar: 'baz' }}" x-init="$watch('foo', (value, oldValue) => console.log(value, oldValue))">
+    <button @click="foo.bar = 'bob'">Update</button>
+</div>
+```
+
+When the `<button>` is pressed, `foo.bar` will be set to "bob", and "{bar: 'bob'} {bar: 'baz'}" will be logged to the console (new and old value).
+
+> ⚠️ Changing a property of a "watched" object as a side effect of the `$watch` callback will generate an infinite loop and eventually error. 
+
+```alpine
+<!-- 🚫 Infinite loop -->
+<div x-data="{ foo: { bar: 'baz', bob: 'lob' }}" x-init="$watch('foo', value => foo.bob = foo.bar">
+    <button @click="foo.bar = 'bob'">Update</button>
+</div>
+```

+ 1 - 1
packages/intersect/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@alpinejs/intersect",
-    "version": "3.7.0",
+    "version": "3.7.1",
     "description": "Trigger JavaScript when an element enters the viewport",
     "author": "Caleb Porzio",
     "license": "MIT",

+ 1 - 1
packages/morph/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@alpinejs/morph",
-    "version": "3.7.0",
+    "version": "3.7.1",
     "description": "Diff and patch a block of HTML on a page with an HTML template",
     "author": "Caleb Porzio",
     "license": "MIT",

+ 1 - 1
packages/persist/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@alpinejs/persist",
-    "version": "3.7.0",
+    "version": "3.7.1",
     "description": "Persist Alpine data across page loads",
     "author": "Caleb Porzio",
     "license": "MIT",

+ 1 - 1
packages/trap/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@alpinejs/trap",
-    "version": "3.7.0",
+    "version": "3.7.1",
     "description": "Trap focus on a page within a specific element",
     "author": "Caleb Porzio",
     "license": "MIT",

+ 22 - 0
tests/cypress/integration/magics/$watch.spec.js

@@ -148,3 +148,25 @@ test('$watch ignores other dependencies',
         get('span').should(haveText('1'))
     }
 )
+
+
+test('deep $watch',
+    html`
+        <div x-data="{ foo: { bar: 'baz'}, bob: 'lob' }" x-init="
+            $watch('foo', value => { bob = value.bar }, {deep: true});
+        ">
+            <h1 x-text="foo.bar"></h1>
+            <h2 x-text="bob"></h2>
+
+            <button x-on:click="foo.bar = 'law'"></button>
+        </div>
+    `,
+    ({ get }) => {
+        get('h1').should(haveText('baz'))
+        get('h2').should(haveText('lob'))
+        get('button').click()
+        get('h1').should(haveText('law'))
+        get('h2').should(haveText('law'))
+    }
+)
+

+ 2 - 2
tests/cypress/integration/plugins/collapse.spec.js

@@ -16,7 +16,7 @@ test('can collapse and expand element',
         get('h1').should(notHaveAttribute('hidden'))
         get('button').click()
         get('h1').should(haveComputedStyle('height', '0px'))
-        get('h1').should(haveAttribute('style', 'height: 0px; display: none; overflow: hidden;'))
+        get('h1').should(haveAttribute('style', 'height: 0px; overflow: hidden; display: none;'))
         get('h1').should(haveAttribute('hidden', 'hidden'))
     },
 )
@@ -64,7 +64,7 @@ test('double-click on x-collapse does not mix styles up',
         get('h1').should(haveAttribute('style', 'display: none; height: 0px; overflow: hidden;'))
         get('button').click()
         get('button').click()
-        get('h1').should(haveAttribute('style', 'height: 0px; display: none; overflow: hidden;'))
+        get('h1').should(haveAttribute('style', 'height: 0px; overflow: hidden; display: none;'))
         get('button').click()
         get('h1').should(haveAttribute('style', 'height: auto;'))
         get('button').click()