@scalewing/react 1.38.0 → 1.39.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 (75) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +53 -1
  3. package/dist/chart-axis.d.ts +61 -0
  4. package/dist/chart-axis.js +83 -0
  5. package/dist/chart-dates.d.ts +6 -0
  6. package/dist/chart-dates.js +15 -0
  7. package/dist/chart-metrics.d.ts +40 -0
  8. package/dist/chart-metrics.js +48 -0
  9. package/dist/chart-scale.d.ts +48 -0
  10. package/dist/chart-scale.js +116 -0
  11. package/dist/chart-table-rows.d.ts +8 -0
  12. package/dist/chart-table-rows.js +1 -0
  13. package/dist/column-chart-bars.d.ts +38 -0
  14. package/dist/column-chart-bars.js +82 -0
  15. package/dist/column-chart-callouts.d.ts +48 -0
  16. package/dist/column-chart-callouts.js +54 -0
  17. package/dist/column-chart-input.d.ts +40 -0
  18. package/dist/column-chart-input.js +60 -0
  19. package/dist/column-chart-layout.d.ts +63 -0
  20. package/dist/column-chart-layout.js +97 -0
  21. package/dist/components/BarChart.d.ts +1 -1
  22. package/dist/components/BarChart.js +1 -1
  23. package/dist/components/ChartLegend.d.ts +38 -0
  24. package/dist/components/ChartLegend.js +32 -0
  25. package/dist/components/ColumnChart.d.ts +72 -0
  26. package/dist/components/ColumnChart.js +71 -0
  27. package/dist/components/DataBar.d.ts +6 -6
  28. package/dist/components/LineChart.d.ts +83 -0
  29. package/dist/components/LineChart.js +77 -0
  30. package/dist/components/chart/ChartTable.d.ts +16 -0
  31. package/dist/components/chart/ChartTable.js +12 -0
  32. package/dist/components/chart/ChartValueAxis.d.ts +14 -0
  33. package/dist/components/chart/ChartValueAxis.js +11 -0
  34. package/dist/components/chart/use-chart-width.d.ts +8 -0
  35. package/dist/components/chart/use-chart-width.js +34 -0
  36. package/dist/components/column-chart/ChartCalloutList.d.ts +16 -0
  37. package/dist/components/column-chart/ChartCalloutList.js +13 -0
  38. package/dist/components/column-chart/ColumnChartDrawing.d.ts +17 -0
  39. package/dist/components/column-chart/ColumnChartDrawing.js +18 -0
  40. package/dist/components/line-chart/LineChartDrawing.d.ts +17 -0
  41. package/dist/components/line-chart/LineChartDrawing.js +16 -0
  42. package/dist/css/chart-marks.d.ts +10 -0
  43. package/dist/css/chart-marks.js +15 -0
  44. package/dist/css/chart-tones.d.ts +68 -0
  45. package/dist/css/chart-tones.js +130 -0
  46. package/dist/css/{css-chart.d.ts → css-bar-chart.d.ts} +2 -2
  47. package/dist/css/{css-chart.js → css-bar-chart.js} +2 -2
  48. package/dist/css/css-chart-legend.d.ts +5 -0
  49. package/dist/css/css-chart-legend.js +102 -0
  50. package/dist/css/css-chart-plot.d.ts +2 -0
  51. package/dist/css/css-chart-plot.js +170 -0
  52. package/dist/css/css-components.js +14 -2
  53. package/dist/css/css-data-bar.d.ts +4 -9
  54. package/dist/css/css-data-bar.js +15 -31
  55. package/dist/css/css-line-chart.d.ts +2 -0
  56. package/dist/css/css-line-chart.js +31 -0
  57. package/dist/css/stylesheet.js +10 -2
  58. package/dist/index.d.ts +3 -0
  59. package/dist/index.js +3 -0
  60. package/dist/is-one-of.d.ts +5 -0
  61. package/dist/is-one-of.js +7 -0
  62. package/dist/line-chart-input.d.ts +39 -0
  63. package/dist/line-chart-input.js +70 -0
  64. package/dist/line-chart-layout.d.ts +68 -0
  65. package/dist/line-chart-layout.js +99 -0
  66. package/dist/line-chart-markers.d.ts +29 -0
  67. package/dist/line-chart-markers.js +57 -0
  68. package/dist/line-chart-path.d.ts +18 -0
  69. package/dist/line-chart-path.js +33 -0
  70. package/dist/line-chart-points.d.ts +6 -0
  71. package/dist/line-chart-points.js +8 -0
  72. package/dist/line-chart-table.d.ts +15 -0
  73. package/dist/line-chart-table.js +29 -0
  74. package/dist/styles.css +219 -0
  75. package/package.json +1 -1
