@softov/scena 0.1.2

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 (496) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +42 -0
  3. package/dist/controls/command.d.ts +18 -0
  4. package/dist/controls/command.js +150 -0
  5. package/dist/controls/events.d.ts +3 -0
  6. package/dist/controls/events.js +43 -0
  7. package/dist/controls/index.d.ts +10 -0
  8. package/dist/controls/index.js +10 -0
  9. package/dist/controls/keybinding.d.ts +9 -0
  10. package/dist/controls/keybinding.js +94 -0
  11. package/dist/controls/layout.d.ts +16 -0
  12. package/dist/controls/layout.js +201 -0
  13. package/dist/controls/manifest.d.ts +21 -0
  14. package/dist/controls/manifest.js +219 -0
  15. package/dist/controls/session.d.ts +16 -0
  16. package/dist/controls/session.js +95 -0
  17. package/dist/controls/shell.d.ts +8 -0
  18. package/dist/controls/shell.js +48 -0
  19. package/dist/controls/storage/layout-local.d.ts +6 -0
  20. package/dist/controls/storage/layout-local.js +47 -0
  21. package/dist/controls/storage/session-local.d.ts +5 -0
  22. package/dist/controls/storage/session-local.js +38 -0
  23. package/dist/controls/when.d.ts +7 -0
  24. package/dist/controls/when.js +226 -0
  25. package/dist/converters/a2ui-v0.10.d.ts +23 -0
  26. package/dist/converters/a2ui-v0.10.js +136 -0
  27. package/dist/converters/index.d.ts +1 -0
  28. package/dist/converters/index.js +1 -0
  29. package/dist/core/backends/modus-backend.d.ts +13 -0
  30. package/dist/core/backends/modus-backend.js +115 -0
  31. package/dist/core/backends/storage-backend.d.ts +7 -0
  32. package/dist/core/backends/storage-backend.js +73 -0
  33. package/dist/core/backends/yjs-backend.d.ts +3 -0
  34. package/dist/core/backends/yjs-backend.js +44 -0
  35. package/dist/core/binding-resolver.d.ts +7 -0
  36. package/dist/core/binding-resolver.js +106 -0
  37. package/dist/core/component-graph.d.ts +6 -0
  38. package/dist/core/component-graph.js +77 -0
  39. package/dist/core/component-registry.d.ts +7 -0
  40. package/dist/core/component-registry.js +87 -0
  41. package/dist/core/computed-dsl.d.ts +2 -0
  42. package/dist/core/computed-dsl.js +267 -0
  43. package/dist/core/converter-registry.d.ts +2 -0
  44. package/dist/core/converter-registry.js +37 -0
  45. package/dist/core/disposable.d.ts +3 -0
  46. package/dist/core/disposable.js +19 -0
  47. package/dist/core/dynamic-resolver.d.ts +12 -0
  48. package/dist/core/dynamic-resolver.js +134 -0
  49. package/dist/core/index.d.ts +44 -0
  50. package/dist/core/index.js +48 -0
  51. package/dist/core/label.d.ts +2 -0
  52. package/dist/core/label.js +14 -0
  53. package/dist/core/mount-menu.d.ts +2 -0
  54. package/dist/core/mount-menu.js +23 -0
  55. package/dist/core/mount-surface.d.ts +15 -0
  56. package/dist/core/mount-surface.js +214 -0
  57. package/dist/core/path-resolver.d.ts +14 -0
  58. package/dist/core/path-resolver.js +169 -0
  59. package/dist/core/permissions.d.ts +2 -0
  60. package/dist/core/permissions.js +50 -0
  61. package/dist/core/reactive-store.d.ts +17 -0
  62. package/dist/core/reactive-store.js +496 -0
  63. package/dist/core/scena.d.ts +2 -0
  64. package/dist/core/scena.js +115 -0
  65. package/dist/core/surface-presentation.d.ts +6 -0
  66. package/dist/core/surface-presentation.js +12 -0
  67. package/dist/i18n/i18n-backend.d.ts +2 -0
  68. package/dist/i18n/i18n-backend.js +35 -0
  69. package/dist/i18n/registry.d.ts +32 -0
  70. package/dist/i18n/registry.js +200 -0
  71. package/dist/porta/Limen.css +50 -0
  72. package/dist/porta/Limen.d.ts +16 -0
  73. package/dist/porta/Limen.js +14 -0
  74. package/dist/porta/PortaContext.d.ts +10 -0
  75. package/dist/porta/PortaContext.js +20 -0
  76. package/dist/porta/PortaLock.css +14 -0
  77. package/dist/porta/PortaLock.d.ts +10 -0
  78. package/dist/porta/PortaLock.js +13 -0
  79. package/dist/porta/SigillumGate.d.ts +8 -0
  80. package/dist/porta/SigillumGate.js +7 -0
  81. package/dist/porta/commands.d.ts +3 -0
  82. package/dist/porta/commands.js +125 -0
  83. package/dist/porta/index.d.ts +18 -0
  84. package/dist/porta/index.js +22 -0
  85. package/dist/porta/login-form.block.d.ts +2 -0
  86. package/dist/porta/login-form.block.js +7 -0
  87. package/dist/porta/match.d.ts +2 -0
  88. package/dist/porta/match.js +20 -0
  89. package/dist/porta/provider.d.ts +59 -0
  90. package/dist/porta/provider.js +1 -0
  91. package/dist/porta/providers/examples/google-oauth.d.ts +6 -0
  92. package/dist/porta/providers/examples/google-oauth.js +21 -0
  93. package/dist/porta/providers/examples/index.d.ts +6 -0
  94. package/dist/porta/providers/examples/index.js +3 -0
  95. package/dist/porta/providers/examples/magic-link.d.ts +8 -0
  96. package/dist/porta/providers/examples/magic-link.js +31 -0
  97. package/dist/porta/providers/examples/sms-otp.d.ts +9 -0
  98. package/dist/porta/providers/examples/sms-otp.js +31 -0
  99. package/dist/porta/providers/password.d.ts +12 -0
  100. package/dist/porta/providers/password.js +46 -0
  101. package/dist/porta/register-blocks.d.ts +3 -0
  102. package/dist/porta/register-blocks.js +31 -0
  103. package/dist/porta/register.d.ts +15 -0
  104. package/dist/porta/register.js +31 -0
  105. package/dist/porta/sigillum.d.ts +19 -0
  106. package/dist/porta/sigillum.js +41 -0
  107. package/dist/react/DefaultShell.d.ts +1 -0
  108. package/dist/react/DefaultShell.js +37 -0
  109. package/dist/react/Scena.d.ts +9 -0
  110. package/dist/react/Scena.js +20 -0
  111. package/dist/react/ScenaProvider.d.ts +8 -0
  112. package/dist/react/ScenaProvider.js +13 -0
  113. package/dist/react/ShellSplitter.d.ts +13 -0
  114. package/dist/react/ShellSplitter.js +88 -0
  115. package/dist/react/SurfaceArea.d.ts +13 -0
  116. package/dist/react/SurfaceArea.js +75 -0
  117. package/dist/react/Translate.d.ts +8 -0
  118. package/dist/react/Translate.js +10 -0
  119. package/dist/react/ViewMount.d.ts +12 -0
  120. package/dist/react/ViewMount.js +268 -0
  121. package/dist/react/core.d.ts +6 -0
  122. package/dist/react/core.js +10 -0
  123. package/dist/react/hooks/useCommand.d.ts +1 -0
  124. package/dist/react/hooks/useCommand.js +6 -0
  125. package/dist/react/hooks/useI18n.d.ts +9 -0
  126. package/dist/react/hooks/useI18n.js +16 -0
  127. package/dist/react/hooks/useLabel.d.ts +2 -0
  128. package/dist/react/hooks/useLabel.js +19 -0
  129. package/dist/react/hooks/useLayout.d.ts +2 -0
  130. package/dist/react/hooks/useLayout.js +10 -0
  131. package/dist/react/hooks/useMounts.d.ts +2 -0
  132. package/dist/react/hooks/useMounts.js +17 -0
  133. package/dist/react/hooks/useStore.d.ts +3 -0
  134. package/dist/react/hooks/useStore.js +40 -0
  135. package/dist/react/hooks/useStoreLabel.d.ts +3 -0
  136. package/dist/react/hooks/useStoreLabel.js +25 -0
  137. package/dist/react/hooks/useSurfacePresentation.d.ts +4 -0
  138. package/dist/react/hooks/useSurfacePresentation.js +16 -0
  139. package/dist/react/index.d.ts +20 -0
  140. package/dist/react/index.js +20 -0
  141. package/dist/react/mount-context.d.ts +8 -0
  142. package/dist/react/mount-context.js +20 -0
  143. package/dist/react/useSurfaceResize.d.ts +39 -0
  144. package/dist/react/useSurfaceResize.js +135 -0
  145. package/dist/runtime/args-schema.d.ts +11 -0
  146. package/dist/runtime/args-schema.js +45 -0
  147. package/dist/runtime/builtins.d.ts +3 -0
  148. package/dist/runtime/builtins.js +193 -0
  149. package/dist/runtime/client-handlers.d.ts +3 -0
  150. package/dist/runtime/client-handlers.js +19 -0
  151. package/dist/runtime/in-memory-socket.d.ts +7 -0
  152. package/dist/runtime/in-memory-socket.js +53 -0
  153. package/dist/runtime/index.d.ts +10 -0
  154. package/dist/runtime/index.js +7 -0
  155. package/dist/runtime/layout-commands.d.ts +5 -0
  156. package/dist/runtime/layout-commands.js +548 -0
  157. package/dist/runtime/opener-commands.d.ts +17 -0
  158. package/dist/runtime/opener-commands.js +96 -0
  159. package/dist/runtime/surface-bridge.d.ts +15 -0
  160. package/dist/runtime/surface-bridge.js +116 -0
  161. package/dist/styles/bar.css +155 -0
  162. package/dist/styles/base.css +285 -0
  163. package/dist/styles/geometry.css +32 -0
  164. package/dist/styles/index.d.ts +29 -0
  165. package/dist/styles/index.js +109 -0
  166. package/dist/styles/scrollbar.css +45 -0
  167. package/dist/styles/surface.css +179 -0
  168. package/dist/styles/theme.css +3 -0
  169. package/dist/styles/themes/dark.css +30 -0
  170. package/dist/styles/themes/light.css +1 -0
  171. package/dist/styles/themes/tokens.css +222 -0
  172. package/dist/types/binding-resolver.d.ts +30 -0
  173. package/dist/types/binding-resolver.js +1 -0
  174. package/dist/types/colors.d.ts +7 -0
  175. package/dist/types/colors.js +59 -0
  176. package/dist/types/command.d.ts +62 -0
  177. package/dist/types/command.js +1 -0
  178. package/dist/types/component-graph.d.ts +72 -0
  179. package/dist/types/component-graph.js +40 -0
  180. package/dist/types/component-registry.d.ts +70 -0
  181. package/dist/types/component-registry.js +1 -0
  182. package/dist/types/converter-registry.d.ts +17 -0
  183. package/dist/types/converter-registry.js +1 -0
  184. package/dist/types/disposable.d.ts +3 -0
  185. package/dist/types/disposable.js +1 -0
  186. package/dist/types/events.d.ts +75 -0
  187. package/dist/types/events.js +1 -0
  188. package/dist/types/host.d.ts +50 -0
  189. package/dist/types/host.js +1 -0
  190. package/dist/types/index.d.ts +23 -0
  191. package/dist/types/index.js +23 -0
  192. package/dist/types/keybinding.d.ts +36 -0
  193. package/dist/types/keybinding.js +1 -0
  194. package/dist/types/label.d.ts +9 -0
  195. package/dist/types/label.js +1 -0
  196. package/dist/types/layout.d.ts +117 -0
  197. package/dist/types/layout.js +1 -0
  198. package/dist/types/manifest.d.ts +152 -0
  199. package/dist/types/manifest.js +1 -0
  200. package/dist/types/mount-menu.d.ts +8 -0
  201. package/dist/types/mount-menu.js +1 -0
  202. package/dist/types/mount-surface.d.ts +87 -0
  203. package/dist/types/mount-surface.js +1 -0
  204. package/dist/types/permissions.d.ts +18 -0
  205. package/dist/types/permissions.js +1 -0
  206. package/dist/types/query.d.ts +34 -0
  207. package/dist/types/query.js +7 -0
  208. package/dist/types/reactive-store.d.ts +39 -0
  209. package/dist/types/reactive-store.js +1 -0
  210. package/dist/types/scena.d.ts +53 -0
  211. package/dist/types/scena.js +1 -0
  212. package/dist/types/scope-backend.d.ts +16 -0
  213. package/dist/types/scope-backend.js +1 -0
  214. package/dist/types/session.d.ts +39 -0
  215. package/dist/types/session.js +1 -0
  216. package/dist/types/shell.d.ts +21 -0
  217. package/dist/types/shell.js +1 -0
  218. package/dist/types/when.d.ts +10 -0
  219. package/dist/types/when.js +1 -0
  220. package/dist/ui/_utils.d.ts +8 -0
  221. package/dist/ui/_utils.js +53 -0
  222. package/dist/ui/campus/CampusMappa.d.ts +18 -0
  223. package/dist/ui/campus/CampusMappa.js +106 -0
  224. package/dist/ui/campus/CampusNodus.d.ts +25 -0
  225. package/dist/ui/campus/CampusNodus.js +211 -0
  226. package/dist/ui/campus/CampusStratum.d.ts +13 -0
  227. package/dist/ui/campus/CampusStratum.js +20 -0
  228. package/dist/ui/campus/CampusVelum.d.ts +7 -0
  229. package/dist/ui/campus/CampusVelum.js +12 -0
  230. package/dist/ui/campus/CampusView.d.ts +27 -0
  231. package/dist/ui/campus/CampusView.js +420 -0
  232. package/dist/ui/campus/context.d.ts +13 -0
  233. package/dist/ui/campus/context.js +12 -0
  234. package/dist/ui/campus/index.d.ts +14 -0
  235. package/dist/ui/campus/index.js +11 -0
  236. package/dist/ui/campus/stratum-context.d.ts +2 -0
  237. package/dist/ui/campus/stratum-context.js +10 -0
  238. package/dist/ui/campus/types.d.ts +47 -0
  239. package/dist/ui/campus/types.js +4 -0
  240. package/dist/ui/chart/BarChart.css +53 -0
  241. package/dist/ui/chart/BarChart.d.ts +24 -0
  242. package/dist/ui/chart/BarChart.js +32 -0
  243. package/dist/ui/chart/Donut.css +15 -0
  244. package/dist/ui/chart/Donut.d.ts +15 -0
  245. package/dist/ui/chart/Donut.js +18 -0
  246. package/dist/ui/chart/LineChart.css +8 -0
  247. package/dist/ui/chart/LineChart.d.ts +24 -0
  248. package/dist/ui/chart/LineChart.js +29 -0
  249. package/dist/ui/chart/catalog.d.ts +2 -0
  250. package/dist/ui/chart/catalog.js +7 -0
  251. package/dist/ui/chart/index.d.ts +6 -0
  252. package/dist/ui/chart/index.js +4 -0
  253. package/dist/ui/control/Button.css +7 -0
  254. package/dist/ui/control/Button.d.ts +17 -0
  255. package/dist/ui/control/Button.js +17 -0
  256. package/dist/ui/control/CheckBox.css +16 -0
  257. package/dist/ui/control/CheckBox.d.ts +15 -0
  258. package/dist/ui/control/CheckBox.js +23 -0
  259. package/dist/ui/control/Checks.css +6 -0
  260. package/dist/ui/control/Checks.d.ts +9 -0
  261. package/dist/ui/control/Checks.js +10 -0
  262. package/dist/ui/control/ChoicePicker.css +16 -0
  263. package/dist/ui/control/ChoicePicker.d.ts +25 -0
  264. package/dist/ui/control/ChoicePicker.js +38 -0
  265. package/dist/ui/control/DateTimeInput.css +1 -0
  266. package/dist/ui/control/DateTimeInput.d.ts +22 -0
  267. package/dist/ui/control/DateTimeInput.js +41 -0
  268. package/dist/ui/control/LocaleToggle.css +38 -0
  269. package/dist/ui/control/LocaleToggle.d.ts +11 -0
  270. package/dist/ui/control/LocaleToggle.js +23 -0
  271. package/dist/ui/control/ReloadButton.d.ts +6 -0
  272. package/dist/ui/control/ReloadButton.js +9 -0
  273. package/dist/ui/control/Slider.css +2 -0
  274. package/dist/ui/control/Slider.d.ts +21 -0
  275. package/dist/ui/control/Slider.js +37 -0
  276. package/dist/ui/control/TextField.css +0 -0
  277. package/dist/ui/control/TextField.d.ts +25 -0
  278. package/dist/ui/control/TextField.js +36 -0
  279. package/dist/ui/control/_field-parts.css +102 -0
  280. package/dist/ui/control/_field-parts.d.ts +15 -0
  281. package/dist/ui/control/_field-parts.js +17 -0
  282. package/dist/ui/control/catalog.d.ts +2 -0
  283. package/dist/ui/control/catalog.js +10 -0
  284. package/dist/ui/control/index.d.ts +13 -0
  285. package/dist/ui/control/index.js +11 -0
  286. package/dist/ui/data/DataTable.d.ts +19 -0
  287. package/dist/ui/data/DataTable.js +20 -0
  288. package/dist/ui/data/Filter.d.ts +13 -0
  289. package/dist/ui/data/Filter.js +56 -0
  290. package/dist/ui/data/List.css +16 -0
  291. package/dist/ui/data/List.d.ts +15 -0
  292. package/dist/ui/data/List.js +18 -0
  293. package/dist/ui/data/Listable.css +245 -0
  294. package/dist/ui/data/Listable.d.ts +60 -0
  295. package/dist/ui/data/Listable.js +209 -0
  296. package/dist/ui/data/Pagination.d.ts +5 -0
  297. package/dist/ui/data/Pagination.js +43 -0
  298. package/dist/ui/data/Tree.css +118 -0
  299. package/dist/ui/data/Tree.d.ts +45 -0
  300. package/dist/ui/data/Tree.js +170 -0
  301. package/dist/ui/data/catalog.d.ts +2 -0
  302. package/dist/ui/data/catalog.js +7 -0
  303. package/dist/ui/data/index.d.ts +11 -0
  304. package/dist/ui/data/index.js +7 -0
  305. package/dist/ui/display/AddPlaceholder.d.ts +6 -0
  306. package/dist/ui/display/AddPlaceholder.js +24 -0
  307. package/dist/ui/display/Alert.css +42 -0
  308. package/dist/ui/display/Alert.d.ts +14 -0
  309. package/dist/ui/display/Alert.js +13 -0
  310. package/dist/ui/display/Avatar.css +19 -0
  311. package/dist/ui/display/Avatar.d.ts +16 -0
  312. package/dist/ui/display/Avatar.js +52 -0
  313. package/dist/ui/display/Badge.css +26 -0
  314. package/dist/ui/display/Badge.d.ts +16 -0
  315. package/dist/ui/display/Badge.js +9 -0
  316. package/dist/ui/display/Card.css +15 -0
  317. package/dist/ui/display/Card.d.ts +11 -0
  318. package/dist/ui/display/Card.js +8 -0
  319. package/dist/ui/display/DetailContainer.d.ts +6 -0
  320. package/dist/ui/display/DetailContainer.js +7 -0
  321. package/dist/ui/display/DetailHeader.css +53 -0
  322. package/dist/ui/display/DetailHeader.d.ts +22 -0
  323. package/dist/ui/display/DetailHeader.js +8 -0
  324. package/dist/ui/display/DetailList.css +26 -0
  325. package/dist/ui/display/DetailList.d.ts +13 -0
  326. package/dist/ui/display/DetailList.js +5 -0
  327. package/dist/ui/display/DetailNotFound.d.ts +17 -0
  328. package/dist/ui/display/DetailNotFound.js +39 -0
  329. package/dist/ui/display/Divider.css +6 -0
  330. package/dist/ui/display/Divider.d.ts +8 -0
  331. package/dist/ui/display/Divider.js +16 -0
  332. package/dist/ui/display/Divisor.css +30 -0
  333. package/dist/ui/display/Divisor.d.ts +11 -0
  334. package/dist/ui/display/Divisor.js +43 -0
  335. package/dist/ui/display/Icon.css +10 -0
  336. package/dist/ui/display/Icon.d.ts +14 -0
  337. package/dist/ui/display/Icon.js +144 -0
  338. package/dist/ui/display/Image.css +1 -0
  339. package/dist/ui/display/Image.d.ts +16 -0
  340. package/dist/ui/display/Image.js +19 -0
  341. package/dist/ui/display/Markdown.css +38 -0
  342. package/dist/ui/display/Markdown.d.ts +8 -0
  343. package/dist/ui/display/Markdown.js +140 -0
  344. package/dist/ui/display/Progress.css +39 -0
  345. package/dist/ui/display/Progress.d.ts +15 -0
  346. package/dist/ui/display/Progress.js +17 -0
  347. package/dist/ui/display/SectionTitle.d.ts +6 -0
  348. package/dist/ui/display/SectionTitle.js +6 -0
  349. package/dist/ui/display/Skeleton.css +20 -0
  350. package/dist/ui/display/Skeleton.d.ts +11 -0
  351. package/dist/ui/display/Skeleton.js +11 -0
  352. package/dist/ui/display/Spinner.css +20 -0
  353. package/dist/ui/display/Spinner.d.ts +12 -0
  354. package/dist/ui/display/Spinner.js +12 -0
  355. package/dist/ui/display/Svg.d.ts +13 -0
  356. package/dist/ui/display/Svg.js +17 -0
  357. package/dist/ui/display/Text.css +20 -0
  358. package/dist/ui/display/Text.d.ts +13 -0
  359. package/dist/ui/display/Text.js +15 -0
  360. package/dist/ui/display/catalog.d.ts +2 -0
  361. package/dist/ui/display/catalog.js +12 -0
  362. package/dist/ui/display/index.d.ts +22 -0
  363. package/dist/ui/display/index.js +14 -0
  364. package/dist/ui/embed/HtmlEmbed.d.ts +12 -0
  365. package/dist/ui/embed/HtmlEmbed.js +16 -0
  366. package/dist/ui/embed/index.d.ts +2 -0
  367. package/dist/ui/embed/index.js +1 -0
  368. package/dist/ui/forms/DangerZone.d.ts +8 -0
  369. package/dist/ui/forms/DangerZone.js +31 -0
  370. package/dist/ui/forms/Field.css +15 -0
  371. package/dist/ui/forms/Field.d.ts +28 -0
  372. package/dist/ui/forms/Field.js +25 -0
  373. package/dist/ui/forms/FieldGroup.css +15 -0
  374. package/dist/ui/forms/FieldGroup.d.ts +7 -0
  375. package/dist/ui/forms/FieldGroup.js +7 -0
  376. package/dist/ui/forms/Form.css +14 -0
  377. package/dist/ui/forms/Form.d.ts +18 -0
  378. package/dist/ui/forms/Form.js +17 -0
  379. package/dist/ui/forms/FormActions.css +11 -0
  380. package/dist/ui/forms/FormActions.d.ts +18 -0
  381. package/dist/ui/forms/FormActions.js +10 -0
  382. package/dist/ui/forms/FormSection.css +19 -0
  383. package/dist/ui/forms/FormSection.d.ts +7 -0
  384. package/dist/ui/forms/FormSection.js +7 -0
  385. package/dist/ui/forms/LoginForm.css +105 -0
  386. package/dist/ui/forms/LoginForm.d.ts +12 -0
  387. package/dist/ui/forms/LoginForm.js +137 -0
  388. package/dist/ui/forms/SchemaForm.css +81 -0
  389. package/dist/ui/forms/SchemaForm.d.ts +26 -0
  390. package/dist/ui/forms/SchemaForm.js +186 -0
  391. package/dist/ui/forms/SettingsContainer.d.ts +8 -0
  392. package/dist/ui/forms/SettingsContainer.js +8 -0
  393. package/dist/ui/forms/catalog.d.ts +2 -0
  394. package/dist/ui/forms/catalog.js +11 -0
  395. package/dist/ui/forms/index.d.ts +19 -0
  396. package/dist/ui/forms/index.js +12 -0
  397. package/dist/ui/forms/schema-walk.d.ts +50 -0
  398. package/dist/ui/forms/schema-walk.js +116 -0
  399. package/dist/ui/index.d.ts +58 -0
  400. package/dist/ui/index.js +63 -0
  401. package/dist/ui/layout/BarLayout.d.ts +2 -0
  402. package/dist/ui/layout/BarLayout.js +18 -0
  403. package/dist/ui/layout/Column.css +6 -0
  404. package/dist/ui/layout/Column.d.ts +12 -0
  405. package/dist/ui/layout/Column.js +13 -0
  406. package/dist/ui/layout/FloatingLayout.d.ts +2 -0
  407. package/dist/ui/layout/FloatingLayout.js +12 -0
  408. package/dist/ui/layout/Grid.css +5 -0
  409. package/dist/ui/layout/Grid.d.ts +13 -0
  410. package/dist/ui/layout/Grid.js +19 -0
  411. package/dist/ui/layout/InlineLayout.d.ts +2 -0
  412. package/dist/ui/layout/InlineLayout.js +13 -0
  413. package/dist/ui/layout/MountTitle.d.ts +12 -0
  414. package/dist/ui/layout/MountTitle.js +42 -0
  415. package/dist/ui/layout/RailLayout.d.ts +2 -0
  416. package/dist/ui/layout/RailLayout.js +38 -0
  417. package/dist/ui/layout/Row.css +16 -0
  418. package/dist/ui/layout/Row.d.ts +13 -0
  419. package/dist/ui/layout/Row.js +21 -0
  420. package/dist/ui/layout/SectionHeader.d.ts +10 -0
  421. package/dist/ui/layout/SectionHeader.js +65 -0
  422. package/dist/ui/layout/SingleLayout.d.ts +2 -0
  423. package/dist/ui/layout/SingleLayout.js +25 -0
  424. package/dist/ui/layout/SpatialCard.d.ts +9 -0
  425. package/dist/ui/layout/SpatialCard.js +30 -0
  426. package/dist/ui/layout/SpatialLayout.d.ts +2 -0
  427. package/dist/ui/layout/SpatialLayout.js +446 -0
  428. package/dist/ui/layout/SplitLayout.d.ts +2 -0
  429. package/dist/ui/layout/SplitLayout.js +159 -0
  430. package/dist/ui/layout/Splitter.d.ts +12 -0
  431. package/dist/ui/layout/Splitter.js +64 -0
  432. package/dist/ui/layout/StackHeader.d.ts +9 -0
  433. package/dist/ui/layout/StackHeader.js +87 -0
  434. package/dist/ui/layout/StackLayout.d.ts +2 -0
  435. package/dist/ui/layout/StackLayout.js +137 -0
  436. package/dist/ui/layout/TabLayout.d.ts +2 -0
  437. package/dist/ui/layout/TabLayout.js +145 -0
  438. package/dist/ui/layout/TabPanelLayout.d.ts +20 -0
  439. package/dist/ui/layout/TabPanelLayout.js +615 -0
  440. package/dist/ui/layout/catalog.d.ts +2 -0
  441. package/dist/ui/layout/catalog.js +10 -0
  442. package/dist/ui/layout/index.d.ts +17 -0
  443. package/dist/ui/layout/index.js +17 -0
  444. package/dist/ui/layout/register.d.ts +3 -0
  445. package/dist/ui/layout/register.js +25 -0
  446. package/dist/ui/media/Audio.css +1 -0
  447. package/dist/ui/media/Audio.d.ts +12 -0
  448. package/dist/ui/media/Audio.js +8 -0
  449. package/dist/ui/media/Video.css +1 -0
  450. package/dist/ui/media/Video.d.ts +16 -0
  451. package/dist/ui/media/Video.js +9 -0
  452. package/dist/ui/media/catalog.d.ts +2 -0
  453. package/dist/ui/media/catalog.js +5 -0
  454. package/dist/ui/media/index.d.ts +2 -0
  455. package/dist/ui/media/index.js +3 -0
  456. package/dist/ui/menu/ActionList.css +262 -0
  457. package/dist/ui/menu/ActionList.d.ts +19 -0
  458. package/dist/ui/menu/ActionList.js +369 -0
  459. package/dist/ui/menu/ContainerMenu.d.ts +13 -0
  460. package/dist/ui/menu/ContainerMenu.js +57 -0
  461. package/dist/ui/menu/ContextMenu.d.ts +27 -0
  462. package/dist/ui/menu/ContextMenu.js +93 -0
  463. package/dist/ui/menu/index.d.ts +10 -0
  464. package/dist/ui/menu/index.js +7 -0
  465. package/dist/ui/menu/token.d.ts +22 -0
  466. package/dist/ui/menu/token.js +145 -0
  467. package/dist/ui/menu/useChatPicker.d.ts +24 -0
  468. package/dist/ui/menu/useChatPicker.js +210 -0
  469. package/dist/ui/navigation/Breadcrumb.css +30 -0
  470. package/dist/ui/navigation/Breadcrumb.d.ts +14 -0
  471. package/dist/ui/navigation/Breadcrumb.js +12 -0
  472. package/dist/ui/navigation/Link.css +13 -0
  473. package/dist/ui/navigation/Link.d.ts +18 -0
  474. package/dist/ui/navigation/Link.js +43 -0
  475. package/dist/ui/navigation/Tabs.css +39 -0
  476. package/dist/ui/navigation/Tabs.d.ts +18 -0
  477. package/dist/ui/navigation/Tabs.js +55 -0
  478. package/dist/ui/navigation/Toolbar.css +25 -0
  479. package/dist/ui/navigation/Toolbar.d.ts +12 -0
  480. package/dist/ui/navigation/Toolbar.js +21 -0
  481. package/dist/ui/navigation/catalog.d.ts +2 -0
  482. package/dist/ui/navigation/catalog.js +5 -0
  483. package/dist/ui/navigation/index.d.ts +8 -0
  484. package/dist/ui/navigation/index.js +5 -0
  485. package/dist/ui/overlay/Modal.css +35 -0
  486. package/dist/ui/overlay/Modal.d.ts +12 -0
  487. package/dist/ui/overlay/Modal.js +57 -0
  488. package/dist/ui/overlay/Popup.d.ts +12 -0
  489. package/dist/ui/overlay/Popup.js +74 -0
  490. package/dist/ui/overlay/catalog.d.ts +2 -0
  491. package/dist/ui/overlay/catalog.js +4 -0
  492. package/dist/ui/overlay/index.d.ts +1 -0
  493. package/dist/ui/overlay/index.js +2 -0
  494. package/dist/ui/register.d.ts +6 -0
  495. package/dist/ui/register.js +26 -0
  496. package/package.json +115 -0
