@ramstack/alpinegear-main 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 +5 -0
- package/alpinegear-main.esm.js +62 -46
- package/alpinegear-main.esm.min.js +1 -1
- package/alpinegear-main.js +62 -46
- package/alpinegear-main.min.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -173,6 +173,11 @@ Provides the `x-hotkey` directive, which allows you to easily handle keyboard sh
|
|
|
173
173
|
**[@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>
|
|
174
174
|
Provides the `x-router` and `x-route` directives, which enable client-side navigation and routing functionality within your Alpine.js application.
|
|
175
175
|
|
|
176
|
+
**[@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>
|
|
177
|
+
Provides a headless dialog directive for Alpine.js based on the native HTML `<dialog>` element.
|
|
178
|
+
It supports declarative composition, value-based close semantics, and both modal and non-modal dialogs,
|
|
179
|
+
with optional Promise-based imperative control.
|
|
180
|
+
|
|
176
181
|
|
|
177
182
|
## Contributions
|
|
178
183
|
Bug reports and contributions are welcome.
|
package/alpinegear-main.esm.js
CHANGED
|
@@ -69,7 +69,7 @@ const is_array = Array.isArray;
|
|
|
69
69
|
const is_nullish = value => value === null || value === undefined;
|
|
70
70
|
const is_checkable_input = el => el.type === "checkbox" || el.type === "radio";
|
|
71
71
|
const is_numeric_input = el => el.type === "number" || el.type === "range";
|
|
72
|
-
const is_template = el => el
|
|
72
|
+
const is_template = el => el.matches("template");
|
|
73
73
|
const is_element = el => el.nodeType === Node.ELEMENT_NODE;
|
|
74
74
|
const as_array = value => is_array(value) ? value : [value];
|
|
75
75
|
const loose_equal = (a, b) => a == b;
|
|
@@ -124,7 +124,7 @@ function watch(get_value, callback, options = null) {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
if (initialized || (options?.immediate ?? true)) {
|
|
127
|
-
|
|
127
|
+
// Prevent the watcher from detecting its own dependencies.
|
|
128
128
|
setTimeout(() => {
|
|
129
129
|
callback(new_value, old_value);
|
|
130
130
|
old_value = new_value;
|
|
@@ -148,10 +148,10 @@ const canonical_names = create_map(
|
|
|
148
148
|
"group");
|
|
149
149
|
|
|
150
150
|
function plugin$5({ directive, entangle, evaluateLater, mapAttributes, mutateDom, prefixed }) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
151
|
+
// creating a shortcut for the directive,
|
|
152
|
+
// when an attribute name starting with & will refer to our directive,
|
|
153
|
+
// allowing us to write like this: &value="prop",
|
|
154
|
+
// which is equivalent to x-bound:value="prop"
|
|
155
155
|
mapAttributes(attr => ({
|
|
156
156
|
name: attr.name.replace(/^&/, prefixed("bound:")),
|
|
157
157
|
value: attr.value
|
|
@@ -167,8 +167,8 @@ function plugin$5({ directive, entangle, evaluateLater, mapAttributes, mutateDom
|
|
|
167
167
|
|
|
168
168
|
expression = expression?.trim();
|
|
169
169
|
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
// since attributes come in a lowercase,
|
|
171
|
+
// we need to convert the bound property name to its canonical form
|
|
172
172
|
const property_name = canonical_names.get(value.trim().replace("-", "").toLowerCase());
|
|
173
173
|
|
|
174
174
|
// if the expression is omitted, then we assume it corresponds
|
|
@@ -225,7 +225,7 @@ function plugin$5({ directive, entangle, evaluateLater, mapAttributes, mutateDom
|
|
|
225
225
|
break;
|
|
226
226
|
|
|
227
227
|
case "open":
|
|
228
|
-
|
|
228
|
+
process_open_attribute();
|
|
229
229
|
break;
|
|
230
230
|
|
|
231
231
|
case "group":
|
|
@@ -279,8 +279,8 @@ function plugin$5({ directive, entangle, evaluateLater, mapAttributes, mutateDom
|
|
|
279
279
|
switch (tag_name) {
|
|
280
280
|
case "INPUT":
|
|
281
281
|
case "TEXTAREA":
|
|
282
|
-
|
|
283
|
-
|
|
282
|
+
// if the value of the bound property is "null" or "undefined",
|
|
283
|
+
// we initialize it with the value from the element.
|
|
284
284
|
is_nullish(get_value()) && update_variable();
|
|
285
285
|
|
|
286
286
|
effect(update_property);
|
|
@@ -290,16 +290,16 @@ function plugin$5({ directive, entangle, evaluateLater, mapAttributes, mutateDom
|
|
|
290
290
|
break;
|
|
291
291
|
|
|
292
292
|
case "SELECT":
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
293
|
+
// WORKAROUND:
|
|
294
|
+
// For the "select" element, there might be a situation
|
|
295
|
+
// where options are generated dynamically using the "x-for" directive,
|
|
296
|
+
// and in this case, attempting to set the "value" property
|
|
297
|
+
// will have no effect since there are no options yet.
|
|
298
|
+
// Therefore, we use a small trick to set the value a bit later
|
|
299
|
+
// when the "x-for" directive has finished its work.
|
|
300
300
|
setTimeout(() => {
|
|
301
|
-
|
|
302
|
-
|
|
301
|
+
// if the value of the bound property is "null" or "undefined",
|
|
302
|
+
// we initialize it with the value from the element.
|
|
303
303
|
is_nullish(get_value()) && update_variable();
|
|
304
304
|
|
|
305
305
|
effect(() => apply_select_values(el, as_array(get_value() ?? [])));
|
|
@@ -361,13 +361,29 @@ function plugin$5({ directive, entangle, evaluateLater, mapAttributes, mutateDom
|
|
|
361
361
|
processed = true;
|
|
362
362
|
}
|
|
363
363
|
|
|
364
|
-
function
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
364
|
+
function process_open_attribute() {
|
|
365
|
+
const [is_details, is_dialog] = [tag_name === "DETAILS", tag_name === "DIALOG"];
|
|
366
|
+
|
|
367
|
+
if (is_details || is_dialog) {
|
|
368
|
+
//
|
|
369
|
+
// <details>:
|
|
370
|
+
// Supports safe two-way binding via the "open" attribute,
|
|
371
|
+
// so we initialize from the element only if the bound value
|
|
372
|
+
// is null or undefined.
|
|
373
|
+
//
|
|
374
|
+
// <dialog>:
|
|
375
|
+
// Directly setting element.open is discouraged by the spec,
|
|
376
|
+
// as it breaks native dialog behavior and the "close" event.
|
|
377
|
+
// Therefore, we always initialize state from the element
|
|
378
|
+
// and treat it as a one-way source of truth.
|
|
379
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/open#value
|
|
380
|
+
//
|
|
381
|
+
(is_dialog || is_nullish(get_value())) && update_variable();
|
|
382
|
+
|
|
383
|
+
//
|
|
384
|
+
// Enable two-way binding only for "<details>"
|
|
385
|
+
//
|
|
386
|
+
is_details && effect(update_property);
|
|
371
387
|
cleanup(listen(el, "toggle", update_variable));
|
|
372
388
|
processed = true;
|
|
373
389
|
}
|
|
@@ -455,19 +471,19 @@ function plugin$4({ directive, evaluateLater, mutateDom }) {
|
|
|
455
471
|
|
|
456
472
|
case Node.ELEMENT_NODE:
|
|
457
473
|
if (node !== el) {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
474
|
+
//
|
|
475
|
+
// When we encounter an element with the "x-data" attribute, its properties
|
|
476
|
+
// are not yet initialized, and the Alpine context is unavailable.
|
|
477
|
+
// Attempting to use these properties will result in
|
|
478
|
+
// an "Alpine Expression Error: [expression] is not defined".
|
|
479
|
+
//
|
|
480
|
+
// Workaround:
|
|
481
|
+
// To avoid this, we manually add our "x-format" directive to the element.
|
|
482
|
+
// Alpine evaluates "x-format" directive once the context is initialized.
|
|
483
|
+
// In the current loop, we skip these elements to defer their processing.
|
|
484
|
+
//
|
|
485
|
+
// This also handles cases where the user manually adds the "x-format" attribute.
|
|
486
|
+
//
|
|
471
487
|
if (node.hasAttribute("x-data") && !has_format_attr(node)) {
|
|
472
488
|
node.setAttribute("x-format", "");
|
|
473
489
|
}
|
|
@@ -659,11 +675,11 @@ function plugin$1(alpine) {
|
|
|
659
675
|
return;
|
|
660
676
|
}
|
|
661
677
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
678
|
+
// Adding a queued task ensures asynchronous content update, allowing Alpine.js
|
|
679
|
+
// to handle context propagation for cloned elements properly.
|
|
680
|
+
// This is important because manipulation can occur within the mutateDom function
|
|
681
|
+
// when mutation observing is disabled, preventing proper context propagation
|
|
682
|
+
// for cloned elements.
|
|
667
683
|
queueMicrotask(() => {
|
|
668
684
|
el.innerHTML = "";
|
|
669
685
|
el.append(tpl.content.cloneNode(true));
|
|
@@ -686,4 +702,4 @@ function plugin({ addScopeToNode, directive, initTree, mutateDom }) {
|
|
|
686
702
|
});
|
|
687
703
|
}
|
|
688
704
|
|
|
689
|
-
export { plugin$5 as bound, plugin$4 as format, plugin$3 as fragment, plugin$2 as match, plugin$1 as template, plugin as when };
|
|
705
|
+
export { plugin$5 as bound, plugin$4 as format, plugin$3 as fragment, plugin$2 as match, plugin$1 as template, plugin as when };
|
|
@@ -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 o=e(...t);return e=>{let t;n(e=>t=e),function(e){return"function"==typeof e?.set}(t)?t.set(e):o(()=>{},{scope:{__val:e}})}}const n=Symbol();let o;const a=(...e)=>console.warn("alpinegear.js:",...e),r=Array.isArray,c=e=>null==e,i=e=>"checkbox"===e.type||"radio"===e.type,l=e=>e
|
|
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 o=e(...t);return e=>{let t;n(e=>t=e),function(e){return"function"==typeof e?.set}(t)?t.set(e):o(()=>{},{scope:{__val:e}})}}const n=Symbol();let o;const a=(...e)=>console.warn("alpinegear.js:",...e),r=Array.isArray,c=e=>null==e,i=e=>"checkbox"===e.type||"radio"===e.type,l=e=>e.matches("template"),u=e=>e.nodeType===Node.ELEMENT_NODE,s=e=>r(e)?e:[e],d=(e,t)=>e==t,f=(e,t)=>e.findIndex(e=>e==t),p=(e,t)=>e.includes(t),m=(e,t,n,o)=>(e.addEventListener(t,n,o),()=>e.removeEventListener(t,n,o)),h=e=>"object"==typeof e?JSON.parse(JSON.stringify(e)):e;function v(e,t,n=null){const{effect:o,release:a}=Alpine;let r,c,i=!1;const l=o(()=>{r=e(),i||(n?.deep&&JSON.stringify(r),c=r),(i||(n?.immediate??1))&&setTimeout(()=>{t(r,c),c=r},0),i=!0});return()=>a(l)}const b=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:l,entangle:u,evaluateLater:g,mapAttributes:x,mutateDom:T,prefixed:_}){x(e=>({name:e.name.replace(/^&/,_("bound:")),value:e.value})),l("bound",(l,{expression:x,value:_,modifiers:k},{effect:N,cleanup:y})=>{if(!_)return void a("x-bound directive expects the presence of a bound property name");const E=l.tagName.toUpperCase();x=x?.trim();const L=b.get(_.trim().replace("-","").toLowerCase());x||=L;const w=e(g,l,x),D=t(g,l,x),S=()=>d(l[L],w())||T(()=>l[L]=w()),A=()=>D((e=>"number"===e.type||"range"===e.type)(l)?function(e){return""===e?null:+e}(l[L]):l[L]);let H;switch(L){case"value":!function(){switch(E){case"INPUT":case"TEXTAREA":c(w())&&A(),N(S),y(m(l,"input",A)),H=!0;break;case"SELECT":setTimeout(()=>{c(w())&&A(),N(()=>function(e,t){for(const n of e.options)n.selected=f(t,n.value)>=0}(l,s(w()??[]))),y(m(l,"change",()=>D(function(e){return e.multiple?[...e.selectedOptions].map(e=>e.value):e.value}(l))))},0),H=!0}}();break;case"checked":i(l)&&(N(S),y(m(l,"change",A)),H=!0);break;case"files":"file"===l.type&&(w()instanceof FileList||A(),N(S),y(m(l,"input",A)),H=!0);break;case"innerHTML":case"innerText":case"textContent":"true"===l.contentEditable&&(c(w())&&A(),N(S),y(m(l,"input",A)),H=!0);break;case"videoHeight":case"videoWidth":O("VIDEO","resize");break;case"naturalHeight":case"naturalWidth":O("IMG","load");break;case"clientHeight":case"clientWidth":case"offsetHeight":case"offsetWidth":y(function(e,t){return o??=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),o.observe(e),()=>{e[n].delete(t),e[n].size||(o.unobserve(e),e[n]=null)}}(l,A)),H=!0;break;case"indeterminate":"checkbox"===l.type&&(c(w())&&A(),N(S),y(m(l,"change",A)),H=!0);break;case"open":!function(){const[e,t]=["DETAILS"===E,"DIALOG"===E];(e||t)&&((t||c(w()))&&A(),e&&N(S),y(m(l,"toggle",A)),H=!0)}();break;case"group":i(l)&&(l.name||T(()=>l.name=x),N(()=>T(()=>function(e,t){e.checked=r(t)?f(t,e.value)>=0:d(e.value,t)}(l,w()??[]))),y(m(l,"input",()=>D(function(e,t){if("radio"===e.type)return e.value;t=s(t);const n=f(t,e.value);return e.checked?n>=0||t.push(e.value):n>=0&&t.splice(n,1),t}(l,w())))),H=!0)}if(!H){const n=p(k,"in")?"in":p(k,"out")?"out":"inout",o=x===_?((e,t)=>{for(;e&&!t(e);)e=(e._x_teleportBack??e).parentElement;return e})(l.parentNode,e=>e._x_dataStack):l;if(!l._x_dataStack)return void a("x-bound directive requires the presence of the x-data directive to bind component properties");if(!o)return void a(`x-bound directive cannot find the parent scope where the '${_}' property is defined`);const r={get:e(g,o,x),set:t(g,o,x)},c={get:e(g,l,_),set:t(g,l,_)};switch(n){case"in":y(v(()=>r.get(),e=>c.set(h(e))));break;case"out":y(v(()=>c.get(),e=>r.set(h(e))));break;default:y(u(r,c))}}function O(e,t){E===e&&(A(),y(m(l,t,A)),H=!0)}})}function x({directive:t,evaluateLater:n,mutateDom:o}){t("format",(t,{modifiers:a},{effect:r})=>{const c=/{{(?<expr>.+?)}}/g,i=p(a,"once"),l=e=>e.hasAttribute("x-format");function u(e){i?o(()=>e()):r(()=>o(()=>e()))}!function a(r){switch(r.nodeType){case Node.TEXT_NODE:!function(t){const a=t.textContent.split(c);if(a.length>1){const r=new DocumentFragment;for(let o=0;a.length>o;o++)if(o%2==0)r.appendChild(document.createTextNode(a[o]));else{const c=e(n,t.parentNode,a[o]),i=document.createTextNode("");r.append(i),u(()=>i.textContent=c())}o(()=>t.parentElement.replaceChild(r,t))}}(r);break;case Node.ELEMENT_NODE:if(r!==t&&(r.hasAttribute("x-data")&&!l(r)&&r.setAttribute("x-format",""),l(r)))break;!function(e){for(let t of e.childNodes)a(t)}(r),function(t){for(let o of t.attributes)if([...o.value.matchAll(c)].length){const a=o.value;u(()=>o.value=a.replace(c,(o,a)=>e(n,t,a)()))}}(r)}}(t)})}function T(e,t,{addScopeToNode:n,cleanup:o,initTree:a,mutateDom:r,scope:c={}}){if(e._r_block)return;document.body._r_block??=(()=>{const e=new MutationObserver(e=>{for(let t of e)for(let e of t.addedNodes)e._r_block?.update()});return e.observe(document.body,{childList:!0,subtree:!0}),e})();let i=l(t)?[...t.content.cloneNode(!0).childNodes]:[t.cloneNode(!0)];r(()=>{for(let t of i)u(t)&&n(t,c,e),e.parentElement.insertBefore(t,e),u(t)&&a(t)}),e._r_block={template:t,update(){r(()=>{for(let t of i??[])e.parentElement.insertBefore(t,e)})},delete(){e._r_block=null;for(let e of i??[])e.remove();i=null}},o(()=>e._r_block?.delete())}function _({addScopeToNode:e,directive:t,initTree:n,mutateDom:o}){t("fragment",(t,{},{cleanup:r})=>{l(t)?T(t,t,{addScopeToNode:e,cleanup:r,initTree:n,mutateDom:o}):a("x-fragment can only be used on a 'template' tag")})}function k({addScopeToNode:t,directive:n,initTree:o,mutateDom:r}){n("match",(n,{},{cleanup:c,effect:i,evaluateLater:u})=>{if(!l(n))return void a("x-match can only be used on a 'template' tag");const s=[];for(let t of n.content.children){const n=t.getAttribute("x-case");null!==n?s.push({el:t,get_value:e(u,n)}):t.hasAttribute("x-default")&&s.push({el:t,get_value:()=>!0,default:!0})}const d=()=>n._r_block?.delete();i(()=>{let e;for(let t of s)t.get_value()&&!e&&(e=t);var a;e?(a=e,n._r_block?.template!==a.el&&(d(),T(n,a.el,{addScopeToNode:t,cleanup:c,initTree:o,mutateDom:r}))):d()})})}function N(e){e.directive("template",(e,{expression:t})=>{if(l(e))return void a("x-template cannot be used on a 'template' tag");const n=document.getElementById(t);l(n)?queueMicrotask(()=>{e.innerHTML="",e.append(n.content.cloneNode(!0))}):a("x-template directive can only reference the template tag")})}function y({addScopeToNode:t,directive:n,initTree:o,mutateDom:r}){n("when",(n,{expression:c},{cleanup:i,effect:u,evaluateLater:s})=>{if(!l(n))return void a("x-when can only be used on a 'template' tag");const d=e(s,c);u(()=>d()?T(n,n,{addScopeToNode:t,cleanup:i,initTree:o,mutateDom:r}):n._r_block?.delete())})}export{g as bound,x as format,_ as fragment,k as match,N as template,y as when};
|
package/alpinegear-main.js
CHANGED
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
const is_nullish = value => value === null || value === undefined;
|
|
73
73
|
const is_checkable_input = el => el.type === "checkbox" || el.type === "radio";
|
|
74
74
|
const is_numeric_input = el => el.type === "number" || el.type === "range";
|
|
75
|
-
const is_template = el => el
|
|
75
|
+
const is_template = el => el.matches("template");
|
|
76
76
|
const is_element = el => el.nodeType === Node.ELEMENT_NODE;
|
|
77
77
|
const as_array = value => is_array(value) ? value : [value];
|
|
78
78
|
const loose_equal = (a, b) => a == b;
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
if (initialized || (options?.immediate ?? true)) {
|
|
130
|
-
|
|
130
|
+
// Prevent the watcher from detecting its own dependencies.
|
|
131
131
|
setTimeout(() => {
|
|
132
132
|
callback(new_value, old_value);
|
|
133
133
|
old_value = new_value;
|
|
@@ -151,10 +151,10 @@
|
|
|
151
151
|
"group");
|
|
152
152
|
|
|
153
153
|
function plugin$5({ directive, entangle, evaluateLater, mapAttributes, mutateDom, prefixed }) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
// creating a shortcut for the directive,
|
|
155
|
+
// when an attribute name starting with & will refer to our directive,
|
|
156
|
+
// allowing us to write like this: &value="prop",
|
|
157
|
+
// which is equivalent to x-bound:value="prop"
|
|
158
158
|
mapAttributes(attr => ({
|
|
159
159
|
name: attr.name.replace(/^&/, prefixed("bound:")),
|
|
160
160
|
value: attr.value
|
|
@@ -170,8 +170,8 @@
|
|
|
170
170
|
|
|
171
171
|
expression = expression?.trim();
|
|
172
172
|
|
|
173
|
-
|
|
174
|
-
|
|
173
|
+
// since attributes come in a lowercase,
|
|
174
|
+
// we need to convert the bound property name to its canonical form
|
|
175
175
|
const property_name = canonical_names.get(value.trim().replace("-", "").toLowerCase());
|
|
176
176
|
|
|
177
177
|
// if the expression is omitted, then we assume it corresponds
|
|
@@ -228,7 +228,7 @@
|
|
|
228
228
|
break;
|
|
229
229
|
|
|
230
230
|
case "open":
|
|
231
|
-
|
|
231
|
+
process_open_attribute();
|
|
232
232
|
break;
|
|
233
233
|
|
|
234
234
|
case "group":
|
|
@@ -282,8 +282,8 @@
|
|
|
282
282
|
switch (tag_name) {
|
|
283
283
|
case "INPUT":
|
|
284
284
|
case "TEXTAREA":
|
|
285
|
-
|
|
286
|
-
|
|
285
|
+
// if the value of the bound property is "null" or "undefined",
|
|
286
|
+
// we initialize it with the value from the element.
|
|
287
287
|
is_nullish(get_value()) && update_variable();
|
|
288
288
|
|
|
289
289
|
effect(update_property);
|
|
@@ -293,16 +293,16 @@
|
|
|
293
293
|
break;
|
|
294
294
|
|
|
295
295
|
case "SELECT":
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
296
|
+
// WORKAROUND:
|
|
297
|
+
// For the "select" element, there might be a situation
|
|
298
|
+
// where options are generated dynamically using the "x-for" directive,
|
|
299
|
+
// and in this case, attempting to set the "value" property
|
|
300
|
+
// will have no effect since there are no options yet.
|
|
301
|
+
// Therefore, we use a small trick to set the value a bit later
|
|
302
|
+
// when the "x-for" directive has finished its work.
|
|
303
303
|
setTimeout(() => {
|
|
304
|
-
|
|
305
|
-
|
|
304
|
+
// if the value of the bound property is "null" or "undefined",
|
|
305
|
+
// we initialize it with the value from the element.
|
|
306
306
|
is_nullish(get_value()) && update_variable();
|
|
307
307
|
|
|
308
308
|
effect(() => apply_select_values(el, as_array(get_value() ?? [])));
|
|
@@ -364,13 +364,29 @@
|
|
|
364
364
|
processed = true;
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
-
function
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
367
|
+
function process_open_attribute() {
|
|
368
|
+
const [is_details, is_dialog] = [tag_name === "DETAILS", tag_name === "DIALOG"];
|
|
369
|
+
|
|
370
|
+
if (is_details || is_dialog) {
|
|
371
|
+
//
|
|
372
|
+
// <details>:
|
|
373
|
+
// Supports safe two-way binding via the "open" attribute,
|
|
374
|
+
// so we initialize from the element only if the bound value
|
|
375
|
+
// is null or undefined.
|
|
376
|
+
//
|
|
377
|
+
// <dialog>:
|
|
378
|
+
// Directly setting element.open is discouraged by the spec,
|
|
379
|
+
// as it breaks native dialog behavior and the "close" event.
|
|
380
|
+
// Therefore, we always initialize state from the element
|
|
381
|
+
// and treat it as a one-way source of truth.
|
|
382
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/open#value
|
|
383
|
+
//
|
|
384
|
+
(is_dialog || is_nullish(get_value())) && update_variable();
|
|
385
|
+
|
|
386
|
+
//
|
|
387
|
+
// Enable two-way binding only for "<details>"
|
|
388
|
+
//
|
|
389
|
+
is_details && effect(update_property);
|
|
374
390
|
cleanup(listen(el, "toggle", update_variable));
|
|
375
391
|
processed = true;
|
|
376
392
|
}
|
|
@@ -458,19 +474,19 @@
|
|
|
458
474
|
|
|
459
475
|
case Node.ELEMENT_NODE:
|
|
460
476
|
if (node !== el) {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
477
|
+
//
|
|
478
|
+
// When we encounter an element with the "x-data" attribute, its properties
|
|
479
|
+
// are not yet initialized, and the Alpine context is unavailable.
|
|
480
|
+
// Attempting to use these properties will result in
|
|
481
|
+
// an "Alpine Expression Error: [expression] is not defined".
|
|
482
|
+
//
|
|
483
|
+
// Workaround:
|
|
484
|
+
// To avoid this, we manually add our "x-format" directive to the element.
|
|
485
|
+
// Alpine evaluates "x-format" directive once the context is initialized.
|
|
486
|
+
// In the current loop, we skip these elements to defer their processing.
|
|
487
|
+
//
|
|
488
|
+
// This also handles cases where the user manually adds the "x-format" attribute.
|
|
489
|
+
//
|
|
474
490
|
if (node.hasAttribute("x-data") && !has_format_attr(node)) {
|
|
475
491
|
node.setAttribute("x-format", "");
|
|
476
492
|
}
|
|
@@ -662,11 +678,11 @@
|
|
|
662
678
|
return;
|
|
663
679
|
}
|
|
664
680
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
681
|
+
// Adding a queued task ensures asynchronous content update, allowing Alpine.js
|
|
682
|
+
// to handle context propagation for cloned elements properly.
|
|
683
|
+
// This is important because manipulation can occur within the mutateDom function
|
|
684
|
+
// when mutation observing is disabled, preventing proper context propagation
|
|
685
|
+
// for cloned elements.
|
|
670
686
|
queueMicrotask(() => {
|
|
671
687
|
el.innerHTML = "";
|
|
672
688
|
el.append(tpl.content.cloneNode(true));
|
|
@@ -700,4 +716,4 @@
|
|
|
700
716
|
|
|
701
717
|
document.addEventListener("alpine:init", () => { Alpine.plugin(__main); });
|
|
702
718
|
|
|
703
|
-
})();
|
|
719
|
+
})();
|
package/alpinegear-main.min.js
CHANGED
|
@@ -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 o=e(...t);return e=>{let t;n(e=>t=e),function(e){return"function"==typeof e?.set}(t)?t.set(e):o(()=>{},{scope:{__val:e}})}}const n=Symbol();let o;const a=(...e)=>console.warn("alpinegear.js:",...e),i=Array.isArray,r=e=>null==e,c=e=>"checkbox"===e.type||"radio"===e.type,l=e=>e
|
|
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 o=e(...t);return e=>{let t;n(e=>t=e),function(e){return"function"==typeof e?.set}(t)?t.set(e):o(()=>{},{scope:{__val:e}})}}const n=Symbol();let o;const a=(...e)=>console.warn("alpinegear.js:",...e),i=Array.isArray,r=e=>null==e,c=e=>"checkbox"===e.type||"radio"===e.type,l=e=>e.matches("template"),u=e=>e.nodeType===Node.ELEMENT_NODE,s=e=>i(e)?e:[e],d=(e,t)=>e==t,f=(e,t)=>e.findIndex(e=>e==t),p=(e,t)=>e.includes(t),m=(e,t,n,o)=>(e.addEventListener(t,n,o),()=>e.removeEventListener(t,n,o)),v=e=>"object"==typeof e?JSON.parse(JSON.stringify(e)):e;function h(e,t,n=null){const{effect:o,release:a}=Alpine;let i,r,c=!1;const l=o(()=>{i=e(),c||(n?.deep&&JSON.stringify(i),r=i),(c||(n?.immediate??1))&&setTimeout(()=>{t(i,r),r=i},0),c=!0});return()=>a(l)}const b=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(e,t,{addScopeToNode:n,cleanup:o,initTree:a,mutateDom:i,scope:r={}}){if(e._r_block)return;document.body._r_block??=(()=>{const e=new MutationObserver(e=>{for(let t of e)for(let e of t.addedNodes)e._r_block?.update()});return e.observe(document.body,{childList:!0,subtree:!0}),e})();let c=l(t)?[...t.content.cloneNode(!0).childNodes]:[t.cloneNode(!0)];i(()=>{for(let t of c)u(t)&&n(t,r,e),e.parentElement.insertBefore(t,e),u(t)&&a(t)}),e._r_block={template:t,update(){i(()=>{for(let t of c??[])e.parentElement.insertBefore(t,e)})},delete(){e._r_block=null;for(let e of c??[])e.remove();c=null}},o(()=>e._r_block?.delete())}function x(u){(function({directive:l,entangle:u,evaluateLater:g,mapAttributes:x,mutateDom:T,prefixed:_}){x(e=>({name:e.name.replace(/^&/,_("bound:")),value:e.value})),l("bound",(l,{expression:x,value:_,modifiers:k},{effect:N,cleanup:y})=>{if(!_)return void a("x-bound directive expects the presence of a bound property name");const E=l.tagName.toUpperCase();x=x?.trim();const L=b.get(_.trim().replace("-","").toLowerCase());x||=L;const D=e(g,l,x),S=t(g,l,x),w=()=>d(l[L],D())||T(()=>l[L]=D()),A=()=>S((e=>"number"===e.type||"range"===e.type)(l)?function(e){return""===e?null:+e}(l[L]):l[L]);let H;switch(L){case"value":!function(){switch(E){case"INPUT":case"TEXTAREA":r(D())&&A(),N(w),y(m(l,"input",A)),H=!0;break;case"SELECT":setTimeout(()=>{r(D())&&A(),N(()=>function(e,t){for(const n of e.options)n.selected=f(t,n.value)>=0}(l,s(D()??[]))),y(m(l,"change",()=>S(function(e){return e.multiple?[...e.selectedOptions].map(e=>e.value):e.value}(l))))},0),H=!0}}();break;case"checked":c(l)&&(N(w),y(m(l,"change",A)),H=!0);break;case"files":"file"===l.type&&(D()instanceof FileList||A(),N(w),y(m(l,"input",A)),H=!0);break;case"innerHTML":case"innerText":case"textContent":"true"===l.contentEditable&&(r(D())&&A(),N(w),y(m(l,"input",A)),H=!0);break;case"videoHeight":case"videoWidth":O("VIDEO","resize");break;case"naturalHeight":case"naturalWidth":O("IMG","load");break;case"clientHeight":case"clientWidth":case"offsetHeight":case"offsetWidth":y(function(e,t){return o??=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),o.observe(e),()=>{e[n].delete(t),e[n].size||(o.unobserve(e),e[n]=null)}}(l,A)),H=!0;break;case"indeterminate":"checkbox"===l.type&&(r(D())&&A(),N(w),y(m(l,"change",A)),H=!0);break;case"open":!function(){const[e,t]=["DETAILS"===E,"DIALOG"===E];(e||t)&&((t||r(D()))&&A(),e&&N(w),y(m(l,"toggle",A)),H=!0)}();break;case"group":c(l)&&(l.name||T(()=>l.name=x),N(()=>T(()=>function(e,t){e.checked=i(t)?f(t,e.value)>=0:d(e.value,t)}(l,D()??[]))),y(m(l,"input",()=>S(function(e,t){if("radio"===e.type)return e.value;t=s(t);const n=f(t,e.value);return e.checked?n>=0||t.push(e.value):n>=0&&t.splice(n,1),t}(l,D())))),H=!0)}if(!H){const n=p(k,"in")?"in":p(k,"out")?"out":"inout",o=x===_?((e,t)=>{for(;e&&!t(e);)e=(e._x_teleportBack??e).parentElement;return e})(l.parentNode,e=>e._x_dataStack):l;if(!l._x_dataStack)return void a("x-bound directive requires the presence of the x-data directive to bind component properties");if(!o)return void a(`x-bound directive cannot find the parent scope where the '${_}' property is defined`);const i={get:e(g,o,x),set:t(g,o,x)},r={get:e(g,l,_),set:t(g,l,_)};switch(n){case"in":y(h(()=>i.get(),e=>r.set(v(e))));break;case"out":y(h(()=>r.get(),e=>i.set(v(e))));break;default:y(u(i,r))}}function O(e,t){E===e&&(A(),y(m(l,t,A)),H=!0)}})})(u),function({directive:t,evaluateLater:n,mutateDom:o}){t("format",(t,{modifiers:a},{effect:i})=>{const r=/{{(?<expr>.+?)}}/g,c=p(a,"once"),l=e=>e.hasAttribute("x-format");function u(e){c?o(()=>e()):i(()=>o(()=>e()))}!function a(i){switch(i.nodeType){case Node.TEXT_NODE:!function(t){const a=t.textContent.split(r);if(a.length>1){const i=new DocumentFragment;for(let o=0;a.length>o;o++)if(o%2==0)i.appendChild(document.createTextNode(a[o]));else{const r=e(n,t.parentNode,a[o]),c=document.createTextNode("");i.append(c),u(()=>c.textContent=r())}o(()=>t.parentElement.replaceChild(i,t))}}(i);break;case Node.ELEMENT_NODE:if(i!==t&&(i.hasAttribute("x-data")&&!l(i)&&i.setAttribute("x-format",""),l(i)))break;!function(e){for(let t of e.childNodes)a(t)}(i),function(t){for(let o of t.attributes)if([...o.value.matchAll(r)].length){const a=o.value;u(()=>o.value=a.replace(r,(o,a)=>e(n,t,a)()))}}(i)}}(t)})}(u),function({addScopeToNode:e,directive:t,initTree:n,mutateDom:o}){t("fragment",(t,{},{cleanup:i})=>{l(t)?g(t,t,{addScopeToNode:e,cleanup:i,initTree:n,mutateDom:o}):a("x-fragment can only be used on a 'template' tag")})}(u),function({addScopeToNode:t,directive:n,initTree:o,mutateDom:i}){n("match",(n,{},{cleanup:r,effect:c,evaluateLater:u})=>{if(!l(n))return void a("x-match can only be used on a 'template' tag");const s=[];for(let t of n.content.children){const n=t.getAttribute("x-case");null!==n?s.push({el:t,get_value:e(u,n)}):t.hasAttribute("x-default")&&s.push({el:t,get_value:()=>!0,default:!0})}const d=()=>n._r_block?.delete();c(()=>{let e;for(let t of s)t.get_value()&&!e&&(e=t);var a;e?(a=e,n._r_block?.template!==a.el&&(d(),g(n,a.el,{addScopeToNode:t,cleanup:r,initTree:o,mutateDom:i}))):d()})})}(u),function(e){e.directive("template",(e,{expression:t})=>{if(l(e))return void a("x-template cannot be used on a 'template' tag");const n=document.getElementById(t);l(n)?queueMicrotask(()=>{e.innerHTML="",e.append(n.content.cloneNode(!0))}):a("x-template directive can only reference the template tag")})}(u),function({addScopeToNode:t,directive:n,initTree:o,mutateDom:i}){n("when",(n,{expression:r},{cleanup:c,effect:u,evaluateLater:s})=>{if(!l(n))return void a("x-when can only be used on a 'template' tag");const d=e(s,r);u(()=>d()?g(n,n,{addScopeToNode:t,cleanup:c,initTree:o,mutateDom:i}):n._r_block?.delete())})}(u)}document.addEventListener("alpine:init",()=>{Alpine.plugin(x)})}();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ramstack/alpinegear-main",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "@ramstack/alpinegear-main is a combined plugin that includes several Alpine.js directives, providing a convenient all-in-one package.",
|
|
5
5
|
"author": "Rameel Burhan",
|
|
6
6
|
"license": "MIT",
|