@mui/internal-docs-infra 0.11.1-canary.21 → 0.11.1-canary.22
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/CodeHighlighter/CodeHighlighter.mjs +11 -2
- package/CodeHighlighter/CodeHighlighterClient.mjs +60 -51
- package/CodeHighlighter/createClientProps.mjs +14 -3
- package/CodeHighlighter/fallbackFormat.d.mts +38 -0
- package/CodeHighlighter/fallbackFormat.mjs +96 -3
- package/CodeHighlighter/prepareInitialSource.d.mts +11 -0
- package/CodeHighlighter/prepareInitialSource.mjs +67 -8
- package/CodeHighlighter/resolveFallbackCritical.d.mts +23 -0
- package/CodeHighlighter/resolveFallbackCritical.mjs +44 -0
- package/CodeHighlighter/types.d.mts +16 -0
- package/CoordinatedLazy/useChunk.mjs +10 -8
- package/CoordinatedLazy/useCoordinatedSwap.mjs +1 -0
- package/abstractCreateTypes/TypeCode.mjs +12 -11
- package/abstractCreateTypes/typesToJsx.mjs +13 -8
- package/package.json +2 -2
- package/pipeline/loadIsomorphicCodeVariant/loadIsomorphicCodeVariant.mjs +41 -1
- package/pipeline/parseSource/frameVisibility.d.mts +17 -1
- package/pipeline/parseSource/frameVisibility.mjs +53 -0
- package/useCode/EditableEngine.mjs +15 -5
- package/useCode/Pre.mjs +43 -48
- package/useCode/SourceEditingEngine.mjs +29 -8
- package/useCode/useCode.mjs +11 -3
- package/useCode/{liveEditingBugs.browser.mjs → useEditable.integration.browser.mjs} +114 -69
- package/useCode/useFileNavigation.mjs +20 -16
- package/useCode/useTransformManagement.mjs +13 -5
- package/useCode/useUIState.mjs +6 -6
- package/useCode/useVariantSelection.mjs +20 -6
- package/useCoordinated/coordinatePreference.mjs +4 -25
- package/useCoordinated/scheduleTasks.d.mts +23 -0
- package/useCoordinated/scheduleTasks.mjs +45 -0
- package/useCoordinated/useCoordinated.mjs +33 -6
- package/useStream/useStream.mjs +2 -4
- package/useStream/useStreamController.mjs +6 -1
- /package/useCode/{liveEditingBugs.browser.d.mts → useEditable.integration.browser.d.mts} +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Internal task-scheduling primitives shared by the coordination/render-timing
|
|
2
|
+
// code (and a few consumers that gate heavy work off the critical path). Kept
|
|
3
|
+
// here rather than in a `*Utils` barrel so it stays an internal helper, not a
|
|
4
|
+
// published API surface. Not re-exported from `index.ts`.
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Yield the current task back to the browser so it can paint and process input
|
|
8
|
+
* before the awaited continuation runs.
|
|
9
|
+
*
|
|
10
|
+
* Uses `scheduler.yield()` when available (modern Chromium) for better priority
|
|
11
|
+
* handling; falls back to `setTimeout(_, 0)`, which macrotask-defers in every
|
|
12
|
+
* browser, in Node/SSR, and in fake-timer test environments.
|
|
13
|
+
*/
|
|
14
|
+
export function yieldToMain() {
|
|
15
|
+
const {
|
|
16
|
+
scheduler
|
|
17
|
+
} = globalThis;
|
|
18
|
+
if (typeof scheduler?.yield === 'function') {
|
|
19
|
+
return scheduler.yield();
|
|
20
|
+
}
|
|
21
|
+
return new Promise(resolve => {
|
|
22
|
+
setTimeout(resolve, 0);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Run `task` during the browser's first idle period, falling back to
|
|
28
|
+
* `setTimeout(task, 0)` where `requestIdleCallback` is unavailable (Safari,
|
|
29
|
+
* Node/SSR, fake timers). Use this for genuinely deferrable background work
|
|
30
|
+
* (e.g. stale-while-revalidate refreshes, the `idle` highlight/enhance swap)
|
|
31
|
+
* that should wait for the main thread to be free.
|
|
32
|
+
*
|
|
33
|
+
* @param options.timeout forwarded to `requestIdleCallback` so the task still
|
|
34
|
+
* runs even if the browser never goes idle.
|
|
35
|
+
* @returns a function that cancels the task if it has not run yet.
|
|
36
|
+
*/
|
|
37
|
+
export function requestIdle(task, options) {
|
|
38
|
+
const idleGlobals = globalThis;
|
|
39
|
+
if (idleGlobals.requestIdleCallback) {
|
|
40
|
+
const handle = idleGlobals.requestIdleCallback(task, options);
|
|
41
|
+
return () => idleGlobals.cancelIdleCallback?.(handle);
|
|
42
|
+
}
|
|
43
|
+
const handle = setTimeout(task, 0);
|
|
44
|
+
return () => clearTimeout(handle);
|
|
45
|
+
}
|
|
@@ -59,7 +59,11 @@ export function useCoordinated(underlying, options) {
|
|
|
59
59
|
lazyCommitPriority = 'idle'
|
|
60
60
|
} = options;
|
|
61
61
|
|
|
62
|
-
// Stable peer id for the lifetime of the mounted component.
|
|
62
|
+
// Stable peer id for the lifetime of the mounted component. Held in a ref so an
|
|
63
|
+
// auto-generated fallback stays stable across renders, an explicit `peerId` prop
|
|
64
|
+
// wins and resyncs on change, and an explicit id later removed keeps the last
|
|
65
|
+
// explicit value. The registration effect keys off [channelKey, peerId].
|
|
66
|
+
/* eslint-disable react-hooks/refs -- deliberate stable-id ref: lazy init + explicit-prop resync during render; the ref is identity memory, never read for rendering output */
|
|
63
67
|
const peerIdRef = React.useRef(null);
|
|
64
68
|
if (peerIdRef.current === null) {
|
|
65
69
|
peerIdRef.current = explicitPeerId ?? generatePeerId();
|
|
@@ -67,6 +71,7 @@ export function useCoordinated(underlying, options) {
|
|
|
67
71
|
peerIdRef.current = explicitPeerId;
|
|
68
72
|
}
|
|
69
73
|
const peerId = peerIdRef.current;
|
|
74
|
+
/* eslint-enable react-hooks/refs */
|
|
70
75
|
|
|
71
76
|
// The visible (committed) value. Lags `underlyingValue` while a
|
|
72
77
|
// phase-1 barrier is open in the receiver flow.
|
|
@@ -84,10 +89,13 @@ export function useCoordinated(underlying, options) {
|
|
|
84
89
|
onCommit,
|
|
85
90
|
setUnderlyingValue
|
|
86
91
|
});
|
|
92
|
+
/* eslint-disable react-hooks/refs -- latest-ref pattern: cache current callbacks for the once-registered peer and long-lived runCoordination closure; intentionally excluded from effect/useCallback deps to avoid re-registering on inline-function identity churn */
|
|
87
93
|
callbacksRef.current.causesLayoutShift = causesLayoutShift;
|
|
88
94
|
callbacksRef.current.preload = preload;
|
|
89
95
|
callbacksRef.current.onCommit = onCommit;
|
|
90
96
|
callbacksRef.current.setUnderlyingValue = setUnderlyingValue;
|
|
97
|
+
/* eslint-enable react-hooks/refs */
|
|
98
|
+
|
|
91
99
|
const timingRef = React.useRef({
|
|
92
100
|
minWaitMs,
|
|
93
101
|
multiPeerExtraMinWaitMs,
|
|
@@ -97,6 +105,7 @@ export function useCoordinated(underlying, options) {
|
|
|
97
105
|
animateDuringPreload,
|
|
98
106
|
lazyCommitPriority
|
|
99
107
|
});
|
|
108
|
+
/* eslint-disable react-hooks/refs -- latest-ref pattern: cache current timing options for the once-registered peer and long-lived runCoordination closure; intentionally excluded from effect/useCallback deps to avoid re-registering on option identity churn */
|
|
100
109
|
timingRef.current.minWaitMs = minWaitMs;
|
|
101
110
|
timingRef.current.multiPeerExtraMinWaitMs = multiPeerExtraMinWaitMs;
|
|
102
111
|
timingRef.current.lazyMinWaitMs = lazyMinWaitMs;
|
|
@@ -104,6 +113,7 @@ export function useCoordinated(underlying, options) {
|
|
|
104
113
|
timingRef.current.ultimateTimeoutMs = ultimateTimeoutMs;
|
|
105
114
|
timingRef.current.animateDuringPreload = animateDuringPreload;
|
|
106
115
|
timingRef.current.lazyCommitPriority = lazyCommitPriority;
|
|
116
|
+
/* eslint-enable react-hooks/refs */
|
|
107
117
|
|
|
108
118
|
// In-flight handle so we can cancel/supersede.
|
|
109
119
|
const handleRef = React.useRef(null);
|
|
@@ -291,9 +301,10 @@ export function useCoordinated(underlying, options) {
|
|
|
291
301
|
} else if (!layoutShiftsSettled() && callbacksRef.current.causesLayoutShift(target)) {
|
|
292
302
|
// No user preload, but the target shifts layout and the gate is still
|
|
293
303
|
// closed: synthesize a preload that only awaits the gate so the commit
|
|
294
|
-
// still holds until the page settles (
|
|
295
|
-
// only inside the user-preload wrapper, so
|
|
296
|
-
// no preload
|
|
304
|
+
// still holds until the page settles (the gate is otherwise consulted
|
|
305
|
+
// only inside the user-preload wrapper, so without this branch a
|
|
306
|
+
// layout-shifting peer with no preload would skip coordination entirely).
|
|
307
|
+
// Once the gate has opened
|
|
297
308
|
// this branch is skipped, so steady-state layout-shifting commits keep
|
|
298
309
|
// the synchronous fast path. The gate wait rejects `AbortError` on
|
|
299
310
|
// supersede, which propagates into the engine's `await preload(...)`
|
|
@@ -365,6 +376,7 @@ export function useCoordinated(underlying, options) {
|
|
|
365
376
|
// Keep the ref pointed at the latest `runCoordination` so the
|
|
366
377
|
// peer-registration callback (set once at mount) always invokes
|
|
367
378
|
// the current closure.
|
|
379
|
+
// eslint-disable-next-line react-hooks/refs -- forward-declared latest-ref: the once-registered peer callback must invoke the current runCoordination closure without re-registering
|
|
368
380
|
runCoordinationRef.current = runCoordination;
|
|
369
381
|
|
|
370
382
|
// Receiver flow: external `underlyingValue` change that we did not
|
|
@@ -376,11 +388,13 @@ export function useCoordinated(underlying, options) {
|
|
|
376
388
|
// the originator's barrier window.
|
|
377
389
|
React.useLayoutEffect(() => {
|
|
378
390
|
if (channelKey === null) {
|
|
391
|
+
// Coordination disabled: the hook is a transparent pass-through,
|
|
392
|
+
// so the visible value / pending value are derived directly from
|
|
393
|
+
// `underlyingValue` at the return rather than mirrored into state.
|
|
394
|
+
// Only reset the in-flight ref here.
|
|
379
395
|
inFlightTargetRef.current = {
|
|
380
396
|
has: false
|
|
381
397
|
};
|
|
382
|
-
setCommittedValue(underlyingValue);
|
|
383
|
-
setPendingValue(underlyingValue);
|
|
384
398
|
return;
|
|
385
399
|
}
|
|
386
400
|
if (lastWrittenRef.current.has) {
|
|
@@ -419,6 +433,7 @@ export function useCoordinated(underlying, options) {
|
|
|
419
433
|
// setter, the originator flow drives every cycle.
|
|
420
434
|
return;
|
|
421
435
|
}
|
|
436
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect -- receiver flow: runCoordination drives the coordination state machine in response to an external underlyingValue change; this is the genuine effect side-effect, not derivable during render
|
|
422
437
|
runCoordination(underlyingValue, false);
|
|
423
438
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
424
439
|
}, [channelKey, underlyingValue, runCoordination]);
|
|
@@ -438,5 +453,17 @@ export function useCoordinated(underlying, options) {
|
|
|
438
453
|
isCoordinating,
|
|
439
454
|
isWaitingForPeers
|
|
440
455
|
}), [pendingValue, isCoordinating, isWaitingForPeers]);
|
|
456
|
+
|
|
457
|
+
// When coordination is disabled the hook is a transparent
|
|
458
|
+
// pass-through: derive the visible value, pending value, and inert
|
|
459
|
+
// coordination flags straight from `underlyingValue` rather than
|
|
460
|
+
// mirroring it into `committedValue` / `pendingValue` state.
|
|
461
|
+
if (channelKey === null) {
|
|
462
|
+
return [underlyingValue, coordinatedSetValue, {
|
|
463
|
+
pendingValue: underlyingValue,
|
|
464
|
+
isCoordinating: false,
|
|
465
|
+
isWaitingForPeers: false
|
|
466
|
+
}];
|
|
467
|
+
}
|
|
441
468
|
return [committedValue, coordinatedSetValue, extras];
|
|
442
469
|
}
|
package/useStream/useStream.mjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { streamChunks } from "./streamChunks.mjs";
|
|
5
5
|
import { useStreamController } from "./useStreamController.mjs";
|
|
6
|
+
import { requestIdle } from "../useCoordinated/scheduleTasks.mjs";
|
|
6
7
|
|
|
7
8
|
/** Options for {@link useStream}. */
|
|
8
9
|
|
|
@@ -99,10 +100,7 @@ export function useStream(options) {
|
|
|
99
100
|
if (!revalidateOnIdle || !streamComplete || typeof window === 'undefined') {
|
|
100
101
|
return undefined;
|
|
101
102
|
}
|
|
102
|
-
|
|
103
|
-
const cancelIdle = window.cancelIdleCallback ?? clearTimeout;
|
|
104
|
-
const handle = requestIdle(() => refresh());
|
|
105
|
-
return () => cancelIdle(handle);
|
|
103
|
+
return requestIdle(() => refresh());
|
|
106
104
|
}, [revalidateOnIdle, streamComplete, refresh]);
|
|
107
105
|
|
|
108
106
|
// Loading until the list has finished streaming AND every rendered chunk has
|
|
@@ -52,7 +52,11 @@ export function useStreamController(options = {}) {
|
|
|
52
52
|
React.useEffect(() => {
|
|
53
53
|
// Chunks register in their own (child) effects, which run before this
|
|
54
54
|
// (parent) effect - so by now the gate reflects every chunk present in the
|
|
55
|
-
// initial commit.
|
|
55
|
+
// initial commit. These setState calls cannot move to render: at render
|
|
56
|
+
// time the gate is still unarmed, so `gate.isSettled()` returns `true` and a
|
|
57
|
+
// render-time derivation would wrongly report 'done' immediately. Only after
|
|
58
|
+
// the child effects register does the gate reflect the initial-commit chunks.
|
|
59
|
+
/* eslint-disable react-hooks/set-state-in-effect -- gate.isSettled() only reflects child chunks after their (child) effects register them; this parent effect runs after, so the value is unavailable during render */
|
|
56
60
|
if (gate.isSettled()) {
|
|
57
61
|
setLoading(false);
|
|
58
62
|
return undefined;
|
|
@@ -69,6 +73,7 @@ export function useStreamController(options = {}) {
|
|
|
69
73
|
} else {
|
|
70
74
|
setLoading(false);
|
|
71
75
|
}
|
|
76
|
+
/* eslint-enable react-hooks/set-state-in-effect */
|
|
72
77
|
return () => {
|
|
73
78
|
cancelled = true;
|
|
74
79
|
};
|
|
File without changes
|