@vielzeug/ore 2.0.3 → 2.0.6

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 (102) hide show
  1. package/dist/_component-class.cjs.map +1 -1
  2. package/dist/_component-class.js.map +1 -1
  3. package/dist/base-element.cjs +1 -1
  4. package/dist/base-element.cjs.map +1 -1
  5. package/dist/base-element.d.ts.map +1 -1
  6. package/dist/base-element.js +1 -1
  7. package/dist/base-element.js.map +1 -1
  8. package/dist/context.cjs.map +1 -1
  9. package/dist/context.js.map +1 -1
  10. package/dist/define.cjs.map +1 -1
  11. package/dist/define.d.ts +3 -3
  12. package/dist/define.d.ts.map +1 -1
  13. package/dist/define.js.map +1 -1
  14. package/dist/directives/each.cjs.map +1 -1
  15. package/dist/directives/each.d.ts.map +1 -1
  16. package/dist/directives/each.js.map +1 -1
  17. package/dist/directives/unsafe-html.cjs.map +1 -1
  18. package/dist/directives/unsafe-html.d.ts.map +1 -1
  19. package/dist/directives/unsafe-html.js.map +1 -1
  20. package/dist/directives/when.cjs.map +1 -1
  21. package/dist/directives/when.d.ts.map +1 -1
  22. package/dist/directives/when.js.map +1 -1
  23. package/dist/errors.cjs +1 -1
  24. package/dist/errors.cjs.map +1 -1
  25. package/dist/errors.d.ts +0 -2
  26. package/dist/errors.d.ts.map +1 -1
  27. package/dist/errors.js +1 -1
  28. package/dist/errors.js.map +1 -1
  29. package/dist/forms/field.cjs +1 -1
  30. package/dist/forms/field.cjs.map +1 -1
  31. package/dist/forms/field.d.ts +1 -1
  32. package/dist/forms/field.d.ts.map +1 -1
  33. package/dist/forms/field.js +1 -1
  34. package/dist/forms/field.js.map +1 -1
  35. package/dist/host-bind.cjs +1 -1
  36. package/dist/host-bind.cjs.map +1 -1
  37. package/dist/host-bind.js +1 -1
  38. package/dist/host-bind.js.map +1 -1
  39. package/dist/index.cjs +1 -1
  40. package/dist/index.d.ts +14 -14
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +1 -1
  43. package/dist/ore.cjs +2 -2
  44. package/dist/ore.cjs.map +1 -1
  45. package/dist/ore.iife.js +2 -2
  46. package/dist/ore.iife.js.map +1 -1
  47. package/dist/ore.js +2 -2
  48. package/dist/ore.js.map +1 -1
  49. package/dist/props.cjs.map +1 -1
  50. package/dist/props.js.map +1 -1
  51. package/dist/runtime.cjs.map +1 -1
  52. package/dist/runtime.d.ts +3 -3
  53. package/dist/runtime.d.ts.map +1 -1
  54. package/dist/runtime.js.map +1 -1
  55. package/dist/slots.cjs.map +1 -1
  56. package/dist/slots.d.ts.map +1 -1
  57. package/dist/slots.js.map +1 -1
  58. package/dist/template/binding-types.d.ts +3 -3
  59. package/dist/template/binding-types.d.ts.map +1 -1
  60. package/dist/template/bindings.cjs +1 -1
  61. package/dist/template/bindings.cjs.map +1 -1
  62. package/dist/template/bindings.d.ts +1 -1
  63. package/dist/template/bindings.d.ts.map +1 -1
  64. package/dist/template/bindings.js +1 -1
  65. package/dist/template/bindings.js.map +1 -1
  66. package/dist/template/compiler.cjs +1 -1
  67. package/dist/template/compiler.cjs.map +1 -1
  68. package/dist/template/compiler.d.ts.map +1 -1
  69. package/dist/template/compiler.js +1 -1
  70. package/dist/template/compiler.js.map +1 -1
  71. package/dist/template/instantiator.cjs +1 -1
  72. package/dist/template/instantiator.cjs.map +1 -1
  73. package/dist/template/instantiator.js +1 -1
  74. package/dist/template/instantiator.js.map +1 -1
  75. package/dist/template/result.cjs.map +1 -1
  76. package/dist/template/result.d.ts.map +1 -1
  77. package/dist/template/result.js.map +1 -1
  78. package/dist/testing/index.d.ts +3 -3
  79. package/dist/testing/index.d.ts.map +1 -1
  80. package/dist/testing/mount.cjs +1 -1
  81. package/dist/testing/mount.cjs.map +1 -1
  82. package/dist/testing/mount.d.ts +11 -11
  83. package/dist/testing/mount.d.ts.map +1 -1
  84. package/dist/testing/mount.js +1 -1
  85. package/dist/testing/mount.js.map +1 -1
  86. package/dist/testing/render-hook.cjs.map +1 -1
  87. package/dist/testing/render-hook.d.ts +2 -2
  88. package/dist/testing/render-hook.d.ts.map +1 -1
  89. package/dist/testing/render-hook.js.map +1 -1
  90. package/dist/testing.cjs.map +1 -1
  91. package/dist/testing.js.map +1 -1
  92. package/dist/utils/dom.cjs +1 -1
  93. package/dist/utils/dom.cjs.map +1 -1
  94. package/dist/utils/dom.js +1 -1
  95. package/dist/utils/dom.js.map +1 -1
  96. package/dist/utils/emit.cjs.map +1 -1
  97. package/dist/utils/emit.d.ts +1 -1
  98. package/dist/utils/emit.d.ts.map +1 -1
  99. package/dist/utils/emit.js.map +1 -1
  100. package/package.json +28 -28
  101. package/dist/template/binding-types.cjs +0 -1
  102. package/dist/template/binding-types.js +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"_component-class.cjs","names":[],"sources":["../src/_component-class.ts"],"sourcesContent":["import type { ComponentDefinition } from './component-types';\n\nimport { BaseElement } from './base-element';\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { normalizePropDefinition, type PropInputDefs, type PropsDef, validatePropDefs } from './props';\nimport { toKebab } from './utils/dom';\n\n/**\n * Builds the element class without touching the browser registry. Keeping\n * declaration work separate from registration makes the latter the only\n * irreversible global side effect in the component-definition path.\n *\n * @internal\n */\nexport function createComponentClass<Props extends Record<string, unknown>>(\n tag: string,\n definition: ComponentDefinition<Props>,\n): CustomElementConstructor {\n const { props: propDefs } = definition;\n\n const normalizedPropDefs: PropsDef<Props> | undefined = (() => {\n if (!propDefs) return undefined;\n\n const errors = validatePropDefs(propDefs as Record<string, unknown>);\n\n if (errors.length > 0) throw new OreApiError(ORE_ERRORS.validationFailed(tag, errors));\n\n const normalized: PropInputDefs = {};\n\n for (const [key, def] of Object.entries(propDefs)) {\n normalized[key] = normalizePropDefinition(def, key);\n }\n\n return normalized as PropsDef<Props>;\n })();\n\n const observedAttrs = normalizedPropDefs ? Object.keys(normalizedPropDefs).map(toKebab) : [];\n\n const ComponentClass = class extends BaseElement {\n static override _definition = definition as unknown as ComponentDefinition;\n static override _normalizedPropDefs = normalizedPropDefs as PropsDef<Record<never, never>> | undefined;\n static override formAssociated = definition.formAssociated ?? false;\n static override observedAttributes = observedAttrs;\n };\n\n return ComponentClass;\n}\n"],"mappings":"sHAcA,SAAgB,EACd,EACA,EAC0B,CAC1B,GAAM,CAAE,MAAO,GAAa,EAEtB,OAAyD,CAC7D,GAAI,CAAC,EAAU,OAEf,IAAM,EAAS,EAAA,iBAAiB,CAAmC,EAEnE,GAAI,EAAO,OAAS,EAAG,MAAM,IAAI,EAAA,YAAY,EAAA,WAAW,iBAAiB,EAAK,CAAM,CAAC,EAErF,IAAM,EAA4B,CAAC,EAEnC,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,CAAQ,EAC9C,EAAW,GAAO,EAAA,wBAAwB,EAAK,CAAG,EAGpD,OAAO,CACT,EAAA,CAAG,EAEG,EAAgB,EAAqB,OAAO,KAAK,CAAkB,CAAC,CAAC,IAAI,EAAA,OAAO,EAAI,CAAC,EAS3F,OAAO,cAP8B,EAAA,WAAY,CAC/C,OAAgB,YAAc,EAC9B,OAAgB,oBAAsB,EACtC,OAAgB,eAAiB,EAAW,gBAAkB,GAC9D,OAAgB,mBAAqB,CACvC,CAGF"}
