react-cheminfo 0.46.0 → 0.48.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 (229) hide show
  1. package/README.md +69 -0
  2. package/lib/chart/core/chartDomain.d.ts +14 -0
  3. package/lib/chart/core/chartDomain.d.ts.map +1 -1
  4. package/lib/chart/core/chartDomain.js +1 -0
  5. package/lib/chart/core/chartDomain.js.map +1 -1
  6. package/lib/chart/core/selectionGeometry.d.ts +4 -2
  7. package/lib/chart/core/selectionGeometry.d.ts.map +1 -1
  8. package/lib/chart/core/selectionGeometry.js +4 -2
  9. package/lib/chart/core/selectionGeometry.js.map +1 -1
  10. package/lib/chart/core/zoomDomain.d.ts +11 -1
  11. package/lib/chart/core/zoomDomain.d.ts.map +1 -1
  12. package/lib/chart/core/zoomDomain.js +25 -5
  13. package/lib/chart/core/zoomDomain.js.map +1 -1
  14. package/lib/chart/ui/chartGestures.d.ts +26 -1
  15. package/lib/chart/ui/chartGestures.d.ts.map +1 -1
  16. package/lib/chart/ui/chartGestures.js +21 -0
  17. package/lib/chart/ui/chartGestures.js.map +1 -1
  18. package/lib/chart/ui/index.d.ts +1 -1
  19. package/lib/chart/ui/index.d.ts.map +1 -1
  20. package/lib/chart/ui/index.js +1 -1
  21. package/lib/chart/ui/index.js.map +1 -1
  22. package/lib/chart/ui/useChartZoom.d.ts.map +1 -1
  23. package/lib/chart/ui/useChartZoom.js +17 -1
  24. package/lib/chart/ui/useChartZoom.js.map +1 -1
  25. package/lib/core.d.ts +1 -0
  26. package/lib/core.d.ts.map +1 -1
  27. package/lib/core.js +1 -0
  28. package/lib/core.js.map +1 -1
  29. package/lib/download/core/cssPaint.d.ts +27 -0
  30. package/lib/download/core/cssPaint.d.ts.map +1 -0
  31. package/lib/download/core/cssPaint.js +63 -0
  32. package/lib/download/core/cssPaint.js.map +1 -0
  33. package/lib/download/core/drawingMarkup.d.ts +11 -0
  34. package/lib/download/core/drawingMarkup.d.ts.map +1 -0
  35. package/lib/download/core/drawingMarkup.js +32 -0
  36. package/lib/download/core/drawingMarkup.js.map +1 -0
  37. package/lib/download/core/figureHtml.d.ts +25 -0
  38. package/lib/download/core/figureHtml.d.ts.map +1 -0
  39. package/lib/download/core/figureHtml.js +174 -0
  40. package/lib/download/core/figureHtml.js.map +1 -0
  41. package/lib/download/core/figureHtmlMarkup.d.ts +107 -0
  42. package/lib/download/core/figureHtmlMarkup.d.ts.map +1 -0
  43. package/lib/download/core/figureHtmlMarkup.js +75 -0
  44. package/lib/download/core/figureHtmlMarkup.js.map +1 -0
  45. package/lib/download/core/figureSvg.d.ts.map +1 -1
  46. package/lib/download/core/figureSvg.js +16 -35
  47. package/lib/download/core/figureSvg.js.map +1 -1
  48. package/lib/download/core/figureSvgDocument.d.ts +3 -3
  49. package/lib/download/core/figureSvgDocument.d.ts.map +1 -1
  50. package/lib/download/core/figureTarget.d.ts +14 -3
  51. package/lib/download/core/figureTarget.d.ts.map +1 -1
  52. package/lib/download/core/figureTarget.js +42 -3
  53. package/lib/download/core/figureTarget.js.map +1 -1
  54. package/lib/download/core/index.d.ts +1 -1
  55. package/lib/download/core/index.d.ts.map +1 -1
  56. package/lib/download/core/index.js +1 -1
  57. package/lib/download/core/index.js.map +1 -1
  58. package/lib/download/core/textLines.d.ts +27 -0
  59. package/lib/download/core/textLines.d.ts.map +1 -0
  60. package/lib/download/core/textLines.js +51 -0
  61. package/lib/download/core/textLines.js.map +1 -0
  62. package/lib/ecosystem/core/lookup.d.ts +2 -1
  63. package/lib/ecosystem/core/lookup.d.ts.map +1 -1
  64. package/lib/ecosystem/core/lookup.js +10 -3
  65. package/lib/ecosystem/core/lookup.js.map +1 -1
  66. package/lib/ecosystem/core/types.d.ts +2 -2
  67. package/lib/ecosystem/core/types.d.ts.map +1 -1
  68. package/lib/ecosystem/core/unlistedSites.d.ts +9 -0
  69. package/lib/ecosystem/core/unlistedSites.d.ts.map +1 -0
  70. package/lib/ecosystem/core/unlistedSites.js +35 -0
  71. package/lib/ecosystem/core/unlistedSites.js.map +1 -0
  72. package/lib/ecosystem/ui/glyphs.d.ts.map +1 -1
  73. package/lib/ecosystem/ui/glyphs.js +7 -0
  74. package/lib/ecosystem/ui/glyphs.js.map +1 -1
  75. package/lib/i18n/core/chromeCatalog.d.ts +1 -1
  76. package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
  77. package/lib/ir/core/irMode.d.ts.map +1 -1
  78. package/lib/ir/core/irMode.js +6 -1
  79. package/lib/ir/core/irMode.js.map +1 -1
  80. package/lib/locales/de.json +56 -1
  81. package/lib/locales/en.json +56 -1
  82. package/lib/locales/es.json +56 -1
  83. package/lib/locales/fr.json +56 -1
  84. package/lib/locales/it.json +56 -1
  85. package/lib/periodic/core/index.d.ts +1 -1
  86. package/lib/periodic/core/index.d.ts.map +1 -1
  87. package/lib/periodic/core/layout.d.ts +11 -0
  88. package/lib/periodic/core/layout.d.ts.map +1 -1
  89. package/lib/periodic/core/layout.js.map +1 -1
  90. package/lib/periodic/ui/ElementCell.d.ts +6 -2
  91. package/lib/periodic/ui/ElementCell.d.ts.map +1 -1
  92. package/lib/periodic/ui/ElementCell.js +2 -2
  93. package/lib/periodic/ui/ElementCell.js.map +1 -1
  94. package/lib/periodic/ui/PeriodicTable.d.ts +3 -98
  95. package/lib/periodic/ui/PeriodicTable.d.ts.map +1 -1
  96. package/lib/periodic/ui/PeriodicTable.js +9 -84
  97. package/lib/periodic/ui/PeriodicTable.js.map +1 -1
  98. package/lib/periodic/ui/PeriodicTableChrome.d.ts +13 -3
  99. package/lib/periodic/ui/PeriodicTableChrome.d.ts.map +1 -1
  100. package/lib/periodic/ui/PeriodicTableChrome.js +10 -20
  101. package/lib/periodic/ui/PeriodicTableChrome.js.map +1 -1
  102. package/lib/periodic/ui/SelectAllCorner.d.ts +23 -0
  103. package/lib/periodic/ui/SelectAllCorner.d.ts.map +1 -0
  104. package/lib/periodic/ui/SelectAllCorner.js +40 -0
  105. package/lib/periodic/ui/SelectAllCorner.js.map +1 -0
  106. package/lib/periodic/ui/headerStyles.d.ts +17 -0
  107. package/lib/periodic/ui/headerStyles.d.ts.map +1 -0
  108. package/lib/periodic/ui/headerStyles.js +19 -0
  109. package/lib/periodic/ui/headerStyles.js.map +1 -0
  110. package/lib/periodic/ui/periodicTableProps.d.ts +115 -0
  111. package/lib/periodic/ui/periodicTableProps.d.ts.map +1 -0
  112. package/lib/periodic/ui/periodicTableProps.js +8 -0
  113. package/lib/periodic/ui/periodicTableProps.js.map +1 -0
  114. package/lib/periodic/ui/tableLayout.d.ts +26 -0
  115. package/lib/periodic/ui/tableLayout.d.ts.map +1 -0
  116. package/lib/periodic/ui/tableLayout.js +86 -0
  117. package/lib/periodic/ui/tableLayout.js.map +1 -0
  118. package/lib/split/ui/SplitColumn.d.ts +29 -0
  119. package/lib/split/ui/SplitColumn.d.ts.map +1 -0
  120. package/lib/split/ui/SplitColumn.js +19 -0
  121. package/lib/split/ui/SplitColumn.js.map +1 -0
  122. package/lib/split/ui/SplitRow.d.ts +14 -53
  123. package/lib/split/ui/SplitRow.d.ts.map +1 -1
  124. package/lib/split/ui/SplitRow.js +8 -90
  125. package/lib/split/ui/SplitRow.js.map +1 -1
  126. package/lib/split/ui/index.d.ts +3 -0
  127. package/lib/split/ui/index.d.ts.map +1 -1
  128. package/lib/split/ui/index.js +1 -0
  129. package/lib/split/ui/index.js.map +1 -1
  130. package/lib/split/ui/splitPanes.d.ts +84 -0
  131. package/lib/split/ui/splitPanes.d.ts.map +1 -0
  132. package/lib/split/ui/splitPanes.js +125 -0
  133. package/lib/split/ui/splitPanes.js.map +1 -0
  134. package/lib/taxonomy/core/index.d.ts +8 -0
  135. package/lib/taxonomy/core/index.d.ts.map +1 -0
  136. package/lib/taxonomy/core/index.js +5 -0
  137. package/lib/taxonomy/core/index.js.map +1 -0
  138. package/lib/taxonomy/core/lineage.d.ts +83 -0
  139. package/lib/taxonomy/core/lineage.d.ts.map +1 -0
  140. package/lib/taxonomy/core/lineage.js +126 -0
  141. package/lib/taxonomy/core/lineage.js.map +1 -0
  142. package/lib/taxonomy/core/ncbi.d.ts +8 -0
  143. package/lib/taxonomy/core/ncbi.d.ts.map +1 -0
  144. package/lib/taxonomy/core/ncbi.js +10 -0
  145. package/lib/taxonomy/core/ncbi.js.map +1 -0
  146. package/lib/taxonomy/core/organismName.d.ts +28 -0
  147. package/lib/taxonomy/core/organismName.d.ts.map +1 -0
  148. package/lib/taxonomy/core/organismName.js +188 -0
  149. package/lib/taxonomy/core/organismName.js.map +1 -0
  150. package/lib/taxonomy/core/organismWords.d.ts +20 -0
  151. package/lib/taxonomy/core/organismWords.d.ts.map +1 -0
  152. package/lib/taxonomy/core/organismWords.js +86 -0
  153. package/lib/taxonomy/core/organismWords.js.map +1 -0
  154. package/lib/taxonomy/core/ranks.d.ts +51 -0
  155. package/lib/taxonomy/core/ranks.d.ts.map +1 -0
  156. package/lib/taxonomy/core/ranks.js +123 -0
  157. package/lib/taxonomy/core/ranks.js.map +1 -0
  158. package/lib/taxonomy/ui/OrganismName.d.ts +28 -0
  159. package/lib/taxonomy/ui/OrganismName.d.ts.map +1 -0
  160. package/lib/taxonomy/ui/OrganismName.js +28 -0
  161. package/lib/taxonomy/ui/OrganismName.js.map +1 -0
  162. package/lib/taxonomy/ui/TaxonLineage.d.ts +67 -0
  163. package/lib/taxonomy/ui/TaxonLineage.d.ts.map +1 -0
  164. package/lib/taxonomy/ui/TaxonLineage.js +45 -0
  165. package/lib/taxonomy/ui/TaxonLineage.js.map +1 -0
  166. package/lib/taxonomy/ui/index.d.ts +6 -0
  167. package/lib/taxonomy/ui/index.d.ts.map +1 -0
  168. package/lib/taxonomy/ui/index.js +4 -0
  169. package/lib/taxonomy/ui/index.js.map +1 -0
  170. package/lib/taxonomy/ui/rankLabel.d.ts +17 -0
  171. package/lib/taxonomy/ui/rankLabel.d.ts.map +1 -0
  172. package/lib/taxonomy/ui/rankLabel.js +77 -0
  173. package/lib/taxonomy/ui/rankLabel.js.map +1 -0
  174. package/lib/ui.d.ts +1 -0
  175. package/lib/ui.d.ts.map +1 -1
  176. package/lib/ui.js +1 -0
  177. package/lib/ui.js.map +1 -1
  178. package/package.json +1 -1
  179. package/src/chart/core/chartDomain.ts +15 -0
  180. package/src/chart/core/selectionGeometry.ts +4 -2
  181. package/src/chart/core/zoomDomain.ts +37 -5
  182. package/src/chart/ui/chartGestures.ts +41 -1
  183. package/src/chart/ui/index.ts +1 -1
  184. package/src/chart/ui/useChartZoom.ts +25 -1
  185. package/src/core.ts +1 -0
  186. package/src/download/core/cssPaint.ts +71 -0
  187. package/src/download/core/drawingMarkup.ts +35 -0
  188. package/src/download/core/figureHtml.ts +214 -0
  189. package/src/download/core/figureHtmlMarkup.ts +187 -0
  190. package/src/download/core/figureSvg.ts +17 -38
  191. package/src/download/core/figureSvgDocument.ts +3 -3
  192. package/src/download/core/figureTarget.ts +41 -8
  193. package/src/download/core/index.ts +1 -0
  194. package/src/download/core/textLines.ts +67 -0
  195. package/src/ecosystem/core/lookup.ts +11 -3
  196. package/src/ecosystem/core/types.ts +4 -2
  197. package/src/ecosystem/core/unlistedSites.ts +37 -0
  198. package/src/ecosystem/ui/glyphs.tsx +44 -0
  199. package/src/ir/core/irMode.ts +6 -1
  200. package/src/locales/de.json +56 -1
  201. package/src/locales/en.json +56 -1
  202. package/src/locales/es.json +56 -1
  203. package/src/locales/fr.json +56 -1
  204. package/src/locales/it.json +56 -1
  205. package/src/periodic/core/index.ts +1 -1
  206. package/src/periodic/core/layout.ts +12 -0
  207. package/src/periodic/ui/ElementCell.tsx +8 -4
  208. package/src/periodic/ui/PeriodicTable.tsx +27 -197
  209. package/src/periodic/ui/PeriodicTableChrome.tsx +23 -20
  210. package/src/periodic/ui/SelectAllCorner.tsx +65 -0
  211. package/src/periodic/ui/headerStyles.ts +23 -0
  212. package/src/periodic/ui/periodicTableProps.ts +117 -0
  213. package/src/periodic/ui/tableLayout.ts +96 -0
  214. package/src/split/ui/SplitColumn.tsx +35 -0
  215. package/src/split/ui/SplitRow.tsx +16 -208
  216. package/src/split/ui/index.ts +3 -0
  217. package/src/split/ui/splitPanes.tsx +283 -0
  218. package/src/taxonomy/core/index.ts +20 -0
  219. package/src/taxonomy/core/lineage.ts +161 -0
  220. package/src/taxonomy/core/ncbi.ts +9 -0
  221. package/src/taxonomy/core/organismName.ts +217 -0
  222. package/src/taxonomy/core/organismWords.ts +86 -0
  223. package/src/taxonomy/core/ranks.ts +134 -0
  224. package/src/taxonomy/ui/OrganismName.tsx +59 -0
  225. package/src/taxonomy/ui/TaxonLineage.tsx +183 -0
  226. package/src/taxonomy/ui/index.ts +5 -0
  227. package/src/taxonomy/ui/rankLabel.ts +81 -0
  228. package/src/ui.ts +1 -0
  229. package/styles/chrome.css +135 -6
