react-cheminfo 0.36.0 → 0.38.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 (115) hide show
  1. package/README.md +77 -1
  2. package/bin/check-seo.mjs +43 -1
  3. package/lib/core.d.ts +1 -0
  4. package/lib/core.d.ts.map +1 -1
  5. package/lib/core.js +1 -0
  6. package/lib/core.js.map +1 -1
  7. package/lib/ecosystem/core/sites.d.ts.map +1 -1
  8. package/lib/ecosystem/core/sites.js +17 -0
  9. package/lib/ecosystem/core/sites.js.map +1 -1
  10. package/lib/ecosystem/core/types.d.ts +1 -1
  11. package/lib/ecosystem/core/types.d.ts.map +1 -1
  12. package/lib/ecosystem/ui/glyphs.d.ts.map +1 -1
  13. package/lib/ecosystem/ui/glyphs.js +4 -0
  14. package/lib/ecosystem/ui/glyphs.js.map +1 -1
  15. package/lib/i18n/core/chromeCatalog.d.ts +1 -1
  16. package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
  17. package/lib/locales/de.json +9 -1
  18. package/lib/locales/en.json +9 -1
  19. package/lib/locales/es.json +9 -1
  20. package/lib/locales/fr.json +9 -1
  21. package/lib/locales/it.json +9 -1
  22. package/lib/number/core/index.d.ts +1 -1
  23. package/lib/number/core/index.d.ts.map +1 -1
  24. package/lib/number/core/index.js +1 -1
  25. package/lib/number/core/index.js.map +1 -1
  26. package/lib/number/core/numberText.d.ts +13 -0
  27. package/lib/number/core/numberText.d.ts.map +1 -1
  28. package/lib/number/core/numberText.js +20 -0
  29. package/lib/number/core/numberText.js.map +1 -1
  30. package/lib/range/core/index.d.ts +4 -0
  31. package/lib/range/core/index.d.ts.map +1 -0
  32. package/lib/range/core/index.js +3 -0
  33. package/lib/range/core/index.js.map +1 -0
  34. package/lib/range/core/rangeBounds.d.ts +79 -0
  35. package/lib/range/core/rangeBounds.d.ts.map +1 -0
  36. package/lib/range/core/rangeBounds.js +110 -0
  37. package/lib/range/core/rangeBounds.js.map +1 -0
  38. package/lib/range/core/rangeHistogram.d.ts +13 -0
  39. package/lib/range/core/rangeHistogram.d.ts.map +1 -0
  40. package/lib/range/core/rangeHistogram.js +39 -0
  41. package/lib/range/core/rangeHistogram.js.map +1 -0
  42. package/lib/range/ui/RangeHistogram.d.ts +20 -0
  43. package/lib/range/ui/RangeHistogram.d.ts.map +1 -0
  44. package/lib/range/ui/RangeHistogram.js +18 -0
  45. package/lib/range/ui/RangeHistogram.js.map +1 -0
  46. package/lib/range/ui/RangeSlider.d.ts +77 -0
  47. package/lib/range/ui/RangeSlider.d.ts.map +1 -0
  48. package/lib/range/ui/RangeSlider.js +60 -0
  49. package/lib/range/ui/RangeSlider.js.map +1 -0
  50. package/lib/range/ui/RangeValue.d.ts +41 -0
  51. package/lib/range/ui/RangeValue.d.ts.map +1 -0
  52. package/lib/range/ui/RangeValue.js +73 -0
  53. package/lib/range/ui/RangeValue.js.map +1 -0
  54. package/lib/range/ui/index.d.ts +3 -0
  55. package/lib/range/ui/index.d.ts.map +1 -0
  56. package/lib/range/ui/index.js +2 -0
  57. package/lib/range/ui/index.js.map +1 -0
  58. package/lib/seo/core/documentMeta.d.ts +16 -0
  59. package/lib/seo/core/documentMeta.d.ts.map +1 -1
  60. package/lib/seo/core/documentMeta.js +18 -0
  61. package/lib/seo/core/documentMeta.js.map +1 -1
  62. package/lib/seo/core/index.d.ts +3 -1
  63. package/lib/seo/core/index.d.ts.map +1 -1
  64. package/lib/seo/core/index.js +2 -1
  65. package/lib/seo/core/index.js.map +1 -1
  66. package/lib/seo/core/noscript.d.ts +8 -0
  67. package/lib/seo/core/noscript.d.ts.map +1 -1
  68. package/lib/seo/core/noscript.js +10 -3
  69. package/lib/seo/core/noscript.js.map +1 -1
  70. package/lib/seo/core/pageMeta.d.ts +10 -2
  71. package/lib/seo/core/pageMeta.d.ts.map +1 -1
  72. package/lib/seo/core/pageMeta.js +12 -3
  73. package/lib/seo/core/pageMeta.js.map +1 -1
  74. package/lib/seo/core/siteFiles.d.ts +32 -3
  75. package/lib/seo/core/siteFiles.d.ts.map +1 -1
  76. package/lib/seo/core/siteFiles.js +13 -4
  77. package/lib/seo/core/siteFiles.js.map +1 -1
  78. package/lib/seo/core/startDocumentMeta.js +8 -7
  79. package/lib/seo/core/startDocumentMeta.js.map +1 -1
  80. package/lib/seo/vite/prerender.d.ts +26 -4
  81. package/lib/seo/vite/prerender.d.ts.map +1 -1
  82. package/lib/seo/vite/prerender.js +100 -30
  83. package/lib/seo/vite/prerender.js.map +1 -1
  84. package/lib/ui.d.ts +1 -0
  85. package/lib/ui.d.ts.map +1 -1
  86. package/lib/ui.js +1 -0
  87. package/lib/ui.js.map +1 -1
  88. package/package.json +1 -1
  89. package/src/core.ts +1 -0
  90. package/src/ecosystem/core/sites.ts +17 -0
  91. package/src/ecosystem/core/types.ts +1 -0
  92. package/src/ecosystem/ui/glyphs.tsx +16 -0
  93. package/src/locales/de.json +9 -1
  94. package/src/locales/en.json +9 -1
  95. package/src/locales/es.json +9 -1
  96. package/src/locales/fr.json +9 -1
  97. package/src/locales/it.json +9 -1
  98. package/src/number/core/index.ts +1 -0
  99. package/src/number/core/numberText.ts +20 -0
  100. package/src/range/core/index.ts +11 -0
  101. package/src/range/core/rangeBounds.ts +143 -0
  102. package/src/range/core/rangeHistogram.ts +38 -0
  103. package/src/range/ui/RangeHistogram.tsx +49 -0
  104. package/src/range/ui/RangeSlider.tsx +209 -0
  105. package/src/range/ui/RangeValue.tsx +166 -0
  106. package/src/range/ui/index.ts +2 -0
  107. package/src/seo/core/documentMeta.ts +22 -0
  108. package/src/seo/core/index.ts +8 -1
  109. package/src/seo/core/noscript.ts +20 -2
  110. package/src/seo/core/pageMeta.ts +29 -5
  111. package/src/seo/core/siteFiles.ts +45 -10
  112. package/src/seo/core/startDocumentMeta.ts +9 -9
  113. package/src/seo/vite/prerender.ts +160 -36
  114. package/src/ui.ts +1 -0
  115. package/styles/chrome.css +135 -0
