@fluffjs/fluff 0.4.5 → 0.5.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.
Files changed (77) hide show
  1. package/bundle.min.js +1 -1
  2. package/decorators/Directive.d.ts +16 -0
  3. package/decorators/Directive.js +23 -0
  4. package/decorators/HostElement.d.ts +1 -0
  5. package/decorators/HostElement.js +4 -0
  6. package/index.d.ts +4 -0
  7. package/index.js +3 -0
  8. package/interfaces/ElementWithDirectives.d.ts +4 -0
  9. package/interfaces/FluffHostElement.d.ts +3 -10
  10. package/package.json +1 -1
  11. package/runtime/BreakController.d.ts +2 -3
  12. package/runtime/BreakController.js +0 -3
  13. package/runtime/FluffBase.d.ts +50 -42
  14. package/runtime/FluffBase.js +185 -242
  15. package/runtime/FluffDirective.d.ts +9 -0
  16. package/runtime/FluffDirective.js +36 -0
  17. package/runtime/FluffElement.d.ts +0 -1
  18. package/runtime/FluffElementImpl.d.ts +5 -10
  19. package/runtime/FluffElementImpl.js +59 -77
  20. package/runtime/FluffMarkers.d.ts +0 -1
  21. package/runtime/FluffMarkers.js +0 -1
  22. package/runtime/ForController.d.ts +2 -5
  23. package/runtime/ForController.js +7 -9
  24. package/runtime/IfController.d.ts +2 -5
  25. package/runtime/IfController.js +12 -13
  26. package/runtime/MarkerController.d.ts +9 -11
  27. package/runtime/MarkerController.js +6 -3
  28. package/runtime/MarkerManager.d.ts +2 -5
  29. package/runtime/MarkerManager.js +11 -50
  30. package/runtime/MarkerManagerInterface.d.ts +5 -2
  31. package/runtime/SwitchController.d.ts +2 -5
  32. package/runtime/SwitchController.js +10 -13
  33. package/runtime/TextController.d.ts +2 -4
  34. package/runtime/TextController.js +8 -16
  35. package/runtime/tests/DirectOutputParent.js +4 -1
  36. package/runtime/tests/TestChildTasksListComponent.js +4 -1
  37. package/runtime/tests/TestForComponent.js +4 -1
  38. package/runtime/tests/TestForReinsertBindsInputParentComponent.js +7 -2
  39. package/runtime/tests/TestForTextMarkerCollisionNoTrackParentComponent.js +5 -2
  40. package/runtime/tests/TestForTextMarkerCollisionParentComponent.js +5 -10
  41. package/runtime/tests/TestForUnsubscribeNestedParentComponent.js +7 -2
  42. package/runtime/tests/TestGetterReactivityComponent.js +4 -1
  43. package/runtime/tests/TestHarness.d.ts +1 -1
  44. package/runtime/tests/TestHarness.js +3 -3
  45. package/runtime/tests/TestIfReinsertBindsInputChildComponent.js +4 -1
  46. package/runtime/tests/TestIfReinsertBindsInputParentComponent.js +7 -2
  47. package/runtime/tests/TestIfUnsubscribeNestedParentComponent.js +7 -2
  48. package/runtime/tests/TestInterpolationNestedPropertyComponentBase.js +4 -1
  49. package/runtime/tests/TestLateDefineForComponent.js +4 -1
  50. package/runtime/tests/TestNullInputTextComponent.js +5 -2
  51. package/runtime/tests/TestOutputBindingChildComponent.js +4 -1
  52. package/runtime/tests/TestOutputBindingParentComponent.js +7 -2
  53. package/runtime/tests/TestParentBindsTasksComponent.js +4 -1
  54. package/runtime/tests/TestSwitchReinsertBindsInputChildComponent.js +4 -1
  55. package/runtime/tests/TestSwitchReinsertBindsInputParentComponent.js +8 -10
  56. package/runtime/tests/TestSwitchUnsubscribeNestedParentComponent.js +7 -9
  57. package/runtime/tests/TestTemplateNestedMarkersComponent.js +5 -2
  58. package/runtime/tests/TestUnsubscribeNestedChildComponent.js +4 -1
  59. package/runtime/tests/TestUnsubscribeNestedGrandchildComponent.js +4 -1
  60. package/runtime/tests/createPipeUnwrapTestComponent.js +4 -1
  61. package/runtime/tests/createPropBindParentComponent.js +4 -1
  62. package/runtime/tests/createTestInterpolationPipeComponent.js +4 -1
  63. package/runtime/tests/createTestInterpolationPipeWithArgsComponent.js +4 -1
  64. package/interfaces/BreakMarkerConfig.d.ts +0 -3
  65. package/interfaces/ForMarkerConfig.d.ts +0 -8
  66. package/interfaces/ForMarkerConfig.js +0 -1
  67. package/interfaces/IfMarkerConfig.d.ts +0 -7
  68. package/interfaces/IfMarkerConfig.js +0 -1
  69. package/interfaces/MarkerConfig.d.ts +0 -6
  70. package/interfaces/MarkerConfig.js +0 -1
  71. package/interfaces/SwitchMarkerConfig.d.ts +0 -10
  72. package/interfaces/SwitchMarkerConfig.js +0 -1
  73. package/interfaces/TextMarkerConfig.d.ts +0 -9
  74. package/interfaces/TextMarkerConfig.js +0 -1
  75. package/runtime/MarkerConfigGuards.d.ts +0 -13
  76. package/runtime/MarkerConfigGuards.js +0 -17
  77. /package/interfaces/{BreakMarkerConfig.js → ElementWithDirectives.js} +0 -0
