@gyral/core 0.2.0 → 0.3.1

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 (517) hide show
  1. package/CHANGELOG.md +129 -0
  2. package/NOTICE +19 -0
  3. package/README.md +35 -8
  4. package/dist/call.d.ts +32 -0
  5. package/dist/call.js +63 -0
  6. package/dist/call.js.map +1 -0
  7. package/dist/children.d.ts +30 -5
  8. package/dist/children.js +26 -4
  9. package/dist/children.js.map +1 -1
  10. package/dist/cli/gyral-types.d.ts +2 -0
  11. package/dist/cli/gyral-types.js +23 -0
  12. package/dist/cli/gyral-types.js.map +1 -0
  13. package/dist/command.d.ts +54 -12
  14. package/dist/command.js +31 -11
  15. package/dist/command.js.map +1 -1
  16. package/dist/compiler/ast.d.ts +23 -0
  17. package/dist/compiler/ast.js +149 -0
  18. package/dist/compiler/ast.js.map +1 -0
  19. package/dist/compiler/compile.d.ts +41 -0
  20. package/dist/compiler/compile.js +148 -0
  21. package/dist/compiler/compile.js.map +1 -0
  22. package/dist/compiler/component-entries.d.ts +7 -0
  23. package/dist/compiler/component-entries.js +42 -0
  24. package/dist/compiler/component-entries.js.map +1 -0
  25. package/dist/compiler/components.d.ts +4 -0
  26. package/dist/compiler/components.js +182 -0
  27. package/dist/compiler/components.js.map +1 -0
  28. package/dist/compiler/facts.d.ts +31 -0
  29. package/dist/compiler/facts.js +285 -0
  30. package/dist/compiler/facts.js.map +1 -0
  31. package/dist/compiler/features.d.ts +34 -0
  32. package/dist/compiler/features.js +158 -0
  33. package/dist/compiler/features.js.map +1 -0
  34. package/dist/compiler/hooks.d.ts +22 -0
  35. package/dist/compiler/hooks.js +241 -0
  36. package/dist/compiler/hooks.js.map +1 -0
  37. package/dist/compiler/loader-source.d.ts +14 -0
  38. package/dist/compiler/loader-source.js +86 -0
  39. package/dist/compiler/loader-source.js.map +1 -0
  40. package/dist/compiler/locate.d.ts +14 -0
  41. package/dist/compiler/locate.js +78 -0
  42. package/dist/compiler/locate.js.map +1 -0
  43. package/dist/compiler/parse5-check.d.ts +21 -0
  44. package/dist/compiler/parse5-check.js +60 -0
  45. package/dist/compiler/parse5-check.js.map +1 -0
  46. package/dist/compiler/prop-schemas.d.ts +4 -0
  47. package/dist/compiler/prop-schemas.js +108 -0
  48. package/dist/compiler/prop-schemas.js.map +1 -0
  49. package/dist/compiler/scan.d.ts +41 -0
  50. package/dist/compiler/scan.js +160 -0
  51. package/dist/compiler/scan.js.map +1 -0
  52. package/dist/compiler/scope.d.ts +8 -0
  53. package/dist/compiler/scope.js +116 -0
  54. package/dist/compiler/scope.js.map +1 -0
  55. package/dist/compiler/source.d.ts +34 -0
  56. package/dist/compiler/source.js +114 -0
  57. package/dist/compiler/source.js.map +1 -0
  58. package/dist/compiler/tag-map.d.ts +41 -0
  59. package/dist/compiler/tag-map.js +126 -0
  60. package/dist/compiler/tag-map.js.map +1 -0
  61. package/dist/components-ready.d.ts +7 -0
  62. package/dist/components-ready.js +19 -0
  63. package/dist/components-ready.js.map +1 -0
  64. package/dist/define.d.ts +13 -4
  65. package/dist/define.js +35 -331
  66. package/dist/define.js.map +1 -1
  67. package/dist/devtools-events.d.ts +13 -0
  68. package/dist/devtools-events.js.map +1 -1
  69. package/dist/devtools-off.d.ts +2 -0
  70. package/dist/devtools-off.js +2 -0
  71. package/dist/devtools-off.js.map +1 -1
  72. package/dist/devtools.d.ts +4 -0
  73. package/dist/devtools.js +17 -2
  74. package/dist/devtools.js.map +1 -1
  75. package/dist/drivers-scope.d.ts +1 -1
  76. package/dist/drivers-scope.js +1 -8
  77. package/dist/drivers-scope.js.map +1 -1
  78. package/dist/element-internals.d.ts +1 -0
  79. package/dist/element-internals.js +11 -0
  80. package/dist/element-internals.js.map +1 -0
  81. package/dist/element-types.d.ts +11 -5
  82. package/dist/element-types.js.map +1 -1
  83. package/dist/element.d.ts +3 -0
  84. package/dist/element.js +322 -0
  85. package/dist/element.js.map +1 -0
  86. package/dist/error-view.d.ts +10 -0
  87. package/dist/error-view.js +30 -0
  88. package/dist/error-view.js.map +1 -0
  89. package/dist/errors.d.ts +21 -0
  90. package/dist/errors.js +47 -0
  91. package/dist/errors.js.map +1 -0
  92. package/dist/errors.json +289 -0
  93. package/dist/eslint/imports.d.ts +26 -0
  94. package/dist/eslint/imports.js +78 -0
  95. package/dist/eslint/imports.js.map +1 -0
  96. package/dist/eslint/index.d.ts +16 -0
  97. package/dist/eslint/index.js +23 -0
  98. package/dist/eslint/index.js.map +1 -0
  99. package/dist/eslint/locate.d.ts +33 -0
  100. package/dist/eslint/locate.js +132 -0
  101. package/dist/eslint/locate.js.map +1 -0
  102. package/dist/eslint/row-purity-rule.d.ts +2 -0
  103. package/dist/eslint/row-purity-rule.js +103 -0
  104. package/dist/eslint/row-purity-rule.js.map +1 -0
  105. package/dist/eslint/template-rule.d.ts +6 -0
  106. package/dist/eslint/template-rule.js +76 -0
  107. package/dist/eslint/template-rule.js.map +1 -0
  108. package/dist/eslint/unused-intent-rule.d.ts +2 -0
  109. package/dist/eslint/unused-intent-rule.js +186 -0
  110. package/dist/eslint/unused-intent-rule.js.map +1 -0
  111. package/dist/features.d.ts +39 -0
  112. package/dist/features.js +2 -0
  113. package/dist/features.js.map +1 -0
  114. package/dist/focus.d.ts +13 -12
  115. package/dist/focus.js +44 -11
  116. package/dist/focus.js.map +1 -1
  117. package/dist/form-associated.d.ts +46 -0
  118. package/dist/form-associated.js +77 -0
  119. package/dist/form-associated.js.map +1 -0
  120. package/dist/forms.d.ts +42 -30
  121. package/dist/forms.js +85 -41
  122. package/dist/forms.js.map +1 -1
  123. package/dist/frame-lane.d.ts +11 -0
  124. package/dist/frame-lane.js +28 -0
  125. package/dist/frame-lane.js.map +1 -0
  126. package/dist/head.d.ts +61 -0
  127. package/dist/head.js +85 -0
  128. package/dist/head.js.map +1 -0
  129. package/dist/hooks/invalid.d.ts +14 -0
  130. package/dist/hooks/invalid.js +72 -0
  131. package/dist/hooks/invalid.js.map +1 -0
  132. package/dist/host-model.d.ts +77 -0
  133. package/dist/host-model.js +278 -0
  134. package/dist/host-model.js.map +1 -0
  135. package/dist/hydration-client.d.ts +9 -0
  136. package/dist/hydration-client.js +35 -0
  137. package/dist/hydration-client.js.map +1 -0
  138. package/dist/hydration-loader.d.ts +13 -0
  139. package/dist/hydration-loader.js +58 -0
  140. package/dist/hydration-loader.js.map +1 -0
  141. package/dist/hydration-off.d.ts +8 -0
  142. package/dist/hydration-off.js +25 -0
  143. package/dist/hydration-off.js.map +1 -0
  144. package/dist/hydration.d.ts +3 -21
  145. package/dist/hydration.js +14 -63
  146. package/dist/hydration.js.map +1 -1
  147. package/dist/index.d.ts +24 -36
  148. package/dist/index.js +14 -32
  149. package/dist/index.js.map +1 -1
  150. package/dist/indexeddb-types.d.ts +97 -0
  151. package/dist/indexeddb-types.js +2 -0
  152. package/dist/indexeddb-types.js.map +1 -0
  153. package/dist/indexeddb.d.ts +5 -0
  154. package/dist/indexeddb.js +118 -0
  155. package/dist/indexeddb.js.map +1 -0
  156. package/dist/intent.d.ts +62 -17
  157. package/dist/intent.js +193 -100
  158. package/dist/intent.js.map +1 -1
  159. package/dist/internal/indexeddb-open.d.ts +8 -0
  160. package/dist/internal/indexeddb-open.js +96 -0
  161. package/dist/internal/indexeddb-open.js.map +1 -0
  162. package/dist/internal/indexeddb-transaction.d.ts +4 -0
  163. package/dist/internal/indexeddb-transaction.js +134 -0
  164. package/dist/internal/indexeddb-transaction.js.map +1 -0
  165. package/dist/internal/interpreter.d.ts +15 -1
  166. package/dist/internal/interpreter.js +42 -47
  167. package/dist/internal/interpreter.js.map +1 -1
  168. package/dist/internal/token.d.ts +1 -0
  169. package/dist/internal/token.js +7 -0
  170. package/dist/internal/token.js.map +1 -0
  171. package/dist/internal.d.ts +20 -0
  172. package/dist/internal.js +22 -0
  173. package/dist/internal.js.map +1 -0
  174. package/dist/invoker-fallback-used.d.ts +4 -0
  175. package/dist/invoker-fallback-used.js +10 -0
  176. package/dist/invoker-fallback-used.js.map +1 -0
  177. package/dist/invoker-fallback.d.ts +4 -0
  178. package/dist/invoker-fallback.js +15 -0
  179. package/dist/invoker-fallback.js.map +1 -0
  180. package/dist/invokers-shim.d.ts +6 -0
  181. package/dist/invokers-shim.js +32 -0
  182. package/dist/invokers-shim.js.map +1 -0
  183. package/dist/invokers.d.ts +3 -5
  184. package/dist/invokers.js +11 -51
  185. package/dist/invokers.js.map +1 -1
  186. package/dist/islands.d.ts +0 -2
  187. package/dist/islands.js +4 -11
  188. package/dist/islands.js.map +1 -1
  189. package/dist/light-dom.d.ts +4 -53
  190. package/dist/light-dom.js +5 -100
  191. package/dist/light-dom.js.map +1 -1
  192. package/dist/prop.d.ts +89 -0
  193. package/dist/prop.js +41 -0
  194. package/dist/prop.js.map +1 -0
  195. package/dist/props.d.ts +57 -21
  196. package/dist/props.js +157 -34
  197. package/dist/props.js.map +1 -1
  198. package/dist/retry.d.ts +15 -0
  199. package/dist/retry.js +48 -0
  200. package/dist/retry.js.map +1 -0
  201. package/dist/scheduler.d.ts +43 -0
  202. package/dist/scheduler.js +212 -0
  203. package/dist/scheduler.js.map +1 -0
  204. package/dist/script-json.d.ts +2 -0
  205. package/dist/script-json.js +13 -0
  206. package/dist/script-json.js.map +1 -0
  207. package/dist/server-component.d.ts +10 -0
  208. package/dist/server-component.js +133 -0
  209. package/dist/server-component.js.map +1 -0
  210. package/dist/server-specs.d.ts +6 -0
  211. package/dist/server-specs.js +13 -0
  212. package/dist/server-specs.js.map +1 -0
  213. package/dist/server.d.ts +34 -0
  214. package/dist/server.js +59 -0
  215. package/dist/server.js.map +1 -0
  216. package/dist/settled.d.ts +11 -0
  217. package/dist/settled.js +62 -0
  218. package/dist/settled.js.map +1 -0
  219. package/dist/spec-features-used.d.ts +21 -0
  220. package/dist/spec-features-used.js +50 -0
  221. package/dist/spec-features-used.js.map +1 -0
  222. package/dist/spec-features.d.ts +28 -0
  223. package/dist/spec-features.js +42 -0
  224. package/dist/spec-features.js.map +1 -0
  225. package/dist/states.d.ts +3 -5
  226. package/dist/states.js +22 -11
  227. package/dist/states.js.map +1 -1
  228. package/dist/storage.d.ts +69 -0
  229. package/dist/storage.js +158 -0
  230. package/dist/storage.js.map +1 -0
  231. package/dist/store-binding.d.ts +6 -3
  232. package/dist/store-binding.js +7 -8
  233. package/dist/store-binding.js.map +1 -1
  234. package/dist/store-scope.d.ts +8 -11
  235. package/dist/store-scope.js +15 -40
  236. package/dist/store-scope.js.map +1 -1
  237. package/dist/store.d.ts +3 -0
  238. package/dist/store.js +45 -10
  239. package/dist/store.js.map +1 -1
  240. package/dist/stores-provider.d.ts +2 -6
  241. package/dist/stores-provider.js +21 -55
  242. package/dist/stores-provider.js.map +1 -1
  243. package/dist/subscription.d.ts +35 -0
  244. package/dist/subscription.js +74 -0
  245. package/dist/subscription.js.map +1 -0
  246. package/dist/subscriptions.d.ts +26 -0
  247. package/dist/subscriptions.js +98 -0
  248. package/dist/subscriptions.js.map +1 -0
  249. package/dist/transitions.d.ts +5 -7
  250. package/dist/transitions.js +17 -20
  251. package/dist/transitions.js.map +1 -1
  252. package/dist/types.d.ts +142 -49
  253. package/dist/types.js.map +1 -1
  254. package/dist/use-dialogs.d.ts +2 -0
  255. package/dist/use-dialogs.js +9 -0
  256. package/dist/use-dialogs.js.map +1 -0
  257. package/dist/use-disposal.d.ts +2 -0
  258. package/dist/use-disposal.js +9 -0
  259. package/dist/use-disposal.js.map +1 -0
  260. package/dist/use-error-view.d.ts +2 -0
  261. package/dist/use-error-view.js +9 -0
  262. package/dist/use-error-view.js.map +1 -0
  263. package/dist/use-errored.d.ts +2 -0
  264. package/dist/use-errored.js +9 -0
  265. package/dist/use-errored.js.map +1 -0
  266. package/dist/use-form-associated.d.ts +2 -0
  267. package/dist/use-form-associated.js +7 -0
  268. package/dist/use-form-associated.js.map +1 -0
  269. package/dist/use-frame-lane.d.ts +2 -0
  270. package/dist/use-frame-lane.js +10 -0
  271. package/dist/use-frame-lane.js.map +1 -0
  272. package/dist/use-invokers.d.ts +2 -0
  273. package/dist/use-invokers.js +10 -0
  274. package/dist/use-invokers.js.map +1 -0
  275. package/dist/use-states.d.ts +2 -0
  276. package/dist/use-states.js +10 -0
  277. package/dist/use-states.js.map +1 -0
  278. package/dist/use-subscriptions.d.ts +2 -0
  279. package/dist/use-subscriptions.js +10 -0
  280. package/dist/use-subscriptions.js.map +1 -0
  281. package/dist/use-transitions.d.ts +2 -0
  282. package/dist/use-transitions.js +10 -0
  283. package/dist/use-transitions.js.map +1 -0
  284. package/dist/view/attributes.d.ts +11 -0
  285. package/dist/view/attributes.js +15 -0
  286. package/dist/view/attributes.js.map +1 -0
  287. package/dist/view/compiled.d.ts +1 -0
  288. package/dist/view/compiled.js +6 -0
  289. package/dist/view/compiled.js.map +1 -0
  290. package/dist/view/dev-off.d.ts +1 -0
  291. package/dist/view/dev-off.js +4 -0
  292. package/dist/view/dev-off.js.map +1 -0
  293. package/dist/view/dev.d.ts +1 -0
  294. package/dist/view/dev.js +5 -0
  295. package/dist/view/dev.js.map +1 -0
  296. package/dist/view/flags.d.ts +1 -0
  297. package/dist/view/flags.js +4 -0
  298. package/dist/view/flags.js.map +1 -0
  299. package/dist/view/index.d.ts +26 -0
  300. package/dist/view/index.js +27 -0
  301. package/dist/view/index.js.map +1 -0
  302. package/dist/view/loc.d.ts +9 -0
  303. package/dist/view/loc.js +50 -0
  304. package/dist/view/loc.js.map +1 -0
  305. package/dist/view/message.d.ts +17 -0
  306. package/dist/view/message.js +40 -0
  307. package/dist/view/message.js.map +1 -0
  308. package/dist/view/messages.d.ts +43 -0
  309. package/dist/view/messages.js +84 -0
  310. package/dist/view/messages.js.map +1 -0
  311. package/dist/view/normalize/check.d.ts +23 -0
  312. package/dist/view/normalize/check.js +81 -0
  313. package/dist/view/normalize/check.js.map +1 -0
  314. package/dist/view/normalize/emit.d.ts +15 -0
  315. package/dist/view/normalize/emit.js +165 -0
  316. package/dist/view/normalize/emit.js.map +1 -0
  317. package/dist/view/normalize/entities.d.ts +4 -0
  318. package/dist/view/normalize/entities.js +38 -0
  319. package/dist/view/normalize/entities.js.map +1 -0
  320. package/dist/view/normalize/errors.d.ts +9 -0
  321. package/dist/view/normalize/errors.js +19 -0
  322. package/dist/view/normalize/errors.js.map +1 -0
  323. package/dist/view/normalize/id.d.ts +10 -0
  324. package/dist/view/normalize/id.js +55 -0
  325. package/dist/view/normalize/id.js.map +1 -0
  326. package/dist/view/normalize/normalize.d.ts +18 -0
  327. package/dist/view/normalize/normalize.js +42 -0
  328. package/dist/view/normalize/normalize.js.map +1 -0
  329. package/dist/view/normalize/repairs.d.ts +24 -0
  330. package/dist/view/normalize/repairs.js +166 -0
  331. package/dist/view/normalize/repairs.js.map +1 -0
  332. package/dist/view/normalize/rules.d.ts +39 -0
  333. package/dist/view/normalize/rules.js +120 -0
  334. package/dist/view/normalize/rules.js.map +1 -0
  335. package/dist/view/normalize/shape.d.ts +5 -0
  336. package/dist/view/normalize/shape.js +38 -0
  337. package/dist/view/normalize/shape.js.map +1 -0
  338. package/dist/view/normalize/source.d.ts +13 -0
  339. package/dist/view/normalize/source.js +34 -0
  340. package/dist/view/normalize/source.js.map +1 -0
  341. package/dist/view/normalize/svg.d.ts +14 -0
  342. package/dist/view/normalize/svg.js +40 -0
  343. package/dist/view/normalize/svg.js.map +1 -0
  344. package/dist/view/normalize/tag-states.d.ts +23 -0
  345. package/dist/view/normalize/tag-states.js +192 -0
  346. package/dist/view/normalize/tag-states.js.map +1 -0
  347. package/dist/view/normalize/tokenizer.d.ts +5 -0
  348. package/dist/view/normalize/tokenizer.js +233 -0
  349. package/dist/view/normalize/tokenizer.js.map +1 -0
  350. package/dist/view/normalize/tokens.d.ts +55 -0
  351. package/dist/view/normalize/tokens.js +24 -0
  352. package/dist/view/normalize/tokens.js.map +1 -0
  353. package/dist/view/normalize/tree.d.ts +65 -0
  354. package/dist/view/normalize/tree.js +235 -0
  355. package/dist/view/normalize/tree.js.map +1 -0
  356. package/dist/view/normalize/types.d.ts +146 -0
  357. package/dist/view/normalize/types.js +29 -0
  358. package/dist/view/normalize/types.js.map +1 -0
  359. package/dist/view/normalize/whitespace.d.ts +2 -0
  360. package/dist/{template-whitespace.js → view/normalize/whitespace.js} +27 -36
  361. package/dist/view/normalize/whitespace.js.map +1 -0
  362. package/dist/view/prepare-stub.d.ts +3 -0
  363. package/dist/view/prepare-stub.js +7 -0
  364. package/dist/view/prepare-stub.js.map +1 -0
  365. package/dist/view/prepare.d.ts +11 -0
  366. package/dist/view/prepare.js +63 -0
  367. package/dist/view/prepare.js.map +1 -0
  368. package/dist/view/registry.d.ts +78 -0
  369. package/dist/view/registry.js +27 -0
  370. package/dist/view/registry.js.map +1 -0
  371. package/dist/view/render/adopt-attr.d.ts +14 -0
  372. package/dist/view/render/adopt-attr.js +83 -0
  373. package/dist/view/render/adopt-attr.js.map +1 -0
  374. package/dist/view/render/adopt-plan.d.ts +10 -0
  375. package/dist/view/render/adopt-plan.js +26 -0
  376. package/dist/view/render/adopt-plan.js.map +1 -0
  377. package/dist/view/render/adopt.d.ts +3 -0
  378. package/dist/view/render/adopt.js +286 -0
  379. package/dist/view/render/adopt.js.map +1 -0
  380. package/dist/view/render/attr-parts.d.ts +72 -0
  381. package/dist/view/render/attr-parts.js +262 -0
  382. package/dist/view/render/attr-parts.js.map +1 -0
  383. package/dist/view/render/child-part.d.ts +51 -0
  384. package/dist/view/render/child-part.js +173 -0
  385. package/dist/view/render/child-part.js.map +1 -0
  386. package/dist/view/render/dev-check.d.ts +12 -0
  387. package/dist/view/render/dev-check.js +122 -0
  388. package/dist/view/render/dev-check.js.map +1 -0
  389. package/dist/view/render/dispose.d.ts +3 -0
  390. package/dist/view/render/dispose.js +76 -0
  391. package/dist/view/render/dispose.js.map +1 -0
  392. package/dist/view/render/hook-part.d.ts +5 -0
  393. package/dist/view/render/hook-part.js +36 -0
  394. package/dist/view/render/hook-part.js.map +1 -0
  395. package/dist/view/render/hook-run.d.ts +2 -0
  396. package/dist/view/render/hook-run.js +72 -0
  397. package/dist/view/render/hook-run.js.map +1 -0
  398. package/dist/view/render/hooks.d.ts +108 -0
  399. package/dist/view/render/hooks.js +108 -0
  400. package/dist/view/render/hooks.js.map +1 -0
  401. package/dist/view/render/hydrate.d.ts +10 -0
  402. package/dist/view/render/hydrate.js +33 -0
  403. package/dist/view/render/hydrate.js.map +1 -0
  404. package/dist/view/render/instance.d.ts +33 -0
  405. package/dist/view/render/instance.js +107 -0
  406. package/dist/view/render/instance.js.map +1 -0
  407. package/dist/view/render/keyed.d.ts +6 -0
  408. package/dist/view/render/keyed.js +15 -0
  409. package/dist/view/render/keyed.js.map +1 -0
  410. package/dist/view/render/list.d.ts +20 -0
  411. package/dist/view/render/list.js +156 -0
  412. package/dist/view/render/list.js.map +1 -0
  413. package/dist/view/render/mismatch.d.ts +10 -0
  414. package/dist/view/render/mismatch.js +55 -0
  415. package/dist/view/render/mismatch.js.map +1 -0
  416. package/dist/view/render/modal.d.ts +3 -0
  417. package/dist/view/render/modal.js +39 -0
  418. package/dist/view/render/modal.js.map +1 -0
  419. package/dist/view/render/nodes.d.ts +10 -0
  420. package/dist/view/render/nodes.js +37 -0
  421. package/dist/view/render/nodes.js.map +1 -0
  422. package/dist/view/render/place.d.ts +18 -0
  423. package/dist/view/render/place.js +69 -0
  424. package/dist/view/render/place.js.map +1 -0
  425. package/dist/view/render/plan.d.ts +26 -0
  426. package/dist/view/render/plan.js +124 -0
  427. package/dist/view/render/plan.js.map +1 -0
  428. package/dist/view/render/raw.d.ts +21 -0
  429. package/dist/view/render/raw.js +72 -0
  430. package/dist/view/render/raw.js.map +1 -0
  431. package/dist/view/render/render.d.ts +15 -0
  432. package/dist/view/render/render.js +65 -0
  433. package/dist/view/render/render.js.map +1 -0
  434. package/dist/view/render/reorder.d.ts +4 -0
  435. package/dist/view/render/reorder.js +101 -0
  436. package/dist/view/render/reorder.js.map +1 -0
  437. package/dist/view/render/rows.d.ts +23 -0
  438. package/dist/view/render/rows.js +95 -0
  439. package/dist/view/render/rows.js.map +1 -0
  440. package/dist/view/render/seen.d.ts +11 -0
  441. package/dist/view/render/seen.js +17 -0
  442. package/dist/view/render/seen.js.map +1 -0
  443. package/dist/view/render/toggles.d.ts +6 -0
  444. package/dist/view/render/toggles.js +6 -0
  445. package/dist/view/render/toggles.js.map +1 -0
  446. package/dist/view/render/values.d.ts +29 -0
  447. package/dist/view/render/values.js +13 -0
  448. package/dist/view/render/values.js.map +1 -0
  449. package/dist/view/render/warn.d.ts +28 -0
  450. package/dist/view/render/warn.js +114 -0
  451. package/dist/view/render/warn.js.map +1 -0
  452. package/dist/view/server/component.d.ts +12 -0
  453. package/dist/view/server/component.js +64 -0
  454. package/dist/view/server/component.js.map +1 -0
  455. package/dist/view/server/escape.d.ts +10 -0
  456. package/dist/view/server/escape.js +34 -0
  457. package/dist/view/server/escape.js.map +1 -0
  458. package/dist/view/server/index.d.ts +48 -0
  459. package/dist/view/server/index.js +80 -0
  460. package/dist/view/server/index.js.map +1 -0
  461. package/dist/view/server/sha256.d.ts +2 -0
  462. package/dist/view/server/sha256.js +75 -0
  463. package/dist/view/server/sha256.js.map +1 -0
  464. package/dist/view/server/tags.d.ts +68 -0
  465. package/dist/view/server/tags.js +132 -0
  466. package/dist/view/server/tags.js.map +1 -0
  467. package/dist/view/server/values.d.ts +18 -0
  468. package/dist/view/server/values.js +94 -0
  469. package/dist/view/server/values.js.map +1 -0
  470. package/dist/view/server/writer.d.ts +21 -0
  471. package/dist/view/server/writer.js +170 -0
  472. package/dist/view/server/writer.js.map +1 -0
  473. package/dist/view/styles.d.ts +25 -0
  474. package/dist/view/styles.js +58 -0
  475. package/dist/view/styles.js.map +1 -0
  476. package/dist/view/template-element.d.ts +10 -0
  477. package/dist/view/template-element.js +45 -0
  478. package/dist/view/template-element.js.map +1 -0
  479. package/dist/view/template.d.ts +29 -0
  480. package/dist/view/template.js +84 -0
  481. package/dist/view/template.js.map +1 -0
  482. package/dist/view/trusted-html.d.ts +6 -0
  483. package/dist/view/trusted-html.js +34 -0
  484. package/dist/view/trusted-html.js.map +1 -0
  485. package/dist/vite.d.ts +57 -11
  486. package/dist/vite.js +319 -27
  487. package/dist/vite.js.map +1 -1
  488. package/package.json +70 -4
  489. package/dist/accessible-name.d.ts +0 -19
  490. package/dist/accessible-name.js +0 -56
  491. package/dist/accessible-name.js.map +0 -1
  492. package/dist/element-directive.d.ts +0 -20
  493. package/dist/element-directive.js +0 -31
  494. package/dist/element-directive.js.map +0 -1
  495. package/dist/invalid.d.ts +0 -21
  496. package/dist/invalid.js +0 -70
  497. package/dist/invalid.js.map +0 -1
  498. package/dist/lit-html-check.d.ts +0 -6
  499. package/dist/lit-html-check.js +0 -48
  500. package/dist/lit-html-check.js.map +0 -1
  501. package/dist/live-boolean.d.ts +0 -22
  502. package/dist/live-boolean.js +0 -34
  503. package/dist/live-boolean.js.map +0 -1
  504. package/dist/random.d.ts +0 -13
  505. package/dist/random.js +0 -19
  506. package/dist/random.js.map +0 -1
  507. package/dist/styles.d.ts +0 -12
  508. package/dist/styles.js +0 -11
  509. package/dist/styles.js.map +0 -1
  510. package/dist/template-whitespace.d.ts +0 -7
  511. package/dist/template-whitespace.js.map +0 -1
  512. package/dist/templates.d.ts +0 -5
  513. package/dist/templates.js +0 -15
  514. package/dist/templates.js.map +0 -1
  515. package/dist/textarea.d.ts +0 -26
  516. package/dist/textarea.js +0 -85
  517. package/dist/textarea.js.map +0 -1
