@alpinejs/docs 3.5.0-revision.1 → 3.6.0-revision.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
order: 17
|
|
3
|
+
title: id
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# x-id
|
|
7
|
+
`x-id` allows you to declare a new "scope" for any new IDs generated using `$id()`. It accepts an array of strings (ID names) and adds a suffix to each `$id('...')` generated within it that is unique to other IDs on the page.
|
|
8
|
+
|
|
9
|
+
`x-id` is meant to be used in conjunction with the `$id(...)` magic.
|
|
10
|
+
|
|
11
|
+
[Visit the $id documentation](/magics/id) for a better understanding of this feature.
|
|
12
|
+
|
|
13
|
+
Here's a brief example of this directive in use:
|
|
14
|
+
|
|
15
|
+
```alpine
|
|
16
|
+
<div x-id="['text-input']">
|
|
17
|
+
<label :for="$id('text-input')">Username</label>
|
|
18
|
+
<!-- for="text-input-1" -->
|
|
19
|
+
|
|
20
|
+
<input type="text" :id="$id('text-input')">
|
|
21
|
+
<!-- id="text-input-1" -->
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div x-id="['text-input']">
|
|
25
|
+
<label :for="$id('text-input')">Username</label>
|
|
26
|
+
<!-- for="text-input-2" -->
|
|
27
|
+
|
|
28
|
+
<input type="text" :id="$id('text-input')">
|
|
29
|
+
<!-- id="text-input-2" -->
|
|
30
|
+
</div>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
|
|
@@ -33,7 +33,7 @@ This is by far the simplest way to get started with Alpine. Include the followin
|
|
|
33
33
|
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.
|
|
34
34
|
|
|
35
35
|
```alpine
|
|
36
|
-
<script defer src="https://unpkg.com/alpinejs@3.
|
|
36
|
+
<script defer src="https://unpkg.com/alpinejs@3.6.0/dist/cdn.min.js"></script>
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
That's it! Alpine is now available for use inside your page.
|
|
@@ -70,7 +70,7 @@ The two main behavioral differences with this approach are:
|
|
|
70
70
|
## Alpine initialization
|
|
71
71
|
|
|
72
72
|
<a name="alpine-initializing"></a>
|
|
73
|
-
### `
|
|
73
|
+
### `alpine:init`
|
|
74
74
|
|
|
75
75
|
Ensuring a bit of code executes after Alpine is loaded, but BEFORE it initializes itself on the page is a necessary task.
|
|
76
76
|
|
|
@@ -85,7 +85,7 @@ document.addEventListener('alpine:init', () => {
|
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
<a name="alpine-initialized"></a>
|
|
88
|
-
### `
|
|
88
|
+
### `alpine:initialized`
|
|
89
89
|
|
|
90
90
|
Alpine also offers a hook that you can use to execute code After it's done initializing called `alpine:initialized`:
|
|
91
91
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
order: 9
|
|
3
|
+
prefix: $
|
|
4
|
+
title: id
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# $id
|
|
8
|
+
|
|
9
|
+
`$id` is a magic property that can be used to generate an element's ID and ensure that it is within on the page and won't conflict with other IDs of the same name.
|
|
10
|
+
|
|
11
|
+
This utility is extremely helpful when building re-usable components (presumably in a back-end template) that might occur multiple times on a page, and make use of ID attributes.
|
|
12
|
+
|
|
13
|
+
Things like input components, modals, listboxes, etc. will all benefit from this utility.
|
|
14
|
+
|
|
15
|
+
<a name="basic-usage"></a>
|
|
16
|
+
## Basic usage
|
|
17
|
+
|
|
18
|
+
Suppose you have two input elements on a page, and you want them to have a unique ID from each other, you can do the following:
|
|
19
|
+
|
|
20
|
+
```alpine
|
|
21
|
+
<input type="text" :id="$id('text-input')">
|
|
22
|
+
<!-- id="text-input-1" -->
|
|
23
|
+
|
|
24
|
+
<input type="text" :id="$id('text-input')">
|
|
25
|
+
<!-- id="text-input-2" -->
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
As you can see, `$id` takes in a string and spits out an appended suffix that is unique on the page.
|
|
29
|
+
|
|
30
|
+
<a name="groups-with-x-id"></a>
|
|
31
|
+
## Grouping with x-id
|
|
32
|
+
|
|
33
|
+
Now let's say you want to have those same two input elements, but this time you want `<label>` elements for each of them.
|
|
34
|
+
|
|
35
|
+
This presents a problem, you now need to be able to reference the same ID twice. One for the `<label>`'s `for` attribute, and the other for the `id` on the input.
|
|
36
|
+
|
|
37
|
+
Here's is a way that you might think to accomplish this and is totally valid:
|
|
38
|
+
|
|
39
|
+
```alpine
|
|
40
|
+
<div x-data="{ id: $id('text-input') }">
|
|
41
|
+
<label :for="id"> <!-- "text-input-1" -->
|
|
42
|
+
<input type="text" :id="id"> <!-- "text-input-1" -->
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div x-data="{ id: $id('text-input') }">
|
|
46
|
+
<label :for="id"> <!-- "text-input-2" -->
|
|
47
|
+
<input type="text" :id="id"> <!-- "text-input-2" -->
|
|
48
|
+
</div>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This approach is fine, however, having to name and store the ID in your component scope feels cumbersome.
|
|
52
|
+
|
|
53
|
+
To accomplish this same task in a more flexible way, you can use Alpine's `x-id` directive to declare an "id scope" for a set of IDs:
|
|
54
|
+
|
|
55
|
+
```alpine
|
|
56
|
+
<div x-id="['text-input']">
|
|
57
|
+
<label :for="$id('text-input')"> <!-- "text-input-1" -->
|
|
58
|
+
<input type="text" :id="$id('text-input')"> <!-- "text-input-1" -->
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<div x-id="['text-input']">
|
|
62
|
+
<label :for="$id('text-input')"> <!-- "text-input-2" -->
|
|
63
|
+
<input type="text" :id="$id('text-input')"> <!-- "text-input-2" -->
|
|
64
|
+
</div>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
As you can see, `x-id` accepts an array of ID names. Now any usages of `$id()` within that scope, will all use the same ID. Think of them as "id groups".
|
|
68
|
+
|
|
69
|
+
<a name="nesting"></a>
|
|
70
|
+
## Nesting
|
|
71
|
+
|
|
72
|
+
As you might have intuited, you can freely nest these `x-id` groups, like so:
|
|
73
|
+
|
|
74
|
+
```alpine
|
|
75
|
+
<div x-id="['text-input']">
|
|
76
|
+
<label :for="$id('text-input')"> <!-- "text-input-1" -->
|
|
77
|
+
<input type="text" :id="$id('text-input')"> <!-- "text-input-1" -->
|
|
78
|
+
|
|
79
|
+
<div x-id="['text-input']">
|
|
80
|
+
<label :for="$id('text-input')"> <!-- "text-input-2" -->
|
|
81
|
+
<input type="text" :id="$id('text-input')"> <!-- "text-input-2" -->
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
<a name="keyed-ids"></a>
|
|
87
|
+
## Keyed IDs (For Looping)
|
|
88
|
+
|
|
89
|
+
Sometimes, it is helpful to specify an additional suffix on the end of an ID for the purpose of identifying it within a loop.
|
|
90
|
+
|
|
91
|
+
For this, `$id()` accepts an optional second parameter that will be added as a suffix on the end of the generated ID.
|
|
92
|
+
|
|
93
|
+
A common example of this need is something like a listbox component that uses the `aria-activedescendant` attribute to tell assistive technologies which element is "active" in the list:
|
|
94
|
+
|
|
95
|
+
```alpine
|
|
96
|
+
<ul
|
|
97
|
+
x-id="['list-item']"
|
|
98
|
+
:aria-activedescendant="$id('list-item', activeItem.id)"
|
|
99
|
+
>
|
|
100
|
+
<template x-for="item in items" :key="item.id">
|
|
101
|
+
<li :id="$id('list-item', item.id)">...</li>
|
|
102
|
+
</template>
|
|
103
|
+
</ul>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
This is an incomplete example of a listbox, but it should still be helpful to demonstrate a scenario where you might need each ID in a group to still be unique to the page, but also be keyed within a loop so that you can reference individual IDs within that group.
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
---
|
|
2
|
+
order: 5
|
|
3
|
+
title: Morph
|
|
4
|
+
description: Morph an element into the provided HTML
|
|
5
|
+
graph_image: https://alpinejs.dev/social_morph.jpg
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Morph Plugin
|
|
9
|
+
|
|
10
|
+
Alpine's Morph plugin allows you to "morph" an element on the page into the provided HTML template, all while preserving any browser or Alpine state within the "morphed" element.
|
|
11
|
+
|
|
12
|
+
This is useful for updating HTML from a server request without loosing Alpine's on-page state. A utility like this is at the core of full-stack frameworks like [Laravel Livewire](https://laravel-livewire.com/) and [Phoenix LiveView](https://dockyard.com/blog/2018/12/12/phoenix-liveview-interactive-real-time-apps-no-need-to-write-javascript).
|
|
13
|
+
|
|
14
|
+
The best way to understand its purpose is with the following interactive visualization. Give it a try!
|
|
15
|
+
|
|
16
|
+
<!-- START_VERBATIM -->
|
|
17
|
+
<div x-data="{ slide: 1 }" class="border rounded">
|
|
18
|
+
<div>
|
|
19
|
+
<img :src="'/img/morphs/morph'+slide+'.png'">
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div class="flex w-full justify-between" style="padding-bottom: 1rem">
|
|
23
|
+
<div class="w-1/2 px-4">
|
|
24
|
+
<button @click="slide = (slide === 1) ? 13 : slide - 1" class="w-full bg-brand rounded-full text-center py-3 font-bold text-white">Previous</button>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="w-1/2 px-4">
|
|
27
|
+
<button @click="slide = (slide % 13) + 1" class="w-full bg-brand rounded-full text-center py-3 font-bold text-white">Next</button>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
<!-- END_VERBATIM -->
|
|
32
|
+
|
|
33
|
+
<a name="installation"></a>
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
You can use this plugin by either including it from a `<script>` tag or installing it via NPM:
|
|
37
|
+
|
|
38
|
+
### Via CDN
|
|
39
|
+
|
|
40
|
+
You can include the CDN build of this plugin as a `<script>` tag, just make sure to include it BEFORE Alpine's core JS file.
|
|
41
|
+
|
|
42
|
+
```alpine
|
|
43
|
+
<!-- Alpine Plugins -->
|
|
44
|
+
<script defer src="https://unpkg.com/@alpinejs/morph@3.x.x/dist/cdn.min.js"></script>
|
|
45
|
+
|
|
46
|
+
<!-- Alpine Core -->
|
|
47
|
+
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Via NPM
|
|
51
|
+
|
|
52
|
+
You can install Morph from NPM for use inside your bundle like so:
|
|
53
|
+
|
|
54
|
+
```shell
|
|
55
|
+
npm install @alpinejs/morph
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Then initialize it from your bundle:
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
import Alpine from 'alpinejs'
|
|
62
|
+
import morph from '@alpinejs/morph'
|
|
63
|
+
|
|
64
|
+
window.Alpine = Alpine
|
|
65
|
+
Alpine.plugin(morph)
|
|
66
|
+
|
|
67
|
+
...
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
<a name="alpine-morph"></a>
|
|
71
|
+
## Alpine.morph()
|
|
72
|
+
|
|
73
|
+
The `Alpine.morph(el, newHtml)` allows you to imperatively morph a dom node based on passed in HTML. It accepts the following parameters:
|
|
74
|
+
|
|
75
|
+
| Parameter | Description |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| `el` | A DOM element on the page. |
|
|
78
|
+
| `newHtml` | A string of HTML to use as the template to morph the dom element into. |
|
|
79
|
+
| `options` (optional) | An options object used mainly for [injecting lifecycle hooks](#lifecycle-hooks). |
|
|
80
|
+
|
|
81
|
+
Here's an example of using `Alpine.morph()` to update an Alpine component with new HTML: (In real apps, this new HTML would likely be coming from the server)
|
|
82
|
+
|
|
83
|
+
```alpine
|
|
84
|
+
<div x-data="{ message: 'Change me, then press the button!' }">
|
|
85
|
+
<input type="text" x-model="message">
|
|
86
|
+
<span x-text="message"></span>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<button>Run Morph</button>
|
|
90
|
+
|
|
91
|
+
<script>
|
|
92
|
+
document.querySelector('button').addEventListener('click', () => {
|
|
93
|
+
let el = document.querySelector('div')
|
|
94
|
+
|
|
95
|
+
Alpine.morph(el, `
|
|
96
|
+
<div x-data="{ message: 'Change me, then press the button!' }">
|
|
97
|
+
<h2>See how new elements have been added</h2>
|
|
98
|
+
|
|
99
|
+
<input type="text" x-model="message">
|
|
100
|
+
<span x-text="message"></span>
|
|
101
|
+
|
|
102
|
+
<h2>but the state of this component hasn't changed? Magical.</h2>
|
|
103
|
+
</div>
|
|
104
|
+
`)
|
|
105
|
+
})
|
|
106
|
+
</script>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
<!-- START_VERBATIM -->
|
|
110
|
+
<div class="demo">
|
|
111
|
+
<div x-data="{ message: 'Change me, then press the button!' }" id="morph-demo-1" class="space-y-2">
|
|
112
|
+
<input type="text" x-model="message" class="w-full">
|
|
113
|
+
<span x-text="message"></span>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<button id="morph-button-1" class="mt-4">Run Morph</button>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<script>
|
|
120
|
+
document.querySelector('#morph-button-1').addEventListener('click', () => {
|
|
121
|
+
let el = document.querySelector('#morph-demo-1')
|
|
122
|
+
|
|
123
|
+
Alpine.morph(el, `
|
|
124
|
+
<div x-data="{ message: 'Change me, then press the button!' }" id="morph-demo-1" class="space-y-2">
|
|
125
|
+
<h4>See how new elements have been added</h4>
|
|
126
|
+
<input type="text" x-model="message" class="w-full">
|
|
127
|
+
<span x-text="message"></span>
|
|
128
|
+
<h4>but the state of this component hasn't changed? Magical.</h4>
|
|
129
|
+
</div>
|
|
130
|
+
`)
|
|
131
|
+
})
|
|
132
|
+
</script>
|
|
133
|
+
<!-- END_VERBATIM -->
|
|
134
|
+
|
|
135
|
+
<a name="lifecycle-hooks"></a>
|
|
136
|
+
### Lifecycle Hooks
|
|
137
|
+
|
|
138
|
+
The "Morph" plugin works by comparing two DOM trees, the live element, and the passed in HTML.
|
|
139
|
+
|
|
140
|
+
Morph walks both trees simultaneusly and compares each node and its children. If it finds differences, it "patches" (changes) the current DOM tree to match the passed in HTML's tree.
|
|
141
|
+
|
|
142
|
+
While the default algorithm is very capable, there are cases where you may want to hook into its lifecycle and observe or change its behavior as it's happening.
|
|
143
|
+
|
|
144
|
+
Before we jump into the available Lifecycle hooks themselves, let's first list out all the potential parameters they receive and explain what each one is:
|
|
145
|
+
|
|
146
|
+
| Parameter | Description |
|
|
147
|
+
| --- | --- |
|
|
148
|
+
| `el` | This is always the actual, current, DOM element on the page that will be "patched" (changed by Morph). |
|
|
149
|
+
| `toEl` | This is a "template element". It's a temporary element representing what the live `el` will be patched to. It will never actually live on the page and should only be used for reference purposes. |
|
|
150
|
+
| `childrenOnly()` | This is a function that can be called inside the hook to tell Morph to skip the current element and only "patch" its children. |
|
|
151
|
+
| `skip()` | A function that when called within the hook will "skip" comparing/patching itself and the children of the current element. |
|
|
152
|
+
|
|
153
|
+
Here are the available lifecycle hooks (passed in as the third parameter to `Alpine.morph(..., options)`):
|
|
154
|
+
|
|
155
|
+
| Option | Description |
|
|
156
|
+
| --- | --- |
|
|
157
|
+
| `updating(el, toEl, childrenOnly, skip)` | Called before patching the `el` with the comparison `toEl`. |
|
|
158
|
+
| `updated(el, toEl)` | Called after Morph has patched `el`. |
|
|
159
|
+
| `removing(el, skip)` | Called before Morph removes an element from the live DOM. |
|
|
160
|
+
| `removed(el)` | Called after Morph has removed an element from the live DOM. |
|
|
161
|
+
| `adding(el, sip)` | Called before adding a new element. |
|
|
162
|
+
| `added(el)` | Called after adding a new element to the live DOM tree. |
|
|
163
|
+
| `key(el)` | A re-usable function to determine how Morph "keys" elements in the tree before comparing/patching. [More on that here](#keys) |
|
|
164
|
+
| `lookahead` | A boolean value telling Morph to enable an extra feature in its algorithm that "looks ahead" to make sure a DOM element that's about to be removed should instead just be "moved" to a later sibling. |
|
|
165
|
+
|
|
166
|
+
Here is code of all these lifecycle hooks for a more concrete reference:
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
Alpine.morph(el, newHtml, {
|
|
170
|
+
updating(el, toEl, childrenOnly, skip) {
|
|
171
|
+
//
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
updated(el, toEl) {
|
|
175
|
+
//
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
removing(el, skip) {
|
|
179
|
+
//
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
removed(el) {
|
|
183
|
+
//
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
adding(el, skip) {
|
|
187
|
+
//
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
added(el) {
|
|
191
|
+
//
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
key(el) {
|
|
195
|
+
// By default Alpine uses the `key=""` HTML attribute.
|
|
196
|
+
return el.id
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
lookahead: true, // Default: false
|
|
200
|
+
})
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
<a name="keys"></a>
|
|
204
|
+
### Keys
|
|
205
|
+
|
|
206
|
+
Dom-diffing utilities like Morph try their best to accurately "morph" the original DOM into the new HTML. However, there are cases where it's impossible to determine if an element should be just changed, or replaced completely.
|
|
207
|
+
|
|
208
|
+
Because of this limitation, Morph has a "key" system that allows developers to "force" preserving certain elements rather than replacing them.
|
|
209
|
+
|
|
210
|
+
The most common use-case for them is a list of siblings within a loop. Below is an example of why keys are necessary sometimes:
|
|
211
|
+
|
|
212
|
+
```html
|
|
213
|
+
<!-- "Live" Dom on the page: -->
|
|
214
|
+
<ul>
|
|
215
|
+
<li>Mark</li>
|
|
216
|
+
<li>Tom</li>
|
|
217
|
+
<li>Travis</li>
|
|
218
|
+
</ul>
|
|
219
|
+
|
|
220
|
+
<!-- New HTML to "morph to": -->
|
|
221
|
+
<ul>
|
|
222
|
+
<li>Travis</li>
|
|
223
|
+
<li>Mark</li>
|
|
224
|
+
<li>Tom</li>
|
|
225
|
+
</ul>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Given the above situation, Morph has no way to know that the "Travis" node has been moved in the DOM tree. It just thinks that "Mark" has been changed to "Travis" and "Travis" changed to "Tom".
|
|
229
|
+
|
|
230
|
+
This is not what we actually want, we want Morph to preserve the original elements and instead of changing them, MOVE them within the `<ul>`.
|
|
231
|
+
|
|
232
|
+
By adding keys to each node, we can accomplish this like so:
|
|
233
|
+
|
|
234
|
+
```html
|
|
235
|
+
<!-- "Live" Dom on the page: -->
|
|
236
|
+
<ul>
|
|
237
|
+
<li key="1">Mark</li>
|
|
238
|
+
<li key="2">Tom</li>
|
|
239
|
+
<li key="3">Travis</li>
|
|
240
|
+
</ul>
|
|
241
|
+
|
|
242
|
+
<!-- New HTML to "morph to": -->
|
|
243
|
+
<ul>
|
|
244
|
+
<li key="3">Travis</li>
|
|
245
|
+
<li key="1">Mark</li>
|
|
246
|
+
<li key="2">Tom</li>
|
|
247
|
+
</ul>
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Now that there are "keys" on the `<li>`s, Morph will match them in both trees and move them accordingly.
|
|
251
|
+
|
|
252
|
+
You can configure what Morph considers a "key" with the `key:` configutation option. [More on that here](#lifecycle-hooks)
|
package/src/en/plugins/trap.md
CHANGED
|
@@ -191,8 +191,8 @@ By adding `.inert` to `x-trap`, when focus is trapped, all other elements on the
|
|
|
191
191
|
|
|
192
192
|
```alpine
|
|
193
193
|
<!-- When `open` is `false`: -->
|
|
194
|
-
<body>
|
|
195
|
-
<div x-trap="open" ...>
|
|
194
|
+
<body x-data="{ open: false }">
|
|
195
|
+
<div x-trap.inert="open" ...>
|
|
196
196
|
...
|
|
197
197
|
</div>
|
|
198
198
|
|
|
@@ -202,8 +202,8 @@ By adding `.inert` to `x-trap`, when focus is trapped, all other elements on the
|
|
|
202
202
|
</body>
|
|
203
203
|
|
|
204
204
|
<!-- When `open` is `true`: -->
|
|
205
|
-
<body>
|
|
206
|
-
<div x-trap="open" ...>
|
|
205
|
+
<body x-data="{ open: true }">
|
|
206
|
+
<div x-trap.inert="open" ...>
|
|
207
207
|
...
|
|
208
208
|
</div>
|
|
209
209
|
|