package/bundle.min.js CHANGED
@@ -1 +1 @@
1
- var V=new Map;function N(o){return function(t){let e={...o,inputs:new Map,outputs:new Map};return V.set(t,e),t}}function $(o){return V.get(o)}var y=class{static getOrCreateArray(t,e){let n=Reflect.get(t,e);if(this.isTypedArray(n))return n;let r=[];return Reflect.set(t,e,r),r}static isTypedArray(t){return Array.isArray(t)}};function H(o){return function(t,e){let n=t.constructor;y.getOrCreateArray(n,"__hostBindings").push({property:String(e),hostProperty:o})}}function W(o){return function(t,e,n){let r=t.constructor;return y.getOrCreateArray(r,"__hostListeners").push({method:String(e),event:o}),n}}function z(o){return typeof o=="function"}function I(o){return function(t){return function(e,n){let{constructor:r}=e;if(!z(r))return;let s=$(r);if(s){let i=typeof t=="string"?t:t?.alias??String(n);s[o].set(String(n),i)}}}}var D=I("inputs");function j(o){return(t,e,n)=>{}}var q=I("outputs");var B=new Map;function R(o){let t=B.get(o);if(!t)return;let e=new t;return(n,...r)=>e.transform(n,...r)}function G(o){return function(t){return t.__pipeName=o,B.set(o,t),t}}function J(o){return(t,e)=>{}}function K(o){return function(t,e){let n=t.constructor;y.getOrCreateArray(n,"__viewChildren").push({property:String(e),selector:o})}}function X(...o){return function(t,e,n){let r=n.value;return typeof r=="function"&&Reflect.set(t,`__watch_${String(e)}`,r),n}}var _;(function(o){o[o.Any=0]="Any",o[o.Inbound=1]="Inbound",o[o.Outbound=2]="Outbound"})(_||(_={}));var g=class{callbacks=new Set;emit(t){for(let e of this.callbacks)try{let n=e(t);n instanceof Promise&&n.catch(r=>{console.error(r)})}catch(n){console.error(n)}}async emitAsync(t){for(let e of this.callbacks)try{await e(t)}catch(n){console.error(n)}}subscribe(t){return this.callbacks.add(t),{unsubscribe:()=>{this.callbacks.delete(t)}}}subscribeOnce(t){let e=async n=>{this.callbacks.delete(e),await t(n)};return this.callbacks.add(e),{unsubscribe:()=>{this.callbacks.delete(e)}}}};function T(o){let t=new WeakSet;return JSON.stringify(o,(e,n)=>{if(typeof n=="object"&&n!==null){if(t.has(n))return"[Circular]";t.add(n)}return n})}var f=class o{onChange=new g;onInboundChange=new g;onOutboundChange=new g;onMetadataChange=new g;value;committed=!0;_isChanging=!1;_parentProperty;_parentSubscription;_commitTriggerSub;_pendingCommitValue;_options;constructor(t){this.isOptionsObject(t)?(this._options=t,t.initialValue!==void 0&&(this.value=t.initialValue),t.commitTrigger!==void 0&&this.setCommitTrigger(t.commitTrigger)):this.value=t}prop(){return this._parentProperty}setValue(t,e=!1,n=!0){if(t instanceof o){let s=this._options?.linkHandler;s&&s(t),this.linkToParent(t);return}if(this._isChanging){let s=this._options?.propertyName;console.error((s?s+": ":"")+"Binding loop detected: setValue called while change is in progress");return}if(!(!(t!==this.value&&T(t)!==T(this.value))&&!(n&&!this.committed))){this._isChanging=!0;try{this.value=t,this.onChange.emit(t),n||(this.committed=!1),e?(this.committed=!0,this.onInboundChange.emit(t)):n&&(this.committed=!0,this.value!==void 0&&this.onOutboundChange.emit(this.value)),!e&&this._parentProperty&&this.pushToParent(t)}finally{this._isChanging=!1}}}linkToParent(t){this.clearParentLink();let e=t;for(;e._parentProperty;)e=e._parentProperty;this._parentProperty=e;let n=this._options?.direction??_.Any;this._parentSubscription=e.subscribe(n,s=>{this.setValueInternal(s,!0)});let r=e.getValue();r!==null&&this.setValueInternal(r,!0)}setValueInternal(t,e){if(!(this._isChanging||!(t!==this.value&&T(t)!==T(this.value)))){this._isChanging=!0;try{this.value=t,this.onChange.emit(t),e&&this.onInboundChange.emit(t)}finally{this._isChanging=!1}}}pushToParent(t){if(!this._parentProperty)return;let e=this._options?.commitTrigger;if(e){if(!!!e.getValue()){this._pendingCommitValue={value:t},this._parentProperty.setValue(t,!1,!1);return}this._pendingCommitValue=void 0}let n=this._parentSubscription;this._parentSubscription=void 0,n?.unsubscribe(),this._parentProperty.setValue(t);let r=this._options?.direction??_.Any;this._parentSubscription=this._parentProperty.subscribe(r,s=>{this.setValueInternal(s,!0)})}clearParentLink(){this._parentSubscription&&(this._parentSubscription.unsubscribe(),this._parentSubscription=void 0),this._parentProperty=void 0}setCommitTrigger(t){this._commitTriggerSub&&(this._commitTriggerSub.unsubscribe(),this._commitTriggerSub=void 0),this._options??={},this._options.commitTrigger=t,this._commitTriggerSub=t.onChange.subscribe(e=>{if(!e||!this._parentProperty||!this._pendingCommitValue)return;let n=this._pendingCommitValue.value;this._pendingCommitValue=void 0,this._parentProperty.setValue(n,!1,!0)})}reset(){this.clearParentLink()}triggerChange(t=_.Any){this.value!==void 0&&(this.onChange.emit(this.value),t==_.Outbound&&this.onOutboundChange.emit(this.value),t==_.Inbound&&this.onOutboundChange.emit(this.value))}subscribe(t,e){return t==_.Inbound?this.onInboundChange.subscribe(n=>{e(n)}):t==_.Outbound?this.onOutboundChange.subscribe(n=>{e(n)}):this.onChange.subscribe(n=>{e(n)})}getValue(){return this.value===void 0?null:this.value}isOptionsObject(t){return typeof t=="object"&&t!==null&&"initialValue"in t}};var Y=["property","event","two-way","class","style","ref"],m=class o extends HTMLElement{static __e=[];static __h=[];static __s=[];static __bindings={};static __expressionsReady=!1;static __pendingInitCallbacks=[];static __setExpressionTable(t,e,n){o.__e=t,o.__h=e,n&&(o.__s=n),o.__expressionsReady=!0;let r=o.__pendingInitCallbacks.splice(0,o.__pendingInitCallbacks.length);for(let s of r)s()}static __decodeDep(t){return Array.isArray(t)?t.map(e=>o.__s[e]):o.__s[t]}static __decodeBinding(t){let[e,n,r,s,i]=t,a=o.__s[e],c=Y[n],u={n:a,b:c};return r&&(u.d=r.map(p=>o.__decodeDep(p))),c==="event"?s!==null&&(u.h=s):s!==null&&(u.e=s),i&&(i.t&&(u.t=i.t),i.s&&(u.s=i.s),i.p&&(u.p=i.p.map(([p,l])=>({n:o.__s[p],a:l})))),u}static __areExpressionsReady(){return o.__expressionsReady}static __addPendingInit(t){o.__pendingInitCallbacks.push(t)}__parentScope;__loopContext={};__baseSubscriptions=[];__getScope(){return{host:this,locals:this.__loopContext,parent:this.__parentScope}}__subscribeToExpression(t,e,n,r){this.__subscribeToExpressionInScope(t,e,n,r)}__evaluateExpr(t,e){let n=this.__getCompiledExprFn(t);try{return n(this,e)}catch{return}}__applyPipesForController(t,e,n){let r=t;r instanceof f&&(r=r.getValue());for(let s of e){let i=this.__getPipeFn(s.name);if(!i){console.warn(`Pipe "${s.name}" not found`);continue}let a=s.argExprIds.map(c=>this.__getCompiledExprFn(c)(this,n));r=i(r,...a)}return r}__processBindingsOnElement(t,e,n){let r=t.getAttribute("data-lid");if(!r)return;let s=this.__getBindingsForLid(r);if(!(!s||s.length===0))for(let i of s)this.__applyBindingWithScope(t,i,e,n)}__getBindingsForLid(t){let e=this.constructor;if(typeof e=="function"){let n=Reflect.get(e,"__bindings");if(this.__isBindingsMap(n)){let r=n[t];if(r)return r.map(s=>o.__decodeBindingAny(s))}}}static __decodeBindingAny(t){return Array.isArray(t)?o.__decodeBinding(t):t}__isBindingsMap(t){return!(!t||typeof t!="object")}__applyBindingWithScope(t,e,n,r){switch(e.b){case"property":this.__applyPropertyBindingWithScope(t,e,n,r);break;case"event":this.__applyEventBindingWithScope(t,e,n);break;case"two-way":this.__applyTwoWayBindingWithScope(t,e,n,r);break;case"class":this.__applyClassBindingWithScope(t,e,n,r);break;case"style":this.__applyStyleBindingWithScope(t,e,n,r);break;case"ref":break}}__getCompiledExprFn(t){let e=o.__e[t];if(typeof e!="function")throw new Error(`Missing compiled expression function for exprId ${t}`);return e}__getCompiledHandlerFn(t){let e=o.__h[t];if(typeof e!="function")throw new Error(`Missing compiled handler function for handlerId ${t}`);return e}__applyPipes(t,e,n){return this.__applyPipesForController(t,e.map(r=>({name:r.n,argExprIds:r.a})),n)}__getPipeFn(t){}__subscribeToExpressionInScope(t,e,n,r){if(!t)return;let s=i=>{r?r.push(i):this.__baseSubscriptions.push(i)};for(let i of t)if(Array.isArray(i))this.__subscribeToPropertyChain(i,e,n,s);else{let a=this.__getReactivePropFromScope(i,e);a?s(a.onChange.subscribe(n)):!(i in e.locals)&&!(i in e.host)&&console.warn(`Binding dependency "${i}" not found on component ${e.host.constructor.name}`)}}__subscribeToPropertyChain(t,e,n,r){if(t.length===0)return;let[s,...i]=t,a=this.__getReactivePropFromScope(s,e);if(a)if(i.length===0)r(a.onChange.subscribe(n));else{let c=[],u=()=>{for(let h of c)h.unsubscribe();c=[];let l=a.getValue();l!=null&&this.__subscribeToNestedChain(l,i,n,h=>{c.push(h),r(h)}),n()};r(a.onChange.subscribe(u));let p=a.getValue();p!=null&&this.__subscribeToNestedChain(p,i,n,l=>{c.push(l),r(l)})}else if(s in e.locals){let c=e.locals[s];c!=null&&i.length>0&&this.__subscribeToNestedChain(c,i,n,r)}else s in e.host||console.warn(`Binding dependency "${s}" not found on component ${e.host.constructor.name}`)}__subscribeToNestedChain(t,e,n,r){if(e.length===0||t===null||t===void 0)return;let[s,...i]=e,a=Reflect.get(t,s);if(a instanceof f)if(i.length===0)r(a.onChange.subscribe(n));else{let c=[],u=()=>{for(let h of c)h.unsubscribe();c=[];let l=a.getValue();l!=null&&this.__subscribeToNestedChain(l,i,n,h=>{c.push(h),r(h)}),n()};r(a.onChange.subscribe(u));let p=a.getValue();p!=null&&this.__subscribeToNestedChain(p,i,n,l=>{c.push(l),r(l)})}else i.length>0&&a!==null&&a!==void 0&&this.__subscribeToNestedChain(a,i,n,r)}__getReactivePropFromScope(t,e){if(t in e.locals)return;let n=`__${t}`;if(n in e.host){let r=Reflect.get(e.host,n);if(r instanceof f)return r}if(e.parent)return this.__getReactivePropFromScope(t,e.parent)}__setChildProperty(t,e,n){let r=Reflect.get(t,e);r instanceof f?r.setValue(n,!0):t instanceof o?Reflect.set(t,e,n):e in t&&t instanceof HTMLElement?Reflect.set(t,e,this.__unwrap(n)):t.setAttribute(e,String(this.__unwrap(n)))}__unwrap(t){return t instanceof f?t.getValue():t}__applyPropertyBindingWithScope(t,e,n,r){let s=t.tagName.toLowerCase(),i=customElements.get(s)!==void 0,a=()=>{try{if(typeof e.e!="number")throw new Error(`Binding for ${e.n} is missing exprId`);let u=this.__getCompiledExprFn(e.e)(this,n.locals);e.p&&e.p.length>0&&(u=this.__applyPipes(u,e.p,n.locals)),this.__setChildProperty(t,e.n,u)}catch(c){console.error("Property binding error:",c)}};this.__subscribeToExpressionInScope(e.d,n,a,r),e.s&&this.__subscribeToExpressionInScope([e.s],n,a,r),i?t instanceof o?a():this.__whenDefined(s,()=>{t instanceof o?a():console.warn(`Element <${s}> is not a FluffBase instance after whenDefined - binding for "${e.n}" skipped`)}):a()}__applyEventBindingWithScope(t,e,n){let r=`__fluff_event_${e.n}`;if(Reflect.has(t,r))return;if(Reflect.set(t,r,!0),typeof e.h!="number")throw new Error(`Event binding for ${e.n} is missing handlerId`);let s=this.__getCompiledHandlerFn(e.h);t.hasAttribute("x-fluff-component")?this.__applyOutputBinding(t,e.n,s,n):t.addEventListener(e.n,i=>{try{s(this,n.locals,i)}catch(a){console.error("Event binding error:",a)}})}__applyOutputBinding(t,e,n,r){let s=()=>{let i=Reflect.get(t,e);if(i instanceof g){let a=i.subscribe(c=>{try{n(this,r.locals,c)}catch(u){console.error("Output binding error:",u)}});return this.__baseSubscriptions.push(a),!0}return!1};s()||this.__whenDefined(t.tagName.toLowerCase(),()=>{s()})}__whenDefined(t,e){customElements.whenDefined(t).then(e).catch(console.error)}__applyTwoWayBindingWithScope(t,e,n,r){if(this.__applyPropertyBindingWithScope(t,e,n,r),typeof e.t!="string"||e.t.length===0)throw new Error(`Two-way binding for ${e.n} is missing targetProp`);let s=this.__getReactivePropFromScope(e.t,n),i=Reflect.get(t,e.n);if(s&&i instanceof f){let a=i.onChange.subscribe(c=>{s.setValue(c,!0)});r?r.push(a):this.__baseSubscriptions.push(a)}}__applyClassBindingWithScope(t,e,n,r){let s=()=>{try{if(typeof e.e!="number")throw new Error(`Class binding for ${e.n} is missing exprId`);let i=this.__getCompiledExprFn(e.e);this.__unwrap(i(this,n.locals))?t.classList.add(e.n):t.classList.remove(e.n)}catch(i){console.error("Class binding error:",i)}};this.__subscribeToExpressionInScope(e.d,n,s,r),s()}__applyStyleBindingWithScope(t,e,n,r){let s=()=>{try{if(typeof e.e!="number")throw new Error(`Style binding for ${e.n} is missing exprId`);let i=this.__getCompiledExprFn(e.e),a=this.__unwrap(i(this,n.locals));this.__hasStyle(t)&&t.style.setProperty(e.n,String(a))}catch(i){console.error("Style binding error:",i)}};this.__subscribeToExpressionInScope(e.d,n,s,r),s()}__hasStyle(t){return"style"in t}};var v=new Map,Q=0;function A(o){let t=`scope_${Q++}`;return v.set(t,o),t}function F(o){return v.get(o)}var L=/^fluff:(if|for|switch|text|break):(\d+)$/,d=class{id;startMarker;endMarker;subscriptions=[];host;shadowRoot;parentScope;loopContext={};markerManager;constructor(t,e,n,r,s){this.id=t,this.startMarker=e,this.endMarker=n,this.host=r,this.shadowRoot=s}setParentScope(t){this.parentScope=t}setLoopContext(t){this.loopContext=t}setMarkerManager(t){this.markerManager=t}cleanup(){for(let t of this.subscriptions)t.unsubscribe();this.subscriptions.length=0}updateRenderContext(t){}evaluateExpr(t){let e=this.getScope(),n=this.collectLocalsFromScope(e);if(e.host.__evaluateExpr)return e.host.__evaluateExpr(t,n);let r=m.__e[t];if(typeof r=="function")try{return r(e.host,n)}catch{return}}getScope(){if(this.parentScope)return this.parentScope;let t=this.__getFluffElementHost();return t?t.__getScope():{host:this.host,locals:this.loopContext,parent:void 0}}collectLocalsFromScope(t){let e={};return t.parent&&Object.assign(e,this.collectLocalsFromScope(t.parent)),Object.assign(e,t.locals),e}subscribeAndRun(t,e){let n=this.getScope(),r=t.filter(s=>Array.isArray(s)?s.length>0&&!s[0].startsWith("["):!s.startsWith("["));n.host.__subscribeToExpression&&n.host.__subscribeToExpression(r,n,e,this.subscriptions),e()}createChildScope(t){return{host:this.host,locals:t,parent:this.parentScope}}clearContentBetweenMarkersWithCleanup(t){for(let r of t)r.unsubscribe();if(t.length=0,!this.endMarker)return;let e=this.startMarker.parentNode;if(!e)return;let n=this.startMarker.nextSibling;for(;n&&n!==this.endMarker;){let r=n.nextSibling;if(n instanceof Comment){let s=L.exec(n.data);if(s&&this.markerManager?.cleanupController){let i=parseInt(s[2],10);this.markerManager.cleanupController(i,n)}}n instanceof HTMLTemplateElement||e.removeChild(n),n=r}}insertBeforeEndMarker(t){if(!this.endMarker)return;let e=this.endMarker.parentNode;e&&e.insertBefore(t,this.endMarker)}refreshParentBindings(){let t=this.startMarker.parentNode;if(!(t instanceof HTMLElement)||!t.hasAttribute("data-lid"))return;let e=this.__getFluffElementHost();if(!e)return;let n=this.getScope();e.__processBindingsOnElementPublic(t,n)}__getFluffElementHost(){return this.host instanceof C?this.host:null}setScopeOnChildren(t,e,n,r,s){if(t instanceof Comment){let i=L.exec(t.data);if(i&&r){let[,a,c]=i,u=parseInt(c,10),p=`/fluff:${a}:${u}`,l=r.getController(u,t),h=l===void 0;if(!l&&r.ensureController){let O=null,x=t.nextSibling;for(;x;){if(x instanceof Comment&&x.data===p){O=x;break}x=x.nextSibling}l=r.ensureController(u,a,t,O)}l&&(l.setParentScope(e),l.setLoopContext(e.locals),l.updateRenderContext(n),h&&l.initialize())}}else if(t instanceof C)t.__loopContext=e.locals,t.__parentScope=e,this.processBindingsOnNode(t,e,s);else if(t instanceof HTMLElement&&customElements.get(t.tagName.toLowerCase())!==void 0){let i=A(e);t.setAttribute("data-fluff-scope-id",i),this.processBindingsOnNode(t,e,s)}else t instanceof HTMLElement&&t.hasAttribute("data-lid")&&this.processBindingsOnNode(t,e,s);for(let i of Array.from(t.childNodes))this.setScopeOnChildren(i,e,n,r,s)}cloneAndInsertTemplate(t,e,n,r){let s=t.content.cloneNode(!0);if(!(s instanceof DocumentFragment))throw new Error("Expected DocumentFragment from template clone");let i=Array.from(s.childNodes),a=this.createChildScope(e);this.insertBeforeEndMarker(s);for(let c of i)this.setScopeOnChildren(c,a,n,this.markerManager,r)}processBindingsOnNode(t,e,n){let r=this.__getFluffElementHost();r&&r.__processBindingsOnElementPublic(t,e,n)}};var w=class extends d{constructor(t,e,n,r,s,i){super(t,e,n,r,s)}initialize(){}updateRenderContext(t){t&&(t.shouldBreak=!0)}};var k=class extends d{config;itemTemplate=null;emptyTemplate=null;bindingsSubscriptions=[];constructor(t,e,n,r,s,i){super(t,e,n,r,s),this.config=i}initialize(){let e=`${this.host.tagName.toLowerCase()}-${this.id}`;this.itemTemplate=this.shadowRoot.querySelector(`template[data-fluff-tpl="${e}"]`),this.emptyTemplate=this.shadowRoot.querySelector(`template[data-fluff-empty="${e}"]`);let n=this.config.deps??[],r=()=>{this.clearContentBetweenMarkersWithCleanup(this.bindingsSubscriptions);let s=this.evaluateExpr(this.config.iterableExprId);if(!Array.isArray(s)||s.length===0){this.emptyTemplate&&this.cloneAndInsertTemplate(this.emptyTemplate,this.loopContext,void 0,this.bindingsSubscriptions);return}if(!this.itemTemplate)return;let i={shouldBreak:!1};for(let a=0;a<s.length&&!i.shouldBreak;a++){let c={...this.loopContext,[this.config.iterator]:s[a],$index:a};this.cloneAndInsertTemplate(this.itemTemplate,c,i,this.bindingsSubscriptions)}this.refreshParentBindings()};this.subscribeAndRun(n,r)}};var P=class extends d{config;templates=[];currentBranchIndex=-1;bindingsSubscriptions=[];constructor(t,e,n,r,s,i){super(t,e,n,r,s),this.config=i}initialize(){let e=`${this.host.tagName.toLowerCase()}-${this.id}-`;this.templates=Array.from(this.shadowRoot.querySelectorAll(`template[data-fluff-branch^="${e}"]`));let n=[];for(let s of this.config.branches)s.deps&&n.push(...s.deps);let r=()=>{let s=-1;for(let i=0;i<this.config.branches.length;i++){let a=this.config.branches[i];if(a.exprId===void 0){s=i;break}if(this.evaluateExpr(a.exprId)){s=i;break}}s!==this.currentBranchIndex&&(this.clearContentBetweenMarkersWithCleanup(this.bindingsSubscriptions),this.currentBranchIndex=s,s>=0&&s<this.templates.length&&this.cloneAndInsertTemplate(this.templates[s],this.loopContext,void 0,this.bindingsSubscriptions),this.refreshParentBindings())};this.subscribeAndRun(n,r)}};var b=class{static isIfConfig(t){return t.type==="if"}static isForConfig(t){return t.type==="for"}static isSwitchConfig(t){return t.type==="switch"}static isTextConfig(t){return t.type==="text"}static isBreakConfig(t){return t.type==="break"}};var E=class extends d{config;templates=[];bindingsSubscriptions=[];constructor(t,e,n,r,s,i){super(t,e,n,r,s),this.config=i}initialize(){let e=`${this.host.tagName.toLowerCase()}-${this.id}-`;this.templates=Array.from(this.shadowRoot.querySelectorAll(`template[data-fluff-case^="${e}"]`));let n=this.config.deps??[],r=()=>{this.clearContentBetweenMarkersWithCleanup(this.bindingsSubscriptions);let s=this.evaluateExpr(this.config.expressionExprId),i=!1,a=!1,c={shouldBreak:!1};for(let u=0;u<this.config.cases.length&&!c.shouldBreak;u++){let p=this.config.cases[u],l=this.templates[u];if(!l)continue;let h=p.isDefault||p.valueExprId!==void 0&&this.evaluateExpr(p.valueExprId)===s;(a||!i&&h)&&(i=!0,this.cloneAndInsertTemplate(l,this.loopContext,c,this.bindingsSubscriptions),a=p.fallthrough)}this.refreshParentBindings()};this.subscribeAndRun(n,r)}};var M=class extends d{config;textNode=null;constructor(t,e,n,r,s,i){super(t,e,n,r,s),this.config=i}initialize(){this.textNode=document.createTextNode(""),this.insertBeforeEndMarker(this.textNode);let t=this.config.deps??[],e=this.config.pipes??[],n=()=>{let r=this.evaluateExpr(this.config.exprId);if(this.host.__applyPipesForController){let s=this.getScope(),i=this.collectLocalsFromScope(s);r=this.host.__applyPipesForController(r,e,i)}this.textNode&&(this.textNode.textContent=this.formatValue(r))};this.subscribeAndRun(t,n)}formatValue(t){return t==null?"":typeof t=="object"?JSON.stringify(t):typeof t=="string"?t:typeof t=="number"||typeof t=="boolean"?String(t):""}};var S=class{controllers=new Map;configs=new Map;host;shadowRoot;constructor(t,e){this.host=t,this.shadowRoot=e}initializeFromConfig(t){this.configs.clear();for(let[n,r]of t)this.configs.set(n,r);for(let[n,r]of t){let{startMarker:s,endMarker:i}=this.findMarkers(n,r.type);if(!s)continue;let a=this.createController(n,s,i,r);a&&(a.setMarkerManager(this),this.registerController(n,s,a))}let e=[];for(let n of this.controllers.values())e.push(...n.values());for(let n of e)n.initialize()}ensureController(t,e,n,r){let s=this.getController(t,n);if(s)return s;let i=this.configs.get(t);if(i?.type!==e)return;let a=this.createController(t,n,r,i);if(a)return a.setMarkerManager(this),this.registerController(t,n,a),a}getController(t,e){return this.controllers.get(t)?.get(e)}cleanupController(t,e){let n=this.controllers.get(t);if(n){if(e){let r=n.get(e);if(!r)return;r.cleanup(),n.delete(e),n.size===0&&this.controllers.delete(t);return}for(let r of n.values())r.cleanup();this.controllers.delete(t)}}cleanup(){for(let t of this.controllers.values())for(let e of t.values())e.cleanup();this.controllers.clear()}registerController(t,e,n){let r=this.controllers.get(t);r||(r=new Map,this.controllers.set(t,r)),r.set(e,n)}findMarkers(t,e){let n=`fluff:${e}:${t}`,r=`/fluff:${e}:${t}`,s=null,i=null,a=document.createTreeWalker(this.shadowRoot,NodeFilter.SHOW_COMMENT,null),c=a.nextNode();for(;c;)c instanceof Comment&&(c.data===n?s=c:c.data===r&&(i=c)),c=a.nextNode();return{startMarker:s,endMarker:i}}createController(t,e,n,r){return b.isIfConfig(r)?new P(t,e,n,this.host,this.shadowRoot,r):b.isForConfig(r)?new k(t,e,n,this.host,this.shadowRoot,r):b.isSwitchConfig(r)?new E(t,e,n,this.host,this.shadowRoot,r):b.isTextConfig(r)?new M(t,e,n,this.host,this.shadowRoot,r):b.isBreakConfig(r)?new w(t,e,n,this.host,this.shadowRoot,r):null}};var C=class extends m{__pipes={};_shadowRoot;_subscriptions=[];_initialized=!1;_pendingInit=!1;_markerManager=null;_markerConfigEntries=null;_MarkerManagerClass=null;constructor(){super(),this._shadowRoot=this.attachShadow({mode:"open"})}connectedCallback(){if(!this._initialized){if(!m.__areExpressionsReady()){this._pendingInit||(this._pendingInit=!0,m.__addPendingInit(()=>{this._pendingInit=!1,this.connectedCallback()}));return}let t=this.getAttribute("data-fluff-scope-id");t&&!this.__parentScope&&(this.__parentScope=F(t),this.__parentScope&&(this.__loopContext=this.__parentScope.locals));let e=this.getAttribute("data-fluff-loop-context");if(e&&Object.keys(this.__loopContext).length===0)try{this.__loopContext=JSON.parse(e)}catch{}this.__applyPendingProps(),this.__render(),this.__setupBindings(),this.getAttribute("data-fluff-scope-id")&&this.__processBindings(),this._initialized=!0,"onInit"in this&&typeof this.onInit=="function"&&this.onInit()}}disconnectedCallback(){"onDestroy"in this&&typeof this.onDestroy=="function"&&this.onDestroy(),this._markerManager&&(this._markerManager.cleanup(),this._markerManager=null);for(let t of this._subscriptions)t.unsubscribe();this._subscriptions=[];for(let t of this.__baseSubscriptions)t.unsubscribe();this.__baseSubscriptions=[]}$watch=(t,e)=>(e(""),{unsubscribe:()=>{}});__processBindingsOnElementPublic(t,e,n){this.__processBindingsOnElement(t,e,n)}__setupBindings(){this.__initializeMarkers(S),this.__processBindings(),this.__initializeMarkersInternal()}__pipe(t,e,...n){let r=this.__pipes[t];return r?r(e,...n):(console.warn(`Pipe "${t}" not found`),e)}__getPipeFn(t){return this.__pipes[t]??R(t)}__getShadowRoot(){return this._shadowRoot}__createProp(t,e){let n=new f(e);return Object.defineProperty(this,t,{get(){return n.getValue()},set(r){n.setValue(r)},enumerable:!0,configurable:!0}),n}__defineClassHostBinding(t,e,n){Object.defineProperty(this,t,{get:()=>!!Reflect.get(this,n),set:r=>{Reflect.set(this,n,r),r?this.classList.add(e):this.classList.remove(e)},enumerable:!0,configurable:!0})}__setMarkerConfigs(t){this._markerConfigEntries=t}__initializeMarkers(t){this._MarkerManagerClass=t}__initializeMarkersInternal(){!this._markerConfigEntries||!this._MarkerManagerClass||(this._markerManager=new this._MarkerManagerClass(this,this._shadowRoot),this._markerManager.initializeFromConfig(this._markerConfigEntries))}__setChildProperty(t,e,n){if(t instanceof HTMLElement&&t.hasAttribute("x-fluff-component")){let r=t.tagName.toLowerCase();if(customElements.get(r)===void 0){this.__whenDefined(r,()=>{this.__setChildProperty(t,e,n)});return}}super.__setChildProperty(t,e,n)}__getReactivePropFromScope(t,e){let n=`__${t}`;if(n in e.host){let r=Reflect.get(e.host,n);if(r instanceof f)return r}if(e.parent)return this.__getReactivePropFromScope(t,e.parent)}__processBindings(){let t=this._shadowRoot.querySelectorAll("[data-lid]"),e=this.__getScope();for(let n of Array.from(t)){let r=n.closest("[x-fluff-component]");r&&r!==n||this.__processBindingsOnElement(n,e)}}__applyPendingProps(){let t=Reflect.get(this,"__pendingProps");if(this.isRecord(t)){for(let[e,n]of Object.entries(t)){console.log("apply-pending-prop",{propName:e,value:n,el:this.tagName});let r=`__${e}`;if(r in this){let s=Reflect.get(this,r);s instanceof f&&s.setValue(n,!0)}else e in this&&Reflect.set(this,e,n)}Reflect.deleteProperty(this,"__pendingProps")}}isRecord(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}};export{N as Component,_ as Direction,m as FluffBase,C as FluffElement,H as HostBinding,W as HostListener,D as Input,j as LinkedProperty,S as MarkerManager,q as Output,G as Pipe,f as Property,g as Publisher,J as Reactive,K as ViewChild,X as Watch,R as getPipeTransform,B as pipeRegistry};
1
+ var N=new Map;function K(o){return function(t){let e={...o,inputs:new Map,outputs:new Map};return N.set(t,e),t}}function W(o){return N.get(o)}var R=new Map,J=new Map;function G(o){return function(t){let e={...o,inputs:new Map,outputs:new Map};return J.set(t,e),t}}function v(o){return R.get(o)}function X(){return Array.from(R.keys())}function Y(o,t){R.set(o,t)}var C=class{static getOrCreateArray(t,e){let n=Reflect.get(t,e);if(this.isTypedArray(n))return n;let s=[];return Reflect.set(t,e,s),s}static isTypedArray(t){return Array.isArray(t)}};function Q(o){return function(t,e){let n=t.constructor;C.getOrCreateArray(n,"__hostBindings").push({property:String(e),hostProperty:o})}}function U(){return function(o,t){}}function Z(o){return function(t,e,n){let s=t.constructor;return C.getOrCreateArray(s,"__hostListeners").push({method:String(e),event:o}),n}}function tt(o){return typeof o=="function"}function T(o){return function(t){return function(e,n){let{constructor:s}=e;if(!tt(s))return;let r=W(s);if(r){let i=typeof t=="string"?t:t?.alias??String(n);r[o].set(String(n),i)}}}}var et=T("inputs");function nt(o){return(t,e,n)=>{}}var st=T("outputs");var A=new Map;function D(o){let t=A.get(o);if(!t)return;let e=new t;return(n,...s)=>e.transform(n,...s)}function rt(o){return function(t){return t.__pipeName=o,A.set(o,t),t}}function it(o){return(t,e)=>{}}function ot(o){return function(t,e){let n=t.constructor;C.getOrCreateArray(n,"__viewChildren").push({property:String(e),selector:o})}}function at(...o){return function(t,e,n){let s=n.value;return typeof s=="function"&&Reflect.set(t,`__watch_${String(e)}`,s),n}}var m;(function(o){o[o.Any=0]="Any",o[o.Inbound=1]="Inbound",o[o.Outbound=2]="Outbound"})(m||(m={}));var y=class{callbacks=new Set;emit(t){for(let e of this.callbacks)try{let n=e(t);n instanceof Promise&&n.catch(s=>{console.error(s)})}catch(n){console.error(n)}}async emitAsync(t){for(let e of this.callbacks)try{await e(t)}catch(n){console.error(n)}}subscribe(t){return this.callbacks.add(t),{unsubscribe:()=>{this.callbacks.delete(t)}}}subscribeOnce(t){let e=async n=>{this.callbacks.delete(e),await t(n)};return this.callbacks.add(e),{unsubscribe:()=>{this.callbacks.delete(e)}}}};function B(o){let t=new WeakSet;return JSON.stringify(o,(e,n)=>{if(typeof n=="object"&&n!==null){if(t.has(n))return"[Circular]";t.add(n)}return n})}var _=class o{onChange=new y;onInboundChange=new y;onOutboundChange=new y;onMetadataChange=new y;value;committed=!0;_isChanging=!1;_parentProperty;_parentSubscription;_commitTriggerSub;_pendingCommitValue;_options;constructor(t){this.isOptionsObject(t)?(this._options=t,t.initialValue!==void 0&&(this.value=t.initialValue),t.commitTrigger!==void 0&&this.setCommitTrigger(t.commitTrigger)):this.value=t}prop(){return this._parentProperty}setValue(t,e=!1,n=!0){if(t instanceof o){let r=this._options?.linkHandler;r&&r(t),this.linkToParent(t);return}if(this._isChanging){let r=this._options?.propertyName;console.error((r?r+": ":"")+"Binding loop detected: setValue called while change is in progress");return}if(!(!(t!==this.value&&B(t)!==B(this.value))&&!(n&&!this.committed))){this._isChanging=!0;try{this.value=t,this.onChange.emit(t),n||(this.committed=!1),e?(this.committed=!0,this.onInboundChange.emit(t)):n&&(this.committed=!0,this.value!==void 0&&this.onOutboundChange.emit(this.value)),!e&&this._parentProperty&&this.pushToParent(t)}finally{this._isChanging=!1}}}linkToParent(t){this.clearParentLink();let e=t;for(;e._parentProperty;)e=e._parentProperty;this._parentProperty=e;let n=this._options?.direction??m.Any;this._parentSubscription=e.subscribe(n,r=>{this.setValueInternal(r,!0)});let s=e.getValue();s!==null&&this.setValueInternal(s,!0)}setValueInternal(t,e){if(!(this._isChanging||!(t!==this.value&&B(t)!==B(this.value)))){this._isChanging=!0;try{this.value=t,this.onChange.emit(t),e&&this.onInboundChange.emit(t)}finally{this._isChanging=!1}}}pushToParent(t){if(!this._parentProperty)return;let e=this._options?.commitTrigger;if(e){if(!!!e.getValue()){this._pendingCommitValue={value:t},this._parentProperty.setValue(t,!1,!1);return}this._pendingCommitValue=void 0}let n=this._parentSubscription;this._parentSubscription=void 0,n?.unsubscribe(),this._parentProperty.setValue(t);let s=this._options?.direction??m.Any;this._parentSubscription=this._parentProperty.subscribe(s,r=>{this.setValueInternal(r,!0)})}clearParentLink(){this._parentSubscription&&(this._parentSubscription.unsubscribe(),this._parentSubscription=void 0),this._parentProperty=void 0}setCommitTrigger(t){this._commitTriggerSub&&(this._commitTriggerSub.unsubscribe(),this._commitTriggerSub=void 0),this._options??={},this._options.commitTrigger=t,this._commitTriggerSub=t.onChange.subscribe(e=>{if(!e||!this._parentProperty||!this._pendingCommitValue)return;let n=this._pendingCommitValue.value;this._pendingCommitValue=void 0,this._parentProperty.setValue(n,!1,!0)})}reset(){this.clearParentLink()}triggerChange(t=m.Any){this.value!==void 0&&(this.onChange.emit(this.value),t===m.Outbound&&this.onOutboundChange.emit(this.value),t===m.Inbound&&this.onInboundChange.emit(this.value))}subscribe(t,e){return t==m.Inbound?this.onInboundChange.subscribe(n=>{e(n)}):t==m.Outbound?this.onOutboundChange.subscribe(n=>{e(n)}):this.onChange.subscribe(n=>{e(n)})}getValue(){return this.value===void 0?null:this.value}isOptionsObject(t){return typeof t=="object"&&t!==null&&"initialValue"in t}};var h=class o extends HTMLElement{static __e=[];static __h=[];static __s=[];static __bindings={};static __expressionsReady=!1;static __pendingInitCallbacks=[];static __setExpressionTable(t,e,n){o.__e=t,o.__h=e,n&&(o.__s=n),o.__expressionsReady=!0;let s=o.__pendingInitCallbacks.splice(0,o.__pendingInitCallbacks.length);for(let r of s)r()}static __decodeDep(t){return Array.isArray(t)?t.map(e=>o.__s[e]):o.__s[t]}static __decodeDeps(t){if(t)return t.map(e=>o.__decodeDep(e))}static __areExpressionsReady(){return o.__expressionsReady}static __addPendingInit(t){o.__pendingInitCallbacks.push(t)}__parentScope;__loopContext={};__baseSubscriptions=[];__getScope(){return{host:this,locals:this.__loopContext,parent:this.__parentScope}}__subscribeToExpression(t,e,n,s){this.__subscribeToExpressionInScope(t,e,n,s)}__evaluateExpr(t,e){let n=this.__getCompiledExprFn(t);try{return n(this,e)}catch{return}}__applyPipesForController(t,e,n){let s=t;s instanceof _&&(s=s.getValue());for(let[r,i]of e){let a=o.__s[r],c=this.__getPipeFn(a);if(!c){console.warn(`Pipe "${a}" not found`);continue}let l=i.map(u=>this.__getCompiledExprFn(u)(this,n));s=c(s,...l)}return s}__processBindingsOnElement(t,e,n){let s=t.getAttribute("data-lid");if(!s)return;let r=this.__getBindingsForLid(s);if(!(!r||r.length===0))for(let i of r)this.__applyBindingWithScope(t,i,e,n)}__getBindingsForLid(t){let e=this.constructor;if(typeof e=="function"){let n=Reflect.get(e,"__bindings");if(this.__isRecord(n)&&t in n){let s=n[t];if(this.__isCompactBindingArray(s))return s}}}__isCompactBindingArray(t){return Array.isArray(t)}__applyBindingWithScope(t,e,n,s){switch(e[1]){case 0:this.__applyPropertyBindingWithScope(t,e,n,s);break;case 1:this.__applyEventBindingWithScope(t,e,n);break;case 2:this.__applyTwoWayBindingWithScope(t,e,n,s);break;case 3:this.__applyClassBindingWithScope(t,e,n,s);break;case 4:this.__applyStyleBindingWithScope(t,e,n,s);break;case 5:break}}__getCompiledExprFn(t){let e=o.__e[t];if(typeof e!="function")throw new Error(`Missing compiled expression function for exprId ${t}`);return e}__getCompiledHandlerFn(t){let e=o.__h[t];if(typeof e!="function")throw new Error(`Missing compiled handler function for handlerId ${t}`);return e}__getPipeFn(t){}__subscribeToExpressionInScope(t,e,n,s){if(!t)return;let r=i=>{s?s.push(i):this.__baseSubscriptions.push(i)};for(let i of t)if(Array.isArray(i))this.__subscribeToPropertyChain(i,e,n,r);else{let a=this.__getReactivePropFromScope(i,e);a?r(a.onChange.subscribe(n)):!(i in e.locals)&&!(i in e.host)&&console.warn(`Binding dependency "${i}" not found on component ${e.host.constructor.name}`)}}__subscribeToPropertyChain(t,e,n,s){if(t.length===0)return;let[r,...i]=t,a=this.__getReactivePropFromScope(r,e);if(a)this.__subscribeToProp(a,i,n,s);else if(r in e.locals){let c=e.locals[r];c!=null&&i.length>0&&this.__subscribeToNestedChain(c,i,n,s)}else r in e.host||console.warn(`Binding dependency "${r}" not found on component ${e.host.constructor.name}`)}__subscribeToProp(t,e,n,s){if(e.length===0){s(t.onChange.subscribe(n));return}let r=[],i=()=>{for(let l of r)l.unsubscribe();r=[];let c=t.getValue();c!=null&&this.__subscribeToNestedChain(c,e,n,l=>{r.push(l),s(l)}),n()};s(t.onChange.subscribe(i));let a=t.getValue();a!=null&&this.__subscribeToNestedChain(a,e,n,c=>{r.push(c),s(c)})}__subscribeToNestedChain(t,e,n,s){if(e.length===0||t===null||t===void 0)return;let[r,...i]=e,a=Reflect.get(t,r);a instanceof _?this.__subscribeToProp(a,i,n,s):i.length>0&&a!==null&&a!==void 0&&this.__subscribeToNestedChain(a,i,n,s)}__getReactivePropFromScope(t,e){if(t in e.locals)return;let n=`__${t}`;if(n in e.host){let s=Reflect.get(e.host,n);if(s instanceof _)return s}if(e.parent)return this.__getReactivePropFromScope(t,e.parent)}__setChildProperty(t,e,n){let s=Reflect.get(t,e);s instanceof _?s.setValue(n,!0):t instanceof o?Reflect.set(t,e,n):e in t&&t instanceof HTMLElement?Reflect.set(t,e,this.__unwrap(n)):t.setAttribute(e,String(this.__unwrap(n)))}__unwrap(t){return t instanceof _?t.getValue():t}__applyPropertyBindingWithScope(t,e,n,s){let[r,,i,a,c]=e,l=o.__s[r],u=o.__decodeDeps(i),f=t.tagName.toLowerCase(),p=customElements.get(f)!==void 0,b=()=>{try{if(typeof a!="number")throw new Error(`Binding for ${l} is missing exprId`);let S=this.__getCompiledExprFn(a)(this,n.locals);c?.p&&c.p.length>0&&(S=this.__applyPipesForController(S,c.p,n.locals)),this.__setChildProperty(t,l,S)}catch(g){console.error("Property binding error:",g)}};this.__subscribeToExpressionInScope(u,n,b,s),c?.s&&this.__subscribeToExpressionInScope([c.s],n,b,s),p?t instanceof o?b():this.__whenDefined(f,()=>{t instanceof o?b():console.warn(`Element <${f}> is not a FluffBase instance after whenDefined - binding for "${l}" skipped`)}):b()}__applyEventBindingWithScope(t,e,n){let[s,,,r]=e,i=o.__s[s],a=`__fluff_event_${i}`;if(Reflect.has(t,a))return;if(Reflect.set(t,a,!0),typeof r!="number")throw new Error(`Event binding for ${i} is missing handlerId`);let c=this.__getCompiledHandlerFn(r),l=t.hasAttribute("data-fluff-directives");t.hasAttribute("x-fluff-component")||l?this.__applyOutputBinding(t,i,c,n):t.addEventListener(i,u=>{try{c(this,n.locals,u)}catch(f){console.error("Event binding error:",f)}})}__applyOutputBinding(t,e,n,s){let r=c=>{if(c instanceof y){let l=c.subscribe(u=>{try{n(this,s.locals,u)}catch(f){console.error("Output binding error:",f)}});return this.__baseSubscriptions.push(l),!0}return!1},i=()=>{let c=Reflect.get(t,e);return r(c)};if((()=>{let c=!1,l=t.__fluffDirectives;if(l)for(let u of l){let f=Reflect.get(u,e);r(f)&&(c=!0)}return c})(),!i()){let c=t.tagName.toLowerCase();c.includes("-")&&this.__whenDefined(c,()=>{i()})}}__whenDefined(t,e){customElements.whenDefined(t).then(e).catch(console.error)}__applyTwoWayBindingWithScope(t,e,n,s){this.__applyPropertyBindingWithScope(t,e,n,s);let r=o.__s[e[0]],i=e[4]?.t;if(typeof i!="string"||i.length===0)throw new Error(`Two-way binding for ${r} is missing targetProp`);let a=this.__getReactivePropFromScope(i,n),c=Reflect.get(t,r);if(a&&c instanceof _){let l=c.onChange.subscribe(u=>{a.setValue(u,!0)});s?s.push(l):this.__baseSubscriptions.push(l)}}__applyClassBindingWithScope(t,e,n,s){let[r,,i,a]=e,c=o.__s[r],l=o.__decodeDeps(i),u=()=>{try{if(typeof a!="number")throw new Error(`Class binding for ${c} is missing exprId`);let f=this.__getCompiledExprFn(a);this.__unwrap(f(this,n.locals))?t.classList.add(c):t.classList.remove(c)}catch(f){console.error("Class binding error:",f)}};this.__subscribeToExpressionInScope(l,n,u,s),u()}__applyStyleBindingWithScope(t,e,n,s){let[r,,i,a]=e,c=o.__s[r],l=o.__decodeDeps(i),u=()=>{try{if(typeof a!="number")throw new Error(`Style binding for ${c} is missing exprId`);let f=this.__getCompiledExprFn(a),p=this.__unwrap(f(this,n.locals));this.__hasStyle(t)&&t.style.setProperty(c,String(p))}catch(f){console.error("Style binding error:",f)}};this.__subscribeToExpressionInScope(l,n,u,s),u()}__hasStyle(t){return"style"in t}__createProp(t,e){let n=typeof t=="number"?o.__s[t]:t,s=new _(e);return Object.defineProperty(this,n,{get(){return s.getValue()},set(r){s.setValue(r)},enumerable:!0,configurable:!0}),s}__defineClassHostBinding(t,e,n){let s=this.__getHostElement();Object.defineProperty(this,t,{get:()=>!!Reflect.get(this,n),set:r=>{Reflect.set(this,n,r),r?s.classList.add(e):s.classList.remove(e)},enumerable:!0,configurable:!0})}__applyPendingProps(){let t=Reflect.get(this,"__pendingProps");if(this.__isRecord(t)){for(let[e,n]of Object.entries(t)){let s=`__${e}`;if(s in this){let r=Reflect.get(this,s);r instanceof _&&r.setValue(n,!0)}else e in this&&Reflect.set(this,e,n)}Reflect.deleteProperty(this,"__pendingProps")}}__isRecord(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}__getHostElement(){return this}__initHostBindings(){}};var F=new Map,ct=0;function O(o){let t=`scope_${ct++}`;return F.set(t,o),t}function H(o){return F.get(o)}function V(o){F.delete(o)}var z=/^fluff:(if|for|switch|text|break):(\d+)$/,d=class{id;startMarker;endMarker;config;subscriptions=[];bindingsSubscriptions=[];host;shadowRoot;parentScope;loopContext={};markerManager;constructor(t,e,n,s,r,i){this.id=t,this.startMarker=e,this.endMarker=n,this.config=i,this.host=s,this.shadowRoot=r}setParentScope(t){this.parentScope=t}setLoopContext(t){this.loopContext=t}setMarkerManager(t){this.markerManager=t}cleanup(){for(let t of this.subscriptions)t.unsubscribe();this.subscriptions.length=0}updateRenderContext(t){}evaluateExpr(t){let e=this.getScope(),n=this.collectLocalsFromScope(e);if(e.host.__evaluateExpr)return e.host.__evaluateExpr(t,n);let s=h.__e[t];if(typeof s=="function")try{return s(e.host,n)}catch{return}}getScope(){if(this.parentScope)return this.parentScope;let t=this.__getFluffElementHost();return t?t.__getScope():{host:this.host,locals:this.loopContext,parent:void 0}}collectLocalsFromScope(t){let e={};return t.parent&&Object.assign(e,this.collectLocalsFromScope(t.parent)),Object.assign(e,t.locals),e}subscribeAndRun(t,e){let n=this.getScope(),s=t.filter(r=>Array.isArray(r)?r.length>0&&!r[0].startsWith("["):!r.startsWith("["));n.host.__subscribeToExpression&&n.host.__subscribeToExpression(s,n,e,this.subscriptions),e()}createChildScope(t){return{host:this.host,locals:t,parent:this.parentScope}}clearContentBetweenMarkersWithCleanup(t){for(let s of t)s.unsubscribe();if(t.length=0,!this.endMarker)return;let e=this.startMarker.parentNode;if(!e)return;let n=this.startMarker.nextSibling;for(;n&&n!==this.endMarker;){let s=n.nextSibling;if(n instanceof Comment){let r=z.exec(n.data);if(r&&this.markerManager){let i=parseInt(r[2],10);this.markerManager.cleanupController(i,n)}}n instanceof HTMLTemplateElement||e.removeChild(n),n=s}}insertBeforeEndMarker(t){if(!this.endMarker)return;let e=this.endMarker.parentNode;e&&e.insertBefore(t,this.endMarker)}refreshParentBindings(){let t=this.startMarker.parentNode;if(!(t instanceof HTMLElement)||!t.hasAttribute("data-lid"))return;let e=this.__getFluffElementHost();if(!e)return;let n=this.getScope();e.__processBindingsOnElementPublic(t,n)}__getFluffElementHost(){return this.host instanceof x?this.host:null}setScopeOnChildren(t,e,n,s,r){if(t instanceof Comment){let i=z.exec(t.data);if(i&&s){let[,a,c]=i,l=parseInt(c,10),u=`/fluff:${a}:${l}`,f=s.getController(l,t),p=f===void 0;if(!f){let b=null,g=t.nextSibling;for(;g;){if(g instanceof Comment&&g.data===u){b=g;break}g=g.nextSibling}f=s.ensureController(l,a,t,b)}f&&(f.setParentScope(e),f.setLoopContext(e.locals),f.updateRenderContext(n),p&&f.initialize())}}else if(t instanceof x)t.__loopContext=e.locals,t.__parentScope=e,this.processBindingsOnNode(t,e,r);else if(t instanceof HTMLElement&&customElements.get(t.tagName.toLowerCase())!==void 0){let i=O(e);t.setAttribute("data-fluff-scope-id",i),this.processBindingsOnNode(t,e,r)}else t instanceof Element&&t.hasAttribute("data-lid")&&this.processBindingsOnNode(t,e,r);for(let i of Array.from(t.childNodes))this.setScopeOnChildren(i,e,n,s,r)}cloneAndInsertTemplate(t,e,n,s){let r=t.content.cloneNode(!0);if(!(r instanceof DocumentFragment))throw new Error("Expected DocumentFragment from template clone");let i=this.unwrapNamespaceWrapper(r),a=Array.from(i.childNodes),c=this.createChildScope(e);this.insertBeforeEndMarker(i);for(let l of a)this.setScopeOnChildren(l,c,n,this.markerManager,s)}unwrapNamespaceWrapper(t){if(t.childNodes.length===1){let{firstChild:e}=t;if(e instanceof Element&&e.hasAttribute("data-fluff-ns-wrapper")){let n=document.createDocumentFragment();for(;e.firstChild;)n.appendChild(e.firstChild);return n}}return t}processBindingsOnNode(t,e,n){let s=this.__getFluffElementHost();s&&s.__processBindingsOnElementPublic(t,e,n)}};var k=class extends d{initialize(){}updateRenderContext(t){t&&(t.shouldBreak=!0)}};var P=class extends d{itemTemplate=null;emptyTemplate=null;initialize(){let e=`${this.host.tagName.toLowerCase()}-${this.id}`;this.itemTemplate=this.shadowRoot.querySelector(`template[data-fluff-tpl="${e}"]`),this.emptyTemplate=this.shadowRoot.querySelector(`template[data-fluff-empty="${e}"]`);let[,n,s,,r]=this.config,i=h.__s[n],a=h.__decodeDeps(r)??[],c=()=>{this.clearContentBetweenMarkersWithCleanup(this.bindingsSubscriptions);let l=this.evaluateExpr(s);if(!Array.isArray(l)||l.length===0){this.emptyTemplate&&this.cloneAndInsertTemplate(this.emptyTemplate,this.loopContext,void 0,this.bindingsSubscriptions);return}if(!this.itemTemplate)return;let u={shouldBreak:!1};for(let f=0;f<l.length&&!u.shouldBreak;f++){let p={...this.loopContext,[i]:l[f],$index:f};this.cloneAndInsertTemplate(this.itemTemplate,p,u,this.bindingsSubscriptions)}this.refreshParentBindings()};this.subscribeAndRun(a,c)}};var E=class extends d{templates=[];currentBranchIndex=-1;initialize(){let e=`${this.host.tagName.toLowerCase()}-${this.id}-`;this.templates=Array.from(this.shadowRoot.querySelectorAll(`template[data-fluff-branch^="${e}"]`));let[,n]=this.config,s=[];for(let i of n)if(i.length>1&&i[1]){let a=h.__decodeDeps(i[1]);a&&s.push(...a)}let r=()=>{let i=-1;for(let a=0;a<n.length;a++){let c=n[a];if(c.length===0||c[0]===null){i=a;break}if(this.evaluateExpr(c[0])){i=a;break}}i!==this.currentBranchIndex&&(this.clearContentBetweenMarkersWithCleanup(this.bindingsSubscriptions),this.currentBranchIndex=i,i>=0&&i<this.templates.length&&this.cloneAndInsertTemplate(this.templates[i],this.loopContext,void 0,this.bindingsSubscriptions),this.refreshParentBindings())};this.subscribeAndRun(s,r)}};var I=class extends d{templates=[];initialize(){let e=`${this.host.tagName.toLowerCase()}-${this.id}-`;this.templates=Array.from(this.shadowRoot.querySelectorAll(`template[data-fluff-case^="${e}"]`));let[,n,s,r]=this.config,i=h.__decodeDeps(s)??[],a=()=>{this.clearContentBetweenMarkersWithCleanup(this.bindingsSubscriptions);let c=this.evaluateExpr(n),l=!1,u=!1,f={shouldBreak:!1};for(let p=0;p<r.length&&!f.shouldBreak;p++){let[b,g,S]=r[p],L=this.templates[p];if(!L)continue;let q=b||S!==null&&this.evaluateExpr(S)===c;(u||!l&&q)&&(l=!0,this.cloneAndInsertTemplate(L,this.loopContext,f,this.bindingsSubscriptions),u=g)}this.refreshParentBindings()};this.subscribeAndRun(i,a)}};var M=class extends d{textNode=null;initialize(){this.textNode=document.createTextNode(""),this.insertBeforeEndMarker(this.textNode);let[,t,e,n]=this.config,s=h.__decodeDeps(e)??[],r=n??[],i=()=>{let a=this.evaluateExpr(t);if(this.host.__applyPipesForController){let c=this.getScope(),l=this.collectLocalsFromScope(c);a=this.host.__applyPipesForController(a,r,l)}this.textNode&&(this.textNode.textContent=this.formatValue(a))};this.subscribeAndRun(s,i)}formatValue(t){return typeof t=="string"?t:typeof t=="number"||typeof t=="boolean"||typeof t=="bigint"?String(t):JSON.stringify(t)}};var j=["if","for","text","switch","break"],w=class{controllers=new Map;configs=new Map;host;shadowRoot;constructor(t,e){this.host=t,this.shadowRoot=e}initializeFromConfig(t){this.configs.clear();for(let[n,s]of t)this.configs.set(n,s);for(let[n]of t){let s=this.configs.get(n);if(!s)continue;let{startMarker:r,endMarker:i}=this.findMarkers(n,j[s[0]]);if(!r)continue;let a=this.createController(n,r,i,s);a&&(a.setMarkerManager(this),this.registerController(n,r,a))}let e=[];for(let n of this.controllers.values())e.push(...n.values());for(let n of e)n.initialize()}ensureController(t,e,n,s){let r=this.getController(t,n);if(r)return r;let i=this.configs.get(t);if(!i||j[i[0]]!==e)return;let a=this.createController(t,n,s,i);if(a)return a.setMarkerManager(this),this.registerController(t,n,a),a}getController(t,e){return this.controllers.get(t)?.get(e)}cleanupController(t,e){let n=this.controllers.get(t);if(n){if(e){let s=n.get(e);if(!s)return;s.cleanup(),n.delete(e),n.size===0&&this.controllers.delete(t);return}for(let s of n.values())s.cleanup();this.controllers.delete(t)}}cleanup(){for(let t of this.controllers.values())for(let e of t.values())e.cleanup();this.controllers.clear()}registerController(t,e,n){let s=this.controllers.get(t);s||(s=new Map,this.controllers.set(t,s)),s.set(e,n)}findMarkers(t,e){let n=`fluff:${e}:${t}`,s=`/fluff:${e}:${t}`,r=null,i=null,a=document.createTreeWalker(this.shadowRoot,NodeFilter.SHOW_COMMENT,null),c=a.nextNode();for(;c;)c instanceof Comment&&(c.data===n?r=c:c.data===s&&(i=c)),c=a.nextNode();return{startMarker:r,endMarker:i}}createController(t,e,n,s){switch(s[0]){case 0:return new E(t,e,n,this.host,this.shadowRoot,s);case 1:return new P(t,e,n,this.host,this.shadowRoot,s);case 2:return new M(t,e,n,this.host,this.shadowRoot,s);case 3:return new I(t,e,n,this.host,this.shadowRoot,s);case 4:return new k(t,e,n,this.host,this.shadowRoot,s);default:return null}}};var x=class extends h{__pipes={};_shadowRoot;_subscriptions=[];_initialized=!1;_pendingInit=!1;_markerManager=null;_markerConfigEntries=null;_MarkerManagerClass=null;_scopeId=null;constructor(){super(),this._shadowRoot=this.attachShadow({mode:"open"})}connectedCallback(){if(!this._initialized){if(!h.__areExpressionsReady()){this._pendingInit||(this._pendingInit=!0,h.__addPendingInit(()=>{this._pendingInit=!1,this.connectedCallback()}));return}this._scopeId=this.getAttribute("data-fluff-scope-id"),this._scopeId&&!this.__parentScope&&(this.__parentScope=H(this._scopeId),this.__parentScope&&(this.__loopContext=this.__parentScope.locals));let t=this.getAttribute("data-fluff-loop-context");if(t&&Object.keys(this.__loopContext).length===0)try{this.__loopContext=JSON.parse(t)}catch{}this.__applyPendingProps(),this.__render(),this.__setupBindings(),this.__initHostBindings(),this._scopeId&&this.__processBindings(),this._initialized=!0,"onInit"in this&&typeof this.onInit=="function"&&this.onInit()}}disconnectedCallback(){"onDestroy"in this&&typeof this.onDestroy=="function"&&this.onDestroy(),this.__destroyDirectives(),this._markerManager&&(this._markerManager.cleanup(),this._markerManager=null);for(let t of this._subscriptions)t.unsubscribe();this._subscriptions=[];for(let t of this.__baseSubscriptions)t.unsubscribe();this.__baseSubscriptions=[],this._scopeId&&(V(this._scopeId),this._scopeId=null)}__destroyDirectives(){let t=this._shadowRoot.querySelectorAll("[data-fluff-directives]");for(let e of Array.from(t)){let n=e.__fluffDirectives;if(n){for(let s of n)s.destroy();e.__fluffDirectives=void 0}}}$watch=(t,e)=>(e(""),{unsubscribe:()=>{}});__processBindingsOnElementPublic(t,e,n){this.__processBindingsOnElement(t,e,n)}__setupBindings(){this.__initializeMarkers(w),this.__instantiateDirectives(),this.__processBindings(),this.__initializeMarkersInternal()}__instantiateDirectives(){let t=this._shadowRoot.querySelectorAll("[data-fluff-directives]");for(let e of Array.from(t)){let n=e.getAttribute("data-fluff-directives");if(!n)continue;let s=n.split(","),r=[];for(let i of s){let a=v(i.trim());if(a&&e instanceof HTMLElement){let c=new a;c.__setHostElement(e),r.push(c),c.initialize()}}r.length>0&&(e.__fluffDirectives=r)}}__getPipeFn(t){return this.__pipes[t]??D(t)}__getShadowRoot(){return this._shadowRoot}__setMarkerConfigs(t){this._markerConfigEntries=t}__initializeMarkers(t){this._MarkerManagerClass=t}__initializeMarkersInternal(){!this._markerConfigEntries||!this._MarkerManagerClass||(this._markerManager=new this._MarkerManagerClass(this,this._shadowRoot),this._markerManager.initializeFromConfig(this._markerConfigEntries))}__setChildProperty(t,e,n){if(t instanceof HTMLElement&&t.hasAttribute("x-fluff-component")){let r=t.tagName.toLowerCase();if(customElements.get(r)===void 0){this.__whenDefined(r,()=>{this.__setChildProperty(t,e,n)});return}}super.__setChildProperty(t,e,n);let s=t.__fluffDirectives;if(s)for(let r of s)e in r&&Reflect.set(r,e,n)}__processBindings(){let t=this._shadowRoot.querySelectorAll("[data-lid]"),e=this.__getScope();for(let n of Array.from(t)){let s=n.closest("[x-fluff-component]");s&&s!==n||this.__processBindingsOnElement(n,e)}}};var $=class extends h{_hostElement=null;_initialized=!1;__setHostElement(t){this._hostElement=t,"__assignHostElementProps"in this&&typeof this.__assignHostElementProps=="function"&&this.__assignHostElementProps(t)}initialize(){this._initialized||(this._initialized=!0,this.__applyPendingProps(),this.__initHostBindings(),"onInit"in this&&typeof this.onInit=="function"&&this.onInit())}destroy(){"onDestroy"in this&&typeof this.onDestroy=="function"&&this.onDestroy();for(let t of this.__baseSubscriptions)t.unsubscribe();this.__baseSubscriptions=[]}__getHostElement(){if(!this._hostElement)throw new Error("Directive host element not set");return this._hostElement}};export{K as Component,m as Direction,G as Directive,h as FluffBase,$ as FluffDirective,x as FluffElement,Q as HostBinding,U as HostElement,Z as HostListener,et as Input,nt as LinkedProperty,w as MarkerManager,st as Output,rt as Pipe,_ as Property,y as Publisher,it as Reactive,ot as ViewChild,at as Watch,Y as __registerDirective,v as getDirectiveClass,X as getDirectiveSelectors,D as getPipeTransform,A as pipeRegistry};
@@ -0,0 +1,16 @@
1
+ import type { FluffDirective } from '../runtime/FluffDirective.js';
2
+ type Constructor = new (...args: unknown[]) => object;
3
+ export type DirectiveConstructor = new (...args: unknown[]) => FluffDirective;
4
+ export interface DirectiveConfig {
5
+ selector: string;
6
+ }
7
+ export interface DirectiveMetadata extends DirectiveConfig {
8
+ inputs: Map<string, string>;
9
+ outputs: Map<string, string>;
10
+ }
11
+ export declare function Directive(config: DirectiveConfig): <T extends Constructor>(target: T) => T;
12
+ export declare function getDirectiveMetadata(target: Constructor): DirectiveMetadata | undefined;
13
+ export declare function getDirectiveClass(selector: string): DirectiveConstructor | undefined;
14
+ export declare function getDirectiveSelectors(): string[];
15
+ export declare function __registerDirective(selector: string, directiveClass: DirectiveConstructor): void;
16
+ export {};
@@ -0,0 +1,23 @@
1
+ const directiveRegistry = new Map();
2
+ const directiveMetadataRegistry = new Map();
3
+ export function Directive(config) {
4
+ return function (target) {
5
+ const metadata = {
6
+ ...config, inputs: new Map(), outputs: new Map()
7
+ };
8
+ directiveMetadataRegistry.set(target, metadata);
9
+ return target;
10
+ };
11
+ }
12
+ export function getDirectiveMetadata(target) {
13
+ return directiveMetadataRegistry.get(target);
14
+ }
15
+ export function getDirectiveClass(selector) {
16
+ return directiveRegistry.get(selector);
17
+ }
18
+ export function getDirectiveSelectors() {
19
+ return Array.from(directiveRegistry.keys());
20
+ }
21
+ export function __registerDirective(selector, directiveClass) {
22
+ directiveRegistry.set(selector, directiveClass);
23
+ }
@@ -0,0 +1 @@
1
+ export declare function HostElement(): PropertyDecorator;
@@ -0,0 +1,4 @@
1
+ export function HostElement() {
2
+ return function (_target, _propertyKey) {
3
+ };
4
+ }
package/index.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export { Component } from './decorators/Component.js';
2
2
  export type { ComponentConfig, ComponentMetadata } from './decorators/Component.js';