@@ -0,0 +1,183 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+
3
+ import { isModifiedClick } from '../../chrome/ui/navItem.ts';
4
+ import { useChromeT } from '../../i18n/ui/useT.ts';
5
+ import { joinClassNames } from '../../shared/ui/joinClassNames.ts';
6
+ import type { Taxon, TaxonLineage as Lineage } from '../core/lineage.ts';
7
+ import { genusOrBelow, principalLineage } from '../core/lineage.ts';
8
+ import { ncbiTaxonomyUrl } from '../core/ncbi.ts';
9
+
10
+ import { OrganismName } from './OrganismName.tsx';
11
+ import { rankLabel } from './rankLabel.ts';
12
+
13
+ /** What a {@link TaxonLineage} needs. */
14
+ export interface TaxonLineageProps {
15
+ /** The lineage, from the top of the tree down to the taxon it leads to. */
16
+ lineage: Lineage;
17
+ /**
18
+ * Whether only the principal ranks are shown — domain, kingdom, phylum,
19
+ * class, order, family, genus, species — with the last taxon kept whatever
20
+ * its rank. Off, every taxon is shown, the clades included.
21
+ * @default true
22
+ */
23
+ principal?: boolean;
24
+ /**
25
+ * The address of a taxon's page on the site. A taxon it answers `undefined`
26
+ * for is written as plain text, and so is every taxon without it.
27
+ * @default undefined
28
+ */
29
+ taxonHref?: (taxon: Taxon) => string | undefined;
30
+ /**
31
+ * What the site does when a taxon's link is followed with a plain click —
32
+ * move to its page without a reload. A modified click is left to the
33
+ * browser, so a taxon still opens in a tab of its own.
34
+ * @default undefined
35
+ */
36
+ onTaxonSelect?: (taxon: Taxon) => void;
37
+ /**
38
+ * Whether each taxon carries its rank as a small label over its name.
39
+ * Without it the rank is the taxon's tooltip, and is read to a screen reader
40
+ * after the name.
41
+ * @default false
42
+ */
43
+ showRanks?: boolean;
44
+ /**
45
+ * Whether a link to the last taxon's page in the NCBI Taxonomy Browser
46
+ * follows the lineage, when that taxon has an id.
47
+ * @default false
48
+ */
49
+ ncbiLink?: boolean;
50
+ /**
51
+ * Whether the last taxon is the page being read: it is then marked as the
52
+ * current page and is never a link.
53
+ * @default false
54
+ */
55
+ current?: boolean;
56
+ /**
57
+ * What names the breadcrumb to a screen reader.
58
+ * @default the catalog's "Lineage"
59
+ */
60
+ label?: string;
61
+ /**
62
+ * Class names added to the root element.
63
+ * @default undefined
64
+ */
65
+ className?: string;
66
+ }
67
+
68
+ /**
69
+ * A lineage as a breadcrumb: the taxa from the top of the tree down, each
70
+ * named with its rank, the last one emphasised.
71
+ *
72
+ * The names under a genus are set in italics as nomenclature sets them, by
73
+ * {@link OrganismName}; the ranks are the chrome's words, translated with it.
74
+ * @param props - See {@link TaxonLineageProps}.
75
+ * @returns The breadcrumb, or nothing for an empty lineage.
76
+ */
77
+ export function TaxonLineage(props: TaxonLineageProps): ReactElement | null {
78
+ const {
79
+ lineage,
80
+ principal = true,
81
+ taxonHref,
82
+ onTaxonSelect,
83
+ showRanks = false,
84
+ ncbiLink = false,
85
+ current = false,
86
+ label,
87
+ className,
88
+ } = props;
89
+ const t = useChromeT();
90
+ const shown = principal ? principalLineage(lineage) : lineage;
91
+ if (shown.length === 0) return null;
92
+ const italic = genusOrBelow(shown);
93
+
94
+ const steps: ReactNode[] = [];
95
+ for (let index = 0; index < shown.length; index++) {
96
+ const taxon = shown[index] as Taxon;
97
+ const last = index === shown.length - 1;
98
+ const rank = rankLabel(t, taxon.rank);
99
+ const name = italic[index] ? (
100
+ <OrganismName name={taxon.name} />
101
+ ) : (
102
+ taxon.name
103
+ );
104
+ const isCurrent = last && current;
105
+ const href = isCurrent ? undefined : taxonHref?.(taxon);
106
+
107
+ steps.push(
108
+ <li
109
+ key={`${taxon.taxId ?? ''}:${taxon.rank}:${taxon.name}`}
110
+ className={joinClassNames(
111
+ 'taxon-lineage__taxon',
112
+ last && 'taxon-lineage__taxon--leaf',
113
+ )}
114
+ title={showRanks ? undefined : rank}
115
+ >
116
+ <span className="taxon-lineage__step">
117
+ {showRanks && <span className="taxon-lineage__rank">{rank}</span>}
118
+ {href === undefined ? (
119
+ <span
120
+ className="taxon-lineage__name"
121
+ aria-current={isCurrent ? 'page' : undefined}
122
+ >
123
+ {name}
124
+ </span>
125
+ ) : (
126
+ <a
127
+ className="taxon-lineage__name"
128
+ href={href}
129
+ onClick={
130
+ onTaxonSelect === undefined
131
+ ? undefined
132
+ : (event) => {
133
+ if (isModifiedClick(event) || event.button !== 0) return;
134
+ event.preventDefault();
135
+ onTaxonSelect(taxon);
136
+ }
137
+ }
138
+ >
139
+ {name}
140
+ </a>
141
+ )}
142
+ {!showRanks && (
143
+ <span className="taxon-lineage__spoken">
144
+ {' '}
145
+ {t('taxonomy.rankNote', { rank })}
146
+ </span>
147
+ )}
148
+ </span>
149
+ {last ? (
150
+ ncbiLink &&
151
+ taxon.taxId !== undefined && (
152
+ <a
153
+ className="taxon-lineage__ncbi"
154
+ href={ncbiTaxonomyUrl(taxon.taxId)}
155
+ target="_blank"
156
+ rel="noreferrer"
157
+ title={t('taxonomy.ncbiTitle', { name: taxon.name })}
158
+ >
159
+ {t('taxonomy.ncbi')}
160
+ </a>
161
+ )
162
+ ) : (
163
+ <span className="taxon-lineage__separator" aria-hidden="true">
164
+ ›
165
+ </span>
166
+ )}
167
+ </li>,
168
+ );
169
+ }
170
+
171
+ return (
172
+ <nav
173
+ className={joinClassNames(
174
+ 'taxon-lineage',
175
+ showRanks && 'taxon-lineage--ranks',
176
+ className,
177
+ )}
178
+ aria-label={label ?? t('taxonomy.lineage')}
179
+ >
180
+ <ol className="taxon-lineage__list">{steps}</ol>
181
+ </nav>
182
+ );
183
+ }
@@ -0,0 +1,5 @@
1
+ export type { OrganismNameProps } from './OrganismName.tsx';
2
+ export { OrganismName } from './OrganismName.tsx';
3
+ export type { TaxonLineageProps } from './TaxonLineage.tsx';
4
+ export { TaxonLineage } from './TaxonLineage.tsx';
5
+ export { useRankLabel } from './rankLabel.ts';
@@ -0,0 +1,81 @@
1
+ import type { ChromeKey } from '../../i18n/core/chromeCatalog.ts';
2
+ import type { Translate } from '../../i18n/ui/useT.ts';
3
+ import { useChromeT } from '../../i18n/ui/useT.ts';
4
+
5
+ // Each rank NCBI writes, with the key its label is translated under. Written
6
+ // out rather than built from the rank, so a key the catalog lacks fails the
7
+ // type check instead of rendering raw.
8
+ const RANK_KEYS: Readonly<Record<string, ChromeKey>> = {
9
+ realm: 'taxonomy.rank.realm',
10
+ domain: 'taxonomy.rank.domain',
11
+ superkingdom: 'taxonomy.rank.superkingdom',
12
+ kingdom: 'taxonomy.rank.kingdom',
13
+ subkingdom: 'taxonomy.rank.subkingdom',
14
+ superphylum: 'taxonomy.rank.superphylum',
15
+ phylum: 'taxonomy.rank.phylum',
16
+ subphylum: 'taxonomy.rank.subphylum',
17
+ superclass: 'taxonomy.rank.superclass',
18
+ class: 'taxonomy.rank.class',
19
+ subclass: 'taxonomy.rank.subclass',
20
+ infraclass: 'taxonomy.rank.infraclass',
21
+ cohort: 'taxonomy.rank.cohort',
22
+ subcohort: 'taxonomy.rank.subcohort',
23
+ superorder: 'taxonomy.rank.superorder',
24
+ order: 'taxonomy.rank.order',
25
+ suborder: 'taxonomy.rank.suborder',
26
+ infraorder: 'taxonomy.rank.infraorder',
27
+ parvorder: 'taxonomy.rank.parvorder',
28
+ superfamily: 'taxonomy.rank.superfamily',
29
+ family: 'taxonomy.rank.family',
30
+ subfamily: 'taxonomy.rank.subfamily',
31
+ tribe: 'taxonomy.rank.tribe',
32
+ subtribe: 'taxonomy.rank.subtribe',
33
+ genus: 'taxonomy.rank.genus',
34
+ subgenus: 'taxonomy.rank.subgenus',
35
+ section: 'taxonomy.rank.section',
36
+ subsection: 'taxonomy.rank.subsection',
37
+ series: 'taxonomy.rank.series',
38
+ subseries: 'taxonomy.rank.subseries',
39
+ 'species group': 'taxonomy.rank.speciesGroup',
40
+ 'species subgroup': 'taxonomy.rank.speciesSubgroup',
41
+ species: 'taxonomy.rank.species',
42
+ 'forma specialis': 'taxonomy.rank.formaSpecialis',
43
+ subspecies: 'taxonomy.rank.subspecies',
44
+ varietas: 'taxonomy.rank.varietas',
45
+ subvariety: 'taxonomy.rank.subvariety',
46
+ forma: 'taxonomy.rank.forma',
47
+ pathogroup: 'taxonomy.rank.pathogroup',
48
+ serogroup: 'taxonomy.rank.serogroup',
49
+ serotype: 'taxonomy.rank.serotype',
50
+ biotype: 'taxonomy.rank.biotype',
51
+ genotype: 'taxonomy.rank.genotype',
52
+ morph: 'taxonomy.rank.morph',
53
+ strain: 'taxonomy.rank.strain',
54
+ isolate: 'taxonomy.rank.isolate',
55
+ 'no rank': 'taxonomy.rank.noRank',
56
+ clade: 'taxonomy.rank.clade',
57
+ 'cellular root': 'taxonomy.rank.cellularRoot',
58
+ 'acellular root': 'taxonomy.rank.acellularRoot',
59
+ };
60
+
61
+ /**
62
+ * A rank as the reader's language names it.
63
+ * @param t - The chrome's formatter.
64
+ * @param rank - The rank, as NCBI writes it.
65
+ * @returns Its label, or the rank itself when the catalog has none for it.
66
+ */
67
+ export function rankLabel(t: Translate<ChromeKey>, rank: string): string {
68
+ const key = Object.hasOwn(RANK_KEYS, rank) ? RANK_KEYS[rank] : undefined;
69
+ return key === undefined ? rank : t(key);
70
+ }
71
+
72
+ /**
73
+ * The label of a rank in the reader's language, for a site writing a rank
74
+ * beside the lineage — a taxon's heading, a list of its children.
75
+ * @returns `label(rank)`: the rank as NCBI writes it, named the way the chrome
76
+ * names it; a rank the catalog does not know is returned as it is.
77
+ */
78
+ export function useRankLabel(): (rank: string) => string {
79
+ const t = useChromeT();
80
+ return (rank) => rankLabel(t, rank);
81
+ }
package/src/ui.ts CHANGED
@@ -31,6 +31,7 @@ export * from './scatter3d/ui/index.ts';
31
31
  export * from './share/ui/index.ts';
