react-cheminfo 0.23.0 → 0.25.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 (264) hide show
  1. package/README.md +39 -26
  2. package/lib/chrome/ui/HeaderToggle.d.ts +52 -0
  3. package/lib/chrome/ui/HeaderToggle.d.ts.map +1 -0
  4. package/lib/chrome/ui/HeaderToggle.js +31 -0
  5. package/lib/chrome/ui/HeaderToggle.js.map +1 -0
  6. package/lib/chrome/ui/index.d.ts +2 -0
  7. package/lib/chrome/ui/index.d.ts.map +1 -1
  8. package/lib/chrome/ui/index.js +1 -0
  9. package/lib/chrome/ui/index.js.map +1 -1
  10. package/lib/citation/core/gfn2Paper.d.ts +10 -0
  11. package/lib/citation/core/gfn2Paper.d.ts.map +1 -0
  12. package/lib/citation/core/gfn2Paper.js +28 -0
  13. package/lib/citation/core/gfn2Paper.js.map +1 -0
  14. package/lib/citation/core/index.d.ts +1 -0
  15. package/lib/citation/core/index.d.ts.map +1 -1
  16. package/lib/citation/core/index.js +1 -0
  17. package/lib/citation/core/index.js.map +1 -1
  18. package/lib/clipboard/ui/ClickToCopy.d.ts +8 -7
  19. package/lib/clipboard/ui/ClickToCopy.d.ts.map +1 -1
  20. package/lib/clipboard/ui/ClickToCopy.js +3 -3
  21. package/lib/clipboard/ui/ClickToCopy.js.map +1 -1
  22. package/lib/conformers.d.ts +27 -0
  23. package/lib/conformers.d.ts.map +1 -0
  24. package/lib/conformers.js +19 -0
  25. package/lib/conformers.js.map +1 -0
  26. package/lib/core.d.ts +1 -0
  27. package/lib/core.d.ts.map +1 -1
  28. package/lib/core.js +1 -0
  29. package/lib/core.js.map +1 -1
  30. package/lib/credits/core/credits.d.ts +12 -0
  31. package/lib/credits/core/credits.d.ts.map +1 -1
  32. package/lib/credits/core/credits.js +14 -0
  33. package/lib/credits/core/credits.js.map +1 -1
  34. package/lib/ecosystem/core/index.d.ts +1 -1
  35. package/lib/ecosystem/core/index.d.ts.map +1 -1
  36. package/lib/ecosystem/core/index.js.map +1 -1
  37. package/lib/ecosystem/core/sites.d.ts +11 -1
  38. package/lib/ecosystem/core/sites.d.ts.map +1 -1
  39. package/lib/ecosystem/core/sites.js +11 -4
  40. package/lib/ecosystem/core/sites.js.map +1 -1
  41. package/lib/ecosystem/ui/EcosystemLinks.d.ts.map +1 -1
  42. package/lib/ecosystem/ui/EcosystemLinks.js +3 -1
  43. package/lib/ecosystem/ui/EcosystemLinks.js.map +1 -1
  44. package/lib/ecosystem/ui/SiteTile.d.ts.map +1 -1
  45. package/lib/ecosystem/ui/SiteTile.js +3 -1
  46. package/lib/ecosystem/ui/SiteTile.js.map +1 -1
  47. package/lib/ecosystem/ui/glyphs.d.ts.map +1 -1
  48. package/lib/ecosystem/ui/glyphs.js +6 -5
  49. package/lib/ecosystem/ui/glyphs.js.map +1 -1
  50. package/lib/format/core/index.d.ts +1 -1
  51. package/lib/format/core/index.d.ts.map +1 -1
  52. package/lib/format/core/index.js +1 -1
  53. package/lib/format/core/index.js.map +1 -1
  54. package/lib/format/core/words.d.ts +9 -0
  55. package/lib/format/core/words.d.ts.map +1 -1
  56. package/lib/format/core/words.js +16 -0
  57. package/lib/format/core/words.js.map +1 -1
  58. package/lib/language/core/index.d.ts +3 -0
  59. package/lib/language/core/index.d.ts.map +1 -0
  60. package/lib/language/core/index.js +3 -0
  61. package/lib/language/core/index.js.map +1 -0
  62. package/lib/language/core/languageName.d.ts +8 -0
  63. package/lib/language/core/languageName.d.ts.map +1 -0
  64. package/lib/language/core/languageName.js +16 -0
  65. package/lib/language/core/languageName.js.map +1 -0
  66. package/lib/language/core/languageParam.d.ts +35 -0
  67. package/lib/language/core/languageParam.d.ts.map +1 -0
  68. package/lib/language/core/languageParam.js +67 -0
  69. package/lib/language/core/languageParam.js.map +1 -0
  70. package/lib/language/ui/SiteLanguage.d.ts +20 -0
  71. package/lib/language/ui/SiteLanguage.d.ts.map +1 -0
  72. package/lib/language/ui/SiteLanguage.js +14 -0
  73. package/lib/language/ui/SiteLanguage.js.map +1 -0
  74. package/lib/language/ui/index.d.ts +4 -0
  75. package/lib/language/ui/index.d.ts.map +1 -0
  76. package/lib/language/ui/index.js +3 -0
  77. package/lib/language/ui/index.js.map +1 -0
  78. package/lib/language/ui/siteLanguageContext.d.ts +12 -0
  79. package/lib/language/ui/siteLanguageContext.d.ts.map +1 -0
  80. package/lib/language/ui/siteLanguageContext.js +19 -0
  81. package/lib/language/ui/siteLanguageContext.js.map +1 -0
  82. package/lib/orbital/core/atomicOrbitals.d.ts +9 -1
  83. package/lib/orbital/core/atomicOrbitals.d.ts.map +1 -1
  84. package/lib/orbital/core/atomicOrbitals.js +7 -0
  85. package/lib/orbital/core/atomicOrbitals.js.map +1 -1
  86. package/lib/orbital/core/hydrogenic.d.ts +2 -1
  87. package/lib/orbital/core/hydrogenic.d.ts.map +1 -1
  88. package/lib/orbital/core/hydrogenic.js +2 -1
  89. package/lib/orbital/core/hydrogenic.js.map +1 -1
  90. package/lib/orbital/core/index.d.ts +1 -0
  91. package/lib/orbital/core/index.d.ts.map +1 -1
  92. package/lib/orbital/core/index.js +1 -0
  93. package/lib/orbital/core/index.js.map +1 -1
  94. package/lib/orbital/core/slaterEnergy.d.ts +35 -0
  95. package/lib/orbital/core/slaterEnergy.d.ts.map +1 -0
  96. package/lib/orbital/core/slaterEnergy.js +66 -0
  97. package/lib/orbital/core/slaterEnergy.js.map +1 -0
  98. package/lib/shared/ui/MenuButton.d.ts +3 -2
  99. package/lib/shared/ui/MenuButton.d.ts.map +1 -1
  100. package/lib/shared/ui/MenuButton.js +1 -1
  101. package/lib/shared/ui/MenuButton.js.map +1 -1
  102. package/lib/structure/core/conformerMinimise.d.ts +36 -0
  103. package/lib/structure/core/conformerMinimise.d.ts.map +1 -0
  104. package/lib/structure/core/conformerMinimise.js +81 -0
  105. package/lib/structure/core/conformerMinimise.js.map +1 -0
  106. package/lib/structure/core/conformerMinimum.d.ts +62 -0
  107. package/lib/structure/core/conformerMinimum.d.ts.map +1 -0
  108. package/lib/structure/core/conformerMinimum.js +90 -0
  109. package/lib/structure/core/conformerMinimum.js.map +1 -0
  110. package/lib/structure/core/conformerOptions.d.ts +62 -0
  111. package/lib/structure/core/conformerOptions.d.ts.map +1 -0
  112. package/lib/structure/core/conformerOptions.js +83 -0
  113. package/lib/structure/core/conformerOptions.js.map +1 -0
  114. package/lib/structure/core/conformerRefine.d.ts +104 -0
  115. package/lib/structure/core/conformerRefine.d.ts.map +1 -0
  116. package/lib/structure/core/conformerRefine.js +130 -0
  117. package/lib/structure/core/conformerRefine.js.map +1 -0
  118. package/lib/structure/core/conformerRefineRank.d.ts +36 -0
  119. package/lib/structure/core/conformerRefineRank.d.ts.map +1 -0
  120. package/lib/structure/core/conformerRefineRank.js +69 -0
  121. package/lib/structure/core/conformerRefineRank.js.map +1 -0
  122. package/lib/structure/core/conformerSession.d.ts +50 -0
  123. package/lib/structure/core/conformerSession.d.ts.map +1 -0
  124. package/lib/structure/core/conformerSession.js +88 -0
  125. package/lib/structure/core/conformerSession.js.map +1 -0
  126. package/lib/structure/core/conformerShape.d.ts +36 -0
  127. package/lib/structure/core/conformerShape.d.ts.map +1 -0
  128. package/lib/structure/core/conformerShape.js +150 -0
  129. package/lib/structure/core/conformerShape.js.map +1 -0
  130. package/lib/structure/core/conformers.d.ts +107 -0
  131. package/lib/structure/core/conformers.d.ts.map +1 -0
  132. package/lib/structure/core/conformers.js +149 -0
  133. package/lib/structure/core/conformers.js.map +1 -0
  134. package/lib/structure/core/geometryRelaxer.d.ts +66 -0
  135. package/lib/structure/core/geometryRelaxer.d.ts.map +1 -0
  136. package/lib/structure/core/geometryRelaxer.js +2 -0
  137. package/lib/structure/core/geometryRelaxer.js.map +1 -0
  138. package/lib/structure/core/index.d.ts +4 -0
  139. package/lib/structure/core/index.d.ts.map +1 -1
  140. package/lib/structure/core/index.js +2 -0
  141. package/lib/structure/core/index.js.map +1 -1
  142. package/lib/structure/core/moleculeCoordinates.d.ts +31 -0
  143. package/lib/structure/core/moleculeCoordinates.d.ts.map +1 -0
  144. package/lib/structure/core/moleculeCoordinates.js +80 -0
  145. package/lib/structure/core/moleculeCoordinates.js.map +1 -0
  146. package/lib/structure/core/molfileExport.d.ts +42 -0
  147. package/lib/structure/core/molfileExport.d.ts.map +1 -0
  148. package/lib/structure/core/molfileExport.js +47 -0
  149. package/lib/structure/core/molfileExport.js.map +1 -0
  150. package/lib/structure/core/oclResources.d.ts +12 -0
  151. package/lib/structure/core/oclResources.d.ts.map +1 -0
  152. package/lib/structure/core/oclResources.js +35 -0
  153. package/lib/structure/core/oclResources.js.map +1 -0
  154. package/lib/translate/core/catalog.d.ts +61 -0
  155. package/lib/translate/core/catalog.d.ts.map +1 -0
  156. package/lib/translate/core/catalog.js +49 -0
  157. package/lib/translate/core/catalog.js.map +1 -0
  158. package/lib/translate/core/checkTranslation.d.ts +32 -0
  159. package/lib/translate/core/checkTranslation.d.ts.map +1 -0
  160. package/lib/translate/core/checkTranslation.js +98 -0
  161. package/lib/translate/core/checkTranslation.js.map +1 -0
  162. package/lib/translate/core/contribution.d.ts +88 -0
  163. package/lib/translate/core/contribution.d.ts.map +1 -0
  164. package/lib/translate/core/contribution.js +14 -0
  165. package/lib/translate/core/contribution.js.map +1 -0
  166. package/lib/translate/core/index.d.ts +19 -0
  167. package/lib/translate/core/index.d.ts.map +1 -0
  168. package/lib/translate/core/index.js +15 -0
  169. package/lib/translate/core/index.js.map +1 -0
  170. package/lib/translate/core/marker.d.ts +45 -0
  171. package/lib/translate/core/marker.d.ts.map +1 -0
  172. package/lib/translate/core/marker.js +79 -0
  173. package/lib/translate/core/marker.js.map +1 -0
  174. package/lib/translate/core/mergeMessages.d.ts +35 -0
  175. package/lib/translate/core/mergeMessages.d.ts.map +1 -0
  176. package/lib/translate/core/mergeMessages.js +69 -0
  177. package/lib/translate/core/mergeMessages.js.map +1 -0
  178. package/lib/translate/core/session.d.ts +102 -0
  179. package/lib/translate/core/session.d.ts.map +1 -0
  180. package/lib/translate/core/session.js +162 -0
  181. package/lib/translate/core/session.js.map +1 -0
  182. package/lib/translate/core/start.d.ts +103 -0
  183. package/lib/translate/core/start.d.ts.map +1 -0
  184. package/lib/translate/core/start.js +92 -0
  185. package/lib/translate/core/start.js.map +1 -0
  186. package/lib/translate/core/suggestions.d.ts +77 -0
  187. package/lib/translate/core/suggestions.d.ts.map +1 -0
  188. package/lib/translate/core/suggestions.js +143 -0
  189. package/lib/translate/core/suggestions.js.map +1 -0
  190. package/lib/translate/core/tables.d.ts +100 -0
  191. package/lib/translate/core/tables.d.ts.map +1 -0
  192. package/lib/translate/core/tables.js +51 -0
  193. package/lib/translate/core/tables.js.map +1 -0
  194. package/lib/translate.d.ts +2 -0
  195. package/lib/translate.d.ts.map +1 -0
  196. package/lib/translate.js +6 -0
  197. package/lib/translate.js.map +1 -0
  198. package/lib/ui.d.ts +1 -0
  199. package/lib/ui.d.ts.map +1 -1
  200. package/lib/ui.js +1 -0
  201. package/lib/ui.js.map +1 -1
  202. package/lib/xtb/core/xtbRelaxer.d.ts +61 -0
  203. package/lib/xtb/core/xtbRelaxer.d.ts.map +1 -0
  204. package/lib/xtb/core/xtbRelaxer.js +108 -0
  205. package/lib/xtb/core/xtbRelaxer.js.map +1 -0
  206. package/lib/xtb.d.ts +11 -0
  207. package/lib/xtb.d.ts.map +1 -0
  208. package/lib/xtb.js +10 -0
  209. package/lib/xtb.js.map +1 -0
  210. package/package.json +18 -11
  211. package/src/chrome/ui/HeaderToggle.tsx +100 -0
  212. package/src/chrome/ui/index.ts +2 -0
  213. package/src/citation/core/gfn2Paper.ts +32 -0
  214. package/src/citation/core/index.ts +1 -0
  215. package/src/clipboard/ui/ClickToCopy.tsx +8 -7
  216. package/src/conformers.ts +87 -0
  217. package/src/core.ts +1 -0
  218. package/src/credits/core/credits.ts +16 -0
  219. package/src/ecosystem/core/index.ts +1 -0
  220. package/src/ecosystem/core/sites.ts +24 -4
  221. package/src/ecosystem/ui/EcosystemLinks.tsx +3 -1
  222. package/src/ecosystem/ui/SiteTile.tsx +3 -1
  223. package/src/ecosystem/ui/glyphs.tsx +16 -22
  224. package/src/format/core/index.ts +1 -1
  225. package/src/format/core/words.ts +19 -0
  226. package/src/language/core/index.ts +7 -0
  227. package/src/language/core/languageName.ts +16 -0
  228. package/src/language/core/languageParam.ts +70 -0
  229. package/src/language/ui/SiteLanguage.tsx +26 -0
  230. package/src/language/ui/index.ts +3 -0
  231. package/src/language/ui/siteLanguageContext.ts +20 -0
  232. package/src/orbital/core/atomicOrbitals.ts +17 -1
  233. package/src/orbital/core/hydrogenic.ts +2 -1
  234. package/src/orbital/core/index.ts +1 -0
  235. package/src/orbital/core/slaterEnergy.ts +83 -0
  236. package/src/shared/ui/MenuButton.tsx +4 -3
  237. package/src/structure/core/conformerMinimise.ts +99 -0
  238. package/src/structure/core/conformerMinimum.ts +125 -0
  239. package/src/structure/core/conformerOptions.ts +125 -0
  240. package/src/structure/core/conformerRefine.ts +234 -0
  241. package/src/structure/core/conformerRefineRank.ts +89 -0
  242. package/src/structure/core/conformerSession.ts +123 -0
  243. package/src/structure/core/conformerShape.ts +181 -0
  244. package/src/structure/core/conformers.ts +282 -0
  245. package/src/structure/core/geometryRelaxer.ts +71 -0
  246. package/src/structure/core/index.ts +13 -0
  247. package/src/structure/core/moleculeCoordinates.ts +93 -0
  248. package/src/structure/core/molfileExport.ts +62 -0
  249. package/src/structure/core/oclResources.ts +41 -0
  250. package/src/translate/core/catalog.ts +83 -0
  251. package/src/translate/core/checkTranslation.ts +128 -0
  252. package/src/translate/core/contribution.ts +99 -0
  253. package/src/translate/core/index.ts +72 -0
  254. package/src/translate/core/marker.ts +85 -0
  255. package/src/translate/core/mergeMessages.ts +74 -0
  256. package/src/translate/core/session.ts +250 -0
  257. package/src/translate/core/start.ts +183 -0
  258. package/src/translate/core/suggestions.ts +211 -0
  259. package/src/translate/core/tables.ts +120 -0
  260. package/src/translate.ts +5 -0
  261. package/src/ui.ts +1 -0
  262. package/src/xtb/core/xtbRelaxer.ts +160 -0
  263. package/src/xtb.ts +16 -0
  264. package/styles/chrome.css +61 -30
