Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: alpinejs/alpine
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v3.13.7
Choose a base ref
...
head repository: alpinejs/alpine
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v3.13.8
Choose a head ref
  • 8 commits
  • 19 files changed
  • 6 contributors

Commits on Mar 8, 2024

  1. bump ui version

    calebporzio committed Mar 8, 2024
    Copy the full SHA
    44a8762 View commit details

Commits on Mar 18, 2024

  1. Fixed persist crash when the stored value is undefined (#4091)

    * Fixed persist crash when the stored value is undefined
    
    Fixed persist crash when the stored value is undefined.
    This bug crashes Alpine
    
    * refactor
    
    ---------
    
    Co-authored-by: Caleb Porzio <calebporzio@gmail.com>
    wahibimoh and calebporzio authored Mar 18, 2024
    Copy the full SHA
    c38a45f View commit details

Commits on Mar 21, 2024

  1. Add missing border to fill example (#4104)

    bb authored Mar 21, 2024
    Copy the full SHA
    fce7e37 View commit details
  2. Bug: Fixes x-model.fill when used with debounce (#4103)

    * 🧪 Adds failing .fill.debounce test
    
    * 🐛 Fixes .fill.debounce conflict
    ekwoka authored Mar 21, 2024
    Copy the full SHA
    4590592 View commit details
  3. Fix fill modifier for radio buttons (#4101)

    * Add failing test
    
    * Move ternary into the if statements
    
    * Assign the target value to a variable
    
    * Only use new value for radio buttons that are checked
    willrowe authored Mar 21, 2024
    Copy the full SHA
    ebffaa7 View commit details
  4. Remove hidden from booleanAttributes (#4099)

    * Remove hidden from booleanAttributes
    
    * Add test for hidden attribute
    
    * Add to test for specific boolean attributes which are not removed when falsy
    IHIutch authored Mar 21, 2024
    Copy the full SHA
    137f8bb View commit details

Commits on Mar 27, 2024

  1. fix (#4111)

    calebporzio authored Mar 27, 2024
    Copy the full SHA
    628d51f View commit details

Commits on Apr 2, 2024

  1. bump to 3.13.8

    calebporzio committed Apr 2, 2024
    Copy the full SHA
    85ff820 View commit details
2 changes: 1 addition & 1 deletion packages/alpinejs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "alpinejs",
"version": "3.13.7",
"version": "3.13.8",
"description": "The rugged, minimal JavaScript framework",
"homepage": "https://alpinejs.dev",
"repository": {
7 changes: 6 additions & 1 deletion packages/alpinejs/src/directives/x-bind.js
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ import { applyBindingsObject, injectBindingProviders } from '../binds'

mapAttributes(startingWith(':', into(prefix('bind:'))))

let handler = (el, { value, modifiers, expression, original }, { effect }) => {
let handler = (el, { value, modifiers, expression, original }, { effect, cleanup }) => {
if (! value) {
let bindingProviders = {}
injectBindingProviders(bindingProviders)
@@ -36,6 +36,11 @@ let handler = (el, { value, modifiers, expression, original }, { effect }) => {

mutateDom(() => bind(el, value, result, modifiers))
}))

cleanup(() => {
el._x_undoAddedClasses && el._x_undoAddedClasses()
el._x_undoAddedStyles && el._x_undoAddedStyles()
})
}

// @todo: see if I can take advantage of the object created here inside the
26 changes: 21 additions & 5 deletions packages/alpinejs/src/directives/x-model.js
Original file line number Diff line number Diff line change
@@ -72,7 +72,9 @@ directive('model', (el, { modifiers, expression }, { effect, cleanup }) => {
if (modifiers.includes('fill'))
if ([undefined, null, ''].includes(getValue())
|| (el.type === 'checkbox' && Array.isArray(getValue()))) {
el.dispatchEvent(new Event(event, {}));
setValue(
getInputValue(el, modifiers, { target: el }, getValue())
);
}
// Register the listener removal callback on the element, so that
// in addition to the cleanup function, x-modelable may call it.
@@ -168,13 +170,27 @@ function getInputValue(el, modifiers, event, currentValue) {
return option.value || option.text
})
} else {
let newValue

if (el.type === 'radio') {
if (event.target.checked) {
newValue = event.target.value
} else {
newValue = currentValue
}
} else {
newValue = event.target.value
}

if (modifiers.includes('number')) {
return safeParseNumber(event.target.value)
return safeParseNumber(newValue)
} else if (modifiers.includes('boolean')) {
return safeParseBoolean(event.target.value)
return safeParseBoolean(newValue)
} else if (modifiers.includes('trim')) {
return newValue.trim()
} else {
return newValue
}

return modifiers.includes('trim') ? event.target.value.trim() : event.target.value
}
})
}
2 changes: 1 addition & 1 deletion packages/alpinejs/src/utils/bind.js
Original file line number Diff line number Diff line change
@@ -150,7 +150,7 @@ function isBooleanAttr(attrName) {
// As per HTML spec table https://html.spec.whatwg.org/multipage/indices.html#attributes-3:boolean-attribute
// Array roughly ordered by estimated usage
const booleanAttributes = [
'disabled','checked','required','readonly','hidden','open', 'selected',
'disabled','checked','required','readonly','open', 'selected',
'autofocus', 'itemscope', 'multiple', 'novalidate','allowfullscreen',
'allowpaymentrequest', 'formnovalidate', 'autoplay', 'controls', 'loop',
'muted', 'playsinline', 'default', 'ismap', 'reversed', 'async', 'defer',
2 changes: 1 addition & 1 deletion packages/anchor/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alpinejs/anchor",
"version": "3.13.7",
"version": "3.13.8",
"description": "Anchor an element's position relative to another",
"homepage": "https://alpinejs.dev/plugins/anchor",
"repository": {
2 changes: 1 addition & 1 deletion packages/collapse/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alpinejs/collapse",
"version": "3.13.7",
"version": "3.13.8",
"description": "Collapse and expand elements with robust animations",
"homepage": "https://alpinejs.dev/plugins/collapse",
"repository": {
2 changes: 1 addition & 1 deletion packages/csp/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alpinejs/csp",
"version": "3.13.7",
"version": "3.13.8",
"description": "A CSP-friendly build of AlpineJS",
"author": "Caleb Porzio",
"license": "MIT",
2 changes: 1 addition & 1 deletion packages/docs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alpinejs/docs",
"version": "3.13.7-revision.1",
"version": "3.13.8-revision.1",
"description": "The documentation for Alpine",
"author": "Caleb Porzio",
"license": "MIT"
2 changes: 1 addition & 1 deletion packages/docs/src/en/directives/model.md
Original file line number Diff line number Diff line change
@@ -379,7 +379,7 @@ By default, if an input has a value attribute, it is ignored by Alpine and inste
But if a bound property is empty, then you can use an input's value attribute to populate the property by adding the `.fill` modifier.

<div x-data="{ message: null }">
<input x-model.fill="message" value="This is the default message.">
<input type="text" x-model.fill="message" value="This is the default message.">
</div>

<a name="programmatic access"></a>
2 changes: 1 addition & 1 deletion packages/docs/src/en/essentials/installation.md
Original file line number Diff line number Diff line change
@@ -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://cdn.jsdelivr.net/npm/alpinejs@3.13.7/dist/cdn.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.8/dist/cdn.min.js"></script>
```

That's it! Alpine is now available for use inside your page.
2 changes: 1 addition & 1 deletion packages/focus/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alpinejs/focus",
"version": "3.13.7",
"version": "3.13.8",
"description": "Manage focus within a page",
"homepage": "https://alpinejs.dev/plugins/focus",
"repository": {
2 changes: 1 addition & 1 deletion packages/intersect/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alpinejs/intersect",
"version": "3.13.7",
"version": "3.13.8",
"description": "Trigger JavaScript when an element enters the viewport",
"homepage": "https://alpinejs.dev/plugins/intersect",
"repository": {
2 changes: 1 addition & 1 deletion packages/mask/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alpinejs/mask",
"version": "3.13.7",
"version": "3.13.8",
"description": "An Alpine plugin for input masking",
"homepage": "https://alpinejs.dev/plugins/mask",
"repository": {
2 changes: 1 addition & 1 deletion packages/morph/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alpinejs/morph",
"version": "3.13.7",
"version": "3.13.8",
"description": "Diff and patch a block of HTML on a page with an HTML template",
"homepage": "https://alpinejs.dev/plugins/morph",
"repository": {
2 changes: 1 addition & 1 deletion packages/persist/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alpinejs/persist",
"version": "3.13.7",
"version": "3.13.8",
"description": "Persist Alpine data across page loads",
"homepage": "https://alpinejs.dev/plugins/persist",
"repository": {
6 changes: 5 additions & 1 deletion packages/persist/src/index.js
Original file line number Diff line number Diff line change
@@ -65,7 +65,11 @@ function storageHas(key, storage) {
}

function storageGet(key, storage) {
return JSON.parse(storage.getItem(key, storage))
let value = storage.getItem(key, storage)

if (value === undefined) return

return JSON.parse(value)
}

function storageSet(key, value, storage) {
2 changes: 1 addition & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alpinejs/ui",
"version": "3.13.6-beta.0",
"version": "3.13.7-beta.0",
"description": "Headless UI components for Alpine",
"homepage": "https://alpinejs.dev/components#headless",
"repository": {
28 changes: 26 additions & 2 deletions tests/cypress/integration/directives/x-bind.spec.js
Original file line number Diff line number Diff line change
@@ -27,13 +27,30 @@ test('style attribute bindings are added by string syntax',
({ get }) => get('span').should(haveClasses(['foo']))
)

test('aria-pressed/checked attribute boolean values are cast to a true/false string',
test('aria-pressed/checked/expanded/selected attribute boolean values are cast to a true/false string',
html`
<div x-data="{ open: true }">
<span x-bind:aria-pressed="open"></span>
<span x-bind:aria-checked="open"></span>
<span x-bind:aria-expanded="open"></span>
<span x-bind:aria-selected="open"></span>
<span x-bind:aria-pressed="false"></span>
<span x-bind:aria-checked="false"></span>
<span x-bind:aria-expanded="false"></span>
<span x-bind:aria-selected="false"></span>
</div>
`,
({ get }) => get('span').should(haveAttribute('aria-pressed', 'true'))
({ get }) => {
get('span:nth-of-type(1)').should(haveAttribute('aria-pressed', 'true'))
get('span:nth-of-type(2)').should(haveAttribute('aria-checked', 'true'))
get('span:nth-of-type(3)').should(haveAttribute('aria-expanded', 'true'))
get('span:nth-of-type(4)').should(haveAttribute('aria-selected', 'true'))
get('span:nth-of-type(5)').should(haveAttribute('aria-pressed', 'false'))
get('span:nth-of-type(6)').should(haveAttribute('aria-checked', 'false'))
get('span:nth-of-type(7)').should(haveAttribute('aria-expanded', 'false'))
get('span:nth-of-type(8)').should(haveAttribute('aria-selected', 'false'))
}
)

test('non-boolean attributes set to null/undefined/false are removed from the element',
@@ -46,6 +63,10 @@ test('non-boolean attributes set to null/undefined/false are removed from the el
<span visible="true" x-bind:visible="null">null</span>
<span visible="true" x-bind:visible="false">false</span>
<span visible="true" x-bind:visible="undefined">undefined</span>
<span hidden="true" x-bind:hidden="null">null</span>
<span hidden="true" x-bind:hidden="false">false</span>
<span hidden="true" x-bind:hidden="undefined">undefined</span>
</div>
`,
({ get }) => {
@@ -55,6 +76,9 @@ test('non-boolean attributes set to null/undefined/false are removed from the el
get('span:nth-of-type(1)').should(notHaveAttribute('visible'))
get('span:nth-of-type(2)').should(notHaveAttribute('visible'))
get('span:nth-of-type(3)').should(notHaveAttribute('visible'))
get('span:nth-of-type(4)').should(notHaveAttribute('hidden'))
get('span:nth-of-type(5)').should(notHaveAttribute('hidden'))
get('span:nth-of-type(6)').should(notHaveAttribute('hidden'))
}
)

43 changes: 42 additions & 1 deletion tests/cypress/integration/directives/x-model.spec.js
Original file line number Diff line number Diff line change
@@ -234,7 +234,7 @@ test('x-model with fill modifier takes input value on null, empty string or unde
}
)

test('x-model with fill modifier works with select/radio elements',
test('x-model with fill modifier works with select elements',
html`
<div x-data="{ a: null, b: null, c: null, d: null }">
<select x-model.fill="a">
@@ -253,6 +253,35 @@ test('x-model with fill modifier works with select/radio elements',
}
);

test('x-model with fill modifier works with radio elements',
html`
<div x-data="{ a: null, b: null, c: '101112', d: null }">
<input x-model.fill="a" type="radio" value="123" />
<input x-model.fill="a" type="radio" value="456" checked />
<input x-model.fill="a" type="radio" value="789" />
<input x-model.fill="a" type="radio" value="101112" />
<input x-model.fill="a" type="radio" value="131415" />
<input x-model.fill="b" name="b" type="radio" value="123" />
<input x-model.fill="b" name="b" type="radio" value="456" />
<input x-model.fill="b" name="b" type="radio" value="789" checked />
<input x-model.fill="b" name="b" type="radio" value="101112" />
<input x-model.fill="b" name="b" type="radio" value="131415" />
<input x-model.fill="c" type="radio" value="123" />
<input x-model.fill="c" type="radio" value="456" />
<input x-model.fill="c" type="radio" value="789" />
<input x-model.fill="c" type="radio" value="101112" />
<input x-model.fill="c" type="radio" value="131415" />
</div>
`,
({ get }) => {
get('[x-data]').should(haveData('a', '456'));
get('[x-data]').should(haveData('b', '789'));
get('[x-data]').should(haveData('c', '101112'));
}
);

test('x-model with fill modifier respects number modifier',
html`
<div x-data="{ a: null, b: null, c: null, d: null }">
@@ -282,3 +311,15 @@ test(
}
);

test(
'x-model with fill and debounce still fills value',
html`
<div x-data="{ a: '' }">
<input type="text" x-model.fill.debounce="a" value="hello" />
</div>
`,
({ get }) => {
get('[x-data]').should(haveData('a', 'hello'));
}
);