@v-ibe/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +40 -0
  3. package/dist/DI/__tests__/scoped-container-dependencies.test.d.ts +1 -0
  4. package/dist/DI/bootstrap.d.ts +18 -0
  5. package/dist/DI/decorators/inject.d.ts +37 -0
  6. package/dist/DI/decorators/inject.js +45 -0
  7. package/dist/DI/decorators/service.d.ts +24 -0
  8. package/dist/DI/decorators/service.js +13 -0
  9. package/dist/DI/di-container.d.ts +53 -0
  10. package/dist/DI/di-container.js +158 -0
  11. package/dist/DI/lifecycle.d.ts +37 -0
  12. package/dist/DI/lifecycle.js +6 -0
  13. package/dist/DI/scoped-container.d.ts +68 -0
  14. package/dist/DI/scoped-container.js +193 -0
  15. package/dist/DI/service-metadata.d.ts +32 -0
  16. package/dist/DI/service-metadata.js +31 -0
  17. package/dist/DI/types.d.ts +4 -0
  18. package/dist/behaviors/__tests__/behavior-system.test.d.ts +1 -0
  19. package/dist/behaviors/behavior-manager.d.ts +60 -0
  20. package/dist/behaviors/behavior-manager.js +131 -0
  21. package/dist/behaviors/behavior-registry.d.ts +68 -0
  22. package/dist/behaviors/behavior-registry.js +105 -0
  23. package/dist/behaviors/constants.d.ts +16 -0
  24. package/dist/behaviors/constants.js +8 -0
  25. package/dist/behaviors/decorators.d.ts +87 -0
  26. package/dist/behaviors/decorators.js +46 -0
  27. package/dist/behaviors/index.d.ts +4 -0
  28. package/dist/components/__tests__/host.test.d.ts +1 -0
  29. package/dist/components/app-tree.d.ts +49 -0
  30. package/dist/components/app-tree.js +122 -0
  31. package/dist/components/base-component.d.ts +85 -0
  32. package/dist/components/base-component.js +438 -0
  33. package/dist/components/decorators/component.d.ts +27 -0
  34. package/dist/components/decorators/component.js +47 -0
  35. package/dist/components/decorators/prop.d.ts +14 -0
  36. package/dist/components/decorators/prop.js +37 -0
  37. package/dist/components/types.d.ts +26 -0
  38. package/dist/core.d.ts +23 -0
  39. package/dist/core.js +8 -0
  40. package/dist/custom-components/__tests__/for.test.d.ts +1 -0
  41. package/dist/custom-components/__tests__/show.test.d.ts +1 -0
  42. package/dist/custom-components/for.d.ts +58 -0
  43. package/dist/custom-components/for.js +313 -0
  44. package/dist/custom-components/index.d.ts +2 -0
  45. package/dist/custom-components/show.d.ts +78 -0
  46. package/dist/custom-components/show.js +88 -0
  47. package/dist/data-management/cache/cache-invalidate.decorator.d.ts +35 -0
  48. package/dist/data-management/cache/cache-invalidate.decorator.js +21 -0
  49. package/dist/data-management/cache/cache-metadata.d.ts +15 -0
  50. package/dist/data-management/cache/cache-provider.interface.d.ts +67 -0
  51. package/dist/data-management/cache/cache-tags.decorator.d.ts +52 -0
  52. package/dist/data-management/cache/cache-tags.decorator.js +13 -0
  53. package/dist/data-management/cache/cache-update.decorator.d.ts +28 -0
  54. package/dist/data-management/cache/cache-update.decorator.js +21 -0
  55. package/dist/data-management/cache/cache.decorator.d.ts +28 -0
  56. package/dist/data-management/cache/cache.decorator.js +13 -0
  57. package/dist/data-management/cache/index.d.ts +11 -0
  58. package/dist/data-management/cache/local-storage-cache.d.ts +40 -0
  59. package/dist/data-management/cache/local-storage-cache.js +268 -0
  60. package/dist/data-management/cache/memory-cache.d.ts +37 -0
  61. package/dist/data-management/cache/memory-cache.js +149 -0
  62. package/dist/data-management/cache/session-storage-cache.d.ts +35 -0
  63. package/dist/data-management/cache/session-storage-cache.js +242 -0
  64. package/dist/data-management/cache/ttl.decorator.d.ts +31 -0
  65. package/dist/data-management/cache/ttl.decorator.js +34 -0
  66. package/dist/data-management/decorators/consume.d.ts +29 -0
  67. package/dist/data-management/decorators/consume.js +28 -0
  68. package/dist/data-management/decorators/id.d.ts +28 -0
  69. package/dist/data-management/decorators/id.js +19 -0
  70. package/dist/data-management/decorators/model.d.ts +48 -0
  71. package/dist/data-management/decorators/model.js +24 -0
  72. package/dist/data-management/decorators/prop.d.ts +43 -0
  73. package/dist/data-management/decorators/prop.js +32 -0
  74. package/dist/data-management/index.d.ts +13 -0
  75. package/dist/data-management/store/json-to-model.d.ts +45 -0
  76. package/dist/data-management/store/json-to-model.js +36 -0
  77. package/dist/data-management/store/store.d.ts +108 -0
  78. package/dist/data-management/store/store.js +207 -0
  79. package/dist/data-management/store/types.d.ts +53 -0
  80. package/dist/events-handler/decorators/emit.d.ts +29 -0
  81. package/dist/events-handler/decorators/emit.js +51 -0
  82. package/dist/events-handler/event-decorators.d.ts +1 -0
  83. package/dist/events-handler/event-emitter.service.d.ts +21 -0
  84. package/dist/events-handler/event-emitter.service.js +85 -0
  85. package/dist/events-handler/event-types.d.ts +12 -0
  86. package/dist/index.d.ts +55 -0
  87. package/dist/index.js +121 -0
  88. package/dist/jsx/dynamic/__tests__/granular-array-renderer.test.d.ts +1 -0
  89. package/dist/jsx/dynamic/__tests__/jsx-array-rendering.test.d.ts +1 -0
  90. package/dist/jsx/dynamic/array-renderer.d.ts +2 -0
  91. package/dist/jsx/dynamic/array-renderer.js +133 -0
  92. package/dist/jsx/dynamic/child-renderer.d.ts +1 -0
  93. package/dist/jsx/dynamic/child-renderer.js +180 -0
  94. package/dist/jsx/dynamic/dom-utils.d.ts +5 -0
  95. package/dist/jsx/dynamic/dom-utils.js +22 -0
  96. package/dist/jsx/dynamic/granular-array-renderer.d.ts +16 -0
  97. package/dist/jsx/dynamic/granular-array-renderer.js +153 -0
  98. package/dist/jsx/dynamic/node-renderer.d.ts +2 -0
  99. package/dist/jsx/dynamic/props-handler.d.ts +3 -0
  100. package/dist/jsx/dynamic/props-handler.js +281 -0
  101. package/dist/jsx/dynamic/text-renderer.d.ts +2 -0
  102. package/dist/jsx/jsx-dev-runtime.d.ts +2 -0
  103. package/dist/jsx/jsx-runtime.d.ts +3 -0
  104. package/dist/jsx/types.d.ts +35 -0
  105. package/dist/jsx/types.js +4 -0
  106. package/dist/jsx-dev-runtime.d.ts +2 -0
  107. package/dist/jsx-dev-runtime.js +8 -0
  108. package/dist/jsx-runtime.d.ts +2 -0
  109. package/dist/jsx-runtime.js +11 -0
  110. package/dist/reactivity/__tests__/context-stack.test.d.ts +1 -0
  111. package/dist/reactivity/__tests__/nested-effects-untrack.test.d.ts +22 -0
  112. package/dist/reactivity/context-scope.d.ts +57 -0
  113. package/dist/reactivity/context-scope.js +35 -0
  114. package/dist/reactivity/decorators/__tests__/ctx-integration.test.d.ts +5 -0
  115. package/dist/reactivity/decorators/__tests__/ctx-loop.test.d.ts +10 -0
  116. package/dist/reactivity/decorators/__tests__/state-intelligent.test.d.ts +1 -0
  117. package/dist/reactivity/decorators/computed.d.ts +6 -0
  118. package/dist/reactivity/decorators/computed.js +17 -0
  119. package/dist/reactivity/decorators/create-event-decorator.d.ts +5 -0
  120. package/dist/reactivity/decorators/create-event-decorator.js +28 -0
  121. package/dist/reactivity/decorators/ctx.d.ts +9 -0
  122. package/dist/reactivity/decorators/ctx.js +91 -0
  123. package/dist/reactivity/decorators/effect.d.ts +9 -0
  124. package/dist/reactivity/decorators/effect.js +24 -0
  125. package/dist/reactivity/decorators/resource.d.ts +48 -0
  126. package/dist/reactivity/decorators/resource.js +20 -0
  127. package/dist/reactivity/decorators/state.d.ts +8 -0
  128. package/dist/reactivity/decorators/state.js +68 -0
  129. package/dist/reactivity/decorators/store.d.ts +6 -0
  130. package/dist/reactivity/decorators/store.js +25 -0
  131. package/dist/reactivity/phase-scheduler.d.ts +81 -0
  132. package/dist/reactivity/phase-scheduler.js +88 -0
  133. package/dist/reactivity/phase-scheduler.test.d.ts +1 -0
  134. package/dist/reactivity/reactive-cache.d.ts +21 -0
  135. package/dist/reactivity/reactive-cache.js +31 -0
  136. package/dist/reactivity/reactive-cache.test.d.ts +1 -0
  137. package/dist/reactivity/reactive-context.d.ts +152 -0
  138. package/dist/reactivity/reactive-context.js +184 -0
  139. package/dist/reactivity/signals/__tests__/composicion-automatica.test.d.ts +1 -0
  140. package/dist/reactivity/signals/__tests__/composite/nivel-1-estructura-basica.test.d.ts +1 -0
  141. package/dist/reactivity/signals/__tests__/composite/nivel-2-registro-subscribers.test.d.ts +1 -0
  142. package/dist/reactivity/signals/__tests__/composite/nivel-3-notificaciones-basicas.test.d.ts +1 -0
  143. package/dist/reactivity/signals/__tests__/composite/nivel-4-comparacion-valores.test.d.ts +1 -0
  144. package/dist/reactivity/signals/__tests__/composite/nivel-5-tracking-automatico.test.d.ts +1 -0
  145. package/dist/reactivity/signals/__tests__/composite/nivel-6-anti-glitch.test.d.ts +1 -0
  146. package/dist/reactivity/signals/__tests__/composite/nivel-7-objetos-anidados.test.d.ts +1 -0
  147. package/dist/reactivity/signals/__tests__/composite/nivel-8-observable-array-support.test.d.ts +1 -0
  148. package/dist/reactivity/signals/__tests__/composite-shallow-tracking.test.d.ts +1 -0
  149. package/dist/reactivity/signals/__tests__/effect.test.d.ts +1 -0
  150. package/dist/reactivity/signals/__tests__/reactive-array/nivel-1-estructura-basica.test.d.ts +1 -0
  151. package/dist/reactivity/signals/__tests__/reactive-array/nivel-2-metodos-mutadores.test.d.ts +1 -0
  152. package/dist/reactivity/signals/__tests__/reactive-array/nivel-3-tracking-por-indice.test.d.ts +1 -0
  153. package/dist/reactivity/signals/__tests__/reactive-array/nivel-4-tracking-length.test.d.ts +1 -0
  154. package/dist/reactivity/signals/__tests__/reactive-array/nivel-5-tracking-mutation.test.d.ts +1 -0
  155. package/dist/reactivity/signals/__tests__/reactive-array/nivel-6-metodos-no-mutadores.test.d.ts +1 -0
  156. package/dist/reactivity/signals/__tests__/reactive-array/nivel-7-composicion-bidireccional.test.d.ts +1 -0
  157. package/dist/reactivity/signals/__tests__/reactive-array/nivel-8-proxies.test.d.ts +1 -0
  158. package/dist/reactivity/signals/__tests__/reactive-array/nivel-9-derived-cache-optimization.test.d.ts +1 -0
  159. package/dist/reactivity/signals/__tests__/resource.test.d.ts +1 -0
  160. package/dist/reactivity/signals/__tests__/signal.test.d.ts +1 -0
  161. package/dist/reactivity/signals/array-strategies.d.ts +120 -0
  162. package/dist/reactivity/signals/array-strategies.js +261 -0
  163. package/dist/reactivity/signals/composite.d.ts +89 -0
  164. package/dist/reactivity/signals/composite.js +145 -0
  165. package/dist/reactivity/signals/computed.d.ts +61 -0
  166. package/dist/reactivity/signals/computed.js +107 -0
  167. package/dist/reactivity/signals/computed.test.d.ts +1 -0
  168. package/dist/reactivity/signals/derived.d.ts +10 -0
  169. package/dist/reactivity/signals/derived.js +24 -0
  170. package/dist/reactivity/signals/effect.d.ts +27 -0
  171. package/dist/reactivity/signals/effect.js +46 -0
  172. package/dist/reactivity/signals/event.d.ts +9 -0
  173. package/dist/reactivity/signals/event.js +15 -0
  174. package/dist/reactivity/signals/reactive-array.d.ts +133 -0
  175. package/dist/reactivity/signals/reactive-array.js +490 -0
  176. package/dist/reactivity/signals/reactive-proxy.d.ts +54 -0
  177. package/dist/reactivity/signals/reactive-proxy.js +299 -0
  178. package/dist/reactivity/signals/reactive-tracking.test.d.ts +1 -0
  179. package/dist/reactivity/signals/resource.d.ts +9 -0
  180. package/dist/reactivity/signals/resource.js +58 -0
  181. package/dist/reactivity/signals/signal.d.ts +39 -0
  182. package/dist/reactivity/signals/signal.js +56 -0
  183. package/dist/reactivity/signals/subscription-management.test.d.ts +1 -0
  184. package/dist/reactivity/types.d.ts +12 -0
  185. package/dist/router/__tests__/link-behavior-active-class.test.d.ts +1 -0
  186. package/dist/router/__tests__/loop-detector.test.d.ts +1 -0
  187. package/dist/router/__tests__/params-container-resolution.test.d.ts +1 -0
  188. package/dist/router/__tests__/router-generated-routes.test.d.ts +1 -0
  189. package/dist/router/__tests__/router-params-granular.test.d.ts +1 -0
  190. package/dist/router/__tests__/router-params-simple.test.d.ts +1 -0
  191. package/dist/router/__tests__/router-query-params.test.d.ts +1 -0
  192. package/dist/router/__tests__/router-route-candidates.test.d.ts +1 -0
  193. package/dist/router/__tests__/routeview-app-articles.test.d.ts +1 -0
  194. package/dist/router/__tests__/routeview-debug.test.d.ts +1 -0
  195. package/dist/router/__tests__/routeview-integration.test.d.ts +1 -0
  196. package/dist/router/__tests__/routeview-this.test.d.ts +1 -0
  197. package/dist/router/decorators/base-policy.d.ts +141 -0
  198. package/dist/router/decorators/base-policy.js +63 -0
  199. package/dist/router/decorators/index.d.ts +6 -0
  200. package/dist/router/decorators/params.d.ts +31 -0
  201. package/dist/router/decorators/params.js +97 -0
  202. package/dist/router/decorators/route-metadata.d.ts +11 -0
  203. package/dist/router/decorators/route-metadata.js +23 -0
  204. package/dist/router/decorators/route.d.ts +39 -0
  205. package/dist/router/decorators/route.js +7 -0
  206. package/dist/router/link.behavior.d.ts +87 -0
  207. package/dist/router/link.behavior.js +227 -0
  208. package/dist/router/policy-evaluator.d.ts +81 -0
  209. package/dist/router/policy-evaluator.js +209 -0
  210. package/dist/router/route-view.d.ts +56 -0
  211. package/dist/router/route-view.js +156 -0
  212. package/dist/router/router.d.ts +67 -0
  213. package/dist/router/router.js +308 -0
  214. package/dist/router/static-analysis/index.d.ts +37 -0
  215. package/dist/router/static-analysis/parser.d.ts +14 -0
  216. package/dist/router/static-analysis/parser.js +147 -0
  217. package/dist/router/static-analysis/scanner.d.ts +27 -0
  218. package/dist/router/static-analysis/scanner.js +91 -0
  219. package/dist/router/trie.d.ts +14 -0
  220. package/dist/router/trie.js +126 -0
  221. package/dist/router/trie.types.d.ts +36 -0
  222. package/dist/styles/base-style-sheet.d.ts +96 -0
  223. package/dist/styles/base-style-sheet.js +149 -0
  224. package/dist/styles/decorators/factories.d.ts +76 -0
  225. package/dist/styles/decorators/factories.js +11 -0
  226. package/dist/styles/decorators/keyframes.d.ts +238 -0
  227. package/dist/styles/decorators/keyframes.js +79 -0
  228. package/dist/styles/decorators/rule.d.ts +177 -0
  229. package/dist/styles/decorators/rule.js +72 -0
  230. package/dist/styles/decorators/scope.d.ts +66 -0
  231. package/dist/styles/decorators/scope.js +17 -0
  232. package/dist/styles/decorators/style.d.ts +1 -0
  233. package/dist/styles/decorators/style.js +20 -0
  234. package/dist/styles/decorators/useStyles.d.ts +5 -0
  235. package/dist/styles/decorators/useStyles.js +29 -0
  236. package/dist/styles/global-styles-registry.d.ts +72 -0
  237. package/dist/styles/global-styles-registry.js +155 -0
  238. package/dist/types.d.ts +1 -0
  239. package/dist/vite-plugins/__tests__/jsx-control-flow-transform.test.d.ts +1 -0
  240. package/dist/vite-plugins/index.d.ts +4 -0
  241. package/dist/vite-plugins/index.js +10 -0
  242. package/dist/vite-plugins/jsx-contextual.d.ts +7 -0
  243. package/dist/vite-plugins/jsx-contextual.js +53 -0
  244. package/dist/vite-plugins/jsx-control-flow-transform.d.ts +60 -0
  245. package/dist/vite-plugins/jsx-control-flow-transform.js +180 -0
  246. package/dist/vite-plugins/jsx-signals.d.ts +2 -0
  247. package/dist/vite-plugins/jsx-signals.js +124 -0
  248. package/dist/vite-plugins/router/route-generator-plugin.d.ts +63 -0
  249. package/dist/vite-plugins/router/route-generator-plugin.js +310 -0
  250. package/package.json +85 -0