@@ -0,0 +1,39 @@
1
+ import { type ChartStrokeTone } from './css/chart-tones.js';
2
+ import { type LineChartCurve } from './line-chart-path.js';
3
+ /** A value on a date (`YYYY-MM-DD`). */
4
+ export type LineChartPoint = {
5
+ x: string;
6
+ y: number;
7
+ };
8
+ /** A downward triangle on the line at one of its points' dates, with words. */
9
+ export type LineChartMarker = {
10
+ x: string;
11
+ label: string;
12
+ tone: ChartStrokeTone;
13
+ };
14
+ /** A period to box, from its first date to its last. */
15
+ export type LineChartPeriod = {
16
+ from: string;
17
+ to: string;
18
+ };
19
+ export type LineChartInput = {
20
+ label: string;
21
+ valueLabel?: string;
22
+ points: readonly LineChartPoint[];
23
+ curve: LineChartCurve;
24
+ tone: ChartStrokeTone;
25
+ markers: readonly LineChartMarker[];
26
+ markersLabel?: string;
27
+ ticks?: readonly string[];
28
+ highlight?: LineChartPeriod;
29
+ };
30
+ /** A date's day count, or a refusal naming what it was. */
31
+ export declare function lineChartDay(what: string, value: string): number;
32
+ /**
33
+ * Refuses what a line chart cannot draw, with a `RangeError`: empty words,
34
+ * a date that is not `YYYY-MM-DD`, points out of date order, a value that
35
+ * is not finite, an unknown curve or tone, a marker off the points' dates
36
+ * or markers without `markersLabel`, a tick outside the points' dates, and
37
+ * a period that ends before it starts.
38
+ */
39
+ export declare function assertLineChartInput(input: LineChartInput): void;
@@ -0,0 +1,70 @@
1
+ import { dayNumber } from './chart-dates.js';
2
+ import { chartStrokeTones } from './css/chart-tones.js';
3
+ import { isOneOf } from './is-one-of.js';
4
+ import { lineChartCurves } from './line-chart-path.js';
5
+ function refuse(message) {
6
+ throw new RangeError(`LineChart ${message}`);
7
+ }
8
+ function assertWords(what, value) {
9
+ if (typeof value !== 'string' || value.trim() === '')
10
+ refuse(`${what} must not be empty`);
11
+ }
12
+ /** A date's day count, or a refusal naming what it was. */
13
+ export function lineChartDay(what, value) {
14
+ const day = typeof value === 'string' ? dayNumber(value) : null;
15
+ if (day === null)
16
+ refuse(`${what} must be a YYYY-MM-DD date: ${String(value)}`);
17
+ return day;
18
+ }
19
+ function assertTone(what, tone) {
20
+ if (!isOneOf(chartStrokeTones, tone))
21
+ refuse(`${what} must be one of ${chartStrokeTones.join(', ')}; received ${String(tone)}`);
22
+ }
23
+ /**
24
+ * Refuses what a line chart cannot draw, with a `RangeError`: empty words,
25
+ * a date that is not `YYYY-MM-DD`, points out of date order, a value that
26
+ * is not finite, an unknown curve or tone, a marker off the points' dates
27
+ * or markers without `markersLabel`, a tick outside the points' dates, and
28
+ * a period that ends before it starts.
29
+ */
30
+ export function assertLineChartInput(input) {
31
+ assertWords('label', input.label);
32
+ if (input.valueLabel !== undefined)
33
+ assertWords('valueLabel', input.valueLabel);
34
+ if (!isOneOf(lineChartCurves, input.curve))
35
+ refuse(`curve must be one of ${lineChartCurves.join(', ')}; received ${String(input.curve)}`);
36
+ assertTone('tone', input.tone);
37
+ let previous = -Infinity;
38
+ for (const point of input.points) {
39
+ const day = lineChartDay('point x', point.x);
40
+ if (day < previous)
41
+ refuse(`points must be in date order: ${point.x} comes after a later date`);
42
+ previous = day;
43
+ if (typeof point.y !== 'number' || !Number.isFinite(point.y))
44
+ refuse(`point y must be a finite number: ${String(point.y)}`);
45
+ }
46
+ const dates = new Set(input.points.map((point) => point.x));
47
+ if (input.markers.length > 0)
48
+ assertWords('markersLabel', input.markersLabel);
49
+ for (const marker of input.markers) {
50
+ if (!dates.has(marker.x))
51
+ refuse(`marker x must be one of the points' dates: ${String(marker.x)}`);
52
+ assertWords('marker label', marker.label);
53
+ assertTone('marker tone', marker.tone);
54
+ }
55
+ const first = input.points[0]?.x;
56
+ const last = input.points.at(-1)?.x;
57
+ for (const tick of input.ticks ?? []) {
58
+ const day = lineChartDay('tick', tick);
59
+ if (first === undefined ||
60
+ day < lineChartDay('point x', first) ||
61
+ day > lineChartDay('point x', last))
62
+ refuse(`tick must fall within the points' dates: ${tick}`);
63
+ }
64
+ if (input.highlight) {
65
+ const from = lineChartDay('highlight from', input.highlight.from);
66
+ const to = lineChartDay('highlight to', input.highlight.to);
67
+ if (to < from)
68
+ refuse('highlight must not end before it starts');
69
+ }
70
+ }
@@ -0,0 +1,68 @@
1
+ import { type ChartPlot, type ChartTick } from './chart-axis.js';
2
+ import { type PlacedMarker } from './line-chart-markers.js';
3
+ import { type ChartPoint, type LineChartCurve } from './line-chart-path.js';
4
+ export type LineChartLayoutInput = {
5
+ width: number;
6
+ /** The points as day counts, in date order. */
7
+ points: readonly {
8
+ day: number;
9
+ y: number;
10
+ }[];
11
+ curve: LineChartCurve;
12
+ area: boolean;
13
+ /** Each marker's day (one of the points') and words. */
14
+ markers: readonly {
15
+ day: number;
16
+ label: string;
17
+ }[];
18
+ /** The days to label on the time axis, and their words. */
19
+ ticks: readonly {
20
+ day: number;
21
+ text: string;
22
+ }[];
23
+ /** The boxed period's first and last days. */
24
+ highlight: {
25
+ from: number;
26
+ to: number;
27
+ } | null;
28
+ /** The words at the line's last value, or none. */
29
+ endLabel: string | null;
30
+ formatTick: (value: number) => string;
31
+ };
32
+ export type LineChartLayout = {
33
+ width: number;
34
+ height: number;
35
+ compact: boolean;
36
+ plot: ChartPlot;
37
+ ticks: ChartTick[];
38
+ path: ChartPoint[];
39
+ area: ChartPoint[];
40
+ last: ChartPoint | null;
41
+ end: {
42
+ x: number;
43
+ y: number;
44
+ text: string;
45
+ } | null;
46
+ dateLabels: {
47
+ day: number;
48
+ x: number;
49
+ y: number;
50
+ text: string;
51
+ }[];
52
+ highlight: {
53
+ x: number;
54
+ y: number;
55
+ width: number;
56
+ height: number;
57
+ } | null;
58
+ markers: PlacedMarker[];
59
+ };
60
+ /**
61
+ * Lays a line chart out at a width: its value axis on the left (through
62
+ * zero), the line through its points by date (straight or in steps), the
63
+ * area under it, its last value beside the plot's end, the time axis's
64
+ * labels (fewer when they would meet), the boxed period, and each marker's
65
+ * triangle and words. A compact chart (under `chartCompactWidth`) has a
66
+ * shorter plot.
67
+ */
68
+ export declare function lineChartLayout(input: LineChartLayoutInput): LineChartLayout;
@@ -0,0 +1,99 @@
1
+ import { endGutter, labelGutter, labelInside, periodBox, valueTicks, valueY, } from './chart-axis.js';
2
+ import { chartCompactWidth, chartGap, chartPlotHeight, chartTextWidth, chartType, } from './chart-metrics.js';
3
+ import { chartScale, extentThroughZero } from './chart-scale.js';
4
+ import { placeMarkers } from './line-chart-markers.js';
5
+ import { closingIndexes } from './line-chart-points.js';
6
+ import { areaPath, linePath, } from './line-chart-path.js';
7
+ /**
8
+ * The time axis's labels: each asked-for day at its place, kept inside the
9
+ * chart, and thinned from the last back so no two meet.
10
+ */
11
+ function dateLabels(ticks, x, width, y) {
12
+ const kept = [];
13
+ const sorted = [...ticks].sort((a, b) => b.day - a.day);
14
+ for (const tick of sorted) {
15
+ const centre = labelInside(x(tick.day), tick.text, width);
16
+ const half = chartTextWidth(tick.text) / 2;
17
+ const next = kept[0];
18
+ if (next &&
19
+ centre + half + chartGap * 2 > next.x - chartTextWidth(next.text) / 2)
20
+ continue;
21
+ kept.unshift({ day: tick.day, x: centre, y, text: tick.text });
22
+ }
23
+ return kept;
24
+ }
25
+ /**
26
+ * Lays a line chart out at a width: its value axis on the left (through
27
+ * zero), the line through its points by date (straight or in steps), the
28
+ * area under it, its last value beside the plot's end, the time axis's
29
+ * labels (fewer when they would meet), the boxed period, and each marker's
30
+ * triangle and words. A compact chart (under `chartCompactWidth`) has a
31
+ * shorter plot.
32
+ */
33
+ export function lineChartLayout(input) {
34
+ const { width, points } = input;
35
+ const compact = width < chartCompactWidth;
36
+ const scale = chartScale(extentThroughZero(points.map((p) => p.y)));
37
+ const left = labelGutter(scale.ticks.map(input.formatTick));
38
+ const right = Math.max(left + 1, width -
39
+ endGutter({ width, left, axisWords: [], endLabel: input.endLabel })
40
+ .gutter);
41
+ const top = chartGap + chartType.lineHeight / 2;
42
+ const plot = {
43
+ left,
44
+ right,
45
+ top,
46
+ bottom: top + chartPlotHeight(compact),
47
+ };
48
+ const first = points[0]?.day ?? 0;
49
+ const span = (points.at(-1)?.day ?? first) - first;
50
+ const dayWidth = span > 0 ? (right - left) / span : right - left;
51
+ const x = (day) => span > 0 ? left + (day - first) * dayWidth : (left + right) / 2;
52
+ const placed = points.map((p) => ({
53
+ x: x(p.day),
54
+ y: valueY(p.y, scale, plot),
55
+ }));
56
+ const path = linePath(placed, input.curve);
57
+ const last = placed.at(-1) ?? null;
58
+ // A marker sits on its day's last point, the day's closing value.
59
+ const closing = closingIndexes(points.map((p) => p.day));
60
+ const markerPoints = input.markers.map((marker) => ({
61
+ x: x(marker.day),
62
+ y: placed[closing.get(marker.day) ?? -1]?.y ?? plot.bottom,
63
+ label: marker.label,
64
+ }));
65
+ return {
66
+ width,
67
+ height: plot.bottom + chartGap + chartType.lineHeight,
68
+ compact,
69
+ plot,
70
+ ticks: valueTicks(scale, plot, input.formatTick),
71
+ path,
72
+ area: input.area ? areaPath(path, valueY(0, scale, plot)) : [],
73
+ last,
74
+ end: last && input.endLabel
75
+ ? { x: right + chartGap, y: last.y, text: input.endLabel }
76
+ : null,
77
+ dateLabels: dateLabels(input.ticks, x, width, plot.bottom + chartGap + chartType.fontSize),
78
+ highlight: points.length > 0
79
+ ? highlightBox(input.highlight, first, span, x, dayWidth, plot)
80
+ : null,
81
+ markers: placeMarkers(markerPoints, plot),
82
+ };
83
+ }
84
+ /**
85
+ * The boxed period: its days, half a day past each end, clipped to the
86
+ * plot. On a chart of one date it is the whole plot when the period holds
87
+ * that date and nothing otherwise.
88
+ */
89
+ function highlightBox(period, first, span, x, dayWidth, plot) {
90
+ if (!period)
91
+ return null;
92
+ if (span === 0 && (period.from > first || period.to < first))
93
+ return null;
94
+ const from = Math.max(x(period.from) - dayWidth / 2, plot.left);
95
+ const to = Math.min(x(period.to) + dayWidth / 2, plot.right);
96
+ if (to < from)
97
+ return null;
98
+ return periodBox(from, to - from, plot, 0);
99
+ }
@@ -0,0 +1,29 @@
1
+ import { type ChartPlot } from './chart-axis.js';
2
+ /**
3
+ * A marker on a line: a downward triangle at its date with its words,
4
+ * below the line where they fit inside the plot, above it otherwise. Its
5
+ * words are left out where they would meet an earlier marker's.
6
+ */
7
+ export type PlacedMarker = {
8
+ /** Its place in the chart's `markers`. */
9
+ order: number;
10
+ x: number;
11
+ /** The triangle's corners, as SVG points. */
12
+ triangle: string;
13
+ /** Its words' centre, moved in so they stay over the plot. */
14
+ labelX: number;
15
+ labelY: number;
16
+ label: string;
17
+ labelShown: boolean;
18
+ };
19
+ /**
20
+ * Places each marker at the line's height on its date: the triangle a
21
+ * small inset under the line, its words under it (moved in to stay over
22
+ * the plot), or both above the line when the words would pass the plot's
23
+ * bottom.
24
+ */
25
+ export declare function placeMarkers(markers: readonly {
26
+ x: number;
27
+ y: number;
28
+ label: string;
29
+ }[], plot: ChartPlot): PlacedMarker[];
@@ -0,0 +1,57 @@
1
+ import { chartInset, chartMarkerSize, chartTextWidth, chartType, } from './chart-metrics.js';
2
+ function meets(a, b) {
3
+ return (a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom);
4
+ }
5
+ /**
6
+ * A centre for words `width` wide that keeps them over the plot, clear of
7
+ * the value axis's words and the last value beside it; centred on the plot
8
+ * when they are wider than it.
9
+ */
10
+ function overPlot(x, width, plot) {
11
+ const low = plot.left + width / 2;
12
+ const high = plot.right - width / 2;
13
+ if (low > high)
14
+ return (plot.left + plot.right) / 2;
15
+ return Math.min(Math.max(x, low), high);
16
+ }
17
+ /**
18
+ * Places each marker at the line's height on its date: the triangle a
19
+ * small inset under the line, its words under it (moved in to stay over
20
+ * the plot), or both above the line when the words would pass the plot's
21
+ * bottom.
22
+ */
23
+ export function placeMarkers(markers, plot) {
24
+ const half = chartMarkerSize / 2;
25
+ const shown = [];
26
+ return markers.map((marker, order) => {
27
+ const below = marker.y + chartInset + chartMarkerSize + chartType.lineHeight <=
28
+ plot.bottom;
29
+ const top = below
30
+ ? marker.y + chartInset
31
+ : marker.y - chartInset - chartMarkerSize;
32
+ const bottom = top + chartMarkerSize;
33
+ const labelY = below
34
+ ? bottom + chartType.fontSize
35
+ : top - (chartType.lineHeight - chartType.fontSize);
36
+ const width = chartTextWidth(marker.label);
37
+ const labelX = overPlot(marker.x, width, plot);
38
+ const box = {
39
+ left: labelX - width / 2,
40
+ right: labelX + width / 2,
41
+ top: labelY - chartType.fontSize,
42
+ bottom: labelY + (chartType.lineHeight - chartType.fontSize),
43
+ };
44
+ const labelShown = !shown.some((taken) => meets(taken, box));
45
+ if (labelShown)
46
+ shown.push(box);
47
+ return {
48
+ order,
49
+ x: marker.x,
50
+ labelX,
51
+ triangle: `${marker.x - half},${top} ${marker.x + half},${top} ${marker.x},${bottom}`,
52
+ labelY,
53
+ label: marker.label,
54
+ labelShown,
55
+ };
56
+ });
57
+ }
@@ -0,0 +1,18 @@
1
+ /** How a line runs between its points. */
2
+ export declare const lineChartCurves: readonly ["linear", "step"];
3
+ export type LineChartCurve = (typeof lineChartCurves)[number];
4
+ /** A point in the chart's pixels. */
5
+ export type ChartPoint = {
6
+ x: number;
7
+ y: number;
8
+ };
9
+ /**
10
+ * The vertices a line is drawn through. `linear` joins each point to the
11
+ * next; `step` holds each value until the next point's date, then moves
12
+ * straight up or down to it, as a balance that changes on a day does.
13
+ */
14
+ export declare function linePath(points: readonly ChartPoint[], curve: LineChartCurve): ChartPoint[];
15
+ /** The area under a line's path, closed along the zero line. */
16
+ export declare function areaPath(path: readonly ChartPoint[], zeroY: number): ChartPoint[];
17
+ /** Vertices as an SVG `points` list. */
18
+ export declare function svgPoints(path: readonly ChartPoint[]): string;
@@ -0,0 +1,33 @@
1
+ /** How a line runs between its points. */
2
+ export const lineChartCurves = ['linear', 'step'];
3
+ /**
4
+ * The vertices a line is drawn through. `linear` joins each point to the
5
+ * next; `step` holds each value until the next point's date, then moves
6
+ * straight up or down to it, as a balance that changes on a day does.
7
+ */
8
+ export function linePath(points, curve) {
9
+ if (curve === 'linear')
10
+ return [...points];
11
+ const path = [];
12
+ points.forEach((point, index) => {
13
+ const previous = points[index - 1];
14
+ if (previous)
15
+ path.push({ x: point.x, y: previous.y });
16
+ path.push(point);
17
+ });
18
+ return path;
19
+ }
20
+ /** The area under a line's path, closed along the zero line. */
21
+ export function areaPath(path, zeroY) {
22
+ if (path.length === 0)
23
+ return [];
24
+ return [
25
+ { x: path[0].x, y: zeroY },
26
+ ...path,
27
+ { x: path.at(-1).x, y: zeroY },
28
+ ];
29
+ }
30
+ /** Vertices as an SVG `points` list. */
31
+ export function svgPoints(path) {
32
+ return path.map((point) => `${point.x},${point.y}`).join(' ');
33
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Each date's closing point: the index of the last point on it. A balance
3
+ * can change twice on one day; the day's markers and figures belong to its
4
+ * closing value.
5
+ */
6
+ export declare function closingIndexes<Day>(days: readonly Day[]): Map<Day, number>;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Each date's closing point: the index of the last point on it. A balance
3
+ * can change twice on one day; the day's markers and figures belong to its
4
+ * closing value.
5
+ */
6
+ export function closingIndexes(days) {
7
+ return new Map(days.map((day, index) => [day, index]));
8
+ }
@@ -0,0 +1,15 @@
1
+ import { type ChartTableRow } from './chart-table-rows.js';
2
+ import { type LineChartMarker, type LineChartPeriod, type LineChartPoint } from './line-chart-input.js';
3
+ /**
4
+ * A line chart's hidden table rows: one per point, headed by its date in
5
+ * the consumer's words, holding its value and (when the chart has markers)
6
+ * the words of the markers on its date, in the date's closing row only;
7
+ * the rows inside the boxed period are current.
8
+ */
9
+ export declare function lineChartRows({ formatDate, formatValue, highlight, markers, points, }: {
10
+ points: readonly LineChartPoint[];
11
+ markers: readonly LineChartMarker[];
12
+ highlight: LineChartPeriod | undefined;
13
+ formatDate: (date: string) => string;
14
+ formatValue: (value: number) => string;
15
+ }): ChartTableRow[];
@@ -0,0 +1,29 @@
1
+ import { closingIndexes } from './line-chart-points.js';
2
+ /**
3
+ * A line chart's hidden table rows: one per point, headed by its date in
4
+ * the consumer's words, holding its value and (when the chart has markers)
5
+ * the words of the markers on its date, in the date's closing row only;
6
+ * the rows inside the boxed period are current.
7
+ */
8
+ export function lineChartRows({ formatDate, formatValue, highlight, markers, points, }) {
9
+ const closing = closingIndexes(points.map((point) => point.x));
10
+ return points.map((point, index) => {
11
+ const cells = [formatValue(point.y)];
12
+ if (markers.length > 0)
13
+ cells.push(closing.get(point.x) === index
14
+ ? markers
15
+ .filter((marker) => marker.x === point.x)
16
+ .map((marker) => marker.label)
17
+ .join(', ')
18
+ : '');
19
+ return {
20
+ key: `${point.x}-${index}`,
21
+ header: formatDate(point.x),
22
+ cells,
23
+ // YYYY-MM-DD dates compare in date order as text.
24
+ current: highlight !== undefined &&
25
+ point.x >= highlight.from &&
26
+ point.x <= highlight.to,
27
+ };
28
+ });
29
+ }