@@ -0,0 +1,278 @@
1
+ // The model side of one Gyral host (docs/design-docs/view/05-element.md, ADR 0006, ADR 0013):
2
+ // state, reducers and commands. element.ts owns the DOM side (props, root, lifecycle,
3
+ // rendering) and asks this object for state and context. Reducers run at once, so `state` is
4
+ // always current; only the render waits (04). The interpreter and the store binding come from
5
+ // features.ts, registered by `command()` and `defineStore()`; marker drivers (focus, emit, store
6
+ // sends) carry their own `local` handler.
7
+ import { DEVTOOLS_ENABLED, devCommands, devOwner, devUpdate } from '#devtools';
8
+ import { splitNext } from './command.js';
9
+ import { features, } from './features.js';
10
+ import { fail } from './errors.js';
11
+ import { runInit } from './init.js';
12
+ import { noteActivity, requestTransition } from './scheduler.js';
13
+ import { errored, subscriptions as subscriptionSet } from '#spec-features';
14
+ import { message } from './view/index.js';
15
+ export class HostModel {
16
+ #host;
17
+ #spec;
18
+ #reducers;
19
+ #binding;
20
+ #model;
21
+ /** Props as of init or the last PropsChanged: the `prev` of the next PropsChanged. */
22
+ #seen;
23
+ #interpreter;
24
+ /** Commands kept while disconnected (init's, before the first connect); undefined once connected. */
25
+ #pending;
26
+ /** Connected to the document (a pending stop checks it, so a move cancels the stop). */
27
+ #on;
28
+ /** `spec.subscriptions`, kept running once the host has rendered (ADR 0025). */
29
+ #subs;
30
+ /** `init` threw (ADR 0024): the host shows its error view, or stays empty. */
31
+ #failure;
32
+ /** Handling `Errored`: a failure now is reported, never sent again (no loops). */
33
+ #erroring;
34
+ constructor(host, spec) {
35
+ /** Commands kept while disconnected (init's, before the first connect); undefined once connected. */
36
+ this.#pending = [];
37
+ /** Connected to the document (a pending stop checks it, so a move cancels the stop). */
38
+ this.#on = false;
39
+ /** Handling `Errored`: a failure now is reported, never sent again (no loops). */
40
+ this.#erroring = false;
41
+ /** The store binding, created on first use. Only reached once `defineStore()` has run. */
42
+ this.stores = () => (this.#binding ??= features.stores(this.#host.el, this.#host.tag, this.#spec.stores ?? [], (store, state, prev) => {
43
+ this.#storeChanged(store, state, prev);
44
+ }));
45
+ this.#host = host;
46
+ this.el = host.el;
47
+ this.tag = host.tag;
48
+ this.root = host.root;
49
+ this.#spec = spec;
50
+ // Sound: dispatch() only calls the reducer whose key equals msg._tag. A component without
51
+ // messages may have no `update` (its spec type is widened to Tagged here).
52
+ this.#reducers = (spec.update ?? {});
53
+ }
54
+ get ready() {
55
+ return this.#model !== undefined;
56
+ }
57
+ /** Set when `init` threw; the host has no state then. */
58
+ get failure() {
59
+ return this.#failure;
60
+ }
61
+ /** The current state, running `init` (and `initialMessages`) on first read. */
62
+ state(initialMessages = []) {
63
+ if (this.#model === undefined) {
64
+ this.#seen = this.#host.props();
65
+ const next = this.#init();
66
+ if (next === undefined)
67
+ return undefined; // init threw: `failure` says so
68
+ this.apply(next);
69
+ for (const msg of initialMessages)
70
+ this.dispatch(msg, false);
71
+ }
72
+ return this.#model.value;
73
+ }
74
+ /** `init(props)`, or undefined after reporting its failure (ADR 0024). */
75
+ #init() {
76
+ try {
77
+ return runInit(this.#spec, this.#seen);
78
+ }
79
+ catch (cause) {
80
+ this.#failure = this.fail(cause, 'init', message(74, this.tag));
81
+ this.#model = { value: undefined };
82
+ return undefined;
83
+ }
84
+ }
85
+ /**
86
+ * Reports a failure of this host (ADR 0024) and, for a failed update, parse or command, sends
87
+ * `Errored` to its optional reducer. A failure while handling `Errored` is only reported.
88
+ */
89
+ fail(cause, phase, text, msg) {
90
+ const error = fail(cause, phase, text, { host: this.el, tag: this.tag, msg });
91
+ if (!this.#erroring && errored !== undefined && this.#reducers['Errored'] !== undefined) {
92
+ this.#erroring = true;
93
+ try {
94
+ errored((msg) => this.dispatch(msg), phase, error);
95
+ }
96
+ finally {
97
+ this.#erroring = false;
98
+ }
99
+ }
100
+ return error;
101
+ }
102
+ hasReducer(tag) {
103
+ return this.#reducers[tag] !== undefined;
104
+ }
105
+ /**
106
+ * Resumes from a server seed (ADR 0012): the server's state, or `init(props)`'s when the
107
+ * seed left it out. Returns init's commands, to start after the first render.
108
+ */
109
+ resume(seed) {
110
+ this.#seen = this.#host.props();
111
+ const next = this.#init();
112
+ if (next === undefined)
113
+ return [];
114
+ const [initial, commands] = splitNext(next);
115
+ // Sound: the seed is this component's own state, written by the server.
116
+ this.#model = { value: 'state' in seed ? seed.state : initial };
117
+ return commands;
118
+ }
119
+ /**
120
+ * PropsChanged when props differ from the last ones seen (`Object.is` per prop). A reducer
121
+ * that throws leaves them unseen, so the next render sends PropsChanged again (ADR 0024).
122
+ */
123
+ syncProps(names) {
124
+ const prev = this.#seen;
125
+ if (prev === undefined || this.#failure !== undefined)
126
+ return;
127
+ const props = this.#host.props();
128
+ if (names.every((name) => Object.is(props[name], prev[name])))
129
+ return;
130
+ if (this.dispatch({ _tag: 'PropsChanged', props, prev }, false))
131
+ this.#seen = props;
132
+ this.#resubscribe();
133
+ }
134
+ /**
135
+ * Runs `msg`'s reducer. A reducer that throws changes nothing (no state, no commands): the
136
+ * failure is reported (ADR 0024) and dispatch returns false.
137
+ */
138
+ dispatch(msg, schedule = true) {
139
+ noteActivity(); // settled() keeps waiting while messages arrive (04)
140
+ const reducer = this.#reducers[msg._tag];
141
+ if (reducer === undefined) {
142
+ // Framework messages have optional reducers; props and stores stay readable as context.
143
+ if (msg._tag !== 'PropsChanged' && msg._tag !== 'StoreChanged' && msg._tag !== 'Errored') {
144
+ console.warn(message(10, this.#host.tag, msg._tag));
145
+ }
146
+ return true;
147
+ }
148
+ if (this.#failure !== undefined)
149
+ return false;
150
+ const prev = this.state();
151
+ let next;
152
+ try {
153
+ next = reducer(prev, msg, this.ctx());
154
+ }
155
+ catch (cause) {
156
+ this.fail(cause, 'update', message(73, this.tag, msg._tag), msg._tag);
157
+ return false;
158
+ }
159
+ this.apply(next);
160
+ const state = this.state();
161
+ if (DEVTOOLS_ENABLED)
162
+ devUpdate(this.#host.el, this.#host.tag, msg, prev, state);
163
+ this.#resubscribe();
164
+ if (!schedule)
165
+ return true;
166
+ if (this.#spec.viewTransition?.(prev, state, msg) === true)
167
+ requestTransition();
168
+ this.#host.invalidate(this.#onFrame(msg._tag));
169
+ return true;
170
+ }
171
+ apply(next) {
172
+ const [state, commands] = splitNext(next);
173
+ this.#model = { value: state };
174
+ for (const cmd of commands) {
175
+ const local = cmd.driver.local;
176
+ if (local !== undefined)
177
+ local(this, cmd.input);
178
+ else if (this.#pending !== undefined)
179
+ this.#pending.push(cmd);
180
+ else
181
+ this.#commands().run(cmd);
182
+ }
183
+ }
184
+ /** Starts commands kept for later (init's, after a server-rendered host's first render). */
185
+ run(commands) {
186
+ this.apply([this.state(), commands]);
187
+ }
188
+ // Reducers and the view get this too; only parsers' type (ParserCtx) names `state`.
189
+ ctx() {
190
+ return {
191
+ props: this.#host.props(),
192
+ read: (store) => this.stores().read(store),
193
+ state: this.state(),
194
+ };
195
+ }
196
+ /**
197
+ * Resolves stores and runs kept commands; after a real detach, starts the subscriptions again
198
+ * (05 "Lifecycle"). Returns true if store instances were bound.
199
+ */
200
+ connect() {
201
+ this.#on = true; // a move: the pending stop finds the host connected and does nothing
202
+ // The nearest <gyral-stores> may differ after a move.
203
+ const rebound = (this.#spec.stores?.length ?? 0) > 0 && this.stores().connect();
204
+ const pending = this.#pending ?? [];
205
+ this.#pending = undefined;
206
+ for (const cmd of pending)
207
+ this.#commands().run(cmd);
208
+ this.#resubscribe(); // a move: unchanged, nothing restarts
209
+ return rebound;
210
+ }
211
+ /**
212
+ * Starts `spec.subscriptions` (ADR 0025): after the first render, as init's commands of a
213
+ * server-rendered host are, so nothing they emit can change what hydration adopts.
214
+ */
215
+ subscribe() {
216
+ const derive = this.#spec.subscriptions;
217
+ if (derive === undefined || subscriptionSet === undefined)
218
+ return;
219
+ this.#subs ??= subscriptionSet(this, derive);
220
+ this.#resubscribe();
221
+ }
222
+ /** Aborts the running command of `lane` (a subscription that left, ADR 0025). */
223
+ cancel(lane) {
224
+ this.#interpreter?.cancel(lane);
225
+ }
226
+ /** Syncs the subscriptions while connected and healthy. */
227
+ #resubscribe() {
228
+ if (this.#pending === undefined && this.#failure === undefined)
229
+ this.#subs?.update();
230
+ }
231
+ /**
232
+ * Stops the commands one microtask later, unless the host is connected again first: a move
233
+ * (`appendChild`, `insertBefore`) disconnects and connects in one task and keeps them running.
234
+ */
235
+ disconnect() {
236
+ this.#binding?.disconnect();
237
+ this.#pending ??= [];
238
+ this.#on = false;
239
+ queueMicrotask(() => {
240
+ if (this.#on)
241
+ return;
242
+ this.#interpreter?.dispose();
243
+ this.#interpreter = undefined;
244
+ this.#subs?.reset();
245
+ });
246
+ }
247
+ /**
248
+ * The interpreter, started with the first command after connecting. Only reached for a
249
+ * command built by `command()`, which registered it (features.ts).
250
+ */
251
+ #commands() {
252
+ const el = this.el;
253
+ return (this.#interpreter ??= features.commands(el, (msg) => {
254
+ this.dispatch(msg);
255
+ }, DEVTOOLS_ENABLED ? devCommands(() => devOwner(el, this.tag)) : undefined, (cause, code, driver) => {
256
+ const owner = `<${this.tag}>`;
257
+ const text = code === 40
258
+ ? message(40, owner, driver)
259
+ : code === 41
260
+ ? message(41, owner, driver)
261
+ : message(43, owner, driver);
262
+ this.fail(cause, 'command', text, driver);
263
+ }));
264
+ }
265
+ /** Does `tag` render in the frame lane (`spec.renderOnFrame`)? */
266
+ #onFrame(tag) {
267
+ return this.#spec.renderOnFrame?.includes(tag) === true;
268
+ }
269
+ #storeChanged(store, state, prev) {
270
+ if (this.#reducers['StoreChanged'] !== undefined) {
271
+ this.dispatch({ _tag: 'StoreChanged', store: store.name, state, prev });
272
+ }
273
+ else {
274
+ this.#host.invalidate(this.#onFrame('StoreChanged'));
275
+ }
276
+ }
277
+ }
278
+ //# sourceMappingURL=host-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-model.js","sourceRoot":"","sources":["../src/host-model.ts"],"names":[],"mappings":"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","sourcesContent":["// The model side of one Gyral host (docs/design-docs/view/05-element.md, ADR 0006, ADR 0013):\n// state, reducers and commands. element.ts owns the DOM side (props, root, lifecycle,\n// rendering) and asks this object for state and context. Reducers run at once, so `state` is\n// always current; only the render waits (04). The interpreter and the store binding come from\n// features.ts, registered by `command()` and `defineStore()`; marker drivers (focus, emit, store\n// sends) carry their own `local` handler.\nimport { DEVTOOLS_ENABLED, devCommands, devOwner, devUpdate } from '#devtools';\nimport { splitNext, type Command, type Next } from './command.js';\nimport {\n features,\n type FeatureHost,\n type LocalDriver,\n type LocalHost,\n type StoreLink,\n} from './features.js';\nimport { fail, type ErrorPhase, type GyralError } from './errors.js';\nimport type { Seed } from './hydration.js';\nimport { runInit } from './init.js';\nimport type { Interpreter } from './internal/interpreter.js';\nimport { noteActivity, requestTransition } from './scheduler.js';\nimport { errored, subscriptions as subscriptionSet } from '#spec-features';\nimport type { Subscriptions } from './subscriptions.js';\nimport type { AnyStore } from './store.js';\nimport type { ComponentSpec, Ctx, IntentRejected, ParserCtx, Tagged } from './types.js';\nimport { message } from './view/index.js';\n\ntype Bag = Readonly<Record<string, unknown>>;\ntype Reducer<S> = (state: S, msg: Tagged, ctx: Ctx<object>) => Next<S, Tagged>;\n/** A command as the model runs it. */\nexport type ModelCommand = Command<Tagged | IntentRejected>;\ntype Cmd = ModelCommand;\n\n/** What the model needs from its element. */\nexport interface ModelHost {\n readonly el: FeatureHost;\n readonly tag: string;\n /** The declared props as components see them (defaults applied). */\n readonly props: () => Bag;\n /** The host's root once it has one (focus commands run against it). */\n readonly root: () => ParentNode | undefined;\n /** Something changed that the next render must show; `onFrame`: in the frame lane (04). */\n readonly invalidate: (onFrame: boolean) => void;\n}\n\nexport class HostModel<S, P> implements LocalHost {\n readonly el: FeatureHost;\n readonly tag: string;\n readonly root: () => ParentNode | undefined;\n readonly #host: ModelHost;\n readonly #spec: ComponentSpec<S, Tagged, P>;\n readonly #reducers: Readonly<Record<string, Reducer<S> | undefined>>;\n #binding: StoreLink | undefined;\n #model: { value: S } | undefined;\n /** Props as of init or the last PropsChanged: the `prev` of the next PropsChanged. */\n #seen: Bag | undefined;\n #interpreter: Interpreter<Tagged | IntentRejected> | undefined;\n /** Commands kept while disconnected (init's, before the first connect); undefined once connected. */\n #pending: Cmd[] | undefined = [];\n /** Connected to the document (a pending stop checks it, so a move cancels the stop). */\n #on = false;\n /** `spec.subscriptions`, kept running once the host has rendered (ADR 0025). */\n #subs: Subscriptions | undefined;\n /** `init` threw (ADR 0024): the host shows its error view, or stays empty. */\n #failure: GyralError | undefined;\n /** Handling `Errored`: a failure now is reported, never sent again (no loops). */\n #erroring = false;\n\n constructor(host: ModelHost, spec: ComponentSpec<S, Tagged, P>) {\n this.#host = host;\n this.el = host.el;\n this.tag = host.tag;\n this.root = host.root;\n this.#spec = spec;\n // Sound: dispatch() only calls the reducer whose key equals msg._tag. A component without\n // messages may have no `update` (its spec type is widened to Tagged here).\n this.#reducers = ((spec as { readonly update?: object }).update ?? {}) as unknown as Readonly<\n Record<string, Reducer<S> | undefined>\n >;\n }\n\n /** The store binding, created on first use. Only reached once `defineStore()` has run. */\n readonly stores = (): StoreLink =>\n (this.#binding ??= (features.stores as NonNullable<typeof features.stores>)(\n this.#host.el,\n this.#host.tag,\n this.#spec.stores ?? [],\n (store, state, prev) => {\n this.#storeChanged(store, state, prev);\n },\n ));\n\n get ready(): boolean {\n return this.#model !== undefined;\n }\n\n /** Set when `init` threw; the host has no state then. */\n get failure(): GyralError | undefined {\n return this.#failure;\n }\n\n /** The current state, running `init` (and `initialMessages`) on first read. */\n state(initialMessages: readonly Tagged[] = []): S {\n if (this.#model === undefined) {\n this.#seen = this.#host.props();\n const next = this.#init();\n if (next === undefined) return undefined as S; // init threw: `failure` says so\n this.apply(next);\n for (const msg of initialMessages) this.dispatch(msg, false);\n }\n return (this.#model as { value: S }).value;\n }\n\n /** `init(props)`, or undefined after reporting its failure (ADR 0024). */\n #init(): Next<S, Tagged> | undefined {\n try {\n return runInit(this.#spec, this.#seen as P);\n } catch (cause) {\n this.#failure = this.fail(cause, 'init', message(74, this.tag));\n this.#model = { value: undefined as S };\n return undefined;\n }\n }\n\n /**\n * Reports a failure of this host (ADR 0024) and, for a failed update, parse or command, sends\n * `Errored` to its optional reducer. A failure while handling `Errored` is only reported.\n */\n fail(cause: unknown, phase: ErrorPhase, text: string, msg?: string): GyralError {\n const error = fail(cause, phase, text, { host: this.el, tag: this.tag, msg });\n if (!this.#erroring && errored !== undefined && this.#reducers['Errored'] !== undefined) {\n this.#erroring = true;\n try {\n errored((msg) => this.dispatch(msg), phase, error);\n } finally {\n this.#erroring = false;\n }\n }\n return error;\n }\n\n hasReducer(tag: string): boolean {\n return this.#reducers[tag] !== undefined;\n }\n\n /**\n * Resumes from a server seed (ADR 0012): the server's state, or `init(props)`'s when the\n * seed left it out. Returns init's commands, to start after the first render.\n */\n resume(seed: Seed): readonly Cmd[] {\n this.#seen = this.#host.props();\n const next = this.#init();\n if (next === undefined) return [];\n const [initial, commands] = splitNext(next);\n // Sound: the seed is this component's own state, written by the server.\n this.#model = { value: 'state' in seed ? (seed.state as S) : initial };\n return commands;\n }\n\n /**\n * PropsChanged when props differ from the last ones seen (`Object.is` per prop). A reducer\n * that throws leaves them unseen, so the next render sends PropsChanged again (ADR 0024).\n */\n syncProps(names: readonly string[]): void {\n const prev = this.#seen;\n if (prev === undefined || this.#failure !== undefined) return;\n const props = this.#host.props();\n if (names.every((name) => Object.is(props[name], prev[name]))) return;\n if (this.dispatch({ _tag: 'PropsChanged', props, prev } as Tagged, false)) this.#seen = props;\n this.#resubscribe();\n }\n\n /**\n * Runs `msg`'s reducer. A reducer that throws changes nothing (no state, no commands): the\n * failure is reported (ADR 0024) and dispatch returns false.\n */\n dispatch(msg: Tagged, schedule = true): boolean {\n noteActivity(); // settled() keeps waiting while messages arrive (04)\n const reducer = this.#reducers[msg._tag];\n if (reducer === undefined) {\n // Framework messages have optional reducers; props and stores stay readable as context.\n if (msg._tag !== 'PropsChanged' && msg._tag !== 'StoreChanged' && msg._tag !== 'Errored') {\n console.warn(message(10, this.#host.tag, msg._tag));\n }\n return true;\n }\n if (this.#failure !== undefined) return false;\n const prev = this.state();\n let next: Next<S, Tagged>;\n try {\n next = reducer(prev, msg, this.ctx() as Ctx<object>);\n } catch (cause) {\n this.fail(cause, 'update', message(73, this.tag, msg._tag), msg._tag);\n return false;\n }\n this.apply(next);\n const state = this.state();\n if (DEVTOOLS_ENABLED) devUpdate(this.#host.el, this.#host.tag, msg, prev, state);\n this.#resubscribe();\n if (!schedule) return true;\n if (this.#spec.viewTransition?.(prev, state, msg) === true) requestTransition();\n this.#host.invalidate(this.#onFrame(msg._tag));\n return true;\n }\n\n apply(next: Next<S, Tagged> | Next<S, Tagged | IntentRejected>): void {\n const [state, commands] = splitNext(next as Next<S, Tagged>);\n this.#model = { value: state };\n for (const cmd of commands as readonly Cmd[]) {\n const local = (cmd.driver as Partial<LocalDriver>).local;\n if (local !== undefined) local(this, cmd.input);\n else if (this.#pending !== undefined) this.#pending.push(cmd);\n else this.#commands().run(cmd);\n }\n }\n\n /** Starts commands kept for later (init's, after a server-rendered host's first render). */\n run(commands: readonly Cmd[]): void {\n this.apply([this.state(), commands]);\n }\n\n // Reducers and the view get this too; only parsers' type (ParserCtx) names `state`.\n ctx(): ParserCtx<P, S> {\n return {\n props: this.#host.props() as P,\n read: (store) => this.stores().read(store),\n state: this.state(),\n };\n }\n\n /**\n * Resolves stores and runs kept commands; after a real detach, starts the subscriptions again\n * (05 \"Lifecycle\"). Returns true if store instances were bound.\n */\n connect(): boolean {\n this.#on = true; // a move: the pending stop finds the host connected and does nothing\n // The nearest <gyral-stores> may differ after a move.\n const rebound = (this.#spec.stores?.length ?? 0) > 0 && this.stores().connect();\n const pending = this.#pending ?? [];\n this.#pending = undefined;\n for (const cmd of pending) this.#commands().run(cmd);\n this.#resubscribe(); // a move: unchanged, nothing restarts\n return rebound;\n }\n\n /**\n * Starts `spec.subscriptions` (ADR 0025): after the first render, as init's commands of a\n * server-rendered host are, so nothing they emit can change what hydration adopts.\n */\n subscribe(): void {\n const derive = this.#spec.subscriptions;\n if (derive === undefined || subscriptionSet === undefined) return;\n this.#subs ??= subscriptionSet(this, derive);\n this.#resubscribe();\n }\n\n /** Aborts the running command of `lane` (a subscription that left, ADR 0025). */\n cancel(lane: string): void {\n this.#interpreter?.cancel(lane);\n }\n\n /** Syncs the subscriptions while connected and healthy. */\n #resubscribe(): void {\n if (this.#pending === undefined && this.#failure === undefined) this.#subs?.update();\n }\n\n /**\n * Stops the commands one microtask later, unless the host is connected again first: a move\n * (`appendChild`, `insertBefore`) disconnects and connects in one task and keeps them running.\n */\n disconnect(): void {\n this.#binding?.disconnect();\n this.#pending ??= [];\n this.#on = false;\n queueMicrotask(() => {\n if (this.#on) return;\n this.#interpreter?.dispose();\n this.#interpreter = undefined;\n this.#subs?.reset();\n });\n }\n\n /**\n * The interpreter, started with the first command after connecting. Only reached for a\n * command built by `command()`, which registered it (features.ts).\n */\n #commands(): Interpreter<Tagged | IntentRejected> {\n const el = this.el;\n return (this.#interpreter ??= (features.commands as NonNullable<typeof features.commands>)(\n el,\n (msg) => {\n this.dispatch(msg);\n },\n DEVTOOLS_ENABLED ? devCommands(() => devOwner(el, this.tag)) : undefined,\n (cause, code, driver) => {\n const owner = `<${this.tag}>`;\n const text =\n code === 40\n ? message(40, owner, driver)\n : code === 41\n ? message(41, owner, driver)\n : message(43, owner, driver);\n this.fail(cause, 'command', text, driver);\n },\n ));\n }\n\n /** Does `tag` render in the frame lane (`spec.renderOnFrame`)? */\n #onFrame(tag: string): boolean {\n return this.#spec.renderOnFrame?.includes(tag) === true;\n }\n\n #storeChanged(store: AnyStore, state: unknown, prev: unknown): void {\n if (this.#reducers['StoreChanged'] !== undefined) {\n this.dispatch({ _tag: 'StoreChanged', store: store.name, state, prev } as Tagged);\n } else {\n this.#host.invalidate(this.#onFrame('StoreChanged'));\n }\n }\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import { type ChildValue, type SeenMarkup } from './view/index.js';
2
+ export { scheduleIsland } from './islands.js';
3
+ /**
4
+ * Hydrates a server-rendered host's root with its first view (view/07-hydration.md "Steps").
5
+ * A shadow root swaps styles in the same step (08 "Hydration"): the shared sheets are adopted
6
+ * and the server's `<style>` removed. On a mismatch development throws; production recovers
7
+ * this component only: it clears the root, renders fresh and warns.
8
+ */
9
+ export declare function hydrateRoot(host: HTMLElement, tag: string, view: ChildValue, root: ShadowRoot | HTMLElement, sheets: CSSStyleSheet[] | undefined, seen: SeenMarkup): void;
@@ -0,0 +1,35 @@
1
+ // The lazily loaded half of hydration (view/07-hydration.md "Loading"): the parallel walk and
2
+ // islands. element.ts imports this module with import() when the first host that needs it
3
+ // connects (one with a seed or `defer-hydration`), so client-only pages never fetch it.
4
+ import { DEVTOOLS_ENABLED, devMismatch } from '#devtools';
5
+ import { DEV, hydrate, HydrationMismatch, message, render, } from './view/index.js';
6
+ export { scheduleIsland } from './islands.js';
7
+ /**
8
+ * Hydrates a server-rendered host's root with its first view (view/07-hydration.md "Steps").
9
+ * A shadow root swaps styles in the same step (08 "Hydration"): the shared sheets are adopted
10
+ * and the server's `<style>` removed. On a mismatch development throws; production recovers
11
+ * this component only: it clears the root, renders fresh and warns.
12
+ */
13
+ export function hydrateRoot(host, tag, view, root, sheets, seen) {
14
+ if (sheets !== undefined) {
15
+ root.adoptedStyleSheets = sheets;
16
+ const first = root.firstChild;
17
+ if (sheets.length > 0 && first?.nodeName === 'STYLE')
18
+ first.remove();
19
+ }
20
+ try {
21
+ hydrate(view, root, `<${tag}>`, seen);
22
+ }
23
+ catch (error) {
24
+ if (!(error instanceof HydrationMismatch))
25
+ throw error;
26
+ if (DEVTOOLS_ENABLED)
27
+ devMismatch(host, tag, error.message);
28
+ if (DEV)
29
+ throw error;
30
+ console.warn(message(63, tag), error.message);
31
+ root.replaceChildren();
32
+ render(view, root, seen);
33
+ }
34
+ }
35
+ //# sourceMappingURL=hydration-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydration-client.js","sourceRoot":"","sources":["../src/hydration-client.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,0FAA0F;AAC1F,wFAAwF;AACxF,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EACL,GAAG,EACH,OAAO,EACP,iBAAiB,EACjB,OAAO,EACP,MAAM,GAGP,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CACzB,IAAiB,EACjB,GAAW,EACX,IAAgB,EAChB,IAA8B,EAC9B,MAAmC,EACnC,IAAgB;IAEhB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACxB,IAAmB,CAAC,kBAAkB,GAAG,MAAM,CAAC;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC;QAC9B,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,EAAE,QAAQ,KAAK,OAAO;YAAE,KAAK,CAAC,MAAM,EAAE,CAAC;IACvE,CAAC;IACD,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,GAAG,EAAE,IAAI,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,CAAC,KAAK,YAAY,iBAAiB,CAAC;YAAE,MAAM,KAAK,CAAC;QACvD,IAAI,gBAAgB;YAAE,WAAW,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5D,IAAI,GAAG;YAAE,MAAM,KAAK,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC","sourcesContent":["// The lazily loaded half of hydration (view/07-hydration.md \"Loading\"): the parallel walk and\n// islands. element.ts imports this module with import() when the first host that needs it\n// connects (one with a seed or `defer-hydration`), so client-only pages never fetch it.\nimport { DEVTOOLS_ENABLED, devMismatch } from '#devtools';\nimport {\n DEV,\n hydrate,\n HydrationMismatch,\n message,\n render,\n type ChildValue,\n type SeenMarkup,\n} from './view/index.js';\n\nexport { scheduleIsland } from './islands.js';\n\n/**\n * Hydrates a server-rendered host's root with its first view (view/07-hydration.md \"Steps\").\n * A shadow root swaps styles in the same step (08 \"Hydration\"): the shared sheets are adopted\n * and the server's `<style>` removed. On a mismatch development throws; production recovers\n * this component only: it clears the root, renders fresh and warns.\n */\nexport function hydrateRoot(\n host: HTMLElement,\n tag: string,\n view: ChildValue,\n root: ShadowRoot | HTMLElement,\n sheets: CSSStyleSheet[] | undefined,\n seen: SeenMarkup,\n): void {\n if (sheets !== undefined) {\n (root as ShadowRoot).adoptedStyleSheets = sheets;\n const first = root.firstChild;\n if (sheets.length > 0 && first?.nodeName === 'STYLE') first.remove();\n }\n try {\n hydrate(view, root, `<${tag}>`, seen);\n } catch (error) {\n if (!(error instanceof HydrationMismatch)) throw error;\n if (DEVTOOLS_ENABLED) devMismatch(host, tag, error.message);\n if (DEV) throw error;\n console.warn(message(63, tag), error.message);\n root.replaceChildren();\n render(view, root, seen);\n }\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import { type Seed } from './hydration.js';
2
+ /** Client side: reads and removes the seed, if this element was server-rendered by Gyral. */
3
+ export declare function takeSeed(host: Element): Seed | undefined;
4
+ /**
5
+ * The walk and islands (hydration-client.ts) once loaded; `null` if loading failed (a stale
6
+ * deployment: server-rendered hosts then render fresh); undefined until then.
7
+ */
8
+ export declare let hydrationCode: typeof import('./hydration-client.js') | null | undefined;
9
+ /**
10
+ * Loads the hydration code (once) and runs `next` when it has loaded or failed, in call
11
+ * order. settled() waits meanwhile (view/07-hydration.md "Loading").
12
+ */
13
+ export declare function whenHydrationLoads(next: () => void): void;
@@ -0,0 +1,58 @@
1
+ // The client's half of seeds and hydration loading (view/07-hydration.md "Loading"), core's
2
+ // `#hydration-loader`: reads a server-rendered host's seed on connect and loads the hydration
3
+ // walk (hydration-client.ts) with import() when the first host that needs it connects.
4
+ // Client-only builds (`gyralVitePreset({ clientOnly: true })`, gyral-c5d.11) resolve
5
+ // `#hydration-loader` to hydration-off.ts instead: no import(), so no hydration chunk.
6
+ import { SEED_ATTRIBUTE } from './hydration.js';
7
+ import { hold } from './scheduler.js';
8
+ import { message } from './view/index.js';
9
+ /** Client side: reads and removes the seed, if this element was server-rendered by Gyral. */
10
+ export function takeSeed(host) {
11
+ const raw = host.getAttribute(SEED_ATTRIBUTE);
12
+ if (raw === null)
13
+ return undefined;
14
+ host.removeAttribute(SEED_ATTRIBUTE);
15
+ try {
16
+ const parsed = JSON.parse(raw);
17
+ if (parsed === null || typeof parsed !== 'object')
18
+ return undefined;
19
+ const props = parsed.props ?? {};
20
+ return 'state' in parsed ? { state: parsed.state, props } : { props };
21
+ }
22
+ catch (error) {
23
+ console.error(message(60, host.localName, SEED_ATTRIBUTE), error);
24
+ return undefined;
25
+ }
26
+ }
27
+ /**
28
+ * The walk and islands (hydration-client.ts) once loaded; `null` if loading failed (a stale
29
+ * deployment: server-rendered hosts then render fresh); undefined until then.
30
+ */
31
+ export let hydrationCode;
32
+ /** Hosts waiting for the code, in connection order; undefined when no load is pending. */
33
+ let waiting;
34
+ /**
35
+ * Loads the hydration code (once) and runs `next` when it has loaded or failed, in call
36
+ * order. settled() waits meanwhile (view/07-hydration.md "Loading").
37
+ */
38
+ export function whenHydrationLoads(next) {
39
+ if (waiting !== undefined) {
40
+ waiting.push(next);
41
+ return;
42
+ }
43
+ waiting = [next];
44
+ const done = (code) => {
45
+ hydrationCode = code;
46
+ const hosts = waiting ?? [];
47
+ waiting = undefined;
48
+ // Each in its own microtask, in order: one host throwing doesn't stop the others. They all
49
+ // run before `hold` counts the load as done.
50
+ for (const host of hosts)
51
+ queueMicrotask(host);
52
+ };
53
+ hold(import('./hydration-client.js').then(done, (error) => {
54
+ console.error(message(61), error);
55
+ done(null);
56
+ }));
57
+ }
58
+ //# sourceMappingURL=hydration-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydration-loader.js","sourceRoot":"","sources":["../src/hydration-loader.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,8FAA8F;AAC9F,uFAAuF;AACvF,qFAAqF;AACrF,uFAAuF;AACvF,OAAO,EAAE,cAAc,EAAa,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C,6FAA6F;AAC7F,MAAM,UAAU,QAAQ,CAAC,IAAa;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC;IAC9C,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACnC,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyB,CAAC;QACvD,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QACpE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;QACjC,OAAO,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;IACxE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,KAAK,CAAC,CAAC;QAClE,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,IAAI,aAAwE,CAAC;AACpF,0FAA0F;AAC1F,IAAI,OAAmC,CAAC;AAExC;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAgB;IACjD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,OAAO;IACT,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC;IACjB,MAAM,IAAI,GAAG,CAAC,IAA0B,EAAQ,EAAE;QAChD,aAAa,GAAG,IAAI,CAAC;QACrB,MAAM,KAAK,GAAG,OAAO,IAAI,EAAE,CAAC;QAC5B,OAAO,GAAG,SAAS,CAAC;QACpB,2FAA2F;QAC3F,6CAA6C;QAC7C,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,cAAc,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,CAAC;IACF,IAAI,CACF,MAAM,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAc,EAAE,EAAE;QAC5D,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,CAAC,CAAC,CACH,CAAC;AACJ,CAAC","sourcesContent":["// The client's half of seeds and hydration loading (view/07-hydration.md \"Loading\"), core's\n// `#hydration-loader`: reads a server-rendered host's seed on connect and loads the hydration\n// walk (hydration-client.ts) with import() when the first host that needs it connects.\n// Client-only builds (`gyralVitePreset({ clientOnly: true })`, gyral-c5d.11) resolve\n// `#hydration-loader` to hydration-off.ts instead: no import(), so no hydration chunk.\nimport { SEED_ATTRIBUTE, type Seed } from './hydration.js';\nimport { hold } from './scheduler.js';\nimport { message } from './view/index.js';\n\n/** Client side: reads and removes the seed, if this element was server-rendered by Gyral. */\nexport function takeSeed(host: Element): Seed | undefined {\n const raw = host.getAttribute(SEED_ATTRIBUTE);\n if (raw === null) return undefined;\n host.removeAttribute(SEED_ATTRIBUTE);\n try {\n const parsed = JSON.parse(raw) as Partial<Seed> | null;\n if (parsed === null || typeof parsed !== 'object') return undefined;\n const props = parsed.props ?? {};\n return 'state' in parsed ? { state: parsed.state, props } : { props };\n } catch (error) {\n console.error(message(60, host.localName, SEED_ATTRIBUTE), error);\n return undefined;\n }\n}\n\n/**\n * The walk and islands (hydration-client.ts) once loaded; `null` if loading failed (a stale\n * deployment: server-rendered hosts then render fresh); undefined until then.\n */\nexport let hydrationCode: typeof import('./hydration-client.js') | null | undefined;\n/** Hosts waiting for the code, in connection order; undefined when no load is pending. */\nlet waiting: (() => void)[] | undefined;\n\n/**\n * Loads the hydration code (once) and runs `next` when it has loaded or failed, in call\n * order. settled() waits meanwhile (view/07-hydration.md \"Loading\").\n */\nexport function whenHydrationLoads(next: () => void): void {\n if (waiting !== undefined) {\n waiting.push(next);\n return;\n }\n waiting = [next];\n const done = (code: typeof hydrationCode): void => {\n hydrationCode = code;\n const hosts = waiting ?? [];\n waiting = undefined;\n // Each in its own microtask, in order: one host throwing doesn't stop the others. They all\n // run before `hold` counts the load as done.\n for (const host of hosts) queueMicrotask(host);\n };\n hold(\n import('./hydration-client.js').then(done, (error: unknown) => {\n console.error(message(61), error);\n done(null);\n }),\n );\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type * as Loader from './hydration-loader.js';
2
+ import { type Seed } from './hydration.js';
3
+ /** A seed means server-rendered markup: drop it, so the host renders fresh. */
4
+ export declare const takeSeed: (host: Element) => Seed | undefined;
5
+ /** Never loads: server-rendered hosts render fresh, as after a failed load. */
6
+ export declare const hydrationCode: typeof Loader.hydrationCode;
7
+ /** Not reached (`hydrationCode` is never undefined); runs `next` at once. */
8
+ export declare const whenHydrationLoads: (next: () => void) => void;
@@ -0,0 +1,25 @@
1
+ import { SEED_ATTRIBUTE } from './hydration.js';
2
+ import { DEV } from './view/index.js';
3
+ let warned = false;
4
+ /** A seed means server-rendered markup: drop it, so the host renders fresh. */
5
+ export const takeSeed = ((host) => {
6
+ if (!host.hasAttribute(SEED_ATTRIBUTE))
7
+ return undefined;
8
+ host.removeAttribute(SEED_ATTRIBUTE);
9
+ if (DEV && !warned) {
10
+ warned = true;
11
+ console.warn(`gyral: <${host.localName}> was server-rendered (it has a hydration seed), but this app ` +
12
+ `is built client-only (gyralVitePreset({ clientOnly: true })), which leaves the ` +
13
+ `hydration code out: it renders fresh, replacing the server's markup, and so does every ` +
14
+ `server-rendered host. Drop clientOnly for apps that render on the server ` +
15
+ `(view/07-hydration.md "Client-only builds").`);
16
+ }
17
+ return { props: {} };
18
+ });
19
+ /** Never loads: server-rendered hosts render fresh, as after a failed load. */
20
+ export const hydrationCode = null;
21
+ /** Not reached (`hydrationCode` is never undefined); runs `next` at once. */
22
+ export const whenHydrationLoads = ((next) => {
23
+ next();
24
+ });
25
+ //# sourceMappingURL=hydration-off.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydration-off.js","sourceRoot":"","sources":["../src/hydration-off.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAa,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAEtC,IAAI,MAAM,GAAG,KAAK,CAAC;AAEnB,+EAA+E;AAC/E,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAa,EAAoB,EAAE;IAC3D,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC;QAAE,OAAO,SAAS,CAAC;IACzD,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC;IACrC,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,GAAG,IAAI,CAAC;QACd,OAAO,CAAC,IAAI,CACV,WAAW,IAAI,CAAC,SAAS,gEAAgE;YACvF,iFAAiF;YACjF,yFAAyF;YACzF,2EAA2E;YAC3E,8CAA8C,CACjD,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AACvB,CAAC,CAAkC,CAAC;AAEpC,+EAA+E;AAC/E,MAAM,CAAC,MAAM,aAAa,GAAgC,IAAI,CAAC;AAE/D,6EAA6E;AAC7E,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,IAAgB,EAAQ,EAAE;IAC5D,IAAI,EAAE,CAAC;AACT,CAAC,CAA4C,CAAC","sourcesContent":["// `#hydration-loader` in client-only builds (`gyralVitePreset({ clientOnly: true })`,\n// gyral-c5d.11, view/07-hydration.md \"Client-only builds\"): the same exports as\n// hydration-loader.ts, without the hydration walk or its import(), so the bundle has no\n// hydration chunk (and, without other import()s, no preload helper). A server-rendered host\n// met anyway renders fresh: its seed is dropped (init runs from its attributes), `hydrationCode`\n// is `null` as after a failed load, so element.ts clears the root, and islands start at once.\n// Development warns once; production renders fresh silently.\nimport type * as Loader from './hydration-loader.js';\nimport { SEED_ATTRIBUTE, type Seed } from './hydration.js';\nimport { DEV } from './view/index.js';\n\nlet warned = false;\n\n/** A seed means server-rendered markup: drop it, so the host renders fresh. */\nexport const takeSeed = ((host: Element): Seed | undefined => {\n if (!host.hasAttribute(SEED_ATTRIBUTE)) return undefined;\n host.removeAttribute(SEED_ATTRIBUTE);\n if (DEV && !warned) {\n warned = true;\n console.warn(\n `gyral: <${host.localName}> was server-rendered (it has a hydration seed), but this app ` +\n `is built client-only (gyralVitePreset({ clientOnly: true })), which leaves the ` +\n `hydration code out: it renders fresh, replacing the server's markup, and so does every ` +\n `server-rendered host. Drop clientOnly for apps that render on the server ` +\n `(view/07-hydration.md \"Client-only builds\").`,\n );\n }\n return { props: {} };\n}) satisfies typeof Loader.takeSeed;\n\n/** Never loads: server-rendered hosts render fresh, as after a failed load. */\nexport const hydrationCode: typeof Loader.hydrationCode = null;\n\n/** Not reached (`hydrationCode` is never undefined); runs `next` at once. */\nexport const whenHydrationLoads = ((next: () => void): void => {\n next();\n}) satisfies typeof Loader.whenHydrationLoads;\n"]}
@@ -1,4 +1,3 @@
1
- import type { PropertyDeclaration } from 'lit';
2
1
  /** Host attribute holding the JSON seed. Removed once the client has read it. */
3
2
  export declare const SEED_ATTRIBUTE = "data-gyral-seed";
4
3
  export interface Seed {
@@ -12,25 +11,8 @@ export interface Seed {
12
11
  }
13
12
  /** JSON equality: seeds are JSON, so two values that serialize alike hydrate alike. */
14
13
  export declare const sameJson: (a: unknown, b: unknown) => boolean;
15
- type Declarations = Readonly<Record<string, PropertyDeclaration>>;
16
14
  /**
17
- * Server side: records the element's state and its props that are not already present as
18
- * attributes (property bindings such as `.items=${data}` are not in the HTML otherwise).
19
- * The SSR renderer escapes attribute values, so the JSON is HTML-safe.
15
+ * Server side: the seed for a component whose props `carried` travel in no attribute
16
+ * (property holes) and whose state is `state`; `initial` is `init(props)`'s state.
20
17
  */
21
- export declare function writeSeed(host: Element, state: unknown, props: Readonly<Record<string, unknown>>, declarations: Declarations, initialState?: {
22
- readonly value: unknown;
23
- }): void;
24
- /**
25
- * Client side, right after hydration (gyral-4k7.12, ADR 0012): Lit SSR writes nothing for
26
- * an empty primitive (`''`, `null`, `undefined`), so `<!--lit-part--><!--/lit-part-->`
27
- * has no Text node between the markers. Hydration still records the primitive as the
28
- * part's committed value, and the next text commit writes `.data` into the
29
- * `<!--/lit-part-->` comment instead. Restore the empty Text node a client render would
30
- * have created. Harmless for `nothing` and empty iterables, which clear or insert before
31
- * the end marker. Shadow roots below `root` are handled by their own hosts.
32
- */
33
- export declare function fillEmptyTextParts(root: Node): void;
34
- /** Client side: reads and removes the seed, if this element was server-rendered by Gyral. */
35
- export declare function takeSeed(host: Element): Seed | undefined;
36
- export {};
18
+ export declare function makeSeed(tag: string, state: unknown, initial: unknown, carried: Readonly<Record<string, unknown>>): Seed;
package/dist/hydration.js CHANGED
@@ -1,72 +1,23 @@
1
+ // Server-render seeds (docs/design-docs/0012-ssr.md, view/06-server.md "Components"). The
2
+ // server writes each component's state, plus the props an attribute can't carry, into one
3
+ // attribute; the client reads it on connect, before its first render, so both sides start from
4
+ // the same state. The client reads seeds in hydration-loader.ts (core's `#hydration-loader`:
5
+ // hydration-off.ts in client-only builds); the walk that then hydrates the server's DOM is
6
+ // hydration-client.ts, which the loader imports lazily (view/07-hydration.md "Loading").
1
7
  import { warnJsonHazard } from './json-safety.js';
8
+ import { DEV } from './view/index.js';
2
9
  /** Host attribute holding the JSON seed. Removed once the client has read it. */
3
10
  export const SEED_ATTRIBUTE = 'data-gyral-seed';
4
11
  /** JSON equality: seeds are JSON, so two values that serialize alike hydrate alike. */
5
12
  export const sameJson = (a, b) => JSON.stringify(a) === JSON.stringify(b);
6
- function attributeName(name, decl) {
7
- if (decl.attribute === false)
8
- return undefined;
9
- return typeof decl.attribute === 'string' ? decl.attribute : name.toLowerCase();
10
- }
11
13
  /**
12
- * Server side: records the element's state and its props that are not already present as
13
- * attributes (property bindings such as `.items=${data}` are not in the HTML otherwise).
14
- * The SSR renderer escapes attribute values, so the JSON is HTML-safe.
14
+ * Server side: the seed for a component whose props `carried` travel in no attribute
15
+ * (property holes) and whose state is `state`; `initial` is `init(props)`'s state.
15
16
  */
16
- export function writeSeed(host, state, props, declarations, initialState) {
17
- const carried = {};
18
- for (const [name, value] of Object.entries(props)) {
19
- const decl = declarations[name] ?? {};
20
- const attr = attributeName(name, decl);
21
- if (value !== undefined && (attr === undefined || !host.hasAttribute(attr))) {
22
- carried[name] = value;
23
- }
24
- }
25
- const derivable = initialState !== undefined && sameJson(state, initialState.value);
26
- const seed = derivable ? { props: carried } : { state, props: carried };
27
- warnJsonHazard(`<${host.localName}>`, seed, 'seed');
28
- host.setAttribute(SEED_ATTRIBUTE, JSON.stringify(seed));
29
- }
30
- /**
31
- * Client side, right after hydration (gyral-4k7.12, ADR 0012): Lit SSR writes nothing for
32
- * an empty primitive (`''`, `null`, `undefined`), so `<!--lit-part--><!--/lit-part-->`
33
- * has no Text node between the markers. Hydration still records the primitive as the
34
- * part's committed value, and the next text commit writes `.data` into the
35
- * `<!--/lit-part-->` comment instead. Restore the empty Text node a client render would
36
- * have created. Harmless for `nothing` and empty iterables, which clear or insert before
37
- * the end marker. Shadow roots below `root` are handled by their own hosts.
38
- */
39
- export function fillEmptyTextParts(root) {
40
- const doc = root.ownerDocument ?? root;
41
- const walker = doc.createTreeWalker(root, NodeFilter.SHOW_COMMENT);
42
- const empty = [];
43
- for (let node = walker.nextNode(); node !== null; node = walker.nextNode()) {
44
- const next = node.nextSibling;
45
- if (node.data === 'lit-part' &&
46
- next instanceof Comment &&
47
- next.data === '/lit-part') {
48
- empty.push(node);
49
- }
50
- }
51
- for (const start of empty)
52
- start.after(doc.createTextNode(''));
53
- }
54
- /** Client side: reads and removes the seed, if this element was server-rendered by Gyral. */
55
- export function takeSeed(host) {
56
- const raw = host.getAttribute(SEED_ATTRIBUTE);
57
- if (raw === null)
58
- return undefined;
59
- host.removeAttribute(SEED_ATTRIBUTE);
60
- try {
61
- const parsed = JSON.parse(raw);
62
- if (parsed === null || typeof parsed !== 'object')
63
- return undefined;
64
- const props = parsed.props ?? {};
65
- return 'state' in parsed ? { state: parsed.state, props } : { props };
66
- }
67
- catch (error) {
68
- console.error(`<${host.localName}> has an unreadable ${SEED_ATTRIBUTE}`, error);
69
- return undefined;
70
- }
17
+ export function makeSeed(tag, state, initial, carried) {
18
+ const seed = sameJson(state, initial) ? { props: carried } : { state, props: carried };
19
+ if (DEV)
20
+ warnJsonHazard(`<${tag}>`, seed, 'seed'); // view/06-server.md "Seed": development
21
+ return seed;
71
22
  }
72
23
  //# sourceMappingURL=hydration.js.map