react-cheminfo 0.37.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.
- package/README.md +77 -1
- package/bin/check-seo.mjs +43 -1
- package/lib/core.d.ts +1 -0
- package/lib/core.d.ts.map +1 -1
- package/lib/core.js +1 -0
- package/lib/core.js.map +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
- package/lib/locales/de.json +9 -1
- package/lib/locales/en.json +9 -1
- package/lib/locales/es.json +9 -1
- package/lib/locales/fr.json +9 -1
- package/lib/locales/it.json +9 -1
- package/lib/number/core/index.d.ts +1 -1
- package/lib/number/core/index.d.ts.map +1 -1
- package/lib/number/core/index.js +1 -1
- package/lib/number/core/index.js.map +1 -1
- package/lib/number/core/numberText.d.ts +13 -0
- package/lib/number/core/numberText.d.ts.map +1 -1
- package/lib/number/core/numberText.js +20 -0
- package/lib/number/core/numberText.js.map +1 -1
- package/lib/range/core/index.d.ts +4 -0
- package/lib/range/core/index.d.ts.map +1 -0
- package/lib/range/core/index.js +3 -0
- package/lib/range/core/index.js.map +1 -0
- package/lib/range/core/rangeBounds.d.ts +79 -0
- package/lib/range/core/rangeBounds.d.ts.map +1 -0
- package/lib/range/core/rangeBounds.js +110 -0
- package/lib/range/core/rangeBounds.js.map +1 -0
- package/lib/range/core/rangeHistogram.d.ts +13 -0
- package/lib/range/core/rangeHistogram.d.ts.map +1 -0
- package/lib/range/core/rangeHistogram.js +39 -0
- package/lib/range/core/rangeHistogram.js.map +1 -0
- package/lib/range/ui/RangeHistogram.d.ts +20 -0
- package/lib/range/ui/RangeHistogram.d.ts.map +1 -0
- package/lib/range/ui/RangeHistogram.js +18 -0
- package/lib/range/ui/RangeHistogram.js.map +1 -0
- package/lib/range/ui/RangeSlider.d.ts +77 -0
- package/lib/range/ui/RangeSlider.d.ts.map +1 -0
- package/lib/range/ui/RangeSlider.js +60 -0
- package/lib/range/ui/RangeSlider.js.map +1 -0
- package/lib/range/ui/RangeValue.d.ts +41 -0
- package/lib/range/ui/RangeValue.d.ts.map +1 -0
- package/lib/range/ui/RangeValue.js +73 -0
- package/lib/range/ui/RangeValue.js.map +1 -0
- package/lib/range/ui/index.d.ts +3 -0
- package/lib/range/ui/index.d.ts.map +1 -0
- package/lib/range/ui/index.js +2 -0
- package/lib/range/ui/index.js.map +1 -0
- package/lib/seo/core/documentMeta.d.ts +16 -0
- package/lib/seo/core/documentMeta.d.ts.map +1 -1
- package/lib/seo/core/documentMeta.js +18 -0
- package/lib/seo/core/documentMeta.js.map +1 -1
- package/lib/seo/core/index.d.ts +3 -1
- package/lib/seo/core/index.d.ts.map +1 -1
- package/lib/seo/core/index.js +2 -1
- package/lib/seo/core/index.js.map +1 -1
- package/lib/seo/core/noscript.d.ts +8 -0
- package/lib/seo/core/noscript.d.ts.map +1 -1
- package/lib/seo/core/noscript.js +10 -3
- package/lib/seo/core/noscript.js.map +1 -1
- package/lib/seo/core/pageMeta.d.ts +10 -2
- package/lib/seo/core/pageMeta.d.ts.map +1 -1
- package/lib/seo/core/pageMeta.js +12 -3
- package/lib/seo/core/pageMeta.js.map +1 -1
- package/lib/seo/core/siteFiles.d.ts +32 -3
- package/lib/seo/core/siteFiles.d.ts.map +1 -1
- package/lib/seo/core/siteFiles.js +13 -4
- package/lib/seo/core/siteFiles.js.map +1 -1
- package/lib/seo/core/startDocumentMeta.js +8 -7
- package/lib/seo/core/startDocumentMeta.js.map +1 -1
- package/lib/seo/vite/prerender.d.ts +26 -4
- package/lib/seo/vite/prerender.d.ts.map +1 -1
- package/lib/seo/vite/prerender.js +100 -30
- package/lib/seo/vite/prerender.js.map +1 -1
- package/lib/ui.d.ts +1 -0
- package/lib/ui.d.ts.map +1 -1
- package/lib/ui.js +1 -0
- package/lib/ui.js.map +1 -1
- package/package.json +1 -1
- package/src/core.ts +1 -0
- package/src/locales/de.json +9 -1
- package/src/locales/en.json +9 -1
- package/src/locales/es.json +9 -1
- package/src/locales/fr.json +9 -1
- package/src/locales/it.json +9 -1
- package/src/number/core/index.ts +1 -0
- package/src/number/core/numberText.ts +20 -0
- package/src/range/core/index.ts +11 -0
- package/src/range/core/rangeBounds.ts +143 -0
- package/src/range/core/rangeHistogram.ts +38 -0
- package/src/range/ui/RangeHistogram.tsx +49 -0
- package/src/range/ui/RangeSlider.tsx +209 -0
- package/src/range/ui/RangeValue.tsx +166 -0
- package/src/range/ui/index.ts +2 -0
- package/src/seo/core/documentMeta.ts +22 -0
- package/src/seo/core/index.ts +8 -1
- package/src/seo/core/noscript.ts +20 -2
- package/src/seo/core/pageMeta.ts +29 -5
- package/src/seo/core/siteFiles.ts +45 -10
- package/src/seo/core/startDocumentMeta.ts +9 -9
- package/src/seo/vite/prerender.ts +160 -36
- package/src/ui.ts +1 -0
- package/styles/chrome.css +135 -0
|
@@ -0,0 +1,110 @@
|
|
|
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
|
+
import { clamp } from "../../format/core/clamp.js";
|
|
11
|
+
import { snapToStep } from "../../number/core/numberText.js";
|
|
12
|
+
/** A range that keeps everything. */
|
|
13
|
+
export const OPEN_RANGE = Object.freeze({ min: null, max: null });
|
|
14
|
+
/**
|
|
15
|
+
* Whether a range cuts anything at all.
|
|
16
|
+
* @param range - The range.
|
|
17
|
+
* @returns Whether either side carries a bound.
|
|
18
|
+
*/
|
|
19
|
+
export function isRangeBounded(range) {
|
|
20
|
+
return range.min !== null || range.max !== null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Whether two ranges keep the same values.
|
|
24
|
+
* @param left - One range.
|
|
25
|
+
* @param right - The other.
|
|
26
|
+
* @returns Whether both sides agree, an open side matching only an open side.
|
|
27
|
+
*/
|
|
28
|
+
export function sameRange(left, right) {
|
|
29
|
+
return Object.is(left.min, right.min) && Object.is(left.max, right.max);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Whether a track can be drawn: two finite ends, the high one above the low.
|
|
33
|
+
* Statistics that have not arrived yet are usually a track of `[0, 0]`.
|
|
34
|
+
* @param domain - The two ends.
|
|
35
|
+
* @returns Whether a slider can be laid along it.
|
|
36
|
+
*/
|
|
37
|
+
export function isRangeDomain(domain) {
|
|
38
|
+
const [low, high] = domain;
|
|
39
|
+
return Number.isFinite(low) && Number.isFinite(high) && high > low;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Where the handles stand for a range: an open side at the end of the track,
|
|
43
|
+
* and a bound past the track held at its end.
|
|
44
|
+
* @param range - The range.
|
|
45
|
+
* @param domain - The track, already checked with {@link isRangeDomain}.
|
|
46
|
+
* @returns The two handle positions, low first.
|
|
47
|
+
*/
|
|
48
|
+
export function rangeHandles(range, domain) {
|
|
49
|
+
const [low, high] = domain;
|
|
50
|
+
const start = range.min === null ? low : clamp(range.min, low, high);
|
|
51
|
+
const end = range.max === null ? high : clamp(range.max, low, high);
|
|
52
|
+
return start <= end ? [start, end] : [end, start];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The range two handles stand for once they have moved.
|
|
56
|
+
*
|
|
57
|
+
* Only a handle that moved changes its side. A bound past the end of the track
|
|
58
|
+
* sits at that end, and dragging the other handle must not turn it into an
|
|
59
|
+
* open side; a handle the reader took to the end of the track, on the other
|
|
60
|
+
* hand, opens its side.
|
|
61
|
+
* @param from - The range before the handles moved.
|
|
62
|
+
* @param handles - Where the handles are now.
|
|
63
|
+
* @param domain - The track.
|
|
64
|
+
* @returns The range the reader asked for.
|
|
65
|
+
*/
|
|
66
|
+
export function movedRange(from, handles, domain) {
|
|
67
|
+
const [low, high] = domain;
|
|
68
|
+
const [start, end] = rangeHandles(from, domain);
|
|
69
|
+
return {
|
|
70
|
+
min: handles[0] === start ? from.min : handles[0] <= low ? null : handles[0],
|
|
71
|
+
max: handles[1] === end ? from.max : handles[1] >= high ? null : handles[1],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Where handles settle while they are dragged: a moved handle onto the step
|
|
76
|
+
* grid laid from the low end of the track, an untouched one where it stood.
|
|
77
|
+
*
|
|
78
|
+
* Snapping the untouched handle too would move a bound the reader typed, say
|
|
79
|
+
* `1.23` on a track stepped by `0.5`, the moment the other handle is dragged.
|
|
80
|
+
* The ends of the track are kept even when they are off the grid, since an end
|
|
81
|
+
* is what opens a side.
|
|
82
|
+
* @param next - Where the slider reports the handles.
|
|
83
|
+
* @param from - The range before the drag started.
|
|
84
|
+
* @param step - The grid spacing.
|
|
85
|
+
* @param domain - The track.
|
|
86
|
+
* @returns The handle positions to draw and to report.
|
|
87
|
+
*/
|
|
88
|
+
export function settleHandles(next, from, step, domain) {
|
|
89
|
+
const [start, end] = rangeHandles(from, domain);
|
|
90
|
+
return [
|
|
91
|
+
next[0] === start ? start : snapHandle(next[0], step, domain),
|
|
92
|
+
next[1] === end ? end : snapHandle(next[1], step, domain),
|
|
93
|
+
];
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* One handle moved onto the step grid, the ends of the track kept as they are.
|
|
97
|
+
* @param value - Where the handle was dropped.
|
|
98
|
+
* @param step - The grid spacing.
|
|
99
|
+
* @param domain - The track.
|
|
100
|
+
* @returns The position the handle settles on.
|
|
101
|
+
*/
|
|
102
|
+
function snapHandle(value, step, domain) {
|
|
103
|
+
const [low, high] = domain;
|
|
104
|
+
if (value <= low)
|
|
105
|
+
return low;
|
|
106
|
+
if (value >= high)
|
|
107
|
+
return high;
|
|
108
|
+
return clamp(snapToStep(value, step, low), low, high);
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=rangeBounds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rangeBounds.js","sourceRoot":"","sources":["../../../src/range/core/rangeBounds.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
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 declare function rangeHistogramPath(counts: ArrayLike<number>): string;
|
|
13
|
+
//# sourceMappingURL=rangeHistogram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rangeHistogram.d.ts","sourceRoot":"","sources":["../../../src/range/core/rangeHistogram.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,MAAM,CAgBpE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
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) {
|
|
13
|
+
const bins = counts.length;
|
|
14
|
+
let tallest = 0;
|
|
15
|
+
for (let index = 0; index < bins; index++) {
|
|
16
|
+
const count = counts[index];
|
|
17
|
+
if (count > tallest)
|
|
18
|
+
tallest = count;
|
|
19
|
+
}
|
|
20
|
+
if (tallest <= 0)
|
|
21
|
+
return '';
|
|
22
|
+
let path = 'M0 1';
|
|
23
|
+
for (let index = 0; index < bins; index++) {
|
|
24
|
+
const count = counts[index];
|
|
25
|
+
const height = count > 0 ? count / tallest : 0;
|
|
26
|
+
path += `V${trim(1 - height)}H${trim((index + 1) / bins)}`;
|
|
27
|
+
}
|
|
28
|
+
return `${path}V1Z`;
|
|
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) {
|
|
37
|
+
return String(Math.round(value * 1e5) / 1e5);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=rangeHistogram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rangeHistogram.js","sourceRoot":"","sources":["../../../src/range/core/rangeHistogram.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAyB;IAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3B,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAW,CAAC;QACtC,IAAI,KAAK,GAAG,OAAO;YAAE,OAAO,GAAG,KAAK,CAAC;IACvC,CAAC;IACD,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAE5B,IAAI,IAAI,GAAG,MAAM,CAAC;IAClB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAW,CAAC;QACtC,MAAM,MAAM,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/C,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;IAC7D,CAAC;IACD,OAAO,GAAG,IAAI,KAAK,CAAC;AACtB,CAAC;AAED;;;;;GAKG;AACH,SAAS,IAAI,CAAC,KAAa;IACzB,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
/** What the histogram over a range slider needs. */
|
|
3
|
+
export interface RangeHistogramProps {
|
|
4
|
+
/** One count per bin, the bins splitting the track into equal widths. */
|
|
5
|
+
counts: ArrayLike<number>;
|
|
6
|
+
/** Where the kept part starts, as a fraction of the track. */
|
|
7
|
+
start: number;
|
|
8
|
+
/** Where it ends. */
|
|
9
|
+
end: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* How the values are spread along the track, the part the handles keep drawn
|
|
13
|
+
* in the brand colour. The outline is drawn twice, the second copy clipped to
|
|
14
|
+
* the handles, so a drag moves one rectangle and the outline is never redrawn.
|
|
15
|
+
* @param props - See {@link RangeHistogramProps}.
|
|
16
|
+
* @returns The histogram, hidden from a screen reader: the values under the
|
|
17
|
+
* track already say what it keeps.
|
|
18
|
+
*/
|
|
19
|
+
export declare function RangeHistogram(props: RangeHistogramProps): ReactElement;
|
|
20
|
+
//# sourceMappingURL=RangeHistogram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RangeHistogram.d.ts","sourceRoot":"","sources":["../../../src/range/ui/RangeHistogram.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAK1C,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC,yEAAyE;IACzE,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAC1B,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,YAAY,CAyBvE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useId, useMemo } from 'react';
|
|
3
|
+
import { rangeHistogramPath } from "../core/rangeHistogram.js";
|
|
4
|
+
/**
|
|
5
|
+
* How the values are spread along the track, the part the handles keep drawn
|
|
6
|
+
* in the brand colour. The outline is drawn twice, the second copy clipped to
|
|
7
|
+
* the handles, so a drag moves one rectangle and the outline is never redrawn.
|
|
8
|
+
* @param props - See {@link RangeHistogramProps}.
|
|
9
|
+
* @returns The histogram, hidden from a screen reader: the values under the
|
|
10
|
+
* track already say what it keeps.
|
|
11
|
+
*/
|
|
12
|
+
export function RangeHistogram(props) {
|
|
13
|
+
const { counts, start, end } = props;
|
|
14
|
+
const clip = `range-histogram-${useId().replaceAll(/\W/g, '')}`;
|
|
15
|
+
const outline = useMemo(() => rangeHistogramPath(counts), [counts]);
|
|
16
|
+
return (_jsxs("svg", { className: "range-slider__histogram", viewBox: "0 0 1 1", preserveAspectRatio: "none", "aria-hidden": "true", children: [_jsx("defs", { children: _jsx("clipPath", { id: clip, children: _jsx("rect", { x: start, y: 0, width: Math.max(end - start, 0), height: 1 }) }) }), _jsx("path", { className: "range-slider__bars", d: outline }), _jsx("path", { className: "range-slider__bars range-slider__bars--kept", d: outline, clipPath: `url(#${clip})` })] }));
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=RangeHistogram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RangeHistogram.js","sourceRoot":"","sources":["../../../src/range/ui/RangeHistogram.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAY/D;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,KAA0B;IACvD,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;IACrC,MAAM,IAAI,GAAG,mBAAmB,KAAK,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC;IAChE,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEpE,OAAO,CACL,eACE,SAAS,EAAC,yBAAyB,EACnC,OAAO,EAAC,SAAS,EACjB,mBAAmB,EAAC,MAAM,iBACd,MAAM,aAElB,yBACE,mBAAU,EAAE,EAAE,IAAI,YAChB,eAAM,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAI,GAC3D,GACN,EACP,eAAM,SAAS,EAAC,oBAAoB,EAAC,CAAC,EAAE,OAAO,GAAI,EACnD,eACE,SAAS,EAAC,6CAA6C,EACvD,CAAC,EAAE,OAAO,EACV,QAAQ,EAAE,QAAQ,IAAI,GAAG,GACzB,IACE,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import type { RangeBounds, RangeDomain } from '../core/rangeBounds.ts';
|
|
3
|
+
/** What a `RangeSlider` needs. */
|
|
4
|
+
export interface RangeSliderProps {
|
|
5
|
+
/** The quantity bounded, written over the track and read to a screen reader. */
|
|
6
|
+
label: string;
|
|
7
|
+
/**
|
|
8
|
+
* The unit written after the label, e.g. `g/mol`.
|
|
9
|
+
* @default undefined — nothing is written
|
|
10
|
+
*/
|
|
11
|
+
unit?: string;
|
|
12
|
+
/**
|
|
13
|
+
* The two ends of the track, low first: usually the smallest and largest
|
|
14
|
+
* value the data holds. A handle at an end leaves that side open, so a value
|
|
15
|
+
* past the track is never cut by a filter nobody touched.
|
|
16
|
+
*/
|
|
17
|
+
domain: RangeDomain;
|
|
18
|
+
/** The range in force; a `null` side is open. */
|
|
19
|
+
value: RangeBounds;
|
|
20
|
+
/**
|
|
21
|
+
* Called when the range settles: a handle released, a value typed, the range
|
|
22
|
+
* cleared. Never while a handle is being dragged, so a page fetching on it
|
|
23
|
+
* fetches once per gesture.
|
|
24
|
+
*/
|
|
25
|
+
onChange: (range: RangeBounds) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Called on every step of a drag, for what is cheap to redraw live — a count,
|
|
28
|
+
* a heatmap computed in the page. Nothing that fetches belongs here.
|
|
29
|
+
* @default undefined
|
|
30
|
+
*/
|
|
31
|
+
onPreview?: (range: RangeBounds) => void;
|
|
32
|
+
/**
|
|
33
|
+
* The spacing the handles move by, from the low end of the track. Typed
|
|
34
|
+
* values are not held to it.
|
|
35
|
+
* @default 1
|
|
36
|
+
*/
|
|
37
|
+
step?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Whether only whole numbers can be typed. A typed decimal is rounded.
|
|
40
|
+
* @default false
|
|
41
|
+
*/
|
|
42
|
+
integer?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* How a value is written under the track.
|
|
45
|
+
* @default the number as it is, with no grouping — a year is not `1,990`
|
|
46
|
+
*/
|
|
47
|
+
format?: (value: number) => string;
|
|
48
|
+
/**
|
|
49
|
+
* How the values are spread along the track: one count per bin, the bins
|
|
50
|
+
* splitting the track into equal widths. Drawn over the track, the part the
|
|
51
|
+
* handles keep in the brand colour.
|
|
52
|
+
* @default undefined — no histogram
|
|
53
|
+
*/
|
|
54
|
+
histogram?: ArrayLike<number>;
|
|
55
|
+
/** @default false */
|
|
56
|
+
disabled?: boolean;
|
|
57
|
+
/** @default undefined */
|
|
58
|
+
className?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Value of the `data-testid` attribute of the wrapper.
|
|
61
|
+
* @default undefined
|
|
62
|
+
*/
|
|
63
|
+
testId?: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A range picked with two handles, its two values written under the track
|
|
67
|
+
* where a click turns either into a box to type an exact number.
|
|
68
|
+
*
|
|
69
|
+
* The handles are Blueprint's — the keyboard, the touch screen and the
|
|
70
|
+
* screen reader are already handled there — dressed in the family's colours.
|
|
71
|
+
* What this adds is the meaning of an end: a handle parked at the end of the
|
|
72
|
+
* track is an open side, not a bound at the track's end.
|
|
73
|
+
* @param props - See {@link RangeSliderProps}.
|
|
74
|
+
* @returns The label, the track and the two values.
|
|
75
|
+
*/
|
|
76
|
+
export declare function RangeSlider(props: RangeSliderProps): ReactElement;
|
|
77
|
+
//# sourceMappingURL=RangeSlider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RangeSlider.d.ts","sourceRoot":"","sources":["../../../src/range/ui/RangeSlider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAM1C,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EAEZ,MAAM,wBAAwB,CAAC;AAchC,kCAAkC;AAClC,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,MAAM,EAAE,WAAW,CAAC;IACpB,iDAAiD;IACjD,KAAK,EAAE,WAAW,CAAC;IACnB;;;;OAIG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACvC;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACzC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAC9B,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,CAsGjE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Button, RangeSlider as BlueprintRangeSlider } from '@blueprintjs/core';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { useChromeT } from "../../i18n/ui/useT.js";
|
|
5
|
+
import { numberText } from "../../number/core/numberText.js";
|
|
6
|
+
import { joinClassNames } from "../../shared/ui/joinClassNames.js";
|
|
7
|
+
import { OPEN_RANGE, isRangeBounded, isRangeDomain, movedRange, rangeHandles, sameRange, settleHandles, } from "../core/rangeBounds.js";
|
|
8
|
+
import { RangeHistogram } from "./RangeHistogram.js";
|
|
9
|
+
import { RangeValue } from "./RangeValue.js";
|
|
10
|
+
/**
|
|
11
|
+
* A range picked with two handles, its two values written under the track
|
|
12
|
+
* where a click turns either into a box to type an exact number.
|
|
13
|
+
*
|
|
14
|
+
* The handles are Blueprint's — the keyboard, the touch screen and the
|
|
15
|
+
* screen reader are already handled there — dressed in the family's colours.
|
|
16
|
+
* What this adds is the meaning of an end: a handle parked at the end of the
|
|
17
|
+
* track is an open side, not a bound at the track's end.
|
|
18
|
+
* @param props - See {@link RangeSliderProps}.
|
|
19
|
+
* @returns The label, the track and the two values.
|
|
20
|
+
*/
|
|
21
|
+
export function RangeSlider(props) {
|
|
22
|
+
const { label, unit, domain, value, onChange, onPreview } = props;
|
|
23
|
+
const { step = 1, integer = false, format = numberText } = props;
|
|
24
|
+
const { histogram, disabled = false, className, testId } = props;
|
|
25
|
+
const t = useChromeT();
|
|
26
|
+
const [drag, setDrag] = useState(null);
|
|
27
|
+
const [editing, setEditing] = useState(null);
|
|
28
|
+
const spacing = step > 0 ? step : 1;
|
|
29
|
+
const drawable = isRangeDomain(domain);
|
|
30
|
+
const handles = drag?.handles ?? rangeHandles(value, domain);
|
|
31
|
+
const shown = drag === null ? value : movedRange(drag.from, handles, domain);
|
|
32
|
+
function move(next) {
|
|
33
|
+
const from = drag?.from ?? value;
|
|
34
|
+
const settled = settleHandles(next, from, spacing, domain);
|
|
35
|
+
setDrag({ from, handles: settled });
|
|
36
|
+
onPreview?.(movedRange(from, settled, domain));
|
|
37
|
+
}
|
|
38
|
+
function release(next) {
|
|
39
|
+
const from = drag?.from ?? value;
|
|
40
|
+
const settled = settleHandles(next, from, spacing, domain);
|
|
41
|
+
const range = movedRange(from, settled, domain);
|
|
42
|
+
setDrag(null);
|
|
43
|
+
if (!sameRange(range, from))
|
|
44
|
+
onChange(range);
|
|
45
|
+
}
|
|
46
|
+
function type(side, typed) {
|
|
47
|
+
const range = { ...value, [side]: typed ?? null };
|
|
48
|
+
if (!sameRange(range, value))
|
|
49
|
+
onChange(range);
|
|
50
|
+
}
|
|
51
|
+
return (_jsxs("div", { className: joinClassNames('range-slider', className), "data-testid": testId, children: [_jsxs("div", { className: "range-slider__head", children: [_jsxs("span", { className: "range-slider__label", children: [label, unit ? _jsxs("span", { className: "range-slider__unit", children: [" (", unit, ")"] }) : null] }), isRangeBounded(value) && !disabled ? (_jsx(Button, { variant: "minimal", size: "small", icon: "cross", "aria-label": t('range.clear', { label }), title: t('range.clear', { label }), onClick: () => onChange(OPEN_RANGE) })) : null] }), drawable ? (_jsxs("div", { className: "range-slider__track", children: [histogram === undefined ? null : (_jsx(RangeHistogram, { counts: histogram, start: (handles[0] - domain[0]) / (domain[1] - domain[0]), end: (handles[1] - domain[0]) / (domain[1] - domain[0]) })), _jsx(BlueprintRangeSlider, { min: domain[0], max: domain[1], stepSize: spacing, labelRenderer: false, disabled: disabled, value: [handles[0], handles[1]], handleHtmlProps: {
|
|
52
|
+
start: { 'aria-label': t('range.lowest', { label }) },
|
|
53
|
+
end: { 'aria-label': t('range.highest', { label }) },
|
|
54
|
+
}, onChange: move, onRelease: release })] })) : null, _jsx("div", { className: "range-slider__values", children: ['min', 'max'].map((side) => (_jsx(RangeValue, { side: side, bound: shown[side], end: side === 'min' ? domain[0] : domain[1], label: label, format: format, limit: side === 'min' ? value.max : value.min, step: spacing, integer: integer, disabled: disabled, editing: editing === side, onEdit: () => setEditing(side), onDone: (typed, cancelled) => {
|
|
55
|
+
setEditing(null);
|
|
56
|
+
if (!cancelled)
|
|
57
|
+
type(side, typed);
|
|
58
|
+
} }, side))) })] }));
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=RangeSlider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RangeSlider.js","sourceRoot":"","sources":["../../../src/range/ui/RangeSlider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
/** What one end of a range slider's row of values needs. */
|
|
3
|
+
export interface RangeValueProps {
|
|
4
|
+
/** Which end this is. */
|
|
5
|
+
side: 'min' | 'max';
|
|
6
|
+
/** The bound on this side, or `null` when the side is open. */
|
|
7
|
+
bound: number | null;
|
|
8
|
+
/** The end of the track on this side, shown faint while the side is open. */
|
|
9
|
+
end: number;
|
|
10
|
+
/** The quantity the slider bounds, for a screen reader. */
|
|
11
|
+
label: string;
|
|
12
|
+
/** How a number is written. */
|
|
13
|
+
format: (value: number) => string;
|
|
14
|
+
/** The bound on the other side, which a typed value may not cross. */
|
|
15
|
+
limit: number | null;
|
|
16
|
+
/** What one press of an arrow key adds in the box. */
|
|
17
|
+
step: number;
|
|
18
|
+
/** Whether only whole numbers are wanted. */
|
|
19
|
+
integer: boolean;
|
|
20
|
+
/** Whether the value can be edited. */
|
|
21
|
+
disabled: boolean;
|
|
22
|
+
/** Whether the box is open for typing. */
|
|
23
|
+
editing: boolean;
|
|
24
|
+
/** Open the box. */
|
|
25
|
+
onEdit: () => void;
|
|
26
|
+
/**
|
|
27
|
+
* Close the box, with what it holds — `undefined` for an emptied box — and
|
|
28
|
+
* whether Escape closed it, in which case nothing typed is kept.
|
|
29
|
+
*/
|
|
30
|
+
onDone: (value: number | undefined, cancelled: boolean) => void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* One end of a range, written under the track: a bound, or the end of the
|
|
34
|
+
* track in faint ink when the side is open. A click turns it into a box, so a
|
|
35
|
+
* value the handles cannot land on is still one click and a few keystrokes
|
|
36
|
+
* away.
|
|
37
|
+
* @param props - See {@link RangeValueProps}.
|
|
38
|
+
* @returns The value, or the box it is typed into.
|
|
39
|
+
*/
|
|
40
|
+
export declare function RangeValue(props: RangeValueProps): ReactElement;
|
|
41
|
+
//# sourceMappingURL=RangeValue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RangeValue.d.ts","sourceRoot":"","sources":["../../../src/range/ui/RangeValue.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAC;AAOzD,4DAA4D;AAC5D,MAAM,WAAW,eAAe;IAC9B,yBAAyB;IACzB,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;IACpB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,+BAA+B;IAC/B,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAClC,sEAAsE;IACtE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,uCAAuC;IACvC,QAAQ,EAAE,OAAO,CAAC;IAClB,0CAA0C;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB;;;OAGG;IACH,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;CACjE;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,CA+C/D"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { useChromeT } from "../../i18n/ui/useT.js";
|
|
4
|
+
import { NumberInput } from "../../number/ui/NumberInput.js";
|
|
5
|
+
import { joinClassNames } from "../../shared/ui/joinClassNames.js";
|
|
6
|
+
/**
|
|
7
|
+
* One end of a range, written under the track: a bound, or the end of the
|
|
8
|
+
* track in faint ink when the side is open. A click turns it into a box, so a
|
|
9
|
+
* value the handles cannot land on is still one click and a few keystrokes
|
|
10
|
+
* away.
|
|
11
|
+
* @param props - See {@link RangeValueProps}.
|
|
12
|
+
* @returns The value, or the box it is typed into.
|
|
13
|
+
*/
|
|
14
|
+
export function RangeValue(props) {
|
|
15
|
+
const { side, bound, end, label, format, disabled, editing, onEdit } = props;
|
|
16
|
+
const t = useChromeT();
|
|
17
|
+
if (editing) {
|
|
18
|
+
const { limit, step, integer, onDone } = props;
|
|
19
|
+
return (_jsx(RangeValueEditor, { side: side, bound: bound, end: end, label: label, format: format, limit: limit, step: step, integer: integer, onDone: onDone }));
|
|
20
|
+
}
|
|
21
|
+
const open = bound === null;
|
|
22
|
+
const shown = open ? end : bound;
|
|
23
|
+
const text = Number.isFinite(shown) ? format(shown) : '–';
|
|
24
|
+
const name = open
|
|
25
|
+
? t(side === 'min' ? 'range.noLowerBound' : 'range.noUpperBound', {
|
|
26
|
+
label,
|
|
27
|
+
})
|
|
28
|
+
: t(side === 'min' ? 'range.lowestIs' : 'range.highestIs', {
|
|
29
|
+
label,
|
|
30
|
+
value: text,
|
|
31
|
+
});
|
|
32
|
+
return (_jsx("button", { type: "button", className: joinClassNames('range-slider__value', open && 'range-slider__value--open'), disabled: disabled, title: t('range.typeValue'), "aria-label": name, onClick: onEdit, children: text }));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The box a value is typed into. Enter or leaving it keeps what it holds;
|
|
36
|
+
* Escape drops it.
|
|
37
|
+
* @param props - See {@link RangeValueEditorProps}.
|
|
38
|
+
* @returns The box, focused and selected.
|
|
39
|
+
*/
|
|
40
|
+
function RangeValueEditor(props) {
|
|
41
|
+
const { side, bound, end, label, format, limit, step, integer } = props;
|
|
42
|
+
const { onDone } = props;
|
|
43
|
+
const t = useChromeT();
|
|
44
|
+
const [typed, setTyped] = useState(bound ?? undefined);
|
|
45
|
+
// The box settles its number — rounded, held inside its bounds — as it is
|
|
46
|
+
// left, and that happens in the same blur this wrapper hears afterwards,
|
|
47
|
+
// before any re-render: refs are what carry it across.
|
|
48
|
+
const latest = useRef(typed);
|
|
49
|
+
const cancelled = useRef(false);
|
|
50
|
+
const host = useRef(null);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
const input = host.current?.querySelector('input');
|
|
53
|
+
input?.focus();
|
|
54
|
+
input?.select();
|
|
55
|
+
}, []);
|
|
56
|
+
function press(event) {
|
|
57
|
+
if (event.key !== 'Enter' && event.key !== 'Escape')
|
|
58
|
+
return;
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
// An Escape that closes the box must not also close a dialog around it.
|
|
61
|
+
event.stopPropagation();
|
|
62
|
+
cancelled.current = event.key === 'Escape';
|
|
63
|
+
if (event.target instanceof HTMLElement)
|
|
64
|
+
event.target.blur();
|
|
65
|
+
}
|
|
66
|
+
return (_jsx("span", { ref: host, className: joinClassNames('range-slider__editor', `range-slider__editor--${side}`), onKeyDown: press, onBlur: () => onDone(latest.current, cancelled.current), children: _jsx(NumberInput, { allowEmpty: true, size: "small", buttons: false, fill: true, value: typed, step: step, integer: integer, min: side === 'max' ? (limit ?? undefined) : undefined, max: side === 'min' ? (limit ?? undefined) : undefined, placeholder: Number.isFinite(end) ? format(end) : undefined, ariaLabel: t(side === 'min' ? 'range.lowest' : 'range.highest', {
|
|
67
|
+
label,
|
|
68
|
+
}), onChange: (next) => {
|
|
69
|
+
latest.current = next;
|
|
70
|
+
setTyped(next);
|
|
71
|
+
} }) }));
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=RangeValue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RangeValue.js","sourceRoot":"","sources":["../../../src/range/ui/RangeValue.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/range/ui/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/range/ui/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAmB,CAAC"}
|
|
@@ -9,6 +9,16 @@
|
|
|
9
9
|
* @param meta - What the page on screen is called and where it is indexed.
|
|
10
10
|
*/
|
|
11
11
|
export declare function writeDocumentMeta(meta: DocumentMeta): void;
|
|
12
|
+
/**
|
|
13
|
+
* Say which language the page on screen is in.
|
|
14
|
+
*
|
|
15
|
+
* The file the build wrote already says it, and a click that switches language
|
|
16
|
+
* has to move it with the rest of the head: a page whose `lang` lies is read
|
|
17
|
+
* aloud wrong by a screen reader and offered to the wrong reader by a search
|
|
18
|
+
* engine, and nothing on screen shows it.
|
|
19
|
+
* @param language - The language tag, e.g. `fr`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function documentLanguage(language: string): void;
|
|
12
22
|
/**
|
|
13
23
|
* Name the browser tab.
|
|
14
24
|
* @param title - The title of the page, site name included.
|
|
@@ -41,5 +51,11 @@ export interface DocumentMeta {
|
|
|
41
51
|
* @default undefined
|
|
42
52
|
*/
|
|
43
53
|
canonical?: string;
|
|
54
|
+
/**
|
|
55
|
+
* The language the page is written in, for `<html lang>`. Left out, the one
|
|
56
|
+
* the page was served with stays as it is.
|
|
57
|
+
* @default undefined
|
|
58
|
+
*/
|
|
59
|
+
language?: string;
|
|
44
60
|
}
|
|
45
61
|
//# sourceMappingURL=documentMeta.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentMeta.d.ts","sourceRoot":"","sources":["../../../src/seo/core/documentMeta.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"documentMeta.d.ts","sourceRoot":"","sources":["../../../src/seo/core/documentMeta.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAM1D;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAIvD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAGjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAiBhD;AAED,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -18,6 +18,24 @@ export function writeDocumentMeta(meta) {
|
|
|
18
18
|
metaDescription(meta.description);
|
|
19
19
|
if (meta.canonical)
|
|
20
20
|
canonicalLink(meta.canonical);
|
|
21
|
+
if (meta.language)
|
|
22
|
+
documentLanguage(meta.language);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Say which language the page on screen is in.
|
|
26
|
+
*
|
|
27
|
+
* The file the build wrote already says it, and a click that switches language
|
|
28
|
+
* has to move it with the rest of the head: a page whose `lang` lies is read
|
|
29
|
+
* aloud wrong by a screen reader and offered to the wrong reader by a search
|
|
30
|
+
* engine, and nothing on screen shows it.
|
|
31
|
+
* @param language - The language tag, e.g. `fr`.
|
|
32
|
+
*/
|
|
33
|
+
export function documentLanguage(language) {
|
|
34
|
+
if (typeof document === 'undefined')
|
|
35
|
+
return;
|
|
36
|
+
const root = document.documentElement;
|
|
37
|
+
if (root)
|
|
38
|
+
root.lang = language;
|
|
21
39
|
}
|
|
22
40
|
/**
|
|
23
41
|
* Name the browser tab.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentMeta.js","sourceRoot":"","sources":["../../../src/seo/core/documentMeta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAEtE;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAkB;IAClD,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO;IAC5C,IAAI,IAAI,CAAC,KAAK;QAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,IAAI,CAAC,WAAW;QAAE,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACxD,IAAI,IAAI,CAAC,SAAS;QAAE,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"documentMeta.js","sourceRoot":"","sources":["../../../src/seo/core/documentMeta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAEtE;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAkB;IAClD,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO;IAC5C,IAAI,IAAI,CAAC,KAAK;QAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,IAAI,CAAC,WAAW;QAAE,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACxD,IAAI,IAAI,CAAC,SAAS;QAAE,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAClD,IAAI,IAAI,CAAC,QAAQ;QAAE,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO;IAC5C,MAAM,IAAI,GAAG,QAAQ,CAAC,eAAe,CAAC;IACtC,IAAI,IAAI;QAAE,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO;IAC5C,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;AACzB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO;IAC5C,MAAM,OAAO,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO;IAE3B,MAAM,QAAQ,GAAG,QAAQ,CAAC,aAAa,CACrC,uBAAuB,CACxB,CAAC;IACF,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,CAAC,IAAI,GAAG,OAAO,CAAC;QACxB,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,CAAC,GAAG,GAAG,WAAW,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC;AACtB,CAAC;AA2BD,SAAS,eAAe,CAAC,OAAe;IACtC,MAAM,QAAQ,GAAG,QAAQ,CAAC,aAAa,CACrC,0BAA0B,CAC3B,CAAC;IACF,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;QAC3B,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;AACzB,CAAC"}
|
package/lib/seo/core/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
export type { AlternateOptions } from './alternates.ts';
|
|
2
|
+
export { alternateLinkTags } from './alternates.ts';
|
|
1
3
|
export type { DocumentMeta } from './documentMeta.ts';
|
|
2
4
|
export { writeDocumentMeta } from './documentMeta.ts';
|
|
3
5
|
export type { NoscriptEcosystem, NoscriptHrefs, NoscriptOptions, NoscriptRoute, NoscriptText, } from './noscript.ts';
|
|
4
6
|
export { noscriptIndex } from './noscript.ts';
|
|
5
7
|
export type { PageMetaOptions } from './pageMeta.ts';
|
|
6
|
-
export { injectPageMeta, pageDocumentMeta, pageHeadTags } from './pageMeta.ts';
|
|
8
|
+
export { injectPageMeta, pageDocumentMeta, pageHeadTags, pageLanguage, } from './pageMeta.ts';
|
|
7
9
|
export type { PageContent, PageSection, PageTable } from './pageProse.ts';
|
|
8
10
|
export { pageProseHtml } from './pageProse.ts';
|
|
9
11
|
export type { PlainDescriptionOptions } from './plainDescription.ts';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/seo/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,aAAa,EACb,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/seo/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,aAAa,EACb,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACrE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACnE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC7E,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,YAAY,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC"}
|