@@ -0,0 +1,145 @@
1
+ // Token parsing for chat-style inputs. A token is a contiguous non-whitespace
2
+ // run starting with one of the configured prefixes ('/' or '@' by default).
3
+ // The "active" token is the one straddling the caret, or none.
4
+ //
5
+ // Ported from web's chat slash token.ts and generalized to accept any prefix.
6
+ export function clampCaretIndex(input, caretIndex) {
7
+ if (typeof caretIndex !== 'number' || Number.isNaN(caretIndex))
8
+ return input.length;
9
+ return Math.max(0, Math.min(input.length, Math.floor(caretIndex)));
10
+ }
11
+ // Returns the active token straddling the caret, when its prefix matches one
12
+ // of `prefixes`. Returns null otherwise. Whitespace-bounded; identical caret
13
+ // rules to web (caret inside or immediately after the token both count).
14
+ export function getActiveToken(input, prefixes = ['/', '@'], caretIndex) {
15
+ if (!input)
16
+ return null;
17
+ const caret = clampCaretIndex(input, caretIndex);
18
+ let probe = -1;
19
+ if (caret < input.length && !/\s/.test(input[caret] ?? '')) {
20
+ probe = caret;
21
+ }
22
+ else if (caret > 0 && !/\s/.test(input[caret - 1] ?? '')) {
23
+ probe = caret - 1;
24
+ }
25
+ else {
26
+ return null;
27
+ }
28
+ let start = probe;
29
+ while (start > 0 && !/\s/.test(input[start - 1] ?? ''))
30
+ start -= 1;
31
+ let end = probe + 1;
32
+ while (end < input.length && !/\s/.test(input[end] ?? ''))
33
+ end += 1;
34
+ const token = input.slice(start, end);
35
+ const prefix = prefixes.find((p) => token.startsWith(p));
36
+ if (!prefix)
37
+ return null;
38
+ return {
39
+ token,
40
+ prefix,
41
+ query: token.slice(prefix.length),
42
+ start,
43
+ end,
44
+ };
45
+ }
46
+ // Rewrite the active token with `replacement` while preserving the rest of
47
+ // the input. `replacement` may be empty to delete the token. Trailing
48
+ // whitespace is collapsed.
49
+ export function replaceActiveToken(input, caretIndex, replacement, prefixes = ['/', '@']) {
50
+ const info = getActiveToken(input, prefixes, caretIndex);
51
+ if (!info)
52
+ return input;
53
+ const before = input.slice(0, info.start);
54
+ const after = input.slice(info.end);
55
+ return `${before}${replacement}${after}`.replace(/[ \t]+$/g, '');
56
+ }
57
+ // Replace the active token with `replacement` and report the caret position
58
+ // after it, so the host can sync caret state + focus. Unlike replaceActiveToken
59
+ // this preserves an intentional trailing space in `replacement` (only the
60
+ // empty-replacement / deletion case trims), and returns the caret so a mention
61
+ // insertion like '@/path ' lands the caret past the space — which dismisses the
62
+ // token and closes the picker. No active token → input unchanged, caret clamped.
63
+ // commitToken('msg @foo', 8, '@/a/b ') → { next: 'msg @/a/b ', caret: 10 }
64
+ // commitToken('say /model', 10, '') → { next: 'say', caret: 3 }
65
+ export function commitToken(input, caretIndex, replacement, prefixes = ['/', '@']) {
66
+ const info = getActiveToken(input, prefixes, caretIndex);
67
+ if (!info)
68
+ return { next: input, caret: clampCaretIndex(input, caretIndex) };
69
+ const before = input.slice(0, info.start);
70
+ const after = input.slice(info.end);
71
+ let next = `${before}${replacement}${after}`;
72
+ if (replacement === '')
73
+ next = next.replace(/[ \t]+$/g, '');
74
+ return { next, caret: Math.min(before.length + replacement.length, next.length) };
75
+ }
76
+ // Write a command's shortcut into the input for a composer-button open:
77
+ // replace the active token if the caret is on one, else append a new token
78
+ // (with a separating space when needed). Returns the new string and the caret
79
+ // position just after the inserted shortcut — the host syncs its caret to this
80
+ // so token detection lands on the freshly-written token.
81
+ // insertShortcut('', 0, '/mode') → { next: '/mode', caret: 5 }
82
+ // insertShortcut('/mod', 4, '/model') → { next: '/model', caret: 6 }
83
+ // insertShortcut('hi', 2, '/mode') → { next: 'hi /mode', caret: 8 }
84
+ export function insertShortcut(input, caretIndex, shortcut, prefixes = ['/', '@']) {
85
+ const info = getActiveToken(input, prefixes, caretIndex);
86
+ if (info) {
87
+ const next = `${input.slice(0, info.start)}${shortcut}${input.slice(info.end)}`;
88
+ return { next, caret: info.start + shortcut.length };
89
+ }
90
+ const sep = input.length > 0 && !/\s$/.test(input) ? ' ' : '';
91
+ const next = `${input}${sep}${shortcut}`;
92
+ return { next, caret: next.length };
93
+ }
94
+ // Match a typed token against a command's `shortcut`. shortcut may be a
95
+ // string ('/agent') or array (['/agent', '/persona']). Returns true if the
96
+ // typed token starts with any registered shortcut — keeps the menu open while
97
+ // the user types more after the sentinel.
98
+ export function shortcutMatchesToken(shortcut, token) {
99
+ if (!shortcut)
100
+ return false;
101
+ const shortcuts = Array.isArray(shortcut) ? shortcut : [shortcut];
102
+ const lower = token.toLowerCase();
103
+ return shortcuts.some((s) => lower.startsWith(s.toLowerCase()));
104
+ }
105
+ // Strip a submenu's sentinel (and a following '=' or whitespace) off the raw
106
+ // token query, leaving the inline-filter text. The sentinel is in shortcut
107
+ // form ('/model'); the raw query excludes the prefix ('model=gemi') so the
108
+ // prefix is dropped before matching. With an array, the first matching
109
+ // sentinel wins. Returns the raw query unchanged when no sentinel is given or
110
+ // none matches.
111
+ // stripSentinel('model=gemi', '/model') === 'gemi'
112
+ // stripSentinel('model', '/model') === ''
113
+ // stripSentinel('rout', '/model') === 'rout'
114
+ // stripSentinel('persona x', ['/agent','/persona']) === 'x'
115
+ export function stripSentinel(rawQuery, sentinel) {
116
+ if (!sentinel)
117
+ return rawQuery;
118
+ const sentinels = Array.isArray(sentinel) ? sentinel : [sentinel];
119
+ const lower = rawQuery.toLowerCase();
120
+ for (const s of sentinels) {
121
+ const bare = s.replace(/^[/@]/, '');
122
+ if (lower.startsWith(bare.toLowerCase())) {
123
+ return rawQuery.slice(bare.length).replace(/^[=\s]+/, '');
124
+ }
125
+ }
126
+ return rawQuery;
127
+ }
128
+ // True when the token still starts with any of the frame's sentinels — the
129
+ // picker keeps a pushed submenu open while this holds, and collapses to the
130
+ // root command list once it doesn't.
131
+ export function tokenMatchesSentinel(token, sentinel) {
132
+ if (!sentinel)
133
+ return true;
134
+ const sentinels = Array.isArray(sentinel) ? sentinel : [sentinel];
135
+ const lower = token.toLowerCase();
136
+ return sentinels.some((s) => lower.startsWith(s.toLowerCase()));
137
+ }
138
+ // Returns the canonical shortcut for a command — first entry when array,
139
+ // the string itself when single, undefined when unset. Used by composer
140
+ // buttons to rewrite the input to match the slash-typed form.
141
+ export function canonicalShortcut(shortcut) {
142
+ if (!shortcut)
143
+ return undefined;
144
+ return Array.isArray(shortcut) ? shortcut[0] : shortcut;
145
+ }
@@ -0,0 +1,24 @@
1
+ import { type Dispatch, type KeyboardEvent as ReactKeyboardEvent, type ReactNode, type SetStateAction } from 'react';
2
+ import type { PickerAction, HostCtx } from '../../types/host.js';
3
+ import type { BindingPath } from '../../types/component-graph.js';
4
+ export interface UseChatPickerParams {
5
+ input: string;
6
+ setInput: Dispatch<SetStateAction<string>>;
7
+ caretIndex?: number | null;
8
+ panelDataContext?: BindingPath;
9
+ slashSlot?: string;
10
+ mentionSlot?: string;
11
+ mentionProvider?: (host: HostCtx) => PickerAction[] | Promise<PickerAction[]>;
12
+ prefixes?: string[];
13
+ onCaretChange?: (caret: number) => void;
14
+ }
15
+ export interface UseChatPickerResult {
16
+ menuVisible: boolean;
17
+ activeSentinel: string | string[] | undefined;
18
+ pickerNode: ReactNode | null;
19
+ handleMenuKeyDown(e: ReactKeyboardEvent<HTMLTextAreaElement | HTMLInputElement>): boolean;
20
+ openCommand(commandId: string): number | null;
21
+ closeMenu(): void;
22
+ }
23
+ export declare function useChatPicker(params: UseChatPickerParams): UseChatPickerResult;
24
+ export declare function sentinelHas(sentinel: string | string[] | undefined, target: string): boolean;
@@ -0,0 +1,210 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
3
+ import { useScena } from '../../react/ScenaProvider.js';
4
+ import { canonicalShortcut, commitToken, getActiveToken, insertShortcut, stripSentinel, tokenMatchesSentinel, } from './token.js';
5
+ import { ActionList } from './ActionList.js';
6
+ // Per-instance host hook for chat-style inputs. Owns:
7
+ // - Token detection on each keystroke
8
+ // - Picker stack (push/replace/back/openInline)
9
+ // - HostCtx factory bound to this instance
10
+ // - Composer button → typing convergence via openCommand(id)
11
+ //
12
+ // Each chat panel owns one of these. Ten panels = ten hooks, no shared state.
13
+ // Reference-stable default so consumers that don't pass `prefixes` don't
14
+ // invalidate every memo that depends on it (tokenInfo → host → ActionList
15
+ // effect → setResolved → re-render). The destructure-default was a fresh
16
+ // array every call and caused "Maximum update depth exceeded".
17
+ const DEFAULT_PREFIXES = ['/', '@'];
18
+ export function useChatPicker(params) {
19
+ const { input, setInput, caretIndex, panelDataContext, slashSlot = 'chat:input/', mentionSlot = 'chat:input@', mentionProvider, prefixes = DEFAULT_PREFIXES, onCaretChange, } = params;
20
+ const scena = useScena();
21
+ // Picker stack — top is what renders. Reset by token changes.
22
+ const [stack, setStack] = useState([]);
23
+ const stackRef = useRef(stack);
24
+ stackRef.current = stack;
25
+ // Imperative handle on the visible ActionList. handleMenuKeyDown routes
26
+ // navigation keys through it so only the focused panel's picker reacts —
27
+ // ActionList's document-level listener is disabled here via manageKeys.
28
+ const actionListRef = useRef(null);
29
+ // Token detection on each render.
30
+ const tokenInfo = useMemo(() => getActiveToken(input, prefixes, caretIndex), [input, prefixes, caretIndex]);
31
+ const menuVisible = tokenInfo !== null;
32
+ // Root frame for the current token's prefix.
33
+ const rootSpecFor = useCallback((query) => tokenInfo?.prefix === '@'
34
+ ? mentionProvider
35
+ ? { provider: mentionProvider, footerHints: true, rich: true }
36
+ : { query: { slot: mentionSlot, q: query }, footerHints: true, rich: true }
37
+ : { query: { slot: slashSlot, q: query }, footerHints: true, rich: true }, [tokenInfo?.prefix, mentionProvider, mentionSlot, slashSlot]);
38
+ // When the active token changes, decide what the root frame should be.
39
+ // - '/' token → query slot (slashSlot)
40
+ // - '@' token → mentionProvider (if any), else mention slot
41
+ // - no token → empty stack
42
+ useEffect(() => {
43
+ if (!tokenInfo) {
44
+ if (stackRef.current.length > 0)
45
+ setStack([]);
46
+ return;
47
+ }
48
+ const top = stackRef.current[stackRef.current.length - 1];
49
+ const isRoot = stackRef.current.length <= 1;
50
+ if (isRoot) {
51
+ setStack([{ spec: rootSpecFor(tokenInfo.query) }]);
52
+ return;
53
+ }
54
+ // A submenu (pushed by a command) is open. If it declared a sentinel and
55
+ // the token no longer starts with it (user edited '/model' → '/rout'),
56
+ // collapse all the way back to the root command list.
57
+ const topSpec = top && 'spec' in top ? top.spec : undefined;
58
+ if (topSpec?.sentinel && !tokenMatchesSentinel(tokenInfo.token, topSpec.sentinel)) {
59
+ setStack([{ spec: rootSpecFor(tokenInfo.query) }]);
60
+ return;
61
+ }
62
+ if (topSpec?.query) {
63
+ // Re-resolve query-mode submenu against the new q.
64
+ setStack((cur) => {
65
+ const next = cur.slice(0, -1);
66
+ next.push({ spec: { ...topSpec, query: { ...topSpec.query, q: tokenInfo.query } } });
67
+ return next;
68
+ });
69
+ }
70
+ // provider/items frames: left as-is; their provider re-runs on its own
71
+ // when host.query (the post-sentinel filter text) changes.
72
+ }, [tokenInfo, rootSpecFor]);
73
+ // Sentinel of the visible submenu (if it declared one) and the post-sentinel
74
+ // filter text. For '/model=gemi' with sentinel '/model', filterQuery='gemi'
75
+ // — providers read host.query to filter inline.
76
+ const activeSentinel = useMemo(() => {
77
+ const t = stack[stack.length - 1];
78
+ return t && 'spec' in t ? t.spec.sentinel : undefined;
79
+ }, [stack]);
80
+ const filterQuery = useMemo(() => stripSentinel(tokenInfo?.query ?? '', activeSentinel), [tokenInfo, activeSentinel]);
81
+ // Host callbacks — bound to this hook's state. Re-created when setInput
82
+ // changes so insertAtCursor / replaceActiveToken always see the latest
83
+ // dispatcher.
84
+ const host = useMemo(() => ({
85
+ pushList: (s) => setStack((cur) => [...cur, { spec: s }]),
86
+ replaceList: (s) => setStack((cur) => {
87
+ const next = cur.slice(0, -1);
88
+ next.push({ spec: s });
89
+ return next;
90
+ }),
91
+ openInline: (componentId) => setStack((cur) => [
92
+ ...cur,
93
+ { component: _jsx(MissingInline, { name: componentId }) },
94
+ ]),
95
+ openPopover: () => undefined, // chat-style hosts don't open detached popovers from within
96
+ back: () => setStack((cur) => (cur.length > 1 ? cur.slice(0, -1) : cur)),
97
+ closeMenu: () => {
98
+ setStack([]);
99
+ const r = commitToken(input, caretIndex, '', prefixes);
100
+ setInput(r.next);
101
+ onCaretChange?.(r.caret);
102
+ },
103
+ keepOpen: () => undefined,
104
+ insertAtCursor: (text) => {
105
+ const r = commitToken(input, caretIndex, text, prefixes);
106
+ setInput(r.next);
107
+ onCaretChange?.(r.caret);
108
+ },
109
+ replaceActiveToken: (replacement) => {
110
+ const r = commitToken(input, caretIndex, replacement, prefixes);
111
+ setInput(r.next);
112
+ onCaretChange?.(r.caret);
113
+ },
114
+ query: filterQuery,
115
+ }), [input, caretIndex, prefixes, setInput, filterQuery, onCaretChange]);
116
+ const top = stack[stack.length - 1];
117
+ // Hoisted out of the conditional so `onBack` keeps a stable identity. Inline,
118
+ // it minted a new arrow every render and defeated the useCallback below that
119
+ // depends on it.
120
+ const popStack = useCallback(() => setStack((cur) => cur.slice(0, -1)), []);
121
+ const onBack = stack.length > 1 ? popStack : undefined;
122
+ // Keyboard hook the host wires to its textarea onKeyDown. Returns true when
123
+ // handled so the host knows whether to call its own default behavior.
124
+ // Navigation keys (ArrowDown/Up/Enter/Tab) are routed through the visible
125
+ // ActionList's imperative controller — this scopes them to THIS panel's
126
+ // picker even when another chat panel also has a picker open.
127
+ const handleMenuKeyDown = useCallback((e) => {
128
+ if (!menuVisible)
129
+ return false;
130
+ if (e.key === 'Escape') {
131
+ e.preventDefault();
132
+ host.closeMenu();
133
+ return true;
134
+ }
135
+ if (e.key === 'ArrowLeft' && onBack) {
136
+ const target = e.target;
137
+ if (target.selectionStart === target.selectionEnd) {
138
+ if (tokenInfo && target.selectionStart === tokenInfo.start + tokenInfo.prefix.length) {
139
+ e.preventDefault();
140
+ onBack();
141
+ return true;
142
+ }
143
+ }
144
+ }
145
+ if (e.key === 'ArrowDown' ||
146
+ e.key === 'ArrowUp' ||
147
+ e.key === 'Enter' ||
148
+ e.key === 'Tab') {
149
+ return actionListRef.current?.handleKey(e) ?? false;
150
+ }
151
+ return false;
152
+ }, [menuVisible, host, onBack, tokenInfo]);
153
+ // openCommand: composer buttons converge with typing. Rewrites the input
154
+ // to the command's canonical shortcut, then triggers picker via the token
155
+ // detection cycle.
156
+ // Opens a command's picker from a composer button. Writes the command's
157
+ // shortcut into the input (replacing the active token, or appending one when
158
+ // the input has none — the button click should work on an empty composer),
159
+ // seeds the root frame, runs the command, and returns the caret position
160
+ // just after the inserted token so the host can sync its caret state + focus
161
+ // the input (otherwise keyboard nav is dead and token detection misfires).
162
+ const openCommand = useCallback((commandId) => {
163
+ const cmd = scena.commands.get(commandId);
164
+ if (!cmd)
165
+ return null;
166
+ const sc = canonicalShortcut(cmd.shortcut);
167
+ let newCaret = null;
168
+ if (sc) {
169
+ const { next, caret } = insertShortcut(input, caretIndex, sc, prefixes);
170
+ newCaret = caret;
171
+ setInput(next);
172
+ // Seed the root command frame first so a submenu the command pushes lands
173
+ // at depth 2 — the token effect only replaces the root frame at depth ≤ 1
174
+ // and would otherwise clobber a freshly-pushed submenu.
175
+ setStack([{ spec: { query: { slot: slashSlot, q: sc.replace(/^[/@]/, '') }, footerHints: true, rich: true } }]);
176
+ }
177
+ // Immediate dispatch so the command's `run` opens its submenu through host
178
+ // (or toggles + closes for toggle commands).
179
+ void scena.commands.execute(commandId, undefined, {
180
+ source: 'menu',
181
+ dataContext: panelDataContext,
182
+ host,
183
+ });
184
+ return newCaret;
185
+ }, [scena, panelDataContext, input, caretIndex, prefixes, host, setInput, slashSlot]);
186
+ const closeMenu = useCallback(() => host.closeMenu(), [host]);
187
+ const pickerNode = top
188
+ ? 'component' in top
189
+ ? top.component
190
+ : (_jsx(ActionList, { ref: actionListRef, spec: top.spec, hostCtx: host, onBack: onBack, dataContext: panelDataContext, manageKeys: false }))
191
+ : null;
192
+ return {
193
+ menuVisible,
194
+ activeSentinel,
195
+ pickerNode,
196
+ handleMenuKeyDown,
197
+ openCommand,
198
+ closeMenu,
199
+ };
200
+ }
201
+ // True when `sentinel` (a frame's single/alias sentinel) contains `target`.
202
+ // Helper for hosts checking "is my submenu the one currently open?".
203
+ export function sentinelHas(sentinel, target) {
204
+ if (!sentinel)
205
+ return false;
206
+ return Array.isArray(sentinel) ? sentinel.includes(target) : sentinel === target;
207
+ }
208
+ function MissingInline({ name }) {
209
+ return _jsxs("div", { style: { padding: 12 }, children: ["[component: ", name, "]"] });
210
+ }
@@ -0,0 +1,30 @@
1
+ .oo-breadcrumb {
2
+ display: flex;
3
+ align-items: center;
4
+ gap: 4px;
5
+ font-size: var(--oo-font-size-sm);
6
+ color: var(--oo-color-fg);
7
+ }
8
+ .oo-breadcrumb__sep {
9
+ color: var(--oo-color-muted);
10
+ margin: 0 4px;
11
+ }
12
+ .oo-breadcrumb__link {
13
+ background: none;
14
+ border: none;
15
+ padding: 0;
16
+ font: inherit;
17
+ color: var(--oo-color-accent);
18
+ cursor: pointer;
19
+ text-decoration: none;
20
+ }
21
+ .oo-breadcrumb__link:hover {
22
+ text-decoration: underline;
23
+ }
24
+ .oo-breadcrumb__item {
25
+ color: var(--oo-color-muted);
26
+ }
27
+ .oo-breadcrumb__item[data-current='true'] {
28
+ color: var(--oo-color-fg);
29
+ font-weight: 500;
30
+ }
@@ -0,0 +1,14 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ import './Breadcrumb.css';
3
+ export interface BreadcrumbItem {
4
+ label: ReactNode;
5
+ href?: string;
6
+ onClick?: () => void;
7
+ }
8
+ export interface BreadcrumbProps {
9
+ items: BreadcrumbItem[];
10
+ separator?: ReactNode;
11
+ style?: CSSProperties;
12
+ className?: string;
13
+ }
14
+ export declare function Breadcrumb({ items, separator, style, className }: BreadcrumbProps): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Fragment } from 'react';
3
+ import './Breadcrumb.css';
4
+ // Trail of items separated by `/`. Last item renders as plain text (current
5
+ // location); earlier items render as links (href) or buttons (onClick) or
6
+ // muted plain text when neither is set.
7
+ export function Breadcrumb({ items, separator = '/', style, className }) {
8
+ return (_jsx("nav", { className: ['oo-breadcrumb', className].filter(Boolean).join(' '), "aria-label": "Breadcrumb", style: style, children: items.map((item, i) => {
9
+ const isLast = i === items.length - 1;
10
+ return (_jsxs(Fragment, { children: [i > 0 ? _jsx("span", { className: "oo-breadcrumb__sep", "aria-hidden": true, children: separator }) : null, item.href ? (_jsx("a", { className: "oo-breadcrumb__link", href: item.href, "aria-current": isLast ? 'page' : undefined, children: item.label })) : item.onClick && !isLast ? (_jsx("button", { type: "button", className: "oo-breadcrumb__link", onClick: item.onClick, children: item.label })) : (_jsx("span", { className: "oo-breadcrumb__item", "data-current": isLast ? 'true' : undefined, children: item.label }))] }, i));
11
+ }) }));
12
+ }
@@ -0,0 +1,13 @@
1
+ .oo-link {
2
+ color: var(--oo-color-accent);
3
+ text-decoration: none;
4
+ cursor: pointer;
5
+ }
6
+ .oo-link:hover {
7
+ text-decoration: underline;
8
+ }
9
+ .oo-link[data-disabled='true'] {
10
+ color: var(--oo-color-muted);
11
+ cursor: not-allowed;
12
+ text-decoration: none;
13
+ }
@@ -0,0 +1,18 @@
1
+ import type { CSSProperties, ReactNode } from 'react';
2
+ import './Link.css';
3
+ export type LinkKind = 'tel' | 'email' | 'web';
4
+ export declare function resolveLinkHref(raw: string): {
5
+ href: string;
6
+ kind: LinkKind;
7
+ };
8
+ export interface LinkProps {
9
+ href?: string;
10
+ label?: ReactNode;
11
+ children?: ReactNode;
12
+ external?: boolean;
13
+ disabled?: boolean;
14
+ onClick?: (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
15
+ weight?: number;
16
+ style?: CSSProperties;
17
+ }
18
+ export declare function Link({ href, label, children, external, disabled, onClick, weight, style }: LinkProps): import("react").JSX.Element;
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { weightStyle } from '../_utils.js';
3
+ import './Link.css';
4
+ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
5
+ // Phone-ish: optional leading +, then digits with spaces/dots/dashes/parens.
6
+ const TEL_RE = /^\+?\d[\d\s().-]*$/;
7
+ // Detect the target kind and normalize to a spec-compliant href:
8
+ // a phone number (or tel: / tel://) → tel:<number> (dials)
9
+ // an email address (or mailto:/email://) → mailto:<addr> (composes)
10
+ // any other already-schemed value → kept as-is
11
+ // everything else → https://<value>
12
+ export function resolveLinkHref(raw) {
13
+ const v = raw.trim();
14
+ // Accept the non-standard tel:// / email:// forms but emit the real scheme.
15
+ if (/^tel:\/\//i.test(v))
16
+ return { href: `tel:${v.slice(6)}`, kind: 'tel' };
17
+ if (/^email:\/\//i.test(v))
18
+ return { href: `mailto:${v.slice(8)}`, kind: 'email' };
19
+ if (/^mailto:/i.test(v))
20
+ return { href: v, kind: 'email' };
21
+ if (/^tel:/i.test(v))
22
+ return { href: v, kind: 'tel' };
23
+ // Already carries a real scheme (http://, https://, ftp://, …) — keep it.
24
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(v))
25
+ return { href: v, kind: 'web' };
26
+ if (EMAIL_RE.test(v))
27
+ return { href: `mailto:${v}`, kind: 'email' };
28
+ if (TEL_RE.test(v))
29
+ return { href: `tel:${v}`, kind: 'tel' };
30
+ return { href: `https://${v}`, kind: 'web' };
31
+ }
32
+ export function Link({ href, label, children, external, disabled, onClick, weight, style }) {
33
+ const resolved = href ? resolveLinkHref(href) : null;
34
+ const content = children ?? label ?? href ?? '';
35
+ const isExternal = external ?? resolved?.kind === 'web';
36
+ return (_jsx("a", { className: "oo-link", href: disabled ? undefined : resolved?.href, target: isExternal ? '_blank' : undefined, rel: isExternal ? 'noopener noreferrer' : undefined, "data-kind": resolved?.kind, "data-disabled": disabled || undefined, style: { ...weightStyle(weight), ...style }, onClick: (e) => {
37
+ if (disabled) {
38
+ e.preventDefault();
39
+ return;
40
+ }
41
+ onClick?.(e);
42
+ }, children: content }));
43
+ }
@@ -0,0 +1,39 @@
1
+ .oo-tabs {
2
+ display: flex;
3
+ flex-direction: column;
4
+ flex: 1;
5
+ min-height: 0;
6
+ }
7
+ .oo-tabs__strip {
8
+ display: flex;
9
+ gap: 2px;
10
+ border-bottom: 1px solid var(--oo-color-border);
11
+ }
12
+ .oo-tabs__tab {
13
+ padding: var(--oo-spacing-xs) var(--oo-spacing-md);
14
+ border: none;
15
+ border-bottom: 2px solid transparent;
16
+ background: transparent;
17
+ color: var(--oo-color-muted);
18
+ cursor: pointer;
19
+ font-size: var(--oo-font-size-sm);
20
+ transition: color 0.327s, border-color 0.327s;
21
+ }
22
+ .oo-tabs__tab:hover {
23
+ background: none;
24
+ color: inherit;
25
+ }
26
+ .oo-tabs__tab[aria-selected='true'] {
27
+ color: inherit;
28
+ border-bottom-color: var(--oo-color-accent);
29
+ }
30
+ .oo-tabs__tab[disabled] {
31
+ cursor: not-allowed;
32
+ opacity: 0.5;
33
+ }
34
+ .oo-tabs__panel {
35
+ flex: 1;
36
+ min-height: 0;
37
+ padding: var(--oo-spacing-sm);
38
+ overflow: auto;
39
+ }
@@ -0,0 +1,18 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ import './Tabs.css';
3
+ export interface TabsTab {
4
+ key?: string;
5
+ title?: string;
6
+ child?: ReactNode;
7
+ label?: string;
8
+ content?: ReactNode;
9
+ disabled?: boolean;
10
+ }
11
+ export interface TabsProps {
12
+ tabs?: TabsTab[];
13
+ weight?: number;
14
+ value?: string;
15
+ defaultValue?: string;
16
+ style?: CSSProperties;
17
+ }
18
+ export declare function Tabs({ tabs, value, defaultValue, weight, style }: TabsProps): import("react").JSX.Element;
@@ -0,0 +1,55 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { useWriteBack } from '../../react/mount-context.js';
4
+ import { weightStyle } from '../_utils.js';
5
+ import './Tabs.css';
6
+ function tabTitle(t) {
7
+ return t.title ?? t.label ?? '';
8
+ }
9
+ function tabChild(t) {
10
+ return t.child ?? t.content;
11
+ }
12
+ export function Tabs({ tabs = [], value, defaultValue, weight, style }) {
13
+ const writeValue = useWriteBack('value');
14
+ // Stable per-tab key: explicit `key`, else the index. Selection tracks this,
15
+ // NOT the (possibly translated) title — so a language switch keeps the tab.
16
+ const keys = tabs.map((t, i) => t.key ?? String(i));
17
+ const [internal, setInternal] = useState(value ?? defaultValue ?? keys[0]);
18
+ useEffect(() => {
19
+ if (value === undefined)
20
+ return;
21
+ setInternal((current) => (current === value ? current : value));
22
+ }, [value]);
23
+ function select(key) {
24
+ setInternal(key);
25
+ writeValue(key);
26
+ }
27
+ const activeIdx = [keys.indexOf(internal ?? ''), keys.indexOf(defaultValue ?? ''), 0].find((i) => i >= 0) ?? 0;
28
+ const active = tabs[activeIdx];
29
+ // Default `flex: 1` fills the surface; weightStyle wins when set.
30
+ const inlineStyle = {
31
+ // display: 'flex',
32
+ // flexDirection: 'column',
33
+ // minHeight: 0,
34
+ // flex: 1,
35
+ ...weightStyle(weight),
36
+ ...style,
37
+ };
38
+ return (_jsxs("div", { className: "oo-tabs", style: inlineStyle, children: [_jsx("div", { className: "oo-tabs__strip", role: "tablist", children: tabs.map((t, i) => {
39
+ const title = tabTitle(t);
40
+ return (_jsx("button", { className: "oo-tabs__tab", role: "tab", "aria-selected": t === active, disabled: t.disabled, onClick: () => select(keys[i]), style: {
41
+ // padding: 'var(--oo-spacing-xs) var(--oo-spacing-md)',
42
+ // fontSize: 'var(--oo-font-size-sm)',
43
+ // border: 'none',
44
+ // borderBottom:
45
+ // t === active
46
+ // ? '2px solid var(--oo-color-accent)'
47
+ // : '2px solid transparent',
48
+ // background: 'transparent',
49
+ // color: t === active ? 'inherit' : 'var(--oo-color-muted)',
50
+ // cursor: t.disabled ? 'not-allowed' : 'pointer',
51
+ // opacity: t.disabled ? 0.5 : 1,
52
+ // font: 'inherit',
53
+ }, children: title }, keys[i]));
54
+ }) }), _jsx("div", { role: "tabpanel", style: { flex: 1, minHeight: 0, overflow: 'auto' }, children: active ? tabChild(active) : null })] }));
55
+ }
@@ -0,0 +1,25 @@
1
+ /* Generic chrome strip: layout toolbars, panel headers, titlebar slots.
2
+ * Direction / alignment / gap come from data-attrs and inline props so the
3
+ * same class works for horizontal control rows AND vertical side rails. */
4
+ .oo-toolbar {
5
+ display: flex;
6
+ align-items: center;
7
+ gap: var(--oo-spacing-sm);
8
+ padding: var(--oo-spacing-xs) var(--oo-spacing-sm);
9
+ border-bottom: 1px solid var(--oo-color-border);
10
+ background: var(--oo-color-surface);
11
+ color: var(--oo-color-fg);
12
+ font-size: var(--oo-font-size-sm);
13
+ flex: 0 0 auto;
14
+ min-height: var(--oo-toolbar-height, 32px);
15
+ user-select: none;
16
+ }
17
+
18
+ .oo-toolbar[data-direction='column'] {
19
+ flex-direction: column;
20
+ align-items: stretch;
21
+ border-bottom: none;
22
+ border-right: 1px solid var(--oo-color-border);
23
+ min-height: 0;
24
+ min-width: var(--oo-toolbar-height, 32px);
25
+ }