@vielzeug/ore 1.0.5 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/README.md +36 -3
  2. package/dist/_dev.cjs +1 -1
  3. package/dist/_dev.cjs.map +1 -1
  4. package/dist/_dev.js +1 -1
  5. package/dist/_dev.js.map +1 -1
  6. package/dist/aria.cjs +1 -1
  7. package/dist/aria.cjs.map +1 -1
  8. package/dist/aria.d.ts +16 -8
  9. package/dist/aria.d.ts.map +1 -1
  10. package/dist/aria.js +1 -1
  11. package/dist/aria.js.map +1 -1
  12. package/dist/base-element.cjs +1 -1
  13. package/dist/base-element.cjs.map +1 -1
  14. package/dist/base-element.d.ts +36 -1
  15. package/dist/base-element.d.ts.map +1 -1
  16. package/dist/base-element.js +1 -1
  17. package/dist/base-element.js.map +1 -1
  18. package/dist/component-types.d.ts +13 -76
  19. package/dist/component-types.d.ts.map +1 -1
  20. package/dist/context.cjs +1 -1
  21. package/dist/context.cjs.map +1 -1
  22. package/dist/context.d.ts +11 -2
  23. package/dist/context.d.ts.map +1 -1
  24. package/dist/context.js +1 -1
  25. package/dist/context.js.map +1 -1
  26. package/dist/define.cjs.map +1 -1
  27. package/dist/define.d.ts +13 -12
  28. package/dist/define.d.ts.map +1 -1
  29. package/dist/define.js.map +1 -1
  30. package/dist/directives/each.cjs +1 -1
  31. package/dist/directives/each.cjs.map +1 -1
  32. package/dist/directives/each.d.ts +6 -0
  33. package/dist/directives/each.d.ts.map +1 -1
  34. package/dist/directives/each.js +1 -1
  35. package/dist/directives/each.js.map +1 -1
  36. package/dist/directives/raw.cjs +1 -1
  37. package/dist/directives/raw.cjs.map +1 -1
  38. package/dist/directives/raw.d.ts.map +1 -1
  39. package/dist/directives/raw.js +1 -1
  40. package/dist/directives/raw.js.map +1 -1
  41. package/dist/directives/when.cjs +1 -1
  42. package/dist/directives/when.cjs.map +1 -1
  43. package/dist/directives/when.d.ts.map +1 -1
  44. package/dist/directives/when.js +1 -1
  45. package/dist/directives/when.js.map +1 -1
  46. package/dist/errors.cjs +2 -2
  47. package/dist/errors.cjs.map +1 -1
  48. package/dist/errors.d.ts +23 -1
  49. package/dist/errors.d.ts.map +1 -1
  50. package/dist/errors.js +2 -2
  51. package/dist/errors.js.map +1 -1
  52. package/dist/forms/context.cjs +2 -0
  53. package/dist/forms/context.cjs.map +1 -0
  54. package/dist/{form-context.d.ts → forms/context.d.ts} +5 -5
  55. package/dist/forms/context.d.ts.map +1 -0
  56. package/dist/forms/context.js +2 -0
  57. package/dist/forms/context.js.map +1 -0
  58. package/dist/forms/field.cjs +2 -0
  59. package/dist/forms/field.cjs.map +1 -0
  60. package/dist/{form-field.d.ts → forms/field.d.ts} +19 -2
  61. package/dist/forms/field.d.ts.map +1 -0
  62. package/dist/forms/field.js +2 -0
  63. package/dist/forms/field.js.map +1 -0
  64. package/dist/forms/index.d.ts +11 -0
  65. package/dist/forms/index.d.ts.map +1 -0
  66. package/dist/forms.cjs +1 -0
  67. package/dist/forms.js +1 -0
  68. package/dist/host-bind.cjs +1 -1
  69. package/dist/host-bind.cjs.map +1 -1
  70. package/dist/host-bind.d.ts +8 -2
  71. package/dist/host-bind.d.ts.map +1 -1
  72. package/dist/host-bind.js +1 -1
  73. package/dist/host-bind.js.map +1 -1
  74. package/dist/index.cjs +1 -1
  75. package/dist/index.d.ts +8 -8
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +1 -1
  78. package/dist/ore.cjs +2 -2
  79. package/dist/ore.cjs.map +1 -1
  80. package/dist/ore.iife.js +2 -2
  81. package/dist/ore.iife.js.map +1 -1
  82. package/dist/ore.js +2 -2
  83. package/dist/ore.js.map +1 -1
  84. package/dist/props.cjs +1 -1
  85. package/dist/props.cjs.map +1 -1
  86. package/dist/props.d.ts.map +1 -1
  87. package/dist/props.js +1 -1
  88. package/dist/props.js.map +1 -1
  89. package/dist/runtime.cjs +1 -1
  90. package/dist/runtime.cjs.map +1 -1
  91. package/dist/runtime.d.ts +32 -1
  92. package/dist/runtime.d.ts.map +1 -1
  93. package/dist/runtime.js +1 -1
  94. package/dist/runtime.js.map +1 -1
  95. package/dist/slots.cjs +1 -1
  96. package/dist/slots.cjs.map +1 -1
  97. package/dist/slots.d.ts +12 -1
  98. package/dist/slots.d.ts.map +1 -1
  99. package/dist/slots.js +1 -1
  100. package/dist/slots.js.map +1 -1
  101. package/dist/template/bindings.cjs +1 -1
  102. package/dist/template/bindings.cjs.map +1 -1
  103. package/dist/template/bindings.d.ts.map +1 -1
  104. package/dist/template/bindings.js +1 -1
  105. package/dist/template/bindings.js.map +1 -1
  106. package/dist/template/compiler.cjs +1 -1
  107. package/dist/template/compiler.cjs.map +1 -1
  108. package/dist/template/compiler.d.ts +11 -1
  109. package/dist/template/compiler.d.ts.map +1 -1
  110. package/dist/template/compiler.js +1 -1
  111. package/dist/template/compiler.js.map +1 -1
  112. package/dist/template/instantiator.cjs +1 -1
  113. package/dist/template/instantiator.cjs.map +1 -1
  114. package/dist/template/instantiator.d.ts +0 -5
  115. package/dist/template/instantiator.d.ts.map +1 -1
  116. package/dist/template/instantiator.js +1 -1
  117. package/dist/template/instantiator.js.map +1 -1
  118. package/dist/testing/dom.cjs +2 -0
  119. package/dist/testing/dom.cjs.map +1 -0
  120. package/dist/testing/dom.d.ts +22 -0
  121. package/dist/testing/dom.d.ts.map +1 -0
  122. package/dist/testing/dom.js +2 -0
  123. package/dist/testing/dom.js.map +1 -0
  124. package/dist/testing/form-internals-polyfill.cjs +2 -0
  125. package/dist/testing/form-internals-polyfill.cjs.map +1 -0
  126. package/dist/testing/form-internals-polyfill.d.ts +17 -0
  127. package/dist/testing/form-internals-polyfill.d.ts.map +1 -0
  128. package/dist/testing/form-internals-polyfill.js +2 -0
  129. package/dist/testing/form-internals-polyfill.js.map +1 -0
  130. package/dist/testing/mount.cjs.map +1 -1
  131. package/dist/testing/mount.d.ts +4 -4
  132. package/dist/testing/mount.d.ts.map +1 -1
  133. package/dist/testing/mount.js.map +1 -1
  134. package/dist/testing/render-hook.cjs +1 -1
  135. package/dist/testing/render-hook.cjs.map +1 -1
  136. package/dist/testing/render-hook.d.ts +6 -6
  137. package/dist/testing/render-hook.d.ts.map +1 -1
  138. package/dist/testing/render-hook.js +1 -1
  139. package/dist/testing/render-hook.js.map +1 -1
  140. package/dist/testing/testing.cjs +1 -1
  141. package/dist/testing/testing.cjs.map +1 -1
  142. package/dist/testing/testing.d.ts +7 -1
  143. package/dist/testing/testing.d.ts.map +1 -1
  144. package/dist/testing/testing.js +1 -1
  145. package/dist/testing/testing.js.map +1 -1
  146. package/dist/testing.cjs +1 -1
  147. package/dist/testing.js +1 -1
  148. package/dist/utils/emit.cjs +1 -1
  149. package/dist/utils/emit.cjs.map +1 -1
  150. package/dist/utils/emit.d.ts +28 -5
  151. package/dist/utils/emit.d.ts.map +1 -1
  152. package/dist/utils/emit.js +1 -1
  153. package/dist/utils/emit.js.map +1 -1
  154. package/package.json +12 -5
  155. package/dist/context-bag.cjs +0 -2
  156. package/dist/context-bag.cjs.map +0 -1
  157. package/dist/context-bag.d.ts +0 -12
  158. package/dist/context-bag.d.ts.map +0 -1
  159. package/dist/context-bag.js +0 -2
  160. package/dist/context-bag.js.map +0 -1
  161. package/dist/form-context.cjs +0 -2
  162. package/dist/form-context.cjs.map +0 -1
  163. package/dist/form-context.d.ts.map +0 -1
  164. package/dist/form-context.js +0 -2
  165. package/dist/form-context.js.map +0 -1
  166. package/dist/form-field.cjs +0 -2
  167. package/dist/form-field.cjs.map +0 -1
  168. package/dist/form-field.d.ts.map +0 -1
  169. package/dist/form-field.js +0 -2
  170. package/dist/form-field.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"context.cjs","names":[],"sources":["../src/context.ts"],"sourcesContent":["/**\n * Component context injection API — `inject` / `injectStrict` / `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 `ctx.provide(key, value)` inside `setup()`.\n */\n\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { getSetupContext, getCurrentElement } 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/** @internal Build a linear ancestor chain (including shadow host boundaries). */\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 const root = node.getRootNode() as Node;\n\n node = (node as HTMLElement).parentElement ?? (root instanceof ShadowRoot ? root.host : null);\n }\n\n return chain;\n};\n\n/**\n * Register a context value on a specific element.\n * @internal Used by ctx.provide() — do not call directly.\n */\nexport const provideOnElement = <T>(el: HTMLElement, key: InjectionKey<T>, value: T): void => {\n if (!contextRegistry.has(el)) contextRegistry.set(el, new Map());\n\n contextRegistry.get(el)!.set(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\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 ctx = getSetupContext();\n\n if (!ctx) throw new OreApiError(ORE_ERRORS.lifecycleOutsideSetup);\n\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)) {\n const cached = cache.get(cacheKey);\n\n if (cached === NOT_FOUND_SENTINEL) return rest.length > 0 ? rest[0] : undefined;\n\n return cached as T;\n }\n\n const found = walkAndFind(ctx.element, key);\n\n cache.set(cacheKey, found);\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 resolved = inject<T>(key, NOT_FOUND_SENTINEL as unknown as T);\n\n if (resolved !== (NOT_FOUND_SENTINEL as unknown)) return resolved;\n\n const host = getCurrentElement();\n\n throw new OreApiError(ORE_ERRORS.injectStrictFailed(String(key), host.localName));\n};\n\nexport function createContext<T>(description?: string): InjectionKey<T> {\n return Symbol(description) as InjectionKey<T>;\n}\n"],"mappings":"2DAWA,IAAM,EAAkB,IAAI,QAOtB,EAAsB,GAAsC,CAChE,IAAM,EAAuB,CAAC,EAC1B,EAAoB,EAExB,KAAO,GAAM,CACP,aAAgB,aAAa,EAAM,KAAK,CAAI,EAEhD,IAAM,EAAO,EAAK,YAAY,EAE9B,EAAQ,EAAqB,gBAAkB,aAAgB,WAAa,EAAK,KAAO,KAC1F,CAEA,OAAO,CACT,EAMa,GAAuB,EAAiB,EAAsB,IAAmB,CACvF,EAAgB,IAAI,CAAE,GAAG,EAAgB,IAAI,EAAI,IAAI,GAAK,EAE/D,EAAgB,IAAI,CAAE,CAAC,CAAE,IAAI,EAAK,CAAK,CACzC,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,EAIA,SAAgB,EAAU,EAAsB,GAAG,EAA2B,CAC5E,IAAM,EAAM,EAAA,gBAAgB,EAE5B,GAAI,CAAC,EAAK,MAAM,IAAI,EAAA,YAAY,EAAA,WAAW,qBAAqB,EAEhE,IAAI,EAAQ,EAAc,IAAI,CAAG,EAE5B,IACH,EAAQ,IAAI,IACZ,EAAc,IAAI,EAAK,CAAK,GAG9B,IAAM,EAAW,EAEjB,GAAI,EAAM,IAAI,CAAQ,EAAG,CACvB,IAAM,EAAS,EAAM,IAAI,CAAQ,EAIjC,OAFI,IAAW,EAA2B,EAAK,OAAS,EAAI,EAAK,GAAK,IAAA,GAE/D,CACT,CAEA,IAAM,EAAQ,EAAY,EAAI,QAAS,CAAG,EAM1C,OAJA,EAAM,IAAI,EAAU,CAAK,EAErB,IAAU,EAA2B,EAAK,OAAS,EAAI,EAAK,GAAK,IAAA,GAE9D,CACT,CAEA,IAAa,EAAmB,GAA4B,CAC1D,IAAM,EAAW,EAAU,EAAK,CAAkC,EAElE,GAAI,IAAc,EAAgC,OAAO,EAEzD,IAAM,EAAO,EAAA,kBAAkB,EAE/B,MAAM,IAAI,EAAA,YAAY,EAAA,WAAW,mBAAmB,OAAO,CAAG,EAAG,EAAK,SAAS,CAAC,CAClF,EAEA,SAAgB,EAAiB,EAAuC,CACtE,OAAO,OAAO,CAAW,CAC3B"}
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\nimport { warn } from './_dev';\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { getHost, 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/** @internal Build a linear ancestor chain (including shadow host boundaries). */\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 const root = node.getRootNode() as Node;\n\n node = (node as HTMLElement).parentElement ?? (root instanceof ShadowRoot ? root.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 => provideOnElement(getHost(), key, value);\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\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 ctx = requireSetupContext('inject');\n\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)) {\n const cached = cache.get(cacheKey);\n\n if (cached === NOT_FOUND_SENTINEL) return rest.length > 0 ? rest[0] : undefined;\n\n return cached as T;\n }\n\n const found = walkAndFind(ctx.element, key);\n\n cache.set(cacheKey, found);\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 resolved = inject<T>(key, NOT_FOUND_SENTINEL as unknown as T);\n\n if (resolved !== (NOT_FOUND_SENTINEL as unknown)) return resolved;\n\n const host = getHost();\n\n throw new OreApiError(ORE_ERRORS.injectStrictFailed(String(key), host.localName));\n};\n\nexport function createContext<T>(description?: string): InjectionKey<T> {\n return Symbol(description) as InjectionKey<T>;\n}\n"],"mappings":"mFAYA,IAAM,EAAkB,IAAI,QAOtB,EAAsB,GAAsC,CAChE,IAAM,EAAuB,CAAC,EAC1B,EAAoB,EAExB,KAAO,GAAM,CACP,aAAgB,aAAa,EAAM,KAAK,CAAI,EAEhD,IAAM,EAAO,EAAK,YAAY,EAE9B,EAAQ,EAAqB,gBAAkB,aAAgB,WAAa,EAAK,KAAO,KAC1F,CAEA,OAAO,CACT,EAMM,GAAuB,EAAiB,EAAsB,IAAmB,CACrF,IAAM,EAAM,EAAgB,IAAI,CAAE,GAAK,IAAI,IAMvC,EAAI,IAAI,CAAG,GACb,EAAA,KACE,uCAAuC,EAAG,UAAU,0DACtD,EAGF,EAAI,IAAI,EAAK,CAAK,EAClB,EAAgB,IAAI,EAAI,CAAG,CAC7B,EAUa,GAAc,EAAsB,IAAmB,EAAiB,EAAA,QAAQ,EAAG,EAAK,CAAK,EAEpG,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,EAIA,SAAgB,EAAU,EAAsB,GAAG,EAA2B,CAC5E,IAAM,EAAM,EAAA,oBAAoB,QAAQ,EAEpC,EAAQ,EAAc,IAAI,CAAG,EAE5B,IACH,EAAQ,IAAI,IACZ,EAAc,IAAI,EAAK,CAAK,GAG9B,IAAM,EAAW,EAEjB,GAAI,EAAM,IAAI,CAAQ,EAAG,CACvB,IAAM,EAAS,EAAM,IAAI,CAAQ,EAIjC,OAFI,IAAW,EAA2B,EAAK,OAAS,EAAI,EAAK,GAAK,IAAA,GAE/D,CACT,CAEA,IAAM,EAAQ,EAAY,EAAI,QAAS,CAAG,EAM1C,OAJA,EAAM,IAAI,EAAU,CAAK,EAErB,IAAU,EAA2B,EAAK,OAAS,EAAI,EAAK,GAAK,IAAA,GAE9D,CACT,CAEA,IAAa,EAAmB,GAA4B,CAC1D,IAAM,EAAW,EAAU,EAAK,CAAkC,EAElE,GAAI,IAAc,EAAgC,OAAO,EAEzD,IAAM,EAAO,EAAA,QAAQ,EAErB,MAAM,IAAI,EAAA,YAAY,EAAA,WAAW,mBAAmB,OAAO,CAAG,EAAG,EAAK,SAAS,CAAC,CAClF,EAEA,SAAgB,EAAiB,EAAuC,CACtE,OAAO,OAAO,CAAW,CAC3B"}
package/dist/context.d.ts CHANGED
@@ -1,13 +1,22 @@
1
1
  /**
2
- * Component context injection API — `inject` / `injectStrict` / `createContext`.
2
+ * Component context injection API — `inject` / `injectStrict` / `provide` / `createContext`.
3
3
  *
4
4
  * Context values are stored on the providing element via a WeakMap registry and
5
5
  * resolved by walking up the DOM tree (including through shadow boundaries).
6
- * Providing is done via `ctx.provide(key, value)` inside `setup()`.
6
+ * Providing is done via `provide(key, value)` inside `setup()`.
7
7
  */
