@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,700 @@
1
+ /**
2
+ * ViewManager — Orchestrateur quản lý view lifecycle.
3
+ *
4
+ * Responsibilities:
5
+ * 1. Load view modules (dynamic import hoặc registry)
6
+ * 2. Invoke factory → get View instance
7
+ * 3. Resolve layout chain (if hasSuperView)
8
+ * 4. Mount vào container
9
+ * 5. commitData cho all views in chain
10
+ * 6. Start all views (activate reactivity)
11
+ * 7. Track active views for cleanup
12
+ *
13
+ * Khác core/ ViewManager:
14
+ * - Nhẹ hơn (~300 dòng thay vì 1145)
15
+ * - Tách rõ concern: ViewManager chỉ orchestrate, không render HTML string
16
+ * - Element tree rendering → ViewController.render()
17
+ * - Section system → Block/BlockOutlet
18
+ */
19
+
20
+ import type { ApplicationInterface } from "../contracts/ApplicationInterface";
21
+ import { ActiveRouteInterface, RouterNavigationType } from "../contracts/RouterInterface";
22
+ import { FragmentInterface, HtmlInterface } from "../contracts/utils";
23
+ import type { ViewControllerConfig, ViewControllerInterface } from "../contracts/ViewControllerInterface";
24
+ import type { ViewInterface } from "../contracts/ViewInterface";
25
+ import type { ViewManagerInterface, ActiveViewInfo } from "../contracts/ViewManagerInterface";
26
+ import { BlockManager, BlockManagerService } from "../services/BlockManager";
27
+ import { Html } from "../elements/Html";
28
+ import { hasData } from "../hellpers/utils";
29
+ import logger from "../services/LoggerService";
30
+ import { StoreService } from "../services/StoreService";
31
+ import { View } from "./View";
32
+ import { InitMode, InitModes } from "../contracts/common";
33
+ import { OOTEnum } from "../types/utils";
34
+ import { WrapperInterface } from "../contracts/ElementInterface";
35
+ import { app } from "../hellpers/app";
36
+
37
+ type RenderPageViewSuccess = {
38
+ type: 'success';
39
+ message: string;
40
+ view: ViewInterface;
41
+ result: ViewInterface | unknown;
42
+ superView: ViewInterface | null;
43
+ finalView: ViewInterface;
44
+ };
45
+
46
+ type RenderPageViewError = {
47
+ type: 'error';
48
+ message: string;
49
+ view: ViewInterface;
50
+ result: null;
51
+ superView: null;
52
+ finalView: ViewInterface;
53
+ };
54
+
55
+ type RenderPageViewResult = RenderPageViewSuccess | RenderPageViewError;
56
+
57
+ function isRenderableObject(result: unknown): result is { oneType: string } {
58
+ return typeof result === 'object' && result !== null && 'oneType' in result;
59
+ }
60
+
61
+ export class ViewManager implements ViewManagerInterface {
62
+ /** DI container */
63
+ private App: ApplicationInterface | null = null;
64
+
65
+ private systemData: Record<string, any> = {}; // For internal use, not exposed to views
66
+
67
+ /** ROOT DOM container where views mount */
68
+ private container: HTMLElement | null = null;
69
+ private rootElement: Html | null = null; // Html wrapper for the root container
70
+ /** View module registry: name → factory or async loader */
71
+ private viewRegistry: Record<string, ((...args: any[]) => any) | (() => Promise<any>)> = {};
72
+
73
+ /** Currently mounted views (keyed by path) */
74
+ private activeViews: Map<string, ActiveViewInfo> = new Map();
75
+
76
+ /** The outermost active view (layout or page) */
77
+ private currentView: ActiveViewInfo | null = null;
78
+
79
+ /** Current layout path — for layout reuse detection */
80
+ private currentLayoutPath: string | null = null;
81
+
82
+ private currentLayoutView: ViewInterface | null = null; // Store the current layout view instance for reuse
83
+ private currentPageView: ViewInterface | null = null; // Store the current page view instance for reference in blocks and sections
84
+ private currentViewType: 'view' | 'layout' | null = null; // Track whether the current view is a page or layout for correct lifecycle handling
85
+
86
+
87
+ /** Current layout view info — reused if same layout */
88
+ private currentLayout: ActiveViewInfo | null = null;
89
+
90
+ private cachedLayouts: Map<string, ViewInterface> = new Map(); // Cache for previously mounted layouts
91
+
92
+ /** All views in the current mount chain (outermost → innermost) */
93
+ private viewStack: ViewInterface[] = [];
94
+
95
+ /** Whether the manager has been initialized */
96
+ private _isInitialized = false;
97
+
98
+ /** Render counter for debugging */
99
+ private renderCount = 0;
100
+
101
+ public store: StoreService = StoreService.instance("ViewManager");
102
+
103
+ public blockManager: BlockManagerService = BlockManager;
104
+
105
+ constructor(app?: ApplicationInterface) {
106
+ if (app) this.App = app;
107
+ }
108
+ isViewMounted(path: string): boolean {
109
+ throw new Error("Method not implemented.");
110
+ }
111
+ destroy(): void {
112
+ throw new Error("Method not implemented.");
113
+ }
114
+
115
+
116
+ // ─── Configuration ──────────────────────────────────────────
117
+
118
+ /**
119
+ * Set the DI container reference.
120
+ */
121
+ setApp(app: ApplicationInterface): void {
122
+ this.App = app;
123
+ }
124
+
125
+ /**
126
+ * Set the root DOM container.
127
+ */
128
+ setContainer(container: HTMLElement): void {
129
+ this.container = container;
130
+ }
131
+
132
+ /**
133
+ * Get the root container element.
134
+ */
135
+ getContainer(): HTMLElement | null {
136
+ return this.container;
137
+ }
138
+
139
+ /**
140
+ * Register view modules.
141
+ *
142
+ * @example
143
+ * viewManager.setViewRegistry({
144
+ * 'web.home': () => import('./views/web/home.js'),
145
+ * 'web.about': () => import('./views/web/about.js'),
146
+ * 'layouts.main': () => import('./views/layouts/main.js'),
147
+ * });
148
+ */
149
+ setViewRegistry(registry: Record<string, ((...args: any[]) => any) | (() => Promise<any>)>): void {
150
+ this.viewRegistry = { ...this.viewRegistry, ...registry };
151
+ }
152
+
153
+ /**
154
+ * Register a single view module.
155
+ */
156
+ registerView(name: string, loader: ((...args: any[]) => any) | (() => Promise<any>)): void {
157
+ this.viewRegistry[name] = loader;
158
+ }
159
+
160
+ /**
161
+ * Initialize the ViewManager.
162
+ */
163
+ init(config?: { container?: HTMLElement | string; registry?: Record<string, any> }): void {
164
+ if (config?.container) {
165
+ if (typeof config.container === 'string') {
166
+ const found = document.querySelector(config.container);
167
+ if (found instanceof HTMLElement) {
168
+ this.container = found;
169
+
170
+ } else {
171
+ console.warn(`[ViewManager] Container selector "${config.container}" not found.`);
172
+ }
173
+ } else {
174
+ this.container = config.container instanceof HTMLElement ? config.container : document.body;
175
+ }
176
+ }
177
+ if (!this.container) {
178
+ this.container = document.body; // Default to body if no container provided
179
+ }
180
+ this.rootElement = new Html({
181
+ ctx: this,
182
+ tagName: this.container.tagName.toLowerCase(),
183
+ element: this.container,
184
+ initMode: 'hydrate',
185
+ });
186
+ if (config?.registry) {
187
+ this.setViewRegistry(config.registry);
188
+ }
189
+ this._isInitialized = true;
190
+ }
191
+
192
+ showError(message: string, details?: any) {
193
+ logger.error(message, details);
194
+ if (this.container) {
195
+ this.container.innerHTML = `<div style="padding: 20px; background: #fee; color: #900; border: 1px solid #900;">
196
+ <h2>Error</h2>
197
+ <p>${message}</p>
198
+ ${details ? `<pre style="white-space: pre-wrap; background: #fdd; padding: 10px; border: 1px solid #900;">${JSON.stringify(details, null, 2)}</pre>` : ''}
199
+ </div>`;
200
+ }
201
+ }
202
+
203
+ // ─── View Loading ───────────────────────────────────────────
204
+ hasView(name: string): boolean {
205
+ return Object.prototype.hasOwnProperty.call(this.viewRegistry, name);
206
+ }
207
+
208
+ exists(name: string): boolean {
209
+ return this.hasView(name);
210
+ }
211
+
212
+ view(name: string, data: Record<string, any>, cache: boolean): any {
213
+ try {
214
+ if (cache && this.store.has(name)) {
215
+ const cachedView = this.store.get<View>(name);
216
+ if (hasData(data)) {
217
+ cachedView?.__ctrl__.updateData(data);
218
+ }
219
+ return cachedView;
220
+ }
221
+ const factory = this.viewRegistry[name];
222
+ if (!factory || typeof factory !== 'function') {
223
+ logger.error(`View "${name}" not found in registry.`);
224
+ return null;
225
+ }
226
+ const view = factory(data ? { data } : {}, { App: this.App, View: this, ...this.systemData });
227
+ if (!view) {
228
+ logger.error(`Factory for view "${name}" did not return a valid view instance.`);
229
+ return null;
230
+ }
231
+ if (cache) {
232
+ this.store.set(name, view);
233
+ }
234
+ return view;
235
+
236
+ }
237
+ catch (err) {
238
+ logger.error(`Error loading view ${name}:`, err);
239
+ return null;
240
+ }
241
+ }
242
+
243
+ private createRenderPageViewError(view: ViewInterface, renderLevel: number, message?: string): RenderPageViewError {
244
+ return {
245
+ type: 'error',
246
+ message: message ?? (renderLevel === 0
247
+ ? `View "${view.__ctrl__.path}" did not return any content from render().`
248
+ : `Nested view "${view.__ctrl__.path}" did not return any content from render().`),
249
+ view,
250
+ result: null,
251
+ superView: null,
252
+ finalView: view,
253
+ };
254
+ }
255
+
256
+ private createRenderPageViewSuccess(
257
+ view: ViewInterface,
258
+ result: ViewInterface | unknown,
259
+ superView: ViewInterface | null,
260
+ finalView: ViewInterface
261
+ ): RenderPageViewSuccess {
262
+ return {
263
+ type: 'success',
264
+ message: '',
265
+ view,
266
+ result,
267
+ superView,
268
+ finalView,
269
+ };
270
+ }
271
+
272
+ private getRenderResultType(result: unknown): OOTEnum {
273
+ return isRenderableObject(result) ? result.oneType as OOTEnum : OOTEnum.UNKNOWN;
274
+ }
275
+
276
+
277
+ async callViewRenderFactory(
278
+ view: ViewInterface,
279
+ method: 'render' | 'prerender' = 'render',
280
+ data: Record<string, any> = {},
281
+ mountRoot: HtmlInterface | null = null,
282
+ initMode: InitMode = InitModes.CREATE,
283
+ cache: boolean = false,
284
+ renderLevel: number = 0
285
+ ): Promise<RenderPageViewResult> {
286
+ const ctrl = view.__ctrl__;
287
+
288
+ if (hasData(data)) {
289
+ ctrl.updateData(data);
290
+ }
291
+
292
+ const result = method === 'render'
293
+ ? ctrl.render()
294
+ : (ctrl.prerender ? ctrl.prerender() : null);
295
+
296
+ if (!result) {
297
+ return this.createRenderPageViewError(view, renderLevel,
298
+ `View "${ctrl.path}" returned nothing from ${method}().`);
299
+ }
300
+
301
+ const resultType = this.getRenderResultType(result);
302
+
303
+ if (resultType === OOTEnum.WRAPPER) {
304
+ return this.createRenderPageViewSuccess(view, result, null, view);
305
+ }
306
+
307
+ if (resultType === OOTEnum.VIEW) {
308
+ const superResult = await this.renderPageView(
309
+ result as ViewInterface, {}, mountRoot, initMode, cache, renderLevel + 1
310
+ );
311
+ if (superResult.type === 'error') {
312
+ return { ...superResult, view };
313
+ }
314
+ return this.createRenderPageViewSuccess(
315
+ view,
316
+ result,
317
+ superResult.view,
318
+ superResult.finalView ?? (result as ViewInterface)
319
+ );
320
+ }
321
+
322
+ return this.createRenderPageViewError(view, renderLevel,
323
+ `View "${ctrl.path}" returned invalid content (type: ${resultType}) from ${method}().`);
324
+ }
325
+
326
+ async renderPageView(
327
+ view: ViewInterface,
328
+ data: Record<string, any>,
329
+ mountRoot: HtmlInterface | null = null,
330
+ initMode: InitMode = InitModes.CREATE,
331
+ cache: boolean = false,
332
+ renderLevel: number = 0
333
+ ): Promise<RenderPageViewResult> {
334
+ try {
335
+ const ctrl = view.__ctrl__;
336
+ if (hasData(data)) {
337
+ ctrl.updateData(data);
338
+ }
339
+ const config: ViewControllerConfig = ctrl.getConfig();
340
+ const hasAsyncData = config.hasAwaitData || config.hasFetchData;
341
+
342
+ // ── Case 1: Không có async data → render ngay ──
343
+ if (!hasAsyncData) {
344
+ return this.callViewRenderFactory(view, 'render', data, mountRoot, initMode, cache, renderLevel);
345
+ }
346
+
347
+ // ── Resolve fetch URL từ ViewController config hoặc fallback Router ──
348
+ const App = app() as ApplicationInterface;
349
+ const Http = App.Http;
350
+ const fetchConfig = config.fetch;
351
+ const fetchUrl = (config.hasAwaitData && fetchConfig?.url)? fetchConfig?.url : App.Router.getFullUrl();
352
+
353
+ // ── Case 2: Có async + có prerender → prerender skeleton trước, fetch sau ──
354
+ if (config.hasPrerender) {
355
+ const prerenderResult = await this.callViewRenderFactory(view, 'prerender', data, mountRoot, initMode, cache, renderLevel);
356
+ if (prerenderResult.type === 'error') {
357
+ logger.error(`Error prerendering view "${ctrl.path}":`, prerenderResult.message);
358
+ // Fallback: render trực tiếp không qua prerender
359
+ return this.callViewRenderFactory(view, 'render', data, mountRoot, initMode, cache, renderLevel);
360
+ }
361
+
362
+ // Fire-and-forget: fetch data rồi re-render thay thế skeleton
363
+ // TODO: Sau khi render() xong, cần swap DOM từ preloadElement → mainElement
364
+ // ViewController.wrapper() tự động lưu prerender vào preloadElement, render vào mainElement
365
+ // Cần bổ sung logic: unmount preloadElement khỏi DOM → mount mainElement vào cùng vị trí
366
+ Http.get(fetchUrl).then(async (response: any) => {
367
+ const asyncData = response?.data ?? {};
368
+ if (hasData(asyncData)) {
369
+ ctrl.updateData(asyncData);
370
+ }
371
+ const finalResult = await this.callViewRenderFactory(view, 'render', asyncData, mountRoot, initMode, cache, renderLevel);
372
+ if (finalResult.type === 'error') {
373
+ logger.error(`Error rendering view "${ctrl.path}" after async data fetch:`, finalResult.message);
374
+ }
375
+ // TODO: swap preloadElement → mainElement trong DOM
376
+ // ctrl.preloadElement?.destroy();
377
+ // ctrl.mainElement?.setParentElement(mountRoot);
378
+ // ctrl.mainElement?.render();
379
+ }).catch((err: any) => {
380
+ logger.error(`Error fetching async data for view "${ctrl.path}":`, err);
381
+ });
382
+
383
+ // Return prerender result ngay — mountView sẽ mount skeleton
384
+ return prerenderResult;
385
+ }
386
+
387
+ // ── Case 3: Có async + không prerender → await fetch rồi render ──
388
+ let asyncData: Record<string, any> = {};
389
+ try {
390
+ const response = await Http.get(fetchUrl);
391
+ asyncData = response?.data ?? {};
392
+ } catch (err) {
393
+ logger.error(`Error fetching async data for view "${ctrl.path}":`, err);
394
+ }
395
+
396
+ if (!hasData(asyncData)) {
397
+ logger.warn(`View "${ctrl.path}" has async data config but fetch returned no data.`);
398
+ }
399
+
400
+ return this.callViewRenderFactory(view, 'render', asyncData, mountRoot, initMode, cache, renderLevel);
401
+ }
402
+ catch (err) {
403
+ logger.error(`Error rendering view ${view.__ctrl__.path}:`, err);
404
+ return this.createRenderPageViewError(view, renderLevel, `Error rendering view "${view.__ctrl__.path}".`);
405
+ }
406
+ }
407
+
408
+
409
+
410
+
411
+
412
+
413
+
414
+
415
+
416
+
417
+ // ─── Mount Orchestration ────────────────────────────────────
418
+
419
+ async mountView(name: string, data?: Record<string, any>, route?: ActiveRouteInterface, navigationType: RouterNavigationType = 'push'): Promise<any> {
420
+ // ── Phase 1: Load view ──
421
+ const view = this.view(name, data ?? {}, true);
422
+ if (!view) {
423
+ this.showError(`Failed to load view "${name}".`);
424
+ return null;
425
+ }
426
+
427
+ const oldPageView = this.currentPageView;
428
+ const oldLayoutView = this.currentLayoutView;
429
+ const oldLayoutPath = this.currentLayoutPath;
430
+
431
+ view.__ctrl__.urlPath = route?.$urlPath ?? null;
432
+
433
+ if(oldLayoutView){
434
+ oldLayoutView.__ctrl__.stop();
435
+ }
436
+ oldPageView?.__ctrl__.stop();
437
+
438
+ // ── Phase 2: Render chain ──
439
+ const renderResult = await this.renderPageView(view, data ?? {}, this.rootElement, InitModes.CREATE, true);
440
+ if (renderResult.type === 'error') {
441
+ this.showError(renderResult.message);
442
+ return null;
443
+ }
444
+
445
+ const pageView: ViewInterface = renderResult.view;
446
+ const finalView: ViewInterface = renderResult.finalView;
447
+ const hasSuperView = renderResult.superView !== null;
448
+ const newLayoutPath = hasSuperView ? finalView.__ctrl__.path : null;
449
+
450
+ // bắt đầu logic
451
+
452
+ // ── Phase 3: Classify mount scenario ──
453
+ const isSameLayout = hasSuperView
454
+ && oldLayoutView !== null
455
+ && finalView === oldLayoutView;
456
+
457
+ // ── Duplicate navigation guard ──
458
+ if (oldPageView === pageView
459
+ && view.__ctrl__.urlPath === oldPageView?.__ctrl__?.urlPath) {
460
+ return renderResult;
461
+ }
462
+
463
+ // ══════════════════════════════════════════════════════════
464
+ // Case 1: Có superView + cùng layout instance (reuse layout)
465
+ // ══════════════════════════════════════════════════════════
466
+ if (hasSuperView && isSameLayout) {
467
+ // Cắt origin chain cũ → gắn page mới vào layout
468
+ oldLayoutView!.__ctrl__.ejectOriginChain();
469
+ pageView.__ctrl__.setChainFromOrigin();
470
+
471
+
472
+ // Mount block content mới vào layout outlets
473
+ this.blockManager.mountAll();
474
+
475
+ }
476
+ // ══════════════════════════════════════════════════════════
477
+ // Case 2: Có superView + layout khác (hoặc first mount có layout)
478
+ // ══════════════════════════════════════════════════════════
479
+ else if (hasSuperView) {
480
+ // Cleanup toàn bộ old views
481
+ oldLayoutView?.__ctrl__.ejectOriginChain();
482
+ this.stopPageView(oldPageView);
483
+ this.stopLayoutView(oldLayoutView);
484
+ this.blockManager.clearAllOutlets();
485
+ this.unmountLayoutDOM(oldLayoutView);
486
+
487
+ // Gắn origin chain cho layout mới
488
+ pageView.__ctrl__.setChainFromOrigin();
489
+
490
+ // Build DOM từ layout wrapper vào container
491
+ this.buildViewDOM(finalView);
492
+
493
+ // Mount block content vào layout outlets
494
+ this.blockManager.mountAll();
495
+
496
+ // Commit & Start toàn bộ chain
497
+ this.commitViewChain(pageView, finalView, true);
498
+ this.startViewChain(pageView, finalView, true);
499
+ }
500
+ // ══════════════════════════════════════════════════════════
501
+ // Case 3: Không có superView (standalone view)
502
+ // ══════════════════════════════════════════════════════════
503
+ else {
504
+ // Cleanup toàn bộ old views
505
+ oldLayoutView?.__ctrl__.ejectOriginChain();
506
+ this.stopPageView(oldPageView);
507
+ this.stopLayoutView(oldLayoutView);
508
+ this.blockManager.clearAllOutlets();
509
+ this.unmountLayoutDOM(oldLayoutView);
510
+
511
+ // Build DOM trực tiếp vào container
512
+ this.buildViewDOM(pageView);
513
+
514
+ // Commit & Start
515
+ this.commitViewChain(pageView, pageView, false);
516
+ this.startViewChain(pageView, pageView, false);
517
+ }
518
+
519
+ // ── Update state ──
520
+ this.currentPageView = pageView;
521
+ this.currentLayoutView = hasSuperView ? finalView : null;
522
+ this.currentLayoutPath = newLayoutPath;
523
+ this.currentViewType = hasSuperView ? 'layout' : 'view';
524
+ this.viewStack = hasSuperView ? [finalView, pageView] : [pageView];
525
+ this.renderCount++;
526
+
527
+ return renderResult;
528
+ }
529
+
530
+ // ─── DOM Building ───────────────────────────────────────────
531
+
532
+ /**
533
+ * Build DOM từ finalView's Wrapper vào container.
534
+ * Wrapper.render() sẽ execute childrenFactory → tạo DOM tree.
535
+ */
536
+ private buildViewDOM(finalView: ViewInterface): void {
537
+ const wrapper = finalView.__ctrl__.mainElement;
538
+ if (!wrapper) {
539
+ logger.error(`[ViewManager] finalView "${finalView.__ctrl__.path}" has no mainElement (Wrapper).`);
540
+ return;
541
+ }
542
+ wrapper.setParentElement(this.rootElement);
543
+ wrapper.render();
544
+ }
545
+
546
+ // ─── Lifecycle: Stop ────────────────────────────────────────
547
+
548
+ private stopPageView(pageView: ViewInterface | null): void {
549
+ if (!pageView) return;
550
+ // Stop block content (tracked by BlockManager)
551
+ this.stopBlockContent();
552
+ // Fire onDeactivated hook
553
+ if (typeof pageView.onDeactivated === 'function') {
554
+ try { pageView.onDeactivated(); }
555
+ catch (e) { logger.error(`[ViewManager] onDeactivated error:`, e); }
556
+ }
557
+ }
558
+
559
+ private stopLayoutView(layoutView: ViewInterface | null): void {
560
+ if (!layoutView) return;
561
+ const wrapper = layoutView.__ctrl__.mainElement;
562
+ if (wrapper && typeof wrapper.stop === 'function') {
563
+ wrapper.stop();
564
+ }
565
+ if (typeof layoutView.onDeactivated === 'function') {
566
+ try { layoutView.onDeactivated(); }
567
+ catch (e) { logger.error(`[ViewManager] layout onDeactivated error:`, e); }
568
+ }
569
+ }
570
+
571
+ private stopBlockContent(): void {
572
+ // BlockManager tracks mounted children per outlet
573
+ for (const [name, children] of (this.blockManager as any).mountedChildren) {
574
+ if (Array.isArray(children)) {
575
+ for (const child of children) {
576
+ if (child && typeof child.stop === 'function') {
577
+ child.stop();
578
+ }
579
+ }
580
+ }
581
+ }
582
+ }
583
+
584
+ // ─── Lifecycle: Start ───────────────────────────────────────
585
+
586
+ private startViewChain(pageView: ViewInterface, finalView: ViewInterface, hasSuperView: boolean): void {
587
+ if (hasSuperView) {
588
+ // 1. Start layout element tree
589
+ this.startLayoutView(finalView);
590
+ // 2. Start page's block content
591
+ this.startBlockContent();
592
+ // 3. Fire page onMounted
593
+ if (typeof pageView.onMounted === 'function') {
594
+ try { pageView.onMounted(); }
595
+ catch (e) { logger.error(`[ViewManager] page onMounted error:`, e); }
596
+ }
597
+ } else {
598
+ // Standalone view — start wrapper tree directly
599
+ const wrapper = pageView.__ctrl__.mainElement;
600
+ if (wrapper && typeof wrapper.start === 'function') {
601
+ wrapper.start();
602
+ }
603
+ if (typeof pageView.onMounted === 'function') {
604
+ try { pageView.onMounted(); }
605
+ catch (e) { logger.error(`[ViewManager] onMounted error:`, e); }
606
+ }
607
+ }
608
+ }
609
+
610
+ private startLayoutView(layoutView: ViewInterface): void {
611
+ const wrapper = layoutView.__ctrl__.mainElement;
612
+ if (wrapper && typeof wrapper.start === 'function') {
613
+ wrapper.start();
614
+ }
615
+ if (typeof layoutView.onMounted === 'function') {
616
+ try { layoutView.onMounted(); }
617
+ catch (e) { logger.error(`[ViewManager] layout onMounted error:`, e); }
618
+ }
619
+ }
620
+
621
+ private startBlockContent(): void {
622
+ for (const [name, children] of (this.blockManager as any).mountedChildren) {
623
+ if (Array.isArray(children)) {
624
+ for (const child of children) {
625
+ if (child && typeof child.start === 'function') {
626
+ child.start();
627
+ }
628
+ }
629
+ }
630
+ }
631
+ }
632
+
633
+ // ─── Lifecycle: Commit Data ─────────────────────────────────
634
+
635
+ private commitViewChain(pageView: ViewInterface, finalView: ViewInterface, hasSuperView: boolean): void {
636
+ if (hasSuperView) {
637
+ finalView.__ctrl__.commitData();
638
+ pageView.__ctrl__.commitData();
639
+ } else {
640
+ pageView.__ctrl__.commitData();
641
+ }
642
+ }
643
+
644
+ // ─── Unmount ────────────────────────────────────────────────
645
+
646
+ private unmountLayoutDOM(layoutView: ViewInterface | null): void {
647
+ if (!layoutView) return;
648
+ const wrapper = layoutView.__ctrl__.mainElement;
649
+ if (wrapper && typeof wrapper.destroy === 'function') {
650
+ wrapper.destroy();
651
+ }
652
+ }
653
+
654
+ unmountAll(): void {
655
+ this.stopPageView(this.currentPageView);
656
+ this.stopLayoutView(this.currentLayoutView);
657
+ this.blockManager.clearAllOutlets();
658
+ this.blockManager.destroy();
659
+
660
+ if (this.currentPageView) {
661
+ this.currentPageView.__ctrl__.destroy();
662
+ }
663
+ if (this.currentLayoutView) {
664
+ this.currentLayoutView.__ctrl__.destroy();
665
+ }
666
+
667
+ this.currentPageView = null;
668
+ this.currentLayoutView = null;
669
+ this.currentLayoutPath = null;
670
+ this.currentViewType = null;
671
+ this.activeViews.clear();
672
+ this.viewStack = [];
673
+ }
674
+
675
+ unmountView(path: string): void {
676
+ const info = this.activeViews.get(path);
677
+ if (!info) return;
678
+ this.activeViews.delete(path);
679
+ }
680
+
681
+ // ─── Getters ────────────────────────────────────────────────
682
+
683
+ getCurrentLayout(): ViewInterface | null {
684
+ return this.currentLayoutView;
685
+ }
686
+
687
+ getCurrentView(): ViewInterface | null {
688
+ return this.currentPageView;
689
+ }
690
+
691
+ getViewStack(): ViewInterface[] {
692
+ return this.viewStack;
693
+ }
694
+
695
+ isInitialized(): boolean {
696
+ return this._isInitialized;
697
+ }
698
+
699
+
700
+ }