duckfn-docs-kit 0.1.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 (65) hide show
  1. package/AGENTS.md +689 -0
  2. package/LICENSE +21 -0
  3. package/README.md +107 -0
  4. package/dist/dom.d.ts +69 -0
  5. package/dist/home/DfkFeatures.d.ts +20 -0
  6. package/dist/home/DfkHero.d.ts +25 -0
  7. package/dist/home/DfkNextSteps.d.ts +16 -0
  8. package/dist/home/styles.d.ts +8 -0
  9. package/dist/index.d.ts +50 -0
  10. package/dist/index.js +2 -0
  11. package/dist/register-DKLiYs-F.js +2324 -0
  12. package/dist/register.d.ts +10 -0
  13. package/dist/remark.d.ts +21 -0
  14. package/dist/remark.js +15 -0
  15. package/dist/runtimeConfig-Bokbb8VH.js +106 -0
  16. package/dist/sql/DfkSql.d.ts +7 -0
  17. package/dist/sql/PreviewTabs.d.ts +37 -0
  18. package/dist/sql/client.d.ts +1 -0
  19. package/dist/sql/client.js +4 -0
  20. package/dist/sql/editor.d.ts +16 -0
  21. package/dist/sql/extensions.d.ts +108 -0
  22. package/dist/sql/extensions.js +198 -0
  23. package/dist/sql/remark.d.ts +88 -0
  24. package/dist/sql/remark.js +69 -0
  25. package/dist/sql/renderers.d.ts +44 -0
  26. package/dist/sql/runtime.d.ts +105 -0
  27. package/dist/sql/runtimeConfig.d.ts +80 -0
  28. package/dist/sql/styles.d.ts +6 -0
  29. package/dist/toc-toggle/TocToggle.d.ts +46 -0
  30. package/dist/toc-toggle/TocToggle.js +69 -0
  31. package/dist/toc-toggle/client.d.ts +1 -0
  32. package/dist/toc-toggle/client.js +9 -0
  33. package/dist/toc-toggle/plugin.d.ts +36 -0
  34. package/dist/toc-toggle/plugin.js +13 -0
  35. package/dist/types.d.ts +42 -0
  36. package/package.json +73 -0
  37. package/src/dom.ts +109 -0
  38. package/src/home/DfkFeatures.ts +78 -0
  39. package/src/home/DfkHero.ts +128 -0
  40. package/src/home/DfkNextSteps.ts +73 -0
  41. package/src/home/home.css +520 -0
  42. package/src/home/styles.ts +28 -0
  43. package/src/index.ts +59 -0
  44. package/src/kit.css +19 -0
  45. package/src/register.ts +39 -0
  46. package/src/remark.ts +60 -0
  47. package/src/sql/DfkSql.css +226 -0
  48. package/src/sql/DfkSql.ts +620 -0
  49. package/src/sql/PreviewTabs.ts +169 -0
  50. package/src/sql/client.ts +16 -0
  51. package/src/sql/editor.ts +75 -0
  52. package/src/sql/extensions.ts +470 -0
  53. package/src/sql/remark.ts +213 -0
  54. package/src/sql/renderers.ts +916 -0
  55. package/src/sql/runtime.ts +348 -0
  56. package/src/sql/runtimeConfig.ts +249 -0
  57. package/src/sql/sql.css +397 -0
  58. package/src/sql/styles.ts +24 -0
  59. package/src/theme/tokens.css +75 -0
  60. package/src/toc-toggle/TocToggle.css +69 -0
  61. package/src/toc-toggle/TocToggle.ts +172 -0
  62. package/src/toc-toggle/client.ts +20 -0
  63. package/src/toc-toggle/plugin.ts +54 -0
  64. package/src/types.ts +47 -0
  65. package/src/vite-env.d.ts +8 -0