1
+ {"version":3,"file":"_component-class.cjs","names":[],"sources":["../src/_component-class.ts"],"sourcesContent":["import { BaseElement } from './base-element';\nimport type { ComponentDefinition } from './component-types';\nimport { ORE_ERRORS, OreApiError } from './errors';\nimport { normalizePropDefinition, type PropInputDefs, type PropsDef, validatePropDefs } from './props';\nimport { toKebab } from './utils/dom';\n\n/**\n * Builds the element class without touching the browser registry. Keeping\n * declaration work separate from registration makes the latter the only\n * irreversible global side effect in the component-definition path.\n *\n * @internal\n */\nexport function createComponentClass<Props extends Record<string, unknown>>(\n tag: string,\n definition: ComponentDefinition<Props>,\n): CustomElementConstructor {\n const { props: propDefs } = definition;\n\n const normalizedPropDefs: PropsDef<Props> | undefined = (() => {\n if (!propDefs) return undefined;\n\n const errors = validatePropDefs(propDefs as Record<string, unknown>);\n\n if (errors.length > 0) throw new OreApiError(ORE_ERRORS.validationFailed(tag, errors));\n\n const normalized: PropInputDefs = {};\n\n for (const [key, def] of Object.entries(propDefs)) {\n normalized[key] = normalizePropDefinition(def, key);\n }\n\n return normalized as PropsDef<Props>;\n })();\n\n const observedAttrs = normalizedPropDefs ? Object.keys(normalizedPropDefs).map(toKebab) : [];\n\n const ComponentClass = class extends BaseElement {\n static override _definition = definition as unknown as ComponentDefinition;\n static override _normalizedPropDefs = normalizedPropDefs as PropsDef<Record<never, never>> | undefined;\n static override formAssociated = definition.formAssociated ?? false;\n static override observedAttributes = observedAttrs;\n };\n\n return ComponentClass;\n}\n"],"mappings":"sHAaA,SAAgB,EACd,EACA,EAC0B,CAC1B,GAAM,CAAE,MAAO,GAAa,EAEtB,OAAyD,CAC7D,GAAI,CAAC,EAAU,OAEf,IAAM,EAAS,EAAA,iBAAiB,CAAmC,EAEnE,GAAI,EAAO,OAAS,EAAG,MAAM,IAAI,EAAA,YAAY,EAAA,WAAW,iBAAiB,EAAK,CAAM,CAAC,EAErF,IAAM,EAA4B,CAAC,EAEnC,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,CAAQ,EAC9C,EAAW,GAAO,EAAA,wBAAwB,EAAK,CAAG,EAGpD,OAAO,CACT,EAAA,CAAG,EAEG,EAAgB,EAAqB,OAAO,KAAK,CAAkB,CAAC,CAAC,IAAI,EAAA,OAAO,EAAI,CAAC,EAS3F,OAAO,cAP8B,EAAA,WAAY,CAC/C,OAAgB,YAAc,EAC9B,OAAgB,oBAAsB,EACtC,OAAgB,eAAiB,EAAW,gBAAkB,GAC9D,OAAgB,mBAAqB,CACvC,CAGF"}
@@ -1 +1 @@
1
- {"version":3,"file":"_component-class.js","names":[],"sources":["../src/_component-class.ts"],"sourcesContent":["import type { ComponentDefinition } from './component-types';\n\nimport { BaseElement } from './base-element';\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { normalizePropDefinition, type PropInputDefs, type PropsDef, validatePropDefs } from './props';\nimport { toKebab } from './utils/dom';\n\n/**\n * Builds the element class without touching the browser registry. Keeping\n * declaration work separate from registration makes the latter the only\n * irreversible global side effect in the component-definition path.\n *\n * @internal\n */\nexport function createComponentClass<Props extends Record<string, unknown>>(\n tag: string,\n definition: ComponentDefinition<Props>,\n): CustomElementConstructor {\n const { props: propDefs } = definition;\n\n const normalizedPropDefs: PropsDef<Props> | undefined = (() => {\n if (!propDefs) return undefined;\n\n const errors = validatePropDefs(propDefs as Record<string, unknown>);\n\n if (errors.length > 0) throw new OreApiError(ORE_ERRORS.validationFailed(tag, errors));\n\n const normalized: PropInputDefs = {};\n\n for (const [key, def] of Object.entries(propDefs)) {\n normalized[key] = normalizePropDefinition(def, key);\n }\n\n return normalized as PropsDef<Props>;\n })();\n\n const observedAttrs = normalizedPropDefs ? Object.keys(normalizedPropDefs).map(toKebab) : [];\n\n const ComponentClass = class extends BaseElement {\n static override _definition = definition as unknown as ComponentDefinition;\n static override _normalizedPropDefs = normalizedPropDefs as PropsDef<Record<never, never>> | undefined;\n static override formAssociated = definition.formAssociated ?? false;\n static override observedAttributes = observedAttrs;\n };\n\n return ComponentClass;\n}\n"],"mappings":"8NAcA,SAAgB,EACd,EACA,EAC0B,CAC1B,GAAM,CAAE,MAAO,GAAa,EAEtB,OAAyD,CAC7D,GAAI,CAAC,EAAU,OAEf,IAAM,EAAS,EAAiB,CAAmC,EAEnE,GAAI,EAAO,OAAS,EAAG,MAAM,IAAI,EAAY,EAAW,iBAAiB,EAAK,CAAM,CAAC,EAErF,IAAM,EAA4B,CAAC,EAEnC,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,CAAQ,EAC9C,EAAW,GAAO,EAAwB,EAAK,CAAG,EAGpD,OAAO,CACT,EAAA,CAAG,EAEG,EAAgB,EAAqB,OAAO,KAAK,CAAkB,CAAC,CAAC,IAAI,CAAO,EAAI,CAAC,EAS3F,OAAO,cAP8B,CAAY,CAC/C,OAAgB,YAAc,EAC9B,OAAgB,oBAAsB,EACtC,OAAgB,eAAiB,EAAW,gBAAkB,GAC9D,OAAgB,mBAAqB,CACvC,CAGF"}
1
+ {"version":3,"file":"_component-class.js","names":[],"sources":["../src/_component-class.ts"],"sourcesContent":["import { BaseElement } from './base-element';\nimport type { ComponentDefinition } from './component-types';\nimport { ORE_ERRORS, OreApiError } from './errors';\nimport { normalizePropDefinition, type PropInputDefs, type PropsDef, validatePropDefs } from './props';\nimport { toKebab } from './utils/dom';\n\n/**\n * Builds the element class without touching the browser registry. Keeping\n * declaration work separate from registration makes the latter the only\n * irreversible global side effect in the component-definition path.\n *\n * @internal\n */\nexport function createComponentClass<Props extends Record<string, unknown>>(\n tag: string,\n definition: ComponentDefinition<Props>,\n): CustomElementConstructor {\n const { props: propDefs } = definition;\n\n const normalizedPropDefs: PropsDef<Props> | undefined = (() => {\n if (!propDefs) return undefined;\n\n const errors = validatePropDefs(propDefs as Record<string, unknown>);\n\n if (errors.length > 0) throw new OreApiError(ORE_ERRORS.validationFailed(tag, errors));\n\n const normalized: PropInputDefs = {};\n\n for (const [key, def] of Object.entries(propDefs)) {\n normalized[key] = normalizePropDefinition(def, key);\n }\n\n return normalized as PropsDef<Props>;\n })();\n\n const observedAttrs = normalizedPropDefs ? Object.keys(normalizedPropDefs).map(toKebab) : [];\n\n const ComponentClass = class extends BaseElement {\n static override _definition = definition as unknown as ComponentDefinition;\n static override _normalizedPropDefs = normalizedPropDefs as PropsDef<Record<never, never>> | undefined;\n static override formAssociated = definition.formAssociated ?? false;\n static override observedAttributes = observedAttrs;\n };\n\n return ComponentClass;\n}\n"],"mappings":"8NAaA,SAAgB,EACd,EACA,EAC0B,CAC1B,GAAM,CAAE,MAAO,GAAa,EAEtB,OAAyD,CAC7D,GAAI,CAAC,EAAU,OAEf,IAAM,EAAS,EAAiB,CAAmC,EAEnE,GAAI,EAAO,OAAS,EAAG,MAAM,IAAI,EAAY,EAAW,iBAAiB,EAAK,CAAM,CAAC,EAErF,IAAM,EAA4B,CAAC,EAEnC,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,CAAQ,EAC9C,EAAW,GAAO,EAAwB,EAAK,CAAG,EAGpD,OAAO,CACT,EAAA,CAAG,EAEG,EAAgB,EAAqB,OAAO,KAAK,CAAkB,CAAC,CAAC,IAAI,CAAO,EAAI,CAAC,EAS3F,OAAO,cAP8B,CAAY,CAC/C,OAAgB,YAAc,EAC9B,OAAgB,oBAAsB,EACtC,OAAgB,eAAiB,EAAW,gBAAkB,GAC9D,OAAgB,mBAAqB,CACvC,CAGF"}
@@ -1,2 +1,2 @@
1
- const e=require("./errors.cjs"),t=require("./runtime.cjs"),n=require("./props.cjs");require("./template/result.cjs");const r=require("./utils/css.cjs");let i=require("@vielzeug/ripple");var a={SETUP_DONE:`setup_done`,SETUP_RUNNING:`setup_running`,UNINITIALIZED:`uninitialized`,UNMOUNTED:`unmounted`},o={CONNECT:`ore:connect`,DISCONNECT:`ore:disconnect`},s=()=>({formResetCallbacks:[],generation:0,mountCallbacks:[],phase:a.UNINITIALIZED,scope:(0,i.createScope)(),templateResult:null}),c=e=>(typeof e==`object`||typeof e==`function`)&&e!==null&&`then`in e&&typeof e.then==`function`,l=class extends HTMLElement{static _definition;static _normalizedPropDefs;static formAssociated=!1;static observedAttributes=[];_component;constructor(){super();let e=this.constructor._definition;e?.shadow!==!1&&this.attachShadow({mode:`open`,...e?.shadow}),this._component=s()}connectedCallback(){(0,i.untrack)(()=>{this._component.phase===a.UNINITIALIZED&&this._runSetup(),this._init()}),this.dispatchEvent(new CustomEvent(o.CONNECT,{bubbles:!1,composed:!1}))}attributeChangedCallback(e,t,r){if(t===r)return;let a=n.getPropMeta(this,e);if(!a)return;let o=a.parse(r);Object.is((0,i.untrack)(()=>a.signal.value),o)||(a.signal.value=o)}disconnectedCallback(){this._component.generation++,this._component.phase=a.UNMOUNTED,this.dispatchEvent(new CustomEvent(o.DISCONNECT,{bubbles:!1,composed:!1})),this._resetSetupState()}_resetSetupState(){this._component.scope.dispose(),this._component.formResetCallbacks=[],this._component.mountCallbacks=[],this._component.phase=a.UNINITIALIZED,this._component.scope=(0,i.createScope)(),this._component.templateResult=null}formResetCallback(){for(let e of this._component.formResetCallbacks)try{e()}catch(e){this._reportLifecycleError(e,`form-reset`)}}_reportLifecycleError(t,n){let r=t instanceof Error?t:Error(String(t)),i=new e.OreLifecycleError(`<${this.localName}> failed during ${this._component.phase} (${n})`,{cause:r,component:this.localName,phase:n});e.reportRuntimeError(i,this)}_runSetup(){this._component.phase=a.SETUP_RUNNING;let r=this.constructor._definition,i=this.constructor._normalizedPropDefs,o=t.createRuntimeContext(this);try{let s;if(this._component.scope.run(()=>{s=t.runWithContext(o,()=>{let e=i?n.createProps(this,i):{};return r.setup(e)})}),this._component.mountCallbacks.push(...o.mountCallbacks),this._component.formResetCallbacks.push(...o.formResetCallbacks),c(s))throw new e.OreApiError(e.ORE_ERRORS.asyncSetupUnsupported);this._component.templateResult=s??null,this._component.phase=a.SETUP_DONE}catch(e){throw this._reportLifecycleError(e,`setup`),this._resetSetupState(),e}}_isStale(e){return this._component.generation!==e||!this.isConnected}_applyResult(e){if(!e)return;let n=this.shadowRoot??this,r=t.createRuntimeContext(this);n.replaceChildren(),this._component.scope.run(()=>{t.runWithContext(r,()=>{e.mount(n,null,t.onCleanup)})})}_init(){this._applyStyles(),this._mountTemplate(),this._component.phase===a.SETUP_DONE&&this._scheduleMountCallbacks()}_applyStyles(){let e=this.constructor._definition;this.shadowRoot&&e?.styles?.length&&(this.shadowRoot.adoptedStyleSheets=e.styles.map(r.loadStylesheet))}_mountTemplate(){let e=this._component.templateResult;e&&this._applyResult(e)}_scheduleMountCallbacks(){if(this._component.mountCallbacks.length===0)return;let e=this._component.generation,n=t.beginPendingWork();queueMicrotask(()=>{try{if(this._isStale(e))return;let n=this._component.mountCallbacks.splice(0);for(let e of n)try{let n=t.createRuntimeContext(this);this._component.scope.run(()=>{t.runWithContext(n,()=>{let n=e();typeof n==`function`&&t.onCleanup(n)})}),n.mountCallbacks.length>0&&this._component.mountCallbacks.push(...n.mountCallbacks),n.formResetCallbacks.length>0&&this._component.formResetCallbacks.push(...n.formResetCallbacks)}catch(e){this._reportLifecycleError(e,`mounted`)}this._component.mountCallbacks.length>0&&this._scheduleMountCallbacks()}finally{n()}})}};exports.BaseElement=l;
1
+ const e=require("./errors.cjs"),t=require("./runtime.cjs"),n=require("./props.cjs"),r=require("./utils/css.cjs");let i=require("@vielzeug/ripple");var a={SETUP_DONE:`setup_done`,SETUP_RUNNING:`setup_running`,UNINITIALIZED:`uninitialized`,UNMOUNTED:`unmounted`},o={CONNECT:`ore:connect`,DISCONNECT:`ore:disconnect`},s=()=>({formResetCallbacks:[],generation:0,mountCallbacks:[],phase:a.UNINITIALIZED,scope:(0,i.createScope)(),templateResult:null}),c=e=>(typeof e==`object`||typeof e==`function`)&&e!==null&&`then`in e&&typeof e.then==`function`,l=class extends HTMLElement{static _definition;static _normalizedPropDefs;static formAssociated=!1;static observedAttributes=[];_component;constructor(){super();let e=this.constructor._definition;e?.shadow!==!1&&this.attachShadow({mode:`open`,...e?.shadow}),this._component=s()}connectedCallback(){(0,i.untrack)(()=>{this._component.phase===a.UNINITIALIZED&&this._runSetup(),this._init()}),this.dispatchEvent(new CustomEvent(o.CONNECT,{bubbles:!1,composed:!1}))}attributeChangedCallback(e,t,r){if(t===r)return;let a=n.getPropMeta(this,e);if(!a)return;let o=a.parse(r);Object.is((0,i.untrack)(()=>a.signal.value),o)||(a.signal.value=o)}disconnectedCallback(){this._component.generation++,this._component.phase=a.UNMOUNTED,this.dispatchEvent(new CustomEvent(o.DISCONNECT,{bubbles:!1,composed:!1})),this._resetSetupState()}_resetSetupState(){this._component.scope.dispose(),this._component.formResetCallbacks=[],this._component.mountCallbacks=[],this._component.phase=a.UNINITIALIZED,this._component.scope=(0,i.createScope)(),this._component.templateResult=null}formResetCallback(){for(let e of this._component.formResetCallbacks)try{e()}catch(e){this._reportLifecycleError(e,`form-reset`)}}_reportLifecycleError(t,n){let r=t instanceof Error?t:Error(String(t)),i=new e.OreLifecycleError(`<${this.localName}> failed during ${this._component.phase} (${n})`,{cause:r,component:this.localName,phase:n});e.reportRuntimeError(i,this)}_runSetup(){this._component.phase=a.SETUP_RUNNING;let r=this.constructor._definition,i=this.constructor._normalizedPropDefs,o=t.createRuntimeContext(this);try{let s;if(this._component.scope.run(()=>{s=t.runWithContext(o,()=>{let e=i?n.createProps(this,i):{};return r.setup(e)})}),this._component.mountCallbacks.push(...o.mountCallbacks),this._component.formResetCallbacks.push(...o.formResetCallbacks),c(s))throw new e.OreApiError(e.ORE_ERRORS.asyncSetupUnsupported);this._component.templateResult=s??null,this._component.phase=a.SETUP_DONE}catch(e){throw this._reportLifecycleError(e,`setup`),this._resetSetupState(),e}}_isStale(e){return this._component.generation!==e||!this.isConnected}_applyResult(e){if(!e)return;let n=this.shadowRoot??this,r=t.createRuntimeContext(this);n.replaceChildren(),this._component.scope.run(()=>{t.runWithContext(r,()=>{e.mount(n,null,t.onCleanup)})})}_init(){this._applyStyles(),this._mountTemplate(),this._component.phase===a.SETUP_DONE&&this._scheduleMountCallbacks()}_applyStyles(){let e=this.constructor._definition;this.shadowRoot&&e?.styles?.length&&(this.shadowRoot.adoptedStyleSheets=e.styles.map(r.loadStylesheet))}_mountTemplate(){let e=this._component.templateResult;e&&this._applyResult(e)}_scheduleMountCallbacks(){if(this._component.mountCallbacks.length===0)return;let e=this._component.generation,n=t.beginPendingWork();queueMicrotask(()=>{try{if(this._isStale(e))return;let n=this._component.mountCallbacks.splice(0);for(let e=0;e<n.length;e++){let r=n[e];try{let e=t.createRuntimeContext(this);this._component.scope.run(()=>{t.runWithContext(e,()=>{let e=r();typeof e==`function`&&t.onCleanup(e)})}),e.mountCallbacks.length>0&&n.push(...e.mountCallbacks),e.formResetCallbacks.length>0&&this._component.formResetCallbacks.push(...e.formResetCallbacks)}catch(e){this._reportLifecycleError(e,`mounted`)}}}finally{n()}})}};exports.BaseElement=l;
2
2
  //# sourceMappingURL=base-element.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"base-element.cjs","names":[],"sources":["../src/base-element.ts"],"sourcesContent":["import { createScope, type Scope, untrack } from '@vielzeug/ripple';\n\nimport type { ComponentDefinition } from './component-types';\n\nimport { OreApiError, type OreErrorPhase, OreLifecycleError, ORE_ERRORS, reportRuntimeError } from './errors';\nimport { createProps, getPropMeta, type InferProps, type PropInputDefs, type PropsDef } from './props';\nimport {\n beginPendingWork,\n createRuntimeContext,\n type OnFormResetCallback,\n type OnMountedCallback,\n onCleanup,\n runWithContext,\n} from './runtime';\nimport { type HTMLResult } from './template/result';\nimport { loadStylesheet } from './utils/css';\n\n// ─── Component phases & lifecycle events ──────────────────────────────────────\n// Internal to BaseElement — the only state machine and event dispatcher in the package.\n\nconst ComponentPhase = {\n SETUP_DONE: 'setup_done',\n SETUP_RUNNING: 'setup_running',\n UNINITIALIZED: 'uninitialized',\n UNMOUNTED: 'unmounted',\n} as const;\n\ntype ComponentPhase = (typeof ComponentPhase)[keyof typeof ComponentPhase];\n\nconst LIFECYCLE_EVENTS = {\n CONNECT: 'ore:connect',\n DISCONNECT: 'ore:disconnect',\n} as const;\n\n// ─── Internal component state ─────────────────────────────────────────────────\n\ntype ComponentState = {\n /** Registered via `onFormReset()` — persists across mount callbacks, unlike `mountCallbacks`. */\n formResetCallbacks: OnFormResetCallback[];\n /** Incremented on every disconnect — invalidates queued mount callbacks. */\n generation: number;\n mountCallbacks: OnMountedCallback[];\n phase: ComponentPhase;\n scope: Scope;\n templateResult: HTMLResult | null;\n};\n\nconst createComponentState = (): ComponentState => ({\n formResetCallbacks: [],\n generation: 0,\n mountCallbacks: [],\n phase: ComponentPhase.UNINITIALIZED,\n scope: createScope(),\n templateResult: null,\n});\n\nconst isPromiseLike = (value: unknown): value is PromiseLike<unknown> =>\n (typeof value === 'object' || typeof value === 'function') &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function';\n\n// ─── BaseElement ──────────────────────────────────────────────────────────────\n\n/**\n * Phase transitions:\n *\n * ```\n * UNINITIALIZED ──_runSetup()──► SETUP_DONE\n * SETUP_DONE ──disconnectedCallback()──► UNMOUNTED ──(reset)──► UNINITIALIZED\n * ```\n *\n * `generation` increments on every disconnect. Scheduled mount callbacks capture\n * it so callbacks belonging to a disconnected instance cannot run after a\n * reconnect (see `_isStale`).\n *\n * Why this lives on the class instead of a standalone pure reducer: every\n * transition here is triggered by running actual user code (`def.setup()`,\n * `onMounted` callbacks) inside a reactive `scope.run()` + `runWithContext()`\n * — there is no meaningful \"decide the next phase\" step that can be separated\n * from \"run the side-effecting thing that produces the phase change\" without\n * introducing a data-only effect-description layer that this package has no\n * other use for. That's why the methods below stay as direct, readable\n * procedural steps instead of a reducer + effect interpreter.\n */\nexport class BaseElement extends HTMLElement {\n static _definition: ComponentDefinition;\n static _normalizedPropDefs: PropsDef<Record<never, never>> | undefined;\n static formAssociated = false;\n static observedAttributes: string[] = [];\n\n private _component: ComponentState;\n\n constructor() {\n super();\n\n const def = (this.constructor as typeof BaseElement)._definition;\n\n if (def?.shadow !== false) {\n this.attachShadow({ mode: 'open', ...(def?.shadow as Partial<ShadowRootInit> | undefined) });\n }\n\n this._component = createComponentState();\n }\n\n connectedCallback(): void {\n untrack(() => {\n if (this._component.phase === ComponentPhase.UNINITIALIZED) this._runSetup();\n\n this._init();\n });\n this.dispatchEvent(new CustomEvent(LIFECYCLE_EVENTS.CONNECT, { bubbles: false, composed: false }));\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n const propMeta = getPropMeta(this, name);\n\n if (!propMeta) return;\n\n const parsed = propMeta.parse(newValue);\n\n if (\n !Object.is(\n untrack(() => propMeta.signal.value),\n parsed,\n )\n )\n propMeta.signal.value = parsed as never;\n }\n\n disconnectedCallback(): void {\n this._component.generation++;\n this._component.phase = ComponentPhase.UNMOUNTED;\n this.dispatchEvent(new CustomEvent(LIFECYCLE_EVENTS.DISCONNECT, { bubbles: false, composed: false }));\n this._resetSetupState();\n }\n\n /** Dispose one connection's resources before its state can be rebuilt. */\n private _resetSetupState(): void {\n this._component.scope.dispose();\n // Reset mutable fields for next connection, keeping the same object for stable references.\n this._component.formResetCallbacks = [];\n this._component.mountCallbacks = [];\n this._component.phase = ComponentPhase.UNINITIALIZED;\n this._component.scope = createScope();\n this._component.templateResult = null;\n }\n\n /**\n * Native form-association lifecycle callback — the browser calls this on every\n * `formAssociated: true` element inside a `<form>` when that form is reset.\n * Runs every `onFormReset()` callback registered during `setup()`.\n */\n formResetCallback(): void {\n for (const callback of this._component.formResetCallbacks) {\n try {\n callback();\n } catch (error) {\n this._reportLifecycleError(error, 'form-reset');\n }\n }\n }\n\n private _reportLifecycleError(error: unknown, phase: OreErrorPhase): void {\n const err = error instanceof Error ? error : new Error(String(error));\n const oreError = new OreLifecycleError(`<${this.localName}> failed during ${this._component.phase} (${phase})`, {\n cause: err,\n component: this.localName,\n phase,\n });\n\n reportRuntimeError(oreError, this);\n }\n\n private _runSetup(): void {\n this._component.phase = ComponentPhase.SETUP_RUNNING;\n\n const def = (this.constructor as typeof BaseElement)._definition;\n const normalizedPropDefs = (this.constructor as typeof BaseElement)._normalizedPropDefs;\n const ctx = createRuntimeContext(this);\n\n try {\n let setupResult: HTMLResult | null | undefined;\n\n this._component.scope.run(() => {\n setupResult = runWithContext(ctx, () => {\n const setupProps = normalizedPropDefs\n ? createProps(this, normalizedPropDefs)\n : ({} as InferProps<PropInputDefs>);\n\n return def.setup(setupProps as InferProps<PropInputDefs>);\n });\n });\n this._component.mountCallbacks.push(...ctx.mountCallbacks);\n this._component.formResetCallbacks.push(...ctx.formResetCallbacks);\n\n if (isPromiseLike(setupResult)) throw new OreApiError(ORE_ERRORS.asyncSetupUnsupported);\n\n this._component.templateResult = setupResult ?? null;\n this._component.phase = ComponentPhase.SETUP_DONE;\n } catch (error) {\n this._reportLifecycleError(error, 'setup');\n // Setup is atomic: a failed run must not leave partial effects or cleanups\n // live until a later disconnect.\n this._resetSetupState();\n throw error;\n }\n }\n\n private _isStale(capturedGeneration: number): boolean {\n return this._component.generation !== capturedGeneration || !this.isConnected;\n }\n\n private _applyResult(result: HTMLResult | null): void {\n if (!result) return;\n\n const host: Element | ShadowRoot = this.shadowRoot ?? this;\n\n // Mounting can register component cleanup, so preserve a runtime context here too.\n const context = createRuntimeContext(this);\n\n host.replaceChildren();\n this._component.scope.run(() => {\n runWithContext(context, () => {\n result.mount(host, null, onCleanup);\n });\n });\n }\n\n private _init(): void {\n this._applyStyles();\n this._mountTemplate();\n\n // Setup completes before the template mounts, so callbacks always observe live DOM.\n if (this._component.phase === ComponentPhase.SETUP_DONE) this._scheduleMountCallbacks();\n }\n\n private _applyStyles(): void {\n const def = (this.constructor as typeof BaseElement)._definition;\n\n if (this.shadowRoot && def?.styles?.length) {\n this.shadowRoot.adoptedStyleSheets = def.styles.map(loadStylesheet);\n }\n }\n\n private _mountTemplate(): void {\n const result = this._component.templateResult;\n\n if (!result) return;\n\n this._applyResult(result);\n }\n\n private _scheduleMountCallbacks(): void {\n if (this._component.mountCallbacks.length === 0) return;\n\n const capturedGeneration = this._component.generation;\n // Tracked as pending work for the duration of this microtask — ended in a `finally`\n // so a thrown callback (already caught per-callback below, but defensive here too)\n // never leaves the counter stuck above zero. See runtime.ts's beginPendingWork().\n const endWork = beginPendingWork();\n\n queueMicrotask(() => {\n try {\n if (this._isStale(capturedGeneration)) return;\n\n // Snapshot callbacks so in-loop registrations don't extend this iteration.\n const batch = this._component.mountCallbacks.splice(0);\n\n for (const callback of batch) {\n try {\n const nestedCtx = createRuntimeContext(this);\n\n this._component.scope.run(() => {\n runWithContext(nestedCtx, () => {\n const cleanup = callback();\n\n if (typeof cleanup === 'function') onCleanup(cleanup);\n });\n });\n\n if (nestedCtx.mountCallbacks.length > 0) {\n this._component.mountCallbacks.push(...nestedCtx.mountCallbacks);\n }\n\n if (nestedCtx.formResetCallbacks.length > 0) {\n this._component.formResetCallbacks.push(...nestedCtx.formResetCallbacks);\n }\n } catch (error) {\n this._reportLifecycleError(error, 'mounted');\n }\n }\n\n // If nested onMounted calls registered new callbacks, schedule them with\n // a fresh token check in the next microtask. This happens *before* endWork()\n // below runs so the counter never dips to zero between the two schedules.\n if (this._component.mountCallbacks.length > 0) {\n this._scheduleMountCallbacks();\n }\n } finally {\n endWork();\n }\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"base-element.cjs","names":[],"sources":["../src/base-element.ts"],"sourcesContent":["import { createScope, type Scope, untrack } from '@vielzeug/ripple';\n\nimport type { ComponentDefinition } from './component-types';\n\nimport { ORE_ERRORS, OreApiError, type OreErrorPhase, OreLifecycleError, reportRuntimeError } from './errors';\nimport { createProps, getPropMeta, type InferProps, type PropInputDefs, type PropsDef } from './props';\nimport {\n beginPendingWork,\n createRuntimeContext,\n type OnFormResetCallback,\n type OnMountedCallback,\n onCleanup,\n runWithContext,\n} from './runtime';\nimport type { HTMLResult } from './template/result';\nimport { loadStylesheet } from './utils/css';\n\n// ─── Component phases & lifecycle events ──────────────────────────────────────\n// Internal to BaseElement — the only state machine and event dispatcher in the package.\n\nconst ComponentPhase = {\n SETUP_DONE: 'setup_done',\n SETUP_RUNNING: 'setup_running',\n UNINITIALIZED: 'uninitialized',\n UNMOUNTED: 'unmounted',\n} as const;\n\ntype ComponentPhase = (typeof ComponentPhase)[keyof typeof ComponentPhase];\n\nconst LIFECYCLE_EVENTS = {\n CONNECT: 'ore:connect',\n DISCONNECT: 'ore:disconnect',\n} as const;\n\n// ─── Internal component state ─────────────────────────────────────────────────\n\ntype ComponentState = {\n /** Registered via `onFormReset()` — persists across mount callbacks, unlike `mountCallbacks`. */\n formResetCallbacks: OnFormResetCallback[];\n /** Incremented on every disconnect — invalidates queued mount callbacks. */\n generation: number;\n mountCallbacks: OnMountedCallback[];\n phase: ComponentPhase;\n scope: Scope;\n templateResult: HTMLResult | null;\n};\n\nconst createComponentState = (): ComponentState => ({\n formResetCallbacks: [],\n generation: 0,\n mountCallbacks: [],\n phase: ComponentPhase.UNINITIALIZED,\n scope: createScope(),\n templateResult: null,\n});\n\nconst isPromiseLike = (value: unknown): value is PromiseLike<unknown> =>\n (typeof value === 'object' || typeof value === 'function') &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function';\n\n// ─── BaseElement ──────────────────────────────────────────────────────────────\n\n/**\n * Phase transitions:\n *\n * ```\n * UNINITIALIZED ──_runSetup()──► SETUP_DONE\n * SETUP_DONE ──disconnectedCallback()──► UNMOUNTED ──(reset)──► UNINITIALIZED\n * ```\n *\n * `generation` increments on every disconnect. Scheduled mount callbacks capture\n * it so callbacks belonging to a disconnected instance cannot run after a\n * reconnect (see `_isStale`).\n *\n * Why this lives on the class instead of a standalone pure reducer: every\n * transition here is triggered by running actual user code (`def.setup()`,\n * `onMounted` callbacks) inside a reactive `scope.run()` + `runWithContext()`\n * — there is no meaningful \"decide the next phase\" step that can be separated\n * from \"run the side-effecting thing that produces the phase change\" without\n * introducing a data-only effect-description layer that this package has no\n * other use for. That's why the methods below stay as direct, readable\n * procedural steps instead of a reducer + effect interpreter.\n */\nexport class BaseElement extends HTMLElement {\n static _definition: ComponentDefinition;\n static _normalizedPropDefs: PropsDef<Record<never, never>> | undefined;\n static formAssociated = false;\n static observedAttributes: string[] = [];\n\n private _component: ComponentState;\n\n constructor() {\n super();\n\n const def = (this.constructor as typeof BaseElement)._definition;\n\n if (def?.shadow !== false) {\n this.attachShadow({ mode: 'open', ...(def?.shadow as Partial<ShadowRootInit> | undefined) });\n }\n\n this._component = createComponentState();\n }\n\n connectedCallback(): void {\n untrack(() => {\n if (this._component.phase === ComponentPhase.UNINITIALIZED) this._runSetup();\n\n this._init();\n });\n this.dispatchEvent(new CustomEvent(LIFECYCLE_EVENTS.CONNECT, { bubbles: false, composed: false }));\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n const propMeta = getPropMeta(this, name);\n\n if (!propMeta) return;\n\n const parsed = propMeta.parse(newValue);\n\n if (\n !Object.is(\n untrack(() => propMeta.signal.value),\n parsed,\n )\n )\n propMeta.signal.value = parsed as never;\n }\n\n disconnectedCallback(): void {\n this._component.generation++;\n this._component.phase = ComponentPhase.UNMOUNTED;\n this.dispatchEvent(new CustomEvent(LIFECYCLE_EVENTS.DISCONNECT, { bubbles: false, composed: false }));\n this._resetSetupState();\n }\n\n /** Dispose one connection's resources before its state can be rebuilt. */\n private _resetSetupState(): void {\n this._component.scope.dispose();\n // Reset mutable fields for next connection, keeping the same object for stable references.\n this._component.formResetCallbacks = [];\n this._component.mountCallbacks = [];\n this._component.phase = ComponentPhase.UNINITIALIZED;\n this._component.scope = createScope();\n this._component.templateResult = null;\n }\n\n /**\n * Native form-association lifecycle callback — the browser calls this on every\n * `formAssociated: true` element inside a `<form>` when that form is reset.\n * Runs every `onFormReset()` callback registered during `setup()`.\n */\n formResetCallback(): void {\n for (const callback of this._component.formResetCallbacks) {\n try {\n callback();\n } catch (error) {\n this._reportLifecycleError(error, 'form-reset');\n }\n }\n }\n\n private _reportLifecycleError(error: unknown, phase: OreErrorPhase): void {\n const err = error instanceof Error ? error : new Error(String(error));\n const oreError = new OreLifecycleError(`<${this.localName}> failed during ${this._component.phase} (${phase})`, {\n cause: err,\n component: this.localName,\n phase,\n });\n\n reportRuntimeError(oreError, this);\n }\n\n private _runSetup(): void {\n this._component.phase = ComponentPhase.SETUP_RUNNING;\n\n const def = (this.constructor as typeof BaseElement)._definition;\n const normalizedPropDefs = (this.constructor as typeof BaseElement)._normalizedPropDefs;\n const ctx = createRuntimeContext(this);\n\n try {\n let setupResult: HTMLResult | null | undefined;\n\n this._component.scope.run(() => {\n setupResult = runWithContext(ctx, () => {\n const setupProps = normalizedPropDefs\n ? createProps(this, normalizedPropDefs)\n : ({} as InferProps<PropInputDefs>);\n\n return def.setup(setupProps as InferProps<PropInputDefs>);\n });\n });\n this._component.mountCallbacks.push(...ctx.mountCallbacks);\n this._component.formResetCallbacks.push(...ctx.formResetCallbacks);\n\n if (isPromiseLike(setupResult)) throw new OreApiError(ORE_ERRORS.asyncSetupUnsupported);\n\n this._component.templateResult = setupResult ?? null;\n this._component.phase = ComponentPhase.SETUP_DONE;\n } catch (error) {\n this._reportLifecycleError(error, 'setup');\n // Setup is atomic: a failed run must not leave partial effects or cleanups\n // live until a later disconnect.\n this._resetSetupState();\n throw error;\n }\n }\n\n private _isStale(capturedGeneration: number): boolean {\n return this._component.generation !== capturedGeneration || !this.isConnected;\n }\n\n private _applyResult(result: HTMLResult | null): void {\n if (!result) return;\n\n const host: Element | ShadowRoot = this.shadowRoot ?? this;\n\n // Mounting can register component cleanup, so preserve a runtime context here too.\n const context = createRuntimeContext(this);\n\n host.replaceChildren();\n this._component.scope.run(() => {\n runWithContext(context, () => {\n result.mount(host, null, onCleanup);\n });\n });\n }\n\n private _init(): void {\n this._applyStyles();\n this._mountTemplate();\n\n // Setup completes before the template mounts, so callbacks always observe live DOM.\n if (this._component.phase === ComponentPhase.SETUP_DONE) this._scheduleMountCallbacks();\n }\n\n private _applyStyles(): void {\n const def = (this.constructor as typeof BaseElement)._definition;\n\n if (this.shadowRoot && def?.styles?.length) {\n this.shadowRoot.adoptedStyleSheets = def.styles.map(loadStylesheet);\n }\n }\n\n private _mountTemplate(): void {\n const result = this._component.templateResult;\n\n if (!result) return;\n\n this._applyResult(result);\n }\n\n private _scheduleMountCallbacks(): void {\n if (this._component.mountCallbacks.length === 0) return;\n\n const capturedGeneration = this._component.generation;\n // Tracked as pending work for the duration of this microtask — ended in a `finally`\n // so a thrown callback (already caught per-callback below, but defensive here too)\n // never leaves the counter stuck above zero. See runtime.ts's beginPendingWork().\n const endWork = beginPendingWork();\n\n queueMicrotask(() => {\n try {\n if (this._isStale(capturedGeneration)) return;\n\n // Snapshot callbacks so in-loop registrations don't extend this iteration.\n // Nested onMounted registrations are appended to `batch` and run in the same\n // microtask — no recursive scheduling. Index-based loop because the array\n // grows as nested callbacks are discovered.\n const batch = this._component.mountCallbacks.splice(0);\n\n for (let i = 0; i < batch.length; i++) {\n const callback = batch[i];\n\n try {\n const nestedCtx = createRuntimeContext(this);\n\n this._component.scope.run(() => {\n runWithContext(nestedCtx, () => {\n const cleanup = callback();\n\n if (typeof cleanup === 'function') onCleanup(cleanup);\n });\n });\n\n if (nestedCtx.mountCallbacks.length > 0) {\n batch.push(...nestedCtx.mountCallbacks);\n }\n\n if (nestedCtx.formResetCallbacks.length > 0) {\n this._component.formResetCallbacks.push(...nestedCtx.formResetCallbacks);\n }\n } catch (error) {\n this._reportLifecycleError(error, 'mounted');\n }\n }\n } finally {\n endWork();\n }\n });\n }\n}\n"],"mappings":"mJAoBA,IAAM,EAAiB,CACrB,WAAY,aACZ,cAAe,gBACf,cAAe,gBACf,UAAW,WACb,EAIM,EAAmB,CACvB,QAAS,cACT,WAAY,gBACd,EAeM,OAA8C,CAClD,mBAAoB,CAAC,EACrB,WAAY,EACZ,eAAgB,CAAC,EACjB,MAAO,EAAe,cACtB,OAAA,EAAO,EAAA,YAAA,CAAY,EACnB,eAAgB,IAClB,GAEM,EAAiB,IACpB,OAAO,GAAU,UAAY,OAAO,GAAU,aAC/C,IAAU,MACV,SAAU,GACV,OAAO,EAAM,MAAS,WAyBX,EAAb,cAAiC,WAAY,CAC3C,OAAO,YACP,OAAO,oBACP,OAAO,eAAiB,GACxB,OAAO,mBAA+B,CAAC,EAEvC,WAEA,aAAc,CACZ,MAAM,EAEN,IAAM,EAAO,KAAK,YAAmC,YAEjD,GAAK,SAAW,IAClB,KAAK,aAAa,CAAE,KAAM,OAAQ,GAAI,GAAK,MAA+C,CAAC,EAG7F,KAAK,WAAa,EAAqB,CACzC,CAEA,mBAA0B,EACxB,EAAA,EAAA,QAAA,KAAc,CACR,KAAK,WAAW,QAAU,EAAe,eAAe,KAAK,UAAU,EAE3E,KAAK,MAAM,CACb,CAAC,EACD,KAAK,cAAc,IAAI,YAAY,EAAiB,QAAS,CAAE,QAAS,GAAO,SAAU,EAAM,CAAC,CAAC,CACnG,CAEA,yBAAyB,EAAc,EAAyB,EAA+B,CAC7F,GAAI,IAAa,EAAU,OAE3B,IAAM,EAAW,EAAA,YAAY,KAAM,CAAI,EAEvC,GAAI,CAAC,EAAU,OAEf,IAAM,EAAS,EAAS,MAAM,CAAQ,EAGnC,OAAO,IAAA,EACN,EAAA,QAAA,KAAc,EAAS,OAAO,KAAK,EACnC,CACF,IAEA,EAAS,OAAO,MAAQ,EAC5B,CAEA,sBAA6B,CAC3B,KAAK,WAAW,aAChB,KAAK,WAAW,MAAQ,EAAe,UACvC,KAAK,cAAc,IAAI,YAAY,EAAiB,WAAY,CAAE,QAAS,GAAO,SAAU,EAAM,CAAC,CAAC,EACpG,KAAK,iBAAiB,CACxB,CAGA,kBAAiC,CAC/B,KAAK,WAAW,MAAM,QAAQ,EAE9B,KAAK,WAAW,mBAAqB,CAAC,EACtC,KAAK,WAAW,eAAiB,CAAC,EAClC,KAAK,WAAW,MAAQ,EAAe,cACvC,KAAK,WAAW,OAAA,EAAQ,EAAA,YAAA,CAAY,EACpC,KAAK,WAAW,eAAiB,IACnC,CAOA,mBAA0B,CACxB,IAAK,IAAM,KAAY,KAAK,WAAW,mBACrC,GAAI,CACF,EAAS,CACX,OAAS,EAAO,CACd,KAAK,sBAAsB,EAAO,YAAY,CAChD,CAEJ,CAEA,sBAA8B,EAAgB,EAA4B,CACxE,IAAM,EAAM,aAAiB,MAAQ,EAAY,MAAM,OAAO,CAAK,CAAC,EAC9D,EAAW,IAAI,EAAA,kBAAkB,IAAI,KAAK,UAAU,kBAAkB,KAAK,WAAW,MAAM,IAAI,EAAM,GAAI,CAC9G,MAAO,EACP,UAAW,KAAK,UAChB,OACF,CAAC,EAED,EAAA,mBAAmB,EAAU,IAAI,CACnC,CAEA,WAA0B,CACxB,KAAK,WAAW,MAAQ,EAAe,cAEvC,IAAM,EAAO,KAAK,YAAmC,YAC/C,EAAsB,KAAK,YAAmC,oBAC9D,EAAM,EAAA,qBAAqB,IAAI,EAErC,GAAI,CACF,IAAI,EAcJ,GAZA,KAAK,WAAW,MAAM,QAAU,CAC9B,EAAc,EAAA,eAAe,MAAW,CACtC,IAAM,EAAa,EACf,EAAA,YAAY,KAAM,CAAkB,EACnC,CAAC,EAEN,OAAO,EAAI,MAAM,CAAuC,CAC1D,CAAC,CACH,CAAC,EACD,KAAK,WAAW,eAAe,KAAK,GAAG,EAAI,cAAc,EACzD,KAAK,WAAW,mBAAmB,KAAK,GAAG,EAAI,kBAAkB,EAE7D,EAAc,CAAW,EAAG,MAAM,IAAI,EAAA,YAAY,EAAA,WAAW,qBAAqB,EAEtF,KAAK,WAAW,eAAiB,GAAe,KAChD,KAAK,WAAW,MAAQ,EAAe,UACzC,OAAS,EAAO,CAKd,MAJA,KAAK,sBAAsB,EAAO,OAAO,EAGzC,KAAK,iBAAiB,EAChB,CACR,CACF,CAEA,SAAiB,EAAqC,CACpD,OAAO,KAAK,WAAW,aAAe,GAAsB,CAAC,KAAK,WACpE,CAEA,aAAqB,EAAiC,CACpD,GAAI,CAAC,EAAQ,OAEb,IAAM,EAA6B,KAAK,YAAc,KAGhD,EAAU,EAAA,qBAAqB,IAAI,EAEzC,EAAK,gBAAgB,EACrB,KAAK,WAAW,MAAM,QAAU,CAC9B,EAAA,eAAe,MAAe,CAC5B,EAAO,MAAM,EAAM,KAAM,EAAA,SAAS,CACpC,CAAC,CACH,CAAC,CACH,CAEA,OAAsB,CACpB,KAAK,aAAa,EAClB,KAAK,eAAe,EAGhB,KAAK,WAAW,QAAU,EAAe,YAAY,KAAK,wBAAwB,CACxF,CAEA,cAA6B,CAC3B,IAAM,EAAO,KAAK,YAAmC,YAEjD,KAAK,YAAc,GAAK,QAAQ,SAClC,KAAK,WAAW,mBAAqB,EAAI,OAAO,IAAI,EAAA,cAAc,EAEtE,CAEA,gBAA+B,CAC7B,IAAM,EAAS,KAAK,WAAW,eAE1B,GAEL,KAAK,aAAa,CAAM,CAC1B,CAEA,yBAAwC,CACtC,GAAI,KAAK,WAAW,eAAe,SAAW,EAAG,OAEjD,IAAM,EAAqB,KAAK,WAAW,WAIrC,EAAU,EAAA,iBAAiB,EAEjC,mBAAqB,CACnB,GAAI,CACF,GAAI,KAAK,SAAS,CAAkB,EAAG,OAMvC,IAAM,EAAQ,KAAK,WAAW,eAAe,OAAO,CAAC,EAErD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACrC,IAAM,EAAW,EAAM,GAEvB,GAAI,CACF,IAAM,EAAY,EAAA,qBAAqB,IAAI,EAE3C,KAAK,WAAW,MAAM,QAAU,CAC9B,EAAA,eAAe,MAAiB,CAC9B,IAAM,EAAU,EAAS,EAErB,OAAO,GAAY,YAAY,EAAA,UAAU,CAAO,CACtD,CAAC,CACH,CAAC,EAEG,EAAU,eAAe,OAAS,GACpC,EAAM,KAAK,GAAG,EAAU,cAAc,EAGpC,EAAU,mBAAmB,OAAS,GACxC,KAAK,WAAW,mBAAmB,KAAK,GAAG,EAAU,kBAAkB,CAE3E,OAAS,EAAO,CACd,KAAK,sBAAsB,EAAO,SAAS,CAC7C,CACF,CACF,QAAU,CACR,EAAQ,CACV,CACF,CAAC,CACH,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"base-element.d.ts","sourceRoot":"","sources":["../src/base-element.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAG7D,OAAO,EAAiE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AA2DvG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,WAAY,SAAQ,WAAW;IAC1C,MAAM,CAAC,WAAW,EAAE,mBAAmB,CAAC;IACxC,MAAM,CAAC,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC;IACvE,MAAM,CAAC,cAAc,UAAS;IAC9B,MAAM,CAAC,kBAAkB,EAAE,MAAM,EAAE,CAAM;IAEzC,OAAO,CAAC,UAAU,CAAiB;;IAcnC,iBAAiB,IAAI,IAAI;IASzB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAkB9F,oBAAoB,IAAI,IAAI;IAO5B,0EAA0E;IAC1E,OAAO,CAAC,gBAAgB;IAUxB;;;;OAIG;IACH,iBAAiB,IAAI,IAAI;IAUzB,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,SAAS;IAmCjB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,KAAK;IAQb,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,uBAAuB;CAmDhC"}