32
32
  export * from './shared/ui/index.ts';
33
33
  export * from './split/ui/index.ts';
34
+ export * from './taxonomy/ui/index.ts';
34
35
  // The conformer table, from the structure module's file rather than its
35
36
  // barrel: `structure/ui/index.ts` is the door that must never reach react-ocl,
36
37
  // and this component does not, but `react-cheminfo/conformers` is imported by
package/styles/chrome.css CHANGED
@@ -1059,6 +1059,112 @@ select,
1059
1059
  text-align: right;
1060
1060
  }
1061
1061
 
1062
+ /* ── Taxonomy ────────────────────────────────────────────────────────────── */
1063
+
1064
+ /* A breadcrumb that wraps between its taxa, never inside one, so a lineage in
1065
+ a table cell stays as narrow as its longest name. The size and the link
1066
+ colour are the page's. */
1067
+ .taxon-lineage {
1068
+ display: flex;
1069
+ min-width: 0;
1070
+ flex-wrap: wrap;
1071
+ align-items: baseline;
1072
+ column-gap: 0.6em;
1073
+ }
1074
+
1075
+ .taxon-lineage__list {
1076
+ display: flex;
1077
+ min-width: 0;
1078
+ flex-wrap: wrap;
1079
+ align-items: baseline;
1080
+ padding: 0;
1081
+ margin: 0;
1082
+ list-style: none;
1083
+ row-gap: 0.1em;
1084
+ }
1085
+
1086
+ .taxon-lineage__taxon {
1087
+ display: inline-flex;
1088
+ align-items: baseline;
1089
+ }
1090
+
1091
+ .taxon-lineage__step {
1092
+ display: inline-flex;
1093
+ flex-direction: column;
1094
+ }
1095
+
1096
+ /* A taxon the site has no page for is read, not followed. */
1097
+ span.taxon-lineage__name {
1098
+ color: var(--text-muted);
1099
+ }
1100
+
1101
+ .taxon-lineage__taxon--leaf .taxon-lineage__name {
1102
+ font-weight: 600;
1103
+ }
1104
+
1105
+ .taxon-lineage__taxon--leaf span.taxon-lineage__name {
1106
+ color: var(--text);
1107
+ }
1108
+
1109
+ .taxon-lineage__separator {
1110
+ margin: 0 0.35em;
1111
+ color: var(--text-faint);
1112
+ }
1113
+
1114
+ .taxon-lineage__rank {
1115
+ color: var(--text-faint);
1116
+ font-size: 0.75em;
1117
+ line-height: 1.2;
1118
+ }
1119
+
1120
+ /* The rank a tooltip shows the pointer, said to a screen reader; never copied
1121
+ with the names. */
1122
+ .taxon-lineage__spoken {
1123
+ position: absolute;
1124
+ width: 1px;
1125
+ height: 1px;
1126
+ overflow: hidden;
1127
+ clip-path: inset(50%);
1128
+ user-select: none;
1129
+ white-space: nowrap;
1130
+ }
1131
+
1132
+ /* With its rank over each name, the separators sit on the line of the names. */
1133
+ .taxon-lineage--ranks .taxon-lineage__taxon {
1134
+ align-items: flex-end;
1135
+ }
1136
+
1137
+ /* A rank wider than its name runs on over the separator rather than pushing
1138
+ the separator away from the name it follows. */
1139
+ .taxon-lineage--ranks .taxon-lineage__rank {
1140
+ width: 0;
1141
+ overflow: visible;
1142
+ white-space: nowrap;
1143
+ }
1144
+
1145
+ .taxon-lineage__ncbi {
1146
+ margin-left: 0.75em;
1147
+ font-size: 0.85em;
1148
+ white-space: nowrap;
1149
+ }
1150
+
1151
+ /* Upright again inside italic text, so a name in a caption still sets its
1152
+ genus apart. */
1153
+ .organism-name {
1154
+ font-style: normal;
1155
+ }
1156
+
1157
+ .organism-name i {
1158
+ font-style: italic;
1159
+ }
1160
+
1161
+ @media print {
1162
+ .taxon-lineage a {
1163
+ color: inherit;
1164
+ text-decoration: none;
1165
+ }
1166
+ }
1167
+
1062
1168
  /* ── Help ────────────────────────────────────────────────────────────────── */
