@mui/internal-docs-infra 0.12.1-canary.4 → 0.12.1-canary.6
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 +41 -6
- package/CodeControllerContext/CodeControllerContext.mjs +14 -0
- package/CodeHighlighter/CodeHighlighterClient.d.mts +1 -1
- package/CodeHighlighter/CodeHighlighterClient.mjs +112 -15
- package/CodeHighlighter/CodeHighlighterContext.d.mts +8 -2
- 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/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 +1 -1
- package/createDemoData/createDemoData.d.mts +1 -1
- package/package.json +32 -3
- 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/loadServerCodeMeta/resolveModulePathWithFs.d.mts +1 -1
- package/pipeline/loadServerCodeMeta/resolveModulePathWithFs.mjs +0 -1
- 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/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 +1 -1
- 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 +1 -1
- package/pipeline/syncPageIndex/metadataToMarkdown.d.mts +1 -1
- package/pipeline/syncTypes/generateTypesMarkdown.d.mts +2 -2
- package/pipeline/transformHtmlCodeBlock/transformHtmlCodeBlock.mjs +1 -1
- package/pipeline/transformMarkdownCode/transformMarkdownCode.mjs +25 -15
- package/pipeline/transformMarkdownMetadata/types.d.mts +1 -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 +10 -0
- 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 +44 -9
- package/useCode/useSourceEnhancing.mjs +41 -9
- package/useCode/useTransformManagement.d.mts +2 -2
- package/useCode/useTransformManagement.mjs +0 -1
- 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/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 +268 -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 +65 -0
- package/useDemoController/useDemoController.mjs +184 -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.mjs +1 -2
- package/useType/useType.d.mts +1 -1
- package/useType/useTypeProp.d.mts +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { PreloadContext } from "./PreloadContext.mjs";
|
|
5
|
-
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
6
|
/**
|
|
7
7
|
* Scopes a cross-instance preload cache (typically at a layout). Descendants
|
|
8
8
|
* call `usePreload` to start dynamic imports of shared helpers keyed by a
|
|
@@ -10,7 +10,6 @@ import { PreloadContext } from "./PreloadContext.mjs";
|
|
|
10
10
|
* instance reuses its promise - so a helper a chunk's data implies (a transform
|
|
11
11
|
* fn, say) is fetched once, in parallel with the content, across the page.
|
|
12
12
|
*/
|
|
13
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
13
|
export function PreloadProvider({
|
|
15
14
|
children
|
|
16
15
|
}) {
|
|
@@ -43,6 +43,12 @@ export interface CodeControllerContext {
|
|
|
43
43
|
* e.g. `{ variantA: {}, variantB: {} }`.
|
|
44
44
|
*/
|
|
45
45
|
components?: Record<string, React.ReactNode> | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Current runtime error message per variant key (or `null` when the variant
|
|
48
|
+
* rendered cleanly), as reported by the preview components. Demos surface the
|
|
49
|
+
* selected variant's error via `useDemo().error`.
|
|
50
|
+
*/
|
|
51
|
+
errors?: Record<string, string | null> | undefined;
|
|
46
52
|
/**
|
|
47
53
|
* Additional source enhancers to apply to parsed HAST sources.
|
|
48
54
|
* These are merged with enhancers from CodeProvider and useCode opts.
|
|
@@ -52,13 +58,38 @@ export interface CodeControllerContext {
|
|
|
52
58
|
* Called once when a block in this controller's scope first activates for
|
|
53
59
|
* editing — immediately for `editActivation: 'eager'`, or on first engagement
|
|
54
60
|
* (hover / focus / click) for `'interaction'`. Lets the host react to "editing
|
|
55
|
-
* has begun" (e.g. fetch the editable source, light up UI
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
61
|
+
* has begun" (e.g. fetch the editable source, light up UI, or preload its live
|
|
62
|
+
* runtime). `deps` reports which file kinds the block spans — `js` when it has any
|
|
63
|
+
* JS/TS/JSX/TSX/MJS file, `css` when it has any CSS file — so the host can warm only
|
|
64
|
+
* the engine chunks it will need. `CodeHighlighter` separately warms its own
|
|
65
|
+
* live-editing dependencies (engine, grammars, worker) at the same moment, so a host
|
|
66
|
+
* that only wants the default behavior can leave this unset.
|
|
59
67
|
*/
|
|
60
|
-
onActivate?: (
|
|
68
|
+
onActivate?: (deps: {
|
|
69
|
+
js: boolean;
|
|
70
|
+
css: boolean;
|
|
71
|
+
}) => void;
|
|
61
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Props a code-controller component receives: `children` to wrap and the optional
|
|
75
|
+
* `url` identifying the demo, plus any custom props `T` (typically a specific
|
|
76
|
+
* controller's options). Mirrors `ContentProps` — a small base extended by `T`.
|
|
77
|
+
*/
|
|
78
|
+
export type CodeControllerProps<T extends {} = {}> = {
|
|
79
|
+
children: React.ReactNode;
|
|
80
|
+
/**
|
|
81
|
+
* The demo's url — identifies this controller, e.g. as the per-demo key for
|
|
82
|
+
* cross-tab sync. Supplied by the demo factory, or passed explicitly.
|
|
83
|
+
*/
|
|
84
|
+
url?: string;
|
|
85
|
+
} & T;
|
|
86
|
+
/**
|
|
87
|
+
* A code-controller component — the counterpart to `DemoContent`. It wraps `children`
|
|
88
|
+
* in a {@link CodeControllerContext} provider, typically sourcing the value from a hook
|
|
89
|
+
* such as `useDemoController`. Parameterize with `T` for the controller's own props
|
|
90
|
+
* (e.g. `CodeController<UseDemoControllerOptions>`).
|
|
91
|
+
*/
|
|
92
|
+
export type CodeController<T extends {} = {}> = React.ComponentType<CodeControllerProps<T>>;
|
|
62
93
|
export declare const CodeControllerContext: React.Context<CodeControllerContext | undefined>;
|
|
63
94
|
/**
|
|
64
95
|
* Hook to access controlled code state and setters. This is useful for custom
|
|
@@ -81,6 +112,10 @@ export declare function useControlledCode(): {
|
|
|
81
112
|
setCode: React.Dispatch<React.SetStateAction<ControlledCode | undefined>> | undefined;
|
|
82
113
|
setSelection: React.Dispatch<React.SetStateAction<Selection>> | undefined;
|
|
83
114
|
components: Record<string, React.ReactNode> | undefined;
|
|
115
|
+
errors: Record<string, string | null> | undefined;
|
|
84
116
|
sourceEnhancers: SourceEnhancers | undefined;
|
|
85
|
-
onActivate: ((
|
|
117
|
+
onActivate: ((deps: {
|
|
118
|
+
js: boolean;
|
|
119
|
+
css: boolean;
|
|
120
|
+
}) => void) | undefined;
|
|
86
121
|
};
|
|
@@ -10,6 +10,19 @@ import * as React from 'react';
|
|
|
10
10
|
* event fires.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Props a code-controller component receives: `children` to wrap and the optional
|
|
15
|
+
* `url` identifying the demo, plus any custom props `T` (typically a specific
|
|
16
|
+
* controller's options). Mirrors `ContentProps` — a small base extended by `T`.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A code-controller component — the counterpart to `DemoContent`. It wraps `children`
|
|
21
|
+
* in a {@link CodeControllerContext} provider, typically sourcing the value from a hook
|
|
22
|
+
* such as `useDemoController`. Parameterize with `T` for the controller's own props
|
|
23
|
+
* (e.g. `CodeController<UseDemoControllerOptions>`).
|
|
24
|
+
*/
|
|
25
|
+
|
|
13
26
|
export const CodeControllerContext = /*#__PURE__*/React.createContext(undefined);
|
|
14
27
|
|
|
15
28
|
/**
|
|
@@ -36,6 +49,7 @@ export function useControlledCode() {
|
|
|
36
49
|
setCode: context?.setCode,
|
|
37
50
|
setSelection: context?.setSelection,
|
|
38
51
|
components: context?.components,
|
|
52
|
+
errors: context?.errors,
|
|
39
53
|
sourceEnhancers: context?.sourceEnhancers,
|
|
40
54
|
onActivate: context?.onActivate
|
|
41
55
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { CodeHighlighterClientProps } from "./types.mjs";
|
|
2
2
|
export declare function CodeHighlighterClient(props: CodeHighlighterClientProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -18,6 +18,7 @@ import { useSpeculativeUseCodePreload } from "./useSpeculativeUseCodePreload.mjs
|
|
|
18
18
|
import { useSpeculativeGrammarPreload } from "./useSpeculativeGrammarPreload.mjs";
|
|
19
19
|
import { useGrammarsReady } from "./useGrammarsReady.mjs";
|
|
20
20
|
import { detectGrammarScopes } from "../pipeline/parseSource/detectGrammarScopes.mjs";
|
|
21
|
+
import { detectFileTypes } from "../pipeline/parseSource/detectFileTypes.mjs";
|
|
21
22
|
import { useChunk } from "../CoordinatedLazy/useChunk.mjs";
|
|
22
23
|
import { useCoordinatedSwap } from "../CoordinatedLazy/useCoordinatedSwap.mjs";
|
|
23
24
|
import { CoordinatedFallbackContext } from "../CoordinatedLazy/CoordinatedFallbackContext.mjs";
|
|
@@ -27,12 +28,40 @@ import * as Errors from "./errors.mjs";
|
|
|
27
28
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
28
29
|
const DEBUG = false; // Set to true for debugging purposes
|
|
29
30
|
|
|
31
|
+
// Safety-net deadline (ms) for the default `'idle'` highlight/enhance swaps. They
|
|
32
|
+
// defer the swap to `requestIdleCallback`, which a busy main thread can starve
|
|
33
|
+
// INDEFINITELY — leaving code stuck at its un-highlighted first paint until a full
|
|
34
|
+
// reload. The `timeout` guarantees the swap still runs even if the browser never
|
|
35
|
+
// goes idle (idle normally wins long before this deadline).
|
|
36
|
+
const IDLE_SWAP_TIMEOUT_MS = 10_000;
|
|
37
|
+
|
|
38
|
+
// Safety-net deadline (ms) for the async transform-deltas pipeline. If it neither
|
|
39
|
+
// resolves nor rejects (a stalled worker / hung delta computation), the block would
|
|
40
|
+
// otherwise wait on `waitingForTransformedCode` forever — code stuck un-highlighted
|
|
41
|
+
// until a reload. On timeout we publish the un-delta'd parsed HAST so the gate drops.
|
|
42
|
+
const TRANSFORM_PIPELINE_TIMEOUT_MS = 10_000;
|
|
43
|
+
|
|
30
44
|
// `useChunk` is the chunk loader/renderer, but here we use only its loading
|
|
31
45
|
// engine (load-when-enabled + abort + `refresh()` with stale-while-revalidate),
|
|
32
46
|
// so the content component is an unused placeholder.
|
|
33
47
|
function NoopChunkContent() {
|
|
34
48
|
return null;
|
|
35
49
|
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Inject a build-time `fallback` into a bridged live-preview node. The controller's
|
|
53
|
+
* components are erased to `ReactNode` across the context, so the type argument on
|
|
54
|
+
* `isValidElement` re-narrows the node to one that accepts `fallback` — no cast. A
|
|
55
|
+
* non-element node (nothing to clone) is returned untouched.
|
|
56
|
+
*/
|
|
57
|
+
function injectFallback(node, fallback) {
|
|
58
|
+
if (! /*#__PURE__*/React.isValidElement(node)) {
|
|
59
|
+
return node;
|
|
60
|
+
}
|
|
61
|
+
return /*#__PURE__*/React.cloneElement(node, {
|
|
62
|
+
fallback
|
|
63
|
+
});
|
|
64
|
+
}
|
|
36
65
|
function useInitialData({
|
|
37
66
|
variants,
|
|
38
67
|
variantName,
|
|
@@ -337,7 +366,9 @@ function useCodeParsing({
|
|
|
337
366
|
const [isHighlightAllowed, setIsHighlightAllowed] = React.useState(highlightAfter === 'init' || highlightAfter === 'hydration' && isHydrated);
|
|
338
367
|
React.useEffect(() => {
|
|
339
368
|
if (highlightAfter === 'idle') {
|
|
340
|
-
return requestIdle(() => setIsHighlightAllowed(true)
|
|
369
|
+
return requestIdle(() => setIsHighlightAllowed(true), {
|
|
370
|
+
timeout: IDLE_SWAP_TIMEOUT_MS
|
|
371
|
+
});
|
|
341
372
|
}
|
|
342
373
|
return undefined;
|
|
343
374
|
}, [highlightAfter]);
|
|
@@ -483,9 +514,30 @@ function useCodeTransforms({
|
|
|
483
514
|
// so this effect never publishes a synchronous pass-through state.
|
|
484
515
|
React.useEffect(() => {
|
|
485
516
|
if (!parsedCode || !sourceParser || !computeHastDeltasLoader) {
|
|
486
|
-
return;
|
|
517
|
+
return undefined;
|
|
487
518
|
}
|
|
488
519
|
|
|
520
|
+
// `settled` guards against two wedges: (1) a late write from a SUPERSEDED run
|
|
521
|
+
// (the cleanup flips it so an in-flight pipeline for an older `parsedCode` can't
|
|
522
|
+
// clobber the current one), and (2) the timeout below committing twice. The first
|
|
523
|
+
// commit wins.
|
|
524
|
+
let settled = false;
|
|
525
|
+
const commit = output => {
|
|
526
|
+
if (!settled) {
|
|
527
|
+
settled = true;
|
|
528
|
+
setTransformedState({
|
|
529
|
+
input: parsedCode,
|
|
530
|
+
output
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
// Safety net: if the pipeline neither resolves NOR rejects (a stalled worker / hung
|
|
536
|
+
// delta computation), the `catch` never fires and `waitingForTransformedCode` would
|
|
537
|
+
// stay true forever. Fall back to the un-delta'd parsed HAST so the gate drops and
|
|
538
|
+
// the block shows highlighted (un-transformed) code rather than plain text forever.
|
|
539
|
+
const timer = setTimeout(() => commit(parsedCode), TRANSFORM_PIPELINE_TIMEOUT_MS);
|
|
540
|
+
|
|
489
541
|
// Process transformations for all variants
|
|
490
542
|
(async () => {
|
|
491
543
|
try {
|
|
@@ -494,18 +546,18 @@ function useCodeTransforms({
|
|
|
494
546
|
// kept out of the initial bundle under CodeProviderLazy.
|
|
495
547
|
const [parseSource, computeHastDeltas] = await Promise.all([sourceParser, computeHastDeltasLoader()]);
|
|
496
548
|
const enhanced = await computeHastDeltas(parsedCode, parseSource);
|
|
497
|
-
|
|
498
|
-
input: parsedCode,
|
|
499
|
-
output: enhanced
|
|
500
|
-
});
|
|
549
|
+
commit(enhanced);
|
|
501
550
|
} catch (error) {
|
|
502
551
|
console.error(new Errors.ErrorCodeHighlighterClientTransformProcessingFailure(error));
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
});
|
|
552
|
+
commit(parsedCode);
|
|
553
|
+
} finally {
|
|
554
|
+
clearTimeout(timer);
|
|
507
555
|
}
|
|
508
556
|
})();
|
|
557
|
+
return () => {
|
|
558
|
+
settled = true; // a newer run (or unmount) supersedes this one; ignore late writes
|
|
559
|
+
clearTimeout(timer);
|
|
560
|
+
};
|
|
509
561
|
}, [parsedCode, sourceParser, computeHastDeltasLoader]);
|
|
510
562
|
|
|
511
563
|
// When the full async pipeline is wired, expose the cached output regardless
|
|
@@ -903,10 +955,21 @@ export function CodeHighlighterClient(props) {
|
|
|
903
955
|
// the editable speculative preload below and notifies the CodeControllerContext.
|
|
904
956
|
const [editingActivated, setEditingActivated] = React.useState(false);
|
|
905
957
|
const controllerOnActivate = controlled?.onActivate;
|
|
958
|
+
// Which live-editing engine chunks the controller should preload on activation: `js`
|
|
959
|
+
// if the demo has any JS/TS file, `css` if any CSS file. Stable across keystrokes
|
|
960
|
+
// (editing changes source content, never which files exist), like the grammar scopes
|
|
961
|
+
// below.
|
|
962
|
+
const editableFileTypes = React.useMemo(() => {
|
|
963
|
+
const editableCode = props.code ?? code;
|
|
964
|
+
return editableCode ? detectFileTypes(editableCode) : {
|
|
965
|
+
js: false,
|
|
966
|
+
css: false
|
|
967
|
+
};
|
|
968
|
+
}, [props.code, code]);
|
|
906
969
|
const handleEditingActivated = React.useCallback(() => {
|
|
907
970
|
setEditingActivated(true);
|
|
908
|
-
controllerOnActivate?.();
|
|
909
|
-
}, [controllerOnActivate]);
|
|
971
|
+
controllerOnActivate?.(editableFileTypes);
|
|
972
|
+
}, [controllerOnActivate, editableFileTypes]);
|
|
910
973
|
|
|
911
974
|
// Grammar scopes the editable files need for live re-highlighting. Unlike the
|
|
912
975
|
// speculative highlight/transform preloads — which intentionally skip
|
|
@@ -1061,7 +1124,9 @@ export function CodeHighlighterClient(props) {
|
|
|
1061
1124
|
const [isEnhanceAllowed, setIsEnhanceAllowed] = React.useState(enhanceAfter === 'init' || enhanceAfter === 'hydration' && isHydrated);
|
|
1062
1125
|
React.useEffect(() => {
|
|
1063
1126
|
if (enhanceAfter === 'idle') {
|
|
1064
|
-
return requestIdle(() => setIsEnhanceAllowed(true)
|
|
1127
|
+
return requestIdle(() => setIsEnhanceAllowed(true), {
|
|
1128
|
+
timeout: IDLE_SWAP_TIMEOUT_MS
|
|
1129
|
+
});
|
|
1065
1130
|
}
|
|
1066
1131
|
return undefined;
|
|
1067
1132
|
}, [enhanceAfter]);
|
|
@@ -1268,13 +1333,45 @@ export function CodeHighlighterClient(props) {
|
|
|
1268
1333
|
setFallbackHasts: handleSetFallbackHasts,
|
|
1269
1334
|
onHookCalled: handleHookCalled
|
|
1270
1335
|
}), [variantName, codeForFallback, fileName, props.fallbackUsesExtraFiles, props.fallbackUsesAllVariants, handleSetFallbackHasts, handleHookCalled]);
|
|
1336
|
+
|
|
1337
|
+
// Keep the build-time render for any variant the controller hasn't produced a live
|
|
1338
|
+
// preview for yet — an in-flight build, a build error, or a variant with no live build
|
|
1339
|
+
// at all — by merging PER VARIANT (live entries override the build-time ones; the rest
|
|
1340
|
+
// stay visible). A whole-object swap (`controlled?.components || props.components`) would
|
|
1341
|
+
// drop the build-time render for ALL variants the instant ANY one went live, flashing
|
|
1342
|
+
// empty previews; the merge keeps "no live entry ⇒ show the build-time render".
|
|
1343
|
+
//
|
|
1344
|
+
// Each live entry is the lazy `DemoRunner`. Render it under a `Suspense` whose fallback is
|
|
1345
|
+
// that variant's build-time render (shown while the chunk resolves), AND inject the same
|
|
1346
|
+
// build-time render as the runner's `fallback` prop — so a live preview that throws on its
|
|
1347
|
+
// FIRST render, before any successful one (e.g. a render-error first edit, where the
|
|
1348
|
+
// baseline never got to paint), shows the original instead of blanking.
|
|
1349
|
+
const bridgedComponents = React.useMemo(() => {
|
|
1350
|
+
const live = controlled?.components;
|
|
1351
|
+
if (!live) {
|
|
1352
|
+
return props.components;
|
|
1353
|
+
}
|
|
1354
|
+
const merged = {
|
|
1355
|
+
...(props.components || {})
|
|
1356
|
+
};
|
|
1357
|
+
for (const variant of Object.keys(live)) {
|
|
1358
|
+
const buildTime = props.components?.[variant];
|
|
1359
|
+
const liveNode = injectFallback(live[variant], buildTime);
|
|
1360
|
+
merged[variant] = /*#__PURE__*/React.createElement(React.Suspense, {
|
|
1361
|
+
key: variant,
|
|
1362
|
+
fallback: buildTime ?? null
|
|
1363
|
+
}, liveNode);
|
|
1364
|
+
}
|
|
1365
|
+
return merged;
|
|
1366
|
+
}, [controlled?.components, props.components]);
|
|
1271
1367
|
const context = React.useMemo(() => ({
|
|
1272
1368
|
code: overlaidCode,
|
|
1273
1369
|
// Use processed/transformed code
|
|
1274
1370
|
setCode: controlled?.setCode,
|
|
1275
1371
|
selection: controlled?.selection || selection,
|
|
1276
1372
|
setSelection: controlled?.setSelection || setSelection,
|
|
1277
|
-
components:
|
|
1373
|
+
components: bridgedComponents,
|
|
1374
|
+
errors: controlled?.errors,
|
|
1278
1375
|
// Only suppress when an external CodeController owns the code; static
|
|
1279
1376
|
// `props.code` still needs the locally-computed list.
|
|
1280
1377
|
availableTransforms: controlled?.code ? [] : availableTransforms,
|
|
@@ -1287,7 +1384,7 @@ export function CodeHighlighterClient(props) {
|
|
|
1287
1384
|
onEditingActivated: handleEditingActivated,
|
|
1288
1385
|
refresh,
|
|
1289
1386
|
preParsedCache
|
|
1290
|
-
}), [overlaidCode, controlled?.setCode, selection, controlled?.selection, controlled?.setSelection, controlled?.
|
|
1387
|
+
}), [overlaidCode, controlled?.setCode, selection, controlled?.selection, controlled?.setSelection, bridgedComponents, controlled?.errors, controlled?.code, availableTransforms, props.url, deferHighlight, activeFallbacks, highlightReady, highlightAfter, editActivation, handleEditingActivated, refresh, preParsedCache]);
|
|
1291
1388
|
if (!props.variants && !props.components && !activeCode) {
|
|
1292
1389
|
throw new Errors.ErrorCodeHighlighterClientMissingData();
|
|
1293
1390
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import type { Code, ControlledCode, Fallbacks, HastRoot } from "./types.mjs";
|
|
3
|
+
import type { Selection } from "../CodeControllerContext/index.mjs";
|
|
4
4
|
/**
|
|
5
5
|
* One cached pre-parsed file. Stored per-fileName: each new write replaces
|
|
6
6
|
* any previous entry for that file. The `source` string is the cache key —
|
|
@@ -18,6 +18,12 @@ export interface CodeHighlighterContextType {
|
|
|
18
18
|
selection?: Selection;
|
|
19
19
|
setSelection?: React.Dispatch<React.SetStateAction<Selection>>;
|
|
20
20
|
components?: Record<string, React.ReactNode>;
|
|
21
|
+
/**
|
|
22
|
+
* Current runtime error message per variant key (or `null` when the variant
|
|
23
|
+
* rendered cleanly), bridged from the controller context. Surfaced through
|
|
24
|
+
* `useDemo().error`.
|
|
25
|
+
*/
|
|
26
|
+
errors?: Record<string, string | null>;
|
|
21
27
|
availableTransforms?: string[];
|
|
22
28
|
url?: string;
|
|
23
29
|
deferHighlight?: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SourceComments, SourceEnhancers } from "./types.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import type { FallbackNode } from "./fallbackFormat.mjs";
|
|
3
3
|
export interface StringFallbackResult {
|
|
4
4
|
/** Compact, windowed fallback frames (text only — `.line` spans stripped). */
|
|
5
5
|
fallback: FallbackNode[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BaseContentLoadingProps, Code, Fallbacks } from "./types.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import type { SourceLineCounts } from "../useCode/sourceLineCounts.mjs";
|
|
3
3
|
/** Per-variant → per-file line metadata threaded for the fallback. */
|
|
4
4
|
export type LineCountsByVariant = Record<string, Record<string, SourceLineCounts>>;
|
|
5
5
|
export declare function codeToFallbackProps(variant: string, code?: Code, _fileName?: string, _needsAllFiles?: boolean, needsAllVariants?: boolean, allFallbackHasts?: Record<string, Fallbacks>, allLineCounts?: LineCountsByVariant): BaseContentLoadingProps;
|
|
@@ -45,6 +45,9 @@ export function createClientProps(props) {
|
|
|
45
45
|
} : undefined),
|
|
46
46
|
...(props.initialExpanded !== undefined ? {
|
|
47
47
|
initialExpanded: props.initialExpanded
|
|
48
|
+
} : undefined),
|
|
49
|
+
...(props.initialDisabled !== undefined ? {
|
|
50
|
+
initialDisabled: props.initialDisabled
|
|
48
51
|
} : undefined)
|
|
49
52
|
};
|
|
50
53
|
return {
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import type { Code, ControlledCode, ParseSource } from "./types.mjs";
|
|
2
2
|
import type { PreParsedCacheEntry } from "./CodeHighlighterContext.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Cache key for a parsed file. Qualified by variant so two variants that share a
|
|
5
|
+
* file name (e.g. both have `Demo.tsx`) get independent entries instead of
|
|
6
|
+
* evicting each other. The `\u0000` separator cannot appear in a variant key or
|
|
7
|
+
* file name, so the two parts can never run together ambiguously.
|
|
8
|
+
*/
|
|
9
|
+
export declare function preParsedCacheKey(variant: string, fileName: string): string;
|
|
3
10
|
/**
|
|
4
11
|
* Pure function to parse controlled code and convert it to regular Code format.
|
|
5
12
|
* Handles the conversion from ControlledCode (string|null sources) to Code (HAST nodes).
|
|
6
13
|
*
|
|
7
14
|
* When `preParsedCache` is supplied, each file's source is first looked up in
|
|
8
|
-
* the cache. If the cached entry's source string
|
|
9
|
-
* cached HAST is reused and `parseSource` is skipped
|
|
10
|
-
*
|
|
11
|
-
*
|
|
15
|
+
* the cache (keyed by variant + file name). If the cached entry's source string
|
|
16
|
+
* matches byte-for-byte, the cached HAST is reused and `parseSource` is skipped.
|
|
17
|
+
* A fresh parse is WRITTEN THROUGH to the cache, so on the next controlled-code
|
|
18
|
+
* change (a keystroke updates one file) every unchanged file is reused instead
|
|
19
|
+
* of re-parsed — only the edited file's source differs. A stale entry is evicted
|
|
20
|
+
* and replaced; a parse failure keeps the raw string and is not cached.
|
|
12
21
|
*/
|
|
13
22
|
export declare function parseControlledCode(controlledCode: ControlledCode, parseSource: ParseSource, preParsedCache?: Map<string, PreParsedCacheEntry>): Code;
|
|
@@ -1,31 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache key for a parsed file. Qualified by variant so two variants that share a
|
|
3
|
+
* file name (e.g. both have `Demo.tsx`) get independent entries instead of
|
|
4
|
+
* evicting each other. The `\u0000` separator cannot appear in a variant key or
|
|
5
|
+
* file name, so the two parts can never run together ambiguously.
|
|
6
|
+
*/
|
|
7
|
+
export function preParsedCacheKey(variant, fileName) {
|
|
8
|
+
return `${variant}\u0000${fileName}`;
|
|
9
|
+
}
|
|
10
|
+
|
|
1
11
|
/**
|
|
2
12
|
* Pure function to parse controlled code and convert it to regular Code format.
|
|
3
13
|
* Handles the conversion from ControlledCode (string|null sources) to Code (HAST nodes).
|
|
4
14
|
*
|
|
5
15
|
* When `preParsedCache` is supplied, each file's source is first looked up in
|
|
6
|
-
* the cache. If the cached entry's source string
|
|
7
|
-
* cached HAST is reused and `parseSource` is skipped
|
|
8
|
-
*
|
|
9
|
-
*
|
|
16
|
+
* the cache (keyed by variant + file name). If the cached entry's source string
|
|
17
|
+
* matches byte-for-byte, the cached HAST is reused and `parseSource` is skipped.
|
|
18
|
+
* A fresh parse is WRITTEN THROUGH to the cache, so on the next controlled-code
|
|
19
|
+
* change (a keystroke updates one file) every unchanged file is reused instead
|
|
20
|
+
* of re-parsed — only the edited file's source differs. A stale entry is evicted
|
|
21
|
+
* and replaced; a parse failure keeps the raw string and is not cached.
|
|
10
22
|
*/
|
|
11
23
|
export function parseControlledCode(controlledCode, parseSource, preParsedCache) {
|
|
12
24
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
25
|
+
* Resolves one file's string source to HAST, reusing a cached parse on an exact
|
|
26
|
+
* source match and writing a fresh parse through to the cache. Returns the raw
|
|
27
|
+
* string (uncached) if `parseSource` throws.
|
|
15
28
|
*/
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
29
|
+
const resolveSource = (variant, fileName, source) => {
|
|
30
|
+
const key = preParsedCacheKey(variant, fileName);
|
|
31
|
+
const entry = preParsedCache?.get(key);
|
|
32
|
+
if (entry) {
|
|
33
|
+
if (entry.source === source) {
|
|
34
|
+
return entry.hast;
|
|
35
|
+
}
|
|
36
|
+
preParsedCache?.delete(key);
|
|
23
37
|
}
|
|
24
|
-
|
|
25
|
-
|
|
38
|
+
try {
|
|
39
|
+
const hast = parseSource(source, fileName);
|
|
40
|
+
preParsedCache?.set(key, {
|
|
41
|
+
source,
|
|
42
|
+
hast
|
|
43
|
+
});
|
|
44
|
+
return hast;
|
|
45
|
+
} catch {
|
|
46
|
+
return source;
|
|
26
47
|
}
|
|
27
|
-
preParsedCache.delete(fileName);
|
|
28
|
-
return undefined;
|
|
29
48
|
};
|
|
30
49
|
const parsed = {};
|
|
31
50
|
for (const [variant, variantCode] of Object.entries(controlledCode)) {
|
|
@@ -39,17 +58,7 @@ export function parseControlledCode(controlledCode, parseSource, preParsedCache)
|
|
|
39
58
|
// Convert null to empty string, then parse
|
|
40
59
|
const sourceToProcess = variantCode.source === null ? '' : variantCode.source;
|
|
41
60
|
if (typeof sourceToProcess === 'string' && variantCode.fileName) {
|
|
42
|
-
|
|
43
|
-
if (cached) {
|
|
44
|
-
mainSource = cached;
|
|
45
|
-
} else {
|
|
46
|
-
try {
|
|
47
|
-
mainSource = parseSource(sourceToProcess, variantCode.fileName);
|
|
48
|
-
} catch (error) {
|
|
49
|
-
// Keep original string if parsing fails
|
|
50
|
-
mainSource = sourceToProcess;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
61
|
+
mainSource = resolveSource(variant, variantCode.fileName, sourceToProcess);
|
|
53
62
|
} else if (typeof sourceToProcess === 'string' && !variantCode.fileName) {
|
|
54
63
|
// Return a basic HAST root node with the source text for unsupported file types
|
|
55
64
|
// This indicates that the source has at least passed through the parsing pipeline
|
|
@@ -74,27 +83,10 @@ export function parseControlledCode(controlledCode, parseSource, preParsedCache)
|
|
|
74
83
|
// Convert null to empty string, then parse
|
|
75
84
|
const fileSourceToProcess = fileData.source === null ? '' : fileData.source;
|
|
76
85
|
if (typeof fileSourceToProcess === 'string') {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
comments: fileData.comments
|
|
82
|
-
};
|
|
83
|
-
} else {
|
|
84
|
-
try {
|
|
85
|
-
const parsedSource = parseSource(fileSourceToProcess, fileName);
|
|
86
|
-
parsedExtraFiles[fileName] = {
|
|
87
|
-
source: parsedSource,
|
|
88
|
-
comments: fileData.comments
|
|
89
|
-
};
|
|
90
|
-
} catch (error) {
|
|
91
|
-
// Keep original if parsing fails
|
|
92
|
-
parsedExtraFiles[fileName] = {
|
|
93
|
-
source: fileSourceToProcess,
|
|
94
|
-
comments: fileData.comments
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
}
|
|
86
|
+
parsedExtraFiles[fileName] = {
|
|
87
|
+
source: resolveSource(variant, fileName, fileSourceToProcess),
|
|
88
|
+
comments: fileData.comments
|
|
89
|
+
};
|
|
98
90
|
} else {
|
|
99
91
|
// Keep other values as-is
|
|
100
92
|
parsedExtraFiles[fileName] = {
|
|
@@ -240,6 +240,14 @@ export type ControlledVariantCode = CodeMeta & {
|
|
|
240
240
|
collapseMap?: CollapseMap;
|
|
241
241
|
totalLines?: number;
|
|
242
242
|
emptyLines?: number[];
|
|
243
|
+
/**
|
|
244
|
+
* The pre-edit build inputs, carried ONLY on the first edit of a variant (the
|
|
245
|
+
* transition from precomputed to controlled). The live runner builds this as a
|
|
246
|
+
* baseline first — so a broken first edit has a good last-good render to fall
|
|
247
|
+
* back to — then swaps to the edited `source`. Read by `useVariantBuilds`;
|
|
248
|
+
* stripped on the next edit so it does not linger in the controlled state.
|
|
249
|
+
*/
|
|
250
|
+
original?: Pick<ControlledVariantCode, 'source' | 'extraFiles'>;
|
|
243
251
|
};
|
|
244
252
|
export type ControlledCode = {
|
|
245
253
|
[key: string]: undefined | null | ControlledVariantCode;
|
|
@@ -261,6 +269,14 @@ type BaseContentProps = CodeIdentityProps & Pick<CodeContentProps, 'code' | 'com
|
|
|
261
269
|
* see it too.
|
|
262
270
|
*/
|
|
263
271
|
initialExpanded?: boolean;
|
|
272
|
+
/**
|
|
273
|
+
* Start an editable block read-only (a truthy value), leaving it to the
|
|
274
|
+
* `editable` / `setEditable` toggle `useCode` returns to turn editing on.
|
|
275
|
+
* Runtime-only; lives on `contentProps` — the demo factory resolves a demo's
|
|
276
|
+
* `initialDisabled` (instance prop → `meta` → `createDemoFactory` default) into it.
|
|
277
|
+
* Distinct from the hard `disabled` opt, which forbids editing outright.
|
|
278
|
+
*/
|
|
279
|
+
initialDisabled?: boolean;
|
|
264
280
|
};
|
|
265
281
|
export type ContentProps<T extends {}> = BaseContentProps & T;
|
|
266
282
|
/**
|
|
@@ -622,6 +638,11 @@ export interface CodeHighlighterBaseProps<T extends {}> extends CodeIdentityProp
|
|
|
622
638
|
* `contentProps` so both `useCode` and the loading fallback honor it.
|
|
623
639
|
*/
|
|
624
640
|
initialExpanded?: boolean;
|
|
641
|
+
/**
|
|
642
|
+
* Start the editable code read-only. Threaded into `contentProps`; `useCode` seeds its
|
|
643
|
+
* `editable` toggle from it (a reader flips it back with `setEditable`). Runtime-only.
|
|
644
|
+
*/
|
|
645
|
+
initialDisabled?: boolean;
|
|
625
646
|
}
|
|
626
647
|
/**
|
|
627
648
|
* Props for the client-side CodeHighlighter component.
|