@brett_lamy/docstream 1.4.0 → 1.5.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 +54 -0
- package/dist/demo/DemoViewer.d.ts +14 -0
- package/dist/demo/DemoViewer.d.ts.map +1 -1
- package/dist/demo/DemoViewer.js +50 -9
- package/dist/demo/DemoViewer.js.map +1 -1
- package/dist/demo/clipboard.d.ts +70 -0
- package/dist/demo/clipboard.d.ts.map +1 -0
- package/dist/demo/clipboard.js +187 -0
- package/dist/demo/clipboard.js.map +1 -0
- package/dist/demo/context.d.ts +6 -0
- package/dist/demo/context.d.ts.map +1 -1
- package/dist/demo/context.js +6 -0
- package/dist/demo/context.js.map +1 -1
- package/dist/demo/copy-demo.d.ts +23 -0
- package/dist/demo/copy-demo.d.ts.map +1 -0
- package/dist/demo/copy-demo.js +81 -0
- package/dist/demo/copy-demo.js.map +1 -0
- package/dist/demo/index.d.ts +8 -2
- package/dist/demo/index.d.ts.map +1 -1
- package/dist/demo/index.js +5 -2
- package/dist/demo/index.js.map +1 -1
- package/dist/demo/vfs.d.ts +51 -0
- package/dist/demo/vfs.d.ts.map +1 -0
- package/dist/demo/vfs.js +156 -0
- package/dist/demo/vfs.js.map +1 -0
- package/dist/docs/DocsRenderer.d.ts +8 -2
- package/dist/docs/DocsRenderer.d.ts.map +1 -1
- package/dist/docs/DocsRenderer.js +8 -6
- package/dist/docs/DocsRenderer.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/streamdown.d.ts +1 -1
- package/dist/streamdown.d.ts.map +1 -1
- package/dist/streamdown.js +2 -2
- package/dist/streamdown.js.map +1 -1
- package/package.json +4 -1
- package/src/demo/DemoViewer.tsx +56 -11
- package/src/demo/clipboard.ts +228 -0
- package/src/demo/context.ts +7 -0
- package/src/demo/copy-demo.tsx +102 -0
- package/src/demo/index.ts +29 -2
- package/src/demo/vfs.ts +197 -0
- package/src/docs/DocsRenderer.tsx +13 -4
- package/src/index.ts +19 -0
- package/src/streamdown.tsx +2 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { parseMarkdown } from "../gitbook/parse.js";
|
|
2
|
+
import { serializeMarkdown } from "../gitbook/serialize.js";
|
|
3
|
+
import { inlineDemoNode, toInlineFiles } from "./markdown.js";
|
|
4
|
+
import { cssToSurface } from "./surface.js";
|
|
5
|
+
export const DOCSTREAM_CLIPBOARD_TYPE = "application/x-docstream+json";
|
|
6
|
+
/** Every `{% demo %}` node in a document (inside tabs, hints, lists …), in document order. */
|
|
7
|
+
export function collectDemoNodes(doc) {
|
|
8
|
+
const out = [];
|
|
9
|
+
const walk = (value) => {
|
|
10
|
+
if (Array.isArray(value)) {
|
|
11
|
+
for (const item of value)
|
|
12
|
+
walk(item);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (!value || typeof value !== "object")
|
|
16
|
+
return;
|
|
17
|
+
const node = value;
|
|
18
|
+
if (node.type === "demo") {
|
|
19
|
+
out.push(value);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
for (const child of Object.values(value))
|
|
23
|
+
if (child && typeof child === "object")
|
|
24
|
+
walk(child);
|
|
25
|
+
};
|
|
26
|
+
walk(doc.children);
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
/** A copy of `doc` with every demo node replaced by `map(node)`. */
|
|
30
|
+
export function mapDemoNodes(doc, map) {
|
|
31
|
+
const walk = (value) => {
|
|
32
|
+
if (Array.isArray(value))
|
|
33
|
+
return value.map(walk);
|
|
34
|
+
if (!value || typeof value !== "object")
|
|
35
|
+
return value;
|
|
36
|
+
if (value.type === "demo")
|
|
37
|
+
return map(value);
|
|
38
|
+
const out = {};
|
|
39
|
+
for (const [k, v] of Object.entries(value))
|
|
40
|
+
out[k] = v && typeof v === "object" ? walk(v) : v;
|
|
41
|
+
return out;
|
|
42
|
+
};
|
|
43
|
+
return walk(doc);
|
|
44
|
+
}
|
|
45
|
+
/** A demo tag's attributes as `meta.json`-style defaults. */
|
|
46
|
+
export function demoNodeMeta(node) {
|
|
47
|
+
const meta = {};
|
|
48
|
+
if (node.title)
|
|
49
|
+
meta.title = node.title;
|
|
50
|
+
if (node.description)
|
|
51
|
+
meta.description = node.description;
|
|
52
|
+
if (node.height)
|
|
53
|
+
meta.height = /^\d+(?:\.\d+)?$/.test(node.height) ? Number(node.height) : node.height;
|
|
54
|
+
if (node.layout)
|
|
55
|
+
meta.layout = node.layout;
|
|
56
|
+
if (node.variants?.length)
|
|
57
|
+
meta.variants = node.variants.map((v) => ({ ...v }));
|
|
58
|
+
if (node.entry)
|
|
59
|
+
meta.entry = node.entry;
|
|
60
|
+
if (node.status)
|
|
61
|
+
meta.status = node.status;
|
|
62
|
+
if (node.bleed !== undefined)
|
|
63
|
+
meta.bleed = node.bleed;
|
|
64
|
+
if (node.className)
|
|
65
|
+
meta.className = node.className;
|
|
66
|
+
if (node.surface)
|
|
67
|
+
meta.surface = cssToSurface(node.surface);
|
|
68
|
+
if (node.variantsWidth)
|
|
69
|
+
meta.variantsWidth = node.variantsWidth;
|
|
70
|
+
return meta;
|
|
71
|
+
}
|
|
72
|
+
/** The clipboard representations of a document (or a selection of one). */
|
|
73
|
+
export function createDocstreamClipboard(doc, options = {}) {
|
|
74
|
+
const serialize = options.serialize ?? serializeMarkdown;
|
|
75
|
+
const files = {};
|
|
76
|
+
const meta = {};
|
|
77
|
+
const inlined = mapDemoNodes(doc, (node) => {
|
|
78
|
+
if (node.files?.length) {
|
|
79
|
+
if (node.src) {
|
|
80
|
+
files[node.src] = toInlineFiles(node.files);
|
|
81
|
+
const tagMeta = demoNodeMeta(node);
|
|
82
|
+
if (Object.keys(tagMeta).length)
|
|
83
|
+
meta[node.src] = tagMeta;
|
|
84
|
+
}
|
|
85
|
+
return node;
|
|
86
|
+
}
|
|
87
|
+
const found = node.src ? options.lookup?.(node) : undefined;
|
|
88
|
+
if (!found?.files.length)
|
|
89
|
+
return node;
|
|
90
|
+
files[node.src] = toInlineFiles(found.files);
|
|
91
|
+
const merged = { ...found.meta, ...demoNodeMeta(node) };
|
|
92
|
+
if (Object.keys(merged).length)
|
|
93
|
+
meta[node.src] = merged;
|
|
94
|
+
return inlineDemoNode(node, found.files, found.meta);
|
|
95
|
+
});
|
|
96
|
+
return {
|
|
97
|
+
payload: { kind: "docstream", version: 1, markdown: serialize(doc), files, meta },
|
|
98
|
+
text: serialize(inlined),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Parse the Markdown of a copied docstream selection (or a single demo). */
|
|
102
|
+
export function createDocstreamClipboardFromMarkdown(markdown, options = {}) {
|
|
103
|
+
const clip = createDocstreamClipboard(parseMarkdown(markdown), options);
|
|
104
|
+
// Keep the author's bytes for the exact representation.
|
|
105
|
+
return { ...clip, payload: { ...clip.payload, markdown } };
|
|
106
|
+
}
|
|
107
|
+
/** The clipboard as react-aria `DragItem`s (for `useClipboard`'s `getItems` / `useDrag`). */
|
|
108
|
+
export function docstreamClipboardItems(clip) {
|
|
109
|
+
return [
|
|
110
|
+
{
|
|
111
|
+
"text/plain": clip.text,
|
|
112
|
+
"text/markdown": clip.text,
|
|
113
|
+
[DOCSTREAM_CLIPBOARD_TYPE]: JSON.stringify(clip.payload),
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
/** Writes the representations straight onto a `DataTransfer` (a copy / cut / dragstart event's). */
|
|
118
|
+
export function writeDocstreamClipboard(data, clip) {
|
|
119
|
+
for (const [type, value] of Object.entries(docstreamClipboardItems(clip)[0]))
|
|
120
|
+
data.setData(type, value);
|
|
121
|
+
}
|
|
122
|
+
/** Validates a `DOCSTREAM_CLIPBOARD_TYPE` string. */
|
|
123
|
+
export function parseDocstreamClipboard(json) {
|
|
124
|
+
if (!json)
|
|
125
|
+
return null;
|
|
126
|
+
let raw;
|
|
127
|
+
try {
|
|
128
|
+
raw = JSON.parse(json);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
if (!raw || typeof raw !== "object")
|
|
134
|
+
return null;
|
|
135
|
+
const value = raw;
|
|
136
|
+
if (value.kind !== "docstream" || typeof value.markdown !== "string")
|
|
137
|
+
return null;
|
|
138
|
+
const files = {};
|
|
139
|
+
for (const [src, list] of Object.entries(value.files && typeof value.files === "object" ? value.files : {})) {
|
|
140
|
+
if (!Array.isArray(list))
|
|
141
|
+
continue;
|
|
142
|
+
const clean = list
|
|
143
|
+
.filter((f) => !!f && typeof f === "object" && typeof f.path === "string" && typeof f.content === "string")
|
|
144
|
+
.map((f) => ({ path: f.path, content: f.content, ...(typeof f.language === "string" && f.language ? { language: f.language } : {}) }));
|
|
145
|
+
if (clean.length)
|
|
146
|
+
files[src] = clean;
|
|
147
|
+
}
|
|
148
|
+
const meta = {};
|
|
149
|
+
for (const [src, m] of Object.entries(value.meta && typeof value.meta === "object" ? value.meta : {})) {
|
|
150
|
+
if (m && typeof m === "object")
|
|
151
|
+
meta[src] = m;
|
|
152
|
+
}
|
|
153
|
+
return { kind: "docstream", version: 1, markdown: value.markdown, files, meta };
|
|
154
|
+
}
|
|
155
|
+
function hasType(types, type) {
|
|
156
|
+
return !!types && Array.prototype.indexOf.call(types, type) >= 0;
|
|
157
|
+
}
|
|
158
|
+
/** True when a `DataTransfer` carries a docstream payload. */
|
|
159
|
+
export function hasDocstreamClipboard(data) {
|
|
160
|
+
return hasType(data?.types, DOCSTREAM_CLIPBOARD_TYPE);
|
|
161
|
+
}
|
|
162
|
+
/** The docstream payload on a paste / drop `DataTransfer`, if any. */
|
|
163
|
+
export function readDocstreamClipboard(data) {
|
|
164
|
+
if (!data || !hasDocstreamClipboard(data))
|
|
165
|
+
return null;
|
|
166
|
+
return parseDocstreamClipboard(data.getData(DOCSTREAM_CLIPBOARD_TYPE));
|
|
167
|
+
}
|
|
168
|
+
/** The docstream payload among react-aria `DropItem`s (`useClipboard`'s `onPaste`, `useDrop`). */
|
|
169
|
+
export async function readDocstreamClipboardItems(items) {
|
|
170
|
+
for (const item of items) {
|
|
171
|
+
if (item.kind === "text" && item.types?.has(DOCSTREAM_CLIPBOARD_TYPE) && item.getText) {
|
|
172
|
+
const payload = parseDocstreamClipboard(await item.getText(DOCSTREAM_CLIPBOARD_TYPE));
|
|
173
|
+
if (payload)
|
|
174
|
+
return payload;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* A payload for Markdown that arrived without one (only `text/plain` / `text/markdown`):
|
|
181
|
+
* inline-file demos give their files by `src`.
|
|
182
|
+
*/
|
|
183
|
+
export function docstreamPayloadFromMarkdown(markdown) {
|
|
184
|
+
const { payload } = createDocstreamClipboardFromMarkdown(markdown);
|
|
185
|
+
return payload;
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=clipboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/demo/clipboard.ts"],"names":[],"mappings":"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"}
|
package/dist/demo/context.d.ts
CHANGED
|
@@ -11,4 +11,10 @@ export declare function useDemoResolver(override?: DemoResolver): DemoResolver |
|
|
|
11
11
|
*/
|
|
12
12
|
export declare const DocstreamDemoRuntimeContext: import("react").Context<DemoRuntimeOptions>;
|
|
13
13
|
export declare function useDemoRuntime(override?: DemoRuntimeOptions): DemoRuntimeOptions;
|
|
14
|
+
/**
|
|
15
|
+
* Demo files held in memory by `src` (a `DemoVFS`), e.g. demos pasted from another page or
|
|
16
|
+
* editor. `DemoViewer` falls back to them when a block has no inline files; the host
|
|
17
|
+
* resolver still wins when it knows `src`. Provided by renderers' / editors' `demoVFS`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const DocstreamDemoVFSContext: import("react").Context<import("./vfs.js").DemoVFS | undefined>;
|
|
14
20
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/demo/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAE/D;;;GAGG;AACH,eAAO,MAAM,oBAAoB,mDAAqD,CAAA;AAEtF,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,GAAG,SAAS,CAGjF;AAED;;;GAGG;AACH,eAAO,MAAM,2BAA2B,6CAAwC,CAAA;AAEhF,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,kBAAkB,GAAG,kBAAkB,CAQhF"}
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/demo/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAE/D;;;GAGG;AACH,eAAO,MAAM,oBAAoB,mDAAqD,CAAA;AAEtF,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,GAAG,SAAS,CAGjF;AAED;;;GAGG;AACH,eAAO,MAAM,2BAA2B,6CAAwC,CAAA;AAEhF,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,kBAAkB,GAAG,kBAAkB,CAQhF;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,8DAAgE,CAAA"}
|
package/dist/demo/context.js
CHANGED
|
@@ -22,4 +22,10 @@ export function useDemoRuntime(override) {
|
|
|
22
22
|
: undefined,
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Demo files held in memory by `src` (a `DemoVFS`), e.g. demos pasted from another page or
|
|
27
|
+
* editor. `DemoViewer` falls back to them when a block has no inline files; the host
|
|
28
|
+
* resolver still wins when it knows `src`. Provided by renderers' / editors' `demoVFS`.
|
|
29
|
+
*/
|
|
30
|
+
export const DocstreamDemoVFSContext = createContext(undefined);
|
|
25
31
|
//# sourceMappingURL=context.js.map
|
package/dist/demo/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/demo/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAGjD;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,aAAa,CAA2B,SAAS,CAAC,CAAA;AAEtF,MAAM,UAAU,eAAe,CAAC,QAAuB;IACrD,MAAM,SAAS,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAA;IAClD,OAAO,QAAQ,IAAI,SAAS,CAAA;AAC9B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,aAAa,CAAqB,EAAE,CAAC,CAAA;AAEhF,MAAM,UAAU,cAAc,CAAC,QAA6B;IAC1D,MAAM,SAAS,GAAG,UAAU,CAAC,2BAA2B,CAAC,CAAA;IACzD,OAAO;QACL,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,SAAS,CAAC,OAAO;QAC/C,YAAY,EAAE,QAAQ,EAAE,YAAY,IAAI,SAAS,CAAC,YAAY;YAC5D,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,YAAY,EAAE,GAAG,QAAQ,EAAE,YAAY,EAAE;YAC1D,CAAC,CAAC,SAAS;KACd,CAAA;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/demo/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAGjD;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,aAAa,CAA2B,SAAS,CAAC,CAAA;AAEtF,MAAM,UAAU,eAAe,CAAC,QAAuB;IACrD,MAAM,SAAS,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAA;IAClD,OAAO,QAAQ,IAAI,SAAS,CAAA;AAC9B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,aAAa,CAAqB,EAAE,CAAC,CAAA;AAEhF,MAAM,UAAU,cAAc,CAAC,QAA6B;IAC1D,MAAM,SAAS,GAAG,UAAU,CAAC,2BAA2B,CAAC,CAAA;IACzD,OAAO;QACL,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,SAAS,CAAC,OAAO;QAC/C,YAAY,EAAE,QAAQ,EAAE,YAAY,IAAI,SAAS,CAAC,YAAY;YAC5D,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,YAAY,EAAE,GAAG,QAAQ,EAAE,YAAY,EAAE;YAC1D,CAAC,CAAC,SAAS;KACd,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,aAAa,CAAsC,SAAS,CAAC,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type DOMAttributes, type MutableRefObject } from "react";
|
|
2
|
+
import { type DocstreamClipboard } from "./clipboard.js";
|
|
3
|
+
export interface DocstreamCopy<T extends HTMLElement> {
|
|
4
|
+
ref: MutableRefObject<T | null>;
|
|
5
|
+
/** react-aria `useClipboard`'s focus handlers: Cmd/Ctrl+C on the focused element copies too. */
|
|
6
|
+
props: DOMAttributes<T>;
|
|
7
|
+
/** Copies; resolves false when there was nothing to copy. */
|
|
8
|
+
copy: () => Promise<boolean>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Copies a `DocstreamClipboard` (all three representations) from a click. Spread `props` on
|
|
12
|
+
* the triggering element (a focusable one, e.g. a `<button>`) and give it `ref`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useDocstreamCopy<T extends HTMLElement = HTMLButtonElement>(produce: () => DocstreamClipboard | null): DocstreamCopy<T>;
|
|
15
|
+
export interface CopyDemoButtonProps {
|
|
16
|
+
/** The clipboard to write, computed on click. `null` disables the copy. */
|
|
17
|
+
clipboard: () => DocstreamClipboard | null;
|
|
18
|
+
label?: string;
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
/** Icon button: copies the demo (Markdown + files + docstream payload) and swaps to a tick. */
|
|
22
|
+
export declare function CopyDemoButton({ clipboard, label, className }: CopyDemoButtonProps): import("react").JSX.Element;
|
|
23
|
+
//# sourceMappingURL=copy-demo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-demo.d.ts","sourceRoot":"","sources":["../../src/demo/copy-demo.tsx"],"names":[],"mappings":"AAMA,OAAO,EAA+B,KAAK,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,OAAO,CAAA;AAG9F,OAAO,EAA2B,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAE9E,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,WAAW;IAClD,GAAG,EAAE,gBAAgB,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;IAC/B,gGAAgG;IAChG,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;IACvB,6DAA6D;IAC7D,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;CAC7B;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,WAAW,GAAG,iBAAiB,EAAE,OAAO,EAAE,MAAM,kBAAkB,GAAG,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,CAyCtI;AAED,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,SAAS,EAAE,MAAM,kBAAkB,GAAG,IAAI,CAAA;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,KAAmB,EAAE,SAAS,EAAE,EAAE,mBAAmB,+BA2BhG"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/* "Copy demo": writes the docstream clipboard (Markdown with the demo's files inline, plus the
|
|
3
|
+
`application/x-docstream+json` payload) through react-aria's `useClipboard`, so pasting into
|
|
4
|
+
a docstream editor recreates the demo with its files. A button click has no copy event of
|
|
5
|
+
its own, so the button focuses itself and runs the browser's copy command; react-aria's
|
|
6
|
+
listener then fills the event's DataTransfer. Where that is unavailable, the Markdown is
|
|
7
|
+
copied as plain text (editors still parse its inline-file demos). */
|
|
8
|
+
import { useEffect, useRef, useState } from "react";
|
|
9
|
+
import { useClipboard } from "react-aria";
|
|
10
|
+
import { CopyIcon, copyText } from "../docs/copy.js";
|
|
11
|
+
import { docstreamClipboardItems } from "./clipboard.js";
|
|
12
|
+
/**
|
|
13
|
+
* Copies a `DocstreamClipboard` (all three representations) from a click. Spread `props` on
|
|
14
|
+
* the triggering element (a focusable one, e.g. a `<button>`) and give it `ref`.
|
|
15
|
+
*/
|
|
16
|
+
export function useDocstreamCopy(produce) {
|
|
17
|
+
const ref = useRef(null);
|
|
18
|
+
const latest = useRef(produce);
|
|
19
|
+
latest.current = produce;
|
|
20
|
+
const wrote = useRef(false);
|
|
21
|
+
const { clipboardProps } = useClipboard({
|
|
22
|
+
getItems: () => {
|
|
23
|
+
const clip = latest.current();
|
|
24
|
+
return clip ? docstreamClipboardItems(clip) : [];
|
|
25
|
+
},
|
|
26
|
+
onCopy: () => {
|
|
27
|
+
wrote.current = true;
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
const copy = async () => {
|
|
31
|
+
const clip = latest.current();
|
|
32
|
+
if (!clip)
|
|
33
|
+
return false;
|
|
34
|
+
const el = ref.current;
|
|
35
|
+
wrote.current = false;
|
|
36
|
+
if (el && typeof document !== "undefined" && typeof document.execCommand === "function") {
|
|
37
|
+
// The copy event targets the selection when there is one; clear it so it targets
|
|
38
|
+
// this (focused) element and nothing else — an editor around us — claims the event.
|
|
39
|
+
const selection = typeof window !== "undefined" ? window.getSelection() : null;
|
|
40
|
+
const ranges = [];
|
|
41
|
+
if (selection)
|
|
42
|
+
for (let i = 0; i < selection.rangeCount; i++)
|
|
43
|
+
ranges.push(selection.getRangeAt(i));
|
|
44
|
+
try {
|
|
45
|
+
if (document.activeElement !== el)
|
|
46
|
+
el.focus({ preventScroll: true });
|
|
47
|
+
selection?.removeAllRanges();
|
|
48
|
+
document.execCommand("copy");
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// fall through to the plain-text copy
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
if (selection && ranges.length && !selection.rangeCount)
|
|
55
|
+
for (const range of ranges)
|
|
56
|
+
selection.addRange(range);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (!wrote.current)
|
|
60
|
+
await copyText(clip.text);
|
|
61
|
+
return true;
|
|
62
|
+
};
|
|
63
|
+
return { ref, props: clipboardProps, copy };
|
|
64
|
+
}
|
|
65
|
+
/** Icon button: copies the demo (Markdown + files + docstream payload) and swaps to a tick. */
|
|
66
|
+
export function CopyDemoButton({ clipboard, label = "Copy demo", className }) {
|
|
67
|
+
const { ref, props, copy } = useDocstreamCopy(clipboard);
|
|
68
|
+
const [copied, setCopied] = useState(false);
|
|
69
|
+
const timer = useRef(undefined);
|
|
70
|
+
useEffect(() => () => clearTimeout(timer.current), []);
|
|
71
|
+
return (_jsx("button", { ...props, ref: ref, type: "button", className: className ? `docs-copy ${className}` : "docs-copy", onClick: () => {
|
|
72
|
+
void copy().then((ok) => {
|
|
73
|
+
if (!ok)
|
|
74
|
+
return;
|
|
75
|
+
setCopied(true);
|
|
76
|
+
clearTimeout(timer.current);
|
|
77
|
+
timer.current = setTimeout(() => setCopied(false), 1600);
|
|
78
|
+
});
|
|
79
|
+
}, "aria-label": copied ? "Copied" : label, title: copied ? "Copied" : `${label} (Markdown with its files — paste into a docstream editor)`, "data-copied": copied || undefined, "data-docstream-copy-demo": "", children: _jsx(CopyIcon, { copied: copied }) }));
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=copy-demo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-demo.js","sourceRoot":"","sources":["../../src/demo/copy-demo.tsx"],"names":[],"mappings":"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"}
|
package/dist/demo/index.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
export { DocstreamDemoContext, DocstreamDemoRuntimeContext, useDemoResolver, useDemoRuntime } from "./context.js";
|
|
2
|
-
export { DemoBlock, DemoFullscreen, DemoViewer, preloadDemos } from "./DemoViewer.js";
|
|
1
|
+
export { DocstreamDemoContext, DocstreamDemoRuntimeContext, DocstreamDemoVFSContext, useDemoResolver, useDemoRuntime } from "./context.js";
|
|
2
|
+
export { DemoBlock, DemoFullscreen, DemoViewer, peekDemoSource, prefetchDemoSources, preloadDemos } from "./DemoViewer.js";
|
|
3
|
+
export { DOCSTREAM_CLIPBOARD_TYPE, collectDemoNodes, createDocstreamClipboard, createDocstreamClipboardFromMarkdown, demoNodeMeta, docstreamClipboardItems, docstreamPayloadFromMarkdown, hasDocstreamClipboard, mapDemoNodes, parseDocstreamClipboard, readDocstreamClipboard, readDocstreamClipboardItems, writeDocstreamClipboard, } from "./clipboard.js";
|
|
4
|
+
export type { CreateDocstreamClipboardOptions, DemoSourceSnapshot, DocstreamClipboard, DocstreamClipboardItem, DocstreamClipboardPayload, DocstreamDropItem, } from "./clipboard.js";
|
|
5
|
+
export { CopyDemoButton, useDocstreamCopy } from "./copy-demo.js";
|
|
6
|
+
export type { CopyDemoButtonProps, DocstreamCopy } from "./copy-demo.js";
|
|
7
|
+
export { createDemoVFS, useDemoVFS, useDemoVFSContext, useDemoVFSEntry, useDemoVFSFiles } from "./vfs.js";
|
|
8
|
+
export type { DemoVFS, DemoVFSChange, DemoVFSEntry, DemoVFSResolverOptions } from "./vfs.js";
|
|
3
9
|
export type { DemoFullscreenProps, DemoViewerProps } from "./DemoViewer.js";
|
|
4
10
|
export { createGlobDemoResolver, demoComponentFrom, demoFromSearch, demoHref, languageForPath, sortDemoFiles, } from "./glob.js";
|
|
5
11
|
export type { GlobDemoResolverOptions } from "./glob.js";
|
package/dist/demo/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/demo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/demo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AACvI,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACvH,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,wBAAwB,EACxB,oCAAoC,EACpC,YAAY,EACZ,uBAAuB,EACvB,4BAA4B,EAC5B,qBAAqB,EACrB,YAAY,EACZ,uBAAuB,EACvB,sBAAsB,EACtB,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,aAAa,CAAA;AACpB,YAAY,EACV,+BAA+B,EAC/B,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EACtB,yBAAyB,EACzB,iBAAiB,GAClB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9D,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACrE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,iBAAiB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,OAAO,CAAA;AACtG,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,OAAO,CAAA;AACzF,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACxE,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,EACd,QAAQ,EACR,eAAe,EACf,aAAa,GACd,MAAM,QAAQ,CAAA;AACf,YAAY,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAA;AACrD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,cAAc,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC3H,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACtD,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACvF,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,SAAS,CAAA"}
|
package/dist/demo/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
export { DocstreamDemoContext, DocstreamDemoRuntimeContext, useDemoResolver, useDemoRuntime } from "./context.js";
|
|
2
|
-
export { DemoBlock, DemoFullscreen, DemoViewer, preloadDemos } from "./DemoViewer.js";
|
|
1
|
+
export { DocstreamDemoContext, DocstreamDemoRuntimeContext, DocstreamDemoVFSContext, useDemoResolver, useDemoRuntime } from "./context.js";
|
|
2
|
+
export { DemoBlock, DemoFullscreen, DemoViewer, peekDemoSource, prefetchDemoSources, preloadDemos } from "./DemoViewer.js";
|
|
3
|
+
export { DOCSTREAM_CLIPBOARD_TYPE, collectDemoNodes, createDocstreamClipboard, createDocstreamClipboardFromMarkdown, demoNodeMeta, docstreamClipboardItems, docstreamPayloadFromMarkdown, hasDocstreamClipboard, mapDemoNodes, parseDocstreamClipboard, readDocstreamClipboard, readDocstreamClipboardItems, writeDocstreamClipboard, } from "./clipboard.js";
|
|
4
|
+
export { CopyDemoButton, useDocstreamCopy } from "./copy-demo.js";
|
|
5
|
+
export { createDemoVFS, useDemoVFS, useDemoVFSContext, useDemoVFSEntry, useDemoVFSFiles } from "./vfs.js";
|
|
3
6
|
export { createGlobDemoResolver, demoComponentFrom, demoFromSearch, demoHref, languageForPath, sortDemoFiles, } from "./glob.js";
|
|
4
7
|
export { defaultDemoMarkdown, inlineDemoMarkdown, inlineDemoNode, resolveDemosToMarkdown, toInlineFiles } from "./markdown.js";
|
|
5
8
|
export { cssToSurface, surfaceToCss } from "./surface.js";
|
package/dist/demo/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/demo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/demo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AACvI,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACvH,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,wBAAwB,EACxB,oCAAoC,EACpC,YAAY,EACZ,uBAAuB,EACvB,4BAA4B,EAC5B,qBAAqB,EACrB,YAAY,EACZ,uBAAuB,EACvB,sBAAsB,EACtB,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,aAAa,CAAA;AASpB,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE9D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,iBAAiB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,OAAO,CAAA;AAGtG,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,EACd,QAAQ,EACR,eAAe,EACf,aAAa,GACd,MAAM,QAAQ,CAAA;AAEf,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,cAAc,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC3H,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { DemoFile, DemoMeta, DemoResolver, InlineDemoRuntime } from "./types.js";
|
|
2
|
+
export interface DemoVFSEntry {
|
|
3
|
+
/** Entry first (or `meta.entry`), paths relative to the demo folder. */
|
|
4
|
+
files: DemoFile[];
|
|
5
|
+
/** `meta.json`-style defaults, usually the `{% demo %}` tag's attributes. */
|
|
6
|
+
meta?: DemoMeta;
|
|
7
|
+
}
|
|
8
|
+
export interface DemoVFSChange {
|
|
9
|
+
src: string;
|
|
10
|
+
/** The new entry; `undefined` when `src` was removed. */
|
|
11
|
+
entry: DemoVFSEntry | undefined;
|
|
12
|
+
}
|
|
13
|
+
export interface DemoVFSResolverOptions {
|
|
14
|
+
/** The host resolver, consulted first. */
|
|
15
|
+
resolver?: DemoResolver;
|
|
16
|
+
/** Runs VFS files for `load(src)`. Without one, `load` rejects for VFS-only demos. */
|
|
17
|
+
runtime?: InlineDemoRuntime;
|
|
18
|
+
/** Extra npm dependencies handed to the runtime. */
|
|
19
|
+
dependencies?: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
export interface DemoVFS {
|
|
22
|
+
get(src: string): DemoVFSEntry | undefined;
|
|
23
|
+
has(src: string): boolean;
|
|
24
|
+
/** Every `src` held, in insertion order. */
|
|
25
|
+
list(): string[];
|
|
26
|
+
/** Adds or replaces `src`. A no-op (and no change event) when nothing differs. */
|
|
27
|
+
set(src: string, files: DemoFile[], meta?: DemoMeta): void;
|
|
28
|
+
delete(src: string): boolean;
|
|
29
|
+
clear(): void;
|
|
30
|
+
/** Everything held, as `{ [src]: entry }`. The object is stable until the next change. */
|
|
31
|
+
snapshot(): Readonly<Record<string, DemoVFSEntry>>;
|
|
32
|
+
/** Files only, as `{ [src]: files }` (what a host usually persists). Stable until the next change. */
|
|
33
|
+
files(): Readonly<Record<string, DemoFile[]>>;
|
|
34
|
+
subscribe(listener: (change: DemoVFSChange) => void): () => void;
|
|
35
|
+
/** This VFS as a `DemoResolver` layered over a host resolver. */
|
|
36
|
+
resolver(options?: DemoVFSResolverOptions): DemoResolver;
|
|
37
|
+
}
|
|
38
|
+
/** A new, empty (or pre-filled) demo VFS. */
|
|
39
|
+
export declare function createDemoVFS(initial?: Record<string, DemoFile[] | DemoVFSEntry>): DemoVFS;
|
|
40
|
+
/**
|
|
41
|
+
* A demo VFS owned by the calling component (created once). Pass it as `demoVFS` to several
|
|
42
|
+
* editors / renderers to share pasted demo files between them.
|
|
43
|
+
*/
|
|
44
|
+
export declare function useDemoVFS(initial?: Record<string, DemoFile[] | DemoVFSEntry>): DemoVFS;
|
|
45
|
+
/** The VFS in context (a renderer's or editor's `demoVFS`), unless `override` is given. */
|
|
46
|
+
export declare function useDemoVFSContext(override?: DemoVFS): DemoVFS | undefined;
|
|
47
|
+
/** `{ [src]: files }` of a VFS, re-rendering on change. */
|
|
48
|
+
export declare function useDemoVFSFiles(vfs: DemoVFS | undefined): Readonly<Record<string, DemoFile[]>>;
|
|
49
|
+
/** One VFS entry, re-rendering when it changes. */
|
|
50
|
+
export declare function useDemoVFSEntry(vfs: DemoVFS | undefined, src: string): DemoVFSEntry | undefined;
|
|
51
|
+
//# sourceMappingURL=vfs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vfs.d.ts","sourceRoot":"","sources":["../../src/demo/vfs.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAsB,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAEtG,MAAM,WAAW,YAAY;IAC3B,wEAAwE;IACxE,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,QAAQ,CAAA;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,yDAAyD;IACzD,KAAK,EAAE,YAAY,GAAG,SAAS,CAAA;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,sFAAsF;IACtF,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAC3B,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACtC;AAED,MAAM,WAAW,OAAO;IACtB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAA;IAC1C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;IACzB,4CAA4C;IAC5C,IAAI,IAAI,MAAM,EAAE,CAAA;IAChB,kFAAkF;IAClF,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAA;IAC1D,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;IAC5B,KAAK,IAAI,IAAI,CAAA;IACb,0FAA0F;IAC1F,QAAQ,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAA;IAClD,sGAAsG;IACtG,KAAK,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAA;IAC7C,SAAS,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,GAAG,MAAM,IAAI,CAAA;IAChE,iEAAiE;IACjE,QAAQ,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,YAAY,CAAA;CACzD;AAiBD,6CAA6C;AAC7C,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,YAAY,CAAC,GAAG,OAAO,CAyD1F;AAuCD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,YAAY,CAAC,GAAG,OAAO,CAIvF;AAED,2FAA2F;AAC3F,wBAAgB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAGzE;AAKD,2DAA2D;AAC3D,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAE9F;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAG/F"}
|
package/dist/demo/vfs.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/* The demo virtual file system: demo files held in memory by `src`, for demos no host
|
|
2
|
+
resolver knows — typically ones pasted from another docstream page or editor.
|
|
3
|
+
|
|
4
|
+
- `DemoViewer` reads it from context (`DocstreamDemoVFSContext`, or a renderer's `demoVFS`):
|
|
5
|
+
a block with no inline files whose `src` is in the VFS shows the VFS files exactly like
|
|
6
|
+
inline files (the host resolver still wins when it knows `src`; the Preview runs through
|
|
7
|
+
the `demoRuntime`, else the Code view opens with the "needs runtime" note).
|
|
8
|
+
- `vfs.resolver({ resolver, runtime })` is the same thing as a `DemoResolver`, layered over
|
|
9
|
+
a host resolver: `files` / `meta` from the host when it knows `src`, else from the VFS;
|
|
10
|
+
`load` from the host, else a component that runs the VFS files through the runtime.
|
|
11
|
+
- One VFS may be shared by several editors / renderers; `subscribe` reports changes so a
|
|
12
|
+
host can persist pasted files. */
|
|
13
|
+
import { useContext, useRef, useSyncExternalStore } from "react";
|
|
14
|
+
import { DocstreamDemoVFSContext } from "./context.js";
|
|
15
|
+
const RUNTIME_NOTE = "Live preview needs the playground runtime. The code is shown instead.";
|
|
16
|
+
function cleanFiles(files) {
|
|
17
|
+
return files
|
|
18
|
+
.filter((f) => f && typeof f.path === "string" && typeof f.content === "string")
|
|
19
|
+
.map((f) => ({ path: f.path, content: f.content, ...(f.language ? { language: f.language } : {}) }));
|
|
20
|
+
}
|
|
21
|
+
function entryFirst(files, entry) {
|
|
22
|
+
const index = entry ? files.findIndex((f) => f.path === entry) : -1;
|
|
23
|
+
return index > 0 ? [files[index], ...files.slice(0, index), ...files.slice(index + 1)] : files;
|
|
24
|
+
}
|
|
25
|
+
const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
26
|
+
/** A new, empty (or pre-filled) demo VFS. */
|
|
27
|
+
export function createDemoVFS(initial) {
|
|
28
|
+
const entries = new Map();
|
|
29
|
+
const listeners = new Set();
|
|
30
|
+
let snap = null;
|
|
31
|
+
let fileSnap = null;
|
|
32
|
+
const put = (src, files, meta) => {
|
|
33
|
+
const entry = { files: cleanFiles(files), ...(meta && Object.keys(meta).length ? { meta } : {}) };
|
|
34
|
+
const prev = entries.get(src);
|
|
35
|
+
if (prev && same(prev, entry))
|
|
36
|
+
return undefined;
|
|
37
|
+
entries.set(src, entry);
|
|
38
|
+
return entry;
|
|
39
|
+
};
|
|
40
|
+
const emit = (change) => {
|
|
41
|
+
snap = null;
|
|
42
|
+
fileSnap = null;
|
|
43
|
+
for (const listener of Array.from(listeners))
|
|
44
|
+
listener(change);
|
|
45
|
+
};
|
|
46
|
+
for (const [src, value] of Object.entries(initial ?? {})) {
|
|
47
|
+
if (Array.isArray(value))
|
|
48
|
+
put(src, value);
|
|
49
|
+
else if (value)
|
|
50
|
+
put(src, value.files, value.meta);
|
|
51
|
+
}
|
|
52
|
+
const vfs = {
|
|
53
|
+
get: (src) => entries.get(src),
|
|
54
|
+
has: (src) => entries.has(src),
|
|
55
|
+
list: () => Array.from(entries.keys()),
|
|
56
|
+
set(src, files, meta) {
|
|
57
|
+
const entry = put(src, files, meta);
|
|
58
|
+
if (entry)
|
|
59
|
+
emit({ src, entry });
|
|
60
|
+
},
|
|
61
|
+
delete(src) {
|
|
62
|
+
if (!entries.delete(src))
|
|
63
|
+
return false;
|
|
64
|
+
emit({ src, entry: undefined });
|
|
65
|
+
return true;
|
|
66
|
+
},
|
|
67
|
+
clear() {
|
|
68
|
+
for (const src of Array.from(entries.keys()))
|
|
69
|
+
vfs.delete(src);
|
|
70
|
+
},
|
|
71
|
+
snapshot() {
|
|
72
|
+
if (!snap)
|
|
73
|
+
snap = Object.fromEntries(entries);
|
|
74
|
+
return snap;
|
|
75
|
+
},
|
|
76
|
+
files() {
|
|
77
|
+
if (!fileSnap)
|
|
78
|
+
fileSnap = Object.fromEntries(Array.from(entries, ([src, e]) => [src, e.files]));
|
|
79
|
+
return fileSnap;
|
|
80
|
+
},
|
|
81
|
+
subscribe(listener) {
|
|
82
|
+
listeners.add(listener);
|
|
83
|
+
return () => {
|
|
84
|
+
listeners.delete(listener);
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
resolver: (options) => layeredResolver(vfs, options ?? {}),
|
|
88
|
+
};
|
|
89
|
+
return vfs;
|
|
90
|
+
}
|
|
91
|
+
function layeredResolver(vfs, { resolver: host, runtime, dependencies }) {
|
|
92
|
+
// Whether the host should be asked first: it lists `src`, or it can't list at all.
|
|
93
|
+
const hostFirst = (src) => !!host && (!host.list || host.list().includes(src) || !vfs.has(src));
|
|
94
|
+
const fromVfs = (src) => {
|
|
95
|
+
const entry = vfs.get(src);
|
|
96
|
+
if (!entry)
|
|
97
|
+
throw new Error(`Unknown demo: ${src}`);
|
|
98
|
+
return entry;
|
|
99
|
+
};
|
|
100
|
+
async function pick(src, viaHost, viaVfs) {
|
|
101
|
+
if (hostFirst(src)) {
|
|
102
|
+
try {
|
|
103
|
+
return await viaHost(host);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (!vfs.has(src))
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return viaVfs(fromVfs(src));
|
|
111
|
+
}
|
|
112
|
+
const layered = {
|
|
113
|
+
list: () => Array.from(new Set([...(host?.list?.() ?? []), ...vfs.list()])),
|
|
114
|
+
meta: (src) => pick(src, (h) => h.meta(src), (e) => e.meta),
|
|
115
|
+
files: (src) => pick(src, (h) => h.files(src), (e) => entryFirst(e.files, e.meta?.entry)),
|
|
116
|
+
load: (src) => pick(src, (h) => h.load(src), (e) => {
|
|
117
|
+
if (!runtime)
|
|
118
|
+
throw new Error(RUNTIME_NOTE);
|
|
119
|
+
const files = entryFirst(e.files, e.meta?.entry);
|
|
120
|
+
const title = e.meta?.title ?? (src.split("/").pop() || "Demo");
|
|
121
|
+
const VfsDemo = ({ variant }) => runtime({ src, title, files, entry: files[0]?.path ?? "index.tsx", ...(variant ? { variant } : {}), ...(dependencies ? { dependencies } : {}) });
|
|
122
|
+
VfsDemo.displayName = `VfsDemo(${src})`;
|
|
123
|
+
return VfsDemo;
|
|
124
|
+
}),
|
|
125
|
+
};
|
|
126
|
+
if (host?.href)
|
|
127
|
+
layered.href = (src, options) => (hostFirst(src) ? host.href(src, options) : undefined);
|
|
128
|
+
return layered;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* A demo VFS owned by the calling component (created once). Pass it as `demoVFS` to several
|
|
132
|
+
* editors / renderers to share pasted demo files between them.
|
|
133
|
+
*/
|
|
134
|
+
export function useDemoVFS(initial) {
|
|
135
|
+
const ref = useRef(null);
|
|
136
|
+
if (!ref.current)
|
|
137
|
+
ref.current = createDemoVFS(initial);
|
|
138
|
+
return ref.current;
|
|
139
|
+
}
|
|
140
|
+
/** The VFS in context (a renderer's or editor's `demoVFS`), unless `override` is given. */
|
|
141
|
+
export function useDemoVFSContext(override) {
|
|
142
|
+
const inherited = useContext(DocstreamDemoVFSContext);
|
|
143
|
+
return override ?? inherited;
|
|
144
|
+
}
|
|
145
|
+
const EMPTY = Object.freeze({});
|
|
146
|
+
const noop = () => () => { };
|
|
147
|
+
/** `{ [src]: files }` of a VFS, re-rendering on change. */
|
|
148
|
+
export function useDemoVFSFiles(vfs) {
|
|
149
|
+
return useSyncExternalStore(vfs ? vfs.subscribe : noop, () => (vfs ? vfs.files() : EMPTY), () => (vfs ? vfs.files() : EMPTY));
|
|
150
|
+
}
|
|
151
|
+
/** One VFS entry, re-rendering when it changes. */
|
|
152
|
+
export function useDemoVFSEntry(vfs, src) {
|
|
153
|
+
const snapshot = useSyncExternalStore(vfs ? vfs.subscribe : noop, () => vfs?.snapshot(), () => vfs?.snapshot());
|
|
154
|
+
return src ? snapshot?.[src] : undefined;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=vfs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vfs.js","sourceRoot":"","sources":["../../src/demo/vfs.ts"],"names":[],"mappings":"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"}
|