3
+ export { Directive, getDirectiveClass, getDirectiveSelectors, __registerDirective } from './decorators/Directive.js';
4
+ export type { DirectiveConfig, DirectiveMetadata } from './decorators/Directive.js';
3
5
  export { HostBinding } from './decorators/HostBinding.js';
6
+ export { HostElement } from './decorators/HostElement.js';
4
7
  export { HostListener } from './decorators/HostListener.js';
5
8
  export { Input } from './decorators/Input.js';
6
9
  export { LinkedProperty } from './decorators/LinkedProperty.js';
@@ -12,6 +15,7 @@ export { ViewChild } from './decorators/ViewChild.js';
12
15
  export { Watch } from './decorators/Watch.js';
13
16
  export { FluffBase } from './runtime/FluffElement.js';
14
17
  export { FluffElement } from './runtime/FluffElement.js';
18
+ export { FluffDirective } from './runtime/FluffDirective.js';
15
19
  export { MarkerManager } from './runtime/FluffMarkers.js';
16
20
  export { Property } from './utils/Property.js';
17
21
  export { Publisher } from './utils/Publisher.js';
package/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  export { Component } from './decorators/Component.js';
2
+ export { Directive, getDirectiveClass, getDirectiveSelectors, __registerDirective } from './decorators/Directive.js';
2
3
  export { HostBinding } from './decorators/HostBinding.js';
