enarratio-astro 0.4.1 → 0.4.3
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/CHANGELOG.md +24 -0
- package/README.md +25 -24
- package/dist/chart.d.ts +10 -1
- package/dist/chart.js +7 -6
- package/dist/data.d.ts +0 -3
- package/dist/data.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/markdown.d.ts +0 -17
- package/dist/markdown.js +2 -2
- package/package.json +21 -21
- package/src/Chart.astro +1 -1
- package/src/Enhance.astro +3 -1
- package/src/chart.ts +22 -9
- package/src/data.ts +2 -2
- package/src/index.ts +1 -0
- package/src/markdown.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,30 @@ every such change is listed here.
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.4.3] - 2026-11-07
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- The `astro` peer dependency is `>=6` (was exactly `7.4.4`), as the README says. A site on any supported Astro version now installs
|
|
15
|
+
without a peer conflict; the version tested here stays pinned in the repository's dev dependencies.
|
|
16
|
+
|
|
17
|
+
### Removed
|
|
18
|
+
|
|
19
|
+
- `parseChartBlock` is no longer exported from `enarratio-astro/markdown`. It was undocumented; use the
|
|
20
|
+
`remarkCharts` or `satteriCharts` plugin instead.
|
|
21
|
+
|
|
22
|
+
## [0.4.2] - 2026-11-03
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Draws with Enarratio 0.7.3: charts no longer move the page when the enhancement layer loads. The redraw keeps the
|
|
27
|
+
height the server drawing showed, a legend entry has its button's box before it is a button, and an interactive
|
|
28
|
+
chart's figure holds the controls the layer adds (Show table, Play as sound, the downloads), inert until it
|
|
29
|
+
arrives.
|
|
30
|
+
- A chart that is not interactive leaves those controls out (Enarratio's `controls: false`), since no layer ever
|
|
31
|
+
makes them work. `renderChart` takes a second argument, `{ interactive }`, for this; it defaults to true, as
|
|
32
|
+
Enarratio does.
|
|
33
|
+
|
|
10
34
|
## [0.4.1] - 2026-11-03
|
|
11
35
|
|
|
12
36
|
### Changed
|
package/README.md
CHANGED
|
@@ -36,6 +36,7 @@ const downloads = [
|
|
|
36
36
|
{ year: 2026, package: "Plugin", downloads: 2800 },
|
|
37
37
|
];
|
|
38
38
|
---
|
|
39
|
+
|
|
39
40
|
<Chart
|
|
40
41
|
type="line"
|
|
41
42
|
data={downloads}
|
|
@@ -57,7 +58,7 @@ columns. The chart CSS is written once per page, however many charts it has.
|
|
|
57
58
|
A code block whose language is `chart` becomes a chart: options, a line of three dashes, then the
|
|
58
59
|
data.
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
````md
|
|
61
62
|
```chart
|
|
62
63
|
type: bar
|
|
63
64
|
x: team
|
|
@@ -72,7 +73,7 @@ Support,Closed,22
|
|
|
72
73
|
Platform,Open,5
|
|
73
74
|
Platform,Closed,31
|
|
74
75
|
```
|
|
75
|
-
|
|
76
|
+
````
|
|
76
77
|
|
|
77
78
|
Register the plugin for Astro's Markdown processor. Astro 7's default, Sätteri:
|
|
78
79
|
|
|
@@ -102,28 +103,28 @@ interactive chart on the page and works with view transitions.
|
|
|
102
103
|
|
|
103
104
|
The component's props and a Markdown block's keys are the same:
|
|
104
105
|
|
|
105
|
-
| Option
|
|
106
|
-
|
|
107
|
-
| `type`
|
|
108
|
-
| `data`
|
|
109
|
-
| `alt`
|
|
110
|
-
| `title`, `subtitle`
|
|
111
|
-
| `caption`, `notes`
|
|
112
|
-
| `source`, `sourceHref` | all
|
|
113
|
-
| `byline`
|
|
114
|
-
| `x`
|
|
115
|
-
| `y`
|
|
116
|
-
| `series`
|
|
117
|
-
| `value`
|
|
118
|
-
| `xLabel`, `yLabel`
|
|
119
|
-
| `xUnit`, `yUnit`
|
|
120
|
-
| `layout`
|
|
121
|
-
| `orientation`
|
|
122
|
-
| `scale`
|
|
123
|
-
| `regression`
|
|
124
|
-
| `dataTable`
|
|
125
|
-
| `id`
|
|
126
|
-
| `interactive`
|
|
106
|
+
| Option | Used by | Notes |
|
|
107
|
+
| ---------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
|
|
108
|
+
| `type` | all | `bar` (default), `line`, `area` (stacked), `scatter` or `heatmap`. |
|
|
109
|
+
| `data` | all | The data (component only; in Markdown it follows the dashes). Up to 5000 rows and 50 columns. |
|
|
110
|
+
| `alt` | all | **Required.** What the chart shows and finds, in a sentence. It names the chart for screen readers. |
|
|
111
|
+
| `title`, `subtitle` | all | Optional. Shown above the chart. |
|
|
112
|
+
| `caption`, `notes` | all | Optional. The caption, under the chart, is for method or caveats; notes are a smaller line for definitions. |
|
|
113
|
+
| `source`, `sourceHref` | all | Optional. Where the data came from, linked when `sourceHref` is set, beside a CSV download of the data. |
|
|
114
|
+
| `byline` | all | Optional. Who made the chart. |
|
|
115
|
+
| `x` | all | The column along the x axis. Column names match without regard to case. ISO dates make a time axis in line and area charts. |
|
|
116
|
+
| `y` | all | The value column. Bar charts count rows when it is missing. For a heatmap, the row column. |
|
|
117
|
+
| `series` | bar, line, area, scatter | Splits rows into series, told apart by color and by legend, labels or symbols. |
|
|
118
|
+
| `value` | heatmap | The cell value column. |
|
|
119
|
+
| `xLabel`, `yLabel` | all | Axis labels. |
|
|
120
|
+
| `xUnit`, `yUnit` | all | Optional. The unit, shown after the axis label (`Sales (units)`) and in the table and summary. |
|
|
121
|
+
| `layout` | bar | `stacked` (default) or `grouped`. |
|
|
122
|
+
| `orientation` | bar | `vertical` (default) or `horizontal`. |
|
|
123
|
+
| `scale` | line, scatter | `linear` (default) or `log`. |
|
|
124
|
+
| `regression` | scatter | A least-squares line with its 95% band. |
|
|
125
|
+
| `dataTable` | all | `details` (default; behind a "Data table" toggle) or `visually-hidden` (screen readers only). |
|
|
126
|
+
| `id` | all | The figure's id. |
|
|
127
|
+
| `interactive` | all | Adds the enhancement script. Off by default, so pages stay script-free. |
|
|
127
128
|
|
|
128
129
|
A chart that cannot be drawn (a column that is not in the data, text in a number column, a missing
|
|
129
130
|
`alt`) is replaced by a short note saying why, and the reason is logged, so one mistake never
|
package/dist/chart.d.ts
CHANGED
|
@@ -63,10 +63,19 @@ export type ChartResult = {
|
|
|
63
63
|
readonly ok: false;
|
|
64
64
|
readonly error: string;
|
|
65
65
|
};
|
|
66
|
+
/** How a chart is drawn, beside what it shows. */
|
|
67
|
+
export interface RenderOptions {
|
|
68
|
+
/**
|
|
69
|
+
* Whether the page enhances the chart (`<Chart interactive>`). An enhanced chart's figure holds
|
|
70
|
+
* the controls the enhancement layer adds, inert until it arrives, so the page does not move;
|
|
71
|
+
* a chart that is never enhanced leaves them out. Defaults to true, as Enarratio does.
|
|
72
|
+
*/
|
|
73
|
+
readonly interactive?: boolean | undefined;
|
|
74
|
+
}
|
|
66
75
|
/**
|
|
67
76
|
* Draws a chart. Bar, line and area charts come from `enarratio/lite`, which builds the SVG as a
|
|
68
77
|
* string with no DOM, the cheapest render on a Worker; scatter plots and heatmaps load
|
|
69
78
|
* `enarratio/plot` (Observable Plot and linkedom) only when a page has one. Never throws: a chart
|
|
70
79
|
* that cannot be drawn returns the reason instead, so one mistake cannot break a page.
|
|
71
80
|
*/
|
|
72
|
-
export declare function renderChart(spec: ChartSpec): Promise<ChartResult>;
|
|
81
|
+
export declare function renderChart(spec: ChartSpec, options?: RenderOptions): Promise<ChartResult>;
|
package/dist/chart.js
CHANGED
|
@@ -22,8 +22,8 @@ function numeric(table, name) {
|
|
|
22
22
|
if (bad)
|
|
23
23
|
throw new Error(`The column "${name}" should hold numbers, but has "${bad[name]}".`);
|
|
24
24
|
}
|
|
25
|
-
/** The options every chart type shares: text, the data table and the
|
|
26
|
-
function figure(spec) {
|
|
25
|
+
/** The options every chart type shares: text, the data table, the id and the pending controls. */
|
|
26
|
+
function figure(spec, options) {
|
|
27
27
|
const alt = text(spec.alt);
|
|
28
28
|
if (!alt)
|
|
29
29
|
throw new Error("Add a description (alt): one sentence on what the chart shows.");
|
|
@@ -43,14 +43,15 @@ function figure(spec) {
|
|
|
43
43
|
...(source ? { source: sourceHref ? { name: source, href: sourceHref } : source } : {}),
|
|
44
44
|
...(id ? { id } : {}),
|
|
45
45
|
dataTable: spec.dataTable === "visually-hidden" ? "visually-hidden" : "details",
|
|
46
|
+
...(options.interactive === false ? { controls: false } : {}),
|
|
46
47
|
};
|
|
47
48
|
}
|
|
48
|
-
async function draw(spec) {
|
|
49
|
+
async function draw(spec, options) {
|
|
49
50
|
const type = (text(spec.type) ?? "bar").toLowerCase();
|
|
50
51
|
if (!CHART_TYPES.includes(type)) {
|
|
51
52
|
throw new Error(`There is no chart type "${spec.type}". Use one of: ${CHART_TYPES.join(", ")}.`);
|
|
52
53
|
}
|
|
53
|
-
const common = figure(spec);
|
|
54
|
+
const common = figure(spec, options);
|
|
54
55
|
const table = typeof spec.data === "string" ? parseTable(spec.data) : tableFromRows(spec.data);
|
|
55
56
|
const x = column(table, spec.x, "x axis");
|
|
56
57
|
const seriesName = text(spec.series) ? column(table, spec.series, "series") : undefined;
|
|
@@ -109,9 +110,9 @@ async function draw(spec) {
|
|
|
109
110
|
* `enarratio/plot` (Observable Plot and linkedom) only when a page has one. Never throws: a chart
|
|
110
111
|
* that cannot be drawn returns the reason instead, so one mistake cannot break a page.
|
|
111
112
|
*/
|
|
112
|
-
export async function renderChart(spec) {
|
|
113
|
+
export async function renderChart(spec, options = {}) {
|
|
113
114
|
try {
|
|
114
|
-
return { ok: true, html: await draw(spec) };
|
|
115
|
+
return { ok: true, html: await draw(spec, options) };
|
|
115
116
|
}
|
|
116
117
|
catch (error) {
|
|
117
118
|
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
package/dist/data.d.ts
CHANGED
|
@@ -5,9 +5,6 @@ export interface Table {
|
|
|
5
5
|
readonly columns: readonly string[];
|
|
6
6
|
readonly rows: ReadonlyArray<Readonly<Record<string, Cell>>>;
|
|
7
7
|
}
|
|
8
|
-
/** Limits that keep one chart's render bounded, whatever an editor pastes. */
|
|
9
|
-
export declare const MAX_ROWS = 5000;
|
|
10
|
-
export declare const MAX_COLUMNS = 50;
|
|
11
8
|
/**
|
|
12
9
|
* Parses the data an editor pasted or typed: CSV, semicolon-separated or tab-separated text
|
|
13
10
|
* whose first row names the columns. Throws an Error whose message an editor can act on.
|
package/dist/data.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Limits that keep one chart's render bounded, whatever an editor pastes. */
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
const MAX_ROWS = 5000;
|
|
3
|
+
const MAX_COLUMNS = 50;
|
|
4
4
|
const NUMBER = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
5
5
|
const GROUPED_NUMBER = /^[+-]?\d{1,3}(?:,\d{3})+(?:\.\d+)?$/;
|
|
6
6
|
/** Reads a cell: numbers (including "1,234") become numbers, an empty cell `null`, the rest text. */
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @packageDocumentation
|
|
7
7
|
*/
|
|
8
|
-
export { CHART_TYPES, type ChartResult, type ChartSpec, type ChartType, renderChart, } from "./chart.js";
|
|
8
|
+
export { CHART_TYPES, type ChartResult, type ChartSpec, type ChartType, type RenderOptions, renderChart, } from "./chart.js";
|
|
9
9
|
export { type Cell, parseTable, type Table, tableFromRows } from "./data.js";
|
|
10
10
|
export { chartMarkup } from "./figure.js";
|
|
11
11
|
export { chartStyles, type StyleOptions, type Styles } from "./styles.js";
|
package/dist/markdown.d.ts
CHANGED
|
@@ -1,23 +1,6 @@
|
|
|
1
|
-
import { type ChartSpec } from "./chart.js";
|
|
2
1
|
import { type StyleOptions } from "./styles.js";
|
|
3
2
|
/** Options for the Markdown plugins: how charts are styled. */
|
|
4
3
|
export type MarkdownChartOptions = StyleOptions;
|
|
5
|
-
/**
|
|
6
|
-
* Reads a `chart` code block: `key: value` lines, a line of three dashes, then the data.
|
|
7
|
-
*
|
|
8
|
-
* ```chart
|
|
9
|
-
* type: line
|
|
10
|
-
* x: month
|
|
11
|
-
* y: visitors
|
|
12
|
-
* alt: Monthly visitors rise from 820 to 1,190.
|
|
13
|
-
* ---
|
|
14
|
-
* month,visitors
|
|
15
|
-
* 2026-01-01,820
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
export declare function parseChartBlock(source: string): ChartSpec & {
|
|
19
|
-
readonly interactive: boolean;
|
|
20
|
-
};
|
|
21
4
|
/** The parts of a Markdown code node the plugins read. */
|
|
22
5
|
interface CodeNode {
|
|
23
6
|
readonly type: "code";
|
package/dist/markdown.js
CHANGED
|
@@ -41,7 +41,7 @@ const KEYS = new Set([
|
|
|
41
41
|
* 2026-01-01,820
|
|
42
42
|
* ```
|
|
43
43
|
*/
|
|
44
|
-
|
|
44
|
+
function parseChartBlock(source) {
|
|
45
45
|
const lines = source.split(/\r?\n/);
|
|
46
46
|
const rule = lines.findIndex((line) => line.trim() === "---");
|
|
47
47
|
if (rule === -1)
|
|
@@ -69,7 +69,7 @@ async function chartHtml(source, first, options) {
|
|
|
69
69
|
let markup;
|
|
70
70
|
try {
|
|
71
71
|
const { interactive, ...spec } = parseChartBlock(source);
|
|
72
|
-
const result = await renderChart(spec);
|
|
72
|
+
const result = await renderChart(spec, { interactive });
|
|
73
73
|
if (!result.ok)
|
|
74
74
|
console.warn(`[enarratio-astro] Markdown chart not drawn: ${result.error}`);
|
|
75
75
|
markup = chartMarkup(result, interactive);
|
package/package.json
CHANGED
|
@@ -1,27 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "enarratio-astro",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Accessible charts for Astro: a Chart component and charts in Markdown, drawn on the server by Enarratio",
|
|
5
5
|
"keywords": [
|
|
6
|
+
"accessibility",
|
|
6
7
|
"astro",
|
|
7
8
|
"astro-component",
|
|
8
|
-
"withastro",
|
|
9
9
|
"charts",
|
|
10
|
-
"
|
|
10
|
+
"enarratio",
|
|
11
11
|
"markdown",
|
|
12
|
-
"
|
|
12
|
+
"withastro"
|
|
13
13
|
],
|
|
14
14
|
"homepage": "https://github.com/DrDustinEdwards/astro/tree/main/packages/enarratio-astro#readme",
|
|
15
15
|
"bugs": {
|
|
16
16
|
"url": "https://github.com/DrDustinEdwards/astro/issues"
|
|
17
17
|
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "Dustin Edwards (https://dustinedwards.info)",
|
|
18
20
|
"repository": {
|
|
19
21
|
"type": "git",
|
|
20
22
|
"url": "git+https://github.com/DrDustinEdwards/astro.git",
|
|
21
23
|
"directory": "packages/enarratio-astro"
|
|
22
24
|
},
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"src",
|
|
28
|
+
"CHANGELOG.md",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
25
31
|
"type": "module",
|
|
26
32
|
"sideEffects": false,
|
|
27
33
|
"exports": {
|
|
@@ -37,30 +43,24 @@
|
|
|
37
43
|
"./Enhance.astro": "./src/Enhance.astro",
|
|
38
44
|
"./package.json": "./package.json"
|
|
39
45
|
},
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"CHANGELOG.md",
|
|
44
|
-
"README.md"
|
|
45
|
-
],
|
|
46
|
-
"engines": {
|
|
47
|
-
"node": ">=22.22"
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public",
|
|
48
|
+
"tag": "latest"
|
|
48
49
|
},
|
|
49
50
|
"scripts": {
|
|
50
51
|
"build": "tsc -p tsconfig.build.json",
|
|
51
52
|
"test": "vitest run",
|
|
52
53
|
"prepare": "npm run build"
|
|
53
54
|
},
|
|
54
|
-
"peerDependencies": {
|
|
55
|
-
"astro": "7.4.4"
|
|
56
|
-
},
|
|
57
55
|
"dependencies": {
|
|
58
56
|
"@observablehq/plot": "0.6.17",
|
|
59
|
-
"enarratio": "0.7.
|
|
57
|
+
"enarratio": "0.7.3",
|
|
60
58
|
"linkedom": "0.18.14"
|
|
61
59
|
},
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"astro": ">=6"
|
|
62
|
+
},
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": ">=22.22"
|
|
65
65
|
}
|
|
66
66
|
}
|
package/src/Chart.astro
CHANGED
|
@@ -21,7 +21,7 @@ interface Props extends ChartSpec, StyleOptions {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const { interactive = false, styles, theme, stylesheetOptions, ...spec } = Astro.props;
|
|
24
|
-
const result = await renderChart(spec);
|
|
24
|
+
const result = await renderChart(spec, { interactive });
|
|
25
25
|
const css = firstOnPage(Astro.request) ? chartStyles({ styles, theme, stylesheetOptions }) : "";
|
|
26
26
|
if (!result.ok) console.warn(`[enarratio-astro] chart ${spec.id ?? ""} not drawn: ${result.error}`);
|
|
27
27
|
---
|
package/src/Enhance.astro
CHANGED
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
import { enhance } from "enarratio/enhance";
|
|
12
12
|
|
|
13
13
|
function run() {
|
|
14
|
-
for (const chart of document.querySelectorAll<HTMLElement>(
|
|
14
|
+
for (const chart of document.querySelectorAll<HTMLElement>(
|
|
15
|
+
"[data-enarratio-interactive-chart]",
|
|
16
|
+
)) {
|
|
15
17
|
enhance(chart);
|
|
16
18
|
}
|
|
17
19
|
}
|
package/src/chart.ts
CHANGED
|
@@ -88,8 +88,18 @@ function numeric(table: Table, name: string): void {
|
|
|
88
88
|
if (bad) throw new Error(`The column "${name}" should hold numbers, but has "${bad[name]}".`);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
/**
|
|
92
|
-
|
|
91
|
+
/** How a chart is drawn, beside what it shows. */
|
|
92
|
+
export interface RenderOptions {
|
|
93
|
+
/**
|
|
94
|
+
* Whether the page enhances the chart (`<Chart interactive>`). An enhanced chart's figure holds
|
|
95
|
+
* the controls the enhancement layer adds, inert until it arrives, so the page does not move;
|
|
96
|
+
* a chart that is never enhanced leaves them out. Defaults to true, as Enarratio does.
|
|
97
|
+
*/
|
|
98
|
+
readonly interactive?: boolean | undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** The options every chart type shares: text, the data table, the id and the pending controls. */
|
|
102
|
+
function figure(spec: ChartSpec, options: RenderOptions) {
|
|
93
103
|
const alt = text(spec.alt);
|
|
94
104
|
if (!alt) throw new Error("Add a description (alt): one sentence on what the chart shows.");
|
|
95
105
|
const title = text(spec.title);
|
|
@@ -111,17 +121,18 @@ function figure(spec: ChartSpec) {
|
|
|
111
121
|
...(id ? { id } : {}),
|
|
112
122
|
dataTable:
|
|
113
123
|
spec.dataTable === "visually-hidden" ? ("visually-hidden" as const) : ("details" as const),
|
|
124
|
+
...(options.interactive === false ? { controls: false } : {}),
|
|
114
125
|
};
|
|
115
126
|
}
|
|
116
127
|
|
|
117
|
-
async function draw(spec: ChartSpec): Promise<string> {
|
|
128
|
+
async function draw(spec: ChartSpec, options: RenderOptions): Promise<string> {
|
|
118
129
|
const type = (text(spec.type) ?? "bar").toLowerCase();
|
|
119
130
|
if (!CHART_TYPES.includes(type as ChartType)) {
|
|
120
131
|
throw new Error(
|
|
121
132
|
`There is no chart type "${spec.type}". Use one of: ${CHART_TYPES.join(", ")}.`,
|
|
122
133
|
);
|
|
123
134
|
}
|
|
124
|
-
const common = figure(spec);
|
|
135
|
+
const common = figure(spec, options);
|
|
125
136
|
const table = typeof spec.data === "string" ? parseTable(spec.data) : tableFromRows(spec.data);
|
|
126
137
|
const x = column(table, spec.x, "x axis");
|
|
127
138
|
const seriesName = text(spec.series) ? column(table, spec.series, "series") : undefined;
|
|
@@ -130,9 +141,8 @@ async function draw(spec: ChartSpec): Promise<string> {
|
|
|
130
141
|
const log = spec.scale === "log" ? ({ yType: "log" } as const) : {};
|
|
131
142
|
|
|
132
143
|
// Enarratio types its field options by the row type; parsed rows are only known at run time,
|
|
133
|
-
// so
|
|
134
|
-
|
|
135
|
-
type Loose = any;
|
|
144
|
+
// so every row is a record of cells and the columns are checked here.
|
|
145
|
+
type Loose = Record<string, Cell>;
|
|
136
146
|
|
|
137
147
|
switch (type as ChartType) {
|
|
138
148
|
case "bar": {
|
|
@@ -186,9 +196,12 @@ async function draw(spec: ChartSpec): Promise<string> {
|
|
|
186
196
|
* `enarratio/plot` (Observable Plot and linkedom) only when a page has one. Never throws: a chart
|
|
187
197
|
* that cannot be drawn returns the reason instead, so one mistake cannot break a page.
|
|
188
198
|
*/
|
|
189
|
-
export async function renderChart(
|
|
199
|
+
export async function renderChart(
|
|
200
|
+
spec: ChartSpec,
|
|
201
|
+
options: RenderOptions = {},
|
|
202
|
+
): Promise<ChartResult> {
|
|
190
203
|
try {
|
|
191
|
-
return { ok: true, html: await draw(spec) };
|
|
204
|
+
return { ok: true, html: await draw(spec, options) };
|
|
192
205
|
} catch (error) {
|
|
193
206
|
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
194
207
|
}
|
package/src/data.ts
CHANGED
|
@@ -8,8 +8,8 @@ export interface Table {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/** Limits that keep one chart's render bounded, whatever an editor pastes. */
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const MAX_ROWS = 5000;
|
|
12
|
+
const MAX_COLUMNS = 50;
|
|
13
13
|
|
|
14
14
|
const NUMBER = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
15
15
|
const GROUPED_NUMBER = /^[+-]?\d{1,3}(?:,\d{3})+(?:\.\d+)?$/;
|
package/src/index.ts
CHANGED
package/src/markdown.ts
CHANGED
|
@@ -46,7 +46,7 @@ const KEYS = new Set([
|
|
|
46
46
|
* 2026-01-01,820
|
|
47
47
|
* ```
|
|
48
48
|
*/
|
|
49
|
-
|
|
49
|
+
function parseChartBlock(source: string): ChartSpec & { readonly interactive: boolean } {
|
|
50
50
|
const lines = source.split(/\r?\n/);
|
|
51
51
|
const rule = lines.findIndex((line) => line.trim() === "---");
|
|
52
52
|
if (rule === -1)
|
|
@@ -78,7 +78,7 @@ async function chartHtml(
|
|
|
78
78
|
let markup: string;
|
|
79
79
|
try {
|
|
80
80
|
const { interactive, ...spec } = parseChartBlock(source);
|
|
81
|
-
const result = await renderChart(spec);
|
|
81
|
+
const result = await renderChart(spec, { interactive });
|
|
82
82
|
if (!result.ok) console.warn(`[enarratio-astro] Markdown chart not drawn: ${result.error}`);
|
|
83
83
|
markup = chartMarkup(result, interactive);
|
|
84
84
|
} catch (error) {
|