@@ -18,6 +18,9 @@
18
18
  */
19
19
  import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
20
20
  import { dirname, join, resolve } from 'node:path';
21
+ import { CHROME_CATALOG } from "../../i18n/core/chromeCatalog.js";
22
+ import { DEFAULT_LANGUAGE } from "../../i18n/core/languages.js";
23
+ import { withLanguagePath } from "../../language/core/languagePath.js";
21
24
  import { trimTrailingSlash } from "../../router/core/address.js";
22
25
  import { noscriptIndex } from "../core/noscript.js";
23
26
  import { pageHeadTags } from "../core/pageMeta.js";
@@ -34,15 +37,35 @@ import { PAGE_BODY_MARKER, PAGE_HEAD_MARKER, fill } from "../core/template.js";
34
37
  * is not a path, or when the origin is not an absolute address.
35
38
  */
36
39
  export function cheminfoPrerender(options) {
37
- const { site, routes, origin, robots = [] } = options;
40
+ const { site, origin, robots = [] } = options;
41
+ const languages = options.languages ?? [DEFAULT_LANGUAGE];
42
+ const tableFor = (language) => typeof options.routes === 'function'
43
+ ? options.routes(language)
44
+ : options.routes;
45
+ // Every language answers the same addresses, so each table is checked and
46
+ // they are checked against each other: a translation that renames a path or
47
+ // drops a page writes a file the sitemap of another language names, and the
48
+ // `hreflang` set would point at an address that is not there.
49
+ const routes = tableFor(DEFAULT_LANGUAGE);
38
50
  assertRoutes(routes);
39
- const structuredData = structuredDataOf(options);
51
+ for (const language of languages) {
52
+ if (language === DEFAULT_LANGUAGE)
53
+ continue;
54
+ assertSamePaths(routes, tableFor(language), language);
55
+ }
56
+ const structuredData = structuredDataOf(options, routes);
40
57
  let out = 'dist';
41
58
  let serve = false;
42
59
  let logger = null;
43
- const page = (template, route) => {
44
- const head = fill(template, PAGE_HEAD_MARKER, `${pageHeadTags({ site, routes, origin, url: route.path })}${structuredData}`);
45
- const crawlPath = crawlPathOf(options, route);
60
+ const page = (template, route, language) => {
61
+ const head = fill(withHtmlLang(template, language), PAGE_HEAD_MARKER, `${pageHeadTags({
62
+ site,
63
+ routes: tableFor(language),
64
+ origin,
65
+ languages,
66
+ url: withLanguagePath(language, route.path),
67
+ })}${structuredData}`);
68
+ const crawlPath = crawlPathOf(options, route, language, tableFor(language));
46
69
  return crawlPath === '' ? head : fill(head, PAGE_BODY_MARKER, crawlPath);
47
70
  };
48
71
  return {
@@ -56,43 +79,59 @@ export function cheminfoPrerender(options) {
56
79
  // from the home route rather than shipped with its markers showing.
57
80
  transformIndexHtml: {
58
81
  order: 'post',
59
- handler: (html) => (serve ? page(html, homeRoute(routes)) : html),
82
+ handler: (html) => serve ? page(html, homeRoute(routes), DEFAULT_LANGUAGE) : html,
60
83
  },
61
- closeBundle() {
84
+ async closeBundle() {
62
85
  if (serve)
63
86
  return;
87
+ // The crawl path names the family in the chrome's own words, and every
88
+ // language but the default arrives as a chunk of its own, so they are all
89
+ // fetched before a single file is written.
90
+ await Promise.all(languages
91
+ .filter((language) => language !== DEFAULT_LANGUAGE)
92
+ .map((language) => CHROME_CATALOG.load(language)));
64
93
  const template = readFileSync(join(out, 'index.html'), 'utf8');
65
- const write = (route, file) => {
94
+ const write = (route, language, file) => {
66
95
  mkdirSync(dirname(file), { recursive: true });
67
- writeFileSync(file, page(template, route));
96
+ writeFileSync(file, page(template, route, language));
68
97
  };
69
- let root = false;
70
- for (const route of routes) {
71
- const address = trimTrailingSlash(route.path);
72
- if (address === '/')
73
- root = true;
74
- write(route, address === '/'
75
- ? join(out, 'index.html')
76
- : join(out, address.slice(1), 'index.html'));
98
+ let written = 0;
99
+ for (const language of languages) {
100
+ const table = tableFor(language);
101
+ let root = false;
102
+ for (const route of table) {
103
+ const address = trimTrailingSlash(withLanguagePath(language, route.path));
104
+ if (address === '/')
105
+ root = true;
106
+ write(route, language, address === '/'
107
+ ? join(out, 'index.html')
108
+ : join(out, address.slice(1), 'index.html'));
109
+ written++;
110
+ }
111
+ // The file a static server hands out for the mount itself. A table
112
+ // naming no root would otherwise leave the template vite built, and
113
+ // ship a site whose front page carries its markers instead of a head.
114
+ // A language other than the default already has its own front page at
115
+ // `/<language>`, so only the unprefixed one is ever missing.
116
+ if (!root && language === DEFAULT_LANGUAGE) {
117
+ write(homeRoute(table), language, join(out, 'index.html'));
118
+ written++;
119
+ }
77
120
  }
78
- // The file a static server hands out for the mount itself. A table naming
79
- // no root would otherwise leave the template vite built, and ship a site
80
- // whose front page carries its markers instead of a head.
81
- if (!root)
82
- write(homeRoute(routes), join(out, 'index.html'));
83
- writeFileSync(join(out, 'sitemap.xml'), sitemapXml({ site, routes, origin }));
121
+ writeFileSync(join(out, 'sitemap.xml'), sitemapXml({ site, routes, origin, languages }));
84
122
  if (robots !== false) {
85
123
  writeFileSync(join(out, 'robots.txt'), robotsTxt({ site, routes, origin }, robots));
86
124
  }
87
- logger?.info(`${routes.length} pages prerendered, and listed in sitemap.xml`);
125
+ const spoken = languages.length > 1 ? ` in ${languages.length} languages` : '';
126
+ logger?.info(`${written} pages prerendered${spoken}, and listed in sitemap.xml`);
88
127
  },
89
128
  };
90
129
  }
91
- function structuredDataOf(options) {
130
+ function structuredDataOf(options, routes) {
92
131
  const { category, ...rest } = options;
93
132
  if (category === false)
94
133
  return '';
95
- const { site, routes, origin } = rest;
134
+ const { site, origin } = rest;
96
135
  const { operatingSystem, description, browserRequirements, currency } = rest;
97
136
  return `\n${structuredDataScript({
98
137
  site,
@@ -105,18 +144,49 @@ function structuredDataOf(options) {
105
144
  currency,
106
145
  })}`;
107
146
  }
108
- function crawlPathOf(options, route) {
109
- const { site, routes, origin, noscript = true } = options;
147
+ function crawlPathOf(options, route, language, routes) {
148
+ const { site, origin } = options;
149
+ // The crawl path of a translated page is that language's: its heading, its
150
+ // intro and the label under every link. Declared as a function of the
151
+ // language, the site writes each of them from its own catalog; declared as a
152
+ // record, it is the same words on every language, which is what a site that
153
+ // speaks one wants and is what it used to be.
154
+ const declared = options.noscript ?? true;
155
+ const noscript = typeof declared === 'function' ? declared(language) : declared;
110
156
  if (noscript === false)
111
157
  return '';
112
- const content = options.content?.(route);
158
+ const content = options.content?.(route, language);
113
159
  const { routes: listed, ...prose } = noscript === true ? {} : noscript;
160
+ // The crawl path of a translated page links to that language's addresses: a
161
+ // French page listing the English ones is a crawler's only route out of it,
162
+ // and it would lead straight back out of the translation.
163
+ const menu = (listed ?? routes).map((entry) => ({
164
+ ...entry,
165
+ path: withLanguagePath(language, entry.path),
166
+ }));
114
167
  return noscriptIndex({
115
168
  site,
116
169
  origin,
117
170
  ...prose,
118
- routes: listed ?? routes,
171
+ routes: menu,
119
172
  content,
173
+ language,
120
174
  });
121
175
  }
176
+ // Two tables of one site answer the same addresses. A translated table that
177
+ // renames or drops a path leaves the `hreflang` set of every other language
178
+ // pointing at an address nothing wrote, which is a soft 404 on each of them.
179
+ function assertSamePaths(source, translated, language) {
180
+ const wanted = source.map((route) => route.path).join(' ');
181
+ const written = translated.map((route) => route.path).join(' ');
182
+ if (wanted !== written) {
183
+ throw new Error(`the ${language} route table answers different addresses than the source one: an address is the same in every language`);
184
+ }
185
+ }
186
+ // The template is written in the default language, so each file says which
187
+ // language it is actually in. A page whose `lang` lies is read aloud wrong and
188
+ // offered to the wrong reader.
189
+ function withHtmlLang(template, language) {
190
+ return template.replace(/<html(?<attributes>[^>]*)\slang="[^"]*"/i, `<html$<attributes> lang="${language}"`);
191
+ }
122
192
  //# sourceMappingURL=prerender.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"prerender.js","sourceRoot":"","sources":["../../../src/seo/vite/prerender.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prerender.js","sourceRoot":"","sources":["../../../src/seo/vite/prerender.ts"],"names":[],"mappings":"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"}
package/lib/ui.d.ts CHANGED
@@ -24,6 +24,7 @@ export * from './parallel/ui/index.ts';
24
24
  export * from './pedagogy/ui/index.ts';
25
25
  export * from './periodic/ui/index.ts';
26
26
  export * from './projection/ui/index.ts';
27
+ export * from './range/ui/index.ts';
27
28
  export * from './router/ui/index.ts';
28
29
  export * from './scatter/ui/index.ts';
29
30
  export * from './scatter3d/ui/index.ts';
package/lib/ui.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AAKrC,YAAY,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,YAAY,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,eAAe,GAChB,MAAM,oCAAoC,CAAC"}
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AAKrC,YAAY,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,YAAY,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,eAAe,GAChB,MAAM,oCAAoC,CAAC"}
package/lib/ui.js CHANGED
@@ -24,6 +24,7 @@ export * from "./parallel/ui/index.js";
24
24
  export * from "./pedagogy/ui/index.js";
25
25
  export * from "./periodic/ui/index.js";
26
26
  export * from "./projection/ui/index.js";
27
+ export * from "./range/ui/index.js";
27
28
  export * from "./router/ui/index.js";
28
29
  export * from "./scatter/ui/index.js";
29
30
  export * from "./scatter3d/ui/index.js";
package/lib/ui.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AAMrC,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAmC,CAAC;AAEnE,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,eAAe,GAChB,MAAM,oCAAoC,CAAC"}
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AAMrC,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAmC,CAAC;AAEnE,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,eAAe,GAChB,MAAM,oCAAoC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-cheminfo",
3
- "version": "0.36.0",
3
+ "version": "0.38.0",
4
4
  "license": "MIT",
5
5
  "description": "React components, hooks and framework-free helpers shared by the cheminfo sites: site chrome, citations, sharing, routing, pedagogy, charts, and the structure, orbital and 3D molecule viewers",
6
6
  "author": "Luc Patiny",
package/src/core.ts CHANGED
@@ -21,6 +21,7 @@ export * from './parallel/core/index.ts';
21
21
  export * from './pedagogy/core/index.ts';
22
22
  export * from './periodic/core/index.ts';
23
23
  export * from './projection/core/index.ts';
24
+ export * from './range/core/index.ts';
24
25
  export * from './router/core/index.ts';
25
26
  export * from './scatter/core/index.ts';
26
27
  export * from './scatter3d/core/index.ts';
@@ -56,6 +56,23 @@ export const ECOSYSTEM_SITES: readonly EcosystemSite[] = [
56
56
  brandAlt: '#9a3412',
57
57
  mark: { plate: '#1c6e42', accent: '#ea580c' },
58
58
  },
59
+ {
60
+ id: 'iupac-name',
61
+ // The name splits on its own hyphen, so it carries no domain and no dot,
62
+ // and the hyphen stays with the first half so the address reads as typed.
63
+ name: { lead: 'iupac-', alt: 'name' },
64
+ host: 'iupac-name.cheminfo.org',
65
+ tagline: 'The IUPAC name of a structure, and the structure a name denotes.',
66
+ group: 'structures',
67
+ // The blue of the IUPAC Blue Book, whose 2013 recommendations are what the
68
+ // site names by. A violet would repeat the lead inchi already owns.
69
+ brand: '#1e40af',
70
+ // The amber the mark's locant 1 is drawn in sits at 3.2:1 on white, short
71
+ // of the 4.5:1 of body text, so the second half of the wordmark takes this
72
+ // darkened form instead, at 7.1:1.
73
+ brandAlt: '#92400e',
74
+ mark: { plate: '#1e40af', accent: '#d97706' },
75
+ },
59
76
  {
60
77
  id: 'openbabel',
61
78
  name: { lead: 'openbabel', alt: 'cheminfo', dot: true },
@@ -6,6 +6,7 @@ export type SiteId =
6
6
  | 'inchi'
7
7
  | 'vcl'
8
8
  | 'smiles'
9
+ | 'iupac-name'
9
10
  | 'openbabel'
10
11
  | 'chemcalc'
11
12
  | 'dbe'
@@ -106,6 +106,22 @@ export const GLYPHS: Record<SiteId, (alt: string) => ReactNode> = {
106
106
  />
107
107
  </>
108
108
  ),
109
+ // A parent chain numbered from the end nearest its group: the atom that
110
+ // takes locant 1 carries the colour, because the numbering is what a name
111
+ // is built on.
112
+ 'iupac-name': (alt) => (
113
+ <>
114
+ <path
115
+ d="M8 20.5 14 10l6 10.5L26 10"
116
+ fill="none"
117
+ stroke="#ffffff"
118
+ strokeWidth="2.6"
119
+ strokeLinecap="round"
120
+ strokeLinejoin="round"
121
+ />
122
+ <circle cx="8" cy="20.5" r="3.4" fill={alt} />
123
+ </>
124
+ ),
109
125
  // Two arrows crossing in opposite directions: one notation turned into
110
126
  // another and back, which is the whole of what this one does.
111
127
  openbabel: (alt) => (
@@ -459,5 +459,13 @@
459
459
  "molecule3d.input.clickBackground": "Den Hintergrund anklicken",
460
460
  "molecule3d.helpNote": "Die Tasten wirken, solange der Zeiger über dem Molekül ist. Auf dem Mac ist Ctrl die Control-Taste, nicht ⌘. Bei eingeschaltetem Messwerkzeug wählt ein Klick ein Atom.",
461
461
  "number.increment": "Erhöhen",
462
- "number.decrement": "Verringern"
462
+ "number.decrement": "Verringern",
463
+ "range.lowest": "{label}, Minimum",
464
+ "range.highest": "{label}, Maximum",
465
+ "range.lowestIs": "{label}, Minimum: {value}",
466
+ "range.highestIs": "{label}, Maximum: {value}",
467
+ "range.noLowerBound": "{label}: keine Untergrenze",
468
+ "range.noUpperBound": "{label}: keine Obergrenze",
469
+ "range.typeValue": "Klicken, um einen Wert einzugeben",
470
+ "range.clear": "{label} zurücksetzen"
463
471
  }
@@ -459,5 +459,13 @@
459
459
  "conformers.strategyDetail.likely-systematic": "Walks the torsion combinations in decreasing likelihood, so the first conformers are the most probable ones and the set is reproducible.",
460
460
  "conformers.minimisation.none": "None (no energies)",
461
461
  "number.increment": "Increase",
462
- "number.decrement": "Decrease"
462
+ "number.decrement": "Decrease",
463
+ "range.lowest": "{label}, lowest",
464
+ "range.highest": "{label}, highest",
465
+ "range.lowestIs": "{label}, lowest: {value}",
466
+ "range.highestIs": "{label}, highest: {value}",
467
+ "range.noLowerBound": "{label}: no lower bound",
468
+ "range.noUpperBound": "{label}: no upper bound",
469
+ "range.typeValue": "Click to type a value",
470
+ "range.clear": "Clear {label}"
463
471
  }
@@ -459,5 +459,13 @@
459
459
  "molecule3d.input.clickBackground": "Hacer clic en el fondo",
460
460
  "molecule3d.helpNote": "Las teclas actúan mientras el puntero está sobre la molécula. En un Mac, Ctrl es la tecla Control, no ⌘. Con una herramienta de medida activa, un clic elige un átomo.",
461
461
  "number.increment": "Aumentar",
462
- "number.decrement": "Disminuir"
462
+ "number.decrement": "Disminuir",
463
+ "range.lowest": "{label}, mínimo",
464
+ "range.highest": "{label}, máximo",
465
+ "range.lowestIs": "{label}, mínimo: {value}",
466
+ "range.highestIs": "{label}, máximo: {value}",
467
+ "range.noLowerBound": "{label}: sin límite inferior",
468
+ "range.noUpperBound": "{label}: sin límite superior",
469
+ "range.typeValue": "Haga clic para escribir un valor",
470
+ "range.clear": "Borrar {label}"
463
471
  }
@@ -459,5 +459,13 @@
459
459
  "molecule3d.input.clickBackground": "Cliquer le fond",
460
460
  "molecule3d.helpNote": "Les touches agissent tant que le pointeur est sur la molécule. Sur un Mac, Ctrl est la touche Contrôle, pas ⌘. Avec un outil de mesure actif, un clic choisit un atome.",
461
461
  "number.increment": "Augmenter",
462
- "number.decrement": "Diminuer"
462
+ "number.decrement": "Diminuer",
463
+ "range.lowest": "{label}, minimum",
464
+ "range.highest": "{label}, maximum",
465
+ "range.lowestIs": "{label}, minimum : {value}",
466
+ "range.highestIs": "{label}, maximum : {value}",
467
+ "range.noLowerBound": "{label} : pas de borne inférieure",
468
+ "range.noUpperBound": "{label} : pas de borne supérieure",
469
+ "range.typeValue": "Cliquer pour saisir une valeur",
470
+ "range.clear": "Effacer {label}"
463
471
  }
@@ -459,5 +459,13 @@
459
459
  "conformers.strategyDetail.likely-systematic": "Percorre le combinazioni di torsioni per probabilità decrescente, così i primi conformeri sono i più probabili e l'insieme è riproducibile.",
460
460
  "conformers.minimisation.none": "Nessuna (senza energie)",
461
461
  "number.increment": "Aumenta",
462
- "number.decrement": "Diminuisci"
462
+ "number.decrement": "Diminuisci",
463
+ "range.lowest": "{label}, minimo",
464
+ "range.highest": "{label}, massimo",
465
+ "range.lowestIs": "{label}, minimo: {value}",
466
+ "range.highestIs": "{label}, massimo: {value}",
467
+ "range.noLowerBound": "{label}: nessun limite inferiore",
468
+ "range.noUpperBound": "{label}: nessun limite superiore",
469
+ "range.typeValue": "Fai clic per inserire un valore",
470
+ "range.clear": "Cancella {label}"
463
471
  }
@@ -2,5 +2,6 @@ export {
2
2
  isPartialNumber,
3
3
  numberText,
4
4
  readNumber,
5
+ snapToStep,
5
6
  stepNumber,
6
7
  } from './numberText.ts';
@@ -78,6 +78,26 @@ export function stepNumber(value: number, delta: number): number {
78
78
  return Math.round(moved * factor) / factor;
79
79
  }
80
80
 
81
+ /**
82
+ * A number moved onto the grid of steps laid from an origin.
83
+ *
84
+ * Rounded to the decimals the step and the origin carry, for the reason
85
+ * {@link stepNumber} is: a slider dragged in steps of `0.1` must report `0.3`,
86
+ * because that is what ends up written in the link.
87
+ * @param value - Where the number is now.
88
+ * @param step - The spacing of the grid. A step that is not above zero leaves
89
+ * the number where it is.
90
+ * @param origin - A point the grid passes through. Defaults to `0`.
91
+ * @returns The grid point nearest the number.
92
+ */
93
+ export function snapToStep(value: number, step: number, origin = 0): number {
94
+ if (!(step > 0) || !Number.isFinite(value)) return value;
95
+ const snapped = origin + Math.round((value - origin) / step) * step;
96
+ const decimals = Math.max(decimalsOf(step), decimalsOf(origin));
97
+ const factor = 10 ** decimals;
98
+ return Math.round(snapped * factor) / factor;
99
+ }
100
+
81
101
  /**
82
102
  * How many decimals a number is written with.
83
103
  * @param value - The number.
@@ -0,0 +1,11 @@
1
+ export type { RangeBounds, RangeDomain, RangeHandles } from './rangeBounds.ts';
2
+ export {
3
+ OPEN_RANGE,
4
+ isRangeBounded,
5
+ isRangeDomain,
6
+ movedRange,
7
+ rangeHandles,
8
+ sameRange,
9
+ settleHandles,
10
+ } from './rangeBounds.ts';
11
+ export { rangeHistogramPath } from './rangeHistogram.ts';
@@ -0,0 +1,143 @@
1
+ /**
2
+ * What a range filter keeps, and how its two handles map to it.
3
+ *
4
+ * A filter is two bounds, either of which may be left open. A handle parked at
5
+ * the end of the track is an open side rather than a bound at the track's end,
6
+ * because the track only covers the values the page knows about: a molecule
7
+ * heavier than the heaviest one in the statistics must not be cut by a filter
8
+ * nobody touched.
9
+ */
10
+
11
+ import { clamp } from '../../format/core/clamp.ts';
12
+ import { snapToStep } from '../../number/core/numberText.ts';
13
+
14
+ /** A lowest and a highest value kept, either of which may be left open. */
15
+ export interface RangeBounds {
16
+ /** The lowest value kept, or `null` when nothing is cut from below. */
17
+ readonly min: number | null;
18
+ /** The highest value kept, or `null` when nothing is cut from above. */
19
+ readonly max: number | null;
20
+ }
21
+
22
+ /** The two ends of a slider's track, low first. */
23
+ export type RangeDomain = readonly [number, number];
24
+
25
+ /** Where the two handles of a slider stand, low first. */
26
+ export type RangeHandles = readonly [number, number];
27
+
28
+ /** A range that keeps everything. */
29
+ export const OPEN_RANGE: RangeBounds = Object.freeze({ min: null, max: null });
30
+
31
+ /**
32
+ * Whether a range cuts anything at all.
33
+ * @param range - The range.
34
+ * @returns Whether either side carries a bound.
35
+ */
36
+ export function isRangeBounded(range: RangeBounds): boolean {
37
+ return range.min !== null || range.max !== null;
38
+ }
39
+
40
+ /**
41
+ * Whether two ranges keep the same values.
42
+ * @param left - One range.
43
+ * @param right - The other.
44
+ * @returns Whether both sides agree, an open side matching only an open side.
45
+ */
46
+ export function sameRange(left: RangeBounds, right: RangeBounds): boolean {
47
+ return Object.is(left.min, right.min) && Object.is(left.max, right.max);
48
+ }
49
+
50
+ /**
51
+ * Whether a track can be drawn: two finite ends, the high one above the low.
52
+ * Statistics that have not arrived yet are usually a track of `[0, 0]`.
53
+ * @param domain - The two ends.
54
+ * @returns Whether a slider can be laid along it.
55
+ */
56
+ export function isRangeDomain(domain: RangeDomain): boolean {
57
+ const [low, high] = domain;
58
+ return Number.isFinite(low) && Number.isFinite(high) && high > low;
59
+ }
60
+
61
+ /**
62
+ * Where the handles stand for a range: an open side at the end of the track,
63
+ * and a bound past the track held at its end.
64
+ * @param range - The range.
65
+ * @param domain - The track, already checked with {@link isRangeDomain}.
66
+ * @returns The two handle positions, low first.
67
+ */
68
+ export function rangeHandles(
69
+ range: RangeBounds,
70
+ domain: RangeDomain,
71
+ ): RangeHandles {
72
+ const [low, high] = domain;
73
+ const start = range.min === null ? low : clamp(range.min, low, high);
74
+ const end = range.max === null ? high : clamp(range.max, low, high);
75
+ return start <= end ? [start, end] : [end, start];
76
+ }
77
+
78
+ /**
79
+ * The range two handles stand for once they have moved.
80
+ *
81
+ * Only a handle that moved changes its side. A bound past the end of the track
82
+ * sits at that end, and dragging the other handle must not turn it into an
83
+ * open side; a handle the reader took to the end of the track, on the other
84
+ * hand, opens its side.
85
+ * @param from - The range before the handles moved.
86
+ * @param handles - Where the handles are now.
87
+ * @param domain - The track.
88
+ * @returns The range the reader asked for.
89
+ */
90
+ export function movedRange(
91
+ from: RangeBounds,
92
+ handles: RangeHandles,
93
+ domain: RangeDomain,
94
+ ): RangeBounds {
95
+ const [low, high] = domain;
96
+ const [start, end] = rangeHandles(from, domain);
97
+ return {
98
+ min:
99
+ handles[0] === start ? from.min : handles[0] <= low ? null : handles[0],
100
+ max: handles[1] === end ? from.max : handles[1] >= high ? null : handles[1],
101
+ };
102
+ }
103
+
104
+ /**
105
+ * Where handles settle while they are dragged: a moved handle onto the step
106
+ * grid laid from the low end of the track, an untouched one where it stood.
107
+ *
108
+ * Snapping the untouched handle too would move a bound the reader typed, say
109
+ * `1.23` on a track stepped by `0.5`, the moment the other handle is dragged.
110
+ * The ends of the track are kept even when they are off the grid, since an end
111
+ * is what opens a side.
112
+ * @param next - Where the slider reports the handles.
113
+ * @param from - The range before the drag started.
114
+ * @param step - The grid spacing.
115
+ * @param domain - The track.
116
+ * @returns The handle positions to draw and to report.
117
+ */
118
+ export function settleHandles(
119
+ next: RangeHandles,
120
+ from: RangeBounds,
121
+ step: number,
122
+ domain: RangeDomain,
123
+ ): RangeHandles {
124
+ const [start, end] = rangeHandles(from, domain);
125
+ return [
126
+ next[0] === start ? start : snapHandle(next[0], step, domain),
127
+ next[1] === end ? end : snapHandle(next[1], step, domain),
128
+ ];
129
+ }
130
+
131
+ /**
132
+ * One handle moved onto the step grid, the ends of the track kept as they are.
133
+ * @param value - Where the handle was dropped.
134
+ * @param step - The grid spacing.
135
+ * @param domain - The track.
136
+ * @returns The position the handle settles on.
137
+ */
138
+ function snapHandle(value: number, step: number, domain: RangeDomain): number {
139
+ const [low, high] = domain;
140
+ if (value <= low) return low;
141
+ if (value >= high) return high;
142
+ return clamp(snapToStep(value, step, low), low, high);
143
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The outline of a histogram whose bins split the track into equal widths, as
3
+ * SVG path data in a box one unit wide and one unit tall.
4
+ *
5
+ * One stepped outline rather than a rectangle per bin: adjacent rectangles
6
+ * leave a hairline seam between them wherever their shared edge falls between
7
+ * two pixels, and a thousand bins would be two thousand elements.
8
+ * @param counts - One count per bin, from the low end of the track.
9
+ * @returns The path data, the tallest bin reaching the top; empty when nothing
10
+ * was counted.
11
+ */
12
+ export function rangeHistogramPath(counts: ArrayLike<number>): string {
13
+ const bins = counts.length;
14
+ let tallest = 0;
15
+ for (let index = 0; index < bins; index++) {
16
+ const count = counts[index] as number;
17
+ if (count > tallest) tallest = count;
18
+ }
19
+ if (tallest <= 0) return '';
20
+
21
+ let path = 'M0 1';
22
+ for (let index = 0; index < bins; index++) {
23
+ const count = counts[index] as number;
24
+ const height = count > 0 ? count / tallest : 0;
25
+ path += `V${trim(1 - height)}H${trim((index + 1) / bins)}`;
26
+ }
27
+ return `${path}V1Z`;
28
+ }
29
+
30
+ /**
31
+ * A coordinate written with the five decimals a box of a few hundred pixels
32
+ * can use.
33
+ * @param value - The coordinate.
34
+ * @returns Its text.
35
+ */
36
+ function trim(value: number): string {
37
+ return String(Math.round(value * 1e5) / 1e5);
38
+ }