4
+ export { HostElement } from './decorators/HostElement.js';
3
5
  export { HostListener } from './decorators/HostListener.js';
4
6
  export { Input } from './decorators/Input.js';
5
7
  export { LinkedProperty } from './decorators/LinkedProperty.js';
@@ -10,6 +12,7 @@ export { ViewChild } from './decorators/ViewChild.js';
10
12
  export { Watch } from './decorators/Watch.js';
11
13
  export { FluffBase } from './runtime/FluffElement.js';
12
14
  export { FluffElement } from './runtime/FluffElement.js';
15
+ export { FluffDirective } from './runtime/FluffDirective.js';
13
16
  export { MarkerManager } from './runtime/FluffMarkers.js';
14
17
  export { Property } from './utils/Property.js';
15
18
  export { Publisher } from './utils/Publisher.js';
@@ -0,0 +1,4 @@
1
+ import type { FluffDirective } from '../runtime/FluffDirective.js';
2
+ export interface ElementWithDirectives extends Element {
3
+ __fluffDirectives?: FluffDirective[];
4
+ }
@@ -1,15 +1,8 @@
1
+ import type { Scope } from '../runtime/ScopeRegistry.js';
1
2
  import type { PropertyChain } from './PropertyChain.js';
2
3
  import type { Subscription } from './Subscription.js';
