sygnal 5.3.7 → 6.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 (438) hide show
  1. package/CHANGELOG.md +646 -0
  2. package/README.md +77 -47
  3. package/dist/astro/client.cjs.js +33 -8114
  4. package/dist/astro/client.cjs.js.map +1 -0
  5. package/dist/astro/client.mjs +33 -8114
  6. package/dist/astro/client.mjs.map +1 -0
  7. package/dist/astro/index.cjs.js +1039 -9
  8. package/dist/astro/index.cjs.js.map +1 -0
  9. package/dist/astro/index.mjs +1038 -9
  10. package/dist/astro/index.mjs.map +1 -0
  11. package/dist/astro/server.cjs.js +3400 -166
  12. package/dist/astro/server.cjs.js.map +1 -0
  13. package/dist/astro/server.mjs +3400 -166
  14. package/dist/astro/server.mjs.map +1 -0
  15. package/dist/devtools.cjs.js +1431 -0
  16. package/dist/devtools.cjs.js.map +1 -0
  17. package/dist/devtools.esm.js +1419 -0
  18. package/dist/devtools.esm.js.map +1 -0
  19. package/dist/diagnostics.cjs.js +4033 -0
  20. package/dist/diagnostics.cjs.js.map +1 -0
  21. package/dist/diagnostics.esm.js +4003 -0
  22. package/dist/diagnostics.esm.js.map +1 -0
  23. package/dist/element.cjs.js +230 -0
  24. package/dist/element.cjs.js.map +1 -0
  25. package/dist/element.esm.js +228 -0
  26. package/dist/element.esm.js.map +1 -0
  27. package/dist/guide/accessibility.md +257 -0
  28. package/dist/guide/adapters.md +221 -0
  29. package/dist/guide/behaviors.md +312 -0
  30. package/dist/guide/browser-sources.md +203 -0
  31. package/dist/guide/drag-and-drop.md +342 -0
  32. package/dist/guide/element-commands.md +306 -0
  33. package/dist/guide/error-boundaries.md +169 -0
  34. package/dist/guide/forms-reference.md +381 -0
  35. package/dist/guide/forms.md +250 -0
  36. package/dist/guide/http.md +299 -0
  37. package/dist/guide/inputs.md +173 -0
  38. package/dist/guide/persistence.md +245 -0
  39. package/dist/guide/recipes/carousel.md +155 -0
  40. package/dist/guide/recipes/charts.md +177 -0
  41. package/dist/guide/recipes/code-editor.md +135 -0
  42. package/dist/guide/recipes/data-grid.md +155 -0
  43. package/dist/guide/recipes/data-table.md +196 -0
  44. package/dist/guide/recipes/i18n.md +222 -0
  45. package/dist/guide/recipes/icons.md +115 -0
  46. package/dist/guide/recipes/overview.md +33 -0
  47. package/dist/guide/recipes/rich-text.md +154 -0
  48. package/dist/guide/resources.md +471 -0
  49. package/dist/guide/ssr.md +255 -0
  50. package/dist/guide/timers.md +178 -0
  51. package/dist/guide/ui/accordion.md +93 -0
  52. package/dist/guide/ui/combobox.md +144 -0
  53. package/dist/guide/ui/dialog.md +124 -0
  54. package/dist/guide/ui/disclosure.md +60 -0
  55. package/dist/guide/ui/menu.md +125 -0
  56. package/dist/guide/ui/overview.md +166 -0
  57. package/dist/guide/ui/popover.md +101 -0
  58. package/dist/guide/ui/select.md +114 -0
  59. package/dist/guide/ui/tabs.md +161 -0
  60. package/dist/guide/ui/toaster.md +152 -0
  61. package/dist/guide/ui/tooltip.md +103 -0
  62. package/dist/guide/undo.md +178 -0
  63. package/dist/guide/virtual-collections.md +183 -0
  64. package/dist/guide/web-components.md +179 -0
  65. package/dist/guide/widgets.md +217 -0
  66. package/dist/index.cjs.js +15283 -6279
  67. package/dist/index.cjs.js.map +1 -0
  68. package/dist/index.d.ts +3739 -370
  69. package/dist/index.esm.js +15230 -6274
  70. package/dist/index.esm.js.map +1 -0
  71. package/dist/jsx-dev-runtime.cjs.js +27 -329
  72. package/dist/jsx-dev-runtime.cjs.js.map +1 -0
  73. package/dist/jsx-dev-runtime.esm.js +20 -322
  74. package/dist/jsx-dev-runtime.esm.js.map +1 -0
  75. package/dist/jsx-runtime.cjs.js +27 -329
  76. package/dist/jsx-runtime.cjs.js.map +1 -0
  77. package/dist/jsx-runtime.esm.js +20 -322
  78. package/dist/jsx-runtime.esm.js.map +1 -0
  79. package/dist/jsx.cjs.js +11 -309
  80. package/dist/jsx.cjs.js.map +1 -0
  81. package/dist/jsx.esm.js +9 -310
  82. package/dist/jsx.esm.js.map +1 -0
  83. package/dist/react.cjs.js +117 -0
  84. package/dist/react.cjs.js.map +1 -0
  85. package/dist/react.esm.js +115 -0
  86. package/dist/react.esm.js.map +1 -0
  87. package/dist/shims/globalthis.cjs +20 -0
  88. package/dist/sygnal.min.js +2 -1
  89. package/dist/sygnal.min.js.map +1 -0
  90. package/dist/ui-combobox.cjs.js +169 -0
  91. package/dist/ui-combobox.cjs.js.map +1 -0
  92. package/dist/ui-combobox.esm.js +148 -0
  93. package/dist/ui-combobox.esm.js.map +1 -0
  94. package/dist/ui-menu.cjs.js +87 -0
  95. package/dist/ui-menu.cjs.js.map +1 -0
  96. package/dist/ui-menu.esm.js +66 -0
  97. package/dist/ui-menu.esm.js.map +1 -0
  98. package/dist/ui-select.cjs.js +104 -0
  99. package/dist/ui-select.cjs.js.map +1 -0
  100. package/dist/ui-select.esm.js +83 -0
  101. package/dist/ui-select.esm.js.map +1 -0
  102. package/dist/ui.cjs.js +738 -0
  103. package/dist/ui.cjs.js.map +1 -0
  104. package/dist/ui.esm.js +727 -0
  105. package/dist/ui.esm.js.map +1 -0
  106. package/dist/vike/ClientOnly.cjs.js +5 -14
  107. package/dist/vike/ClientOnly.cjs.js.map +1 -0
  108. package/dist/vike/ClientOnly.mjs +5 -14
  109. package/dist/vike/ClientOnly.mjs.map +1 -0
  110. package/dist/vike/{+config.js → config/+config.js} +10 -1
  111. package/dist/vike/config/+config.js.map +1 -0
  112. package/dist/vike/config/package.json +6 -0
  113. package/dist/vike/onRenderClient.cjs.js +166 -95
  114. package/dist/vike/onRenderClient.cjs.js.map +1 -0
  115. package/dist/vike/onRenderClient.mjs +166 -95
  116. package/dist/vike/onRenderClient.mjs.map +1 -0
  117. package/dist/vike/onRenderHtml.cjs.js +60 -24
  118. package/dist/vike/onRenderHtml.cjs.js.map +1 -0
  119. package/dist/vike/onRenderHtml.mjs +61 -25
  120. package/dist/vike/onRenderHtml.mjs.map +1 -0
  121. package/dist/vite/plugin.cjs.js +926 -65
  122. package/dist/vite/plugin.cjs.js.map +1 -0
  123. package/dist/vite/plugin.mjs +925 -65
  124. package/dist/vite/plugin.mjs.map +1 -0
  125. package/dist/zag.cjs.js +408 -0
  126. package/dist/zag.cjs.js.map +1 -0
  127. package/dist/zag.esm.js +405 -0
  128. package/dist/zag.esm.js.map +1 -0
  129. package/llms.txt +313 -0
  130. package/package.json +109 -16
  131. package/src/astro/client.ts +40 -18
  132. package/src/astro/index.d.ts +48 -1
  133. package/src/astro/index.ts +106 -9
  134. package/src/astro/server.ts +11 -3
  135. package/src/collection.ts +6 -90
  136. package/src/core/actions.ts +134 -0
  137. package/src/core/cell.ts +202 -0
  138. package/src/core/debug.ts +23 -0
  139. package/src/core/define.ts +242 -0
  140. package/src/core/hooks.ts +314 -0
  141. package/src/core/hosts/collection.ts +325 -0
  142. package/src/core/hosts/switchable.ts +146 -0
  143. package/src/core/instance.ts +592 -0
  144. package/src/core/markers/clientonly.ts +13 -0
  145. package/src/core/markers/lazy.ts +40 -0
  146. package/src/core/markers/portal.ts +96 -0
  147. package/src/core/markers/suspense.ts +41 -0
  148. package/src/core/markers/transition.ts +70 -0
  149. package/src/core/registry.ts +25 -0
  150. package/src/core/runtime.ts +573 -0
  151. package/src/core/statics.ts +104 -0
  152. package/src/core/teardown.ts +60 -0
  153. package/src/core/view.ts +37 -0
  154. package/src/cycle/dom/DocumentDOMSource.ts +13 -8
  155. package/src/cycle/dom/ElementFinder.ts +7 -9
  156. package/src/cycle/dom/EventDelegator.ts +174 -223
  157. package/src/cycle/dom/IsolateModule.ts +65 -35
  158. package/src/cycle/dom/MainDOMSource.ts +13 -2
  159. package/src/cycle/dom/PriorityQueue.ts +4 -2
  160. package/src/cycle/dom/SymbolTree.ts +18 -47
  161. package/src/cycle/dom/classNameModule.ts +76 -0
  162. package/src/cycle/dom/controlledInputModule.ts +50 -0
  163. package/src/cycle/dom/enrichEventStream.ts +29 -45
  164. package/src/cycle/dom/fragment.ts +7 -0
  165. package/src/cycle/dom/isolate.ts +30 -27
  166. package/src/cycle/dom/makeDOMDriver.ts +115 -57
  167. package/src/cycle/dom/mockDOMSource.ts +83 -9
  168. package/src/cycle/dom/modules.ts +21 -4
  169. package/src/cycle/dom/propsModule.ts +65 -0
  170. package/src/cycle/dom/selectModule.ts +22 -17
  171. package/src/cycle/dom/snabbdom.ts +1 -6
  172. package/src/cycle/dom/thunk.ts +3 -0
  173. package/src/cycle/dom/utils.ts +98 -0
  174. package/src/cycle/dom/viewTransition.ts +43 -0
  175. package/src/cycle/state/StateSource.ts +20 -4
  176. package/src/cycle/state/objIsEqual.ts +50 -0
  177. package/src/cycle/state/types.ts +0 -10
  178. package/src/defineComponent.ts +34 -0
  179. package/src/devtools.d.ts +151 -0
  180. package/src/devtools.ts +34 -0
  181. package/src/element.d.ts +59 -0
  182. package/src/element.ts +235 -0
  183. package/src/extra/backoff.ts +9 -0
  184. package/src/extra/behaviors.ts +169 -0
  185. package/src/extra/browserSignals.ts +23 -0
  186. package/src/extra/browserSources.ts +326 -0
  187. package/src/extra/command.ts +3 -3
  188. package/src/extra/controls.ts +47 -0
  189. package/src/extra/copyAsTest.ts +286 -0
  190. package/src/extra/devtools.ts +109 -31
  191. package/src/extra/devtoolsActions.ts +379 -0
  192. package/src/extra/devtoolsHook.ts +9 -0
  193. package/src/extra/devtoolsNext.ts +83 -0
  194. package/src/extra/diagnostics/checks/actionLog.ts +108 -0
  195. package/src/extra/diagnostics/checks/behaviors.ts +49 -0
  196. package/src/extra/diagnostics/checks/browserSources.ts +96 -0
  197. package/src/extra/diagnostics/checks/collections.ts +67 -0
  198. package/src/extra/diagnostics/checks/controls.ts +148 -0
  199. package/src/extra/diagnostics/checks/dataset.ts +57 -0
  200. package/src/extra/diagnostics/checks/dom.ts +250 -0
  201. package/src/extra/diagnostics/checks/elementCommands.ts +175 -0
  202. package/src/extra/diagnostics/checks/events.ts +83 -0
  203. package/src/extra/diagnostics/checks/fetch.ts +135 -0
  204. package/src/extra/diagnostics/checks/forms.ts +163 -0
  205. package/src/extra/diagnostics/checks/index.ts +202 -0
  206. package/src/extra/diagnostics/checks/inspect.ts +427 -0
  207. package/src/extra/diagnostics/checks/next.ts +417 -0
  208. package/src/extra/diagnostics/checks/persist.ts +54 -0
  209. package/src/extra/diagnostics/checks/props.ts +56 -0
  210. package/src/extra/diagnostics/checks/public.d.ts +302 -0
  211. package/src/extra/diagnostics/checks/replies.ts +128 -0
  212. package/src/extra/diagnostics/checks/router.ts +100 -0
  213. package/src/extra/diagnostics/checks/rxjsHints.ts +88 -0
  214. package/src/extra/diagnostics/checks/shared.ts +203 -0
  215. package/src/extra/diagnostics/checks/shorthand.ts +115 -0
  216. package/src/extra/diagnostics/checks/sortable.ts +129 -0
  217. package/src/extra/diagnostics/checks/state.ts +148 -0
  218. package/src/extra/diagnostics/checks/statics.ts +48 -0
  219. package/src/extra/diagnostics/checks/strict.ts +55 -0
  220. package/src/extra/diagnostics/checks/timers.ts +80 -0
  221. package/src/extra/diagnostics/checks/viewTransitions.ts +47 -0
  222. package/src/extra/diagnostics/checks/virtual.ts +73 -0
  223. package/src/extra/diagnostics/checks/widgets.ts +109 -0
  224. package/src/extra/diagnostics/checks/wiring.ts +121 -0
  225. package/src/extra/diagnostics/codes.ts +477 -0
  226. package/src/extra/diagnostics/index.ts +353 -0
  227. package/src/extra/diagnostics/legacy.ts +76 -0
  228. package/src/extra/driverFactories.ts +172 -60
  229. package/src/extra/elementCommands.ts +53 -0
  230. package/src/extra/eventDriver.ts +4 -0
  231. package/src/extra/fetchDriver.ts +519 -0
  232. package/src/extra/flatten.ts +75 -0
  233. package/src/extra/focusWithin.ts +27 -0
  234. package/src/extra/form.ts +268 -0
  235. package/src/extra/formHelpers.ts +139 -0
  236. package/src/extra/head.ts +106 -0
  237. package/src/extra/hmr.ts +2 -3
  238. package/src/extra/owned.ts +24 -0
  239. package/src/extra/pager.ts +50 -0
  240. package/src/extra/persist.ts +133 -0
  241. package/src/extra/pwa.ts +1 -1
  242. package/src/extra/queryCache.ts +107 -0
  243. package/src/extra/reducers.ts +13 -6
  244. package/src/extra/reduxDevtools.ts +92 -0
  245. package/src/extra/replies.ts +54 -0
  246. package/src/extra/router.ts +323 -0
  247. package/src/extra/run.ts +94 -210
  248. package/src/extra/selection.ts +76 -0
  249. package/src/extra/socketDriver.ts +265 -0
  250. package/src/extra/sortable.ts +377 -0
  251. package/src/extra/ssr.ts +427 -160
  252. package/src/extra/standardSchema.ts +27 -0
  253. package/src/extra/testing.ts +3158 -190
  254. package/src/extra/timers.ts +95 -0
  255. package/src/extra/undo.ts +261 -0
  256. package/src/extra/viewTransitions.ts +38 -0
  257. package/src/extra/virtual.ts +513 -0
  258. package/src/extra/widget.ts +201 -0
  259. package/src/extra/xstreamExtras.ts +269 -0
  260. package/src/index.d.ts +3012 -87
  261. package/src/index.ts +32 -10
  262. package/src/jsx-runtime.ts +15 -1
  263. package/src/jsx.ts +2 -1
  264. package/src/lazy.ts +50 -7
  265. package/src/portal.ts +3 -1
  266. package/src/pragma/index.ts +262 -134
  267. package/src/react-peers.d.ts +5 -0
  268. package/src/react.d.ts +43 -0
  269. package/src/react.ts +110 -0
  270. package/src/shared.ts +48 -0
  271. package/src/slot.ts +1 -1
  272. package/src/suspense.ts +3 -1
  273. package/src/switchable.ts +6 -119
  274. package/src/transition.ts +3 -1
  275. package/src/ui/accordion.ts +64 -0
  276. package/src/ui/dialog.ts +129 -0
  277. package/src/ui/disclosure.ts +35 -0
  278. package/src/ui/popover.ts +45 -0
  279. package/src/ui/shared.ts +94 -0
  280. package/src/ui/tabs.ts +82 -0
  281. package/src/ui/toaster.ts +198 -0
  282. package/src/ui/tooltip.ts +70 -0
  283. package/src/ui/zag/combobox.ts +115 -0
  284. package/src/ui/zag/menu.ts +40 -0
  285. package/src/ui/zag/select.ts +54 -0
  286. package/src/ui/zag/shared.ts +43 -0
  287. package/src/ui-combobox.d.ts +20 -0
  288. package/src/ui-combobox.ts +6 -0
  289. package/src/ui-menu.d.ts +30 -0
  290. package/src/ui-menu.ts +6 -0
  291. package/src/ui-select.d.ts +17 -0
  292. package/src/ui-select.ts +6 -0
  293. package/src/ui-zag-types.d.ts +42 -0
  294. package/src/ui.d.ts +208 -0
  295. package/src/ui.ts +15 -0
  296. package/src/vike/+config.ts +9 -1
  297. package/src/vike/ClientOnly.ts +1 -1
  298. package/src/vike/onRenderClient.ts +144 -96
  299. package/src/vike/onRenderHtml.ts +69 -26
  300. package/src/vike/types.ts +27 -4
  301. package/src/vite/globalthis-shim.ts +18 -0
  302. package/src/vite/globalthis.ts +56 -0
  303. package/src/vite/plugin.d.ts +114 -2
  304. package/src/vite/plugin.ts +920 -56
  305. package/src/zag.d.ts +64 -0
  306. package/src/zag.ts +238 -0
  307. package/dist/astro/astro/client.d.ts +0 -5
  308. package/dist/astro/astro/index.d.ts +0 -16
  309. package/dist/astro/astro/server.d.ts +0 -12
  310. package/dist/astro/client.d.ts +0 -5
  311. package/dist/astro/client.esm.js +0 -4665
  312. package/dist/astro/collection.d.ts +0 -12
  313. package/dist/astro/component.d.ts +0 -22
  314. package/dist/astro/cycle/dom/BodyDOMSource.d.ts +0 -10
  315. package/dist/astro/cycle/dom/DOMSource.d.ts +0 -11
  316. package/dist/astro/cycle/dom/DocumentDOMSource.d.ts +0 -12
  317. package/dist/astro/cycle/dom/ElementFinder.d.ts +0 -8
  318. package/dist/astro/cycle/dom/EventDelegator.d.ts +0 -34
  319. package/dist/astro/cycle/dom/IsolateModule.d.ts +0 -23
  320. package/dist/astro/cycle/dom/MainDOMSource.d.ts +0 -32
  321. package/dist/astro/cycle/dom/PriorityQueue.d.ts +0 -7
  322. package/dist/astro/cycle/dom/ScopeChecker.d.ts +0 -9
  323. package/dist/astro/cycle/dom/SymbolTree.d.ts +0 -9
  324. package/dist/astro/cycle/dom/VNodeWrapper.d.ts +0 -8
  325. package/dist/astro/cycle/dom/enrichEventStream.d.ts +0 -24
  326. package/dist/astro/cycle/dom/fromEvent.d.ts +0 -6
  327. package/dist/astro/cycle/dom/index.d.ts +0 -8
  328. package/dist/astro/cycle/dom/isolate.d.ts +0 -9
  329. package/dist/astro/cycle/dom/makeDOMDriver.d.ts +0 -11
  330. package/dist/astro/cycle/dom/mockDOMSource.d.ts +0 -17
  331. package/dist/astro/cycle/dom/modules.d.ts +0 -5
  332. package/dist/astro/cycle/dom/snabbdom.d.ts +0 -22
  333. package/dist/astro/cycle/dom/styleModule.d.ts +0 -13
  334. package/dist/astro/cycle/dom/thunk.d.ts +0 -11
  335. package/dist/astro/cycle/dom/utils.d.ts +0 -8
  336. package/dist/astro/cycle/isolate/index.d.ts +0 -42
  337. package/dist/astro/cycle/run/adapt.d.ts +0 -6
  338. package/dist/astro/cycle/run/index.d.ts +0 -36
  339. package/dist/astro/cycle/run/internals.d.ts +0 -8
  340. package/dist/astro/cycle/run/types.d.ts +0 -49
  341. package/dist/astro/cycle/state/Collection.d.ts +0 -29
  342. package/dist/astro/cycle/state/StateSource.d.ts +0 -20
  343. package/dist/astro/cycle/state/index.d.ts +0 -5
  344. package/dist/astro/cycle/state/pickCombine.d.ts +0 -3
  345. package/dist/astro/cycle/state/pickMerge.d.ts +0 -3
  346. package/dist/astro/cycle/state/types.d.ts +0 -18
  347. package/dist/astro/cycle/state/withState.d.ts +0 -17
  348. package/dist/astro/extra/classes.d.ts +0 -7
  349. package/dist/astro/extra/devtools.d.ts +0 -78
  350. package/dist/astro/extra/dragDriver.d.ts +0 -20
  351. package/dist/astro/extra/driverFactories.d.ts +0 -12
  352. package/dist/astro/extra/eventDriver.d.ts +0 -9
  353. package/dist/astro/extra/exactState.d.ts +0 -1
  354. package/dist/astro/extra/hmr.d.ts +0 -17
  355. package/dist/astro/extra/logDriver.d.ts +0 -2
  356. package/dist/astro/extra/processDrag.d.ts +0 -19
  357. package/dist/astro/extra/processForm.d.ts +0 -15
  358. package/dist/astro/extra/run.d.ts +0 -13
  359. package/dist/astro/extra/xstreamCompat.d.ts +0 -5
  360. package/dist/astro/index.d.ts +0 -19
  361. package/dist/astro/index.esm.js +0 -27
  362. package/dist/astro/jsx-dev-runtime.d.ts +0 -1
  363. package/dist/astro/jsx-runtime.d.ts +0 -4
  364. package/dist/astro/jsx.d.ts +0 -2
  365. package/dist/astro/pragma/fn.d.ts +0 -7
  366. package/dist/astro/pragma/index.d.ts +0 -7
  367. package/dist/astro/pragma/is.d.ts +0 -10
  368. package/dist/astro/server.d.ts +0 -12
  369. package/dist/astro/server.esm.js +0 -25
  370. package/dist/astro/switchable.d.ts +0 -7
  371. package/dist/collection.d.ts +0 -12
  372. package/dist/component.d.ts +0 -22
  373. package/dist/cycle/dom/BodyDOMSource.d.ts +0 -10
  374. package/dist/cycle/dom/DOMSource.d.ts +0 -11
  375. package/dist/cycle/dom/DocumentDOMSource.d.ts +0 -12
  376. package/dist/cycle/dom/ElementFinder.d.ts +0 -8
  377. package/dist/cycle/dom/EventDelegator.d.ts +0 -34
  378. package/dist/cycle/dom/IsolateModule.d.ts +0 -23
  379. package/dist/cycle/dom/MainDOMSource.d.ts +0 -32
  380. package/dist/cycle/dom/PriorityQueue.d.ts +0 -7
  381. package/dist/cycle/dom/ScopeChecker.d.ts +0 -9
  382. package/dist/cycle/dom/SymbolTree.d.ts +0 -9
  383. package/dist/cycle/dom/VNodeWrapper.d.ts +0 -8
  384. package/dist/cycle/dom/enrichEventStream.d.ts +0 -24
  385. package/dist/cycle/dom/fromEvent.d.ts +0 -6
  386. package/dist/cycle/dom/index.d.ts +0 -8
  387. package/dist/cycle/dom/isolate.d.ts +0 -9
  388. package/dist/cycle/dom/makeDOMDriver.d.ts +0 -11
  389. package/dist/cycle/dom/mockDOMSource.d.ts +0 -17
  390. package/dist/cycle/dom/modules.d.ts +0 -5
  391. package/dist/cycle/dom/snabbdom.d.ts +0 -22
  392. package/dist/cycle/dom/styleModule.d.ts +0 -13
  393. package/dist/cycle/dom/thunk.d.ts +0 -11
  394. package/dist/cycle/dom/utils.d.ts +0 -8
  395. package/dist/cycle/isolate/index.d.ts +0 -42
  396. package/dist/cycle/run/adapt.d.ts +0 -6
  397. package/dist/cycle/run/index.d.ts +0 -36
  398. package/dist/cycle/run/internals.d.ts +0 -8
  399. package/dist/cycle/run/types.d.ts +0 -49
  400. package/dist/cycle/state/Collection.d.ts +0 -29
  401. package/dist/cycle/state/StateSource.d.ts +0 -20
  402. package/dist/cycle/state/index.d.ts +0 -5
  403. package/dist/cycle/state/pickCombine.d.ts +0 -3
  404. package/dist/cycle/state/pickMerge.d.ts +0 -3
  405. package/dist/cycle/state/types.d.ts +0 -18
  406. package/dist/cycle/state/withState.d.ts +0 -17
  407. package/dist/extra/classes.d.ts +0 -7
  408. package/dist/extra/devtools.d.ts +0 -78
  409. package/dist/extra/dragDriver.d.ts +0 -20
  410. package/dist/extra/driverFactories.d.ts +0 -12
  411. package/dist/extra/eventDriver.d.ts +0 -9
  412. package/dist/extra/exactState.d.ts +0 -1
  413. package/dist/extra/hmr.d.ts +0 -17
  414. package/dist/extra/logDriver.d.ts +0 -2
  415. package/dist/extra/processDrag.d.ts +0 -19
  416. package/dist/extra/processForm.d.ts +0 -15
  417. package/dist/extra/run.d.ts +0 -13
  418. package/dist/extra/xstreamCompat.d.ts +0 -5
  419. package/dist/jsx-dev-runtime.d.ts +0 -1
  420. package/dist/jsx-dev-runtime.js +0 -224
  421. package/dist/jsx-runtime.d.ts +0 -4
  422. package/dist/jsx-runtime.js +0 -224
  423. package/dist/jsx.d.ts +0 -2
  424. package/dist/pragma/fn.d.ts +0 -7
  425. package/dist/pragma/index.d.ts +0 -7
  426. package/dist/pragma/is.d.ts +0 -10
  427. package/dist/switchable.d.ts +0 -7
  428. package/dist/vike/+config.cjs.js +0 -65
  429. package/src/component.ts +0 -2256
  430. package/src/cycle/isolate/index.ts +0 -196
  431. package/src/cycle/run/index.ts +0 -151
  432. package/src/cycle/run/internals.ts +0 -143
  433. package/src/cycle/state/Collection.ts +0 -174
  434. package/src/cycle/state/index.ts +0 -5
  435. package/src/cycle/state/pickCombine.ts +0 -167
  436. package/src/cycle/state/pickMerge.ts +0 -122
  437. package/src/cycle/state/withState.ts +0 -47
  438. package/src/pragma/fn.ts +0 -55
