react-cheminfo 0.69.0 → 0.71.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 (616) hide show
  1. package/README.md +70 -2
  2. package/lib/about/core/providers.d.ts +6 -0
  3. package/lib/about/core/providers.d.ts.map +1 -1
  4. package/lib/about/core/providers.js +7 -0
  5. package/lib/about/core/providers.js.map +1 -1
  6. package/lib/about/ui/AboutProvidedBy.js +34 -0
  7. package/lib/about/ui/AboutProvidedBy.js.map +1 -1
  8. package/lib/chart/ui/useChartPointer.d.ts +9 -1
  9. package/lib/chart/ui/useChartPointer.d.ts.map +1 -1
  10. package/lib/chart/ui/useChartPointer.js +11 -3
  11. package/lib/chart/ui/useChartPointer.js.map +1 -1
  12. package/lib/credits/core/credits.d.ts +41 -0
  13. package/lib/credits/core/credits.d.ts.map +1 -1
  14. package/lib/credits/core/credits.js +50 -0
  15. package/lib/credits/core/credits.js.map +1 -1
  16. package/lib/download/core/drawingMarkup.d.ts +8 -1
  17. package/lib/download/core/drawingMarkup.d.ts.map +1 -1
  18. package/lib/download/core/drawingMarkup.js +13 -1
  19. package/lib/download/core/drawingMarkup.js.map +1 -1
  20. package/lib/download/core/figurePng.d.ts +14 -0
  21. package/lib/download/core/figurePng.d.ts.map +1 -1
  22. package/lib/download/core/figurePng.js +21 -6
  23. package/lib/download/core/figurePng.js.map +1 -1
  24. package/lib/download/core/figureSvg.d.ts.map +1 -1
  25. package/lib/download/core/figureSvg.js +5 -3
  26. package/lib/download/core/figureSvg.js.map +1 -1
  27. package/lib/download/core/figureTarget.d.ts +13 -0
  28. package/lib/download/core/figureTarget.d.ts.map +1 -1
  29. package/lib/download/core/figureTarget.js +25 -5
  30. package/lib/download/core/figureTarget.js.map +1 -1
  31. package/lib/download/core/svgBounds.d.ts +15 -0
  32. package/lib/download/core/svgBounds.d.ts.map +1 -1
  33. package/lib/download/core/svgBounds.js +20 -0
  34. package/lib/download/core/svgBounds.js.map +1 -1
  35. package/lib/download/core/svgToPng.d.ts.map +1 -1
  36. package/lib/download/core/svgToPng.js +4 -2
  37. package/lib/download/core/svgToPng.js.map +1 -1
  38. package/lib/format/core/relativeTime.d.ts +8 -3
  39. package/lib/format/core/relativeTime.d.ts.map +1 -1
  40. package/lib/format/core/relativeTime.js +19 -7
  41. package/lib/format/core/relativeTime.js.map +1 -1
  42. package/lib/host/core/connectHost.d.ts +25 -34
  43. package/lib/host/core/connectHost.d.ts.map +1 -1
  44. package/lib/host/core/connectHost.js +43 -89
  45. package/lib/host/core/connectHost.js.map +1 -1
  46. package/lib/host/core/hostOutputs.d.ts +58 -0
  47. package/lib/host/core/hostOutputs.d.ts.map +1 -0
  48. package/lib/host/core/hostOutputs.js +151 -0
  49. package/lib/host/core/hostOutputs.js.map +1 -0
  50. package/lib/host/core/index.d.ts +9 -3
  51. package/lib/host/core/index.d.ts.map +1 -1
  52. package/lib/host/core/index.js +4 -1
  53. package/lib/host/core/index.js.map +1 -1
  54. package/lib/host/core/irKinds.d.ts +124 -0
  55. package/lib/host/core/irKinds.d.ts.map +1 -0
  56. package/lib/host/core/irKinds.js +46 -0
  57. package/lib/host/core/irKinds.js.map +1 -0
  58. package/lib/host/core/kinds.d.ts +13 -5
  59. package/lib/host/core/kinds.d.ts.map +1 -1
  60. package/lib/host/core/kinds.js +11 -5
  61. package/lib/host/core/kinds.js.map +1 -1
  62. package/lib/host/core/protocol.d.ts +50 -7
  63. package/lib/host/core/protocol.d.ts.map +1 -1
  64. package/lib/host/core/protocol.js +10 -6
  65. package/lib/host/core/protocol.js.map +1 -1
  66. package/lib/host/core/selectInputs.d.ts +37 -0
  67. package/lib/host/core/selectInputs.d.ts.map +1 -0
  68. package/lib/host/core/selectInputs.js +110 -0
  69. package/lib/host/core/selectInputs.js.map +1 -0
  70. package/lib/host/testing/sciPeaks.d.ts +31 -0
  71. package/lib/host/testing/sciPeaks.d.ts.map +1 -1
  72. package/lib/host/testing/sciPeaks.js +73 -0
  73. package/lib/host/testing/sciPeaks.js.map +1 -1
  74. package/lib/host/testing/standInHost.d.ts +9 -1
  75. package/lib/host/testing/standInHost.d.ts.map +1 -1
  76. package/lib/host/testing/standInHost.js +19 -1
  77. package/lib/host/testing/standInHost.js.map +1 -1
  78. package/lib/host/ui/useHostConnection.d.ts +13 -5
  79. package/lib/host/ui/useHostConnection.d.ts.map +1 -1
  80. package/lib/host/ui/useHostConnection.js +4 -3
  81. package/lib/host/ui/useHostConnection.js.map +1 -1
  82. package/lib/host-testing.d.ts +2 -2
  83. package/lib/host-testing.d.ts.map +1 -1
  84. package/lib/host-testing.js +2 -2
  85. package/lib/host-testing.js.map +1 -1
  86. package/lib/i18n/core/chromeCatalog.d.ts +1 -1
  87. package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
  88. package/lib/ir/core/handPicking.d.ts +58 -0
  89. package/lib/ir/core/handPicking.d.ts.map +1 -0
  90. package/lib/ir/core/handPicking.js +130 -0
  91. package/lib/ir/core/handPicking.js.map +1 -0
  92. package/lib/ir/core/index.d.ts +3 -0
  93. package/lib/ir/core/index.d.ts.map +1 -1
  94. package/lib/ir/core/index.js +3 -0
  95. package/lib/ir/core/index.js.map +1 -1
  96. package/lib/ir/core/irBandState.d.ts +57 -0
  97. package/lib/ir/core/irBandState.d.ts.map +1 -0
  98. package/lib/ir/core/irBandState.js +119 -0
  99. package/lib/ir/core/irBandState.js.map +1 -0
  100. package/lib/ir/core/irCommands.d.ts +11 -0
  101. package/lib/ir/core/irCommands.d.ts.map +1 -1
  102. package/lib/ir/core/irCommands.js +6 -0
  103. package/lib/ir/core/irCommands.js.map +1 -1
  104. package/lib/ir/core/irPeaks.d.ts +28 -0
  105. package/lib/ir/core/irPeaks.d.ts.map +1 -0
  106. package/lib/ir/core/irPeaks.js +66 -0
  107. package/lib/ir/core/irPeaks.js.map +1 -0
  108. package/lib/ir/core/irReducer.d.ts +8 -0
  109. package/lib/ir/core/irReducer.d.ts.map +1 -1
  110. package/lib/ir/core/irReducer.js +15 -32
  111. package/lib/ir/core/irReducer.js.map +1 -1
  112. package/lib/ir/core/irSpectrum.d.ts +15 -0
  113. package/lib/ir/core/irSpectrum.d.ts.map +1 -1
  114. package/lib/ir/core/irSpectrum.js.map +1 -1
  115. package/lib/ir/core/irState.d.ts +9 -6
  116. package/lib/ir/core/irState.d.ts.map +1 -1
  117. package/lib/ir/core/irState.js +10 -6
  118. package/lib/ir/core/irState.js.map +1 -1
  119. package/lib/ir/core/pickBands.d.ts +14 -0
  120. package/lib/ir/core/pickBands.d.ts.map +1 -1
  121. package/lib/ir/core/pickBands.js +39 -33
  122. package/lib/ir/core/pickBands.js.map +1 -1
  123. package/lib/ir/core/ramanBands.d.ts +9 -1
  124. package/lib/ir/core/ramanBands.d.ts.map +1 -1
  125. package/lib/ir/core/ramanBands.js +2 -2
  126. package/lib/ir/core/ramanBands.js.map +1 -1
  127. package/lib/ir/core/spectrumBands.d.ts +46 -0
  128. package/lib/ir/core/spectrumBands.d.ts.map +1 -0
  129. package/lib/ir/core/spectrumBands.js +98 -0
  130. package/lib/ir/core/spectrumBands.js.map +1 -0
  131. package/lib/ir/ui/BandRow.d.ts +5 -0
  132. package/lib/ir/ui/BandRow.d.ts.map +1 -1
  133. package/lib/ir/ui/BandRow.js +4 -3
  134. package/lib/ir/ui/BandRow.js.map +1 -1
  135. package/lib/ir/ui/BandsPanel.d.ts +5 -0
  136. package/lib/ir/ui/BandsPanel.d.ts.map +1 -1
  137. package/lib/ir/ui/BandsPanel.js +36 -16
  138. package/lib/ir/ui/BandsPanel.js.map +1 -1
  139. package/lib/ir/ui/BandsToolbar.d.ts +9 -0
  140. package/lib/ir/ui/BandsToolbar.d.ts.map +1 -0
  141. package/lib/ir/ui/BandsToolbar.js +61 -0
  142. package/lib/ir/ui/BandsToolbar.js.map +1 -0
  143. package/lib/ir/ui/IrCanvas.d.ts +2 -1
  144. package/lib/ir/ui/IrCanvas.d.ts.map +1 -1
  145. package/lib/ir/ui/IrCanvas.js +19 -5
  146. package/lib/ir/ui/IrCanvas.js.map +1 -1
  147. package/lib/ir/ui/IrChart.d.ts.map +1 -1
  148. package/lib/ir/ui/IrChart.js +8 -1
  149. package/lib/ir/ui/IrChart.js.map +1 -1
  150. package/lib/ir/ui/IrDocumentationDialog.js +1 -1
  151. package/lib/ir/ui/IrDocumentationDialog.js.map +1 -1
  152. package/lib/ir/ui/IrEditor.d.ts +4 -2
  153. package/lib/ir/ui/IrEditor.d.ts.map +1 -1
  154. package/lib/ir/ui/IrEditor.js.map +1 -1
  155. package/lib/ir/ui/IrShell.d.ts.map +1 -1
  156. package/lib/ir/ui/IrShell.js +6 -0
  157. package/lib/ir/ui/IrShell.js.map +1 -1
  158. package/lib/ir/ui/IrStatusBar.d.ts.map +1 -1
  159. package/lib/ir/ui/IrStatusBar.js +1 -1
  160. package/lib/ir/ui/IrStatusBar.js.map +1 -1
  161. package/lib/ir/ui/IrToolbar.d.ts +4 -3
  162. package/lib/ir/ui/IrToolbar.d.ts.map +1 -1
  163. package/lib/ir/ui/IrToolbar.js +5 -4
  164. package/lib/ir/ui/IrToolbar.js.map +1 -1
  165. package/lib/ir/ui/VibrationalEditor.d.ts +2 -1
  166. package/lib/ir/ui/VibrationalEditor.d.ts.map +1 -1
  167. package/lib/ir/ui/VibrationalEditor.js.map +1 -1
  168. package/lib/ir/ui/irActions.d.ts +5 -0
  169. package/lib/ir/ui/irActions.d.ts.map +1 -1
  170. package/lib/ir/ui/irActions.js +6 -0
  171. package/lib/ir/ui/irActions.js.map +1 -1
  172. package/lib/ir/ui/irChartProps.d.ts +4 -1
  173. package/lib/ir/ui/irChartProps.d.ts.map +1 -1
  174. package/lib/ir/ui/useIrEditor.d.ts +5 -11
  175. package/lib/ir/ui/useIrEditor.d.ts.map +1 -1
  176. package/lib/ir/ui/useIrEditor.js +17 -18
  177. package/lib/ir/ui/useIrEditor.js.map +1 -1
  178. package/lib/locales/de.json +63 -0
  179. package/lib/locales/en.json +63 -0
  180. package/lib/locales/es.json +63 -0
  181. package/lib/locales/fr.json +63 -0
  182. package/lib/locales/it.json +63 -0
  183. package/lib/mass/core/analyseSpectrum.d.ts +85 -0
  184. package/lib/mass/core/analyseSpectrum.d.ts.map +1 -0
  185. package/lib/mass/core/analyseSpectrum.js +101 -0
  186. package/lib/mass/core/analyseSpectrum.js.map +1 -0
  187. package/lib/mass/core/ascendingTrace.d.ts +24 -0
  188. package/lib/mass/core/ascendingTrace.d.ts.map +1 -0
  189. package/lib/mass/core/ascendingTrace.js +57 -0
  190. package/lib/mass/core/ascendingTrace.js.map +1 -0
  191. package/lib/mass/core/centroidPeaks.d.ts +77 -0
  192. package/lib/mass/core/centroidPeaks.d.ts.map +1 -0
  193. package/lib/mass/core/centroidPeaks.js +62 -0
  194. package/lib/mass/core/centroidPeaks.js.map +1 -0
  195. package/lib/mass/core/detectMassFormat.d.ts +24 -0
  196. package/lib/mass/core/detectMassFormat.d.ts.map +1 -0
  197. package/lib/mass/core/detectMassFormat.js +105 -0
  198. package/lib/mass/core/detectMassFormat.js.map +1 -0
  199. package/lib/mass/core/downloadSpectra.d.ts +24 -0
  200. package/lib/mass/core/downloadSpectra.d.ts.map +1 -0
  201. package/lib/mass/core/downloadSpectra.js +35 -0
  202. package/lib/mass/core/downloadSpectra.js.map +1 -0
  203. package/lib/mass/core/fromJcamp.d.ts +46 -0
  204. package/lib/mass/core/fromJcamp.d.ts.map +1 -0
  205. package/lib/mass/core/fromJcamp.js +123 -0
  206. package/lib/mass/core/fromJcamp.js.map +1 -0
  207. package/lib/mass/core/fromText.d.ts +30 -0
  208. package/lib/mass/core/fromText.d.ts.map +1 -0
  209. package/lib/mass/core/fromText.js +39 -0
  210. package/lib/mass/core/fromText.js.map +1 -0
  211. package/lib/mass/core/index.d.ts +70 -0
  212. package/lib/mass/core/index.d.ts.map +1 -0
  213. package/lib/mass/core/index.js +42 -0
  214. package/lib/mass/core/index.js.map +1 -0
  215. package/lib/mass/core/jcampTechnique.d.ts +38 -0
  216. package/lib/mass/core/jcampTechnique.d.ts.map +1 -0
  217. package/lib/mass/core/jcampTechnique.js +70 -0
  218. package/lib/mass/core/jcampTechnique.js.map +1 -0
  219. package/lib/mass/core/labelStackBox.d.ts +49 -0
  220. package/lib/mass/core/labelStackBox.d.ts.map +1 -0
  221. package/lib/mass/core/labelStackBox.js +44 -0
  222. package/lib/mass/core/labelStackBox.js.map +1 -0
  223. package/lib/mass/core/labelledPeaks.d.ts +79 -0
  224. package/lib/mass/core/labelledPeaks.d.ts.map +1 -0
  225. package/lib/mass/core/labelledPeaks.js +74 -0
  226. package/lib/mass/core/labelledPeaks.js.map +1 -0
  227. package/lib/mass/core/loadMassSpectra.d.ts +57 -0
  228. package/lib/mass/core/loadMassSpectra.d.ts.map +1 -0
  229. package/lib/mass/core/loadMassSpectra.js +45 -0
  230. package/lib/mass/core/loadMassSpectra.js.map +1 -0
  231. package/lib/mass/core/loadedMassSpectrum.d.ts +42 -0
  232. package/lib/mass/core/loadedMassSpectrum.d.ts.map +1 -0
  233. package/lib/mass/core/loadedMassSpectrum.js +15 -0
  234. package/lib/mass/core/loadedMassSpectrum.js.map +1 -0
  235. package/lib/mass/core/massCommands.d.ts +170 -0
  236. package/lib/mass/core/massCommands.d.ts.map +1 -0
  237. package/lib/mass/core/massCommands.js +95 -0
  238. package/lib/mass/core/massCommands.js.map +1 -0
  239. package/lib/mass/core/massDomain.d.ts +121 -0
  240. package/lib/mass/core/massDomain.d.ts.map +1 -0
  241. package/lib/mass/core/massDomain.js +179 -0
  242. package/lib/mass/core/massDomain.js.map +1 -0
  243. package/lib/mass/core/massEditorApi.d.ts +65 -0
  244. package/lib/mass/core/massEditorApi.d.ts.map +1 -0
  245. package/lib/mass/core/massEditorApi.js +10 -0
  246. package/lib/mass/core/massEditorApi.js.map +1 -0
  247. package/lib/mass/core/massFormat.d.ts +78 -0
  248. package/lib/mass/core/massFormat.d.ts.map +1 -0
  249. package/lib/mass/core/massFormat.js +168 -0
  250. package/lib/mass/core/massFormat.js.map +1 -0
  251. package/lib/mass/core/massMeta.d.ts +85 -0
  252. package/lib/mass/core/massMeta.d.ts.map +1 -0
  253. package/lib/mass/core/massMeta.js +182 -0
  254. package/lib/mass/core/massMeta.js.map +1 -0
  255. package/lib/mass/core/massReducer.d.ts +82 -0
  256. package/lib/mass/core/massReducer.d.ts.map +1 -0
  257. package/lib/mass/core/massReducer.js +163 -0
  258. package/lib/mass/core/massReducer.js.map +1 -0
  259. package/lib/mass/core/massResolution.d.ts +92 -0
  260. package/lib/mass/core/massResolution.d.ts.map +1 -0
  261. package/lib/mass/core/massResolution.js +126 -0
  262. package/lib/mass/core/massResolution.js.map +1 -0
  263. package/lib/mass/core/massSidePanels.d.ts +28 -0
  264. package/lib/mass/core/massSidePanels.d.ts.map +1 -0
  265. package/lib/mass/core/massSidePanels.js +12 -0
  266. package/lib/mass/core/massSidePanels.js.map +1 -0
  267. package/lib/mass/core/massSpectrum.d.ts +206 -0
  268. package/lib/mass/core/massSpectrum.d.ts.map +1 -0
  269. package/lib/mass/core/massSpectrum.js +41 -0
  270. package/lib/mass/core/massSpectrum.js.map +1 -0
  271. package/lib/mass/core/massState.d.ts +145 -0
  272. package/lib/mass/core/massState.d.ts.map +1 -0
  273. package/lib/mass/core/massState.js +102 -0
  274. package/lib/mass/core/massState.js.map +1 -0
  275. package/lib/mass/core/massStateEdits.d.ts +51 -0
  276. package/lib/mass/core/massStateEdits.d.ts.map +1 -0
  277. package/lib/mass/core/massStateEdits.js +90 -0
  278. package/lib/mass/core/massStateEdits.js.map +1 -0
  279. package/lib/mass/core/massSummary.d.ts +77 -0
  280. package/lib/mass/core/massSummary.d.ts.map +1 -0
  281. package/lib/mass/core/massSummary.js +174 -0
  282. package/lib/mass/core/massSummary.js.map +1 -0
  283. package/lib/mass/core/mzDecimalsSetting.d.ts +36 -0
  284. package/lib/mass/core/mzDecimalsSetting.d.ts.map +1 -0
  285. package/lib/mass/core/mzDecimalsSetting.js +42 -0
  286. package/lib/mass/core/mzDecimalsSetting.js.map +1 -0
  287. package/lib/mass/core/nearestPeak.d.ts +75 -0
  288. package/lib/mass/core/nearestPeak.d.ts.map +1 -0
  289. package/lib/mass/core/nearestPeak.js +99 -0
  290. package/lib/mass/core/nearestPeak.js.map +1 -0
  291. package/lib/mass/core/peakLabelLines.d.ts +77 -0
  292. package/lib/mass/core/peakLabelLines.d.ts.map +1 -0
  293. package/lib/mass/core/peakLabelLines.js +54 -0
  294. package/lib/mass/core/peakLabelLines.js.map +1 -0
  295. package/lib/mass/core/peakLabelPlan.d.ts +109 -0
  296. package/lib/mass/core/peakLabelPlan.d.ts.map +1 -0
  297. package/lib/mass/core/peakLabelPlan.js +143 -0
  298. package/lib/mass/core/peakLabelPlan.js.map +1 -0
  299. package/lib/mass/core/peakTable.d.ts +54 -0
  300. package/lib/mass/core/peakTable.d.ts.map +1 -0
  301. package/lib/mass/core/peakTable.js +53 -0
  302. package/lib/mass/core/peakTable.js.map +1 -0
  303. package/lib/mass/core/resolutionOf.d.ts +60 -0
  304. package/lib/mass/core/resolutionOf.d.ts.map +1 -0
  305. package/lib/mass/core/resolutionOf.js +84 -0
  306. package/lib/mass/core/resolutionOf.js.map +1 -0
  307. package/lib/mass/core/scanFilter.d.ts +25 -0
  308. package/lib/mass/core/scanFilter.d.ts.map +1 -0
  309. package/lib/mass/core/scanFilter.js +107 -0
  310. package/lib/mass/core/scanFilter.js.map +1 -0
  311. package/lib/mass/core/spectrumJcamp.d.ts +47 -0
  312. package/lib/mass/core/spectrumJcamp.d.ts.map +1 -0
  313. package/lib/mass/core/spectrumJcamp.js +167 -0
  314. package/lib/mass/core/spectrumJcamp.js.map +1 -0
  315. package/lib/mass/core/toMassSpectrum.d.ts +67 -0
  316. package/lib/mass/core/toMassSpectrum.d.ts.map +1 -0
  317. package/lib/mass/core/toMassSpectrum.js +78 -0
  318. package/lib/mass/core/toMassSpectrum.js.map +1 -0
  319. package/lib/mass/core/traceIcon.d.ts +82 -0
  320. package/lib/mass/core/traceIcon.d.ts.map +1 -0
  321. package/lib/mass/core/traceIcon.js +66 -0
  322. package/lib/mass/core/traceIcon.js.map +1 -0
  323. package/lib/mass/core/writtenResolution.d.ts +40 -0
  324. package/lib/mass/core/writtenResolution.d.ts.map +1 -0
  325. package/lib/mass/core/writtenResolution.js +77 -0
  326. package/lib/mass/core/writtenResolution.js.map +1 -0
  327. package/lib/mass/ui/MassAboutDialog.d.ts +16 -0
  328. package/lib/mass/ui/MassAboutDialog.d.ts.map +1 -0
  329. package/lib/mass/ui/MassAboutDialog.js +44 -0
  330. package/lib/mass/ui/MassAboutDialog.js.map +1 -0
  331. package/lib/mass/ui/MassCanvas.d.ts +46 -0
  332. package/lib/mass/ui/MassCanvas.d.ts.map +1 -0
  333. package/lib/mass/ui/MassCanvas.js +84 -0
  334. package/lib/mass/ui/MassCanvas.js.map +1 -0
  335. package/lib/mass/ui/MassChart.d.ts +21 -0
  336. package/lib/mass/ui/MassChart.d.ts.map +1 -0
  337. package/lib/mass/ui/MassChart.js +139 -0
  338. package/lib/mass/ui/MassChart.js.map +1 -0
  339. package/lib/mass/ui/MassCommandProvider.d.ts +15 -0
  340. package/lib/mass/ui/MassCommandProvider.d.ts.map +1 -0
  341. package/lib/mass/ui/MassCommandProvider.js +14 -0
  342. package/lib/mass/ui/MassCommandProvider.js.map +1 -0
  343. package/lib/mass/ui/MassCommandTooltip.d.ts +16 -0
  344. package/lib/mass/ui/MassCommandTooltip.d.ts.map +1 -0
  345. package/lib/mass/ui/MassCommandTooltip.js +22 -0
  346. package/lib/mass/ui/MassCommandTooltip.js.map +1 -0
  347. package/lib/mass/ui/MassDocumentationDialog.d.ts +18 -0
  348. package/lib/mass/ui/MassDocumentationDialog.d.ts.map +1 -0
  349. package/lib/mass/ui/MassDocumentationDialog.js +70 -0
  350. package/lib/mass/ui/MassDocumentationDialog.js.map +1 -0
  351. package/lib/mass/ui/MassEditor.d.ts +78 -0
  352. package/lib/mass/ui/MassEditor.d.ts.map +1 -0
  353. package/lib/mass/ui/MassEditor.js +42 -0
  354. package/lib/mass/ui/MassEditor.js.map +1 -0
  355. package/lib/mass/ui/MassHeader.d.ts +12 -0
  356. package/lib/mass/ui/MassHeader.d.ts.map +1 -0
  357. package/lib/mass/ui/MassHeader.js +20 -0
  358. package/lib/mass/ui/MassHeader.js.map +1 -0
  359. package/lib/mass/ui/MassLogo.d.ts +21 -0
  360. package/lib/mass/ui/MassLogo.d.ts.map +1 -0
  361. package/lib/mass/ui/MassLogo.js +36 -0
  362. package/lib/mass/ui/MassLogo.js.map +1 -0
  363. package/lib/mass/ui/MassPointerTracker.d.ts +44 -0
  364. package/lib/mass/ui/MassPointerTracker.d.ts.map +1 -0
  365. package/lib/mass/ui/MassPointerTracker.js +29 -0
  366. package/lib/mass/ui/MassPointerTracker.js.map +1 -0
  367. package/lib/mass/ui/MassShell.d.ts +29 -0
  368. package/lib/mass/ui/MassShell.d.ts.map +1 -0
  369. package/lib/mass/ui/MassShell.js +133 -0
  370. package/lib/mass/ui/MassShell.js.map +1 -0
  371. package/lib/mass/ui/MassSidePanel.d.ts +32 -0
  372. package/lib/mass/ui/MassSidePanel.d.ts.map +1 -0
  373. package/lib/mass/ui/MassSidePanel.js +44 -0
  374. package/lib/mass/ui/MassSidePanel.js.map +1 -0
  375. package/lib/mass/ui/MassStateProvider.d.ts +19 -0
  376. package/lib/mass/ui/MassStateProvider.d.ts.map +1 -0
  377. package/lib/mass/ui/MassStateProvider.js +16 -0
  378. package/lib/mass/ui/MassStateProvider.js.map +1 -0
  379. package/lib/mass/ui/MassStatusBar.d.ts +15 -0
  380. package/lib/mass/ui/MassStatusBar.d.ts.map +1 -0
  381. package/lib/mass/ui/MassStatusBar.js +50 -0
  382. package/lib/mass/ui/MassStatusBar.js.map +1 -0
  383. package/lib/mass/ui/MassToolbar.d.ts +24 -0
  384. package/lib/mass/ui/MassToolbar.d.ts.map +1 -0
  385. package/lib/mass/ui/MassToolbar.js +36 -0
  386. package/lib/mass/ui/MassToolbar.js.map +1 -0
  387. package/lib/mass/ui/MetadataPanel.d.ts +35 -0
  388. package/lib/mass/ui/MetadataPanel.d.ts.map +1 -0
  389. package/lib/mass/ui/MetadataPanel.js +100 -0
  390. package/lib/mass/ui/MetadataPanel.js.map +1 -0
  391. package/lib/mass/ui/MzDecimalsMenu.d.ts +28 -0
  392. package/lib/mass/ui/MzDecimalsMenu.d.ts.map +1 -0
  393. package/lib/mass/ui/MzDecimalsMenu.js +40 -0
  394. package/lib/mass/ui/MzDecimalsMenu.js.map +1 -0
  395. package/lib/mass/ui/PeakLabels.d.ts +93 -0
  396. package/lib/mass/ui/PeakLabels.d.ts.map +1 -0
  397. package/lib/mass/ui/PeakLabels.js +91 -0
  398. package/lib/mass/ui/PeakLabels.js.map +1 -0
  399. package/lib/mass/ui/PeakTable.d.ts +34 -0
  400. package/lib/mass/ui/PeakTable.d.ts.map +1 -0
  401. package/lib/mass/ui/PeakTable.js +49 -0
  402. package/lib/mass/ui/PeakTable.js.map +1 -0
  403. package/lib/mass/ui/PeaksPanel.d.ts +31 -0
  404. package/lib/mass/ui/PeaksPanel.d.ts.map +1 -0
  405. package/lib/mass/ui/PeaksPanel.js +53 -0
  406. package/lib/mass/ui/PeaksPanel.js.map +1 -0
  407. package/lib/mass/ui/SpectraPanel.d.ts +17 -0
  408. package/lib/mass/ui/SpectraPanel.d.ts.map +1 -0
  409. package/lib/mass/ui/SpectraPanel.js +76 -0
  410. package/lib/mass/ui/SpectraPanel.js.map +1 -0
  411. package/lib/mass/ui/SpectrumRow.d.ts +26 -0
  412. package/lib/mass/ui/SpectrumRow.d.ts.map +1 -0
  413. package/lib/mass/ui/SpectrumRow.js +141 -0
  414. package/lib/mass/ui/SpectrumRow.js.map +1 -0
  415. package/lib/mass/ui/SpectrumTrace.d.ts +46 -0
  416. package/lib/mass/ui/SpectrumTrace.d.ts.map +1 -0
  417. package/lib/mass/ui/SpectrumTrace.js +68 -0
  418. package/lib/mass/ui/SpectrumTrace.js.map +1 -0
  419. package/lib/mass/ui/index.d.ts +69 -0
  420. package/lib/mass/ui/index.d.ts.map +1 -0
  421. package/lib/mass/ui/index.js +42 -0
  422. package/lib/mass/ui/index.js.map +1 -0
  423. package/lib/mass/ui/massActions.d.ts +52 -0
  424. package/lib/mass/ui/massActions.d.ts.map +1 -0
  425. package/lib/mass/ui/massActions.js +62 -0
  426. package/lib/mass/ui/massActions.js.map +1 -0
  427. package/lib/mass/ui/massChartProps.d.ts +128 -0
  428. package/lib/mass/ui/massChartProps.d.ts.map +1 -0
  429. package/lib/mass/ui/massChartProps.js +14 -0
  430. package/lib/mass/ui/massChartProps.js.map +1 -0
  431. package/lib/mass/ui/massCommandContext.d.ts +36 -0
  432. package/lib/mass/ui/massCommandContext.d.ts.map +1 -0
  433. package/lib/mass/ui/massCommandContext.js +45 -0
  434. package/lib/mass/ui/massCommandContext.js.map +1 -0
  435. package/lib/mass/ui/massHostPanels.d.ts +48 -0
  436. package/lib/mass/ui/massHostPanels.d.ts.map +1 -0
  437. package/lib/mass/ui/massHostPanels.js +41 -0
  438. package/lib/mass/ui/massHostPanels.js.map +1 -0
  439. package/lib/mass/ui/massStateContext.d.ts +26 -0
  440. package/lib/mass/ui/massStateContext.d.ts.map +1 -0
  441. package/lib/mass/ui/massStateContext.js +37 -0
  442. package/lib/mass/ui/massStateContext.js.map +1 -0
  443. package/lib/mass/ui/useIntensityZoom.d.ts +20 -0
  444. package/lib/mass/ui/useIntensityZoom.d.ts.map +1 -0
  445. package/lib/mass/ui/useIntensityZoom.js +42 -0
  446. package/lib/mass/ui/useIntensityZoom.js.map +1 -0
  447. package/lib/mass/ui/useMassEditor.d.ts +52 -0
  448. package/lib/mass/ui/useMassEditor.d.ts.map +1 -0
  449. package/lib/mass/ui/useMassEditor.js +93 -0
  450. package/lib/mass/ui/useMassEditor.js.map +1 -0
  451. package/lib/mass/ui/useMassFiles.d.ts +22 -0
  452. package/lib/mass/ui/useMassFiles.d.ts.map +1 -0
  453. package/lib/mass/ui/useMassFiles.js +71 -0
  454. package/lib/mass/ui/useMassFiles.js.map +1 -0
  455. package/lib/mass/ui/useMassHandle.d.ts +15 -0
  456. package/lib/mass/ui/useMassHandle.d.ts.map +1 -0
  457. package/lib/mass/ui/useMassHandle.js +35 -0
  458. package/lib/mass/ui/useMassHandle.js.map +1 -0
  459. package/lib/mass/ui/useMassPointer.d.ts +70 -0
  460. package/lib/mass/ui/useMassPointer.d.ts.map +1 -0
  461. package/lib/mass/ui/useMassPointer.js +57 -0
  462. package/lib/mass/ui/useMassPointer.js.map +1 -0
  463. package/lib/mass/ui/useMassShortcuts.d.ts +21 -0
  464. package/lib/mass/ui/useMassShortcuts.d.ts.map +1 -0
  465. package/lib/mass/ui/useMassShortcuts.js +66 -0
  466. package/lib/mass/ui/useMassShortcuts.js.map +1 -0
  467. package/lib/mass/ui/useMassSide.d.ts +27 -0
  468. package/lib/mass/ui/useMassSide.d.ts.map +1 -0
  469. package/lib/mass/ui/useMassSide.js +45 -0
  470. package/lib/mass/ui/useMassSide.js.map +1 -0
  471. package/lib/mass/ui/useMassZoom.d.ts +92 -0
  472. package/lib/mass/ui/useMassZoom.d.ts.map +1 -0
  473. package/lib/mass/ui/useMassZoom.js +65 -0
  474. package/lib/mass/ui/useMassZoom.js.map +1 -0
  475. package/lib/mass.d.ts +16 -0
  476. package/lib/mass.d.ts.map +1 -0
  477. package/lib/mass.js +16 -0
  478. package/lib/mass.js.map +1 -0
  479. package/lib/panel/ui/PanelRail.d.ts.map +1 -1
  480. package/lib/panel/ui/PanelRail.js +6 -1
  481. package/lib/panel/ui/PanelRail.js.map +1 -1
  482. package/lib/slides/ui/slideSanitizeSchema.d.ts +3 -2
  483. package/lib/slides/ui/slideSanitizeSchema.d.ts.map +1 -1
  484. package/lib/slides/ui/slideSanitizeSchema.js +82 -2
  485. package/lib/slides/ui/slideSanitizeSchema.js.map +1 -1
  486. package/package.json +6 -1
  487. package/src/about/core/providers.ts +7 -0
  488. package/src/about/ui/AboutProvidedBy.tsx +49 -0
  489. package/src/chart/ui/useChartPointer.ts +18 -4
  490. package/src/credits/core/credits.ts +53 -0
  491. package/src/download/core/drawingMarkup.ts +18 -1
  492. package/src/download/core/figurePng.ts +21 -8
  493. package/src/download/core/figureSvg.ts +5 -2
  494. package/src/download/core/figureTarget.ts +28 -3
  495. package/src/download/core/svgBounds.ts +21 -0
  496. package/src/download/core/svgToPng.ts +3 -4
  497. package/src/format/core/relativeTime.ts +29 -7
  498. package/src/host/core/connectHost.ts +77 -120
  499. package/src/host/core/hostOutputs.ts +197 -0
  500. package/src/host/core/index.ts +13 -7
  501. package/src/host/core/irKinds.ts +92 -0
  502. package/src/host/core/kinds.ts +16 -6
  503. package/src/host/core/protocol.ts +50 -8
  504. package/src/host/core/selectInputs.ts +145 -0
  505. package/src/host/testing/sciPeaks.ts +140 -0
  506. package/src/host/testing/standInHost.ts +30 -5
  507. package/src/host/ui/useHostConnection.ts +17 -8
  508. package/src/host-testing.ts +4 -0
  509. package/src/ir/core/handPicking.ts +154 -0
  510. package/src/ir/core/index.ts +14 -0
  511. package/src/ir/core/irBandState.ts +155 -0
  512. package/src/ir/core/irCommands.ts +7 -0
  513. package/src/ir/core/irPeaks.ts +79 -0
  514. package/src/ir/core/irReducer.ts +27 -34
  515. package/src/ir/core/irSpectrum.ts +16 -0
  516. package/src/ir/core/irState.ts +15 -8
  517. package/src/ir/core/pickBands.ts +46 -39
  518. package/src/ir/core/ramanBands.ts +2 -2
  519. package/src/ir/core/spectrumBands.ts +113 -0
  520. package/src/ir/ui/BandRow.tsx +20 -2
  521. package/src/ir/ui/BandsPanel.tsx +46 -88
  522. package/src/ir/ui/BandsToolbar.tsx +152 -0
  523. package/src/ir/ui/IrCanvas.tsx +22 -11
  524. package/src/ir/ui/IrChart.tsx +10 -1
  525. package/src/ir/ui/IrDocumentationDialog.tsx +7 -0
  526. package/src/ir/ui/IrEditor.tsx +4 -2
  527. package/src/ir/ui/IrShell.tsx +5 -0
  528. package/src/ir/ui/IrStatusBar.tsx +4 -1
  529. package/src/ir/ui/IrToolbar.tsx +14 -5
  530. package/src/ir/ui/VibrationalEditor.tsx +2 -1
  531. package/src/ir/ui/irActions.ts +11 -0
  532. package/src/ir/ui/irChartProps.ts +4 -1
  533. package/src/ir/ui/useIrEditor.ts +21 -21
  534. package/src/locales/de.json +63 -0
  535. package/src/locales/en.json +63 -0
  536. package/src/locales/es.json +63 -0
  537. package/src/locales/fr.json +63 -0
  538. package/src/locales/it.json +63 -0
  539. package/src/mass/core/analyseSpectrum.ts +191 -0
  540. package/src/mass/core/ascendingTrace.ts +62 -0
  541. package/src/mass/core/centroidPeaks.ts +114 -0
  542. package/src/mass/core/detectMassFormat.ts +113 -0
  543. package/src/mass/core/downloadSpectra.ts +52 -0
  544. package/src/mass/core/fromJcamp.ts +151 -0
  545. package/src/mass/core/fromText.ts +58 -0
  546. package/src/mass/core/index.ts +194 -0
  547. package/src/mass/core/jcampTechnique.ts +87 -0
  548. package/src/mass/core/labelStackBox.ts +75 -0
  549. package/src/mass/core/labelledPeaks.ts +135 -0
  550. package/src/mass/core/loadMassSpectra.ts +86 -0
  551. package/src/mass/core/loadedMassSpectrum.ts +43 -0
  552. package/src/mass/core/massCommands.ts +156 -0
  553. package/src/mass/core/massDomain.ts +229 -0
  554. package/src/mass/core/massEditorApi.ts +68 -0
  555. package/src/mass/core/massFormat.ts +187 -0
  556. package/src/mass/core/massMeta.ts +239 -0
  557. package/src/mass/core/massReducer.ts +232 -0
  558. package/src/mass/core/massResolution.ts +169 -0
  559. package/src/mass/core/massSidePanels.ts +27 -0
  560. package/src/mass/core/massSpectrum.ts +220 -0
  561. package/src/mass/core/massState.ts +206 -0
  562. package/src/mass/core/massStateEdits.ts +104 -0
  563. package/src/mass/core/massSummary.ts +213 -0
  564. package/src/mass/core/mzDecimalsSetting.ts +52 -0
  565. package/src/mass/core/nearestPeak.ts +130 -0
  566. package/src/mass/core/peakLabelLines.ts +112 -0
  567. package/src/mass/core/peakLabelPlan.ts +246 -0
  568. package/src/mass/core/peakTable.ts +82 -0
  569. package/src/mass/core/resolutionOf.ts +100 -0
  570. package/src/mass/core/scanFilter.ts +119 -0
  571. package/src/mass/core/spectrumJcamp.ts +186 -0
  572. package/src/mass/core/toMassSpectrum.ts +126 -0
  573. package/src/mass/core/traceIcon.ts +105 -0
  574. package/src/mass/core/writtenResolution.ts +81 -0
  575. package/src/mass/ui/MassAboutDialog.tsx +89 -0
  576. package/src/mass/ui/MassCanvas.tsx +170 -0
  577. package/src/mass/ui/MassChart.tsx +266 -0
  578. package/src/mass/ui/MassCommandProvider.tsx +34 -0
  579. package/src/mass/ui/MassCommandTooltip.tsx +36 -0
  580. package/src/mass/ui/MassDocumentationDialog.tsx +136 -0
  581. package/src/mass/ui/MassEditor.tsx +130 -0
  582. package/src/mass/ui/MassHeader.tsx +38 -0
  583. package/src/mass/ui/MassLogo.tsx +84 -0
  584. package/src/mass/ui/MassPointerTracker.tsx +72 -0
  585. package/src/mass/ui/MassShell.tsx +237 -0
  586. package/src/mass/ui/MassSidePanel.tsx +107 -0
  587. package/src/mass/ui/MassStateProvider.tsx +32 -0
  588. package/src/mass/ui/MassStatusBar.tsx +108 -0
  589. package/src/mass/ui/MassToolbar.tsx +120 -0
  590. package/src/mass/ui/MetadataPanel.tsx +201 -0
  591. package/src/mass/ui/MzDecimalsMenu.tsx +86 -0
  592. package/src/mass/ui/PeakLabels.tsx +242 -0
  593. package/src/mass/ui/PeakTable.tsx +199 -0
  594. package/src/mass/ui/PeaksPanel.tsx +182 -0
  595. package/src/mass/ui/SpectraPanel.tsx +153 -0
  596. package/src/mass/ui/SpectrumRow.tsx +246 -0
  597. package/src/mass/ui/SpectrumTrace.tsx +119 -0
  598. package/src/mass/ui/index.ts +69 -0
  599. package/src/mass/ui/massActions.ts +109 -0
  600. package/src/mass/ui/massChartProps.ts +130 -0
  601. package/src/mass/ui/massCommandContext.tsx +65 -0
  602. package/src/mass/ui/massHostPanels.ts +71 -0
  603. package/src/mass/ui/massStateContext.ts +48 -0
  604. package/src/mass/ui/useIntensityZoom.ts +55 -0
  605. package/src/mass/ui/useMassEditor.ts +156 -0
  606. package/src/mass/ui/useMassFiles.ts +91 -0
  607. package/src/mass/ui/useMassHandle.ts +58 -0
  608. package/src/mass/ui/useMassPointer.ts +120 -0
  609. package/src/mass/ui/useMassShortcuts.ts +85 -0
  610. package/src/mass/ui/useMassSide.ts +63 -0
  611. package/src/mass/ui/useMassZoom.ts +157 -0
  612. package/src/mass.ts +16 -0
  613. package/src/panel/ui/PanelRail.tsx +5 -1
  614. package/src/slides/ui/slideSanitizeSchema.ts +86 -2
  615. package/styles/chrome.css +7 -0
  616. package/styles/slides.css +47 -0
