sprae 5.3.0 → 6.1.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/sprae.js CHANGED
@@ -375,19 +375,6 @@ secondary["value"] = (el, expr) => {
375
375
  } : (value) => el.value = value;
376
376
  return (state2) => update(evaluate(state2));
377
377
  };
378
- secondary["on"] = (el, expr) => {
379
- let evaluate = parseExpr(el, expr, ":on");
380
- return (state2) => {
381
- let listeners = evaluate(state2);
382
- let offs = [];
383
- for (let evt in listeners)
384
- offs.push(on(el, evt, listeners[evt]));
385
- return () => {
386
- for (let off of offs)
387
- off();
388
- };
389
- };
390
- };
391
378
  var directives_default = (el, expr, state2, name) => {
392
379
  let evt = name.startsWith("on") && name.slice(2);
393
380
  let evaluate = parseExpr(el, expr, ":" + name);
@@ -401,43 +388,20 @@ var directives_default = (el, expr, state2, name) => {
401
388
  };
402
389
  return (state3) => attr(el, name, evaluate(state3));
403
390
  };
404
- var on = (target, evt, origFn) => {
405
- if (!origFn)
391
+ var on = (el, e, fn) => {
392
+ if (!fn)
406
393
  return;
407
- let ctxs = evt.split("..").map((e) => {
408
- let ctx = { evt: "", target, test: () => true };
409
- ctx.evt = (e.startsWith("on") ? e.slice(2) : e).replace(
410
- /\.(\w+)?-?([-\w]+)?/g,
411
- (match, mod, param = "") => (ctx.test = mods[mod]?.(ctx, ...param.split("-")) || ctx.test, "")
412
- );
413
- return ctx;
414
- });
415
- if (ctxs.length == 1)
416
- return addListenerWithMods(origFn, ctxs[0]);
417
- const onFn = (fn, cur = 0) => {
418
- let off;
419
- let curListener = (e) => {
420
- if (cur)
421
- off();
422
- let nextFn = fn.call(target, e);
423
- if (typeof nextFn !== "function")
424
- nextFn = () => {
425
- };
426
- if (cur + 1 < ctxs.length)
427
- onFn(nextFn, !cur ? 1 : cur + 1);
428
- };
429
- return off = addListenerWithMods(curListener, ctxs[cur]);
430
- };
431
- let rootOff = onFn(origFn);
432
- return () => rootOff();
433
- function addListenerWithMods(fn, { evt: evt2, target: target2, test, defer, stop, prevent, ...opts }) {
434
- if (defer)
435
- fn = defer(fn);
436
- let cb = (e) => test(e) && (stop && e.stopPropagation(), prevent && e.preventDefault(), fn.call(target2, e));
437
- target2.addEventListener(evt2, cb, opts);
438
- return () => target2.removeEventListener(evt2, cb, opts);
439
- }
440
- ;
394
+ const ctx = { evt: "", target: el, test: () => true };
395
+ ctx.evt = (e.startsWith("on") ? e.slice(2) : e).replace(
396
+ /\.(\w+)?-?([-\w]+)?/g,
397
+ (match, mod, param = "") => (ctx.test = mods[mod]?.(ctx, ...param.split("-")) || ctx.test, "")
398
+ );
399
+ const { evt, target, test, defer, stop, prevent, ...opts } = ctx;
400
+ if (defer)
401
+ fn = defer(fn);
402
+ const cb = (e2) => test(e2) && (stop && e2.stopPropagation(), prevent && e2.preventDefault(), fn.call(target, e2));
403
+ target.addEventListener(evt, cb, opts);
404
+ return () => target.removeEventListener(evt, cb, opts);
441
405
  };
442
406
  var mods = {
443
407
  prevent(ctx) {
@@ -461,9 +425,6 @@ var mods = {
461
425
  document(ctx) {
462
426
  ctx.target = document;
463
427
  },
464
- toggle(ctx) {
465
- ctx.defer = (fn, out) => (e) => out ? (out.call?.(ctx.target, e), out = null) : out = fn();
466
- },
467
428
  throttle(ctx, limit) {
468
429
  ctx.defer = (fn) => throttle(fn, limit ? Number(limit) || 0 : 108);
469
430
  },
@@ -548,9 +509,8 @@ var evaluatorMemo = {};
548
509
  function parseExpr(el, expression, dir) {
549
510
  let evaluate = evaluatorMemo[expression];
550
511
  if (!evaluate) {
551
- let rightSideSafeExpression = /^[\n\s]*if.*\(.*\)/.test(expression) || /\b(let|const)\s/.test(expression) && !dir.startsWith(":on") ? `(() => {${expression}})()` : expression;
552
512
  try {
553
- evaluate = evaluatorMemo[expression] = new Function(`__scope`, `with (__scope) { return ${rightSideSafeExpression.trim()} };`);
513
+ evaluate = evaluatorMemo[expression] = new Function(`__scope`, `with (__scope) { return ${expression.trim()} };`);
554
514
  } catch (e) {
555
515
  return exprError(e, el, expression, dir);
556
516
  }
@@ -605,18 +565,18 @@ function sprae(container, values) {
605
565
  }
606
566
  if (el.attributes) {
607
567
  for (let i = 0; i < el.attributes.length; ) {
608
- let attr2 = el.attributes[i];
609
- if (attr2.name[0] !== ":") {
568
+ let attr2 = el.attributes[i], prefix = attr2.name[0];
569
+ if (prefix === ":" || prefix === "@") {
570
+ el.removeAttribute(attr2.name);
571
+ let expr = prefix === "@" ? `event=>{${attr2.value}}` : attr2.value, names = attr2.name.slice(1).split(prefix);
572
+ for (let name of names) {
573
+ if (prefix === "@")
574
+ name = `on` + name;
575
+ let dir = secondary[name] || directives_default;
576
+ updates.push(dir(el, expr, state2, name));
577
+ }
578
+ } else
610
579
  i++;
611
- continue;
612
- }
613
- el.removeAttribute(attr2.name);
614
- let expr = attr2.value;
615
- let attrNames = attr2.name.slice(1).split(":");
616
- for (let attrName of attrNames) {
617
- let dir = secondary[attrName] || directives_default;
618
- updates.push(dir(el, expr, state2, attrName));
619
- }
620
580
  }
621
581
  }
622
582
  for (let i = 0, child; child = el.children[i]; i++) {
package/sprae.min.js CHANGED
@@ -1 +1 @@
1
- var e,t,r=Promise.prototype.then.bind(Promise.resolve()),n=new WeakMap,l=class extends Map{#e=new FinalizationRegistry((e=>super.delete(e)));get size(){return[...this].length}constructor(e=[]){super();for(const[t,r]of e)this.set(t,r)}get(e){return super.get(e)?.deref()}set(e,t){let r=super.get(e);return r&&this.#e.unregister(r),r=(e=>n.get(e)||(e=>{const t=new WeakRef(e);return n.set(e,t),t})(e))(t),this.#e.register(t,e,r),super.set(e,r)}},s=new Set,i=new WeakMap,o=new WeakMap,a=new WeakMap,u=Symbol("parent"),c={Array:Array,Object:Object,Number:Number,String:String,Boolean:Boolean,Date:Date,console:console,window:window,document:document,history:history,location:location},f={has:()=>!0,get(t,r){if("symbol"==typeof r)return t[r];if(!(r in t))return t[u]?.[r];if(r in Object.prototype||Array.isArray(t)&&r in Array.prototype&&"length"!==r)return t[r];let n=t[r];if(e){let n=i.get(t);n||i.set(t,n={}),n[r]?n[r].includes(e)||n[r].push(e):n[r]=[e]}if(n&&n.constructor===Object||Array.isArray(n)){let e=o.get(n);return e||o.set(n,e=new Proxy(n,f)),e}return n},set(e,t,r){if(!(t in e)&&e[u]&&t in e[u])return e[u][t]=r;if(!Array.isArray(e)&&Object.is(e[t],r))return!0;e[t]=r;let n=i.get(e)?.[t];if(n)for(let e of n)s.add(e);return h(),!0},deleteProperty:(e,t)=>(e[t]=void 0,delete e[t],!0)},p=(e,t)=>{if(o.has(e))return o.get(e);if(a.has(e))return e;let r=new Proxy(e,f);o.set(e,r),a.set(r,e);let n=Object.getOwnPropertyDescriptors(e);for(let t in n){let l=n[t];l.get&&l.get&&(l.get=l.get.bind(r),Object.defineProperty(e,t,l))}return e[u]=t?p(t):c,r},y=t=>{const r=()=>{let n=e;e=r,t(),e=n};return r(),r},h=()=>{t||(t=!0,r((()=>{for(let e of s)e.call();s.clear(),t=!1})))},g={},d={};g.if=(e,t)=>{let r=document.createTextNode(""),n=[j(e,t,":if")],l=[e],s=e;for(;(s=e.nextElementSibling)&&s.hasAttribute(":else");)s.removeAttribute(":else"),(t=s.getAttribute(":if"))?(s.removeAttribute(":if"),s.remove(),l.push(s),n.push(j(e,t,":else :if"))):(s.remove(),l.push(s),n.push((()=>1)));return e.replaceWith(s=r),e=>{let t=n.findIndex((t=>t(e)));l[t]!=s&&((s[m]||s).replaceWith(s=l[t]||r),O(s,e))}};var m=Symbol(":each");g.each=(e,t)=>{let r=function(e){let t=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,r=e.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!r)return;let n=r[2].trim(),l=r[1].replace(/^\s*\(|\)\s*$/g,"").trim(),s=l.match(t);return s?[l.replace(t,"").trim(),s[1].trim(),n]:[l,"",n]}(t);if(!r)return E(new Error,e,t,":each");const n=e[m]=document.createTextNode("");e.replaceWith(n);const s=j(e,r[2],":each"),i=e.getAttribute(":key"),o=i?j(null,i,":each"):null;e.removeAttribute(":key");const a=e.getAttribute(":ref"),u=new l,c=new l;let f=[];return l=>{let i=s(l);i?"number"==typeof i?i=Array.from({length:i},((e,t)=>[t+1,t])):Array.isArray(i)?i=i.map(((e,t)=>[t+1,e])):"object"==typeof i?i=Object.entries(i):E(Error("Bad list value"),e,t,":each"):i=[];let y=[],h=[];for(let[t,n]of i){let s,i,f=o?.({[r[0]]:n,[r[1]]:t});null==f?s=e.cloneNode(!0):(s=c.get(f))||c.set(f,s=e.cloneNode(!0)),y.push(s),null!=f&&(i=u.get(f))?i[r[0]]=n:(i=p({[r[0]]:n,[a||""]:null,[r[1]]:t},l),null!=f&&u.set(f,i)),h.push(i)}!function(e,t,r,n){const l=new Map,s=new Map;let i,o;for(i=0;i<t.length;i++)l.set(t[i],i);for(i=0;i<r.length;i++)s.set(r[i],i);for(i=o=0;i!==t.length||o!==r.length;){var a=t[i],u=r[o];if(null===a)i++;else if(r.length<=o)e.removeChild(t[i]),i++;else if(t.length<=i)e.insertBefore(u,t[i]||n),o++;else if(a===u)i++,o++;else{var c=s.get(a),f=l.get(u);void 0===c?(e.removeChild(t[i]),i++):void 0===f?(e.insertBefore(u,t[i]||n),o++):(e.insertBefore(t[f],t[i]||n),t[f]=null,f>i+1&&i++,o++)}}}(n.parentNode,f,y,n),f=y;for(let e=0;e<y.length;e++)O(y[e],h[e])}},g.with=(e,t,r)=>{const n=j(e,t,":with")(r);O(e,p(n,r))},g.ref=(e,t,r)=>{r[t]=e},d.render=(e,t,r)=>{let n=j(e,t,":render")(r);n||E(new Error("Template not found"),e,t,":render");let l=n.content.cloneNode(!0);e.replaceChildren(l),O(e,r)},d.id=(e,t)=>{let r=j(e,t,":id");return t=>{return n=r(t),e.id=n||0===n?n:"";var n}},d.class=(e,t)=>{let r=j(e,t,":class"),n=e.getAttribute("class");return t=>{let l=r(t),s=[n];l&&("string"==typeof l?s.push(l):Array.isArray(l)?s.push(...l):s.push(...Object.entries(l).map((([e,t])=>t?e:"")))),(s=s.filter(Boolean).join(" "))?e.setAttribute("class",s):e.removeAttribute("class")}},d.style=(e,t)=>{let r=j(e,t,":style"),n=e.getAttribute("style")||"";return n.endsWith(";")||(n+="; "),t=>{let l=r(t);if("string"==typeof l)e.setAttribute("style",n+l);else{e.setAttribute("style",n);for(let t in l)e.style.setProperty(t,l[t])}}},d.text=(e,t)=>{let r=j(e,t,":text");return t=>{let n=r(t);e.textContent=null==n?"":n}},d[""]=(e,t)=>{let r=j(e,t,":");if(r)return t=>{let n=r(t);for(let t in n)x(e,t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase())),n[t])}},d.value=(e,t)=>{let r,n,l=j(e,t,":value"),s="text"===e.type||""===e.type?t=>e.setAttribute("value",e.value=null==t?"":t):"TEXTAREA"===e.tagName||"text"===e.type||""===e.type?t=>(r=e.selectionStart,n=e.selectionEnd,e.setAttribute("value",e.value=null==t?"":t),r&&e.setSelectionRange(r,n)):"checkbox"===e.type?t=>(e.value=t?"on":"",x(e,"checked",t)):"select-one"===e.type?t=>{for(let t in e.options)t.removeAttribute("selected");e.value=t,e.selectedOptions[0]?.setAttribute("selected","")}:t=>e.value=t;return e=>s(l(e))},d.on=(e,t)=>{let r=j(e,t,":on");return t=>{let n=r(t),l=[];for(let t in n)l.push(v(e,t,n[t]));return()=>{for(let e of l)e()}}};var b=(e,t,r,n)=>{let l=n.startsWith("on")&&n.slice(2),s=j(e,t,":"+n);if(s)return l?t=>{let r=s(t)||(()=>{});return v(e,l,r)}:t=>x(e,n,s(t))},v=(e,t,r)=>{if(!r)return;let n=t.split("..").map((t=>{let r={evt:"",target:e,test:()=>!0};return r.evt=(t.startsWith("on")?t.slice(2):t).replace(/\.(\w+)?-?([-\w]+)?/g,((e,t,n="")=>(r.test=A[t]?.(r,...n.split("-"))||r.test,""))),r}));if(1==n.length)return i(r,n[0]);const l=(t,r=0)=>{let s;return s=i((i=>{r&&s();let o=t.call(e,i);"function"!=typeof o&&(o=()=>{}),r+1<n.length&&l(o,r?r+1:1)}),n[r])};let s=l(r);return()=>s();function i(e,{evt:t,target:r,test:n,defer:l,stop:s,prevent:i,...o}){l&&(e=l(e));let a=t=>n(t)&&(s&&t.stopPropagation(),i&&t.preventDefault(),e.call(r,t));return r.addEventListener(t,a,o),()=>r.removeEventListener(t,a,o)}},A={prevent(e){e.prevent=!0},stop(e){e.stop=!0},once(e){e.once=!0},passive(e){e.passive=!0},capture(e){e.capture=!0},window(e){e.target=window},document(e){e.target=document},toggle(e){e.defer=(t,r)=>n=>r?(r.call?.(e.target,n),r=null):r=t()},throttle(e,t){e.defer=e=>k(e,t?Number(t)||0:108)},debounce(e,t){e.defer=e=>W(e,t?Number(t)||0:108)},outside:e=>t=>{let r=e.target;return!(r.contains(t.target)||!1===t.target.isConnected||r.offsetWidth<1&&r.offsetHeight<1)},self:e=>t=>t.target===e.target,ctrl:(e,...t)=>e=>w.ctrl(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),shift:(e,...t)=>e=>w.shift(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),alt:(e,...t)=>e=>w.alt(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),meta:(e,...t)=>e=>w.meta(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),arrow:e=>w.arrow,enter:e=>w.enter,escape:e=>w.escape,tab:e=>w.tab,space:e=>w.space,backspace:e=>w.backspace,delete:e=>w.delete,digit:e=>w.digit,letter:e=>w.letter,character:e=>w.character},w={ctrl:e=>e.ctrlKey||"Control"===e.key||"Ctrl"===e.key,shift:e=>e.shiftKey||"Shift"===e.key,alt:e=>e.altKey||"Alt"===e.key,meta:e=>e.metaKey||"Meta"===e.key||"Command"===e.key,arrow:e=>e.key.startsWith("Arrow"),enter:e=>"Enter"===e.key,escape:e=>e.key.startsWith("Esc"),tab:e=>"Tab"===e.key,space:e=>" "===e.key||"Space"===e.key||" "===e.key,backspace:e=>"Backspace"===e.key,delete:e=>"Delete"===e.key,digit:e=>/^\d$/.test(e.key),letter:e=>/^[a-zA-Z]$/.test(e.key),character:e=>/^\S$/.test(e.key)},k=(e,t)=>{let r,n,l=s=>{r=!0,setTimeout((()=>{if(r=!1,n)return n=!1,l(s),e(s)}),t)};return t=>r?n=!0:(l(t),e(t))},W=(e,t)=>{let r;return n=>{clearTimeout(r),r=setTimeout((()=>{r=null,e(n)}),t)}},x=(e,t,r)=>{null==r||!1===r?e.removeAttribute(t):e.setAttribute(t,!0===r?"":"number"==typeof r||"string"==typeof r?r:"")},S={};function j(e,t,r){let n=S[t];if(!n){let l=/^[\n\s]*if.*\(.*\)/.test(t)||/\b(let|const)\s/.test(t)&&!r.startsWith(":on")?`(() => {${t}})()`:t;try{n=S[t]=new Function("__scope",`with (__scope) { return ${l.trim()} };`)}catch(n){return E(n,e,t,r)}}return l=>{let s;try{s=n.call(e,l)}catch(n){return E(n,e,t,r)}return s}}function E(e,t,n,l){Object.assign(e,{element:t,expression:n}),console.warn(`∴ ${e.message}\n\n${l}=${n?`"${n}"\n\n`:""}`,t),r((()=>{throw e}),0)}O.globals=c;var N=new WeakMap;function O(e,t){if(!e.children)return;if(N.has(e))return Object.assign(N.get(e),t);const r=p(t||{}),n=[],l=(e,t=e.parentNode)=>{for(let l in g){let s=":"+l;if(e.hasAttribute?.(s)){let i=e.getAttribute(s);if(e.removeAttribute(s),n.push(g[l](e,i,r,l)),N.has(e))return;if(e.parentNode!==t)return!1}}if(e.attributes)for(let t=0;t<e.attributes.length;){let l=e.attributes[t];if(":"!==l.name[0]){t++;continue}e.removeAttribute(l.name);let s=l.value,i=l.name.slice(1).split(":");for(let t of i){let l=d[t]||b;n.push(l(e,s,r,t))}}for(let t,r=0;t=e.children[r];r++)!1===l(t,e)&&r--};l(e);for(let e of n)if(e){let t;y((()=>{"function"==typeof t&&t(),t=e(r)}))}return N.set(e,r),r}var $=O;document.currentScript&&O(document.documentElement);export{$ as default};
1
+ var e,t,r=Promise.prototype.then.bind(Promise.resolve()),n=new WeakMap,l=class extends Map{#e=new FinalizationRegistry((e=>super.delete(e)));get size(){return[...this].length}constructor(e=[]){super();for(const[t,r]of e)this.set(t,r)}get(e){return super.get(e)?.deref()}set(e,t){let r=super.get(e);return r&&this.#e.unregister(r),r=(e=>n.get(e)||(e=>{const t=new WeakRef(e);return n.set(e,t),t})(e))(t),this.#e.register(t,e,r),super.set(e,r)}},s=new Set,i=new WeakMap,o=new WeakMap,a=new WeakMap,u=Symbol("parent"),c={Array:Array,Object:Object,Number:Number,String:String,Boolean:Boolean,Date:Date,console:console,window:window,document:document,history:history,location:location},f={has:()=>!0,get(t,r){if("symbol"==typeof r)return t[r];if(!(r in t))return t[u]?.[r];if(r in Object.prototype||Array.isArray(t)&&r in Array.prototype&&"length"!==r)return t[r];let n=t[r];if(e){let n=i.get(t);n||i.set(t,n={}),n[r]?n[r].includes(e)||n[r].push(e):n[r]=[e]}if(n&&n.constructor===Object||Array.isArray(n)){let e=o.get(n);return e||o.set(n,e=new Proxy(n,f)),e}return n},set(e,t,r){if(!(t in e)&&e[u]&&t in e[u])return e[u][t]=r;if(!Array.isArray(e)&&Object.is(e[t],r))return!0;e[t]=r;let n=i.get(e)?.[t];if(n)for(let e of n)s.add(e);return h(),!0},deleteProperty:(e,t)=>(e[t]=void 0,delete e[t],!0)},p=(e,t)=>{if(o.has(e))return o.get(e);if(a.has(e))return e;let r=new Proxy(e,f);o.set(e,r),a.set(r,e);let n=Object.getOwnPropertyDescriptors(e);for(let t in n){let l=n[t];l.get&&l.get&&(l.get=l.get.bind(r),Object.defineProperty(e,t,l))}return e[u]=t?p(t):c,r},y=t=>{const r=()=>{let n=e;e=r,t(),e=n};return r(),r},h=()=>{t||(t=!0,r((()=>{for(let e of s)e.call();s.clear(),t=!1})))},d={},g={};d.if=(e,t)=>{let r=document.createTextNode(""),n=[j(e,t,":if")],l=[e],s=e;for(;(s=e.nextElementSibling)&&s.hasAttribute(":else");)s.removeAttribute(":else"),(t=s.getAttribute(":if"))?(s.removeAttribute(":if"),s.remove(),l.push(s),n.push(j(e,t,":else :if"))):(s.remove(),l.push(s),n.push((()=>1)));return e.replaceWith(s=r),e=>{let t=n.findIndex((t=>t(e)));l[t]!=s&&((s[m]||s).replaceWith(s=l[t]||r),O(s,e))}};var m=Symbol(":each");d.each=(e,t)=>{let r=function(e){let t=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,r=e.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!r)return;let n=r[2].trim(),l=r[1].replace(/^\s*\(|\)\s*$/g,"").trim(),s=l.match(t);return s?[l.replace(t,"").trim(),s[1].trim(),n]:[l,"",n]}(t);if(!r)return E(new Error,e,t,":each");const n=e[m]=document.createTextNode("");e.replaceWith(n);const s=j(e,r[2],":each"),i=e.getAttribute(":key"),o=i?j(null,i,":each"):null;e.removeAttribute(":key");const a=e.getAttribute(":ref"),u=new l,c=new l;let f=[];return l=>{let i=s(l);i?"number"==typeof i?i=Array.from({length:i},((e,t)=>[t+1,t])):Array.isArray(i)?i=i.map(((e,t)=>[t+1,e])):"object"==typeof i?i=Object.entries(i):E(Error("Bad list value"),e,t,":each"):i=[];let y=[],h=[];for(let[t,n]of i){let s,i,f=o?.({[r[0]]:n,[r[1]]:t});null==f?s=e.cloneNode(!0):(s=c.get(f))||c.set(f,s=e.cloneNode(!0)),y.push(s),null!=f&&(i=u.get(f))?i[r[0]]=n:(i=p({[r[0]]:n,[a||""]:null,[r[1]]:t},l),null!=f&&u.set(f,i)),h.push(i)}!function(e,t,r,n){const l=new Map,s=new Map;let i,o;for(i=0;i<t.length;i++)l.set(t[i],i);for(i=0;i<r.length;i++)s.set(r[i],i);for(i=o=0;i!==t.length||o!==r.length;){var a=t[i],u=r[o];if(null===a)i++;else if(r.length<=o)e.removeChild(t[i]),i++;else if(t.length<=i)e.insertBefore(u,t[i]||n),o++;else if(a===u)i++,o++;else{var c=s.get(a),f=l.get(u);void 0===c?(e.removeChild(t[i]),i++):void 0===f?(e.insertBefore(u,t[i]||n),o++):(e.insertBefore(t[f],t[i]||n),t[f]=null,f>i+1&&i++,o++)}}}(n.parentNode,f,y,n),f=y;for(let e=0;e<y.length;e++)O(y[e],h[e])}},d.with=(e,t,r)=>{const n=j(e,t,":with")(r);O(e,p(n,r))},d.ref=(e,t,r)=>{r[t]=e},g.render=(e,t,r)=>{let n=j(e,t,":render")(r);n||E(new Error("Template not found"),e,t,":render");let l=n.content.cloneNode(!0);e.replaceChildren(l),O(e,r)},g.id=(e,t)=>{let r=j(e,t,":id");return t=>{return n=r(t),e.id=n||0===n?n:"";var n}},g.class=(e,t)=>{let r=j(e,t,":class"),n=e.getAttribute("class");return t=>{let l=r(t),s=[n];l&&("string"==typeof l?s.push(l):Array.isArray(l)?s.push(...l):s.push(...Object.entries(l).map((([e,t])=>t?e:"")))),(s=s.filter(Boolean).join(" "))?e.setAttribute("class",s):e.removeAttribute("class")}},g.style=(e,t)=>{let r=j(e,t,":style"),n=e.getAttribute("style")||"";return n.endsWith(";")||(n+="; "),t=>{let l=r(t);if("string"==typeof l)e.setAttribute("style",n+l);else{e.setAttribute("style",n);for(let t in l)e.style.setProperty(t,l[t])}}},g.text=(e,t)=>{let r=j(e,t,":text");return t=>{let n=r(t);e.textContent=null==n?"":n}},g[""]=(e,t)=>{let r=j(e,t,":");if(r)return t=>{let n=r(t);for(let t in n)W(e,t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase())),n[t])}},g.value=(e,t)=>{let r,n,l=j(e,t,":value"),s="text"===e.type||""===e.type?t=>e.setAttribute("value",e.value=null==t?"":t):"TEXTAREA"===e.tagName||"text"===e.type||""===e.type?t=>(r=e.selectionStart,n=e.selectionEnd,e.setAttribute("value",e.value=null==t?"":t),r&&e.setSelectionRange(r,n)):"checkbox"===e.type?t=>(e.value=t?"on":"",W(e,"checked",t)):"select-one"===e.type?t=>{for(let t in e.options)t.removeAttribute("selected");e.value=t,e.selectedOptions[0]?.setAttribute("selected","")}:t=>e.value=t;return e=>s(l(e))};var b=(e,t,r,n)=>{let l=n.startsWith("on")&&n.slice(2),s=j(e,t,":"+n);if(s)return l?t=>{let r=s(t)||(()=>{});return v(e,l,r)}:t=>W(e,n,s(t))},v=(e,t,r)=>{if(!r)return;const n={evt:"",target:e,test:()=>!0};n.evt=(t.startsWith("on")?t.slice(2):t).replace(/\.(\w+)?-?([-\w]+)?/g,((e,t,r="")=>(n.test=A[t]?.(n,...r.split("-"))||n.test,"")));const{evt:l,target:s,test:i,defer:o,stop:a,prevent:u,...c}=n;o&&(r=o(r));const f=e=>i(e)&&(a&&e.stopPropagation(),u&&e.preventDefault(),r.call(s,e));return s.addEventListener(l,f,c),()=>s.removeEventListener(l,f,c)},A={prevent(e){e.prevent=!0},stop(e){e.stop=!0},once(e){e.once=!0},passive(e){e.passive=!0},capture(e){e.capture=!0},window(e){e.target=window},document(e){e.target=document},throttle(e,t){e.defer=e=>k(e,t?Number(t)||0:108)},debounce(e,t){e.defer=e=>x(e,t?Number(t)||0:108)},outside:e=>t=>{let r=e.target;return!(r.contains(t.target)||!1===t.target.isConnected||r.offsetWidth<1&&r.offsetHeight<1)},self:e=>t=>t.target===e.target,ctrl:(e,...t)=>e=>w.ctrl(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),shift:(e,...t)=>e=>w.shift(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),alt:(e,...t)=>e=>w.alt(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),meta:(e,...t)=>e=>w.meta(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),arrow:e=>w.arrow,enter:e=>w.enter,escape:e=>w.escape,tab:e=>w.tab,space:e=>w.space,backspace:e=>w.backspace,delete:e=>w.delete,digit:e=>w.digit,letter:e=>w.letter,character:e=>w.character},w={ctrl:e=>e.ctrlKey||"Control"===e.key||"Ctrl"===e.key,shift:e=>e.shiftKey||"Shift"===e.key,alt:e=>e.altKey||"Alt"===e.key,meta:e=>e.metaKey||"Meta"===e.key||"Command"===e.key,arrow:e=>e.key.startsWith("Arrow"),enter:e=>"Enter"===e.key,escape:e=>e.key.startsWith("Esc"),tab:e=>"Tab"===e.key,space:e=>" "===e.key||"Space"===e.key||" "===e.key,backspace:e=>"Backspace"===e.key,delete:e=>"Delete"===e.key,digit:e=>/^\d$/.test(e.key),letter:e=>/^[a-zA-Z]$/.test(e.key),character:e=>/^\S$/.test(e.key)},k=(e,t)=>{let r,n,l=s=>{r=!0,setTimeout((()=>{if(r=!1,n)return n=!1,l(s),e(s)}),t)};return t=>r?n=!0:(l(t),e(t))},x=(e,t)=>{let r;return n=>{clearTimeout(r),r=setTimeout((()=>{r=null,e(n)}),t)}},W=(e,t,r)=>{null==r||!1===r?e.removeAttribute(t):e.setAttribute(t,!0===r?"":"number"==typeof r||"string"==typeof r?r:"")},S={};function j(e,t,r){let n=S[t];if(!n)try{n=S[t]=new Function("__scope",`with (__scope) { return ${t.trim()} };`)}catch(n){return E(n,e,t,r)}return l=>{let s;try{s=n.call(e,l)}catch(n){return E(n,e,t,r)}return s}}function E(e,t,n,l){Object.assign(e,{element:t,expression:n}),console.warn(`∴ ${e.message}\n\n${l}=${n?`"${n}"\n\n`:""}`,t),r((()=>{throw e}),0)}O.globals=c;var N=new WeakMap;function O(e,t){if(!e.children)return;if(N.has(e))return Object.assign(N.get(e),t);const r=p(t||{}),n=[],l=(e,t=e.parentNode)=>{for(let l in d){let s=":"+l;if(e.hasAttribute?.(s)){let i=e.getAttribute(s);if(e.removeAttribute(s),n.push(d[l](e,i,r,l)),N.has(e))return;if(e.parentNode!==t)return!1}}if(e.attributes)for(let t=0;t<e.attributes.length;){let l=e.attributes[t],s=l.name[0];if(":"===s||"@"===s){e.removeAttribute(l.name);let t="@"===s?`event=>{${l.value}}`:l.value,i=l.name.slice(1).split(s);for(let l of i){"@"===s&&(l="on"+l);let i=g[l]||b;n.push(i(e,t,r,l))}}else t++}for(let t,r=0;t=e.children[r];r++)!1===l(t,e)&&r--};l(e);for(let e of n)if(e){let t;y((()=>{"function"==typeof t&&t(),t=e(r)}))}return N.set(e,r),r}var $=O;document.currentScript&&O(document.documentElement);export{$ as default};
package/src/core.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { state as createState, fx, sandbox } from './state.js';
2
- import defaultDirective, { primary, secondary } from './directives.js';
2
+ import defaultDirective, { primary, secondary, on } from './directives.js';
3
3
 
4
4
  sprae.globals=sandbox
5
5
 
@@ -39,18 +39,23 @@ export default function sprae(container, values) {
39
39
  // catch other attributes as secondary
40
40
  if (el.attributes) {
41
41
  for (let i = 0; i < el.attributes.length;) {
42
- let attr = el.attributes[i]
43
- if (attr.name[0] !== ':') {i++; continue}
44
- el.removeAttribute(attr.name)
45
- let expr = attr.value
42
+ let attr = el.attributes[i], prefix = attr.name[0]
46
43
 
47
- // multiple attributes like :id:for=""
48
- let attrNames = attr.name.slice(1).split(':')
49
- for (let attrName of attrNames) {
50
- let dir = secondary[attrName] || defaultDirective;
51
- updates.push(dir(el, expr, state, attrName));
52
- // NOTE: secondary directives don't stop flow nor extend state, so no need to check
44
+ if (prefix === ':' || prefix === '@') {
45
+ el.removeAttribute(attr.name)
46
+ let expr = prefix === '@' ? `event=>{${attr.value}}` : attr.value,
47
+ names = attr.name.slice(1).split(prefix)
48
+
49
+ // multiple attributes like :id:for="" or @click@touchstart
50
+ for (let name of names) {
51
+ // @click forwards to :onclick=event=>{...inline}
52
+ if (prefix === '@') name = `on` + name
53
+ let dir = secondary[name] || defaultDirective;
54
+ updates.push(dir(el, expr, state, name));
55
+ // NOTE: secondary directives don't stop flow nor extend state, so no need to check
56
+ }
53
57
  }
58
+ else i++;
54
59
  }
55
60
  }
56
61
 
package/src/directives.js CHANGED
@@ -240,18 +240,6 @@ secondary['value'] = (el, expr) => {
240
240
  return (state) => update(evaluate(state))
241
241
  }
242
242
 
243
- secondary['on'] = (el, expr) => {
244
- let evaluate = parseExpr(el, expr, ':on')
245
-
246
- return (state) => {
247
- let listeners = evaluate(state);
248
- let offs = []; for (let evt in listeners) offs.push(on(el, evt, listeners[evt]));
249
- return () => {
250
- for (let off of offs) off()
251
- }
252
- }
253
- }
254
-
255
243
  // any unknown directive
256
244
  export default (el, expr, state, name) => {
257
245
  let evt = name.startsWith('on') && name.slice(2)
@@ -268,50 +256,30 @@ export default (el, expr, state, name) => {
268
256
  return state => attr(el, name, evaluate(state))
269
257
  }
270
258
 
271
- // bind event to target
272
- const on = (target, evt, origFn) => {
273
- if (!origFn) return
274
-
275
- // ona..onb
276
- let ctxs = evt.split('..').map(e => {
277
- let ctx = { evt:'', target, test:()=>true };
278
- // onevt.debounce-108 -> evt.debounce-108
279
- ctx.evt = (e.startsWith('on') ? e.slice(2) : e).replace(/\.(\w+)?-?([-\w]+)?/g,
280
- (match, mod, param='') => (ctx.test = mods[mod]?.(ctx, ...param.split('-')) || ctx.test, '')
281
- );
282
- return ctx;
283
- });
284
-
285
- // single event bind
286
- if (ctxs.length == 1) return addListenerWithMods(origFn, ctxs[0])
287
-
288
- // events chain cycler
289
- const onFn = (fn, cur=0) => {
290
- let off
291
- let curListener = e => {
292
- if (cur) off(); // don't remove entry listener - we must keep chain entry always open
293
- let nextFn = fn.call(target, e)
294
- if (typeof nextFn !== 'function') nextFn = ()=>{}
295
- if (cur+1 < ctxs.length) onFn(nextFn, !cur ? 1 : cur+1);
296
- }
297
- return off = addListenerWithMods(curListener, ctxs[cur])
298
- }
299
- let rootOff = onFn(origFn)
300
- return () => rootOff()
259
+ // bind event to a target
260
+ export const on = (el, e, fn) => {
261
+ if (!fn) return
262
+
263
+ const ctx = { evt:'', target:el, test:()=>true };
264
+
265
+ // onevt.debounce-108 -> evt.debounce-108
266
+ ctx.evt = (e.startsWith('on') ? e.slice(2) : e).replace(/\.(\w+)?-?([-\w]+)?/g,
267
+ (match, mod, param='') => (ctx.test = mods[mod]?.(ctx, ...param.split('-')) || ctx.test, '')
268
+ );
301
269
 
302
270
  // add listener applying the context
303
- function addListenerWithMods(fn, {evt, target, test, defer, stop, prevent, ...opts} ) {
304
- if (defer) fn = defer(fn)
305
-
306
- let cb = e => test(e) && (
307
- stop&&e.stopPropagation(),
308
- prevent&&e.preventDefault(),
309
- fn.call(target, e)
310
- )
311
-
312
- target.addEventListener(evt, cb, opts)
313
- return () => target.removeEventListener(evt, cb, opts)
314
- };
271
+ const {evt, target, test, defer, stop, prevent, ...opts} = ctx;
272
+
273
+ if (defer) fn = defer(fn)
274
+
275
+ const cb = e => test(e) && (
276
+ stop&&e.stopPropagation(),
277
+ prevent&&e.preventDefault(),
278
+ fn.call(target, e)
279
+ )
280
+
281
+ target.addEventListener(evt, cb, opts)
282
+ return () => target.removeEventListener(evt, cb, opts)
315
283
  }
316
284
 
317
285
  // event modifiers
@@ -329,8 +297,6 @@ const mods = {
329
297
  window(ctx) { ctx.target = window },
330
298
  document(ctx) { ctx.target = document },
331
299
 
332
- toggle(ctx) { ctx.defer = (fn, out) => (e => out ? (out.call?.(ctx.target, e), out=null) : (out = fn())) },
333
-
334
300
  throttle(ctx, limit) { ctx.defer = fn => throttle(fn, limit ? Number(limit) || 0 : 108) },
335
301
  debounce(ctx, wait) { ctx.defer = fn => debounce(fn, wait ? Number(wait) || 0 : 108) },
336
302
 
@@ -418,19 +384,8 @@ function parseExpr(el, expression, dir) {
418
384
  let evaluate = evaluatorMemo[expression]
419
385
 
420
386
  if (!evaluate) {
421
- // Some expressions that are useful in Alpine are not valid as the right side of an expression.
422
- // Here we'll detect if the expression isn't valid for an assignement and wrap it in a self-
423
- // calling function so that we don't throw an error AND a "return" statement can b e used.
424
- let rightSideSafeExpression = 0
425
- // Support expressions starting with "if" statements like: "if (...) doSomething()"
426
- || /^[\n\s]*if.*\(.*\)/.test(expression)
427
- // Support expressions starting with "let/const" like: "let foo = 'bar'"
428
- || (/\b(let|const)\s/.test(expression) && !dir.startsWith(':on'))
429
- ? `(() => {${expression}})()`
430
- : expression;
431
-
432
387
  try {
433
- evaluate = evaluatorMemo[expression] = new Function(`__scope`,`with (__scope) { return ${rightSideSafeExpression.trim()} };`)
388
+ evaluate = evaluatorMemo[expression] = new Function(`__scope`,`with (__scope) { return ${expression.trim()} };`)
434
389
  } catch ( e ) {
435
390
  return exprError(e, el, expression, dir)
436
391
  }