@@ -0,0 +1,438 @@
1
+ import { RESOURCE_PROPERTY_KEYS } from "../reactivity/decorators/resource.js";
2
+ import { reactiveContext } from "../reactivity/reactive-context.js";
3
+ import { createResource } from "../reactivity/signals/resource.js";
4
+ import { AppTree } from "./app-tree.js";
5
+ import { bindProps } from "../jsx/dynamic/props-handler.js";
6
+ import { renderChild } from "../jsx/dynamic/child-renderer.js";
7
+ import { Fragment } from "../jsx/types.js";
8
+ import { globalStylesheets } from "../styles/global-styles-registry.js";
9
+ import { BehaviorManager } from "../behaviors/behavior-manager.js";
10
+ import { ScopedContainer } from "../DI/scoped-container.js";
11
+ import { getServiceMetadata } from "../DI/service-metadata.js";
12
+ class BaseComponent extends HTMLElement {
13
+ constructor() {
14
+ super();
15
+ this.#isInitialized = false;
16
+ this.#globalStylesheetIds = [];
17
+ this.#documentStylesheetIds = [];
18
+ this._pendingContextInitializers = [];
19
+ this._pendingEffects = [];
20
+ this.behaviorManager = new BehaviorManager(this);
21
+ const metadata = AppTree.getMetadata(this.constructor);
22
+ const useShadowDOM = metadata?.useShadowDOM !== false;
23
+ if (useShadowDOM) {
24
+ this.attachShadow({ mode: "open" });
25
+ }
26
+ }
27
+ #isInitialized;
28
+ #globalStylesheetIds;
29
+ #documentStylesheetIds;
30
+ /**
31
+ * Obtiene el root donde se renderizan los elementos.
32
+ * Puede ser shadowRoot o el elemento mismo si no usa shadow DOM.
33
+ */
34
+ get renderRoot() {
35
+ return this.shadowRoot || this;
36
+ }
37
+ /**
38
+ * Registra un efecto pendiente que se ejecutará después de la inicialización
39
+ * Usado por el decorador @Effect para diferir la ejecución
40
+ */
41
+ queueEffect(effectFn) {
42
+ if (this.#isInitialized) {
43
+ queueMicrotask(effectFn);
44
+ return;
45
+ }
46
+ if (!this._pendingEffects) {
47
+ this._pendingEffects = [];
48
+ }
49
+ this._pendingEffects.push(effectFn);
50
+ }
51
+ /**
52
+ * Ejecuta todos los efectos pendientes
53
+ * Se llama al final de initializeForJSX()
54
+ */
55
+ flushPendingEffects() {
56
+ if (this._pendingEffects && this._pendingEffects.length > 0) {
57
+ const effects = this._pendingEffects;
58
+ this._pendingEffects = [];
59
+ effects.forEach((effectFn) => {
60
+ queueMicrotask(effectFn);
61
+ });
62
+ }
63
+ }
64
+ // Inicialización controlada por JSX
65
+ initializeForJSX() {
66
+ if (this.#isInitialized) {
67
+ return;
68
+ }
69
+ reactiveContext.untrack(() => {
70
+ this.registerSharedStylesheetsIfNeeded();
71
+ this.registerDocumentStylesIfNeeded();
72
+ this.adoptSharedStylesheets();
73
+ this.adoptLocalStylesheet();
74
+ this.initializeContexts();
75
+ this.initializeResources();
76
+ if (typeof this.onInit === "function") {
77
+ this.onInit();
78
+ }
79
+ });
80
+ this.#isInitialized = true;
81
+ this.flushPendingEffects();
82
+ }
83
+ connectedCallback() {
84
+ if (this.#isInitialized) {
85
+ if (typeof this.onConnected === "function") {
86
+ this.onConnected();
87
+ }
88
+ return;
89
+ }
90
+ this.init().catch((error) => {
91
+ console.error("[BaseComponent] Error durante inicialización:", error);
92
+ this.renderError(error);
93
+ });
94
+ }
95
+ /**
96
+ * Bootstrap services declared in @Component({ services: [...] })
97
+ * for a given node. Creates a ScopedContainer with parent chain resolution.
98
+ * Used by both init() (DOM path) and createAndRenderComponent() (JSX path).
99
+ */
100
+ static bootstrapServicesForNode(node, metadata, sync = false) {
101
+ if (!metadata.services?.length) return;
102
+ const parentContainer = node.parent ? AppTree.findContainerFor(node.parent) : void 0;
103
+ const container = new ScopedContainer(parentContainer);
104
+ for (const ServiceClass of metadata.services) {
105
+ container.register(ServiceClass);
106
+ }
107
+ for (const ServiceClass of metadata.services) {
108
+ const serviceMeta = getServiceMetadata(ServiceClass);
109
+ if (serviceMeta) {
110
+ for (const dep of serviceMeta.dependencies) {
111
+ if (metadata.services.includes(dep)) {
112
+ container.registerDependency(ServiceClass, dep);
113
+ }
114
+ }
115
+ }
116
+ }
117
+ if (sync) {
118
+ container.bootstrapSync();
119
+ }
120
+ node.container = container;
121
+ }
122
+ /**
123
+ * Assign __container to a component instance.
124
+ * Uses the node's own container if it has one, otherwise walks up the tree.
125
+ */
126
+ static assignContainer(instance, node) {
127
+ instance.__container = node.container ?? AppTree.findContainerFor(node) ?? void 0;
128
+ }
129
+ /**
130
+ * Proceso de inicialización asíncrona del componente
131
+ * Incluye renderizado progresivo
132
+ */
133
+ async init() {
134
+ const parentNode = this.findParentNode();
135
+ this.appNode = AppTree.registerInstance(this, parentNode);
136
+ const metadata = AppTree.getMetadata(this.constructor);
137
+ if (metadata?.services?.length) {
138
+ BaseComponent.bootstrapServicesForNode(this.appNode, metadata);
139
+ await this.appNode.container.bootstrap();
140
+ }
141
+ BaseComponent.assignContainer(this, this.appNode);
142
+ this.initializeForJSX();
143
+ this.renderRoot.innerHTML = "";
144
+ if (typeof this.view === "function") {
145
+ const viewResult = this.view();
146
+ const isIterable = (value) => {
147
+ return value && typeof value === "object" && typeof value[Symbol.iterator] === "function";
148
+ };
149
+ if (viewResult instanceof Node) {
150
+ this.renderRoot.appendChild(viewResult);
151
+ } else if (isIterable(viewResult)) {
152
+ for (const child of viewResult) {
153
+ renderChild(this.renderRoot, child);
154
+ }
155
+ } else if (viewResult != null) {
156
+ renderChild(this.renderRoot, viewResult);
157
+ }
158
+ }
159
+ if (typeof this.onConnected === "function") {
160
+ this.onConnected();
161
+ }
162
+ this.#isInitialized = true;
163
+ }
164
+ /**
165
+ * Renderiza un estado de error si la inicialización falla
166
+ */
167
+ renderError(error) {
168
+ this.renderRoot.innerHTML = `
169
+ <div style="padding: 20px; border: 2px solid #ff4444; background: #fff5f5; border-radius: 4px; margin: 10px;">
170
+ <h3 style="margin: 0 0 10px 0; color: #ff4444;">❌ Error de Inicialización</h3>
171
+ <p style="margin: 0 0 10px 0; color: #333;">El componente <strong>${this.constructor.name}</strong> falló al inicializar.</p>
172
+ <pre style="background: #f5f5f5; padding: 10px; overflow: auto; font-size: 12px; border-radius: 3px; color: #333;">${error.stack || error.message || String(error)}</pre>
173
+ </div>
174
+ `;
175
+ }
176
+ /**
177
+ * Encuentra el nodo padre de este componente en el AppTree.
178
+ */
179
+ findParentNode() {
180
+ let currentElement = this.parentElement;
181
+ while (currentElement) {
182
+ if (currentElement instanceof BaseComponent) {
183
+ const parentNode = AppTree.findByInstance(currentElement);
184
+ if (parentNode) {
185
+ return parentNode;
186
+ }
187
+ if (currentElement.appNode) {
188
+ return currentElement.appNode;
189
+ }
190
+ }
191
+ if (currentElement instanceof ShadowRoot) {
192
+ currentElement = currentElement.host;
193
+ } else {
194
+ currentElement = currentElement.parentElement;
195
+ }
196
+ }
197
+ return void 0;
198
+ }
199
+ disconnectedCallback() {
200
+ if (this.appNode?.container) {
201
+ this.appNode.container.dispose();
202
+ }
203
+ if (this.#globalStylesheetIds.length > 0) {
204
+ globalStylesheets.unregister(this.#globalStylesheetIds);
205
+ this.#globalStylesheetIds = [];
206
+ }
207
+ if (this.#documentStylesheetIds.length > 0) {
208
+ globalStylesheets.unregisterDocumentStyles(this.#documentStylesheetIds);
209
+ this.#documentStylesheetIds = [];
210
+ }
211
+ if (this.appNode) {
212
+ AppTree.unregisterInstance(this.appNode);
213
+ }
214
+ this.behaviorManager.disconnectAll();
215
+ if (typeof this.onDisconnected === "function") {
216
+ this.onDisconnected();
217
+ }
218
+ }
219
+ /**
220
+ * Registra las stylesheets @Shared si este componente las declara.
221
+ */
222
+ registerSharedStylesheetsIfNeeded() {
223
+ const metadata = AppTree.getMetadata(
224
+ this.constructor
225
+ );
226
+ if (metadata?.sharedStylesClasses && metadata.sharedStylesClasses.length > 0) {
227
+ this.#globalStylesheetIds = globalStylesheets.registerShared(
228
+ metadata.sharedStylesClasses,
229
+ this
230
+ );
231
+ }
232
+ }
233
+ /**
234
+ * Registra las stylesheets @ForDocument si este componente las declara.
235
+ */
236
+ registerDocumentStylesIfNeeded() {
237
+ const metadata = AppTree.getMetadata(
238
+ this.constructor
239
+ );
240
+ if (metadata?.documentStylesClasses && metadata.documentStylesClasses.length > 0) {
241
+ this.#documentStylesheetIds = globalStylesheets.registerDocument(
242
+ metadata.documentStylesClasses,
243
+ this
244
+ );
245
+ }
246
+ }
247
+ /**
248
+ * Adopta todas las stylesheets @Shared registradas en el shadow root.
249
+ */
250
+ adoptSharedStylesheets() {
251
+ if (!this.shadowRoot) {
252
+ console.warn("Cannot adopt shared stylesheets: shadow root not available");
253
+ return;
254
+ }
255
+ const sharedSheets = globalStylesheets.getSharedStylesheets();
256
+ if (sharedSheets.length > 0) {
257
+ const existingSheets = this.shadowRoot.adoptedStyleSheets;
258
+ const existingArray = Array.from(existingSheets);
259
+ const sharedInExisting = sharedSheets.filter((ss) => existingArray.includes(ss));
260
+ if (sharedInExisting.length === sharedSheets.length) {
261
+ return;
262
+ }
263
+ const filteredExisting = existingArray.filter((sheet) => !sharedSheets.includes(sheet));
264
+ const newSheets = [...sharedSheets, ...filteredExisting];
265
+ this.shadowRoot.adoptedStyleSheets = newSheets;
266
+ }
267
+ }
268
+ /**
269
+ * Adopta las stylesheets LOCALES de este componente específico.
270
+ */
271
+ adoptLocalStylesheet() {
272
+ if (!this.shadowRoot) {
273
+ console.warn("Cannot adopt local stylesheet: shadow root not available");
274
+ return;
275
+ }
276
+ const metadata = AppTree.getMetadata(
277
+ this.constructor
278
+ );
279
+ if (metadata?.stylesClass) {
280
+ const stylesInstance = new metadata.stylesClass();
281
+ const stylesheet = stylesInstance.getStyleSheet();
282
+ this.shadowRoot.adoptedStyleSheets = [
283
+ ...this.shadowRoot.adoptedStyleSheets,
284
+ stylesheet
285
+ ];
286
+ stylesInstance.setHost(this);
287
+ }
288
+ }
289
+ initializeContexts() {
290
+ if (this._pendingContextInitializers) {
291
+ this._pendingContextInitializers.forEach((initializer) => {
292
+ initializer();
293
+ });
294
+ this._pendingContextInitializers = [];
295
+ }
296
+ }
297
+ initializeResources() {
298
+ const resourceInitializers = this.constructor[RESOURCE_PROPERTY_KEYS] || [];
299
+ for (const { key, source } of resourceInitializers) {
300
+ const resource = createResource(
301
+ (signal) => source.call(this, signal)
302
+ );
303
+ this[key] = resource;
304
+ }
305
+ }
306
+ jsx(type, props) {
307
+ if (type == null) {
308
+ return null;
309
+ }
310
+ if (type === Fragment) {
311
+ return props.children;
312
+ }
313
+ const { children, ...restProps } = props || {};
314
+ if (typeof type === "function" && type.prototype instanceof BaseComponent) {
315
+ return this.createAndRenderComponent(type, restProps, children);
316
+ }
317
+ if (typeof type === "function") {
318
+ const result = type({ ...restProps, children });
319
+ if (typeof result === "function") {
320
+ return result();
321
+ }
322
+ return result;
323
+ }
324
+ if (typeof type === "string") {
325
+ return this.createNativeElement(
326
+ type,
327
+ restProps,
328
+ ...this.normalizeChildren(children)
329
+ );
330
+ }
331
+ throw new Error(`Unknown component type: ${typeof type} - ${type}`);
332
+ }
333
+ jsxDEV(type, props) {
334
+ return this.jsx(type, props);
335
+ }
336
+ jsxs(type, props) {
337
+ return this.jsx(type, props);
338
+ }
339
+ /**
340
+ * Aplica className al host element del componente.
341
+ */
342
+ applyClassNameToHost(instance, classNameValue) {
343
+ if (typeof classNameValue === "object" && classNameValue?.isSignal) {
344
+ import("../reactivity/signals/effect.js").then(({ effect }) => {
345
+ effect(() => {
346
+ const className = classNameValue.get();
347
+ this.setHostClassName(instance, className);
348
+ }, { priority: "Frame" });
349
+ });
350
+ } else if (typeof classNameValue === "function") {
351
+ import("../reactivity/signals/effect.js").then(({ effect }) => {
352
+ effect(() => {
353
+ const className = classNameValue();
354
+ this.setHostClassName(instance, className);
355
+ }, { priority: "Frame" });
356
+ });
357
+ } else {
358
+ this.setHostClassName(instance, classNameValue);
359
+ }
360
+ }
361
+ /**
362
+ * Establece las clases CSS en el host element.
363
+ */
364
+ setHostClassName(instance, className) {
365
+ if (!className) return;
366
+ const classStr = Array.isArray(className) ? className.join(" ") : String(className);
367
+ if (classStr.trim()) {
368
+ instance.className = classStr.trim();
369
+ }
370
+ }
371
+ createAndRenderComponent(ComponentClass, props, children) {
372
+ let instance;
373
+ reactiveContext.untrack(() => {
374
+ instance = new ComponentClass();
375
+ const tagName = this.convertClassNameToTagName(ComponentClass.name);
376
+ Object.defineProperty(instance, "tagName", {
377
+ value: tagName.toUpperCase(),
378
+ configurable: false,
379
+ enumerable: true
380
+ });
381
+ Object.defineProperty(instance, "nodeName", {
382
+ value: tagName.toUpperCase(),
383
+ configurable: false,
384
+ enumerable: true
385
+ });
386
+ const node = AppTree.registerInstance(instance, this.appNode);
387
+ instance.appNode = node;
388
+ const childMetadata = AppTree.getMetadata(ComponentClass);
389
+ if (childMetadata?.services?.length) {
390
+ BaseComponent.bootstrapServicesForNode(node, childMetadata, true);
391
+ }
392
+ BaseComponent.assignContainer(instance, node);
393
+ if (props) {
394
+ Object.keys(props).forEach((key) => {
395
+ if (key === "children") return;
396
+ if (key === "className" || key === "class") {
397
+ this.applyClassNameToHost(instance, props[key]);
398
+ } else {
399
+ instance[key] = props[key];
400
+ }
401
+ });
402
+ }
403
+ instance.initializeForJSX();
404
+ const view = instance.view();
405
+ if (view instanceof Node && instance.shadowRoot) {
406
+ instance.shadowRoot.appendChild(view);
407
+ } else if (Array.isArray(view) && instance.shadowRoot) {
408
+ view.forEach((child) => renderChild(instance.shadowRoot, child));
409
+ }
410
+ if (children) {
411
+ const normalizedChildren = this.normalizeChildren(children);
412
+ normalizedChildren.forEach((child) => {
413
+ renderChild(instance, child);
414
+ });
415
+ }
416
+ });
417
+ return instance;
418
+ }
419
+ createNativeElement(type, props, ...children) {
420
+ const el = document.createElement(type);
421
+ if (props) {
422
+ bindProps(el, props, this.behaviorManager);
423
+ }
424
+ const flatChildren = children.flat();
425
+ flatChildren.forEach((child) => renderChild(el, child));
426
+ return el;
427
+ }
428
+ normalizeChildren(children) {
429
+ if (!children) return [];
430
+ return Array.isArray(children) ? children : [children];
431
+ }
432
+ convertClassNameToTagName(className) {
433
+ return className.replace(/_/g, "-").replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
434
+ }
435
+ }
436
+ export {
437
+ BaseComponent
438
+ };
@@ -0,0 +1,27 @@
1
+ import { BaseStyleSheet } from '../../styles/base-style-sheet';
2
+ export interface ComponentConfig {
3
+ /**
4
+ * Clase(s) de estilos del componente.
5
+ * El scope se determina por el decorador de cada clase:
6
+ * - Sin decorador: Local
7
+ * - @Shared: Shadow roots
8
+ * - @ForDocument: Documento
9
+ */
10
+ styles?: (new () => BaseStyleSheet) | (new () => BaseStyleSheet)[];
11
+ /**
12
+ * Si es false, el componente no usará Shadow DOM.
13
+ * Por defecto es true (usa Shadow DOM).
14
+ * Útil para componentes que necesitan heredar estilos del documento (ej: Link con activeClass).
15
+ */
16
+ useShadowDOM?: boolean;
17
+ /**
18
+ * Servicios que este componente provee a sí mismo y a sus hijos.
19
+ * Los hijos resuelven servicios subiendo por el árbol de componentes.
20
+ */
21
+ services?: (new (...args: any[]) => any)[];
22
+ }
23
+ /**
24
+ * Decorador @Component para registrar componentes web.
25
+ * Uso: @Component() o @Component({ styles: [MyStyles] })
26
+ */
27
+ export declare function Component(config?: ComponentConfig): any;
@@ -0,0 +1,47 @@
1
+ import { RESOURCE_PROPERTY_KEYS } from "../../reactivity/decorators/resource.js";
2
+ import { AppTree } from "../app-tree.js";
3
+ import { getStyleScope } from "../../styles/decorators/scope.js";
4
+ function convertClassNameToTagName(className) {
5
+ const kebabCase = className.replace(/_/g, "-").replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
6
+ return `use-${kebabCase}`;
7
+ }
8
+ function Component(config = {}) {
9
+ return function(ComponentClass, context) {
10
+ const tagName = convertClassNameToTagName(ComponentClass.name);
11
+ const resourceKeys = context?.metadata?.resourceKeys || [];
12
+ ComponentClass[RESOURCE_PROPERTY_KEYS] = resourceKeys;
13
+ let categorizedStyles = {
14
+ local: [],
15
+ shared: [],
16
+ document: []
17
+ };
18
+ if (config?.styles) {
19
+ const stylesArray = Array.isArray(config.styles) ? config.styles : [config.styles];
20
+ stylesArray.forEach((StyleClass) => {
21
+ const scope = getStyleScope(StyleClass);
22
+ categorizedStyles[scope].push(StyleClass);
23
+ });
24
+ }
25
+ AppTree.registerMetadata({
26
+ tagName,
27
+ componentClass: ComponentClass,
28
+ resourceKeys,
29
+ stylesClass: categorizedStyles.local[0],
30
+ localStyles: categorizedStyles.local.length > 0 ? categorizedStyles.local : void 0,
31
+ sharedStylesClasses: categorizedStyles.shared.length > 0 ? categorizedStyles.shared : void 0,
32
+ documentStylesClasses: categorizedStyles.document.length > 0 ? categorizedStyles.document : void 0,
33
+ useShadowDOM: config.useShadowDOM !== false,
34
+ // Por defecto true
35
+ services: config.services
36
+ });
37
+ if (!customElements.get(tagName)) {
38
+ customElements.define(tagName, ComponentClass);
39
+ } else {
40
+ console.warn(`[Component] ⚠ Tag "${tagName}" ya registrado`);
41
+ }
42
+ return ComponentClass;
43
+ };
44
+ }
45
+ export {
46
+ Component
47
+ };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @Prop decorator for component properties that may receive reactive expressions.
3
+ *
4
+ * When a prop receives a zero-argument function (a reactive getter from the parent),
5
+ * this decorator automatically unwraps it on access, creating a direct reactive
6
+ * subscription from the child to the parent's signals.
7
+ *
8
+ * For non-function values or callback functions (with parameters), the value is
9
+ * returned as-is.
10
+ *
11
+ * When used in a @Behavior class, this decorator also registers the prop name
12
+ * in the behavior's metadata for the PropertyRegistry to resolve.
13
+ */
14
+ export declare function Prop<This extends object, Value>(target: undefined, context: ClassFieldDecoratorContext<This, Value>): (this: This, initialValue: Value) => Value;
@@ -0,0 +1,37 @@
1
+ import { BEHAVIOR_PROPS } from "../../behaviors/constants.js";
2
+ function Prop(target, context) {
3
+ if (context.kind !== "field") {
4
+ throw new Error("@Prop can only be applied to class fields.");
5
+ }
6
+ const storageKey = Symbol(`prop_storage_${String(context.name)}`);
7
+ const metadata = context.metadata;
8
+ if (!metadata[BEHAVIOR_PROPS]) {
9
+ metadata[BEHAVIOR_PROPS] = /* @__PURE__ */ new Set();
10
+ }
11
+ metadata[BEHAVIOR_PROPS].add(String(context.name));
12
+ return function(initialValue) {
13
+ this[storageKey] = initialValue;
14
+ Object.defineProperty(this, context.name, {
15
+ get: () => {
16
+ const storedValue = this[storageKey];
17
+ const propName = String(context.name);
18
+ if (propName.startsWith("on") && propName.length > 2) {
19
+ return storedValue;
20
+ }
21
+ if (typeof storedValue === "function" && storedValue.length === 0) {
22
+ return storedValue();
23
+ }
24
+ return storedValue;
25
+ },
26
+ set: (newValue) => {
27
+ this[storageKey] = newValue;
28
+ },
29
+ enumerable: true,
30
+ configurable: true
31
+ });
32
+ return initialValue;
33
+ };
34
+ }
35
+ export {
36
+ Prop
37
+ };
@@ -0,0 +1,26 @@
1
+ import { BaseComponent } from './base-component';
2
+ import { BaseStyleSheet } from '../styles/base-style-sheet';
3
+ import { ScopedContainer } from '../DI/scoped-container';
4
+ export type Constructor<T = {}> = new (...args: any[]) => T;
5
+ export type ComponentMetadata = {
6
+ tagName: string;
7
+ componentClass: Constructor<any>;
8
+ routePath?: string;
9
+ viewPropertyName?: string;
10
+ resourceKeys: string[];
11
+ stylesClass?: new () => BaseStyleSheet;
12
+ localStyles?: Constructor<any>[];
13
+ sharedStylesClasses?: Constructor<any>[];
14
+ documentStylesClasses?: Constructor<any>[];
15
+ useShadowDOM?: boolean;
16
+ services?: Constructor[];
17
+ };
18
+ export interface INode {
19
+ id: string;
20
+ metadata: ComponentMetadata;
21
+ instance: BaseComponent;
22
+ parent?: INode;
23
+ children: INode[];
24
+ contextStore?: object;
25
+ container?: ScopedContainer;
26
+ }
package/dist/core.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ import { Router } from './router/router';
2
+ import { Trie } from './router/trie';
3
+ import { PolicyEvaluator } from './router/policy-evaluator';
4
+ import { EventEmitter } from './events-handler/event-emitter.service';
5
+ /**
6
+ * Core framework services.
7
+ * Include these in your root component's services array.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { BaseComponent, Component, core, RouteView } from '@v-ibe/core';
12
+ *
13
+ * @Component({
14
+ * services: [...core, AuthService, MyPolicy]
15
+ * })
16
+ * export class App extends BaseComponent {
17
+ * view() {
18
+ * return <RouteView />;
19
+ * }
20
+ * }
21
+ * ```
22
+ */
23
+ export declare const core: (typeof Trie | typeof PolicyEvaluator | typeof Router | typeof EventEmitter)[];
package/dist/core.js ADDED
@@ -0,0 +1,8 @@
1
+ import { Router } from "./router/router.js";
2
+ import { Trie } from "./router/trie.js";
3
+ import { PolicyEvaluator } from "./router/policy-evaluator.js";
4
+ import { EventEmitter } from "./events-handler/event-emitter.service.js";
5
+ const core = [Router, Trie, PolicyEvaluator, EventEmitter];
6
+ export {
7
+ core
8
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,58 @@
1
+ import { ISignal } from '../reactivity/signals/signal';
2
+ import { ReactiveArray } from '../reactivity/signals/reactive-array';
3
+ /**
4
+ * Props del componente For
5
+ */
6
+ export interface ForProps<T> {
7
+ /**
8
+ * Array de items a renderizar.
9
+ * Para granularidad fina óptima, debe ser un ReactiveArray (via @State).
10
+ * También acepta: Signal<T[]>, función, o array plano.
11
+ */
12
+ each: T[] | (() => T[]) | ISignal<T[]> | ReactiveArray<T>;
13
+ /**
14
+ * Función de render para cada item.
15
+ * IMPORTANTE: Esta función se ejecuta DENTRO de un effect individual por item.
16
+ * Cambios en array[i] solo re-ejecutan el effect del índice i.
17
+ */
18
+ children: (item: T, index: number) => any;
19
+ /**
20
+ * Elemento a mostrar cuando el array está vacío.
21
+ */
22
+ fallback?: any;
23
+ /**
24
+ * Función para extraer key única de cada item.
25
+ * Si no se provee, usa auto-keying (id, key, _id, uuid).
26
+ * Para granularidad óptima, es mejor que los items tengan IDs estables.
27
+ */
28
+ getKey?: (item: T, index: number) => string | number;
29
+ }
30
+ /**
31
+ * For - Helper con granularidad fina para listas
32
+ *
33
+ * @example Granularidad fina con @State
34
+ * ```tsx
35
+ * @Component
36
+ * class TodoList extends BaseComponent {
37
+ * @State todos: Todo[] = [...];
38
+ *
39
+ * view() {
40
+ * return (
41
+ * <For each={this.todos}>
42
+ * {(todo) => <TodoItem key={todo.id} todo={todo} />}
43
+ * </For>
44
+ * );
45
+ * }
46
+ * }
47
+ * // Solo los TodoItem que cambian se re-renderizan
48
+ * ```
49
+ *
50
+ * @example Con array plano (sin granularidad fina)
51
+ * ```tsx
52
+ * <For each={[1, 2, 3]}>
53
+ * {(n) => <div>{n}</div>}
54
+ * </For>
55
+ * // Funciona, pero re-renderiza todo cuando cambia
56
+ * ```
57
+ */
58
+ export declare function For<T>(props: ForProps<T>): DocumentFragment;