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
package/dist/ui.cjs.js ADDED
@@ -0,0 +1,738 @@
1
+ 'use strict';
2
+
3
+ var sygnal = require('sygnal');
4
+
5
+ /*
6
+ * PLAN-5 2-U: helpers the sygnal/ui parts share. Everything from the core comes through
7
+ * '../index', which the 'sygnal/ui' build turns into the external 'sygnal' (one core per app).
8
+ */
9
+ /** `v` as a quoted CSS string, for an attribute selector (`.tab[data-value="a b"]`) */
10
+ const lit = (v) => '"' + String(v).replace(/["\\]/g, '\\$&') + '"';
11
+ /**
12
+ * G-407: a part of an id: letters, digits and '-' as they are, anything else (whitespace, '_')
13
+ * as `_<code>_` (as the core's uidPart), so two values never make the same id ('a b' / 'a_b')
14
+ */
15
+ const part = (v) => String(v).replace(/[^A-Za-z0-9-]/g, (c) => '_' + c.charCodeAt(0) + '_');
16
+ /**
17
+ * The ids of one part's elements: `uid('<slice id>-<kind>-<value>')`. The slice id is the part's
18
+ * key in `uses` (keyed() below) unless an `id` option names it; uid() makes it unique per
19
+ * component instance. The slice id and the value are escaped (part()): no whitespace (aria-controls
20
+ * is a list of ids) and no collisions.
21
+ */
22
+ const idsOf = (s, uid, fallback) => (kind, v) => {
23
+ const n = `${part(s?.id ?? fallback)}-${kind}${v == null ? '' : '-' + part(v)}`;
24
+ return uid ? uid(n) : n;
25
+ };
26
+ /**
27
+ * an ELEMENT target whose `m` command runs `run(element, options)` (a D102 spec command). G-425:
28
+ * `__sel` is the selector renderComponent's `t.commands('ELEMENT')` logs in its place
29
+ */
30
+ const on = (sel, m, run) => ({ toString: () => '' + sel, __sel: sel, spec: { commands: { [m]: run } } });
31
+ /**
32
+ * G-400: SYNC's trigger for a dialog / popover behavior: `false` when its element left the page
33
+ * while the state says open (removed while open: no close / toggle event comes), and on the
34
+ * first look when the state says open but the element isn't (a host made again on a state that
35
+ * was open)
36
+ */
37
+ const gone = (DOM, STATE, sel, isOpen) => {
38
+ let first = true;
39
+ return DOM.select(sel).elements().compose(sygnal.sampleCombine(STATE.stream)).filter(([e, s]) => {
40
+ const f = first;
41
+ first = false;
42
+ return !!s?.open && (!e?.length || (f && !isOpen(e[0])));
43
+ }).mapTo(false);
44
+ };
45
+ /**
46
+ * Writes the `uses` key into the slice's `id` (the prefix of the ids the attribute helpers make)
47
+ * when no `id` option set it. Runs after the behavior's own merge, on the copy of the host's
48
+ * initialState (or the sub-component default) that merge made. G-407: `id` is also a calculated
49
+ * field, so a host reducer that replaces the slice without it gets it back (the ids stay).
50
+ */
51
+ const keyed = (b) => {
52
+ const merge = b.merge;
53
+ // G-423: renderToString gives a missing `id` the same key (extra/ssr.ts withUses)
54
+ b.keyed = 1;
55
+ b.merge = (c, k) => {
56
+ const id = b.options?.id ?? k;
57
+ b.calculated = { ...b.calculated, id: (s) => s.id ?? id };
58
+ merge(c, k);
59
+ for (const f of ['initialState', '_idle']) {
60
+ const o = c[f];
61
+ if (o && o[k] && o[k].id == null)
62
+ o[k] = { ...o[k], id: k };
63
+ }
64
+ };
65
+ return b;
66
+ };
67
+ const mod = (e) => e.altKey || e.ctrlKey || e.metaKey;
68
+ /**
69
+ * Roving focus (WAI-ARIA APG): a keydown on one of `sel`'s elements becomes the `data-value` of
70
+ * the element to move to: `next` / `prev` keys step through them in DOM order (wrapping unless
71
+ * loop is false), Home / End go to the first / last. Disabled elements are skipped. The keys it
72
+ * handles have their default prevented (no page scroll); every other key passes through.
73
+ * Reads the elements of the host's own DOM (DOM.select(sel).elements()), so it needs a real
74
+ * DOM: on renderComponent's mock DOM, simulate the action with a value instead.
75
+ */
76
+ const keyNav = (DOM, sel, next, prev, loop) => {
77
+ const keys = [...next, ...prev, 'Home', 'End'], s = DOM.select(sel);
78
+ const ours = (e) => !mod(e) && keys.includes(e.key);
79
+ return s.events('keydown', { preventDefault: ours })
80
+ .compose(sygnal.sampleCombine(s.elements()))
81
+ .map(([e, els]) => {
82
+ if (!ours(e))
83
+ return;
84
+ const list = [...(els || [])].filter((el) => !el.disabled), n = list.length, k = e.key;
85
+ const i = list.findIndex((el) => el.contains(e.target));
86
+ const j = k == 'Home' ? 0 : k == 'End' ? n - 1 : i + (next.includes(k) ? 1 : -1);
87
+ const to = loop === false ? list[j] : list[(j + n) % n];
88
+ return to?.getAttribute('data-value');
89
+ })
90
+ .filter((v) => v != null);
91
+ };
92
+
93
+ /*
94
+ * PLAN-5 2-U (S-3, from spike 0-S3): Dialog, a behavior over a native <dialog>.
95
+ *
96
+ * Settings.uses = { prefs: dialog({ dialog: '.prefs', trigger: '.open-prefs', close: '.close-prefs' }) }
97
+ *
98
+ * The host renders the <dialog> (aria-labelledby its heading) and its buttons. OPEN calls
99
+ * showModal() through ELEMENT: the browser traps the focus, makes the page inert, closes on
100
+ * Escape and returns the focus. `open` / `returnValue` follow the dialog's own close event,
101
+ * whichever way it closed (a close button, Escape, a form method="dialog", closedby="any"), and
102
+ * its toggle event when it opened without the model (commandfor="…" command="show-modal").
103
+ *
104
+ * Options: `dialog` (required; 3-W G-536: it must match only this dialog, not one nested in it,
105
+ * whose close / toggle / FAIL events it would take too), `trigger` and `close` (clicks dispatch OPEN / CLOSE), `modal`
106
+ * (true; false opens it with show()), `cancelable` (true; false keeps Escape from closing it:
107
+ * the cancel event is prevented, and OPEN sets closedby="none" (G-405: Chromium's CloseWatcher
108
+ * closes on a second Escape otherwise)), `returnFocus` (true: when the dialog closes and the
109
+ * focus was lost, which WebKit does after a mouse click, the element that opened it gets it
110
+ * (G-407: the clicked trigger, recorded by OPEN), else the trigger; a selector names another
111
+ * element; false: leave it to the browser. G-430: the opener is focused from the close event, so
112
+ * a dialog rendered only while open needs no command target).
113
+ * State: { open, returnValue }. Actions: OPEN, CLOSE (data: the returnValue), CLOSED (the close
114
+ * event's returnValue), TOGGLED (from the toggle event), CANCEL (Escape: a host entry can react;
115
+ * the cancel event, or with cancelable: false the Escape keydown in the dialog (G-429): closedby
116
+ * "none" stops the cancel event, and OPEN removes the attribute again when the dialog closes;
117
+ * G-457: not an Escape an element inside handled (defaultPrevented) or an IME one, and not for a
118
+ * non-modal dialog, which Escape doesn't cancel either way),
119
+ * SYNC (G-400: the dialog left the page while open: `open: false`; G-524: or OPEN's showModal()
120
+ * threw: no close event then).
121
+ * G-400: OPEN / CLOSE send commands that check the dialog itself (showModal only on a closed
122
+ * one, close only on an open one), so a state that is out of step can't block them.
123
+ */
124
+ // G-579: an open popover Escape closes before the dialog: an auto or hint one (the `popover`
125
+ // property: an engine without hint reads it as manual; the attribute where there is none). Not a
126
+ // manual one (a Toaster region moved into the modal, D198; a tooltip): Escape cancels the dialog
127
+ const first = (p) => { try {
128
+ return /^(auto|hint|)$/i.test(p.popover ?? p.getAttribute('popover')) && p.matches(':popover-open');
129
+ }
130
+ catch (_) {
131
+ return false;
132
+ } };
133
+ // G-429: Escape in this dialog (not in a dialog nested in it, nor with a popover open inside it
134
+ // that Escape closes first, G-579). G-457: not one an element inside handled (a Zag combobox or
135
+ // menu closing its list prevents it: the browser sends no cancel then either), nor one that ends
136
+ // an IME composition (Safari sends keyCode 229 with isComposing false)
137
+ const esc = (e) => e.key == 'Escape' && !e.defaultPrevented && !e.isComposing && e.keyCode != 229 &&
138
+ e.target?.closest?.('dialog') == e.ownerTarget && ![...(e.ownerTarget?.querySelectorAll?.('[popover]') ?? [])].some(first);
139
+ // the focus went nowhere: body, a detached element, or inside a dialog that just closed
140
+ const lost = () => {
141
+ const a = document.activeElement;
142
+ return !a || a == document.body || !a.isConnected || !!a.closest?.('dialog:not([open])');
143
+ };
144
+ // an ELEMENT target (D102 spec command): focus `sel` only when the focus was lost
145
+ const refocus = (sel) => on(sel, 'focus', (el, o) => { lost() && el.focus(o); });
146
+ // G-524: OPEN's showModal() threw (bubbles: the DOM driver listens at its root)
147
+ const FAIL = 'sygnaldialogfail';
148
+ const base$5 = /*#__PURE__*/ sygnal.defineBehavior({
149
+ initialState: { open: false, returnValue: '' },
150
+ intent: ({ DOM, STATE }, { dialog: d, trigger, close, cancelable, modal }) => ({
151
+ ...(trigger && { OPEN: DOM.click(trigger) }),
152
+ ...(close && { CLOSE: DOM.click(close).mapTo('') }),
153
+ TOGGLED: DOM.toggle(d).map((e) => e.newState == 'open'),
154
+ CLOSED: DOM.close(d).map((e) => e.target?.returnValue ?? ''),
155
+ // G-429: with cancelable: false the dialog has closedby="none", so Escape fires no cancel
156
+ // event: CANCEL is the Escape keydown (the cancel event, which a browser without closedby
157
+ // still fires, is only prevented). G-457: a non-modal one (show()) gets no cancel event from
158
+ // Escape with cancelable: true either, so no CANCEL: only its cancel event, prevented
159
+ CANCEL: cancelable !== false
160
+ ? DOM.select(d).events('cancel')
161
+ : modal === false
162
+ ? DOM.select(d).events('cancel', { preventDefault: true })
163
+ : sygnal.xs.merge(DOM.select(d).events('cancel', { preventDefault: true }).filter(() => false), DOM.select(d).events('keydown').filter(esc)),
164
+ // G-524: SYNC also when OPEN's showModal() threw (FAIL, below; true). 3-U G-533: only this
165
+ // behavior's dialog's own FAIL, not one bubbling from a dialog inside it (another behavior's)
166
+ SYNC: ((f) => STATE ? sygnal.xs.merge(gone(DOM, STATE, d, (e) => e.open), f) : f)(DOM.select(d).events(FAIL).filter((e) => e.target === e.ownerTarget).mapTo(true)),
167
+ }),
168
+ model: {
169
+ OPEN: {
170
+ STATE: (s) => (s.open ? sygnal.ABORT : { ...s, open: true, returnValue: '' }),
171
+ ELEMENT: (_s, d, _n, _p, o) => {
172
+ const m = o.modal === false ? 'show' : 'showModal', by = d?.ownerTarget;
173
+ return { [m]: on(o.dialog, m, (el) => {
174
+ if (el.open)
175
+ return;
176
+ // G-407: who opened it: the clicked trigger, else the element with the focus
177
+ const a = document.activeElement, op = by?.nodeType == 1 ? by : a != document.body ? a : null;
178
+ const cb = o.cancelable === false && !el.hasAttribute('closedby');
179
+ if (cb)
180
+ el.setAttribute('closedby', 'none');
181
+ // G-461: a showModal() that throws (a disconnected dialog, a popover open on it) leaves
182
+ // no closedby and arms no listener (a later close would focus this opener). G-488: and
183
+ // the state goes back to closed, so the next OPEN can open it; G-524: through SYNC (an
184
+ // internal FAIL event), not a close event: the host's close listeners don't run for a
185
+ // dialog that never opened, and no previous returnValue comes again. The error is the
186
+ // command's (thrown once)
187
+ try {
188
+ el[m]();
189
+ }
190
+ catch (e) {
191
+ cb && el.removeAttribute('closedby');
192
+ el.dispatchEvent(new Event(FAIL, { bubbles: true }));
193
+ throw e;
194
+ }
195
+ // on close: G-429 the closedby it set goes (it is the behavior's, not the host's); G-430
196
+ // the element that opened it gets the focus back when it was lost, here rather than by a
197
+ // command (a dialog the host renders only while open is gone by then), and nothing
198
+ // keeps the opener after that. Capture: at the target it runs before the DOM driver's
199
+ // listener, so before CLOSED (whose trigger fallback would take the focus first: a
200
+ // browser-sent event runs the microtasks between listeners)
201
+ el.addEventListener('close', () => {
202
+ cb && el.removeAttribute('closedby');
203
+ if ((o.returnFocus ?? true) === true && op?.isConnected && lost())
204
+ op.focus();
205
+ }, { once: true, capture: true });
206
+ }) };
207
+ },
208
+ },
209
+ CLOSE: { ELEMENT: (_s, rv, _n, _p, o) => ({ close: on(o.dialog, 'close', (el, x) => { el.open && el.close(x.returnValue); }), returnValue: typeof rv == 'string' ? rv : '' }) },
210
+ TOGGLED: (s, open) => (open && !s.open ? { ...s, open, returnValue: '' } : sygnal.ABORT),
211
+ CLOSED: {
212
+ STATE: (s, returnValue) => (!s.open && s.returnValue === returnValue ? sygnal.ABORT : { ...s, open: false, returnValue }),
213
+ ELEMENT: (s, _d, _n, _p, o) => {
214
+ const f = o.returnFocus ?? true, sel = f === true ? o.trigger : f;
215
+ if (!s.open || !sel)
216
+ return sygnal.ABORT;
217
+ // true: the element that opened it (OPEN's close listener, G-430), else the trigger; a
218
+ // selector: that element (each only when the focus was lost)
219
+ return { focus: refocus(sel) };
220
+ },
221
+ },
222
+ CANCEL: () => sygnal.ABORT,
223
+ // G-534: after a failed OPEN the returnValue is '' (also when OPEN's STATE aborted: the state
224
+ // was open while the element was closed)
225
+ SYNC: (s, failed) => (s.open ? { ...s, open: false, ...(failed === true && { returnValue: '' }) } : sygnal.ABORT),
226
+ },
227
+ });
228
+ /** A native <dialog> as a behavior: `uses = { help: dialog({ dialog: '.help', trigger: '.open-help', close: '.close-help' }) }`. */
229
+ const dialog = (options = {}) => base$5({ ...options, open: false, returnValue: '' });
230
+
231
+ /*
232
+ * PLAN-5 2-U (S-3, from spike 0-S3): Popover, a behavior over the Popover API.
233
+ *
234
+ * Filters.uses = { filters: popover({ popover: '.filters', close: '.filters-done' }) }
235
+ * <button popovertarget={uid('filters')}>Filters</button>
236
+ * <div className="filters" id={uid('filters')} popover="auto">…</div>
237
+ *
238
+ * The browser does the work: a `popovertarget` button opens and closes it, sets aria-expanded,
239
+ * light-dismisses it (a click outside, Escape) and returns the focus. The behavior mirrors
240
+ * `open` from the popover's toggle event and adds OPEN / CLOSE / TOGGLE for the model (ELEMENT
241
+ * showPopover / hidePopover / togglePopover). Open it from elsewhere with a host intent:
242
+ * `'filters.OPEN': DOM.click('.edit-filters')`. (No `trigger` option: a button that toggles an
243
+ * auto popover through the model reopens it, because the press outside light-dismisses it first;
244
+ * `popovertarget` buttons are exempt.)
245
+ *
246
+ * Options: `popover` (required), `close` (a button inside; its click dispatches CLOSE).
247
+ * State: { open }. Actions: OPEN, CLOSE, TOGGLE, TOGGLED (data: open, from the toggle event),
248
+ * SYNC (G-400: the popover left the page while open: `open: false`).
249
+ * G-400 / G-406: OPEN and CLOSE send commands that check the popover itself (`:popover-open`),
250
+ * not the state, which follows the asynchronous toggle event: OPEN then CLOSE in one tick ends
251
+ * closed, and a popover removed while open opens again.
252
+ */
253
+ const isOpen = (el) => { try {
254
+ return el.matches(':popover-open');
255
+ }
256
+ catch (_) {
257
+ return false;
258
+ } };
259
+ const base$4 = /*#__PURE__*/ sygnal.defineBehavior({
260
+ initialState: { open: false },
261
+ intent: ({ DOM, STATE }, { popover: p, close }) => ({
262
+ ...(close && { CLOSE: DOM.click(close) }),
263
+ TOGGLED: DOM.toggle(p).map((e) => e.newState == 'open'),
264
+ ...(STATE && { SYNC: gone(DOM, STATE, p, isOpen) }),
265
+ }),
266
+ model: {
267
+ OPEN: { ELEMENT: (_s, _d, _n, _p, o) => ({ showPopover: on(o.popover, 'showPopover', (el) => { isOpen(el) || el.showPopover(); }) }) },
268
+ CLOSE: { ELEMENT: (_s, _d, _n, _p, o) => ({ hidePopover: on(o.popover, 'hidePopover', (el) => { isOpen(el) && el.hidePopover(); }) }) },
269
+ TOGGLE: { ELEMENT: (_s, _d, _n, _p, o) => ({ togglePopover: o.popover }) },
270
+ TOGGLED: (s, open) => (s.open == open ? sygnal.ABORT : { ...s, open }),
271
+ SYNC: (s) => (s.open ? { ...s, open: false } : sygnal.ABORT),
272
+ },
273
+ });
274
+ /** A popover (Popover API) as a behavior: `uses = { filters: popover({ popover: '.filters' }) }`. */
275
+ const popover = (options = {}) => base$4({ ...options, open: false });
276
+
277
+ /*
278
+ * PLAN-5 2-U (S-3, from spike 0-S3): Tooltip, a manual popover placed by CSS anchor positioning,
279
+ * shown on hover / focus after a delay and hidden after a delay (D197 `timers`).
280
+ *
281
+ * Toolbar.uses = { saveTip: tooltip({ trigger: '.save', tip: '.save-tip' }) }
282
+ *
283
+ * The host renders the trigger with aria-describedby (the tip's id) and `anchor-name`, and the
284
+ * tip with role="tooltip", popover="manual", `position-anchor` and `position-area` (styles; see
285
+ * the guide). No JavaScript positioning.
286
+ *
287
+ * Options: `trigger`, `tip` (required), `showDelay` (500 ms), `hideDelay` (100 ms).
288
+ * State: { open, pending: null | 'show' | 'hide', hover, focus }. Actions: ENTER / LEAVE (data
289
+ * 'hover' | 'focus': the pointer on the trigger or the tip (it stays open while hovered, WCAG
290
+ * 1.4.13), or the focus on the trigger), SHOW / HIDE (the timers), ESCAPE (hides it at once),
291
+ * TOGGLED. Timers (joined to the host's `timers`): '<key>.show' / '<key>.hide'; one whose state
292
+ * goes away is cancelled, so leaving before the delay never shows the tip. Needs
293
+ * makeTimerDriver() (tests: fake timers).
294
+ * G-403: the pointer and the focus are tracked apart (it hides once both have left: a mouse
295
+ * leaving doesn't hide a tip the keyboard focus still shows); touch pointer events are ignored
296
+ * (a tap focuses the trigger instead); the document keydown listener for Escape is there only
297
+ * while the tip is shown or about to be, so a page of tooltips has at most the open one's.
298
+ */
299
+ const mouse = (e) => e?.pointerType != 'touch';
300
+ const which = (k) => (k == 'focus' ? 'focus' : 'hover');
301
+ const base$3 = /*#__PURE__*/ sygnal.defineBehavior({
302
+ initialState: { open: false, pending: null, hover: false, focus: false },
303
+ timers: (s, o) => ({
304
+ show: s?.pending == 'show' && { after: o.showDelay ?? 500, action: 'SHOW' },
305
+ hide: s?.pending == 'hide' && { after: o.hideDelay ?? 100, action: 'HIDE' },
306
+ }),
307
+ intent: ({ DOM, STATE }, { trigger, tip }) => ({
308
+ ENTER: sygnal.xs.merge(sygnal.xs.merge(DOM.pointerenter(trigger), DOM.pointerenter(tip)).filter(mouse).mapTo('hover'), DOM.focus(trigger).mapTo('focus')),
309
+ LEAVE: sygnal.xs.merge(sygnal.xs.merge(DOM.pointerleave(trigger), DOM.pointerleave(tip)).filter(mouse).mapTo('hover'), DOM.blur(trigger).mapTo('focus')),
310
+ ESCAPE: (STATE ? STATE.stream.map((s) => !!(s?.open || s?.pending)).compose(sygnal.dropRepeats()) : sygnal.xs.of(true))
311
+ .map((on) => (on ? DOM.keydown('document').key().filter((k) => k == 'Escape') : sygnal.xs.never()))
312
+ .flatten(),
313
+ TOGGLED: DOM.toggle(tip).map((e) => e.newState == 'open'),
314
+ }),
315
+ model: {
316
+ ENTER: (s, k) => {
317
+ const n = { ...s, [which(k)]: true }, pending = s.open ? null : 'show';
318
+ return s[which(k)] && s.pending == pending ? sygnal.ABORT : { ...n, pending };
319
+ },
320
+ LEAVE: (s, k) => {
321
+ const n = { ...s, [which(k)]: false };
322
+ // still hovered or focused: as it was
323
+ const pending = n.hover || n.focus ? s.pending : s.open ? 'hide' : null;
324
+ return !s[which(k)] && s.pending == pending ? sygnal.ABORT : { ...n, pending };
325
+ },
326
+ SHOW: {
327
+ STATE: (s) => ({ ...s, pending: null }),
328
+ ELEMENT: (s, _d, _n, _p, o) => (s.open ? sygnal.ABORT : { showPopover: o.tip }),
329
+ },
330
+ HIDE: {
331
+ STATE: (s) => ({ ...s, pending: null }),
332
+ ELEMENT: (s, _d, _n, _p, o) => (s.open ? { hidePopover: o.tip } : sygnal.ABORT),
333
+ },
334
+ ESCAPE: {
335
+ STATE: (s) => (s.open || s.pending ? { ...s, pending: null } : sygnal.ABORT),
336
+ ELEMENT: (s, _d, _n, _p, o) => (s.open ? { hidePopover: o.tip } : sygnal.ABORT),
337
+ },
338
+ TOGGLED: (s, open) => (s.open == open ? sygnal.ABORT : { ...s, open }),
339
+ },
340
+ });
341
+ /** A tooltip as a behavior: `uses = { tip: tooltip({ trigger: '.save', tip: '.save-tip', showDelay: 500 }) }`. */
342
+ const tooltip = (options = {}) => base$3({ ...options, open: false, pending: null, hover: false, focus: false });
343
+
344
+ /*
345
+ * PLAN-5 2-U (S-4): Tabs, a behavior that wires the host's own markup (WAI-ARIA APG tabs).
346
+ *
347
+ * Settings.uses = { tabs: tabs({ tab: '.tab', selected: 'general' }) }
348
+ * const a = tabsAttrs(state.tabs, uid)
349
+ * <div {...a.list} aria-label="Settings">
350
+ * <button className="tab" {...a.tab('general')}>General</button> …
351
+ * </div>
352
+ * <section {...a.panel('general')}>…</section> …
353
+ *
354
+ * The host renders the tabs and panels; `tabsAttrs` gives each its attributes from the slice:
355
+ * roles, ids (from `uid`, so every instance has its own), aria-selected / aria-controls /
356
+ * aria-labelledby, the roving tabindex, `hidden` on the other panels, and the hooks
357
+ * `data-value` / `data-state` ('active' | 'inactive'). A click on a tab selects it; the arrow
358
+ * keys move the focus between the tabs (and select, unless `activation: 'manual'`), Home / End
359
+ * go to the first / last; disabled tabs are skipped.
360
+ *
361
+ * Options: `tab` (required: the tabs' selector), `selected` (the start; none: the first tab
362
+ * rendered), `orientation` ('horizontal' | 'vertical': which arrow keys), `activation`
363
+ * ('automatic' | 'manual'), `loop` (true), `id` (the ids' prefix; default: the key in `uses`).
364
+ * State: { id, selected, orientation }. Actions: SELECT (a value, or a click), MOVE (a value:
365
+ * focus it, and select it unless manual).
366
+ * G-397: `tabsAttrs(slice, uid, values)` with the tabs' values shows the first one selected when
367
+ * `selected` isn't among them (a removed tab); a host that removes tabs re-selects a neighbour
368
+ * and moves the focus to it in its own reducer (the guide's closable tabs).
369
+ */
370
+ const base$2 = /*#__PURE__*/ sygnal.defineBehavior({
371
+ initialState: { id: null, selected: null, orientation: 'horizontal' },
372
+ intent: ({ DOM }, { tab, orientation, loop }) => {
373
+ const v = orientation == 'vertical';
374
+ return {
375
+ SELECT: DOM.click(tab).data('value'),
376
+ MOVE: keyNav(DOM, tab, [v ? 'ArrowDown' : 'ArrowRight'], [v ? 'ArrowUp' : 'ArrowLeft'], loop),
377
+ };
378
+ },
379
+ model: {
380
+ SELECT: (s, v) => (v == null || String(v) === s.selected ? sygnal.ABORT : { ...s, selected: String(v) }),
381
+ MOVE: {
382
+ STATE: (s, v, _n, _p, o) => (o.activation == 'manual' || v === s.selected ? sygnal.ABORT : { ...s, selected: v }),
383
+ ELEMENT: (_s, v, _n, _p, o) => ({ focus: o.tab + '[data-value=' + lit(v) + ']' }),
384
+ },
385
+ },
386
+ });
387
+ /** Tabs as a behavior over the host's markup: `uses = { tabs: tabs({ tab: '.tab', selected: 'general' }) }`; render with `tabsAttrs`. */
388
+ const tabs = (options = {}) => keyed(base$2({ ...options, ...(options.selected != null && { selected: String(options.selected) }) }));
389
+ /**
390
+ * The attributes of a tab set, from its slice: `list` (the tablist), `tab(value)` and
391
+ * `panel(value)`. Spread them on the host's elements: `<button className="tab" {...a.tab('general')}>`.
392
+ * `values` (optional): the tabs' values in order (leave disabled ones out). With it, a `selected`
393
+ * that isn't one of them (its tab was removed) shows the first one selected (G-397); without it,
394
+ * the first tab rendered is selected only while nothing is.
395
+ */
396
+ const tabsAttrs = (s, uid, values) => {
397
+ const id = idsOf(s, uid, 'tabs'), state = (b) => (b ? 'active' : 'inactive');
398
+ const vs = values && values.map(String);
399
+ let first = vs?.[0], sel = s?.selected == null ? null : String(s.selected);
400
+ if (vs && sel != null && !vs.includes(sel))
401
+ sel = null;
402
+ // no selection (or a removed one): the first value, or the first tab (or panel) rendered
403
+ const on = (v) => {
404
+ v = String(v);
405
+ if (sel != null)
406
+ return v === sel;
407
+ first ?? (first = v);
408
+ return v === first;
409
+ };
410
+ return {
411
+ list: { role: 'tablist', 'aria-orientation': s?.orientation || 'horizontal' },
412
+ tab: (v) => {
413
+ const b = on(v);
414
+ return { type: 'button', id: id('tab', v), role: 'tab', 'aria-selected': b, 'aria-controls': id('panel', v), tabindex: b ? '0' : '-1', 'data-value': String(v), 'data-state': state(b) };
415
+ },
416
+ panel: (v) => {
417
+ const b = on(v);
418
+ return { id: id('panel', v), role: 'tabpanel', 'aria-labelledby': id('tab', v), tabindex: '0', hidden: !b, 'data-state': state(b) };
419
+ },
420
+ };
421
+ };
422
+
423
+ /*
424
+ * PLAN-5 2-U (S-4): Accordion, a behavior that wires the host's own markup (WAI-ARIA APG
425
+ * accordion).
426
+ *
427
+ * Faq.uses = { faq: accordion({ trigger: '.faq-trigger' }) }
428
+ * const a = accordionAttrs(state.faq, uid)
429
+ * <h3><button className="faq-trigger" {...a.trigger('ship')}>Shipping</button></h3>
430
+ * <div {...a.panel('ship')}>…</div>
431
+ *
432
+ * `accordionAttrs` gives the triggers aria-expanded / aria-controls (and aria-disabled on the one
433
+ * open panel when it can't be collapsed), the panels role="region" / aria-labelledby / hidden,
434
+ * ids from `uid`, and the hooks `data-value` / `data-state` ('open' | 'closed'). A click on a
435
+ * trigger toggles its panel; Up / Down / Home / End move the focus between the triggers.
436
+ *
437
+ * Options: `trigger` (required), `multiple` (false: opening one closes the others),
438
+ * `collapsible` (true; false: the last open panel stays open), `expanded` (the start: a value or
439
+ * an array), `loop` (true), `id` (the ids' prefix; default: the key in `uses`).
440
+ * State: { id, expanded: string[], collapsible }. Actions: TOGGLE, EXPAND, COLLAPSE (a value, or
441
+ * a click), MOVE (a value: focus that trigger).
442
+ */
443
+ const expand = (s, v, o) => {
444
+ v = String(v);
445
+ return s.expanded.includes(v) ? sygnal.ABORT : { ...s, expanded: o.multiple ? [...s.expanded, v] : [v] };
446
+ };
447
+ const collapse = (s, v) => {
448
+ v = String(v);
449
+ return !s.expanded.includes(v) || (s.collapsible === false && s.expanded.length == 1) ? sygnal.ABORT
450
+ : { ...s, expanded: s.expanded.filter((x) => x !== v) };
451
+ };
452
+ const base$1 = /*#__PURE__*/ sygnal.defineBehavior({
453
+ initialState: { id: null, expanded: [], collapsible: true },
454
+ intent: ({ DOM }, { trigger, loop }) => ({
455
+ TOGGLE: DOM.click(trigger).data('value'),
456
+ MOVE: keyNav(DOM, trigger, ['ArrowDown'], ['ArrowUp'], loop),
457
+ }),
458
+ model: {
459
+ TOGGLE: (s, v, _n, _p, o) => (v == null ? sygnal.ABORT : s.expanded.includes(String(v)) ? collapse(s, v) : expand(s, v, o)),
460
+ EXPAND: (s, v, _n, _p, o) => (v == null ? sygnal.ABORT : expand(s, v, o)),
461
+ COLLAPSE: (s, v) => (v == null ? sygnal.ABORT : collapse(s, v)),
462
+ MOVE: { ELEMENT: (_s, v, _n, _p, o) => ({ focus: o.trigger + '[data-value=' + lit(v) + ']' }) },
463
+ },
464
+ });
465
+ /** An accordion as a behavior over the host's markup: `uses = { faq: accordion({ trigger: '.faq-trigger' }) }`; render with `accordionAttrs`. */
466
+ const accordion = (options = {}) => keyed(base$1({ ...options, ...(options.expanded != null && { expanded: [].concat(options.expanded).map(String) }) }));
467
+ /** The attributes of an accordion, from its slice: `trigger(value)` and `panel(value)`. */
468
+ const accordionAttrs = (s, uid) => {
469
+ const id = idsOf(s, uid, 'accordion'), ex = s?.expanded || [];
470
+ const on = (v) => ex.includes(String(v)), state = (v) => (on(v) ? 'open' : 'closed');
471
+ const only = s?.collapsible === false && ex.length == 1;
472
+ return {
473
+ trigger: (v) => ({
474
+ type: 'button', id: id('trigger', v), 'aria-expanded': on(v), 'aria-controls': id('panel', v),
475
+ 'aria-disabled': only && on(v) ? true : undefined, 'data-value': String(v), 'data-state': state(v),
476
+ }),
477
+ panel: (v) => ({ id: id('panel', v), role: 'region', 'aria-labelledby': id('trigger', v), hidden: !on(v), 'data-state': state(v) }),
478
+ };
479
+ };
480
+
481
+ /*
482
+ * PLAN-5 2-U (S-4): Disclosure, a button that shows and hides a panel (WAI-ARIA APG disclosure).
483
+ *
484
+ * Card.uses = { more: disclosure({ trigger: '.more-toggle' }) }
485
+ * const a = disclosureAttrs(state.more, uid)
486
+ * <button className="more-toggle" {...a.trigger}>Details</button>
487
+ * <div {...a.panel}>…</div>
488
+ *
489
+ * Options: `trigger` (required), `open` (the start, false), `id` (the ids' prefix; default: the
490
+ * key in `uses`). State: { id, open }. Actions: TOGGLE (a click), OPEN, CLOSE.
491
+ */
492
+ const base = /*#__PURE__*/ sygnal.defineBehavior({
493
+ initialState: { id: null, open: false },
494
+ intent: ({ DOM }, { trigger }) => ({ TOGGLE: DOM.click(trigger) }),
495
+ model: {
496
+ TOGGLE: (s) => ({ ...s, open: !s.open }),
497
+ OPEN: (s) => (s.open ? sygnal.ABORT : { ...s, open: true }),
498
+ CLOSE: (s) => (s.open ? { ...s, open: false } : sygnal.ABORT),
499
+ },
500
+ });
501
+ /** A disclosure as a behavior over the host's markup: `uses = { more: disclosure({ trigger: '.more-toggle' }) }`; render with `disclosureAttrs`. */
502
+ const disclosure = (options = {}) => keyed(base(options));
503
+ /** The attributes of a disclosure, from its slice: `trigger` and `panel`. */
504
+ const disclosureAttrs = (s, uid) => {
505
+ const id = idsOf(s, uid, 'disclosure'), open = !!s?.open, state = open ? 'open' : 'closed';
506
+ return {
507
+ trigger: { type: 'button', 'aria-expanded': open, 'aria-controls': id('panel'), 'data-state': state },
508
+ panel: { id: id('panel'), hidden: !open, 'data-state': state },
509
+ };
510
+ };
511
+
512
+ /*
513
+ * PLAN-5 2-U (T-1, D198, from spike 0-S4): the Toaster component.
514
+ *
515
+ * anywhere: SAVE: { EVENTS: event('TOAST', { text: 'Saved', kind: 'success' }) }
516
+ * once: <Toaster /> (main.js: run(App, { TIMER: makeTimerDriver() }))
517
+ *
518
+ * - TOAST adds { id, text, kind ('info' | 'success' | 'warning' | 'error'; default 'info'),
519
+ * timeoutMs (default 5000; 0 = until dismissed) }. A string is the text. A TOAST with the `id`
520
+ * of a shown toast replaces it in place and restarts its timer ('Saving…' → 'Saved').
521
+ * TOAST_DISMISS removes the toast with that id (no id: all of them). G-398: ids compare as
522
+ * strings (the Collection's keys); an automatic id is 't<n>', never one a shown toast has.
523
+ * - Each toast is a Collection item: its `timers` static auto-dismisses it (GS-7; fake-timer
524
+ * testable), its Dismiss button removes it, Transition animates it (`transition` names the
525
+ * classes, `duration` is how long a leaving toast stays: the leave animation's length).
526
+ * - Two persistent live regions: role="status" (polite) for every kind but errors, role="alert"
527
+ * for errors. They are rendered while empty, so a toast added later is announced.
528
+ * - While the pointer or the focus is in the region, the timers stop (and start over when both
529
+ * have left; G-399: `hover` and `focus` are tracked apart): `pauseOnHover={false}` turns this
530
+ * off. A focused Dismiss button moves the focus to the next toast's (else the previous one's,
531
+ * else where the focus came from) before its toast goes; a focused element removed any other
532
+ * way gets a focusout sent (Chromium sends none), so the region never stays paused.
533
+ * - The region is a `popover="manual"` element (top layer, above the page), re-parented into the
534
+ * topmost open modal <dialog> while one is open and back when it closes or is removed (a
535
+ * MutationObserver in the region's hooks, D198): outside the modal it would be drawn but inert
536
+ * (spike 0-S4). `__sygnalHome` keeps its events in this component (G-356). The region is the
537
+ * only child of a wrapper (`.toaster-home`), so the moved element has no siblings to patch.
538
+ * G-404: the dialogs of the region's own root (a shadow root) are looked at and observed too.
539
+ * G-426: the focus is that root's activeElement (in a shadow root the document's is the host).
540
+ *
541
+ * Class hooks: .toaster-home, .toaster (+ `className`), .toaster-status, .toaster-alert,
542
+ * .toaster-list, .toast, .toast-text, .toast-dismiss. Data attributes: data-kind on .toast,
543
+ * data-paused on .toaster.
544
+ */
545
+ // ── the region's placement (D198) ────────────────────────────────────
546
+ // the open modal dialogs, in the order they became modal (the last one is on top)
547
+ const order = [];
548
+ const modal = (d) => { try {
549
+ return d.matches(':modal');
550
+ }
551
+ catch (_) {
552
+ return false;
553
+ } };
554
+ // G-404: the dialogs of the document and of the region's own root (a shadow root: sygnal/element)
555
+ const topModal = (root) => {
556
+ const all = [...document.querySelectorAll('dialog')];
557
+ if (root !== document && root?.querySelectorAll)
558
+ all.push(...root.querySelectorAll('dialog'));
559
+ const open = all.filter(modal);
560
+ for (let i = order.length; i--;)
561
+ if (!open.includes(order[i]))
562
+ order.splice(i, 1);
563
+ for (const d of open)
564
+ if (!order.includes(d))
565
+ order.push(d);
566
+ return order[order.length - 1];
567
+ };
568
+ const show = (el) => { try {
569
+ el.matches(':popover-open') || el.showPopover();
570
+ }
571
+ catch (_) { } };
572
+ // the element with the focus in `el`'s root
573
+ const act = (el) => (el.getRootNode?.() || document).activeElement;
574
+ // G-428: a focusout that leaves `t`: not to an element inside it, and with no relatedTarget not
575
+ // while the focus is still inside (the window lost the focus: it comes back to the same element)
576
+ const left = (t, e) => !(t && t.contains?.(e.relatedTarget || act(t)));
577
+ // a toast on its way out (its Transition's leave classes)
578
+ const leaving = (b) => /-leave-/.test(b.closest?.('.toast')?.className || '');
579
+ const placement = {
580
+ insert: (v) => {
581
+ const el = v.elm, home = el.parentNode, root = el.getRootNode?.() || document;
582
+ el.__sygnalHome = home;
583
+ show(el);
584
+ // G-399: the focus in the region, and where it came from (where it goes back to). G-432: a
585
+ // focus from nowhere (the region's own refocus after a move, the browser's after a modal
586
+ // closed, the window focused again) keeps the last element it came from. G-458: but not one
587
+ // a press in the region gave: the user comes back from nowhere after a click on the page took
588
+ // the focus, and a mouse Dismiss would focus (and scroll to) an element left long ago. (A focus
589
+ // that comes back from another element names that one; a focus that left to a modal comes
590
+ // back from nowhere when it closes and keeps it: G-432)
591
+ // G-499: the press is its time, and counts for a focus within a second (a press released
592
+ // outside, a right-click or a touch scroll gets no focusin or click to clear it); a cancelled
593
+ // one (the browser took it for a scroll) at once
594
+ el.addEventListener('pointerdown', (e) => { el._p = e.timeStamp; });
595
+ el.addEventListener('pointercancel', () => { el._p = 0; });
596
+ el.addEventListener('focusin', (e) => {
597
+ if (!el.contains(e.relatedTarget)) {
598
+ el._f = 1;
599
+ el._from = e.relatedTarget || (el._p && e.timeStamp - el._p < 1e3 ? null : el._from);
600
+ }
601
+ el._p = 0;
602
+ });
603
+ el.addEventListener('focusout', (e) => { if (left(el, e))
604
+ el._f = 0; });
605
+ // a Dismiss button with the focus (keyboard; a click that focused it): the focus moves to the
606
+ // next toast's Dismiss button, else the previous one's, else back where it came from, before
607
+ // the button goes (a removed focused element gets no focusout in Chromium)
608
+ el.addEventListener('click', (e) => {
609
+ el._p = 0;
610
+ const b = e.target?.closest?.('.toast-dismiss');
611
+ // G-426: the root's activeElement (in a shadow root, the document's is the host)
612
+ if (!b || !b.contains(act(el)))
613
+ return;
614
+ const bs = [...el.querySelectorAll('.toast-dismiss')].filter((x) => x === b || !leaving(x)), i = bs.indexOf(b);
615
+ const to = bs[i + 1] || bs[i - 1] || (el._from?.isConnected && !el.contains(el._from) && el._from);
616
+ to ? to.focus() : b.blur();
617
+ });
618
+ if (typeof MutationObserver == 'undefined')
619
+ return;
620
+ const place = () => {
621
+ const to = topModal(root) || home;
622
+ if (el.parentNode !== to) {
623
+ // a move blurs a focused Dismiss button: give the focus back
624
+ const a = act(el), f = el.contains(a) && a;
625
+ to.appendChild(el);
626
+ f && f.focus();
627
+ }
628
+ // a moved popover is closed: show it again (on top of the dialog it is in)
629
+ show(el);
630
+ };
631
+ // `open` flips on showModal / close; a dialog removed while open takes the region with it
632
+ const mo = el._mo = new MutationObserver((rs) => {
633
+ // G-399: the focused element was removed (a toast dismissed some other way): no focusout
634
+ // in Chromium, so the region would stay paused; send one
635
+ if (el._f && !el.contains(act(el))) {
636
+ el._f = 0;
637
+ el.dispatchEvent(new FocusEvent('focusout', { bubbles: true }));
638
+ }
639
+ if (home.isConnected && (!el.isConnected || (el.parentNode !== home && !modal(el.parentNode)) || rs.some((r) => r.type == 'attributes')))
640
+ place();
641
+ });
642
+ const opts = { subtree: true, childList: true, attributes: true, attributeFilter: ['open'] };
643
+ mo.observe(document.body, opts);
644
+ // G-404: a region in a shadow root sees that root's dialogs open and close too
645
+ if (root !== document && root.nodeType == 11)
646
+ mo.observe(root, opts);
647
+ place();
648
+ },
649
+ // removed with its wrapper while in a dialog: take it out of the dialog too
650
+ destroy: (v) => {
651
+ const el = v.elm;
652
+ el._mo?.disconnect();
653
+ el.parentNode !== el.__sygnalHome && el.remove();
654
+ },
655
+ };
656
+ // ── one toast ──────────────────────────────────────────────────────
657
+ // (statics through a /*#__PURE__*/ Object.assign, so every bundler drops an unused Toaster; a
658
+ // componentName, so diagnostics and DevTools name them in minified builds too)
659
+ const ToastItem = /*#__PURE__*/ Object.assign(function ToastItem({ state, dismissLabel, transition, duration }) {
660
+ return sygnal.createElement(sygnal.Transition, { name: transition, duration }, sygnal.createElement('div', { className: 'toast', 'data-kind': state.kind }, sygnal.createElement('span', { className: 'toast-text' }, state.text), sygnal.createElement('button', { type: 'button', className: 'toast-dismiss', 'aria-label': dismissLabel + ': ' + state.text }, dismissLabel)));
661
+ }, {
662
+ componentName: 'ToastItem',
663
+ intent: ({ DOM }) => ({ DISMISS: DOM.click('.toast-dismiss') }),
664
+ // a replaced toast (rev) gets a new timer name, so its timer starts over
665
+ timers: (s) => ({ ['expire' + (s?.rev || '')]: s?.timeoutMs > 0 && !s.paused && { after: s.timeoutMs, action: 'EXPIRE' } }),
666
+ model: { DISMISS: () => undefined, EXPIRE: () => undefined },
667
+ });
668
+ // ── the toaster ──────────────────────────────────────────────────────
669
+ const polite = (t) => t.kind != 'error';
670
+ const urgent = (t) => t.kind == 'error';
671
+ // entering or leaving the region (not moving between its children)
672
+ const crossing = (e) => !e.ownerTarget?.contains?.(e.relatedTarget);
673
+ const paused = (s, p) => ({ ...s, paused: p, toasts: s.toasts.map((t) => ({ ...t, paused: p })) });
674
+ // the pointer or the focus came in or left: paused while either is in (unless pauseOnHover={false})
675
+ const pause = (s, k, on, p) => {
676
+ if (s[k] === on)
677
+ return sygnal.ABORT;
678
+ const n = { ...s, [k]: on }, z = p.pauseOnHover !== false && !!(n.hover || n.focus);
679
+ return z === s.paused ? n : paused(n, z);
680
+ };
681
+ // ids compare as strings (the Collection's keys do: 7 and '7' are one toast)
682
+ const same = (a, b) => '' + a === '' + b;
683
+ /** Renders the toasts that `event('TOAST', { text, kind, timeoutMs })` sends from anywhere. Render it once: `<Toaster />`. */
684
+ const Toaster = /*#__PURE__*/ Object.assign(function Toaster({ state, label = 'Notifications', dismissLabel = 'Dismiss', transition = 'toast', duration = 200, className }) {
685
+ const list = (filter) => sygnal.createElement('div', { className: 'toaster-list' }, sygnal.createElement(sygnal.Collection, { of: ToastItem, from: 'toasts', filter, dismissLabel, transition, duration }));
686
+ return sygnal.createElement('div', { className: 'toaster-home' }, sygnal.createElement('section', {
687
+ className: className ? 'toaster ' + className : 'toaster', 'aria-label': label, attrs: { popover: 'manual' },
688
+ 'data-paused': state.paused ? '' : undefined, hook: placement,
689
+ }, sygnal.createElement('div', { className: 'toaster-status', role: 'status', 'aria-live': 'polite' }, list(polite)), sygnal.createElement('div', { className: 'toaster-alert', role: 'alert' }, list(urgent))));
690
+ }, {
691
+ componentName: 'Toaster',
692
+ isolatedState: true,
693
+ initialState: { toasts: [], next: 1, paused: false, hover: false, focus: false },
694
+ intent: ({ EVENTS, DOM }) => ({
695
+ TOAST: EVENTS.select('TOAST'),
696
+ DISMISS: EVENTS.select('TOAST_DISMISS'),
697
+ // G-399: the pointer and the focus apart (the timers stop while either is in the region)
698
+ HOVER: sygnal.xs.merge(DOM.pointerover('.toaster').filter(crossing).mapTo(true), DOM.pointerout('.toaster').filter(crossing).mapTo(false)),
699
+ FOCUS: sygnal.xs.merge(DOM.focusin('.toaster').filter(crossing).mapTo(true), DOM.focusout('.toaster').filter((e) => left(e.ownerTarget, e)).mapTo(false)),
700
+ }),
701
+ model: {
702
+ TOAST: (s, d) => {
703
+ const t = typeof d == 'string' ? { text: d } : d || {};
704
+ // G-398: an automatic id is 't<n>', one no shown toast has (a user's 2 or '2' never meets it)
705
+ const i = t.id == null ? -1 : s.toasts.findIndex((x) => same(x.id, t.id));
706
+ let n = s.next, id = t.id;
707
+ if (id == null) {
708
+ while (s.toasts.some((x) => same(x.id, 't' + n)))
709
+ n++;
710
+ id = 't' + n++;
711
+ }
712
+ const toast = { ...t, id, kind: t.kind || 'info', timeoutMs: t.timeoutMs ?? 5000, paused: s.paused, rev: i < 0 ? 0 : s.toasts[i].rev + 1 };
713
+ return {
714
+ ...s,
715
+ next: n,
716
+ toasts: i < 0 ? [...s.toasts, toast] : s.toasts.map((x, j) => (j == i ? toast : x)),
717
+ };
718
+ },
719
+ DISMISS: (s, id) => {
720
+ const toasts = id == null ? [] : s.toasts.filter((x) => !same(x.id, id));
721
+ return toasts.length == s.toasts.length ? sygnal.ABORT : { ...s, toasts };
722
+ },
723
+ HOVER: (s, on, _n, p) => pause(s, 'hover', on, p),
724
+ FOCUS: (s, on, _n, p) => pause(s, 'focus', on, p),
725
+ },
726
+ });
727
+
728
+ exports.Toaster = Toaster;
729
+ exports.accordion = accordion;
730
+ exports.accordionAttrs = accordionAttrs;
731
+ exports.dialog = dialog;
732
+ exports.disclosure = disclosure;
733
+ exports.disclosureAttrs = disclosureAttrs;
734
+ exports.popover = popover;
735
+ exports.tabs = tabs;
736
+ exports.tabsAttrs = tabsAttrs;
737
+ exports.tooltip = tooltip;
738
+ //# sourceMappingURL=ui.cjs.js.map