enarratio-astro 0.1.0 → 0.4.2

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 CHANGED
@@ -1,22 +1,86 @@
1
- # Changelog
2
-
3
- All notable changes to enarratio-astro are recorded here. The format follows
4
- [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
5
- [Semantic Versioning](https://semver.org/). Before 1.0.0, a minor version may change the options;
6
- every such change is listed here.
7
-
8
- ## [Unreleased]
9
-
10
- ## [0.1.0] - 2026-10-24
11
-
12
- ### Added
13
-
14
- - `<Chart>`: bar, line, stacked area, scatter and heatmap charts drawn on the server by Enarratio
15
- 0.3.1, from rows or from CSV, semicolon- or tab-separated text, with a required description, a
16
- data table, and light and dark themes. The chart CSS is written once per page.
17
- - Charts in Markdown: `chart` code blocks, with `satteriCharts()` for Sätteri and `remarkCharts`
18
- for remark.
19
- - `<Enhance />` and the `interactive` option: Enarratio's enhancement script, only on pages that
20
- ask for it.
21
- - `styles`: `"theme"` (default), `"base"` for sites whose tokens define the colors, or `"none"`.
22
- - A note in place of a chart that cannot be drawn, saying why.
1
+ # Changelog
2
+
3
+ All notable changes to enarratio-astro are recorded here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
5
+ [Semantic Versioning](https://semver.org/). Before 1.0.0, a minor version may change the options;
6
+ every such change is listed here.
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.4.2] - 2026-11-03
11
+
12
+ ### Changed
13
+
14
+ - Draws with Enarratio 0.7.3: charts no longer move the page when the enhancement layer loads. The redraw keeps the
15
+ height the server drawing showed, a legend entry has its button's box before it is a button, and an interactive
16
+ chart's figure holds the controls the layer adds (Show table, Play as sound, the downloads), inert until it
17
+ arrives.
18
+ - A chart that is not interactive leaves those controls out (Enarratio's `controls: false`), since no layer ever
19
+ makes them work. `renderChart` takes a second argument, `{ interactive }`, for this; it defaults to true, as
20
+ Enarratio does.
21
+
22
+ ## [0.4.1] - 2026-11-03
23
+
24
+ ### Changed
25
+
26
+ - Draws with Enarratio 0.7.2: timeline text never renders under 12 px.
27
+ - Requires Node.js 22.22 or later (was 22.16), the floor Astro 7.4 sets.
28
+
29
+ ## [0.4.0] - 2026-11-01
30
+
31
+ ### Changed
32
+
33
+ - Draws with Enarratio 0.7.0 (0.6.0's phone drawings and Play as sound, and 0.7.0's tactile SVG download and
34
+ forced-colors legend swatches).
35
+
36
+ ### Release
37
+
38
+ - Staging works: the release job's setup-node moves from v4 to v7, whose v4 placeholder `NODE_AUTH_TOKEN` was sent
39
+ in place of the trusted-publishing token (E401 on 0.2.0, 0.2.1 and 0.3.0, so 0.1.0 is the newest on npm).
40
+
41
+ - Each release's `npm pack` tarball gets a GitHub artifact attestation beside npm's provenance:
42
+ `gh attestation verify enarratio-astro-<version>.tgz --repo DrDustinEdwards/astro` checks a download.
43
+
44
+ ## [0.3.0] - 2026-10-31
45
+
46
+ ### Changed
47
+
48
+ - Draws with Enarratio 0.5.0: axis titles clear of the ticks, ticks thinned to fit, the y range rounded to the
49
+ drawn ticks, proportional tick figures, text-safe series ink in the Capsomer theme, and Download SVG and PNG
50
+ through `enarratio/enhance`.
51
+ - First release on npm since 0.1.0: 0.2.0 and 0.2.1 were tagged but never reached npm, because trusted
52
+ publishing was not yet set up.
53
+
54
+ ## [0.2.1] - 2026-10-31
55
+
56
+ ### Changed
57
+
58
+ - Draws with Enarratio 0.4.1: capitalized summaries, ranges said with their unit, day ticks for
59
+ whole-day data, and linked bars whose links sit in the data table.
60
+
61
+ ## [0.2.0] - 2026-10-31
62
+
63
+ ### Changed
64
+
65
+ - Draws with Enarratio 0.4.0: a head with the title and the finding, a summary under the chart, a
66
+ CSV download, and wide charts that scroll sideways on a phone. The base styles now set system
67
+ colors under forced colors.
68
+
69
+ ### Added
70
+
71
+ - `subtitle`, `notes`, `source`, `sourceHref`, `byline`, `xUnit` and `yUnit`, as props and as
72
+ Markdown keys.
73
+
74
+ ## [0.1.0] - 2026-10-24
75
+
76
+ ### Added
77
+
78
+ - `<Chart>`: bar, line, stacked area, scatter and heatmap charts drawn on the server by Enarratio
79
+ 0.3.1, from rows or from CSV, semicolon- or tab-separated text, with a required description, a
80
+ data table, and light and dark themes. The chart CSS is written once per page.
81
+ - Charts in Markdown: `chart` code blocks, with `satteriCharts()` for Sätteri and `remarkCharts`
82
+ for remark.
83
+ - `<Enhance />` and the `interactive` option: Enarratio's enhancement script, only on pages that
84
+ ask for it.
85
+ - `styles`: `"theme"` (default), `"base"` for sites whose tokens define the colors, or `"none"`.
86
+ - A note in place of a chart that cannot be drawn, saying why.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Dustin Edwards
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dustin Edwards
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,151 +1,155 @@
1
- # enarratio-astro
2
-
3
- **Accessible charts for [Astro](https://astro.build): a `<Chart>` component and charts in Markdown,
4
- drawn on the server by [Enarratio](https://github.com/DrDustinEdwards/enarratio).**
5
-
6
- A chart arrives in the page as HTML and SVG: complete before any script runs, readable by screen
7
- readers and search engines, with a data table, and in light and dark. It draws bar (stacked, side
8
- by side, vertical or horizontal; counting rows when no value column is given), line, stacked area,
9
- scatter (with an optional regression line and 95% band) and heatmap charts. A chart can be made
10
- interactive (hover and focus details, keyboard navigation, click-to-filter) with Enarratio's small
11
- enhancement script, which is added only to pages that ask for it.
12
-
13
- Supports Astro 6 or later. Status: 0.x, so options may change before 1.0; every change is in the
14
- [changelog](https://github.com/DrDustinEdwards/astro/blob/main/packages/enarratio-astro/CHANGELOG.md). For EmDash sites,
15
- [enarratio-emdash](https://github.com/DrDustinEdwards/astro/tree/main/packages/enarratio-emdash#readme) adds the same charts as a block
16
- in the editor.
17
-
18
- ## Install
19
-
20
- ```sh
21
- npm install enarratio-astro
22
- ```
23
-
24
- ## In a page
25
-
26
- ```astro
27
- ---
28
- import Chart from "enarratio-astro/Chart.astro";
29
-
30
- const downloads = [
31
- { year: 2024, package: "Core", downloads: 4100 },
32
- { year: 2025, package: "Core", downloads: 5300 },
33
- { year: 2026, package: "Core", downloads: 6100 },
34
- { year: 2024, package: "Plugin", downloads: 1200 },
35
- { year: 2025, package: "Plugin", downloads: 1900 },
36
- { year: 2026, package: "Plugin", downloads: 2800 },
37
- ];
38
- ---
39
- <Chart
40
- type="line"
41
- data={downloads}
42
- x="year"
43
- y="downloads"
44
- series="package"
45
- title="Downloads per year"
46
- alt="Downloads per year, 2024 to 2026: the core grows from 4,100 to 6,100, the plugin from 1,200 to 2,800."
47
- interactive
48
- />
49
- ```
50
-
51
- `data` is rows as objects (from code, JSON or a content collection; dates become ISO dates) or
52
- text: CSV, semicolon-separated, or pasted from a spreadsheet (tab-separated), first row naming the
53
- columns. The chart CSS is written once per page, however many charts it has.
54
-
55
- ## In Markdown
56
-
57
- A code block whose language is `chart` becomes a chart: options, a line of three dashes, then the
58
- data.
59
-
60
- ~~~md
61
- ```chart
62
- type: bar
63
- x: team
64
- y: tickets
65
- series: status
66
- layout: grouped
67
- alt: Support has the most open tickets; Platform has closed the most.
68
- ---
69
- team,status,tickets
70
- Support,Open,14
71
- Support,Closed,22
72
- Platform,Open,5
73
- Platform,Closed,31
74
- ```
75
- ~~~
76
-
77
- Register the plugin for Astro's Markdown processor. Astro 7's default, Sätteri:
78
-
79
- ```js
80
- // astro.config.mjs
81
- import { satteri } from "@astrojs/markdown-satteri";
82
- import { satteriCharts } from "enarratio-astro/markdown";
83
-
84
- export default defineConfig({
85
- markdown: { processor: satteri({ mdastPlugins: [satteriCharts()] }) },
86
- });
87
- ```
88
-
89
- With remark (Astro 6, or Astro 7's unified processor):
90
-
91
- ```js
92
- import { remarkCharts } from "enarratio-astro/markdown";
93
-
94
- export default defineConfig({ markdown: { remarkPlugins: [remarkCharts] } });
95
- ```
96
-
97
- A Markdown chart with `interactive: true` is marked for the enhancement script; include it once in
98
- the page's layout with `<Enhance />` from `enarratio-astro/Enhance.astro`. It finds every
99
- interactive chart on the page and works with view transitions.
100
-
101
- ## Options
102
-
103
- The component's props and a Markdown block's keys are the same:
104
-
105
- | Option | Used by | Notes |
106
- |---|---|---|
107
- | `type` | all | `bar` (default), `line`, `area` (stacked), `scatter` or `heatmap`. |
108
- | `data` | all | The data (component only; in Markdown it follows the dashes). Up to 5000 rows and 50 columns. |
109
- | `alt` | all | **Required.** What the chart shows and finds, in a sentence. It names the chart for screen readers. |
110
- | `title`, `caption` | all | Optional. The caption is for source, method or caveats. |
111
- | `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. |
112
- | `y` | all | The value column. Bar charts count rows when it is missing. For a heatmap, the row column. |
113
- | `series` | bar, line, area, scatter | Splits rows into series, told apart by color and by legend, labels or symbols. |
114
- | `value` | heatmap | The cell value column. |
115
- | `xLabel`, `yLabel` | all | Axis labels. |
116
- | `layout` | bar | `stacked` (default) or `grouped`. |
117
- | `orientation` | bar | `vertical` (default) or `horizontal`. |
118
- | `scale` | line, scatter | `linear` (default) or `log`. |
119
- | `regression` | scatter | A least-squares line with its 95% band. |
120
- | `dataTable` | all | `details` (default; behind a "Data table" toggle) or `visually-hidden` (screen readers only). |
121
- | `id` | all | The figure's id. |
122
- | `interactive` | all | Adds the enhancement script. Off by default, so pages stay script-free. |
123
-
124
- A chart that cannot be drawn (a column that is not in the data, text in a number column, a missing
125
- `alt`) is replaced by a short note saying why, and the reason is logged, so one mistake never
126
- breaks the page. All text is escaped.
127
-
128
- ## Styles
129
-
130
- The component takes `styles`, `theme` and `stylesheetOptions`; the Markdown plugins take the same
131
- as options (`satteriCharts({ styles: "base" })`).
132
-
133
- - `styles: "theme"` (default): an Enarratio theme (`theme`, default Enarratio's own), in light and
134
- dark. Charts follow the page's `color-scheme`; for a site that switches with an attribute, pass
135
- `stylesheetOptions={{ colorScheme: { dark: '[data-theme="dark"]' } }}`.
136
- - `styles: "base"`: layout rules without colors or fonts, for a site whose own design tokens define
137
- the `--enarratio-*` properties. [Capsomer](https://github.com/DrDustinEdwards/capsomer)'s tokens do.
138
- - `styles: "none"`: nothing; the site includes Enarratio's stylesheet itself.
139
-
140
- Enarratio's [README](https://github.com/DrDustinEdwards/enarratio#themes) covers themes and the
141
- custom properties.
142
-
143
- ## Rendering cost
144
-
145
- Bar, line and area charts are drawn by `enarratio/lite`, which builds the SVG as a string with no
146
- DOM, the cheapest render on Cloudflare Workers. Scatter plots and heatmaps load `enarratio/plot`
147
- (Observable Plot and linkedom) only when a page has one.
148
-
149
- ## License
150
-
151
- [MIT](LICENSE). Copyright (c) 2026 Dustin Edwards.
1
+ # enarratio-astro
2
+
3
+ **Accessible charts for [Astro](https://astro.build): a `<Chart>` component and charts in Markdown,
4
+ drawn on the server by [Enarratio](https://github.com/DrDustinEdwards/enarratio).**
5
+
6
+ A chart arrives in the page as HTML and SVG: complete before any script runs, readable by screen
7
+ readers and search engines, with a data table, and in light and dark. It draws bar (stacked, side
8
+ by side, vertical or horizontal; counting rows when no value column is given), line, stacked area,
9
+ scatter (with an optional regression line and 95% band) and heatmap charts. A chart can be made
10
+ interactive (hover and focus details, keyboard navigation, click-to-filter) with Enarratio's small
11
+ enhancement script, which is added only to pages that ask for it.
12
+
13
+ Supports Astro 6 or later. Status: 0.x, so options may change before 1.0; every change is in the
14
+ [changelog](https://github.com/DrDustinEdwards/astro/blob/main/packages/enarratio-astro/CHANGELOG.md). For EmDash sites,
15
+ [enarratio-emdash](https://github.com/DrDustinEdwards/astro/tree/main/packages/enarratio-emdash#readme) adds the same charts as a block
16
+ in the editor.
17
+
18
+ ## Install
19
+
20
+ ```sh
21
+ npm install enarratio-astro
22
+ ```
23
+
24
+ ## In a page
25
+
26
+ ```astro
27
+ ---
28
+ import Chart from "enarratio-astro/Chart.astro";
29
+
30
+ const downloads = [
31
+ { year: 2024, package: "Core", downloads: 4100 },
32
+ { year: 2025, package: "Core", downloads: 5300 },
33
+ { year: 2026, package: "Core", downloads: 6100 },
34
+ { year: 2024, package: "Plugin", downloads: 1200 },
35
+ { year: 2025, package: "Plugin", downloads: 1900 },
36
+ { year: 2026, package: "Plugin", downloads: 2800 },
37
+ ];
38
+ ---
39
+ <Chart
40
+ type="line"
41
+ data={downloads}
42
+ x="year"
43
+ y="downloads"
44
+ series="package"
45
+ title="Downloads per year"
46
+ alt="Downloads per year, 2024 to 2026: the core grows from 4,100 to 6,100, the plugin from 1,200 to 2,800."
47
+ interactive
48
+ />
49
+ ```
50
+
51
+ `data` is rows as objects (from code, JSON or a content collection; dates become ISO dates) or
52
+ text: CSV, semicolon-separated, or pasted from a spreadsheet (tab-separated), first row naming the
53
+ columns. The chart CSS is written once per page, however many charts it has.
54
+
55
+ ## In Markdown
56
+
57
+ A code block whose language is `chart` becomes a chart: options, a line of three dashes, then the
58
+ data.
59
+
60
+ ~~~md
61
+ ```chart
62
+ type: bar
63
+ x: team
64
+ y: tickets
65
+ series: status
66
+ layout: grouped
67
+ alt: Support has the most open tickets; Platform has closed the most.
68
+ ---
69
+ team,status,tickets
70
+ Support,Open,14
71
+ Support,Closed,22
72
+ Platform,Open,5
73
+ Platform,Closed,31
74
+ ```
75
+ ~~~
76
+
77
+ Register the plugin for Astro's Markdown processor. Astro 7's default, Sätteri:
78
+
79
+ ```js
80
+ // astro.config.mjs
81
+ import { satteri } from "@astrojs/markdown-satteri";
82
+ import { satteriCharts } from "enarratio-astro/markdown";
83
+
84
+ export default defineConfig({
85
+ markdown: { processor: satteri({ mdastPlugins: [satteriCharts()] }) },
86
+ });
87
+ ```
88
+
89
+ With remark (Astro 6, or Astro 7's unified processor):
90
+
91
+ ```js
92
+ import { remarkCharts } from "enarratio-astro/markdown";
93
+
94
+ export default defineConfig({ markdown: { remarkPlugins: [remarkCharts] } });
95
+ ```
96
+
97
+ A Markdown chart with `interactive: true` is marked for the enhancement script; include it once in
98
+ the page's layout with `<Enhance />` from `enarratio-astro/Enhance.astro`. It finds every
99
+ interactive chart on the page and works with view transitions.
100
+
101
+ ## Options
102
+
103
+ The component's props and a Markdown block's keys are the same:
104
+
105
+ | Option | Used by | Notes |
106
+ |---|---|---|
107
+ | `type` | all | `bar` (default), `line`, `area` (stacked), `scatter` or `heatmap`. |
108
+ | `data` | all | The data (component only; in Markdown it follows the dashes). Up to 5000 rows and 50 columns. |
109
+ | `alt` | all | **Required.** What the chart shows and finds, in a sentence. It names the chart for screen readers. |
110
+ | `title`, `subtitle` | all | Optional. Shown above the chart. |
111
+ | `caption`, `notes` | all | Optional. The caption, under the chart, is for method or caveats; notes are a smaller line for definitions. |
112
+ | `source`, `sourceHref` | all | Optional. Where the data came from, linked when `sourceHref` is set, beside a CSV download of the data. |
113
+ | `byline` | all | Optional. Who made the chart. |
114
+ | `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. |
115
+ | `y` | all | The value column. Bar charts count rows when it is missing. For a heatmap, the row column. |
116
+ | `series` | bar, line, area, scatter | Splits rows into series, told apart by color and by legend, labels or symbols. |
117
+ | `value` | heatmap | The cell value column. |
118
+ | `xLabel`, `yLabel` | all | Axis labels. |
119
+ | `xUnit`, `yUnit` | all | Optional. The unit, shown after the axis label (`Sales (units)`) and in the table and summary. |
120
+ | `layout` | bar | `stacked` (default) or `grouped`. |
121
+ | `orientation` | bar | `vertical` (default) or `horizontal`. |
122
+ | `scale` | line, scatter | `linear` (default) or `log`. |
123
+ | `regression` | scatter | A least-squares line with its 95% band. |
124
+ | `dataTable` | all | `details` (default; behind a "Data table" toggle) or `visually-hidden` (screen readers only). |
125
+ | `id` | all | The figure's id. |
126
+ | `interactive` | all | Adds the enhancement script. Off by default, so pages stay script-free. |
127
+
128
+ A chart that cannot be drawn (a column that is not in the data, text in a number column, a missing
129
+ `alt`) is replaced by a short note saying why, and the reason is logged, so one mistake never
130
+ breaks the page. All text is escaped.
131
+
132
+ ## Styles
133
+
134
+ The component takes `styles`, `theme` and `stylesheetOptions`; the Markdown plugins take the same
135
+ as options (`satteriCharts({ styles: "base" })`).
136
+
137
+ - `styles: "theme"` (default): an Enarratio theme (`theme`, default Enarratio's own), in light and
138
+ dark. Charts follow the page's `color-scheme`; for a site that switches with an attribute, pass
139
+ `stylesheetOptions={{ colorScheme: { dark: '[data-theme="dark"]' } }}`.
140
+ - `styles: "base"`: layout rules without colors or fonts, for a site whose own design tokens define
141
+ the `--enarratio-*` properties. [Capsomer](https://github.com/DrDustinEdwards/capsomer)'s tokens do.
142
+ - `styles: "none"`: nothing; the site includes Enarratio's stylesheet itself.
143
+
144
+ Enarratio's [README](https://github.com/DrDustinEdwards/enarratio#themes) covers themes and the
145
+ custom properties.
146
+
147
+ ## Rendering cost
148
+
149
+ Bar, line and area charts are drawn by `enarratio/lite`, which builds the SVG as a string with no
150
+ DOM, the cheapest render on Cloudflare Workers. Scatter plots and heatmaps load `enarratio/plot`
151
+ (Observable Plot and linkedom) only when a page has one.
152
+
153
+ ## License
154
+
155
+ [MIT](LICENSE). Copyright (c) 2026 Dustin Edwards.
package/dist/chart.d.ts CHANGED
@@ -17,8 +17,18 @@ export interface ChartSpec {
17
17
  /** Required: what the chart shows and finds, in a sentence. Names the chart for screen readers. */
18
18
  readonly alt?: string | undefined;
19
19
  readonly title?: string | undefined;
20
- /** Source, method or caveats, below the chart. */
20
+ /** A line under the title saying what the chart shows or how to read it. */
21
+ readonly subtitle?: string | undefined;
22
+ /** Method or caveats, below the chart. */
21
23
  readonly caption?: string | undefined;
24
+ /** Notes under the chart: what a measure means, what was left out. */
25
+ readonly notes?: string | undefined;
26
+ /** Where the data come from, in the source line beside the CSV download. */
27
+ readonly source?: string | undefined;
28
+ /** A link for the source (https). */
29
+ readonly sourceHref?: string | undefined;
30
+ /** Who made the chart, in the source line. */
31
+ readonly byline?: string | undefined;
22
32
  /** The column along the x axis. Column names match without regard to case. */
23
33
  readonly x?: string | undefined;
24
34
  /** The value column. Bar charts count rows without one; for a heatmap, the row column. */
@@ -29,6 +39,9 @@ export interface ChartSpec {
29
39
  readonly value?: string | undefined;
30
40
  readonly xLabel?: string | undefined;
31
41
  readonly yLabel?: string | undefined;
42
+ /** Units added to the axis labels and table headers: "Weight (kg)". */
43
+ readonly xUnit?: string | undefined;
44
+ readonly yUnit?: string | undefined;
32
45
  /** Bar: series stacked (default) or side by side ("grouped"). */
33
46
  readonly layout?: string | undefined;
34
47
  /** Bar: "vertical" (default) or "horizontal". */
@@ -50,10 +63,19 @@ export type ChartResult = {
50
63
  readonly ok: false;
51
64
  readonly error: string;
52
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
+ }
53
75
  /**
54
76
  * Draws a chart. Bar, line and area charts come from `enarratio/lite`, which builds the SVG as a
55
77
  * string with no DOM, the cheapest render on a Worker; scatter plots and heatmaps load
56
78
  * `enarratio/plot` (Observable Plot and linkedom) only when a page has one. Never throws: a chart
57
79
  * that cannot be drawn returns the reason instead, so one mistake cannot break a page.
58
80
  */
59
- 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,32 +22,36 @@ 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 id. */
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.");
30
30
  const title = text(spec.title);
31
- const caption = text(spec.caption);
32
- const xLabel = text(spec.xLabel);
33
- const yLabel = text(spec.yLabel);
31
+ const source = text(spec.source);
32
+ const sourceHref = text(spec.sourceHref);
33
+ if (sourceHref && !source)
34
+ throw new Error("Name the source (source) that the link (sourceHref) goes to.");
34
35
  const id = text(spec.id)?.replace(/[^A-Za-z0-9_-]/g, "");
36
+ const optional = Object.fromEntries(["subtitle", "caption", "notes", "byline", "xLabel", "yLabel", "xUnit", "yUnit"]
37
+ .map((key) => [key, text(spec[key])])
38
+ .filter(([, value]) => value !== undefined));
35
39
  return {
36
40
  alt,
37
41
  ...(title ? { title } : {}),
38
- ...(caption ? { caption } : {}),
39
- ...(xLabel ? { xLabel } : {}),
40
- ...(yLabel ? { yLabel } : {}),
42
+ ...optional,
43
+ ...(source ? { source: sourceHref ? { name: source, href: sourceHref } : source } : {}),
41
44
  ...(id ? { id } : {}),
42
45
  dataTable: spec.dataTable === "visually-hidden" ? "visually-hidden" : "details",
46
+ ...(options.interactive === false ? { controls: false } : {}),
43
47
  };
44
48
  }
45
- async function draw(spec) {
49
+ async function draw(spec, options) {
46
50
  const type = (text(spec.type) ?? "bar").toLowerCase();
47
51
  if (!CHART_TYPES.includes(type)) {
48
52
  throw new Error(`There is no chart type "${spec.type}". Use one of: ${CHART_TYPES.join(", ")}.`);
49
53
  }
50
- const common = figure(spec);
54
+ const common = figure(spec, options);
51
55
  const table = typeof spec.data === "string" ? parseTable(spec.data) : tableFromRows(spec.data);
52
56
  const x = column(table, spec.x, "x axis");
53
57
  const seriesName = text(spec.series) ? column(table, spec.series, "series") : undefined;
@@ -106,9 +110,9 @@ async function draw(spec) {
106
110
  * `enarratio/plot` (Observable Plot and linkedom) only when a page has one. Never throws: a chart
107
111
  * that cannot be drawn returns the reason instead, so one mistake cannot break a page.
108
112
  */
109
- export async function renderChart(spec) {
113
+ export async function renderChart(spec, options = {}) {
110
114
  try {
111
- return { ok: true, html: await draw(spec) };
115
+ return { ok: true, html: await draw(spec, options) };
112
116
  }
113
117
  catch (error) {
114
118
  return { ok: false, error: error instanceof Error ? error.message : String(error) };
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.js CHANGED
@@ -6,13 +6,20 @@ const KEYS = new Set([
6
6
  "type",
7
7
  "alt",
8
8
  "title",
9
+ "subtitle",
9
10
  "caption",
11
+ "notes",
12
+ "source",
13
+ "sourceHref",
14
+ "byline",
10
15
  "x",
11
16
  "y",
12
17
  "series",
13
18
  "value",
14
19
  "xLabel",
15
20
  "yLabel",
21
+ "xUnit",
22
+ "yUnit",
16
23
  "layout",
17
24
  "orientation",
18
25
  "scale",
@@ -62,7 +69,7 @@ async function chartHtml(source, first, options) {
62
69
  let markup;
63
70
  try {
64
71
  const { interactive, ...spec } = parseChartBlock(source);
65
- const result = await renderChart(spec);
72
+ const result = await renderChart(spec, { interactive });
66
73
  if (!result.ok)
67
74
  console.warn(`[enarratio-astro] Markdown chart not drawn: ${result.error}`);
68
75
  markup = chartMarkup(result, interactive);