8
8
  export type InjectionKey<T> = symbol & {
9
9
  readonly __ore_injection_key?: T;
10
10
  };
11
+ /**
12
+ * Register a context value on the current component's host element, making it
13
+ * available to descendant components via `inject(key)`.
14
+ *
15
+ * Provide a `Readable` (signal/computed) rather than a raw value if descendants
16
+ * need to observe later changes — `inject()` resolves and caches the value once
17
+ * per consumer, so re-calling `provide()` with a new raw value later is not seen.
18
+ */
19
+ export declare const provide: <T>(key: InjectionKey<T>, value: T) => void;
11
20
  export declare function inject<T>(key: InjectionKey<T>): T | undefined;
12
21
  export declare function inject<T>(key: InjectionKey<T>, fallback: T): T;
13
22
  export declare const injectStrict: <T>(key: InjectionKey<T>) => T;
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,MAAM,GAAG;IACrC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;CAClC,CAAC;AA6CF,wBAAgB,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;AAC/D,wBAAgB,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;AAgChE,eAAO,MAAM,YAAY,GAAI,CAAC,EAAE,KAAK,YAAY,CAAC,CAAC,CAAC,KAAG,CAQtD,CAAC;AAEF,wBAAgB,aAAa,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,CAEtE"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,MAAM,GAAG;IACrC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;CAClC,CAAC;AAuCF;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,EAAE,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,KAAG,IAA+C,CAAC;AAmB5G,wBAAgB,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;AAC/D,wBAAgB,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;AA8BhE,eAAO,MAAM,YAAY,GAAI,CAAC,EAAE,KAAK,YAAY,CAAC,CAAC,CAAC,KAAG,CAQtD,CAAC;AAEF,wBAAgB,aAAa,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,CAEtE"}
package/dist/context.js CHANGED
@@ -1,2 +1,2 @@
1
- import{ORE_ERRORS as e,OreApiError as t}from"./errors.js";import{getCurrentElement as n,getSetupContext as r}from"./runtime.js";var i=new WeakMap,a=e=>{let t=[],n=e;for(;n;){n instanceof HTMLElement&&t.push(n);let e=n.getRootNode();n=n.parentElement??(e instanceof ShadowRoot?e.host:null)}return t},o=(e,t,n)=>{i.has(e)||i.set(e,new Map),i.get(e).set(t,n)},s=Symbol(`inject.not_found`),c=new WeakMap,l=(e,t)=>{let n=a(e);for(let e of n){let n=i.get(e);if(n?.has(t))return n.get(t)}return s};function u(n,...i){let a=r();if(!a)throw new t(e.lifecycleOutsideSetup);let o=c.get(a);o||(o=new Map,c.set(a,o));let u=n;if(o.has(u)){let e=o.get(u);return e===s?i.length>0?i[0]:void 0:e}let d=l(a.element,n);return o.set(u,d),d===s?i.length>0?i[0]:void 0:d}var d=r=>{let i=u(r,s);if(i!==s)return i;let a=n();throw new t(e.injectStrictFailed(String(r),a.localName))};function f(e){return Symbol(e)}export{f as createContext,u as inject,d as injectStrict,o as provideOnElement};
1
+ import{warn as e}from"./_dev.js";import{ORE_ERRORS as t,OreApiError as n}from"./errors.js";import{getHost as r,requireSetupContext as i}from"./runtime.js";var a=new WeakMap,o=e=>{let t=[],n=e;for(;n;){n instanceof HTMLElement&&t.push(n);let e=n.getRootNode();n=n.parentElement??(e instanceof ShadowRoot?e.host:null)}return t},s=(t,n,r)=>{let i=a.get(t)??new Map;i.has(n)&&e(`provide(): key already provided on <${t.localName}> — overwriting. Provide a Readable to update it instead.`),i.set(n,r),a.set(t,i)},c=(e,t)=>s(r(),e,t),l=Symbol(`inject.not_found`),u=new WeakMap,d=(e,t)=>{let n=o(e);for(let e of n){let n=a.get(e);if(n?.has(t))return n.get(t)}return l};function f(e,...t){let n=i(`inject`),r=u.get(n);r||(r=new Map,u.set(n,r));let a=e;if(r.has(a)){let e=r.get(a);return e===l?t.length>0?t[0]:void 0:e}let o=d(n.element,e);return r.set(a,o),o===l?t.length>0?t[0]:void 0:o}var p=e=>{let i=f(e,l);if(i!==l)return i;let a=r();throw new n(t.injectStrictFailed(String(e),a.localName))};function m(e){return Symbol(e)}export{m as createContext,f as inject,p as injectStrict,c as provide};
2
2
  //# sourceMappingURL=context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","names":[],"sources":["../src/context.ts"],"sourcesContent":["/**\n * Component context injection API — `inject` / `injectStrict` / `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 `ctx.provide(key, value)` inside `setup()`.\n */\n\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { getSetupContext, getCurrentElement } 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/** @internal Build a linear ancestor chain (including shadow host boundaries). */\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 const root = node.getRootNode() as Node;\n\n node = (node as HTMLElement).parentElement ?? (root instanceof ShadowRoot ? root.host : null);\n }\n\n return chain;\n};\n\n/**\n * Register a context value on a specific element.\n * @internal Used by ctx.provide() — do not call directly.\n */\nexport const provideOnElement = <T>(el: HTMLElement, key: InjectionKey<T>, value: T): void => {\n if (!contextRegistry.has(el)) contextRegistry.set(el, new Map());\n\n contextRegistry.get(el)!.set(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\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 ctx = getSetupContext();\n\n if (!ctx) throw new OreApiError(ORE_ERRORS.lifecycleOutsideSetup);\n\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)) {\n const cached = cache.get(cacheKey);\n\n if (cached === NOT_FOUND_SENTINEL) return rest.length > 0 ? rest[0] : undefined;\n\n return cached as T;\n }\n\n const found = walkAndFind(ctx.element, key);\n\n cache.set(cacheKey, found);\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 resolved = inject<T>(key, NOT_FOUND_SENTINEL as unknown as T);\n\n if (resolved !== (NOT_FOUND_SENTINEL as unknown)) return resolved;\n\n const host = getCurrentElement();\n\n throw new OreApiError(ORE_ERRORS.injectStrictFailed(String(key), host.localName));\n};\n\nexport function createContext<T>(description?: string): InjectionKey<T> {\n return Symbol(description) as InjectionKey<T>;\n}\n"],"mappings":"gIAWA,IAAM,EAAkB,IAAI,QAOtB,EAAsB,GAAsC,CAChE,IAAM,EAAuB,CAAC,EAC1B,EAAoB,EAExB,KAAO,GAAM,CACP,aAAgB,aAAa,EAAM,KAAK,CAAI,EAEhD,IAAM,EAAO,EAAK,YAAY,EAE9B,EAAQ,EAAqB,gBAAkB,aAAgB,WAAa,EAAK,KAAO,KAC1F,CAEA,OAAO,CACT,EAMa,GAAuB,EAAiB,EAAsB,IAAmB,CACvF,EAAgB,IAAI,CAAE,GAAG,EAAgB,IAAI,EAAI,IAAI,GAAK,EAE/D,EAAgB,IAAI,CAAE,CAAC,CAAE,IAAI,EAAK,CAAK,CACzC,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,EAIA,SAAgB,EAAU,EAAsB,GAAG,EAA2B,CAC5E,IAAM,EAAM,EAAgB,EAE5B,GAAI,CAAC,EAAK,MAAM,IAAI,EAAY,EAAW,qBAAqB,EAEhE,IAAI,EAAQ,EAAc,IAAI,CAAG,EAE5B,IACH,EAAQ,IAAI,IACZ,EAAc,IAAI,EAAK,CAAK,GAG9B,IAAM,EAAW,EAEjB,GAAI,EAAM,IAAI,CAAQ,EAAG,CACvB,IAAM,EAAS,EAAM,IAAI,CAAQ,EAIjC,OAFI,IAAW,EAA2B,EAAK,OAAS,EAAI,EAAK,GAAK,IAAA,GAE/D,CACT,CAEA,IAAM,EAAQ,EAAY,EAAI,QAAS,CAAG,EAM1C,OAJA,EAAM,IAAI,EAAU,CAAK,EAErB,IAAU,EAA2B,EAAK,OAAS,EAAI,EAAK,GAAK,IAAA,GAE9D,CACT,CAEA,IAAa,EAAmB,GAA4B,CAC1D,IAAM,EAAW,EAAU,EAAK,CAAkC,EAElE,GAAI,IAAc,EAAgC,OAAO,EAEzD,IAAM,EAAO,EAAkB,EAE/B,MAAM,IAAI,EAAY,EAAW,mBAAmB,OAAO,CAAG,EAAG,EAAK,SAAS,CAAC,CAClF,EAEA,SAAgB,EAAiB,EAAuC,CACtE,OAAO,OAAO,CAAW,CAC3B"}
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\nimport { warn } from './_dev';\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { getHost, 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/** @internal Build a linear ancestor chain (including shadow host boundaries). */\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 const root = node.getRootNode() as Node;\n\n node = (node as HTMLElement).parentElement ?? (root instanceof ShadowRoot ? root.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 => provideOnElement(getHost(), key, value);\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\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 ctx = requireSetupContext('inject');\n\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)) {\n const cached = cache.get(cacheKey);\n\n if (cached === NOT_FOUND_SENTINEL) return rest.length > 0 ? rest[0] : undefined;\n\n return cached as T;\n }\n\n const found = walkAndFind(ctx.element, key);\n\n cache.set(cacheKey, found);\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 resolved = inject<T>(key, NOT_FOUND_SENTINEL as unknown as T);\n\n if (resolved !== (NOT_FOUND_SENTINEL as unknown)) return resolved;\n\n const host = getHost();\n\n throw new OreApiError(ORE_ERRORS.injectStrictFailed(String(key), host.localName));\n};\n\nexport function createContext<T>(description?: string): InjectionKey<T> {\n return Symbol(description) as InjectionKey<T>;\n}\n"],"mappings":"2JAYA,IAAM,EAAkB,IAAI,QAOtB,EAAsB,GAAsC,CAChE,IAAM,EAAuB,CAAC,EAC1B,EAAoB,EAExB,KAAO,GAAM,CACP,aAAgB,aAAa,EAAM,KAAK,CAAI,EAEhD,IAAM,EAAO,EAAK,YAAY,EAE9B,EAAQ,EAAqB,gBAAkB,aAAgB,WAAa,EAAK,KAAO,KAC1F,CAEA,OAAO,CACT,EAMM,GAAuB,EAAiB,EAAsB,IAAmB,CACrF,IAAM,EAAM,EAAgB,IAAI,CAAE,GAAK,IAAI,IAMvC,EAAI,IAAI,CAAG,GACb,EACE,uCAAuC,EAAG,UAAU,0DACtD,EAGF,EAAI,IAAI,EAAK,CAAK,EAClB,EAAgB,IAAI,EAAI,CAAG,CAC7B,EAUa,GAAc,EAAsB,IAAmB,EAAiB,EAAQ,EAAG,EAAK,CAAK,EAEpG,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,EAIA,SAAgB,EAAU,EAAsB,GAAG,EAA2B,CAC5E,IAAM,EAAM,EAAoB,QAAQ,EAEpC,EAAQ,EAAc,IAAI,CAAG,EAE5B,IACH,EAAQ,IAAI,IACZ,EAAc,IAAI,EAAK,CAAK,GAG9B,IAAM,EAAW,EAEjB,GAAI,EAAM,IAAI,CAAQ,EAAG,CACvB,IAAM,EAAS,EAAM,IAAI,CAAQ,EAIjC,OAFI,IAAW,EAA2B,EAAK,OAAS,EAAI,EAAK,GAAK,IAAA,GAE/D,CACT,CAEA,IAAM,EAAQ,EAAY,EAAI,QAAS,CAAG,EAM1C,OAJA,EAAM,IAAI,EAAU,CAAK,EAErB,IAAU,EAA2B,EAAK,OAAS,EAAI,EAAK,GAAK,IAAA,GAE9D,CACT,CAEA,IAAa,EAAmB,GAA4B,CAC1D,IAAM,EAAW,EAAU,EAAK,CAAkC,EAElE,GAAI,IAAc,EAAgC,OAAO,EAEzD,IAAM,EAAO,EAAQ,EAErB,MAAM,IAAI,EAAY,EAAW,mBAAmB,OAAO,CAAG,EAAG,EAAK,SAAS,CAAC,CAClF,EAEA,SAAgB,EAAiB,EAAuC,CACtE,OAAO,OAAO,CAAW,CAC3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"define.cjs","names":[],"sources":["../src/define.ts"],"sourcesContent":["import type { ComponentDefinition } from './component-types';\n\nimport { BaseElement } from './base-element';\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport {\n type InferProps,\n normalizePropDefinition,\n prop,\n type PropDef,\n type PropInputDefs,\n type PropsDef,\n validatePropDefs,\n} from './props';\nimport { toKebab } from './utils/dom';\n\nexport { prop };\nexport type { InferProps, PropDef, PropInputDefs, PropsDef };\nexport type { HostBindFn } from './host-bind';\n\n/**\n * Define and register a web component.\n *\n * The `setup` function runs once per instance on first connect and returns an\n * `HTMLResult`. All reactive behaviour is expressed through reactive directives\n * inside the template — not by re-evaluating setup itself.\n *\n * Pass a `SlotNames` type parameter to get typed `ctx.slots` access:\n * ```ts\n * define<Record<never, never>, Record<never, never>, 'header' | 'footer'>('my-card', {\n * setup(_props, { slots }) {\n * const hasHeader = slots.has('header'); // typed ✓\n * },\n * });\n * ```\n *\n * @example\n * ```ts\n * define('my-counter', {\n * props: { count: prop.number(0) },\n * setup(props) {\n * return html`<button @click=${() => props.count.value++}>${props.count}</button>`;\n * },\n * });\n * ```\n */\nexport function define<\n Props extends Record<string, unknown> = Record<never, never>,\n Emits extends Record<string, unknown> = Record<string, never>,\n const SlotNames extends string = string,\n>(tag: string, definition: ComponentDefinition<Props, Emits, SlotNames>): 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 { 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 // Named class for DevTools and error messages\n const ComponentClass = class extends BaseElement {\n static override _definition = definition as ComponentDefinition<any, any, any>;\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 Object.defineProperty(ComponentClass, 'name', { value: tag });\n customElements.define(tag, ComponentClass);\n}\n"],"mappings":"sHA6CA,SAAgB,EAId,EAAa,EAAgE,CAC7E,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,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,EAGrF,EAAiB,cAAc,EAAA,WAAY,CAC/C,OAAgB,YAAc,EAC9B,OAAgB,oBAAsB,EACtC,OAAgB,eAAiB,EAAW,gBAAkB,GAC9D,OAAgB,mBAAqB,CACvC,EAEA,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 type { ComponentDefinition } from './component-types';\n\nimport { BaseElement } from './base-element';\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport {\n type InferProps,\n normalizePropDefinition,\n prop,\n type PropDef,\n type PropInputDefs,\n type PropsDef,\n validatePropDefs,\n} from './props';\nimport { toKebab } from './utils/dom';\n\nexport { prop };\nexport type { InferProps, PropDef, PropInputDefs, PropsDef };\nexport type { HostBindFn } from './host-bind';\n\n/**\n * Define and register a web component.\n *\n * The `setup` function runs once per instance on first connect and returns an\n * `HTMLResult`. All reactive behaviour is expressed through reactive directives\n * inside the 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 { 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 // Named class for DevTools and error messages\n const ComponentClass = class extends BaseElement {\n static override _definition = definition as ComponentDefinition<any>;\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 Object.defineProperty(ComponentClass, 'name', { value: tag });\n customElements.define(tag, ComponentClass);\n}\n"],"mappings":"sHA8CA,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,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,EAGrF,EAAiB,cAAc,EAAA,WAAY,CAC/C,OAAgB,YAAc,EAC9B,OAAgB,oBAAsB,EACtC,OAAgB,eAAiB,EAAW,gBAAkB,GAC9D,OAAgB,mBAAqB,CACvC,EAEA,OAAO,eAAe,EAAgB,OAAQ,CAAE,MAAO,CAAI,CAAC,EAC5D,eAAe,OAAO,EAAK,CAAc,CAC3C"}
package/dist/define.d.ts CHANGED
@@ -10,24 +10,25 @@ export type { HostBindFn } from './host-bind';
10
10
  * `HTMLResult`. All reactive behaviour is expressed through reactive directives
