@brett_lamy/docstream 1.0.0 → 1.1.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/README.md +102 -0
- package/package.json +5 -1
- package/src/demo/DemoViewer.tsx +705 -0
- package/src/demo/context.ts +13 -0
- package/src/demo/glob.ts +188 -0
- package/src/demo/index.ts +15 -0
- package/src/demo/markdown.ts +102 -0
- package/src/demo/types.ts +53 -0
- package/src/docs/CollapsibleCode.tsx +54 -0
- package/src/docs/DocsRenderer.tsx +147 -36
- package/src/docs/PageActions.tsx +219 -0
- package/src/docs/controls.tsx +138 -0
- package/src/docs/copy.tsx +82 -0
- package/src/docs/tabs-sync.ts +61 -0
- package/src/gitbook/ast.ts +35 -0
- package/src/gitbook/index.ts +1 -1
- package/src/gitbook/parse.ts +48 -1
- package/src/gitbook/serialize.ts +16 -1
- package/src/index.ts +35 -2
- package/src/playground/PlaygroundStreamdown.tsx +14 -3
- package/src/playground/ReactCodePreview.tsx +8 -37
- package/src/streamdown.tsx +21 -3
- package/src/styles.css +917 -1
package/README.md
CHANGED
|
@@ -255,6 +255,104 @@ const client = createBundledSourceClient({
|
|
|
255
255
|
Entries may also be lazy import functions. Keys can be `mount:path` (recommended)
|
|
256
256
|
or just `path` when names cannot collide.
|
|
257
257
|
|
|
258
|
+
### File-backed live demos
|
|
259
|
+
|
|
260
|
+
`{% demo %}` puts a live example into a page while the page stays **one Markdown
|
|
261
|
+
document**. The example is a folder of real files. The component renders in-page
|
|
262
|
+
(same React tree, lazily loaded near the viewport), and the Code view shows the
|
|
263
|
+
actual file contents.
|
|
264
|
+
|
|
265
|
+
```md
|
|
266
|
+
{% demo src="button/sizes" %}
|
|
267
|
+
|
|
268
|
+
{% demo src="blocks/inbox" title="Inbox" description="…" height="420" layout="auto" variants="full:Full,compact:Compact" viewport="tablet" %}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Only `src` (`<page>/<example>`) is required. `title`, `description`, `height`
|
|
272
|
+
and `variants` default to the folder's `meta.json`. `layout="auto"` (the default)
|
|
273
|
+
uses the **multi-file viewer** for two or more source files: Preview | Code,
|
|
274
|
+
desktop/tablet/phone widths, a draggable resize handle with a width readout,
|
|
275
|
+
variants, copy, a fullscreen overlay and an optional deep link. Code view has a
|
|
276
|
+
file tree (entry first) with a copy button per file. A single file gets the
|
|
277
|
+
**single-file card**: the preview with a collapsible code panel underneath.
|
|
278
|
+
`variant` is passed to the component as a prop. Frames are CSS size containers,
|
|
279
|
+
so a demo's `@container` queries respond to the preview width. The tag
|
|
280
|
+
round-trips through `parseMarkdown`/`serializeMarkdown`, and while streaming, a
|
|
281
|
+
half-arrived tag is hidden rather than shown as text.
|
|
282
|
+
|
|
283
|
+
```txt
|
|
284
|
+
examples/button/sizes/
|
|
285
|
+
index.tsx ← default export: ({ variant }) => …
|
|
286
|
+
Sizes.css
|
|
287
|
+
meta.json ← { title, description, height, variants: [{ id, label }], entry, layout, bleed }
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Tell docstream where demos live with a `DemoResolver`. With Vite, three
|
|
291
|
+
`import.meta.glob` maps are enough:
|
|
292
|
+
|
|
293
|
+
```tsx
|
|
294
|
+
import { MarkdownContent, createGlobDemoResolver, demoHref } from "@brett_lamy/docstream"
|
|
295
|
+
|
|
296
|
+
const demoResolver = createGlobDemoResolver({
|
|
297
|
+
root: "./examples", // ids are <page>/<example> below this prefix
|
|
298
|
+
modules: import.meta.glob("./examples/*/*/index.tsx"),
|
|
299
|
+
sources: import.meta.glob("./examples/*/*/**/*.{ts,tsx,css,json}", { query: "?raw", import: "default" }),
|
|
300
|
+
metas: import.meta.glob("./examples/*/*/meta.json", { eager: true, import: "default" }),
|
|
301
|
+
href: (src) => demoHref(src), // optional "?demo=<src>" deep link → route it to <DemoFullscreen src={src} />
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
<MarkdownContent markdown={page} demoResolver={demoResolver} pageActions />
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
`demoResolver` is accepted by `DocsRenderer`, `MarkdownContent`,
|
|
308
|
+
`GitbookStreamdown` and the playground renderer, and it's provided through
|
|
309
|
+
`DocstreamDemoContext`, so nested renderers inherit it. You can also write a
|
|
310
|
+
resolver by hand:
|
|
311
|
+
`{ list?(), meta(src), files(src), load(src), href?(src, { variant }) }`.
|
|
312
|
+
`createGlobDemoResolver` is plain TypeScript, so it's exported from the package
|
|
313
|
+
root and from `@brett_lamy/docstream/demo`, not from the Node-only `./vite` entry.
|
|
314
|
+
|
|
315
|
+
### Page actions
|
|
316
|
+
|
|
317
|
+
`pageActions` renders a shadcn-style **Copy page ▾** above the content, with
|
|
318
|
+
Copy as Markdown, View as Markdown, Open in ChatGPT and Open in Claude. Pass
|
|
319
|
+
`true`, or pass options such as `{ markdownUrl, pageUrl, prompt, actions, transform }`.
|
|
320
|
+
You can also place `<DocPageActions markdown={page} />` yourself. Copying
|
|
321
|
+
resolves every `{% demo %}` into its real files as titled fences, so the copied
|
|
322
|
+
page is self-contained. The same resolution is available as a pure helper for
|
|
323
|
+
build-time `.md` or `llms.txt` generation:
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
import { resolveDemosToMarkdown } from "@brett_lamy/docstream/demo"
|
|
327
|
+
|
|
328
|
+
const md = await resolveDemosToMarkdown(page, demoResolver)
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Synced tabs (install instructions)
|
|
332
|
+
|
|
333
|
+
When every tab in a tab set is a single code block, the tabs render as one code
|
|
334
|
+
block, with pill tabs, a terminal glyph for shell code, and a copy button in its
|
|
335
|
+
header. Add `sync="<key>"` and every tab set with the same key follows the
|
|
336
|
+
reader's choice. The choice is matched by tab title and is remembered in
|
|
337
|
+
`localStorage` across the page and across visits:
|
|
338
|
+
|
|
339
|
+
````md
|
|
340
|
+
{% tabs sync="pm" %}
|
|
341
|
+
{% tab title="npm" %}
|
|
342
|
+
```sh
|
|
343
|
+
npm install @brett_lamy/docstream
|
|
344
|
+
```
|
|
345
|
+
{% endtab %}
|
|
346
|
+
{% tab title="pnpm" %}
|
|
347
|
+
```sh
|
|
348
|
+
pnpm add @brett_lamy/docstream
|
|
349
|
+
```
|
|
350
|
+
{% endtab %}
|
|
351
|
+
{% endtabs %}
|
|
352
|
+
````
|
|
353
|
+
|
|
354
|
+
Every code block now also has a copy button.
|
|
355
|
+
|
|
258
356
|
## Assets and OpenAPI Specs
|
|
259
357
|
|
|
260
358
|
Relative image and OpenAPI spec paths can be resolved against an asset base:
|
|
@@ -278,6 +376,10 @@ You can also resolve paths yourself with `resolveAsset`.
|
|
|
278
376
|
- `SourcePreview`: Imports and renders a mounted component or CSF story export.
|
|
279
377
|
- `createViteSourceClient`: Reads, writes, and imports files exposed by the Vite plugin.
|
|
280
378
|
- `createBundledSourceClient`: Imports bundled source modules in read-only production builds.
|
|
379
|
+
- `DemoViewer` / `DemoFullscreen`: The `{% demo %}` viewer, and one demo filling the viewport (for `?demo=` deep links).
|
|
380
|
+
- `createGlobDemoResolver`, `demoHref`, `demoFromSearch`: Build a `DemoResolver` from `import.meta.glob` maps; deep-link helpers.
|
|
381
|
+
- `resolveDemosToMarkdown(markdown, resolver)`: Inlines each `{% demo %}` as its real files (pure, async).
|
|
382
|
+
- `DocPageActions`: The "Copy page ▾" menu.
|
|
281
383
|
|
|
282
384
|
### Parser and Serializer
|
|
283
385
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brett_lamy/docstream",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "GitBook-aware readonly markdown and AI stream renderer.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -65,6 +65,10 @@
|
|
|
65
65
|
"types": "./src/source/index.ts",
|
|
66
66
|
"import": "./src/source/index.ts"
|
|
67
67
|
},
|
|
68
|
+
"./demo": {
|
|
69
|
+
"types": "./src/demo/index.ts",
|
|
70
|
+
"import": "./src/demo/index.ts"
|
|
71
|
+
},
|
|
68
72
|
"./vite": {
|
|
69
73
|
"types": "./src/vite/index.ts",
|
|
70
74
|
"import": "./src/vite/index.ts"
|