@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,615 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState, } from 'react';
3
+ import { useScena } from '../../react/ScenaProvider.js';
4
+ import { ContextMenu } from '../menu/ContextMenu.js';
5
+ import { Divisor } from '../display/Divisor.js';
6
+ import { resolveColorRgb } from '../../types/colors.js';
7
+ import { NAMED_GLYPH } from '../display/Icon.js';
8
+ import { useStoreLabel } from '../../react/hooks/useStoreLabel.js';
9
+ // Multi-group tabs. Recursive binary tree: a leaf is one Tab strip; a split
10
+ // holds two children with a draggable divider. Drag a tab onto another
11
+ // leaf's 5 zones to either join (center) or split (top/right/bottom/left).
12
+ // Each leaf has a top-right [...] menu for group-level actions.
13
+ const DRAG_MIME = 'application/x-scena-tab-panel';
14
+ const EDGE_THRESHOLD = 0.2;
15
+ const MIN_RATIO = 0.05;
16
+ // ----- Tree helpers (pure) -----
17
+ function newLeafId() {
18
+ // Random suffix — the previous `g${counter}` scheme collided with persisted
19
+ // tree leaf ids after a reload (the counter resets, localStorage doesn't),
20
+ // producing two leaves with the same id. `replaceLeaf` then mutated both,
21
+ // and `mapLeaves(... ? null : l)` dropped both, collapsing whole splits.
22
+ return `g_${Math.random().toString(36).slice(2, 10)}`;
23
+ }
24
+ function makeLeaf(tabs, activeKey) {
25
+ return { kind: 'leaf', id: newLeafId(), tabs, activeKey };
26
+ }
27
+ function collectTabs(node, out) {
28
+ if (node.kind === 'leaf') {
29
+ for (const k of node.tabs)
30
+ out.add(k);
31
+ return;
32
+ }
33
+ collectTabs(node.first, out);
34
+ collectTabs(node.second, out);
35
+ }
36
+ function collectLeaves(node, out) {
37
+ if (node.kind === 'leaf') {
38
+ out.push(node);
39
+ return;
40
+ }
41
+ collectLeaves(node.first, out);
42
+ collectLeaves(node.second, out);
43
+ }
44
+ // Strip dead tabs from each leaf. Empty leaves are KEPT — a leaf only goes
45
+ // away through explicit user action (drag-last-tab-out via `removeTab`, or
46
+ // "Close group" via the leaf menu). That's what makes "Split group right"
47
+ // usable: the freshly-created sibling leaf is empty by design and must
48
+ // survive the next render so the user can drop a tab into it.
49
+ function pruneTree(node, alive) {
50
+ if (node.kind === 'leaf') {
51
+ const tabs = node.tabs.filter((k) => alive.has(k));
52
+ const activeKey = node.activeKey && alive.has(node.activeKey)
53
+ ? node.activeKey
54
+ : tabs[0];
55
+ return { ...node, tabs, activeKey };
56
+ }
57
+ return {
58
+ ...node,
59
+ first: pruneTree(node.first, alive),
60
+ second: pruneTree(node.second, alive),
61
+ };
62
+ }
63
+ // Map across leaves; if `fn` returns null, the leaf is dropped (parent
64
+ // collapses to surviving sibling). Returns null if every leaf dropped.
65
+ function mapLeaves(node, fn) {
66
+ if (node.kind === 'leaf')
67
+ return fn(node);
68
+ const first = mapLeaves(node.first, fn);
69
+ const second = mapLeaves(node.second, fn);
70
+ if (first && second)
71
+ return { ...node, first, second };
72
+ return first ?? second;
73
+ }
74
+ // Replace one leaf identified by id. Used by split-on-drop.
75
+ function replaceLeaf(node, leafId, replacement) {
76
+ if (node.kind === 'leaf')
77
+ return node.id === leafId ? replacement : node;
78
+ return {
79
+ ...node,
80
+ first: replaceLeaf(node.first, leafId, replacement),
81
+ second: replaceLeaf(node.second, leafId, replacement),
82
+ };
83
+ }
84
+ // Find a parent split that contains `leafId` directly, return path so we
85
+ // can rewrite ratio at the divider. (Not used for v1; ratio updates flow
86
+ // through replaceSplit below.)
87
+ function replaceSplit(node, match, patch) {
88
+ if (node.kind === 'leaf')
89
+ return node;
90
+ if (match(node))
91
+ return { ...node, ...patch };
92
+ return {
93
+ ...node,
94
+ first: replaceSplit(node.first, match, patch),
95
+ second: replaceSplit(node.second, match, patch),
96
+ };
97
+ }
98
+ // Reassigns ids for any leaf whose id was already seen in this walk. Heals
99
+ // trees persisted before the `newLeafId` collision fix landed — without this,
100
+ // `replaceLeaf` would mutate every leaf sharing the duplicate id at once.
101
+ function dedupeLeafIds(node, seen) {
102
+ if (node.kind === 'leaf') {
103
+ if (seen.has(node.id)) {
104
+ const fresh = newLeafId();
105
+ seen.add(fresh);
106
+ return { ...node, id: fresh };
107
+ }
108
+ seen.add(node.id);
109
+ return node;
110
+ }
111
+ return {
112
+ ...node,
113
+ first: dedupeLeafIds(node.first, seen),
114
+ second: dedupeLeafIds(node.second, seen),
115
+ };
116
+ }
117
+ function reconcile(raw, mountKeys, focusedKey) {
118
+ const alive = new Set(mountKeys);
119
+ let tree = raw
120
+ ? dedupeLeafIds(pruneTree(raw, alive), new Set())
121
+ : makeLeaf([...mountKeys], focusedKey);
122
+ // Append orphans (mounts not in tree yet). Prefer the leaf holding the
123
+ // focused key; otherwise the first non-empty leaf; otherwise the first
124
+ // leaf. Intentional empty groups (split-right / split-down) are NOT
125
+ // auto-filled — they wait for an explicit drop.
126
+ const present = new Set();
127
+ collectTabs(tree, present);
128
+ const orphans = mountKeys.filter((k) => !present.has(k));
129
+ if (orphans.length > 0) {
130
+ const leaves = [];
131
+ collectLeaves(tree, leaves);
132
+ const target = (focusedKey && leaves.find((l) => l.tabs.includes(focusedKey))) ||
133
+ leaves.find((l) => l.tabs.length > 0) ||
134
+ leaves[0];
135
+ if (target) {
136
+ // Pick the active tab for the target leaf. Prefer focusedKey when it's
137
+ // one of the orphans we just appended; otherwise the last orphan wins
138
+ // (most recently opened). Without this, the leaf would keep showing
139
+ // whatever was active before — the user clicks "open" and nothing
140
+ // visibly changes.
141
+ const newActive = focusedKey && orphans.includes(focusedKey)
142
+ ? focusedKey
143
+ : orphans[orphans.length - 1];
144
+ tree = replaceLeaf(tree, target.id, {
145
+ ...target,
146
+ tabs: [...target.tabs, ...orphans],
147
+ activeKey: newActive,
148
+ });
149
+ }
150
+ }
151
+ // Re-open case: tab already exists in some leaf but focusedKey just
152
+ // changed (surfaces.open → focus emits scena:mount:focused →
153
+ // activeContainerKey updates). Sync the containing leaf's activeKey so the
154
+ // tab actually becomes active in its leaf.
155
+ if (focusedKey) {
156
+ const next = mapLeaves(tree, (l) => {
157
+ if (l.tabs.includes(focusedKey) && l.activeKey !== focusedKey) {
158
+ return { ...l, activeKey: focusedKey };
159
+ }
160
+ return l;
161
+ });
162
+ if (next)
163
+ tree = next;
164
+ }
165
+ return { tree };
166
+ }
167
+ // Structural (key-order-independent) equality for two trees. Used to decide
168
+ // whether the reconciled tree needs to be written back to state — a JSON
169
+ // compare would risk a false-negative on key order and loop the commit effect.
170
+ function treesEqual(a, b) {
171
+ if (a === b)
172
+ return true;
173
+ if (!a || !b || a.kind !== b.kind)
174
+ return false;
175
+ if (a.kind === 'leaf' && b.kind === 'leaf') {
176
+ return (a.id === b.id &&
177
+ a.activeKey === b.activeKey &&
178
+ a.tabs.length === b.tabs.length &&
179
+ a.tabs.every((t, i) => t === b.tabs[i]));
180
+ }
181
+ if (a.kind === 'split' && b.kind === 'split') {
182
+ return (a.direction === b.direction &&
183
+ (a.ratio ?? 0.5) === (b.ratio ?? 0.5) &&
184
+ treesEqual(a.first, b.first) &&
185
+ treesEqual(a.second, b.second));
186
+ }
187
+ return false;
188
+ }
189
+ // Renders one leaf: tab strip + group menu + active mount + drop overlay.
190
+ function GroupPanel({ leaf, ctx }) {
191
+ const scena = useScena();
192
+ const activeKey = leaf.activeKey ?? leaf.tabs[0];
193
+ // const activeMount = ctx.mounts.find((m) => m.key === activeKey);
194
+ const [dragOverTab, setDragOverTab] = useState(null);
195
+ const [zone, setZone] = useState(null);
196
+ const bodyRef = useRef(null);
197
+ const tabsRef = useRef(null);
198
+ // Vertical wheel → horizontal scroll on the leaf's tab strip. Native
199
+ // listener (not React's onWheel) so we can preventDefault — React's
200
+ // synthetic wheel is passive and would scroll the surrounding page
201
+ // vertically instead. Same pattern as packages/web's TabBar.
202
+ useEffect(() => {
203
+ const el = tabsRef.current;
204
+ if (!el)
205
+ return;
206
+ function onWheel(e) {
207
+ if (e.deltaY === 0)
208
+ return;
209
+ e.preventDefault();
210
+ el.scrollLeft += e.deltaY;
211
+ }
212
+ el.addEventListener('wheel', onWheel, { passive: false });
213
+ return () => el.removeEventListener('wheel', onWheel);
214
+ }, []);
215
+ // Drop-preview cleanup. Two HTML5 DnD quirks bite here:
216
+ // 1) `dragleave` fires when the cursor enters a CHILD of the body
217
+ // (the child becomes the new target), but we only want to clear when
218
+ // the cursor actually leaves the body's bounds.
219
+ // 2) When the user releases the mouse OR the drag ends on a different
220
+ // element entirely, no `dragleave` may fire on this body at all —
221
+ // so its `zone` state would persist across drags.
222
+ // The window listeners below guarantee zone clears on every drag end/drop
223
+ // regardless of where it happened.
224
+ useEffect(() => {
225
+ const clearAll = () => {
226
+ setZone(null);
227
+ setDragOverTab(null);
228
+ };
229
+ window.addEventListener('dragend', clearAll);
230
+ window.addEventListener('drop', clearAll);
231
+ return () => {
232
+ window.removeEventListener('dragend', clearAll);
233
+ window.removeEventListener('drop', clearAll);
234
+ };
235
+ }, []);
236
+ function setLeafActive(key) {
237
+ const next = mapLeaves(ctx.tree, (l) => l.id === leaf.id ? { ...l, activeKey: key } : l);
238
+ if (next)
239
+ ctx.commit(next);
240
+ ctx.onActivate(key);
241
+ }
242
+ // ----- Tab DnD source -----
243
+ function onTabDragStart(e, tabKey) {
244
+ const payload = { sourceLeafId: leaf.id, tabKey };
245
+ e.dataTransfer.setData(DRAG_MIME, JSON.stringify(payload));
246
+ e.dataTransfer.effectAllowed = 'move';
247
+ }
248
+ // ----- Tab-strip drop (reorder within strip OR move into this leaf) -----
249
+ function onTabStripDragOver(e, idx) {
250
+ if (!e.dataTransfer.types.includes(DRAG_MIME))
251
+ return;
252
+ e.preventDefault();
253
+ e.dataTransfer.dropEffect = 'move';
254
+ setDragOverTab(idx);
255
+ }
256
+ function onTabStripDragLeave() {
257
+ setDragOverTab(null);
258
+ }
259
+ function onTabStripDrop(e, toIdx) {
260
+ if (!e.dataTransfer.types.includes(DRAG_MIME))
261
+ return;
262
+ e.preventDefault();
263
+ setDragOverTab(null);
264
+ const payload = readPayload(e);
265
+ if (!payload)
266
+ return;
267
+ insertTab(ctx, payload, leaf.id, toIdx);
268
+ }
269
+ // ----- Body 5-zone drop -----
270
+ function computeZone(e) {
271
+ const el = bodyRef.current;
272
+ if (!el)
273
+ return null;
274
+ const rect = el.getBoundingClientRect();
275
+ if (rect.width <= 0 || rect.height <= 0)
276
+ return null;
277
+ const x = (e.clientX - rect.left) / rect.width;
278
+ const y = (e.clientY - rect.top) / rect.height;
279
+ if (y < EDGE_THRESHOLD)
280
+ return 'top';
281
+ if (y > 1 - EDGE_THRESHOLD)
282
+ return 'bottom';
283
+ if (x < EDGE_THRESHOLD)
284
+ return 'left';
285
+ if (x > 1 - EDGE_THRESHOLD)
286
+ return 'right';
287
+ return 'center';
288
+ }
289
+ function onBodyDragOver(e) {
290
+ if (!e.dataTransfer.types.includes(DRAG_MIME))
291
+ return;
292
+ e.preventDefault();
293
+ e.dataTransfer.dropEffect = 'move';
294
+ setZone(computeZone(e));
295
+ }
296
+ function onBodyDragLeave(e) {
297
+ // Clear only when the cursor leaves the body entirely. `relatedTarget`
298
+ // is the element being entered (if any) — if it's inside the body we're
299
+ // still inside; only clear when it's outside or null (left the window).
300
+ const next = e.relatedTarget;
301
+ if (!next || !e.currentTarget.contains(next)) {
302
+ setZone(null);
303
+ }
304
+ }
305
+ function onBodyDrop(e) {
306
+ if (!e.dataTransfer.types.includes(DRAG_MIME))
307
+ return;
308
+ e.preventDefault();
309
+ const z = computeZone(e);
310
+ setZone(null);
311
+ const payload = readPayload(e);
312
+ if (!payload || !z)
313
+ return;
314
+ if (z === 'center') {
315
+ insertTab(ctx, payload, leaf.id, leaf.tabs.length);
316
+ }
317
+ else {
318
+ splitLeafOnDrop(ctx, payload, leaf.id, z);
319
+ }
320
+ }
321
+ // ----- [...] group menu -----
322
+ // Items come from the `tab-group:context` slot. Layout-commands.ts (group.*)
323
+ // owns the actions; this menu just opens the picker with the right
324
+ // capability paths injected so the commands target this leaf.
325
+ const [menu, setMenu] = useState(null);
326
+ function openGroupMenu(e) {
327
+ e.stopPropagation();
328
+ const rect = e.currentTarget.getBoundingClientRect();
329
+ setMenu({ x: rect.right - 4, y: rect.bottom + 2 });
330
+ }
331
+ function closeMenu() {
332
+ setMenu(null);
333
+ }
334
+ // ----- Per-tab context menu (right-click on tab) -----
335
+ const [tabMenu, setTabMenu] = useState(null);
336
+ function openTabMenu(e, tabKey, tabIdx) {
337
+ e.preventDefault();
338
+ setTabMenu({ x: e.clientX, y: e.clientY, tabKey, tabIdx });
339
+ }
340
+ function closeTabMenu() {
341
+ setTabMenu(null);
342
+ }
343
+ // Host-contributed rows for the right-clicked tab (e.g. explorer's "Open
344
+ // with <viewer>" alternates). Empty for tabs no host claims.
345
+ const tabMenuMount = tabMenu
346
+ ? ctx.mounts.find((m) => m.key === tabMenu.tabKey)
347
+ : undefined;
348
+ const tabMenuExtra = tabMenuMount
349
+ ? scena.mountMenus.collect('tab:context', tabMenuMount)
350
+ : undefined;
351
+ return (_jsxs("div", { className: "oo-tab-panel-group", "data-leaf-id": leaf.id, style: {
352
+ flex: 1,
353
+ minWidth: 0,
354
+ minHeight: 0,
355
+ display: 'flex',
356
+ flexDirection: 'column',
357
+ overflow: 'hidden',
358
+ }, children: [_jsxs("div", { className: "tab-bar", children: [_jsx("div", { className: "tab-bar__strip", ref: tabsRef, children: leaf.tabs.map((key, ti) => {
359
+ const m = ctx.mounts.find((mm) => mm.key === key);
360
+ return _jsx(TabTitle, { resourceKey: key, idx: ti, m: m, isActive: key === activeKey, isPinned: ctx.pinned.has(key), dragOverTab: dragOverTab, onDragStart: (e) => onTabDragStart(e, key), onDragOver: (e) => onTabStripDragOver(e, ti), onDragLeave: onTabStripDragLeave, onDrop: (e) => onTabStripDrop(e, ti), onClick: () => setLeafActive(key), onContextMenu: (e) => openTabMenu(e, key, ti), onClose: () => ctx.onClose(key), onUnpin: (e) => {
361
+ e.stopPropagation();
362
+ scena.store.set('$/tab/key', key);
363
+ scena.store.set('$/surface/name', ctx.surface);
364
+ void scena.commands.execute('tab.unpin');
365
+ } }, key);
366
+ }) }), _jsx("div", { className: "tab-bar__extras", children: _jsx("button", { className: "tab-bar__more", title: "Group actions", "aria-label": "Group actions", onClick: openGroupMenu, children: NAMED_GLYPH.moreHoriz }) })] }), _jsxs("div", { ref: bodyRef, onDragOver: onBodyDragOver, onDragLeave: onBodyDragLeave, onDrop: onBodyDrop, style: {
367
+ flex: 1,
368
+ minHeight: 0,
369
+ position: 'relative',
370
+ overflow: 'auto',
371
+ }, children: [leaf.tabs.length === 0 ? (_jsx("div", { style: { padding: 24, color: 'var(--oo-color-muted)' }, children: "Empty group. Drag a tab here." })) : (
372
+ // Keep every tab in the group mounted; show only the active one.
373
+ // Rendering just the active mount unmounts the rest, losing state.
374
+ leaf.tabs.map((key) => {
375
+ const m = ctx.mounts.find((mm) => mm.key === key);
376
+ if (!m)
377
+ return null;
378
+ return (_jsx("div", { className: "oo-layout__mount", "data-active": key === activeKey || undefined, style: { position: 'absolute', inset: 0, overflow: 'auto', display: key === activeKey ? 'block' : 'none' }, children: ctx.renderMount(m) }, key));
379
+ })), zone ? _jsx(DropPreview, { zone: zone }) : null] }), menu ? (_jsx(ContextMenu, { x: menu.x, y: menu.y, onClose: closeMenu, spec: { query: { slot: 'tab-group:context' }, footerHints: true }, context: {
380
+ '$/surface/name': ctx.surface,
381
+ '$/surface/layoutId': 'tab-panel',
382
+ '$/surface/mountCount': ctx.mounts.length,
383
+ '$/surface/closedHistory': 0,
384
+ '$/group/key': leaf.id,
385
+ '$/group/tabCount': leaf.tabs.length,
386
+ '$/group/canClose': true,
387
+ '$/group/canMaximize': false,
388
+ '$/tab/canSplit': true,
389
+ '$/tab/canMove': ctx.leafCount > 1,
390
+ } })) : null, tabMenu ? (_jsx(ContextMenu, { x: tabMenu.x, y: tabMenu.y, onClose: closeTabMenu, spec: { query: { slot: 'tab:context' }, extraItems: tabMenuExtra, footerHints: true }, context: {
391
+ '$/surface/name': ctx.surface,
392
+ '$/surface/layoutId': 'tab-panel',
393
+ '$/surface/mountCount': ctx.mounts.length,
394
+ '$/surface/closedHistory': 0,
395
+ '$/group/key': leaf.id,
396
+ '$/group/tabCount': leaf.tabs.length,
397
+ '$/group/canClose': true,
398
+ '$/tab/key': tabMenu.tabKey,
399
+ '$/tab/index': tabMenu.tabIdx,
400
+ '$/tab/leafId': leaf.id,
401
+ '$/tab/isActive': tabMenu.tabKey === activeKey,
402
+ '$/tab/isPinned': ctx.pinned.has(tabMenu.tabKey),
403
+ '$/tab/canSplit': true,
404
+ '$/tab/canMove': ctx.leafCount > 1,
405
+ } })) : null] }));
406
+ }
407
+ function DropPreview({ zone }) {
408
+ const base = {
409
+ position: 'absolute',
410
+ pointerEvents: 'none',
411
+ background: 'rgba(59,130,246,0.12)',
412
+ border: '2px solid rgba(59,130,246,0.6)',
413
+ boxSizing: 'border-box',
414
+ zIndex: 5,
415
+ transition: 'all 80ms ease-out',
416
+ };
417
+ const style = (() => {
418
+ switch (zone) {
419
+ case 'center':
420
+ return { ...base, inset: 0 };
421
+ case 'top':
422
+ return { ...base, top: 0, left: 0, right: 0, height: '50%' };
423
+ case 'bottom':
424
+ return { ...base, bottom: 0, left: 0, right: 0, height: '50%' };
425
+ case 'left':
426
+ return { ...base, top: 0, bottom: 0, left: 0, width: '50%' };
427
+ case 'right':
428
+ return { ...base, top: 0, bottom: 0, right: 0, width: '50%' };
429
+ }
430
+ })();
431
+ return _jsx("div", { className: "oo-tab-panel-drop-preview", style: style });
432
+ }
433
+ function readPayload(e) {
434
+ const raw = e.dataTransfer.getData(DRAG_MIME);
435
+ if (!raw)
436
+ return null;
437
+ try {
438
+ const obj = JSON.parse(raw);
439
+ if (typeof obj.sourceLeafId !== 'string' || typeof obj.tabKey !== 'string') {
440
+ return null;
441
+ }
442
+ return obj;
443
+ }
444
+ catch {
445
+ return null;
446
+ }
447
+ }
448
+ // Remove `tabKey` from the leaf that holds it; if that leaf is the
449
+ // target's same leaf, just rewrite tabs; otherwise prune empty leaves.
450
+ function removeTab(tree, tabKey) {
451
+ return mapLeaves(tree, (l) => {
452
+ if (!l.tabs.includes(tabKey))
453
+ return l;
454
+ const tabs = l.tabs.filter((k) => k !== tabKey);
455
+ if (tabs.length === 0)
456
+ return null;
457
+ return {
458
+ ...l,
459
+ tabs,
460
+ activeKey: l.activeKey === tabKey ? tabs[0] : l.activeKey,
461
+ };
462
+ });
463
+ }
464
+ function insertTab(ctx, payload, targetLeafId, insertIdx) {
465
+ // Same-leaf reorder
466
+ if (payload.sourceLeafId === targetLeafId) {
467
+ const next = mapLeaves(ctx.tree, (l) => {
468
+ if (l.id !== targetLeafId)
469
+ return l;
470
+ const fromIdx = l.tabs.indexOf(payload.tabKey);
471
+ if (fromIdx === -1)
472
+ return l;
473
+ const tabs = [...l.tabs];
474
+ tabs.splice(fromIdx, 1);
475
+ const adjusted = fromIdx < insertIdx ? insertIdx - 1 : insertIdx;
476
+ tabs.splice(adjusted, 0, payload.tabKey);
477
+ return { ...l, tabs, activeKey: payload.tabKey };
478
+ });
479
+ if (next)
480
+ ctx.commit(next);
481
+ ctx.onActivate(payload.tabKey);
482
+ return;
483
+ }
484
+ // Cross-leaf: remove from source, insert into target.
485
+ const removed = removeTab(ctx.tree, payload.tabKey);
486
+ if (!removed)
487
+ return;
488
+ const inserted = mapLeaves(removed, (l) => {
489
+ if (l.id !== targetLeafId)
490
+ return l;
491
+ const tabs = [...l.tabs];
492
+ const clamped = Math.max(0, Math.min(insertIdx, tabs.length));
493
+ tabs.splice(clamped, 0, payload.tabKey);
494
+ return { ...l, tabs, activeKey: payload.tabKey };
495
+ });
496
+ if (inserted)
497
+ ctx.commit(inserted);
498
+ ctx.onActivate(payload.tabKey);
499
+ }
500
+ function splitLeafOnDrop(ctx, payload, targetLeafId, zone) {
501
+ // Edge case: dragging the only tab of a leaf onto itself — no-op.
502
+ let sourceTree = ctx.tree;
503
+ const sourceLeaf = collectLeavesById(sourceTree, payload.sourceLeafId);
504
+ if (sourceLeaf &&
505
+ sourceLeaf.id === targetLeafId &&
506
+ sourceLeaf.tabs.length === 1) {
507
+ return;
508
+ }
509
+ sourceTree = removeTab(sourceTree, payload.tabKey);
510
+ if (!sourceTree)
511
+ return;
512
+ const target = collectLeavesById(sourceTree, targetLeafId);
513
+ if (!target)
514
+ return;
515
+ const newLeaf = makeLeaf([payload.tabKey], payload.tabKey);
516
+ const direction = zone === 'left' || zone === 'right' ? 'row' : 'column';
517
+ const newFirst = zone === 'left' || zone === 'top' ? newLeaf : target;
518
+ const newSecond = zone === 'left' || zone === 'top' ? target : newLeaf;
519
+ const split = {
520
+ kind: 'split',
521
+ direction,
522
+ ratio: 0.5,
523
+ first: newFirst,
524
+ second: newSecond,
525
+ };
526
+ const next = replaceLeaf(sourceTree, targetLeafId, split);
527
+ ctx.commit(next);
528
+ ctx.onActivate(payload.tabKey);
529
+ }
530
+ function collectLeavesById(node, id) {
531
+ if (node.kind === 'leaf')
532
+ return node.id === id ? node : null;
533
+ return (collectLeavesById(node.first, id) || collectLeavesById(node.second, id));
534
+ }
535
+ // Recursive node renderer with shared container ref for divider math.
536
+ function NodeRender({ node, ctx, }) {
537
+ if (node.kind === 'leaf') {
538
+ return _jsx(GroupPanel, { leaf: node, ctx: ctx });
539
+ }
540
+ return _jsx(SplitRender, { node: node, ctx: ctx });
541
+ }
542
+ function SplitRender({ node, ctx, }) {
543
+ const containerRef = useRef(null);
544
+ const ratio = node.ratio ?? 0.5;
545
+ function onDividerCommit(newRatio) {
546
+ const next = replaceSplit(ctx.tree, (s) => s === node, { ratio: newRatio });
547
+ ctx.commit(next);
548
+ }
549
+ const horizontal = node.direction === 'row';
550
+ return (_jsxs("div", { ref: containerRef, className: "oo-tab-panel-split", "data-direction": node.direction, style: {
551
+ display: 'flex',
552
+ flexDirection: horizontal ? 'row' : 'column',
553
+ flex: 1,
554
+ minWidth: 0,
555
+ minHeight: 0,
556
+ }, children: [_jsx("div", { style: { flex: ratio, minWidth: 0, minHeight: 0, display: 'flex' }, children: _jsx(NodeRender, { node: node.first, ctx: ctx }) }), _jsx(Divisor, { direction: node.direction === 'row' ? 'row' : 'col', containerRef: containerRef, min: MIN_RATIO, max: 1 - MIN_RATIO, onCommit: onDividerCommit }), _jsx("div", { style: { flex: 1 - ratio, minWidth: 0, minHeight: 0, display: 'flex' }, children: _jsx(NodeRender, { node: node.second, ctx: ctx }) })] }));
557
+ }
558
+ // ----- Public component -----
559
+ export function TabPanelLayout({ surface, mounts, state, setState, renderMount, onActivate, onClose, }) {
560
+ const mountKeys = mounts.map((m) => m.key);
561
+ const { tree } = reconcile(state.tabPanel?.tree, mountKeys, state.activeContainerKey);
562
+ // Persist the reconciled tree so `state.tabPanel.tree` always equals what's
563
+ // rendered. reconcile() appends just-opened mounts ("orphans") and prunes
564
+ // closed ones at render time only; without writing that back, the raw
565
+ // persisted tree drifts from the view. Every tab.*/group.* context command
566
+ // resolves its target tabs from the raw tree (layout-commands.ts), so on a
567
+ // drifted tree "Close others" / "Close to the right" act on a stale, partial
568
+ // set — e.g. open three tabs, right-click the middle, Close others, and the
569
+ // just-opened tabs survive. reconcile is idempotent, so this converges in one
570
+ // extra render (treesEqual stops the commit once raw == rendered).
571
+ useEffect(() => {
572
+ if (!treesEqual(state.tabPanel?.tree, tree)) {
573
+ setState({ tabPanel: { tree } });
574
+ }
575
+ });
576
+ // Total leaf count drives the `$/tab/canMove` capability — `move to group`
577
+ // only makes sense when there's somewhere to move to.
578
+ const leaves = [];
579
+ collectLeaves(tree, leaves);
580
+ const ctx = {
581
+ surface,
582
+ mounts,
583
+ renderMount,
584
+ onActivate,
585
+ onClose,
586
+ tree,
587
+ commit: (next) => setState({ tabPanel: { tree: next } }),
588
+ leafCount: leaves.length,
589
+ pinned: new Set(state.split?.pinned ?? []),
590
+ };
591
+ return (_jsx("div", { className: "oo-layout oo-layout--tab-panel", style: {
592
+ display: 'flex',
593
+ height: '100%',
594
+ minHeight: 0,
595
+ }, children: _jsx(NodeRender, { node: tree, ctx: ctx }) }));
596
+ }
597
+ export function TabTitle({ m, resourceKey, isActive, dragOverTab, idx, onDragStart, onDragOver, onDragLeave, onDrop, onClick, onContextMenu, onClose, onUnpin, isPinned }) {
598
+ const scena = useScena();
599
+ // Per-field merge: mount.props ?? component.props ?? key.
600
+ const compProps = m
601
+ ? scena.components.get(m.component.component)?.props
602
+ : undefined;
603
+ const title = useStoreLabel(m?.props?.title ?? compProps?.title, '', m?.dataContext) || resourceKey;
604
+ const icon = m?.props?.icon ?? compProps?.icon;
605
+ const color = m?.props?.color ?? compProps?.color;
606
+ return (_jsxs("div", { className: "tab-bar__tab", "data-active": isActive, "data-drag-over": dragOverTab === idx ? 'true' : undefined, "data-color": color, "data-pinned": isPinned || undefined, draggable: true, onDragStart: onDragStart, onDragOver: onDragOver, onDragLeave: onDragLeave, onDrop: onDrop, onClick: onClick, onContextMenu: onContextMenu, title: title, style: {
607
+ ...(color ? { '--tab-color': resolveColorRgb(color) } : {})
608
+ }, children: [icon ? _jsx("span", { className: "tab__icon", "aria-hidden": true, children: icon }) : null, _jsx("span", { className: "tab__label", children: title }), isPinned ? (_jsx("span", { className: "pin", onClick: (e) => {
609
+ e.stopPropagation();
610
+ onUnpin(e);
611
+ }, title: "Unpin", children: NAMED_GLYPH.pin })) : (_jsx("span", { className: "close", onClick: (e) => {
612
+ e.stopPropagation();
613
+ onClose(e);
614
+ }, title: "Close", children: NAMED_GLYPH.closePanel }))] }));
615
+ }
@@ -0,0 +1,2 @@
1
+ import type { ComponentDefinition } from '../../types/component-registry.js';
2
+ export declare const CATALOG_LAYOUT_MAP: ComponentDefinition[];
@@ -0,0 +1,10 @@
1
+ // Catalog registration for layout primitives. Dynamic import() so importing
2
+ // this file pulls nothing eager — components load on first render. Direct
3
+ // re-exports for React use live in ./index.ts; the lazy layout strategies are
4
+ // in ./register.ts.
5
+ export const CATALOG_LAYOUT_MAP = [
6
+ { component: 'Row', category: 'inline', renderer: { kind: 'react', load: () => import('./Row.js').then((m) => ({ default: m.Row })) } },
7
+ { component: 'Column', category: 'inline', renderer: { kind: 'react', load: () => import('./Column.js').then((m) => ({ default: m.Column })) } },
8
+ { component: 'Grid', category: 'inline', renderer: { kind: 'react', load: () => import('./Grid.js').then((m) => ({ default: m.Grid })) } },
9
+ { component: 'Splitter', category: 'page', renderer: { kind: 'react', load: () => import('./Splitter.js').then((m) => ({ default: m.Splitter })) } },
10
+ ];
@@ -0,0 +1,17 @@
1
+ export { Row } from './Row.js';
2
+ export { Column } from './Column.js';
3
+ export { Grid } from './Grid.js';
4
+ export type { GridProps } from './Grid.js';
5
+ export { TabLayout } from './TabLayout.js';
6
+ export { TabPanelLayout } from './TabPanelLayout.js';
7
+ export { SingleLayout } from './SingleLayout.js';
8
+ export { SplitLayout } from './SplitLayout.js';
9
+ export { StackLayout } from './StackLayout.js';
10
+ export { SpatialLayout } from './SpatialLayout.js';
11
+ export { SpatialCard } from './SpatialCard.js';
12
+ export type { SpatialCardData } from './SpatialCard.js';
13
+ export { RailLayout } from './RailLayout.js';
14
+ export { InlineLayout } from './InlineLayout.js';
15
+ export { BarLayout } from './BarLayout.js';
16
+ export { FloatingLayout } from './FloatingLayout.js';
17
+ export { registerBuiltinLayouts } from './register.js';
@@ -0,0 +1,17 @@
1
+ // Direct-React re-exports. Catalog registration (Row/Column/Grid) lives in
2
+ // ../catalog.ts; the layout strategies are registered (lazily) by ./register.ts.
3
+ export { Row } from './Row.js';
4
+ export { Column } from './Column.js';
5
+ export { Grid } from './Grid.js';
6
+ export { TabLayout } from './TabLayout.js';
7
+ export { TabPanelLayout } from './TabPanelLayout.js';
8
+ export { SingleLayout } from './SingleLayout.js';
9
+ export { SplitLayout } from './SplitLayout.js';
10
+ export { StackLayout } from './StackLayout.js';
11
+ export { SpatialLayout } from './SpatialLayout.js';
12
+ export { SpatialCard } from './SpatialCard.js';
13
+ export { RailLayout } from './RailLayout.js';
14
+ export { InlineLayout } from './InlineLayout.js';
15
+ export { BarLayout } from './BarLayout.js';
16
+ export { FloatingLayout } from './FloatingLayout.js';
17
+ export { registerBuiltinLayouts } from './register.js';
@@ -0,0 +1,3 @@
1
+ import type { Scena } from '../../types/scena.js';
2
+ import type { Disposable } from '../../types/disposable.js';
3
+ export declare function registerBuiltinLayouts(scena: Scena): Disposable;