11
11
  * inside the template — not by re-evaluating setup itself.
12
12
  *
13
- * Pass a `SlotNames` type parameter to get typed `ctx.slots` access:
14
- * ```ts
15
- * define<Record<never, never>, Record<never, never>, 'header' | 'footer'>('my-card', {
16
- * setup(_props, { slots }) {
17
- * const hasHeader = slots.has('header'); // typed ✓
18
- * },
19
- * });
20
- * ```
13
+ * Everything besides `props` lifecycle hooks, host bindings, context, slots,
14
+ * emit — is a free function imported from `@vielzeug/ore` and called directly
15
+ * from inside `setup()` (or from a composable it calls):
21
16
  *
22
- * @example
23
17
  * ```ts
24
- * define('my-counter', {
18
+ * import { define, html, prop, onMounted, useEmit, useSlots } from '@vielzeug/ore';
19
+ *
20
+ * define<{ count?: number }>('my-counter', {
25
21
  * props: { count: prop.number(0) },
26
22
  * setup(props) {
27
- * return html`<button @click=${() => props.count.value++}>${props.count}</button>`;
23
+ * const emit = useEmit<{ increment: number }>();
24
+ * const slots = useSlots<'header' | 'footer'>();
25
+ *
26
+ * onMounted(() => console.log('mounted'));
27
+ *
28
+ * return html`<button @click=${() => emit('increment', props.count.value + 1)}>${props.count}</button>`;
28
29
  * },
29
30
  * });
30
31
  * ```
31
32
  */
32
- export declare function define<Props extends Record<string, unknown> = Record<never, never>, Emits extends Record<string, unknown> = Record<string, never>, const SlotNames extends string = string>(tag: string, definition: ComponentDefinition<Props, Emits, SlotNames>): void;
33
+ export declare function define<Props extends Record<string, unknown> = Record<never, never>>(tag: string, definition: ComponentDefinition<Props>): void;
33
34
  //# sourceMappingURL=define.d.ts.map