1063
1169
 
1064
1170
  /*
@@ -1176,21 +1282,35 @@ select,
1176
1282
  /* ── The splitter ───────────────────────────────────────────────────────── */
1177
1283
 
1178
1284
  /*
1179
- The bar between the two figures of a `<SplitRow>` is react-science's, and it
1180
- keeps react-science's look — the pale track with the grip written on it that
1181
- NMRium and every other tool of ours is divided by. It is barely visible on
1182
- purpose: what is read is the two figures, and the bar is found by the pointer
1183
- that changes over it rather than by the eye.
1285
+ The bar between the two figures of a `<SplitRow>` or a `<SplitColumn>` is
1286
+ react-science's, and it keeps react-science's look — the pale track with the
1287
+ grip written on it that NMRium and every other tool of ours is divided by. It
1288
+ is barely visible on purpose: what is read is the two figures, and the bar is
1289
+ found by the pointer that changes over it rather than by the eye.
1184
1290
 
1185
1291
  All this says is that eleven pixels is more gutter than two figures need.
1186
1292
  `:nth-child(2)` is the bar: a split is only mounted with a pane on each side
1187
1293
  of it, so the three children are always side, bar, side.
1294
+
1295
+ **Which measurement is the seven pixels is the direction's, so each direction
1296
+ says it for itself.** A row's bar is a column of pixels, and narrowing it is
1297
+ narrowing its width; a column's bar is that same line turned a quarter, so
1298
+ there the seven pixels are its height and the width is left to run the width
1299
+ of the pane. One rule for both — the width one, which is what this was — turns
1300
+ a column's bar into a seven-by-ten nub against the left edge of the pane:
1301
+ addressable, draggable, and invisible. The whole argument for a splitter is a
1302
+ line a reader can see, so a bar that renders as a dot is no splitter at all.
1188
1303
  */
1189
- .split-row > div > div:nth-child(2) {
1304
+ .split-row:not(.split-row--down) > div > div:nth-child(2) {
1190
1305
  width: 7px;
1191
1306
  min-width: 7px;
1192
1307
  }
1193
1308
 
1309
+ .split-row--down > div > div:nth-child(2) {
1310
+ height: 7px;
1311
+ min-height: 7px;
1312
+ }
1313
+
1194
1314
  /* ── Printing ────────────────────────────────────────────────────────────── */
1195
1315
 
1196
1316
  /*
@@ -1218,4 +1338,13 @@ select,
1218
1338
  .click-to-copy__icon.click-to-copy__icon.click-to-copy__icon {
1219
1339
  display: none !important;
1220
1340
  }
1341
+
1342
+ /*
1343
+ The bar is a control, and nothing is dragged on paper: all it leaves there
1344
+ is a grey line nobody drew. The panes keep the shares the reader left them
1345
+ at — that is the layout being printed — and simply meet.
1346
+ */
1347
+ .split-row > div > div:nth-child(2) {
1348
+ display: none !important;
1349
+ }
1221
1350
  }