@@ -0,0 +1,170 @@
1
+ import type { DragEvent } from 'react';
2
+ import { useCallback, useMemo, useState } from 'react';
3
+
4
+ import type { MassPlotClick } from '../core/massEditorApi.ts';
5
+ import type { MassDomain } from '../core/massSpectrum.ts';
6
+ import type { NearestPeak } from '../core/nearestPeak.ts';
7
+
8
+ import { MassChart } from './MassChart.tsx';
9
+ import { MassStatusBar } from './MassStatusBar.tsx';
10
+ import { useMassActions, useMassEditorState } from './massStateContext.ts';
11
+
12
+ export interface MassCanvasProps {
13
+ /**
14
+ * The m/z of the peak the pointer is resting on, wherever it was hovered —
15
+ * the chart or the peak table.
16
+ * @default null
17
+ */
18
+ highlightMz?: number | null;
19
+ /**
20
+ * Told which peak the pointer has come to rest on over the chart.
21
+ * @default undefined
22
+ */
23
+ onHighlight?: (mz: number | null) => void;
24
+ /**
25
+ * The `id` put on the box the chart is drawn in, which the "Save figure"
26
+ * panel is pointed at.
27
+ * @default undefined
28
+ */
29
+ chartId?: string;
30
+ /**
31
+ * Told of a click on the plot, with the spectrum selected at that moment.
32
+ * @default undefined
33
+ */
34
+ onPlotClick?: (click: MassPlotClick) => void;
35
+ /**
36
+ * Read files dropped on the chart.
37
+ * @default undefined — a drop is left to the page
38
+ */
39
+ onDropFiles?: (files: File[]) => void;
40
+ }
41
+
42
+ /**
43
+ * The chart, and the status bar under it.
44
+ *
45
+ * This is where the state meets the drawing: the chart holds nothing, so
46
+ * everything it draws is read out of the state here and every gesture it reports
47
+ * is written back. The window in particular goes **both** ways — the chart is
48
+ * told what to show and reports what it arrives at — which is what lets a toolbar
49
+ * button, a row of the peak table and a drag all move it.
50
+ *
51
+ * The chart is also where files are dropped, because that is where a chemist
52
+ * expects the spectrum to land; the box is outlined while one is held over it.
53
+ * @param props - Component props.
54
+ * @returns The canvas.
55
+ */
56
+ export function MassCanvas(props: MassCanvasProps) {
57
+ const {
58
+ highlightMz = null,
59
+ onHighlight,
60
+ chartId,
61
+ onPlotClick,
62
+ onDropFiles,
63
+ } = props;
64
+ const { state, visibleSpectra } = useMassEditorState();
65
+ const actions = useMassActions();
66
+ const { domain, tool, selectedId } = state.view;
67
+ const { showLabels, labelLimit, showCharges, mzDecimals } = state.settings;
68
+ const [isDropping, setIsDropping] = useState(false);
69
+
70
+ const onDomainChange = useCallback(
71
+ (next: MassDomain) => actions.setDomain(next),
72
+ [actions],
73
+ );
74
+
75
+ const onPeakHover = useMemo(
76
+ () =>
77
+ onHighlight === undefined
78
+ ? undefined
79
+ : (peak: NearestPeak | null) => onHighlight(peak?.mz ?? null),
80
+ [onHighlight],
81
+ );
82
+
83
+ // Which spectrum was selected is the viewer's to say, not the chart's: the
84
+ // chart only knows where the press landed.
85
+ const onClick = useMemo(
86
+ () =>
87
+ onPlotClick === undefined
88
+ ? undefined
89
+ : (mz: number, peak: NearestPeak | null) =>
90
+ onPlotClick({
91
+ mz,
92
+ peakMz: peak?.mz ?? null,
93
+ spectrumId: selectedId,
94
+ }),
95
+ [onPlotClick, selectedId],
96
+ );
97
+
98
+ const drop =
99
+ onDropFiles === undefined
100
+ ? {}
101
+ : {
102
+ onDragOver: (event: DragEvent<HTMLDivElement>) => {
103
+ if (!event.dataTransfer.types.includes('Files')) return;
104
+ // Without this the browser opens the file in place of the page.
105
+ event.preventDefault();
106
+ event.dataTransfer.dropEffect = 'copy';
107
+ if (!isDropping) setIsDropping(true);
108
+ },
109
+ onDragLeave: () => setIsDropping(false),
110
+ onDrop: (event: DragEvent<HTMLDivElement>) => {
111
+ event.preventDefault();
112
+ setIsDropping(false);
113
+ const files = [...event.dataTransfer.files];
114
+ if (files.length > 0) onDropFiles(files);
115
+ },
116
+ };
117
+
118
+ return (
119
+ <div style={rootStyle}>
120
+ <div
121
+ id={chartId}
122
+ style={isDropping ? droppingChartStyle : chartStyle}
123
+ {...drop}
124
+ >
125
+ <MassChart
126
+ spectra={visibleSpectra}
127
+ labelledId={selectedId}
128
+ showLabels={showLabels}
129
+ labelLimit={labelLimit}
130
+ showCharges={showCharges}
131
+ // A number chosen holds for every mass on the chart; left to the
132
+ // spectra, the chart decides per spectrum, labels and crosshair alike.
133
+ {...(mzDecimals === 'auto' ? {} : { mzDecimals })}
134
+ highlightMz={highlightMz}
135
+ domain={domain}
136
+ onDomainChange={onDomainChange}
137
+ drag={tool === 'box' ? 'box' : 'xAxis'}
138
+ // The shell runs `f` through its command table, where it is listed.
139
+ answersKeys={false}
140
+ emphasisedId={visibleSpectra.length > 1 ? selectedId : null}
141
+ {...(onPeakHover === undefined ? {} : { onPeakHover })}
142
+ {...(onClick === undefined ? {} : { onPlotClick: onClick })}
143
+ />
144
+ </div>
145
+ <MassStatusBar />
146
+ </div>
147
+ );
148
+ }
149
+
150
+ const rootStyle = {
151
+ display: 'flex',
152
+ flexDirection: 'column',
153
+ flex: '1 1 1px',
154
+ minWidth: 0,
155
+ minHeight: 0,
156
+ } as const;
157
+
158
+ /** The chart takes what the status bar does not. */
159
+ const chartStyle = {
160
+ flex: '1 1 1px',
161
+ minHeight: 0,
162
+ outline: '2px dashed transparent',
163
+ outlineOffset: -4,
164
+ } as const;
165
+
166
+ /** The same box while a file is held over it, saying where it will land. */
167
+ const droppingChartStyle = {
168
+ ...chartStyle,
169
+ outlineColor: 'var(--accent, currentColor)',
170
+ } as const;
@@ -0,0 +1,266 @@
1
+ import type { ReactElement } from 'react';
2
+ import { useId, useLayoutEffect, useMemo, useRef } from 'react';
3
+
4
+ import { sameChartDomain } from '../../chart/core/chartDomain.ts';
5
+ import { MARGIN, plotRect } from '../../chart/core/chartGeometry.ts';
6
+ import { Axes } from '../../chart/ui/Axes.tsx';
7
+ import { AxisGuide } from '../../chart/ui/AxisGuide.tsx';
8
+ import { SelectionRect } from '../../chart/ui/SelectionRect.tsx';
9
+ import { chartSurfaceStyle } from '../../chart/ui/chartSurface.ts';
10
+ import { useChartSize } from '../../chart/ui/useChartSize.ts';
11
+ import type { MassSpectrum } from '../core/massSpectrum.ts';
12
+ import { DEFAULT_LABEL_LIMIT } from '../core/massState.ts';
13
+ import { mzDecimalsOf } from '../core/resolutionOf.ts';
14
+
15
+ import { MassPointerTracker } from './MassPointerTracker.tsx';
16
+ import { PeakLabels } from './PeakLabels.tsx';
17
+ import { SpectrumTrace } from './SpectrumTrace.tsx';
18
+ import type { MassChartProps } from './massChartProps.ts';
19
+ import { useMassPointer } from './useMassPointer.ts';
20
+ import { useMassZoom } from './useMassZoom.ts';
21
+
22
+ /**
23
+ * The chart: every layer of a mass spectrum, in one SVG.
24
+ *
25
+ * The axes go under the data, so a grid line is never read as a peak. Only the
26
+ * data band is clipped, so a zoomed trace stops at the plot edge while the
27
+ * labels over the tallest peaks are allowed out over the margin — clip those and
28
+ * the base peak of every spectrum loses its label. The guide, the drag rectangle
29
+ * and the crosshair go over everything, because each answers a question being
30
+ * asked right now.
31
+ *
32
+ * Nothing is held here. The spectra, what is labelled, what is being looked at
33
+ * and the window are all props, and every gesture comes back out as a callback
34
+ * — so one component draws an editor's chart, a report page's single spectrum
35
+ * and a test.
36
+ * @param props - Component props.
37
+ * @returns The chart.
38
+ */
39
+ export function MassChart(props: MassChartProps): ReactElement {
40
+ const {
41
+ spectra,
42
+ labelledId,
43
+ showLabels = true,
44
+ labelLimit = DEFAULT_LABEL_LIMIT,
45
+ showCharges = false,
46
+ mzDecimals: askedDecimals,
47
+ annotationLabels,
48
+ highlightMz = null,
49
+ onPeakHover,
50
+ domain = null,
51
+ onDomainChange,
52
+ onPlotClick,
53
+ drag = 'xAxis',
54
+ answersKeys = true,
55
+ emphasisedId = null,
56
+ width,
57
+ height,
58
+ children,
59
+ } = props;
60
+
61
+ const [containerRef, measured] = useChartSize<HTMLDivElement>();
62
+ const svgRef = useRef<SVGSVGElement | null>(null);
63
+
64
+ const plot = useMemo(
65
+ () =>
66
+ plotRect({
67
+ width: width ?? measured.width,
68
+ height: height ?? measured.height,
69
+ }),
70
+ [width, height, measured.width, measured.height],
71
+ );
72
+ // Read back off the plot rather than off the measurement, so a chart briefly
73
+ // laid out at nothing still draws its axes inside a box that holds them.
74
+ const frameWidth = plot.right + MARGIN.right;
75
+ const frameHeight = plot.bottom + MARGIN.bottom;
76
+
77
+ // The host's window goes *into* the zoom rather than over it, so a drag is
78
+ // always measured against what is on screen.
79
+ const zoom = useMassZoom({
80
+ spectra,
81
+ svgRef,
82
+ plot,
83
+ domain,
84
+ drag,
85
+ keys: answersKeys,
86
+ ...(onPlotClick === undefined
87
+ ? {}
88
+ : { onClick: ({ mz, peak }) => onPlotClick(mz, peak) }),
89
+ });
90
+ const { domain: shown, xScale, yScale, selection, handlers } = zoom;
91
+
92
+ // A chart holding nothing still builds scales on a placeholder window, and a
93
+ // placeholder reported would become a window the host imposes on whatever is
94
+ // dropped next — drawn entirely off screen.
95
+ const holdsNothing = spectra.length === 0;
96
+ const reported = useRef(shown);
97
+ // Before the browser paints, so a host that stores the window and hands it
98
+ // back does so in the frame the gesture landed in rather than the one after.
99
+ useLayoutEffect(() => {
100
+ if (holdsNothing || sameChartDomain(reported.current, shown)) return;
101
+ reported.current = shown;
102
+ onDomainChange?.(shown);
103
+ }, [holdsNothing, shown, onDomainChange]);
104
+
105
+ const pointer = useMassPointer({
106
+ svgRef,
107
+ plot,
108
+ xScale,
109
+ yScale,
110
+ spectra,
111
+ ...(onPeakHover === undefined ? {} : { onPeak: onPeakHover }),
112
+ });
113
+
114
+ const labelled = useMemo(
115
+ () => labelledSpectrum(spectra, labelledId),
116
+ [spectra, labelledId],
117
+ );
118
+ const painted = useMemo(
119
+ () => emphasisedLast(spectra, emphasisedId),
120
+ [spectra, emphasisedId],
121
+ );
122
+
123
+ // The crosshair reads every drawn spectrum, so it is written to what they
124
+ // resolve together; the labels are of one spectrum, and written to its own.
125
+ const readoutDecimals = useMemo(
126
+ () => askedDecimals ?? mzDecimalsOf(spectra),
127
+ [askedDecimals, spectra],
128
+ );
129
+ const labelDecimals = useMemo(
130
+ () =>
131
+ askedDecimals ??
132
+ (labelled === null ? readoutDecimals : mzDecimalsOf([labelled])),
133
+ [askedDecimals, labelled, readoutDecimals],
134
+ );
135
+
136
+ // React's generated id carries the punctuation it keeps its own ids apart
137
+ // with, which a URL fragment is under no obligation to accept.
138
+ const clipId = `mass-plot-${useId().replaceAll(/\W/g, '')}`;
139
+
140
+ return (
141
+ <div ref={containerRef} style={containerStyle}>
142
+ <svg
143
+ ref={svgRef}
144
+ role="img"
145
+ aria-label={CHART_LABEL}
146
+ width={frameWidth}
147
+ height={frameHeight}
148
+ viewBox={`0 0 ${frameWidth} ${frameHeight}`}
149
+ style={chartSurfaceStyle(pointer.position !== null)}
150
+ {...handlers}
151
+ >
152
+ <defs>
153
+ <clipPath id={clipId}>
154
+ <rect
155
+ x={plot.left}
156
+ y={plot.top}
157
+ width={plot.width}
158
+ height={plot.height}
159
+ />
160
+ </clipPath>
161
+ </defs>
162
+
163
+ <Axes
164
+ plot={plot}
165
+ xDomain={shown.x}
166
+ yDomain={shown.y}
167
+ xScale={xScale}
168
+ yScale={yScale}
169
+ xTitle="m/z"
170
+ yTitle="relative intensity (%)"
171
+ />
172
+
173
+ <g clipPath={`url(#${clipId})`}>
174
+ {painted.map((spectrum) => (
175
+ <SpectrumTrace
176
+ key={spectrum.id}
177
+ spectrum={spectrum}
178
+ plot={plot}
179
+ xScale={xScale}
180
+ yScale={yScale}
181
+ strokeWidth={
182
+ spectrum.id === emphasisedId ? EMPHASISED_WIDTH : undefined
183
+ }
184
+ />
185
+ ))}
186
+ {children}
187
+ </g>
188
+
189
+ {showLabels && labelled !== null ? (
190
+ <PeakLabels
191
+ spectrum={labelled}
192
+ plot={plot}
193
+ xScale={xScale}
194
+ yScale={yScale}
195
+ limit={labelLimit}
196
+ showCharges={showCharges}
197
+ mzDecimals={labelDecimals}
198
+ {...(annotationLabels === undefined ? {} : { annotationLabels })}
199
+ color={spectra.length > 1 ? labelled.color : undefined}
200
+ />
201
+ ) : null}
202
+ <AxisGuide value={highlightMz} plot={plot} xScale={xScale} />
203
+ <SelectionRect selection={selection} plot={plot} />
204
+ <MassPointerTracker
205
+ position={pointer.position}
206
+ readout={pointer.readout}
207
+ plot={plot}
208
+ mzDecimals={readoutDecimals}
209
+ />
210
+ </svg>
211
+ </div>
212
+ );
213
+ }
214
+
215
+ /**
216
+ * The one spectrum whose peaks are labelled.
217
+ * @param spectra - What the chart draws.
218
+ * @param labelledId - The identity asked for, `null` for none, absent to let the
219
+ * chart take the first.
220
+ * @returns The spectrum, or `null` when none answers.
221
+ */
222
+ function labelledSpectrum(
223
+ spectra: readonly MassSpectrum[],
224
+ labelledId: string | null | undefined,
225
+ ): MassSpectrum | null {
226
+ if (labelledId === undefined) return spectra[0] ?? null;
227
+ if (labelledId === null) return null;
228
+ for (const spectrum of spectra) {
229
+ if (spectrum.id === labelledId) return spectrum;
230
+ }
231
+ return null;
232
+ }
233
+
234
+ /**
235
+ * The traces in painting order, with the emphasised one last — last is in
236
+ * front, and in front is what lets a trace crossing a dozen others be followed.
237
+ * @param spectra - The traces, in the order they were opened.
238
+ * @param emphasisedId - Identity of the one to raise, `null` for none.
239
+ * @returns The order to paint in — the array itself when nothing moves.
240
+ */
241
+ function emphasisedLast(
242
+ spectra: readonly MassSpectrum[],
243
+ emphasisedId: string | null,
244
+ ): readonly MassSpectrum[] {
245
+ if (emphasisedId === null) return spectra;
246
+ const at = spectra.findIndex((spectrum) => spectrum.id === emphasisedId);
247
+ if (at === -1 || at === spectra.length - 1) return spectra;
248
+ return [
249
+ ...spectra.slice(0, at),
250
+ ...spectra.slice(at + 1),
251
+ spectra[at] as MassSpectrum,
252
+ ];
253
+ }
254
+
255
+ /** What the chart is, and what can be done to it, for whoever cannot see it. */
256
+ const CHART_LABEL =
257
+ 'Mass spectrum. Drag across it to zoom the m/z axis, drag below the baseline to take the intensity axis with it, turn the wheel to scale the intensity, and double click to fit everything again.';
258
+
259
+ /**
260
+ * How thick the trace every panel is about is drawn: barely thicker, so it
261
+ * reads as the same kind of thing as the others.
262
+ */
263
+ const EMPHASISED_WIDTH = 2;
264
+
265
+ /** The box the chart is measured against, and fills. */
266
+ const containerStyle = { width: '100%', height: '100%' } as const;
@@ -0,0 +1,34 @@
1
+ import type { ReactNode } from 'react';
2
+ import { useMemo } from 'react';
3
+
4
+ import type { MassCommandHandlers } from '../core/massCommands.ts';
5
+
6
+ import type { MassCommandContextValue } from './massCommandContext.tsx';
7
+ import { massCommandContext } from './massCommandContext.tsx';
8
+
9
+ export interface MassCommandProviderProps {
10
+ /** What each command does. */
11
+ handlers: MassCommandHandlers;
12
+ /** The viewer. */
13
+ children: ReactNode;
14
+ }
15
+
16
+ /**
17
+ * Put the command handlers where the toolbar and the panels can reach them.
18
+ * @param props - Component props.
19
+ * @returns The provider.
20
+ */
21
+ export function MassCommandProvider(props: MassCommandProviderProps) {
22
+ const { handlers, children } = props;
23
+
24
+ const value = useMemo<MassCommandContextValue>(
25
+ () => ({ handlers, run: (id) => handlers[id]?.() }),
26
+ [handlers],
27
+ );
28
+
29
+ return (
30
+ <massCommandContext.Provider value={value}>
31
+ {children}
32
+ </massCommandContext.Provider>
33
+ );
34
+ }
@@ -0,0 +1,36 @@
1
+ import { TooltipHelpContent } from 'react-science/ui';
2
+
3
+ import type { MassCommand, MassCommandId } from '../core/massCommands.ts';
4
+ import { massCommands } from '../core/massCommands.ts';
5
+
6
+ export interface MassCommandTooltipProps {
7
+ /** Which command the tooltip is about. */
8
+ id: MassCommandId;
9
+ }
10
+
11
+ /**
12
+ * One command's tooltip: its title, what it does, and every way to do it.
13
+ *
14
+ * `TooltipHelpContent` from react-science, which is what NMRium's tooltips and
15
+ * the infrared viewer's are, so a page holding these viewers side by side
16
+ * explains itself the same way in all of them.
17
+ * @param props - Component props.
18
+ * @returns The tooltip's content.
19
+ */
20
+ export function MassCommandTooltip(props: MassCommandTooltipProps) {
21
+ const { id } = props;
22
+ const entry: MassCommand = massCommands[id];
23
+ const shortcuts = entry.shortcut?.label ?? entry.shortcut?.keys;
24
+
25
+ return (
26
+ <TooltipHelpContent
27
+ title={entry.title}
28
+ description={entry.description}
29
+ shortcuts={shortcuts === undefined ? undefined : [...shortcuts]}
30
+ subTitles={entry.gestures?.map((gesture) => ({
31
+ title: gesture.title,
32
+ shortcuts: [...gesture.shortcuts],
33
+ }))}
34
+ />
35
+ );
36
+ }
@@ -0,0 +1,136 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ import type { DocumentationSection } from '../../panel/ui/DocumentationDialogFrame.tsx';
4
+ import { DocumentationDialogFrame } from '../../panel/ui/DocumentationDialogFrame.tsx';
5
+ import type { MassCommand } from '../core/massCommands.ts';
6
+ import { massCommandLabel, massCommands } from '../core/massCommands.ts';
7
+ import { HIGH_RESOLVING_POWER } from '../core/massResolution.ts';
8
+
9
+ export interface MassDocumentationDialogProps {
10
+ /** Whether the dialog is open. */
11
+ isOpen: boolean;
12
+ /** Close it. */
13
+ onClose: () => void;
14
+ }
15
+
16
+ /**
17
+ * How to use the viewer, written in the viewer.
18
+ *
19
+ * In the component rather than on a site, so there is nowhere to leave for and
20
+ * nothing to keep in step: every key in the last section is read out of the
21
+ * same command table the toolbar and the key handler read, so a shortcut cannot
22
+ * be documented as one thing and bound as another.
23
+ * @param props - Component props.
24
+ * @returns The dialog.
25
+ */
26
+ export function MassDocumentationDialog(props: MassDocumentationDialogProps) {
27
+ const { isOpen, onClose } = props;
28
+ return (
29
+ <DocumentationDialogFrame
30
+ isOpen={isOpen}
31
+ onClose={onClose}
32
+ title="Using the mass spectrum viewer"
33
+ sections={SECTIONS}
34
+ />
35
+ );
36
+ }
37
+
38
+ /**
39
+ * One row of the gestures table: a command, its key and what it does.
40
+ * @param props - Component props.
41
+ * @param props.entry - The command, as the table words it.
42
+ * @returns The row.
43
+ */
44
+ function CommandRow(props: { entry: MassCommand }): ReactNode {
45
+ const { entry } = props;
46
+ const keys = entry.shortcut?.label ?? entry.shortcut?.keys ?? [];
47
+ const gestures = (entry.gestures ?? []).flatMap(
48
+ (gesture) => gesture.shortcuts,
49
+ );
50
+ return (
51
+ <tr>
52
+ <th style={labelCellStyle}>{entry.title}</th>
53
+ <td style={keyCellStyle}>{[...keys, ...gestures].join(' · ')}</td>
54
+ <td style={cellStyle}>{entry.description}</td>
55
+ </tr>
56
+ );
57
+ }
58
+
59
+ const tableStyle = {
60
+ width: '100%',
61
+ borderCollapse: 'collapse',
62
+ fontSize: 12,
63
+ } as const;
64
+
65
+ const cellStyle = { padding: '3px 6px', verticalAlign: 'top' } as const;
66
+
67
+ const labelCellStyle = {
68
+ ...cellStyle,
69
+ textAlign: 'left',
70
+ whiteSpace: 'nowrap',
71
+ } as const;
72
+
73
+ const keyCellStyle = {
74
+ ...cellStyle,
75
+ whiteSpace: 'nowrap',
76
+ opacity: 0.7,
77
+ } as const;
78
+
79
+ /** What the guide says, in reading order. */
80
+ const SECTIONS: readonly DocumentationSection[] = [
81
+ {
82
+ id: 'open',
83
+ title: 'Opening a spectrum',
84
+ body: (
85
+ <p>
86
+ Drop JCAMP-DX files (<code>.jdx</code>, <code>.dx</code>) or two columns
87
+ of m/z and intensity (<code>.txt</code>, <code>.csv</code>,{' '}
88
+ <code>.xy</code>) on the chart, or use {massCommandLabel('openFiles')}.
89
+ A JCAMP holding several blocks, or a GC/MS export holding a page per
90
+ scan, gives one spectrum per block or page.
91
+ </p>
92
+ ),
93
+ },
94
+ {
95
+ id: 'peaks',
96
+ title: 'Profile and centroid',
97
+ body: (
98
+ <p>
99
+ A continuous profile is peak picked as it is read; a peak table is taken
100
+ as it stands. Each row of the Spectra panel draws a spectrum as its
101
+ profile or as its picked peaks, never both. The peaks of the selected
102
+ spectrum are labelled on the chart: zoom onto a cluster and every line
103
+ of it is labelled.
104
+ </p>
105
+ ),
106
+ },
107
+ {
108
+ id: 'resolution',
109
+ title: 'High or low resolution',
110
+ body: (
111
+ <p>
112
+ A profile is measured: the median resolving power of its tallest peaks,
113
+ at half height, is high resolution from{' '}
114
+ {HIGH_RESOLVING_POWER.toLocaleString('en-US')}. A peak table has no
115
+ widths, so the instrument its file names decides, and failing that the
116
+ decimals its masses were written with. Masses are written as high
117
+ resolution, to four decimals, or as nominal masses, whole. To write them
118
+ another way, pick the number of decimals in the Peaks panel toolbar; it
119
+ holds for the chart and the tables alike.
120
+ </p>
121
+ ),
122
+ },
123
+ {
124
+ id: 'keys',
125
+ title: 'Gestures and keys',
126
+ body: (
127
+ <table style={tableStyle}>
128
+ <tbody>
129
+ {Object.values(massCommands).map((entry) => (
130
+ <CommandRow key={entry.title} entry={entry} />
131
+ ))}
132
+ </tbody>
133
+ </table>
134
+ ),
135
+ },
136
+ ];