@ramstack/alpinegear-bound 1.2.4 → 1.4.0

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/README.md CHANGED
@@ -387,6 +387,11 @@ Provides the `x-hotkey` directive, which allows you to easily handle keyboard sh
387
387
  **[@ramstack/alpinegear-router](https://www.npmjs.com/package/@ramstack/alpinegear-router)** ([README](https://github.com/rameel/ramstack.alpinegear.js/tree/main/src/plugins/router))<br>
388
388
  Provides the `x-router` and `x-route` directives, which enable client-side navigation and routing functionality within your Alpine.js application.
389
389
 
390
+ **[@ramstack/alpinegear-dialog](https://www.npmjs.com/package/@ramstack/alpinegear-dialog)** ([README](https://github.com/rameel/ramstack.alpinegear.js/tree/main/src/plugins/dialog))<br>
391
+ Provides a headless dialog directive for Alpine.js based on the native HTML `<dialog>` element.
392
+ It supports declarative composition, value-based close semantics, and both modal and non-modal dialogs,
393
+ with optional Promise-based imperative control.
394
+
390
395
 
391
396
  ## Contributions
392
397
  Bug reports and contributions are welcome.
@@ -122,7 +122,7 @@ function watch(get_value, callback, options = null) {
122
122
  }
123
123
 
124
124
  if (initialized || (options?.immediate ?? true)) {
125
-
125
+ // Prevent the watcher from detecting its own dependencies.
126
126
  setTimeout(() => {
127
127
  callback(new_value, old_value);
128
128
  old_value = new_value;
@@ -146,10 +146,10 @@ const canonical_names = create_map(
146
146
  "group");
147
147
 
148
148
  function plugin({ directive, entangle, evaluateLater, mapAttributes, mutateDom, prefixed }) {
149
-
150
-
151
-
152
-
149
+ // creating a shortcut for the directive,
150
+ // when an attribute name starting with & will refer to our directive,
151
+ // allowing us to write like this: &value="prop",
152
+ // which is equivalent to x-bound:value="prop"
153
153
  mapAttributes(attr => ({
154
154
  name: attr.name.replace(/^&/, prefixed("bound:")),
155
155
  value: attr.value
@@ -165,8 +165,8 @@ function plugin({ directive, entangle, evaluateLater, mapAttributes, mutateDom,
165
165
 
166
166
  expression = expression?.trim();
167
167
 
168
-
169
-
168
+ // since attributes come in a lowercase,
169
+ // we need to convert the bound property name to its canonical form
170
170
  const property_name = canonical_names.get(value.trim().replace("-", "").toLowerCase());
171
171
 
172
172
  // if the expression is omitted, then we assume it corresponds
@@ -223,7 +223,7 @@ function plugin({ directive, entangle, evaluateLater, mapAttributes, mutateDom,
223
223
  break;
224
224
 
225
225
  case "open":
226
- process_details();
226
+ process_open_attribute();
227
227
  break;
228
228
 
229
229
  case "group":
@@ -277,8 +277,8 @@ function plugin({ directive, entangle, evaluateLater, mapAttributes, mutateDom,
277
277
  switch (tag_name) {
278
278
  case "INPUT":
279
279
  case "TEXTAREA":
280
-
281
-
280
+ // if the value of the bound property is "null" or "undefined",
281
+ // we initialize it with the value from the element.
282
282
  is_nullish(get_value()) && update_variable();
283
283
 
284
284
  effect(update_property);
@@ -288,16 +288,16 @@ function plugin({ directive, entangle, evaluateLater, mapAttributes, mutateDom,
288
288
  break;
289
289
 
290
290
  case "SELECT":
291
-
292
-
293
-
294
-
295
-
296
-
297
-
291
+ // WORKAROUND:
292
+ // For the "select" element, there might be a situation
293
+ // where options are generated dynamically using the "x-for" directive,
294
+ // and in this case, attempting to set the "value" property
295
+ // will have no effect since there are no options yet.
296
+ // Therefore, we use a small trick to set the value a bit later
297
+ // when the "x-for" directive has finished its work.
298
298
  setTimeout(() => {
299
-
300
-
299
+ // if the value of the bound property is "null" or "undefined",
300
+ // we initialize it with the value from the element.
301
301
  is_nullish(get_value()) && update_variable();
302
302
 
303
303
  effect(() => apply_select_values(el, as_array(get_value() ?? [])));
@@ -359,13 +359,29 @@ function plugin({ directive, entangle, evaluateLater, mapAttributes, mutateDom,
359
359
  processed = true;
360
360
  }
361
361
 
362
- function process_details() {
363
- if (tag_name === "DETAILS") {
364
-
365
-
366
- is_nullish(get_value()) && update_variable();
367
-
368
- effect(update_property);
362
+ function process_open_attribute() {
363
+ const [is_details, is_dialog] = [tag_name === "DETAILS", tag_name === "DIALOG"];
364
+
365
+ if (is_details || is_dialog) {
366
+ //
367
+ // <details>:
368
+ // Supports safe two-way binding via the "open" attribute,
369
+ // so we initialize from the element only if the bound value
370
+ // is null or undefined.
371
+ //
372
+ // <dialog>:
373
+ // Directly setting element.open is discouraged by the spec,
374
+ // as it breaks native dialog behavior and the "close" event.
375
+ // Therefore, we always initialize state from the element
376
+ // and treat it as a one-way source of truth.
377
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/open#value
378
+ //
379
+ (is_dialog || is_nullish(get_value())) && update_variable();
380
+
381
+ //
382
+ // Enable two-way binding only for "<details>"
383
+ //
384
+ is_details && effect(update_property);
369
385
  cleanup(listen(el, "toggle", update_variable));
370
386
  processed = true;
371
387
  }
@@ -428,4 +444,4 @@ function collect_group_values(el, values) {
428
444
  return values;
429
445
  }
430
446
 
431
- export { plugin as bound };
447
+ export { plugin as bound };
@@ -1 +1 @@
1
- function e(e,...t){const n=e(...t);return()=>{let e;return n(t=>e=t),t=e,"function"==typeof t?.get?e.get():e;var t}}function t(e,...t){const n=e(...t);t[t.length-1]=`${t.at(-1)} = __val`;const i=e(...t);return e=>{let t;n(e=>t=e),function(e){return"function"==typeof e?.set}(t)?t.set(e):i(()=>{},{scope:{__val:e}})}}const n=Symbol();let i;const a=(...e)=>console.warn("alpinegear.js:",...e),r=Array.isArray,o=e=>null==e,c=e=>"checkbox"===e.type||"radio"===e.type,s=e=>r(e)?e:[e],u=(e,t)=>e==t,l=(e,t)=>e.findIndex(e=>e==t),d=(e,t)=>e.includes(t),f=(e,t,n,i)=>(e.addEventListener(t,n,i),()=>e.removeEventListener(t,n,i)),p=e=>"object"==typeof e?JSON.parse(JSON.stringify(e)):e;function h(e,t,n=null){const{effect:i,release:a}=Alpine;let r,o,c=!1;const s=i(()=>{r=e(),c||(n?.deep&&JSON.stringify(r),o=r),(c||(n?.immediate??1))&&setTimeout(()=>{t(r,o),o=r},0),c=!0});return()=>a(s)}const v=new Map("value,checked,files,innerHTML,innerText,textContent,videoHeight,videoWidth,naturalHeight,naturalWidth,clientHeight,clientWidth,offsetHeight,offsetWidth,indeterminate,open,group".split(",").map(e=>[e.trim().toLowerCase(),e.trim()]));function b({directive:b,entangle:g,evaluateLater:m,mapAttributes:k,mutateDom:x,prefixed:y}){k(e=>({name:e.name.replace(/^&/,y("bound:")),value:e.value})),b("bound",(b,{expression:k,value:y,modifiers:T},{effect:w,cleanup:E})=>{if(!y)return void a("x-bound directive expects the presence of a bound property name");const H=b.tagName.toUpperCase();k=k?.trim();const L=v.get(y.trim().replace("-","").toLowerCase());k||=L;const _=e(m,b,k),S=t(m,b,k),W=()=>u(b[L],_())||x(()=>b[L]=_()),A=()=>S((e=>"number"===e.type||"range"===e.type)(b)?function(e){return""===e?null:+e}(b[L]):b[L]);let C;switch(L){case"value":!function(){switch(H){case"INPUT":case"TEXTAREA":o(_())&&A(),w(W),E(f(b,"input",A)),C=!0;break;case"SELECT":setTimeout(()=>{o(_())&&A(),w(()=>function(e,t){for(const n of e.options)n.selected=l(t,n.value)>=0}(b,s(_()??[]))),E(f(b,"change",()=>S(function(e){return e.multiple?[...e.selectedOptions].map(e=>e.value):e.value}(b))))},0),C=!0}}();break;case"checked":c(b)&&(w(W),E(f(b,"change",A)),C=!0);break;case"files":"file"===b.type&&(_()instanceof FileList||A(),w(W),E(f(b,"input",A)),C=!0);break;case"innerHTML":case"innerText":case"textContent":"true"===b.contentEditable&&(o(_())&&A(),w(W),E(f(b,"input",A)),C=!0);break;case"videoHeight":case"videoWidth":N("VIDEO","resize");break;case"naturalHeight":case"naturalWidth":N("IMG","load");break;case"clientHeight":case"clientWidth":case"offsetHeight":case"offsetWidth":E(function(e,t){return i??=new ResizeObserver(e=>{for(const t of e)for(const e of t.target[n]?.values()??[])e(t)}),e[n]??=new Set,e[n].add(t),i.observe(e),()=>{e[n].delete(t),e[n].size||(i.unobserve(e),e[n]=null)}}(b,A)),C=!0;break;case"indeterminate":"checkbox"===b.type&&(o(_())&&A(),w(W),E(f(b,"change",A)),C=!0);break;case"open":"DETAILS"===H&&(o(_())&&A(),w(W),E(f(b,"toggle",A)),C=!0);break;case"group":c(b)&&(b.name||x(()=>b.name=k),w(()=>x(()=>function(e,t){e.checked=r(t)?l(t,e.value)>=0:u(e.value,t)}(b,_()??[]))),E(f(b,"input",()=>S(function(e,t){if("radio"===e.type)return e.value;t=s(t);const n=l(t,e.value);return e.checked?n>=0||t.push(e.value):n>=0&&t.splice(n,1),t}(b,_())))),C=!0)}if(!C){const n=d(T,"in")?"in":d(T,"out")?"out":"inout",i=k===y?((e,t)=>{for(;e&&!t(e);)e=(e._x_teleportBack??e).parentElement;return e})(b.parentNode,e=>e._x_dataStack):b;if(!b._x_dataStack)return void a("x-bound directive requires the presence of the x-data directive to bind component properties");if(!i)return void a(`x-bound directive cannot find the parent scope where the '${y}' property is defined`);const r={get:e(m,i,k),set:t(m,i,k)},o={get:e(m,b,y),set:t(m,b,y)};switch(n){case"in":E(h(()=>r.get(),e=>o.set(p(e))));break;case"out":E(h(()=>o.get(),e=>r.set(p(e))));break;default:E(g(r,o))}}function N(e,t){H===e&&(A(),E(f(b,t,A)),C=!0)}})}export{b as bound};
1
+ function e(e,...t){const n=e(...t);return()=>{let e;return n(t=>e=t),t=e,"function"==typeof t?.get?e.get():e;var t}}function t(e,...t){const n=e(...t);t[t.length-1]=`${t.at(-1)} = __val`;const i=e(...t);return e=>{let t;n(e=>t=e),function(e){return"function"==typeof e?.set}(t)?t.set(e):i(()=>{},{scope:{__val:e}})}}const n=Symbol();let i;const a=(...e)=>console.warn("alpinegear.js:",...e),r=Array.isArray,o=e=>null==e,c=e=>"checkbox"===e.type||"radio"===e.type,s=e=>r(e)?e:[e],u=(e,t)=>e==t,l=(e,t)=>e.findIndex(e=>e==t),d=(e,t)=>e.includes(t),f=(e,t,n,i)=>(e.addEventListener(t,n,i),()=>e.removeEventListener(t,n,i)),p=e=>"object"==typeof e?JSON.parse(JSON.stringify(e)):e;function h(e,t,n=null){const{effect:i,release:a}=Alpine;let r,o,c=!1;const s=i(()=>{r=e(),c||(n?.deep&&JSON.stringify(r),o=r),(c||(n?.immediate??1))&&setTimeout(()=>{t(r,o),o=r},0),c=!0});return()=>a(s)}const v=new Map("value,checked,files,innerHTML,innerText,textContent,videoHeight,videoWidth,naturalHeight,naturalWidth,clientHeight,clientWidth,offsetHeight,offsetWidth,indeterminate,open,group".split(",").map(e=>[e.trim().toLowerCase(),e.trim()]));function b({directive:b,entangle:g,evaluateLater:m,mapAttributes:k,mutateDom:x,prefixed:y}){k(e=>({name:e.name.replace(/^&/,y("bound:")),value:e.value})),b("bound",(b,{expression:k,value:y,modifiers:L},{effect:T,cleanup:w})=>{if(!y)return void a("x-bound directive expects the presence of a bound property name");const E=b.tagName.toUpperCase();k=k?.trim();const H=v.get(y.trim().replace("-","").toLowerCase());k||=H;const _=e(m,b,k),S=t(m,b,k),A=()=>u(b[H],_())||x(()=>b[H]=_()),W=()=>S((e=>"number"===e.type||"range"===e.type)(b)?function(e){return""===e?null:+e}(b[H]):b[H]);let O;switch(H){case"value":!function(){switch(E){case"INPUT":case"TEXTAREA":o(_())&&W(),T(A),w(f(b,"input",W)),O=!0;break;case"SELECT":setTimeout(()=>{o(_())&&W(),T(()=>function(e,t){for(const n of e.options)n.selected=l(t,n.value)>=0}(b,s(_()??[]))),w(f(b,"change",()=>S(function(e){return e.multiple?[...e.selectedOptions].map(e=>e.value):e.value}(b))))},0),O=!0}}();break;case"checked":c(b)&&(T(A),w(f(b,"change",W)),O=!0);break;case"files":"file"===b.type&&(_()instanceof FileList||W(),T(A),w(f(b,"input",W)),O=!0);break;case"innerHTML":case"innerText":case"textContent":"true"===b.contentEditable&&(o(_())&&W(),T(A),w(f(b,"input",W)),O=!0);break;case"videoHeight":case"videoWidth":C("VIDEO","resize");break;case"naturalHeight":case"naturalWidth":C("IMG","load");break;case"clientHeight":case"clientWidth":case"offsetHeight":case"offsetWidth":w(function(e,t){return i??=new ResizeObserver(e=>{for(const t of e)for(const e of t.target[n]?.values()??[])e(t)}),e[n]??=new Set,e[n].add(t),i.observe(e),()=>{e[n].delete(t),e[n].size||(i.unobserve(e),e[n]=null)}}(b,W)),O=!0;break;case"indeterminate":"checkbox"===b.type&&(o(_())&&W(),T(A),w(f(b,"change",W)),O=!0);break;case"open":!function(){const[e,t]=["DETAILS"===E,"DIALOG"===E];(e||t)&&((t||o(_()))&&W(),e&&T(A),w(f(b,"toggle",W)),O=!0)}();break;case"group":c(b)&&(b.name||x(()=>b.name=k),T(()=>x(()=>function(e,t){e.checked=r(t)?l(t,e.value)>=0:u(e.value,t)}(b,_()??[]))),w(f(b,"input",()=>S(function(e,t){if("radio"===e.type)return e.value;t=s(t);const n=l(t,e.value);return e.checked?n>=0||t.push(e.value):n>=0&&t.splice(n,1),t}(b,_())))),O=!0)}if(!O){const n=d(L,"in")?"in":d(L,"out")?"out":"inout",i=k===y?((e,t)=>{for(;e&&!t(e);)e=(e._x_teleportBack??e).parentElement;return e})(b.parentNode,e=>e._x_dataStack):b;if(!b._x_dataStack)return void a("x-bound directive requires the presence of the x-data directive to bind component properties");if(!i)return void a(`x-bound directive cannot find the parent scope where the '${y}' property is defined`);const r={get:e(m,i,k),set:t(m,i,k)},o={get:e(m,b,y),set:t(m,b,y)};switch(n){case"in":w(h(()=>r.get(),e=>o.set(p(e))));break;case"out":w(h(()=>o.get(),e=>r.set(p(e))));break;default:w(g(r,o))}}function C(e,t){E===e&&(W(),w(f(b,t,W)),O=!0)}})}export{b as bound};
@@ -125,7 +125,7 @@
125
125
  }
126
126
 
127
127
  if (initialized || (options?.immediate ?? true)) {
128
-
128
+ // Prevent the watcher from detecting its own dependencies.
129
129
  setTimeout(() => {
130
130
  callback(new_value, old_value);
131
131
  old_value = new_value;
@@ -149,10 +149,10 @@
149
149
  "group");
150
150
 
151
151
  function plugin({ directive, entangle, evaluateLater, mapAttributes, mutateDom, prefixed }) {
152
-
153
-
154
-
155
-
152
+ // creating a shortcut for the directive,
153
+ // when an attribute name starting with & will refer to our directive,
154
+ // allowing us to write like this: &value="prop",
155
+ // which is equivalent to x-bound:value="prop"
156
156
  mapAttributes(attr => ({
157
157
  name: attr.name.replace(/^&/, prefixed("bound:")),
158
158
  value: attr.value
@@ -168,8 +168,8 @@
168
168
 
169
169
  expression = expression?.trim();
170
170
 
171
-
172
-
171
+ // since attributes come in a lowercase,
172
+ // we need to convert the bound property name to its canonical form
173
173
  const property_name = canonical_names.get(value.trim().replace("-", "").toLowerCase());
174
174
 
175
175
  // if the expression is omitted, then we assume it corresponds
@@ -226,7 +226,7 @@
226
226
  break;
227
227
 
228
228
  case "open":
229
- process_details();
229
+ process_open_attribute();
230
230
  break;
231
231
 
232
232
  case "group":
@@ -280,8 +280,8 @@
280
280
  switch (tag_name) {
281
281
  case "INPUT":
282
282
  case "TEXTAREA":
283
-
284
-
283
+ // if the value of the bound property is "null" or "undefined",
284
+ // we initialize it with the value from the element.
285
285
  is_nullish(get_value()) && update_variable();
286
286
 
287
287
  effect(update_property);
@@ -291,16 +291,16 @@
291
291
  break;
292
292
 
293
293
  case "SELECT":
294
-
295
-
296
-
297
-
298
-
299
-
300
-
294
+ // WORKAROUND:
295
+ // For the "select" element, there might be a situation
296
+ // where options are generated dynamically using the "x-for" directive,
297
+ // and in this case, attempting to set the "value" property
298
+ // will have no effect since there are no options yet.
299
+ // Therefore, we use a small trick to set the value a bit later
300
+ // when the "x-for" directive has finished its work.
301
301
  setTimeout(() => {
302
-
303
-
302
+ // if the value of the bound property is "null" or "undefined",
303
+ // we initialize it with the value from the element.
304
304
  is_nullish(get_value()) && update_variable();
305
305
 
306
306
  effect(() => apply_select_values(el, as_array(get_value() ?? [])));
@@ -362,13 +362,29 @@
362
362
  processed = true;
363
363
  }
364
364
 
365
- function process_details() {
366
- if (tag_name === "DETAILS") {
367
-
368
-
369
- is_nullish(get_value()) && update_variable();
370
-
371
- effect(update_property);
365
+ function process_open_attribute() {
366
+ const [is_details, is_dialog] = [tag_name === "DETAILS", tag_name === "DIALOG"];
367
+
368
+ if (is_details || is_dialog) {
369
+ //
370
+ // <details>:
371
+ // Supports safe two-way binding via the "open" attribute,
372
+ // so we initialize from the element only if the bound value
373
+ // is null or undefined.
374
+ //
375
+ // <dialog>:
376
+ // Directly setting element.open is discouraged by the spec,
377
+ // as it breaks native dialog behavior and the "close" event.
378
+ // Therefore, we always initialize state from the element
379
+ // and treat it as a one-way source of truth.
380
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/open#value
381
+ //
382
+ (is_dialog || is_nullish(get_value())) && update_variable();
383
+
384
+ //
385
+ // Enable two-way binding only for "<details>"
386
+ //
387
+ is_details && effect(update_property);
372
388
  cleanup(listen(el, "toggle", update_variable));
373
389
  processed = true;
374
390
  }
@@ -433,4 +449,4 @@
433
449
 
434
450
  document.addEventListener("alpine:init", () => { Alpine.plugin(plugin); });
435
451
 
436
- })();
452
+ })();
@@ -1 +1 @@
1
- !function(){"use strict";function e(e,...t){const n=e(...t);return()=>{let e;return n(t=>e=t),t=e,"function"==typeof t?.get?e.get():e;var t}}function t(e,...t){const n=e(...t);t[t.length-1]=`${t.at(-1)} = __val`;const i=e(...t);return e=>{let t;n(e=>t=e),function(e){return"function"==typeof e?.set}(t)?t.set(e):i(()=>{},{scope:{__val:e}})}}const n=Symbol();let i;const a=(...e)=>console.warn("alpinegear.js:",...e),r=Array.isArray,o=e=>null==e,c=e=>"checkbox"===e.type||"radio"===e.type,s=e=>r(e)?e:[e],u=(e,t)=>e==t,l=(e,t)=>e.findIndex(e=>e==t),d=(e,t)=>e.includes(t),p=(e,t,n,i)=>(e.addEventListener(t,n,i),()=>e.removeEventListener(t,n,i)),f=e=>"object"==typeof e?JSON.parse(JSON.stringify(e)):e;function v(e,t,n=null){const{effect:i,release:a}=Alpine;let r,o,c=!1;const s=i(()=>{r=e(),c||(n?.deep&&JSON.stringify(r),o=r),(c||(n?.immediate??1))&&setTimeout(()=>{t(r,o),o=r},0),c=!0});return()=>a(s)}const h=new Map("value,checked,files,innerHTML,innerText,textContent,videoHeight,videoWidth,naturalHeight,naturalWidth,clientHeight,clientWidth,offsetHeight,offsetWidth,indeterminate,open,group".split(",").map(e=>[e.trim().toLowerCase(),e.trim()]));function g({directive:g,entangle:b,evaluateLater:m,mapAttributes:k,mutateDom:x,prefixed:y}){k(e=>({name:e.name.replace(/^&/,y("bound:")),value:e.value})),g("bound",(g,{expression:k,value:y,modifiers:E},{effect:L,cleanup:T})=>{if(!y)return void a("x-bound directive expects the presence of a bound property name");const w=g.tagName.toUpperCase();k=k?.trim();const H=h.get(y.trim().replace("-","").toLowerCase());k||=H;const _=e(m,g,k),S=t(m,g,k),A=()=>u(g[H],_())||x(()=>g[H]=_()),W=()=>S((e=>"number"===e.type||"range"===e.type)(g)?function(e){return""===e?null:+e}(g[H]):g[H]);let C;switch(H){case"value":!function(){switch(w){case"INPUT":case"TEXTAREA":o(_())&&W(),L(A),T(p(g,"input",W)),C=!0;break;case"SELECT":setTimeout(()=>{o(_())&&W(),L(()=>function(e,t){for(const n of e.options)n.selected=l(t,n.value)>=0}(g,s(_()??[]))),T(p(g,"change",()=>S(function(e){return e.multiple?[...e.selectedOptions].map(e=>e.value):e.value}(g))))},0),C=!0}}();break;case"checked":c(g)&&(L(A),T(p(g,"change",W)),C=!0);break;case"files":"file"===g.type&&(_()instanceof FileList||W(),L(A),T(p(g,"input",W)),C=!0);break;case"innerHTML":case"innerText":case"textContent":"true"===g.contentEditable&&(o(_())&&W(),L(A),T(p(g,"input",W)),C=!0);break;case"videoHeight":case"videoWidth":N("VIDEO","resize");break;case"naturalHeight":case"naturalWidth":N("IMG","load");break;case"clientHeight":case"clientWidth":case"offsetHeight":case"offsetWidth":T(function(e,t){return i??=new ResizeObserver(e=>{for(const t of e)for(const e of t.target[n]?.values()??[])e(t)}),e[n]??=new Set,e[n].add(t),i.observe(e),()=>{e[n].delete(t),e[n].size||(i.unobserve(e),e[n]=null)}}(g,W)),C=!0;break;case"indeterminate":"checkbox"===g.type&&(o(_())&&W(),L(A),T(p(g,"change",W)),C=!0);break;case"open":"DETAILS"===w&&(o(_())&&W(),L(A),T(p(g,"toggle",W)),C=!0);break;case"group":c(g)&&(g.name||x(()=>g.name=k),L(()=>x(()=>function(e,t){e.checked=r(t)?l(t,e.value)>=0:u(e.value,t)}(g,_()??[]))),T(p(g,"input",()=>S(function(e,t){if("radio"===e.type)return e.value;t=s(t);const n=l(t,e.value);return e.checked?n>=0||t.push(e.value):n>=0&&t.splice(n,1),t}(g,_())))),C=!0)}if(!C){const n=d(E,"in")?"in":d(E,"out")?"out":"inout",i=k===y?((e,t)=>{for(;e&&!t(e);)e=(e._x_teleportBack??e).parentElement;return e})(g.parentNode,e=>e._x_dataStack):g;if(!g._x_dataStack)return void a("x-bound directive requires the presence of the x-data directive to bind component properties");if(!i)return void a(`x-bound directive cannot find the parent scope where the '${y}' property is defined`);const r={get:e(m,i,k),set:t(m,i,k)},o={get:e(m,g,y),set:t(m,g,y)};switch(n){case"in":T(v(()=>r.get(),e=>o.set(f(e))));break;case"out":T(v(()=>o.get(),e=>r.set(f(e))));break;default:T(b(r,o))}}function N(e,t){w===e&&(W(),T(p(g,t,W)),C=!0)}})}document.addEventListener("alpine:init",()=>{Alpine.plugin(g)})}();
1
+ !function(){"use strict";function e(e,...t){const n=e(...t);return()=>{let e;return n(t=>e=t),t=e,"function"==typeof t?.get?e.get():e;var t}}function t(e,...t){const n=e(...t);t[t.length-1]=`${t.at(-1)} = __val`;const i=e(...t);return e=>{let t;n(e=>t=e),function(e){return"function"==typeof e?.set}(t)?t.set(e):i(()=>{},{scope:{__val:e}})}}const n=Symbol();let i;const a=(...e)=>console.warn("alpinegear.js:",...e),r=Array.isArray,o=e=>null==e,c=e=>"checkbox"===e.type||"radio"===e.type,s=e=>r(e)?e:[e],u=(e,t)=>e==t,l=(e,t)=>e.findIndex(e=>e==t),d=(e,t)=>e.includes(t),f=(e,t,n,i)=>(e.addEventListener(t,n,i),()=>e.removeEventListener(t,n,i)),p=e=>"object"==typeof e?JSON.parse(JSON.stringify(e)):e;function v(e,t,n=null){const{effect:i,release:a}=Alpine;let r,o,c=!1;const s=i(()=>{r=e(),c||(n?.deep&&JSON.stringify(r),o=r),(c||(n?.immediate??1))&&setTimeout(()=>{t(r,o),o=r},0),c=!0});return()=>a(s)}const h=new Map("value,checked,files,innerHTML,innerText,textContent,videoHeight,videoWidth,naturalHeight,naturalWidth,clientHeight,clientWidth,offsetHeight,offsetWidth,indeterminate,open,group".split(",").map(e=>[e.trim().toLowerCase(),e.trim()]));function g({directive:g,entangle:b,evaluateLater:m,mapAttributes:k,mutateDom:x,prefixed:y}){k(e=>({name:e.name.replace(/^&/,y("bound:")),value:e.value})),g("bound",(g,{expression:k,value:y,modifiers:L},{effect:E,cleanup:T})=>{if(!y)return void a("x-bound directive expects the presence of a bound property name");const w=g.tagName.toUpperCase();k=k?.trim();const H=h.get(y.trim().replace("-","").toLowerCase());k||=H;const _=e(m,g,k),A=t(m,g,k),S=()=>u(g[H],_())||x(()=>g[H]=_()),W=()=>A((e=>"number"===e.type||"range"===e.type)(g)?function(e){return""===e?null:+e}(g[H]):g[H]);let O;switch(H){case"value":!function(){switch(w){case"INPUT":case"TEXTAREA":o(_())&&W(),E(S),T(f(g,"input",W)),O=!0;break;case"SELECT":setTimeout(()=>{o(_())&&W(),E(()=>function(e,t){for(const n of e.options)n.selected=l(t,n.value)>=0}(g,s(_()??[]))),T(f(g,"change",()=>A(function(e){return e.multiple?[...e.selectedOptions].map(e=>e.value):e.value}(g))))},0),O=!0}}();break;case"checked":c(g)&&(E(S),T(f(g,"change",W)),O=!0);break;case"files":"file"===g.type&&(_()instanceof FileList||W(),E(S),T(f(g,"input",W)),O=!0);break;case"innerHTML":case"innerText":case"textContent":"true"===g.contentEditable&&(o(_())&&W(),E(S),T(f(g,"input",W)),O=!0);break;case"videoHeight":case"videoWidth":C("VIDEO","resize");break;case"naturalHeight":case"naturalWidth":C("IMG","load");break;case"clientHeight":case"clientWidth":case"offsetHeight":case"offsetWidth":T(function(e,t){return i??=new ResizeObserver(e=>{for(const t of e)for(const e of t.target[n]?.values()??[])e(t)}),e[n]??=new Set,e[n].add(t),i.observe(e),()=>{e[n].delete(t),e[n].size||(i.unobserve(e),e[n]=null)}}(g,W)),O=!0;break;case"indeterminate":"checkbox"===g.type&&(o(_())&&W(),E(S),T(f(g,"change",W)),O=!0);break;case"open":!function(){const[e,t]=["DETAILS"===w,"DIALOG"===w];(e||t)&&((t||o(_()))&&W(),e&&E(S),T(f(g,"toggle",W)),O=!0)}();break;case"group":c(g)&&(g.name||x(()=>g.name=k),E(()=>x(()=>function(e,t){e.checked=r(t)?l(t,e.value)>=0:u(e.value,t)}(g,_()??[]))),T(f(g,"input",()=>A(function(e,t){if("radio"===e.type)return e.value;t=s(t);const n=l(t,e.value);return e.checked?n>=0||t.push(e.value):n>=0&&t.splice(n,1),t}(g,_())))),O=!0)}if(!O){const n=d(L,"in")?"in":d(L,"out")?"out":"inout",i=k===y?((e,t)=>{for(;e&&!t(e);)e=(e._x_teleportBack??e).parentElement;return e})(g.parentNode,e=>e._x_dataStack):g;if(!g._x_dataStack)return void a("x-bound directive requires the presence of the x-data directive to bind component properties");if(!i)return void a(`x-bound directive cannot find the parent scope where the '${y}' property is defined`);const r={get:e(m,i,k),set:t(m,i,k)},o={get:e(m,g,y),set:t(m,g,y)};switch(n){case"in":T(v(()=>r.get(),e=>o.set(p(e))));break;case"out":T(v(()=>o.get(),e=>r.set(p(e))));break;default:T(b(r,o))}}function C(e,t){w===e&&(W(),T(f(g,t,W)),O=!0)}})}document.addEventListener("alpine:init",()=>{Alpine.plugin(g)})}();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramstack/alpinegear-bound",
3
- "version": "1.2.4",
3
+ "version": "1.4.0",
4
4
  "description": "@ramstack/alpinegear-bound provides the 'x-bound' Alpine.js directive, which allows for two-way binding of input elements and their associated data properties.",
5
5
  "author": "Rameel Burhan",
6
6
  "license": "MIT",