duckfn-docs-kit 0.3.0 → 0.4.1
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/AGENTS.md +326 -234
- package/README.md +10 -6
- package/dist/IconButton.d.ts +22 -0
- package/dist/codemirror.d.ts +29 -0
- package/dist/download.d.ts +51 -0
- package/dist/index.d.ts +28 -7
- package/dist/index.js +2 -2
- package/dist/mermaid/DfkMermaid.d.ts +25 -0
- package/dist/mermaid/config.d.ts +48 -0
- package/dist/mermaid/remark.d.ts +40 -0
- package/dist/mermaid/remark.js +32 -0
- package/dist/mermaid/render.d.ts +92 -0
- package/dist/mermaid/styles.d.ts +6 -0
- package/dist/panzoom-view.d.ts +17 -0
- package/dist/{register-CALCwFBv.js → register-wdwf0LC4.js} +1365 -738
- package/dist/remark.d.ts +1 -1
- package/dist/source-dialog.d.ts +35 -0
- package/dist/sql/PreviewTabs.d.ts +39 -23
- package/dist/sql/SvgViewer.d.ts +53 -0
- package/dist/sql/client.js +1 -1
- package/dist/sql/harness.js +1 -1
- package/dist/sql/remark.d.ts +6 -1
- package/dist/sql/renderers.d.ts +9 -0
- package/package.json +6 -2
- package/src/IconButton.ts +50 -0
- package/src/codemirror.ts +97 -0
- package/src/download.ts +169 -0
- package/src/index.ts +31 -7
- package/src/mermaid/DfkMermaid.css +326 -0
- package/src/mermaid/DfkMermaid.ts +411 -0
- package/src/mermaid/config.ts +74 -0
- package/src/mermaid/remark.ts +98 -0
- package/src/mermaid/render.ts +172 -0
- package/src/mermaid/styles.ts +24 -0
- package/src/panzoom-view.ts +235 -0
- package/src/register.ts +3 -0
- package/src/remark.ts +1 -1
- package/src/source-dialog.ts +126 -0
- package/src/sql/DfkSql.css +13 -10
- package/src/sql/DfkSql.ts +60 -51
- package/src/sql/PreviewTabs.ts +98 -52
- package/src/sql/SvgViewer.ts +155 -0
- package/src/sql/remark.ts +6 -1
- package/src/sql/renderers.ts +433 -159
- package/src/sql/sql.css +189 -19
- package/dist/sql/editor.d.ts +0 -16
- package/src/sql/editor.ts +0 -75
package/AGENTS.md
CHANGED
|
@@ -1,234 +1,326 @@
|
|
|
1
|
-
# duckfn-docs-kit — usage guide for agents and site authors
|
|
2
|
-
|
|
3
|
-
This is the **consumer-facing** companion to [`README.md`](./README.md): the README says what to
|
|
4
|
-
import and how to wire it into `docusaurus.config.ts`, this file states the **contracts and the
|
|
5
|
-
traps** — the things that are easy to get subtly wrong when you write a docs page or review one.
|
|
6
|
-
|
|
7
|
-
Read it before writing runnable SQL blocks or configuring preloads.
|
|
8
|
-
|
|
9
|
-
> Developing the kit itself? Its internal conventions (rendering contract, shadow-DOM rules,
|
|
10
|
-
> release flow) are in `CONVENTIONS.md` in the repository. That file is **not** published; this one
|
|
11
|
-
> is, so it is what a dependency reader sees.
|
|
12
|
-
|
|
13
|
-
## The three things that most often go wrong
|
|
14
|
-
|
|
15
|
-
1. **A runnable block shows only the result of its *last* statement.** Stacking several independent
|
|
16
|
-
examples in one block means the reader sees one result and the others silently vanish. One
|
|
17
|
-
example per block; several statements only for a preamble (`SET`, `CREATE`, …) that the last
|
|
18
|
-
query needs.
|
|
19
|
-
2. **`show: "html"` / `"iframe"` / `"svg"` need to be told which column holds the
|
|
20
|
-
than one result column you **must** name it: `"field": "<column>"`. Without
|
|
21
|
-
nothing to preview. `"tab_name"` names the column that labels each preview
|
|
22
|
-
tabs read `Row 1`, `Row 2`, …
|
|
23
|
-
3. **Only a block whose info string is JSON with `"type":"duckfn"` becomes runnable.** A bare
|
|
24
|
-
```` ```sql ```` block (or any other metastring) stays a plain, un-runnable code block — no Run
|
|
25
|
-
button, nothing executed.
|
|
26
|
-
|
|
27
|
-
## Install and wire it up
|
|
28
|
-
|
|
29
|
-
See [`README.md`](./README.md) — install, the three `docusaurus.config.ts` plugins, and the one CSS
|
|
30
|
-
import. Everything below assumes that is already done.
|
|
31
|
-
|
|
32
|
-
## Runnable SQL blocks
|
|
33
|
-
|
|
34
|
-
### The shape
|
|
35
|
-
|
|
36
|
-
A fenced block whose info string is a JSON config. The block itself becomes a CodeMirror editor
|
|
37
|
-
with a Run button; nothing executes until the reader clicks it.
|
|
38
|
-
|
|
39
|
-
````md
|
|
40
|
-
```sql {"type":"duckfn"}
|
|
41
|
-
SELECT 40 + 2 AS answer;
|
|
42
|
-
```
|
|
43
|
-
````
|
|
44
|
-
|
|
45
|
-
Works in `.md` and `.mdx` alike — the metastring is rewritten during the build, before either format
|
|
46
|
-
is compiled.
|
|
47
|
-
|
|
48
|
-
### Config reference
|
|
49
|
-
|
|
50
|
-
| Field | Meaning |
|
|
51
|
-
| --- | --- |
|
|
52
|
-
| `type` | `"duckfn"`. Required — this is what makes the block runnable. |
|
|
53
|
-
| `show` | `table` (default), `text`, `html`, `iframe`, `svg`. See *Result renderers*. |
|
|
54
|
-
| `field` | The column holding the markup, for `html` / `iframe` / `svg`. Required when the result has more than one column. |
|
|
55
|
-
| `tab_name` | The column whose value labels each preview tab. Defaults to `Row N`. |
|
|
56
|
-
| `option.width` · `option.height` | CSS lengths for the preview box (`"100%"`, `"640px"`). |
|
|
57
|
-
| `option.sandbox` | Sandbox tokens for the iframe, replacing the default `allow-scripts`. Widen deliberately. |
|
|
58
|
-
| `extensions` | Extra extension names to `LOAD` before this block runs, on top of the site's preloads. |
|
|
59
|
-
| `repository` | Where those extensions come from: `community`, `core`, or a repository URL. |
|
|
60
|
-
| `allowUnsignedExtensions` | Accept an unverifiable signature. Site-wide via the preload config, or per block; the first block to initialise the engine settles it. |
|
|
61
|
-
| `expect` | `ok` (default) or `error`. `error` declares "this block must fail" — see *Testing*. |
|
|
62
|
-
|
|
63
|
-
### Behaviour you have to design around
|
|
64
|
-
|
|
65
|
-
- **The result shown is the last statement's.** A block with `SET …; CREATE …; SELECT …` shows the
|
|
66
|
-
`SELECT`. A block with three independent `SELECT`s shows the third one only.
|
|
67
|
-
- **Default `show`:** a single column with a single row renders as `text`; anything else renders as
|
|
68
|
-
a `table`. Set `show` explicitly when the shape matters.
|
|
69
|
-
- **One DuckDB-Wasm instance per page, one connection per page.** Blocks on the same page share
|
|
70
|
-
state — a table or macro created in one block is visible to the next — and pages are isolated
|
|
71
|
-
from each other. Do not write a block that depends on another *page*.
|
|
72
|
-
- **The site's preloaded extensions are already loaded.** Call into them directly; do not add
|
|
73
|
-
`extensions` for the extension the site documents.
|
|
74
|
-
- **Errors are a result, not a broken block.** A failing statement renders its message in the result
|
|
75
|
-
area and keeps whatever the reader typed.
|
|
76
|
-
- **Every result has a tab strip** (even a plain table), and
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
|
83
|
-
|
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
86
|
-
| `
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
`
|
|
94
|
-
|
|
95
|
-
`
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
1
|
+
# duckfn-docs-kit — usage guide for agents and site authors
|
|
2
|
+
|
|
3
|
+
This is the **consumer-facing** companion to [`README.md`](./README.md): the README says what to
|
|
4
|
+
import and how to wire it into `docusaurus.config.ts`, this file states the **contracts and the
|
|
5
|
+
traps** — the things that are easy to get subtly wrong when you write a docs page or review one.
|
|
6
|
+
|
|
7
|
+
Read it before writing runnable SQL blocks or configuring preloads.
|
|
8
|
+
|
|
9
|
+
> Developing the kit itself? Its internal conventions (rendering contract, shadow-DOM rules,
|
|
10
|
+
> release flow) are in `CONVENTIONS.md` in the repository. That file is **not** published; this one
|
|
11
|
+
> is, so it is what a dependency reader sees.
|
|
12
|
+
|
|
13
|
+
## The three things that most often go wrong
|
|
14
|
+
|
|
15
|
+
1. **A runnable block shows only the result of its *last* statement.** Stacking several independent
|
|
16
|
+
examples in one block means the reader sees one result and the others silently vanish. One
|
|
17
|
+
example per block; several statements only for a preamble (`SET`, `CREATE`, …) that the last
|
|
18
|
+
query needs.
|
|
19
|
+
2. **`show: "html"` / `"iframe"` / `"svg"` / `"mermaid"` need to be told which column holds the
|
|
20
|
+
markup.** With more than one result column you **must** name it: `"field": "<column>"`. Without
|
|
21
|
+
it the renderer has nothing to preview. `"tab_name"` names the column that labels each preview
|
|
22
|
+
tab, and without it tabs read `Row 1`, `Row 2`, …
|
|
23
|
+
3. **Only a block whose info string is JSON with `"type":"duckfn"` becomes runnable.** A bare
|
|
24
|
+
```` ```sql ```` block (or any other metastring) stays a plain, un-runnable code block — no Run
|
|
25
|
+
button, nothing executed.
|
|
26
|
+
|
|
27
|
+
## Install and wire it up
|
|
28
|
+
|
|
29
|
+
See [`README.md`](./README.md) — install, the three `docusaurus.config.ts` plugins, and the one CSS
|
|
30
|
+
import. Everything below assumes that is already done.
|
|
31
|
+
|
|
32
|
+
## Runnable SQL blocks
|
|
33
|
+
|
|
34
|
+
### The shape
|
|
35
|
+
|
|
36
|
+
A fenced block whose info string is a JSON config. The block itself becomes a CodeMirror editor
|
|
37
|
+
with a Run button; nothing executes until the reader clicks it.
|
|
38
|
+
|
|
39
|
+
````md
|
|
40
|
+
```sql {"type":"duckfn"}
|
|
41
|
+
SELECT 40 + 2 AS answer;
|
|
42
|
+
```
|
|
43
|
+
````
|
|
44
|
+
|
|
45
|
+
Works in `.md` and `.mdx` alike — the metastring is rewritten during the build, before either format
|
|
46
|
+
is compiled.
|
|
47
|
+
|
|
48
|
+
### Config reference
|
|
49
|
+
|
|
50
|
+
| Field | Meaning |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `type` | `"duckfn"`. Required — this is what makes the block runnable. |
|
|
53
|
+
| `show` | `table` (default), `text`, `html`, `iframe`, `svg`, `mermaid`. See *Result renderers*. |
|
|
54
|
+
| `field` | The column holding the markup, for `html` / `iframe` / `svg` / `mermaid`. Required when the result has more than one column. |
|
|
55
|
+
| `tab_name` | The column whose value labels each preview tab. Defaults to `Row N`. |
|
|
56
|
+
| `option.width` · `option.height` | CSS lengths for the preview box (`"100%"`, `"640px"`). |
|
|
57
|
+
| `option.sandbox` | Sandbox tokens for the iframe, replacing the default `allow-scripts`. Widen deliberately. |
|
|
58
|
+
| `extensions` | Extra extension names to `LOAD` before this block runs, on top of the site's preloads. |
|
|
59
|
+
| `repository` | Where those extensions come from: `community`, `core`, or a repository URL. |
|
|
60
|
+
| `allowUnsignedExtensions` | Accept an unverifiable signature. Site-wide via the preload config, or per block; the first block to initialise the engine settles it. |
|
|
61
|
+
| `expect` | `ok` (default) or `error`. `error` declares "this block must fail" — see *Testing*. |
|
|
62
|
+
|
|
63
|
+
### Behaviour you have to design around
|
|
64
|
+
|
|
65
|
+
- **The result shown is the last statement's.** A block with `SET …; CREATE …; SELECT …` shows the
|
|
66
|
+
`SELECT`. A block with three independent `SELECT`s shows the third one only.
|
|
67
|
+
- **Default `show`:** a single column with a single row renders as `text`; anything else renders as
|
|
68
|
+
a `table`. Set `show` explicitly when the shape matters.
|
|
69
|
+
- **One DuckDB-Wasm instance per page, one connection per page.** Blocks on the same page share
|
|
70
|
+
state — a table or macro created in one block is visible to the next — and pages are isolated
|
|
71
|
+
from each other. Do not write a block that depends on another *page*.
|
|
72
|
+
- **The site's preloaded extensions are already loaded.** Call into them directly; do not add
|
|
73
|
+
`extensions` for the extension the site documents.
|
|
74
|
+
- **Errors are a result, not a broken block.** A failing statement renders its message in the result
|
|
75
|
+
area and keeps whatever the reader typed.
|
|
76
|
+
- **Every result has a tab strip** (even a plain table), and all of its result-wide chrome sits at the
|
|
77
|
+
strip's right end — see *The strip at the right of the tabs*. Table results bring sorting, resizable
|
|
78
|
+
rows/columns, a right-click menu and header drag.
|
|
79
|
+
|
|
80
|
+
### Result renderers
|
|
81
|
+
|
|
82
|
+
| `show` | What it renders | Needs |
|
|
83
|
+
| --- | --- | --- |
|
|
84
|
+
| `table` | The result grid. | — |
|
|
85
|
+
| `text` | A bare scalar, as one line. | A single column/row result. |
|
|
86
|
+
| `html` / `iframe` | One tab per row; the markup goes into a sandboxed `iframe` (`srcdoc`), with a trailing `Table` tab that is always last. | `field` (unless the result has exactly one column). `tab_name` to label tabs. |
|
|
87
|
+
| `svg` | The markup is spliced **into the page** (one tab per row, trailing `Table` tab). Zoom and pan open in fullscreen, where the tab strip also offers **reset zoom** / **edit source**. | Same as above. |
|
|
88
|
+
| `mermaid` | The cell is handed to `<dfk-mermaid>`, which renders in its **embedded** mode: no frame of its own and no floating cluster — **reset zoom** and **edit source** join the result's tab strip instead. One tab per row, trailing `Table` tab. | Same as above. |
|
|
89
|
+
|
|
90
|
+
Two facts worth knowing before you pick one:
|
|
91
|
+
|
|
92
|
+
- `html` and `iframe` are the *same* renderer. The frame is sandboxed with `allow-scripts` and
|
|
93
|
+
**without** `allow-same-origin`, so a report's JavaScript runs while the frame keeps an opaque
|
|
94
|
+
origin — that is what makes charts work, and it is also why the parent page cannot read
|
|
95
|
+
`iframe.contentDocument` (it is `null` by design).
|
|
96
|
+
- `svg` shares the page, so anything that could execute or navigate — `script`, `foreignObject`,
|
|
97
|
+
`on*` handlers, `javascript:` links — is stripped before insertion.
|
|
98
|
+
|
|
99
|
+
### The strip at the right of the tabs
|
|
100
|
+
|
|
101
|
+
Every result — a plain table included — carries the same tab strip, and the right end of it is where
|
|
102
|
+
the result-wide controls live, in this order: **the active tab's own buttons**, **download**, then
|
|
103
|
+
the **fullscreen** toggle.
|
|
104
|
+
|
|
105
|
+
| Active tab | Controls |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| `Table` | Search, copy table, column-width mode, reset view, unfreeze columns |
|
|
108
|
+
| `svg` / `mermaid` | Reset zoom, edit source |
|
|
109
|
+
| `html` / `iframe` / `text` | — |
|
|
110
|
+
|
|
111
|
+
- Those table buttons are the "whole table" half of the grid's right-click menu, placed where they
|
|
112
|
+
cannot cover a cell; the menu itself keeps the per-cell items (copy this cell, wrap this
|
|
113
|
+
row/column, freeze up to this column). Freezing, column widths and the current view therefore
|
|
114
|
+
survive a switch to another tab and back. **Unfreeze columns** is hidden until a column has
|
|
115
|
+
actually been frozen, so it does not sit there as a dead control.
|
|
116
|
+
- **Search** opens as an input in the strip rather than floating over the cells it searches, because
|
|
117
|
+
the table spans the full width. It highlights every hit, shows `3/12`, and steps with the arrows;
|
|
118
|
+
it is per result, not shared between blocks.
|
|
119
|
+
- **Download** saves whatever the active tab shows, in that tab's format: `.csv` for a table, `.svg`
|
|
120
|
+
for `svg` / `mermaid`, `.html` for `html` / `iframe`, `.txt` for `text`. It is hidden only while
|
|
121
|
+
there is nothing to save yet (a figure that has not rendered).
|
|
122
|
+
- **Fullscreen** makes the result fill the viewport; the same button (now "Exit fullscreen") stays
|
|
123
|
+
put, and <kbd>Esc</kbd> works too. It is also the only place a figure zooms or pans.
|
|
124
|
+
|
|
125
|
+
### Examples
|
|
126
|
+
|
|
127
|
+
A table result, and a scalar that degrades to text:
|
|
128
|
+
|
|
129
|
+
````md
|
|
130
|
+
```sql {"type":"duckfn","show":"table"}
|
|
131
|
+
SELECT * FROM range(10) WHERE range > 5;
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```sql {"type":"duckfn"}
|
|
135
|
+
SELECT 1;
|
|
136
|
+
```
|
|
137
|
+
````
|
|
138
|
+
|
|
139
|
+
An HTML (or iframe) report — note `field` and `tab_name`:
|
|
140
|
+
|
|
141
|
+
````md
|
|
142
|
+
```sql {"type":"duckfn","show":"iframe","field":"html","tab_name":"label","option":{"height":"170px"}}
|
|
143
|
+
SELECT * FROM (VALUES
|
|
144
|
+
('Bars', '<!doctype html><body><h4>Quarterly revenue</h4><svg viewBox="0 0 240 80">…</svg></body>')
|
|
145
|
+
) AS t(label, html);
|
|
146
|
+
```
|
|
147
|
+
````
|
|
148
|
+
|
|
149
|
+
An inline SVG, and an extension that is not preloaded:
|
|
150
|
+
|
|
151
|
+
````md
|
|
152
|
+
```sql {"type":"duckfn","show":"svg","option":{"height":"140px"}}
|
|
153
|
+
SELECT '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40"/></svg>';
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```sql {"type":"duckfn","show":"table","extensions":["inet"]}
|
|
157
|
+
SELECT '127.0.0.1'::INET::VARCHAR AS ip;
|
|
158
|
+
```
|
|
159
|
+
````
|
|
160
|
+
|
|
161
|
+
A diagram built by a query (the same element a ```` ```mermaid ```` fence produces):
|
|
162
|
+
|
|
163
|
+
````md
|
|
164
|
+
```sql {"type":"duckfn","show":"mermaid"}
|
|
165
|
+
SELECT 'flowchart LR' || chr(10)
|
|
166
|
+
|| ' A["a SELECT"] --> B["one result cell"]' AS diagram;
|
|
167
|
+
```
|
|
168
|
+
````
|
|
169
|
+
|
|
170
|
+
### Mistakes to check for when reviewing a page
|
|
171
|
+
|
|
172
|
+
- Several independent examples stacked in one block — only the last result is visible. **Split
|
|
173
|
+
them into one block per example.**
|
|
174
|
+
- `show: "html"` / `"iframe"` / `"svg"` / `"mermaid"` with a multi-column result and no `field`.
|
|
175
|
+
- No `tab_name`, so the preview tabs read `Row 1`, `Row 2`, … instead of something meaningful.
|
|
176
|
+
- A bare ```` ```sql ```` block where a runnable one was intended (it renders as a plain listing).
|
|
177
|
+
- Declaring `extensions` for the extension the site already preloads.
|
|
178
|
+
- A block that depends on a table created on a *different* page.
|
|
179
|
+
|
|
180
|
+
## Mermaid diagrams (`remarkMermaid`)
|
|
181
|
+
|
|
182
|
+
````ts
|
|
183
|
+
// docusaurus.config.ts, in the docs preset's `remarkPlugins`
|
|
184
|
+
remarkPlugins: [remarkMermaid],
|
|
185
|
+
````
|
|
186
|
+
|
|
187
|
+
A ```` ```mermaid ```` fence becomes a `<dfk-mermaid>` element that renders the diagram **in the
|
|
188
|
+
browser** (mermaid is a lazy `import()`, so a page with no diagram never downloads it). Do **not**
|
|
189
|
+
also install `@docusaurus/theme-mermaid` or list it in `themes`, and do not set `markdown.mermaid`:
|
|
190
|
+
the kit's element replaces both, and two renderers on one page would fight.
|
|
191
|
+
|
|
192
|
+
What the reader gets, in the element's top-right corner on hover: **reset zoom**, **fullscreen**,
|
|
193
|
+
**edit the source** in a CodeMirror dialog, and **download SVG**. Zoom and pan are off until the
|
|
194
|
+
diagram is expanded — fullscreen is what turns the wheel into a zoom and a drag into a pan.
|
|
195
|
+
|
|
196
|
+
- **The file is named after the section it sits in.** `1. Expansion.svg`, not
|
|
197
|
+
`mermaid-diagram.svg`, in a cascade that walks from the most specific source to the most general:
|
|
198
|
+
the diagram's own title (mermaid frontmatter, `---\ntitle: …\n---`) → the nearest heading above
|
|
199
|
+
it → the document title → `mermaid-diagram.svg`. So a diagram is best named by the heading it
|
|
200
|
+
lives under; give it a frontmatter `title:` when the heading is not the name you want. The name
|
|
201
|
+
goes through `filenamify`, so nothing a filesystem chokes on (`:`, `?`, `*`, `|`, …) reaches the
|
|
202
|
+
file.
|
|
203
|
+
- **The diagram on the page is a picture, not a viewport.** The cursor is the browser's (an I-beam
|
|
204
|
+
over a label), the wheel scrolls the page, and dragging selects text — labels are still text, and
|
|
205
|
+
copying one works. Expanding the diagram is what turns the pointer into a `grab` hand and gives a
|
|
206
|
+
drag to panning; **Reset zoom** returns it to fit without leaving fullscreen, and zooming is off
|
|
207
|
+
again the moment the diagram is back inline. There is no select/drag mode to remember.
|
|
208
|
+
- **A `show: "mermaid"` result reuses the same element**, in an *embedded* mode: the result panel
|
|
209
|
+
already draws the frame and the strip, so the element renders neither a frame nor a floating
|
|
210
|
+
cluster, and **reset zoom** / **edit source** move into the tab strip. See *The strip at the right
|
|
211
|
+
of the tabs*.
|
|
212
|
+
|
|
213
|
+
- **The palette is a site choice, not a page one.** The kit's default is the `neo` look with
|
|
214
|
+
`redux-color` / `redux-dark-color`; a site overrides it in its own config, which also keeps the
|
|
215
|
+
kit fork-free for downstream docs sites:
|
|
216
|
+
|
|
217
|
+
````ts
|
|
218
|
+
remarkMermaid({config: {theme: {light: 'neutral', dark: 'dark'}, options: {look: 'classic'}}})
|
|
219
|
+
````
|
|
220
|
+
|
|
221
|
+
`theme` is per colour mode (the element re-renders on a theme switch); `look` has no light/dark
|
|
222
|
+
counterpart and lives in `options`. Mermaid silently ignores a value it does not recognise, so
|
|
223
|
+
check a diagram in a browser — a build proves nothing here.
|
|
224
|
+
- **Diagrams render per page, in the page's own colour mode** — read from `<html data-theme>` (the
|
|
225
|
+
attribute written before first paint), not from a framework hook. That is what keeps a dark-mode
|
|
226
|
+
first load from painting a light diagram and then a dark one.
|
|
227
|
+
- **Labels**: keep them quoted (`A["text"]`), use `<br/>` for a line break, and avoid a bare `#` or
|
|
228
|
+
an unescaped `&`. A syntax error shows up in the page, not in the build.
|
|
229
|
+
- A ```` ```mermaid ```` fence inside a longer fence (documenting it, as here) is *not* turned into
|
|
230
|
+
a diagram — it is text inside the outer code block.
|
|
231
|
+
|
|
232
|
+
## Preloading extensions (the `dfkExtensions` plugin)
|
|
233
|
+
|
|
234
|
+
The site declares an ordered preload list; the kit fetches the release assets at dev/build startup,
|
|
235
|
+
injects the list into every page and loads them — in order — while DuckDB initialises. Blocks can
|
|
236
|
+
then call into those extensions without declaring anything.
|
|
237
|
+
|
|
238
|
+
Three source kinds:
|
|
239
|
+
|
|
240
|
+
| Entry | Meaning |
|
|
241
|
+
| --- | --- |
|
|
242
|
+
| `'json'` | A name: `LOAD json` from the official repository. |
|
|
243
|
+
| `{name: 'h3', repository: 'community'}` | `community`, `core` or a repository URL. On wasm `INSTALL` only records *where* a later `LOAD` fetches from. |
|
|
244
|
+
| `{url: 'duckdb-extensions/x.duckdb_extension.wasm', release: {repository, asset}}` | The site serves the file itself; with `release`, the build fetches that asset from the repository's latest release (cached by sha256 in `<siteDir>/.cache/duckfn-docs-kit/`). |
|
|
245
|
+
|
|
246
|
+
Constraints that bite:
|
|
247
|
+
|
|
248
|
+
- **The file name is a contract**: the text before the first dot is the entry symbol DuckDB looks
|
|
249
|
+
up, so a release asset named `duckfn-wasm_eh.duckdb_extension.wasm` must be served as
|
|
250
|
+
`duckfn.duckdb_extension.wasm` (the `url` decides the file name).
|
|
251
|
+
- **Platforms must match**: a `wasm_eh` extension needs a runtime bundle on the `eh` platform. Pin
|
|
252
|
+
`@duckdb/duckdb-wasm` to the exact version whose bundled DuckDB is ABI-compatible with the
|
|
253
|
+
extension build.
|
|
254
|
+
- **Unsigned third-party extensions need `allowUnsignedExtensions: true`** (the WebAssembly
|
|
255
|
+
equivalent of `duckdb -unsigned`). Community extensions are signed and load without it.
|
|
256
|
+
|
|
257
|
+
## Testing the blocks (`duckfn-sql-verify`)
|
|
258
|
+
|
|
259
|
+
The kit runs every block in a **real browser**, on the same runtime the page uses, so what CI
|
|
260
|
+
checks is what a reader gets:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
duckfn-sql-verify --site . # or: npx duckfn-sql-verify --site .
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
It collects every runnable block (`docs/` plus each `i18n/<locale>/…/current/` by default), runs it
|
|
267
|
+
in DuckDB-Wasm **in a headless browser** (driven with `playwright-core`, launching your system
|
|
268
|
+
Chrome/Edge via `executablePath` — so no browser download) with the site's extension loaded, and
|
|
269
|
+
fails the process when a block does not behave as it declares. It is fully offline: the engine and
|
|
270
|
+
the extension are served from local files. Wire it into `package.json` as
|
|
271
|
+
`"test": "duckfn-sql-verify --site ."`.
|
|
272
|
+
|
|
273
|
+
- **A block that demonstrates a failure must say so**: `{"type":"duckfn","expect":"error"}`. The
|
|
274
|
+
check is two-way — a block that declares `error` and starts succeeding is reported too — and a
|
|
275
|
+
`-- error:` comment in the SQL is *not* read; only the metadata counts.
|
|
276
|
+
- Useful options: `--extension <path|url>`, `--platform eh|mvp`, `--content <dir>` (repeatable),
|
|
277
|
+
`--browser <path>` (the Chrome/Edge executable; otherwise a detected one or `DFK_BROWSER`),
|
|
278
|
+
`--timeout <ms>`, `--report <file>`, `--quiet`. It needs `playwright-core`, which the kit lists
|
|
279
|
+
as a dependency; unlike `playwright` it never downloads a browser.
|
|
280
|
+
- The default extension is the single file under `static/duckdb-extensions/`.
|
|
281
|
+
- **File-system examples stay plain code blocks.** Under DuckDB-Wasm the raw file system is not
|
|
282
|
+
POSIX-faithful: `dfn_file_exists` reads a missing file as "opened" (always `true`), writes/append
|
|
283
|
+
byte order is wrong, and there is no existence primitive in DuckDB's C API to correct it. So keep
|
|
284
|
+
any `COPY … TO` / `output_dir` / file-write demo as a non-runnable block and note the reason.
|
|
285
|
+
|
|
286
|
+
## TOC collapse control (`dfkTocToggle()`)
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
plugins: [dfkTocToggle()],
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Adds a collapse button to the desktop table of contents and remembers the choice in
|
|
293
|
+
`localStorage` (`duckfn:toc-collapsed`). Custom labels come from the plugin's `labels` option,
|
|
294
|
+
keyed by a lower-cased `html-lang` prefix (`{en: {hide, show}, 'zh-hans': {…}}`).
|
|
295
|
+
|
|
296
|
+
## Version placeholder (`remarkVersionPlaceholder`)
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
remarkPlugins: [[remarkVersionPlaceholder, {version: DUCKFN_VERSION}]],
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Replaces `{{DUCKFN_VERSION}}` inside `text`, `inlineCode` and `code` nodes, so a release updates one
|
|
303
|
+
file instead of every page. It only touches that exact placeholder — anything else is left alone.
|
|
304
|
+
|
|
305
|
+
## Home-page components
|
|
306
|
+
|
|
307
|
+
`<dfk-hero>`, `<dfk-features>`, `<dfk-next-steps>` (along with `<dfk-sql>` and `<dfk-mermaid>`,
|
|
308
|
+
which the plugins generate) are registered by the barrel import (`duckfn-docs-kit`). The home
|
|
309
|
+
components are **setter-driven and do not reflect attributes**:
|
|
310
|
+
give them named setters (`setTitle`, `setTagline`, `setFeatures`, …), not markup content. They
|
|
311
|
+
render into shadow roots, inherit `--duckfn-*` / `--ifm-*` CSS variables from the page, and are
|
|
312
|
+
safe to call before the element is connected.
|
|
313
|
+
|
|
314
|
+
## Troubleshooting
|
|
315
|
+
|
|
316
|
+
| Symptom | Likely cause |
|
|
317
|
+
| --- | --- |
|
|
318
|
+
| A code block has no Run button | Its info string is not JSON with `"type":"duckfn"`. |
|
|
319
|
+
| The block runs but nothing appears in the preview | `show: "html"` / `"iframe"` / `"svg"` without `field` on a multi-column result. |
|
|
320
|
+
| The preview tabs are labelled `Row 1`, `Row 2`, … | No `tab_name`. |
|
|
321
|
+
| Clicking Run shows an error like `Table with name … does not exist` | The block depends on something created on another page, or on a statement that is no longer the last one in its block. |
|
|
322
|
+
| `LOAD` fails with a signature error | `allowUnsignedExtensions: true` missing for a third-party asset. |
|
|
323
|
+
| A preloaded extension fails to load | The served file name's pre-dot part does not match the extension's entry symbol, or the platform does not match the runtime bundle. |
|
|
324
|
+
| Only the last of several examples shows a result | That is the contract — split the block. |
|
|
325
|
+
| A ```` ```mermaid ```` fence renders as a plain code block | `remarkMermaid` is not in the docs preset's `remarkPlugins`; and if `@docusaurus/theme-mermaid` is still installed, remove it and `markdown.mermaid`. |
|
|
326
|
+
| A diagram is blank, or shows a message instead | The mermaid source does not parse — the message carries mermaid's own error text. |
|
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# duckfn-docs-kit
|
|
2
2
|
|
|
3
3
|
Shared building blocks for [duckfn](https://github.com/shijianjs/duckfn)-family
|
|
4
|
-
DuckDB extension documentation sites: runnable SQL blocks,
|
|
5
|
-
a TOC collapse control, the home-page web components and
|
|
6
|
-
remark plugin. Each one is a self-contained entry point
|
|
7
|
-
wires into its own config — the alternative is copying
|
|
8
|
-
extension's docs site.
|
|
4
|
+
DuckDB extension documentation sites: runnable SQL blocks, mermaid diagrams,
|
|
5
|
+
extension preloading, a TOC collapse control, the home-page web components and
|
|
6
|
+
the version-placeholder remark plugin. Each one is a self-contained entry point
|
|
7
|
+
that a Docusaurus 3 site wires into its own config — the alternative is copying
|
|
8
|
+
the same glue into every extension's docs site.
|
|
9
9
|
|
|
10
10
|
Plain TypeScript over the native DOM: no React and no UI framework of its own.
|
|
11
11
|
The components are retained-mode classes — they build their DOM once, expose
|
|
@@ -22,9 +22,10 @@ npm install duckfn-docs-kit
|
|
|
22
22
|
|
|
23
23
|
| Import | Runs in | What it provides |
|
|
24
24
|
| --- | --- | --- |
|
|
25
|
-
| `duckfn-docs-kit` | browser |
|
|
25
|
+
| `duckfn-docs-kit` | browser | Custom elements (`<dfk-hero>`, `<dfk-features>`, `<dfk-next-steps>`, `<dfk-sql>`, `<dfk-mermaid>`), `registerDfkElements()` and the value types their setters accept |
|
|
26
26
|
| `duckfn-docs-kit/remark` | Node (build) | `remarkVersionPlaceholder`: replaces `{{DUCKFN_VERSION}}` inside `text` / `inlineCode` / `code` nodes |
|
|
27
27
|
| `duckfn-docs-kit/sql/remark` | Node (build) | `remarkRunnableSql`: turns fenced `sql {"type":"duckfn",…}` blocks into `<dfk-sql>` elements |
|
|
28
|
+
| `duckfn-docs-kit/mermaid/remark` | Node (build) | `remarkMermaid`: turns ```` ```mermaid ```` fences into `<dfk-mermaid>` diagrams |
|
|
28
29
|
| `duckfn-docs-kit/sql/extensions` | Node (build) | `dfkExtensions()` Docusaurus plugin: preloads a site's DuckDB extensions before the first block runs |
|
|
29
30
|
| `duckfn-docs-kit/toc-toggle/plugin` | Node (build) | `dfkTocToggle()` Docusaurus plugin: adds the TOC collapse control |
|
|
30
31
|
| `duckfn-docs-kit/toc-toggle/TocToggle` | browser | The TOC collapse class, for a site that drives it itself |
|
|
@@ -43,6 +44,7 @@ import {dfkExtensions} from 'duckfn-docs-kit/sql/extensions';
|
|
|
43
44
|
import {dfkTocToggle} from 'duckfn-docs-kit/toc-toggle/plugin';
|
|
44
45
|
import {remarkVersionPlaceholder} from 'duckfn-docs-kit/remark';
|
|
45
46
|
import {remarkRunnableSql} from 'duckfn-docs-kit/sql/remark';
|
|
47
|
+
import {remarkMermaid} from 'duckfn-docs-kit/mermaid/remark';
|
|
46
48
|
import {DUCKFN_VERSION} from './duckfn-version';
|
|
47
49
|
|
|
48
50
|
export default {
|
|
@@ -54,6 +56,8 @@ export default {
|
|
|
54
56
|
remarkPlugins: [
|
|
55
57
|
[remarkVersionPlaceholder, {version: DUCKFN_VERSION}],
|
|
56
58
|
remarkRunnableSql,
|
|
59
|
+
// ```mermaid fences become diagrams; no @docusaurus/theme-mermaid.
|
|
60
|
+
remarkMermaid,
|
|
57
61
|
],
|
|
58
62
|
},
|
|
59
63
|
},
|