react-cheminfo 0.64.0 → 0.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (640) hide show
  1. package/README.md +282 -0
  2. package/lib/card/core/cardAddress.d.ts +70 -0
  3. package/lib/card/core/cardAddress.d.ts.map +1 -0
  4. package/lib/card/core/cardAddress.js +59 -0
  5. package/lib/card/core/cardAddress.js.map +1 -0
  6. package/lib/card/core/cardPageUrl.d.ts +49 -0
  7. package/lib/card/core/cardPageUrl.d.ts.map +1 -0
  8. package/lib/card/core/cardPageUrl.js +59 -0
  9. package/lib/card/core/cardPageUrl.js.map +1 -0
  10. package/lib/card/core/index.d.ts +7 -0
  11. package/lib/card/core/index.d.ts.map +1 -0
  12. package/lib/card/core/index.js +4 -0
  13. package/lib/card/core/index.js.map +1 -0
  14. package/lib/card/core/panelRoom.d.ts +40 -0
  15. package/lib/card/core/panelRoom.d.ts.map +1 -0
  16. package/lib/card/core/panelRoom.js +40 -0
  17. package/lib/card/core/panelRoom.js.map +1 -0
  18. package/lib/card/ui/CardDetailsButton.d.ts +38 -0
  19. package/lib/card/ui/CardDetailsButton.d.ts.map +1 -0
  20. package/lib/card/ui/CardDetailsButton.js +50 -0
  21. package/lib/card/ui/CardDetailsButton.js.map +1 -0
  22. package/lib/card/ui/CardFigure.d.ts +51 -0
  23. package/lib/card/ui/CardFigure.d.ts.map +1 -0
  24. package/lib/card/ui/CardFigure.js +27 -0
  25. package/lib/card/ui/CardFigure.js.map +1 -0
  26. package/lib/card/ui/CardFrame.d.ts +30 -0
  27. package/lib/card/ui/CardFrame.d.ts.map +1 -0
  28. package/lib/card/ui/CardFrame.js +20 -0
  29. package/lib/card/ui/CardFrame.js.map +1 -0
  30. package/lib/card/ui/CopyTableButton.d.ts +37 -0
  31. package/lib/card/ui/CopyTableButton.d.ts.map +1 -0
  32. package/lib/card/ui/CopyTableButton.js +19 -0
  33. package/lib/card/ui/CopyTableButton.js.map +1 -0
  34. package/lib/card/ui/cardTooltip.d.ts +14 -0
  35. package/lib/card/ui/cardTooltip.d.ts.map +1 -0
  36. package/lib/card/ui/cardTooltip.js +15 -0
  37. package/lib/card/ui/cardTooltip.js.map +1 -0
  38. package/lib/card/ui/embed.d.ts +15 -0
  39. package/lib/card/ui/embed.d.ts.map +1 -0
  40. package/lib/card/ui/embed.js +24 -0
  41. package/lib/card/ui/embed.js.map +1 -0
  42. package/lib/card/ui/fitCardToFrame.d.ts +31 -0
  43. package/lib/card/ui/fitCardToFrame.d.ts.map +1 -0
  44. package/lib/card/ui/fitCardToFrame.js +66 -0
  45. package/lib/card/ui/fitCardToFrame.js.map +1 -0
  46. package/lib/card/ui/holdRoomForPanels.d.ts +16 -0
  47. package/lib/card/ui/holdRoomForPanels.d.ts.map +1 -0
  48. package/lib/card/ui/holdRoomForPanels.js +76 -0
  49. package/lib/card/ui/holdRoomForPanels.js.map +1 -0
  50. package/lib/card/ui/index.d.ts +11 -0
  51. package/lib/card/ui/index.d.ts.map +1 -0
  52. package/lib/card/ui/index.js +7 -0
  53. package/lib/card/ui/index.js.map +1 -0
  54. package/lib/card/ui/openPanels.d.ts +25 -0
  55. package/lib/card/ui/openPanels.d.ts.map +1 -0
  56. package/lib/card/ui/openPanels.js +85 -0
  57. package/lib/card/ui/openPanels.js.map +1 -0
  58. package/lib/card.d.ts +13 -0
  59. package/lib/card.d.ts.map +1 -0
  60. package/lib/card.js +13 -0
  61. package/lib/card.js.map +1 -0
  62. package/lib/conformers.d.ts +1 -0
  63. package/lib/conformers.d.ts.map +1 -1
  64. package/lib/conformers.js +1 -0
  65. package/lib/conformers.js.map +1 -1
  66. package/lib/core.d.ts +4 -0
  67. package/lib/core.d.ts.map +1 -1
  68. package/lib/core.js +5 -0
  69. package/lib/core.js.map +1 -1
  70. package/lib/fetch/core/apiError.d.ts +56 -0
  71. package/lib/fetch/core/apiError.d.ts.map +1 -0
  72. package/lib/fetch/core/apiError.js +43 -0
  73. package/lib/fetch/core/apiError.js.map +1 -0
  74. package/lib/fetch/core/fetchJson.d.ts +47 -0
  75. package/lib/fetch/core/fetchJson.d.ts.map +1 -0
  76. package/lib/fetch/core/fetchJson.js +109 -0
  77. package/lib/fetch/core/fetchJson.js.map +1 -0
  78. package/lib/fetch/core/index.d.ts +5 -0
  79. package/lib/fetch/core/index.d.ts.map +1 -0
  80. package/lib/fetch/core/index.js +3 -0
  81. package/lib/fetch/core/index.js.map +1 -0
  82. package/lib/formula/core/formulaText.d.ts +46 -0
  83. package/lib/formula/core/formulaText.d.ts.map +1 -0
  84. package/lib/formula/core/formulaText.js +74 -0
  85. package/lib/formula/core/formulaText.js.map +1 -0
  86. package/lib/formula/core/index.d.ts +6 -0
  87. package/lib/formula/core/index.d.ts.map +1 -0
  88. package/lib/formula/core/index.js +4 -0
  89. package/lib/formula/core/index.js.map +1 -0
  90. package/lib/formula/core/normalizeFormula.d.ts +22 -0
  91. package/lib/formula/core/normalizeFormula.d.ts.map +1 -0
  92. package/lib/formula/core/normalizeFormula.js +46 -0
  93. package/lib/formula/core/normalizeFormula.js.map +1 -0
  94. package/lib/formula/core/readFormula.d.ts +73 -0
  95. package/lib/formula/core/readFormula.d.ts.map +1 -0
  96. package/lib/formula/core/readFormula.js +132 -0
  97. package/lib/formula/core/readFormula.js.map +1 -0
  98. package/lib/formula/ui/CopyableFormula.d.ts +31 -0
  99. package/lib/formula/ui/CopyableFormula.d.ts.map +1 -0
  100. package/lib/formula/ui/CopyableFormula.js +19 -0
  101. package/lib/formula/ui/CopyableFormula.js.map +1 -0
  102. package/lib/formula/ui/FormulaInput.d.ts +29 -0
  103. package/lib/formula/ui/FormulaInput.d.ts.map +1 -0
  104. package/lib/formula/ui/FormulaInput.js +16 -0
  105. package/lib/formula/ui/FormulaInput.js.map +1 -0
  106. package/lib/formula/ui/QuestionFormula.d.ts +14 -0
  107. package/lib/formula/ui/QuestionFormula.d.ts.map +1 -0
  108. package/lib/formula/ui/QuestionFormula.js +13 -0
  109. package/lib/formula/ui/QuestionFormula.js.map +1 -0
  110. package/lib/formula/ui/index.d.ts +7 -0
  111. package/lib/formula/ui/index.d.ts.map +1 -0
  112. package/lib/formula/ui/index.js +4 -0
  113. package/lib/formula/ui/index.js.map +1 -0
  114. package/lib/formula.d.ts +11 -0
  115. package/lib/formula.d.ts.map +1 -0
  116. package/lib/formula.js +11 -0
  117. package/lib/formula.js.map +1 -0
  118. package/lib/hooks/ui/index.d.ts +1 -0
  119. package/lib/hooks/ui/index.d.ts.map +1 -1
  120. package/lib/hooks/ui/index.js.map +1 -1
  121. package/lib/hooks/ui/keyTargets.d.ts +4 -2
  122. package/lib/hooks/ui/keyTargets.d.ts.map +1 -1
  123. package/lib/hooks/ui/keyTargets.js +5 -3
  124. package/lib/hooks/ui/keyTargets.js.map +1 -1
  125. package/lib/hooks/ui/useAsync.d.ts +20 -5
  126. package/lib/hooks/ui/useAsync.d.ts.map +1 -1
  127. package/lib/hooks/ui/useAsync.js +29 -14
  128. package/lib/hooks/ui/useAsync.js.map +1 -1
  129. package/lib/i18n/core/chromeCatalog.d.ts +1 -1
  130. package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
  131. package/lib/locales/de.json +37 -0
  132. package/lib/locales/en.json +37 -0
  133. package/lib/locales/es.json +37 -0
  134. package/lib/locales/fr.json +37 -0
  135. package/lib/locales/it.json +37 -0
  136. package/lib/molecule3d/core/highlight.d.ts.map +1 -1
  137. package/lib/molecule3d/core/highlight.js +2 -8
  138. package/lib/molecule3d/core/highlight.js.map +1 -1
  139. package/lib/molecule3d/core/index.d.ts +1 -1
  140. package/lib/molecule3d/core/index.d.ts.map +1 -1
  141. package/lib/molecule3d/core/index.js +1 -1
  142. package/lib/molecule3d/core/index.js.map +1 -1
  143. package/lib/molecule3d/core/measurement.d.ts +17 -0
  144. package/lib/molecule3d/core/measurement.d.ts.map +1 -1
  145. package/lib/molecule3d/core/measurement.js +43 -0
  146. package/lib/molecule3d/core/measurement.js.map +1 -1
  147. package/lib/molecule3d/ui/drawScene.d.ts +4 -2
  148. package/lib/molecule3d/ui/drawScene.d.ts.map +1 -1
  149. package/lib/molecule3d/ui/drawScene.js +1 -1
  150. package/lib/molecule3d/ui/drawScene.js.map +1 -1
  151. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts +3 -1
  152. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts.map +1 -1
  153. package/lib/molecule3d/ui/sceneDrawer.d.ts +47 -0
  154. package/lib/molecule3d/ui/sceneDrawer.d.ts.map +1 -0
  155. package/lib/molecule3d/ui/sceneDrawer.js +103 -0
  156. package/lib/molecule3d/ui/sceneDrawer.js.map +1 -0
  157. package/lib/molecule3d/ui/useMoleculeScene.d.ts +2 -1
  158. package/lib/molecule3d/ui/useMoleculeScene.d.ts.map +1 -1
  159. package/lib/molecule3d/ui/useMoleculeScene.js +13 -22
  160. package/lib/molecule3d/ui/useMoleculeScene.js.map +1 -1
  161. package/lib/molecule3d/ui/useSharedCamera.d.ts +1 -3
  162. package/lib/molecule3d/ui/useSharedCamera.d.ts.map +1 -1
  163. package/lib/molecule3d/ui/useSharedCamera.js.map +1 -1
  164. package/lib/moleculesClient/core/index.d.ts +5 -0
  165. package/lib/moleculesClient/core/index.d.ts.map +1 -0
  166. package/lib/moleculesClient/core/index.js +3 -0
  167. package/lib/moleculesClient/core/index.js.map +1 -0
  168. package/lib/moleculesClient/core/moleculesClient.d.ts +12 -0
  169. package/lib/moleculesClient/core/moleculesClient.d.ts.map +1 -0
  170. package/lib/moleculesClient/core/moleculesClient.js +105 -0
  171. package/lib/moleculesClient/core/moleculesClient.js.map +1 -0
  172. package/lib/moleculesClient/core/moleculesClientApi.d.ts +100 -0
  173. package/lib/moleculesClient/core/moleculesClientApi.d.ts.map +1 -0
  174. package/lib/moleculesClient/core/moleculesClientApi.js +20 -0
  175. package/lib/moleculesClient/core/moleculesClientApi.js.map +1 -0
  176. package/lib/moleculesClient/core/moleculesTypes.d.ts +154 -0
  177. package/lib/moleculesClient/core/moleculesTypes.d.ts.map +1 -0
  178. package/lib/moleculesClient/core/moleculesTypes.js +2 -0
  179. package/lib/moleculesClient/core/moleculesTypes.js.map +1 -0
  180. package/lib/moleculesClient/core/requestRetry.d.ts +50 -0
  181. package/lib/moleculesClient/core/requestRetry.d.ts.map +1 -0
  182. package/lib/moleculesClient/core/requestRetry.js +108 -0
  183. package/lib/moleculesClient/core/requestRetry.js.map +1 -0
  184. package/lib/molstar/core/camera.d.ts +2 -1
  185. package/lib/molstar/core/camera.d.ts.map +1 -1
  186. package/lib/molstar/core/camera.js +3 -2
  187. package/lib/molstar/core/camera.js.map +1 -1
  188. package/lib/molstar/core/framing.d.ts +102 -0
  189. package/lib/molstar/core/framing.d.ts.map +1 -0
  190. package/lib/molstar/core/framing.js +120 -0
  191. package/lib/molstar/core/framing.js.map +1 -0
  192. package/lib/molstar/core/hover.d.ts +16 -0
  193. package/lib/molstar/core/hover.d.ts.map +1 -1
  194. package/lib/molstar/core/hover.js +14 -0
  195. package/lib/molstar/core/hover.js.map +1 -1
  196. package/lib/molstar/core/index.d.ts +4 -1
  197. package/lib/molstar/core/index.d.ts.map +1 -1
  198. package/lib/molstar/core/index.js +2 -1
  199. package/lib/molstar/core/index.js.map +1 -1
  200. package/lib/pedagogy/core/answers.d.ts +46 -0
  201. package/lib/pedagogy/core/answers.d.ts.map +1 -0
  202. package/lib/pedagogy/core/answers.js +77 -0
  203. package/lib/pedagogy/core/answers.js.map +1 -0
  204. package/lib/pedagogy/core/attempts.d.ts +86 -0
  205. package/lib/pedagogy/core/attempts.d.ts.map +1 -0
  206. package/lib/pedagogy/core/attempts.js +117 -0
  207. package/lib/pedagogy/core/attempts.js.map +1 -0
  208. package/lib/pedagogy/core/index.d.ts +8 -0
  209. package/lib/pedagogy/core/index.d.ts.map +1 -1
  210. package/lib/pedagogy/core/index.js +4 -0
  211. package/lib/pedagogy/core/index.js.map +1 -1
  212. package/lib/pedagogy/core/progressController.d.ts +64 -0
  213. package/lib/pedagogy/core/progressController.d.ts.map +1 -0
  214. package/lib/pedagogy/core/progressController.js +56 -0
  215. package/lib/pedagogy/core/progressController.js.map +1 -0
  216. package/lib/pedagogy/core/seed.d.ts +96 -0
  217. package/lib/pedagogy/core/seed.d.ts.map +1 -0
  218. package/lib/pedagogy/core/seed.js +128 -0
  219. package/lib/pedagogy/core/seed.js.map +1 -0
  220. package/lib/pedagogy/core/series.d.ts +77 -0
  221. package/lib/pedagogy/core/series.d.ts.map +1 -0
  222. package/lib/pedagogy/core/series.js +10 -0
  223. package/lib/pedagogy/core/series.js.map +1 -0
  224. package/lib/pedagogy/ui/AnswerFields.d.ts +21 -0
  225. package/lib/pedagogy/ui/AnswerFields.d.ts.map +1 -0
  226. package/lib/pedagogy/ui/AnswerFields.js +24 -0
  227. package/lib/pedagogy/ui/AnswerFields.js.map +1 -0
  228. package/lib/pedagogy/ui/ExerciseList.d.ts +82 -0
  229. package/lib/pedagogy/ui/ExerciseList.d.ts.map +1 -0
  230. package/lib/pedagogy/ui/ExerciseList.js +53 -0
  231. package/lib/pedagogy/ui/ExerciseList.js.map +1 -0
  232. package/lib/pedagogy/ui/ExerciseSeries.d.ts +95 -0
  233. package/lib/pedagogy/ui/ExerciseSeries.d.ts.map +1 -0
  234. package/lib/pedagogy/ui/ExerciseSeries.js +74 -0
  235. package/lib/pedagogy/ui/ExerciseSeries.js.map +1 -0
  236. package/lib/pedagogy/ui/QuestionCard.d.ts +64 -0
  237. package/lib/pedagogy/ui/QuestionCard.d.ts.map +1 -0
  238. package/lib/pedagogy/ui/QuestionCard.js +73 -0
  239. package/lib/pedagogy/ui/QuestionCard.js.map +1 -0
  240. package/lib/pedagogy/ui/index.d.ts +10 -0
  241. package/lib/pedagogy/ui/index.d.ts.map +1 -1
  242. package/lib/pedagogy/ui/index.js +6 -0
  243. package/lib/pedagogy/ui/index.js.map +1 -1
  244. package/lib/pedagogy/ui/seriesCounts.d.ts +17 -0
  245. package/lib/pedagogy/ui/seriesCounts.d.ts.map +1 -0
  246. package/lib/pedagogy/ui/seriesCounts.js +27 -0
  247. package/lib/pedagogy/ui/seriesCounts.js.map +1 -0
  248. package/lib/pedagogy/ui/seriesParts.d.ts +55 -0
  249. package/lib/pedagogy/ui/seriesParts.d.ts.map +1 -0
  250. package/lib/pedagogy/ui/seriesParts.js +38 -0
  251. package/lib/pedagogy/ui/seriesParts.js.map +1 -0
  252. package/lib/pedagogy/ui/useAttemptRecords.d.ts +10 -0
  253. package/lib/pedagogy/ui/useAttemptRecords.d.ts.map +1 -0
  254. package/lib/pedagogy/ui/useAttemptRecords.js +11 -0
  255. package/lib/pedagogy/ui/useAttemptRecords.js.map +1 -0
  256. package/lib/periodic/ui/PeriodicTable.d.ts.map +1 -1
  257. package/lib/periodic/ui/PeriodicTable.js +6 -3
  258. package/lib/periodic/ui/PeriodicTable.js.map +1 -1
  259. package/lib/property/core/copyableText.d.ts +14 -0
  260. package/lib/property/core/copyableText.d.ts.map +1 -0
  261. package/lib/property/core/copyableText.js +21 -0
  262. package/lib/property/core/copyableText.js.map +1 -0
  263. package/lib/property/core/index.d.ts +2 -0
  264. package/lib/property/core/index.d.ts.map +1 -0
  265. package/lib/property/core/index.js +2 -0
  266. package/lib/property/core/index.js.map +1 -0
  267. package/lib/property/ui/PropertyTable.d.ts +43 -0
  268. package/lib/property/ui/PropertyTable.d.ts.map +1 -0
  269. package/lib/property/ui/PropertyTable.js +19 -0
  270. package/lib/property/ui/PropertyTable.js.map +1 -0
  271. package/lib/property/ui/index.d.ts +3 -0
  272. package/lib/property/ui/index.d.ts.map +1 -0
  273. package/lib/property/ui/index.js +2 -0
  274. package/lib/property/ui/index.js.map +1 -0
  275. package/lib/router/core/history.d.ts +24 -3
  276. package/lib/router/core/history.d.ts.map +1 -1
  277. package/lib/router/core/history.js +55 -7
  278. package/lib/router/core/history.js.map +1 -1
  279. package/lib/router/core/index.d.ts +3 -3
  280. package/lib/router/core/index.d.ts.map +1 -1
  281. package/lib/router/core/index.js +2 -2
  282. package/lib/router/core/index.js.map +1 -1
  283. package/lib/router/core/languageRoute.d.ts +61 -0
  284. package/lib/router/core/languageRoute.d.ts.map +1 -0
  285. package/lib/router/core/languageRoute.js +96 -0
  286. package/lib/router/core/languageRoute.js.map +1 -0
  287. package/lib/router/core/siteAddresses.d.ts +23 -0
  288. package/lib/router/core/siteAddresses.d.ts.map +1 -1
  289. package/lib/router/core/siteAddresses.js +26 -0
  290. package/lib/router/core/siteAddresses.js.map +1 -1
  291. package/lib/router/core/tabRouter.d.ts +2 -108
  292. package/lib/router/core/tabRouter.d.ts.map +1 -1
  293. package/lib/router/core/tabRouter.js +38 -5
  294. package/lib/router/core/tabRouter.js.map +1 -1
  295. package/lib/router/core/tabRouterTypes.d.ts +154 -0
  296. package/lib/router/core/tabRouterTypes.d.ts.map +1 -0
  297. package/lib/router/core/tabRouterTypes.js +2 -0
  298. package/lib/router/core/tabRouterTypes.js.map +1 -0
  299. package/lib/seo/core/fitDescription.d.ts +40 -0
  300. package/lib/seo/core/fitDescription.d.ts.map +1 -0
  301. package/lib/seo/core/fitDescription.js +45 -0
  302. package/lib/seo/core/fitDescription.js.map +1 -0
  303. package/lib/seo/core/index.d.ts +7 -0
  304. package/lib/seo/core/index.d.ts.map +1 -1
  305. package/lib/seo/core/index.js +4 -0
  306. package/lib/seo/core/index.js.map +1 -1
  307. package/lib/seo/core/limits.d.ts +24 -0
  308. package/lib/seo/core/limits.d.ts.map +1 -0
  309. package/lib/seo/core/limits.js +24 -0
  310. package/lib/seo/core/limits.js.map +1 -0
  311. package/lib/seo/core/pageContent.d.ts +25 -0
  312. package/lib/seo/core/pageContent.d.ts.map +1 -0
  313. package/lib/seo/core/pageContent.js +25 -0
  314. package/lib/seo/core/pageContent.js.map +1 -0
  315. package/lib/seo/core/plainDescription.d.ts.map +1 -1
  316. package/lib/seo/core/plainDescription.js +3 -2
  317. package/lib/seo/core/plainDescription.js.map +1 -1
  318. package/lib/seo/core/routeProblems.d.ts.map +1 -1
  319. package/lib/seo/core/routeProblems.js +1 -6
  320. package/lib/seo/core/routeProblems.js.map +1 -1
  321. package/lib/seo/core/routeTable.d.ts +31 -0
  322. package/lib/seo/core/routeTable.d.ts.map +1 -0
  323. package/lib/seo/core/routeTable.js +96 -0
  324. package/lib/seo/core/routeTable.js.map +1 -0
  325. package/lib/seo/vite/index.d.ts +2 -0
  326. package/lib/seo/vite/index.d.ts.map +1 -1
  327. package/lib/seo/vite/index.js +1 -0
  328. package/lib/seo/vite/index.js.map +1 -1
  329. package/lib/seo/vite/prerender.d.ts +10 -0
  330. package/lib/seo/vite/prerender.d.ts.map +1 -1
  331. package/lib/seo/vite/prerender.js +12 -1
  332. package/lib/seo/vite/prerender.js.map +1 -1
  333. package/lib/seo/vite/routeTable.d.ts +40 -0
  334. package/lib/seo/vite/routeTable.d.ts.map +1 -0
  335. package/lib/seo/vite/routeTable.js +44 -0
  336. package/lib/seo/vite/routeTable.js.map +1 -0
  337. package/lib/server/answerAddresses.d.ts +51 -0
  338. package/lib/server/answerAddresses.d.ts.map +1 -0
  339. package/lib/server/answerAddresses.js +72 -0
  340. package/lib/server/answerAddresses.js.map +1 -0
  341. package/lib/server/cardMeta.d.ts +57 -0
  342. package/lib/server/cardMeta.d.ts.map +1 -0
  343. package/lib/server/cardMeta.js +52 -0
  344. package/lib/server/cardMeta.js.map +1 -0
  345. package/lib/server/config.d.ts +72 -0
  346. package/lib/server/config.d.ts.map +1 -0
  347. package/lib/server/config.js +67 -0
  348. package/lib/server/config.js.map +1 -0
  349. package/lib/server/envNumber.d.ts +35 -0
  350. package/lib/server/envNumber.d.ts.map +1 -0
  351. package/lib/server/envNumber.js +42 -0
  352. package/lib/server/envNumber.js.map +1 -0
  353. package/lib/server/healthRoute.d.ts +26 -0
  354. package/lib/server/healthRoute.d.ts.map +1 -0
  355. package/lib/server/healthRoute.js +22 -0
  356. package/lib/server/healthRoute.js.map +1 -0
  357. package/lib/server/listenSite.d.ts +38 -0
  358. package/lib/server/listenSite.d.ts.map +1 -0
  359. package/lib/server/listenSite.js +60 -0
  360. package/lib/server/listenSite.js.map +1 -0
  361. package/lib/server/mcpServer.d.ts +8 -0
  362. package/lib/server/mcpServer.d.ts.map +1 -0
  363. package/lib/server/mcpServer.js +11 -0
  364. package/lib/server/mcpServer.js.map +1 -0
  365. package/lib/server/repositoryVersion.d.ts +16 -0
  366. package/lib/server/repositoryVersion.d.ts.map +1 -0
  367. package/lib/server/repositoryVersion.js +33 -0
  368. package/lib/server/repositoryVersion.js.map +1 -0
  369. package/lib/server/routeOptions.d.ts +23 -0
  370. package/lib/server/routeOptions.d.ts.map +1 -0
  371. package/lib/server/routeOptions.js +20 -0
  372. package/lib/server/routeOptions.js.map +1 -0
  373. package/lib/server/routeTable.d.ts +14 -0
  374. package/lib/server/routeTable.d.ts.map +1 -0
  375. package/lib/server/routeTable.js +32 -0
  376. package/lib/server/routeTable.js.map +1 -0
  377. package/lib/server/siteView.d.ts +29 -0
  378. package/lib/server/siteView.d.ts.map +1 -0
  379. package/lib/server/siteView.js +21 -0
  380. package/lib/server/siteView.js.map +1 -0
  381. package/lib/server/spaPages.d.ts +32 -0
  382. package/lib/server/spaPages.d.ts.map +1 -0
  383. package/lib/server/spaPages.js +126 -0
  384. package/lib/server/spaPages.js.map +1 -0
  385. package/lib/server/spaSite.d.ts +30 -0
  386. package/lib/server/spaSite.d.ts.map +1 -0
  387. package/lib/server/spaSite.js +170 -0
  388. package/lib/server/spaSite.js.map +1 -0
  389. package/lib/server/spaSiteOptions.d.ts +126 -0
  390. package/lib/server/spaSiteOptions.d.ts.map +1 -0
  391. package/lib/server/spaSiteOptions.js +2 -0
  392. package/lib/server/spaSiteOptions.js.map +1 -0
  393. package/lib/server/staticSite.d.ts +9 -0
  394. package/lib/server/staticSite.d.ts.map +1 -1
  395. package/lib/server/staticSite.js +41 -19
  396. package/lib/server/staticSite.js.map +1 -1
  397. package/lib/server/toolSiteServer.d.ts +77 -0
  398. package/lib/server/toolSiteServer.d.ts.map +1 -0
  399. package/lib/server/toolSiteServer.js +58 -0
  400. package/lib/server/toolSiteServer.js.map +1 -0
  401. package/lib/server/trustProxy.d.ts +20 -0
  402. package/lib/server/trustProxy.d.ts.map +1 -0
  403. package/lib/server/trustProxy.js +32 -0
  404. package/lib/server/trustProxy.js.map +1 -0
  405. package/lib/server/types.d.ts +13 -0
  406. package/lib/server/types.d.ts.map +1 -0
  407. package/lib/server/types.js +2 -0
  408. package/lib/server/types.js.map +1 -0
  409. package/lib/server.d.ts +22 -0
  410. package/lib/server.d.ts.map +1 -1
  411. package/lib/server.js +12 -0
  412. package/lib/server.js.map +1 -1
  413. package/lib/share/core/config.d.ts +18 -0
  414. package/lib/share/core/config.d.ts.map +1 -1
  415. package/lib/share/core/config.js +33 -2
  416. package/lib/share/core/config.js.map +1 -1
  417. package/lib/share/core/index.d.ts +3 -1
  418. package/lib/share/core/index.d.ts.map +1 -1
  419. package/lib/share/core/index.js +2 -1
  420. package/lib/share/core/index.js.map +1 -1
  421. package/lib/share/core/keySetParam.d.ts +40 -0
  422. package/lib/share/core/keySetParam.d.ts.map +1 -0
  423. package/lib/share/core/keySetParam.js +60 -0
  424. package/lib/share/core/keySetParam.js.map +1 -0
  425. package/lib/share/core/vocabulary.d.ts +8 -0
  426. package/lib/share/core/vocabulary.d.ts.map +1 -1
  427. package/lib/shell/ui/ShareControl.d.ts +75 -0
  428. package/lib/shell/ui/ShareControl.d.ts.map +1 -0
  429. package/lib/shell/ui/ShareControl.js +40 -0
  430. package/lib/shell/ui/ShareControl.js.map +1 -0
  431. package/lib/shell/ui/ShellFrame.d.ts +14 -0
  432. package/lib/shell/ui/ShellFrame.d.ts.map +1 -0
  433. package/lib/shell/ui/ShellFrame.js +45 -0
  434. package/lib/shell/ui/ShellFrame.js.map +1 -0
  435. package/lib/shell/ui/SiteShell.d.ts +251 -0
  436. package/lib/shell/ui/SiteShell.d.ts.map +1 -0
  437. package/lib/shell/ui/SiteShell.js +39 -0
  438. package/lib/shell/ui/SiteShell.js.map +1 -0
  439. package/lib/shell/ui/index.d.ts +5 -0
  440. package/lib/shell/ui/index.d.ts.map +1 -0
  441. package/lib/shell/ui/index.js +3 -0
  442. package/lib/shell/ui/index.js.map +1 -0
  443. package/lib/state/core/index.d.ts +1 -0
  444. package/lib/state/core/index.d.ts.map +1 -1
  445. package/lib/state/core/index.js.map +1 -1
  446. package/lib/state/core/legacyEntries.d.ts +30 -0
  447. package/lib/state/core/legacyEntries.d.ts.map +1 -0
  448. package/lib/state/core/legacyEntries.js +51 -0
  449. package/lib/state/core/legacyEntries.js.map +1 -0
  450. package/lib/state/core/persistBucket.d.ts +26 -2
  451. package/lib/state/core/persistBucket.d.ts.map +1 -1
  452. package/lib/state/core/persistBucket.js +26 -9
  453. package/lib/state/core/persistBucket.js.map +1 -1
  454. package/lib/state/core/persistSignalBucket.d.ts +26 -0
  455. package/lib/state/core/persistSignalBucket.d.ts.map +1 -1
  456. package/lib/state/core/persistSignalBucket.js +31 -0
  457. package/lib/state/core/persistSignalBucket.js.map +1 -1
  458. package/lib/state/core/storageEntry.d.ts +15 -0
  459. package/lib/state/core/storageEntry.d.ts.map +1 -1
  460. package/lib/state/core/storageEntry.js +33 -0
  461. package/lib/state/core/storageEntry.js.map +1 -1
  462. package/lib/structure/ui/StructureExportButton.d.ts +27 -0
  463. package/lib/structure/ui/StructureExportButton.d.ts.map +1 -0
  464. package/lib/structure/ui/StructureExportButton.js +21 -0
  465. package/lib/structure/ui/StructureExportButton.js.map +1 -0
  466. package/lib/structure/ui/index.d.ts +4 -0
  467. package/lib/structure/ui/index.d.ts.map +1 -1
  468. package/lib/structure/ui/index.js +2 -0
  469. package/lib/structure/ui/index.js.map +1 -1
  470. package/lib/structure/ui/useStructureDraft.d.ts +32 -0
  471. package/lib/structure/ui/useStructureDraft.d.ts.map +1 -0
  472. package/lib/structure/ui/useStructureDraft.js +20 -0
  473. package/lib/structure/ui/useStructureDraft.js.map +1 -0
  474. package/lib/ui.d.ts +2 -0
  475. package/lib/ui.d.ts.map +1 -1
  476. package/lib/ui.js +2 -0
  477. package/lib/ui.js.map +1 -1
  478. package/lib/worker/core/index.d.ts +1 -1
  479. package/lib/worker/core/index.d.ts.map +1 -1
  480. package/lib/worker/core/messages.d.ts +4 -2
  481. package/lib/worker/core/messages.d.ts.map +1 -1
  482. package/lib/worker/core/messages.js.map +1 -1
  483. package/lib/worker/core/oclResourcesUrl.d.ts +16 -0
  484. package/lib/worker/core/oclResourcesUrl.d.ts.map +1 -0
  485. package/lib/worker/core/oclResourcesUrl.js +19 -0
  486. package/lib/worker/core/oclResourcesUrl.js.map +1 -0
  487. package/lib/worker/core/serveWorkerRequests.d.ts +8 -0
  488. package/lib/worker/core/serveWorkerRequests.d.ts.map +1 -1
  489. package/lib/worker/core/serveWorkerRequests.js +15 -2
  490. package/lib/worker/core/serveWorkerRequests.js.map +1 -1
  491. package/lib/worker/core/workerChannel.d.ts +3 -4
  492. package/lib/worker/core/workerChannel.d.ts.map +1 -1
  493. package/lib/worker/core/workerChannel.js +72 -67
  494. package/lib/worker/core/workerChannel.js.map +1 -1
  495. package/lib/worker/core/workerChannelParts.d.ts +17 -6
  496. package/lib/worker/core/workerChannelParts.d.ts.map +1 -1
  497. package/lib/worker/core/workerChannelParts.js +20 -4
  498. package/lib/worker/core/workerChannelParts.js.map +1 -1
  499. package/lib/worker/core/workerChannelTypes.d.ts +46 -2
  500. package/lib/worker/core/workerChannelTypes.d.ts.map +1 -1
  501. package/lib/worker/core/workerSlot.d.ts +66 -0
  502. package/lib/worker/core/workerSlot.d.ts.map +1 -0
  503. package/lib/worker/core/workerSlot.js +107 -0
  504. package/lib/worker/core/workerSlot.js.map +1 -0
  505. package/package.json +16 -1
  506. package/src/card/core/cardAddress.ts +100 -0
  507. package/src/card/core/cardPageUrl.ts +97 -0
  508. package/src/card/core/index.ts +6 -0
  509. package/src/card/core/panelRoom.ts +66 -0
  510. package/src/card/ui/CardDetailsButton.tsx +104 -0
  511. package/src/card/ui/CardFigure.tsx +86 -0
  512. package/src/card/ui/CardFrame.tsx +46 -0
  513. package/src/card/ui/CopyTableButton.tsx +81 -0
  514. package/src/card/ui/cardTooltip.ts +18 -0
  515. package/src/card/ui/embed.ts +27 -0
  516. package/src/card/ui/fitCardToFrame.ts +76 -0
  517. package/src/card/ui/holdRoomForPanels.ts +83 -0
  518. package/src/card/ui/index.ts +14 -0
  519. package/src/card/ui/openPanels.ts +106 -0
  520. package/src/card.ts +13 -0
  521. package/src/conformers.ts +4 -0
  522. package/src/core.ts +5 -0
  523. package/src/fetch/core/apiError.ts +65 -0
  524. package/src/fetch/core/fetchJson.ts +129 -0
  525. package/src/fetch/core/index.ts +4 -0
  526. package/src/formula/core/formulaText.ts +96 -0
  527. package/src/formula/core/index.ts +20 -0
  528. package/src/formula/core/normalizeFormula.ts +50 -0
  529. package/src/formula/core/readFormula.ts +211 -0
  530. package/src/formula/ui/CopyableFormula.tsx +51 -0
  531. package/src/formula/ui/FormulaInput.tsx +50 -0
  532. package/src/formula/ui/QuestionFormula.tsx +20 -0
  533. package/src/formula/ui/index.ts +6 -0
  534. package/src/formula.ts +11 -0
  535. package/src/hooks/ui/index.ts +1 -0
  536. package/src/hooks/ui/keyTargets.ts +5 -3
  537. package/src/hooks/ui/useAsync.ts +50 -14
  538. package/src/locales/de.json +37 -0
  539. package/src/locales/en.json +37 -0
  540. package/src/locales/es.json +37 -0
  541. package/src/locales/fr.json +37 -0
  542. package/src/locales/it.json +37 -0
  543. package/src/molecule3d/core/highlight.ts +2 -8
  544. package/src/molecule3d/core/index.ts +1 -0
  545. package/src/molecule3d/core/measurement.ts +47 -0
  546. package/src/molecule3d/ui/drawScene.ts +13 -2
  547. package/src/molecule3d/ui/moleculeViewer3DProps.ts +3 -1
  548. package/src/molecule3d/ui/sceneDrawer.ts +132 -0
  549. package/src/molecule3d/ui/useMoleculeScene.ts +16 -26
  550. package/src/molecule3d/ui/useSharedCamera.ts +1 -3
  551. package/src/moleculesClient/core/index.ts +19 -0
  552. package/src/moleculesClient/core/moleculesClient.ts +175 -0
  553. package/src/moleculesClient/core/moleculesClientApi.ts +120 -0
  554. package/src/moleculesClient/core/moleculesTypes.ts +163 -0
  555. package/src/moleculesClient/core/requestRetry.ts +118 -0
  556. package/src/molstar/core/camera.ts +3 -2
  557. package/src/molstar/core/framing.ts +200 -0
  558. package/src/molstar/core/hover.ts +26 -0
  559. package/src/molstar/core/index.ts +21 -1
  560. package/src/pedagogy/core/answers.ts +94 -0
  561. package/src/pedagogy/core/attempts.ts +205 -0
  562. package/src/pedagogy/core/index.ts +36 -0
  563. package/src/pedagogy/core/progressController.ts +116 -0
  564. package/src/pedagogy/core/seed.ts +177 -0
  565. package/src/pedagogy/core/series.ts +82 -0
  566. package/src/pedagogy/ui/AnswerFields.tsx +63 -0
  567. package/src/pedagogy/ui/ExerciseList.tsx +202 -0
  568. package/src/pedagogy/ui/ExerciseSeries.tsx +250 -0
  569. package/src/pedagogy/ui/QuestionCard.tsx +231 -0
  570. package/src/pedagogy/ui/index.ts +18 -0
  571. package/src/pedagogy/ui/seriesCounts.ts +34 -0
  572. package/src/pedagogy/ui/seriesParts.tsx +127 -0
  573. package/src/pedagogy/ui/useAttemptRecords.ts +16 -0
  574. package/src/periodic/ui/PeriodicTable.tsx +6 -3
  575. package/src/property/core/copyableText.ts +20 -0
  576. package/src/property/core/index.ts +1 -0
  577. package/src/property/ui/PropertyTable.tsx +83 -0
  578. package/src/property/ui/index.ts +2 -0
  579. package/src/router/core/history.ts +61 -7
  580. package/src/router/core/index.ts +3 -2
  581. package/src/router/core/languageRoute.ts +136 -0
  582. package/src/router/core/siteAddresses.ts +38 -0
  583. package/src/router/core/tabRouter.ts +59 -117
  584. package/src/router/core/tabRouterTypes.ts +158 -0
  585. package/src/seo/core/fitDescription.ts +74 -0
  586. package/src/seo/core/index.ts +17 -0
  587. package/src/seo/core/limits.ts +27 -0
  588. package/src/seo/core/pageContent.ts +42 -0
  589. package/src/seo/core/plainDescription.ts +4 -2
  590. package/src/seo/core/routeProblems.ts +1 -7
  591. package/src/seo/core/routeTable.ts +103 -0
  592. package/src/seo/vite/index.ts +2 -0
  593. package/src/seo/vite/prerender.ts +26 -1
  594. package/src/seo/vite/routeTable.ts +79 -0
  595. package/src/server/answerAddresses.ts +92 -0
  596. package/src/server/cardMeta.ts +88 -0
  597. package/src/server/config.ts +125 -0
  598. package/src/server/envNumber.ts +65 -0
  599. package/src/server/healthRoute.ts +42 -0
  600. package/src/server/listenSite.ts +90 -0
  601. package/src/server/mcpServer.ts +14 -0
  602. package/src/server/repositoryVersion.ts +33 -0
  603. package/src/server/routeOptions.ts +26 -0
  604. package/src/server/routeTable.ts +35 -0
  605. package/src/server/siteView.ts +42 -0
  606. package/src/server/spaPages.ts +179 -0
  607. package/src/server/spaSite.ts +216 -0
  608. package/src/server/spaSiteOptions.ts +133 -0
  609. package/src/server/staticSite.ts +65 -35
  610. package/src/server/toolSiteServer.ts +127 -0
  611. package/src/server/trustProxy.ts +32 -0
  612. package/src/server/types.ts +25 -0
  613. package/src/server.ts +40 -0
  614. package/src/share/core/config.ts +45 -2
  615. package/src/share/core/index.ts +4 -0
  616. package/src/share/core/keySetParam.ts +92 -0
  617. package/src/share/core/vocabulary.ts +8 -0
  618. package/src/shell/ui/ShareControl.tsx +150 -0
  619. package/src/shell/ui/ShellFrame.tsx +180 -0
  620. package/src/shell/ui/SiteShell.tsx +297 -0
  621. package/src/shell/ui/index.ts +9 -0
  622. package/src/state/core/index.ts +1 -0
  623. package/src/state/core/legacyEntries.ts +76 -0
  624. package/src/state/core/persistBucket.ts +50 -10
  625. package/src/state/core/persistSignalBucket.ts +52 -0
  626. package/src/state/core/storageEntry.ts +32 -0
  627. package/src/structure/ui/StructureExportButton.tsx +57 -0
  628. package/src/structure/ui/index.ts +4 -0
  629. package/src/structure/ui/useStructureDraft.ts +47 -0
  630. package/src/ui.ts +2 -0
  631. package/src/worker/core/index.ts +1 -0
  632. package/src/worker/core/messages.ts +4 -3
  633. package/src/worker/core/oclResourcesUrl.ts +21 -0
  634. package/src/worker/core/serveWorkerRequests.ts +30 -2
  635. package/src/worker/core/workerChannel.ts +74 -74
  636. package/src/worker/core/workerChannelParts.ts +33 -13
  637. package/src/worker/core/workerChannelTypes.ts +47 -2
  638. package/src/worker/core/workerSlot.ts +181 -0
  639. package/styles/card.css +145 -0
  640. package/styles/chrome.css +248 -0
