@mui/internal-docs-infra 0.12.1-canary.2 → 0.12.1-canary.21
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/ChunkProvider/PreloadProvider.mjs +1 -2
- package/ChunkProvider/usePreload.d.mts +1 -1
- package/ChunkProvider/usePreload.mjs +0 -1
- package/CodeControllerContext/CodeControllerContext.d.mts +45 -10
- package/CodeControllerContext/CodeControllerContext.mjs +15 -1
- package/CodeHighlighter/CodeHighlighterClient.d.mts +3 -2
- package/CodeHighlighter/CodeHighlighterClient.mjs +113 -18
- package/CodeHighlighter/CodeHighlighterContext.d.mts +9 -3
- package/CodeHighlighter/buildStringFallback.d.mts +1 -1
- package/CodeHighlighter/codeToFallbackProps.d.mts +1 -1
- package/CodeHighlighter/createClientProps.mjs +3 -0
- package/CodeHighlighter/fallbackCompression.d.mts +1 -1
- package/CodeHighlighter/parseControlledCode.d.mts +13 -4
- package/CodeHighlighter/parseControlledCode.mjs +41 -49
- package/CodeHighlighter/types.d.mts +21 -0
- package/CodeHighlighter/useGrammarsReady.mjs +44 -9
- package/CodeProvider/CodeProvider.d.mts +1 -1
- package/CodeProvider/CodeProviderLazy.d.mts +1 -1
- package/CodeProvider/createParseSourceWorkerClient.d.mts +6 -0
- package/CodeProvider/createParseSourceWorkerClient.mjs +83 -15
- package/CodeProvider/useCodeProviderValue.mjs +50 -4
- package/abstractCreateDemo/abstractCreateDemo.d.mts +15 -1
- package/abstractCreateDemo/abstractCreateDemo.mjs +8 -0
- package/abstractCreateDemoClient/abstractCreateDemoClient.mjs +4 -0
- package/abstractCreateTypes/abstractCreateTypes.d.mts +12 -1
- package/abstractCreateTypes/abstractCreateTypes.mjs +4 -0
- package/abstractCreateTypes/typesToJsx.d.mts +8 -0
- package/abstractCreateTypes/typesToJsx.mjs +2 -1
- package/cli/loadNextConfig.d.mts +9 -0
- package/cli/loadNextConfig.mjs +11 -2
- package/cli/runValidate.mjs +15 -7
- package/cli/validateWorker.d.mts +1 -0
- package/cli/validateWorker.mjs +2 -1
- package/createDemoData/createDemoData.d.mts +1 -1
- package/package.json +34 -5
- package/pipeline/cacheUtils/constants.d.mts +5 -0
- package/pipeline/cacheUtils/constants.mjs +5 -0
- package/pipeline/cacheUtils/hashCacheContent.d.mts +5 -0
- package/pipeline/cacheUtils/hashCacheContent.mjs +9 -0
- package/pipeline/cacheUtils/index.d.mts +9 -0
- package/pipeline/cacheUtils/index.mjs +7 -0
- package/pipeline/cacheUtils/loadFileCache.d.mts +13 -0
- package/pipeline/cacheUtils/loadFileCache.mjs +20 -0
- package/pipeline/cacheUtils/loadFileCacheEntry.d.mts +13 -0
- package/pipeline/cacheUtils/loadFileCacheEntry.mjs +47 -0
- package/pipeline/cacheUtils/resolveCachePath.d.mts +16 -0
- package/pipeline/cacheUtils/resolveCachePath.mjs +24 -0
- package/pipeline/cacheUtils/saveFileCache.d.mts +17 -0
- package/pipeline/cacheUtils/saveFileCache.mjs +54 -0
- package/pipeline/cacheUtils/types.d.mts +23 -0
- package/pipeline/cacheUtils/types.mjs +1 -0
- package/pipeline/cacheUtils/withFileCache.d.mts +40 -0
- package/pipeline/cacheUtils/withFileCache.mjs +81 -0
- package/pipeline/hastUtils/hastUtils.d.mts +1 -1
- package/pipeline/hastUtils/hastUtils.mjs +0 -1
- package/pipeline/loadIsomorphicCodeSource/loadIsomorphicCodeSource.d.mts +1 -1
- package/pipeline/loadIsomorphicCodeSource/loadIsomorphicCodeSource.mjs +1 -1
- package/pipeline/loadIsomorphicCodeVariant/applyCodeTransform.mjs +0 -1
- package/pipeline/loadIsomorphicCodeVariant/diffHast.d.mts +1 -1
- package/pipeline/loadIsomorphicCodeVariant/hasAllCodeVariants.d.mts +1 -1
- package/pipeline/loadIsomorphicCodeVariant/maybeCodeInitialData.d.mts +1 -1
- package/pipeline/loadPrecomputedSitemap/loadPrecomputedSitemap.d.mts +6 -0
- package/pipeline/loadPrecomputedSitemap/loadPrecomputedSitemap.mjs +2 -1
- package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.d.mts +6 -0
- package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.mjs +5 -1
- package/pipeline/loadServerCodeMeta/resolveModulePathWithFs.d.mts +1 -1
- package/pipeline/loadServerCodeMeta/resolveModulePathWithFs.mjs +0 -1
- package/pipeline/loadServerPageIndex/enrichPageIndex.d.mts +15 -0
- package/pipeline/loadServerPageIndex/enrichPageIndex.mjs +50 -0
- package/pipeline/loadServerPageIndex/extractPrefixAndTitle.d.mts +19 -0
- package/pipeline/loadServerPageIndex/extractPrefixAndTitle.mjs +80 -0
- package/pipeline/loadServerPageIndex/index.d.mts +5 -2
- package/pipeline/loadServerPageIndex/index.mjs +4 -1
- package/pipeline/loadServerPageIndex/loadServerPageIndex.d.mts +13 -22
- package/pipeline/loadServerPageIndex/loadServerPageIndex.mjs +32 -124
- package/pipeline/loadServerPageIndex/resolvePageIndexCacheKey.d.mts +13 -0
- package/pipeline/loadServerPageIndex/resolvePageIndexCacheKey.mjs +23 -0
- package/pipeline/loadServerTypes/highlightTypes.d.mts +3 -3
- package/pipeline/loadServerTypes/highlightTypesMeta.d.mts +4 -4
- package/pipeline/loadServerTypes/loadServerTypes.d.mts +2 -2
- package/pipeline/loadServerTypes/loadServerTypes.mjs +67 -7
- package/pipeline/loadServerTypesMeta/createOptimizedProgram.d.mts +2 -1
- package/pipeline/loadServerTypesMeta/formatClass.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatComponent.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatFunction.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatHook.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatRaw.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatType.d.mts +1 -1
- package/pipeline/loadServerTypesMeta/loadServerTypesMeta.d.mts +7 -7
- package/pipeline/loadServerTypesMeta/loadServerTypesMeta.mjs +1 -1
- package/pipeline/loadServerTypesMeta/processTypes.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/worker.d.mts +1 -1
- package/pipeline/loadServerTypesText/loadServerTypesText.d.mts +16 -2
- package/pipeline/loadServerTypesText/loadServerTypesText.mjs +30 -8
- package/pipeline/loadServerTypesText/normalizeTypesSourceDataForCache.d.mts +2 -0
- package/pipeline/loadServerTypesText/normalizeTypesSourceDataForCache.mjs +144 -0
- package/pipeline/loadServerTypesText/resolveTypesCacheKey.d.mts +19 -0
- package/pipeline/loadServerTypesText/resolveTypesCacheKey.mjs +29 -0
- package/pipeline/loaderUtils/parseImportsAndComments.d.mts +5 -3
- package/pipeline/loaderUtils/parseImportsAndComments.mjs +284 -40
- package/pipeline/parseCreateFactoryCall/parseCreateFactoryCall.d.mts +2 -2
- package/pipeline/parseCreateFactoryCall/parseCreateFactoryCall.mjs +2 -3
- package/pipeline/parseSource/detectFileTypes.d.mts +16 -0
- package/pipeline/parseSource/detectFileTypes.mjs +44 -0
- package/pipeline/syncPageIndex/mergeMetadataMarkdown.d.mts +25 -1
- package/pipeline/syncPageIndex/mergeMetadataMarkdown.mjs +79 -49
- package/pipeline/syncPageIndex/metadataToMarkdown.d.mts +15 -1
- package/pipeline/syncPageIndex/metadataToMarkdown.mjs +32 -10
- package/pipeline/syncPageIndex/syncPageIndex.d.mts +12 -0
- package/pipeline/syncPageIndex/syncPageIndex.mjs +154 -40
- package/pipeline/syncTypes/generateTypesMarkdown.d.mts +2 -2
- package/pipeline/syncTypes/syncTypes.d.mts +7 -0
- package/pipeline/syncTypes/syncTypes.mjs +31 -1
- package/pipeline/transformHtmlCodeBlock/transformHtmlCodeBlock.mjs +1 -1
- package/pipeline/transformMarkdownCode/transformMarkdownCode.mjs +25 -15
- package/pipeline/transformMarkdownMetadata/transformMarkdownMetadata.mjs +3 -0
- package/pipeline/transformMarkdownMetadata/types.d.mts +8 -1
- package/useCode/EditableEngine.d.mts +1 -1
- package/useCode/Pre.d.mts +9 -2
- package/useCode/Pre.mjs +4 -3
- package/useCode/TransformEngine.d.mts +1 -1
- package/useCode/useCode.d.mts +17 -1
- package/useCode/useCode.mjs +22 -1
- package/useCode/useCopyFunctionality.d.mts +2 -2
- package/useCode/useEditable.browser.mjs +0 -1
- package/useCode/useFileNavigation.d.mts +3 -0
- package/useCode/useFileNavigation.mjs +3 -1
- package/useCode/useSourceEditing.mjs +45 -10
- package/useCode/useSourceEnhancing.mjs +41 -9
- package/useCode/useTransformManagement.d.mts +2 -2
- package/useCode/useTransformManagement.mjs +19 -3
- package/useCode/useUIState.d.mts +4 -0
- package/useCode/useUIState.mjs +8 -1
- package/useCode/useVariantSelection.d.mts +1 -1
- package/useCoordinated/useCoordinated.d.mts +1 -1
- package/useCoordinated/useCoordinatedLocalStorage.d.mts +1 -1
- package/useCoordinated/useCoordinatedLocalStorage.mjs +0 -1
- package/useCoordinated/useCoordinatedPreference.d.mts +1 -1
- package/useCoordinated/useCoordinatedPreference.mjs +0 -1
- package/useCrossTabState/index.d.mts +2 -0
- package/useCrossTabState/index.mjs +2 -0
- package/useCrossTabState/useCrossTabMirror.d.mts +26 -0
- package/useCrossTabState/useCrossTabMirror.mjs +108 -0
- package/useCrossTabState/useCrossTabState.d.mts +21 -0
- package/useCrossTabState/useCrossTabState.mjs +31 -0
- package/useDemo/exportVariant.mjs +2 -4
- package/useDemo/exportVariantAsCra.d.mts +1 -1
- package/useDemo/exportVariantAsCra.mjs +0 -1
- package/useDemo/useDemo.d.mts +4 -1
- package/useDemo/useDemo.mjs +5 -0
- package/useDemoController/BuildEngine.d.mts +2 -0
- package/useDemoController/BuildEngine.mjs +10 -0
- package/useDemoController/DemoRunner.d.mts +34 -0
- package/useDemoController/DemoRunner.mjs +83 -0
- package/useDemoController/ErrorBoundary.d.mts +34 -0
- package/useDemoController/ErrorBoundary.mjs +49 -0
- package/useDemoController/Runner.d.mts +44 -0
- package/useDemoController/Runner.mjs +71 -0
- package/useDemoController/absolutizeImports.d.mts +13 -0
- package/useDemoController/absolutizeImports.mjs +73 -0
- package/useDemoController/buildScope.d.mts +48 -0
- package/useDemoController/buildScope.mjs +270 -0
- package/useDemoController/collectSources.d.mts +67 -0
- package/useDemoController/collectSources.mjs +92 -0
- package/useDemoController/compileCssModule.d.mts +64 -0
- package/useDemoController/compileCssModule.mjs +40 -0
- package/useDemoController/compileCssWithPostcss.d.mts +17 -0
- package/useDemoController/compileCssWithPostcss.mjs +89 -0
- package/useDemoController/compileModule.d.mts +14 -0
- package/useDemoController/compileModule.mjs +17 -0
- package/useDemoController/constants.d.mts +13 -0
- package/useDemoController/constants.mjs +13 -0
- package/useDemoController/createRequire.d.mts +10 -0
- package/useDemoController/createRequire.mjs +17 -0
- package/useDemoController/createTranspileWorkerClient.d.mts +27 -0
- package/useDemoController/createTranspileWorkerClient.mjs +139 -0
- package/useDemoController/cssModules.d.mts +47 -0
- package/useDemoController/currentBrowserTarget.d.mts +16 -0
- package/useDemoController/currentBrowserTarget.mjs +36 -0
- package/useDemoController/evalCode.d.mts +12 -0
- package/useDemoController/evalCode.mjs +35 -0
- package/useDemoController/generateCssModuleSource.d.mts +11 -0
- package/useDemoController/generateCssModuleSource.mjs +55 -0
- package/useDemoController/generateElement.d.mts +21 -0
- package/useDemoController/generateElement.mjs +26 -0
- package/useDemoController/hashString.d.mts +11 -0
- package/useDemoController/hashString.mjs +20 -0
- package/useDemoController/importCode.d.mts +11 -0
- package/useDemoController/importCode.mjs +15 -0
- package/useDemoController/index.d.mts +1 -0
- package/useDemoController/index.mjs +1 -0
- package/useDemoController/instantiateElement.d.mts +24 -0
- package/useDemoController/instantiateElement.mjs +57 -0
- package/useDemoController/instantiateModule.d.mts +17 -0
- package/useDemoController/instantiateModule.mjs +24 -0
- package/useDemoController/resolveCssImports.d.mts +27 -0
- package/useDemoController/resolveCssImports.mjs +79 -0
- package/useDemoController/transformCode.d.mts +14 -0
- package/useDemoController/transformCode.mjs +42 -0
- package/useDemoController/transpileClientSingleton.d.mts +10 -0
- package/useDemoController/transpileClientSingleton.mjs +83 -0
- package/useDemoController/transpileSource.d.mts +29 -0
- package/useDemoController/transpileSource.mjs +36 -0
- package/useDemoController/transpileWorker.d.mts +14 -0
- package/useDemoController/transpileWorker.mjs +41 -0
- package/useDemoController/types.d.mts +30 -0
- package/useDemoController/types.mjs +1 -0
- package/useDemoController/useDemoController.d.mts +54 -0
- package/useDemoController/useDemoController.mjs +186 -0
- package/useDemoController/useRunner.d.mts +53 -0
- package/useDemoController/useRunner.mjs +118 -0
- package/useDemoController/useVariantBuilds.d.mts +31 -0
- package/useDemoController/useVariantBuilds.mjs +188 -0
- package/useSearch/types.d.mts +1 -1
- package/useType/TypesDataProvider.d.mts +1 -1
- package/useType/TypesDataProvider.mjs +1 -2
- package/useType/useType.d.mts +1 -1
- package/useType/useTypeProp.d.mts +1 -1
- package/withDocsInfra/withDeploymentConfig.mjs +57 -0
- package/withDocsInfra/withDocsInfra.d.mts +14 -0
- package/withDocsInfra/withDocsInfra.mjs +25 -11
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { useCodeExternals } from '@mui/internal-docs-infra/CodeExternalsContext';
|
|
5
|
+
import { getTranspile } from "./transpileClientSingleton.mjs";
|
|
6
|
+
import { useVariantBuilds } from "./useVariantBuilds.mjs";
|
|
7
|
+
|
|
8
|
+
// The live runtime is loaded LAZILY in two chunks, warmed when a demo activates for
|
|
9
|
+
// editing (via `onActivate` below) or, failing that, on the first build:
|
|
10
|
+
// - `BuildEngine` — the build half (`buildScope`) + render half (`DemoRunner` + the
|
|
11
|
+
// react-runner reimplementation), bundled together (see `BuildEngine.ts`).
|
|
12
|
+
// - `compileCss` — the PostCSS toolchain, only needed for demos with CSS files.
|
|
13
|
+
// Keeping them out of the eager `useDemoController` chunk means a reader who never edits
|
|
14
|
+
// never fetches them. `DemoRunner` is lazy, so the host must render the returned
|
|
15
|
+
// `components` under a `Suspense` boundary — `CodeHighlighterClient` does, falling back to
|
|
16
|
+
// the build-time render while the chunk resolves (see the `components` return doc).
|
|
17
|
+
|
|
18
|
+
let buildEngineImport = null;
|
|
19
|
+
function preloadBuildEngine() {
|
|
20
|
+
if (!buildEngineImport) {
|
|
21
|
+
buildEngineImport = import("./BuildEngine.mjs");
|
|
22
|
+
}
|
|
23
|
+
return buildEngineImport;
|
|
24
|
+
}
|
|
25
|
+
let compileCssImport = null;
|
|
26
|
+
function preloadCompileCss() {
|
|
27
|
+
if (!compileCssImport) {
|
|
28
|
+
compileCssImport = import(/* webpackChunkName: "compileCss" */"./compileCssWithPostcss.mjs");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const DemoRunner = /*#__PURE__*/React.lazy(() => preloadBuildEngine().then(module => ({
|
|
32
|
+
default: module.DemoRunner
|
|
33
|
+
})));
|
|
34
|
+
/**
|
|
35
|
+
* Drives the live previews for a demo controller. Owns the controlled `code` state,
|
|
36
|
+
* transpiles each variant OFF the main thread (via a shared Web Worker, with a
|
|
37
|
+
* main-thread fallback) and renders the ready ones through {@link DemoRunner}, and
|
|
38
|
+
* collects the per-variant `errors` — returning exactly the `{ code, setCode,
|
|
39
|
+
* components, errors }` shape a `CodeControllerContext` provider expects, so a host
|
|
40
|
+
* wires it up in one line and reads results back through `useDemo`.
|
|
41
|
+
*
|
|
42
|
+
* Because transpilation is async, a variant joins `components` only once its build
|
|
43
|
+
* resolves; editing never blocks the UI thread, and an in-flight variant shows its
|
|
44
|
+
* fallback rather than a flash of empty preview. Keeping `code` unset until the
|
|
45
|
+
* first `setCode` lets the host serve its build-time/server render first.
|
|
46
|
+
*
|
|
47
|
+
* By default the controlled code is also mirrored across same-origin tabs of the same
|
|
48
|
+
* page (via the `crossTabSync` option), so a reader editing a demo in a Chrome split
|
|
49
|
+
* view sees it update in both panes.
|
|
50
|
+
*/
|
|
51
|
+
export function useDemoController() {
|
|
52
|
+
const [code, setControlledCode] = React.useState(null);
|
|
53
|
+
// Build errors (transpile/CSS failures) and render errors (the entry throwing) live
|
|
54
|
+
// in SEPARATE maps so they never clobber each other: a build error is owned by
|
|
55
|
+
// `useVariantBuilds` (set on failure, cleared on the next good build); a render
|
|
56
|
+
// error is owned by the live `DemoRunner` (set while it throws, cleared when it
|
|
57
|
+
// renders cleanly). A CSS-only fix doesn't re-render the entry, so the build channel
|
|
58
|
+
// must clear itself rather than wait for the runner. They are merged below.
|
|
59
|
+
const [buildErrors, setBuildErrors] = React.useState({});
|
|
60
|
+
const [renderErrors, setRenderErrors] = React.useState({});
|
|
61
|
+
const [transpile, setTranspile] = React.useState(null);
|
|
62
|
+
const externalsContext = useCodeExternals();
|
|
63
|
+
const externals = React.useMemo(() => externalsContext?.externals ?? {
|
|
64
|
+
react: React
|
|
65
|
+
}, [externalsContext]);
|
|
66
|
+
|
|
67
|
+
// Identity-stable reporters; each dedups a no-op so it doesn't churn state. The
|
|
68
|
+
// `?? null` treats "never set" (undefined) and "cleared" (null) as equal, so
|
|
69
|
+
// clearing a variant that never errored is a no-op.
|
|
70
|
+
const reportBuildError = React.useCallback((variant, message) => {
|
|
71
|
+
setBuildErrors(previous => (previous[variant] ?? null) === message ? previous : {
|
|
72
|
+
...previous,
|
|
73
|
+
[variant]: message
|
|
74
|
+
});
|
|
75
|
+
}, []);
|
|
76
|
+
const reportRenderError = React.useCallback((variant, message) => {
|
|
77
|
+
setRenderErrors(previous => (previous[variant] ?? null) === message ? previous : {
|
|
78
|
+
...previous,
|
|
79
|
+
[variant]: message
|
|
80
|
+
});
|
|
81
|
+
}, []);
|
|
82
|
+
|
|
83
|
+
// Reset (the toolbar button clears `code` to `undefined`) must also drop any stale
|
|
84
|
+
// build/render error, so a prior syntax error's overlay doesn't linger over the
|
|
85
|
+
// restored original — nothing rebuilds after a reset to clear it otherwise. Do it in
|
|
86
|
+
// the setter that performs the reset rather than reacting to the `code` change in an
|
|
87
|
+
// effect; the length guards keep each clear a no-op once its map is empty.
|
|
88
|
+
const setCode = React.useCallback(action => {
|
|
89
|
+
setControlledCode(action);
|
|
90
|
+
// Drop stale errors alongside a reset (`code` cleared to `null`).
|
|
91
|
+
if (!action) {
|
|
92
|
+
setBuildErrors({});
|
|
93
|
+
setRenderErrors({});
|
|
94
|
+
}
|
|
95
|
+
}, [setControlledCode]);
|
|
96
|
+
|
|
97
|
+
// Resolve the page-shared transpile (worker, or main-thread fallback) into state once
|
|
98
|
+
// there's code to build — a local first edit, or a cross-tab edit that arrives without
|
|
99
|
+
// this tab engaging its own editor. `onActivate` below has usually already spun the
|
|
100
|
+
// worker up (so `getTranspile()` here resolves from cache), but this covers the
|
|
101
|
+
// passive/synced tab that never activates. Client-only, so the worker is never built
|
|
102
|
+
// on the server and the controller renders with no `components` until the client takes
|
|
103
|
+
// over.
|
|
104
|
+
React.useEffect(() => {
|
|
105
|
+
if (!code || transpile) {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
let active = true;
|
|
109
|
+
getTranspile().then(resolved => {
|
|
110
|
+
if (active) {
|
|
111
|
+
setTranspile(() => resolved);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
return () => {
|
|
115
|
+
active = false;
|
|
116
|
+
};
|
|
117
|
+
}, [code, transpile]);
|
|
118
|
+
|
|
119
|
+
// Warm the lazy engine modules the moment editing ACTIVATES (before the first
|
|
120
|
+
// keystroke), all kicked off here so they download in PARALLEL rather than
|
|
121
|
+
// waterfalling one inside another. The host passes which file kinds the demo spans, so
|
|
122
|
+
// a CSS-free demo never fetches the CSS toolchain and a reader who never activates
|
|
123
|
+
// fetches nothing. (If a host doesn't call this, each still loads on the first build,
|
|
124
|
+
// just a beat later.)
|
|
125
|
+
const onActivate = React.useCallback(deps => {
|
|
126
|
+
// The build + render engine — needed for any demo.
|
|
127
|
+
preloadBuildEngine();
|
|
128
|
+
// The transpile runs in a Web Worker; `getTranspile()` spins it up, loading sucrase
|
|
129
|
+
// OFF the main thread. (A direct `import('./transpileSource')` here would instead
|
|
130
|
+
// pull sucrase INTO the main bundle, defeating the worker.)
|
|
131
|
+
if (deps.js) {
|
|
132
|
+
getTranspile();
|
|
133
|
+
}
|
|
134
|
+
// The PostCSS toolchain — only for demos with CSS.
|
|
135
|
+
if (deps.css) {
|
|
136
|
+
preloadCompileCss();
|
|
137
|
+
}
|
|
138
|
+
}, []);
|
|
139
|
+
const built = useVariantBuilds(code, transpile, externals, reportBuildError);
|
|
140
|
+
const components = React.useMemo(() => {
|
|
141
|
+
if (!code) {
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
const result = {};
|
|
145
|
+
for (const variant of Object.keys(code)) {
|
|
146
|
+
const variantBuild = built[variant];
|
|
147
|
+
if (!variantBuild) {
|
|
148
|
+
continue; // first build still in flight — no component yet
|
|
149
|
+
}
|
|
150
|
+
// Render the lazy `DemoRunner` WITHOUT a per-variant Suspense here: the boundary
|
|
151
|
+
// belongs to the HOST, which can fall back to the BUILD-TIME render while the lazy
|
|
152
|
+
// chunk resolves. A `<Suspense fallback={null}>` here paints an empty frame on a
|
|
153
|
+
// NEWLY-MOUNTED boundary — the first edit after `reset()`, where `built` was cleared
|
|
154
|
+
// so no prior live frame exists for `startTransition` to hold — flashing blank.
|
|
155
|
+
// Bubbling to the host's boundary shows the original instead.
|
|
156
|
+
result[variant] = /*#__PURE__*/React.createElement(DemoRunner, {
|
|
157
|
+
key: variant,
|
|
158
|
+
runnerCode: variantBuild.runnerCode,
|
|
159
|
+
scope: variantBuild.scope,
|
|
160
|
+
css: variantBuild.css,
|
|
161
|
+
onError: message => reportRenderError(variant, message)
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
165
|
+
}, [code, built, reportRenderError]);
|
|
166
|
+
|
|
167
|
+
// Merge the two channels: a build failure takes precedence (the preview is stale
|
|
168
|
+
// until it builds), otherwise the render error, else `null`.
|
|
169
|
+
const errors = React.useMemo(() => {
|
|
170
|
+
if (!code) {
|
|
171
|
+
return {};
|
|
172
|
+
}
|
|
173
|
+
const merged = {};
|
|
174
|
+
for (const variant of new Set([...Object.keys(buildErrors), ...Object.keys(renderErrors)])) {
|
|
175
|
+
merged[variant] = buildErrors[variant] || renderErrors[variant] || null;
|
|
176
|
+
}
|
|
177
|
+
return merged;
|
|
178
|
+
}, [code, buildErrors, renderErrors]);
|
|
179
|
+
return {
|
|
180
|
+
code,
|
|
181
|
+
setCode,
|
|
182
|
+
components,
|
|
183
|
+
errors,
|
|
184
|
+
onActivate
|
|
185
|
+
};
|
|
186
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { Scope } from "./types.mjs";
|
|
3
|
+
export interface UseRunnerOptions {
|
|
4
|
+
/** Already-transpiled entry code to evaluate + render (see {@link Runner}). */
|
|
5
|
+
transpiledCode: string;
|
|
6
|
+
/** Identifiers (and an `import` registry) exposed to the evaluated entry. */
|
|
7
|
+
scope?: Scope;
|
|
8
|
+
/**
|
|
9
|
+
* When `true`, the preview clears on error instead of keeping the last
|
|
10
|
+
* successfully-rendered element. Defaults to `false`.
|
|
11
|
+
*/
|
|
12
|
+
disableCache?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Shown when the entry throws on a render BEFORE any successful one (so there is no
|
|
15
|
+
* last-good element to keep) — typically the host's build-time render, so a broken first
|
|
16
|
+
* edit shows the original instead of blanking. Ignored once a render has succeeded (the
|
|
17
|
+
* last-good element is kept instead) and when `disableCache` is set.
|
|
18
|
+
*/
|
|
19
|
+
fallback?: React.ReactNode;
|
|
20
|
+
}
|
|
21
|
+
export interface UseRunnerResult {
|
|
22
|
+
/** The node to render — a `Runner`, the cached last-good one, the `fallback`, or `null`. */
|
|
23
|
+
element: React.ReactNode;
|
|
24
|
+
/** The current error message, or `null` when the code rendered cleanly. */
|
|
25
|
+
error: string | null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Evaluates already-transpiled entry code and returns the element to render plus
|
|
29
|
+
* the current error message. Transpilation happens upstream (off the main thread);
|
|
30
|
+
* this hook owns only the synchronous evaluate + render + error bookkeeping.
|
|
31
|
+
*
|
|
32
|
+
* Errors are reported asynchronously (after the runner renders), so the hook keeps
|
|
33
|
+
* the last successfully-rendered element on screen while `error` is set — giving a
|
|
34
|
+
* stable preview as the source is edited into and out of broken states. The error
|
|
35
|
+
* is kept across edits and cleared only once a render succeeds, so a continuously-
|
|
36
|
+
* broken edit never flashes it off and back on. Pass `disableCache` to clear the
|
|
37
|
+
* preview on error instead.
|
|
38
|
+
*
|
|
39
|
+
* The live element and the inputs it was built from live in a SINGLE state object,
|
|
40
|
+
* not two `useState` hooks. The "adjust state during render" pattern issues a
|
|
41
|
+
* render-phase update; with the inputs and element split across two hooks, React
|
|
42
|
+
* could commit the input update while dropping the element one (e.g. when a parent
|
|
43
|
+
* re-render rebases the in-progress render), stranding a stale element that the
|
|
44
|
+
* adjust never rebuilt because the inputs already matched. Keeping them together
|
|
45
|
+
* makes the update atomic: if it is dropped, the inputs revert with it and the
|
|
46
|
+
* adjust simply re-fires on the next render.
|
|
47
|
+
*/
|
|
48
|
+
export declare function useRunner({
|
|
49
|
+
transpiledCode,
|
|
50
|
+
scope,
|
|
51
|
+
disableCache,
|
|
52
|
+
fallback
|
|
53
|
+
}: UseRunnerOptions): UseRunnerResult;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Runner } from "./Runner.mjs";
|
|
5
|
+
/**
|
|
6
|
+
* Evaluates already-transpiled entry code and returns the element to render plus
|
|
7
|
+
* the current error message. Transpilation happens upstream (off the main thread);
|
|
8
|
+
* this hook owns only the synchronous evaluate + render + error bookkeeping.
|
|
9
|
+
*
|
|
10
|
+
* Errors are reported asynchronously (after the runner renders), so the hook keeps
|
|
11
|
+
* the last successfully-rendered element on screen while `error` is set — giving a
|
|
12
|
+
* stable preview as the source is edited into and out of broken states. The error
|
|
13
|
+
* is kept across edits and cleared only once a render succeeds, so a continuously-
|
|
14
|
+
* broken edit never flashes it off and back on. Pass `disableCache` to clear the
|
|
15
|
+
* preview on error instead.
|
|
16
|
+
*
|
|
17
|
+
* The live element and the inputs it was built from live in a SINGLE state object,
|
|
18
|
+
* not two `useState` hooks. The "adjust state during render" pattern issues a
|
|
19
|
+
* render-phase update; with the inputs and element split across two hooks, React
|
|
20
|
+
* could commit the input update while dropping the element one (e.g. when a parent
|
|
21
|
+
* re-render rebases the in-progress render), stranding a stale element that the
|
|
22
|
+
* adjust never rebuilt because the inputs already matched. Keeping them together
|
|
23
|
+
* makes the update atomic: if it is dropped, the inputs revert with it and the
|
|
24
|
+
* adjust simply re-fires on the next render.
|
|
25
|
+
*/
|
|
26
|
+
export function useRunner({
|
|
27
|
+
transpiledCode,
|
|
28
|
+
scope,
|
|
29
|
+
disableCache,
|
|
30
|
+
fallback
|
|
31
|
+
}) {
|
|
32
|
+
const lastGoodElementRef = React.useRef(null);
|
|
33
|
+
// When an error swaps the preview back to the cached last-good element, that
|
|
34
|
+
// element re-renders cleanly and fires `onRendered` with no error. This flag
|
|
35
|
+
// tells that one "success" NOT to clear the error the swap just set.
|
|
36
|
+
const suppressErrorClearRef = React.useRef(false);
|
|
37
|
+
// `onRendered` is baked into the `Runner` element, which is only rebuilt when the
|
|
38
|
+
// code/scope/disableCache inputs change — so a `fallback` that changes on its own
|
|
39
|
+
// (e.g. the host's build-time render updating) wouldn't reach the closure. Read it
|
|
40
|
+
// through a ref kept current in an effect so the latest `fallback` is always used.
|
|
41
|
+
const fallbackRef = React.useRef(fallback);
|
|
42
|
+
React.useEffect(() => {
|
|
43
|
+
fallbackRef.current = fallback;
|
|
44
|
+
});
|
|
45
|
+
const [state, setState] = React.useState(() => ({
|
|
46
|
+
element: createRunnerElement(transpiledCode, scope),
|
|
47
|
+
error: null,
|
|
48
|
+
transpiledCode,
|
|
49
|
+
scope,
|
|
50
|
+
disableCache
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
// Build a fresh live element whenever the inputs change, using React's supported
|
|
54
|
+
// "adjust state during render" pattern so an edit takes effect immediately. The
|
|
55
|
+
// prior error is KEPT here (not reset to null) so a continuously-broken edit
|
|
56
|
+
// doesn't flash the error off and back on; it's cleared only once a render
|
|
57
|
+
// actually succeeds (see `onRendered`).
|
|
58
|
+
if (state.transpiledCode !== transpiledCode || state.scope !== scope || state.disableCache !== disableCache) {
|
|
59
|
+
const element = createRunnerElement(transpiledCode, scope);
|
|
60
|
+
setState(previous => ({
|
|
61
|
+
element,
|
|
62
|
+
error: previous.error,
|
|
63
|
+
transpiledCode,
|
|
64
|
+
scope,
|
|
65
|
+
disableCache
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
element: state.element,
|
|
70
|
+
error: state.error
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Declared after the state above so it can reference `setState`; hoisting lets
|
|
74
|
+
// the `useState` initializer call it. The refs are only ever touched inside the
|
|
75
|
+
// async `onRendered` callback, never during render.
|
|
76
|
+
function createRunnerElement(nextCode, nextScope) {
|
|
77
|
+
const element = /*#__PURE__*/React.createElement(Runner, {
|
|
78
|
+
transpiledCode: nextCode,
|
|
79
|
+
scope: nextScope,
|
|
80
|
+
onRendered(error) {
|
|
81
|
+
if (error) {
|
|
82
|
+
// Keeping a cached element means it re-renders cleanly next and fires a
|
|
83
|
+
// no-error `onRendered`; mark that one success to be ignored so it
|
|
84
|
+
// doesn't wipe this error. Only when there actually IS a cached element
|
|
85
|
+
// to swap to — with `disableCache`, or before the first successful
|
|
86
|
+
// render, the preview falls back to `fallback`/`null` and no such
|
|
87
|
+
// re-render happens, so there is nothing to suppress (and suppressing
|
|
88
|
+
// would eat the real next success).
|
|
89
|
+
if (!disableCache && lastGoodElementRef.current !== null) {
|
|
90
|
+
suppressErrorClearRef.current = true;
|
|
91
|
+
}
|
|
92
|
+
setState(previous => ({
|
|
93
|
+
...previous,
|
|
94
|
+
// Before any successful render there is no last-good element to keep, so show the
|
|
95
|
+
// host's build-time `fallback` (the original) rather than blanking. `disableCache`
|
|
96
|
+
// opts out and clears to `null`.
|
|
97
|
+
element: disableCache ? null : lastGoodElementRef.current ?? fallbackRef.current ?? null,
|
|
98
|
+
error: error.toString()
|
|
99
|
+
}));
|
|
100
|
+
} else if (suppressErrorClearRef.current) {
|
|
101
|
+
// The cached last-good element re-rendering after an error swap — keep
|
|
102
|
+
// the error, just remember the element.
|
|
103
|
+
suppressErrorClearRef.current = false;
|
|
104
|
+
lastGoodElementRef.current = element;
|
|
105
|
+
} else {
|
|
106
|
+
// A genuine clean render of the current code — cache it and clear any
|
|
107
|
+
// prior error.
|
|
108
|
+
lastGoodElementRef.current = element;
|
|
109
|
+
setState(previous => previous.error === null ? previous : {
|
|
110
|
+
...previous,
|
|
111
|
+
error: null
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
return element;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ControlledCode } from '@mui/internal-docs-infra/CodeHighlighter/types';
|
|
2
|
+
import type { Transpile } from "./transpileSource.mjs";
|
|
3
|
+
import type { Scope } from "./types.mjs";
|
|
4
|
+
/** A variant's transpiled, ready-to-render build. */
|
|
5
|
+
export interface VariantBuild {
|
|
6
|
+
/** The transpiled entry code for the runner to evaluate. */
|
|
7
|
+
runnerCode: string;
|
|
8
|
+
/** The built module registry the entry evaluates against. */
|
|
9
|
+
scope: Scope;
|
|
10
|
+
/** Compiled stylesheet text for the variant. */
|
|
11
|
+
css: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Builds each variant's scope OFF the main thread and exposes the ready ones. A
|
|
15
|
+
* variant appears in the returned map only once its (worker) transpile resolves —
|
|
16
|
+
* so a host can leave an in-flight variant showing its fallback rather than a
|
|
17
|
+
* loading state. On edit, a variant keeps its previous build until the new one
|
|
18
|
+
* resolves (and on a transpile error too, reported via `report`), so the preview
|
|
19
|
+
* never flashes.
|
|
20
|
+
*
|
|
21
|
+
* A variant's FIRST build is never cancelled. On the first edit the controller is
|
|
22
|
+
* seeded with the ORIGINAL source and the real edit follows; if that edit arrives
|
|
23
|
+
* before the seed's build settles, it is DEFERRED (not aborted) so the baseline
|
|
24
|
+
* always builds and renders before the edit lands — giving a broken edit a good
|
|
25
|
+
* preview to fall back to. Later edits abort the in-flight build as usual.
|
|
26
|
+
*
|
|
27
|
+
* Per-variant bookkeeping (request ids, abort controllers, last-built input, the
|
|
28
|
+
* first-build-done set, and the deferred edit) lives in refs since it never
|
|
29
|
+
* affects render; only the resolved `built` map is state.
|
|
30
|
+
*/
|
|
31
|
+
export declare function useVariantBuilds(code: ControlledCode | null | undefined, transpile: Transpile | null, externals: Record<string, unknown>, report: (variant: string, message: string | null) => void): Record<string, VariantBuild>;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
|
|
5
|
+
// The build half of the runtime (`buildScope` + its scope-assembly and eval machinery)
|
|
6
|
+
// is the bulk of this engine, but it's only needed once a demo is actually EDITED —
|
|
7
|
+
// before that the host shows the build-time render. So it's loaded LAZILY on the first
|
|
8
|
+
// build, from the shared `BuildEngine` chunk it shares with the render half (`DemoRunner`,
|
|
9
|
+
// loaded by `useDemoController`) — one chunk for the whole engine. The promise is
|
|
10
|
+
// module-level, so the chunk is fetched once and every later build reuses it; readers who
|
|
11
|
+
// never edit never fetch it.
|
|
12
|
+
|
|
13
|
+
let buildEnginePromise = null;
|
|
14
|
+
function loadBuildScope() {
|
|
15
|
+
if (!buildEnginePromise) {
|
|
16
|
+
buildEnginePromise = import("./BuildEngine.mjs").then(module => module.buildScope);
|
|
17
|
+
}
|
|
18
|
+
return buildEnginePromise;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** A variant's transpiled, ready-to-render build. */
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Builds each variant's scope OFF the main thread and exposes the ready ones. A
|
|
25
|
+
* variant appears in the returned map only once its (worker) transpile resolves —
|
|
26
|
+
* so a host can leave an in-flight variant showing its fallback rather than a
|
|
27
|
+
* loading state. On edit, a variant keeps its previous build until the new one
|
|
28
|
+
* resolves (and on a transpile error too, reported via `report`), so the preview
|
|
29
|
+
* never flashes.
|
|
30
|
+
*
|
|
31
|
+
* A variant's FIRST build is never cancelled. On the first edit the controller is
|
|
32
|
+
* seeded with the ORIGINAL source and the real edit follows; if that edit arrives
|
|
33
|
+
* before the seed's build settles, it is DEFERRED (not aborted) so the baseline
|
|
34
|
+
* always builds and renders before the edit lands — giving a broken edit a good
|
|
35
|
+
* preview to fall back to. Later edits abort the in-flight build as usual.
|
|
36
|
+
*
|
|
37
|
+
* Per-variant bookkeeping (request ids, abort controllers, last-built input, the
|
|
38
|
+
* first-build-done set, and the deferred edit) lives in refs since it never
|
|
39
|
+
* affects render; only the resolved `built` map is state.
|
|
40
|
+
*/
|
|
41
|
+
export function useVariantBuilds(code, transpile, externals, report) {
|
|
42
|
+
const [built, setBuilt] = React.useState({});
|
|
43
|
+
|
|
44
|
+
// Per-variant async bookkeeping (render-irrelevant → refs, not state).
|
|
45
|
+
const requestIds = React.useRef(new Map());
|
|
46
|
+
const controllers = React.useRef(new Map());
|
|
47
|
+
// The exact input object a variant's latest build was STARTED from (not just
|
|
48
|
+
// resolved). Set when a build begins, so an unrelated re-render can't re-trigger
|
|
49
|
+
// a build of the same in-flight input (the controlled code is immutable, so an
|
|
50
|
+
// unchanged variant keeps its object identity).
|
|
51
|
+
const builtFrom = React.useRef(new Map());
|
|
52
|
+
// Variants whose FIRST build has settled (resolved or errored). Until then the
|
|
53
|
+
// build is never cancelled; a superseding edit waits in `deferred`.
|
|
54
|
+
const firstBuildDone = React.useRef(new Set());
|
|
55
|
+
const deferred = React.useRef(new Map());
|
|
56
|
+
React.useEffect(() => {
|
|
57
|
+
if (!code || !transpile) {
|
|
58
|
+
// Controller cleared (e.g. `reset()`): abort in-flight builds and forget all
|
|
59
|
+
// per-variant state, so the next edit is treated as a first build again
|
|
60
|
+
// (re-running the `.original` baseline branch). Drop the resolved `built` map
|
|
61
|
+
// too, so the re-edit starts from an EMPTY map — exactly like a true first
|
|
62
|
+
// edit — instead of briefly flashing the pre-reset build before the rebuilt
|
|
63
|
+
// baseline lands.
|
|
64
|
+
if (!code) {
|
|
65
|
+
for (const controller of controllers.current.values()) {
|
|
66
|
+
controller.abort();
|
|
67
|
+
}
|
|
68
|
+
controllers.current.clear();
|
|
69
|
+
requestIds.current.clear();
|
|
70
|
+
builtFrom.current.clear();
|
|
71
|
+
firstBuildDone.current.clear();
|
|
72
|
+
deferred.current.clear();
|
|
73
|
+
// One-shot reset, NOT a cascading render: `built` is not an effect dep, so
|
|
74
|
+
// clearing it doesn't re-run this effect, and once empty the updater is a
|
|
75
|
+
// no-op. Runs only when `code` is undefined, so it never touches an edit.
|
|
76
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect -- one-shot reset on controller clear
|
|
77
|
+
setBuilt(previous => Object.keys(previous).length > 0 ? {} : previous);
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const startBuild = (variant, variantCode) => {
|
|
82
|
+
const {
|
|
83
|
+
source
|
|
84
|
+
} = variantCode;
|
|
85
|
+
if (!source) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
builtFrom.current.set(variant, variantCode);
|
|
89
|
+
controllers.current.get(variant)?.abort();
|
|
90
|
+
const controller = new AbortController();
|
|
91
|
+
controllers.current.set(variant, controller);
|
|
92
|
+
const requestId = (requestIds.current.get(variant) ?? 0) + 1;
|
|
93
|
+
requestIds.current.set(variant, requestId);
|
|
94
|
+
|
|
95
|
+
// After this build settles, build any edit deferred while it ran.
|
|
96
|
+
const buildDeferred = () => {
|
|
97
|
+
const next = deferred.current.get(variant);
|
|
98
|
+
if (next) {
|
|
99
|
+
deferred.current.delete(variant);
|
|
100
|
+
startBuild(variant, next);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
loadBuildScope().then(buildScope => buildScope({
|
|
104
|
+
extraFiles: variantCode.extraFiles,
|
|
105
|
+
externals,
|
|
106
|
+
mainCode: source,
|
|
107
|
+
transpile,
|
|
108
|
+
signal: controller.signal
|
|
109
|
+
})).then(result => {
|
|
110
|
+
if (requestIds.current.get(variant) !== requestId) {
|
|
111
|
+
return; // superseded by a newer edit
|
|
112
|
+
}
|
|
113
|
+
firstBuildDone.current.add(variant);
|
|
114
|
+
// The build is now valid — clear any prior build error. A render error (if
|
|
115
|
+
// the entry then throws) is a SEPARATE channel reported by the runner; this
|
|
116
|
+
// only clears the build error, which the runner can't clear itself (a
|
|
117
|
+
// CSS-only fix never re-renders the entry).
|
|
118
|
+
report(variant, null);
|
|
119
|
+
// Commit the freshly-built variant urgently (a transition here would let a later
|
|
120
|
+
// edit's commit supersede it before it paints, costing the runner its last-good).
|
|
121
|
+
// The `.original` baseline still renders first when the build is fast enough; when
|
|
122
|
+
// it isn't (a cold first edit, where React coalesces the baseline + edit commits and
|
|
123
|
+
// the baseline never paints), a render error in the edit falls back to the host's
|
|
124
|
+
// build-time render instead of blanking (see the runner's `fallback`).
|
|
125
|
+
setBuilt(previous => ({
|
|
126
|
+
...previous,
|
|
127
|
+
[variant]: {
|
|
128
|
+
runnerCode: result.runnerCode ?? '',
|
|
129
|
+
scope: {
|
|
130
|
+
import: result.imports
|
|
131
|
+
},
|
|
132
|
+
css: result.css
|
|
133
|
+
}
|
|
134
|
+
}));
|
|
135
|
+
buildDeferred();
|
|
136
|
+
}).catch(thrown => {
|
|
137
|
+
if (requestIds.current.get(variant) !== requestId || controller.signal.aborted) {
|
|
138
|
+
return; // superseded / aborted
|
|
139
|
+
}
|
|
140
|
+
// The attempt finished (failed) — later edits may now cancel.
|
|
141
|
+
firstBuildDone.current.add(variant);
|
|
142
|
+
report(variant, thrown instanceof Error ? thrown.toString() : String(thrown));
|
|
143
|
+
buildDeferred();
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
for (const variant of Object.keys(code)) {
|
|
147
|
+
const variantCode = code[variant];
|
|
148
|
+
if (!variantCode || !variantCode.source) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
// First build of a variant that carries a baseline (`.original`, tagged on the
|
|
152
|
+
// FIRST edit): build the ORIGINAL inputs FIRST so the preview shows a good
|
|
153
|
+
// baseline before this (possibly broken) edit, then build the edit (which
|
|
154
|
+
// waits via the defer path below). Gated on `!controllers.has` so it fires
|
|
155
|
+
// exactly once — a re-render or a lingering `.original` never re-baselines.
|
|
156
|
+
const original = variantCode.original;
|
|
157
|
+
if (original?.source && !controllers.current.has(variant)) {
|
|
158
|
+
deferred.current.set(variant, variantCode);
|
|
159
|
+
startBuild(variant, {
|
|
160
|
+
source: original.source,
|
|
161
|
+
extraFiles: original.extraFiles
|
|
162
|
+
});
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
// Skip a variant whose exact input we already built — so editing one variant
|
|
166
|
+
// doesn't re-transpile and re-evaluate the others.
|
|
167
|
+
if (builtFrom.current.get(variant) === variantCode) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
// Never cancel a variant's FIRST build: while it's in flight, defer this edit
|
|
171
|
+
// (keeping only the latest) instead of aborting, so the baseline renders
|
|
172
|
+
// first. Later edits (first build done) abort the in-flight build as usual.
|
|
173
|
+
if (controllers.current.get(variant) && !firstBuildDone.current.has(variant)) {
|
|
174
|
+
deferred.current.set(variant, variantCode);
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
startBuild(variant, variantCode);
|
|
178
|
+
}
|
|
179
|
+
}, [code, transpile, externals, report]);
|
|
180
|
+
|
|
181
|
+
// Abort any in-flight builds on unmount.
|
|
182
|
+
React.useEffect(() => () => {
|
|
183
|
+
for (const controller of controllers.current.values()) {
|
|
184
|
+
controller.abort();
|
|
185
|
+
}
|
|
186
|
+
}, []);
|
|
187
|
+
return built;
|
|
188
|
+
}
|
package/useSearch/types.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ElapsedTime, Orama, Result, SearchParams } from '@orama/orama';
|
|
2
2
|
import type { Sitemap, SitemapPage, SitemapSection, SitemapPart, SitemapExport, SitemapSectionData } from "../createSitemap/types.mjs";
|
|
3
3
|
/**
|
|
4
4
|
* Base search result structure that can be extended by consumers
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { TypesDataContext } from "./TypesDataContext.mjs";
|
|
5
|
-
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
6
|
/**
|
|
7
7
|
* Provider that collects type data from all `useTypes()` calls within its subtree.
|
|
8
8
|
* This enables `useType(name)` to look up individual type data anywhere in the tree,
|
|
9
9
|
* and `useTypeProp(typeName, propName)` to look up individual properties.
|
|
10
10
|
*/
|
|
11
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
11
|
export function TypesDataProvider({
|
|
13
12
|
children
|
|
14
13
|
}) {
|
package/useType/useType.d.mts
CHANGED