@mui/internal-docs-infra 0.12.1-canary.12 → 0.12.1-canary.14
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/CodeControllerContext/CodeControllerContext.d.mts +4 -4
- package/CodeControllerContext/CodeControllerContext.mjs +1 -1
- package/CodeHighlighter/CodeHighlighterClient.mjs +2 -4
- package/CodeHighlighter/CodeHighlighterContext.d.mts +1 -1
- package/package.json +2 -2
- package/useCode/useCode.mjs +12 -1
- package/useCode/useSourceEditing.mjs +1 -1
- package/useCode/useTransformManagement.mjs +19 -2
- package/useDemoController/useDemoController.d.mts +9 -20
- package/useDemoController/useDemoController.mjs +6 -22
- package/useDemoController/useVariantBuilds.d.mts +1 -1
- package/useDemoController/useVariantBuilds.mjs +1 -1
|
@@ -18,7 +18,7 @@ export interface CodeControllerContext {
|
|
|
18
18
|
* code is always a string to simplify use. It will be highlighted when it is passed as `code`.
|
|
19
19
|
* This behavior depends on client-side highlighting and the CodeProvider component.
|
|
20
20
|
*/
|
|
21
|
-
code?: ControlledCode;
|
|
21
|
+
code?: ControlledCode | null;
|
|
22
22
|
/**
|
|
23
23
|
* Controls the state for displaying the given code. This works with build-time and client-side
|
|
24
24
|
* loading. If using server loading, the selection won't work for fallback loading and would
|
|
@@ -30,7 +30,7 @@ export interface CodeControllerContext {
|
|
|
30
30
|
* called when the user interacts with the code highlighting. It's recommended to only set `code`
|
|
31
31
|
* after the first `setCode` event fires to benefit from server or build-time rendering.
|
|
32
32
|
*/
|
|
33
|
-
setCode?: React.Dispatch<React.SetStateAction<ControlledCode |
|
|
33
|
+
setCode?: React.Dispatch<React.SetStateAction<ControlledCode | null>>;
|
|
34
34
|
/**
|
|
35
35
|
* Setter function for updating the selection state. When provided in the context, this function
|
|
36
36
|
* will be called when the user interacts with the code highlighting interface.
|
|
@@ -107,9 +107,9 @@ export declare const CodeControllerContext: React.Context<CodeControllerContext
|
|
|
107
107
|
* - components: Override components for the preview
|
|
108
108
|
*/
|
|
109
109
|
export declare function useControlledCode(): {
|
|
110
|
-
code: ControlledCode |
|
|
110
|
+
code: ControlledCode | null;
|
|
111
111
|
selection: Selection | undefined;
|
|
112
|
-
setCode: React.Dispatch<React.SetStateAction<ControlledCode |
|
|
112
|
+
setCode: React.Dispatch<React.SetStateAction<ControlledCode | null>> | undefined;
|
|
113
113
|
setSelection: React.Dispatch<React.SetStateAction<Selection>> | undefined;
|
|
114
114
|
components: Record<string, React.ReactNode> | undefined;
|
|
115
115
|
errors: Record<string, string | null> | undefined;
|
|
@@ -44,7 +44,7 @@ if (process.env.NODE_ENV !== "production") CodeControllerContext.displayName = "
|
|
|
44
44
|
export function useControlledCode() {
|
|
45
45
|
const context = React.useContext(CodeControllerContext);
|
|
46
46
|
return {
|
|
47
|
-
code: context?.code,
|
|
47
|
+
code: context?.code ?? null,
|
|
48
48
|
selection: context?.selection,
|
|
49
49
|
setCode: context?.setCode,
|
|
50
50
|
setSelection: context?.setSelection,
|
|
@@ -1372,9 +1372,7 @@ export function CodeHighlighterClient(props) {
|
|
|
1372
1372
|
setSelection: controlled?.setSelection || setSelection,
|
|
1373
1373
|
components: bridgedComponents,
|
|
1374
1374
|
errors: controlled?.errors,
|
|
1375
|
-
|
|
1376
|
-
// `props.code` still needs the locally-computed list.
|
|
1377
|
-
availableTransforms: controlled?.code ? [] : availableTransforms,
|
|
1375
|
+
availableTransforms,
|
|
1378
1376
|
url: props.url,
|
|
1379
1377
|
deferHighlight,
|
|
1380
1378
|
fallbacks: activeFallbacks,
|
|
@@ -1384,7 +1382,7 @@ export function CodeHighlighterClient(props) {
|
|
|
1384
1382
|
onEditingActivated: handleEditingActivated,
|
|
1385
1383
|
refresh,
|
|
1386
1384
|
preParsedCache
|
|
1387
|
-
}), [overlaidCode, controlled?.setCode, selection, controlled?.selection, controlled?.setSelection, bridgedComponents, controlled?.errors,
|
|
1385
|
+
}), [overlaidCode, controlled?.setCode, selection, controlled?.selection, controlled?.setSelection, bridgedComponents, controlled?.errors, availableTransforms, props.url, deferHighlight, activeFallbacks, highlightReady, highlightAfter, editActivation, handleEditingActivated, refresh, preParsedCache]);
|
|
1388
1386
|
if (!props.variants && !props.components && !activeCode) {
|
|
1389
1387
|
throw new Errors.ErrorCodeHighlighterClientMissingData();
|
|
1390
1388
|
}
|
|
@@ -14,7 +14,7 @@ export interface PreParsedCacheEntry {
|
|
|
14
14
|
}
|
|
15
15
|
export interface CodeHighlighterContextType {
|
|
16
16
|
code?: Code;
|
|
17
|
-
setCode?: React.Dispatch<React.SetStateAction<ControlledCode |
|
|
17
|
+
setCode?: React.Dispatch<React.SetStateAction<ControlledCode | null>>;
|
|
18
18
|
selection?: Selection;
|
|
19
19
|
setSelection?: React.Dispatch<React.SetStateAction<Selection>>;
|
|
20
20
|
components?: Record<string, React.ReactNode>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mui/internal-docs-infra",
|
|
3
|
-
"version": "0.12.1-canary.
|
|
3
|
+
"version": "0.12.1-canary.14",
|
|
4
4
|
"author": "MUI Team",
|
|
5
5
|
"description": "MUI Infra - internal documentation creation tools.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -804,5 +804,5 @@
|
|
|
804
804
|
"bin": {
|
|
805
805
|
"docs-infra": "./cli/index.mjs"
|
|
806
806
|
},
|
|
807
|
-
"gitSha": "
|
|
807
|
+
"gitSha": "d5ea0579af3522e24975d0aa66473075294d2022"
|
|
808
808
|
}
|
package/useCode/useCode.mjs
CHANGED
|
@@ -385,6 +385,17 @@ export function useCode(contentProps, opts) {
|
|
|
385
385
|
// is in scope and the block isn't hard-`disabled`. Otherwise `setEditable` is omitted,
|
|
386
386
|
// so a host renders no toggle.
|
|
387
387
|
const canToggleEditing = Boolean(controllerContext?.setCode) && !disabled;
|
|
388
|
+
|
|
389
|
+
// Discard live edits when the reader switches language.
|
|
390
|
+
const rawSelectTransform = transformManagement.selectTransform;
|
|
391
|
+
const resetSource = sourceEditing.reset;
|
|
392
|
+
const hasControlledEdits = Boolean(controllerContext?.code);
|
|
393
|
+
const selectTransform = React.useCallback(transformName => {
|
|
394
|
+
if (hasControlledEdits) {
|
|
395
|
+
resetSource?.();
|
|
396
|
+
}
|
|
397
|
+
rawSelectTransform(transformName);
|
|
398
|
+
}, [hasControlledEdits, resetSource, rawSelectTransform]);
|
|
388
399
|
return {
|
|
389
400
|
variants: variantSelection.variantKeys,
|
|
390
401
|
selectedVariant: variantSelection.selectedVariantKey,
|
|
@@ -404,7 +415,7 @@ export function useCode(contentProps, opts) {
|
|
|
404
415
|
copyMarkdown: copyFunctionality.copyMarkdown,
|
|
405
416
|
availableTransforms: transformManagement.availableTransforms,
|
|
406
417
|
selectedTransform: transformManagement.selectedTransform,
|
|
407
|
-
selectTransform
|
|
418
|
+
selectTransform,
|
|
408
419
|
pendingTransform: transformManagement.pendingTransform,
|
|
409
420
|
editable: uiState.editable,
|
|
410
421
|
setEditable: canToggleEditing ? uiState.setEditable : undefined,
|
|
@@ -246,7 +246,7 @@ export function useSourceEditing({
|
|
|
246
246
|
// survive the reset and the source viewer could reuse it for the rebuilt original.
|
|
247
247
|
context?.preParsedCache?.clear();
|
|
248
248
|
// Back to an empty controlled state, so the next edit re-tags `.original`.
|
|
249
|
-
contextSetCode(
|
|
249
|
+
contextSetCode(null);
|
|
250
250
|
}, [contextSetCode, context?.preParsedCache]);
|
|
251
251
|
const isEditable = !disabled && Boolean(contextSetCode) && Boolean(selectedVariant);
|
|
252
252
|
const canReset = !disabled && Boolean(contextSetCode);
|
|
@@ -122,7 +122,19 @@ export function useTransformManagement({
|
|
|
122
122
|
// here, otherwise rename-only entries would be dropped from
|
|
123
123
|
// resolution and the storage key would shift whenever a transform's
|
|
124
124
|
// visibility changed between sibling demos.
|
|
125
|
-
const
|
|
125
|
+
const contextAvailableTransforms = context?.availableTransforms;
|
|
126
|
+
// What the CURRENT (possibly edited) code can actually apply. Empty while
|
|
127
|
+
// live-editing, since controlled code carries no transform manifest.
|
|
128
|
+
const applicableFromCode = React.useMemo(() => getApplicableTransforms(effectiveCode, selectedVariantKey), [effectiveCode, selectedVariantKey]);
|
|
129
|
+
const applicableTransforms = React.useMemo(() => {
|
|
130
|
+
// Fall back to the controller's visible list while editing so a language
|
|
131
|
+
// switch still validates — it discards the edit and re-applies to the
|
|
132
|
+
// pristine build-time source (see `useCode.selectTransform`).
|
|
133
|
+
if (applicableFromCode.length === 0 && contextAvailableTransforms?.length) {
|
|
134
|
+
return contextAvailableTransforms;
|
|
135
|
+
}
|
|
136
|
+
return applicableFromCode;
|
|
137
|
+
}, [applicableFromCode, contextAvailableTransforms]);
|
|
126
138
|
|
|
127
139
|
// Coordinator key. Demos sharing the same applicable transform set
|
|
128
140
|
// belong to the same coordination group: a user click in one demo
|
|
@@ -509,6 +521,11 @@ export function useTransformManagement({
|
|
|
509
521
|
// `onCommit` when its `(variant, transform)` keys match the values
|
|
510
522
|
// about to be rendered.
|
|
511
523
|
const transformedFiles = React.useMemo(() => {
|
|
524
|
+
// While live-editing, `selectedTransform` may still be e.g. `js`, so
|
|
525
|
+
// return `undefined` to render the edited source as-is (see `useFileNavigation`).
|
|
526
|
+
if (delayedAppliedTransform && !applicableFromCode.includes(delayedAppliedTransform)) {
|
|
527
|
+
return undefined;
|
|
528
|
+
}
|
|
512
529
|
if (precomputed && precomputed.variant === selectedVariant && precomputed.transform === delayedAppliedTransform) {
|
|
513
530
|
return precomputed.result;
|
|
514
531
|
}
|
|
@@ -521,7 +538,7 @@ export function useTransformManagement({
|
|
|
521
538
|
return undefined;
|
|
522
539
|
}
|
|
523
540
|
return transformEngine(selectedVariant, delayedAppliedTransform, transformRuntimeDeps, context?.fallbacks);
|
|
524
|
-
}, [precomputed, selectedVariant, delayedAppliedTransform, context?.fallbacks, transformEngine]);
|
|
541
|
+
}, [precomputed, selectedVariant, delayedAppliedTransform, applicableFromCode, context?.fallbacks, transformEngine]);
|
|
525
542
|
const result = {
|
|
526
543
|
availableTransforms,
|
|
527
544
|
selectedTransform,
|
|
@@ -1,26 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { ControlledCode } from '@mui/internal-docs-infra/CodeHighlighter/types';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* to opt a demo out. SSR-safe — the channel only opens in the browser.
|
|
8
|
-
*/
|
|
9
|
-
crossTabSync?: boolean;
|
|
3
|
+
import type { CodeControllerContext } from '@mui/internal-docs-infra/CodeControllerContext';
|
|
4
|
+
export interface UseDemoControllerResult {
|
|
5
|
+
/** The controlled source, keyed by variant. `null` until the first edit. */
|
|
6
|
+
code: ControlledCode | null;
|
|
10
7
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* only with its counterpart in the other tab. Without it, sync falls back to
|
|
15
|
-
* page-level — correct only when the page has a single demo.
|
|
8
|
+
* Updates the controlled source (e.g. as a reader edits a variant). Typed as the
|
|
9
|
+
* context's `setCode` (`Dispatch<SetStateAction>`) so the whole result drops straight
|
|
10
|
+
* into a `CodeControllerContext.Provider` with no cast.
|
|
16
11
|
*/
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
export interface UseDemoControllerResult {
|
|
20
|
-
/** The controlled source, keyed by variant. `undefined` until the first edit. */
|
|
21
|
-
code: ControlledCode | undefined;
|
|
22
|
-
/** Updates the controlled source (e.g. as a reader edits a variant). */
|
|
23
|
-
setCode: React.Dispatch<React.SetStateAction<ControlledCode | undefined>>;
|
|
12
|
+
setCode: NonNullable<CodeControllerContext['setCode']>;
|
|
24
13
|
/**
|
|
25
14
|
* One live preview node per variant, keyed by variant — for the variants that
|
|
26
15
|
* have finished building. `undefined` until at least one is ready, so a host can
|
|
@@ -62,4 +51,4 @@ export interface UseDemoControllerResult {
|
|
|
62
51
|
* page (via the `crossTabSync` option), so a reader editing a demo in a Chrome split
|
|
63
52
|
* view sees it update in both panes.
|
|
64
53
|
*/
|
|
65
|
-
export declare function useDemoController(
|
|
54
|
+
export declare function useDemoController(): UseDemoControllerResult;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { useCodeExternals } from '@mui/internal-docs-infra/CodeExternalsContext';
|
|
5
|
-
import { useCrossTabState } from '@mui/internal-docs-infra/useCrossTabState';
|
|
6
5
|
import { getTranspile } from "./transpileClientSingleton.mjs";
|
|
7
6
|
import { useVariantBuilds } from "./useVariantBuilds.mjs";
|
|
8
7
|
|
|
@@ -49,22 +48,8 @@ const DemoRunner = /*#__PURE__*/React.lazy(() => preloadBuildEngine().then(modul
|
|
|
49
48
|
* page (via the `crossTabSync` option), so a reader editing a demo in a Chrome split
|
|
50
49
|
* view sees it update in both panes.
|
|
51
50
|
*/
|
|
52
|
-
export function useDemoController(
|
|
53
|
-
const
|
|
54
|
-
crossTabSync = true,
|
|
55
|
-
url
|
|
56
|
-
} = options;
|
|
57
|
-
// The controlled code, owned here and mirrored across same-origin tabs of this page.
|
|
58
|
-
// The channel name combines the page path with the per-demo `url`, so split-view tabs
|
|
59
|
-
// of one page sync each demo independently; `null` (disabled, or on the server) opens
|
|
60
|
-
// no channel and `useCrossTabState` behaves like a plain `useState`.
|
|
61
|
-
const syncChannel = React.useMemo(() => {
|
|
62
|
-
if (!crossTabSync || typeof window === 'undefined') {
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
return `mui-docs-infra:demo-controller:${window.location.pathname}\u0000${url ?? ''}`;
|
|
66
|
-
}, [crossTabSync, url]);
|
|
67
|
-
const [code, setControlledCode] = useCrossTabState(syncChannel, undefined);
|
|
51
|
+
export function useDemoController() {
|
|
52
|
+
const [code, setControlledCode] = React.useState(null);
|
|
68
53
|
// Build errors (transpile/CSS failures) and render errors (the entry throwing) live
|
|
69
54
|
// in SEPARATE maps so they never clobber each other: a build error is owned by
|
|
70
55
|
// `useVariantBuilds` (set on failure, cleared on the next good build); a render
|
|
@@ -102,11 +87,10 @@ export function useDemoController(options = {}) {
|
|
|
102
87
|
// effect; the length guards keep each clear a no-op once its map is empty.
|
|
103
88
|
const setCode = React.useCallback(action => {
|
|
104
89
|
setControlledCode(action);
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
setRenderErrors(previous => Object.keys(previous).length > 0 ? {} : previous);
|
|
90
|
+
// Drop stale errors alongside a reset (`code` cleared to `null`).
|
|
91
|
+
if (!action) {
|
|
92
|
+
setBuildErrors({});
|
|
93
|
+
setRenderErrors({});
|
|
110
94
|
}
|
|
111
95
|
}, [setControlledCode]);
|
|
112
96
|
|
|
@@ -28,4 +28,4 @@ export interface VariantBuild {
|
|
|
28
28
|
* first-build-done set, and the deferred edit) lives in refs since it never
|
|
29
29
|
* affects render; only the resolved `built` map is state.
|
|
30
30
|
*/
|
|
31
|
-
export declare function useVariantBuilds(code: ControlledCode | undefined, transpile: Transpile | null, externals: Record<string, unknown>, report: (variant: string, message: string | null) => void): Record<string, VariantBuild>;
|
|
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>;
|
|
@@ -139,7 +139,7 @@ export function useVariantBuilds(code, transpile, externals, report) {
|
|
|
139
139
|
}
|
|
140
140
|
// The attempt finished (failed) — later edits may now cancel.
|
|
141
141
|
firstBuildDone.current.add(variant);
|
|
142
|
-
report(variant, thrown instanceof Error ? thrown.
|
|
142
|
+
report(variant, thrown instanceof Error ? thrown.toString() : String(thrown));
|
|
143
143
|
buildDeferred();
|
|
144
144
|
});
|
|
145
145
|
};
|