3
- export interface FluffHostScope {
4
- host: FluffHostElement;
5
- locals: Record<string, unknown>;
6
- parent?: FluffHostScope;
7
- }
8
4
  export interface FluffHostElement extends HTMLElement {
9
- __subscribeToExpression?: (deps: PropertyChain[], scope: FluffHostScope, callback: () => void, subscriptions: Subscription[]) => void;
5
+ __subscribeToExpression?: (deps: PropertyChain[], scope: Scope, callback: () => void, subscriptions: Subscription[]) => void;
10
6
  __evaluateExpr?: (exprId: number, locals: Record<string, unknown>) => unknown;
11
- __applyPipesForController?: (value: unknown, pipes: {
12
- name: string;
13
- argExprIds: number[];
14
- }[], locals: Record<string, unknown>) => unknown;
7
+ __applyPipesForController?: (value: unknown, pipes: [number, number[]][], locals: Record<string, unknown>) => unknown;
15
8
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluffjs/fluff",
3
- "version": "0.4.5",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "module": "./index.js",
@@ -1,8 +1,7 @@
1
- import type { BreakMarkerConfig } from '../interfaces/BreakMarkerConfig.js';
1
+ import type { CompactBreakConfig } from './FluffBase.js';
2
2
  import type { RenderContext } from '../interfaces/RenderContext.js';
3
3
  import { MarkerController } from './MarkerController.js';
4
- export declare class BreakController extends MarkerController {
5
- constructor(id: number, startMarker: Comment, endMarker: Comment | null, host: HTMLElement, shadowRoot: ShadowRoot, _config: BreakMarkerConfig);
4
+ export declare class BreakController extends MarkerController<CompactBreakConfig> {
6
5
  initialize(): void;
7
6
  updateRenderContext(renderContext?: RenderContext): void;
8
7
  }
@@ -1,8 +1,5 @@
1
1
  import { MarkerController } from './MarkerController.js';
2
2
  export class BreakController extends MarkerController {
3
- constructor(id, startMarker, endMarker, host, shadowRoot, _config) {
4
- super(id, startMarker, endMarker, host, shadowRoot);
5
- }
6
3
  initialize() {
7
4
  }
8
5
  updateRenderContext(renderContext) {
@@ -4,46 +4,34 @@ import { Property } from '../utils/Property.js';
4
4
  import type { Scope } from './ScopeRegistry.js';
5
5
  export type ExpressionFn = (t: unknown, l: Record<string, unknown>) => unknown;
6
6
  export type HandlerFn = (t: unknown, l: Record<string, unknown>, e: unknown) => void;
7
- export interface BindingInfo {
8
- n: string;
9
- b: 'property' | 'event' | 'two-way' | 'class' | 'style' | 'ref';
10
- e?: number;
11
- h?: number;
12
- t?: string;
13
- d?: PropertyChain[];
14
- s?: string;
15
- p?: {
16
- n: string;
17
- a: number[];
18
- }[];
19
- }
20
7
  /**
21
- * Compact Binding Format (Decoder)
8
+ * Compact Binding Format
22
9
  *
23
- * Bindings are received as tuples to minimize bundle size. All strings are
10
+ * Bindings are consumed as tuples to minimize bundle size. All strings are
24
11
  * stored in a global string table (FluffBase.__s) and referenced by index.
25
12
  *
26
13
  * Format: [nameIdx, bindType, deps, id, extras?]
27
14
  *
28
- * - nameIdx: Index into __s for the binding name (e.g., "value", "click")
29
- * - bindType: Numeric binding type (0=property, 1=event, 2=two-way, 3=class, 4=style, 5=ref)
30
- * - deps: Array of interned dependency chains, or null. Each dep is either:
31
- * - A single index (for simple property like "foo")
32
- * - An array of indices (for nested property chain like ["device", "name"])
33
- * - id: Expression ID (for property/two-way/class/style) or Handler ID (for event), or null
34
- * - extras: Optional object with additional binding metadata:
35
- * - t: Target property name for two-way bindings
36
- * - s: Subscribe source name
37
- * - p: Pipes array of [pipeNameIdx, argExprIds[]]
15
+ * [0] nameIdx: Index into __s for the binding target name (e.g., "value", "click")
16
+ * [1] bindType: Numeric binding type: 0=property, 1=event, 2=two-way, 3=class, 4=style, 5=ref
17
+ * [2] deps: Array of dependency chains (CompactDep[]) or null. Each dep is either:
18
+ * - A single number index (simple property, e.g. "foo")
19
+ * - An array of number indices (nested chain, e.g. ["device", "name"])
20
+ * [3] id: Expression ID (property/two-way/class/style) or Handler ID (event), or null
21
+ * [4] extras: Optional object with additional binding metadata:
22
+ * - t: Target property name string for two-way bindings
23
+ * - s: Subscribe source property name string
24
+ * - p: Pipes as [pipeNameIdx, argExprIds[]][] (compact pipe format)
38
25
  *
39
26
  * The string table is set via FluffBase.__setExpressionTable(exprs, handlers, strings).
40
- * __decodeBinding() converts CompactBinding back to BindingInfo for runtime use.
41
27
  */
42
28
  type CompactDep = number | number[];
43
29
  export type CompactBinding = [
44
30
  number,
45
31
  number,
32
+ // [1] bindType: 0=property, 1=event, 2=two-way, 3=class, 4=style, 5=ref
46
33
  CompactDep[] | null,
34
+ // [2] deps
47
35
  number | null,
48
36
  {
49
37
  t?: string;
@@ -51,20 +39,38 @@ export type CompactBinding = [
51
39
  p?: [number, number[]][];
52
40
  }?
53
41
  ];
54
- export type CompactMarkerConfig = [0, ([number | null, CompactDep[] | null] | [])[]] | [1, number, number, boolean, CompactDep[] | null, number | null] | [2, number, CompactDep[] | null, [number, number[]][] | null] | [3, number, CompactDep[] | null, [boolean, boolean, number | null][]] | [4];
42
+ /**
43
+ * Compact Marker Config Format (Decoder)
44
+ *
45
+ * Marker configs use the same string table as bindings. Type is numeric:
46
+ * 0=if, 1=for, 2=text, 3=switch, 4=break
47
+ *
48
+ * Format varies by type:
49
+ * - if: [0, branches[]] where branch = [exprId?, deps?]
50
+ * - for: [1, iteratorIdx, iterableExprId, hasEmpty, deps?, trackByIdx?]
51
+ * - text: [2, exprId, deps?, pipes?]
52
+ * - switch: [3, expressionExprId, deps?, cases[]]
53
+ * - break: [4]
54
+ *
55
+ * deps are interned as CompactDep[] (same as bindings)
56
+ * pipes are [pipeNameIdx, argExprIds[]][]
57
+ */
58
+ export type CompactIfConfig = [0, ([number | null, CompactDep[] | null] | [])[]];
59
+ export type CompactForConfig = [1, number, number, boolean, CompactDep[] | null, number | null];
60
+ export type CompactTextConfig = [2, number, CompactDep[] | null, [number, number[]][] | null];
61
+ export type CompactSwitchConfig = [3, number, CompactDep[] | null, [boolean, boolean, number | null][]];
62
+ export type CompactBreakConfig = [4];
63
+ export type CompactMarkerConfig = CompactIfConfig | CompactForConfig | CompactTextConfig | CompactSwitchConfig | CompactBreakConfig;
55
64
  export declare abstract class FluffBase extends HTMLElement {
56
65
  static __e: ExpressionFn[];
57
66
  static __h: HandlerFn[];
58
67
  static __s: string[];
59
- static __bindings: Record<string, (CompactBinding | BindingInfo)[]>;
68
+ static __bindings: Record<string, CompactBinding[]>;
60
69
  private static __expressionsReady;
61
70
  private static readonly __pendingInitCallbacks;
62
71
  static __setExpressionTable(expressions: ExpressionFn[], handlers: HandlerFn[], strings?: string[]): void;
63
- static __decodeString(idx: number): string;
64
72
  static __decodeDep(dep: number | number[]): string | string[];
65
73
  static __decodeDeps(deps: (number | number[])[] | null): (string | string[])[] | undefined;
66
- static __decodeMarkerConfig(compact: CompactMarkerConfig): unknown;
67
- private static __decodeBinding;
68
74
  static __areExpressionsReady(): boolean;
69
75
  static __addPendingInit(callback: () => void): void;
70
76
  __parentScope?: Scope;
@@ -73,24 +79,17 @@ export declare abstract class FluffBase extends HTMLElement {
73
79
  __getScope(): Scope;
74
80
  __subscribeToExpression(deps: PropertyChain[], scope: Scope, callback: () => void, subscriptions: Subscription[]): void;
75
81
  __evaluateExpr(exprId: number, locals: Record<string, unknown>): unknown;
76
- __applyPipesForController(value: unknown, pipes: {
77
- name: string;
78
- argExprIds: number[];
79
- }[], locals: Record<string, unknown>): unknown;
82
+ __applyPipesForController(value: unknown, pipes: [number, number[]][], locals: Record<string, unknown>): unknown;
80
83
  protected __processBindingsOnElement(el: Element, scope: Scope, subscriptions?: Subscription[]): void;
81
84
  private __getBindingsForLid;
82
- private static __decodeBindingAny;
83
- private __isBindingsMap;
84
- protected __applyBindingWithScope(el: Element, binding: BindingInfo, scope: Scope, subscriptions?: Subscription[]): void;
85
+ private __isCompactBindingArray;
86
+ protected __applyBindingWithScope(el: Element, binding: CompactBinding, scope: Scope, subscriptions?: Subscription[]): void;
85
87
  protected __getCompiledExprFn(exprId: number): ExpressionFn;
86
88
  protected __getCompiledHandlerFn(handlerId: number): HandlerFn;
87
- protected __applyPipes(value: unknown, pipes: {
88
- n: string;
89
- a: number[];
90
- }[], locals: Record<string, unknown>): unknown;
91
89
  protected __getPipeFn(_name: string): ((value: unknown, ...args: unknown[]) => unknown) | undefined;
92
90
  protected __subscribeToExpressionInScope(deps: PropertyChain[] | undefined, scope: Scope, callback: () => void, subscriptions?: Subscription[]): void;
93
91
  private __subscribeToPropertyChain;
92
+ private __subscribeToProp;
94
93
  private __subscribeToNestedChain;
95
94
  protected __getReactivePropFromScope(propName: string, scope: Scope): Property<unknown> | undefined;
96
95
  protected __setChildProperty(el: Element, propName: string, value: unknown): void;
@@ -103,5 +102,14 @@ export declare abstract class FluffBase extends HTMLElement {
103
102
  private __applyClassBindingWithScope;
104
103
  private __applyStyleBindingWithScope;
105
104
  private __hasStyle;
105
+ protected __createProp<T>(nameOrIdx: string | number, options: T | {
106
+ initialValue: T;
107
+ [key: string]: unknown;
108
+ }): Property<T>;
109
+ protected __defineClassHostBinding(name: string, className: string, privateName: string): void;
110
+ protected __applyPendingProps(): void;
111
+ protected __isRecord(value: unknown): value is Record<string, unknown>;
112
+ protected __getHostElement(): HTMLElement;
113
+ protected __initHostBindings(): void;
106
114
  }
107
115
  export {};