@@ -0,0 +1,9 @@
1
+ /*
2
+ * PLAN-3: the retry delay shared by makeSocketDriver's `reconnect` and makeFetchDriver's `retry`.
3
+ * Delay of retry n (from 0): `min(maxDelayMs, delayMs * 2^n)`, varied by ±`jitter` (a fraction;
4
+ * `false` = none). Defaults `{ delayMs: 500, maxDelayMs: 10000, jitter: 0.2 }`.
5
+ */
6
+ export const backoff = (p: {delayMs?: number; maxDelayMs?: number; jitter?: number | boolean}, n: number) => {
7
+ const j = p.jitter === false ? 0 : p.jitter == null || p.jitter === true ? 0.2 : +p.jitter;
8
+ return Math.min(p.maxDelayMs ?? 10000, (p.delayMs ?? 500) * 2 ** n) * (1 + j * (2 * Math.random() - 1));
9
+ };
@@ -0,0 +1,169 @@
1
+ /*
2
+ * PLAN-4 GS-1: reusable behaviors.
3
+ *
4
+ * const pager = defineBehavior({ initialState, intent: (sources, options) => ..., model, calculated })
5
+ * TaskList.uses = { pager: pager({ pageSize: 10, next: Newer, prev: Older }) }
6
+ *
7
+ * A behavior runs on state[key] (a lens). Its actions are '<key>.<ACTION>' (D109). Each value a
8
+ * factory returns carries its own `merge(component, key)`; the core only loops over `uses` and
9
+ * calls it (D114), so an app that never imports this module pays nothing.
10
+ *
11
+ * Merge rules (applied to the component instance, never to its statics):
12
+ * - initialState: state[key] = the behavior's initialState, with the options that name one of its
13
+ * keys (pageSize) overriding it, plus its calculated fields. On a sub-component host (a
14
+ * Collection item, a child with a `state` prop) the slice isn't written into initialState
15
+ * (that would replace the parent's slice, SYG405): state[key] reads as that default until the
16
+ * first write (the core's `_idle` defaults, as for resources).
17
+ * - calculated: fields of the slice, stored on it (state.pager.offset), recomputed after every
18
+ * behavior reducer and after any host STATE reducer that changes state[key].
19
+ * - model: each entry gets the slice (STATE returns the new slice; ABORT and the slice itself
20
+ * mean no change, GS-4), `next('ACTION')` names the behavior's own actions. A host entry for
21
+ * the same action ('pager.NEXT') runs after the behavior's: a host STATE reducer gets the full
22
+ * state with the behavior's update applied (its ABORT keeps that update), a host EFFECT runs
23
+ * after the behavior's, and a host value sink (EVENTS, PARENT, a driver) replaces the
24
+ * behavior's value for that sink.
25
+ * - intent: gets the host's sources (DOM is the host's isolated DOM source; CHILD, EVENTS and
26
+ * drivers as they are) with STATE lensed to the slice, plus the options. A host intent action
27
+ * with the same namespaced name overrides the behavior's trigger.
28
+ * - `instance._behaviorActions` maps each behavior-owned action to its key (t.actions, 2-C).
29
+ * A host intent action of the same name makes it host-owned (removed from the map).
30
+ * - renderComponent marks the streams it adds for simulateAction (`__sygnalTestActions`); they
31
+ * are merged with a behavior trigger of the same name instead of overriding it.
32
+ * - D197 (PLAN-5): every model handler gets `(slice, data, next, props, options, key)`: the
33
+ * use's options and its key in `uses` (so a driver request can name a reply action
34
+ * `key + '.LOADED'`); the intent gets `(sources, options, key)`.
35
+ * - D197: `HOST: (state, data, next, props, options, key) => state` in a model entry is a STATE
36
+ * reducer on the host's whole state (sortable reorders the host's array); ABORT or the same
37
+ * state is no change; the slice's calculated fields are recomputed when it changed. G-378:
38
+ * with a STATE in the same entry, STATE runs first and HOST gets its result.
39
+ * - D197: `timers: (slice, options, key) => ({ name: spec })` declares timers (makeTimerDriver)
40
+ * for the host: named '<key>.<name>', a spec's action / frame naming one of the behavior's
41
+ * actions is namespaced as next() does. They join the host's own `timers` static through an
42
+ * accessor on the component function (installed once; the host's own value is kept as is and
43
+ * can still be assigned), which reads the host's current `uses`.
44
+ * - Limitations: a host intent must return an object (not one stream).
45
+ */
46
+ import xs from './xstreamCompat'
47
+ import {isAbort} from '../shared'
48
+ // a model entry as { sink: fn }: a constant is sent as is, `true` sends the action's data, an
49
+ // EFFECT constant does nothing (as the core treats them)
50
+ const sinksOf = (e: any, S: string): any => {
51
+ const o: any = typeof e == 'function' ? {[S]: e} : {...e}
52
+ for (const s in o) {
53
+ const v = o[s]
54
+ if (typeof v != 'function') o[s] = s == 'EFFECT' ? () => {} : v === true || v === undefined ? (_: any, d: any) => d : () => v
55
+ }
56
+ return o
57
+ }
58
+
59
+ // two STATE reducers in turn: the second gets the first's state (the given one when it ABORTs);
60
+ // an ABORT from the second keeps the first's
61
+ const seq = (bf: any, hf: any) => (st: any, ...x: any[]) => {
62
+ const r = bf(st, ...x), q = hf(isAbort(r) ? st : r, ...x)
63
+ return isAbort(q) ? r : q
64
+ }
65
+
66
+ const calcOf = (calcs: any) => (r: any) => {
67
+ if (r && typeof r == 'object') for (const f in calcs) r = {...r, [f]: calcs[f](r)}
68
+ return r
69
+ }
70
+
71
+ // the hosts whose `timers` static is an accessor (D197); the accessor's getter: the host's own
72
+ // timers plus each behavior's (from the host's current `uses`)
73
+ const timed = new WeakSet<any>()
74
+ const addTimers = (v: any): void => {
75
+ if (timed.has(v)) return
76
+ timed.add(v)
77
+ let own = v.timers
78
+ const all = (st: any) => {
79
+ const o: any = {}, f = own
80
+ if (typeof f == 'function') Object.assign(o, f(st))
81
+ else if (f && typeof f == 'object') for (const r in f) o[r] = f[r](st)
82
+ const u = v.uses
83
+ for (const k in u) {
84
+ const b = u[k], t = b?.timers?.(st?.[k] ?? b.state, b.options, k), rn = (a: any) => a in (b.model || {}) ? k + '.' + a : a
85
+ for (const n in t) {
86
+ const x = t[n]
87
+ o[k + '.' + n] = x && {...x, ...(x.action && {action: rn(x.action)}), ...(x.frame && {frame: rn(x.frame)})}
88
+ }
89
+ }
90
+ return o
91
+ }
92
+ Object.defineProperty(v, 'timers', {configurable: true, enumerable: true, get: () => all, set: (x: any) => { own = x }})
93
+ }
94
+
95
+ const mergeBehavior = (c: any, k: string, b: any): void => {
96
+ const S = c.stateSourceName, calcs = b.calculated, calc = calcOf(calcs), model = c.model = {...c.model}, slice = b.state
97
+ const owned = c._behaviorActions ||= {}, ns = (a: string) => k + '.' + a, opts = b.options
98
+ if (b.timers && c.view) addTimers(c.view)
99
+ if (c.isSubComponent && !c.isolatedState) c._idle = {...c._idle, [k]: slice}
100
+ else c.initialState = {...(typeof c.initialState == 'object' ? c.initialState : {}), [k]: slice}
101
+
102
+ // the slice's calculated fields stay fresh when a host reducer changes state[key]
103
+ const fresh = (f: any) => (st: any, ...x: any[]) => {
104
+ const r = f(st, ...x)
105
+ return r && typeof r == 'object' && st && r[k] !== st[k] ? {...r, [k]: calc(r[k])} : r
106
+ }
107
+ if (calcs) for (const a in model) {
108
+ const e = model[a]
109
+ if (typeof e == 'function') { if (!a.includes('|') || a.split('|')[1].trim() == S) model[a] = fresh(e) }
110
+ else if (e?.[S]) model[a] = {...e, [S]: fresh(e[S])}
111
+ }
112
+
113
+ for (const a in b.model) {
114
+ const e = sinksOf(b.model[a], S), m: any = {}, host = model[ns(a)]
115
+ for (const s in e) {
116
+ // HOST: a STATE reducer on the host's whole state (D197). G-378: with a STATE in the same
117
+ // entry, STATE runs first and HOST gets the state with its update (seq)
118
+ const whole = s == 'HOST', o = whole ? S : s
119
+ const f = (st: any, d: any, next: any, p: any) => {
120
+ const r = e[s](whole ? st : st?.[k], d, next && ((t: string, ...y: any[]) => next(t in b.model ? ns(t) : t, ...y)), p, opts, k)
121
+ return whole ? (isAbort(r) || r === st || !r || r[k] === st?.[k] ? r : {...r, [k]: calc(r[k])})
122
+ : s != S || isAbort(r) ? r : r === st[k] ? st : {...st, [k]: calc(r)}
123
+ }
124
+ m[o] = !m[o] ? f : whole ? seq(m[o], f) : seq(f, m[o])
125
+ }
126
+ if (host) {
127
+ const hs = sinksOf(host, S)
128
+ for (const s in hs) {
129
+ const bf = m[s], hf = hs[s]
130
+ m[s] = !bf ? hf
131
+ : s == S ? seq(bf, hf)
132
+ : s == 'EFFECT' ? (...x: any[]) => { bf(...x); hf(...x) }
133
+ : hf
134
+ }
135
+ }
136
+ model[ns(a)] = m
137
+ owned[ns(a)] = k
138
+ }
139
+
140
+ // one combined intent per instance: the behaviors' actions, then the host's own (which win)
141
+ if (!c._uses) {
142
+ const own = c.intent, list: any[] = c._uses = []
143
+ c.intent = (so: any) => {
144
+ const o: any = {}
145
+ for (const [k, b, slice] of list) {
146
+ const st = so[S], i = b.intent?.({...so, [S]: st?.select({get: (s: any) => s?.[k] ?? slice})}, b.options, k)
147
+ for (const a in i) o[k + '.' + a] = i[a], owned[k + '.' + a] = k
148
+ }
149
+ const h = own?.(so), test = h?.__sygnalTestActions || []
150
+ // renderComponent adds a stream for each static model action (simulateAction): merged in, not an override
151
+ for (const a in h) test.includes(a) && o[a] ? o[a] = xs.merge(o[a], h[a]) : (delete owned[a], o[a] = h[a])
152
+ return o
153
+ }
154
+ }
155
+ c._uses.push([k, b, slice])
156
+ }
157
+
158
+ /**
159
+ * defineBehavior({ initialState, intent?, model?, calculated?, timers? }) returns a factory; call
160
+ * it with the options for one use (`pager({ pageSize: 10, next: Newer })`) in a component's `uses`.
161
+ */
162
+ export const defineBehavior = (def: any) => (options: any = {}): any => {
163
+ const init = {...def.initialState}, b: any = {...def, options}
164
+ for (const o in options) if (o in init) init[o] = options[o]
165
+ // the slice a host starts with: initialState, the options naming its keys, its calculated fields
166
+ b.state = calcOf(def.calculated)(init)
167
+ b.merge = (c: any, k: string) => mergeBehavior(c, k, b)
168
+ return b
169
+ }
@@ -0,0 +1,23 @@
1
+ /*
2
+ * Browser signals (PLAN-3 §1.6, H-6): window focus / the page becoming visible, and the network
3
+ * coming back online. makeFetchDriver's refetchOnFocus / refetchOnReconnect and refetchEvery use
4
+ * them; PLAN-4's browser sources reuse them. Safe without a DOM (SSR, Node): nothing fires.
5
+ */
6
+
7
+ export type BrowserSignal = 'focus' | 'online';
8
+
9
+ /** true while the document is hidden (a background tab); false without a DOM */
10
+ export const isHidden = (): boolean => (globalThis as any).document?.visibilityState == 'hidden';
11
+
12
+ /**
13
+ * Calls `fn('focus')` when the window gains focus or the document becomes visible, and
14
+ * `fn('online')` when the browser goes online. Returns the unsubscribe function.
15
+ */
16
+ export const onBrowserSignals = (fn: (signal: BrowserSignal) => void): (() => void) => {
17
+ const w: any = (globalThis as any).window;
18
+ if (!w?.addEventListener) return () => {};
19
+ const focus = () => isHidden() || fn('focus'), online = () => fn('online');
20
+ const on: Array<[any, string, () => void]> = [[w, 'focus', focus], [w, 'online', online], [w.document, 'visibilitychange', focus]];
21
+ on.forEach(([t, e, f]) => t?.addEventListener(e, f));
22
+ return () => on.forEach(([t, e, f]) => t?.removeEventListener(e, f));
23
+ };
@@ -0,0 +1,326 @@
1
+ import {makeReplies} from './replies';
2
+ import {defHooks} from '../core/registry';
3
+
4
+ /*
5
+ * PLAN-5 B-3: browser sources, in the timers declaration shape (GS-7, S-8). A component declares
6
+ * what it watches as a function of its state; each entry's events come back as its own actions:
7
+ *
8
+ * Card.browser = (state) => ({
9
+ * seen: !state.seen && { intersection: '.cover', action: 'SEEN' },
10
+ * dark: { media: '(prefers-color-scheme: dark)', action: 'DARK' },
11
+ * })
12
+ * run(App, { BROWSER: makeBrowserDriver() })
13
+ *
14
+ * - Declaration: `C.browser = (state) => ({ [name]: spec | falsy })` (or an object of such
15
+ * functions), the spec's kind being the source key it has (the first of KINDS): `intersection` / `resize` (a selector in
16
+ * the component's own DOM, or `true` for its root element), `media` (a query), `storage` (a key;
17
+ * `area: 'session'`, `json: true`), `visibility: true`, `online: true`, `geolocation` (true or
18
+ * PositionOptions). `action` names the action; `error` (geolocation, storage) the failure one.
19
+ * - Diffed per (instance, name), comparing specs structurally, as timers: a new name starts, a
20
+ * removed or falsy one stops, a changed spec restarts. The core sends only `background: true`
21
+ * entries while the instance is on a hidden Switchable page (they restart when it's shown);
22
+ * dispose stops them, app dispose stops all; SSR runs no drivers.
23
+ * - Sources that have a current value (media, storage, visibility, online) send it when they
24
+ * start; intersection / resize send what their observer reports (each element once at first).
25
+ * - Commands, sent on the driver's sink from a model entry (the method: a key the driver knows):
26
+ * `{ copy: text, ok?, error? }` and `{ paste: true, ok, error? }` (the clipboard, data
27
+ * `{ text }`), `{ setItem: key, value, area?, json? }` / `{ removeItem: key, area? }` (storage;
28
+ * this page's `storage` declarations hear a change; an unchanged value is silent, G-384).
29
+ * - The core has no code for any of it (0 B): the driver's source is marked `__sygnalStatic:
30
+ * 'browser'` (statics.ts) and answers with reply actions (replies.ts). A component's DOM
31
+ * (intersection, resize) reaches the driver through a definition hook registered by the first
32
+ * driver made (renderComponent's fake too): it binds each declaring instance's DOM source at
33
+ * its creation (G-383: a definition cached before the hook existed is made again, define.ts).
34
+ * - Unused sources cost nothing with makeBrowserDriverWith(intersectionSource, ...);
35
+ * makeBrowserDriver() has them all.
36
+ * - Diagnostics (dev entry, through the `browserSource` hook): SYG663 an invalid spec or command,
37
+ * SYG664 a kind the driver wasn't made with, SYG665 a failure with no `error` action, SYG668
38
+ * an intersection / resize declaration with nothing to observe (no DOM source bound). A
39
+ * component declaring `browser` with no driver is SYG643, as timers.
40
+ */
41
+
42
+ const g: any = globalThis;
43
+ const noop = () => {};
44
+ const KINDS = ['intersection', 'resize', 'media', 'storage', 'visibility', 'online', 'geolocation'];
45
+ const diag = (...a: any[]) => g.__SYGNAL_DIAGNOSTICS__?.browserSource?.(...a);
46
+
47
+ /** What a declared source gets: the instance's DOM source, its action, its failure */
48
+ export interface BrowserCtx {
49
+ dom: any;
50
+ send: (data: any) => void;
51
+ fail: (data: any) => void;
52
+ /** G-383: a DOM-backed source that has nothing to observe reports it (SYG668; dev entry) */
53
+ miss: (why: string) => void;
54
+ /** G-390: the driver's shared observers, by kind and options */
55
+ obs: Map<string, any>;
56
+ }
57
+ /** A browser source: the declaration kinds (`d`) and sink commands (`c`) it adds to the driver */
58
+ export interface BrowserSource {
59
+ d?: Record<string, (spec: any, ctx: BrowserCtx) => (() => void) | void>;
60
+ c?: Record<string, (cmd: any, ok: (data: any) => void, fail: (data: any) => void) => void>;
61
+ }
62
+
63
+ // the driver names in use (the definition hook looks each up in a declaring instance's sources)
64
+ const names = new Set<string>();
65
+ let hooked: any;
66
+ const hook = () => hooked ||= defHooks.push((src: any, view: any) => view.browser == null ? undefined : {
67
+ ...src,
68
+ intent: (so: any) => {
69
+ for (const n of names) if (n in so) so[n]?.__b?.(so.DOM);
70
+ return src.intent ? src.intent(so) : {};
71
+ },
72
+ });
73
+
74
+ /** `{ ...el.dataset }` and its place among the target's elements */
75
+ const where = (els: any[], el: any) => ({index: els.indexOf(el), dataset: {...el.dataset}});
76
+
77
+ /**
78
+ * G-390: one observer per driver for each kind and options (`key`), shared by every declaration
79
+ * of them: it maps each element to the declarations' handlers. A declaration that starts on an
80
+ * element already observed gets its last report (a microtask later), as its own observer's first
81
+ * one; the observer is disconnected when nothing is left to observe.
82
+ */
83
+ const shared = (c: BrowserCtx, key: string, Obs: any, opts: any) => {
84
+ let r = c.obs.get(key);
85
+ if (!r) {
86
+ const h = new Map<any, Set<any>>(), last = new Map<any, any>();
87
+ const o = new Obs((es: any[]) => es.forEach(e => { last.set(e.target, e); h.get(e.target)?.forEach(f => f(e)); }), opts);
88
+ c.obs.set(key, r = {
89
+ add: (el: any, f: any) => {
90
+ let s = h.get(el);
91
+ if (!s) h.set(el, s = new Set()), o.observe(el);
92
+ else if (last.has(el)) Promise.resolve().then(() => s!.has(f) && f(last.get(el)));
93
+ s.add(f);
94
+ },
95
+ del: (el: any, f: any) => {
96
+ const s = h.get(el);
97
+ if (!s?.delete(f) || s.size) return;
98
+ h.delete(el); last.delete(el); o.unobserve(el);
99
+ if (!h.size) { o.disconnect(); c.obs.delete(key); }
100
+ },
101
+ });
102
+ }
103
+ return r;
104
+ };
105
+ // G-390: a DOM source's elements() stream per target, shared by its declarations (one query a patch)
106
+ const found = new WeakMap<any, Record<string, any>>();
107
+ const elementsOf = (dom: any, target: any) => {
108
+ let m = found.get(dom);
109
+ if (!m) found.set(dom, m = {});
110
+ const t = target === true ? '' : '' + target;
111
+ return m[t] ||= dom.select(t).elements();
112
+ };
113
+
114
+ /**
115
+ * Observe the elements `target` selects in the instance's DOM (`true`: its root element) with the
116
+ * driver's shared observer of `kind` (IntersectionObserver, ResizeObserver) and options: new ones
117
+ * are observed and gone ones let go after every patch. Nothing without a DOM source (SYG668) or
118
+ * the observer.
119
+ */
120
+ const track = (c: BrowserCtx, kind: string, target: any, Obs: any, opts: any, data: (e: any) => any) => {
121
+ if (!c.dom) return c.miss('dom');
122
+ if (!Obs) return;
123
+ let els: any[] = [];
124
+ const o = shared(c, kind + JSON.stringify(opts), Obs, opts), f = (e: any) => c.send({...data(e), ...where(els, e.target)});
125
+ const $ = elementsOf(c.dom, target);
126
+ const l = {next: (now: any[]) => {
127
+ for (const e of now) els.includes(e) || o.add(e, f);
128
+ for (const e of els) now.includes(e) || o.del(e, f);
129
+ els = [...now];
130
+ }};
131
+ $.addListener(l);
132
+ return () => { $.removeListener(l); els.forEach(e => o.del(e, f)); };
133
+ };
134
+
135
+ /** Element visibility: `{ intersection: '.cover' | true, action, threshold?, rootMargin? }`, data `{ visible, ratio, index, dataset }` */
136
+ export const intersectionSource: BrowserSource = {d: {
137
+ intersection: (s, c) => track(c, 'i', s.intersection, g.IntersectionObserver, {threshold: s.threshold, rootMargin: s.rootMargin},
138
+ (e) => ({visible: e.isIntersecting, ratio: e.intersectionRatio})),
139
+ }};
140
+
141
+ /** Element size: `{ resize: '.chart' | true, action }`, data `{ width, height, index, dataset }` (the content box) */
142
+ export const resizeSource: BrowserSource = {d: {
143
+ resize: (s, c) => track(c, 'r', s.resize, g.ResizeObserver, undefined,
144
+ (e) => ({width: e.contentRect.width, height: e.contentRect.height})),
145
+ }};
146
+
147
+ /** A media query: `{ media: '(prefers-color-scheme: dark)', action }`, data `{ matches, media }` */
148
+ export const mediaSource: BrowserSource = {d: {
149
+ media: (s, c) => {
150
+ const m = g.matchMedia?.(s.media);
151
+ if (!m) return;
152
+ const f = () => c.send({matches: m.matches, media: s.media});
153
+ f();
154
+ m.addEventListener('change', f);
155
+ return () => m.removeEventListener('change', f);
156
+ },
157
+ }};
158
+
159
+ const area = (s: any) => g[s.area == 'session' ? 'sessionStorage' : 'localStorage'];
160
+ const failed = (e: any) => ({name: e?.name, message: e?.message});
161
+
162
+ /**
163
+ * A storage key (read and observed, other tabs' writes included): `{ storage: 'theme', action,
164
+ * area?: 'session', json?: true, error? }`, data `{ key, value }` (null when absent; parsed with
165
+ * `json`). Commands `{ setItem: key, value, area?, json? }`, `{ removeItem: key, area? }`.
166
+ * For a component's state that should survive a reload, use persist() instead.
167
+ */
168
+ // this page's storage declarations (every driver's): a write here reaches them directly
169
+ const watching = new Set<(e: any) => void>();
170
+ export const storageSource: BrowserSource = {
171
+ d: {storage: (s, c) => {
172
+ const key = s.storage;
173
+ const f = (e?: any) => {
174
+ try {
175
+ const a = area(s);
176
+ if (e && (e.storageArea != a || e.key != null && e.key != key)) return;
177
+ let v = a.getItem(key);
178
+ if (s.json && v != null) v = JSON.parse(v);
179
+ c.send({key, value: v});
180
+ } catch (x) { c.fail(failed(x)); }
181
+ };
182
+ f();
183
+ watching.add(f);
184
+ g.addEventListener?.('storage', f);
185
+ return () => { watching.delete(f); g.removeEventListener?.('storage', f); };
186
+ }},
187
+ c: (() => {
188
+ const write = (v: any, value: any, ok: any, fail: any) => {
189
+ try {
190
+ const a = area(v), key = v.setItem ?? v.removeItem, old = a.getItem(key);
191
+ value == null ? a.removeItem(key) : a.setItem(key, value);
192
+ // G-384: this page's declarations hear a change (the browser fires `storage` in the other
193
+ // tabs only), and only a change: a model that writes back what it read settles. Not
194
+ // dispatched on window, so other `storage` listeners see other tabs' writes only.
195
+ if (old !== (value ?? null)) [...watching].forEach(f => f({key, storageArea: a}));
196
+ ok({key});
197
+ } catch (x) { fail(failed(x)); }
198
+ };
199
+ return {
200
+ setItem: (v, ok, fail) => write(v, v.json ? JSON.stringify(v.value) : '' + v.value, ok, fail),
201
+ removeItem: (v, ok, fail) => write(v, null, ok, fail),
202
+ };
203
+ })(),
204
+ };
205
+
206
+ /** The document's visibility: `{ visibility: true, action }`, data `{ visible }` */
207
+ export const visibilitySource: BrowserSource = {d: {
208
+ visibility: (_, c) => {
209
+ const d = g.document;
210
+ if (!d) return;
211
+ const f = () => c.send({visible: d.visibilityState != 'hidden'});
212
+ f();
213
+ d.addEventListener('visibilitychange', f);
214
+ return () => d.removeEventListener('visibilitychange', f);
215
+ },
216
+ }};
217
+
218
+ /** The network: `{ online: true, action }`, data `{ online }` */
219
+ export const onlineSource: BrowserSource = {d: {
220
+ online: (_, c) => {
221
+ if (!g.navigator || !g.addEventListener) return;
222
+ const f = () => c.send({online: g.navigator.onLine});
223
+ f();
224
+ g.addEventListener('online', f);
225
+ g.addEventListener('offline', f);
226
+ return () => { g.removeEventListener('online', f); g.removeEventListener('offline', f); };
227
+ },
228
+ }};
229
+
230
+ /**
231
+ * The position (permission-gated): `{ geolocation: true | PositionOptions, action, error? }`,
232
+ * data `{ latitude, longitude, accuracy, altitude, altitudeAccuracy, heading, speed, timestamp }`;
233
+ * a failure (denied, unavailable, timeout) `{ code, message }` to `error`.
234
+ */
235
+ export const geolocationSource: BrowserSource = {d: {
236
+ geolocation: (s, c) => {
237
+ const geo = g.navigator?.geolocation;
238
+ if (!geo) return c.fail({code: 2, message: 'Geolocation is not available'});
239
+ const id = geo.watchPosition((p: any) => {
240
+ const {latitude, longitude, accuracy, altitude, altitudeAccuracy, heading, speed} = p.coords;
241
+ c.send({latitude, longitude, accuracy, altitude, altitudeAccuracy, heading, speed, timestamp: p.timestamp});
242
+ }, (e: any) => c.fail({code: e.code, message: e.message}), s.geolocation === true ? undefined : s.geolocation);
243
+ return () => geo.clearWatch(id);
244
+ },
245
+ }};
246
+
247
+ /**
248
+ * The clipboard (permission-gated), as commands: `{ copy: text, ok?, error? }` and
249
+ * `{ paste: true, ok, error? }`, data `{ text }`; a failure `{ name, message }` to `error`.
250
+ */
251
+ export const clipboardSource: BrowserSource = {c: {
252
+ copy: (v, ok, fail) => {
253
+ const text = '' + v.copy, cb = g.navigator?.clipboard;
254
+ cb ? cb.writeText(text).then(() => ok({text}), (e: any) => fail(failed(e))) : fail({name: 'NotSupportedError', message: 'Clipboard is not available'});
255
+ },
256
+ paste: (_, ok, fail) => {
257
+ const cb = g.navigator?.clipboard;
258
+ cb ? cb.readText().then((text: string) => ok({text}), (e: any) => fail(failed(e))) : fail({name: 'NotSupportedError', message: 'Clipboard is not available'});
259
+ },
260
+ }};
261
+
262
+ /**
263
+ * The driver over `sources` and `runners` (sender → { c: component name, on: { [name]: entry } },
264
+ * an entry being { k: the spec's JSON, s: the spec, x: stop }). renderComponent's fake passes its
265
+ * own sources and map.
266
+ */
267
+ export const browserDriver = (sources: BrowserSource[], runners: Map<any, any>) => (sink$: any, name?: string) => {
268
+ const d: any = {}, cmd: any = {}, doms = new Map<any, any>(), obs = new Map<string, any>();
269
+ for (const s of sources) { Object.assign(d, s.d); Object.assign(cmd, s.c); }
270
+ const update = (id: any, decl: any, comp?: any) => {
271
+ let r = runners.get(id);
272
+ if (!r) runners.set(id, r = {c: comp, on: {}});
273
+ const on = r.on;
274
+ for (const n in on) if (on[n].k != JSON.stringify(decl?.[n])) on[n].x(), delete on[n];
275
+ for (const n in decl) {
276
+ const s = decl[n];
277
+ if (!s || on[n]) continue;
278
+ const e: any = on[n] = {k: JSON.stringify(s), s, x: noop};
279
+ const k = typeof s == 'object' && KINDS.find(k => k in s);
280
+ if (!k || !s.action || typeof s.action != 'string' || (k == 'intersection' || k == 'resize') && s[k] !== true && (typeof s[k] != 'string' || !s[k])) diag('SYG663', n, s, comp);
281
+ else if (!d[k]) diag('SYG664', n, s, comp, k);
282
+ else e.x = d[k](s, {
283
+ dom: doms.get(id),
284
+ send: (v: any) => reply(id, s.action, v),
285
+ fail: (v: any) => s.error ? reply(id, s.error, v) : diag('SYG665', n, s, comp, v),
286
+ miss: (why: string) => diag('SYG668', n, s, comp, why),
287
+ obs,
288
+ }) || noop;
289
+ }
290
+ if (!decl) runners.delete(id);
291
+ };
292
+ const stopAll = () => runners.forEach((_, id) => update(id, 0));
293
+ const {replies, reply} = makeReplies(id => { update(id, 0); doms.delete(id); });
294
+ hook();
295
+ if (name) names.add(name);
296
+ sink$.addListener({
297
+ next: (v: any) => {
298
+ if (!v || typeof v != 'object') return;
299
+ const id = v.__emitterId;
300
+ if ('browser' in v && id !== undefined) return update(id, v.browser, v.__emitterName);
301
+ // G-388: the method is any key the driver knows ({ ok, copy } too); G-389: a handler that
302
+ // throws (a value JSON can't encode, a clipboard without the method) fails like a rejection
303
+ const k = Object.keys(v), m = k.find(k => k in cmd) || k[0], f = cmd[m];
304
+ if (!f) return diag('SYG663', m, v, v.__emitterName, 0, Object.keys(cmd));
305
+ const fail = (x: any) => v.error ? reply(id, v.error, x) : diag('SYG665', m, v, v.__emitterName, x);
306
+ try { f(v, (x: any) => v.ok && reply(id, v.ok, x), fail); } catch (x) { fail(failed(x)); }
307
+ },
308
+ error: noop,
309
+ complete: stopAll,
310
+ });
311
+ // a declaring instance's own source (its DOM bound by the definition hook)
312
+ const src = (): any => {
313
+ const o: any = {...replies, __sygnalStatic: 'browser', replies: (id: any) => (o.i = id, replies.replies(id)), isolateSource: src, __b: (dom: any) => doms.set(o.i, dom)};
314
+ return o;
315
+ };
316
+ return {...src(), dispose: stopAll};
317
+ };
318
+
319
+ /**
320
+ * A driver for the components' `browser` declarations and the BROWSER sink commands, with only
321
+ * the given sources: `run(App, { BROWSER: makeBrowserDriverWith(intersectionSource, mediaSource) })`.
322
+ */
323
+ export const makeBrowserDriverWith = (...sources: BrowserSource[]) => browserDriver(sources, new Map());
324
+
325
+ /** Every browser source: `run(App, { BROWSER: makeBrowserDriver() })` */
326
+ export const makeBrowserDriver = () => makeBrowserDriverWith(intersectionSource, resizeSource, mediaSource, storageSource, visibilitySource, onlineSource, geolocationSource, clipboardSource);
@@ -14,11 +14,11 @@ export interface Command {
14
14
  send(type: string, data?: any): void;
15
15
  /** @internal — raw stream used by component wiring */
16
16
  _stream: Stream<CommandMessage>;
17
- /** @internal — marker for component.ts detection */
17
+ /** @internal — marker for the core's detection */
18
18
  __sygnalCommand: true;
19
- /** @internal — stamped by component.ts when wired to a child */
19
+ /** @internal — stamped by the core when wired to a child */
20
20
  _targetComponentId?: number;
21
- /** @internal — stamped by component.ts when wired to a child */
21
+ /** @internal — stamped by the core when wired to a child */
22
22
  _targetComponentName?: string;
23
23
  }