@@ -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,EACL,KAAK,UAAU,EAEf,IAAI,EACJ,KAAK,OAAO,EACZ,KAAK,aAAa,EAClB,KAAK,QAAQ,EAEd,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,IAAI,EAAE,CAAC;AAChB,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,MAAM,CACpB,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAC5D,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAC7D,KAAK,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM,EACvC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,mBAAmB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,GAAG,IAAI,CAmC7E"}
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,EACL,KAAK,UAAU,EAEf,IAAI,EACJ,KAAK,OAAO,EACZ,KAAK,aAAa,EAClB,KAAK,QAAQ,EAEd,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,IAAI,EAAE,CAAC;AAChB,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;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,CAmCN"}
@@ -1 +1 @@
1
- {"version":3,"file":"define.js","names":[],"sources":["../src/define.ts"],"sourcesContent":["import type { ComponentDefinition } from './component-types';\n\nimport { BaseElement } from './base-element';\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport {\n type InferProps,\n normalizePropDefinition,\n prop,\n type PropDef,\n type PropInputDefs,\n type PropsDef,\n validatePropDefs,\n} from './props';\nimport { toKebab } from './utils/dom';\n\nexport { prop };\nexport type { InferProps, PropDef, PropInputDefs, PropsDef };\nexport type { HostBindFn } from './host-bind';\n\n/**\n * Define and register a web component.\n *\n * The `setup` function runs once per instance on first connect and returns an\n * `HTMLResult`. All reactive behaviour is expressed through reactive directives\n * inside the template — not by re-evaluating setup itself.\n *\n * Pass a `SlotNames` type parameter to get typed `ctx.slots` access:\n * ```ts\n * define<Record<never, never>, Record<never, never>, 'header' | 'footer'>('my-card', {\n * setup(_props, { slots }) {\n * const hasHeader = slots.has('header'); // typed ✓\n * },\n * });\n * ```\n *\n * @example\n * ```ts\n * define('my-counter', {\n * props: { count: prop.number(0) },\n * setup(props) {\n * return html`<button @click=${() => props.count.value++}>${props.count}</button>`;\n * },\n * });\n * ```\n */\nexport function define<\n Props extends Record<string, unknown> = Record<never, never>,\n Emits extends Record<string, unknown> = Record<string, never>,\n const SlotNames extends string = string,\n>(tag: string, definition: ComponentDefinition<Props, Emits, SlotNames>): 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 { 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 // Named class for DevTools and error messages\n const ComponentClass = class extends BaseElement {\n static override _definition = definition as ComponentDefinition<any, any, any>;\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 Object.defineProperty(ComponentClass, 'name', { value: tag });\n customElements.define(tag, ComponentClass);\n}\n"],"mappings":"wOA6CA,SAAgB,EAId,EAAa,EAAgE,CAC7E,GAAI,CAAC,EAAK,MAAM,IAAI,EAAY,EAAW,iBAAiB,EAE5D,GAAI,eAAe,IAAI,CAAG,EAAG,MAAM,IAAI,EAAY,EAAW,gBAAgB,CAAG,CAAC,EAElF,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,EAGrF,EAAiB,cAAc,CAAY,CAC/C,OAAgB,YAAc,EAC9B,OAAgB,oBAAsB,EACtC,OAAgB,eAAiB,EAAW,gBAAkB,GAC9D,OAAgB,mBAAqB,CACvC,EAEA,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 type { ComponentDefinition } from './component-types';\n\nimport { BaseElement } from './base-element';\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport {\n type InferProps,\n normalizePropDefinition,\n prop,\n type PropDef,\n type PropInputDefs,\n type PropsDef,\n validatePropDefs,\n} from './props';\nimport { toKebab } from './utils/dom';\n\nexport { prop };\nexport type { InferProps, PropDef, PropInputDefs, PropsDef };\nexport type { HostBindFn } from './host-bind';\n\n/**\n * Define and register a web component.\n *\n * The `setup` function runs once per instance on first connect and returns an\n * `HTMLResult`. All reactive behaviour is expressed through reactive directives\n * inside the 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 { 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 // Named class for DevTools and error messages\n const ComponentClass = class extends BaseElement {\n static override _definition = definition as ComponentDefinition<any>;\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 Object.defineProperty(ComponentClass, 'name', { value: tag });\n customElements.define(tag, ComponentClass);\n}\n"],"mappings":"wOA8CA,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,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,EAGrF,EAAiB,cAAc,CAAY,CAC/C,OAAgB,YAAc,EAC9B,OAAgB,oBAAsB,EACtC,OAAgB,eAAiB,EAAW,gBAAkB,GAC9D,OAAgB,mBAAqB,CACvC,EAEA,OAAO,eAAe,EAAgB,OAAQ,CAAE,MAAO,CAAI,CAAC,EAC5D,eAAe,OAAO,EAAK,CAAc,CAC3C"}
@@ -1,2 +1,2 @@
1
- const e=require("../_dev.cjs"),t=require("../errors.cjs"),n=require("../types/bindings.cjs"),r=require("../utils/dom.cjs");let i=require("@vielzeug/ripple");var a=(e,t,n,r,a)=>{let o=(0,i.signal)(e),s=(0,i.signal)(t),c=n(o,s),l=[];return{cleanups:l,data:o,index:s,key:``,nodes:c.mount(r,a,e=>l.push(e))}},o=e=>{r.runAll(e.cleanups),r.removeNodes(e.nodes)},s=(e,n,r,s,c,l)=>{let u=[],d=new Set;for(let e=0;e<n.length;e++){let i=String(r(n[e],e));if(d.has(i))throw new t.OreApiError(t.ORE_ERRORS.eachDuplicateKey(i,e));d.add(i),u.push(i)}for(let[t,n]of e)d.has(t)||(o(n),e.delete(t));let f=[];for(let t=0;t<n.length;t++){let r=u[t],o=e.get(r);if(o)(0,i.batch)(()=>{o.data.value=n[t],o.index.value=t}),f.push(o);else{let o=(0,i.untrack)(()=>a(n[t],t,s,c,l));o.key=r,e.set(r,o),f.push(o)}}let p=l;for(let e=f.length-1;e>=0;e--){let t=f[e],n=t.nodes[0];if(n&&n!==p.previousSibling)for(let e of t.nodes)c.insertBefore(e,p);p=n??p}return f};function c(t,a,c,l){let u=Array.isArray(t)?(0,i.signal)(t):typeof t==`function`?(0,i.computed)(t):t;return e.devOnly(()=>{try{let t=99999;a({},t)===t&&e.warn(`each(): key function returns only the index. Index keys cause full list re-renders on insert/remove — pass a stable item identifier (e.g. item.id) instead.`)}catch{}}),n.createDirectiveResult((t,n)=>{let d=t.parentNode,f=document.createComment(`each/end`);d.insertBefore(f,t.nextSibling);let p=new Map,m=[],h=null,g=[],_=()=>{l&&(h=l().mount(d,f,e=>g.push(e)))},v=()=>{h&&(r.runAll(g),r.removeNodes(h),h=null,g=[])},y=(0,i.effect)(()=>{let t=u.value??[];if(t.length===0){for(let e of(0,i.untrack)(()=>m))o(e);p=new Map,m=[],h||(0,i.untrack)(_);return}v();try{m=(0,i.untrack)(()=>s(p,t,a,c,d,f))}catch(t){e.warn(`each() reconciliation error: ${t instanceof Error?t.message:String(t)}`);for(let e of p.values())o(e);p=new Map,m=[]}});n(()=>y.dispose()),n(()=>{v();for(let e of m)o(e);f.remove()})})}exports.each=c;
1
+ const e=require("../_dev.cjs"),t=require("../errors.cjs"),n=require("../types/bindings.cjs"),r=require("../utils/dom.cjs");let i=require("@vielzeug/ripple");var a=(e,t,n,r,a)=>{let o=(0,i.signal)(e),s=(0,i.signal)(t),c=n(o,s),l=[];return{cleanups:l,data:o,index:s,key:``,nodes:c.mount(r,a,e=>l.push(e))}},o=e=>{r.runAll(e.cleanups),r.removeNodes(e.nodes)},s=(e,n,r,s,c,l)=>{let u=[],d=new Set;for(let e=0;e<n.length;e++){let i=String(r(n[e],e));if(d.has(i))throw new t.OreApiError(t.ORE_ERRORS.eachDuplicateKey(i,e));d.add(i),u.push(i)}for(let[t,n]of e)d.has(t)||(o(n),e.delete(t));let f=[];for(let t=0;t<n.length;t++){let r=u[t],o=e.get(r);if(o)(0,i.batch)(()=>{o.data.value=n[t],o.index.value=t}),f.push(o);else{let o=(0,i.untrack)(()=>a(n[t],t,s,c,l));o.key=r,e.set(r,o),f.push(o)}}let p=l;for(let e=f.length-1;e>=0;e--){let t=f[e],n=t.nodes[0];if(n&&n!==p.previousSibling)for(let e of t.nodes)c.insertBefore(e,p);p=n??p}return f};function c(a,c,l,u){let d=Array.isArray(a)?(0,i.signal)(a):typeof a==`function`?(0,i.computed)(a):a;return n.createDirectiveResult((n,a)=>{let f=n.parentNode;t.invariant(f,`each() anchor comment has no parent node`);let p=document.createComment(`each/end`);f.insertBefore(p,n.nextSibling);let m=new Map,h=[],g=null,_=[],v=()=>{u&&(g=u().mount(f,p,e=>_.push(e)))},y=()=>{g&&(r.runAll(_),r.removeNodes(g),g=null,_=[])},b=(0,i.effect)(()=>{let t=d.value??[];if(t.length===0){for(let e of(0,i.untrack)(()=>h))o(e);m=new Map,h=[],g||(0,i.untrack)(v);return}y();try{h=(0,i.untrack)(()=>s(m,t,c,l,f,p))}catch(t){e.warn(`each() reconciliation error: ${t instanceof Error?t.message:String(t)}`);for(let e of m.values())o(e);m=new Map,h=[]}});a(()=>b.dispose()),a(()=>{y();for(let e of h)o(e);p.remove()})})}exports.each=c;
2
2
  //# sourceMappingURL=each.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"each.cjs","names":[],"sources":["../../src/directives/each.ts"],"sourcesContent":["import { batch, computed, effect as rawEffect, type Readable, signal, type Signal, untrack } from '@vielzeug/ripple';\n\nimport { devOnly, warn } from '../_dev';\nimport { OreApiError, ORE_ERRORS } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult } from '../types/bindings';\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};\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\n const result = render(dataSignal, indexSignal);\n const cleanups: (() => void)[] = [];\n const nodes = result.mount(parent, insertBefore, (fn) => cleanups.push(fn));\n\n return { cleanups, data: dataSignal, index: indexSignal, key: '', nodes };\n};\n\nconst removeItem = <T>(entry: ItemEntry<T>): void => {\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 */\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 devOnly(() => {\n try {\n const SENTINEL_IDX = 99999;\n const testKey = keyFn({} as T, SENTINEL_IDX);\n\n if (testKey === SENTINEL_IDX) {\n warn(\n 'each(): key function returns only the index. Index keys cause full list re-renders on insert/remove — pass a stable item identifier (e.g. item.id) instead.',\n );\n }\n } catch {\n /* ignore — keyFn may throw on a non-item sentinel; that is fine */\n }\n });\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode!;\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 warn(`each() reconciliation error: ${err instanceof Error ? err.message : String(err)}`);\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.cjs","names":[],"sources":["../../src/directives/each.ts"],"sourcesContent":["import { batch, computed, effect as rawEffect, type Readable, signal, type Signal, untrack } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { invariant, OreApiError, ORE_ERRORS } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult } from '../types/bindings';\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};\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\n const result = render(dataSignal, indexSignal);\n const cleanups: (() => void)[] = [];\n const nodes = result.mount(parent, insertBefore, (fn) => cleanups.push(fn));\n\n return { cleanups, data: dataSignal, index: indexSignal, key: '', nodes };\n};\n\nconst removeItem = <T>(entry: ItemEntry<T>): void => {\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. Duplicate keys within one render throw immediately (see `eachDuplicateKey`).\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 warn(`each() reconciliation error: ${err instanceof Error ? err.message : String(err)}`);\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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"}
@@ -19,6 +19,12 @@ type MaybeReactiveArray<T> = Readable<T[]> | (() => T[]) | T[];
19
19
  * tracked. Pass a `Signal<T[]>` or `() => T[]` for reactive lists.
20
20
  *
21
21
  * **Optional fallback:** the fourth argument renders when the list is empty.
22
+ *
23
+ * **Key choice:** pass a stable item identifier (e.g. `item.id`), never the
24
+ * array index — an index-based key reassigns to a different item whenever the
25
+ * list is reordered or an item is inserted/removed before it, causing full
26
+ * item teardown/recreation instead of the in-place update `each()` is built
27
+ * for. Duplicate keys within one render throw immediately (see `eachDuplicateKey`).
22
28
  */
23
29
  export declare function each<T>(list: MaybeReactiveArray<T>, keyFn: (item: T, index: number) => string | number, render: (item: Readable<T>, index: Readable<number>) => HTMLResult, fallback?: () => HTMLResult): DirectiveResult;
24
30
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"each.d.ts","sourceRoot":"","sources":["../../src/directives/each.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,KAAK,QAAQ,EAAgC,MAAM,kBAAkB,CAAC;AAIrH,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAKjG,KAAK,kBAAkB,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;AAkH/D;;;;;;;;;;;;;;;;;;GAkBG;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,EAAwC,KAAK,QAAQ,EAAgC,MAAM,kBAAkB,CAAC;AAIrH,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAKjG,KAAK,kBAAkB,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;AAkH/D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;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,CAuEjB"}
@@ -1,2 +1,2 @@
1
- import{devOnly as e,warn as t}from"../_dev.js";import{ORE_ERRORS as n,OreApiError as r}from"../errors.js";import{createDirectiveResult as i}from"../types/bindings.js";import{removeNodes as a,runAll as o}from"../utils/dom.js";import{batch as s,computed as c,effect as l,signal as u,untrack as d}from"@vielzeug/ripple";var f=(e,t,n,r,i)=>{let a=u(e),o=u(t),s=n(a,o),c=[];return{cleanups:c,data:a,index:o,key:``,nodes:s.mount(r,i,e=>c.push(e))}},p=e=>{o(e.cleanups),a(e.nodes)},m=(e,t,i,a,o,c)=>{let l=[],u=new Set;for(let e=0;e<t.length;e++){let a=String(i(t[e],e));if(u.has(a))throw new r(n.eachDuplicateKey(a,e));u.add(a),l.push(a)}for(let[t,n]of e)u.has(t)||(p(n),e.delete(t));let m=[];for(let n=0;n<t.length;n++){let r=l[n],i=e.get(r);if(i)s(()=>{i.data.value=t[n],i.index.value=n}),m.push(i);else{let i=d(()=>f(t[n],n,a,o,c));i.key=r,e.set(r,i),m.push(i)}}let h=c;for(let e=m.length-1;e>=0;e--){let t=m[e],n=t.nodes[0];if(n&&n!==h.previousSibling)for(let e of t.nodes)o.insertBefore(e,h);h=n??h}return m};function h(n,r,s,f){let h=Array.isArray(n)?u(n):typeof n==`function`?c(n):n;return e(()=>{try{let e=99999;r({},e)===e&&t(`each(): key function returns only the index. Index keys cause full list re-renders on insert/remove — pass a stable item identifier (e.g. item.id) instead.`)}catch{}}),i((e,n)=>{let i=e.parentNode,c=document.createComment(`each/end`);i.insertBefore(c,e.nextSibling);let u=new Map,g=[],_=null,v=[],y=()=>{f&&(_=f().mount(i,c,e=>v.push(e)))},b=()=>{_&&(o(v),a(_),_=null,v=[])},x=l(()=>{let e=h.value??[];if(e.length===0){for(let e of d(()=>g))p(e);u=new Map,g=[],_||d(y);return}b();try{g=d(()=>m(u,e,r,s,i,c))}catch(e){t(`each() reconciliation error: ${e instanceof Error?e.message:String(e)}`);for(let e of u.values())p(e);u=new Map,g=[]}});n(()=>x.dispose()),n(()=>{b();for(let e of g)p(e);c.remove()})})}export{h as each};
1
+ import{warn as e}from"../_dev.js";import{ORE_ERRORS as t,OreApiError as n,invariant as r}from"../errors.js";import{createDirectiveResult as i}from"../types/bindings.js";import{removeNodes as a,runAll as o}from"../utils/dom.js";import{batch as s,computed as c,effect as l,signal as u,untrack as d}from"@vielzeug/ripple";var f=(e,t,n,r,i)=>{let a=u(e),o=u(t),s=n(a,o),c=[];return{cleanups:c,data:a,index:o,key:``,nodes:s.mount(r,i,e=>c.push(e))}},p=e=>{o(e.cleanups),a(e.nodes)},m=(e,r,i,a,o,c)=>{let l=[],u=new Set;for(let e=0;e<r.length;e++){let a=String(i(r[e],e));if(u.has(a))throw new n(t.eachDuplicateKey(a,e));u.add(a),l.push(a)}for(let[t,n]of e)u.has(t)||(p(n),e.delete(t));let m=[];for(let t=0;t<r.length;t++){let n=l[t],i=e.get(n);if(i)s(()=>{i.data.value=r[t],i.index.value=t}),m.push(i);else{let i=d(()=>f(r[t],t,a,o,c));i.key=n,e.set(n,i),m.push(i)}}let h=c;for(let e=m.length-1;e>=0;e--){let t=m[e],n=t.nodes[0];if(n&&n!==h.previousSibling)for(let e of t.nodes)o.insertBefore(e,h);h=n??h}return m};function h(t,n,s,f){let h=Array.isArray(t)?u(t):typeof t==`function`?c(t):t;return i((t,i)=>{let c=t.parentNode;r(c,`each() anchor comment has no parent node`);let u=document.createComment(`each/end`);c.insertBefore(u,t.nextSibling);let g=new Map,_=[],v=null,y=[],b=()=>{f&&(v=f().mount(c,u,e=>y.push(e)))},x=()=>{v&&(o(y),a(v),v=null,y=[])},S=l(()=>{let t=h.value??[];if(t.length===0){for(let e of d(()=>_))p(e);g=new Map,_=[],v||d(b);return}x();try{_=d(()=>m(g,t,n,s,c,u))}catch(t){e(`each() reconciliation error: ${t instanceof Error?t.message:String(t)}`);for(let e of g.values())p(e);g=new Map,_=[]}});i(()=>S.dispose()),i(()=>{x();for(let e of _)p(e);u.remove()})})}export{h as each};
2
2
  //# sourceMappingURL=each.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"each.js","names":[],"sources":["../../src/directives/each.ts"],"sourcesContent":["import { batch, computed, effect as rawEffect, type Readable, signal, type Signal, untrack } from '@vielzeug/ripple';\n\nimport { devOnly, warn } from '../_dev';\nimport { OreApiError, ORE_ERRORS } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult } from '../types/bindings';\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};\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\n const result = render(dataSignal, indexSignal);\n const cleanups: (() => void)[] = [];\n const nodes = result.mount(parent, insertBefore, (fn) => cleanups.push(fn));\n\n return { cleanups, data: dataSignal, index: indexSignal, key: '', nodes };\n};\n\nconst removeItem = <T>(entry: ItemEntry<T>): void => {\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 */\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 devOnly(() => {\n try {\n const SENTINEL_IDX = 99999;\n const testKey = keyFn({} as T, SENTINEL_IDX);\n\n if (testKey === SENTINEL_IDX) {\n warn(\n 'each(): key function returns only the index. Index keys cause full list re-renders on insert/remove — pass a stable item identifier (e.g. item.id) instead.',\n );\n }\n } catch {\n /* ignore — keyFn may throw on a non-item sentinel; that is fine */\n }\n });\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode!;\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 warn(`each() reconciliation error: ${err instanceof Error ? err.message : String(err)}`);\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 { batch, computed, effect as rawEffect, type Readable, signal, type Signal, untrack } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { invariant, OreApiError, ORE_ERRORS } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult } from '../types/bindings';\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};\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\n const result = render(dataSignal, indexSignal);\n const cleanups: (() => void)[] = [];\n const nodes = result.mount(parent, insertBefore, (fn) => cleanups.push(fn));\n\n return { cleanups, data: dataSignal, index: indexSignal, key: '', nodes };\n};\n\nconst removeItem = <T>(entry: ItemEntry<T>): void => {\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. Duplicate keys within one render throw immediately (see `eachDuplicateKey`).\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 warn(`each() reconciliation error: ${err instanceof Error ? err.message : String(err)}`);\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,2 +1,2 @@