1
+ {"version":3,"file":"base-element.d.ts","sourceRoot":"","sources":["../src/base-element.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAG7D,OAAO,EAAiE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AA2DvG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,WAAY,SAAQ,WAAW;IAC1C,MAAM,CAAC,WAAW,EAAE,mBAAmB,CAAC;IACxC,MAAM,CAAC,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC;IACvE,MAAM,CAAC,cAAc,UAAS;IAC9B,MAAM,CAAC,kBAAkB,EAAE,MAAM,EAAE,CAAM;IAEzC,OAAO,CAAC,UAAU,CAAiB;;IAcnC,iBAAiB,IAAI,IAAI;IASzB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAkB9F,oBAAoB,IAAI,IAAI;IAO5B,0EAA0E;IAC1E,OAAO,CAAC,gBAAgB;IAUxB;;;;OAIG;IACH,iBAAiB,IAAI,IAAI;IAUzB,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,SAAS;IAmCjB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,KAAK;IAQb,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,uBAAuB;CAiDhC"}
@@ -1,2 +1,2 @@
1
- import{ORE_ERRORS as e,OreApiError as t,OreLifecycleError as n,reportRuntimeError as r}from"./errors.js";import{beginPendingWork as i,createRuntimeContext as a,onCleanup as o,runWithContext as s}from"./runtime.js";import{createProps as c,getPropMeta as l}from"./props.js";import"./template/result.js";import{loadStylesheet as u}from"./utils/css.js";import{createScope as d,untrack as f}from"@vielzeug/ripple";var p={SETUP_DONE:`setup_done`,SETUP_RUNNING:`setup_running`,UNINITIALIZED:`uninitialized`,UNMOUNTED:`unmounted`},m={CONNECT:`ore:connect`,DISCONNECT:`ore:disconnect`},h=()=>({formResetCallbacks:[],generation:0,mountCallbacks:[],phase:p.UNINITIALIZED,scope:d(),templateResult:null}),g=e=>(typeof e==`object`||typeof e==`function`)&&e!==null&&`then`in e&&typeof e.then==`function`,_=class extends HTMLElement{static _definition;static _normalizedPropDefs;static formAssociated=!1;static observedAttributes=[];_component;constructor(){super();let e=this.constructor._definition;e?.shadow!==!1&&this.attachShadow({mode:`open`,...e?.shadow}),this._component=h()}connectedCallback(){f(()=>{this._component.phase===p.UNINITIALIZED&&this._runSetup(),this._init()}),this.dispatchEvent(new CustomEvent(m.CONNECT,{bubbles:!1,composed:!1}))}attributeChangedCallback(e,t,n){if(t===n)return;let r=l(this,e);if(!r)return;let i=r.parse(n);Object.is(f(()=>r.signal.value),i)||(r.signal.value=i)}disconnectedCallback(){this._component.generation++,this._component.phase=p.UNMOUNTED,this.dispatchEvent(new CustomEvent(m.DISCONNECT,{bubbles:!1,composed:!1})),this._resetSetupState()}_resetSetupState(){this._component.scope.dispose(),this._component.formResetCallbacks=[],this._component.mountCallbacks=[],this._component.phase=p.UNINITIALIZED,this._component.scope=d(),this._component.templateResult=null}formResetCallback(){for(let e of this._component.formResetCallbacks)try{e()}catch(e){this._reportLifecycleError(e,`form-reset`)}}_reportLifecycleError(e,t){let i=e instanceof Error?e:Error(String(e)),a=new n(`<${this.localName}> failed during ${this._component.phase} (${t})`,{cause:i,component:this.localName,phase:t});r(a,this)}_runSetup(){this._component.phase=p.SETUP_RUNNING;let n=this.constructor._definition,r=this.constructor._normalizedPropDefs,i=a(this);try{let a;if(this._component.scope.run(()=>{a=s(i,()=>{let e=r?c(this,r):{};return n.setup(e)})}),this._component.mountCallbacks.push(...i.mountCallbacks),this._component.formResetCallbacks.push(...i.formResetCallbacks),g(a))throw new t(e.asyncSetupUnsupported);this._component.templateResult=a??null,this._component.phase=p.SETUP_DONE}catch(e){throw this._reportLifecycleError(e,`setup`),this._resetSetupState(),e}}_isStale(e){return this._component.generation!==e||!this.isConnected}_applyResult(e){if(!e)return;let t=this.shadowRoot??this,n=a(this);t.replaceChildren(),this._component.scope.run(()=>{s(n,()=>{e.mount(t,null,o)})})}_init(){this._applyStyles(),this._mountTemplate(),this._component.phase===p.SETUP_DONE&&this._scheduleMountCallbacks()}_applyStyles(){let e=this.constructor._definition;this.shadowRoot&&e?.styles?.length&&(this.shadowRoot.adoptedStyleSheets=e.styles.map(u))}_mountTemplate(){let e=this._component.templateResult;e&&this._applyResult(e)}_scheduleMountCallbacks(){if(this._component.mountCallbacks.length===0)return;let e=this._component.generation,t=i();queueMicrotask(()=>{try{if(this._isStale(e))return;let t=this._component.mountCallbacks.splice(0);for(let e of t)try{let t=a(this);this._component.scope.run(()=>{s(t,()=>{let t=e();typeof t==`function`&&o(t)})}),t.mountCallbacks.length>0&&this._component.mountCallbacks.push(...t.mountCallbacks),t.formResetCallbacks.length>0&&this._component.formResetCallbacks.push(...t.formResetCallbacks)}catch(e){this._reportLifecycleError(e,`mounted`)}this._component.mountCallbacks.length>0&&this._scheduleMountCallbacks()}finally{t()}})}};export{_ as BaseElement};
1
+ import{ORE_ERRORS as e,OreApiError as t,OreLifecycleError as n,reportRuntimeError as r}from"./errors.js";import{beginPendingWork as i,createRuntimeContext as a,onCleanup as o,runWithContext as s}from"./runtime.js";import{createProps as c,getPropMeta as l}from"./props.js";import{loadStylesheet as u}from"./utils/css.js";import{createScope as d,untrack as f}from"@vielzeug/ripple";var p={SETUP_DONE:`setup_done`,SETUP_RUNNING:`setup_running`,UNINITIALIZED:`uninitialized`,UNMOUNTED:`unmounted`},m={CONNECT:`ore:connect`,DISCONNECT:`ore:disconnect`},h=()=>({formResetCallbacks:[],generation:0,mountCallbacks:[],phase:p.UNINITIALIZED,scope:d(),templateResult:null}),g=e=>(typeof e==`object`||typeof e==`function`)&&e!==null&&`then`in e&&typeof e.then==`function`,_=class extends HTMLElement{static _definition;static _normalizedPropDefs;static formAssociated=!1;static observedAttributes=[];_component;constructor(){super();let e=this.constructor._definition;e?.shadow!==!1&&this.attachShadow({mode:`open`,...e?.shadow}),this._component=h()}connectedCallback(){f(()=>{this._component.phase===p.UNINITIALIZED&&this._runSetup(),this._init()}),this.dispatchEvent(new CustomEvent(m.CONNECT,{bubbles:!1,composed:!1}))}attributeChangedCallback(e,t,n){if(t===n)return;let r=l(this,e);if(!r)return;let i=r.parse(n);Object.is(f(()=>r.signal.value),i)||(r.signal.value=i)}disconnectedCallback(){this._component.generation++,this._component.phase=p.UNMOUNTED,this.dispatchEvent(new CustomEvent(m.DISCONNECT,{bubbles:!1,composed:!1})),this._resetSetupState()}_resetSetupState(){this._component.scope.dispose(),this._component.formResetCallbacks=[],this._component.mountCallbacks=[],this._component.phase=p.UNINITIALIZED,this._component.scope=d(),this._component.templateResult=null}formResetCallback(){for(let e of this._component.formResetCallbacks)try{e()}catch(e){this._reportLifecycleError(e,`form-reset`)}}_reportLifecycleError(e,t){let i=e instanceof Error?e:Error(String(e)),a=new n(`<${this.localName}> failed during ${this._component.phase} (${t})`,{cause:i,component:this.localName,phase:t});r(a,this)}_runSetup(){this._component.phase=p.SETUP_RUNNING;let n=this.constructor._definition,r=this.constructor._normalizedPropDefs,i=a(this);try{let a;if(this._component.scope.run(()=>{a=s(i,()=>{let e=r?c(this,r):{};return n.setup(e)})}),this._component.mountCallbacks.push(...i.mountCallbacks),this._component.formResetCallbacks.push(...i.formResetCallbacks),g(a))throw new t(e.asyncSetupUnsupported);this._component.templateResult=a??null,this._component.phase=p.SETUP_DONE}catch(e){throw this._reportLifecycleError(e,`setup`),this._resetSetupState(),e}}_isStale(e){return this._component.generation!==e||!this.isConnected}_applyResult(e){if(!e)return;let t=this.shadowRoot??this,n=a(this);t.replaceChildren(),this._component.scope.run(()=>{s(n,()=>{e.mount(t,null,o)})})}_init(){this._applyStyles(),this._mountTemplate(),this._component.phase===p.SETUP_DONE&&this._scheduleMountCallbacks()}_applyStyles(){let e=this.constructor._definition;this.shadowRoot&&e?.styles?.length&&(this.shadowRoot.adoptedStyleSheets=e.styles.map(u))}_mountTemplate(){let e=this._component.templateResult;e&&this._applyResult(e)}_scheduleMountCallbacks(){if(this._component.mountCallbacks.length===0)return;let e=this._component.generation,t=i();queueMicrotask(()=>{try{if(this._isStale(e))return;let t=this._component.mountCallbacks.splice(0);for(let e=0;e<t.length;e++){let n=t[e];try{let e=a(this);this._component.scope.run(()=>{s(e,()=>{let e=n();typeof e==`function`&&o(e)})}),e.mountCallbacks.length>0&&t.push(...e.mountCallbacks),e.formResetCallbacks.length>0&&this._component.formResetCallbacks.push(...e.formResetCallbacks)}catch(e){this._reportLifecycleError(e,`mounted`)}}}finally{t()}})}};export{_ as BaseElement};
2
2
  //# sourceMappingURL=base-element.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"base-element.js","names":[],"sources":["../src/base-element.ts"],"sourcesContent":["import { createScope, type Scope, untrack } from '@vielzeug/ripple';\n\nimport type { ComponentDefinition } from './component-types';\n\nimport { OreApiError, type OreErrorPhase, OreLifecycleError, ORE_ERRORS, reportRuntimeError } from './errors';\nimport { createProps, getPropMeta, type InferProps, type PropInputDefs, type PropsDef } from './props';\nimport {\n beginPendingWork,\n createRuntimeContext,\n type OnFormResetCallback,\n type OnMountedCallback,\n onCleanup,\n runWithContext,\n} from './runtime';\nimport { type HTMLResult } from './template/result';\nimport { loadStylesheet } from './utils/css';\n\n// ─── Component phases & lifecycle events ──────────────────────────────────────\n// Internal to BaseElement — the only state machine and event dispatcher in the package.\n\nconst ComponentPhase = {\n SETUP_DONE: 'setup_done',\n SETUP_RUNNING: 'setup_running',\n UNINITIALIZED: 'uninitialized',\n UNMOUNTED: 'unmounted',\n} as const;\n\ntype ComponentPhase = (typeof ComponentPhase)[keyof typeof ComponentPhase];\n\nconst LIFECYCLE_EVENTS = {\n CONNECT: 'ore:connect',\n DISCONNECT: 'ore:disconnect',\n} as const;\n\n// ─── Internal component state ─────────────────────────────────────────────────\n\ntype ComponentState = {\n /** Registered via `onFormReset()` — persists across mount callbacks, unlike `mountCallbacks`. */\n formResetCallbacks: OnFormResetCallback[];\n /** Incremented on every disconnect — invalidates queued mount callbacks. */\n generation: number;\n mountCallbacks: OnMountedCallback[];\n phase: ComponentPhase;\n scope: Scope;\n templateResult: HTMLResult | null;\n};\n\nconst createComponentState = (): ComponentState => ({\n formResetCallbacks: [],\n generation: 0,\n mountCallbacks: [],\n phase: ComponentPhase.UNINITIALIZED,\n scope: createScope(),\n templateResult: null,\n});\n\nconst isPromiseLike = (value: unknown): value is PromiseLike<unknown> =>\n (typeof value === 'object' || typeof value === 'function') &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function';\n\n// ─── BaseElement ──────────────────────────────────────────────────────────────\n\n/**\n * Phase transitions:\n *\n * ```\n * UNINITIALIZED ──_runSetup()──► SETUP_DONE\n * SETUP_DONE ──disconnectedCallback()──► UNMOUNTED ──(reset)──► UNINITIALIZED\n * ```\n *\n * `generation` increments on every disconnect. Scheduled mount callbacks capture\n * it so callbacks belonging to a disconnected instance cannot run after a\n * reconnect (see `_isStale`).\n *\n * Why this lives on the class instead of a standalone pure reducer: every\n * transition here is triggered by running actual user code (`def.setup()`,\n * `onMounted` callbacks) inside a reactive `scope.run()` + `runWithContext()`\n * — there is no meaningful \"decide the next phase\" step that can be separated\n * from \"run the side-effecting thing that produces the phase change\" without\n * introducing a data-only effect-description layer that this package has no\n * other use for. That's why the methods below stay as direct, readable\n * procedural steps instead of a reducer + effect interpreter.\n */\nexport class BaseElement extends HTMLElement {\n static _definition: ComponentDefinition;\n static _normalizedPropDefs: PropsDef<Record<never, never>> | undefined;\n static formAssociated = false;\n static observedAttributes: string[] = [];\n\n private _component: ComponentState;\n\n constructor() {\n super();\n\n const def = (this.constructor as typeof BaseElement)._definition;\n\n if (def?.shadow !== false) {\n this.attachShadow({ mode: 'open', ...(def?.shadow as Partial<ShadowRootInit> | undefined) });\n }\n\n this._component = createComponentState();\n }\n\n connectedCallback(): void {\n untrack(() => {\n if (this._component.phase === ComponentPhase.UNINITIALIZED) this._runSetup();\n\n this._init();\n });\n this.dispatchEvent(new CustomEvent(LIFECYCLE_EVENTS.CONNECT, { bubbles: false, composed: false }));\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n const propMeta = getPropMeta(this, name);\n\n if (!propMeta) return;\n\n const parsed = propMeta.parse(newValue);\n\n if (\n !Object.is(\n untrack(() => propMeta.signal.value),\n parsed,\n )\n )\n propMeta.signal.value = parsed as never;\n }\n\n disconnectedCallback(): void {\n this._component.generation++;\n this._component.phase = ComponentPhase.UNMOUNTED;\n this.dispatchEvent(new CustomEvent(LIFECYCLE_EVENTS.DISCONNECT, { bubbles: false, composed: false }));\n this._resetSetupState();\n }\n\n /** Dispose one connection's resources before its state can be rebuilt. */\n private _resetSetupState(): void {\n this._component.scope.dispose();\n // Reset mutable fields for next connection, keeping the same object for stable references.\n this._component.formResetCallbacks = [];\n this._component.mountCallbacks = [];\n this._component.phase = ComponentPhase.UNINITIALIZED;\n this._component.scope = createScope();\n this._component.templateResult = null;\n }\n\n /**\n * Native form-association lifecycle callback — the browser calls this on every\n * `formAssociated: true` element inside a `<form>` when that form is reset.\n * Runs every `onFormReset()` callback registered during `setup()`.\n */\n formResetCallback(): void {\n for (const callback of this._component.formResetCallbacks) {\n try {\n callback();\n } catch (error) {\n this._reportLifecycleError(error, 'form-reset');\n }\n }\n }\n\n private _reportLifecycleError(error: unknown, phase: OreErrorPhase): void {\n const err = error instanceof Error ? error : new Error(String(error));\n const oreError = new OreLifecycleError(`<${this.localName}> failed during ${this._component.phase} (${phase})`, {\n cause: err,\n component: this.localName,\n phase,\n });\n\n reportRuntimeError(oreError, this);\n }\n\n private _runSetup(): void {\n this._component.phase = ComponentPhase.SETUP_RUNNING;\n\n const def = (this.constructor as typeof BaseElement)._definition;\n const normalizedPropDefs = (this.constructor as typeof BaseElement)._normalizedPropDefs;\n const ctx = createRuntimeContext(this);\n\n try {\n let setupResult: HTMLResult | null | undefined;\n\n this._component.scope.run(() => {\n setupResult = runWithContext(ctx, () => {\n const setupProps = normalizedPropDefs\n ? createProps(this, normalizedPropDefs)\n : ({} as InferProps<PropInputDefs>);\n\n return def.setup(setupProps as InferProps<PropInputDefs>);\n });\n });\n this._component.mountCallbacks.push(...ctx.mountCallbacks);\n this._component.formResetCallbacks.push(...ctx.formResetCallbacks);\n\n if (isPromiseLike(setupResult)) throw new OreApiError(ORE_ERRORS.asyncSetupUnsupported);\n\n this._component.templateResult = setupResult ?? null;\n this._component.phase = ComponentPhase.SETUP_DONE;\n } catch (error) {\n this._reportLifecycleError(error, 'setup');\n // Setup is atomic: a failed run must not leave partial effects or cleanups\n // live until a later disconnect.\n this._resetSetupState();\n throw error;\n }\n }\n\n private _isStale(capturedGeneration: number): boolean {\n return this._component.generation !== capturedGeneration || !this.isConnected;\n }\n\n private _applyResult(result: HTMLResult | null): void {\n if (!result) return;\n\n const host: Element | ShadowRoot = this.shadowRoot ?? this;\n\n // Mounting can register component cleanup, so preserve a runtime context here too.\n const context = createRuntimeContext(this);\n\n host.replaceChildren();\n this._component.scope.run(() => {\n runWithContext(context, () => {\n result.mount(host, null, onCleanup);\n });\n });\n }\n\n private _init(): void {\n this._applyStyles();\n this._mountTemplate();\n\n // Setup completes before the template mounts, so callbacks always observe live DOM.\n if (this._component.phase === ComponentPhase.SETUP_DONE) this._scheduleMountCallbacks();\n }\n\n private _applyStyles(): void {\n const def = (this.constructor as typeof BaseElement)._definition;\n\n if (this.shadowRoot && def?.styles?.length) {\n this.shadowRoot.adoptedStyleSheets = def.styles.map(loadStylesheet);\n }\n }\n\n private _mountTemplate(): void {\n const result = this._component.templateResult;\n\n if (!result) return;\n\n this._applyResult(result);\n }\n\n private _scheduleMountCallbacks(): void {\n if (this._component.mountCallbacks.length === 0) return;\n\n const capturedGeneration = this._component.generation;\n // Tracked as pending work for the duration of this microtask — ended in a `finally`\n // so a thrown callback (already caught per-callback below, but defensive here too)\n // never leaves the counter stuck above zero. See runtime.ts's beginPendingWork().\n const endWork = beginPendingWork();\n\n queueMicrotask(() => {\n try {\n if (this._isStale(capturedGeneration)) return;\n\n // Snapshot callbacks so in-loop registrations don't extend this iteration.\n const batch = this._component.mountCallbacks.splice(0);\n\n for (const callback of batch) {\n try {\n const nestedCtx = createRuntimeContext(this);\n\n this._component.scope.run(() => {\n runWithContext(nestedCtx, () => {\n const cleanup = callback();\n\n if (typeof cleanup === 'function') onCleanup(cleanup);\n });\n });\n\n if (nestedCtx.mountCallbacks.length > 0) {\n this._component.mountCallbacks.push(...nestedCtx.mountCallbacks);\n }\n\n if (nestedCtx.formResetCallbacks.length > 0) {\n this._component.formResetCallbacks.push(...nestedCtx.formResetCallbacks);\n }\n } catch (error) {\n this._reportLifecycleError(error, 'mounted');\n }\n }\n\n // If nested onMounted calls registered new callbacks, schedule them with\n // a fresh token check in the next microtask. This happens *before* endWork()\n // below runs so the counter never dips to zero between the two schedules.\n if (this._component.mountCallbacks.length > 0) {\n this._scheduleMountCallbacks();\n }\n } finally {\n endWork();\n }\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"base-element.js","names":[],"sources":["../src/base-element.ts"],"sourcesContent":["import { createScope, type Scope, untrack } from '@vielzeug/ripple';\n\nimport type { ComponentDefinition } from './component-types';\n\nimport { ORE_ERRORS, OreApiError, type OreErrorPhase, OreLifecycleError, reportRuntimeError } from './errors';\nimport { createProps, getPropMeta, type InferProps, type PropInputDefs, type PropsDef } from './props';\nimport {\n beginPendingWork,\n createRuntimeContext,\n type OnFormResetCallback,\n type OnMountedCallback,\n onCleanup,\n runWithContext,\n} from './runtime';\nimport type { HTMLResult } from './template/result';\nimport { loadStylesheet } from './utils/css';\n\n// ─── Component phases & lifecycle events ──────────────────────────────────────\n// Internal to BaseElement — the only state machine and event dispatcher in the package.\n\nconst ComponentPhase = {\n SETUP_DONE: 'setup_done',\n SETUP_RUNNING: 'setup_running',\n UNINITIALIZED: 'uninitialized',\n UNMOUNTED: 'unmounted',\n} as const;\n\ntype ComponentPhase = (typeof ComponentPhase)[keyof typeof ComponentPhase];\n\nconst LIFECYCLE_EVENTS = {\n CONNECT: 'ore:connect',\n DISCONNECT: 'ore:disconnect',\n} as const;\n\n// ─── Internal component state ─────────────────────────────────────────────────\n\ntype ComponentState = {\n /** Registered via `onFormReset()` — persists across mount callbacks, unlike `mountCallbacks`. */\n formResetCallbacks: OnFormResetCallback[];\n /** Incremented on every disconnect — invalidates queued mount callbacks. */\n generation: number;\n mountCallbacks: OnMountedCallback[];\n phase: ComponentPhase;\n scope: Scope;\n templateResult: HTMLResult | null;\n};\n\nconst createComponentState = (): ComponentState => ({\n formResetCallbacks: [],\n generation: 0,\n mountCallbacks: [],\n phase: ComponentPhase.UNINITIALIZED,\n scope: createScope(),\n templateResult: null,\n});\n\nconst isPromiseLike = (value: unknown): value is PromiseLike<unknown> =>\n (typeof value === 'object' || typeof value === 'function') &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function';\n\n// ─── BaseElement ──────────────────────────────────────────────────────────────\n\n/**\n * Phase transitions:\n *\n * ```\n * UNINITIALIZED ──_runSetup()──► SETUP_DONE\n * SETUP_DONE ──disconnectedCallback()──► UNMOUNTED ──(reset)──► UNINITIALIZED\n * ```\n *\n * `generation` increments on every disconnect. Scheduled mount callbacks capture\n * it so callbacks belonging to a disconnected instance cannot run after a\n * reconnect (see `_isStale`).\n *\n * Why this lives on the class instead of a standalone pure reducer: every\n * transition here is triggered by running actual user code (`def.setup()`,\n * `onMounted` callbacks) inside a reactive `scope.run()` + `runWithContext()`\n * — there is no meaningful \"decide the next phase\" step that can be separated\n * from \"run the side-effecting thing that produces the phase change\" without\n * introducing a data-only effect-description layer that this package has no\n * other use for. That's why the methods below stay as direct, readable\n * procedural steps instead of a reducer + effect interpreter.\n */\nexport class BaseElement extends HTMLElement {\n static _definition: ComponentDefinition;\n static _normalizedPropDefs: PropsDef<Record<never, never>> | undefined;\n static formAssociated = false;\n static observedAttributes: string[] = [];\n\n private _component: ComponentState;\n\n constructor() {\n super();\n\n const def = (this.constructor as typeof BaseElement)._definition;\n\n if (def?.shadow !== false) {\n this.attachShadow({ mode: 'open', ...(def?.shadow as Partial<ShadowRootInit> | undefined) });\n }\n\n this._component = createComponentState();\n }\n\n connectedCallback(): void {\n untrack(() => {\n if (this._component.phase === ComponentPhase.UNINITIALIZED) this._runSetup();\n\n this._init();\n });\n this.dispatchEvent(new CustomEvent(LIFECYCLE_EVENTS.CONNECT, { bubbles: false, composed: false }));\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n const propMeta = getPropMeta(this, name);\n\n if (!propMeta) return;\n\n const parsed = propMeta.parse(newValue);\n\n if (\n !Object.is(\n untrack(() => propMeta.signal.value),\n parsed,\n )\n )\n propMeta.signal.value = parsed as never;\n }\n\n disconnectedCallback(): void {\n this._component.generation++;\n this._component.phase = ComponentPhase.UNMOUNTED;\n this.dispatchEvent(new CustomEvent(LIFECYCLE_EVENTS.DISCONNECT, { bubbles: false, composed: false }));\n this._resetSetupState();\n }\n\n /** Dispose one connection's resources before its state can be rebuilt. */\n private _resetSetupState(): void {\n this._component.scope.dispose();\n // Reset mutable fields for next connection, keeping the same object for stable references.\n this._component.formResetCallbacks = [];\n this._component.mountCallbacks = [];\n this._component.phase = ComponentPhase.UNINITIALIZED;\n this._component.scope = createScope();\n this._component.templateResult = null;\n }\n\n /**\n * Native form-association lifecycle callback — the browser calls this on every\n * `formAssociated: true` element inside a `<form>` when that form is reset.\n * Runs every `onFormReset()` callback registered during `setup()`.\n */\n formResetCallback(): void {\n for (const callback of this._component.formResetCallbacks) {\n try {\n callback();\n } catch (error) {\n this._reportLifecycleError(error, 'form-reset');\n }\n }\n }\n\n private _reportLifecycleError(error: unknown, phase: OreErrorPhase): void {\n const err = error instanceof Error ? error : new Error(String(error));\n const oreError = new OreLifecycleError(`<${this.localName}> failed during ${this._component.phase} (${phase})`, {\n cause: err,\n component: this.localName,\n phase,\n });\n\n reportRuntimeError(oreError, this);\n }\n\n private _runSetup(): void {\n this._component.phase = ComponentPhase.SETUP_RUNNING;\n\n const def = (this.constructor as typeof BaseElement)._definition;\n const normalizedPropDefs = (this.constructor as typeof BaseElement)._normalizedPropDefs;\n const ctx = createRuntimeContext(this);\n\n try {\n let setupResult: HTMLResult | null | undefined;\n\n this._component.scope.run(() => {\n setupResult = runWithContext(ctx, () => {\n const setupProps = normalizedPropDefs\n ? createProps(this, normalizedPropDefs)\n : ({} as InferProps<PropInputDefs>);\n\n return def.setup(setupProps as InferProps<PropInputDefs>);\n });\n });\n this._component.mountCallbacks.push(...ctx.mountCallbacks);\n this._component.formResetCallbacks.push(...ctx.formResetCallbacks);\n\n if (isPromiseLike(setupResult)) throw new OreApiError(ORE_ERRORS.asyncSetupUnsupported);\n\n this._component.templateResult = setupResult ?? null;\n this._component.phase = ComponentPhase.SETUP_DONE;\n } catch (error) {\n this._reportLifecycleError(error, 'setup');\n // Setup is atomic: a failed run must not leave partial effects or cleanups\n // live until a later disconnect.\n this._resetSetupState();\n throw error;\n }\n }\n\n private _isStale(capturedGeneration: number): boolean {\n return this._component.generation !== capturedGeneration || !this.isConnected;\n }\n\n private _applyResult(result: HTMLResult | null): void {\n if (!result) return;\n\n const host: Element | ShadowRoot = this.shadowRoot ?? this;\n\n // Mounting can register component cleanup, so preserve a runtime context here too.\n const context = createRuntimeContext(this);\n\n host.replaceChildren();\n this._component.scope.run(() => {\n runWithContext(context, () => {\n result.mount(host, null, onCleanup);\n });\n });\n }\n\n private _init(): void {\n this._applyStyles();\n this._mountTemplate();\n\n // Setup completes before the template mounts, so callbacks always observe live DOM.\n if (this._component.phase === ComponentPhase.SETUP_DONE) this._scheduleMountCallbacks();\n }\n\n private _applyStyles(): void {\n const def = (this.constructor as typeof BaseElement)._definition;\n\n if (this.shadowRoot && def?.styles?.length) {\n this.shadowRoot.adoptedStyleSheets = def.styles.map(loadStylesheet);\n }\n }\n\n private _mountTemplate(): void {\n const result = this._component.templateResult;\n\n if (!result) return;\n\n this._applyResult(result);\n }\n\n private _scheduleMountCallbacks(): void {\n if (this._component.mountCallbacks.length === 0) return;\n\n const capturedGeneration = this._component.generation;\n // Tracked as pending work for the duration of this microtask — ended in a `finally`\n // so a thrown callback (already caught per-callback below, but defensive here too)\n // never leaves the counter stuck above zero. See runtime.ts's beginPendingWork().\n const endWork = beginPendingWork();\n\n queueMicrotask(() => {\n try {\n if (this._isStale(capturedGeneration)) return;\n\n // Snapshot callbacks so in-loop registrations don't extend this iteration.\n // Nested onMounted registrations are appended to `batch` and run in the same\n // microtask — no recursive scheduling. Index-based loop because the array\n // grows as nested callbacks are discovered.\n const batch = this._component.mountCallbacks.splice(0);\n\n for (let i = 0; i < batch.length; i++) {\n const callback = batch[i];\n\n try {\n const nestedCtx = createRuntimeContext(this);\n\n this._component.scope.run(() => {\n runWithContext(nestedCtx, () => {\n const cleanup = callback();\n\n if (typeof cleanup === 'function') onCleanup(cleanup);\n });\n });\n\n if (nestedCtx.mountCallbacks.length > 0) {\n batch.push(...nestedCtx.mountCallbacks);\n }\n\n if (nestedCtx.formResetCallbacks.length > 0) {\n this._component.formResetCallbacks.push(...nestedCtx.formResetCallbacks);\n }\n } catch (error) {\n this._reportLifecycleError(error, 'mounted');\n }\n }\n } finally {\n endWork();\n }\n });\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"context.cjs","names":[],"sources":["../src/context.ts"],"sourcesContent":["/**\n * Component context injection API — `inject` / `injectStrict` / `provide` / `createContext`.\n *\n * Context values are stored on the providing element via a WeakMap registry and\n * resolved by walking up the DOM tree (including through shadow boundaries).\n * Providing is done via `provide(key, value)` inside `setup()`.\n *\n * Keys are `Symbol.for`-based (see `createContext`) so provide/inject still match\n * across a duplicated module graph — the same cross-copy survival rule as the\n * object brands in `utils/brand.ts`.\n */\n\nimport { warn } from './_dev';\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { requireSetupContext, type RuntimeContext } from './runtime';\n\nconst contextRegistry = new WeakMap<HTMLElement, Map<InjectionKey<unknown>, unknown>>();\n\nexport type InjectionKey<T> = symbol & {\n readonly __ore_injection_key?: T;\n};\n\n/**\n * Build a linear ancestor chain (including shadow host boundaries).\n * Walks `parentNode` (not `parentElement`) so non-HTML intermediate parents\n * (e.g. an `SVGElement` between child and provider) don't break the chain.\n */\nconst buildAncestorChain = (start: HTMLElement): HTMLElement[] => {\n const chain: HTMLElement[] = [];\n let node: Node | null = start;\n\n while (node) {\n if (node instanceof HTMLElement) chain.push(node);\n\n // A ShadowRoot's parentNode is null — hop to its host to keep walking.\n node = node.parentNode ?? (node instanceof ShadowRoot ? node.host : null);\n }\n\n return chain;\n};\n\n/**\n * Register a context value on a specific element.\n * @internal Backs the public `provide()` — do not call directly.\n */\nconst provideOnElement = <T>(el: HTMLElement, key: InjectionKey<T>, value: T): void => {\n const map = contextRegistry.get(el) ?? new Map<InjectionKey<unknown>, unknown>();\n\n // `inject()` memoizes its result per consumer (see resolvedCache below), so a\n // provider swapping the raw value after a descendant already read it would be\n // silently ignored downstream. Provide a `Readable` (signal/computed) instead\n // of a raw value so descendants observe updates through the value itself.\n if (map.has(key)) {\n warn(\n `provide(): key already provided on <${el.localName}> — overwriting. Provide a Readable to update it instead.`,\n );\n }\n\n map.set(key, value);\n contextRegistry.set(el, map);\n};\n\n/**\n * Register a context value on the current component's host element, making it\n * available to descendant components via `inject(key)`.\n *\n * Provide a `Readable` (signal/computed) rather than a raw value if descendants\n * need to observe later changes — `inject()` resolves and caches the value once\n * per consumer, so re-calling `provide()` with a new raw value later is not seen.\n */\nexport const provide = <T>(key: InjectionKey<T>, value: T): void => {\n provideOnElement(requireSetupContext('provide').element, key, value);\n};\n\nconst NOT_FOUND_SENTINEL = Symbol('inject.not_found');\n\n/** Per-setup-context cache: avoids repeated ancestor walks for the same key. */\nconst resolvedCache = new WeakMap<object, Map<InjectionKey<unknown>, unknown>>();\n\nconst walkAndFind = <T>(element: HTMLElement, key: InjectionKey<T>): T | typeof NOT_FOUND_SENTINEL => {\n const chain = buildAncestorChain(element);\n\n for (const node of chain) {\n const map = contextRegistry.get(node);\n\n if (map?.has(key)) return map.get(key) as T;\n }\n\n return NOT_FOUND_SENTINEL;\n};\n\n/** Cached ancestor-walk lookup shared by `inject()` and `injectStrict()`. */\nconst lookup = <T>(ctx: RuntimeContext, key: InjectionKey<T>): T | typeof NOT_FOUND_SENTINEL => {\n let cache = resolvedCache.get(ctx);\n\n if (!cache) {\n cache = new Map();\n resolvedCache.set(ctx, cache);\n }\n\n const cacheKey = key as InjectionKey<unknown>;\n\n if (!cache.has(cacheKey)) cache.set(cacheKey, walkAndFind(ctx.element, key));\n\n return cache.get(cacheKey) as T | typeof NOT_FOUND_SENTINEL;\n};\n\nexport function inject<T>(key: InjectionKey<T>): T | undefined;\nexport function inject<T>(key: InjectionKey<T>, fallback: T): T;\nexport function inject<T>(key: InjectionKey<T>, ...rest: [T?]): T | undefined {\n const found = lookup(requireSetupContext('inject'), key);\n\n if (found === NOT_FOUND_SENTINEL) return rest.length > 0 ? rest[0] : undefined;\n\n return found;\n}\n\nexport const injectStrict = <T>(key: InjectionKey<T>): T => {\n const ctx = requireSetupContext('injectStrict');\n const found = lookup(ctx, key);\n\n if (found !== NOT_FOUND_SENTINEL) return found;\n\n throw new OreApiError(ORE_ERRORS.injectStrictFailed(String(key), ctx.element.localName));\n};\n\nlet anonymousKeyCounter = 0;\n\n/**\n * Create a typed context key. `Symbol.for`-keyed (`ore:context:<description>`) so\n * a provider and an injector loaded from two bundled copies of ore still match\n * (see module header). Two `createContext('theme')` calls intentionally produce\n * the same key — use distinct descriptions for distinct contexts.\n *\n * Always pass a description: anonymous keys are minted from a per-graph counter,\n * so they do NOT survive duplicated module graphs (each copy numbers its own).\n */\nexport function createContext<T>(description?: string): InjectionKey<T> {\n if (description === undefined) {\n warn(\n 'createContext() called without a description — anonymous context keys do not survive duplicated module graphs.',\n );\n }\n\n return Symbol.for(`ore:context:${description ?? `anonymous-${++anonymousKeyCounter}`}`) as InjectionKey<T>;\n}\n"],"mappings":"iFAgBA,IAAM,EAAkB,IAAI,QAWtB,EAAsB,GAAsC,CAChE,IAAM,EAAuB,CAAC,EAC1B,EAAoB,EAExB,KAAO,GACD,aAAgB,aAAa,EAAM,KAAK,CAAI,EAGhD,EAAO,EAAK,aAAe,aAAgB,WAAa,EAAK,KAAO,MAGtE,OAAO,CACT,EAMM,GAAuB,EAAiB,EAAsB,IAAmB,CACrF,IAAM,EAAM,EAAgB,IAAI,CAAE,GAAK,IAAI,IAMvC,EAAI,IAAI,CAAG,GAEX,GAAuC,EAAG,UAA1C,EAIJ,EAAI,IAAI,EAAK,CAAK,EAClB,EAAgB,IAAI,EAAI,CAAG,CAC7B,EAUa,GAAc,EAAsB,IAAmB,CAClE,EAAiB,EAAA,oBAAoB,SAAS,CAAC,CAAC,QAAS,EAAK,CAAK,CACrE,EAEM,EAAqB,OAAO,kBAAkB,EAG9C,EAAgB,IAAI,QAEpB,GAAkB,EAAsB,IAAwD,CACpG,IAAM,EAAQ,EAAmB,CAAO,EAExC,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAM,EAAgB,IAAI,CAAI,EAEpC,GAAI,GAAK,IAAI,CAAG,EAAG,OAAO,EAAI,IAAI,CAAG,CACvC,CAEA,OAAO,CACT,EAGM,GAAa,EAAqB,IAAwD,CAC9F,IAAI,EAAQ,EAAc,IAAI,CAAG,EAE5B,IACH,EAAQ,IAAI,IACZ,EAAc,IAAI,EAAK,CAAK,GAG9B,IAAM,EAAW,EAIjB,OAFK,EAAM,IAAI,CAAQ,GAAG,EAAM,IAAI,EAAU,EAAY,EAAI,QAAS,CAAG,CAAC,EAEpE,EAAM,IAAI,CAAQ,CAC3B,EAIA,SAAgB,EAAU,EAAsB,GAAG,EAA2B,CAC5E,IAAM,EAAQ,EAAO,EAAA,oBAAoB,QAAQ,EAAG,CAAG,EAIvD,OAFI,IAAU,EAA2B,EAAK,OAAS,EAAI,EAAK,GAAK,IAAA,GAE9D,CACT,CAEA,IAAa,EAAmB,GAA4B,CAC1D,IAAM,EAAM,EAAA,oBAAoB,cAAc,EACxC,EAAQ,EAAO,EAAK,CAAG,EAE7B,GAAI,IAAU,EAAoB,OAAO,EAEzC,MAAM,IAAI,EAAA,YAAY,EAAA,WAAW,mBAAmB,OAAO,CAAG,EAAG,EAAI,QAAQ,SAAS,CAAC,CACzF,EAEI,EAAsB,EAW1B,SAAgB,EAAiB,EAAuC,CAOtE,OAAO,OAAO,IAAI,eAAe,GAAe,aAAa,EAAE,KAAuB,CACxF"}
1
+ {"version":3,"file":"context.cjs","names":[],"sources":["../src/context.ts"],"sourcesContent":["/**\n * Component context injection API — `inject` / `injectStrict` / `provide` / `createContext`.\n *\n * Context values are stored on the providing element via a WeakMap registry and\n * resolved by walking up the DOM tree (including through shadow boundaries).\n * Providing is done via `provide(key, value)` inside `setup()`.\n *\n * Keys are `Symbol.for`-based (see `createContext`) so provide/inject still match\n * across a duplicated module graph — the same cross-copy survival rule as the\n * object brands in `utils/brand.ts`.\n */\n\nimport { warn } from './_dev';\nimport { ORE_ERRORS, OreApiError } from './errors';\nimport { type RuntimeContext, requireSetupContext } from './runtime';\n\nconst contextRegistry = new WeakMap<HTMLElement, Map<InjectionKey<unknown>, unknown>>();\n\nexport type InjectionKey<T> = symbol & {\n readonly __ore_injection_key?: T;\n};\n\n/**\n * Build a linear ancestor chain (including shadow host boundaries).\n * Walks `parentNode` (not `parentElement`) so non-HTML intermediate parents\n * (e.g. an `SVGElement` between child and provider) don't break the chain.\n */\nconst buildAncestorChain = (start: HTMLElement): HTMLElement[] => {\n const chain: HTMLElement[] = [];\n let node: Node | null = start;\n\n while (node) {\n if (node instanceof HTMLElement) chain.push(node);\n\n // A ShadowRoot's parentNode is null — hop to its host to keep walking.\n node = node.parentNode ?? (node instanceof ShadowRoot ? node.host : null);\n }\n\n return chain;\n};\n\n/**\n * Register a context value on a specific element.\n * @internal Backs the public `provide()` — do not call directly.\n */\nconst provideOnElement = <T>(el: HTMLElement, key: InjectionKey<T>, value: T): void => {\n const map = contextRegistry.get(el) ?? new Map<InjectionKey<unknown>, unknown>();\n\n // `inject()` memoizes its result per consumer (see resolvedCache below), so a\n // provider swapping the raw value after a descendant already read it would be\n // silently ignored downstream. Provide a `Readable` (signal/computed) instead\n // of a raw value so descendants observe updates through the value itself.\n if (map.has(key)) {\n warn(\n `provide(): key already provided on <${el.localName}> — overwriting. Provide a Readable to update it instead.`,\n );\n }\n\n map.set(key, value);\n contextRegistry.set(el, map);\n};\n\n/**\n * Register a context value on the current component's host element, making it\n * available to descendant components via `inject(key)`.\n *\n * Provide a `Readable` (signal/computed) rather than a raw value if descendants\n * need to observe later changes — `inject()` resolves and caches the value once\n * per consumer, so re-calling `provide()` with a new raw value later is not seen.\n */\nexport const provide = <T>(key: InjectionKey<T>, value: T): void => {\n provideOnElement(requireSetupContext('provide').element, key, value);\n};\n\nconst NOT_FOUND_SENTINEL = Symbol('inject.not_found');\n\n/** Per-setup-context cache: avoids repeated ancestor walks for the same key. */\nconst resolvedCache = new WeakMap<object, Map<InjectionKey<unknown>, unknown>>();\n\nconst walkAndFind = <T>(element: HTMLElement, key: InjectionKey<T>): T | typeof NOT_FOUND_SENTINEL => {\n const chain = buildAncestorChain(element);\n\n for (const node of chain) {\n const map = contextRegistry.get(node);\n\n if (map?.has(key)) return map.get(key) as T;\n }\n\n return NOT_FOUND_SENTINEL;\n};\n\n/** Cached ancestor-walk lookup shared by `inject()` and `injectStrict()`. */\nconst lookup = <T>(ctx: RuntimeContext, key: InjectionKey<T>): T | typeof NOT_FOUND_SENTINEL => {\n let cache = resolvedCache.get(ctx);\n\n if (!cache) {\n cache = new Map();\n resolvedCache.set(ctx, cache);\n }\n\n const cacheKey = key as InjectionKey<unknown>;\n\n if (!cache.has(cacheKey)) cache.set(cacheKey, walkAndFind(ctx.element, key));\n\n return cache.get(cacheKey) as T | typeof NOT_FOUND_SENTINEL;\n};\n\nexport function inject<T>(key: InjectionKey<T>): T | undefined;\nexport function inject<T>(key: InjectionKey<T>, fallback: T): T;\nexport function inject<T>(key: InjectionKey<T>, ...rest: [T?]): T | undefined {\n const found = lookup(requireSetupContext('inject'), key);\n\n if (found === NOT_FOUND_SENTINEL) return rest.length > 0 ? rest[0] : undefined;\n\n return found;\n}\n\nexport const injectStrict = <T>(key: InjectionKey<T>): T => {\n const ctx = requireSetupContext('injectStrict');\n const found = lookup(ctx, key);\n\n if (found !== NOT_FOUND_SENTINEL) return found;\n\n throw new OreApiError(ORE_ERRORS.injectStrictFailed(String(key), ctx.element.localName));\n};\n\nlet anonymousKeyCounter = 0;\n\n/**\n * Create a typed context key. `Symbol.for`-keyed (`ore:context:<description>`) so\n * a provider and an injector loaded from two bundled copies of ore still match\n * (see module header). Two `createContext('theme')` calls intentionally produce\n * the same key — use distinct descriptions for distinct contexts.\n *\n * Always pass a description: anonymous keys are minted from a per-graph counter,\n * so they do NOT survive duplicated module graphs (each copy numbers its own).\n */\nexport function createContext<T>(description?: string): InjectionKey<T> {\n if (description === undefined) {\n warn(\n 'createContext() called without a description — anonymous context keys do not survive duplicated module graphs.',\n );\n }\n\n return Symbol.for(`ore:context:${description ?? `anonymous-${++anonymousKeyCounter}`}`) as InjectionKey<T>;\n}\n"],"mappings":"iFAgBA,IAAM,EAAkB,IAAI,QAWtB,EAAsB,GAAsC,CAChE,IAAM,EAAuB,CAAC,EAC1B,EAAoB,EAExB,KAAO,GACD,aAAgB,aAAa,EAAM,KAAK,CAAI,EAGhD,EAAO,EAAK,aAAe,aAAgB,WAAa,EAAK,KAAO,MAGtE,OAAO,CACT,EAMM,GAAuB,EAAiB,EAAsB,IAAmB,CACrF,IAAM,EAAM,EAAgB,IAAI,CAAE,GAAK,IAAI,IAMvC,EAAI,IAAI,CAAG,GAEX,GAAuC,EAAG,UAA1C,EAIJ,EAAI,IAAI,EAAK,CAAK,EAClB,EAAgB,IAAI,EAAI,CAAG,CAC7B,EAUa,GAAc,EAAsB,IAAmB,CAClE,EAAiB,EAAA,oBAAoB,SAAS,CAAC,CAAC,QAAS,EAAK,CAAK,CACrE,EAEM,EAAqB,OAAO,kBAAkB,EAG9C,EAAgB,IAAI,QAEpB,GAAkB,EAAsB,IAAwD,CACpG,IAAM,EAAQ,EAAmB,CAAO,EAExC,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAM,EAAgB,IAAI,CAAI,EAEpC,GAAI,GAAK,IAAI,CAAG,EAAG,OAAO,EAAI,IAAI,CAAG,CACvC,CAEA,OAAO,CACT,EAGM,GAAa,EAAqB,IAAwD,CAC9F,IAAI,EAAQ,EAAc,IAAI,CAAG,EAE5B,IACH,EAAQ,IAAI,IACZ,EAAc,IAAI,EAAK,CAAK,GAG9B,IAAM,EAAW,EAIjB,OAFK,EAAM,IAAI,CAAQ,GAAG,EAAM,IAAI,EAAU,EAAY,EAAI,QAAS,CAAG,CAAC,EAEpE,EAAM,IAAI,CAAQ,CAC3B,EAIA,SAAgB,EAAU,EAAsB,GAAG,EAA2B,CAC5E,IAAM,EAAQ,EAAO,EAAA,oBAAoB,QAAQ,EAAG,CAAG,EAIvD,OAFI,IAAU,EAA2B,EAAK,OAAS,EAAI,EAAK,GAAK,IAAA,GAE9D,CACT,CAEA,IAAa,EAAmB,GAA4B,CAC1D,IAAM,EAAM,EAAA,oBAAoB,cAAc,EACxC,EAAQ,EAAO,EAAK,CAAG,EAE7B,GAAI,IAAU,EAAoB,OAAO,EAEzC,MAAM,IAAI,EAAA,YAAY,EAAA,WAAW,mBAAmB,OAAO,CAAG,EAAG,EAAI,QAAQ,SAAS,CAAC,CACzF,EAEI,EAAsB,EAW1B,SAAgB,EAAiB,EAAuC,CAOtE,OAAO,OAAO,IAAI,eAAe,GAAe,aAAa,EAAE,KAAuB,CACxF"}
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","names":[],"sources":["../src/context.ts"],"sourcesContent":["/**\n * Component context injection API — `inject` / `injectStrict` / `provide` / `createContext`.\n *\n * Context values are stored on the providing element via a WeakMap registry and\n * resolved by walking up the DOM tree (including through shadow boundaries).\n * Providing is done via `provide(key, value)` inside `setup()`.\n *\n * Keys are `Symbol.for`-based (see `createContext`) so provide/inject still match\n * across a duplicated module graph — the same cross-copy survival rule as the\n * object brands in `utils/brand.ts`.\n */\n\nimport { warn } from './_dev';\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { requireSetupContext, type RuntimeContext } from './runtime';\n\nconst contextRegistry = new WeakMap<HTMLElement, Map<InjectionKey<unknown>, unknown>>();\n\nexport type InjectionKey<T> = symbol & {\n readonly __ore_injection_key?: T;\n};\n\n/**\n * Build a linear ancestor chain (including shadow host boundaries).\n * Walks `parentNode` (not `parentElement`) so non-HTML intermediate parents\n * (e.g. an `SVGElement` between child and provider) don't break the chain.\n */\nconst buildAncestorChain = (start: HTMLElement): HTMLElement[] => {\n const chain: HTMLElement[] = [];\n let node: Node | null = start;\n\n while (node) {\n if (node instanceof HTMLElement) chain.push(node);\n\n // A ShadowRoot's parentNode is null — hop to its host to keep walking.\n node = node.parentNode ?? (node instanceof ShadowRoot ? node.host : null);\n }\n\n return chain;\n};\n\n/**\n * Register a context value on a specific element.\n * @internal Backs the public `provide()` — do not call directly.\n */\nconst provideOnElement = <T>(el: HTMLElement, key: InjectionKey<T>, value: T): void => {\n const map = contextRegistry.get(el) ?? new Map<InjectionKey<unknown>, unknown>();\n\n // `inject()` memoizes its result per consumer (see resolvedCache below), so a\n // provider swapping the raw value after a descendant already read it would be\n // silently ignored downstream. Provide a `Readable` (signal/computed) instead\n // of a raw value so descendants observe updates through the value itself.\n if (map.has(key)) {\n warn(\n `provide(): key already provided on <${el.localName}> — overwriting. Provide a Readable to update it instead.`,\n );\n }\n\n map.set(key, value);\n contextRegistry.set(el, map);\n};\n\n/**\n * Register a context value on the current component's host element, making it\n * available to descendant components via `inject(key)`.\n *\n * Provide a `Readable` (signal/computed) rather than a raw value if descendants\n * need to observe later changes — `inject()` resolves and caches the value once\n * per consumer, so re-calling `provide()` with a new raw value later is not seen.\n */\nexport const provide = <T>(key: InjectionKey<T>, value: T): void => {\n provideOnElement(requireSetupContext('provide').element, key, value);\n};\n\nconst NOT_FOUND_SENTINEL = Symbol('inject.not_found');\n\n/** Per-setup-context cache: avoids repeated ancestor walks for the same key. */\nconst resolvedCache = new WeakMap<object, Map<InjectionKey<unknown>, unknown>>();\n\nconst walkAndFind = <T>(element: HTMLElement, key: InjectionKey<T>): T | typeof NOT_FOUND_SENTINEL => {\n const chain = buildAncestorChain(element);\n\n for (const node of chain) {\n const map = contextRegistry.get(node);\n\n if (map?.has(key)) return map.get(key) as T;\n }\n\n return NOT_FOUND_SENTINEL;\n};\n\n/** Cached ancestor-walk lookup shared by `inject()` and `injectStrict()`. */\nconst lookup = <T>(ctx: RuntimeContext, key: InjectionKey<T>): T | typeof NOT_FOUND_SENTINEL => {\n let cache = resolvedCache.get(ctx);\n\n if (!cache) {\n cache = new Map();\n resolvedCache.set(ctx, cache);\n }\n\n const cacheKey = key as InjectionKey<unknown>;\n\n if (!cache.has(cacheKey)) cache.set(cacheKey, walkAndFind(ctx.element, key));\n\n return cache.get(cacheKey) as T | typeof NOT_FOUND_SENTINEL;\n};\n\nexport function inject<T>(key: InjectionKey<T>): T | undefined;\nexport function inject<T>(key: InjectionKey<T>, fallback: T): T;\nexport function inject<T>(key: InjectionKey<T>, ...rest: [T?]): T | undefined {\n const found = lookup(requireSetupContext('inject'), key);\n\n if (found === NOT_FOUND_SENTINEL) return rest.length > 0 ? rest[0] : undefined;\n\n return found;\n}\n\nexport const injectStrict = <T>(key: InjectionKey<T>): T => {\n const ctx = requireSetupContext('injectStrict');\n const found = lookup(ctx, key);\n\n if (found !== NOT_FOUND_SENTINEL) return found;\n\n throw new OreApiError(ORE_ERRORS.injectStrictFailed(String(key), ctx.element.localName));\n};\n\nlet anonymousKeyCounter = 0;\n\n/**\n * Create a typed context key. `Symbol.for`-keyed (`ore:context:<description>`) so\n * a provider and an injector loaded from two bundled copies of ore still match\n * (see module header). Two `createContext('theme')` calls intentionally produce\n * the same key — use distinct descriptions for distinct contexts.\n *\n * Always pass a description: anonymous keys are minted from a per-graph counter,\n * so they do NOT survive duplicated module graphs (each copy numbers its own).\n */\nexport function createContext<T>(description?: string): InjectionKey<T> {\n if (description === undefined) {\n warn(\n 'createContext() called without a description — anonymous context keys do not survive duplicated module graphs.',\n );\n }\n\n return Symbol.for(`ore:context:${description ?? `anonymous-${++anonymousKeyCounter}`}`) as InjectionKey<T>;\n}\n"],"mappings":"+HAgBA,IAAM,EAAkB,IAAI,QAWtB,EAAsB,GAAsC,CAChE,IAAM,EAAuB,CAAC,EAC1B,EAAoB,EAExB,KAAO,GACD,aAAgB,aAAa,EAAM,KAAK,CAAI,EAGhD,EAAO,EAAK,aAAe,aAAgB,WAAa,EAAK,KAAO,MAGtE,OAAO,CACT,EAMM,GAAuB,EAAiB,EAAsB,IAAmB,CACrF,IAAM,EAAM,EAAgB,IAAI,CAAE,GAAK,IAAI,IAMvC,EAAI,IAAI,CAAG,GAEX,GAAuC,EAAG,UAA1C,EAIJ,EAAI,IAAI,EAAK,CAAK,EAClB,EAAgB,IAAI,EAAI,CAAG,CAC7B,EAUa,GAAc,EAAsB,IAAmB,CAClE,EAAiB,EAAoB,SAAS,CAAC,CAAC,QAAS,EAAK,CAAK,CACrE,EAEM,EAAqB,OAAO,kBAAkB,EAG9C,EAAgB,IAAI,QAEpB,GAAkB,EAAsB,IAAwD,CACpG,IAAM,EAAQ,EAAmB,CAAO,EAExC,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAM,EAAgB,IAAI,CAAI,EAEpC,GAAI,GAAK,IAAI,CAAG,EAAG,OAAO,EAAI,IAAI,CAAG,CACvC,CAEA,OAAO,CACT,EAGM,GAAa,EAAqB,IAAwD,CAC9F,IAAI,EAAQ,EAAc,IAAI,CAAG,EAE5B,IACH,EAAQ,IAAI,IACZ,EAAc,IAAI,EAAK,CAAK,GAG9B,IAAM,EAAW,EAIjB,OAFK,EAAM,IAAI,CAAQ,GAAG,EAAM,IAAI,EAAU,EAAY,EAAI,QAAS,CAAG,CAAC,EAEpE,EAAM,IAAI,CAAQ,CAC3B,EAIA,SAAgB,EAAU,EAAsB,GAAG,EAA2B,CAC5E,IAAM,EAAQ,EAAO,EAAoB,QAAQ,EAAG,CAAG,EAIvD,OAFI,IAAU,EAA2B,EAAK,OAAS,EAAI,EAAK,GAAK,IAAA,GAE9D,CACT,CAEA,IAAa,EAAmB,GAA4B,CAC1D,IAAM,EAAM,EAAoB,cAAc,EACxC,EAAQ,EAAO,EAAK,CAAG,EAE7B,GAAI,IAAU,EAAoB,OAAO,EAEzC,MAAM,IAAI,EAAY,EAAW,mBAAmB,OAAO,CAAG,EAAG,EAAI,QAAQ,SAAS,CAAC,CACzF,EAEI,EAAsB,EAW1B,SAAgB,EAAiB,EAAuC,CAOtE,OAAO,OAAO,IAAI,eAAe,GAAe,aAAa,EAAE,KAAuB,CACxF"}
1
+ {"version":3,"file":"context.js","names":[],"sources":["../src/context.ts"],"sourcesContent":["/**\n * Component context injection API — `inject` / `injectStrict` / `provide` / `createContext`.\n *\n * Context values are stored on the providing element via a WeakMap registry and\n * resolved by walking up the DOM tree (including through shadow boundaries).\n * Providing is done via `provide(key, value)` inside `setup()`.\n *\n * Keys are `Symbol.for`-based (see `createContext`) so provide/inject still match\n * across a duplicated module graph — the same cross-copy survival rule as the\n * object brands in `utils/brand.ts`.\n */\n\nimport { warn } from './_dev';\nimport { ORE_ERRORS, OreApiError } from './errors';\nimport { type RuntimeContext, requireSetupContext } from './runtime';\n\nconst contextRegistry = new WeakMap<HTMLElement, Map<InjectionKey<unknown>, unknown>>();\n\nexport type InjectionKey<T> = symbol & {\n readonly __ore_injection_key?: T;\n};\n\n/**\n * Build a linear ancestor chain (including shadow host boundaries).\n * Walks `parentNode` (not `parentElement`) so non-HTML intermediate parents\n * (e.g. an `SVGElement` between child and provider) don't break the chain.\n */\nconst buildAncestorChain = (start: HTMLElement): HTMLElement[] => {\n const chain: HTMLElement[] = [];\n let node: Node | null = start;\n\n while (node) {\n if (node instanceof HTMLElement) chain.push(node);\n\n // A ShadowRoot's parentNode is null — hop to its host to keep walking.\n node = node.parentNode ?? (node instanceof ShadowRoot ? node.host : null);\n }\n\n return chain;\n};\n\n/**\n * Register a context value on a specific element.\n * @internal Backs the public `provide()` — do not call directly.\n */\nconst provideOnElement = <T>(el: HTMLElement, key: InjectionKey<T>, value: T): void => {\n const map = contextRegistry.get(el) ?? new Map<InjectionKey<unknown>, unknown>();\n\n // `inject()` memoizes its result per consumer (see resolvedCache below), so a\n // provider swapping the raw value after a descendant already read it would be\n // silently ignored downstream. Provide a `Readable` (signal/computed) instead\n // of a raw value so descendants observe updates through the value itself.\n if (map.has(key)) {\n warn(\n `provide(): key already provided on <${el.localName}> — overwriting. Provide a Readable to update it instead.`,\n );\n }\n\n map.set(key, value);\n contextRegistry.set(el, map);\n};\n\n/**\n * Register a context value on the current component's host element, making it\n * available to descendant components via `inject(key)`.\n *\n * Provide a `Readable` (signal/computed) rather than a raw value if descendants\n * need to observe later changes — `inject()` resolves and caches the value once\n * per consumer, so re-calling `provide()` with a new raw value later is not seen.\n */\nexport const provide = <T>(key: InjectionKey<T>, value: T): void => {\n provideOnElement(requireSetupContext('provide').element, key, value);\n};\n\nconst NOT_FOUND_SENTINEL = Symbol('inject.not_found');\n\n/** Per-setup-context cache: avoids repeated ancestor walks for the same key. */\nconst resolvedCache = new WeakMap<object, Map<InjectionKey<unknown>, unknown>>();\n\nconst walkAndFind = <T>(element: HTMLElement, key: InjectionKey<T>): T | typeof NOT_FOUND_SENTINEL => {\n const chain = buildAncestorChain(element);\n\n for (const node of chain) {\n const map = contextRegistry.get(node);\n\n if (map?.has(key)) return map.get(key) as T;\n }\n\n return NOT_FOUND_SENTINEL;\n};\n\n/** Cached ancestor-walk lookup shared by `inject()` and `injectStrict()`. */\nconst lookup = <T>(ctx: RuntimeContext, key: InjectionKey<T>): T | typeof NOT_FOUND_SENTINEL => {\n let cache = resolvedCache.get(ctx);\n\n if (!cache) {\n cache = new Map();\n resolvedCache.set(ctx, cache);\n }\n\n const cacheKey = key as InjectionKey<unknown>;\n\n if (!cache.has(cacheKey)) cache.set(cacheKey, walkAndFind(ctx.element, key));\n\n return cache.get(cacheKey) as T | typeof NOT_FOUND_SENTINEL;\n};\n\nexport function inject<T>(key: InjectionKey<T>): T | undefined;\nexport function inject<T>(key: InjectionKey<T>, fallback: T): T;\nexport function inject<T>(key: InjectionKey<T>, ...rest: [T?]): T | undefined {\n const found = lookup(requireSetupContext('inject'), key);\n\n if (found === NOT_FOUND_SENTINEL) return rest.length > 0 ? rest[0] : undefined;\n\n return found;\n}\n\nexport const injectStrict = <T>(key: InjectionKey<T>): T => {\n const ctx = requireSetupContext('injectStrict');\n const found = lookup(ctx, key);\n\n if (found !== NOT_FOUND_SENTINEL) return found;\n\n throw new OreApiError(ORE_ERRORS.injectStrictFailed(String(key), ctx.element.localName));\n};\n\nlet anonymousKeyCounter = 0;\n\n/**\n * Create a typed context key. `Symbol.for`-keyed (`ore:context:<description>`) so\n * a provider and an injector loaded from two bundled copies of ore still match\n * (see module header). Two `createContext('theme')` calls intentionally produce\n * the same key — use distinct descriptions for distinct contexts.\n *\n * Always pass a description: anonymous keys are minted from a per-graph counter,\n * so they do NOT survive duplicated module graphs (each copy numbers its own).\n */\nexport function createContext<T>(description?: string): InjectionKey<T> {\n if (description === undefined) {\n warn(\n 'createContext() called without a description — anonymous context keys do not survive duplicated module graphs.',\n );\n }\n\n return Symbol.for(`ore:context:${description ?? `anonymous-${++anonymousKeyCounter}`}`) as InjectionKey<T>;\n}\n"],"mappings":"+HAgBA,IAAM,EAAkB,IAAI,QAWtB,EAAsB,GAAsC,CAChE,IAAM,EAAuB,CAAC,EAC1B,EAAoB,EAExB,KAAO,GACD,aAAgB,aAAa,EAAM,KAAK,CAAI,EAGhD,EAAO,EAAK,aAAe,aAAgB,WAAa,EAAK,KAAO,MAGtE,OAAO,CACT,EAMM,GAAuB,EAAiB,EAAsB,IAAmB,CACrF,IAAM,EAAM,EAAgB,IAAI,CAAE,GAAK,IAAI,IAMvC,EAAI,IAAI,CAAG,GAEX,GAAuC,EAAG,UAA1C,EAIJ,EAAI,IAAI,EAAK,CAAK,EAClB,EAAgB,IAAI,EAAI,CAAG,CAC7B,EAUa,GAAc,EAAsB,IAAmB,CAClE,EAAiB,EAAoB,SAAS,CAAC,CAAC,QAAS,EAAK,CAAK,CACrE,EAEM,EAAqB,OAAO,kBAAkB,EAG9C,EAAgB,IAAI,QAEpB,GAAkB,EAAsB,IAAwD,CACpG,IAAM,EAAQ,EAAmB,CAAO,EAExC,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAM,EAAgB,IAAI,CAAI,EAEpC,GAAI,GAAK,IAAI,CAAG,EAAG,OAAO,EAAI,IAAI,CAAG,CACvC,CAEA,OAAO,CACT,EAGM,GAAa,EAAqB,IAAwD,CAC9F,IAAI,EAAQ,EAAc,IAAI,CAAG,EAE5B,IACH,EAAQ,IAAI,IACZ,EAAc,IAAI,EAAK,CAAK,GAG9B,IAAM,EAAW,EAIjB,OAFK,EAAM,IAAI,CAAQ,GAAG,EAAM,IAAI,EAAU,EAAY,EAAI,QAAS,CAAG,CAAC,EAEpE,EAAM,IAAI,CAAQ,CAC3B,EAIA,SAAgB,EAAU,EAAsB,GAAG,EAA2B,CAC5E,IAAM,EAAQ,EAAO,EAAoB,QAAQ,EAAG,CAAG,EAIvD,OAFI,IAAU,EAA2B,EAAK,OAAS,EAAI,EAAK,GAAK,IAAA,GAE9D,CACT,CAEA,IAAa,EAAmB,GAA4B,CAC1D,IAAM,EAAM,EAAoB,cAAc,EACxC,EAAQ,EAAO,EAAK,CAAG,EAE7B,GAAI,IAAU,EAAoB,OAAO,EAEzC,MAAM,IAAI,EAAY,EAAW,mBAAmB,OAAO,CAAG,EAAG,EAAI,QAAQ,SAAS,CAAC,CACzF,EAEI,EAAsB,EAW1B,SAAgB,EAAiB,EAAuC,CAOtE,OAAO,OAAO,IAAI,eAAe,GAAe,aAAa,EAAE,KAAuB,CACxF"}
@@ -1 +1 @@
1
- {"version":3,"file":"define.cjs","names":[],"sources":["../src/define.ts"],"sourcesContent":["import type { ComponentDefinition } from './component-types';\n\nimport { createComponentClass } from './_component-class';\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { prop, type PropDef } from './props';\n\nexport { prop };\nexport type { PropDef };\nexport type { HostBindFn } from './host-bind';\n\n/**\n * Define and register a web component.\n *\n * The `setup` function runs for each connection and returns an `HTMLResult`.\n * Disconnecting disposes its state; reconnecting rebuilds it. All reactive\n * behaviour within a connection is expressed through directives inside the\n * template — not by re-evaluating setup itself.\n *\n * Everything besides `props` — lifecycle hooks, host bindings, context, slots,\n * emit — is a free function imported from `@vielzeug/ore` and called directly\n * from inside `setup()` (or from a composable it calls):\n *\n * ```ts\n * import { define, html, prop, onMounted, useEmit, useSlots } from '@vielzeug/ore';\n *\n * define<{ count?: number }>('my-counter', {\n * props: { count: prop.number(0) },\n * setup(props) {\n * const emit = useEmit<{ increment: number }>();\n * const slots = useSlots<'header' | 'footer'>();\n *\n * onMounted(() => console.log('mounted'));\n *\n * return html`<button @click=${() => emit('increment', props.count.value + 1)}>${props.count}</button>`;\n * },\n * });\n * ```\n */\nexport function define<Props extends Record<string, unknown> = Record<never, never>>(\n tag: string,\n definition: ComponentDefinition<Props>,\n): void {\n if (!tag) throw new OreApiError(ORE_ERRORS.defineRequiresTag);\n\n if (customElements.get(tag)) throw new OreApiError(ORE_ERRORS.defineDuplicate(tag));\n\n const ComponentClass = createComponentClass(tag, definition);\n\n // Registration is intentionally the sole global side effect of define().\n Object.defineProperty(ComponentClass, 'name', { value: tag });\n customElements.define(tag, ComponentClass);\n}\n"],"mappings":"6FAsCA,SAAgB,EACd,EACA,EACM,CACN,GAAI,CAAC,EAAK,MAAM,IAAI,EAAA,YAAY,EAAA,WAAW,iBAAiB,EAE5D,GAAI,eAAe,IAAI,CAAG,EAAG,MAAM,IAAI,EAAA,YAAY,EAAA,WAAW,gBAAgB,CAAG,CAAC,EAElF,IAAM,EAAiB,EAAA,qBAAqB,EAAK,CAAU,EAG3D,OAAO,eAAe,EAAgB,OAAQ,CAAE,MAAO,CAAI,CAAC,EAC5D,eAAe,OAAO,EAAK,CAAc,CAC3C"}
1
+ {"version":3,"file":"define.cjs","names":[],"sources":["../src/define.ts"],"sourcesContent":["import { createComponentClass } from './_component-class';\nimport type { ComponentDefinition } from './component-types';\nimport { ORE_ERRORS, OreApiError } from './errors';\nimport { type PropDef, prop } from './props';\n\nexport type { HostBindFn } from './host-bind';\nexport type { PropDef };\nexport { prop };\n\n/**\n * Define and register a web component.\n *\n * The `setup` function runs for each connection and returns an `HTMLResult`.\n * Disconnecting disposes its state; reconnecting rebuilds it. All reactive\n * behaviour within a connection is expressed through directives inside the\n * template — not by re-evaluating setup itself.\n *\n * Everything besides `props` — lifecycle hooks, host bindings, context, slots,\n * emit — is a free function imported from `@vielzeug/ore` and called directly\n * from inside `setup()` (or from a composable it calls):\n *\n * ```ts\n * import { define, html, prop, onMounted, useEmit, useSlots } from '@vielzeug/ore';\n *\n * define<{ count?: number }>('my-counter', {\n * props: { count: prop.number(0) },\n * setup(props) {\n * const emit = useEmit<{ increment: number }>();\n * const slots = useSlots<'header' | 'footer'>();\n *\n * onMounted(() => console.log('mounted'));\n *\n * return html`<button @click=${() => emit('increment', props.count.value + 1)}>${props.count}</button>`;\n * },\n * });\n * ```\n */\nexport function define<Props extends Record<string, unknown> = Record<never, never>>(\n tag: string,\n definition: ComponentDefinition<Props>,\n): void {\n if (!tag) throw new OreApiError(ORE_ERRORS.defineRequiresTag);\n\n if (customElements.get(tag)) throw new OreApiError(ORE_ERRORS.defineDuplicate(tag));\n\n const ComponentClass = createComponentClass(tag, definition);\n\n // Registration is intentionally the sole global side effect of define().\n Object.defineProperty(ComponentClass, 'name', { value: tag });\n customElements.define(tag, ComponentClass);\n}\n"],"mappings":"6FAqCA,SAAgB,EACd,EACA,EACM,CACN,GAAI,CAAC,EAAK,MAAM,IAAI,EAAA,YAAY,EAAA,WAAW,iBAAiB,EAE5D,GAAI,eAAe,IAAI,CAAG,EAAG,MAAM,IAAI,EAAA,YAAY,EAAA,WAAW,gBAAgB,CAAG,CAAC,EAElF,IAAM,EAAiB,EAAA,qBAAqB,EAAK,CAAU,EAG3D,OAAO,eAAe,EAAgB,OAAQ,CAAE,MAAO,CAAI,CAAC,EAC5D,eAAe,OAAO,EAAK,CAAc,CAC3C"}
package/dist/define.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import type { ComponentDefinition } from './component-types';
2
- import { prop, type PropDef } from './props';
3
- export { prop };
4
- export type { PropDef };
2
+ import { type PropDef, prop } from './props';
5
3
  export type { HostBindFn } from './host-bind';
4
+ export type { PropDef };
5
+ export { prop };
6
6
  /**
7
7
  * Define and register a web component.
8
8
  *
@@ -1 +1 @@
1
- {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAI7D,OAAO,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAE7C,OAAO,EAAE,IAAI,EAAE,CAAC;AAChB,YAAY,EAAE,OAAO,EAAE,CAAC;AACxB,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,MAAM,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EACjF,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,mBAAmB,CAAC,KAAK,CAAC,GACrC,IAAI,CAUN"}
1
+ {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,OAAO,EAAE,KAAK,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE7C,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,OAAO,EAAE,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,CAAC;AAEhB;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,MAAM,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EACjF,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,mBAAmB,CAAC,KAAK,CAAC,GACrC,IAAI,CAUN"}
@@ -1 +1 @@
1
- {"version":3,"file":"define.js","names":[],"sources":["../src/define.ts"],"sourcesContent":["import type { ComponentDefinition } from './component-types';\n\nimport { createComponentClass } from './_component-class';\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { prop, type PropDef } from './props';\n\nexport { prop };\nexport type { PropDef };\nexport type { HostBindFn } from './host-bind';\n\n/**\n * Define and register a web component.\n *\n * The `setup` function runs for each connection and returns an `HTMLResult`.\n * Disconnecting disposes its state; reconnecting rebuilds it. All reactive\n * behaviour within a connection is expressed through directives inside the\n * template — not by re-evaluating setup itself.\n *\n * Everything besides `props` — lifecycle hooks, host bindings, context, slots,\n * emit — is a free function imported from `@vielzeug/ore` and called directly\n * from inside `setup()` (or from a composable it calls):\n *\n * ```ts\n * import { define, html, prop, onMounted, useEmit, useSlots } from '@vielzeug/ore';\n *\n * define<{ count?: number }>('my-counter', {\n * props: { count: prop.number(0) },\n * setup(props) {\n * const emit = useEmit<{ increment: number }>();\n * const slots = useSlots<'header' | 'footer'>();\n *\n * onMounted(() => console.log('mounted'));\n *\n * return html`<button @click=${() => emit('increment', props.count.value + 1)}>${props.count}</button>`;\n * },\n * });\n * ```\n */\nexport function define<Props extends Record<string, unknown> = Record<never, never>>(\n tag: string,\n definition: ComponentDefinition<Props>,\n): void {\n if (!tag) throw new OreApiError(ORE_ERRORS.defineRequiresTag);\n\n if (customElements.get(tag)) throw new OreApiError(ORE_ERRORS.defineDuplicate(tag));\n\n const ComponentClass = createComponentClass(tag, definition);\n\n // Registration is intentionally the sole global side effect of define().\n Object.defineProperty(ComponentClass, 'name', { value: tag });\n customElements.define(tag, ComponentClass);\n}\n"],"mappings":"yJAsCA,SAAgB,EACd,EACA,EACM,CACN,GAAI,CAAC,EAAK,MAAM,IAAI,EAAY,EAAW,iBAAiB,EAE5D,GAAI,eAAe,IAAI,CAAG,EAAG,MAAM,IAAI,EAAY,EAAW,gBAAgB,CAAG,CAAC,EAElF,IAAM,EAAiB,EAAqB,EAAK,CAAU,EAG3D,OAAO,eAAe,EAAgB,OAAQ,CAAE,MAAO,CAAI,CAAC,EAC5D,eAAe,OAAO,EAAK,CAAc,CAC3C"}
1
+ {"version":3,"file":"define.js","names":[],"sources":["../src/define.ts"],"sourcesContent":["import { createComponentClass } from './_component-class';\nimport type { ComponentDefinition } from './component-types';\nimport { ORE_ERRORS, OreApiError } from './errors';\nimport { type PropDef, prop } from './props';\n\nexport type { HostBindFn } from './host-bind';\nexport type { PropDef };\nexport { prop };\n\n/**\n * Define and register a web component.\n *\n * The `setup` function runs for each connection and returns an `HTMLResult`.\n * Disconnecting disposes its state; reconnecting rebuilds it. All reactive\n * behaviour within a connection is expressed through directives inside the\n * template — not by re-evaluating setup itself.\n *\n * Everything besides `props` — lifecycle hooks, host bindings, context, slots,\n * emit — is a free function imported from `@vielzeug/ore` and called directly\n * from inside `setup()` (or from a composable it calls):\n *\n * ```ts\n * import { define, html, prop, onMounted, useEmit, useSlots } from '@vielzeug/ore';\n *\n * define<{ count?: number }>('my-counter', {\n * props: { count: prop.number(0) },\n * setup(props) {\n * const emit = useEmit<{ increment: number }>();\n * const slots = useSlots<'header' | 'footer'>();\n *\n * onMounted(() => console.log('mounted'));\n *\n * return html`<button @click=${() => emit('increment', props.count.value + 1)}>${props.count}</button>`;\n * },\n * });\n * ```\n */\nexport function define<Props extends Record<string, unknown> = Record<never, never>>(\n tag: string,\n definition: ComponentDefinition<Props>,\n): void {\n if (!tag) throw new OreApiError(ORE_ERRORS.defineRequiresTag);\n\n if (customElements.get(tag)) throw new OreApiError(ORE_ERRORS.defineDuplicate(tag));\n\n const ComponentClass = createComponentClass(tag, definition);\n\n // Registration is intentionally the sole global side effect of define().\n Object.defineProperty(ComponentClass, 'name', { value: tag });\n customElements.define(tag, ComponentClass);\n}\n"],"mappings":"yJAqCA,SAAgB,EACd,EACA,EACM,CACN,GAAI,CAAC,EAAK,MAAM,IAAI,EAAY,EAAW,iBAAiB,EAE5D,GAAI,eAAe,IAAI,CAAG,EAAG,MAAM,IAAI,EAAY,EAAW,gBAAgB,CAAG,CAAC,EAElF,IAAM,EAAiB,EAAqB,EAAK,CAAU,EAG3D,OAAO,eAAe,EAAgB,OAAQ,CAAE,MAAO,CAAI,CAAC,EAC5D,eAAe,OAAO,EAAK,CAAc,CAC3C"}
@@ -1 +1 @@
1
- {"version":3,"file":"each.cjs","names":[],"sources":["../../src/directives/each.ts"],"sourcesContent":["import {\n batch,\n computed,\n createScope,\n effect as rawEffect,\n type Readable,\n type Scope,\n signal,\n type Signal,\n untrack,\n} from '@vielzeug/ripple';\n\nimport { invariant, OreApiError, ORE_ERRORS, OreLifecycleError, reportRuntimeError } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult } from '../template/result';\nimport { removeNodes, runAll } from '../utils/dom';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ntype MaybeReactiveArray<T> = Readable<T[]> | (() => T[]) | T[];\n\ntype ItemEntry<T> = {\n cleanups: (() => void)[];\n data: Signal<T>;\n index: Signal<number>;\n /** The key used to identify this entry. */\n key: string;\n nodes: Node[];\n scope: Scope;\n};\n\n// ─── Item lifecycle ───────────────────────────────────────────────────────────\n\nconst createItem = <T>(\n item: T,\n index: number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n): ItemEntry<T> => {\n const dataSignal: Signal<T> = signal(item);\n const indexSignal: Signal<number> = signal(index);\n const scope = createScope();\n const cleanups: (() => void)[] = [];\n let nodes: Node[] = [];\n\n scope.run(() => {\n const result = render(dataSignal, indexSignal);\n\n nodes = result.mount(parent, insertBefore, (fn) => cleanups.push(fn));\n });\n\n return { cleanups, data: dataSignal, index: indexSignal, key: '', nodes, scope };\n};\n\nconst removeItem = <T>(entry: ItemEntry<T>): void => {\n entry.scope.dispose();\n runAll(entry.cleanups);\n removeNodes(entry.nodes);\n};\n\n// ─── Reconciler ───────────────────────────────────────────────────────────────\n\n/**\n * Reconciles the live item map (mutated in-place) against the next array.\n * Stale entries are removed and destroyed; new entries are created and inserted.\n * Existing entries are updated in-place via signal writes.\n * Returns the ordered list of entries matching nextList.\n */\nconst reconcileItems = <T>(\n itemsMap: Map<string, ItemEntry<T>>,\n next: T[],\n keyFn: (item: T, index: number) => string | number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n parent: ParentNode,\n endMarker: Node,\n): ItemEntry<T>[] => {\n const nextKeys: string[] = [];\n const nextKeySet = new Set<string>();\n\n for (let i = 0; i < next.length; i++) {\n const key = String(keyFn(next[i], i));\n\n if (nextKeySet.has(key)) throw new OreApiError(ORE_ERRORS.eachDuplicateKey(key, i));\n\n nextKeySet.add(key);\n nextKeys.push(key);\n }\n\n // Remove stale entries from the map\n for (const [key, entry] of itemsMap) {\n if (!nextKeySet.has(key)) {\n removeItem(entry);\n itemsMap.delete(key);\n }\n }\n\n // Build the next ordered list: update existing items, create new ones\n const nextOrdered: ItemEntry<T>[] = [];\n\n for (let i = 0; i < next.length; i++) {\n const key = nextKeys[i];\n const existing = itemsMap.get(key);\n\n if (existing) {\n batch(() => {\n existing.data.value = next[i];\n existing.index.value = i;\n });\n nextOrdered.push(existing);\n } else {\n const entry = untrack(() => createItem(next[i], i, render, parent, endMarker));\n\n entry.key = key;\n itemsMap.set(key, entry);\n nextOrdered.push(entry);\n }\n }\n\n // DOM ordering: right-to-left pass — move any item not already adjacent to cursor.\n // O(n) DOM operations in the worst case; optimal for the typical small list sizes\n // encountered in UI components (tabs, options, menu items).\n let cursor: Node = endMarker;\n\n for (let j = nextOrdered.length - 1; j >= 0; j--) {\n const entry = nextOrdered[j];\n const firstNode = entry.nodes[0];\n\n if (firstNode && firstNode !== cursor.previousSibling) {\n for (const node of entry.nodes) parent.insertBefore(node, cursor);\n }\n\n cursor = firstNode ?? cursor;\n }\n\n return nextOrdered;\n};\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Renders a keyed list of items as a `DirectiveResult`.\n *\n * Each item is rendered by the provided render function.\n * Items are reused by key when the list changes; only stale items are destroyed.\n *\n * The render function receives a `Readable<T>` signal and a `Readable<number>` index\n * signal. Use `item.value` to read the current item inside reactive expressions:\n *\n * ```ts\n * html`${each(items, (item) => item.id, (item) => html`<li>${() => item.value.name}</li>`)}`\n * ```\n *\n * **Plain array:** when a plain `T[]` is passed (not a signal or getter), it is\n * treated as a one-time static render. Mutations to the original array are not\n * tracked. Pass a `Signal<T[]>` or `() => T[]` for reactive lists.\n *\n * **Optional fallback:** the fourth argument renders when the list is empty.\n *\n * **Key choice:** pass a stable item identifier (e.g. `item.id`), never the\n * array index — an index-based key reassigns to a different item whenever the\n * list is reordered or an item is inserted/removed before it, causing full\n * item teardown/recreation instead of the in-place update `each()` is built\n * for.\n *\n * **Duplicate keys:** a reconciliation failure (e.g. duplicate keys, see `eachDuplicateKey`)\n * does not throw past this function — an uncaught exception inside the reactive effect that\n * drives `each()` would risk corrupting unrelated effects scheduled in the same update batch.\n * Instead the list is cleared and the failure is reported via the `ore:error` DOM event (see\n * `OreLifecycleError`, phase `'each-reconcile'`) plus a dev-only console log — listen for\n * `ore:error` on `document`/`window` to observe this in every build, including production.\n */\nexport function each<T>(\n list: MaybeReactiveArray<T>,\n keyFn: (item: T, index: number) => string | number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n fallback?: () => HTMLResult,\n): DirectiveResult {\n const listSignal = Array.isArray(list)\n ? signal(list as T[])\n : typeof list === 'function'\n ? computed(list as () => T[])\n : list;\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'each() anchor comment has no parent node');\n\n const endMarker = document.createComment('each/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n let itemsMap = new Map<string, ItemEntry<T>>();\n let itemsOrdered: ItemEntry<T>[] = [];\n let fallbackNodes: Node[] | null = null;\n let fallbackCleanups: (() => void)[] = [];\n\n const mountFallback = (): void => {\n if (!fallback) return;\n\n const result = fallback();\n\n fallbackNodes = result.mount(parent, endMarker, (fn) => fallbackCleanups.push(fn));\n };\n\n const clearFallback = (): void => {\n if (fallbackNodes) {\n runAll(fallbackCleanups);\n removeNodes(fallbackNodes);\n fallbackNodes = null;\n fallbackCleanups = [];\n }\n };\n\n const sub = rawEffect(() => {\n const nextList = listSignal.value ?? [];\n\n if (nextList.length === 0) {\n for (const entry of untrack(() => itemsOrdered)) removeItem(entry);\n itemsMap = new Map();\n itemsOrdered = [];\n\n if (!fallbackNodes) untrack(mountFallback);\n\n return;\n }\n\n clearFallback();\n\n try {\n itemsOrdered = untrack(() => reconcileItems(itemsMap, nextList, keyFn, render, parent, endMarker));\n } catch (err) {\n const cause = err instanceof Error ? err : new Error(String(err));\n\n // Dispatched on the anchor comment (always a live DOM node) rather than the enclosing\n // component's host element, which each() has no direct reference to — the event still\n // bubbles/composes up to any ancestor listener, including a global one on document.\n reportRuntimeError(\n new OreLifecycleError(`each() failed to reconcile a list update: ${cause.message}`, {\n cause,\n component: 'each()',\n phase: 'each-reconcile',\n }),\n anchor,\n );\n\n for (const entry of itemsMap.values()) removeItem(entry);\n itemsMap = new Map();\n itemsOrdered = [];\n }\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n clearFallback();\n for (const entry of itemsOrdered) removeItem(entry);\n endMarker.remove();\n });\n });\n}\n"],"mappings":"qIAgCA,IAAM,GACJ,EACA,EACA,EACA,EACA,IACiB,CACjB,IAAM,GAAA,EAAwB,EAAA,OAAA,CAAO,CAAI,EACnC,GAAA,EAA8B,EAAA,OAAA,CAAO,CAAK,EAC1C,GAAA,EAAQ,EAAA,YAAA,CAAY,EACpB,EAA2B,CAAC,EAC9B,EAAgB,CAAC,EAQrB,OANA,EAAM,QAAU,CAGd,EAFe,EAAO,EAAY,CAE1B,CAAA,CAAO,MAAM,EAAQ,EAAe,GAAO,EAAS,KAAK,CAAE,CAAC,CACtE,CAAC,EAEM,CAAE,WAAU,KAAM,EAAY,MAAO,EAAa,IAAK,GAAI,QAAO,OAAM,CACjF,EAEM,EAAiB,GAA8B,CACnD,EAAM,MAAM,QAAQ,EACpB,EAAA,OAAO,EAAM,QAAQ,EACrB,EAAA,YAAY,EAAM,KAAK,CACzB,EAUM,GACJ,EACA,EACA,EACA,EACA,EACA,IACmB,CACnB,IAAM,EAAqB,CAAC,EACtB,EAAa,IAAI,IAEvB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,IAAM,EAAM,OAAO,EAAM,EAAK,GAAI,CAAC,CAAC,EAEpC,GAAI,EAAW,IAAI,CAAG,EAAG,MAAM,IAAI,EAAA,YAAY,EAAA,WAAW,iBAAiB,EAAK,CAAC,CAAC,EAElF,EAAW,IAAI,CAAG,EAClB,EAAS,KAAK,CAAG,CACnB,CAGA,IAAK,GAAM,CAAC,EAAK,KAAU,EACpB,EAAW,IAAI,CAAG,IACrB,EAAW,CAAK,EAChB,EAAS,OAAO,CAAG,GAKvB,IAAM,EAA8B,CAAC,EAErC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,IAAM,EAAM,EAAS,GACf,EAAW,EAAS,IAAI,CAAG,EAEjC,GAAI,GACF,EAAA,EAAA,MAAA,KAAY,CACV,EAAS,KAAK,MAAQ,EAAK,GAC3B,EAAS,MAAM,MAAQ,CACzB,CAAC,EACD,EAAY,KAAK,CAAQ,MACpB,CACL,IAAM,GAAA,EAAQ,EAAA,QAAA,KAAc,EAAW,EAAK,GAAI,EAAG,EAAQ,EAAQ,CAAS,CAAC,EAE7E,EAAM,IAAM,EACZ,EAAS,IAAI,EAAK,CAAK,EACvB,EAAY,KAAK,CAAK,CACxB,CACF,CAKA,IAAI,EAAe,EAEnB,IAAK,IAAI,EAAI,EAAY,OAAS,EAAG,GAAK,EAAG,IAAK,CAChD,IAAM,EAAQ,EAAY,GACpB,EAAY,EAAM,MAAM,GAE9B,GAAI,GAAa,IAAc,EAAO,gBACpC,IAAK,IAAM,KAAQ,EAAM,MAAO,EAAO,aAAa,EAAM,CAAM,EAGlE,EAAS,GAAa,CACxB,CAEA,OAAO,CACT,EAoCA,SAAgB,EACd,EACA,EACA,EACA,EACiB,CACjB,IAAM,EAAa,MAAM,QAAQ,CAAI,GAAA,EACjC,EAAA,OAAA,CAAO,CAAW,EAClB,OAAO,GAAS,YAAA,EACd,EAAA,SAAA,CAAS,CAAiB,EAC1B,EAEN,OAAO,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,0CAA0C,EAE5D,IAAM,EAAY,SAAS,cAAc,UAAU,EAEnD,EAAO,aAAa,EAAW,EAAO,WAAW,EAEjD,IAAI,EAAW,IAAI,IACf,EAA+B,CAAC,EAChC,EAA+B,KAC/B,EAAmC,CAAC,EAElC,MAA4B,CAC3B,IAIL,EAFe,EAEC,CAAA,CAAO,MAAM,EAAQ,EAAY,GAAO,EAAiB,KAAK,CAAE,CAAC,EACnF,EAEM,MAA4B,CAC5B,IACF,EAAA,OAAO,CAAgB,EACvB,EAAA,YAAY,CAAa,EACzB,EAAgB,KAChB,EAAmB,CAAC,EAExB,EAEM,GAAA,EAAM,EAAA,OAAA,KAAgB,CAC1B,IAAM,EAAW,EAAW,OAAS,CAAC,EAEtC,GAAI,EAAS,SAAW,EAAG,CACzB,IAAK,IAAM,KAAA,EAAS,EAAA,QAAA,KAAc,CAAY,EAAG,EAAW,CAAK,EACjE,EAAW,IAAI,IACf,EAAe,CAAC,EAEX,IAAe,EAAA,EAAA,QAAA,CAAQ,CAAa,EAEzC,MACF,CAEA,EAAc,EAEd,GAAI,CACF,GAAA,EAAe,EAAA,QAAA,KAAc,EAAe,EAAU,EAAU,EAAO,EAAQ,EAAQ,CAAS,CAAC,CACnG,OAAS,EAAK,CACZ,IAAM,EAAQ,aAAe,MAAQ,EAAU,MAAM,OAAO,CAAG,CAAC,EAKhE,EAAA,mBACE,IAAI,EAAA,kBAAkB,6CAA6C,EAAM,UAAW,CAClF,QACA,UAAW,SACX,MAAO,gBACT,CAAC,EACD,CACF,EAEA,IAAK,IAAM,KAAS,EAAS,OAAO,EAAG,EAAW,CAAK,EACvD,EAAW,IAAI,IACf,EAAe,CAAC,CAClB,CACF,CAAC,EAED,MAAsB,EAAI,QAAQ,CAAC,EACnC,MAAsB,CACpB,EAAc,EACd,IAAK,IAAM,KAAS,EAAc,EAAW,CAAK,EAClD,EAAU,OAAO,CACnB,CAAC,CACH,CAAC,CACH"}
1
+ {"version":3,"file":"each.cjs","names":[],"sources":["../../src/directives/each.ts"],"sourcesContent":["import {\n batch,\n computed,\n createScope,\n type Readable,\n effect as rawEffect,\n type Scope,\n type Signal,\n signal,\n untrack,\n} from '@vielzeug/ripple';\n\nimport { invariant, ORE_ERRORS, OreApiError, OreLifecycleError, reportRuntimeError } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult } from '../template/result';\nimport { removeNodes, runAll } from '../utils/dom';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ntype MaybeReactiveArray<T> = Readable<T[]> | (() => T[]) | T[];\n\ntype ItemEntry<T> = {\n cleanups: (() => void)[];\n data: Signal<T>;\n index: Signal<number>;\n /** The key used to identify this entry. */\n key: string;\n nodes: Node[];\n scope: Scope;\n};\n\n// ─── Item lifecycle ───────────────────────────────────────────────────────────\n\nconst createItem = <T>(\n item: T,\n index: number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n): ItemEntry<T> => {\n const dataSignal: Signal<T> = signal(item);\n const indexSignal: Signal<number> = signal(index);\n const scope = createScope();\n const cleanups: (() => void)[] = [];\n let nodes: Node[] = [];\n\n scope.run(() => {\n const result = render(dataSignal, indexSignal);\n\n nodes = result.mount(parent, insertBefore, (fn) => cleanups.push(fn));\n });\n\n return { cleanups, data: dataSignal, index: indexSignal, key: '', nodes, scope };\n};\n\nconst removeItem = <T>(entry: ItemEntry<T>): void => {\n entry.scope.dispose();\n runAll(entry.cleanups);\n removeNodes(entry.nodes);\n};\n\n// ─── Reconciler ───────────────────────────────────────────────────────────────\n\n/**\n * Reconciles the live item map (mutated in-place) against the next array.\n * Stale entries are removed and destroyed; new entries are created and inserted.\n * Existing entries are updated in-place via signal writes.\n * Returns the ordered list of entries matching nextList.\n */\nconst reconcileItems = <T>(\n itemsMap: Map<string, ItemEntry<T>>,\n next: T[],\n keyFn: (item: T, index: number) => string | number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n parent: ParentNode,\n endMarker: Node,\n): ItemEntry<T>[] => {\n const nextKeys: string[] = [];\n const nextKeySet = new Set<string>();\n\n for (let i = 0; i < next.length; i++) {\n const key = String(keyFn(next[i], i));\n\n if (nextKeySet.has(key)) throw new OreApiError(ORE_ERRORS.eachDuplicateKey(key, i));\n\n nextKeySet.add(key);\n nextKeys.push(key);\n }\n\n // Remove stale entries from the map\n for (const [key, entry] of itemsMap) {\n if (!nextKeySet.has(key)) {\n removeItem(entry);\n itemsMap.delete(key);\n }\n }\n\n // Build the next ordered list: update existing items, create new ones\n const nextOrdered: ItemEntry<T>[] = [];\n\n for (let i = 0; i < next.length; i++) {\n const key = nextKeys[i];\n const existing = itemsMap.get(key);\n\n if (existing) {\n batch(() => {\n existing.data.value = next[i];\n existing.index.value = i;\n });\n nextOrdered.push(existing);\n } else {\n const entry = untrack(() => createItem(next[i], i, render, parent, endMarker));\n\n entry.key = key;\n itemsMap.set(key, entry);\n nextOrdered.push(entry);\n }\n }\n\n // DOM ordering: right-to-left pass — move any item not already adjacent to cursor.\n // O(n) DOM operations in the worst case; optimal for the typical small list sizes\n // encountered in UI components (tabs, options, menu items).\n let cursor: Node = endMarker;\n\n for (let j = nextOrdered.length - 1; j >= 0; j--) {\n const entry = nextOrdered[j];\n const firstNode = entry.nodes[0];\n\n if (firstNode && firstNode !== cursor.previousSibling) {\n for (const node of entry.nodes) parent.insertBefore(node, cursor);\n }\n\n cursor = firstNode ?? cursor;\n }\n\n return nextOrdered;\n};\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Renders a keyed list of items as a `DirectiveResult`.\n *\n * Each item is rendered by the provided render function.\n * Items are reused by key when the list changes; only stale items are destroyed.\n *\n * The render function receives a `Readable<T>` signal and a `Readable<number>` index\n * signal. Use `item.value` to read the current item inside reactive expressions:\n *\n * ```ts\n * html`${each(items, (item) => item.id, (item) => html`<li>${() => item.value.name}</li>`)}`\n * ```\n *\n * **Plain array:** when a plain `T[]` is passed (not a signal or getter), it is\n * treated as a one-time static render. Mutations to the original array are not\n * tracked. Pass a `Signal<T[]>` or `() => T[]` for reactive lists.\n *\n * **Optional fallback:** the fourth argument renders when the list is empty.\n *\n * **Key choice:** pass a stable item identifier (e.g. `item.id`), never the\n * array index — an index-based key reassigns to a different item whenever the\n * list is reordered or an item is inserted/removed before it, causing full\n * item teardown/recreation instead of the in-place update `each()` is built\n * for.\n *\n * **Duplicate keys:** a reconciliation failure (e.g. duplicate keys, see `eachDuplicateKey`)\n * does not throw past this function — an uncaught exception inside the reactive effect that\n * drives `each()` would risk corrupting unrelated effects scheduled in the same update batch.\n * Instead the list is cleared and the failure is reported via the `ore:error` DOM event (see\n * `OreLifecycleError`, phase `'each-reconcile'`) plus a dev-only console log — listen for\n * `ore:error` on `document`/`window` to observe this in every build, including production.\n */\nexport function each<T>(\n list: MaybeReactiveArray<T>,\n keyFn: (item: T, index: number) => string | number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n fallback?: () => HTMLResult,\n): DirectiveResult {\n const listSignal = Array.isArray(list)\n ? signal(list as T[])\n : typeof list === 'function'\n ? computed(list as () => T[])\n : list;\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'each() anchor comment has no parent node');\n\n const endMarker = document.createComment('each/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n let itemsMap = new Map<string, ItemEntry<T>>();\n let itemsOrdered: ItemEntry<T>[] = [];\n let fallbackNodes: Node[] | null = null;\n let fallbackCleanups: (() => void)[] = [];\n\n const mountFallback = (): void => {\n if (!fallback) return;\n\n const result = fallback();\n\n fallbackNodes = result.mount(parent, endMarker, (fn) => fallbackCleanups.push(fn));\n };\n\n const clearFallback = (): void => {\n if (fallbackNodes) {\n runAll(fallbackCleanups);\n removeNodes(fallbackNodes);\n fallbackNodes = null;\n fallbackCleanups = [];\n }\n };\n\n const sub = rawEffect(() => {\n const nextList = listSignal.value ?? [];\n\n if (nextList.length === 0) {\n for (const entry of untrack(() => itemsOrdered)) removeItem(entry);\n itemsMap = new Map();\n itemsOrdered = [];\n\n if (!fallbackNodes) untrack(mountFallback);\n\n return;\n }\n\n clearFallback();\n\n try {\n itemsOrdered = untrack(() => reconcileItems(itemsMap, nextList, keyFn, render, parent, endMarker));\n } catch (err) {\n const cause = err instanceof Error ? err : new Error(String(err));\n\n // Dispatched on the anchor comment (always a live DOM node) rather than the enclosing\n // component's host element, which each() has no direct reference to — the event still\n // bubbles/composes up to any ancestor listener, including a global one on document.\n reportRuntimeError(\n new OreLifecycleError(`each() failed to reconcile a list update: ${cause.message}`, {\n cause,\n component: 'each()',\n phase: 'each-reconcile',\n }),\n anchor,\n );\n\n for (const entry of itemsMap.values()) removeItem(entry);\n itemsMap = new Map();\n itemsOrdered = [];\n }\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n clearFallback();\n for (const entry of itemsOrdered) removeItem(entry);\n endMarker.remove();\n });\n });\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"each.d.ts","sourceRoot":"","sources":["../../src/directives/each.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,QAAQ,EAKd,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAKlG,KAAK,kBAAkB,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;AAyH/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,IAAI,CAAC,CAAC,EACpB,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC3B,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,EAClD,MAAM,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,UAAU,EAClE,QAAQ,CAAC,EAAE,MAAM,UAAU,GAC1B,eAAe,CAmFjB"}
1
+ {"version":3,"file":"each.d.ts","sourceRoot":"","sources":["../../src/directives/each.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAMd,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAKlG,KAAK,kBAAkB,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;AAyH/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,IAAI,CAAC,CAAC,EACpB,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC3B,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,EAClD,MAAM,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,UAAU,EAClE,QAAQ,CAAC,EAAE,MAAM,UAAU,GAC1B,eAAe,CAmFjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"each.js","names":[],"sources":["../../src/directives/each.ts"],"sourcesContent":["import {\n batch,\n computed,\n createScope,\n effect as rawEffect,\n type Readable,\n type Scope,\n signal,\n type Signal,\n untrack,\n} from '@vielzeug/ripple';\n\nimport { invariant, OreApiError, ORE_ERRORS, OreLifecycleError, reportRuntimeError } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult } from '../template/result';\nimport { removeNodes, runAll } from '../utils/dom';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ntype MaybeReactiveArray<T> = Readable<T[]> | (() => T[]) | T[];\n\ntype ItemEntry<T> = {\n cleanups: (() => void)[];\n data: Signal<T>;\n index: Signal<number>;\n /** The key used to identify this entry. */\n key: string;\n nodes: Node[];\n scope: Scope;\n};\n\n// ─── Item lifecycle ───────────────────────────────────────────────────────────\n\nconst createItem = <T>(\n item: T,\n index: number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n): ItemEntry<T> => {\n const dataSignal: Signal<T> = signal(item);\n const indexSignal: Signal<number> = signal(index);\n const scope = createScope();\n const cleanups: (() => void)[] = [];\n let nodes: Node[] = [];\n\n scope.run(() => {\n const result = render(dataSignal, indexSignal);\n\n nodes = result.mount(parent, insertBefore, (fn) => cleanups.push(fn));\n });\n\n return { cleanups, data: dataSignal, index: indexSignal, key: '', nodes, scope };\n};\n\nconst removeItem = <T>(entry: ItemEntry<T>): void => {\n entry.scope.dispose();\n runAll(entry.cleanups);\n removeNodes(entry.nodes);\n};\n\n// ─── Reconciler ───────────────────────────────────────────────────────────────\n\n/**\n * Reconciles the live item map (mutated in-place) against the next array.\n * Stale entries are removed and destroyed; new entries are created and inserted.\n * Existing entries are updated in-place via signal writes.\n * Returns the ordered list of entries matching nextList.\n */\nconst reconcileItems = <T>(\n itemsMap: Map<string, ItemEntry<T>>,\n next: T[],\n keyFn: (item: T, index: number) => string | number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n parent: ParentNode,\n endMarker: Node,\n): ItemEntry<T>[] => {\n const nextKeys: string[] = [];\n const nextKeySet = new Set<string>();\n\n for (let i = 0; i < next.length; i++) {\n const key = String(keyFn(next[i], i));\n\n if (nextKeySet.has(key)) throw new OreApiError(ORE_ERRORS.eachDuplicateKey(key, i));\n\n nextKeySet.add(key);\n nextKeys.push(key);\n }\n\n // Remove stale entries from the map\n for (const [key, entry] of itemsMap) {\n if (!nextKeySet.has(key)) {\n removeItem(entry);\n itemsMap.delete(key);\n }\n }\n\n // Build the next ordered list: update existing items, create new ones\n const nextOrdered: ItemEntry<T>[] = [];\n\n for (let i = 0; i < next.length; i++) {\n const key = nextKeys[i];\n const existing = itemsMap.get(key);\n\n if (existing) {\n batch(() => {\n existing.data.value = next[i];\n existing.index.value = i;\n });\n nextOrdered.push(existing);\n } else {\n const entry = untrack(() => createItem(next[i], i, render, parent, endMarker));\n\n entry.key = key;\n itemsMap.set(key, entry);\n nextOrdered.push(entry);\n }\n }\n\n // DOM ordering: right-to-left pass — move any item not already adjacent to cursor.\n // O(n) DOM operations in the worst case; optimal for the typical small list sizes\n // encountered in UI components (tabs, options, menu items).\n let cursor: Node = endMarker;\n\n for (let j = nextOrdered.length - 1; j >= 0; j--) {\n const entry = nextOrdered[j];\n const firstNode = entry.nodes[0];\n\n if (firstNode && firstNode !== cursor.previousSibling) {\n for (const node of entry.nodes) parent.insertBefore(node, cursor);\n }\n\n cursor = firstNode ?? cursor;\n }\n\n return nextOrdered;\n};\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Renders a keyed list of items as a `DirectiveResult`.\n *\n * Each item is rendered by the provided render function.\n * Items are reused by key when the list changes; only stale items are destroyed.\n *\n * The render function receives a `Readable<T>` signal and a `Readable<number>` index\n * signal. Use `item.value` to read the current item inside reactive expressions:\n *\n * ```ts\n * html`${each(items, (item) => item.id, (item) => html`<li>${() => item.value.name}</li>`)}`\n * ```\n *\n * **Plain array:** when a plain `T[]` is passed (not a signal or getter), it is\n * treated as a one-time static render. Mutations to the original array are not\n * tracked. Pass a `Signal<T[]>` or `() => T[]` for reactive lists.\n *\n * **Optional fallback:** the fourth argument renders when the list is empty.\n *\n * **Key choice:** pass a stable item identifier (e.g. `item.id`), never the\n * array index — an index-based key reassigns to a different item whenever the\n * list is reordered or an item is inserted/removed before it, causing full\n * item teardown/recreation instead of the in-place update `each()` is built\n * for.\n *\n * **Duplicate keys:** a reconciliation failure (e.g. duplicate keys, see `eachDuplicateKey`)\n * does not throw past this function — an uncaught exception inside the reactive effect that\n * drives `each()` would risk corrupting unrelated effects scheduled in the same update batch.\n * Instead the list is cleared and the failure is reported via the `ore:error` DOM event (see\n * `OreLifecycleError`, phase `'each-reconcile'`) plus a dev-only console log — listen for\n * `ore:error` on `document`/`window` to observe this in every build, including production.\n */\nexport function each<T>(\n list: MaybeReactiveArray<T>,\n keyFn: (item: T, index: number) => string | number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n fallback?: () => HTMLResult,\n): DirectiveResult {\n const listSignal = Array.isArray(list)\n ? signal(list as T[])\n : typeof list === 'function'\n ? computed(list as () => T[])\n : list;\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'each() anchor comment has no parent node');\n\n const endMarker = document.createComment('each/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n let itemsMap = new Map<string, ItemEntry<T>>();\n let itemsOrdered: ItemEntry<T>[] = [];\n let fallbackNodes: Node[] | null = null;\n let fallbackCleanups: (() => void)[] = [];\n\n const mountFallback = (): void => {\n if (!fallback) return;\n\n const result = fallback();\n\n fallbackNodes = result.mount(parent, endMarker, (fn) => fallbackCleanups.push(fn));\n };\n\n const clearFallback = (): void => {\n if (fallbackNodes) {\n runAll(fallbackCleanups);\n removeNodes(fallbackNodes);\n fallbackNodes = null;\n fallbackCleanups = [];\n }\n };\n\n const sub = rawEffect(() => {\n const nextList = listSignal.value ?? [];\n\n if (nextList.length === 0) {\n for (const entry of untrack(() => itemsOrdered)) removeItem(entry);\n itemsMap = new Map();\n itemsOrdered = [];\n\n if (!fallbackNodes) untrack(mountFallback);\n\n return;\n }\n\n clearFallback();\n\n try {\n itemsOrdered = untrack(() => reconcileItems(itemsMap, nextList, keyFn, render, parent, endMarker));\n } catch (err) {\n const cause = err instanceof Error ? err : new Error(String(err));\n\n // Dispatched on the anchor comment (always a live DOM node) rather than the enclosing\n // component's host element, which each() has no direct reference to — the event still\n // bubbles/composes up to any ancestor listener, including a global one on document.\n reportRuntimeError(\n new OreLifecycleError(`each() failed to reconcile a list update: ${cause.message}`, {\n cause,\n component: 'each()',\n phase: 'each-reconcile',\n }),\n anchor,\n );\n\n for (const entry of itemsMap.values()) removeItem(entry);\n itemsMap = new Map();\n itemsOrdered = [];\n }\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n clearFallback();\n for (const entry of itemsOrdered) removeItem(entry);\n endMarker.remove();\n });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"each.js","names":[],"sources":["../../src/directives/each.ts"],"sourcesContent":["import {\n batch,\n computed,\n createScope,\n type Readable,\n effect as rawEffect,\n type Scope,\n type Signal,\n signal,\n untrack,\n} from '@vielzeug/ripple';\n\nimport { invariant, ORE_ERRORS, OreApiError, OreLifecycleError, reportRuntimeError } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult } from '../template/result';\nimport { removeNodes, runAll } from '../utils/dom';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ntype MaybeReactiveArray<T> = Readable<T[]> | (() => T[]) | T[];\n\ntype ItemEntry<T> = {\n cleanups: (() => void)[];\n data: Signal<T>;\n index: Signal<number>;\n /** The key used to identify this entry. */\n key: string;\n nodes: Node[];\n scope: Scope;\n};\n\n// ─── Item lifecycle ───────────────────────────────────────────────────────────\n\nconst createItem = <T>(\n item: T,\n index: number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n): ItemEntry<T> => {\n const dataSignal: Signal<T> = signal(item);\n const indexSignal: Signal<number> = signal(index);\n const scope = createScope();\n const cleanups: (() => void)[] = [];\n let nodes: Node[] = [];\n\n scope.run(() => {\n const result = render(dataSignal, indexSignal);\n\n nodes = result.mount(parent, insertBefore, (fn) => cleanups.push(fn));\n });\n\n return { cleanups, data: dataSignal, index: indexSignal, key: '', nodes, scope };\n};\n\nconst removeItem = <T>(entry: ItemEntry<T>): void => {\n entry.scope.dispose();\n runAll(entry.cleanups);\n removeNodes(entry.nodes);\n};\n\n// ─── Reconciler ───────────────────────────────────────────────────────────────\n\n/**\n * Reconciles the live item map (mutated in-place) against the next array.\n * Stale entries are removed and destroyed; new entries are created and inserted.\n * Existing entries are updated in-place via signal writes.\n * Returns the ordered list of entries matching nextList.\n */\nconst reconcileItems = <T>(\n itemsMap: Map<string, ItemEntry<T>>,\n next: T[],\n keyFn: (item: T, index: number) => string | number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n parent: ParentNode,\n endMarker: Node,\n): ItemEntry<T>[] => {\n const nextKeys: string[] = [];\n const nextKeySet = new Set<string>();\n\n for (let i = 0; i < next.length; i++) {\n const key = String(keyFn(next[i], i));\n\n if (nextKeySet.has(key)) throw new OreApiError(ORE_ERRORS.eachDuplicateKey(key, i));\n\n nextKeySet.add(key);\n nextKeys.push(key);\n }\n\n // Remove stale entries from the map\n for (const [key, entry] of itemsMap) {\n if (!nextKeySet.has(key)) {\n removeItem(entry);\n itemsMap.delete(key);\n }\n }\n\n // Build the next ordered list: update existing items, create new ones\n const nextOrdered: ItemEntry<T>[] = [];\n\n for (let i = 0; i < next.length; i++) {\n const key = nextKeys[i];\n const existing = itemsMap.get(key);\n\n if (existing) {\n batch(() => {\n existing.data.value = next[i];\n existing.index.value = i;\n });\n nextOrdered.push(existing);\n } else {\n const entry = untrack(() => createItem(next[i], i, render, parent, endMarker));\n\n entry.key = key;\n itemsMap.set(key, entry);\n nextOrdered.push(entry);\n }\n }\n\n // DOM ordering: right-to-left pass — move any item not already adjacent to cursor.\n // O(n) DOM operations in the worst case; optimal for the typical small list sizes\n // encountered in UI components (tabs, options, menu items).\n let cursor: Node = endMarker;\n\n for (let j = nextOrdered.length - 1; j >= 0; j--) {\n const entry = nextOrdered[j];\n const firstNode = entry.nodes[0];\n\n if (firstNode && firstNode !== cursor.previousSibling) {\n for (const node of entry.nodes) parent.insertBefore(node, cursor);\n }\n\n cursor = firstNode ?? cursor;\n }\n\n return nextOrdered;\n};\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Renders a keyed list of items as a `DirectiveResult`.\n *\n * Each item is rendered by the provided render function.\n * Items are reused by key when the list changes; only stale items are destroyed.\n *\n * The render function receives a `Readable<T>` signal and a `Readable<number>` index\n * signal. Use `item.value` to read the current item inside reactive expressions:\n *\n * ```ts\n * html`${each(items, (item) => item.id, (item) => html`<li>${() => item.value.name}</li>`)}`\n * ```\n *\n * **Plain array:** when a plain `T[]` is passed (not a signal or getter), it is\n * treated as a one-time static render. Mutations to the original array are not\n * tracked. Pass a `Signal<T[]>` or `() => T[]` for reactive lists.\n *\n * **Optional fallback:** the fourth argument renders when the list is empty.\n *\n * **Key choice:** pass a stable item identifier (e.g. `item.id`), never the\n * array index — an index-based key reassigns to a different item whenever the\n * list is reordered or an item is inserted/removed before it, causing full\n * item teardown/recreation instead of the in-place update `each()` is built\n * for.\n *\n * **Duplicate keys:** a reconciliation failure (e.g. duplicate keys, see `eachDuplicateKey`)\n * does not throw past this function — an uncaught exception inside the reactive effect that\n * drives `each()` would risk corrupting unrelated effects scheduled in the same update batch.\n * Instead the list is cleared and the failure is reported via the `ore:error` DOM event (see\n * `OreLifecycleError`, phase `'each-reconcile'`) plus a dev-only console log — listen for\n * `ore:error` on `document`/`window` to observe this in every build, including production.\n */\nexport function each<T>(\n list: MaybeReactiveArray<T>,\n keyFn: (item: T, index: number) => string | number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n fallback?: () => HTMLResult,\n): DirectiveResult {\n const listSignal = Array.isArray(list)\n ? signal(list as T[])\n : typeof list === 'function'\n ? computed(list as () => T[])\n : list;\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'each() anchor comment has no parent node');\n\n const endMarker = document.createComment('each/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n let itemsMap = new Map<string, ItemEntry<T>>();\n let itemsOrdered: ItemEntry<T>[] = [];\n let fallbackNodes: Node[] | null = null;\n let fallbackCleanups: (() => void)[] = [];\n\n const mountFallback = (): void => {\n if (!fallback) return;\n\n const result = fallback();\n\n fallbackNodes = result.mount(parent, endMarker, (fn) => fallbackCleanups.push(fn));\n };\n\n const clearFallback = (): void => {\n if (fallbackNodes) {\n runAll(fallbackCleanups);\n removeNodes(fallbackNodes);\n fallbackNodes = null;\n fallbackCleanups = [];\n }\n };\n\n const sub = rawEffect(() => {\n const nextList = listSignal.value ?? [];\n\n if (nextList.length === 0) {\n for (const entry of untrack(() => itemsOrdered)) removeItem(entry);\n itemsMap = new Map();\n itemsOrdered = [];\n\n if (!fallbackNodes) untrack(mountFallback);\n\n return;\n }\n\n clearFallback();\n\n try {\n itemsOrdered = untrack(() => reconcileItems(itemsMap, nextList, keyFn, render, parent, endMarker));\n } catch (err) {\n const cause = err instanceof Error ? err : new Error(String(err));\n\n // Dispatched on the anchor comment (always a live DOM node) rather than the enclosing\n // component's host element, which each() has no direct reference to — the event still\n // bubbles/composes up to any ancestor listener, including a global one on document.\n reportRuntimeError(\n new OreLifecycleError(`each() failed to reconcile a list update: ${cause.message}`, {\n cause,\n component: 'each()',\n phase: 'each-reconcile',\n }),\n anchor,\n );\n\n for (const entry of itemsMap.values()) removeItem(entry);\n itemsMap = new Map();\n itemsOrdered = [];\n }\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n clearFallback();\n for (const entry of itemsOrdered) removeItem(entry);\n endMarker.remove();\n });\n });\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"unsafe-html.cjs","names":[],"sources":["../../src/directives/unsafe-html.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, type Signal } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../template/result';\nimport { createReplaceableSlot } from '../utils/dom';\n\nconst parseHtml = (html: string, parent: ParentNode, insertBefore: Node): Node[] => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const nodes = Array.from(tpl.content.cloneNode(true).childNodes);\n\n for (const node of nodes) parent.insertBefore(node, insertBefore);\n\n return nodes;\n};\n\n/**\n * Renders HTML without escaping as a DirectiveResult.\n *\n * This is intentionally named `unsafeHtml`: sanitization is an application\n * boundary, not mutable process-wide framework configuration. Sanitize\n * untrusted content before passing it here.\n *\n * Supports static strings, signals, and getter functions `() => string`.\n * When reactive, the DOM is updated in-place whenever the value changes.\n */\nexport function unsafeHtml(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult {\n if (typeof value === 'function') {\n const c = computed(value);\n\n return createDirectiveResult((anchor, registerCleanup) => {\n unsafeHtml(c).mount(anchor, registerCleanup);\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'unsafeHtml() anchor comment has no parent node');\n\n const endMarker = document.createComment('unsafe-html/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (isReactive(value)) {\n const slot = createReplaceableSlot();\n const src = value as Readable<string>;\n\n const stop = rawEffect(() => {\n slot.clear();\n slot.setNodes(parseHtml(src.value, parent, endMarker));\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n } else {\n parseHtml(value, parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"qIAMA,IAAM,GAAa,EAAc,EAAoB,IAA+B,CAClF,IAAM,EAAM,SAAS,cAAc,UAAU,EAE7C,EAAI,UAAY,EAEhB,IAAM,EAAQ,MAAM,KAAK,EAAI,QAAQ,UAAU,EAAI,CAAC,CAAC,UAAU,EAE/D,IAAK,IAAM,KAAQ,EAAO,EAAO,aAAa,EAAM,CAAY,EAEhE,OAAO,CACT,EAYA,SAAgB,EAAW,EAAqF,CAC9G,GAAI,OAAO,GAAU,WAAY,CAC/B,IAAM,GAAA,EAAI,EAAA,SAAA,CAAS,CAAK,EAExB,OAAO,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,EAAW,CAAC,CAAC,CAAC,MAAM,EAAQ,CAAe,CAC7C,CAAC,CACH,CAEA,OAAO,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,gDAAgD,EAElE,IAAM,EAAY,SAAS,cAAc,iBAAiB,EAI1D,GAFA,EAAO,aAAa,EAAW,EAAO,WAAW,GAEjD,EAAI,EAAA,WAAA,CAAW,CAAK,EAAG,CACrB,IAAM,EAAO,EAAA,sBAAsB,EAC7B,EAAM,EAEN,GAAA,EAAO,EAAA,OAAA,KAAgB,CAC3B,EAAK,MAAM,EACX,EAAK,SAAS,EAAU,EAAI,MAAO,EAAQ,CAAS,CAAC,CACvD,CAAC,EAED,MAAsB,EAAK,QAAQ,CAAC,EACpC,MAAsB,CACpB,EAAK,MAAM,EACX,EAAU,OAAO,CACnB,CAAC,CACH,MACE,EAAU,EAAO,EAAQ,CAAS,EAElC,MAAsB,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH"}
1
+ {"version":3,"file":"unsafe-html.cjs","names":[],"sources":["../../src/directives/unsafe-html.ts"],"sourcesContent":["import { computed, isReactive, type Readable, effect as rawEffect, type Signal } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../template/result';\nimport { createReplaceableSlot } from '../utils/dom';\n\nconst parseHtml = (html: string, parent: ParentNode, insertBefore: Node): Node[] => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const nodes = Array.from(tpl.content.cloneNode(true).childNodes);\n\n for (const node of nodes) parent.insertBefore(node, insertBefore);\n\n return nodes;\n};\n\n/**\n * Renders HTML without escaping as a DirectiveResult.\n *\n * This is intentionally named `unsafeHtml`: sanitization is an application\n * boundary, not mutable process-wide framework configuration. Sanitize\n * untrusted content before passing it here.\n *\n * Supports static strings, signals, and getter functions `() => string`.\n * When reactive, the DOM is updated in-place whenever the value changes.\n */\nexport function unsafeHtml(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult {\n if (typeof value === 'function') {\n const c = computed(value);\n\n return createDirectiveResult((anchor, registerCleanup) => {\n unsafeHtml(c).mount(anchor, registerCleanup);\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'unsafeHtml() anchor comment has no parent node');\n\n const endMarker = document.createComment('unsafe-html/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (isReactive(value)) {\n const slot = createReplaceableSlot();\n const src = value as Readable<string>;\n\n const stop = rawEffect(() => {\n slot.clear();\n slot.setNodes(parseHtml(src.value, parent, endMarker));\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n } else {\n parseHtml(value, parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"qIAMA,IAAM,GAAa,EAAc,EAAoB,IAA+B,CAClF,IAAM,EAAM,SAAS,cAAc,UAAU,EAE7C,EAAI,UAAY,EAEhB,IAAM,EAAQ,MAAM,KAAK,EAAI,QAAQ,UAAU,EAAI,CAAC,CAAC,UAAU,EAE/D,IAAK,IAAM,KAAQ,EAAO,EAAO,aAAa,EAAM,CAAY,EAEhE,OAAO,CACT,EAYA,SAAgB,EAAW,EAAqF,CAC9G,GAAI,OAAO,GAAU,WAAY,CAC/B,IAAM,GAAA,EAAI,EAAA,SAAA,CAAS,CAAK,EAExB,OAAO,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,EAAW,CAAC,CAAC,CAAC,MAAM,EAAQ,CAAe,CAC7C,CAAC,CACH,CAEA,OAAO,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,gDAAgD,EAElE,IAAM,EAAY,SAAS,cAAc,iBAAiB,EAI1D,GAFA,EAAO,aAAa,EAAW,EAAO,WAAW,GAEjD,EAAI,EAAA,WAAA,CAAW,CAAK,EAAG,CACrB,IAAM,EAAO,EAAA,sBAAsB,EAC7B,EAAM,EAEN,GAAA,EAAO,EAAA,OAAA,KAAgB,CAC3B,EAAK,MAAM,EACX,EAAK,SAAS,EAAU,EAAI,MAAO,EAAQ,CAAS,CAAC,CACvD,CAAC,EAED,MAAsB,EAAK,QAAQ,CAAC,EACpC,MAAsB,CACpB,EAAK,MAAM,EACX,EAAU,OAAO,CACnB,CAAC,CACH,MACE,EAAU,EAAO,EAAQ,CAAS,EAElC,MAAsB,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"unsafe-html.d.ts","sourceRoot":"","sources":["../../src/directives/unsafe-html.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAGzG,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAejF;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,eAAe,CAsC9G"}
1
+ {"version":3,"file":"unsafe-html.d.ts","sourceRoot":"","sources":["../../src/directives/unsafe-html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,QAAQ,EAAuB,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAGzG,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAejF;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,eAAe,CAsC9G"}
@@ -1 +1 @@
1
- {"version":3,"file":"unsafe-html.js","names":[],"sources":["../../src/directives/unsafe-html.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, type Signal } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../template/result';\nimport { createReplaceableSlot } from '../utils/dom';\n\nconst parseHtml = (html: string, parent: ParentNode, insertBefore: Node): Node[] => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const nodes = Array.from(tpl.content.cloneNode(true).childNodes);\n\n for (const node of nodes) parent.insertBefore(node, insertBefore);\n\n return nodes;\n};\n\n/**\n * Renders HTML without escaping as a DirectiveResult.\n *\n * This is intentionally named `unsafeHtml`: sanitization is an application\n * boundary, not mutable process-wide framework configuration. Sanitize\n * untrusted content before passing it here.\n *\n * Supports static strings, signals, and getter functions `() => string`.\n * When reactive, the DOM is updated in-place whenever the value changes.\n */\nexport function unsafeHtml(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult {\n if (typeof value === 'function') {\n const c = computed(value);\n\n return createDirectiveResult((anchor, registerCleanup) => {\n unsafeHtml(c).mount(anchor, registerCleanup);\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'unsafeHtml() anchor comment has no parent node');\n\n const endMarker = document.createComment('unsafe-html/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (isReactive(value)) {\n const slot = createReplaceableSlot();\n const src = value as Readable<string>;\n\n const stop = rawEffect(() => {\n slot.clear();\n slot.setNodes(parseHtml(src.value, parent, endMarker));\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n } else {\n parseHtml(value, parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"uOAMA,IAAM,GAAa,EAAc,EAAoB,IAA+B,CAClF,IAAM,EAAM,SAAS,cAAc,UAAU,EAE7C,EAAI,UAAY,EAEhB,IAAM,EAAQ,MAAM,KAAK,EAAI,QAAQ,UAAU,EAAI,CAAC,CAAC,UAAU,EAE/D,IAAK,IAAM,KAAQ,EAAO,EAAO,aAAa,EAAM,CAAY,EAEhE,OAAO,CACT,EAYA,SAAgB,EAAW,EAAqF,CAC9G,GAAI,OAAO,GAAU,WAAY,CAC/B,IAAM,EAAI,EAAS,CAAK,EAExB,OAAO,GAAuB,EAAQ,IAAoB,CACxD,EAAW,CAAC,CAAC,CAAC,MAAM,EAAQ,CAAe,CAC7C,CAAC,CACH,CAEA,OAAO,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAO,WAEtB,EAAU,EAAQ,gDAAgD,EAElE,IAAM,EAAY,SAAS,cAAc,iBAAiB,EAI1D,GAFA,EAAO,aAAa,EAAW,EAAO,WAAW,EAE7C,EAAW,CAAK,EAAG,CACrB,IAAM,EAAO,EAAsB,EAC7B,EAAM,EAEN,EAAO,MAAgB,CAC3B,EAAK,MAAM,EACX,EAAK,SAAS,EAAU,EAAI,MAAO,EAAQ,CAAS,CAAC,CACvD,CAAC,EAED,MAAsB,EAAK,QAAQ,CAAC,EACpC,MAAsB,CACpB,EAAK,MAAM,EACX,EAAU,OAAO,CACnB,CAAC,CACH,MACE,EAAU,EAAO,EAAQ,CAAS,EAElC,MAAsB,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH"}
1
+ {"version":3,"file":"unsafe-html.js","names":[],"sources":["../../src/directives/unsafe-html.ts"],"sourcesContent":["import { computed, isReactive, type Readable, effect as rawEffect, type Signal } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../template/result';\nimport { createReplaceableSlot } from '../utils/dom';\n\nconst parseHtml = (html: string, parent: ParentNode, insertBefore: Node): Node[] => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const nodes = Array.from(tpl.content.cloneNode(true).childNodes);\n\n for (const node of nodes) parent.insertBefore(node, insertBefore);\n\n return nodes;\n};\n\n/**\n * Renders HTML without escaping as a DirectiveResult.\n *\n * This is intentionally named `unsafeHtml`: sanitization is an application\n * boundary, not mutable process-wide framework configuration. Sanitize\n * untrusted content before passing it here.\n *\n * Supports static strings, signals, and getter functions `() => string`.\n * When reactive, the DOM is updated in-place whenever the value changes.\n */\nexport function unsafeHtml(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult {\n if (typeof value === 'function') {\n const c = computed(value);\n\n return createDirectiveResult((anchor, registerCleanup) => {\n unsafeHtml(c).mount(anchor, registerCleanup);\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'unsafeHtml() anchor comment has no parent node');\n\n const endMarker = document.createComment('unsafe-html/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (isReactive(value)) {\n const slot = createReplaceableSlot();\n const src = value as Readable<string>;\n\n const stop = rawEffect(() => {\n slot.clear();\n slot.setNodes(parseHtml(src.value, parent, endMarker));\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n } else {\n parseHtml(value, parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"uOAMA,IAAM,GAAa,EAAc,EAAoB,IAA+B,CAClF,IAAM,EAAM,SAAS,cAAc,UAAU,EAE7C,EAAI,UAAY,EAEhB,IAAM,EAAQ,MAAM,KAAK,EAAI,QAAQ,UAAU,EAAI,CAAC,CAAC,UAAU,EAE/D,IAAK,IAAM,KAAQ,EAAO,EAAO,aAAa,EAAM,CAAY,EAEhE,OAAO,CACT,EAYA,SAAgB,EAAW,EAAqF,CAC9G,GAAI,OAAO,GAAU,WAAY,CAC/B,IAAM,EAAI,EAAS,CAAK,EAExB,OAAO,GAAuB,EAAQ,IAAoB,CACxD,EAAW,CAAC,CAAC,CAAC,MAAM,EAAQ,CAAe,CAC7C,CAAC,CACH,CAEA,OAAO,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAO,WAEtB,EAAU,EAAQ,gDAAgD,EAElE,IAAM,EAAY,SAAS,cAAc,iBAAiB,EAI1D,GAFA,EAAO,aAAa,EAAW,EAAO,WAAW,EAE7C,EAAW,CAAK,EAAG,CACrB,IAAM,EAAO,EAAsB,EAC7B,EAAM,EAEN,EAAO,MAAgB,CAC3B,EAAK,MAAM,EACX,EAAK,SAAS,EAAU,EAAI,MAAO,EAAQ,CAAS,CAAC,CACvD,CAAC,EAED,MAAsB,EAAK,QAAQ,CAAC,EACpC,MAAsB,CACpB,EAAK,MAAM,EACX,EAAU,OAAO,CACnB,CAAC,CACH,MACE,EAAU,EAAO,EAAQ,CAAS,EAElC,MAAsB,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"when.cjs","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, untrack } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../template/result';\nimport { createReplaceableSlot, removeNodes } from '../utils/dom';\n\ntype MaybeReactive<T> = T | (() => T) | Readable<T>;\n\ntype WhenRenderable = HTMLResult | null | undefined | false;\n\nconst NO_PARENT_MSG = 'when() anchor comment has no parent node';\n\n/**\n * Conditionally renders one of two branches as a `DirectiveResult`.\n *\n * The condition may be a boolean, signal, or getter function.\n * When the condition changes, the current branch is cleaned up and\n * the new branch is mounted in its place.\n *\n * @example\n * ```ts\n * html`${when(isLoggedIn, () => html`<p>Welcome</p>`, () => html`<p>Log in</p>`)}`\n * ```\n */\nexport function when(\n condition: MaybeReactive<boolean>,\n truthy: () => WhenRenderable,\n falsy?: () => WhenRenderable,\n): DirectiveResult {\n if (typeof condition !== 'function' && !isReactive(condition)) {\n return createDirectiveResult((anchor, registerCleanup) => {\n const branch = condition ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const nodes = branch.mount(parent, anchor, registerCleanup);\n\n registerCleanup(() => removeNodes(nodes));\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const ownedComputed = typeof condition === 'function' ? computed(condition as () => boolean) : null;\n const conditionSignal = ownedComputed ?? (condition as Readable<boolean>);\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const endMarker = document.createComment('when/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n const slot = createReplaceableSlot();\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n slot.clear();\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n slot.setNodes(untrack(() => branch.mount(parent, endMarker, slot.registerCleanup)));\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n });\n}\n"],"mappings":"qIAUA,IAAM,EAAgB,2CActB,SAAgB,EACd,EACA,EACA,EACiB,CAiBjB,OAhBI,OAAO,GAAc,YAAc,EAAA,EAAC,EAAA,WAAA,CAAW,CAAS,EACnD,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAY,EAAO,EAAI,EAAQ,EAAM,EAAI,KAExD,GAAI,CAAC,GAAU,CAAC,EAAA,aAAa,CAAM,EAAG,OAEtC,IAAM,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,CAAa,EAE/B,IAAM,EAAQ,EAAO,MAAM,EAAQ,EAAQ,CAAe,EAE1D,MAAsB,EAAA,YAAY,CAAK,CAAC,CAC1C,CAAC,EAGI,EAAA,uBAAuB,EAAQ,IAAoB,CAExD,IAAM,GADgB,OAAO,GAAc,YAAA,EAAa,EAAA,SAAA,CAAS,CAA0B,EAAI,OACrD,EAEpC,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,CAAa,EAE/B,IAAM,EAAY,SAAS,cAAc,UAAU,EAEnD,EAAO,aAAa,EAAW,EAAO,WAAW,EAEjD,IAAM,EAAO,EAAA,sBAAsB,EAE7B,GAAA,EAAM,EAAA,OAAA,KAAgB,CAC1B,IAAM,EAAO,EAAgB,MAE7B,EAAK,MAAM,EAEX,IAAM,EAAS,EAAO,EAAO,EAAI,EAAQ,EAAM,EAAI,KAE/C,CAAC,GAAU,CAAC,EAAA,aAAa,CAAM,GAEnC,EAAK,UAAA,EAAS,EAAA,QAAA,KAAc,EAAO,MAAM,EAAQ,EAAW,EAAK,eAAe,CAAC,CAAC,CACpF,CAAC,EAED,MAAsB,EAAI,QAAQ,CAAC,EACnC,MAAsB,CACpB,EAAK,MAAM,EACX,EAAU,OAAO,CACnB,CAAC,CACH,CAAC,CACH"}
1
+ {"version":3,"file":"when.cjs","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, isReactive, type Readable, effect as rawEffect, untrack } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../template/result';\nimport { createReplaceableSlot, removeNodes } from '../utils/dom';\n\ntype MaybeReactive<T> = T | (() => T) | Readable<T>;\n\ntype WhenRenderable = HTMLResult | null | undefined | false;\n\nconst NO_PARENT_MSG = 'when() anchor comment has no parent node';\n\n/**\n * Conditionally renders one of two branches as a `DirectiveResult`.\n *\n * The condition may be a boolean, signal, or getter function.\n * When the condition changes, the current branch is cleaned up and\n * the new branch is mounted in its place.\n *\n * @example\n * ```ts\n * html`${when(isLoggedIn, () => html`<p>Welcome</p>`, () => html`<p>Log in</p>`)}`\n * ```\n */\nexport function when(\n condition: MaybeReactive<boolean>,\n truthy: () => WhenRenderable,\n falsy?: () => WhenRenderable,\n): DirectiveResult {\n if (typeof condition !== 'function' && !isReactive(condition)) {\n return createDirectiveResult((anchor, registerCleanup) => {\n const branch = condition ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const nodes = branch.mount(parent, anchor, registerCleanup);\n\n registerCleanup(() => removeNodes(nodes));\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const ownedComputed = typeof condition === 'function' ? computed(condition as () => boolean) : null;\n const conditionSignal = ownedComputed ?? (condition as Readable<boolean>);\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const endMarker = document.createComment('when/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n const slot = createReplaceableSlot();\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n slot.clear();\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n slot.setNodes(untrack(() => branch.mount(parent, endMarker, slot.registerCleanup)));\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n });\n}\n"],"mappings":"qIAUA,IAAM,EAAgB,2CActB,SAAgB,EACd,EACA,EACA,EACiB,CAiBjB,OAhBI,OAAO,GAAc,YAAc,EAAA,EAAC,EAAA,WAAA,CAAW,CAAS,EACnD,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAY,EAAO,EAAI,EAAQ,EAAM,EAAI,KAExD,GAAI,CAAC,GAAU,CAAC,EAAA,aAAa,CAAM,EAAG,OAEtC,IAAM,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,CAAa,EAE/B,IAAM,EAAQ,EAAO,MAAM,EAAQ,EAAQ,CAAe,EAE1D,MAAsB,EAAA,YAAY,CAAK,CAAC,CAC1C,CAAC,EAGI,EAAA,uBAAuB,EAAQ,IAAoB,CAExD,IAAM,GADgB,OAAO,GAAc,YAAA,EAAa,EAAA,SAAA,CAAS,CAA0B,EAAI,OACrD,EAEpC,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,CAAa,EAE/B,IAAM,EAAY,SAAS,cAAc,UAAU,EAEnD,EAAO,aAAa,EAAW,EAAO,WAAW,EAEjD,IAAM,EAAO,EAAA,sBAAsB,EAE7B,GAAA,EAAM,EAAA,OAAA,KAAgB,CAC1B,IAAM,EAAO,EAAgB,MAE7B,EAAK,MAAM,EAEX,IAAM,EAAS,EAAO,EAAO,EAAI,EAAQ,EAAM,EAAI,KAE/C,CAAC,GAAU,CAAC,EAAA,aAAa,CAAM,GAEnC,EAAK,UAAA,EAAS,EAAA,QAAA,KAAc,EAAO,MAAM,EAAQ,EAAW,EAAK,eAAe,CAAC,CAAC,CACpF,CAAC,EAED,MAAsB,EAAI,QAAQ,CAAC,EACnC,MAAsB,CACpB,EAAK,MAAM,EACX,EAAU,OAAO,CACnB,CAAC,CACH,CAAC,CACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"when.d.ts","sourceRoot":"","sources":["../../src/directives/when.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,QAAQ,EAAW,MAAM,kBAAkB,CAAC;AAGrG,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,UAAU,EAAgB,MAAM,oBAAoB,CAAC;AAGhH,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AAEpD,KAAK,cAAc,GAAG,UAAU,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC;AAI5D;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAClB,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,EACjC,MAAM,EAAE,MAAM,cAAc,EAC5B,KAAK,CAAC,EAAE,MAAM,cAAc,GAC3B,eAAe,CAiDjB"}
1
+ {"version":3,"file":"when.d.ts","sourceRoot":"","sources":["../../src/directives/when.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,QAAQ,EAAgC,MAAM,kBAAkB,CAAC;AAGrG,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,UAAU,EAAgB,MAAM,oBAAoB,CAAC;AAGhH,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AAEpD,KAAK,cAAc,GAAG,UAAU,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC;AAI5D;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAClB,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,EACjC,MAAM,EAAE,MAAM,cAAc,EAC5B,KAAK,CAAC,EAAE,MAAM,cAAc,GAC3B,eAAe,CAiDjB"}