@saolabs/client 1.0.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 (383) hide show
  1. package/README.md +221 -0
  2. package/dist/index.d.ts +46 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +38 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/plugins.d.ts +38 -0
  7. package/dist/plugins.d.ts.map +1 -0
  8. package/dist/plugins.js +61 -0
  9. package/dist/plugins.js.map +1 -0
  10. package/dist/src/core/app/Application.d.ts +159 -0
  11. package/dist/src/core/app/Application.d.ts.map +1 -0
  12. package/dist/src/core/app/Application.js +338 -0
  13. package/dist/src/core/app/Application.js.map +1 -0
  14. package/dist/src/core/bootstrap/app.d.ts +4 -0
  15. package/dist/src/core/bootstrap/app.d.ts.map +1 -0
  16. package/dist/src/core/bootstrap/app.js +49 -0
  17. package/dist/src/core/bootstrap/app.js.map +1 -0
  18. package/dist/src/core/bootstrap/providers/ApiServiceProvider.d.ts +9 -0
  19. package/dist/src/core/bootstrap/providers/ApiServiceProvider.d.ts.map +1 -0
  20. package/dist/src/core/bootstrap/providers/ApiServiceProvider.js +18 -0
  21. package/dist/src/core/bootstrap/providers/ApiServiceProvider.js.map +1 -0
  22. package/dist/src/core/bootstrap/providers/CoreServiceProvider.d.ts +6 -0
  23. package/dist/src/core/bootstrap/providers/CoreServiceProvider.d.ts.map +1 -0
  24. package/dist/src/core/bootstrap/providers/CoreServiceProvider.js +21 -0
  25. package/dist/src/core/bootstrap/providers/CoreServiceProvider.js.map +1 -0
  26. package/dist/src/core/bootstrap/providers/HelperServiceProvider.d.ts +7 -0
  27. package/dist/src/core/bootstrap/providers/HelperServiceProvider.d.ts.map +1 -0
  28. package/dist/src/core/bootstrap/providers/HelperServiceProvider.js +14 -0
  29. package/dist/src/core/bootstrap/providers/HelperServiceProvider.js.map +1 -0
  30. package/dist/src/core/bootstrap/providers/RouteServiceProvider.d.ts +9 -0
  31. package/dist/src/core/bootstrap/providers/RouteServiceProvider.d.ts.map +1 -0
  32. package/dist/src/core/bootstrap/providers/RouteServiceProvider.js +18 -0
  33. package/dist/src/core/bootstrap/providers/RouteServiceProvider.js.map +1 -0
  34. package/dist/src/core/bootstrap/providers/ServiceProvider.d.ts +38 -0
  35. package/dist/src/core/bootstrap/providers/ServiceProvider.d.ts.map +1 -0
  36. package/dist/src/core/bootstrap/providers/ServiceProvider.js +41 -0
  37. package/dist/src/core/bootstrap/providers/ServiceProvider.js.map +1 -0
  38. package/dist/src/core/bootstrap/providers/ViewServiceProvider.d.ts +9 -0
  39. package/dist/src/core/bootstrap/providers/ViewServiceProvider.d.ts.map +1 -0
  40. package/dist/src/core/bootstrap/providers/ViewServiceProvider.js +18 -0
  41. package/dist/src/core/bootstrap/providers/ViewServiceProvider.js.map +1 -0
  42. package/dist/src/core/bootstrap/providers/default-providers.d.ts +14 -0
  43. package/dist/src/core/bootstrap/providers/default-providers.d.ts.map +1 -0
  44. package/dist/src/core/bootstrap/providers/default-providers.js +79 -0
  45. package/dist/src/core/bootstrap/providers/default-providers.js.map +1 -0
  46. package/dist/src/core/bootstrap/providers/index.d.ts +10 -0
  47. package/dist/src/core/bootstrap/providers/index.d.ts.map +1 -0
  48. package/dist/src/core/bootstrap/providers/index.js +9 -0
  49. package/dist/src/core/bootstrap/providers/index.js.map +1 -0
  50. package/dist/src/core/bootstrap/providers/provider-order.d.ts +19 -0
  51. package/dist/src/core/bootstrap/providers/provider-order.d.ts.map +1 -0
  52. package/dist/src/core/bootstrap/providers/provider-order.js +51 -0
  53. package/dist/src/core/bootstrap/providers/provider-order.js.map +1 -0
  54. package/dist/src/core/cache/ViewCache.d.ts +46 -0
  55. package/dist/src/core/cache/ViewCache.d.ts.map +1 -0
  56. package/dist/src/core/cache/ViewCache.js +85 -0
  57. package/dist/src/core/cache/ViewCache.js.map +1 -0
  58. package/dist/src/core/cache/index.d.ts +2 -0
  59. package/dist/src/core/cache/index.d.ts.map +1 -0
  60. package/dist/src/core/cache/index.js +2 -0
  61. package/dist/src/core/cache/index.js.map +1 -0
  62. package/dist/src/core/contracts/ApiInterface.d.ts +11 -0
  63. package/dist/src/core/contracts/ApiInterface.d.ts.map +1 -0
  64. package/dist/src/core/contracts/ApiInterface.js +2 -0
  65. package/dist/src/core/contracts/ApiInterface.js.map +1 -0
  66. package/dist/src/core/contracts/ApplicationInterface.d.ts +66 -0
  67. package/dist/src/core/contracts/ApplicationInterface.d.ts.map +1 -0
  68. package/dist/src/core/contracts/ApplicationInterface.js +3 -0
  69. package/dist/src/core/contracts/ApplicationInterface.js.map +1 -0
  70. package/dist/src/core/contracts/BlockInterface.d.ts +67 -0
  71. package/dist/src/core/contracts/BlockInterface.d.ts.map +1 -0
  72. package/dist/src/core/contracts/BlockInterface.js +2 -0
  73. package/dist/src/core/contracts/BlockInterface.js.map +1 -0
  74. package/dist/src/core/contracts/ComponentInterface.d.ts +24 -0
  75. package/dist/src/core/contracts/ComponentInterface.d.ts.map +1 -0
  76. package/dist/src/core/contracts/ComponentInterface.js +2 -0
  77. package/dist/src/core/contracts/ComponentInterface.js.map +1 -0
  78. package/dist/src/core/contracts/ElementInterface.d.ts +117 -0
  79. package/dist/src/core/contracts/ElementInterface.d.ts.map +1 -0
  80. package/dist/src/core/contracts/ElementInterface.js +2 -0
  81. package/dist/src/core/contracts/ElementInterface.js.map +1 -0
  82. package/dist/src/core/contracts/EventServiceInterface.d.ts +37 -0
  83. package/dist/src/core/contracts/EventServiceInterface.d.ts.map +1 -0
  84. package/dist/src/core/contracts/EventServiceInterface.js +3 -0
  85. package/dist/src/core/contracts/EventServiceInterface.js.map +1 -0
  86. package/dist/src/core/contracts/HelperInterface.d.ts +231 -0
  87. package/dist/src/core/contracts/HelperInterface.d.ts.map +1 -0
  88. package/dist/src/core/contracts/HelperInterface.js +3 -0
  89. package/dist/src/core/contracts/HelperInterface.js.map +1 -0
  90. package/dist/src/core/contracts/HttpServiceInterface.d.ts +38 -0
  91. package/dist/src/core/contracts/HttpServiceInterface.d.ts.map +1 -0
  92. package/dist/src/core/contracts/HttpServiceInterface.js +3 -0
  93. package/dist/src/core/contracts/HttpServiceInterface.js.map +1 -0
  94. package/dist/src/core/contracts/LoggerServiceInterface.d.ts +37 -0
  95. package/dist/src/core/contracts/LoggerServiceInterface.d.ts.map +1 -0
  96. package/dist/src/core/contracts/LoggerServiceInterface.js +3 -0
  97. package/dist/src/core/contracts/LoggerServiceInterface.js.map +1 -0
  98. package/dist/src/core/contracts/LoopContextInterface.d.ts +14 -0
  99. package/dist/src/core/contracts/LoopContextInterface.d.ts.map +1 -0
  100. package/dist/src/core/contracts/LoopContextInterface.js +3 -0
  101. package/dist/src/core/contracts/LoopContextInterface.js.map +1 -0
  102. package/dist/src/core/contracts/MarkerInterface.d.ts +55 -0
  103. package/dist/src/core/contracts/MarkerInterface.d.ts.map +1 -0
  104. package/dist/src/core/contracts/MarkerInterface.js +2 -0
  105. package/dist/src/core/contracts/MarkerInterface.js.map +1 -0
  106. package/dist/src/core/contracts/ReactiveInterface.d.ts +38 -0
  107. package/dist/src/core/contracts/ReactiveInterface.d.ts.map +1 -0
  108. package/dist/src/core/contracts/ReactiveInterface.js +2 -0
  109. package/dist/src/core/contracts/ReactiveInterface.js.map +1 -0
  110. package/dist/src/core/contracts/RouterInterface.d.ts +58 -0
  111. package/dist/src/core/contracts/RouterInterface.d.ts.map +1 -0
  112. package/dist/src/core/contracts/RouterInterface.js +2 -0
  113. package/dist/src/core/contracts/RouterInterface.js.map +1 -0
  114. package/dist/src/core/contracts/ServiceProviderInterface.d.ts +12 -0
  115. package/dist/src/core/contracts/ServiceProviderInterface.d.ts.map +1 -0
  116. package/dist/src/core/contracts/ServiceProviderInterface.js +2 -0
  117. package/dist/src/core/contracts/ServiceProviderInterface.js.map +1 -0
  118. package/dist/src/core/contracts/StorageServiceInterface.d.ts +43 -0
  119. package/dist/src/core/contracts/StorageServiceInterface.d.ts.map +1 -0
  120. package/dist/src/core/contracts/StorageServiceInterface.js +3 -0
  121. package/dist/src/core/contracts/StorageServiceInterface.js.map +1 -0
  122. package/dist/src/core/contracts/StoreServiceInterface.d.ts +45 -0
  123. package/dist/src/core/contracts/StoreServiceInterface.d.ts.map +1 -0
  124. package/dist/src/core/contracts/StoreServiceInterface.js +3 -0
  125. package/dist/src/core/contracts/StoreServiceInterface.js.map +1 -0
  126. package/dist/src/core/contracts/ViewCacheInterface.d.ts +13 -0
  127. package/dist/src/core/contracts/ViewCacheInterface.d.ts.map +1 -0
  128. package/dist/src/core/contracts/ViewCacheInterface.js +3 -0
  129. package/dist/src/core/contracts/ViewCacheInterface.js.map +1 -0
  130. package/dist/src/core/contracts/ViewControllerInterface.d.ts +115 -0
  131. package/dist/src/core/contracts/ViewControllerInterface.d.ts.map +1 -0
  132. package/dist/src/core/contracts/ViewControllerInterface.js +2 -0
  133. package/dist/src/core/contracts/ViewControllerInterface.js.map +1 -0
  134. package/dist/src/core/contracts/ViewInterface.d.ts +24 -0
  135. package/dist/src/core/contracts/ViewInterface.d.ts.map +1 -0
  136. package/dist/src/core/contracts/ViewInterface.js +2 -0
  137. package/dist/src/core/contracts/ViewInterface.js.map +1 -0
  138. package/dist/src/core/contracts/ViewManagerInterface.d.ts +44 -0
  139. package/dist/src/core/contracts/ViewManagerInterface.d.ts.map +1 -0
  140. package/dist/src/core/contracts/ViewManagerInterface.js +2 -0
  141. package/dist/src/core/contracts/ViewManagerInterface.js.map +1 -0
  142. package/dist/src/core/contracts/ViewStateInterface.d.ts +40 -0
  143. package/dist/src/core/contracts/ViewStateInterface.d.ts.map +1 -0
  144. package/dist/src/core/contracts/ViewStateInterface.js +3 -0
  145. package/dist/src/core/contracts/ViewStateInterface.js.map +1 -0
  146. package/dist/src/core/contracts/common.d.ts +28 -0
  147. package/dist/src/core/contracts/common.d.ts.map +1 -0
  148. package/dist/src/core/contracts/common.js +29 -0
  149. package/dist/src/core/contracts/common.js.map +1 -0
  150. package/dist/src/core/contracts/utils.d.ts +20 -0
  151. package/dist/src/core/contracts/utils.d.ts.map +1 -0
  152. package/dist/src/core/contracts/utils.js +4 -0
  153. package/dist/src/core/contracts/utils.js.map +1 -0
  154. package/dist/src/core/contracts/views.d.ts +23 -0
  155. package/dist/src/core/contracts/views.d.ts.map +1 -0
  156. package/dist/src/core/contracts/views.js +2 -0
  157. package/dist/src/core/contracts/views.js.map +1 -0
  158. package/dist/src/core/elements/Block.d.ts +58 -0
  159. package/dist/src/core/elements/Block.d.ts.map +1 -0
  160. package/dist/src/core/elements/Block.js +77 -0
  161. package/dist/src/core/elements/Block.js.map +1 -0
  162. package/dist/src/core/elements/BlockOutlet.d.ts +34 -0
  163. package/dist/src/core/elements/BlockOutlet.d.ts.map +1 -0
  164. package/dist/src/core/elements/BlockOutlet.js +59 -0
  165. package/dist/src/core/elements/BlockOutlet.js.map +1 -0
  166. package/dist/src/core/elements/Component.d.ts +62 -0
  167. package/dist/src/core/elements/Component.d.ts.map +1 -0
  168. package/dist/src/core/elements/Component.js +72 -0
  169. package/dist/src/core/elements/Component.js.map +1 -0
  170. package/dist/src/core/elements/ElementManager.d.ts +23 -0
  171. package/dist/src/core/elements/ElementManager.d.ts.map +1 -0
  172. package/dist/src/core/elements/ElementManager.js +33 -0
  173. package/dist/src/core/elements/ElementManager.js.map +1 -0
  174. package/dist/src/core/elements/Fragment.d.ts +51 -0
  175. package/dist/src/core/elements/Fragment.d.ts.map +1 -0
  176. package/dist/src/core/elements/Fragment.js +133 -0
  177. package/dist/src/core/elements/Fragment.js.map +1 -0
  178. package/dist/src/core/elements/Html.d.ts +52 -0
  179. package/dist/src/core/elements/Html.d.ts.map +1 -0
  180. package/dist/src/core/elements/Html.js +299 -0
  181. package/dist/src/core/elements/Html.js.map +1 -0
  182. package/dist/src/core/elements/Output.d.ts +69 -0
  183. package/dist/src/core/elements/Output.d.ts.map +1 -0
  184. package/dist/src/core/elements/Output.js +121 -0
  185. package/dist/src/core/elements/Output.js.map +1 -0
  186. package/dist/src/core/elements/Reactive.d.ts +77 -0
  187. package/dist/src/core/elements/Reactive.d.ts.map +1 -0
  188. package/dist/src/core/elements/Reactive.js +199 -0
  189. package/dist/src/core/elements/Reactive.js.map +1 -0
  190. package/dist/src/core/elements/TextElement.d.ts +46 -0
  191. package/dist/src/core/elements/TextElement.d.ts.map +1 -0
  192. package/dist/src/core/elements/TextElement.js +94 -0
  193. package/dist/src/core/elements/TextElement.js.map +1 -0
  194. package/dist/src/core/elements/Wrapper.d.ts +50 -0
  195. package/dist/src/core/elements/Wrapper.d.ts.map +1 -0
  196. package/dist/src/core/elements/Wrapper.js +96 -0
  197. package/dist/src/core/elements/Wrapper.js.map +1 -0
  198. package/dist/src/core/elements/Yield.d.ts +34 -0
  199. package/dist/src/core/elements/Yield.d.ts.map +1 -0
  200. package/dist/src/core/elements/Yield.js +56 -0
  201. package/dist/src/core/elements/Yield.js.map +1 -0
  202. package/dist/src/core/elements/helpers.d.ts +8 -0
  203. package/dist/src/core/elements/helpers.d.ts.map +1 -0
  204. package/dist/src/core/elements/helpers.js +40 -0
  205. package/dist/src/core/elements/helpers.js.map +1 -0
  206. package/dist/src/core/elements/index.d.ts +12 -0
  207. package/dist/src/core/elements/index.d.ts.map +1 -0
  208. package/dist/src/core/elements/index.js +12 -0
  209. package/dist/src/core/elements/index.js.map +1 -0
  210. package/dist/src/core/hellpers/ApiClient.d.ts +58 -0
  211. package/dist/src/core/hellpers/ApiClient.d.ts.map +1 -0
  212. package/dist/src/core/hellpers/ApiClient.js +122 -0
  213. package/dist/src/core/hellpers/ApiClient.js.map +1 -0
  214. package/dist/src/core/hellpers/app.d.ts +3 -0
  215. package/dist/src/core/hellpers/app.d.ts.map +1 -0
  216. package/dist/src/core/hellpers/app.js +53 -0
  217. package/dist/src/core/hellpers/app.js.map +1 -0
  218. package/dist/src/core/hellpers/utils.d.ts +26 -0
  219. package/dist/src/core/hellpers/utils.d.ts.map +1 -0
  220. package/dist/src/core/hellpers/utils.js +96 -0
  221. package/dist/src/core/hellpers/utils.js.map +1 -0
  222. package/dist/src/core/routers/Router.d.ts +212 -0
  223. package/dist/src/core/routers/Router.d.ts.map +1 -0
  224. package/dist/src/core/routers/Router.js +623 -0
  225. package/dist/src/core/routers/Router.js.map +1 -0
  226. package/dist/src/core/routers/index.d.ts +3 -0
  227. package/dist/src/core/routers/index.d.ts.map +1 -0
  228. package/dist/src/core/routers/index.js +2 -0
  229. package/dist/src/core/routers/index.js.map +1 -0
  230. package/dist/src/core/services/BlockManager.d.ts +63 -0
  231. package/dist/src/core/services/BlockManager.d.ts.map +1 -0
  232. package/dist/src/core/services/BlockManager.js +191 -0
  233. package/dist/src/core/services/BlockManager.js.map +1 -0
  234. package/dist/src/core/services/DomService.d.ts +9 -0
  235. package/dist/src/core/services/DomService.d.ts.map +1 -0
  236. package/dist/src/core/services/DomService.js +18 -0
  237. package/dist/src/core/services/DomService.js.map +1 -0
  238. package/dist/src/core/services/EventService.d.ts +58 -0
  239. package/dist/src/core/services/EventService.d.ts.map +1 -0
  240. package/dist/src/core/services/EventService.js +212 -0
  241. package/dist/src/core/services/EventService.js.map +1 -0
  242. package/dist/src/core/services/HelperService.d.ts +443 -0
  243. package/dist/src/core/services/HelperService.d.ts.map +1 -0
  244. package/dist/src/core/services/HelperService.js +1650 -0
  245. package/dist/src/core/services/HelperService.js.map +1 -0
  246. package/dist/src/core/services/HttpService.d.ts +63 -0
  247. package/dist/src/core/services/HttpService.d.ts.map +1 -0
  248. package/dist/src/core/services/HttpService.js +182 -0
  249. package/dist/src/core/services/HttpService.js.map +1 -0
  250. package/dist/src/core/services/LoggerService.d.ts +56 -0
  251. package/dist/src/core/services/LoggerService.d.ts.map +1 -0
  252. package/dist/src/core/services/LoggerService.js +94 -0
  253. package/dist/src/core/services/LoggerService.js.map +1 -0
  254. package/dist/src/core/services/MarkerRegistry.d.ts +94 -0
  255. package/dist/src/core/services/MarkerRegistry.d.ts.map +1 -0
  256. package/dist/src/core/services/MarkerRegistry.js +199 -0
  257. package/dist/src/core/services/MarkerRegistry.js.map +1 -0
  258. package/dist/src/core/services/MarkerService.d.ts +299 -0
  259. package/dist/src/core/services/MarkerService.d.ts.map +1 -0
  260. package/dist/src/core/services/MarkerService.js +723 -0
  261. package/dist/src/core/services/MarkerService.js.map +1 -0
  262. package/dist/src/core/services/StorageService.d.ts +69 -0
  263. package/dist/src/core/services/StorageService.d.ts.map +1 -0
  264. package/dist/src/core/services/StorageService.js +243 -0
  265. package/dist/src/core/services/StorageService.js.map +1 -0
  266. package/dist/src/core/services/StoreService.d.ts +80 -0
  267. package/dist/src/core/services/StoreService.d.ts.map +1 -0
  268. package/dist/src/core/services/StoreService.js +301 -0
  269. package/dist/src/core/services/StoreService.js.map +1 -0
  270. package/dist/src/core/services/index.d.ts +9 -0
  271. package/dist/src/core/services/index.d.ts.map +1 -0
  272. package/dist/src/core/services/index.js +9 -0
  273. package/dist/src/core/services/index.js.map +1 -0
  274. package/dist/src/core/types/utils.d.ts +29 -0
  275. package/dist/src/core/types/utils.d.ts.map +1 -0
  276. package/dist/src/core/types/utils.js +22 -0
  277. package/dist/src/core/types/utils.js.map +1 -0
  278. package/dist/src/core/view/LoopContext.d.ts +38 -0
  279. package/dist/src/core/view/LoopContext.d.ts.map +1 -0
  280. package/dist/src/core/view/LoopContext.js +100 -0
  281. package/dist/src/core/view/LoopContext.js.map +1 -0
  282. package/dist/src/core/view/Section.d.ts +41 -0
  283. package/dist/src/core/view/Section.d.ts.map +1 -0
  284. package/dist/src/core/view/Section.js +67 -0
  285. package/dist/src/core/view/Section.js.map +1 -0
  286. package/dist/src/core/view/View.d.ts +63 -0
  287. package/dist/src/core/view/View.d.ts.map +1 -0
  288. package/dist/src/core/view/View.js +85 -0
  289. package/dist/src/core/view/View.js.map +1 -0
  290. package/dist/src/core/view/ViewController.d.ts +277 -0
  291. package/dist/src/core/view/ViewController.d.ts.map +1 -0
  292. package/dist/src/core/view/ViewController.js +862 -0
  293. package/dist/src/core/view/ViewController.js.map +1 -0
  294. package/dist/src/core/view/ViewManager.d.ts +141 -0
  295. package/dist/src/core/view/ViewManager.d.ts.map +1 -0
  296. package/dist/src/core/view/ViewManager.js +565 -0
  297. package/dist/src/core/view/ViewManager.js.map +1 -0
  298. package/dist/src/core/view/ViewState.d.ts +117 -0
  299. package/dist/src/core/view/ViewState.d.ts.map +1 -0
  300. package/dist/src/core/view/ViewState.js +410 -0
  301. package/dist/src/core/view/ViewState.js.map +1 -0
  302. package/dist/src/core/view/index.d.ts +6 -0
  303. package/dist/src/core/view/index.d.ts.map +1 -0
  304. package/dist/src/core/view/index.js +6 -0
  305. package/dist/src/core/view/index.js.map +1 -0
  306. package/index.ts +62 -0
  307. package/package.json +70 -0
  308. package/plugins.ts +77 -0
  309. package/src/core/app/Application.ts +410 -0
  310. package/src/core/bootstrap/app.ts +58 -0
  311. package/src/core/bootstrap/providers/ApiServiceProvider.ts +18 -0
  312. package/src/core/bootstrap/providers/CoreServiceProvider.ts +19 -0
  313. package/src/core/bootstrap/providers/HelperServiceProvider.ts +12 -0
  314. package/src/core/bootstrap/providers/RouteServiceProvider.ts +17 -0
  315. package/src/core/bootstrap/providers/ServiceProvider.ts +51 -0
  316. package/src/core/bootstrap/providers/ViewServiceProvider.ts +17 -0
  317. package/src/core/bootstrap/providers/default-providers.ts +94 -0
  318. package/src/core/bootstrap/providers/index.ts +9 -0
  319. package/src/core/bootstrap/providers/provider-order.test.ts +67 -0
  320. package/src/core/bootstrap/providers/provider-order.ts +66 -0
  321. package/src/core/cache/ViewCache.ts +102 -0
  322. package/src/core/cache/index.ts +1 -0
  323. package/src/core/contracts/ApiInterface.ts +11 -0
  324. package/src/core/contracts/ApplicationInterface.ts +79 -0
  325. package/src/core/contracts/BlockInterface.ts +76 -0
  326. package/src/core/contracts/ComponentInterface.ts +26 -0
  327. package/src/core/contracts/ElementInterface.ts +140 -0
  328. package/src/core/contracts/EventServiceInterface.ts +47 -0
  329. package/src/core/contracts/HelperInterface.ts +256 -0
  330. package/src/core/contracts/HttpServiceInterface.ts +51 -0
  331. package/src/core/contracts/LoggerServiceInterface.ts +48 -0
  332. package/src/core/contracts/LoopContextInterface.ts +15 -0
  333. package/src/core/contracts/MarkerInterface.ts +77 -0
  334. package/src/core/contracts/ReactiveInterface.ts +45 -0
  335. package/src/core/contracts/RouterInterface.ts +65 -0
  336. package/src/core/contracts/ServiceProviderInterface.ts +12 -0
  337. package/src/core/contracts/StorageServiceInterface.ts +48 -0
  338. package/src/core/contracts/StoreServiceInterface.ts +50 -0
  339. package/src/core/contracts/ViewCacheInterface.ts +14 -0
  340. package/src/core/contracts/ViewControllerInterface.ts +135 -0
  341. package/src/core/contracts/ViewInterface.ts +31 -0
  342. package/src/core/contracts/ViewManagerInterface.ts +45 -0
  343. package/src/core/contracts/ViewStateInterface.ts +47 -0
  344. package/src/core/contracts/common.ts +27 -0
  345. package/src/core/contracts/utils.ts +23 -0
  346. package/src/core/contracts/views.ts +23 -0
  347. package/src/core/elements/Block.ts +113 -0
  348. package/src/core/elements/BlockOutlet.ts +83 -0
  349. package/src/core/elements/Component.ts +114 -0
  350. package/src/core/elements/ElementManager.ts +48 -0
  351. package/src/core/elements/Fragment.ts +168 -0
  352. package/src/core/elements/Html.ts +364 -0
  353. package/src/core/elements/Output.ts +167 -0
  354. package/src/core/elements/Reactive.ts +253 -0
  355. package/src/core/elements/TextElement.ts +110 -0
  356. package/src/core/elements/Wrapper.ts +131 -0
  357. package/src/core/elements/Yield.ts +70 -0
  358. package/src/core/elements/helpers.ts +56 -0
  359. package/src/core/elements/index.ts +26 -0
  360. package/src/core/hellpers/ApiClient.ts +145 -0
  361. package/src/core/hellpers/app.ts +57 -0
  362. package/src/core/hellpers/utils.ts +109 -0
  363. package/src/core/routers/Router.ts +765 -0
  364. package/src/core/routers/index.ts +2 -0
  365. package/src/core/services/BlockManager.ts +210 -0
  366. package/src/core/services/DomService.ts +26 -0
  367. package/src/core/services/EventService.ts +266 -0
  368. package/src/core/services/HelperService.ts +1653 -0
  369. package/src/core/services/HttpService.ts +235 -0
  370. package/src/core/services/LoggerService.ts +139 -0
  371. package/src/core/services/MarkerRegistry.ts +239 -0
  372. package/src/core/services/MarkerService.ts +923 -0
  373. package/src/core/services/StorageService.ts +268 -0
  374. package/src/core/services/StoreService.ts +338 -0
  375. package/src/core/services/index.ts +8 -0
  376. package/src/core/types/utils.ts +30 -0
  377. package/src/core/view/LoopContext.ts +109 -0
  378. package/src/core/view/Section.ts +86 -0
  379. package/src/core/view/View.ts +109 -0
  380. package/src/core/view/ViewController.ts +1002 -0
  381. package/src/core/view/ViewManager.ts +700 -0
  382. package/src/core/view/ViewState.ts +453 -0
  383. package/src/core/view/index.ts +5 -0