1
- const e=require("../_dev.cjs"),t=require("../types/bindings.cjs"),n=require("../utils/dom.cjs");let r=require("@vielzeug/ripple");var i=null,a=!1,o=e=>{i=e,e||(a=!1)},s=()=>{i=null,a=!1},c=t=>i?i(t):(t&&!a&&(a=!0,e.warn(`raw() was called without a sanitizer registered. Passing user-supplied HTML directly to raw() is an XSS risk. Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).`)),t),l=(e,t,n)=>{let r=document.createElement(`template`);r.innerHTML=e;let i=Array.from(r.content.cloneNode(!0).childNodes);for(let e of i)t.insertBefore(e,n);return i};function u(e){if(typeof e==`function`){let n=(0,r.computed)(e);return t.createDirectiveResult((e,t)=>{t(()=>n.dispose()),u(n).mount(e,t)})}return t.createDirectiveResult((t,i)=>{let a=t.parentNode,o=document.createComment(`raw/end`);if(a.insertBefore(o,t.nextSibling),(0,r.isReactive)(e)){let t=[],s=e,u=(0,r.effect)(()=>{n.removeNodes(t),t=l(c(s.value),a,o)});i(()=>u.dispose()),i(()=>{n.removeNodes(t),o.remove()})}else l(c(e),a,o),i(()=>o.remove())})}exports._resetRawSanitizer=s,exports.raw=u,exports.setRawSanitizer=o;
1
+ const e=require("../_dev.cjs"),t=require("../errors.cjs"),n=require("../types/bindings.cjs"),r=require("../utils/dom.cjs");let i=require("@vielzeug/ripple");var a=null,o=!1,s=e=>{a=e,e||(o=!1)},c=()=>{a=null,o=!1},l=t=>a?a(t):(t&&!o&&(o=!0,e.warn(`raw() was called without a sanitizer registered. Passing user-supplied HTML directly to raw() is an XSS risk. Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).`)),t),u=(e,t,n)=>{let r=document.createElement(`template`);r.innerHTML=e;let i=Array.from(r.content.cloneNode(!0).childNodes);for(let e of i)t.insertBefore(e,n);return i};function d(e){if(typeof e==`function`){let t=(0,i.computed)(e);return n.createDirectiveResult((e,n)=>{n(()=>t.dispose()),d(t).mount(e,n)})}return n.createDirectiveResult((n,a)=>{let o=n.parentNode;t.invariant(o,`raw() anchor comment has no parent node`);let s=document.createComment(`raw/end`);if(o.insertBefore(s,n.nextSibling),(0,i.isReactive)(e)){let t=[],n=e,c=(0,i.effect)(()=>{r.removeNodes(t),t=u(l(n.value),o,s)});a(()=>c.dispose()),a(()=>{r.removeNodes(t),s.remove()})}else u(l(e),o,s),a(()=>s.remove())})}exports._resetRawSanitizer=c,exports.raw=d,exports.setRawSanitizer=s;
2
2
  //# sourceMappingURL=raw.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"raw.cjs","names":[],"sources":["../../src/directives/raw.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, type Signal } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { createDirectiveResult, type DirectiveResult } from '../types/bindings';\nimport { removeNodes } from '../utils/dom';\n\ntype RawSanitizer = (html: string) => string;\n\nlet _sanitizer: RawSanitizer | null = null;\nlet _warned = false;\n\nexport const setRawSanitizer = (fn: RawSanitizer | null): void => {\n _sanitizer = fn;\n\n if (!fn) _warned = false;\n};\n\n/** @internal */\nexport const _resetRawSanitizer = (): void => {\n _sanitizer = null;\n _warned = false;\n};\n\nconst sanitize = (value: string): string => {\n if (_sanitizer) return _sanitizer(value);\n\n if (value && !_warned) {\n _warned = true;\n warn(\n 'raw() was called without a sanitizer registered. ' +\n 'Passing user-supplied HTML directly to raw() is an XSS risk. ' +\n 'Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).',\n );\n }\n\n return value;\n};\n\nconst parseRaw = (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 a trusted HTML string without escaping as a DirectiveResult.\n * Only use with content you control — passing user-supplied strings\n * directly is an XSS risk. Register a sanitizer with setRawSanitizer()\n * to add a runtime safety net.\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 raw(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 registerCleanup(() => c.dispose());\n raw(c).mount(anchor, registerCleanup);\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode!;\n const endMarker = document.createComment('raw/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (isReactive(value)) {\n let currentNodes: Node[] = [];\n const src = value as Readable<string>;\n\n const stop = rawEffect(() => {\n removeNodes(currentNodes);\n currentNodes = parseRaw(sanitize(src.value), parent, endMarker);\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n removeNodes(currentNodes);\n endMarker.remove();\n });\n } else {\n parseRaw(sanitize(value), parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"kIAQA,IAAI,EAAkC,KAClC,EAAU,GAED,EAAmB,GAAkC,CAChE,EAAa,EAER,IAAI,EAAU,GACrB,EAGa,MAAiC,CAC5C,EAAa,KACb,EAAU,EACZ,EAEM,EAAY,GACZ,EAAmB,EAAW,CAAK,GAEnC,GAAS,CAAC,IACZ,EAAU,GACV,EAAA,KACE,uMAGF,GAGK,GAGH,GAAY,EAAc,EAAoB,IAA+B,CACjF,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,EAWA,SAAgB,EAAI,EAAqF,CACvG,GAAI,OAAO,GAAU,WAAY,CAC/B,IAAM,GAAA,EAAA,EAAA,SAAA,CAAa,CAAK,EAExB,OAAO,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,MAAsB,EAAE,QAAQ,CAAC,EACjC,EAAI,CAAC,CAAC,CAAC,MAAM,EAAQ,CAAe,CACtC,CAAC,CACH,CAEA,OAAO,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAO,WAChB,EAAY,SAAS,cAAc,SAAS,EAIlD,GAFA,EAAO,aAAa,EAAW,EAAO,WAAW,GAEjD,EAAA,EAAA,WAAA,CAAe,CAAK,EAAG,CACrB,IAAI,EAAuB,CAAC,EACtB,EAAM,EAEN,GAAA,EAAA,EAAA,OAAA,KAAuB,CAC3B,EAAA,YAAY,CAAY,EACxB,EAAe,EAAS,EAAS,EAAI,KAAK,EAAG,EAAQ,CAAS,CAChE,CAAC,EAED,MAAsB,EAAK,QAAQ,CAAC,EACpC,MAAsB,CACpB,EAAA,YAAY,CAAY,EACxB,EAAU,OAAO,CACnB,CAAC,CACH,MACE,EAAS,EAAS,CAAK,EAAG,EAAQ,CAAS,EAE3C,MAAsB,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH"}