24
24
 
@@ -0,0 +1,47 @@
1
+ /**
2
+ * controls(spec) (PLAN-4 CT-1): element tokens that link a view to its intent by identifier.
3
+ *
4
+ * const { Draft, Add } = controls({ Draft: 'input', Add: 'button' })
5
+ * <Draft value={state.draft} /><Add>Add</Add>
6
+ * App.intent = ({ DOM }) => ({ DRAFT: DOM.input(Draft).value(), ADD: DOM.click(Add) })
7
+ *
8
+ * Each key becomes a control: a JSX tag that renders its spec's element with every prop passed
9
+ * through plus data-control="<Key>" (merged into data.attrs), and that stringifies to
10
+ * [data-control="<Key>"], so it is accepted wherever a selector string is (DOM.select and the
11
+ * DOM.<event> shorthands through MainDOMSource.select, simulateEvent, query, template strings).
12
+ *
13
+ * A control is not a component: the pragma recognises it by its `__sygnalControl` render hook
14
+ * (src/pragma/index.ts) and calls it with the props, the children and its own createElement.
15
+ * The JSX runtime entries use the core's pragma (D188), so the `h` passed in is the core
16
+ * createElement; the hook keeps it a parameter (spec.vnode's contract, D101/D116).
17
+ *
18
+ * A spec is an intrinsic tag name or a spec object { kind, vnode(props, children, h), commands? }
19
+ * (the frozen contract D101/D116, PLAN-5 widgets build on it). vnode() must return one element
20
+ * vnode; the stamp keeps its key, hooks and other data, and the props' key is copied onto it
21
+ * when it has none. `kind` ('element' for a tag) and `spec` stay on the control (inspect(),
22
+ * element commands).
23
+ *
24
+ * In dev, the 'sygnal/diagnostics' entry publishes `control(control, vnode)` on the core bridge:
25
+ * SYG125 (component statics on a control, or a vnode() that isn't one element vnode) and the
26
+ * controls listed by inspect(). Without it (production) the call is skipped.
27
+ */
28
+ export function controls(spec: Record<string, any>): Record<string, any> {
29
+ const out: Record<string, any> = {}
30
+ for (const key in spec) {
31
+ const s = spec[key]
32
+ const control: any = () => {}
33
+ control.__sygnalControl = (data: any, children: any[], h: any) => {
34
+ const v = typeof s == 'string' ? h(s, data, ...children) : s.vnode(data || {}, children, h)
35
+ ;(globalThis as any).__SYGNAL_DIAGNOSTICS__?.control?.(control, v)
36
+ const d = v.data ||= {}
37
+ d.attrs = {...d.attrs, 'data-control': key}
38
+ if (v.key === undefined && data) v.key = data.key
39
+ return v
40
+ }
41
+ control.toString = () => `[data-control="${key}"]`
42
+ control.kind = typeof s == 'string' ? 'element' : s.kind
43
+ control.spec = s
44
+ out[key] = control
45
+ }
46
+ return out
47
+ }