@@ -0,0 +1,297 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+
3
+ import type { AboutContent } from '../../about/core/about.ts';
4
+ import type { NavItem } from '../../chrome/ui/navItem.ts';
5
+ import type { CitedWork } from '../../citation/core/works.ts';
6
+ import type { SiteId, SiteRecord } from '../../ecosystem/core/sites.ts';
7
+ import { writeRoute } from '../../router/core/history.ts';
8
+ import type { TabRouter } from '../../router/core/tabRouter.ts';
9
+ import { useTabRoute } from '../../router/ui/useTabRoute.ts';
10
+ import type { ShareParamCodecs } from '../../share/core/index.ts';
11
+
12
+ import type { ShareControlProps } from './ShareControl.tsx';
13
+ import { ShellFrame } from './ShellFrame.tsx';
14
+
15
+ /**
16
+ * A slot of the bar: an element, or a function handed whether the bar has run
17
+ * out of room, so a site's own entries fold with the shared ones.
18
+ */
19
+ export type ShellSlot = ReactNode | ((compact: boolean) => ReactNode);
20
+
21
+ /** The site's About: the record, and where it is served. */
22
+ export interface ShellAbout {
23
+ /** What the site says about itself; its works also feed the Cite button. */
24
+ content: AboutContent;
25
+ /**
26
+ * The About address.
27
+ * @default the router's address of the About tab, or `/about` without one
28
+ */
29
+ href?: string;
30
+ /**
31
+ * Whether the About is the page on show, in which case it is what the main
32
+ * area draws.
33
+ * @default whether the router's tab is the About tab, `false` without one
34
+ */
35
+ active?: boolean;
36
+ /**
37
+ * What the site does when the entry is picked, for a page that routes in
38
+ * place.
39
+ * @default a move to the About tab with a router, the plain link without
40
+ */
41
+ onSelect?: () => void;
42
+ /**
43
+ * What the active entry is named by.
44
+ * @default 'about'
45
+ */
46
+ id?: string;
47
+ /**
48
+ * What the entry reads.
49
+ * @default the chrome's own word for it
50
+ */
51
+ label?: string;
52
+ /**
53
+ * What the pointer is told.
54
+ * @default the chrome's own sentence
55
+ */
56
+ title?: string;
57
+ /**
58
+ * The page itself, for a site whose About carries more than its record — a
59
+ * section of its own, a sign-in, a mark.
60
+ * @default `<AboutPage content={content} />`
61
+ */
62
+ page?: ReactNode;
63
+ }
64
+
65
+ /** The strip under the page. */
66
+ export interface ShellFooter {
67
+ /**
68
+ * The site the footer sits on, for a shell given a `site` record rather
69
+ * than a `siteId`.
70
+ * @default the shell's `siteId`, and no footer without one
71
+ */
72
+ siteId?: SiteId;
73
+ /**
74
+ * What introduces the family.
75
+ * @default undefined
76
+ */
77
+ heading?: string;
78
+ /**
79
+ * How much of each sibling is written.
80
+ * @default 'grid'
81
+ */
82
+ layout?: 'grid' | 'row';
83
+ /**
84
+ * One line under the family, set as the footer's note.
85
+ * @default undefined
86
+ */
87
+ note?: ReactNode;
88
+ /**
89
+ * Anything else under the family.
90
+ * @default undefined
91
+ */
92
+ children?: ReactNode;
93
+ }
94
+
95
+ /** What {@link SiteShell} needs. */
96
+ export interface SiteShellProps<
97
+ Codecs extends ShareParamCodecs = Record<string, never>,
98
+ Tab extends string = string,
99
+ > {
100
+ /**
101
+ * The site, named. One of `site` and `siteId` is required.
102
+ * @default undefined
103
+ */
104
+ siteId?: SiteId;
105
+ /**
106
+ * The site, passed rather than named, for one outside the family's registry.
107
+ * @default undefined
108
+ */
109
+ site?: SiteRecord;
110
+ /**
111
+ * The site's own mark, for a site the shared glyphs do not hold.
112
+ * @default the family's mark for the site
113
+ */
114
+ mark?: ReactNode;
115
+ /**
116
+ * Edge of the mark, in pixels.
117
+ * @default 28
118
+ */
119
+ markSize?: number;
120
+ /**
121
+ * The site's router. With it the shell follows the address itself: the
122
+ * page on show is the tab it names, and the About tab is served as the About
123
+ * page.
124
+ * @default undefined — the page says which entry is active
125
+ */
126
+ router?: TabRouter<Tab>;
127
+ /**
128
+ * The tab the About is served at.
129
+ * @default 'about'
130
+ */
131
+ aboutTab?: Tab;
132
+ /** The pages, in the order the bar lists them; About is not one of them. */
133
+ nav: readonly NavItem[];
134
+ /**
135
+ * Which of the pages is on show.
136
+ * @default the router's tab, or none without a router
137
+ */
138
+ activeId?: string;
139
+ /**
140
+ * Where the brand leads.
141
+ * @default '/'
142
+ */
143
+ homeHref?: string;
144
+ /**
145
+ * What the site does when the brand is picked.
146
+ * @default undefined
147
+ */
148
+ onHome?: () => void;
149
+ /**
150
+ * Draws one page the site's own way.
151
+ * @default undefined
152
+ */
153
+ renderNavItem?: (item: NavItem, isActive: boolean) => ReactNode;
154
+ /**
155
+ * The part a link hides the pages with; the bar then lists none.
156
+ * @default 'tabs'
157
+ */
158
+ navPart?: string;
159
+ /**
160
+ * How wide the bar, the page and the footer run, all three alike.
161
+ * @default 'page'
162
+ */
163
+ width?: 'page' | 'full';
164
+ /**
165
+ * Whether the page is framed in another site: no bar, no footer, and the
166
+ * frame as the margin.
167
+ * @default false
168
+ */
169
+ embedded?: boolean;
170
+ /**
171
+ * The parts the link switches off, provided to every `PagePart` below.
172
+ * @default undefined — no provider; the page brings its own
173
+ */
174
+ hidden?: readonly string[];
175
+ /**
176
+ * The About entry and page; `false` leaves both out.
177
+ * @default false
178
+ */
179
+ about?: ShellAbout | false;
180
+ /**
181
+ * The works the Cite button offers; `false` leaves it out.
182
+ * @default the About's works, and no button when it has none
183
+ */
184
+ cite?: readonly CitedWork[] | false;
185
+ /**
186
+ * Whether the Tools menu of the family is in the bar.
187
+ * @default true
188
+ */
189
+ ecosystem?: boolean;
190
+ /**
191
+ * Entries between About and Cite — an API link, a version.
192
+ * @default undefined
193
+ */
194
+ actionsAfterAbout?: ShellSlot;
195
+ /**
196
+ * Entries between Cite and Tools — a feedback form, a specification.
197
+ * @default undefined
198
+ */
199
+ actionsAfterCite?: ShellSlot;
200
+ /**
201
+ * Entries after Tools — a unit picker, an admin action.
202
+ * @default undefined
203
+ */
204
+ actions?: ShellSlot;
205
+ /**
206
+ * The language switcher, after the site's own entries.
207
+ * @default undefined
208
+ */
209
+ language?: ShellSlot;
210
+ /**
211
+ * Who is signed in, at the right end.
212
+ * @default undefined
213
+ */
214
+ account?: ReactNode;
215
+ /**
216
+ * The Share entry: what `ShareControl` is given, the shell passing it the
217
+ * site and the compact state, or a control of the site's own.
218
+ * @default undefined — no Share entry
219
+ */
220
+ share?: ShareControlProps<Codecs> | ReactElement;
221
+ /**
222
+ * The contact form of the Contact entry, or `false` to leave it out.
223
+ * @default the family's form
224
+ */
225
+ contact?: string | false;
226
+ /**
227
+ * What sits between the bar and the page — a tagline, a banner — dropped
228
+ * with the bar when the page is framed.
229
+ * @default undefined
230
+ */
231
+ belowHeader?: ReactNode;
232
+ /**
233
+ * Classes the main area carries beside the shell's own.
234
+ * @default undefined
235
+ */
236
+ mainClassName?: string;
237
+ /**
238
+ * `data-testid` of the main area.
239
+ * @default undefined
240
+ */
241
+ mainTestId?: string;
242
+ /**
243
+ * The strip under the page, or `false` for none on this page.
244
+ * @default the family's links alone
245
+ */
246
+ footer?: ShellFooter | false;
247
+ /** The page the address names. */
248
+ children: ReactNode;
249
+ }
250
+
251
+ /**
252
+ * The chrome every site of the family carries, around its page: the theme,
253
+ * the bar with About · Cite · Tools · Contact · Share at its right, the page,
254
+ * and the footer linking every sibling. A framed page gets the page alone.
255
+ *
256
+ * Everything the bar holds is the shared components, in the family's order; a
257
+ * site fills the slots between them and never re-orders them. With a router,
258
+ * the shell also follows the address: it marks the tab on show and serves the
259
+ * About tab as the shared About page.
260
+ * @param props - See {@link SiteShellProps}.
261
+ * @returns The page in its chrome.
262
+ */
263
+ export function SiteShell<
264
+ Codecs extends ShareParamCodecs = Record<string, never>,
265
+ Tab extends string = string,
266
+ >(props: SiteShellProps<Codecs, Tab>): ReactElement {
267
+ const { router } = props;
268
+ if (router === undefined) return <ShellFrame {...props} />;
269
+ return <RoutedShell {...props} router={router} />;
270
+ }
271
+
272
+ function RoutedShell<Codecs extends ShareParamCodecs, Tab extends string>(
273
+ props: SiteShellProps<Codecs, Tab> & { router: TabRouter<Tab> },
274
+ ): ReactElement {
275
+ const { router, aboutTab = 'about' as Tab, about, activeId } = props;
276
+ const route = useTabRoute(router);
277
+ const routedAbout: ShellAbout | false =
278
+ about === undefined || about === false
279
+ ? false
280
+ : {
281
+ ...about,
282
+ href: about.href ?? router.format({ tab: aboutTab }),
283
+ active: about.active ?? route.tab === aboutTab,
284
+ onSelect:
285
+ about.onSelect ??
286
+ (() => {
287
+ writeRoute(router, { tab: aboutTab });
288
+ }),
289
+ };
290
+ return (
291
+ <ShellFrame
292
+ {...props}
293
+ about={routedAbout}
294
+ activeId={activeId ?? route.tab}
295
+ />
296
+ );
297
+ }
@@ -0,0 +1,9 @@
1
+ export type { ShareControlProps } from './ShareControl.tsx';
2
+ export { ShareControl } from './ShareControl.tsx';
3
+ export type {
4
+ ShellAbout,
5
+ ShellFooter,
6
+ ShellSlot,
7
+ SiteShellProps,
8
+ } from './SiteShell.tsx';
9
+ export { SiteShell } from './SiteShell.tsx';
@@ -1,3 +1,4 @@
1
+ export type { LegacyStorageKey } from './legacyEntries.ts';
1
2
  export type {
2
3
  BucketRead,
3
4
  PersistBucketOptions,
@@ -0,0 +1,76 @@
1
+ import {
2
+ readStorageText,
3
+ removeStorageEntry,
4
+ writeStorageEntry,
5
+ writeStorageText,
6
+ } from './storageEntry.ts';
7
+
8
+ /**
9
+ * An entry a bucket was kept under before it took its versioned key: the full
10
+ * storage key, as written, or the key with a function turning its payload into
11
+ * the bucket's current shape.
12
+ */
13
+ export type LegacyStorageKey =
14
+ | string
15
+ | {
16
+ /** The full storage key, e.g. `storage` or `mixonat:preferences`. */
17
+ key: string;
18
+ /**
19
+ * Turn the old payload, as `JSON.parse` read it, into what the bucket
20
+ * stores now. Answering `undefined`, or throwing, adopts nothing.
21
+ */
22
+ migrate: (stored: unknown) => unknown;
23
+ };
24
+
25
+ /**
26
+ * Carry a returning visitor's entry over to the versioned key a bucket now
27
+ * uses, once.
28
+ *
29
+ * The first legacy key holding something is copied — as it is, or through its
30
+ * `migrate` — and only while the versioned entry does not exist, so it never
31
+ * overwrites what the bucket has written since. With `forget`, every legacy
32
+ * entry found is removed afterwards, adopted or not, so a bucket cleared later
33
+ * is not filled again from the old key on the next visit. Best effort, like
34
+ * every access to the store: one that cannot be reached adopts nothing.
35
+ * @param storageKey - The versioned key the bucket occupies.
36
+ * @param legacyKeys - The older entries, the preferred one first.
37
+ * @param forget - Whether to remove the legacy entries once read.
38
+ */
39
+ export function adoptLegacyEntries(
40
+ storageKey: string,
41
+ legacyKeys: readonly LegacyStorageKey[],
42
+ forget: boolean,
43
+ ): void {
44
+ if (legacyKeys.length === 0) return;
45
+ let adopted = readStorageText(storageKey) !== null;
46
+ for (const legacy of legacyKeys) {
47
+ const key = typeof legacy === 'string' ? legacy : legacy.key;
48
+ if (key === storageKey) continue;
49
+ const text = readStorageText(key);
50
+ if (text === null) continue;
51
+ if (!adopted) {
52
+ adopted =
53
+ typeof legacy === 'string'
54
+ ? writeStorageText(storageKey, text)
55
+ : writeMigrated(storageKey, text, legacy.migrate);
56
+ }
57
+ if (forget) removeStorageEntry(key);
58
+ }
59
+ }
60
+
61
+ function writeMigrated(
62
+ storageKey: string,
63
+ text: string,
64
+ migrate: (stored: unknown) => unknown,
65
+ ): boolean {
66
+ let value: unknown;
67
+ try {
68
+ value = migrate(JSON.parse(text));
69
+ } catch {
70
+ // A payload nobody can read any more is left to the defaults.
71
+ return false;
72
+ }
73
+ if (value === undefined) return false;
74
+ writeStorageEntry(storageKey, value);
75
+ return readStorageText(storageKey) !== null;
76
+ }
@@ -1,3 +1,5 @@
1
+ import type { LegacyStorageKey } from './legacyEntries.ts';
2
+ import { adoptLegacyEntries } from './legacyEntries.ts';
1
3
  import { isPlainRecord, mergeStored } from './mergeStored.ts';
2
4
  import {
3
5
  readStorageEntry,
@@ -16,30 +18,46 @@ import {
16
18
  * quota is full still gets a working site, with their preferences lasting only
17
19
  * as long as the tab.
18
20
  * @param options - See {@link PersistBucketOptions}.
19
- * @returns The three ways to use the bucket: read it, write it, forget it.
21
+ * @returns The ways to use the bucket: read it, write it, forget it, and
22
+ * hear another tab write it.
20
23
  */
21
24
  export function persistBucket<T extends object>(
22
25
  options: PersistBucketOptions<T>,
23
26
  ): PersistedBucket<T> {
24
27
  const { key, version = 1, defaults, onQuotaExceeded } = options;
28
+ const { legacyKeys = [], forgetLegacyKeys = false } = options;
25
29
  const storageKey = versionedStorageKey(key, version);
30
+ adoptLegacyEntries(storageKey, legacyKeys, forgetLegacyKeys);
31
+
32
+ function read(): BucketRead<T> {
33
+ const stored = readStorageEntry(storageKey);
34
+ const usable = isPlainRecord(stored) ? stored : undefined;
35
+ return {
36
+ value: mergeStored(defaults, usable),
37
+ firstRun: usable === undefined,
38
+ };
39
+ }
26
40
 
27
41
  return {
28
42
  storageKey,
29
- read: () => {
30
- const stored = readStorageEntry(storageKey);
31
- const usable = isPlainRecord(stored) ? stored : undefined;
32
- return {
33
- value: mergeStored(defaults, usable),
34
- firstRun: usable === undefined,
35
- };
36
- },
43
+ read,
37
44
  write: (value: T) => {
38
45
  writeStorageEntry(storageKey, value, onQuotaExceeded);
39
46
  },
40
47
  clear: () => {
41
48
  removeStorageEntry(storageKey);
42
49
  },
50
+ subscribe: (listener) => {
51
+ function handleStorage(event: Event): void {
52
+ const change = event as { key?: unknown; newValue?: unknown };
53
+ if (change.key !== storageKey || change.newValue === null) return;
54
+ listener(read());
55
+ }
56
+ globalThis.addEventListener?.('storage', handleStorage);
57
+ return () => {
58
+ globalThis.removeEventListener?.('storage', handleStorage);
59
+ };
60
+ },
43
61
  };
44
62
  }
45
63
 
@@ -70,9 +88,23 @@ export interface PersistBucketOptions<T extends object> {
70
88
  * @default undefined
71
89
  */
72
90
  onQuotaExceeded?: (error: unknown) => void;
91
+ /**
92
+ * The entries the bucket was kept under before this key: an unversioned
93
+ * one, another site's, or a shape that needs a `migrate`. The first holding
94
+ * something is copied over once, while the versioned entry does not exist.
95
+ * @default []
96
+ */
97
+ legacyKeys?: readonly LegacyStorageKey[];
98
+ /**
99
+ * Remove every legacy entry found once it has been read, so a bucket
100
+ * cleared later is not filled again from the old key. Left off, the old
101
+ * entries stay where they are.
102
+ * @default false
103
+ */
104
+ forgetLegacyKeys?: boolean;
73
105
  }
74
106
 
75
- /** The three ways a page uses its bucket. */
107
+ /** The ways a page uses its bucket. */
76
108
  export interface PersistedBucket<T extends object> {
77
109
  /** The versioned key the bucket occupies, e.g. `smiles:exercises:v1`. */
78
110
  readonly storageKey: string;
@@ -82,6 +114,14 @@ export interface PersistedBucket<T extends object> {
82
114
  write: (value: T) => void;
83
115
  /** Forget the bucket, leaving whatever the page holds in memory untouched. */
84
116
  clear: () => void;
117
+ /**
118
+ * Hear another tab of the same site store the bucket. The tab writing never
119
+ * hears its own write, and a removal is not news: the listener is handed
120
+ * what is stored now, merged over the defaults.
121
+ * @param listener - Called with the fresh read after each write elsewhere.
122
+ * @returns The function that stops listening.
123
+ */
124
+ subscribe: (listener: (read: BucketRead<T>) => void) => () => void;
85
125
  }
86
126
 
87
127
  /** What one read of a bucket found. */
@@ -1,5 +1,7 @@
1
+ import type { LegacyStorageKey } from './legacyEntries.ts';
1
2
  import { isPlainRecord } from './mergeStored.ts';
2
3
  import { persistBucket } from './persistBucket.ts';
4
+ import { readStorageText } from './storageEntry.ts';
3
5
 
4
6
  /**
5
7
  * Keep a tree of signals in `localStorage`, under one versioned key.
@@ -19,6 +21,12 @@ import { persistBucket } from './persistBucket.ts';
19
21
  * the tracking is always done by the copy of the library that made the
20
22
  * signals. A member that is neither a signal nor a plain object is ignored.
21
23
  * Never put a `computed()` in a bucket: it cannot be written back.
24
+ *
25
+ * With `syncAcrossTabs`, every tab follows the entry: a tab opened before
26
+ * another one stored its work would otherwise write its stale copy over it. A
27
+ * write that would store what is already there is skipped, so two tabs cannot
28
+ * echo each other, and nothing is written while another tab's copy is being
29
+ * taken on.
22
30
  * @param options - See {@link PersistSignalBucketOptions}.
23
31
  * @returns The same bucket, rehydrated, so it can be exported directly.
24
32
  */
@@ -26,26 +34,51 @@ export function persistSignalBucket<TBucket extends object>(
26
34
  options: PersistSignalBucketOptions<TBucket>,
27
35
  ): TBucket {
28
36
  const { key, version, bucket, effect, onQuotaExceeded } = options;
37
+ const { legacyKeys, forgetLegacyKeys, syncAcrossTabs = false } = options;
29
38
  const stored = persistBucket({
30
39
  key,
31
40
  version,
32
41
  defaults: snapshotBucket(bucket),
33
42
  onQuotaExceeded,
43
+ legacyKeys,
44
+ forgetLegacyKeys,
34
45
  });
35
46
 
36
47
  const { value, firstRun } = stored.read();
37
48
  if (!firstRun) hydrateBucket(bucket, value);
38
49
 
39
50
  let subscribed = false;
51
+ let adopting = false;
40
52
  effect(() => {
41
53
  const snapshot = snapshotBucket(bucket);
42
54
  if (!subscribed) {
43
55
  subscribed = true;
44
56
  return;
45
57
  }
58
+ if (adopting) return;
59
+ if (
60
+ syncAcrossTabs !== false &&
61
+ readStorageText(stored.storageKey) === JSON.stringify(snapshot)
62
+ ) {
63
+ return;
64
+ }
46
65
  stored.write(snapshot);
47
66
  });
48
67
 
68
+ if (syncAcrossTabs !== false) {
69
+ stored.subscribe((read) => {
70
+ if (typeof syncAcrossTabs === 'function' && !syncAcrossTabs(bucket)) {
71
+ return;
72
+ }
73
+ adopting = true;
74
+ try {
75
+ hydrateBucket(bucket, read.value);
76
+ } finally {
77
+ adopting = false;
78
+ }
79
+ });
80
+ }
81
+
49
82
  return bucket;
50
83
  }
51
84
 
@@ -77,6 +110,25 @@ export interface PersistSignalBucketOptions<TBucket extends object> {
77
110
  * @default undefined
78
111
  */
79
112
  onQuotaExceeded?: (error: unknown) => void;
113
+ /**
114
+ * The entries the bucket was kept under before this key, the preferred one
115
+ * first; see `persistBucket`.
116
+ * @default []
117
+ */
118
+ legacyKeys?: readonly LegacyStorageKey[];
119
+ /**
120
+ * Remove every legacy entry found once it has been read.
121
+ * @default false
122
+ */
123
+ forgetLegacyKeys?: boolean;
124
+ /**
125
+ * Take on what another tab stores, and skip a write that would store what is
126
+ * already there. A function decides each time, handed the bucket as this tab
127
+ * holds it: a bucket of work in progress keeps its own while it has some,
128
+ * rather than two tabs overwriting each other in turn.
129
+ * @default false
130
+ */
131
+ syncAcrossTabs?: boolean | ((bucket: TBucket) => boolean);
80
132
  }
81
133
 
82
134
  interface SignalLeaf {
@@ -81,6 +81,38 @@ export function removeStorageEntry(storageKey: string): void {
81
81
  }
82
82
  }
83
83
 
84
+ /**
85
+ * Read one `localStorage` entry as the text it was stored as, so two copies of
86
+ * a payload can be compared without parsing either.
87
+ * @param storageKey - The full key.
88
+ * @returns The stored text, or `null` when there is none or the store cannot
89
+ * be reached.
90
+ */
91
+ export function readStorageText(storageKey: string): string | null {
92
+ try {
93
+ return globalThis.localStorage?.getItem(storageKey) ?? null;
94
+ } catch {
95
+ return null;
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Write one `localStorage` entry as text, exactly as given. Best effort.
101
+ * @param storageKey - The full key.
102
+ * @param text - What to store.
103
+ * @returns Whether the store took it.
104
+ */
105
+ export function writeStorageText(storageKey: string, text: string): boolean {
106
+ try {
107
+ const storage = globalThis.localStorage as Storage | undefined;
108
+ if (storage === undefined) return false;
109
+ storage.setItem(storageKey, text);
110
+ return true;
111
+ } catch {
112
+ return false;
113
+ }
114
+ }
115
+
84
116
  function isQuotaExceeded(error: unknown): boolean {
85
117
  if (typeof error !== 'object' || error === null) return false;
86
118
  const { name, code } = error as { name?: unknown; code?: unknown };
@@ -0,0 +1,57 @@
1
+ import type { ReactElement } from 'react';
2
+ import { useState } from 'react';
3
+
4
+ import { useChromeT } from '../../i18n/ui/useT.ts';
5
+ import { OverlayIconButton } from '../../overlay/ui/OverlayIconButton.tsx';
6
+
7
+ import { StructureExportDialog } from './StructureExportDialog.tsx';
8
+ import type { StructureExportPanelProps } from './StructureExportPanel.tsx';
9
+
10
+ /** What {@link StructureExportButton} hands over. */
11
+ export interface StructureExportButtonProps extends StructureExportPanelProps {
12
+ /**
13
+ * What the glyph is called, for the pointer and for a screen reader.
14
+ * @default the chrome's own line, `Copy or save the structure: SMILES,
15
+ * molfile`
16
+ */
17
+ label?: string;
18
+ /**
19
+ * Value of the `data-testid` attribute of the glyph.
20
+ * @default 'card-structure'
21
+ */
22
+ testId?: string;
23
+ }
24
+
25
+ /**
26
+ * The glyph beside a figure that hands its one structure over: as a SMILES,
27
+ * a molfile or an idCode, each copied with a click, or as a picture — the
28
+ * export dialog, the one the chat opens on its own molecule cards. It is drawn
29
+ * like the figure's other glyphs, so it sits in the `tools` of a `CardFigure`
30
+ * or of any overlay bar.
31
+ * @param props - The structure, the name of its files, and the glyph's name.
32
+ * @returns The glyph; the dialog is drawn over the page while it is open.
33
+ */
34
+ export function StructureExportButton(
35
+ props: StructureExportButtonProps,
36
+ ): ReactElement {
37
+ const { label, testId = 'card-structure', ...structure } = props;
38
+ const t = useChromeT();
39
+ const [isOpen, setIsOpen] = useState(false);
40
+ return (
41
+ <>
42
+ <OverlayIconButton
43
+ icon="export"
44
+ label={label ?? t('structure.export.glyph')}
45
+ active={isOpen}
46
+ opensMenu
47
+ testId={testId}
48
+ onClick={() => setIsOpen(true)}
49
+ />
50
+ <StructureExportDialog
51
+ {...structure}
52
+ isOpen={isOpen}
53
+ onClose={() => setIsOpen(false)}
54
+ />
55
+ </>
56
+ );
57
+ }
@@ -25,6 +25,10 @@ export type { StructureEditorHelpProps } from './StructureEditorHelp.tsx';
25
25
  export { StructureEditorHelp } from './StructureEditorHelp.tsx';
26
26
  export type { StructureExportDialogProps } from './StructureExportDialog.tsx';
27
27
  export { StructureExportDialog } from './StructureExportDialog.tsx';
28
+ export type { StructureExportButtonProps } from './StructureExportButton.tsx';
29
+ export { StructureExportButton } from './StructureExportButton.tsx';
28
30
  export type { StructureExportPanelProps } from './StructureExportPanel.tsx';
29
31
  export type { ToolbarFloorOptions } from './useToolbarFloor.ts';
30
32
  export { useToolbarFloor } from './useToolbarFloor.ts';
33
+ export type { StructureDraft } from './useStructureDraft.ts';
34
+ export { useStructureDraft } from './useStructureDraft.ts';