@mui/internal-docs-infra 0.12.1-canary.2 → 0.12.1-canary.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ChunkProvider/PreloadProvider.mjs +1 -2
- package/ChunkProvider/usePreload.d.mts +1 -1
- package/ChunkProvider/usePreload.mjs +0 -1
- package/CodeControllerContext/CodeControllerContext.d.mts +45 -10
- package/CodeControllerContext/CodeControllerContext.mjs +15 -1
- package/CodeHighlighter/CodeHighlighterClient.d.mts +3 -2
- package/CodeHighlighter/CodeHighlighterClient.mjs +113 -18
- package/CodeHighlighter/CodeHighlighterContext.d.mts +9 -3
- package/CodeHighlighter/buildStringFallback.d.mts +1 -1
- package/CodeHighlighter/codeToFallbackProps.d.mts +1 -1
- package/CodeHighlighter/createClientProps.mjs +3 -0
- package/CodeHighlighter/fallbackCompression.d.mts +1 -1
- package/CodeHighlighter/parseControlledCode.d.mts +13 -4
- package/CodeHighlighter/parseControlledCode.mjs +41 -49
- package/CodeHighlighter/types.d.mts +21 -0
- package/CodeHighlighter/useGrammarsReady.mjs +44 -9
- package/CodeProvider/CodeProvider.d.mts +1 -1
- package/CodeProvider/CodeProviderLazy.d.mts +1 -1
- package/CodeProvider/createParseSourceWorkerClient.d.mts +6 -0
- package/CodeProvider/createParseSourceWorkerClient.mjs +83 -15
- package/CodeProvider/useCodeProviderValue.mjs +50 -4
- package/abstractCreateDemo/abstractCreateDemo.d.mts +15 -1
- package/abstractCreateDemo/abstractCreateDemo.mjs +8 -0
- package/abstractCreateDemoClient/abstractCreateDemoClient.mjs +4 -0
- package/abstractCreateTypes/abstractCreateTypes.d.mts +12 -1
- package/abstractCreateTypes/abstractCreateTypes.mjs +4 -0
- package/abstractCreateTypes/typesToJsx.d.mts +8 -0
- package/abstractCreateTypes/typesToJsx.mjs +2 -1
- package/cli/loadNextConfig.d.mts +9 -0
- package/cli/loadNextConfig.mjs +11 -2
- package/cli/runValidate.mjs +15 -7
- package/cli/validateWorker.d.mts +1 -0
- package/cli/validateWorker.mjs +2 -1
- package/createDemoData/createDemoData.d.mts +1 -1
- package/package.json +34 -5
- package/pipeline/cacheUtils/constants.d.mts +5 -0
- package/pipeline/cacheUtils/constants.mjs +5 -0
- package/pipeline/cacheUtils/hashCacheContent.d.mts +5 -0
- package/pipeline/cacheUtils/hashCacheContent.mjs +9 -0
- package/pipeline/cacheUtils/index.d.mts +9 -0
- package/pipeline/cacheUtils/index.mjs +7 -0
- package/pipeline/cacheUtils/loadFileCache.d.mts +13 -0
- package/pipeline/cacheUtils/loadFileCache.mjs +20 -0
- package/pipeline/cacheUtils/loadFileCacheEntry.d.mts +13 -0
- package/pipeline/cacheUtils/loadFileCacheEntry.mjs +47 -0
- package/pipeline/cacheUtils/resolveCachePath.d.mts +16 -0
- package/pipeline/cacheUtils/resolveCachePath.mjs +24 -0
- package/pipeline/cacheUtils/saveFileCache.d.mts +17 -0
- package/pipeline/cacheUtils/saveFileCache.mjs +54 -0
- package/pipeline/cacheUtils/types.d.mts +23 -0
- package/pipeline/cacheUtils/types.mjs +1 -0
- package/pipeline/cacheUtils/withFileCache.d.mts +40 -0
- package/pipeline/cacheUtils/withFileCache.mjs +81 -0
- package/pipeline/hastUtils/hastUtils.d.mts +1 -1
- package/pipeline/hastUtils/hastUtils.mjs +0 -1
- package/pipeline/loadIsomorphicCodeSource/loadIsomorphicCodeSource.d.mts +1 -1
- package/pipeline/loadIsomorphicCodeSource/loadIsomorphicCodeSource.mjs +1 -1
- package/pipeline/loadIsomorphicCodeVariant/applyCodeTransform.mjs +0 -1
- package/pipeline/loadIsomorphicCodeVariant/diffHast.d.mts +1 -1
- package/pipeline/loadIsomorphicCodeVariant/hasAllCodeVariants.d.mts +1 -1
- package/pipeline/loadIsomorphicCodeVariant/maybeCodeInitialData.d.mts +1 -1
- package/pipeline/loadPrecomputedSitemap/loadPrecomputedSitemap.d.mts +6 -0
- package/pipeline/loadPrecomputedSitemap/loadPrecomputedSitemap.mjs +2 -1
- package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.d.mts +6 -0
- package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.mjs +5 -1
- package/pipeline/loadServerCodeMeta/resolveModulePathWithFs.d.mts +1 -1
- package/pipeline/loadServerCodeMeta/resolveModulePathWithFs.mjs +0 -1
- package/pipeline/loadServerPageIndex/enrichPageIndex.d.mts +15 -0
- package/pipeline/loadServerPageIndex/enrichPageIndex.mjs +50 -0
- package/pipeline/loadServerPageIndex/extractPrefixAndTitle.d.mts +19 -0
- package/pipeline/loadServerPageIndex/extractPrefixAndTitle.mjs +80 -0
- package/pipeline/loadServerPageIndex/index.d.mts +5 -2
- package/pipeline/loadServerPageIndex/index.mjs +4 -1
- package/pipeline/loadServerPageIndex/loadServerPageIndex.d.mts +13 -22
- package/pipeline/loadServerPageIndex/loadServerPageIndex.mjs +32 -124
- package/pipeline/loadServerPageIndex/resolvePageIndexCacheKey.d.mts +13 -0
- package/pipeline/loadServerPageIndex/resolvePageIndexCacheKey.mjs +23 -0
- package/pipeline/loadServerTypes/highlightTypes.d.mts +3 -3
- package/pipeline/loadServerTypes/highlightTypesMeta.d.mts +4 -4
- package/pipeline/loadServerTypes/loadServerTypes.d.mts +2 -2
- package/pipeline/loadServerTypes/loadServerTypes.mjs +67 -7
- package/pipeline/loadServerTypesMeta/createOptimizedProgram.d.mts +2 -1
- package/pipeline/loadServerTypesMeta/formatClass.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatComponent.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatFunction.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatHook.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatRaw.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatType.d.mts +1 -1
- package/pipeline/loadServerTypesMeta/loadServerTypesMeta.d.mts +7 -7
- package/pipeline/loadServerTypesMeta/loadServerTypesMeta.mjs +1 -1
- package/pipeline/loadServerTypesMeta/processTypes.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/worker.d.mts +1 -1
- package/pipeline/loadServerTypesText/loadServerTypesText.d.mts +16 -2
- package/pipeline/loadServerTypesText/loadServerTypesText.mjs +30 -8
- package/pipeline/loadServerTypesText/normalizeTypesSourceDataForCache.d.mts +2 -0
- package/pipeline/loadServerTypesText/normalizeTypesSourceDataForCache.mjs +144 -0
- package/pipeline/loadServerTypesText/resolveTypesCacheKey.d.mts +19 -0
- package/pipeline/loadServerTypesText/resolveTypesCacheKey.mjs +29 -0
- package/pipeline/loaderUtils/parseImportsAndComments.d.mts +5 -3
- package/pipeline/loaderUtils/parseImportsAndComments.mjs +284 -40
- package/pipeline/parseCreateFactoryCall/parseCreateFactoryCall.d.mts +2 -2
- package/pipeline/parseCreateFactoryCall/parseCreateFactoryCall.mjs +2 -3
- package/pipeline/parseSource/detectFileTypes.d.mts +16 -0
- package/pipeline/parseSource/detectFileTypes.mjs +44 -0
- package/pipeline/syncPageIndex/mergeMetadataMarkdown.d.mts +25 -1
- package/pipeline/syncPageIndex/mergeMetadataMarkdown.mjs +79 -49
- package/pipeline/syncPageIndex/metadataToMarkdown.d.mts +15 -1
- package/pipeline/syncPageIndex/metadataToMarkdown.mjs +32 -10
- package/pipeline/syncPageIndex/syncPageIndex.d.mts +12 -0
- package/pipeline/syncPageIndex/syncPageIndex.mjs +154 -40
- package/pipeline/syncTypes/generateTypesMarkdown.d.mts +2 -2
- package/pipeline/syncTypes/syncTypes.d.mts +7 -0
- package/pipeline/syncTypes/syncTypes.mjs +31 -1
- package/pipeline/transformHtmlCodeBlock/transformHtmlCodeBlock.mjs +1 -1
- package/pipeline/transformMarkdownCode/transformMarkdownCode.mjs +25 -15
- package/pipeline/transformMarkdownMetadata/transformMarkdownMetadata.mjs +3 -0
- package/pipeline/transformMarkdownMetadata/types.d.mts +8 -1
- package/useCode/EditableEngine.d.mts +1 -1
- package/useCode/Pre.d.mts +9 -2
- package/useCode/Pre.mjs +4 -3
- package/useCode/TransformEngine.d.mts +1 -1
- package/useCode/useCode.d.mts +17 -1
- package/useCode/useCode.mjs +22 -1
- package/useCode/useCopyFunctionality.d.mts +2 -2
- package/useCode/useEditable.browser.mjs +0 -1
- package/useCode/useFileNavigation.d.mts +3 -0
- package/useCode/useFileNavigation.mjs +3 -1
- package/useCode/useSourceEditing.mjs +45 -10
- package/useCode/useSourceEnhancing.mjs +41 -9
- package/useCode/useTransformManagement.d.mts +2 -2
- package/useCode/useTransformManagement.mjs +19 -3
- package/useCode/useUIState.d.mts +4 -0
- package/useCode/useUIState.mjs +8 -1
- package/useCode/useVariantSelection.d.mts +1 -1
- package/useCoordinated/useCoordinated.d.mts +1 -1
- package/useCoordinated/useCoordinatedLocalStorage.d.mts +1 -1
- package/useCoordinated/useCoordinatedLocalStorage.mjs +0 -1
- package/useCoordinated/useCoordinatedPreference.d.mts +1 -1
- package/useCoordinated/useCoordinatedPreference.mjs +0 -1
- package/useCrossTabState/index.d.mts +2 -0
- package/useCrossTabState/index.mjs +2 -0
- package/useCrossTabState/useCrossTabMirror.d.mts +26 -0
- package/useCrossTabState/useCrossTabMirror.mjs +108 -0
- package/useCrossTabState/useCrossTabState.d.mts +21 -0
- package/useCrossTabState/useCrossTabState.mjs +31 -0
- package/useDemo/exportVariant.mjs +2 -4
- package/useDemo/exportVariantAsCra.d.mts +1 -1
- package/useDemo/exportVariantAsCra.mjs +0 -1
- package/useDemo/useDemo.d.mts +4 -1
- package/useDemo/useDemo.mjs +5 -0
- package/useDemoController/BuildEngine.d.mts +2 -0
- package/useDemoController/BuildEngine.mjs +10 -0
- package/useDemoController/DemoRunner.d.mts +34 -0
- package/useDemoController/DemoRunner.mjs +83 -0
- package/useDemoController/ErrorBoundary.d.mts +34 -0
- package/useDemoController/ErrorBoundary.mjs +49 -0
- package/useDemoController/Runner.d.mts +44 -0
- package/useDemoController/Runner.mjs +71 -0
- package/useDemoController/absolutizeImports.d.mts +13 -0
- package/useDemoController/absolutizeImports.mjs +73 -0
- package/useDemoController/buildScope.d.mts +48 -0
- package/useDemoController/buildScope.mjs +270 -0
- package/useDemoController/collectSources.d.mts +67 -0
- package/useDemoController/collectSources.mjs +92 -0
- package/useDemoController/compileCssModule.d.mts +64 -0
- package/useDemoController/compileCssModule.mjs +40 -0
- package/useDemoController/compileCssWithPostcss.d.mts +17 -0
- package/useDemoController/compileCssWithPostcss.mjs +89 -0
- package/useDemoController/compileModule.d.mts +14 -0
- package/useDemoController/compileModule.mjs +17 -0
- package/useDemoController/constants.d.mts +13 -0
- package/useDemoController/constants.mjs +13 -0
- package/useDemoController/createRequire.d.mts +10 -0
- package/useDemoController/createRequire.mjs +17 -0
- package/useDemoController/createTranspileWorkerClient.d.mts +27 -0
- package/useDemoController/createTranspileWorkerClient.mjs +139 -0
- package/useDemoController/cssModules.d.mts +47 -0
- package/useDemoController/currentBrowserTarget.d.mts +16 -0
- package/useDemoController/currentBrowserTarget.mjs +36 -0
- package/useDemoController/evalCode.d.mts +12 -0
- package/useDemoController/evalCode.mjs +35 -0
- package/useDemoController/generateCssModuleSource.d.mts +11 -0
- package/useDemoController/generateCssModuleSource.mjs +55 -0
- package/useDemoController/generateElement.d.mts +21 -0
- package/useDemoController/generateElement.mjs +26 -0
- package/useDemoController/hashString.d.mts +11 -0
- package/useDemoController/hashString.mjs +20 -0
- package/useDemoController/importCode.d.mts +11 -0
- package/useDemoController/importCode.mjs +15 -0
- package/useDemoController/index.d.mts +1 -0
- package/useDemoController/index.mjs +1 -0
- package/useDemoController/instantiateElement.d.mts +24 -0
- package/useDemoController/instantiateElement.mjs +57 -0
- package/useDemoController/instantiateModule.d.mts +17 -0
- package/useDemoController/instantiateModule.mjs +24 -0
- package/useDemoController/resolveCssImports.d.mts +27 -0
- package/useDemoController/resolveCssImports.mjs +79 -0
- package/useDemoController/transformCode.d.mts +14 -0
- package/useDemoController/transformCode.mjs +42 -0
- package/useDemoController/transpileClientSingleton.d.mts +10 -0
- package/useDemoController/transpileClientSingleton.mjs +83 -0
- package/useDemoController/transpileSource.d.mts +29 -0
- package/useDemoController/transpileSource.mjs +36 -0
- package/useDemoController/transpileWorker.d.mts +14 -0
- package/useDemoController/transpileWorker.mjs +41 -0
- package/useDemoController/types.d.mts +30 -0
- package/useDemoController/types.mjs +1 -0
- package/useDemoController/useDemoController.d.mts +54 -0
- package/useDemoController/useDemoController.mjs +186 -0
- package/useDemoController/useRunner.d.mts +53 -0
- package/useDemoController/useRunner.mjs +118 -0
- package/useDemoController/useVariantBuilds.d.mts +31 -0
- package/useDemoController/useVariantBuilds.mjs +188 -0
- package/useSearch/types.d.mts +1 -1
- package/useType/TypesDataProvider.d.mts +1 -1
- package/useType/TypesDataProvider.mjs +1 -2
- package/useType/useType.d.mts +1 -1
- package/useType/useTypeProp.d.mts +1 -1
- package/withDocsInfra/withDeploymentConfig.mjs +57 -0
- package/withDocsInfra/withDocsInfra.d.mts +14 -0
- package/withDocsInfra/withDocsInfra.mjs +25 -11
|
@@ -281,12 +281,16 @@ export const transformMarkdownCode = (options = {}) => {
|
|
|
281
281
|
tagName: 'code',
|
|
282
282
|
data: {
|
|
283
283
|
hName: 'code',
|
|
284
|
-
hProperties: codeHProperties
|
|
284
|
+
hProperties: codeHProperties,
|
|
285
|
+
// Pass the source as raw hast via `hChildren` so remark-rehype
|
|
286
|
+
// skips its mdast `text` handler, which line-trims (and would
|
|
287
|
+
// strip the per-line indentation) on the way to hast.
|
|
288
|
+
hChildren: [{
|
|
289
|
+
type: 'text',
|
|
290
|
+
value: codeNode.value
|
|
291
|
+
}]
|
|
285
292
|
},
|
|
286
|
-
children: [
|
|
287
|
-
type: 'text',
|
|
288
|
-
value: codeNode.value
|
|
289
|
-
}]
|
|
293
|
+
children: []
|
|
290
294
|
}]
|
|
291
295
|
};
|
|
292
296
|
const outputElement = {
|
|
@@ -607,12 +611,15 @@ export const transformMarkdownCode = (options = {}) => {
|
|
|
607
611
|
data: {
|
|
608
612
|
hName: 'code',
|
|
609
613
|
hProperties: codeHProperties,
|
|
610
|
-
meta: `variant=${block.variant}${Object.entries(block.props).map(([key, value]) => ` ${key}=${value}`).join('')}
|
|
614
|
+
meta: `variant=${block.variant}${Object.entries(block.props).map(([key, value]) => ` ${key}=${value}`).join('')}`,
|
|
615
|
+
// Raw hast `hChildren` to keep per-line indentation;
|
|
616
|
+
// see the filename branch above.
|
|
617
|
+
hChildren: [{
|
|
618
|
+
type: 'text',
|
|
619
|
+
value: block.node.value
|
|
620
|
+
}]
|
|
611
621
|
},
|
|
612
|
-
children: [
|
|
613
|
-
type: 'text',
|
|
614
|
-
value: block.node.value
|
|
615
|
-
}]
|
|
622
|
+
children: []
|
|
616
623
|
}]
|
|
617
624
|
}]
|
|
618
625
|
}]
|
|
@@ -745,12 +752,15 @@ export const transformMarkdownCode = (options = {}) => {
|
|
|
745
752
|
data: {
|
|
746
753
|
hName: 'code',
|
|
747
754
|
hProperties: codeHProperties,
|
|
748
|
-
meta: `variant=${block.variant}${Object.entries(block.props).map(([key, value]) => ` ${key}=${value}`).join('')}
|
|
755
|
+
meta: `variant=${block.variant}${Object.entries(block.props).map(([key, value]) => ` ${key}=${value}`).join('')}`,
|
|
756
|
+
// Raw hast `hChildren` to keep per-line indentation;
|
|
757
|
+
// see the filename branch above.
|
|
758
|
+
hChildren: [{
|
|
759
|
+
type: 'text',
|
|
760
|
+
value: block.node.value
|
|
761
|
+
}]
|
|
749
762
|
},
|
|
750
|
-
children: [
|
|
751
|
-
type: 'text',
|
|
752
|
-
value: block.node.value
|
|
753
|
-
}]
|
|
763
|
+
children: []
|
|
754
764
|
}]
|
|
755
765
|
}]
|
|
756
766
|
}]
|
|
@@ -834,6 +834,9 @@ export const transformMarkdownMetadata = (options = {}) => {
|
|
|
834
834
|
if (options.extractToIndex.indexWrapperComponent) {
|
|
835
835
|
updateOptions.indexWrapperComponent = options.extractToIndex.indexWrapperComponent;
|
|
836
836
|
}
|
|
837
|
+
if (options.extractToIndex.cacheDir) {
|
|
838
|
+
updateOptions.cacheDir = options.extractToIndex.cacheDir;
|
|
839
|
+
}
|
|
837
840
|
}
|
|
838
841
|
await syncPageIndex(updateOptions);
|
|
839
842
|
} catch (error) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PhrasingContent } from 'mdast';
|
|
2
|
-
import {
|
|
2
|
+
import type { Audience } from "../../createSitemap/types.mjs";
|
|
3
3
|
/**
|
|
4
4
|
* Base options for syncing page indexes.
|
|
5
5
|
* Shared between extractToIndex (markdown metadata) and updateParentIndex (types).
|
|
@@ -28,6 +28,13 @@ export type SyncPageIndexBaseOptions = {
|
|
|
28
28
|
* @default false
|
|
29
29
|
*/
|
|
30
30
|
errorIfOutOfDate?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Directory for the sha256-validated JSON cache of page indexes. When set, each
|
|
33
|
+
* index written is also cached at `{cacheDir}/pages-index/{route}.json`, leaving it
|
|
34
|
+
* warm for the next cold `loadServerPageIndex` read.
|
|
35
|
+
* @default undefined (disabled)
|
|
36
|
+
*/
|
|
37
|
+
cacheDir?: string;
|
|
31
38
|
};
|
|
32
39
|
/**
|
|
33
40
|
* Plugin options for transformMarkdownMetadata
|
package/useCode/Pre.d.mts
CHANGED
|
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import type { SetSource } from "./useSourceEditing.mjs";
|
|
3
3
|
import type { VariantSource } from "../CodeHighlighter/types.mjs";
|
|
4
4
|
import type { FallbackNode } from "../CodeHighlighter/fallbackFormat.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import type { SourceLineCounts } from "./sourceLineCounts.mjs";
|
|
6
6
|
export declare function Pre({
|
|
7
7
|
children,
|
|
8
8
|
className,
|
|
@@ -22,7 +22,8 @@ export declare function Pre({
|
|
|
22
22
|
onTransitionReady,
|
|
23
23
|
swapTarget,
|
|
24
24
|
editActivation,
|
|
25
|
-
onActivate
|
|
25
|
+
onActivate,
|
|
26
|
+
editable
|
|
26
27
|
}: {
|
|
27
28
|
children: VariantSource;
|
|
28
29
|
className?: string;
|
|
@@ -160,4 +161,10 @@ export declare function Pre({
|
|
|
160
161
|
* the live-editing engine, grammars, and worker at the activation moment.
|
|
161
162
|
*/
|
|
162
163
|
onActivate?: () => void;
|
|
164
|
+
/**
|
|
165
|
+
* Whether edit mode is on. When `false` the block stays read-only — `useEditable` is
|
|
166
|
+
* never enabled, so there's no `contentEditable`, no engine load, and no `onActivate`.
|
|
167
|
+
* Defaults to `true`; the host drives it from the `editable` toggle `useCode` returns.
|
|
168
|
+
*/
|
|
169
|
+
editable?: boolean;
|
|
163
170
|
}): React.ReactNode;
|
package/useCode/Pre.mjs
CHANGED
|
@@ -240,7 +240,8 @@ export function Pre({
|
|
|
240
240
|
onTransitionReady,
|
|
241
241
|
swapTarget,
|
|
242
242
|
editActivation,
|
|
243
|
-
onActivate
|
|
243
|
+
onActivate,
|
|
244
|
+
editable = true
|
|
244
245
|
}) {
|
|
245
246
|
// Defer the decompressing `decodeHastSource` to a post-paint render ONLY when the
|
|
246
247
|
// first-paint `.fallback` is ALREADY highlighted — i.e. the promoted highlighted-visible
|
|
@@ -419,7 +420,7 @@ export function Pre({
|
|
|
419
420
|
const collapsedBounds = React.useMemo(() => expanded ? undefined : computeCollapsedBounds(hast, indentation, collapseToEmpty), [hast, expanded, collapseToEmpty]);
|
|
420
421
|
useEditable(preRef, onEditableChange, {
|
|
421
422
|
indentation,
|
|
422
|
-
disabled: !setSource || !editableReady,
|
|
423
|
+
disabled: !setSource || !editableReady || !editable,
|
|
423
424
|
minColumn: collapsedBounds?.minColumn,
|
|
424
425
|
minRow: collapsedBounds?.minRow,
|
|
425
426
|
maxRow: collapsedBounds?.maxRow,
|
|
@@ -874,7 +875,7 @@ export function Pre({
|
|
|
874
875
|
// Collapse-to-empty empties the collapsed window, so the focused-line count is 0
|
|
875
876
|
// regardless of the precomputed value.
|
|
876
877
|
const sourceFocusedLines = collapseToEmpty ? 0 : rawFocusedLines;
|
|
877
|
-
const isEditable = Boolean(setSource);
|
|
878
|
+
const isEditable = Boolean(setSource) && editable;
|
|
878
879
|
|
|
879
880
|
// Focus-trap state for editable code blocks. When the user tabs into the
|
|
880
881
|
// wrapper (keyboard-only, gated by `:focus-visible`), an overlay prompts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { TransformRuntimeDeps } from "../pipeline/loadIsomorphicCodeVariant/applyCodeTransformWithComments.mjs";
|
|
2
2
|
import type { VariantSource, VariantCode, Transforms, SourceComments, Fallbacks } from "../CodeHighlighter/types.mjs";
|
|
3
3
|
import type { FallbackNode } from "../CodeHighlighter/fallbackFormat.mjs";
|
|
4
4
|
import type { TransformedFiles } from "./useCodeUtils.mjs";
|
package/useCode/useCode.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { ContentProps, SourceEnhancers } from "../CodeHighlighter/types.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import type { UseCopierOpts } from "../useCopier/index.mjs";
|
|
4
4
|
export type UseCodeOpts = {
|
|
5
5
|
preClassName?: string;
|
|
6
6
|
copy?: UseCopierOpts;
|
|
@@ -203,6 +203,22 @@ export interface UseCodeResult<T extends {} = {}> {
|
|
|
203
203
|
* stays anchored to the demo the user interacted with.
|
|
204
204
|
*/
|
|
205
205
|
pendingTransform: string | null | undefined;
|
|
206
|
+
/**
|
|
207
|
+
* Whether edit mode is currently on. `true` by default; starts `false` when the block
|
|
208
|
+
* opts in via `initialDisabled` — per demo through the `createDemo` `meta`, or across a
|
|
209
|
+
* factory's demos through `createDemoFactory`. While `false` the block renders
|
|
210
|
+
* read-only and the live-editing engine is not even warmed; flip it with
|
|
211
|
+
* {@link setEditable}. Independent of `editActivation`, which governs *when* the engine
|
|
212
|
+
* loads once editing is on, and of `disabled`, which turns editing off permanently.
|
|
213
|
+
*/
|
|
214
|
+
editable: boolean;
|
|
215
|
+
/**
|
|
216
|
+
* Turns edit mode on or off. `undefined` when the block can't be edited at all — no
|
|
217
|
+
* `CodeControllerContext` with `setCode` in scope, or editing is hard-`disabled` — so
|
|
218
|
+
* a toggle button can render only when this is defined. Toggling off keeps the
|
|
219
|
+
* reader's edits (use {@link reset} to discard them).
|
|
220
|
+
*/
|
|
221
|
+
setEditable?: (editable: boolean) => void;
|
|
206
222
|
/**
|
|
207
223
|
* Replace the source of the currently selected file (or `fileName` when
|
|
208
224
|
* provided) in the controlled code. Internal hooks may pass additional
|
package/useCode/useCode.mjs
CHANGED
|
@@ -149,10 +149,12 @@ export function useCode(contentProps, opts) {
|
|
|
149
149
|
// disagree.
|
|
150
150
|
const collapseToEmpty = contentProps.collapseToEmpty === true;
|
|
151
151
|
const initialExpanded = contentProps.initialExpanded === true;
|
|
152
|
+
const initialDisabled = contentProps.initialDisabled === true;
|
|
152
153
|
|
|
153
154
|
// Sub-hook: UI State Management (needs slug to check for relevant hash)
|
|
154
155
|
const uiState = useUIState({
|
|
155
156
|
initialExpanded,
|
|
157
|
+
initialDisabled,
|
|
156
158
|
mainSlug: userProps.slug
|
|
157
159
|
});
|
|
158
160
|
|
|
@@ -347,6 +349,7 @@ export function useCode(contentProps, opts) {
|
|
|
347
349
|
setSource: sourceEditing.setSource,
|
|
348
350
|
editActivation: context?.editActivation,
|
|
349
351
|
onActivate: context?.onEditingActivated,
|
|
352
|
+
editable: uiState.editable,
|
|
350
353
|
effectiveCode,
|
|
351
354
|
fileHashMode,
|
|
352
355
|
saveHashVariantToLocalStorage,
|
|
@@ -377,6 +380,22 @@ export function useCode(contentProps, opts) {
|
|
|
377
380
|
title: userProps.name,
|
|
378
381
|
copyOpts
|
|
379
382
|
});
|
|
383
|
+
|
|
384
|
+
// Editing can be toggled only where it's possible at all: a controller with `setCode`
|
|
385
|
+
// is in scope and the block isn't hard-`disabled`. Otherwise `setEditable` is omitted,
|
|
386
|
+
// so a host renders no toggle.
|
|
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]);
|
|
380
399
|
return {
|
|
381
400
|
variants: variantSelection.variantKeys,
|
|
382
401
|
selectedVariant: variantSelection.selectedVariantKey,
|
|
@@ -396,8 +415,10 @@ export function useCode(contentProps, opts) {
|
|
|
396
415
|
copyMarkdown: copyFunctionality.copyMarkdown,
|
|
397
416
|
availableTransforms: transformManagement.availableTransforms,
|
|
398
417
|
selectedTransform: transformManagement.selectedTransform,
|
|
399
|
-
selectTransform
|
|
418
|
+
selectTransform,
|
|
400
419
|
pendingTransform: transformManagement.pendingTransform,
|
|
420
|
+
editable: uiState.editable,
|
|
421
|
+
setEditable: canToggleEditing ? uiState.setEditable : undefined,
|
|
401
422
|
setSource: sourceEditing.setSource,
|
|
402
423
|
reset: sourceEditing.reset,
|
|
403
424
|
refresh: context?.refresh,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import type { UseCopierOpts } from "../useCopier/index.mjs";
|
|
3
3
|
import type { Fallbacks, VariantCode, VariantSource } from "../CodeHighlighter/types.mjs";
|
|
4
4
|
import type { FallbackNode } from "../CodeHighlighter/fallbackFormat.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import type { MarkdownFile } from "./generateVariantMarkdown.mjs";
|
|
6
6
|
import type { TransformedFiles } from "./useCodeUtils.mjs";
|
|
7
7
|
interface UseCopyFunctionalityProps {
|
|
8
8
|
selectedFile: VariantSource | null;
|
|
@@ -2,7 +2,6 @@ import { describe, it, expect, vi, afterEach, beforeAll } from 'vitest';
|
|
|
2
2
|
import { renderHook, act } from '@testing-library/react';
|
|
3
3
|
import { userEvent } from 'vitest/browser';
|
|
4
4
|
import { useEditable, preloadEditableEngine } from "./useEditable.mjs";
|
|
5
|
-
|
|
6
5
|
// `useEditable` loads its heavy runtime (the `EditableEngine` chunk) on demand
|
|
7
6
|
// and only applies `contentEditable` once it resolves. Warm that load once so
|
|
8
7
|
// the synchronous assertions below see `contentEditable` applied within `act`,
|
|
@@ -30,6 +30,8 @@ interface UseFileNavigationProps {
|
|
|
30
30
|
editActivation?: 'eager' | 'interaction';
|
|
31
31
|
/** Forwarded to `<Pre>` / `useEditable`: fired once when the block engages for editing. */
|
|
32
32
|
onActivate?: () => void;
|
|
33
|
+
/** Forwarded to `<Pre>`: whether edit mode is on. When `false` the block stays read-only. */
|
|
34
|
+
editable?: boolean;
|
|
33
35
|
effectiveCode?: Code;
|
|
34
36
|
selectVariant?: React.Dispatch<React.SetStateAction<string>>;
|
|
35
37
|
fileHashMode?: 'remove-hash' | 'remove-filename';
|
|
@@ -153,6 +155,7 @@ export declare function useFileNavigation({
|
|
|
153
155
|
setSource,
|
|
154
156
|
editActivation,
|
|
155
157
|
onActivate,
|
|
158
|
+
editable,
|
|
156
159
|
effectiveCode,
|
|
157
160
|
selectVariant,
|
|
158
161
|
fileHashMode,
|
|
@@ -70,6 +70,7 @@ export function useFileNavigation({
|
|
|
70
70
|
setSource,
|
|
71
71
|
editActivation,
|
|
72
72
|
onActivate,
|
|
73
|
+
editable,
|
|
73
74
|
effectiveCode,
|
|
74
75
|
selectVariant,
|
|
75
76
|
fileHashMode = 'remove-hash',
|
|
@@ -542,6 +543,7 @@ export function useFileNavigation({
|
|
|
542
543
|
setSource: setSource,
|
|
543
544
|
editActivation: editActivation,
|
|
544
545
|
onActivate: onActivate,
|
|
546
|
+
editable: editable,
|
|
545
547
|
shouldHighlight: shouldHighlight,
|
|
546
548
|
fallback: selectedFileFallback,
|
|
547
549
|
fallbackLineCounts: selectedFileLineCounts,
|
|
@@ -555,7 +557,7 @@ export function useFileNavigation({
|
|
|
555
557
|
}, getPreRenderKey(fileSlug, enhancementPhase));
|
|
556
558
|
}
|
|
557
559
|
return null;
|
|
558
|
-
}, [selectedVariant, shouldHighlight, preClassName, setSource, editActivation, onActivate, enhancedSource, isEnhancing, mainSlug, selectedFile, selectedVariantKey, sourceEnhancers, selectedFileNameInternal, selectedFileFallback, selectedFileLineCounts, expanded, collapseToEmpty, expand, transforming, onPreTransitionReady, variantBridgeLineMode, resolveSwapTarget]);
|
|
560
|
+
}, [selectedVariant, shouldHighlight, preClassName, setSource, editActivation, onActivate, editable, enhancedSource, isEnhancing, mainSlug, selectedFile, selectedVariantKey, sourceEnhancers, selectedFileNameInternal, selectedFileFallback, selectedFileLineCounts, expanded, collapseToEmpty, expand, transforming, onPreTransitionReady, variantBridgeLineMode, resolveSwapTarget]);
|
|
559
561
|
const selectedFileLines = React.useMemo(() => {
|
|
560
562
|
if (selectedFile == null) {
|
|
561
563
|
return 0;
|
|
@@ -3,6 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
// (via `useCopyFunctionality`/`Pre`). Passing it into the lazy editing engine
|
|
4
4
|
// keeps that engine chunk from statically pulling it (and `hastDecompress`).
|
|
5
5
|
import { stringOrHastToString } from "../pipeline/hastUtils/index.mjs";
|
|
6
|
+
import { preParsedCacheKey } from "../CodeHighlighter/parseControlledCode.mjs";
|
|
6
7
|
import { useCodeContext } from "../CodeProvider/CodeContext.mjs";
|
|
7
8
|
import { peekEditingEngine, loadEditingEngine, preloadEditingEngine, resetEditingEngineCache } from "./editingEngineCache.mjs";
|
|
8
9
|
// The edit-time runtime (`analyzeSource`/`shiftComments`/`toControlledCode`) lives
|
|
@@ -50,11 +51,11 @@ export function useSourceEditing({
|
|
|
50
51
|
editingEngineLoader
|
|
51
52
|
} = useCodeContext();
|
|
52
53
|
|
|
53
|
-
// Monotonic token bumped by every `setSource`/`reset`. A cold first edit
|
|
54
|
-
//
|
|
55
|
-
// before
|
|
56
|
-
//
|
|
57
|
-
//
|
|
54
|
+
// Monotonic token bumped by every `setSource`/`reset`. A cold first edit defers
|
|
55
|
+
// its commit until the engine chunk resolves; if a later edit or a `reset`
|
|
56
|
+
// happens before then, the stale deferred commit must NOT run (it would re-apply
|
|
57
|
+
// a superseded edit and, after a reset, reverse it). The deferred callback
|
|
58
|
+
// captures the token at schedule time and bails if it changed.
|
|
58
59
|
const editTokenRef = React.useRef(0);
|
|
59
60
|
const setSource = React.useCallback((source, fileName, position, preParsed) => {
|
|
60
61
|
if (!contextSetCode) {
|
|
@@ -76,13 +77,13 @@ export function useSourceEditing({
|
|
|
76
77
|
const resolvedFileName = fileName ?? selectedVariant?.fileName;
|
|
77
78
|
const preParsedCache = context?.preParsedCache;
|
|
78
79
|
if (preParsed !== undefined && preParsedCache && resolvedFileName) {
|
|
79
|
-
preParsedCache.set(resolvedFileName, {
|
|
80
|
+
preParsedCache.set(preParsedCacheKey(selectedVariantKey, resolvedFileName), {
|
|
80
81
|
source,
|
|
81
82
|
hast: preParsed
|
|
82
83
|
});
|
|
83
84
|
}
|
|
84
85
|
const applyUpdate = engine => {
|
|
85
|
-
|
|
86
|
+
const applyEdit = currentCode => {
|
|
86
87
|
const newCode = currentCode ? {
|
|
87
88
|
...currentCode
|
|
88
89
|
} : engine.toControlledCode(effectiveCode, selectedVariantKey, context?.fallbacks, stringOrHastToString);
|
|
@@ -175,8 +176,37 @@ export function useSourceEditing({
|
|
|
175
176
|
}
|
|
176
177
|
};
|
|
177
178
|
}
|
|
179
|
+
const editedVariant = newCode[selectedVariantKey];
|
|
180
|
+
if (editedVariant) {
|
|
181
|
+
if (!currentCode) {
|
|
182
|
+
// FIRST edit (precomputed → controlled): carry the pre-edit build
|
|
183
|
+
// inputs so the runner renders the ORIGINAL as a baseline before this
|
|
184
|
+
// (possibly broken) edit, then swaps to it (see `useVariantBuilds`).
|
|
185
|
+
newCode[selectedVariantKey] = {
|
|
186
|
+
...editedVariant,
|
|
187
|
+
original: {
|
|
188
|
+
source: variant.source,
|
|
189
|
+
extraFiles: variant.extraFiles
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
} else if (editedVariant.original) {
|
|
193
|
+
// Subsequent edit: the baseline already rendered — drop `original` so
|
|
194
|
+
// it doesn't linger in (and bloat) the controlled state.
|
|
195
|
+
const stripped = {
|
|
196
|
+
...editedVariant
|
|
197
|
+
};
|
|
198
|
+
delete stripped.original;
|
|
199
|
+
newCode[selectedVariantKey] = stripped;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
178
202
|
return newCode;
|
|
179
|
-
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// A SINGLE update carries the edited code to the controller — which the
|
|
206
|
+
// editor reflects immediately (no seed/handoff dance). On the FIRST edit
|
|
207
|
+
// `applyEdit` tags it with `.original`, so the runner renders the original
|
|
208
|
+
// as a baseline before swapping to this edit (see `useVariantBuilds`).
|
|
209
|
+
contextSetCode(applyEdit);
|
|
180
210
|
};
|
|
181
211
|
|
|
182
212
|
// Apply synchronously from the warm cache (the common case — the warm
|
|
@@ -211,8 +241,13 @@ export function useSourceEditing({
|
|
|
211
241
|
}
|
|
212
242
|
// Supersede any pending cold edit so it can't re-apply after this reset.
|
|
213
243
|
editTokenRef.current += 1;
|
|
214
|
-
|
|
215
|
-
|
|
244
|
+
// Evict any pre-parsed HAST so the original re-parses fresh on the next render
|
|
245
|
+
// (matches `refresh()`); a stale entry keyed by (variant, fileName) would otherwise
|
|
246
|
+
// survive the reset and the source viewer could reuse it for the rebuilt original.
|
|
247
|
+
context?.preParsedCache?.clear();
|
|
248
|
+
// Back to an empty controlled state, so the next edit re-tags `.original`.
|
|
249
|
+
contextSetCode(null);
|
|
250
|
+
}, [contextSetCode, context?.preParsedCache]);
|
|
216
251
|
const isEditable = !disabled && Boolean(contextSetCode) && Boolean(selectedVariant);
|
|
217
252
|
const canReset = !disabled && Boolean(contextSetCode);
|
|
218
253
|
return {
|
|
@@ -4,6 +4,13 @@ import * as React from 'react';
|
|
|
4
4
|
import { decodeHastSource } from "../pipeline/loadIsomorphicCodeVariant/decodeHastSource.mjs";
|
|
5
5
|
import { recordEnhancerApplied, shouldSkipEnhancer } from "../pipeline/loadIsomorphicCodeVariant/runSourceEnhancers.mjs";
|
|
6
6
|
|
|
7
|
+
// Safety-net deadline (ms) for the async enhancer pass. A client-side enhancer that
|
|
8
|
+
// REJECTS or HANGS would otherwise leave `asyncWork` non-null forever — keeping
|
|
9
|
+
// `isEnhancing` true and locking the consumer (`<Pre>` via `useFileNavigation`) at its
|
|
10
|
+
// un-enhanced 'base' phase until a full page reload. On failure/timeout we settle to the
|
|
11
|
+
// already sync-enhanced result so the phase advances.
|
|
12
|
+
const ENHANCER_TIMEOUT_MS = 10_000;
|
|
13
|
+
|
|
7
14
|
/**
|
|
8
15
|
* Resolves a `VariantSource` to a HAST root that is safe to mutate.
|
|
9
16
|
*
|
|
@@ -194,22 +201,47 @@ export function useSourceEnhancing({
|
|
|
194
201
|
const enhancers = sourceEnhancers;
|
|
195
202
|
const name = fileName || 'unknown';
|
|
196
203
|
let cancelled = false;
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const final = await applyEnhancersFrom(asyncResult, comments, name, enhancers, asyncStartIndex + 1);
|
|
204
|
+
|
|
205
|
+
// Clear `asyncWork` (keeping whatever enhanced source we already have) so
|
|
206
|
+
// `isEnhancing` drops and the consumer's phase advances. Used by the failure and
|
|
207
|
+
// timeout paths below — without it a rejected/hung enhancer wedges 'base' forever.
|
|
208
|
+
const settleWithCurrent = () => {
|
|
203
209
|
if (!cancelled) {
|
|
204
|
-
setState({
|
|
205
|
-
enhancedSource:
|
|
210
|
+
setState(previous => ({
|
|
211
|
+
enhancedSource: previous.enhancedSource,
|
|
206
212
|
asyncWork: null
|
|
207
|
-
});
|
|
213
|
+
}));
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// Safety net for a hung enhancer (a promise that never settles): force-settle after
|
|
218
|
+
// the deadline so the un-enhanced phase isn't locked until a reload.
|
|
219
|
+
const timer = setTimeout(settleWithCurrent, ENHANCER_TIMEOUT_MS);
|
|
220
|
+
async function continueEnhancing() {
|
|
221
|
+
try {
|
|
222
|
+
const asyncResult = await firstAsyncPromise;
|
|
223
|
+
if (cancelled) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const final = await applyEnhancersFrom(asyncResult, comments, name, enhancers, asyncStartIndex + 1);
|
|
227
|
+
if (!cancelled) {
|
|
228
|
+
setState({
|
|
229
|
+
enhancedSource: final,
|
|
230
|
+
asyncWork: null
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
} catch (error) {
|
|
234
|
+
// A rejected async enhancer must not strand `asyncWork` non-null forever.
|
|
235
|
+
console.error('Async source enhancer failed; settling with the current result.', error);
|
|
236
|
+
settleWithCurrent();
|
|
237
|
+
} finally {
|
|
238
|
+
clearTimeout(timer);
|
|
208
239
|
}
|
|
209
240
|
}
|
|
210
241
|
continueEnhancing();
|
|
211
242
|
return () => {
|
|
212
243
|
cancelled = true;
|
|
244
|
+
clearTimeout(timer);
|
|
213
245
|
};
|
|
214
246
|
}, [state.asyncWork, sourceEnhancers, fileName, comments]);
|
|
215
247
|
return {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Code, VariantCode } from "../CodeHighlighter/types.mjs";
|
|
2
2
|
import type { CreateTransformedFiles } from "./TransformEngine.mjs";
|
|
3
3
|
import { preloadTransformEngine, resetTransformEngineCache } from "./transformEngineCache.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import type { CodeHighlighterContextType } from "../CodeHighlighter/CodeHighlighterContext.mjs";
|
|
5
|
+
import type { TransitionPhase } from "./useTransitionPhase.mjs";
|
|
6
6
|
export { preloadTransformEngine, resetTransformEngineCache };
|
|
7
7
|
interface UseTransformManagementProps {
|
|
8
8
|
context?: CodeHighlighterContextType;
|
|
@@ -13,7 +13,6 @@ import { usePreference } from "../usePreference/index.mjs";
|
|
|
13
13
|
import { useCoordinated } from "../useCoordinated/index.mjs";
|
|
14
14
|
import { useHighlightGate } from "./useHighlightGate.mjs";
|
|
15
15
|
import { useTransitionPhase } from "./useTransitionPhase.mjs";
|
|
16
|
-
|
|
17
16
|
// Stable identity for the hast helpers handed to the transform engine; both are
|
|
18
17
|
// module-level functions, so this never needs to change.
|
|
19
18
|
const transformRuntimeDeps = {
|
|
@@ -123,7 +122,19 @@ export function useTransformManagement({
|
|
|
123
122
|
// here, otherwise rename-only entries would be dropped from
|
|
124
123
|
// resolution and the storage key would shift whenever a transform's
|
|
125
124
|
// visibility changed between sibling demos.
|
|
126
|
-
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]);
|
|
127
138
|
|
|
128
139
|
// Coordinator key. Demos sharing the same applicable transform set
|
|
129
140
|
// belong to the same coordination group: a user click in one demo
|
|
@@ -510,6 +521,11 @@ export function useTransformManagement({
|
|
|
510
521
|
// `onCommit` when its `(variant, transform)` keys match the values
|
|
511
522
|
// about to be rendered.
|
|
512
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
|
+
}
|
|
513
529
|
if (precomputed && precomputed.variant === selectedVariant && precomputed.transform === delayedAppliedTransform) {
|
|
514
530
|
return precomputed.result;
|
|
515
531
|
}
|
|
@@ -522,7 +538,7 @@ export function useTransformManagement({
|
|
|
522
538
|
return undefined;
|
|
523
539
|
}
|
|
524
540
|
return transformEngine(selectedVariant, delayedAppliedTransform, transformRuntimeDeps, context?.fallbacks);
|
|
525
|
-
}, [precomputed, selectedVariant, delayedAppliedTransform, context?.fallbacks, transformEngine]);
|
|
541
|
+
}, [precomputed, selectedVariant, delayedAppliedTransform, applicableFromCode, context?.fallbacks, transformEngine]);
|
|
526
542
|
const result = {
|
|
527
543
|
availableTransforms,
|
|
528
544
|
selectedTransform,
|
package/useCode/useUIState.d.mts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
interface UseUIStateProps {
|
|
3
3
|
initialExpanded?: boolean;
|
|
4
|
+
initialDisabled?: boolean;
|
|
4
5
|
mainSlug?: string;
|
|
5
6
|
}
|
|
6
7
|
export interface UseUIStateResult {
|
|
7
8
|
expanded: boolean;
|
|
8
9
|
expand: () => void;
|
|
9
10
|
setExpanded: React.Dispatch<React.SetStateAction<boolean>>;
|
|
11
|
+
editable: boolean;
|
|
12
|
+
setEditable: React.Dispatch<React.SetStateAction<boolean>>;
|
|
10
13
|
}
|
|
11
14
|
/**
|
|
12
15
|
* Hook for managing UI state like expansion and focus
|
|
@@ -14,6 +17,7 @@ export interface UseUIStateResult {
|
|
|
14
17
|
*/
|
|
15
18
|
export declare function useUIState({
|
|
16
19
|
initialExpanded,
|
|
20
|
+
initialDisabled,
|
|
17
21
|
mainSlug
|
|
18
22
|
}: UseUIStateProps): UseUIStateResult;
|
|
19
23
|
export {};
|
package/useCode/useUIState.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import { isHashRelevantToDemo } from "./useFileNavigation.mjs";
|
|
|
7
7
|
*/
|
|
8
8
|
export function useUIState({
|
|
9
9
|
initialExpanded = false,
|
|
10
|
+
initialDisabled = false,
|
|
10
11
|
mainSlug
|
|
11
12
|
}) {
|
|
12
13
|
const [hash] = useUrlHashState();
|
|
@@ -14,6 +15,10 @@ export function useUIState({
|
|
|
14
15
|
const [expanded, setExpanded] = React.useState(initialExpanded || hasRelevantHash);
|
|
15
16
|
const expand = React.useCallback(() => setExpanded(true), []);
|
|
16
17
|
|
|
18
|
+
// Edit-mode toggle. Starts on unless the block opted into `initialDisabled`; the host
|
|
19
|
+
// exposes `setEditable` (gated on a controller) so a reader can flip read-only ↔ edit.
|
|
20
|
+
const [editable, setEditable] = React.useState(!initialDisabled);
|
|
21
|
+
|
|
17
22
|
// Auto-expand if hash becomes relevant. This is a one-way OR-latch: it ratchets
|
|
18
23
|
// `expanded` to true but never collapses, so adjusting state during render is safe
|
|
19
24
|
// (the branch is skipped once `expanded` is true, avoiding an extra render).
|
|
@@ -23,6 +28,8 @@ export function useUIState({
|
|
|
23
28
|
return {
|
|
24
29
|
expanded,
|
|
25
30
|
expand,
|
|
26
|
-
setExpanded
|
|
31
|
+
setExpanded,
|
|
32
|
+
editable,
|
|
33
|
+
setEditable
|
|
27
34
|
};
|
|
28
35
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { Code, VariantCode } from "../CodeHighlighter/types.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import type { TransitionPhase } from "./useTransitionPhase.mjs";
|
|
4
4
|
interface UseVariantSelectionProps {
|
|
5
5
|
effectiveCode: Code;
|
|
6
6
|
initialVariant?: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import type { ChannelKey, PeerId } from "./coordinatePreference.mjs";
|
|
3
3
|
/**
|
|
4
4
|
* Options for {@link useCoordinated}. See `coordinatePreference` for
|
|
5
5
|
* the underlying semantics; only React-specific behaviors are
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import type { UseCoordinatedExtras, UseCoordinatedOptions } from "./useCoordinated.mjs";
|
|
3
3
|
/**
|
|
4
4
|
* `useLocalStorageState` + coordination in one call. Cross-tab sync
|
|
5
5
|
* happens via the underlying storage events; the coordinator handles
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import useLocalStorageState from "../useLocalStorageState/index.mjs";
|
|
4
4
|
import { useCoordinated } from "./useCoordinated.mjs";
|
|
5
|
-
|
|
6
5
|
/**
|
|
7
6
|
* `useLocalStorageState` + coordination in one call. Cross-tab sync
|
|
8
7
|
* happens via the underlying storage events; the coordinator handles
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import type { UseCoordinatedExtras, UseCoordinatedOptions } from "./useCoordinated.mjs";
|
|
3
3
|
/**
|
|
4
4
|
* `usePreference` + {@link useCoordinated} in one call.
|
|
5
5
|
*
|