1
+ {"version":3,"file":"raw.cjs","names":[],"sources":["../../src/directives/raw.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, type Signal } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../types/bindings';\nimport { removeNodes } from '../utils/dom';\n\ntype RawSanitizer = (html: string) => string;\n\nlet _sanitizer: RawSanitizer | null = null;\nlet _warned = false;\n\nexport const setRawSanitizer = (fn: RawSanitizer | null): void => {\n _sanitizer = fn;\n\n if (!fn) _warned = false;\n};\n\n/** @internal */\nexport const _resetRawSanitizer = (): void => {\n _sanitizer = null;\n _warned = false;\n};\n\nconst sanitize = (value: string): string => {\n if (_sanitizer) return _sanitizer(value);\n\n if (value && !_warned) {\n _warned = true;\n warn(\n 'raw() was called without a sanitizer registered. ' +\n 'Passing user-supplied HTML directly to raw() is an XSS risk. ' +\n 'Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).',\n );\n }\n\n return value;\n};\n\nconst parseRaw = (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 a trusted HTML string without escaping as a DirectiveResult.\n * Only use with content you control — passing user-supplied strings\n * directly is an XSS risk. Register a sanitizer with setRawSanitizer()\n * to add a runtime safety net.\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 raw(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 registerCleanup(() => c.dispose());\n raw(c).mount(anchor, registerCleanup);\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'raw() anchor comment has no parent node');\n\n const endMarker = document.createComment('raw/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (isReactive(value)) {\n let currentNodes: Node[] = [];\n const src = value as Readable<string>;\n\n const stop = rawEffect(() => {\n removeNodes(currentNodes);\n currentNodes = parseRaw(sanitize(src.value), parent, endMarker);\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n removeNodes(currentNodes);\n endMarker.remove();\n });\n } else {\n parseRaw(sanitize(value), parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"6JASA,IAAI,EAAkC,KAClC,EAAU,GAED,EAAmB,GAAkC,CAChE,EAAa,EAER,IAAI,EAAU,GACrB,EAGa,MAAiC,CAC5C,EAAa,KACb,EAAU,EACZ,EAEM,EAAY,GACZ,EAAmB,EAAW,CAAK,GAEnC,GAAS,CAAC,IACZ,EAAU,GACV,EAAA,KACE,uMAGF,GAGK,GAGH,GAAY,EAAc,EAAoB,IAA+B,CACjF,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,EAWA,SAAgB,EAAI,EAAqF,CACvG,GAAI,OAAO,GAAU,WAAY,CAC/B,IAAM,GAAA,EAAA,EAAA,SAAA,CAAa,CAAK,EAExB,OAAO,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,MAAsB,EAAE,QAAQ,CAAC,EACjC,EAAI,CAAC,CAAC,CAAC,MAAM,EAAQ,CAAe,CACtC,CAAC,CACH,CAEA,OAAO,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,yCAAyC,EAE3D,IAAM,EAAY,SAAS,cAAc,SAAS,EAIlD,GAFA,EAAO,aAAa,EAAW,EAAO,WAAW,GAEjD,EAAA,EAAA,WAAA,CAAe,CAAK,EAAG,CACrB,IAAI,EAAuB,CAAC,EACtB,EAAM,EAEN,GAAA,EAAA,EAAA,OAAA,KAAuB,CAC3B,EAAA,YAAY,CAAY,EACxB,EAAe,EAAS,EAAS,EAAI,KAAK,EAAG,EAAQ,CAAS,CAChE,CAAC,EAED,MAAsB,EAAK,QAAQ,CAAC,EACpC,MAAsB,CACpB,EAAA,YAAY,CAAY,EACxB,EAAU,OAAO,CACnB,CAAC,CACH,MACE,EAAS,EAAS,CAAK,EAAG,EAAQ,CAAS,EAE3C,MAAsB,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"raw.d.ts","sourceRoot":"","sources":["../../src/directives/raw.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAGzG,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGhF,KAAK,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAK7C,eAAO,MAAM,eAAe,GAAI,IAAI,YAAY,GAAG,IAAI,KAAG,IAIzD,CAAC;AAmCF;;;;;;;;GAQG;AACH,wBAAgB,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,eAAe,CAoCvG"}
1
+ {"version":3,"file":"raw.d.ts","sourceRoot":"","sources":["../../src/directives/raw.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAIzG,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGhF,KAAK,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAK7C,eAAO,MAAM,eAAe,GAAI,IAAI,YAAY,GAAG,IAAI,KAAG,IAIzD,CAAC;AAmCF;;;;;;;;GAQG;AACH,wBAAgB,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,eAAe,CAuCvG"}
@@ -1,2 +1,2 @@
1
- import{warn as e}from"../_dev.js";import{createDirectiveResult as t}from"../types/bindings.js";import{removeNodes as n}from"../utils/dom.js";import{computed as r,effect as i,isReactive as a}from"@vielzeug/ripple";var o=null,s=!1,c=e=>{o=e,e||(s=!1)},l=()=>{o=null,s=!1},u=t=>o?o(t):(t&&!s&&(s=!0,e(`raw() was called without a sanitizer registered. Passing user-supplied HTML directly to raw() is an XSS risk. Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).`)),t),d=(e,t,n)=>{let r=document.createElement(`template`);r.innerHTML=e;let i=Array.from(r.content.cloneNode(!0).childNodes);for(let e of i)t.insertBefore(e,n);return i};function f(e){if(typeof e==`function`){let n=r(e);return t((e,t)=>{t(()=>n.dispose()),f(n).mount(e,t)})}return t((t,r)=>{let o=t.parentNode,s=document.createComment(`raw/end`);if(o.insertBefore(s,t.nextSibling),a(e)){let t=[],a=e,c=i(()=>{n(t),t=d(u(a.value),o,s)});r(()=>c.dispose()),r(()=>{n(t),s.remove()})}else d(u(e),o,s),r(()=>s.remove())})}export{l as _resetRawSanitizer,f as raw,c as setRawSanitizer};
1
+ import{warn as e}from"../_dev.js";import{invariant as t}from"../errors.js";import{createDirectiveResult as n}from"../types/bindings.js";import{removeNodes as r}from"../utils/dom.js";import{computed as i,effect as a,isReactive as o}from"@vielzeug/ripple";var s=null,c=!1,l=e=>{s=e,e||(c=!1)},u=()=>{s=null,c=!1},d=t=>s?s(t):(t&&!c&&(c=!0,e(`raw() was called without a sanitizer registered. Passing user-supplied HTML directly to raw() is an XSS risk. Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).`)),t),f=(e,t,n)=>{let r=document.createElement(`template`);r.innerHTML=e;let i=Array.from(r.content.cloneNode(!0).childNodes);for(let e of i)t.insertBefore(e,n);return i};function p(e){if(typeof e==`function`){let t=i(e);return n((e,n)=>{n(()=>t.dispose()),p(t).mount(e,n)})}return n((n,i)=>{let s=n.parentNode;t(s,`raw() anchor comment has no parent node`);let c=document.createComment(`raw/end`);if(s.insertBefore(c,n.nextSibling),o(e)){let t=[],n=e,o=a(()=>{r(t),t=f(d(n.value),s,c)});i(()=>o.dispose()),i(()=>{r(t),c.remove()})}else f(d(e),s,c),i(()=>c.remove())})}export{u as _resetRawSanitizer,p as raw,l as setRawSanitizer};
2
2
  //# sourceMappingURL=raw.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"raw.js","names":[],"sources":["../../src/directives/raw.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, type Signal } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { createDirectiveResult, type DirectiveResult } from '../types/bindings';\nimport { removeNodes } from '../utils/dom';\n\ntype RawSanitizer = (html: string) => string;\n\nlet _sanitizer: RawSanitizer | null = null;\nlet _warned = false;\n\nexport const setRawSanitizer = (fn: RawSanitizer | null): void => {\n _sanitizer = fn;\n\n if (!fn) _warned = false;\n};\n\n/** @internal */\nexport const _resetRawSanitizer = (): void => {\n _sanitizer = null;\n _warned = false;\n};\n\nconst sanitize = (value: string): string => {\n if (_sanitizer) return _sanitizer(value);\n\n if (value && !_warned) {\n _warned = true;\n warn(\n 'raw() was called without a sanitizer registered. ' +\n 'Passing user-supplied HTML directly to raw() is an XSS risk. ' +\n 'Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).',\n );\n }\n\n return value;\n};\n\nconst parseRaw = (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 a trusted HTML string without escaping as a DirectiveResult.\n * Only use with content you control — passing user-supplied strings\n * directly is an XSS risk. Register a sanitizer with setRawSanitizer()\n * to add a runtime safety net.\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 raw(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 registerCleanup(() => c.dispose());\n raw(c).mount(anchor, registerCleanup);\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode!;\n const endMarker = document.createComment('raw/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (isReactive(value)) {\n let currentNodes: Node[] = [];\n const src = value as Readable<string>;\n\n const stop = rawEffect(() => {\n removeNodes(currentNodes);\n currentNodes = parseRaw(sanitize(src.value), parent, endMarker);\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n removeNodes(currentNodes);\n endMarker.remove();\n });\n } else {\n parseRaw(sanitize(value), parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"qNAQA,IAAI,EAAkC,KAClC,EAAU,GAED,EAAmB,GAAkC,CAChE,EAAa,EAER,IAAI,EAAU,GACrB,EAGa,MAAiC,CAC5C,EAAa,KACb,EAAU,EACZ,EAEM,EAAY,GACZ,EAAmB,EAAW,CAAK,GAEnC,GAAS,CAAC,IACZ,EAAU,GACV,EACE,uMAGF,GAGK,GAGH,GAAY,EAAc,EAAoB,IAA+B,CACjF,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,EAWA,SAAgB,EAAI,EAAqF,CACvG,GAAI,OAAO,GAAU,WAAY,CAC/B,IAAM,EAAI,EAAS,CAAK,EAExB,OAAO,GAAuB,EAAQ,IAAoB,CACxD,MAAsB,EAAE,QAAQ,CAAC,EACjC,EAAI,CAAC,CAAC,CAAC,MAAM,EAAQ,CAAe,CACtC,CAAC,CACH,CAEA,OAAO,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAO,WAChB,EAAY,SAAS,cAAc,SAAS,EAIlD,GAFA,EAAO,aAAa,EAAW,EAAO,WAAW,EAE7C,EAAW,CAAK,EAAG,CACrB,IAAI,EAAuB,CAAC,EACtB,EAAM,EAEN,EAAO,MAAgB,CAC3B,EAAY,CAAY,EACxB,EAAe,EAAS,EAAS,EAAI,KAAK,EAAG,EAAQ,CAAS,CAChE,CAAC,EAED,MAAsB,EAAK,QAAQ,CAAC,EACpC,MAAsB,CACpB,EAAY,CAAY,EACxB,EAAU,OAAO,CACnB,CAAC,CACH,MACE,EAAS,EAAS,CAAK,EAAG,EAAQ,CAAS,EAE3C,MAAsB,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH"}
1
+ {"version":3,"file":"raw.js","names":[],"sources":["../../src/directives/raw.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, type Signal } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../types/bindings';\nimport { removeNodes } from '../utils/dom';\n\ntype RawSanitizer = (html: string) => string;\n\nlet _sanitizer: RawSanitizer | null = null;\nlet _warned = false;\n\nexport const setRawSanitizer = (fn: RawSanitizer | null): void => {\n _sanitizer = fn;\n\n if (!fn) _warned = false;\n};\n\n/** @internal */\nexport const _resetRawSanitizer = (): void => {\n _sanitizer = null;\n _warned = false;\n};\n\nconst sanitize = (value: string): string => {\n if (_sanitizer) return _sanitizer(value);\n\n if (value && !_warned) {\n _warned = true;\n warn(\n 'raw() was called without a sanitizer registered. ' +\n 'Passing user-supplied HTML directly to raw() is an XSS risk. ' +\n 'Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).',\n );\n }\n\n return value;\n};\n\nconst parseRaw = (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 a trusted HTML string without escaping as a DirectiveResult.\n * Only use with content you control — passing user-supplied strings\n * directly is an XSS risk. Register a sanitizer with setRawSanitizer()\n * to add a runtime safety net.\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 raw(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 registerCleanup(() => c.dispose());\n raw(c).mount(anchor, registerCleanup);\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'raw() anchor comment has no parent node');\n\n const endMarker = document.createComment('raw/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (isReactive(value)) {\n let currentNodes: Node[] = [];\n const src = value as Readable<string>;\n\n const stop = rawEffect(() => {\n removeNodes(currentNodes);\n currentNodes = parseRaw(sanitize(src.value), parent, endMarker);\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n removeNodes(currentNodes);\n endMarker.remove();\n });\n } else {\n parseRaw(sanitize(value), parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"8PASA,IAAI,EAAkC,KAClC,EAAU,GAED,EAAmB,GAAkC,CAChE,EAAa,EAER,IAAI,EAAU,GACrB,EAGa,MAAiC,CAC5C,EAAa,KACb,EAAU,EACZ,EAEM,EAAY,GACZ,EAAmB,EAAW,CAAK,GAEnC,GAAS,CAAC,IACZ,EAAU,GACV,EACE,uMAGF,GAGK,GAGH,GAAY,EAAc,EAAoB,IAA+B,CACjF,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,EAWA,SAAgB,EAAI,EAAqF,CACvG,GAAI,OAAO,GAAU,WAAY,CAC/B,IAAM,EAAI,EAAS,CAAK,EAExB,OAAO,GAAuB,EAAQ,IAAoB,CACxD,MAAsB,EAAE,QAAQ,CAAC,EACjC,EAAI,CAAC,CAAC,CAAC,MAAM,EAAQ,CAAe,CACtC,CAAC,CACH,CAEA,OAAO,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAO,WAEtB,EAAU,EAAQ,yCAAyC,EAE3D,IAAM,EAAY,SAAS,cAAc,SAAS,EAIlD,GAFA,EAAO,aAAa,EAAW,EAAO,WAAW,EAE7C,EAAW,CAAK,EAAG,CACrB,IAAI,EAAuB,CAAC,EACtB,EAAM,EAEN,EAAO,MAAgB,CAC3B,EAAY,CAAY,EACxB,EAAe,EAAS,EAAS,EAAI,KAAK,EAAG,EAAQ,CAAS,CAChE,CAAC,EAED,MAAsB,EAAK,QAAQ,CAAC,EACpC,MAAsB,CACpB,EAAY,CAAY,EACxB,EAAU,OAAO,CACnB,CAAC,CACH,MACE,EAAS,EAAS,CAAK,EAAG,EAAQ,CAAS,EAE3C,MAAsB,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH"}
@@ -1,2 +1,2 @@
1
- const e=require("../types/bindings.cjs"),t=require("../utils/dom.cjs");let n=require("@vielzeug/ripple");var r=(e,t,n,r)=>e.mount(t,n,r);function i(i,a,o){return typeof i!=`function`&&!(0,n.isReactive)(i)?e.createDirectiveResult((n,s)=>{let c=i?a():o?o():null;if(!c||!e.isHtmlResult(c))return;let l=n.parentNode,u=r(c,l,n,s);s(()=>t.removeNodes(u))}):e.createDirectiveResult((s,c)=>{let l=typeof i==`function`?(0,n.computed)(i):null,u=l??i;l&&c(()=>l.dispose());let d=s.parentNode,f=document.createComment(`when/end`);d.insertBefore(f,s.nextSibling);let p=[],m=[],h=(0,n.effect)(()=>{let i=u.value;t.runAll(m),t.removeNodes(p),m=[],p=[];let s=i?a():o?o():null;if(!s||!e.isHtmlResult(s))return;let c=[];p=(0,n.untrack)(()=>r(s,d,f,e=>c.push(e))),m=c});c(()=>h.dispose()),c(()=>{t.runAll(m),t.removeNodes(p),f.remove()})})}exports.when=i;
1
+ const e=require("../errors.cjs"),t=require("../types/bindings.cjs"),n=require("../utils/dom.cjs");let r=require("@vielzeug/ripple");var i=`when() anchor comment has no parent node`,a=(e,t,n,r)=>e.mount(t,n,r);function o(o,s,c){return typeof o!=`function`&&!(0,r.isReactive)(o)?t.createDirectiveResult((r,l)=>{let u=o?s():c?c():null;if(!u||!t.isHtmlResult(u))return;let d=r.parentNode;e.invariant(d,i);let f=a(u,d,r,l);l(()=>n.removeNodes(f))}):t.createDirectiveResult((l,u)=>{let d=typeof o==`function`?(0,r.computed)(o):null,f=d??o;d&&u(()=>d.dispose());let p=l.parentNode;e.invariant(p,i);let m=document.createComment(`when/end`);p.insertBefore(m,l.nextSibling);let h=[],g=[],_=(0,r.effect)(()=>{let e=f.value;n.runAll(g),n.removeNodes(h),g=[],h=[];let i=e?s():c?c():null;if(!i||!t.isHtmlResult(i))return;let o=[];h=(0,r.untrack)(()=>a(i,p,m,e=>o.push(e))),g=o});u(()=>_.dispose()),u(()=>{n.runAll(g),n.removeNodes(h),m.remove()})})}exports.when=o;
2
2
  //# sourceMappingURL=when.cjs.map
@@ -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 type { RegisterCleanup } from '../template';\n\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../types/bindings';\nimport { removeNodes, runAll } from '../utils/dom';\n\ntype MaybeReactive<T> = T | (() => T) | Readable<T>;\n\ntype WhenRenderable = HTMLResult | null | undefined | false;\n\nconst mountBranch = (\n result: HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n registerCleanup: RegisterCleanup,\n): Node[] => result.mount(parent, insertBefore, registerCleanup);\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 const nodes = mountBranch(branch, 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 if (ownedComputed) registerCleanup(() => ownedComputed.dispose());\n\n const parent = anchor.parentNode!;\n const endMarker = document.createComment('when/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n let currentNodes: Node[] = [];\n let currentCleanups: (() => void)[] = [];\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n runAll(currentCleanups);\n removeNodes(currentNodes);\n currentCleanups = [];\n currentNodes = [];\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const branchCleanups: (() => void)[] = [];\n\n currentNodes = untrack(() => mountBranch(branch, parent, endMarker, (fn) => branchCleanups.push(fn)));\n currentCleanups = branchCleanups;\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n runAll(currentCleanups);\n removeNodes(currentNodes);\n endMarker.remove();\n });\n });\n}\n"],"mappings":"yGAWA,IAAM,GACJ,EACA,EACA,EACA,IACW,EAAO,MAAM,EAAQ,EAAc,CAAe,EAc/D,SAAgB,EACd,EACA,EACA,EACiB,CAcjB,OAbI,OAAO,GAAc,YAAc,EAAA,EAAA,EAAA,WAAA,CAAY,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,WAChB,EAAQ,EAAY,EAAQ,EAAQ,EAAQ,CAAe,EAEjE,MAAsB,EAAA,YAAY,CAAK,CAAC,CAC1C,CAAC,EAGI,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAgB,OAAO,GAAc,YAAA,EAAA,EAAA,SAAA,CAAsB,CAA0B,EAAI,KACzF,EAAkB,GAAkB,EAEtC,GAAe,MAAsB,EAAc,QAAQ,CAAC,EAEhE,IAAM,EAAS,EAAO,WAChB,EAAY,SAAS,cAAc,UAAU,EAEnD,EAAO,aAAa,EAAW,EAAO,WAAW,EAEjD,IAAI,EAAuB,CAAC,EACxB,EAAkC,CAAC,EAEjC,GAAA,EAAA,EAAA,OAAA,KAAsB,CAC1B,IAAM,EAAO,EAAgB,MAE7B,EAAA,OAAO,CAAe,EACtB,EAAA,YAAY,CAAY,EACxB,EAAkB,CAAC,EACnB,EAAe,CAAC,EAEhB,IAAM,EAAS,EAAO,EAAO,EAAI,EAAQ,EAAM,EAAI,KAEnD,GAAI,CAAC,GAAU,CAAC,EAAA,aAAa,CAAM,EAAG,OAEtC,IAAM,EAAiC,CAAC,EAExC,GAAA,EAAA,EAAA,QAAA,KAA6B,EAAY,EAAQ,EAAQ,EAAY,GAAO,EAAe,KAAK,CAAE,CAAC,CAAC,EACpG,EAAkB,CACpB,CAAC,EAED,MAAsB,EAAI,QAAQ,CAAC,EACnC,MAAsB,CACpB,EAAA,OAAO,CAAe,EACtB,EAAA,YAAY,CAAY,EACxB,EAAU,OAAO,CACnB,CAAC,CACH,CAAC,CACH"}
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 type { RegisterCleanup } from '../template';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../types/bindings';\nimport { removeNodes, runAll } 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\nconst mountBranch = (\n result: HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n registerCleanup: RegisterCleanup,\n): Node[] => result.mount(parent, insertBefore, registerCleanup);\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 = mountBranch(branch, 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 if (ownedComputed) registerCleanup(() => ownedComputed.dispose());\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 let currentNodes: Node[] = [];\n let currentCleanups: (() => void)[] = [];\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n runAll(currentCleanups);\n removeNodes(currentNodes);\n currentCleanups = [];\n currentNodes = [];\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const branchCleanups: (() => void)[] = [];\n\n currentNodes = untrack(() => mountBranch(branch, parent, endMarker, (fn) => branchCleanups.push(fn)));\n currentCleanups = branchCleanups;\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n runAll(currentCleanups);\n removeNodes(currentNodes);\n endMarker.remove();\n });\n });\n}\n"],"mappings":"oIAYA,IAAM,EAAgB,2CAEhB,GACJ,EACA,EACA,EACA,IACW,EAAO,MAAM,EAAQ,EAAc,CAAe,EAc/D,SAAgB,EACd,EACA,EACA,EACiB,CAiBjB,OAhBI,OAAO,GAAc,YAAc,EAAA,EAAA,EAAA,WAAA,CAAY,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,EAAY,EAAQ,EAAQ,EAAQ,CAAe,EAEjE,MAAsB,EAAA,YAAY,CAAK,CAAC,CAC1C,CAAC,EAGI,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAgB,OAAO,GAAc,YAAA,EAAA,EAAA,SAAA,CAAsB,CAA0B,EAAI,KACzF,EAAkB,GAAkB,EAEtC,GAAe,MAAsB,EAAc,QAAQ,CAAC,EAEhE,IAAM,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,CAAa,EAE/B,IAAM,EAAY,SAAS,cAAc,UAAU,EAEnD,EAAO,aAAa,EAAW,EAAO,WAAW,EAEjD,IAAI,EAAuB,CAAC,EACxB,EAAkC,CAAC,EAEjC,GAAA,EAAA,EAAA,OAAA,KAAsB,CAC1B,IAAM,EAAO,EAAgB,MAE7B,EAAA,OAAO,CAAe,EACtB,EAAA,YAAY,CAAY,EACxB,EAAkB,CAAC,EACnB,EAAe,CAAC,EAEhB,IAAM,EAAS,EAAO,EAAO,EAAI,EAAQ,EAAM,EAAI,KAEnD,GAAI,CAAC,GAAU,CAAC,EAAA,aAAa,CAAM,EAAG,OAEtC,IAAM,EAAiC,CAAC,EAExC,GAAA,EAAA,EAAA,QAAA,KAA6B,EAAY,EAAQ,EAAQ,EAAY,GAAO,EAAe,KAAK,CAAE,CAAC,CAAC,EACpG,EAAkB,CACpB,CAAC,EAED,MAAsB,EAAI,QAAQ,CAAC,EACnC,MAAsB,CACpB,EAAA,OAAO,CAAe,EACtB,EAAA,YAAY,CAAY,EACxB,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;AAIrG,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,UAAU,EAAgB,MAAM,mBAAmB,CAAC;AAG/G,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;AAS5D;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAClB,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,EACjC,MAAM,EAAE,MAAM,cAAc,EAC5B,KAAK,CAAC,EAAE,MAAM,cAAc,GAC3B,eAAe,CAqDjB"}
1
+ {"version":3,"file":"when.d.ts","sourceRoot":"","sources":["../../src/directives/when.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,QAAQ,EAAW,MAAM,kBAAkB,CAAC;AAKrG,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,UAAU,EAAgB,MAAM,mBAAmB,CAAC;AAG/G,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;AAW5D;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAClB,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,EACjC,MAAM,EAAE,MAAM,cAAc,EAC5B,KAAK,CAAC,EAAE,MAAM,cAAc,GAC3B,eAAe,CA2DjB"}
@@ -1,2 +1,2 @@
1
- import{createDirectiveResult as e,isHtmlResult as t}from"../types/bindings.js";import{removeNodes as n,runAll as r}from"../utils/dom.js";import{computed as i,effect as a,isReactive as o,untrack as s}from"@vielzeug/ripple";var c=(e,t,n,r)=>e.mount(t,n,r);function l(l,u,d){return typeof l!=`function`&&!o(l)?e((e,r)=>{let i=l?u():d?d():null;if(!i||!t(i))return;let a=e.parentNode,o=c(i,a,e,r);r(()=>n(o))}):e((e,o)=>{let f=typeof l==`function`?i(l):null,p=f??l;f&&o(()=>f.dispose());let m=e.parentNode,h=document.createComment(`when/end`);m.insertBefore(h,e.nextSibling);let g=[],_=[],v=a(()=>{let e=p.value;r(_),n(g),_=[],g=[];let i=e?u():d?d():null;if(!i||!t(i))return;let a=[];g=s(()=>c(i,m,h,e=>a.push(e))),_=a});o(()=>v.dispose()),o(()=>{r(_),n(g),h.remove()})})}export{l as when};
1
+ import{invariant as e}from"../errors.js";import{createDirectiveResult as t,isHtmlResult as n}from"../types/bindings.js";import{removeNodes as r,runAll as i}from"../utils/dom.js";import{computed as a,effect as o,isReactive as s,untrack as c}from"@vielzeug/ripple";var l=`when() anchor comment has no parent node`,u=(e,t,n,r)=>e.mount(t,n,r);function d(d,f,p){return typeof d!=`function`&&!s(d)?t((t,i)=>{let a=d?f():p?p():null;if(!a||!n(a))return;let o=t.parentNode;e(o,l);let s=u(a,o,t,i);i(()=>r(s))}):t((t,s)=>{let m=typeof d==`function`?a(d):null,h=m??d;m&&s(()=>m.dispose());let g=t.parentNode;e(g,l);let _=document.createComment(`when/end`);g.insertBefore(_,t.nextSibling);let v=[],y=[],b=o(()=>{let e=h.value;i(y),r(v),y=[],v=[];let t=e?f():p?p():null;if(!t||!n(t))return;let a=[];v=c(()=>u(t,g,_,e=>a.push(e))),y=a});s(()=>b.dispose()),s(()=>{i(y),r(v),_.remove()})})}export{d as when};
2
2
  //# sourceMappingURL=when.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"when.js","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, untrack } from '@vielzeug/ripple';\n\nimport type { RegisterCleanup } from '../template';\n\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../types/bindings';\nimport { removeNodes, runAll } from '../utils/dom';\n\ntype MaybeReactive<T> = T | (() => T) | Readable<T>;\n\ntype WhenRenderable = HTMLResult | null | undefined | false;\n\nconst mountBranch = (\n result: HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n registerCleanup: RegisterCleanup,\n): Node[] => result.mount(parent, insertBefore, registerCleanup);\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 const nodes = mountBranch(branch, 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 if (ownedComputed) registerCleanup(() => ownedComputed.dispose());\n\n const parent = anchor.parentNode!;\n const endMarker = document.createComment('when/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n let currentNodes: Node[] = [];\n let currentCleanups: (() => void)[] = [];\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n runAll(currentCleanups);\n removeNodes(currentNodes);\n currentCleanups = [];\n currentNodes = [];\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const branchCleanups: (() => void)[] = [];\n\n currentNodes = untrack(() => mountBranch(branch, parent, endMarker, (fn) => branchCleanups.push(fn)));\n currentCleanups = branchCleanups;\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n runAll(currentCleanups);\n removeNodes(currentNodes);\n endMarker.remove();\n });\n });\n}\n"],"mappings":"8NAWA,IAAM,GACJ,EACA,EACA,EACA,IACW,EAAO,MAAM,EAAQ,EAAc,CAAe,EAc/D,SAAgB,EACd,EACA,EACA,EACiB,CAcjB,OAbI,OAAO,GAAc,YAAc,CAAC,EAAW,CAAS,EACnD,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAY,EAAO,EAAI,EAAQ,EAAM,EAAI,KAExD,GAAI,CAAC,GAAU,CAAC,EAAa,CAAM,EAAG,OAEtC,IAAM,EAAS,EAAO,WAChB,EAAQ,EAAY,EAAQ,EAAQ,EAAQ,CAAe,EAEjE,MAAsB,EAAY,CAAK,CAAC,CAC1C,CAAC,EAGI,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAgB,OAAO,GAAc,WAAa,EAAS,CAA0B,EAAI,KACzF,EAAkB,GAAkB,EAEtC,GAAe,MAAsB,EAAc,QAAQ,CAAC,EAEhE,IAAM,EAAS,EAAO,WAChB,EAAY,SAAS,cAAc,UAAU,EAEnD,EAAO,aAAa,EAAW,EAAO,WAAW,EAEjD,IAAI,EAAuB,CAAC,EACxB,EAAkC,CAAC,EAEjC,EAAM,MAAgB,CAC1B,IAAM,EAAO,EAAgB,MAE7B,EAAO,CAAe,EACtB,EAAY,CAAY,EACxB,EAAkB,CAAC,EACnB,EAAe,CAAC,EAEhB,IAAM,EAAS,EAAO,EAAO,EAAI,EAAQ,EAAM,EAAI,KAEnD,GAAI,CAAC,GAAU,CAAC,EAAa,CAAM,EAAG,OAEtC,IAAM,EAAiC,CAAC,EAExC,EAAe,MAAc,EAAY,EAAQ,EAAQ,EAAY,GAAO,EAAe,KAAK,CAAE,CAAC,CAAC,EACpG,EAAkB,CACpB,CAAC,EAED,MAAsB,EAAI,QAAQ,CAAC,EACnC,MAAsB,CACpB,EAAO,CAAe,EACtB,EAAY,CAAY,EACxB,EAAU,OAAO,CACnB,CAAC,CACH,CAAC,CACH"}
1
+ {"version":3,"file":"when.js","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, untrack } from '@vielzeug/ripple';\n\nimport type { RegisterCleanup } from '../template';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../types/bindings';\nimport { removeNodes, runAll } 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\nconst mountBranch = (\n result: HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n registerCleanup: RegisterCleanup,\n): Node[] => result.mount(parent, insertBefore, registerCleanup);\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 = mountBranch(branch, 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 if (ownedComputed) registerCleanup(() => ownedComputed.dispose());\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 let currentNodes: Node[] = [];\n let currentCleanups: (() => void)[] = [];\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n runAll(currentCleanups);\n removeNodes(currentNodes);\n currentCleanups = [];\n currentNodes = [];\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const branchCleanups: (() => void)[] = [];\n\n currentNodes = untrack(() => mountBranch(branch, parent, endMarker, (fn) => branchCleanups.push(fn)));\n currentCleanups = branchCleanups;\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n runAll(currentCleanups);\n removeNodes(currentNodes);\n endMarker.remove();\n });\n });\n}\n"],"mappings":"uQAYA,IAAM,EAAgB,2CAEhB,GACJ,EACA,EACA,EACA,IACW,EAAO,MAAM,EAAQ,EAAc,CAAe,EAc/D,SAAgB,EACd,EACA,EACA,EACiB,CAiBjB,OAhBI,OAAO,GAAc,YAAc,CAAC,EAAW,CAAS,EACnD,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAY,EAAO,EAAI,EAAQ,EAAM,EAAI,KAExD,GAAI,CAAC,GAAU,CAAC,EAAa,CAAM,EAAG,OAEtC,IAAM,EAAS,EAAO,WAEtB,EAAU,EAAQ,CAAa,EAE/B,IAAM,EAAQ,EAAY,EAAQ,EAAQ,EAAQ,CAAe,EAEjE,MAAsB,EAAY,CAAK,CAAC,CAC1C,CAAC,EAGI,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAgB,OAAO,GAAc,WAAa,EAAS,CAA0B,EAAI,KACzF,EAAkB,GAAkB,EAEtC,GAAe,MAAsB,EAAc,QAAQ,CAAC,EAEhE,IAAM,EAAS,EAAO,WAEtB,EAAU,EAAQ,CAAa,EAE/B,IAAM,EAAY,SAAS,cAAc,UAAU,EAEnD,EAAO,aAAa,EAAW,EAAO,WAAW,EAEjD,IAAI,EAAuB,CAAC,EACxB,EAAkC,CAAC,EAEjC,EAAM,MAAgB,CAC1B,IAAM,EAAO,EAAgB,MAE7B,EAAO,CAAe,EACtB,EAAY,CAAY,EACxB,EAAkB,CAAC,EACnB,EAAe,CAAC,EAEhB,IAAM,EAAS,EAAO,EAAO,EAAI,EAAQ,EAAM,EAAI,KAEnD,GAAI,CAAC,GAAU,CAAC,EAAa,CAAM,EAAG,OAEtC,IAAM,EAAiC,CAAC,EAExC,EAAe,MAAc,EAAY,EAAQ,EAAQ,EAAY,GAAO,EAAe,KAAK,CAAE,CAAC,CAAC,EACpG,EAAkB,CACpB,CAAC,EAED,MAAsB,EAAI,QAAQ,CAAC,EACnC,MAAsB,CACpB,EAAO,CAAe,EACtB,EAAY,CAAY,EACxB,EAAU,OAAO,CACnB,CAAC,CACH,CAAC,CACH"}
package/dist/errors.cjs CHANGED
@@ -1,3 +1,3 @@
1
- const e=require("./_dev.cjs");var t=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},n=class extends t{constructor(e){super(e)}},r=class extends t{component;phase;constructor(e,t){super(e,{cause:t.cause}),this.component=t.component,this.phase=t.phase}};function i(t,n){e.error(`<${t.component}> setup error (phase: ${t.phase}):`,t.cause),n.dispatchEvent(new CustomEvent(`ore:error`,{bubbles:!0,composed:!0,detail:t}))}var a=class extends t{},o={defineDuplicate:e=>`define('${e}') called twice — custom element already registered`,defineFieldRequiresFormAssociated:e=>`useField() requires define('${e}', { formAssociated: true })`,defineRequiresTag:`define() requires a tag name`,eachDuplicateKey:(e,t)=>`each() received duplicate key "${e}" at index ${t}`,injectStrictFailed:(e,t)=>`injectStrict() could not resolve key "${e}" in <${t}>`,lifecycleOutsideSetup:`Lifecycle hooks must be called during component setup`,propInvalidReflect:`Structured props cannot use reflect:true — use prop.json() with reflect:false`,validationFailed:(e,t)=>`Validation failed for <${e}>:\n${t.join(`
2
- `)}`};exports.ORE_ERRORS=o,exports.OreApiError=n,exports.OreError=t,exports.OreLifecycleError=r,exports.OreTimeoutError=a,exports.reportRuntimeError=i;
1
+ const e=require("./_dev.cjs");var t=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},n=class extends t{constructor(e){super(e)}},r=class extends t{constructor(e){super(e)}},i=class extends t{component;phase;constructor(e,t){super(e,{cause:t.cause}),this.component=t.component,this.phase=t.phase}};function a(t,n){e.error(`<${t.component}> setup error (phase: ${t.phase}):`,t.cause),n.dispatchEvent(new CustomEvent(`ore:error`,{bubbles:!0,composed:!0,detail:t}))}var o=class extends t{},s={defineDuplicate:e=>`define('${e}') called twice — custom element already registered`,defineFieldRequiresFormAssociated:e=>`useField() requires define('${e}', { formAssociated: true })`,defineRequiresTag:`define() requires a tag name`,eachDuplicateKey:(e,t)=>`each() received duplicate key "${e}" at index ${t}`,injectStrictFailed:(e,t)=>`injectStrict() could not resolve key "${e}" in <${t}>`,invalidDynamicTagName:e=>`html\`...\`: dynamic tag name "${e}" is not a valid HTML element name`,invariantViolated:e=>`invariant violated: ${e}`,lifecycleOutsideSetup:`Lifecycle hooks must be called during component setup`,propInvalidReflect:`Structured props cannot use reflect:true — use prop.json() with reflect:false`,validationFailed:(e,t)=>`Validation failed for <${e}>:\n${t.join(`
2
+ `)}`};function c(e,t){if(!e)throw new r(s.invariantViolated(t))}exports.ORE_ERRORS=s,exports.OreApiError=n,exports.OreError=t,exports.OreInternalError=r,exports.OreLifecycleError=i,exports.OreTimeoutError=o,exports.invariant=c,exports.reportRuntimeError=a;
3
3
  //# sourceMappingURL=errors.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import { error as logError } from './_dev';\n\n// ─── Structured error types ───────────────────────────────────────────────────\n\n/** Base class for all Ore errors. Use `instanceof OreError` to catch any Ore-originated error. */\nexport class OreError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is OreError {\n return err instanceof OreError;\n }\n}\n\n/** Thrown when Ore API is called incorrectly (e.g. outside setup, duplicate define, invalid prop). */\nexport class OreApiError extends OreError {\n constructor(message: string) {\n super(message);\n }\n}\n\n/**\n * The phase in which a component error occurred.\n * - `'setup'` — synchronous setup() threw\n * - `'async-setup'` — async setup() promise rejected\n * - `'mounted'` — an onMounted callback threw\n */\nexport type OreErrorPhase = 'async-setup' | 'mounted' | 'setup';\n\n/**\n * Structured error thrown by the Ore runtime when component setup fails.\n * Provides component name and original cause for debugging.\n */\nexport class OreLifecycleError extends OreError {\n readonly component: string;\n readonly phase: OreErrorPhase;\n\n constructor(message: string, options: { cause: Error; component: string; phase: OreErrorPhase }) {\n super(message, { cause: options.cause });\n this.component = options.component;\n this.phase = options.phase;\n }\n}\n\n/**\n * Report a runtime error via the ore:error event and console.\n */\nexport function reportRuntimeError(error: OreLifecycleError, element: HTMLElement): void {\n logError(`<${error.component}> setup error (phase: ${error.phase}):`, error.cause);\n\n element.dispatchEvent(\n new CustomEvent('ore:error', {\n bubbles: true,\n composed: true,\n detail: error,\n }),\n );\n}\n\n// ─── Error message constants ─────────────────────────────────────────────────\n\n/** Thrown by `waitFor` and `waitForEvent` in the testing sub-path when a condition is not met within the timeout. */\nexport class OreTimeoutError extends OreError {}\n\nexport const ORE_ERRORS = {\n defineDuplicate: (tag: string): string => `define('${tag}') called twice — custom element already registered`,\n defineFieldRequiresFormAssociated: (tag: string): string =>\n `useField() requires define('${tag}', { formAssociated: true })`,\n defineRequiresTag: 'define() requires a tag name',\n eachDuplicateKey: (key: string, index: number): string => `each() received duplicate key \"${key}\" at index ${index}`,\n injectStrictFailed: (key: string, tag: string): string => `injectStrict() could not resolve key \"${key}\" in <${tag}>`,\n lifecycleOutsideSetup: 'Lifecycle hooks must be called during component setup',\n propInvalidReflect: 'Structured props cannot use reflect:true — use prop.json() with reflect:false',\n validationFailed: (tag: string, errors: string[]): string => `Validation failed for <${tag}>:\\n${errors.join('\\n')}`,\n} as const;\n"],"mappings":"8BAKA,IAAa,EAAb,MAAa,UAAiB,KAAM,CAClC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,IAAI,OAAO,KACvB,OAAO,eAAe,KAAM,IAAI,OAAO,SAAS,CAClD,CAEA,OAAO,GAAG,EAA+B,CACvC,OAAO,aAAe,CACxB,CACF,EAGa,EAAb,cAAiC,CAAS,CACxC,YAAY,EAAiB,CAC3B,MAAM,CAAO,CACf,CACF,EAca,EAAb,cAAuC,CAAS,CAC9C,UACA,MAEA,YAAY,EAAiB,EAAoE,CAC/F,MAAM,EAAS,CAAE,MAAO,EAAQ,KAAM,CAAC,EACvC,KAAK,UAAY,EAAQ,UACzB,KAAK,MAAQ,EAAQ,KACvB,CACF,EAKA,SAAgB,EAAmB,EAA0B,EAA4B,CACvF,EAAA,MAAS,IAAI,EAAM,UAAU,wBAAwB,EAAM,MAAM,IAAK,EAAM,KAAK,EAEjF,EAAQ,cACN,IAAI,YAAY,YAAa,CAC3B,QAAS,GACT,SAAU,GACV,OAAQ,CACV,CAAC,CACH,CACF,CAKA,IAAa,EAAb,cAAqC,CAAS,CAAC,EAElC,EAAa,CACxB,gBAAkB,GAAwB,WAAW,EAAI,qDACzD,kCAAoC,GAClC,+BAA+B,EAAI,8BACrC,kBAAmB,+BACnB,kBAAmB,EAAa,IAA0B,kCAAkC,EAAI,aAAa,IAC7G,oBAAqB,EAAa,IAAwB,yCAAyC,EAAI,QAAQ,EAAI,GACnH,sBAAuB,wDACvB,mBAAoB,gFACpB,kBAAmB,EAAa,IAA6B,0BAA0B,EAAI,MAAM,EAAO,KAAK;CAAI,GACnH"}
