@mui/internal-docs-infra 0.11.1-canary.8 → 0.11.1
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/ChunkContext.d.mts +10 -0
- package/ChunkProvider/ChunkContext.mjs +15 -0
- package/ChunkProvider/ChunkProvider.d.mts +14 -0
- package/ChunkProvider/ChunkProvider.mjs +38 -0
- package/ChunkProvider/PreloadContext.d.mts +14 -0
- package/ChunkProvider/PreloadContext.mjs +18 -0
- package/ChunkProvider/PreloadProvider.d.mts +13 -0
- package/ChunkProvider/PreloadProvider.mjs +33 -0
- package/ChunkProvider/index.d.mts +7 -0
- package/ChunkProvider/index.mjs +7 -0
- package/ChunkProvider/types.d.mts +23 -0
- package/ChunkProvider/types.mjs +1 -0
- package/ChunkProvider/usePreload.d.mts +8 -0
- package/ChunkProvider/usePreload.mjs +21 -0
- package/CodeControllerContext/CodeControllerContext.d.mts +11 -0
- package/CodeControllerContext/CodeControllerContext.mjs +2 -1
- package/CodeHighlighter/CodeHighlighter.d.mts +15 -1
- package/CodeHighlighter/CodeHighlighter.mjs +97 -319
- package/CodeHighlighter/CodeHighlighterChunk.d.mts +42 -0
- package/CodeHighlighter/CodeHighlighterChunk.mjs +77 -0
- package/CodeHighlighter/CodeHighlighterClient.mjs +597 -128
- package/CodeHighlighter/CodeHighlighterContext.d.mts +57 -1
- package/CodeHighlighter/CodeHighlighterFallbackContext.d.mts +14 -2
- package/CodeHighlighter/CodeHighlighterFallbackContext.mjs +1 -3
- package/CodeHighlighter/CodeInitialSourceLoader.d.mts +10 -0
- package/CodeHighlighter/CodeInitialSourceLoader.mjs +108 -0
- package/CodeHighlighter/CodeSourceLoader.d.mts +11 -0
- package/CodeHighlighter/CodeSourceLoader.mjs +128 -0
- package/CodeHighlighter/buildCodeHighlighterChunkProps.d.mts +47 -0
- package/CodeHighlighter/buildCodeHighlighterChunkProps.mjs +61 -0
- package/CodeHighlighter/buildStringFallback.d.mts +29 -0
- package/CodeHighlighter/buildStringFallback.mjs +42 -0
- package/CodeHighlighter/codeToFallbackProps.d.mts +31 -2
- package/CodeHighlighter/codeToFallbackProps.mjs +347 -42
- package/CodeHighlighter/createClientProps.d.mts +17 -0
- package/CodeHighlighter/createClientProps.mjs +78 -0
- package/CodeHighlighter/errors.d.mts +6 -0
- package/CodeHighlighter/errors.mjs +10 -0
- package/CodeHighlighter/fallbackCompression.d.mts +96 -0
- package/CodeHighlighter/fallbackCompression.mjs +253 -0
- package/CodeHighlighter/fallbackFormat.d.mts +137 -0
- package/CodeHighlighter/fallbackFormat.mjs +422 -0
- package/CodeHighlighter/index.d.mts +4 -1
- package/CodeHighlighter/index.mjs +3 -1
- package/CodeHighlighter/mergeComments.d.mts +38 -0
- package/CodeHighlighter/mergeComments.mjs +80 -0
- package/CodeHighlighter/prepareInitialSource.d.mts +42 -0
- package/CodeHighlighter/prepareInitialSource.mjs +292 -0
- package/CodeHighlighter/resolveFallbackCritical.d.mts +23 -0
- package/CodeHighlighter/resolveFallbackCritical.mjs +44 -0
- package/CodeHighlighter/types.d.mts +272 -8
- package/CodeHighlighter/useCodeFallback.d.mts +94 -0
- package/CodeHighlighter/useCodeFallback.mjs +204 -0
- package/CodeHighlighter/useGrammarsReady.d.mts +18 -0
- package/CodeHighlighter/useGrammarsReady.mjs +45 -0
- package/CodeHighlighter/useSpeculativeCodePreload.d.mts +26 -0
- package/CodeHighlighter/useSpeculativeCodePreload.mjs +40 -0
- package/CodeHighlighter/useSpeculativeEditingPreload.d.mts +33 -0
- package/CodeHighlighter/useSpeculativeEditingPreload.mjs +58 -0
- package/CodeHighlighter/useSpeculativeGrammarPreload.d.mts +23 -0
- package/CodeHighlighter/useSpeculativeGrammarPreload.mjs +31 -0
- package/CodeHighlighter/useSpeculativeUseCodePreload.d.mts +22 -0
- package/CodeHighlighter/useSpeculativeUseCodePreload.mjs +41 -0
- package/CodeProvider/CodeContext.d.mts +47 -12
- package/CodeProvider/CodeContext.mjs +7 -0
- package/CodeProvider/CodeProvider.d.mts +4 -2
- package/CodeProvider/CodeProvider.mjs +40 -102
- package/CodeProvider/CodeProviderLazy.d.mts +40 -0
- package/CodeProvider/CodeProviderLazy.mjs +96 -0
- package/CodeProvider/constants.d.mts +26 -0
- package/CodeProvider/constants.mjs +24 -0
- package/CodeProvider/createParseSourceWorkerClient.d.mts +6 -0
- package/CodeProvider/createParseSourceWorkerClient.mjs +22 -2
- package/CodeProvider/index.d.mts +2 -1
- package/CodeProvider/index.mjs +9 -1
- package/CodeProvider/parseSourceWorker.mjs +33 -0
- package/CodeProvider/useCodeProviderValue.d.mts +54 -0
- package/CodeProvider/useCodeProviderValue.mjs +188 -0
- package/CoordinatedLazy/ChunkServerLoader.d.mts +25 -0
- package/CoordinatedLazy/ChunkServerLoader.mjs +97 -0
- package/CoordinatedLazy/CoordinatedContentContext.d.mts +15 -0
- package/CoordinatedLazy/CoordinatedContentContext.mjs +22 -0
- package/CoordinatedLazy/CoordinatedFallbackContext.d.mts +11 -0
- package/CoordinatedLazy/CoordinatedFallbackContext.mjs +13 -0
- package/CoordinatedLazy/CoordinatedGateContext.d.mts +14 -0
- package/CoordinatedLazy/CoordinatedGateContext.mjs +19 -0
- package/CoordinatedLazy/CoordinatedLazy.d.mts +14 -0
- package/CoordinatedLazy/CoordinatedLazy.mjs +86 -0
- package/CoordinatedLazy/CoordinatedLazyClient.d.mts +24 -0
- package/CoordinatedLazy/CoordinatedLazyClient.mjs +65 -0
- package/CoordinatedLazy/LazyContent.d.mts +26 -0
- package/CoordinatedLazy/LazyContent.mjs +80 -0
- package/CoordinatedLazy/LazyContentServer.d.mts +18 -0
- package/CoordinatedLazy/LazyContentServer.mjs +25 -0
- package/CoordinatedLazy/buildChunkRenderInputs.d.mts +8 -0
- package/CoordinatedLazy/buildChunkRenderInputs.mjs +35 -0
- package/CoordinatedLazy/createCoordinatedLazy.d.mts +32 -0
- package/CoordinatedLazy/createCoordinatedLazy.mjs +127 -0
- package/CoordinatedLazy/index.d.mts +14 -0
- package/CoordinatedLazy/index.mjs +18 -0
- package/CoordinatedLazy/resolveChunkRender.d.mts +26 -0
- package/CoordinatedLazy/resolveChunkRender.mjs +73 -0
- package/CoordinatedLazy/types.d.mts +408 -0
- package/CoordinatedLazy/types.mjs +1 -0
- package/CoordinatedLazy/useChunk.d.mts +30 -0
- package/CoordinatedLazy/useChunk.mjs +135 -0
- package/CoordinatedLazy/useCoordinatedFallback.d.mts +12 -0
- package/CoordinatedLazy/useCoordinatedFallback.mjs +40 -0
- package/CoordinatedLazy/useCoordinatedSwap.d.mts +16 -0
- package/CoordinatedLazy/useCoordinatedSwap.mjs +124 -0
- package/LICENSE +1 -1
- package/abstractCreateDemo/abstractCreateDemo.d.mts +54 -3
- package/abstractCreateDemo/abstractCreateDemo.mjs +47 -7
- package/abstractCreateDemo/resolveDemoFlag.d.mts +20 -0
- package/abstractCreateDemo/resolveDemoFlag.mjs +25 -0
- package/abstractCreateStream/abstractCreateStream.d.mts +18 -0
- package/abstractCreateStream/abstractCreateStream.mjs +45 -0
- package/abstractCreateStream/index.d.mts +2 -0
- package/abstractCreateStream/index.mjs +1 -0
- package/abstractCreateStream/types.d.mts +34 -0
- package/abstractCreateStream/types.mjs +1 -0
- package/abstractCreateTypes/TypeCode.mjs +12 -11
- package/abstractCreateTypes/typesToJsx.mjs +30 -9
- package/cli/ensureDemoClients.mjs +4 -148
- package/cli/ensureDemoPages.d.mts +45 -0
- package/cli/ensureDemoPages.mjs +99 -0
- package/cli/fileUtils/index.d.mts +11 -0
- package/cli/fileUtils/index.mjs +48 -0
- package/cli/findDemoIndexFiles.d.mts +15 -0
- package/cli/findDemoIndexFiles.mjs +121 -0
- package/cli/index.mjs +1 -1
- package/cli/loadNextConfig.d.mts +25 -0
- package/cli/loadNextConfig.mjs +60 -1
- package/cli/runBrowser.mjs +1 -1
- package/cli/runValidate.mjs +44 -1
- package/package.json +85 -5
- package/pipeline/enhanceCodeEmphasis/enhanceCodeEmphasis.mjs +30 -0
- package/pipeline/enhanceCodeEmphasis/enhanceCodeEmphasisLazy.d.mts +17 -0
- package/pipeline/enhanceCodeEmphasis/enhanceCodeEmphasisLazy.mjs +52 -0
- package/pipeline/hastUtils/frameFallbackFromSpans.d.mts +18 -0
- package/pipeline/hastUtils/frameFallbackFromSpans.mjs +24 -0
- package/pipeline/hastUtils/hast.d.mts +27 -0
- package/pipeline/hastUtils/hastCompression.d.mts +3 -1
- package/pipeline/hastUtils/hastCompression.mjs +9 -1
- package/pipeline/hastUtils/hastDecompress.mjs +10 -4
- package/pipeline/hastUtils/hastDictionary.mjs +9 -0
- package/pipeline/hastUtils/hastUtils.d.mts +4 -3
- package/pipeline/hastUtils/hastUtils.mjs +24 -12
- package/pipeline/hastUtils/index.d.mts +2 -1
- package/pipeline/hastUtils/index.mjs +2 -1
- package/pipeline/hastUtils/stripHighlightingSpans.d.mts +6 -2
- package/pipeline/hastUtils/stripHighlightingSpans.mjs +22 -10
- package/pipeline/lintJavascriptDemoFocus/lintJavascriptDemoFocus.mjs +10 -7
- package/pipeline/loadIsomorphicCodeVariant/applyCodeTransform.d.mts +31 -13
- package/pipeline/loadIsomorphicCodeVariant/applyCodeTransform.mjs +50 -55
- package/pipeline/loadIsomorphicCodeVariant/applyCodeTransformWithComments.d.mts +78 -0
- package/pipeline/loadIsomorphicCodeVariant/applyCodeTransformWithComments.mjs +405 -0
- package/pipeline/loadIsomorphicCodeVariant/computeHastDeltas.d.mts +5 -5
- package/pipeline/loadIsomorphicCodeVariant/computeHastDeltas.mjs +36 -66
- package/pipeline/loadIsomorphicCodeVariant/decodeHastSource.d.mts +23 -0
- package/pipeline/loadIsomorphicCodeVariant/decodeHastSource.mjs +92 -0
- package/pipeline/loadIsomorphicCodeVariant/decodeSource.d.mts +19 -0
- package/pipeline/loadIsomorphicCodeVariant/decodeSource.mjs +25 -0
- package/pipeline/loadIsomorphicCodeVariant/decodeSourceToText.d.mts +17 -0
- package/pipeline/loadIsomorphicCodeVariant/decodeSourceToText.mjs +26 -0
- package/pipeline/loadIsomorphicCodeVariant/diffHast.d.mts +26 -2
- package/pipeline/loadIsomorphicCodeVariant/diffHast.mjs +563 -19
- package/pipeline/loadIsomorphicCodeVariant/embedTransforms.d.mts +49 -0
- package/pipeline/loadIsomorphicCodeVariant/embedTransforms.mjs +152 -0
- package/pipeline/loadIsomorphicCodeVariant/findExpandingRanges.d.mts +51 -0
- package/pipeline/loadIsomorphicCodeVariant/findExpandingRanges.mjs +161 -0
- package/pipeline/loadIsomorphicCodeVariant/flattenCodeVariant.mjs +6 -3
- package/pipeline/loadIsomorphicCodeVariant/getAvailableTransforms.d.mts +12 -0
- package/pipeline/loadIsomorphicCodeVariant/getAvailableTransforms.mjs +44 -0
- package/pipeline/loadIsomorphicCodeVariant/getInitialVisibleSourceLines.d.mts +16 -0
- package/pipeline/loadIsomorphicCodeVariant/getInitialVisibleSourceLines.mjs +74 -0
- package/pipeline/loadIsomorphicCodeVariant/loadCodeFallback.mjs +17 -5
- package/pipeline/loadIsomorphicCodeVariant/loadIsomorphicCodeVariant.mjs +229 -15
- package/pipeline/loadIsomorphicCodeVariant/transformSource.d.mts +2 -2
- package/pipeline/loadIsomorphicCodeVariant/transformSource.mjs +56 -22
- package/pipeline/loadPrecomputedCodeHighlighter/loadPrecomputedCodeHighlighter.d.mts +18 -0
- package/pipeline/loadPrecomputedCodeHighlighter/loadPrecomputedCodeHighlighter.mjs +11 -7
- package/pipeline/loadServerTypes/hastTypeUtils.d.mts +2 -2
- package/pipeline/loadServerTypes/hastTypeUtils.mjs +4 -4
- package/pipeline/loadServerTypes/loadServerTypes.mjs +1 -1
- package/pipeline/loadServerTypesMeta/extractJSDocText.d.mts +14 -0
- package/pipeline/loadServerTypesMeta/extractJSDocText.mjs +60 -0
- package/pipeline/loadServerTypesMeta/processTypes.mjs +43 -46
- package/pipeline/loadServerTypesText/order.mjs +1 -1
- package/pipeline/loadServerTypesText/parseTypesMarkdown.mjs +3 -1
- package/pipeline/loaderUtils/index.d.mts +0 -1
- package/pipeline/loaderUtils/index.mjs +0 -1
- package/pipeline/loaderUtils/parseImportsAndComments.d.mts +5 -1
- package/pipeline/loaderUtils/parseImportsAndComments.mjs +19 -9
- package/pipeline/loaderUtils/resolveModulePath.mjs +23 -1
- package/pipeline/parseCreateFactoryCall/parseCreateFactoryCall.d.mts +12 -0
- package/pipeline/parseCreateFactoryCall/parseCreateFactoryCall.mjs +17 -13
- package/pipeline/parseSource/addLineGutters.mjs +45 -11
- package/pipeline/parseSource/calculateFrameRanges.d.mts +22 -0
- package/pipeline/parseSource/calculateFrameRanges.mjs +69 -25
- package/pipeline/parseSource/detectGrammarScopes.d.mts +13 -0
- package/pipeline/parseSource/detectGrammarScopes.mjs +35 -0
- package/pipeline/parseSource/extendSyntaxTokens.mjs +501 -43
- package/pipeline/parseSource/frameVisibility.d.mts +47 -0
- package/pipeline/parseSource/frameVisibility.mjs +114 -0
- package/pipeline/parseSource/grammarCache.d.mts +33 -0
- package/pipeline/parseSource/grammarCache.mjs +73 -0
- package/pipeline/parseSource/grammarLoaders.d.mts +14 -0
- package/pipeline/parseSource/grammarLoaders.mjs +24 -0
- package/pipeline/parseSource/grammarMaps.d.mts +21 -1
- package/pipeline/parseSource/grammarMaps.mjs +36 -0
- package/pipeline/parseSource/isFrameSpan.d.mts +19 -0
- package/pipeline/parseSource/isFrameSpan.mjs +24 -0
- package/pipeline/parseSource/parseSource.d.mts +41 -6
- package/pipeline/parseSource/parseSource.mjs +184 -36
- package/pipeline/parseSource/redistributeFrameFallbacks.d.mts +40 -0
- package/pipeline/parseSource/redistributeFrameFallbacks.mjs +138 -0
- package/pipeline/parseSource/restructureFrames.d.mts +5 -0
- package/pipeline/parseSource/restructureFrames.mjs +179 -16
- package/pipeline/syncPageIndex/metadataToMarkdown.mjs +6 -2
- package/pipeline/transformHtmlCodeBlock/transformHtmlCodeBlock.d.mts +26 -0
- package/pipeline/transformHtmlCodeBlock/transformHtmlCodeBlock.mjs +181 -114
- package/pipeline/transformHtmlCodeInline/removeSuffixFromHighlightedNodes.d.mts +12 -0
- package/pipeline/transformHtmlCodeInline/removeSuffixFromHighlightedNodes.mjs +52 -0
- package/pipeline/transformHtmlCodeInline/transformHtmlCodeInline.mjs +22 -1
- package/pipeline/transformTypescriptToJavascript/removeTypes.d.mts +5 -8
- package/pipeline/transformTypescriptToJavascript/removeTypes.mjs +27 -93
- package/useCode/EditableEngine.d.mts +233 -0
- package/useCode/EditableEngine.mjs +1712 -0
- package/useCode/EditingEngine.d.mts +13 -0
- package/useCode/EditingEngine.mjs +14 -0
- package/useCode/Pre.browser.mjs +5 -1
- package/useCode/Pre.d.mts +127 -1
- package/useCode/Pre.mjs +417 -165
- package/useCode/SourceEditingEngine.d.mts +50 -0
- package/useCode/SourceEditingEngine.mjs +461 -0
- package/useCode/TransformEngine.d.mts +39 -0
- package/useCode/TransformEngine.mjs +208 -0
- package/useCode/editingEngineCache.d.mts +29 -0
- package/useCode/editingEngineCache.mjs +68 -0
- package/useCode/sourceLineCounts.d.mts +80 -0
- package/useCode/sourceLineCounts.mjs +284 -0
- package/useCode/subscribeToggleNudge.d.mts +3 -0
- package/useCode/subscribeToggleNudge.mjs +95 -0
- package/useCode/transformEngineCache.d.mts +21 -0
- package/useCode/transformEngineCache.mjs +60 -0
- package/useCode/useCode.d.mts +140 -1
- package/useCode/useCode.mjs +250 -19
- package/useCode/useCodeUtils.d.mts +131 -20
- package/useCode/useCodeUtils.mjs +267 -194
- package/useCode/useCopyFunctionality.d.mts +13 -1
- package/useCode/useCopyFunctionality.mjs +39 -9
- package/useCode/useEditable.browser.mjs +10 -2
- package/useCode/useEditable.d.mts +27 -106
- package/useCode/useEditable.integration.browser.d.mts +1 -0
- package/useCode/useEditable.integration.browser.mjs +870 -0
- package/useCode/useEditable.mjs +198 -1247
- package/useCode/useEditableUtils.d.mts +50 -1
- package/useCode/useEditableUtils.mjs +29 -0
- package/useCode/useFileNavigation.d.mts +91 -3
- package/useCode/useFileNavigation.mjs +201 -41
- package/useCode/useHighlightGate.d.mts +17 -0
- package/useCode/useHighlightGate.mjs +147 -0
- package/useCode/useSourceEditing.d.mts +8 -0
- package/useCode/useSourceEditing.mjs +158 -314
- package/useCode/useSourceEnhancing.d.mts +5 -1
- package/useCode/useSourceEnhancing.mjs +22 -36
- package/useCode/useTransformManagement.d.mts +93 -5
- package/useCode/useTransformManagement.mjs +496 -28
- package/useCode/useTransitionPhase.d.mts +24 -0
- package/useCode/useTransitionPhase.mjs +49 -0
- package/useCode/useUIState.d.mts +2 -2
- package/useCode/useUIState.mjs +8 -8
- package/useCode/useVariantSelection.d.mts +130 -6
- package/useCode/useVariantSelection.mjs +529 -93
- package/useCodeWindow/useCodeWindow.d.mts +19 -2
- package/useCodeWindow/useCodeWindow.mjs +98 -71
- package/useCoordinated/coordinatePreference.d.mts +439 -0
- package/useCoordinated/coordinatePreference.mjs +951 -0
- package/useCoordinated/coordinatePreference.testUtils.d.mts +21 -0
- package/useCoordinated/coordinatePreference.testUtils.mjs +69 -0
- package/useCoordinated/createSettleGate.d.mts +96 -0
- package/useCoordinated/createSettleGate.mjs +171 -0
- package/useCoordinated/index.d.mts +8 -0
- package/useCoordinated/index.mjs +8 -0
- package/useCoordinated/layoutShiftGate.d.mts +24 -0
- package/useCoordinated/layoutShiftGate.mjs +79 -0
- package/useCoordinated/pageSettleGate.d.mts +11 -0
- package/useCoordinated/pageSettleGate.mjs +13 -0
- package/useCoordinated/scheduleTasks.d.mts +23 -0
- package/useCoordinated/scheduleTasks.mjs +45 -0
- package/useCoordinated/useCoordinated.d.mts +193 -0
- package/useCoordinated/useCoordinated.mjs +469 -0
- package/useCoordinated/useCoordinatedLazy.d.mts +17 -0
- package/useCoordinated/useCoordinatedLazy.mjs +38 -0
- package/useCoordinated/useCoordinatedLocalStorage.d.mts +16 -0
- package/useCoordinated/useCoordinatedLocalStorage.mjs +22 -0
- package/useCoordinated/useCoordinatedPreference.d.mts +20 -0
- package/useCoordinated/useCoordinatedPreference.mjs +26 -0
- package/useCoordinated/useSettleGate.d.mts +11 -0
- package/useCoordinated/useSettleGate.mjs +34 -0
- package/useDemo/exportVariant.d.mts +12 -5
- package/useDemo/exportVariant.mjs +59 -5
- package/useDemo/useDemo.d.mts +5 -2
- package/useScrollAnchor/useScrollAnchor.mjs +28 -5
- package/useStream/index.d.mts +6 -0
- package/useStream/index.mjs +6 -0
- package/useStream/streamChunks.d.mts +23 -0
- package/useStream/streamChunks.mjs +85 -0
- package/useStream/types.d.mts +45 -0
- package/useStream/types.mjs +1 -0
- package/useStream/useStream.d.mts +57 -0
- package/useStream/useStream.mjs +119 -0
- package/useStream/useStreamController.d.mts +15 -0
- package/useStream/useStreamController.mjs +90 -0
- package/withDocsInfra/withDocsInfra.d.mts +19 -0
- package/withDocsInfra/withDocsInfra.mjs +13 -5
- package/pipeline/loaderUtils/convertCommentsToOneIndexed.d.mts +0 -8
- package/pipeline/loaderUtils/convertCommentsToOneIndexed.mjs +0 -16
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { registerLayoutShiftSource } from "./layoutShiftGate.mjs";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Declares the calling component as a source of an initial, post-hydration
|
|
8
|
+
* layout shift — e.g. a code block that swaps from its plain fallback to
|
|
9
|
+
* highlighted (and focus-collapsed) output once it hydrates.
|
|
10
|
+
*
|
|
11
|
+
* While any registered source is unsettled, {@link useCoordinated} holds its
|
|
12
|
+
* layout-shifting commits, so a page-wide transform/variant change lands as a
|
|
13
|
+
* single unified update instead of a cascade as blocks swap in at staggered
|
|
14
|
+
* idle times. The host doesn't wire anything into its coordinated hooks — this
|
|
15
|
+
* registration is the only opt-in.
|
|
16
|
+
*
|
|
17
|
+
* Pass `settled: true` once the component has reached its stable
|
|
18
|
+
* post-hydration layout. Registration happens on mount and is released on
|
|
19
|
+
* unmount, so a component that unmounts before it settles can't hold the gate
|
|
20
|
+
* open for the rest of the page.
|
|
21
|
+
*/
|
|
22
|
+
export function useCoordinatedLazy(settled) {
|
|
23
|
+
const settleRef = React.useRef(null);
|
|
24
|
+
React.useEffect(() => {
|
|
25
|
+
settleRef.current = registerLayoutShiftSource();
|
|
26
|
+
return () => {
|
|
27
|
+
// Idempotent — doubles as a release when the component unmounts before
|
|
28
|
+
// it ever settled.
|
|
29
|
+
settleRef.current?.();
|
|
30
|
+
settleRef.current = null;
|
|
31
|
+
};
|
|
32
|
+
}, []);
|
|
33
|
+
React.useEffect(() => {
|
|
34
|
+
if (settled) {
|
|
35
|
+
settleRef.current?.();
|
|
36
|
+
}
|
|
37
|
+
}, [settled]);
|
|
38
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
import { type UseCoordinatedExtras, type UseCoordinatedOptions } from "./useCoordinated.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* `useLocalStorageState` + coordination in one call. Cross-tab sync
|
|
5
|
+
* happens via the underlying storage events; the coordinator handles
|
|
6
|
+
* within-tab peers (sibling demos on the same page) so their visible
|
|
7
|
+
* value flips land in a single layout pass.
|
|
8
|
+
*
|
|
9
|
+
* @param storageKey - localStorage key, or `null` to disable storage
|
|
10
|
+
* (falls back to regular `useState` semantics).
|
|
11
|
+
* @param initializer - Initial value, identical to
|
|
12
|
+
* `useLocalStorageState`.
|
|
13
|
+
* @param options - Coordination options. Pass `channelKey: null` to
|
|
14
|
+
* skip the coordinator entirely.
|
|
15
|
+
*/
|
|
16
|
+
export declare function useCoordinatedLocalStorage<TPreload = void>(storageKey: string | null, initializer: string | null | (() => string | null), options: UseCoordinatedOptions<string | null, TPreload>): [string | null, React.Dispatch<React.SetStateAction<string | null>>, UseCoordinatedExtras<string | null>];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import useLocalStorageState from "../useLocalStorageState/index.mjs";
|
|
4
|
+
import { useCoordinated } from "./useCoordinated.mjs";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `useLocalStorageState` + coordination in one call. Cross-tab sync
|
|
8
|
+
* happens via the underlying storage events; the coordinator handles
|
|
9
|
+
* within-tab peers (sibling demos on the same page) so their visible
|
|
10
|
+
* value flips land in a single layout pass.
|
|
11
|
+
*
|
|
12
|
+
* @param storageKey - localStorage key, or `null` to disable storage
|
|
13
|
+
* (falls back to regular `useState` semantics).
|
|
14
|
+
* @param initializer - Initial value, identical to
|
|
15
|
+
* `useLocalStorageState`.
|
|
16
|
+
* @param options - Coordination options. Pass `channelKey: null` to
|
|
17
|
+
* skip the coordinator entirely.
|
|
18
|
+
*/
|
|
19
|
+
export function useCoordinatedLocalStorage(storageKey, initializer, options) {
|
|
20
|
+
const underlying = useLocalStorageState(storageKey, initializer);
|
|
21
|
+
return useCoordinated(underlying, options);
|
|
22
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
import { type UseCoordinatedExtras, type UseCoordinatedOptions } from "./useCoordinated.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* `usePreference` + {@link useCoordinated} in one call.
|
|
5
|
+
*
|
|
6
|
+
* Cross-tab sync happens through the underlying `localStorage` /
|
|
7
|
+
* `storage` event flow that `usePreference` already provides; the
|
|
8
|
+
* coordinator handles within-tab peers so demos that share the same
|
|
9
|
+
* preference key commit their visible flip together rather than
|
|
10
|
+
* cascading layout shifts.
|
|
11
|
+
*
|
|
12
|
+
* @param type - Preference type, identical to `usePreference`.
|
|
13
|
+
* @param name - Variant/transform name(s), identical to
|
|
14
|
+
* `usePreference`.
|
|
15
|
+
* @param initializer - Initial value or initializer, identical to
|
|
16
|
+
* `usePreference`.
|
|
17
|
+
* @param options - Coordination options. Pass `channelKey: null` to
|
|
18
|
+
* skip the coordinator entirely.
|
|
19
|
+
*/
|
|
20
|
+
export declare function useCoordinatedPreference<TPreload = void>(type: 'variant' | 'transform', name: string | string[], initializer: string | null | (() => string | null) | undefined, options: UseCoordinatedOptions<string | null, TPreload>): [string | null, React.Dispatch<React.SetStateAction<string | null>>, UseCoordinatedExtras<string | null>];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { usePreference } from "../usePreference/usePreference.mjs";
|
|
4
|
+
import { useCoordinated } from "./useCoordinated.mjs";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `usePreference` + {@link useCoordinated} in one call.
|
|
8
|
+
*
|
|
9
|
+
* Cross-tab sync happens through the underlying `localStorage` /
|
|
10
|
+
* `storage` event flow that `usePreference` already provides; the
|
|
11
|
+
* coordinator handles within-tab peers so demos that share the same
|
|
12
|
+
* preference key commit their visible flip together rather than
|
|
13
|
+
* cascading layout shifts.
|
|
14
|
+
*
|
|
15
|
+
* @param type - Preference type, identical to `usePreference`.
|
|
16
|
+
* @param name - Variant/transform name(s), identical to
|
|
17
|
+
* `usePreference`.
|
|
18
|
+
* @param initializer - Initial value or initializer, identical to
|
|
19
|
+
* `usePreference`.
|
|
20
|
+
* @param options - Coordination options. Pass `channelKey: null` to
|
|
21
|
+
* skip the coordinator entirely.
|
|
22
|
+
*/
|
|
23
|
+
export function useCoordinatedPreference(type, name, initializer, options) {
|
|
24
|
+
const underlying = usePreference(type, name, initializer ?? null);
|
|
25
|
+
return useCoordinated(underlying, options);
|
|
26
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SettleGate } from "./createSettleGate.mjs";
|
|
2
|
+
/**
|
|
3
|
+
* Register the calling component as a source on a settle gate and release it
|
|
4
|
+
* once `settled` is `true`. Generalizes `useCoordinatedLazy`: registration
|
|
5
|
+
* happens on mount and the release is idempotent, so a component that unmounts
|
|
6
|
+
* before settling can't hold the gate open. Defaults to the page-global
|
|
7
|
+
* {@link pageSettleGate}; pass `null` to opt out of registration entirely (used
|
|
8
|
+
* when a swap conditionally registers with a controller gate that may be
|
|
9
|
+
* absent).
|
|
10
|
+
*/
|
|
11
|
+
export declare function useSettleGate(settled: boolean, gate?: SettleGate | null): void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { pageSettleGate } from "./pageSettleGate.mjs";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Register the calling component as a source on a settle gate and release it
|
|
8
|
+
* once `settled` is `true`. Generalizes `useCoordinatedLazy`: registration
|
|
9
|
+
* happens on mount and the release is idempotent, so a component that unmounts
|
|
10
|
+
* before settling can't hold the gate open. Defaults to the page-global
|
|
11
|
+
* {@link pageSettleGate}; pass `null` to opt out of registration entirely (used
|
|
12
|
+
* when a swap conditionally registers with a controller gate that may be
|
|
13
|
+
* absent).
|
|
14
|
+
*/
|
|
15
|
+
export function useSettleGate(settled, gate = pageSettleGate) {
|
|
16
|
+
const settleRef = React.useRef(null);
|
|
17
|
+
React.useEffect(() => {
|
|
18
|
+
if (!gate) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
settleRef.current = gate.register();
|
|
22
|
+
return () => {
|
|
23
|
+
// Idempotent - doubles as a release when the component unmounts before it
|
|
24
|
+
// ever settled, so it can't hold the gate open for the rest of the page.
|
|
25
|
+
settleRef.current?.();
|
|
26
|
+
settleRef.current = null;
|
|
27
|
+
};
|
|
28
|
+
}, [gate]);
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
if (settled) {
|
|
31
|
+
settleRef.current?.();
|
|
32
|
+
}
|
|
33
|
+
}, [settled]);
|
|
34
|
+
}
|
|
@@ -140,12 +140,19 @@ export interface ExportConfig {
|
|
|
140
140
|
rootFile: string;
|
|
141
141
|
};
|
|
142
142
|
/**
|
|
143
|
-
* Transform function that runs at the very start of the export process
|
|
144
|
-
* Can modify the variant code and metadata before any other processing happens
|
|
143
|
+
* Transform function that runs at the very start of the export process.
|
|
144
|
+
* Can modify the variant code and metadata before any other processing happens.
|
|
145
|
+
*
|
|
146
|
+
* Every source handed to this hook — `variant.source`, each
|
|
147
|
+
* `variant.extraFiles[*].source`, and each `globals[*].source` — is decoded to
|
|
148
|
+
* either a plain string or a live HAST tree (`HastRoot`); the serialized
|
|
149
|
+
* `hastCompressed` / `hastJson` shapes never reach it. Read a source as text
|
|
150
|
+
* with `stringOrHastToString`, or inspect / transform the HAST directly.
|
|
151
|
+
* Decoded trees are clones you own, so mutating them is safe.
|
|
145
152
|
* @example
|
|
146
|
-
* transformVariant: (variant,
|
|
147
|
-
* variant: { ...variant, source:
|
|
148
|
-
* globals: { ...globals,
|
|
153
|
+
* transformVariant: (variant, variantName, globals) => ({
|
|
154
|
+
* variant: { ...variant, source: `// ${variantName}\n${stringOrHastToString(variant.source)}` },
|
|
155
|
+
* globals: { ...globals, 'theme.css': { source: '.new {}', metadata: true } },
|
|
149
156
|
* })
|
|
150
157
|
*/
|
|
151
158
|
transformVariant?: (variant: VariantCode, variantName?: string, globals?: VariantExtraFiles) => {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { externalsToPackages } from "../pipeline/loaderUtils/index.mjs";
|
|
7
7
|
import { getFileNameFromUrl } from "../pipeline/loaderUtils/getFileNameFromUrl.mjs";
|
|
8
8
|
import { examineCodeVariant } from "../pipeline/loadIsomorphicCodeVariant/examineCodeVariant.mjs";
|
|
9
|
+
import { decodeSource } from "../pipeline/loadIsomorphicCodeVariant/decodeSource.mjs";
|
|
9
10
|
import { mergeCodeMetadata, extractCodeMetadata } from "../pipeline/loadIsomorphicCodeVariant/mergeCodeMetadata.mjs";
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -33,6 +34,47 @@ function mergeFiles(...fileSets) {
|
|
|
33
34
|
return merged;
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Decode every `source` in an extra-files map to `string | HastRoot` (never a
|
|
39
|
+
* serialized `hastJson` / `hastCompressed` payload), reusing the shared decode
|
|
40
|
+
* cache. Each file's own `fallback` is the DEFLATE dictionary for a
|
|
41
|
+
* `hastCompressed` source. URL-only string entries are passed through untouched.
|
|
42
|
+
*/
|
|
43
|
+
function decodeExtraFilesSources(files) {
|
|
44
|
+
const decoded = {};
|
|
45
|
+
for (const [name, fileData] of Object.entries(files)) {
|
|
46
|
+
if (typeof fileData === 'string' || fileData.source === undefined) {
|
|
47
|
+
decoded[name] = fileData;
|
|
48
|
+
} else {
|
|
49
|
+
decoded[name] = {
|
|
50
|
+
...fileData,
|
|
51
|
+
source: decodeSource(fileData.source, fileData.fallback)
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return decoded;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Decode a variant's main `source` and all of its extra-file sources to
|
|
60
|
+
* `string | HastRoot` (see {@link decodeExtraFilesSources}), so downstream
|
|
61
|
+
* consumers — most notably the user-supplied `transformVariant` hook — never
|
|
62
|
+
* have to handle serialized `hastCompressed` / `hastJson` payloads or thread
|
|
63
|
+
* their dictionaries.
|
|
64
|
+
*/
|
|
65
|
+
function decodeVariantSources(variant) {
|
|
66
|
+
const decoded = {
|
|
67
|
+
...variant
|
|
68
|
+
};
|
|
69
|
+
if (variant.source !== undefined) {
|
|
70
|
+
decoded.source = decodeSource(variant.source, variant.fallback);
|
|
71
|
+
}
|
|
72
|
+
if (variant.extraFiles) {
|
|
73
|
+
decoded.extraFiles = decodeExtraFilesSources(variant.extraFiles);
|
|
74
|
+
}
|
|
75
|
+
return decoded;
|
|
76
|
+
}
|
|
77
|
+
|
|
36
78
|
/**
|
|
37
79
|
* Extract filename from URL or return undefined if not available
|
|
38
80
|
*/
|
|
@@ -155,13 +197,23 @@ export function exportVariant(variantCode, config = {}) {
|
|
|
155
197
|
metadata: processedGlobals
|
|
156
198
|
} = extractCodeMetadata(variantCode);
|
|
157
199
|
|
|
158
|
-
// Run optional transform hook to modify variant and globals before processing
|
|
200
|
+
// Run optional transform hook to modify variant and globals before processing.
|
|
159
201
|
if (transformVariant) {
|
|
160
|
-
|
|
202
|
+
// Decode sources before handing them to the hook so it only ever sees a
|
|
203
|
+
// plain string or a live `HastRoot`, never a serialized `hastJson` /
|
|
204
|
+
// `hastCompressed` payload. Precomputed / SSR variants can still carry
|
|
205
|
+
// serialized sources here; the co-located `fallback` is the dictionary
|
|
206
|
+
// needed to decode them. `decodeSource` reuses the shared decode cache (so a
|
|
207
|
+
// source already decoded for rendering is not inflated again) and clones the
|
|
208
|
+
// tree so the hook owns what it receives. Decoding lazily here keeps it off
|
|
209
|
+
// the no-transform path, where `flattenCodeVariant` decodes at the end.
|
|
210
|
+
const decodedVariant = decodeVariantSources(processedVariantCode);
|
|
211
|
+
const decodedGlobals = decodeExtraFilesSources(processedGlobals);
|
|
212
|
+
const transformed = transformVariant(decodedVariant, variantName, decodedGlobals);
|
|
161
213
|
if (transformed) {
|
|
162
214
|
// Re-extract metadata after transformation
|
|
163
215
|
const result = transformed.variant && extractCodeMetadata(transformed.variant);
|
|
164
|
-
processedVariantCode = result?.variant ||
|
|
216
|
+
processedVariantCode = result?.variant || decodedVariant;
|
|
165
217
|
|
|
166
218
|
// Start fresh with only the new metadata and explicitly transformed globals
|
|
167
219
|
// Do NOT merge with the original processedGlobals to avoid duplication
|
|
@@ -278,8 +330,10 @@ export function exportVariant(variantCode, config = {}) {
|
|
|
278
330
|
},
|
|
279
331
|
devDependencies: {
|
|
280
332
|
...(!isFramework && {
|
|
281
|
-
|
|
282
|
-
|
|
333
|
+
// Pinned to major versions instead of `latest` to work around
|
|
334
|
+
// https://github.com/stackblitz/webcontainer-core/issues/2104
|
|
335
|
+
'@vitejs/plugin-react': '^5',
|
|
336
|
+
vite: '^7'
|
|
283
337
|
}),
|
|
284
338
|
...(useTypescript && {
|
|
285
339
|
typescript: 'latest',
|
package/useDemo/useDemo.d.mts
CHANGED
|
@@ -58,6 +58,7 @@ export declare function useDemo<T extends {} = {}>(contentProps: ContentProps<T>
|
|
|
58
58
|
selectedFileLines: number;
|
|
59
59
|
selectedFileName: string | undefined;
|
|
60
60
|
selectedFileUrl: string | undefined;
|
|
61
|
+
selectedFileSlug: string | undefined;
|
|
61
62
|
selectFileName: (fileName: string) => void;
|
|
62
63
|
allFilesSlugs: Array<{
|
|
63
64
|
fileName: string;
|
|
@@ -67,13 +68,15 @@ export declare function useDemo<T extends {} = {}>(contentProps: ContentProps<T>
|
|
|
67
68
|
expanded: boolean;
|
|
68
69
|
expand: () => void;
|
|
69
70
|
setExpanded: (expanded: boolean) => void;
|
|
70
|
-
copy: (event: React.MouseEvent<Element>) => Promise<void>;
|
|
71
|
-
copyMarkdown: (event: React.MouseEvent<Element>) => Promise<void>;
|
|
71
|
+
copy: (event: React.MouseEvent<Element, MouseEvent>) => Promise<void>;
|
|
72
|
+
copyMarkdown: (event: React.MouseEvent<Element, MouseEvent>) => Promise<void>;
|
|
72
73
|
availableTransforms: string[];
|
|
73
74
|
selectedTransform: string | null | undefined;
|
|
74
75
|
selectTransform: (transformName: string | null) => void;
|
|
76
|
+
pendingTransform: string | null | undefined;
|
|
75
77
|
setSource?: (source: string, fileName?: string) => void;
|
|
76
78
|
reset?: () => void;
|
|
79
|
+
refresh?: () => void;
|
|
77
80
|
userProps: T & {
|
|
78
81
|
name?: string;
|
|
79
82
|
slug?: string;
|
|
@@ -42,10 +42,16 @@ export function useScrollAnchor() {
|
|
|
42
42
|
activeSessionCleanupRef.current = null;
|
|
43
43
|
|
|
44
44
|
// Snapshot the scroll target at session start so a later ref change
|
|
45
|
-
// doesn't redirect compensation mid-flight.
|
|
46
|
-
|
|
45
|
+
// doesn't redirect compensation mid-flight. `scrollElement` is the attached
|
|
46
|
+
// container (if any); `scrollTarget` is what receives the user-interaction
|
|
47
|
+
// listeners (the container or the window).
|
|
48
|
+
const scrollElement = scrollContainerRef.current;
|
|
49
|
+
const scrollTarget = scrollElement ?? window;
|
|
47
50
|
const interactionTarget = scrollTarget;
|
|
48
|
-
|
|
51
|
+
|
|
52
|
+
// Mutable so it can be re-baselined when an attached container can't yet
|
|
53
|
+
// absorb a delta (see below).
|
|
54
|
+
let initialTop = anchor.getBoundingClientRect().top;
|
|
49
55
|
let active = true;
|
|
50
56
|
let cleanupTimer;
|
|
51
57
|
|
|
@@ -58,8 +64,25 @@ export function useScrollAnchor() {
|
|
|
58
64
|
return;
|
|
59
65
|
}
|
|
60
66
|
const delta = anchor.getBoundingClientRect().top - initialTop;
|
|
61
|
-
if (Math.abs(delta)
|
|
62
|
-
|
|
67
|
+
if (Math.abs(delta) <= 0.5) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (!scrollElement) {
|
|
71
|
+
window.scrollBy(0, delta);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const before = scrollElement.scrollTop;
|
|
75
|
+
scrollElement.scrollBy(0, delta);
|
|
76
|
+
const remainder = delta - (scrollElement.scrollTop - before);
|
|
77
|
+
if (Math.abs(remainder) > 0.5) {
|
|
78
|
+
// The container couldn't absorb this part — it isn't scrollable yet
|
|
79
|
+
// (its content hasn't exceeded its `max-height`). Re-baseline instead
|
|
80
|
+
// of forcing the difference elsewhere: scrolling the page would shift
|
|
81
|
+
// the surrounding layout, and carrying the delta forward would snap the
|
|
82
|
+
// anchor back the instant the container becomes scrollable. Accepting
|
|
83
|
+
// the small drift now keeps the surrounding layout still and lets the
|
|
84
|
+
// container hold the anchor smoothly from here on.
|
|
85
|
+
initialTop += remainder;
|
|
63
86
|
}
|
|
64
87
|
});
|
|
65
88
|
function cleanup() {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { useStream } from "./useStream.mjs";
|
|
2
|
+
export { useStreamController } from "./useStreamController.mjs";
|
|
3
|
+
export { streamChunks } from "./streamChunks.mjs";
|
|
4
|
+
export type { UseStreamOptions, UseStreamResult } from "./useStream.mjs";
|
|
5
|
+
export type { ChunkSnapshot } from "./streamChunks.mjs";
|
|
6
|
+
export type { UseStreamControllerOptions, UseStreamControllerResult, StreamSource, StreamUrlsResult } from "./types.mjs";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Client loading: stream a list of chunks in on the client and coordinate their
|
|
2
|
+
// swaps. Sits above `Chunk` (a single piece) and is the client-driven sibling of
|
|
3
|
+
// `abstractCreateStream` (server/build loading).
|
|
4
|
+
export { useStream } from "./useStream.mjs";
|
|
5
|
+
export { useStreamController } from "./useStreamController.mjs";
|
|
6
|
+
export { streamChunks } from "./streamChunks.mjs";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { StreamSource } from "./types.mjs";
|
|
2
|
+
/** A snapshot emitted by {@link streamChunks} after each chunk lands. */
|
|
3
|
+
export interface ChunkSnapshot<P> {
|
|
4
|
+
/** All chunks loaded so far, in order. */
|
|
5
|
+
chunks: P[];
|
|
6
|
+
/** `true` on the snapshot that completes the stream (last-chunk signal). */
|
|
7
|
+
lastChunk: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Drive any {@link StreamSource} `mode` and yield an accumulating snapshot after
|
|
11
|
+
* each chunk lands. Isomorphic: the client (`useStream`) iterates it and
|
|
12
|
+
* `setState`s each snapshot for progressive reveal; the server awaits it to
|
|
13
|
+
* completion for non-incremental modes.
|
|
14
|
+
*
|
|
15
|
+
* - `'data'` - one `load`, one terminal snapshot.
|
|
16
|
+
* - `'urls'` - `loadUrls`, then `loadChunk` per URL, one snapshot each; the
|
|
17
|
+
* final URL is the last chunk unless `loadUrls` returned `lastChunk: false`.
|
|
18
|
+
* - `'stream'` - runs the generator (which pushes into the array and yields),
|
|
19
|
+
* surfacing a snapshot per yield, then a terminal snapshot on return.
|
|
20
|
+
*
|
|
21
|
+
* Stops early (without a terminal snapshot) if `signal` aborts.
|
|
22
|
+
*/
|
|
23
|
+
export declare function streamChunks<P, O>(source: StreamSource<P, O>, options: O, signal: AbortSignal): AsyncGenerator<ChunkSnapshot<P>, void, void>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** A snapshot emitted by {@link streamChunks} after each chunk lands. */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Drive any {@link StreamSource} `mode` and yield an accumulating snapshot after
|
|
5
|
+
* each chunk lands. Isomorphic: the client (`useStream`) iterates it and
|
|
6
|
+
* `setState`s each snapshot for progressive reveal; the server awaits it to
|
|
7
|
+
* completion for non-incremental modes.
|
|
8
|
+
*
|
|
9
|
+
* - `'data'` - one `load`, one terminal snapshot.
|
|
10
|
+
* - `'urls'` - `loadUrls`, then `loadChunk` per URL, one snapshot each; the
|
|
11
|
+
* final URL is the last chunk unless `loadUrls` returned `lastChunk: false`.
|
|
12
|
+
* - `'stream'` - runs the generator (which pushes into the array and yields),
|
|
13
|
+
* surfacing a snapshot per yield, then a terminal snapshot on return.
|
|
14
|
+
*
|
|
15
|
+
* Stops early (without a terminal snapshot) if `signal` aborts.
|
|
16
|
+
*/
|
|
17
|
+
export async function* streamChunks(source, options, signal) {
|
|
18
|
+
if (source.mode === 'data') {
|
|
19
|
+
const data = await source.load(options, signal);
|
|
20
|
+
if (signal.aborted) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
yield {
|
|
24
|
+
chunks: [data],
|
|
25
|
+
lastChunk: true
|
|
26
|
+
};
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (source.mode === 'urls') {
|
|
30
|
+
const result = await source.loadUrls(options, signal);
|
|
31
|
+
if (signal.aborted) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const urls = result.chunks;
|
|
35
|
+
const accumulated = [];
|
|
36
|
+
for (let index = 0; index < urls.length; index += 1) {
|
|
37
|
+
// Sequential by design: chunks stream in and yield in order for
|
|
38
|
+
// progressive reveal - loading in parallel would defeat that.
|
|
39
|
+
// eslint-disable-next-line no-await-in-loop
|
|
40
|
+
const data = await source.loadChunk(urls[index], options, signal);
|
|
41
|
+
if (signal.aborted) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
accumulated.push(data);
|
|
45
|
+
const isLast = index === urls.length - 1 && result.lastChunk !== false;
|
|
46
|
+
yield {
|
|
47
|
+
chunks: [...accumulated],
|
|
48
|
+
lastChunk: isLast
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (urls.length === 0) {
|
|
52
|
+
// Nothing to load - still signal completion so a controller can settle.
|
|
53
|
+
yield {
|
|
54
|
+
chunks: [],
|
|
55
|
+
lastChunk: result.lastChunk !== false
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// stream mode: the generator pushes into `accumulated` and yields after each.
|
|
62
|
+
const accumulated = [];
|
|
63
|
+
const generator = source.stream(accumulated, options, signal);
|
|
64
|
+
let step = await generator.next();
|
|
65
|
+
while (!step.done) {
|
|
66
|
+
if (signal.aborted) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
yield {
|
|
70
|
+
chunks: [...accumulated],
|
|
71
|
+
lastChunk: false
|
|
72
|
+
};
|
|
73
|
+
// Sequential by design: a generator is driven one step at a time.
|
|
74
|
+
// eslint-disable-next-line no-await-in-loop
|
|
75
|
+
step = await generator.next();
|
|
76
|
+
}
|
|
77
|
+
if (signal.aborted) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// Generator returned -> the stream is complete.
|
|
81
|
+
yield {
|
|
82
|
+
chunks: [...accumulated],
|
|
83
|
+
lastChunk: true
|
|
84
|
+
};
|
|
85
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
import type { SettleGate } from "../useCoordinated/createSettleGate.mjs";
|
|
3
|
+
export type { StreamSource, StreamUrlsResult } from "../CoordinatedLazy/types.mjs";
|
|
4
|
+
/** Options for `useStreamController`. */
|
|
5
|
+
export interface UseStreamControllerOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Total number of chunks that will register. The controller stays `loading`
|
|
8
|
+
* until that many have registered and all have settled - **known-count**
|
|
9
|
+
* completion. Use when the chunk count is known up front.
|
|
10
|
+
*/
|
|
11
|
+
knownCount?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Hold the controller `loading` for an unknown-count stream until `markLast`
|
|
14
|
+
* is called - **last-chunk** completion. Ignored when `knownCount` is set.
|
|
15
|
+
* Use for a streaming loader that pushes chunks over time and signals the end
|
|
16
|
+
* when its generator returns.
|
|
17
|
+
*/
|
|
18
|
+
streaming?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Coordination channel forwarded to chunks for cross-instance commits (e.g.
|
|
21
|
+
* a later page-wide change landing together). `null` opts out.
|
|
22
|
+
*/
|
|
23
|
+
channelKey?: string | null;
|
|
24
|
+
/** Override the gate's safety timeout (ms). */
|
|
25
|
+
safetyTimeoutMs?: number;
|
|
26
|
+
}
|
|
27
|
+
/** Result of `useStreamController`. */
|
|
28
|
+
export interface UseStreamControllerResult {
|
|
29
|
+
/**
|
|
30
|
+
* Provider that scopes chunk registration to this controller: it supplies the
|
|
31
|
+
* controller's gate as the ambient gate, so chunks rendered inside register
|
|
32
|
+
* their swap with it (via `CoordinatedLazy`) without a `gate` prop.
|
|
33
|
+
*/
|
|
34
|
+
Controller: React.ComponentType<{
|
|
35
|
+
children: React.ReactNode;
|
|
36
|
+
}>;
|
|
37
|
+
/** `true` while any registered chunk is still loading; `false` once all settle. */
|
|
38
|
+
loading: boolean;
|
|
39
|
+
/** The controller's settle gate (also provided as the ambient gate). */
|
|
40
|
+
gate: SettleGate;
|
|
41
|
+
/** Mark the last chunk as arrived - terminal for a streaming controller. */
|
|
42
|
+
markLast: () => void;
|
|
43
|
+
/** Declare/adjust the total chunk count (known-count completion). */
|
|
44
|
+
setKnownCount: (count: number) => void;
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { StreamSource } from "./types.mjs";
|
|
3
|
+
/** Options for {@link useStream}. */
|
|
4
|
+
export interface UseStreamOptions<P, O> {
|
|
5
|
+
/**
|
|
6
|
+
* The source that produces the chunk list, by `mode`: `urls` resolves the
|
|
7
|
+
* chunk URLs then loads each, `stream` pushes chunks over time, `data` yields
|
|
8
|
+
* a single chunk. Streamed snapshots accumulate into `chunks`.
|
|
9
|
+
*/
|
|
10
|
+
source: StreamSource<P, O>;
|
|
11
|
+
/** Options passed to the source loaders. */
|
|
12
|
+
loaderOptions?: O;
|
|
13
|
+
/** Coordination channel forwarded to the owned controller. */
|
|
14
|
+
channelKey?: string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Opt into stale-while-revalidate: once the list has finished streaming,
|
|
17
|
+
* automatically {@link UseStreamResult.refresh} it once on the first idle
|
|
18
|
+
* period (via `requestIdleCallback`). Client-only; the current list stays
|
|
19
|
+
* visible while the background re-stream runs.
|
|
20
|
+
*/
|
|
21
|
+
revalidateOnIdle?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** Result of {@link useStream}. */
|
|
24
|
+
export interface UseStreamResult<P> {
|
|
25
|
+
/** The chunks loaded so far, accumulating as they stream in. */
|
|
26
|
+
chunks: P[];
|
|
27
|
+
/** Controller provider that scopes the rendered chunks' coordination. */
|
|
28
|
+
Controller: React.ComponentType<{
|
|
29
|
+
children: React.ReactNode;
|
|
30
|
+
}>;
|
|
31
|
+
/** `true` until the list has finished streaming and every chunk has settled. */
|
|
32
|
+
loading: boolean;
|
|
33
|
+
/** `true` once the list has finished streaming (the last chunk arrived). */
|
|
34
|
+
streamComplete: boolean;
|
|
35
|
+
/** `true` while a background re-stream (revalidation) is in flight; the current list stays. */
|
|
36
|
+
revalidating: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Re-stream the list in the background and swap the fresh list in atomically
|
|
39
|
+
* once it completes, keeping the current list visible meanwhile
|
|
40
|
+
* (stale-while-revalidate). Aborts any prior in-flight refresh.
|
|
41
|
+
*/
|
|
42
|
+
refresh: () => void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Stream a list of chunks on the client and own a `StreamController` that scopes
|
|
46
|
+
* their coordination. Render the returned `chunks` as chunk components inside
|
|
47
|
+
* the returned `Controller`; each chunk registers its swap with the controller,
|
|
48
|
+
* and the list's completion (`markLast`) plus those swaps drive `loading`.
|
|
49
|
+
*
|
|
50
|
+
* The controller runs in `streaming` mode, so it stays `loading` until the list
|
|
51
|
+
* finishes streaming - at which point the chunks present can settle it.
|
|
52
|
+
*
|
|
53
|
+
* `refresh()` (and the opt-in `revalidateOnIdle`) re-stream the list in the
|
|
54
|
+
* background and swap the result in atomically when it completes, without a
|
|
55
|
+
* loading flash — the current list stays visible the whole time.
|
|
56
|
+
*/
|
|
57
|
+
export declare function useStream<P, O>(options: UseStreamOptions<P, O>): UseStreamResult<P>;
|