@@ -0,0 +1,69 @@
1
+ //#region src/sql/remark.ts
2
+ var e = "dfk-sql";
3
+ function t(e) {
4
+ if (!e) return null;
5
+ try {
6
+ let t = JSON.parse(e);
7
+ if (typeof t == "object" && t && t.type === "duckfn") return t;
8
+ } catch {}
9
+ return null;
10
+ }
11
+ function n(e) {
12
+ return Math.max(1, e.split("\n").length);
13
+ }
14
+ function r(e) {
15
+ return {
16
+ type: "mdxJsxFlowElement",
17
+ name: "div",
18
+ attributes: [{
19
+ type: "mdxJsxAttribute",
20
+ name: "className",
21
+ value: "dfk-sql-editor-skeleton"
22
+ }],
23
+ children: Array.from({ length: n(e) }, () => ({
24
+ type: "mdxJsxFlowElement",
25
+ name: "span",
26
+ attributes: [{
27
+ type: "mdxJsxAttribute",
28
+ name: "className",
29
+ value: "dfk-sql-editor-skeleton-line"
30
+ }],
31
+ children: []
32
+ }))
33
+ };
34
+ }
35
+ function i(t, n) {
36
+ let i = String(t.value ?? "");
37
+ return {
38
+ type: "mdxJsxFlowElement",
39
+ name: e,
40
+ attributes: [{
41
+ type: "mdxJsxAttribute",
42
+ name: "config",
43
+ value: JSON.stringify(n)
44
+ }, {
45
+ type: "mdxJsxAttribute",
46
+ name: "sql",
47
+ value: i
48
+ }],
49
+ children: [r(i), t]
50
+ };
51
+ }
52
+ var a = (e = {}) => (e) => {
53
+ let n = (e) => {
54
+ if (typeof e != "object" || !e) return;
55
+ let r = e;
56
+ Array.isArray(r.children) && (r.children = r.children.map((e) => {
57
+ if (typeof e != "object" || !e) return e;
58
+ let r = e;
59
+ if (r.type === "code" && r.lang === "sql") {
60
+ let e = t(r.meta);
61
+ if (e) return i(r, e);
62
+ }
63
+ return n(r), r;
64
+ }));
65
+ };
66
+ n(e);
67
+ };
68
+ //#endregion
69
+ export { e as DFK_SQL_TAG, a as remarkRunnableSql };
@@ -0,0 +1,44 @@
1
+ import type { QueryResult } from './runtime';
2
+ import type { RunnableSqlConfig } from './remark';
3
+ /**
4
+ * Result renderers, keyed by the config's `show` field.
5
+ *
6
+ * The registry is the seam later phases plug into. It ships `table` (VisActor
7
+ * VTable), a `text` fallback, the markup previews `iframe` / `html` / `svg`,
8
+ * plus the `error` view every renderer shares.
9
+ *
10
+ * Heavy dependencies (`@visactor/vtable`) load through dynamic `import()`
11
+ * inside the renderer, so a page that never runs a query never pays for them,
12
+ * and Docusaurus' Node prerender never touches them.
13
+ */
14
+ export interface RenderContext {
15
+ /** Container element in the light DOM, sized by `sql.css`. */
16
+ host: HTMLElement;
17
+ config: RunnableSqlConfig;
18
+ /** Localised strings resolved by the component (labels-by-html-lang). */
19
+ labels: Record<string, string>;
20
+ /**
21
+ * The component's fullscreen toggle, parked at the right end of the tab
22
+ * strip. `<dfk-sql>` owns the button's state and therefore the node; the
23
+ * renderer only borrows it so every result has the same chrome.
24
+ */
25
+ fullscreenButton: HTMLElement;
26
+ }
27
+ /**
28
+ * Renders `result` into `context.host`. Resolves with a disposer releasing any
29
+ * resources (table instances) the renderer created; it runs on the next render
30
+ * and when the element disconnects.
31
+ *
32
+ * Every renderer is async — the heavy ones await their dynamic `import()`, and
33
+ * the trivial ones just resolve immediately — so the caller has exactly one
34
+ * shape to handle.
35
+ */
36
+ export type Renderer = (context: RenderContext, result: QueryResult) => Promise<void | (() => void)>;
37
+ /** Shared error view: a styled block, never a thrown exception. */
38
+ export declare const errorRenderer: Renderer;
39
+ /**
40
+ * Picks the renderer for a result: the config's `show` wins, otherwise a
41
+ * single-column single-row result degrades to `text` (a bare scalar like
42
+ * `SELECT 1;` reads better as a line than as a 1×1 table), otherwise `table`.
43
+ */
44
+ export declare function rendererFor(config: RunnableSqlConfig, result: QueryResult): Renderer;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * The browser-side DuckDB-Wasm runtime: one instance per docs-site frontend
3
+ * runtime (module-level singleton), *not* persisted across page loads.
4
+ *
5
+ * Design points:
6
+ *
7
+ * - `@duckdb/duckdb-wasm` is only ever reached through a dynamic `import()`,
8
+ * so Docusaurus' Node prerender pass and the initial page load never touch
9
+ * it. The wasm binary and the worker script come from the official jsDelivr
10
+ * CDN (`getJsDelivrBundles` + `selectBundle`), which sidesteps any webpack
11
+ * `asyncWebAssembly` / worker configuration on the consuming site.
12
+ * `selectBundle` falls back to a non-`SharedArrayBuffer` bundle when the
13
+ * page is not crossOrigin-isolated (GitHub Pages), so it works everywhere.
14
+ * - `init()` is idempotent and retryable: a failed init leaves `state` at
15
+ * `'error'` and clears the memoised promise, so a later Run click can try
16
+ * again.
17
+ * - `execute()` hands the whole string to DuckDB. Multi-statement queries
18
+ * return the result of the **last** statement, which is exactly the
19
+ * documented behaviour for runnable blocks.
20
+ * - Extensions get into the shared instance two ways, both through the same
21
+ * memoised loader: the **site preload list** (the ordered `preload` array of
22
+ * the JSON `<script>` tag the build-time plugin injects, loaded right after
23
+ * `connect()` so a block can rely on the extension without naming it), and
24
+ * the **per-block `extensions` config** loaded on demand by
25
+ * {@link DuckDBRuntime.loadExtension}. Note that on WebAssembly `INSTALL` is
26
+ * a no-op (there is no persistent storage to install *into*): it only
27
+ * records where a later `LOAD` fetches a name from. A load by name fetches
28
+ * `<repository>/duckdb-wasm/<revision>/<platform>/<name>.duckdb_extension.wasm`
29
+ * and verifies the signature; a `{url}` preload fetches exactly that URL
30
+ * (which is why the URL must be absolute — the worker runs from a blob URL
31
+ * and cannot resolve relative paths). Either way, the text before the first
32
+ * dot of the file name is the entry symbol DuckDB looks up, so a release
33
+ * asset like `duckfn-wasm_eh.duckdb_extension.wasm` has to be renamed to
34
+ * `duckfn.duckdb_extension.wasm` on the way in (enforced by validation).
35
+ * - Extension names, repositories and URLs are **validated, not escaped** (see
36
+ * `sql/runtimeConfig`): `LOAD` cannot take them as parameters.
37
+ * - `allowUnsignedExtensions` is opt-in and per-instance: it is a database
38
+ * setting fixed by `open()`, so it has to be known before the first
39
+ * `connect()`. The site-wide value (from the injected config) and the first
40
+ * caller's are merged by whichever `init()` actually creates the instance.
41
+ */
42
+ export type RuntimeState = 'idle' | 'loading' | 'ready' | 'error';
43
+ /**
44
+ * Options for {@link DuckDBRuntime.init}. They are merged with the site-wide
45
+ * injected config, and only read by the caller that actually creates the
46
+ * instance: `allowUnsignedExtensions` is fixed at `open()` time and later
47
+ * callers cannot retune a database that already exists.
48
+ */
49
+ export interface RuntimeOptions {
50
+ /** Let `LOAD` accept an extension whose signature does not verify. */
51
+ allowUnsignedExtensions?: boolean;
52
+ }
53
+ /** Options for {@link DuckDBRuntime.loadExtension}. */
54
+ export interface LoadExtensionOptions {
55
+ /** `community`, `core` or a repository URL, instead of the official default. */
56
+ repository?: string;
57
+ }
58
+ /** A normalised query result: column names plus row objects keyed by them. */
59
+ export interface QueryResult {
60
+ columns: string[];
61
+ rows: Record<string, unknown>[];
62
+ /** Set when the statement failed; `columns`/`rows` are then empty. */
63
+ error?: string;
64
+ }
65
+ export declare class DuckDBRuntime {
66
+ #private;
67
+ /** The per-frontend-runtime singleton; shared by every `<dfk-sql>` block. */
68
+ static getInstance(): DuckDBRuntime;
69
+ get state(): RuntimeState;
70
+ /** The last init failure's message, for the UI to display. */
71
+ get message(): string;
72
+ /**
73
+ * Creates the database in the background (first Run click triggers it; a
74
+ * consuming site may also call it early to warm the instance). Concurrent
75
+ * callers share one promise, and it only resolves once the site's preloads
76
+ * are loaded too.
77
+ *
78
+ * Options and the injected site config are only read by the caller that
79
+ * actually creates the instance: `allowUnsignedExtensions` is fixed at
80
+ * `open()` time, and later callers cannot retune a database that already
81
+ * exists. A malformed injected config fails here, before any download.
82
+ */
83
+ init(options?: RuntimeOptions): Promise<void>;
84
+ /** Runs `sql` and resolves with the (last statement's) result. */
85
+ execute(sql: string): Promise<QueryResult>;
86
+ /**
87
+ * Loads one extension on demand — what a runnable block's `extensions`
88
+ * config ends up doing.
89
+ *
90
+ * `LOAD` is the whole mechanism on WebAssembly: it fetches the extension's
91
+ * `.duckdb_extension.wasm` and verifies the signature before loading it.
92
+ * `INSTALL … FROM` only records *where* a later `LOAD` should fetch from
93
+ * (there is no persistent storage to install into), which is also why it is
94
+ * used for a non-default `repository` instead of the global
95
+ * `SET custom_extension_repository` — the recorded source stays attached to
96
+ * this one extension.
97
+ *
98
+ * The name and repository are validated rather than escaped — `LOAD` takes
99
+ * an identifier, not a parameter, so anything that could terminate the
100
+ * statement is rejected outright. Successful loads (and in-flight ones) are
101
+ * memoised per repository + name; a **failure** is not, so a Run click can
102
+ * retry.
103
+ */
104
+ loadExtension(name: string, options?: LoadExtensionOptions): Promise<void>;
105
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * The contract between the build-time plugin (`sql/extensions`) and the
3
+ * browser runtime (`sql/runtime`).
4
+ *
5
+ * The plugin writes one JSON `<script>` tag into every page carrying the
6
+ * site's runtime configuration; the runtime reads it once, when the shared
7
+ * DuckDB instance is first created. Tag id, entry shapes and the validators
8
+ * live together in this dependency-free module so the two sides cannot drift —
9
+ * and so the browser bundle never drags in Node code (or the Node plugin the
10
+ * DOM).
11
+ *
12
+ * This module must not import anything: it is bundled into both the browser
13
+ * and the Node entry points.
14
+ */
15
+ /** Id of the JSON config `<script>` the build-time plugin injects per page. */
16
+ export declare const DFK_SQL_RUNTIME_TAG_ID = "dfk-sql-runtime";
17
+ /** A bare SQL identifier: `LOAD` / `INSTALL` cannot be parameterised, so this is the guard. */
18
+ export declare const EXTENSION_NAME_PATTERN: RegExp;
19
+ /** A repository URL with no character that could escape the SQL string literal. */
20
+ export declare const REPOSITORY_URL_PATTERN: RegExp;
21
+ /** Bare `FROM` keywords `INSTALL` accepts instead of a repository URL. */
22
+ export declare const REPOSITORY_KEYWORDS: Set<string>;
23
+ /** An extension preloaded by name, from the official repository or another one. */
24
+ export interface NamedPreloadEntry {
25
+ /** The extension name, e.g. `duckfn`. */
26
+ name: string;
27
+ /** `community`, `core` or a repository URL; omitted = the official repository. */
28
+ repository?: string;
29
+ }
30
+ /** A GitHub release asset the build-time plugin copies to `url` at build time. */
31
+ export interface PreloadReleaseSource {
32
+ /** The GitHub repository, `owner/name`. */
33
+ repository: string;
34
+ /** The asset name on that repository's latest release, e.g. `duckfn-wasm_eh.duckdb_extension.wasm`. */
35
+ asset: string;
36
+ }
37
+ /** An extension preloaded from a file, served by the site itself or remotely. */
38
+ export interface UrlPreloadEntry {
39
+ /**
40
+ * A site-relative path (`duckdb-extensions/duckfn.duckdb_extension.wasm`),
41
+ * resolved against the site's baseUrl and served from `static/`; or an
42
+ * absolute `http(s)://` URL.
43
+ *
44
+ * The base name of the last path segment — the text before its first dot —
45
+ * must be the extension name: on WebAssembly that text is what DuckDB turns
46
+ * into the `<name>_init_c_api` entry symbol, which is exactly why a release
47
+ * asset like `duckfn-wasm_eh.duckdb_extension.wasm` has to be renamed to
48
+ * `duckfn.duckdb_extension.wasm` on the way in.
49
+ */
50
+ url: string;
51
+ /** Fetch the file from the repository's latest GitHub release at build time. */
52
+ release?: PreloadReleaseSource;
53
+ }
54
+ /** One entry of the ordered site-level preload list. */
55
+ export type PreloadEntry = string | NamedPreloadEntry | UrlPreloadEntry;
56
+ /** The config the build-time plugin injects and the browser runtime reads. */
57
+ export interface SiteRuntimeConfig {
58
+ /** Let `LOAD` accept extensions without a valid signature; a site-wide opt-in. */
59
+ allowUnsignedExtensions?: boolean;
60
+ /** Ordered: every entry loads, one after another, before the instance is `ready`. */
61
+ preload: PreloadEntry[];
62
+ }
63
+ /** True for the only absolute URL form a preload may carry. */
64
+ export declare function isAbsoluteHttpUrl(value: string): boolean;
65
+ /**
66
+ * The entry-symbol base name of a served extension file: the text before the
67
+ * first dot in its last path segment. DuckDB loads a direct file by that name
68
+ * (`duckfn.duckdb_extension.wasm` -> `duckfn` -> `duckfn_init_c_api`), so a
69
+ * file still carrying a platform suffix cannot be loaded as-is.
70
+ */
71
+ export declare function extensionBaseName(url: string): string;
72
+ /**
73
+ * Validates and normalises one preload entry, dropping unknown keys and
74
+ * lower-casing repository keywords; throws with a readable message on
75
+ * anything that could not be turned into a safe `LOAD` / `INSTALL` statement
76
+ * or a static file path.
77
+ */
78
+ export declare function normalizePreloadEntry(entry: unknown): PreloadEntry;
79
+ /** Validates the injected config envelope and normalises every preload entry. */
80
+ export declare function parseSiteRuntimeConfig(value: unknown): SiteRuntimeConfig;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The one parsed stylesheet shared by every `<dfk-sql>` shadow root.
3
+ * Created lazily: `CSSStyleSheet` does not exist during Docusaurus' Node
4
+ * prerender, and only the browser ever calls this.
5
+ */
6
+ export declare function sqlStyles(): CSSStyleSheet;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Adds a collapse/expand control to the desktop table of contents.
3
+ *
4
+ * Docusaurus only has `themeConfig.docs.sidebar.hideable` for the left sidebar;
5
+ * the right-hand TOC has no such option (`themeConfig.tableOfContents` only
6
+ * accepts `minHeadingLevel` / `maxHeadingLevel`). So the button is injected here
7
+ * and the layout is switched by the `toc-collapsed` class on `<body>`. The
8
+ * matching CSS lives in `TocToggle.css`, next to this file.
9
+ *
10
+ * This is the class-ified form of the original TOC glue: the button and TOC
11
+ * references are held in fields instead of being looked up with
12
+ * `document.querySelector` on every update, and all module-level mutable state
13
+ * now lives inside {@link TocToggle}. `client.ts` next to this file is the thin
14
+ * Docusaurus glue that the `toc-toggle/plugin` entry injects into a site.
15
+ */
16
+ export interface TocToggleLabels {
17
+ hide: string;
18
+ show: string;
19
+ }
20
+ export interface TocToggleOptions {
21
+ /** Keyed by a lower-cased html-lang prefix; falls back to `en`. */
22
+ labels?: Record<string, TocToggleLabels>;
23
+ storageKey?: string;
24
+ }
25
+ export declare class TocToggle {
26
+ #private;
27
+ constructor(options?: TocToggleOptions);
28
+ /**
29
+ * Reconciles the button with the current page. The TOC is rendered by React,
30
+ * so it only exists on pages with headings and only on wide viewports; the
31
+ * button may also have been discarded by a re-render, so it is rebuilt when
32
+ * missing.
33
+ */
34
+ refresh(): void;
35
+ /**
36
+ * Reads the stored preference, applies it before React renders (so a collapsed
37
+ * TOC never flashes open) and wires up the viewport listener.
38
+ */
39
+ init(): void;
40
+ }
41
+ /**
42
+ * Builds a {@link TocToggle}. `client.ts` — the glue the `toc-toggle/plugin`
43
+ * entry injects — calls `init()` once (behind a `typeof window` guard) and
44
+ * exports `onRouteDidUpdate` bound to `refresh()`.
45
+ */
46
+ export declare function createTocToggle(options?: TocToggleOptions): TocToggle;
@@ -0,0 +1,69 @@
1
+ //#region src/toc-toggle/TocToggle.ts
2
+ var e = {
3
+ en: {
4
+ hide: "Collapse table of contents",
5
+ show: "Expand table of contents"
6
+ },
7
+ "zh-hans": {
8
+ hide: "收起目录",
9
+ show: "展开目录"
10
+ }
11
+ }, t = class {
12
+ #e;
13
+ #t;
14
+ #n = !1;
15
+ #r = null;
16
+ constructor(t = {}) {
17
+ this.#e = t.labels ?? e, this.#t = t.storageKey ?? "duckfn:toc-collapsed";
18
+ }
19
+ #i() {
20
+ let t = (document.documentElement.getAttribute("lang") ?? "en").toLowerCase();
21
+ return this.#e[t] ?? this.#e.en ?? e.en;
22
+ }
23
+ #a() {
24
+ try {
25
+ return window.localStorage.getItem(this.#t) === "true";
26
+ } catch {
27
+ return !1;
28
+ }
29
+ }
30
+ #o(e) {
31
+ try {
32
+ window.localStorage.setItem(this.#t, String(e));
33
+ } catch {}
34
+ }
35
+ #s() {
36
+ if (!this.#r) return;
37
+ let { hide: e, show: t } = this.#i(), n = this.#n ? t : e;
38
+ this.#r.setAttribute("aria-label", n), this.#r.setAttribute("title", n), this.#r.setAttribute("aria-expanded", String(!this.#n));
39
+ }
40
+ #c(e) {
41
+ e.id ||= "doc-toc";
42
+ let t = document.createElement("button");
43
+ return t.type = "button", t.className = "clean-btn toc-toggle", t.setAttribute("aria-controls", e.id), t.addEventListener("click", () => {
44
+ this.#n = !this.#n, this.#o(this.#n), this.#u();
45
+ }), t;
46
+ }
47
+ #l(e) {
48
+ document.body?.classList.toggle("toc-collapsed", e);
49
+ }
50
+ #u() {
51
+ this.#l(this.#n), this.#s();
52
+ }
53
+ refresh() {
54
+ let e = document.querySelector(".theme-doc-toc-desktop");
55
+ if (this.#r && !this.#r.isConnected && (this.#r = null), !e) {
56
+ this.#r?.remove(), this.#r = null, this.#l(!1);
57
+ return;
58
+ }
59
+ e.parentElement?.classList.add("toc-column"), this.#r || (this.#r = this.#c(e), e.parentElement?.insertBefore(this.#r, e)), this.#u();
60
+ }
61
+ init() {
62
+ this.#n = this.#a(), this.#l(this.#n), window.matchMedia("(min-width: 997px)").addEventListener("change", () => window.setTimeout(() => this.refresh(), 0));
63
+ }
64
+ };
65
+ function n(e) {
66
+ return new t(e);
67
+ }
68
+ //#endregion
69
+ export { t as TocToggle, n as createTocToggle };
@@ -0,0 +1 @@
1
+ export declare function onRouteDidUpdate(): void;
@@ -0,0 +1,9 @@
1
+ import { createTocToggle as e } from "./TocToggle.js";
2
+ //#region src/toc-toggle/client.ts
3
+ var t = e();
4
+ typeof window < "u" && t.init();
5
+ function n() {
6
+ t.refresh();
7
+ }
8
+ //#endregion
9
+ export { n as onRouteDidUpdate };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * `duckfn-docs-kit/toc-toggle/plugin` — wires the kit's TOC collapse control
3
+ * into a Docusaurus site.
4
+ *
5
+ * The button and its behaviour live in `toc-toggle/TocToggle` +
6
+ * `TocToggle.css`; what a site used to hand-write as a client module is now
7
+ * injected by this plugin, so a site's own `clientModules` only carries client
8
+ * code the site itself owns.
9
+ *
10
+ * This is Node-side build code: it must not import any browser module, and the
11
+ * browser side must not import this file (the glue it injects is
12
+ * `./client.ts`, resolved through the package exports map).
13
+ */
14
+ /**
15
+ * The slice of Docusaurus' plugin API this module touches, typed structurally
16
+ * (like `sql/extensions.ts`) so the kit keeps zero Docusaurus dependencies.
17
+ */
18
+ export interface DfkTocToggleContext {
19
+ siteDir: string;
20
+ }
21
+ export interface DfkTocTogglePlugin {
22
+ name: string;
23
+ getClientModules(): string[];
24
+ }
25
+ /** The plugin module Docusaurus calls with its `LoadContext` and options. */
26
+ export type DfkTocTogglePluginModule = (context: DfkTocToggleContext) => DfkTocTogglePlugin;
27
+ /**
28
+ * Builds the plugin. Usage in `docusaurus.config.ts`:
29
+ *
30
+ * ```ts
31
+ * import {dfkTocToggle} from 'duckfn-docs-kit/toc-toggle/plugin';
32
+ *
33
+ * plugins: [dfkTocToggle()],
34
+ * ```
35
+ */
36
+ export declare function dfkTocToggle(): DfkTocTogglePluginModule;
@@ -0,0 +1,13 @@
1
+ import { createRequire as e } from "node:module";
2
+ import t from "node:path";
3
+ //#region src/toc-toggle/plugin.ts
4
+ function n() {
5
+ return (n) => ({
6
+ name: "dfk-toc-toggle",
7
+ getClientModules() {
8
+ return [e(t.join(n.siteDir, "package.json")).resolve("duckfn-docs-kit/toc-toggle/client")];
9
+ }
10
+ });
11
+ }
12
+ //#endregion
13
+ export { n as dfkTocToggle };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Value types the home-page web components accept.
3
+ *
4
+ * Every string is already resolved for the *current* locale: a custom element
5
+ * cannot render Docusaurus' React `<Translate>`, so the docs site resolves the
6
+ * copy with the imperative `translate()` API and hands plain strings to the
7
+ * components' `set*` methods. Internal `href`s are baseUrl-resolved by the
8
+ * caller (`useBaseUrl`), because a raw `<a href>` inside a custom element gets
9
+ * no Docusaurus prefixing.
10
+ *
11
+ * Icon fields are Iconify icon *names* (e.g. `lucide:arrow-right`), rendered by
12
+ * the official `<iconify-icon>` web component, which fetches the glyph from the
13
+ * public Iconify API. This package ships no icon data of its own.
14
+ */
15
+ /** A hero call-to-action. */
16
+ export interface HeroLink {
17
+ label: string;
18
+ href: string;
19
+ }
20
+ /** The secondary hero action (the GitHub button), which also carries a glyph. */
21
+ export interface HeroAction extends HeroLink {
22
+ /** Iconify icon name, e.g. `simple-icons:github`. */
23
+ icon: string;
24
+ }
25
+ /** A shields.io-style badge in the hero row. Always an external link. */
26
+ export interface HeroBadge {
27
+ href: string;
28
+ src: string;
29
+ alt: string;
30
+ }
31
+ export interface FeatureItem {
32
+ /** Iconify icon name, e.g. `lucide:sparkles`. */
33
+ icon: string;
34
+ title: string;
35
+ details: string;
36
+ }
37
+ export interface NextStepItem {
38
+ /** Already baseUrl-resolved internal path. */
39
+ href: string;
40
+ title: string;
41
+ details: string;
42
+ }
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "duckfn-docs-kit",
3
+ "version": "0.1.0",
4
+ "description": "Shared Docusaurus building blocks (TOC toggle, home-page web components, brand tokens, remark version placeholder) for duckfn-family extension docs sites.",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "duckdb",
8
+ "duckdb-wasm",
9
+ "docusaurus",
10
+ "documentation",
11
+ "web-components",
12
+ "remark",
13
+ "sql"
14
+ ],
15
+ "homepage": "https://shijianjs.github.io/duckfn/docs/docs-kit",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/shijianjs/duckfn.git",
19
+ "directory": "duckfn-docs-kit"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/shijianjs/duckfn/issues"
23
+ },
24
+ "type": "module",
25
+ "main": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "default": "./dist/index.js"
31
+ },
32
+ "./src/*": "./src/*",
33
+ "./*": {
34
+ "types": "./dist/*.d.ts",
35
+ "default": "./dist/*.js"
36
+ }
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "src",
41
+ "AGENTS.md"
42
+ ],
43
+ "scripts": {
44
+ "build": "vite build && tsc -p tsconfig.build.json",
45
+ "typecheck": "tsc -p tsconfig.json --noEmit",
46
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
47
+ "prepack": "npm run build"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "dependencies": {
53
+ "@codemirror/commands": "^6.11.1",
54
+ "@codemirror/lang-sql": "^6.10.0",
55
+ "@codemirror/state": "^6.7.6",
56
+ "@codemirror/view": "^6.43.13",
57
+ "@duckdb/duckdb-wasm": "1.33.1-dev64.0",
58
+ "@visactor/vtable": "^1.26.8",
59
+ "codemirror": "^6.0.2",
60
+ "iconify-icon": "^3.0.3",
61
+ "sql-formatter": "^15.9.0"
62
+ },
63
+ "devDependencies": {
64
+ "@types/node": "^26.6.3",
65
+ "@types/react": "^19.3.0",
66
+ "typescript": "~7.0.2",
67
+ "unified": "^11.0.5",
68
+ "vite": "^8.3.1"
69
+ },
70
+ "engines": {
71
+ "node": ">=20.0"
72
+ }
73
+ }