@brett_lamy/docstream 1.1.0 → 1.2.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.
- package/README.md +147 -9
- package/package.json +3 -1
- package/src/demo/DemoViewer.tsx +213 -46
- package/src/demo/context.ts +17 -1
- package/src/demo/glob.ts +12 -4
- package/src/demo/index.ts +15 -5
- package/src/demo/markdown.ts +138 -41
- package/src/demo/types.ts +46 -2
- package/src/docs/DocsRenderer.tsx +147 -34
- package/src/docs/PageActions.tsx +10 -6
- package/src/docs/controls.tsx +4 -1
- package/src/gitbook/ast.ts +63 -4
- package/src/gitbook/flatten.ts +47 -0
- package/src/gitbook/index.ts +6 -2
- package/src/gitbook/inline.ts +5 -2
- package/src/gitbook/outline.ts +45 -0
- package/src/gitbook/package-managers.ts +98 -0
- package/src/gitbook/parse.ts +179 -8
- package/src/gitbook/serialize.ts +40 -4
- package/src/index.ts +23 -1
- package/src/playground/InlineDemoPreview.tsx +77 -0
- package/src/playground/PlaygroundStreamdown.tsx +12 -2
- package/src/playground/ReactCodePreview.tsx +67 -36
- package/src/playground/filesystem.ts +83 -1
- package/src/playground/index.ts +7 -2
- package/src/streamdown.tsx +6 -2
- package/src/styles.css +117 -8
package/README.md
CHANGED
|
@@ -284,9 +284,79 @@ half-arrived tag is hidden rather than shown as text.
|
|
|
284
284
|
examples/button/sizes/
|
|
285
285
|
index.tsx ← default export: ({ variant }) => …
|
|
286
286
|
Sizes.css
|
|
287
|
-
meta.json ← { title, description, height, variants: [{ id, label }], entry, layout, bleed
|
|
287
|
+
meta.json ← { title, description, height, variants: [{ id, label }], entry, layout, bleed,
|
|
288
|
+
className, surface, status, variantsWidth }
|
|
288
289
|
```
|
|
289
290
|
|
|
291
|
+
`meta.height` is a minimum for single-file previews (in-page components may grow
|
|
292
|
+
past it) and the stage height for the multi-file viewer. `className` / `surface`
|
|
293
|
+
(a style object, CSS custom properties welcome) style the preview canvas,
|
|
294
|
+
`status` shows a small label in the header ("Live", "Needs network"), and
|
|
295
|
+
`variantsWidth` sizes the variant switch. Block-level demo roots fill the canvas
|
|
296
|
+
width; intrinsically sized ones (a button, an image) are centred.
|
|
297
|
+
|
|
298
|
+
#### Demos that carry their files (block form)
|
|
299
|
+
|
|
300
|
+
A `{% demo %}` can carry its files inline, one titled fence per file (entry
|
|
301
|
+
first, or `entry="App.tsx"`), closed by `{% enddemo %}`. A file that contains
|
|
302
|
+
fences gets a longer fence. This is what **Copy page** produces, so a copied page
|
|
303
|
+
renders back as the same page anywhere:
|
|
304
|
+
|
|
305
|
+
`````md
|
|
306
|
+
{% demo src="composer/scroll-fab" title="Scroll → FAB" height="380" variants="full:Full,compact:Compact" %}
|
|
307
|
+
```tsx title="index.tsx"
|
|
308
|
+
import { items } from "./data"
|
|
309
|
+
export default function ScrollFab({ variant }) { … }
|
|
310
|
+
```
|
|
311
|
+
```ts title="data.ts"
|
|
312
|
+
export const items = ["a", "b"]
|
|
313
|
+
```
|
|
314
|
+
````md title="README.md"
|
|
315
|
+
```sh
|
|
316
|
+
npm start
|
|
317
|
+
```
|
|
318
|
+
````
|
|
319
|
+
{% enddemo %}
|
|
320
|
+
`````
|
|
321
|
+
|
|
322
|
+
The self-closing tag (`{% demo … %}` or `{% demo … /%}`) keeps working. A tag
|
|
323
|
+
followed by a blank line and an ordinary code block (no `{% enddemo %}`) means
|
|
324
|
+
what it did before 1.2: a demo, then a code block. While streaming, a block whose
|
|
325
|
+
`{% enddemo %}` hasn't arrived is `open`: its code shows, its preview waits.
|
|
326
|
+
|
|
327
|
+
| The block has… | and there is… | Preview | Code view |
|
|
328
|
+
| --- | --- | --- | --- |
|
|
329
|
+
| `src` only | a resolver that knows `src` | the component, in-page | the resolver's files |
|
|
330
|
+
| inline files | a resolver that knows `src` (its `list()` includes it, and it loads) | the component, in-page | the resolver's files (they win) |
|
|
331
|
+
| inline files | no resolver, or one that doesn't know `src` | the files, run by the `demoRuntime` | the inline files |
|
|
332
|
+
| inline files | no runtime (e.g. the `/streamdown` entry) | a one-line note; the viewer opens on Code | the inline files |
|
|
333
|
+
| `src` only | no resolver | a placeholder chip | — |
|
|
334
|
+
|
|
335
|
+
The package root's `GitbookStreamdown` (`PlaygroundStreamdown`) runs inline demos
|
|
336
|
+
in almost-node by default. Elsewhere pass `demoRuntime`:
|
|
337
|
+
|
|
338
|
+
```tsx
|
|
339
|
+
import { createAlmostNodeDemoRuntime } from "@brett_lamy/docstream/playground"
|
|
340
|
+
|
|
341
|
+
const demoRuntime = createAlmostNodeDemoRuntime({ workspaceOptions: { basePath: "/docs" } })
|
|
342
|
+
|
|
343
|
+
<MarkdownContent markdown={page} demoResolver={demoResolver} demoRuntime={demoRuntime}
|
|
344
|
+
demoDependencies={{ "@brett_lamy/ui": "^1.2.0" }} />
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
How it runs (`createInlineDemoProject`): the files go under `/src/demo/`; a tiny
|
|
348
|
+
wrapper entry imports the entry file's default export (or first exported
|
|
349
|
+
function) and renders it with `variant` from the iframe's `?variant=` query, so
|
|
350
|
+
switching variants reloads the iframe, not Vite. An entry that mounts itself
|
|
351
|
+
(`createRoot(…)`) is used directly and gets no `variant`. npm imports: `react`
|
|
352
|
+
and `react-dom` are provided; `demoDependencies` (or a `package.json` among the
|
|
353
|
+
files) declares others. Limits: almost-node resolves bare imports from esm.sh at
|
|
354
|
+
the declared major version, so packages must work as browser ESM there; CSS
|
|
355
|
+
imported from packages may not load (import the CSS file from the demo instead,
|
|
356
|
+
or inline it); each inline demo boots its own container (the fullscreen overlay
|
|
357
|
+
boots a second one). `preloadDemos(resolver, srcs)` settles resolver demos before
|
|
358
|
+
the first render (server rendering, static export).
|
|
359
|
+
|
|
290
360
|
Tell docstream where demos live with a `DemoResolver`. With Vite, three
|
|
291
361
|
`import.meta.glob` maps are enough:
|
|
292
362
|
|
|
@@ -317,15 +387,21 @@ root and from `@brett_lamy/docstream/demo`, not from the Node-only `./vite` entr
|
|
|
317
387
|
`pageActions` renders a shadcn-style **Copy page ▾** above the content, with
|
|
318
388
|
Copy as Markdown, View as Markdown, Open in ChatGPT and Open in Claude. Pass
|
|
319
389
|
`true`, or pass options such as `{ markdownUrl, pageUrl, prompt, actions, transform }`.
|
|
320
|
-
You can also place `<DocPageActions markdown={page} />` yourself.
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
390
|
+
You can also place `<DocPageActions markdown={page} />` yourself. Copy and View
|
|
391
|
+
give **renderable docstream Markdown**: every `{% demo %}` keeps its tag (with its
|
|
392
|
+
`meta.json` defaults folded in as attributes) and gains its files inline, and
|
|
393
|
+
everything else is returned byte-for-byte, so pasting the copy into docstream
|
|
394
|
+
renders the same page — with or without the resolver. Open in ChatGPT / Claude
|
|
395
|
+
send the page URL. The same resolution is a pure helper for build-time `.md` or
|
|
396
|
+
`llms.txt` generation; the plain form is only produced when you ask for it:
|
|
324
397
|
|
|
325
398
|
```ts
|
|
326
399
|
import { resolveDemosToMarkdown } from "@brett_lamy/docstream/demo"
|
|
327
400
|
|
|
328
|
-
const md = await resolveDemosToMarkdown(page, demoResolver)
|
|
401
|
+
const md = await resolveDemosToMarkdown(page, demoResolver) // renderable (default)
|
|
402
|
+
const prompt = await resolveDemosToMarkdown(page, demoResolver, { format: "plain" })
|
|
403
|
+
// plain: "**Example — Title**" + fences per demo, commands as npm `sh` fences,
|
|
404
|
+
// titled tab sets as a heading + a bold label per tab — for LLM prompts only.
|
|
329
405
|
```
|
|
330
406
|
|
|
331
407
|
### Synced tabs (install instructions)
|
|
@@ -351,7 +427,61 @@ pnpm add @brett_lamy/docstream
|
|
|
351
427
|
{% endtabs %}
|
|
352
428
|
````
|
|
353
429
|
|
|
354
|
-
Every code block
|
|
430
|
+
Every code block has a copy button. Untitled blocks show just the code with the
|
|
431
|
+
button floating top-right; a header bar appears only when the block has a
|
|
432
|
+
`title` (file name).
|
|
433
|
+
|
|
434
|
+
### Installation sections and command boxes
|
|
435
|
+
|
|
436
|
+
`{% command %}` holds **one** npm / npx command. docstream derives the pnpm,
|
|
437
|
+
yarn and bun forms and shows them as tabs (pnpm first) with a terminal glyph and
|
|
438
|
+
a copy button; the reader's manager is synced page-wide and across visits (key
|
|
439
|
+
`pm`, shared with `{% tabs sync="pm" %}`). Derivations: `npm install|i x` → `pnpm
|
|
440
|
+
add x` / `yarn add x` / `bun add x` (`-D`, `-E`, `-O`, `-g` mapped), `npm install`
|
|
441
|
+
→ `<pm> install`, `npm uninstall x` → `<pm> remove x`, `npx x` / `npm exec x` →
|
|
442
|
+
`pnpm dlx x` / `yarn dlx x` / `bunx x`, `npm run s` → `pnpm s` / `yarn s` / `bun
|
|
443
|
+
run s`, `npm test|start` → `pnpm test` / `bun run test`, `npm create x` → `<pm>
|
|
444
|
+
create x`; other lines (comments, `cd`) are kept, `a && b` is converted per part.
|
|
445
|
+
Override a manager verbatim with `pnpm="…"`, `yarn="…"` or `bun="…"`; use another
|
|
446
|
+
sync group with `sync="…"`. Multi-line commands use the block form:
|
|
447
|
+
|
|
448
|
+
```md
|
|
449
|
+
{% command %}npm install @brett_lamy/ui{% endcommand %}
|
|
450
|
+
|
|
451
|
+
{% command bun="bun add -d vitest" %}
|
|
452
|
+
npm install -D vitest
|
|
453
|
+
npm run test -- --watch
|
|
454
|
+
{% endcommand %}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
A tab set with a `title` renders as a section: the title is a real heading
|
|
458
|
+
(`h2`, or `level="3"`/`"4"`) with an anchor id, the tab switch sits as pill tabs
|
|
459
|
+
on the right of the heading row, and the active tab's blocks follow in the page
|
|
460
|
+
flow (no card around them). `documentOutline(doc)` lists these titles with the
|
|
461
|
+
page's headings for a table of contents.
|
|
462
|
+
|
|
463
|
+
`````md
|
|
464
|
+
{% tabs title="Installation" sync="install-method" %}
|
|
465
|
+
{% tab title="npm" %}
|
|
466
|
+
{% command %}npm install @brett_lamy/ui{% endcommand %}
|
|
467
|
+
|
|
468
|
+
Import the stylesheet once at your app's entry, then the parts:
|
|
469
|
+
|
|
470
|
+
```tsx
|
|
471
|
+
import '@brett_lamy/ui/styles.css'
|
|
472
|
+
import { Composer } from '@brett_lamy/ui'
|
|
473
|
+
```
|
|
474
|
+
{% endtab %}
|
|
475
|
+
|
|
476
|
+
{% tab title="shadcn CLI" %}
|
|
477
|
+
{% command %}npx shadcn@latest add https://blamy.github.io/ui/r/composer.json{% endcommand %}
|
|
478
|
+
{% endtab %}
|
|
479
|
+
{% endtabs %}
|
|
480
|
+
`````
|
|
481
|
+
|
|
482
|
+
Both round-trip through `parseMarkdown`/`serializeMarkdown`, are kept as they are
|
|
483
|
+
by Copy page, and a half-streamed one-line `{% command %}` is held back until it
|
|
484
|
+
closes.
|
|
355
485
|
|
|
356
486
|
## Assets and OpenAPI Specs
|
|
357
487
|
|
|
@@ -378,7 +508,10 @@ You can also resolve paths yourself with `resolveAsset`.
|
|
|
378
508
|
- `createBundledSourceClient`: Imports bundled source modules in read-only production builds.
|
|
379
509
|
- `DemoViewer` / `DemoFullscreen`: The `{% demo %}` viewer, and one demo filling the viewport (for `?demo=` deep links).
|
|
380
510
|
- `createGlobDemoResolver`, `demoHref`, `demoFromSearch`: Build a `DemoResolver` from `import.meta.glob` maps; deep-link helpers.
|
|
381
|
-
- `resolveDemosToMarkdown(markdown, resolver)`:
|
|
511
|
+
- `resolveDemosToMarkdown(markdown, resolver, { format })`: Gives each `{% demo %}` its real files inline — renderable docstream by default, `format: "plain"` for LLM prompts (pure, async).
|
|
512
|
+
- `inlineDemoMarkdown(node, files, meta)`: One demo as a pasteable block-form `{% demo %}`.
|
|
513
|
+
- `preloadDemos(resolver, srcs)`: Settle resolver demos before the first render (SSR, static export).
|
|
514
|
+
- `createAlmostNodeDemoRuntime(options)` / `InlineDemoPreview` / `createInlineDemoProject(files, { entry, dependencies })` (`/playground`): Run inline demo files in almost-node.
|
|
382
515
|
- `DocPageActions`: The "Copy page ▾" menu.
|
|
383
516
|
|
|
384
517
|
### Parser and Serializer
|
|
@@ -391,6 +524,9 @@ You can also resolve paths yourself with `resolveAsset`.
|
|
|
391
524
|
- `serializeInline(nodes)`: Serializes inline nodes.
|
|
392
525
|
- `plainText(nodes)`: Extracts plain text from inline nodes.
|
|
393
526
|
- `refDefinitions(markdown)`: Reads reference-style link definitions.
|
|
527
|
+
- `packageManagerCommands(npmCommand, overrides)`: The npm / pnpm / yarn / bun forms of a command.
|
|
528
|
+
- `documentOutline(doc)` / `slugify(text)`: Headings (incl. titled tab sets) with anchor ids, for a TOC.
|
|
529
|
+
- `flattenForPlainMarkdown(doc)`: docstream-only blocks (commands, titled tabs) as plain Markdown.
|
|
394
530
|
|
|
395
531
|
### Types
|
|
396
532
|
|
|
@@ -411,7 +547,9 @@ The package CSS is intentionally token-driven. It uses normal CSS variables and
|
|
|
411
547
|
}
|
|
412
548
|
```
|
|
413
549
|
|
|
414
|
-
Import the CSS once, then set tokens globally in your app.
|
|
550
|
+
Import the CSS once, then set tokens globally in your app. The command box's
|
|
551
|
+
terminal glyph has its own tokens (`--gb-term-bg`, `--gb-term-fg`), so setting
|
|
552
|
+
panel colors to `currentColor` doesn't blank it. Components also expose stable classes such as `docs-code`, `docs-tabs`, `docs-hint`, `docs-table`, and `docs-openapi`.
|
|
415
553
|
|
|
416
554
|
Code highlighting follows the surrounding `color-scheme`: set `color-scheme: dark` on a dark page (or any dark container) and code switches to the dark palette. Each token color is a custom property (`--docs-tok-keyword`, `--docs-tok-string`, `--docs-tok-type`, `--docs-tok-function`, `--docs-tok-number`, `--docs-tok-constant`, `--docs-tok-operator`, `--docs-tok-comment`) if you want your own palette.
|
|
417
555
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brett_lamy/docstream",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "GitBook-aware readonly markdown and AI stream renderer.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
"files": [
|
|
16
16
|
"src",
|
|
17
17
|
"!src/**/*.test.ts",
|
|
18
|
+
"!src/**/*.test.tsx",
|
|
19
|
+
"!src/**/__fixtures__",
|
|
18
20
|
"README.md"
|
|
19
21
|
],
|
|
20
22
|
"sideEffects": [
|