@@ -0,0 +1,1002 @@
1
+ import type { BlockInterface, BlockOutletInterface, BlockRenderFactory } from "../contracts/BlockInterface";
2
+ import type { FragmentInterface, HtmlInterface, OneChildrenFactory, OneElementEventHandler, OneNodeInterface, OutputInterface, TextInterface, WrapperInterface, YieldInterface } from "../contracts/ElementInterface";
3
+ import type { LoopContextInterface } from "../contracts/LoopContextInterface";
4
+ import type { ReactiveChildrenFactory, ReactiveInterface } from "../contracts/ReactiveInterface";
5
+ import type { ViewControllerInterface, ViewType, ViewConfig, ViewRuntimeConfig, ViewControllerConfig } from "../contracts/ViewControllerInterface";
6
+ import type { ViewInterface, ViewRenderFactory } from "../contracts/ViewInterface";
7
+ import type { ViewStateInterface } from "../contracts/ViewStateInterface";
8
+ import type { OneObjectType } from "../types/utils";
9
+ import { ViewState } from "./ViewState";
10
+ import { LoopContext } from "./LoopContext";
11
+ import { Reactive } from "../elements/Reactive";
12
+ import BlockManager, { BlockManagerService } from "../services/BlockManager";
13
+ import { Component } from "../elements/Component";
14
+ import { generateUUID } from "../hellpers/utils";
15
+ import { Output } from "../elements/Output";
16
+ import { View } from "./View";
17
+ import { ApplicationInterface } from "../contracts/ApplicationInterface";
18
+ import { SectionConstruvtorArgs, SectionContentRenderer, SectionContentType, SectionInterface, SectionItemType } from "../contracts/views";
19
+ import { Section } from "./Section";
20
+ import { InitMode } from "../contracts/common";
21
+ import { Block, BlockOutlet, Fragment, Html, TextElement } from "../elements";
22
+ import { Wrapper } from "../elements/Wrapper";
23
+ import { YieldElement } from "../elements/Yield";
24
+ import { app } from "../hellpers/app";
25
+ import { ComponentInterface } from "../contracts/ComponentInterface";
26
+
27
+ type ElementChild = ReactiveInterface | ComponentInterface | HtmlInterface | TextInterface | FragmentInterface | OutputInterface | BlockOutletInterface | YieldInterface | OneNodeInterface;
28
+
29
+ /**
30
+ * ViewController — the brain behind a View.
31
+ *
32
+ * Manages:
33
+ * - Reactive state (ViewState) — useState, subscribe, batch flush
34
+ * - DOM element tree — via Html, Reactive, TextElement, Fragment
35
+ * - Event delegation — addEventListener with centralized cleanup
36
+ * - Loop contexts — @foreach, @for, @while with LoopContext stack
37
+ * - Block management — for layout views with @useBlock
38
+ * - Lifecycle — setup, render, destroy
39
+ * - Reactive scheduling — batched DOM updates via requestAnimationFrame
40
+ *
41
+ * KEY DIFFERENCE from core/ViewController:
42
+ * OLD: render() returns HTML string → innerHTML → scan DOM for bindings
43
+ * NEW: render() builds element tree directly → Reactive regions update in-place
44
+ *
45
+ * Compiled .one output calls methods like:
46
+ * this.__ctrl__.addEventListener(el, 'click', handlers)
47
+ * this.__ctrl__.states.__.useState(0, 'count')
48
+ * this.__ctrl__.__foreach(items, (item, key, index, loop) => [...])
49
+ */
50
+ export class ViewController implements ViewControllerInterface {
51
+
52
+ // ─── Identity ───────────────────────────────────────────────
53
+ oneType: OneObjectType = 'ViewController';
54
+ public viewId: string;
55
+ public path: string;
56
+ public viewType: ViewType;
57
+
58
+ // ─── Core References ────────────────────────────────────────
59
+ /** The View instance this controller manages */
60
+ public view: ViewInterface;
61
+ /** Reactive state manager */
62
+ public states: ViewState;
63
+ /** App container reference (set later by framework) */
64
+ private __App: ApplicationInterface;
65
+
66
+ // ─── View Hierarchy ─────────────────────────────────────────
67
+ /** Parent view controller (for nested views) */
68
+ public parent: ViewControllerInterface | null = null;
69
+ /** Child view controllers (for nested views) */
70
+ public children: ViewControllerInterface[] = [];
71
+ /** Layout (super) view's controller */
72
+ public superView: ViewControllerInterface | null = null;
73
+ /** Path to layout (super) view — e.g. 'layouts.main' */
74
+ public superViewPath: string | null = null;
75
+ /** Whether this controller IS a layout */
76
+ public isSuperView: boolean = false;
77
+ /** For layouts: the original page view's controller (for block mounting) */
78
+ public originView: ViewControllerInterface | null = null;
79
+
80
+
81
+ // ─── Data & Config ──────────────────────────────────────────
82
+ /** Raw input data from route/parent */
83
+ public data: Record<string, any> = {};
84
+ /** User-defined config from setup() */
85
+ private config: ViewConfig = {};
86
+ /** Typed runtime config from compiled $__setup__ */
87
+ private runtimeConfig: ViewRuntimeConfig | null = {};
88
+ /** Track own properties to avoid conflicts when setting user config */
89
+ private ownProperties: Set<string> = new Set(['__ctrl__']);
90
+
91
+ // ─── DOM & Rendering ────────────────────────────────────────
92
+
93
+
94
+ /** Root Html element — the container this view renders into */
95
+ private rootElement: HtmlInterface | null = null;
96
+
97
+ private parentElement: HtmlInterface | null = null; // For non-root views, track the parent element for correct mounting
98
+
99
+ /** Root element tree returned by renderFactory (Fragment, Html, etc.) */
100
+ private _rootTree: any = null;
101
+ /** Compiled render factory — produces the element tree */
102
+ private renderFactory: ViewRenderFactory | null = null;
103
+ /** Compiled prerender factory — produces the prerender element tree */
104
+ private prerenderFactory: ViewRenderFactory | null = null;
105
+
106
+ public childrenFactory: OneChildrenFactory | null = null;
107
+
108
+ /** Stored render output for lifecycle management */
109
+ public renderOutput: any = null;
110
+ /** Stored prerender output for hydration or caching */
111
+ public prerenderOutput: any = null;
112
+ /** DOM children — for compatibility with HtmlInterface */
113
+ public domChildren: Node[] = [];
114
+ /** Flag: currently in a virtual render (for hydration or caching) */
115
+ public isVirtualRendering: boolean = false;
116
+ public initMode: InitMode = 'create';
117
+
118
+ // ─── Reactive System ────────────────────────────────────────
119
+ /** Pending reactive updates — deduped, flushed in one RAF */
120
+ private pendingReactiveUpdates: Set<ReactiveInterface> = new Set();
121
+ private hasScheduledUpdate = false;
122
+ /** Centralized AbortController for all event listeners */
123
+ private eventAbortController: AbortController = new AbortController();
124
+
125
+ // ─── Loop ───────────────────────────────────────────────────
126
+ /** Current loop context stack (@foreach, @for, @while) */
127
+ public loopContext: LoopContext | null = null;
128
+
129
+ // ─── Layout (Sections & Blocks) ─────────────────────────────
130
+ /** Section management across views */
131
+ public sections: Map<string, SectionInterface> = new Map();
132
+ /** Block slots in layout views */
133
+ public blocks: Map<string, BlockInterface> = new Map();
134
+
135
+ public elements: Map<string, ElementChild> = new Map();
136
+
137
+ public preloadElement: WrapperInterface | null = null; // For pre-rendering elements before the main render
138
+ public mainElement: WrapperInterface | null = null; // The main rendered element tree
139
+ // ─── Lifecycle Flags ────────────────────────────────────────
140
+ /** Whether this view is currently active (mounted in DOM) */
141
+ public isActive: boolean = false;
142
+ /** Whether initial data has been committed */
143
+ private _isDataCommitted = false;
144
+ /** Whether the view has been mounted */
145
+ private _isMounted = false;
146
+ /** Whether the view has been fully destroyed */
147
+ private _isDestroyed = false;
148
+ /** For future use: scanning DOM for bindings */
149
+ protected isScanMode: boolean = false;
150
+
151
+ // --- Route params for reference in blocks and sections (set by ViewManager on navigate) ---
152
+ public urlPath: string | null = null;
153
+
154
+ public callingMethod: string | null = null; // For debugging: track which method is currently executing
155
+
156
+
157
+ // ─── Constructor ────────────────────────────────────────────
158
+
159
+ constructor(view: ViewInterface, path: string = '', viewType: ViewType = 'view', viewId: string | null = null) {
160
+ this.__App = app<ApplicationInterface>();
161
+ this.view = view;
162
+ this.path = path;
163
+ this.viewType = viewType;
164
+ this.viewId = viewId ?? this.generateViewId();
165
+ this.states = new ViewState(this);
166
+ }
167
+
168
+ // ─── Lifecycle ──────────────────────────────────────────────
169
+
170
+ /**
171
+ * Setup — called by compiled $__setup__ with full config.
172
+ *
173
+ * Lưu config, extract metadata, lưu render factory.
174
+ * CHƯA gọi commitConstructorData — đợi ViewManager gọi commitData().
175
+ */
176
+ setup(config: ViewRuntimeConfig): void {
177
+ this.runtimeConfig = config as ViewRuntimeConfig;
178
+
179
+ // Extract metadata
180
+ if (config.viewId) this.viewId = config.viewId;
181
+ if (config.path) this.path = config.path;
182
+ this.data = config.data || {};
183
+ this.superViewPath = config.superView || null;
184
+
185
+ // Store render factory
186
+ if (typeof config.render === 'function') {
187
+ this.setRenderFactory(config.render.bind(this));
188
+ }
189
+
190
+ if (typeof config.prerender === 'function') {
191
+ this.prerenderFactory = config.prerender.bind(this);
192
+ }
193
+
194
+ }
195
+
196
+ getConfig(key?: string, defaultValue?: any): ViewControllerConfig | any {
197
+ if (key) {
198
+ return this.runtimeConfig?.[key] ?? (this.config[key] ?? defaultValue);
199
+ }
200
+ return { ...this.runtimeConfig, ...this.config };
201
+ }
202
+
203
+ /** Set static view config shared by all instances of a compiled view class. */
204
+ setStaticConfig(config: ViewConfig): void {
205
+ this.config = config || {};
206
+ }
207
+
208
+ /** Set user-defined properties/methods on the View instance */
209
+ setUserDefinedConfig(userConfig: Record<string, any>): void {
210
+ for (const [key, value] of Object.entries(userConfig)) {
211
+ if (!this.ownProperties.has(key)) {
212
+ (this.view as any)[key] = typeof value === 'function' && value.bind
213
+ ? value.bind(this.view)
214
+ : value;
215
+ }
216
+ }
217
+ }
218
+
219
+ /** Set the compiled render factory */
220
+ setRenderFactory(factory: ViewRenderFactory): void {
221
+ this.renderFactory = factory;
222
+ }
223
+
224
+ /** Set root element — the container this view renders into */
225
+ setRootElement(rootElement: HtmlInterface): void {
226
+ this.rootElement = rootElement;
227
+ }
228
+
229
+ setParentElement(parent: HtmlInterface | null): void {
230
+ this.parentElement = parent;
231
+ }
232
+
233
+ /** Render the view's element tree into rootElement.
234
+ *
235
+ * The compiled render factory (bound to this ViewController) returns
236
+ * the root element tree (typically a Fragment). We set its parent
237
+ * to rootElement, call render() to build DOM, and store the reference
238
+ * for start/stop lifecycle management.
239
+ */
240
+ render(): any {
241
+ const oldCallingMethod = this.callingMethod;
242
+ this.callingMethod = 'render';
243
+ let output = this.renderFactory ? this.renderFactory() : null;
244
+ if (this.isVirtualRendering) {
245
+ return output;
246
+ }
247
+ this.renderOutput = output;
248
+ this.callingMethod = oldCallingMethod;
249
+ return output;
250
+ }
251
+
252
+ prerender(): any {
253
+ const oldCallingMethod = this.callingMethod;
254
+ this.callingMethod = 'prerender';
255
+ let output = this.prerenderFactory ? this.prerenderFactory() : null;
256
+ if (this.isVirtualRendering) {
257
+ return output;
258
+ }
259
+ this.prerenderOutput = output;
260
+ this.callingMethod = oldCallingMethod;
261
+ return output;
262
+ }
263
+
264
+ hydrate(): any {
265
+ this.initMode = 'hydrate';
266
+ }
267
+
268
+ hydrateRender(): any {
269
+ this.initMode = 'hydrate';
270
+ let output = this.render();
271
+ this.initMode = 'create';
272
+ return output;
273
+ }
274
+ hydratePrerender(): any {
275
+ this.initMode = 'hydrate';
276
+ let output = this.prerender();
277
+ this.initMode = 'create';
278
+ return output;
279
+ }
280
+
281
+ mount(root: HTMLElement): void {
282
+
283
+ }
284
+
285
+ unmount(): void {
286
+
287
+ }
288
+
289
+ /**
290
+ * Start — activate reactive subscriptions throughout the element tree.
291
+ * Called AFTER render() and commitData().
292
+ *
293
+ * Flow: render() → commitData() → start()
294
+ * This ensures initial state values are set before subscriptions fire.
295
+ */
296
+ start(): void {
297
+ if (this._isDestroyed || !this._rootTree) return;
298
+
299
+ // Recursively start all children (Output, TextElement, Html, Reactive, Fragment)
300
+ if ('start' in this._rootTree && typeof this._rootTree.start === 'function') {
301
+ this._rootTree.start();
302
+ }
303
+
304
+ // Fire onMounted hook
305
+ if (typeof this.view.onMounted === 'function') {
306
+ try {
307
+ this.view.onMounted();
308
+ } catch (e) {
309
+ console.error(`[ViewController] onMounted error in "${this.path}":`, e);
310
+ }
311
+ }
312
+ }
313
+
314
+ /**
315
+ * Stop — deactivate reactive subscriptions (for caching/deactivation).
316
+ * DOM stays intact but reactive updates are paused.
317
+ */
318
+ stop(): void {
319
+ if (this._isDestroyed || !this._rootTree) return;
320
+
321
+ // Recursively stop all children
322
+ if ('stop' in this._rootTree && typeof this._rootTree.stop === 'function') {
323
+ this._rootTree.stop();
324
+ }
325
+
326
+ // Fire onDeactivated hook
327
+ if (typeof this.view.onDeactivated === 'function') {
328
+ try {
329
+ this.view.onDeactivated();
330
+ } catch (e) {
331
+ console.error(`[ViewController] onDeactivated error in "${this.path}":`, e);
332
+ }
333
+ }
334
+ }
335
+
336
+ /** Full destroy — cleanup everything */
337
+ destroy(): void {
338
+ if (this._isDestroyed) return;
339
+ this._isDestroyed = true;
340
+
341
+ // Stop reactive subscriptions first
342
+ this.stop();
343
+
344
+ // Cancel pending updates
345
+ this.pendingReactiveUpdates.clear();
346
+ this.hasScheduledUpdate = false;
347
+
348
+ // Abort all event listeners
349
+ this.eventAbortController.abort();
350
+
351
+ // Destroy root tree
352
+ if (this._rootTree && 'destroy' in this._rootTree && typeof this._rootTree.destroy === 'function') {
353
+ this._rootTree.destroy();
354
+ }
355
+ this._rootTree = null;
356
+
357
+
358
+ // Destroy state
359
+ this.states.__.destroy();
360
+
361
+ // Cleanup loop context stack
362
+ this.loopContext = null;
363
+
364
+ // Fire onDestroy hook
365
+ if (typeof this.view.onDestroy === 'function') {
366
+ try {
367
+ this.view.onDestroy();
368
+ } catch (e) {
369
+ console.error(`[ViewController] onDestroy error in "${this.path}":`, e);
370
+ }
371
+ }
372
+
373
+ // Nullify references
374
+ this.rootElement = null;
375
+ this.renderFactory = null;
376
+ this.prerenderFactory = null;
377
+ this._isMounted = false;
378
+ }
379
+
380
+ // ─── Data Lifecycle ─────────────────────────────────────────
381
+
382
+ /**
383
+ * Commit initial data — set initial state values.
384
+ * Called by ViewManager AFTER render + block mounting.
385
+ *
386
+ * Flow: commitConstructorData() → update$xxx(initial) → lockUpdateRealState()
387
+ */
388
+ commitData(): void {
389
+ }
390
+
391
+ /**
392
+ * Update data from external source (navigate same view, different params).
393
+ * Flow: unlock → updateVariableData(newData) → re-set states → lock
394
+ */
395
+ updateData(newData: Record<string, any>): void {
396
+ this.runtimeConfig?.updateVariableData?.(newData);
397
+ }
398
+
399
+ /**
400
+ * Update single data item.
401
+ */
402
+ updateDataItem(key: string, value: any): void {
403
+ }
404
+
405
+ // ─── Event Management ───────────────────────────────────────
406
+
407
+ /**
408
+ * Register event listeners on an element.
409
+ * All listeners are tracked via AbortController for centralized cleanup.
410
+ *
411
+ * Handlers can be:
412
+ * - Direct function: (event) => { ... }
413
+ * - Object with handler + params: { handler: fn, params: [...] }
414
+ * - Object with string handler (method name on view): { handler: 'handleClick' }
415
+ */
416
+ addEventListener(element: HTMLElement, event: string, handlers: OneElementEventHandler): void {
417
+ for (const h of handlers) {
418
+ let fn: EventListener;
419
+
420
+ if (typeof h === 'function') {
421
+ fn = h as EventListener;
422
+ } else if (typeof h === 'object' && h !== null) {
423
+ const handlerDef = h as { handler: string | ((event: Event) => any); params?: any[] };
424
+ if (typeof handlerDef.handler === 'string') {
425
+ // Method name on view
426
+ const methodName = handlerDef.handler;
427
+ const view = this.view;
428
+ fn = ((event: Event) => {
429
+ if (typeof (view as any)[methodName] === 'function') {
430
+ const params = handlerDef.params
431
+ ? handlerDef.params.map(p => {
432
+ if (typeof p === 'function') return p(event);
433
+ return p === '@EVENT' ? event : p;
434
+ })
435
+ : [event];
436
+ (view as any)[methodName](...params);
437
+ }
438
+ }) as EventListener;
439
+ } else if (typeof handlerDef.handler === 'function') {
440
+ const originalHandler = handlerDef.handler;
441
+ if (handlerDef.params) {
442
+ fn = ((event: Event) => {
443
+ const params = handlerDef.params!.map((p: any) => {
444
+ if (typeof p === 'function') return p(event);
445
+ return p === '@EVENT' ? event : p;
446
+ });
447
+ (originalHandler as Function).apply(this.view, params);
448
+ }) as EventListener;
449
+ } else {
450
+ fn = originalHandler as EventListener;
451
+ }
452
+ } else {
453
+ continue;
454
+ }
455
+ } else {
456
+ continue;
457
+ }
458
+
459
+ element.addEventListener(event, fn, { signal: this.eventAbortController.signal });
460
+ }
461
+ }
462
+
463
+ // ─── Reactive Scheduling ────────────────────────────────────
464
+
465
+ /**
466
+ * Schedule a reactive region for re-render.
467
+ * Multiple calls in the same frame are batched into a single RAF.
468
+ */
469
+ scheduleUpdate(reactive: ReactiveInterface): void {
470
+ if (this._isDestroyed) return;
471
+
472
+ this.pendingReactiveUpdates.add(reactive);
473
+
474
+ if (!this.hasScheduledUpdate) {
475
+ this.hasScheduledUpdate = true;
476
+ requestAnimationFrame(() => this.flushReactiveUpdates());
477
+ }
478
+ }
479
+
480
+ private flushReactiveUpdates(): void {
481
+ if (this._isDestroyed) return;
482
+ this.hasScheduledUpdate = false;
483
+
484
+ const updates = Array.from(this.pendingReactiveUpdates);
485
+ this.pendingReactiveUpdates.clear();
486
+
487
+ for (const reactive of updates) {
488
+ try {
489
+ reactive.render();
490
+ } catch (e) {
491
+ console.error(`[ViewController] Reactive update error in "${this.path}":`, e);
492
+ }
493
+ }
494
+ }
495
+
496
+
497
+ section(name: string, config: { type: SectionItemType; contentType?: SectionContentType; stateKeys?: string[], [key: string]: any }, contentRenderFactory: SectionContentRenderer): SectionInterface {
498
+ if (this.sections.has(name)) {
499
+ const section = this.sections.get(name);
500
+ if (section) {
501
+ return section;
502
+ }
503
+ }
504
+ config.ctx = this;
505
+ config.name = name;
506
+ config.renderFactory = contentRenderFactory;
507
+ const section = new Section(config as SectionConstruvtorArgs);
508
+ this.sections.set(name, section);
509
+ return section;
510
+ }
511
+
512
+
513
+ // template methods called by compiled output — these build the element tree directly
514
+
515
+ block(id: string | null, name: string, contentRenderFactory: BlockRenderFactory): BlockInterface {
516
+ if (!id) {
517
+ id = `b-${name}`;
518
+ }
519
+ const existing = this.blocks.get(id);
520
+ const initMode = this.initMode;
521
+ if (existing) {
522
+ existing.contentRenderFactory = contentRenderFactory;
523
+ BlockManager.active(name, this.viewId);
524
+ existing.initMode = initMode;
525
+ return existing;
526
+ }
527
+ const block = new Block({ ctx: this, name, id, initMode, contentRenderFactory });
528
+ this.blocks.set(id, block);
529
+ BlockManager.add(block);
530
+ return block;
531
+ }
532
+
533
+
534
+ blockOutlet(id: string | null = null, name: string, parentElement: HtmlInterface | null): BlockOutletInterface {
535
+ const initMode = this.initMode;
536
+ if(!id) {
537
+ id = `ob-${name}`;
538
+ }
539
+ const existing = this.elements.get(id);
540
+ if (existing instanceof BlockOutlet) {
541
+ existing.setParentElement(parentElement);
542
+ existing.initMode = initMode;
543
+ return existing;
544
+ }
545
+ const outlet = new BlockOutlet({ ctx: this, name, id, parentElement, initMode });
546
+ this.elements.set(id, outlet);
547
+ // do something if needed
548
+ return outlet;
549
+ }
550
+
551
+
552
+ mountBlock(id: string | null = null, name: string, parent: HtmlInterface | null): BlockOutletInterface {
553
+ return this.blockOutlet(id, name, parent);
554
+ }
555
+
556
+
557
+ /**
558
+ * @useBlock(name) — register a block slot in the layout.
559
+ * Creates a Reactive region between markers that will hold the block content.
560
+ * BlockManager.mountAll() later inserts the page view's block content here.
561
+ */
562
+ useBlock(id: string | null = null, name: string, parent: HtmlInterface): BlockOutlet {
563
+ return this.blockOutlet(id, name, parent);
564
+ }
565
+
566
+ yield(id: string, name: string, defaultValue: any = null, parentElement: HtmlInterface | null = null): YieldInterface {
567
+ const existing = this.elements.get(id);
568
+ if (existing instanceof YieldElement) {
569
+ existing.setParentElement(parentElement);
570
+ existing.defaultValue = defaultValue;
571
+ return existing;
572
+ }
573
+ const yieldEl = new YieldElement({ ctx: this, name, initMode: this.initMode, id, defaultValue });
574
+ yieldEl.setParentElement(parentElement);
575
+ this.elements.set(id, yieldEl);
576
+ return yieldEl;
577
+ }
578
+
579
+ yieldContent(name: string, defaultValue: any = null): any {
580
+ return this.App.View?.yieldContent?.(name, defaultValue) ?? defaultValue;
581
+ }
582
+
583
+ wrapper(factory: OneChildrenFactory): WrapperInterface {
584
+ const callingMethod = this.callingMethod;
585
+ let key: 'preloadElement' | 'mainElement' = callingMethod === 'prerender' ? 'preloadElement' : 'mainElement';
586
+ let wrapper = this[key];
587
+ if (!wrapper) {
588
+ wrapper = new Wrapper({ ctx: this, initMode: this.initMode, parentElement: this.parentElement, childrenFactory: factory });
589
+ this[key] = wrapper;
590
+ }else{
591
+ wrapper.setChildrenFactory(factory);
592
+ }
593
+ return wrapper;
594
+ }
595
+
596
+
597
+ fragment(id: string | null = null, parentElement: HtmlInterface | null, childrenFactory: OneChildrenFactory): FragmentInterface {
598
+ if (!id) {
599
+ id = `fr-${generateUUID(5)}`;
600
+ }
601
+ const existing = this.elements.get(id);
602
+ if (existing instanceof Fragment) {
603
+ if(childrenFactory) {
604
+ existing.setChildrenFactory(childrenFactory);
605
+ }
606
+ return existing;
607
+ }
608
+ const initMode = this.initMode;
609
+ const fragment = new Fragment({ctx: this, id, initMode, parentElement, childrenFactory });
610
+ this.elements.set(id, fragment);
611
+ return fragment;
612
+ }
613
+
614
+
615
+ /**
616
+ * Template and Directive Helpers
617
+ * These methods are called by the compiled output for loops, conditionals, and other directives.
618
+ */
619
+
620
+ html(id: string | null = null, tagName: string, parentElement: HtmlInterface | null, config: any, childrenFactory?: OneChildrenFactory): OneNodeInterface {
621
+ if (!id) {
622
+ id = `el-${tagName}-${generateUUID(5)}`;
623
+ }
624
+ const existing = this.elements.get(id);
625
+ if (existing instanceof Html) {
626
+ existing.updateConfig(config);
627
+ if(childrenFactory) {
628
+ existing.setChildrenFactory(childrenFactory);
629
+ }
630
+ return existing;
631
+ }
632
+ const element = new Html({ ctx: this, tagName, id, parentElement, initMode: this.initMode, config, childrenFactory });
633
+ this.elements.set(id, element);
634
+ return element;
635
+ }
636
+
637
+
638
+ reactive(id: string | null, type: string, parentReactive: ReactiveInterface | null, parentElement: HtmlInterface | null, stateKeys: string[], childrenFactory: ReactiveChildrenFactory): ReactiveInterface {
639
+ // check
640
+ if (!id) {
641
+ id = `r-${type}-${generateUUID(5)}`;
642
+ }
643
+ const existing = this.elements.get(id);
644
+ if (existing instanceof Reactive) {
645
+ existing.setChildrenFactory(childrenFactory);
646
+ existing.setStateKeys(stateKeys);
647
+ return existing;
648
+ }
649
+ const reactive: ReactiveInterface = new Reactive({
650
+ type,
651
+ id,
652
+ ctx: this,
653
+ parentReactive,
654
+ parentElement,
655
+ stateKeys,
656
+ childrenFactory
657
+ });
658
+ this.elements.set(id, reactive);
659
+ return reactive;
660
+ }
661
+
662
+ output(id: string | null, parent: HtmlInterface | null, isEscapeHTML: boolean = true, stateKeys: string[] = [], contentFactory: () => string = () => ''): OutputInterface {
663
+ if(!id) {
664
+ id = `o-${generateUUID(5)}`;
665
+ }
666
+ const existing = this.elements.get(id);
667
+ if (existing instanceof Output) {
668
+ existing.setStateKeys(stateKeys);
669
+ existing.contentFactory = contentFactory;
670
+ return existing;
671
+ }
672
+ const output = new Output({
673
+ ctx: this,
674
+ id,
675
+ parent,
676
+ stateKeys,
677
+ isEscapeHTML,
678
+ contentFactory,
679
+ });
680
+ this.elements.set(id, output);
681
+ return output;
682
+ }
683
+
684
+ text(text: string): Text{
685
+ return document.createTextNode(text) as Text;
686
+ }
687
+
688
+ include(
689
+ id: string | null = null,
690
+ path: string = '',
691
+ parentElement: HtmlInterface | null,
692
+ stateKeys: string[],
693
+ dataFactory: (parentElement: HtmlInterface | null) => Record<string, any>
694
+ ): Component {
695
+ if(!id) {
696
+ id = `cpn-${generateUUID(5)}`;
697
+ }
698
+ const existing = this.elements.get(id);
699
+ if (existing instanceof Component) {
700
+ existing.setDataFactory(dataFactory);
701
+ if(stateKeys) {
702
+ existing.setStateKeys(stateKeys);
703
+ }
704
+ return existing;
705
+ }
706
+ let component = new Component({
707
+ ctx: this,
708
+ id: id ?? generateUUID(10),
709
+ stateKeys,
710
+ parent: parentElement,
711
+ dataFactory,
712
+ path,
713
+ type: 'default',
714
+ });
715
+ this.elements.set(id, component);
716
+
717
+ return component;
718
+ }
719
+
720
+ includeIf(id: string | null = null, path: string, parentElement: HtmlInterface | null, stateKeys: string[], dataFactory: (parentElement: HtmlInterface | null) => Record<string, any>): Component {
721
+ if(!id) {
722
+ id = `c-${generateUUID(5)}`;
723
+ }
724
+ const existing = this.elements.get(id);
725
+ if (existing instanceof Component) {
726
+ existing.setDataFactory(dataFactory);
727
+ if(stateKeys) {
728
+ existing.setStateKeys(stateKeys);
729
+ }
730
+ return existing;
731
+ }
732
+ let component = new Component({
733
+ ctx: this,
734
+ id: id ?? generateUUID(10),
735
+ stateKeys,
736
+ parent: parentElement,
737
+ dataFactory,
738
+ path,
739
+ type: 'if',
740
+ });
741
+ this.elements.set(id, component);
742
+ return component;
743
+ }
744
+
745
+ includeWhen(id: string | null, condition: { stateKeys: string[], checker: () => any }, path: string, parentElement: HtmlInterface | null, stateKeys: string[], dataFactory: (parentElement: HtmlInterface | null) => Record<string, any>): Component {
746
+ if(!id) {
747
+ id = `cpn-${generateUUID(5)}`;
748
+ }
749
+ const existing = this.elements.get(id);
750
+ if (existing instanceof Component) {
751
+ existing.setDataFactory(dataFactory);
752
+ existing.setCondition(condition);
753
+ if(stateKeys) {
754
+ existing.setStateKeys(stateKeys);
755
+ }
756
+ return existing;
757
+ }
758
+ let component = new Component({
759
+ ctx: this,
760
+ id: id ?? generateUUID(10),
761
+ stateKeys,
762
+ parent: parentElement,
763
+ dataFactory,
764
+ path,
765
+ type: 'when',
766
+ condition,
767
+ });
768
+ this.elements.set(id, component);
769
+ return component;
770
+ }
771
+
772
+ extendView(path: string, data: Record<string, any> = {}): ViewInterface | null {
773
+ this.superViewPath = path;
774
+ const superView:ViewInterface = this.App.View?.view(path, data, true);
775
+ if(superView){
776
+ this.setSuperView(superView?.__ctrl__);
777
+ return superView;
778
+ }
779
+
780
+ // If super view not found, log error and return null
781
+ return superView;
782
+ }
783
+
784
+
785
+ // ─── Loop Directives ────────────────────────────────────────
786
+
787
+ /** Create and push a new LoopContext onto the stack */
788
+ __setLoopContext(length: number): LoopContext {
789
+ const parent = this.loopContext;
790
+ this.loopContext = new LoopContext(parent);
791
+ this.loopContext.setCount(length);
792
+ return this.loopContext;
793
+ }
794
+
795
+ /** Pop the current LoopContext, restore parent */
796
+ __resetLoopContext(): LoopContext | null {
797
+ if (this.loopContext?.parent) {
798
+ const parent = this.loopContext.parent;
799
+ this.loopContext.parent = null;
800
+ Object.freeze(this.loopContext);
801
+ this.loopContext = parent;
802
+ } else if (this.loopContext) {
803
+ Object.freeze(this.loopContext);
804
+ this.loopContext = null;
805
+ }
806
+ return this.loopContext;
807
+ }
808
+
809
+ /**
810
+ * @foreach directive — iterate over array or object.
811
+ * Returns array of children (not HTML string like the old system).
812
+ *
813
+ * @example Compiled output:
814
+ * ctrl.__foreach(items, (item, key, index, loop) => [
815
+ * em.h(ctrl, parent, 'div', {}, () => [em.t(`Item: ${item}`)])
816
+ * ])
817
+ */
818
+ __foreach<T>(
819
+ list: T[] | Record<string, T>,
820
+ callback: (item: T, key: string, index: number, loop: LoopContext) => any
821
+ ): any[] {
822
+ if (!list || typeof list !== 'object') return [];
823
+
824
+ const result: any[] = [];
825
+ try {
826
+ if (Array.isArray(list)) {
827
+ const loopCtx = this.__setLoopContext(list.length);
828
+ loopCtx.setType('increment');
829
+ list.forEach((item, index) => {
830
+ loopCtx.setCurrentTimes(index);
831
+ const output = callback(item, String(index), index, loopCtx);
832
+ if (output !== undefined && output !== null) {
833
+ if (Array.isArray(output)) result.push(...output);
834
+ else result.push(output);
835
+ }
836
+ });
837
+ } else {
838
+ const keys = Object.keys(list);
839
+ const loopCtx = this.__setLoopContext(keys.length);
840
+ loopCtx.setType('increment');
841
+ keys.forEach((key, index) => {
842
+ loopCtx.setCurrentTimes(index);
843
+ const output = callback((list as Record<string, T>)[key], key, index, loopCtx);
844
+ if (output !== undefined && output !== null) {
845
+ if (Array.isArray(output)) result.push(...output);
846
+ else result.push(output);
847
+ }
848
+ });
849
+ }
850
+ } catch (e) {
851
+ console.error(`[ViewController] @foreach error in "${this.path}":`, e);
852
+ } finally {
853
+ this.__resetLoopContext();
854
+ }
855
+ return result;
856
+ }
857
+
858
+ __forelse<T>(list: T[], callback: (item: T, key: string, index: number, loop: LoopContext) => any, emptyCallback: () => any = () => []): any[] {
859
+ if (this.App.Helper.count(list) === 0) {
860
+ return emptyCallback();
861
+ }
862
+ return this.__foreach(list, callback);
863
+ }
864
+
865
+ __each<T>(list: T[], callback: (item: T, key: string, index: number, loop: LoopContext) => any): any[] {
866
+ return this.__foreach(list, callback);
867
+ }
868
+
869
+ /**
870
+ * @for directive
871
+ */
872
+ __for(
873
+ loopType: 'increment' | 'decrement' = 'increment',
874
+ start: number = 0,
875
+ end: number = 0,
876
+ execute: (loop: LoopContext) => any = () => []
877
+ ): any {
878
+ const loopCtx = this.__setLoopContext(end);
879
+ loopCtx.setType(loopType);
880
+ let result: any;
881
+ try {
882
+ result = typeof execute === 'function' ? execute(loopCtx) : [];
883
+ } catch (e) {
884
+ console.error(`[ViewController] @for error in "${this.path}":`, e);
885
+ result = [];
886
+ } finally {
887
+ this.__resetLoopContext();
888
+ }
889
+ return result;
890
+ }
891
+
892
+ /**
893
+ * @while directive
894
+ */
895
+ __while(execute: (loop: LoopContext) => any, maxIterations: number = 10000): any {
896
+ const loopCtx = this.__setLoopContext(-1);
897
+ loopCtx.setType('increment');
898
+ let result: any;
899
+ try {
900
+ result = typeof execute === 'function' ? execute(loopCtx) : [];
901
+ } catch (e) {
902
+ console.error(`[ViewController] @while error in "${this.path}":`, e);
903
+ result = [];
904
+ } finally {
905
+ if (loopCtx.count === -1) {
906
+ (loopCtx as any).count = loopCtx.iteration;
907
+ }
908
+ this.__resetLoopContext();
909
+ }
910
+ return result;
911
+ }
912
+
913
+
914
+ // mounting
915
+
916
+
917
+ // ─── Config & App Access ────────────────────────────────────
918
+
919
+ setApp(app: ApplicationInterface): void {
920
+ this.__App = app;
921
+ }
922
+
923
+
924
+ getParentView(): ViewInterface | null {
925
+ return this.parent ? this.parent.view : null;
926
+ }
927
+ getChildrenViews(): ViewInterface[] {
928
+ return this.children.map(child => child.view);
929
+ }
930
+
931
+ getSuperView(): ViewInterface | null {
932
+ return this.superView ? this.superView.view : null;
933
+ }
934
+
935
+ getOriginView(): ViewInterface | null {
936
+ return this.originView?.view || null;
937
+ }
938
+
939
+ setOriginView(origin: ViewControllerInterface): void {
940
+ this.originView = origin;
941
+ }
942
+ setSuperView(superView: ViewControllerInterface): void {
943
+ this.superView = superView;
944
+ }
945
+ setIsSuperView(isSuper: boolean): void {
946
+ this.isSuperView = isSuper;
947
+ }
948
+ setParent(parent: ViewControllerInterface): void {
949
+ this.parent = parent;
950
+ }
951
+ addChild(child: ViewControllerInterface): void {
952
+ this.children.push(child);
953
+ }
954
+
955
+
956
+ /**
957
+ * For nested views: set the chain of super views up to the root, so each view has a reference to its layout parents.
958
+ * Called by ViewManager after creating the view and its super view(s).
959
+ */
960
+ setChainFromOrigin(): void {
961
+ if(this.superView){
962
+ this.superView.setOriginView(this);
963
+ this.superView.setChainFromOrigin();
964
+ }
965
+ }
966
+
967
+ /**
968
+ * When a view is destroyed, it should eject itself from the origin chain to prevent memory leaks.
969
+ */
970
+ ejectOriginChain(): void {
971
+ if(this.originView){
972
+ const origin = this.originView;
973
+ this.originView = null;
974
+ origin.ejectOriginChain();
975
+ }
976
+ }
977
+
978
+ get App(): ApplicationInterface {
979
+ return this.__App as ApplicationInterface;
980
+ }
981
+
982
+ get isMounted(): boolean {
983
+ return this._isMounted;
984
+ }
985
+
986
+ get isDestroyed(): boolean {
987
+ return this._isDestroyed;
988
+ }
989
+
990
+
991
+ /** Whether this view has a super view (layout) */
992
+ get hasSuperView(): boolean {
993
+ return this.superViewPath !== null && this.superViewPath !== '';
994
+ }
995
+
996
+
997
+ // ─── Private ────────────────────────────────────────────────
998
+
999
+ private generateViewId(): string {
1000
+ return `v_${Date.now().toString(36)}_${Math.random().toString(36).substring(2, 8)}`;
1001
+ }
1002
+ }