1
+ {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import { error as logError } from './_dev';\n\n// ─── Structured error types ───────────────────────────────────────────────────\n\n/** Base class for all Ore errors. Use `instanceof OreError` to catch any Ore-originated error. */\nexport class OreError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is OreError {\n return err instanceof OreError;\n }\n}\n\n/** Thrown when Ore API is called incorrectly (e.g. outside setup, duplicate define, invalid prop). */\nexport class OreApiError extends OreError {\n constructor(message: string) {\n super(message);\n }\n}\n\n/**\n * Thrown when an internal invariant fails — e.g. compiled template metadata no\n * longer matching the DOM it was cloned from. Distinct from `OreApiError`: this\n * is never the caller's fault, it signals a bug in ore itself. See `invariant()`.\n */\nexport class OreInternalError extends OreError {\n constructor(message: string) {\n super(message);\n }\n}\n\n/**\n * The phase in which a component error occurred.\n * - `'setup'` — synchronous setup() threw\n * - `'async-setup'` — async setup() promise rejected\n * - `'mounted'` — an onMounted callback threw\n * - `'form-reset'` — an onFormReset callback threw\n */\nexport type OreErrorPhase = 'async-setup' | 'form-reset' | 'mounted' | 'setup';\n\n/**\n * Structured error thrown by the Ore runtime when component setup fails.\n * Provides component name and original cause for debugging.\n */\nexport class OreLifecycleError extends OreError {\n readonly component: string;\n readonly phase: OreErrorPhase;\n\n constructor(message: string, options: { cause: Error; component: string; phase: OreErrorPhase }) {\n super(message, { cause: options.cause });\n this.component = options.component;\n this.phase = options.phase;\n }\n}\n\n/**\n * Report a runtime error via the ore:error event and console.\n */\nexport function reportRuntimeError(error: OreLifecycleError, element: HTMLElement): void {\n logError(`<${error.component}> setup error (phase: ${error.phase}):`, error.cause);\n\n element.dispatchEvent(\n new CustomEvent('ore:error', {\n bubbles: true,\n composed: true,\n detail: error,\n }),\n );\n}\n\n// ─── Error message constants ─────────────────────────────────────────────────\n\n/** Thrown by `waitFor` and `waitForEvent` in the testing sub-path when a condition is not met within the timeout. */\nexport class OreTimeoutError extends OreError {}\n\nexport const ORE_ERRORS = {\n defineDuplicate: (tag: string): string => `define('${tag}') called twice — custom element already registered`,\n defineFieldRequiresFormAssociated: (tag: string): string =>\n `useField() requires define('${tag}', { formAssociated: true })`,\n defineRequiresTag: 'define() requires a tag name',\n eachDuplicateKey: (key: string, index: number): string => `each() received duplicate key \"${key}\" at index ${index}`,\n injectStrictFailed: (key: string, tag: string): string => `injectStrict() could not resolve key \"${key}\" in <${tag}>`,\n invalidDynamicTagName: (tagName: string): string =>\n `html\\`...\\`: dynamic tag name \"${tagName}\" is not a valid HTML element name`,\n invariantViolated: (message: string): string => `invariant violated: ${message}`,\n lifecycleOutsideSetup: 'Lifecycle hooks must be called during component setup',\n propInvalidReflect: 'Structured props cannot use reflect:true — use prop.json() with reflect:false',\n validationFailed: (tag: string, errors: string[]): string => `Validation failed for <${tag}>:\\n${errors.join('\\n')}`,\n} as const;\n\n/**\n * Assert an internal invariant that must always hold — e.g. compiled template\n * metadata staying in sync with the DOM it was cloned from. A failed invariant\n * means a bug in ore itself, never user input, so it throws `OreInternalError`\n * unconditionally (every build, never gated like `_dev.ts`'s `warn()`).\n *\n * Narrowing caveat: `asserts condition` only narrows the exact expression\n * passed in. Assign to a local `const` first — `invariant(el.parentNode, msg)`\n * does not narrow later reads of `el.parentNode`.\n */\nexport function invariant(condition: unknown, message: string): asserts condition {\n if (!condition) throw new OreInternalError(ORE_ERRORS.invariantViolated(message));\n}\n"],"mappings":"8BAKA,IAAa,EAAb,MAAa,UAAiB,KAAM,CAClC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,IAAI,OAAO,KACvB,OAAO,eAAe,KAAM,IAAI,OAAO,SAAS,CAClD,CAEA,OAAO,GAAG,EAA+B,CACvC,OAAO,aAAe,CACxB,CACF,EAGa,EAAb,cAAiC,CAAS,CACxC,YAAY,EAAiB,CAC3B,MAAM,CAAO,CACf,CACF,EAOa,EAAb,cAAsC,CAAS,CAC7C,YAAY,EAAiB,CAC3B,MAAM,CAAO,CACf,CACF,EAea,EAAb,cAAuC,CAAS,CAC9C,UACA,MAEA,YAAY,EAAiB,EAAoE,CAC/F,MAAM,EAAS,CAAE,MAAO,EAAQ,KAAM,CAAC,EACvC,KAAK,UAAY,EAAQ,UACzB,KAAK,MAAQ,EAAQ,KACvB,CACF,EAKA,SAAgB,EAAmB,EAA0B,EAA4B,CACvF,EAAA,MAAS,IAAI,EAAM,UAAU,wBAAwB,EAAM,MAAM,IAAK,EAAM,KAAK,EAEjF,EAAQ,cACN,IAAI,YAAY,YAAa,CAC3B,QAAS,GACT,SAAU,GACV,OAAQ,CACV,CAAC,CACH,CACF,CAKA,IAAa,EAAb,cAAqC,CAAS,CAAC,EAElC,EAAa,CACxB,gBAAkB,GAAwB,WAAW,EAAI,qDACzD,kCAAoC,GAClC,+BAA+B,EAAI,8BACrC,kBAAmB,+BACnB,kBAAmB,EAAa,IAA0B,kCAAkC,EAAI,aAAa,IAC7G,oBAAqB,EAAa,IAAwB,yCAAyC,EAAI,QAAQ,EAAI,GACnH,sBAAwB,GACtB,kCAAkC,EAAQ,oCAC5C,kBAAoB,GAA4B,uBAAuB,IACvE,sBAAuB,wDACvB,mBAAoB,gFACpB,kBAAmB,EAAa,IAA6B,0BAA0B,EAAI,MAAM,EAAO,KAAK;CAAI,GACnH,EAYA,SAAgB,EAAU,EAAoB,EAAoC,CAChF,GAAI,CAAC,EAAW,MAAM,IAAI,EAAiB,EAAW,kBAAkB,CAAO,CAAC,CAClF"}