@@ -12,6 +12,7 @@ export {
12
12
  citationFilename,
13
13
  formatCitation,
14
14
  } from './formats.ts';
15
+ export { GFN2_XTB_PAPER, GFN2_XTB_WORK } from './gfn2Paper.ts';
15
16
  export { OPENCHEMLIB_PAPER, OPENCHEMLIB_WORK } from './openchemlibPaper.ts';
16
17
  export { PLATFORM_PAPER, PLATFORM_WORK } from './platformPaper.ts';
17
18
  export type { Reference, ReferenceAuthor } from './reference.ts';
@@ -24,7 +24,7 @@ export interface ClickToCopyProps {
24
24
  * function is called only when the value is clicked.
25
25
  */
26
26
  value: ClipboardContent | (() => ClipboardContent);
27
- /** What is shown; the pointer turns into the copy cursor over it. */
27
+ /** What is shown; the pointer turns into a clipboard over it. */
28
28
  children: ReactNode;
29
29
  /**
30
30
  * What the value is, named in the hover title: `Copy the SMILES (C=CC=O)`.
@@ -46,9 +46,10 @@ export interface ClickToCopyProps {
46
46
  */
47
47
  as?: ClickToCopyElement;
48
48
  /**
49
- * Whether the value is a tab stop and a button of its own, with its glyph.
50
- * Off when a copy button beside it already copies the same value, so the
51
- * keyboard and a screen reader meet one control, and the eye one glyph.
49
+ * Whether the value is a tab stop and a button of its own, with the glyph a
50
+ * keyboard is shown instead of the cursor. Off when a copy button beside it
51
+ * already copies the same value, so the keyboard and a screen reader meet
52
+ * one control.
52
53
  * @default true
53
54
  */
54
55
  focusable?: boolean;
@@ -83,9 +84,9 @@ const NESTED_CONTROL =
83
84
  * A value that is copied by clicking it.
84
85
  *
85
86
  * Text in a tool is not selectable — a drag across a viewer must not paint the
86
- * page — so what is worth taking away is copied this way instead: the copy
87
- * cursor, a tint and a clipboard glyph announce it on hover, a click or `Enter`
88
- * puts it on the clipboard, and a tick confirms it. The click stops there, so
87
+ * page — so what is worth taking away is copied this way instead: a cursor
88
+ * carrying a clipboard and a tint announce it on hover, a click or `Enter` puts
89
+ * it on the clipboard, and a tick confirms it. The click stops there, so
89
90
  * a value inside a clickable row copies without also opening the row, and a
90
91
  * link or a button nested in the value keeps its own click.
91
92
  * @param props - See {@link ClickToCopyProps}.
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Conformers of a structure: generated, MMFF94-ranked, duplicate minima
3
+ * dropped, and refined against a `GeometryRelaxer`.
4
+ *
5
+ * Its own door because every step runs openchemlib, and `react-cheminfo/core`
6
+ * costs nothing on import. The relaxer contract itself, and the coordinates a
7
+ * relaxer reads and writes, stay in `react-cheminfo/core`: the code that
8
+ * orchestrates a refinement needs neither openchemlib nor WebAssembly.
9
+ */
10
+
11
+ export type {
12
+ Conformer,
13
+ ConformerLimits,
14
+ ConformerRanking,
15
+ ConformerSet,
16
+ StopReason,
17
+ } from './structure/core/conformers.ts';
18
+ export {
19
+ continueConformers,
20
+ generateConformers,
21
+ strategyConstant,
22
+ } from './structure/core/conformers.ts';
23
+ export type {
24
+ ConformerRefinement,
25
+ ConformerSetRefinement,
26
+ RefineConformersOptions,
27
+ } from './structure/core/conformerRefine.ts';
28
+ export {
29
+ REFINED_RANKING,
30
+ REFINED_SAME_ENERGY_TOLERANCE,
31
+ refineConformers,
32
+ } from './structure/core/conformerRefine.ts';
33
+ export type {
34
+ RefinedMinimum,
35
+ RefinedRanking,
36
+ } from './structure/core/conformerRefineRank.ts';
37
+ export {
38
+ isRefinedDuplicate,
39
+ rankByRefinedEnergy,
40
+ } from './structure/core/conformerRefineRank.ts';
41
+ export type { RankedConformer } from './structure/core/conformerMinimise.ts';
42
+ export {
43
+ minimiseConformer,
44
+ rankByEnergy,
45
+ } from './structure/core/conformerMinimise.ts';
46
+ export type { KeptConformer } from './structure/core/conformerMinimum.ts';
47
+ export {
48
+ SAME_CHIRALITY_TOLERANCE,
49
+ SAME_ENERGY_TOLERANCE,
50
+ SAME_SHAPE_TOLERANCE,
51
+ isKeptMinimum,
52
+ isSameMinimum,
53
+ isSameShape,
54
+ minimisedShapes,
55
+ } from './structure/core/conformerMinimum.ts';
56
+ export type {
57
+ ConformerOptions,
58
+ ConformerStrategy,
59
+ MinimisationAlgorithm,
60
+ } from './structure/core/conformerOptions.ts';
61
+ export {
62
+ CONFORMER_STRATEGIES,
63
+ DEFAULT_CONFORMER_OPTIONS,
64
+ MINIMISATION_ALGORITHMS,
65
+ MINIMISATION_LABELS,
66
+ ROTATABLE_BOND_WARNING,
67
+ STRATEGY_DETAILS,
68
+ STRATEGY_LABELS,
69
+ isConformerStrategy,
70
+ isMinimisationAlgorithm,
71
+ sameConformerOptions,
72
+ } from './structure/core/conformerOptions.ts';
73
+ export type { ConformerSession } from './structure/core/conformerSession.ts';
74
+ export {
75
+ keepConformerSession,
76
+ openConformerSession,
77
+ readPotentialCount,
78
+ } from './structure/core/conformerSession.ts';
79
+ export type {
80
+ ConformerShape,
81
+ PrincipalMoments,
82
+ } from './structure/core/conformerShape.ts';
83
+ export {
84
+ conformerShape,
85
+ hasFiniteCoordinates,
86
+ } from './structure/core/conformerShape.ts';
87
+ export { registerResources } from './structure/core/oclResources.ts';
package/src/core.ts CHANGED
@@ -10,6 +10,7 @@ export * from './download/core/index.ts';
10
10
  export * from './ecosystem/core/index.ts';
11
11
  export * from './error/core/index.ts';
12
12
  export * from './format/core/index.ts';
13
+ export * from './language/core/index.ts';
13
14
  export * from './orbital/core/index.ts';
14
15
  export * from './overlay/core/index.ts';
15
16
  export * from './parallel/core/index.ts';
@@ -143,6 +143,22 @@ export const CREDITS = [
143
143
  description: 'the array and spectrum operations the data goes through.',
144
144
  license: 'MIT',
145
145
  },
146
+ {
147
+ id: 'occ',
148
+ name: 'OCC',
149
+ href: 'https://github.com/peterspackman/occ',
150
+ description:
151
+ 'the GFN2-xTB implementation the refined geometries and energies come from.',
152
+ license: 'GPL-3.0',
153
+ },
154
+ {
155
+ id: 'xtb-wasm',
156
+ name: 'xtb-wasm',
157
+ href: 'https://github.com/cheminfo/xtb-wasm',
158
+ description:
159
+ 'GFN2-xTB compiled to WebAssembly, driven from a pool of web workers.',
160
+ license: 'MIT',
161
+ },
146
162
  {
147
163
  id: 'molstar',
148
164
  name: 'Mol*',
@@ -15,6 +15,7 @@ export type {
15
15
  SiteMarkColors,
16
16
  SiteName,
17
17
  SiteRecord,
18
+ SiteUrlOptions,
18
19
  } from './sites.ts';
19
20
  export { ECOSYSTEM_SITES, siteUrl } from './sites.ts';
20
21
  export { siteTokensCss } from './tokens.ts';
@@ -1,4 +1,6 @@
1
1
  // tokens-ok: file — every site's two colours are declared here.
2
+ import { withLanguageParam } from '../../language/core/languageParam.ts';
3
+
2
4
  import type { EcosystemSite, SiteRecord } from './types.ts';
3
5
 
4
6
  export type {
@@ -118,8 +120,10 @@ export const ECOSYSTEM_SITES: readonly EcosystemSite[] = [
118
120
  tagline: 'Turn a batch of NMR spectra into a map of your samples.',
119
121
  group: 'spectra',
120
122
  brand: '#4d7c0f',
121
- brandAlt: '#b91c1c',
122
- mark: { plate: '#4d7c0f', accent: '#b91c1c' },
123
+ // A yellow, because it is what stays apart from both this green and the
124
+ // white for a red–green colour-blind visitor; any red merges with the plate.
125
+ brandAlt: '#a16207',
126
+ mark: { plate: '#4d7c0f', accent: '#fde047' },
123
127
  },
124
128
  {
125
129
  id: 'derepflow',
@@ -294,6 +298,7 @@ export const ECOSYSTEM_SITES: readonly EcosystemSite[] = [
294
298
  name: { lead: 'atoms', alt: 'cheminfo', dot: true },
295
299
  host: 'atoms.cheminfo.org',
296
300
  repository: 'https://github.com/cheminfo/atoms.cheminfo.org',
301
+ publicRepository: true,
297
302
  tagline: 'Electrons, neutrons, Lewis structures and oxidation states.',
298
303
  group: 'practice',
299
304
  brand: '#b91c1c',
@@ -307,6 +312,7 @@ export const ECOSYSTEM_SITES: readonly EcosystemSite[] = [
307
312
  name: { lead: 'moles', alt: 'cheminfo', dot: true },
308
313
  host: 'moles.cheminfo.org',
309
314
  repository: 'https://github.com/cheminfo/moles.cheminfo.org',
315
+ publicRepository: true,
310
316
  tagline: 'Balance a reaction, and work out its mass composition.',
311
317
  group: 'practice',
312
318
  brand: '#334155',
@@ -330,11 +336,25 @@ export const ECOSYSTEM_SITES: readonly EcosystemSite[] = [
330
336
  },
331
337
  ];
332
338
 
339
+ /** How a link to a site is written, beyond the site itself. */
340
+ export interface SiteUrlOptions {
341
+ /**
342
+ * The language the visitor is reading in, carried so the site opens in it
343
+ * rather than in the one it defaults to.
344
+ * @default undefined — the link names no language
345
+ */
346
+ language?: string;
347
+ }
348
+
333
349
  /**
334
350
  * The address of a site, which is its host over https.
335
351
  * @param site - The site being linked to.
352
+ * @param options - See {@link SiteUrlOptions}.
336
353
  * @returns The URL to open.
337
354
  */
338
- export function siteUrl(site: SiteRecord): string {
339
- return `https://${site.host}/`;
355
+ export function siteUrl(
356
+ site: SiteRecord,
357
+ options: SiteUrlOptions = {},
358
+ ): string {
359
+ return withLanguageParam(`https://${site.host}/`, options.language);
340
360
  }
@@ -1,5 +1,6 @@
1
1
  import type { CSSProperties, ReactElement } from 'react';
2
2
 
3
+ import { useSiteLanguage } from '../../language/ui/siteLanguageContext.ts';
3
4
  import { joinClassNames } from '../../shared/ui/joinClassNames.ts';
4
5
  import { TOKEN } from '../../tokens/core/familyTokens.ts';
5
6
  import { groupedSites } from '../core/lookup.ts';
@@ -87,6 +88,7 @@ export interface EcosystemLinksProps {
87
88
  * @returns The section of links.
88
89
  */
89
90
  export function EcosystemLinks(props: EcosystemLinksProps): ReactElement {
91
+ const language = useSiteLanguage();
90
92
  const {
91
93
  className,
92
94
  currentSiteId,
@@ -117,7 +119,7 @@ export function EcosystemLinks(props: EcosystemLinksProps): ReactElement {
117
119
  <a
118
120
  key={site.id}
119
121
  style={{ ...LINK_STYLE, color: site.brand }}
120
- href={siteUrl(site)}
122
+ href={siteUrl(site, { language })}
121
123
  >
122
124
  {site.host}
123
125
  </a>
@@ -1,5 +1,6 @@
1
1
  import type { CSSProperties, ReactElement } from 'react';
2
2
 
3
+ import { useSiteLanguage } from '../../language/ui/siteLanguageContext.ts';
3
4
  import { TOKEN } from '../../tokens/core/familyTokens.ts';
4
5
  import { siteNameColors } from '../core/nameColors.ts';
5
6
  import type { EcosystemSite, SiteId } from '../core/sites.ts';
@@ -85,6 +86,7 @@ export interface SiteTileProps {
85
86
  * @returns The tile.
86
87
  */
87
88
  export function SiteTile(props: SiteTileProps): ReactElement {
89
+ const language = useSiteLanguage();
88
90
  const {
89
91
  className,
90
92
  site,
@@ -140,7 +142,7 @@ export function SiteTile(props: SiteTileProps): ReactElement {
140
142
  <a
141
143
  className={className}
142
144
  style={style}
143
- href={siteUrl(site)}
145
+ href={siteUrl(site, { language })}
144
146
  target={newTab ? '_blank' : undefined}
145
147
  rel={newTab ? 'noreferrer' : undefined}
146
148
  onMouseEnter={() => onHover?.(site.id)}
@@ -179,30 +179,24 @@ export const GLYPHS: Record<SiteId, (alt: string) => ReactNode> = {
179
179
  />
180
180
  </g>
181
181
  ),
182
- // Two groups of samples with the outline that holds each: the picture the
183
- // tool exists to draw. One is drawn and one is filled rather than both
184
- // outlined, because two rings crossing close up into a blob at 16 px —
185
- // checked at 16, 20, 24, 32 and 64 before this was settled on.
182
+ // A score plot without its axes: four samples, and the three the analysis
183
+ // sets apart carrying the answering colour — the map the tool exists to
184
+ // draw. The spacing is irregular so the groups read as measured samples
185
+ // rather than as a pattern, and the two groups sit six units apart, against
186
+ // under one inside either.
186
187
  metabo: (accent) => (
187
188
  <>
188
- <ellipse
189
- cx="12"
190
- cy="12.5"
191
- rx="5.8"
192
- ry="9"
193
- fill="none"
194
- stroke="#ffffff"
195
- strokeWidth="3"
196
- transform="rotate(-32 12 12.5)"
197
- />
198
- <ellipse
199
- cx="20.5"
200
- cy="20"
201
- rx="5.4"
202
- ry="8.6"
203
- fill={accent}
204
- transform="rotate(32 20.5 20)"
205
- />
189
+ <g fill="#ffffff">
190
+ <circle cx="6.6" cy="20.4" r="2.6" />
191
+ <circle cx="12.4" cy="18.3" r="2.6" />
192
+ <circle cx="9.3" cy="25.8" r="2.6" />
193
+ <circle cx="14.9" cy="24.1" r="2.6" />
194
+ </g>
195
+ <g fill={accent}>
196
+ <circle cx="20.1" cy="7.2" r="2.6" />
197
+ <circle cx="25.8" cy="8.6" r="2.6" />
198
+ <circle cx="22.2" cy="13.2" r="2.6" />
199
+ </g>
206
200
  </>
207
201
  ),
208
202
  // One formula branching into every structure it can be.
@@ -14,4 +14,4 @@ export { roundTo } from './roundTo.ts';
14
14
  export { formatSuperscript } from './superscript.ts';
15
15
  export type { DurationStyle, FormatDurationOptions } from './units.ts';
16
16
  export { formatBytes, formatDuration } from './units.ts';
17
- export { pluralize } from './words.ts';
17
+ export { ordinal, pluralize } from './words.ts';
@@ -15,3 +15,22 @@ export function pluralize(
15
15
  ): string {
16
16
  return count === 1 ? singular : plural;
17
17
  }
18
+
19
+ /**
20
+ * English ordinal of a position.
21
+ *
22
+ * Only the ordinal comes back, never the noun it counts, so the caller writes
23
+ * the sentence: `the ${ordinal(n)} conformer produced`.
24
+ * @param position - 1-based position.
25
+ * @returns E.g. `1st`, `2nd`, `12th`, `23rd`.
26
+ */
27
+ export function ordinal(position: number): string {
28
+ const teens = position % 100;
29
+ const suffix =
30
+ teens >= 11 && teens <= 13
31
+ ? 'th'
32
+ : (ORDINAL_SUFFIXES[position % 10] ?? 'th');
33
+ return `${position}${suffix}`;
34
+ }
35
+
36
+ const ORDINAL_SUFFIXES: Record<number, string> = { 1: 'st', 2: 'nd', 3: 'rd' };
@@ -0,0 +1,7 @@
1
+ export { languageName } from './languageName.ts';
2
+ export {
3
+ LANGUAGE_PARAM,
4
+ isLanguageTag,
5
+ readLanguageParam,
6
+ withLanguageParam,
7
+ } from './languageParam.ts';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The name of a language, e.g. `French` for `fr`.
3
+ * @param locale - The locale to name.
4
+ * @param displayLocale - The language the name is written in.
5
+ * @returns The name, or the tag itself when the runtime cannot name it.
6
+ */
7
+ export function languageName(locale: string, displayLocale = 'en'): string {
8
+ try {
9
+ return (
10
+ new Intl.DisplayNames([displayLocale], { type: 'language' }).of(locale) ??
11
+ locale
12
+ );
13
+ } catch {
14
+ return locale;
15
+ }
16
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * The language a page is read in, as the family carries it between its sites.
3
+ *
4
+ * A link from one site to another keeps the language the visitor is reading
5
+ * in: the tag travels as a query parameter rather than as the path prefix a
6
+ * translated site routes by, because the site being linked to may not speak
7
+ * that language at all. A parameter it does not know is ignored; a `/fr/`
8
+ * path it does not have is a 404.
9
+ */
10
+
11
+ import { parseQueryString } from '../../router/core/query.ts';
12
+
13
+ /** Query parameter every site of the family carries its language in. */
14
+ export const LANGUAGE_PARAM = 'lang';
15
+
16
+ /**
17
+ * Whether a string is a language a link may name: a BCP 47 tag already
18
+ * written in its canonical form, e.g. `fr`, `pt-BR`, `zh-Hant`.
19
+ * @param value - The candidate tag.
20
+ * @returns True when the tag is valid and canonical.
21
+ */
22
+ export function isLanguageTag(value: string): boolean {
23
+ if (value.length === 0 || value.length > 35) return false;
24
+ try {
25
+ return Intl.getCanonicalLocales(value)[0] === value;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+
31
+ /**
32
+ * The language an address names.
33
+ * @param search - The query string, with or without its leading `?`.
34
+ * @returns The tag, or `undefined` when the address names none or names
35
+ * something that is not a language.
36
+ */
37
+ export function readLanguageParam(search: string): string | undefined {
38
+ const value = parseQueryString(search)[LANGUAGE_PARAM];
39
+ if (value === undefined || !isLanguageTag(value)) return undefined;
40
+ return value;
41
+ }
42
+
43
+ /**
44
+ * An address that names the language it should be read in.
45
+ * @param url - The address, absolute or relative.
46
+ * @param language - The tag to write, or `undefined` to leave the address
47
+ * alone — which is what a site passes while it is in the language every
48
+ * other site defaults to.
49
+ * @returns The address, with the language written into its query.
50
+ */
51
+ export function withLanguageParam(
52
+ url: string,
53
+ language: string | undefined,
54
+ ): string {
55
+ if (language === undefined || !isLanguageTag(language)) return url;
56
+ let address: URL;
57
+ try {
58
+ address = new URL(url, RELATIVE_BASE);
59
+ } catch {
60
+ return url;
61
+ }
62
+ address.searchParams.set(LANGUAGE_PARAM, language);
63
+ const written = address.toString();
64
+ return written.startsWith(RELATIVE_BASE)
65
+ ? written.slice(RELATIVE_BASE.length)
66
+ : written;
67
+ }
68
+
69
+ // Only ever used to resolve a relative address, and stripped again after.
70
+ const RELATIVE_BASE = 'https://relative.invalid';
@@ -0,0 +1,26 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+
3
+ import { SiteLanguageContext } from './siteLanguageContext.ts';
4
+
5
+ /** Props of {@link SiteLanguage}. */
6
+ export interface SiteLanguageProps {
7
+ /**
8
+ * The language the page is being read in, or `undefined` while it is the
9
+ * one every site opens in — a link then names no language at all.
10
+ */
11
+ value: string | undefined;
12
+ /** The page. */
13
+ children: ReactNode;
14
+ }
15
+
16
+ /**
17
+ * Tells every link to a sibling site which language the visitor is reading in,
18
+ * so moving between the tools of the family keeps the language rather than
19
+ * landing in English again.
20
+ * @param props - The language, and the page under it.
21
+ * @returns The page.
22
+ */
23
+ export function SiteLanguage(props: SiteLanguageProps): ReactElement {
24
+ const { value, children } = props;
25
+ return <SiteLanguageContext value={value}>{children}</SiteLanguageContext>;
26
+ }
@@ -0,0 +1,3 @@
1
+ export type { SiteLanguageProps } from './SiteLanguage.tsx';
2
+ export { SiteLanguage } from './SiteLanguage.tsx';
3
+ export { useSiteLanguage } from './siteLanguageContext.ts';
@@ -0,0 +1,20 @@
1
+ import { createContext, use } from 'react';
2
+
3
+ import { readLanguageParam } from '../core/languageParam.ts';
4
+
5
+ /** What a site declares the page is being read in. */
6
+ export const SiteLanguageContext = createContext<string | undefined>(undefined);
7
+
8
+ /**
9
+ * The language a link out of this page should name.
10
+ *
11
+ * Under a `SiteLanguage` it is what the site declared. Without one it is
12
+ * whatever the address itself names, so a site that has not been told anything
13
+ * still passes on the language it was opened in.
14
+ * @returns The tag, or `undefined` when no language is to be carried.
15
+ */
16
+ export function useSiteLanguage(): string | undefined {
17
+ const declared = use(SiteLanguageContext);
18
+ if (declared !== undefined) return declared;
19
+ return readLanguageParam(globalThis.location?.search ?? '');
20
+ }
@@ -29,6 +29,7 @@ import {
29
29
  import type { RealHarmonic } from './realHarmonics.ts';
30
30
  import { harmonicsOf, subshellLetter } from './realHarmonics.ts';
31
31
  import { slaterScreening } from './screening.ts';
32
+ import { slaterRemovalEnergy } from './slaterEnergy.ts';
32
33
 
33
34
  /** One atomic orbital of one element: a shape, a size and an occupancy. */
34
35
  export interface AtomicOrbital {
@@ -50,8 +51,16 @@ export interface AtomicOrbital {
50
51
  effectiveCharge: number;
51
52
  /** Shielding `S` those rules produced. */
52
53
  shielding: number;
53
- /** `−13.6 Z_eff²/n²`, electronvolts. */
54
+ /** `−13.606 Z_eff²/n²`, electronvolts: one rydberg times `Z_eff²/n²`. */
54
55
  energy: number;
56
+ /**
57
+ * Energy to pull this electron off the atom, electronvolts: the difference
58
+ * of Slater total energies between the ion and the atom. `null` when the
59
+ * subshell is empty, there being no electron to remove. This, not
60
+ * {@link AtomicOrbital.energy}, is the number to compare with a measured
61
+ * ionisation energy — see `slaterEnergy.ts`.
62
+ */
63
+ removalEnergy: number | null;
55
64
  /** `n − ℓ − 1` spheres on which the wavefunction changes sign. */
56
65
  radialNodes: number;
57
66
  /** ℓ planes or cones on which it changes sign. */
@@ -120,6 +129,12 @@ export function atomicOrbitalsOf(
120
129
  l: subshell.l,
121
130
  charge,
122
131
  };
132
+ // Once per subshell, not once per harmonic: the seven orbitals of an f
133
+ // subshell share one removal energy.
134
+ const removalEnergy =
135
+ subshellElectrons === 0
136
+ ? null
137
+ : slaterRemovalEnergy(atomicNumber, configuration, subshell);
123
138
  const harmonics = harmonicsOf(subshell.l);
124
139
  const spread = hundDistribution(subshellElectrons, harmonics.length);
125
140
  for (let index = 0; index < harmonics.length; index++) {
@@ -135,6 +150,7 @@ export function atomicOrbitalsOf(
135
150
  effectiveCharge: charge,
136
151
  shielding: screening.shielding,
137
152
  energy: orbitalEnergy(parameters),
153
+ removalEnergy,
138
154
  radialNodes: radialNodeCount(parameters),
139
155
  angularNodes: subshell.l,
140
156
  meanRadius: meanRadius(parameters),
@@ -57,7 +57,8 @@ export function meanRadius(parameters: HydrogenicParameters): number {
57
57
  }
58
58
 
59
59
  /**
60
- * Orbital energy in the hydrogen-like model, `E = −13.6 Z²/n²` eV.
60
+ * Orbital energy in the hydrogen-like model, `E = −13.606 Z²/n²` eV — one
61
+ * rydberg times `Z²/n²`.
61
62
  * @param parameters - Which orbital.
62
63
  * @returns The energy in electronvolts, always negative.
63
64
  */
@@ -69,3 +69,4 @@ export type {
69
69
  export { runAtomicSample } from './sample.ts';
70
70
  export type { Screening } from './screening.ts';
71
71
  export { groupRank, slaterScreening } from './screening.ts';
72
+ export { slaterRemovalEnergy, slaterTotalEnergy } from './slaterEnergy.ts';
@@ -0,0 +1,83 @@
1
+ /**
2
+ * What Slater's rules are actually good for: the energy it takes to pull one
3
+ * electron off the atom.
4
+ *
5
+ * The hydrogen-like orbital energy `−Ry Z_eff²/n²` is the model's own number
6
+ * and it orders the orbitals correctly, but it is not an ionisation energy and
7
+ * must never be read as one — it is 5.4× the measured value for neon, while
8
+ * being within 10% for lithium, so it is not even a constant factor off.
9
+ *
10
+ * Slater fitted his rules to *total* energies, and that is how they are used:
11
+ * add up `n Z_eff²/n²` over every electron of the atom, do the same for the ion
12
+ * with one electron gone — recomputing the shielding, which is the whole point,
13
+ * since the remaining electrons are screened by one fewer neighbour — and
14
+ * subtract. Over the first four periods that difference lands within a factor
15
+ * 0.74–1.81 of the measured first ionisation energy, against 0.9–5.4 for the
16
+ * orbital energy.
17
+ */
18
+
19
+ import { RYDBERG_ELECTRONVOLTS } from './constants.ts';
20
+ import type { Subshell, SubshellOccupancy } from './electronConfiguration.ts';
21
+ import { slaterScreening } from './screening.ts';
22
+
23
+ /**
24
+ * Total electronic energy of a configuration in the Slater model.
25
+ * @param atomicNumber - Proton count, the `Z` each electron is screened from.
26
+ * @param configuration - Every occupied subshell.
27
+ * @returns The sum of `−Ry Z_eff²/n²` over every electron, electronvolts.
28
+ */
29
+ export function slaterTotalEnergy(
30
+ atomicNumber: number,
31
+ configuration: readonly SubshellOccupancy[],
32
+ ): number {
33
+ let energy = 0;
34
+ for (const occupied of configuration) {
35
+ const { effectiveCharge } = slaterScreening(
36
+ atomicNumber,
37
+ configuration,
38
+ occupied,
39
+ );
40
+ energy -=
41
+ (occupied.electrons *
42
+ RYDBERG_ELECTRONVOLTS *
43
+ effectiveCharge *
44
+ effectiveCharge) /
45
+ (occupied.n * occupied.n);
46
+ }
47
+ return energy;
48
+ }
49
+
50
+ /**
51
+ * Energy needed to take one electron out of a subshell and off the atom.
52
+ * @param atomicNumber - Proton count.
53
+ * @param configuration - Every occupied subshell of the neutral atom.
54
+ * @param subshell - The subshell the electron leaves.
55
+ * @returns `E(ion) − E(atom)`, electronvolts, positive for a bound electron.
56
+ * @throws {RangeError} When that subshell holds no electron to remove.
57
+ */
58
+ export function slaterRemovalEnergy(
59
+ atomicNumber: number,
60
+ configuration: readonly SubshellOccupancy[],
61
+ subshell: Subshell,
62
+ ): number {
63
+ const ion: SubshellOccupancy[] = [];
64
+ let found = false;
65
+ for (const occupied of configuration) {
66
+ if (occupied.n === subshell.n && occupied.l === subshell.l) {
67
+ found = true;
68
+ if (occupied.electrons === 1) continue;
69
+ ion.push({ ...occupied, electrons: occupied.electrons - 1 });
70
+ continue;
71
+ }
72
+ ion.push(occupied);
73
+ }
74
+ if (!found) {
75
+ throw new RangeError(
76
+ `the ${subshell.n}${'spdf'[subshell.l] ?? '?'} subshell holds no electron to remove`,
77
+ );
78
+ }
79
+ return (
80
+ slaterTotalEnergy(atomicNumber, ion) -
81
+ slaterTotalEnergy(atomicNumber, configuration)
82
+ );
83
+ }