@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.
Files changed (221) hide show
  1. package/ChunkProvider/PreloadProvider.mjs +1 -2
  2. package/ChunkProvider/usePreload.d.mts +1 -1
  3. package/ChunkProvider/usePreload.mjs +0 -1
  4. package/CodeControllerContext/CodeControllerContext.d.mts +45 -10
  5. package/CodeControllerContext/CodeControllerContext.mjs +15 -1
  6. package/CodeHighlighter/CodeHighlighterClient.d.mts +3 -2
  7. package/CodeHighlighter/CodeHighlighterClient.mjs +113 -18
  8. package/CodeHighlighter/CodeHighlighterContext.d.mts +9 -3
  9. package/CodeHighlighter/buildStringFallback.d.mts +1 -1
  10. package/CodeHighlighter/codeToFallbackProps.d.mts +1 -1
  11. package/CodeHighlighter/createClientProps.mjs +3 -0
  12. package/CodeHighlighter/fallbackCompression.d.mts +1 -1
  13. package/CodeHighlighter/parseControlledCode.d.mts +13 -4
  14. package/CodeHighlighter/parseControlledCode.mjs +41 -49
  15. package/CodeHighlighter/types.d.mts +21 -0
  16. package/CodeHighlighter/useGrammarsReady.mjs +44 -9
  17. package/CodeProvider/CodeProvider.d.mts +1 -1
  18. package/CodeProvider/CodeProviderLazy.d.mts +1 -1
  19. package/CodeProvider/createParseSourceWorkerClient.d.mts +6 -0
  20. package/CodeProvider/createParseSourceWorkerClient.mjs +83 -15
  21. package/CodeProvider/useCodeProviderValue.mjs +50 -4
  22. package/abstractCreateDemo/abstractCreateDemo.d.mts +15 -1
  23. package/abstractCreateDemo/abstractCreateDemo.mjs +8 -0
  24. package/abstractCreateDemoClient/abstractCreateDemoClient.mjs +4 -0
  25. package/abstractCreateTypes/abstractCreateTypes.d.mts +12 -1
  26. package/abstractCreateTypes/abstractCreateTypes.mjs +4 -0
  27. package/abstractCreateTypes/typesToJsx.d.mts +8 -0
  28. package/abstractCreateTypes/typesToJsx.mjs +2 -1
  29. package/cli/loadNextConfig.d.mts +9 -0
  30. package/cli/loadNextConfig.mjs +11 -2
  31. package/cli/runValidate.mjs +15 -7
  32. package/cli/validateWorker.d.mts +1 -0
  33. package/cli/validateWorker.mjs +2 -1
  34. package/createDemoData/createDemoData.d.mts +1 -1
  35. package/package.json +34 -5
  36. package/pipeline/cacheUtils/constants.d.mts +5 -0
  37. package/pipeline/cacheUtils/constants.mjs +5 -0
  38. package/pipeline/cacheUtils/hashCacheContent.d.mts +5 -0
  39. package/pipeline/cacheUtils/hashCacheContent.mjs +9 -0
  40. package/pipeline/cacheUtils/index.d.mts +9 -0
  41. package/pipeline/cacheUtils/index.mjs +7 -0
  42. package/pipeline/cacheUtils/loadFileCache.d.mts +13 -0
  43. package/pipeline/cacheUtils/loadFileCache.mjs +20 -0
  44. package/pipeline/cacheUtils/loadFileCacheEntry.d.mts +13 -0
  45. package/pipeline/cacheUtils/loadFileCacheEntry.mjs +47 -0
  46. package/pipeline/cacheUtils/resolveCachePath.d.mts +16 -0
  47. package/pipeline/cacheUtils/resolveCachePath.mjs +24 -0
  48. package/pipeline/cacheUtils/saveFileCache.d.mts +17 -0
  49. package/pipeline/cacheUtils/saveFileCache.mjs +54 -0
  50. package/pipeline/cacheUtils/types.d.mts +23 -0
  51. package/pipeline/cacheUtils/types.mjs +1 -0
  52. package/pipeline/cacheUtils/withFileCache.d.mts +40 -0
  53. package/pipeline/cacheUtils/withFileCache.mjs +81 -0
  54. package/pipeline/hastUtils/hastUtils.d.mts +1 -1
  55. package/pipeline/hastUtils/hastUtils.mjs +0 -1
  56. package/pipeline/loadIsomorphicCodeSource/loadIsomorphicCodeSource.d.mts +1 -1
  57. package/pipeline/loadIsomorphicCodeSource/loadIsomorphicCodeSource.mjs +1 -1
  58. package/pipeline/loadIsomorphicCodeVariant/applyCodeTransform.mjs +0 -1
  59. package/pipeline/loadIsomorphicCodeVariant/diffHast.d.mts +1 -1
  60. package/pipeline/loadIsomorphicCodeVariant/hasAllCodeVariants.d.mts +1 -1
  61. package/pipeline/loadIsomorphicCodeVariant/maybeCodeInitialData.d.mts +1 -1
  62. package/pipeline/loadPrecomputedSitemap/loadPrecomputedSitemap.d.mts +6 -0
  63. package/pipeline/loadPrecomputedSitemap/loadPrecomputedSitemap.mjs +2 -1
  64. package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.d.mts +6 -0
  65. package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.mjs +5 -1
  66. package/pipeline/loadServerCodeMeta/resolveModulePathWithFs.d.mts +1 -1
  67. package/pipeline/loadServerCodeMeta/resolveModulePathWithFs.mjs +0 -1
  68. package/pipeline/loadServerPageIndex/enrichPageIndex.d.mts +15 -0
  69. package/pipeline/loadServerPageIndex/enrichPageIndex.mjs +50 -0
  70. package/pipeline/loadServerPageIndex/extractPrefixAndTitle.d.mts +19 -0
  71. package/pipeline/loadServerPageIndex/extractPrefixAndTitle.mjs +80 -0
  72. package/pipeline/loadServerPageIndex/index.d.mts +5 -2
  73. package/pipeline/loadServerPageIndex/index.mjs +4 -1
  74. package/pipeline/loadServerPageIndex/loadServerPageIndex.d.mts +13 -22
  75. package/pipeline/loadServerPageIndex/loadServerPageIndex.mjs +32 -124
  76. package/pipeline/loadServerPageIndex/resolvePageIndexCacheKey.d.mts +13 -0
  77. package/pipeline/loadServerPageIndex/resolvePageIndexCacheKey.mjs +23 -0
  78. package/pipeline/loadServerTypes/highlightTypes.d.mts +3 -3
  79. package/pipeline/loadServerTypes/highlightTypesMeta.d.mts +4 -4
  80. package/pipeline/loadServerTypes/loadServerTypes.d.mts +2 -2
  81. package/pipeline/loadServerTypes/loadServerTypes.mjs +67 -7
  82. package/pipeline/loadServerTypesMeta/createOptimizedProgram.d.mts +2 -1
  83. package/pipeline/loadServerTypesMeta/formatClass.d.mts +2 -2
  84. package/pipeline/loadServerTypesMeta/formatComponent.d.mts +2 -2
  85. package/pipeline/loadServerTypesMeta/formatFunction.d.mts +2 -2
  86. package/pipeline/loadServerTypesMeta/formatHook.d.mts +2 -2
  87. package/pipeline/loadServerTypesMeta/formatRaw.d.mts +2 -2
  88. package/pipeline/loadServerTypesMeta/formatType.d.mts +1 -1
  89. package/pipeline/loadServerTypesMeta/loadServerTypesMeta.d.mts +7 -7
  90. package/pipeline/loadServerTypesMeta/loadServerTypesMeta.mjs +1 -1
  91. package/pipeline/loadServerTypesMeta/processTypes.d.mts +2 -2
  92. package/pipeline/loadServerTypesMeta/worker.d.mts +1 -1
  93. package/pipeline/loadServerTypesText/loadServerTypesText.d.mts +16 -2
  94. package/pipeline/loadServerTypesText/loadServerTypesText.mjs +30 -8
  95. package/pipeline/loadServerTypesText/normalizeTypesSourceDataForCache.d.mts +2 -0
  96. package/pipeline/loadServerTypesText/normalizeTypesSourceDataForCache.mjs +144 -0
  97. package/pipeline/loadServerTypesText/resolveTypesCacheKey.d.mts +19 -0
  98. package/pipeline/loadServerTypesText/resolveTypesCacheKey.mjs +29 -0
  99. package/pipeline/loaderUtils/parseImportsAndComments.d.mts +5 -3
  100. package/pipeline/loaderUtils/parseImportsAndComments.mjs +284 -40
  101. package/pipeline/parseCreateFactoryCall/parseCreateFactoryCall.d.mts +2 -2
  102. package/pipeline/parseCreateFactoryCall/parseCreateFactoryCall.mjs +2 -3
  103. package/pipeline/parseSource/detectFileTypes.d.mts +16 -0
  104. package/pipeline/parseSource/detectFileTypes.mjs +44 -0
  105. package/pipeline/syncPageIndex/mergeMetadataMarkdown.d.mts +25 -1
  106. package/pipeline/syncPageIndex/mergeMetadataMarkdown.mjs +79 -49
  107. package/pipeline/syncPageIndex/metadataToMarkdown.d.mts +15 -1
  108. package/pipeline/syncPageIndex/metadataToMarkdown.mjs +32 -10
  109. package/pipeline/syncPageIndex/syncPageIndex.d.mts +12 -0
  110. package/pipeline/syncPageIndex/syncPageIndex.mjs +154 -40
  111. package/pipeline/syncTypes/generateTypesMarkdown.d.mts +2 -2
  112. package/pipeline/syncTypes/syncTypes.d.mts +7 -0
  113. package/pipeline/syncTypes/syncTypes.mjs +31 -1
  114. package/pipeline/transformHtmlCodeBlock/transformHtmlCodeBlock.mjs +1 -1
  115. package/pipeline/transformMarkdownCode/transformMarkdownCode.mjs +25 -15
  116. package/pipeline/transformMarkdownMetadata/transformMarkdownMetadata.mjs +3 -0
  117. package/pipeline/transformMarkdownMetadata/types.d.mts +8 -1
  118. package/useCode/EditableEngine.d.mts +1 -1
  119. package/useCode/Pre.d.mts +9 -2
  120. package/useCode/Pre.mjs +4 -3
  121. package/useCode/TransformEngine.d.mts +1 -1
  122. package/useCode/useCode.d.mts +17 -1
  123. package/useCode/useCode.mjs +22 -1
  124. package/useCode/useCopyFunctionality.d.mts +2 -2
  125. package/useCode/useEditable.browser.mjs +0 -1
  126. package/useCode/useFileNavigation.d.mts +3 -0
  127. package/useCode/useFileNavigation.mjs +3 -1
  128. package/useCode/useSourceEditing.mjs +45 -10
  129. package/useCode/useSourceEnhancing.mjs +41 -9
  130. package/useCode/useTransformManagement.d.mts +2 -2
  131. package/useCode/useTransformManagement.mjs +19 -3
  132. package/useCode/useUIState.d.mts +4 -0
  133. package/useCode/useUIState.mjs +8 -1
  134. package/useCode/useVariantSelection.d.mts +1 -1
  135. package/useCoordinated/useCoordinated.d.mts +1 -1
  136. package/useCoordinated/useCoordinatedLocalStorage.d.mts +1 -1
  137. package/useCoordinated/useCoordinatedLocalStorage.mjs +0 -1
  138. package/useCoordinated/useCoordinatedPreference.d.mts +1 -1
  139. package/useCoordinated/useCoordinatedPreference.mjs +0 -1
  140. package/useCrossTabState/index.d.mts +2 -0
  141. package/useCrossTabState/index.mjs +2 -0
  142. package/useCrossTabState/useCrossTabMirror.d.mts +26 -0
  143. package/useCrossTabState/useCrossTabMirror.mjs +108 -0
  144. package/useCrossTabState/useCrossTabState.d.mts +21 -0
  145. package/useCrossTabState/useCrossTabState.mjs +31 -0
  146. package/useDemo/exportVariant.mjs +2 -4
  147. package/useDemo/exportVariantAsCra.d.mts +1 -1
  148. package/useDemo/exportVariantAsCra.mjs +0 -1
  149. package/useDemo/useDemo.d.mts +4 -1
  150. package/useDemo/useDemo.mjs +5 -0
  151. package/useDemoController/BuildEngine.d.mts +2 -0
  152. package/useDemoController/BuildEngine.mjs +10 -0
  153. package/useDemoController/DemoRunner.d.mts +34 -0
  154. package/useDemoController/DemoRunner.mjs +83 -0
  155. package/useDemoController/ErrorBoundary.d.mts +34 -0
  156. package/useDemoController/ErrorBoundary.mjs +49 -0
  157. package/useDemoController/Runner.d.mts +44 -0
  158. package/useDemoController/Runner.mjs +71 -0
  159. package/useDemoController/absolutizeImports.d.mts +13 -0
  160. package/useDemoController/absolutizeImports.mjs +73 -0
  161. package/useDemoController/buildScope.d.mts +48 -0
  162. package/useDemoController/buildScope.mjs +270 -0
  163. package/useDemoController/collectSources.d.mts +67 -0
  164. package/useDemoController/collectSources.mjs +92 -0
  165. package/useDemoController/compileCssModule.d.mts +64 -0
  166. package/useDemoController/compileCssModule.mjs +40 -0
  167. package/useDemoController/compileCssWithPostcss.d.mts +17 -0
  168. package/useDemoController/compileCssWithPostcss.mjs +89 -0
  169. package/useDemoController/compileModule.d.mts +14 -0
  170. package/useDemoController/compileModule.mjs +17 -0
  171. package/useDemoController/constants.d.mts +13 -0
  172. package/useDemoController/constants.mjs +13 -0
  173. package/useDemoController/createRequire.d.mts +10 -0
  174. package/useDemoController/createRequire.mjs +17 -0
  175. package/useDemoController/createTranspileWorkerClient.d.mts +27 -0
  176. package/useDemoController/createTranspileWorkerClient.mjs +139 -0
  177. package/useDemoController/cssModules.d.mts +47 -0
  178. package/useDemoController/currentBrowserTarget.d.mts +16 -0
  179. package/useDemoController/currentBrowserTarget.mjs +36 -0
  180. package/useDemoController/evalCode.d.mts +12 -0
  181. package/useDemoController/evalCode.mjs +35 -0
  182. package/useDemoController/generateCssModuleSource.d.mts +11 -0
  183. package/useDemoController/generateCssModuleSource.mjs +55 -0
  184. package/useDemoController/generateElement.d.mts +21 -0
  185. package/useDemoController/generateElement.mjs +26 -0
  186. package/useDemoController/hashString.d.mts +11 -0
  187. package/useDemoController/hashString.mjs +20 -0
  188. package/useDemoController/importCode.d.mts +11 -0
  189. package/useDemoController/importCode.mjs +15 -0
  190. package/useDemoController/index.d.mts +1 -0
  191. package/useDemoController/index.mjs +1 -0
  192. package/useDemoController/instantiateElement.d.mts +24 -0
  193. package/useDemoController/instantiateElement.mjs +57 -0
  194. package/useDemoController/instantiateModule.d.mts +17 -0
  195. package/useDemoController/instantiateModule.mjs +24 -0
  196. package/useDemoController/resolveCssImports.d.mts +27 -0
  197. package/useDemoController/resolveCssImports.mjs +79 -0
  198. package/useDemoController/transformCode.d.mts +14 -0
  199. package/useDemoController/transformCode.mjs +42 -0
  200. package/useDemoController/transpileClientSingleton.d.mts +10 -0
  201. package/useDemoController/transpileClientSingleton.mjs +83 -0
  202. package/useDemoController/transpileSource.d.mts +29 -0
  203. package/useDemoController/transpileSource.mjs +36 -0
  204. package/useDemoController/transpileWorker.d.mts +14 -0
  205. package/useDemoController/transpileWorker.mjs +41 -0
  206. package/useDemoController/types.d.mts +30 -0
  207. package/useDemoController/types.mjs +1 -0
  208. package/useDemoController/useDemoController.d.mts +54 -0
  209. package/useDemoController/useDemoController.mjs +186 -0
  210. package/useDemoController/useRunner.d.mts +53 -0
  211. package/useDemoController/useRunner.mjs +118 -0
  212. package/useDemoController/useVariantBuilds.d.mts +31 -0
  213. package/useDemoController/useVariantBuilds.mjs +188 -0
  214. package/useSearch/types.d.mts +1 -1
  215. package/useType/TypesDataProvider.d.mts +1 -1
  216. package/useType/TypesDataProvider.mjs +1 -2
  217. package/useType/useType.d.mts +1 -1
  218. package/useType/useTypeProp.d.mts +1 -1
  219. package/withDocsInfra/withDeploymentConfig.mjs +57 -0
  220. package/withDocsInfra/withDocsInfra.d.mts +14 -0
  221. package/withDocsInfra/withDocsInfra.mjs +25 -11
@@ -2,7 +2,6 @@
2
2
 
3
3
  import { usePreference } from "../usePreference/usePreference.mjs";
4
4
  import { useCoordinated } from "./useCoordinated.mjs";
5
-
6
5
  /**
7
6
  * `usePreference` + {@link useCoordinated} in one call.
8
7
  *
@@ -0,0 +1,2 @@
1
+ export * from "./useCrossTabState.mjs";
2
+ export * from "./useCrossTabMirror.mjs";
@@ -0,0 +1,2 @@
1
+ export * from "./useCrossTabState.mjs";
2
+ export * from "./useCrossTabMirror.mjs";
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Mirrors a value you already own across same-origin browser tabs/windows through a
3
+ * `BroadcastChannel` — so, for example, two Chrome split-view tabs of the same page
4
+ * keep a live demo's edits in sync. The lower-level building block behind
5
+ * `useCrossTabState`: use it when the state lives elsewhere (a reducer, a store, a
6
+ * controller's own `useState`) and you only want to keep it in sync; reach for
7
+ * `useCrossTabState` when you just want a synced `useState`.
8
+ *
9
+ * Pass a `key` (the channel name) that is identical across the tabs meant to share
10
+ * state, and `null` to disable — no channel is opened, which also makes it SSR-safe
11
+ * and gives the caller a clean off switch. `value` is broadcast whenever it changes
12
+ * locally; an incoming remote value is handed to `applyRemote` WITHOUT being echoed
13
+ * back, so two tabs can't ping-pong. Last write wins.
14
+ *
15
+ * A tab opened mid-edit catches up: on mount it asks peers for the current state, and
16
+ * any tab already holding shared state replies. A fresh tab with nothing to share
17
+ * stays quiet, so it can never blank out the asker; and once a tab holds shared state
18
+ * it ignores further catch-up replies, keeping its own value authoritative.
19
+ *
20
+ * `value` must be structured-cloneable (plain data) — `postMessage` clones it.
21
+ *
22
+ * @param key The channel name; tabs sync only when their keys match. `null` disables syncing (and is SSR-safe).
23
+ * @param value The current value, broadcast to other tabs whenever it changes.
24
+ * @param applyRemote Called with a value received from another tab — apply it to your own state.
25
+ */
26
+ export declare function useCrossTabMirror<T>(key: string | null, value: T, applyRemote: (value: T) => void): void;
@@ -0,0 +1,108 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+
5
+ /**
6
+ * Channel protocol: a `state` push (a local change, or a `reply` catching a newcomer
7
+ * up), or a newcomer's `request` for the current state.
8
+ */
9
+
10
+ /**
11
+ * Mirrors a value you already own across same-origin browser tabs/windows through a
12
+ * `BroadcastChannel` — so, for example, two Chrome split-view tabs of the same page
13
+ * keep a live demo's edits in sync. The lower-level building block behind
14
+ * `useCrossTabState`: use it when the state lives elsewhere (a reducer, a store, a
15
+ * controller's own `useState`) and you only want to keep it in sync; reach for
16
+ * `useCrossTabState` when you just want a synced `useState`.
17
+ *
18
+ * Pass a `key` (the channel name) that is identical across the tabs meant to share
19
+ * state, and `null` to disable — no channel is opened, which also makes it SSR-safe
20
+ * and gives the caller a clean off switch. `value` is broadcast whenever it changes
21
+ * locally; an incoming remote value is handed to `applyRemote` WITHOUT being echoed
22
+ * back, so two tabs can't ping-pong. Last write wins.
23
+ *
24
+ * A tab opened mid-edit catches up: on mount it asks peers for the current state, and
25
+ * any tab already holding shared state replies. A fresh tab with nothing to share
26
+ * stays quiet, so it can never blank out the asker; and once a tab holds shared state
27
+ * it ignores further catch-up replies, keeping its own value authoritative.
28
+ *
29
+ * `value` must be structured-cloneable (plain data) — `postMessage` clones it.
30
+ *
31
+ * @param key The channel name; tabs sync only when their keys match. `null` disables syncing (and is SSR-safe).
32
+ * @param value The current value, broadcast to other tabs whenever it changes.
33
+ * @param applyRemote Called with a value received from another tab — apply it to your own state.
34
+ */
35
+ export function useCrossTabMirror(key, value, applyRemote) {
36
+ const channelRef = React.useRef(null);
37
+ // The last value sent OR received on the channel. A local change whose value
38
+ // differs from it is broadcast; a value we just applied from a remote message
39
+ // matches it, so the broadcast effect below skips it — that's the echo guard.
40
+ const lastSyncedRef = React.useRef(value);
41
+ // Whether this tab holds shared state (has broadcast a change or adopted a peer's).
42
+ // Only a holder answers a newcomer's request, and a holder ignores catch-up replies.
43
+ const primedRef = React.useRef(false);
44
+ // Keep the latest `applyRemote` without re-opening the channel when an inline
45
+ // callback identity changes between renders.
46
+ const applyRemoteRef = React.useRef(applyRemote);
47
+ React.useEffect(() => {
48
+ applyRemoteRef.current = applyRemote;
49
+ });
50
+
51
+ // Open the channel (declared before the broadcast effect, so on mount the channel
52
+ // exists by the time that effect first runs and skips the initial value).
53
+ React.useEffect(() => {
54
+ if (key === null || typeof BroadcastChannel === 'undefined') {
55
+ return undefined;
56
+ }
57
+ const channel = new BroadcastChannel(key);
58
+ channelRef.current = channel;
59
+ channel.onmessage = event => {
60
+ const message = event.data;
61
+ if (message.kind === 'request') {
62
+ // A tab just came online and asked for the current state. Only a tab that
63
+ // holds shared state answers, so a fresh peer can't reply with a blank value.
64
+ if (primedRef.current) {
65
+ channel.postMessage({
66
+ kind: 'state',
67
+ value: lastSyncedRef.current,
68
+ reply: true
69
+ });
70
+ }
71
+ return;
72
+ }
73
+ // A catch-up reply must not overwrite state we already hold (a fast local edit,
74
+ // or an earlier reply we already took). A normal push — a peer's edit — always
75
+ // wins (last write wins).
76
+ if (message.reply && primedRef.current) {
77
+ return;
78
+ }
79
+ primedRef.current = true;
80
+ lastSyncedRef.current = message.value;
81
+ applyRemoteRef.current(message.value);
82
+ };
83
+ // Ask any existing tab to send its current state, so a tab opened mid-edit catches
84
+ // up instead of starting blank.
85
+ channel.postMessage({
86
+ kind: 'request'
87
+ });
88
+ return () => {
89
+ channel.close();
90
+ channelRef.current = null;
91
+ };
92
+ }, [key]);
93
+
94
+ // Broadcast local changes. A value we just received (so it equals `lastSyncedRef`)
95
+ // is not re-sent, which stops the echo.
96
+ React.useEffect(() => {
97
+ const channel = channelRef.current;
98
+ if (!channel || Object.is(value, lastSyncedRef.current)) {
99
+ return;
100
+ }
101
+ lastSyncedRef.current = value;
102
+ primedRef.current = true;
103
+ channel.postMessage({
104
+ kind: 'state',
105
+ value
106
+ });
107
+ }, [value]);
108
+ }
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ /**
3
+ * A `useState` whose value is mirrored across same-origin browser tabs/windows of the
4
+ * same page through a `BroadcastChannel` — set it in one tab and the others follow.
5
+ * For example, edit a live demo in a Chrome split view and both panes stay in sync.
6
+ *
7
+ * Drop-in for `useState`: returns `[value, setValue]` and supports lazy initializers
8
+ * and functional updates. The extra `key` is the channel name — tabs sync only when
9
+ * their keys match, and `null` disables syncing (also SSR-safe; no channel opens on
10
+ * the server). State is EPHEMERAL: nothing is persisted, but a tab opened mid-session
11
+ * catches up from a peer that already holds it instead of starting at `initialValue`.
12
+ * For state that must survive a reload, use `useLocalStorageState` instead.
13
+ *
14
+ * `value` must be structured-cloneable (plain data) — `postMessage` clones it. When the
15
+ * state lives elsewhere (a reducer, a store, a controller) and you only want to sync
16
+ * it, use the lower-level {@link useCrossTabMirror} instead.
17
+ *
18
+ * @param key The channel name; tabs sync only when their keys match. `null` disables syncing (and is SSR-safe).
19
+ * @param initialValue The initial state, or a lazy initializer — exactly like `useState`.
20
+ */
21
+ export declare function useCrossTabState<T>(key: string | null, initialValue: T | (() => T)): [T, React.Dispatch<React.SetStateAction<T>>];
@@ -0,0 +1,31 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { useCrossTabMirror } from "./useCrossTabMirror.mjs";
5
+
6
+ /**
7
+ * A `useState` whose value is mirrored across same-origin browser tabs/windows of the
8
+ * same page through a `BroadcastChannel` — set it in one tab and the others follow.
9
+ * For example, edit a live demo in a Chrome split view and both panes stay in sync.
10
+ *
11
+ * Drop-in for `useState`: returns `[value, setValue]` and supports lazy initializers
12
+ * and functional updates. The extra `key` is the channel name — tabs sync only when
13
+ * their keys match, and `null` disables syncing (also SSR-safe; no channel opens on
14
+ * the server). State is EPHEMERAL: nothing is persisted, but a tab opened mid-session
15
+ * catches up from a peer that already holds it instead of starting at `initialValue`.
16
+ * For state that must survive a reload, use `useLocalStorageState` instead.
17
+ *
18
+ * `value` must be structured-cloneable (plain data) — `postMessage` clones it. When the
19
+ * state lives elsewhere (a reducer, a store, a controller) and you only want to sync
20
+ * it, use the lower-level {@link useCrossTabMirror} instead.
21
+ *
22
+ * @param key The channel name; tabs sync only when their keys match. `null` disables syncing (and is SSR-safe).
23
+ * @param initialValue The initial state, or a lazy initializer — exactly like `useState`.
24
+ */
25
+ export function useCrossTabState(key, initialValue) {
26
+ const [value, setValue] = React.useState(initialValue);
27
+ // `setValue` applies a peer's value directly; `useCrossTabMirror` broadcasts our
28
+ // resolved `value` on change and skips echoing back what it just handed us.
29
+ useCrossTabMirror(key, value, setValue);
30
+ return [value, setValue];
31
+ }
@@ -330,10 +330,8 @@ export function exportVariant(variantCode, config = {}) {
330
330
  },
331
331
  devDependencies: {
332
332
  ...(!isFramework && {
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'
333
+ '@vitejs/plugin-react': 'latest',
334
+ vite: 'latest'
337
335
  }),
338
336
  ...(useTypescript && {
339
337
  typescript: 'latest',
@@ -4,7 +4,7 @@
4
4
  * without library-specific dependencies
5
5
  */
6
6
  import type { VariantCode } from "../CodeHighlighter/types.mjs";
7
- import { type ExportConfig } from "./exportVariant.mjs";
7
+ import type { ExportConfig } from "./exportVariant.mjs";
8
8
  /**
9
9
  * Export a VariantCode as a Create React App template
10
10
  * Returns an object with the exported VariantCode and entrypoint path
@@ -5,7 +5,6 @@
5
5
  */
6
6
 
7
7
  import { exportVariant } from "./exportVariant.mjs";
8
-
9
8
  /**
10
9
  * Export a VariantCode as a Create React App template
11
10
  * Returns an object with the exported VariantCode and entrypoint path
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import type { UseCodeOpts } from "../useCode/index.mjs";
3
3
  import type { ContentProps } from "../CodeHighlighter/types.mjs";
4
- import { type ExportConfig } from "./exportVariant.mjs";
4
+ import type { ExportConfig } from "./exportVariant.mjs";
5
5
  /**
6
6
  * Demo templates use the exportVariant/exportVariantAsCra with flattenCodeVariant pattern:
7
7
  *
@@ -74,6 +74,8 @@ export declare function useDemo<T extends {} = {}>(contentProps: ContentProps<T>
74
74
  selectedTransform: string | null | undefined;
75
75
  selectTransform: (transformName: string | null) => void;
76
76
  pendingTransform: string | null | undefined;
77
+ editable: boolean;
78
+ setEditable?: (editable: boolean) => void;
77
79
  setSource?: (source: string, fileName?: string) => void;
78
80
  reset?: () => void;
79
81
  refresh?: () => void;
@@ -82,6 +84,7 @@ export declare function useDemo<T extends {} = {}>(contentProps: ContentProps<T>
82
84
  slug?: string;
83
85
  };
84
86
  component: string | number | bigint | true | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | Iterable<React.ReactNode> | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | React.ReactPortal | null | undefined> | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | null;
87
+ error: string | null;
85
88
  focusRef: React.RefObject<HTMLButtonElement | null>;
86
89
  resetFocus: () => void;
87
90
  openStackBlitz: () => void;
@@ -81,6 +81,10 @@ export function useDemo(contentProps, opts) {
81
81
  return effectiveComponents[code.selectedVariant] || null;
82
82
  }, [effectiveComponents, code.selectedVariant]);
83
83
 
84
+ // Surface the selected variant's runtime error, reported by its preview
85
+ // component (e.g. `DemoRunner`) and bridged through `CodeHighlighterContext`.
86
+ const error = context?.errors?.[code.selectedVariant] ?? null;
87
+
84
88
  // Demo-specific ref and focus management. Typed as `HTMLButtonElement` since
85
89
  // the typical pattern is an invisible focus-target button rendered inside the
86
90
  // demo. `resetFocus` simply calls `.focus()` on it.
@@ -181,6 +185,7 @@ export function useDemo(contentProps, opts) {
181
185
  ...code,
182
186
  // Demo-specific additions
183
187
  component,
188
+ error,
184
189
  focusRef,
185
190
  resetFocus,
186
191
  openStackBlitz,
@@ -0,0 +1,2 @@
1
+ export { buildScope } from "./buildScope.mjs";
2
+ export { DemoRunner } from "./DemoRunner.mjs";
@@ -0,0 +1,10 @@
1
+ // The lazy "build engine" chunk for the live-demo runtime: both halves bundled together
2
+ // so editing a demo fetches ONE chunk instead of two — the BUILD half (`buildScope` plus
3
+ // its scope-assembly and eval machinery) and the RENDER half (`DemoRunner` plus the
4
+ // react-runner reimplementation). It is imported DYNAMICALLY (never statically) from
5
+ // `useVariantBuilds` (which needs `buildScope`) and `useDemoController` (which needs
6
+ // `DemoRunner`), both under the `BuildEngine` webpack chunk name; see those files for
7
+ // why the engine is deferred to the first edit. Keeping it out of the eager
8
+ // `useDemoController` chunk is the whole point — don't add a static import of this file.
9
+ export { buildScope } from "./buildScope.mjs";
10
+ export { DemoRunner } from "./DemoRunner.mjs";
@@ -0,0 +1,34 @@
1
+ import * as React from 'react';
2
+ import type { Scope } from "./types.mjs";
3
+ export interface DemoRunnerProps {
4
+ /** The already-transpiled entry code for the variant (from the transpile worker). */
5
+ runnerCode: string;
6
+ /** The built module registry the entry evaluates against. */
7
+ scope: Scope;
8
+ /** Compiled stylesheet text collected from the variant's CSS extra files. */
9
+ css?: string;
10
+ /**
11
+ * Called with the runner's current error message (or `null` when it renders
12
+ * cleanly). Lets the controller surface errors while the live preview keeps
13
+ * showing the last good render.
14
+ */
15
+ onError?: (message: string | null) => void;
16
+ /**
17
+ * Shown when the entry throws BEFORE any successful render (no last-good element to keep)
18
+ * — typically the host's build-time render, so a broken first edit shows the original
19
+ * instead of blanking. The host (`CodeHighlighterClient`) injects it per variant.
20
+ */
21
+ fallback?: React.ReactNode;
22
+ }
23
+ /**
24
+ * Renders one ready demo variant. Wraps the content in an {@link ErrorBoundary} as
25
+ * a backstop; runtime errors thrown while rendering the entry are already caught by
26
+ * the inner `Runner` and reported through `onError` the same way.
27
+ */
28
+ export declare function DemoRunner({
29
+ runnerCode,
30
+ scope,
31
+ css,
32
+ onError,
33
+ fallback
34
+ }: DemoRunnerProps): React.JSX.Element;
@@ -0,0 +1,83 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { useRunner } from "./useRunner.mjs";
5
+ import { ErrorBoundary } from "./ErrorBoundary.mjs";
6
+
7
+ // ---------------------------------------------------------------------------
8
+ // Presentational preview for a single demo variant. The async transpilation +
9
+ // scope build happen upstream in `useDemoController` (off the main thread, in a
10
+ // worker), so this is mounted only once a variant is READY and stays fully
11
+ // synchronous: it evaluates the already-transpiled entry, renders it, and reports
12
+ // runtime errors. Not built for direct use — `useDemoController` owns it.
13
+ // ---------------------------------------------------------------------------
14
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
+ /**
16
+ * Renders one ready demo variant. Wraps the content in an {@link ErrorBoundary} as
17
+ * a backstop; runtime errors thrown while rendering the entry are already caught by
18
+ * the inner `Runner` and reported through `onError` the same way.
19
+ */
20
+ export function DemoRunner({
21
+ runnerCode,
22
+ scope,
23
+ css,
24
+ onError,
25
+ fallback
26
+ }) {
27
+ return /*#__PURE__*/_jsx(ErrorBoundary, {
28
+ resetKeys: [runnerCode, scope],
29
+ onError: caught => onError?.(caught.message),
30
+ children: /*#__PURE__*/_jsx(DemoRunnerContent, {
31
+ runnerCode: runnerCode,
32
+ scope: scope,
33
+ css: css,
34
+ onError: onError,
35
+ fallback: fallback
36
+ })
37
+ });
38
+ }
39
+ function DemoRunnerContent({
40
+ runnerCode,
41
+ scope,
42
+ css,
43
+ onError,
44
+ fallback
45
+ }) {
46
+ const {
47
+ element,
48
+ error
49
+ } = useRunner({
50
+ transpiledCode: runnerCode,
51
+ scope,
52
+ fallback
53
+ });
54
+
55
+ // Report the current error (or `null` when clean) to the host without unmounting
56
+ // the live preview, which `useRunner` keeps showing. The latest `onError` is kept
57
+ // in a ref so an inline callback doesn't re-fire the report.
58
+ const onErrorRef = React.useRef(onError);
59
+ React.useEffect(() => {
60
+ onErrorRef.current = onError;
61
+ });
62
+ // Report on every change, but clear (`null`) only on unmount — clearing on each
63
+ // change would blink the error off and back on as the source is edited.
64
+ React.useEffect(() => {
65
+ onErrorRef.current?.(error);
66
+ }, [error]);
67
+ React.useEffect(() => () => {
68
+ onErrorRef.current?.(null);
69
+ }, []);
70
+
71
+ // Render the compiled module CSS as a `<style>` inside the output (rather than
72
+ // injecting it into `document.head`) so the scoped styles are co-located with the
73
+ // demo and easy to inspect. A plain `<style>` (no `precedence`) is not hoisted by
74
+ // React, and its rules still apply document-wide.
75
+ return /*#__PURE__*/_jsxs(React.Fragment, {
76
+ children: [css ? /*#__PURE__*/_jsx("div", {
77
+ "data-demo-styles": "",
78
+ children: /*#__PURE__*/_jsx("style", {
79
+ children: css
80
+ })
81
+ }) : null, element]
82
+ });
83
+ }
@@ -0,0 +1,34 @@
1
+ import * as React from 'react';
2
+ export interface ErrorBoundaryProps {
3
+ children: React.ReactNode;
4
+ /** Called with the error thrown while rendering `children`. */
5
+ onError?: (error: Error) => void;
6
+ /**
7
+ * When any value in this array changes, a caught error is cleared and
8
+ * `children` render again — letting a fixed input recover from a prior crash.
9
+ */
10
+ resetKeys?: ReadonlyArray<unknown>;
11
+ /** Rendered in place of `children` while an error is caught. Defaults to `null`. */
12
+ fallback?: React.ReactNode;
13
+ }
14
+ interface ErrorBoundaryState {
15
+ error: Error | null;
16
+ /** The `resetKeys` the current state was derived from, compared element-wise. */
17
+ resetKeys: ReadonlyArray<unknown>;
18
+ }
19
+ /**
20
+ * Generic error boundary: catches errors thrown while rendering its subtree,
21
+ * reports them through `onError`, and renders `fallback` instead of tearing down
22
+ * the surrounding tree. Pass `resetKeys` (e.g. the live-edited source) so a fixed
23
+ * input retries rendering after a previous crash.
24
+ *
25
+ * Implemented as a class because error boundaries require `getDerivedStateFromError`.
26
+ */
27
+ export declare class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
28
+ state: ErrorBoundaryState;
29
+ static getDerivedStateFromError(error: unknown): Partial<ErrorBoundaryState>;
30
+ static getDerivedStateFromProps(props: ErrorBoundaryProps, state: ErrorBoundaryState): Partial<ErrorBoundaryState> | null;
31
+ componentDidCatch(error: unknown): void;
32
+ render(): React.ReactNode;
33
+ }
34
+ export {};
@@ -0,0 +1,49 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ /** Normalizes an unknown thrown value into an `Error`. */
5
+ function toError(thrown) {
6
+ return thrown instanceof Error ? thrown : new Error(String(thrown));
7
+ }
8
+
9
+ /** Whether two reset-key arrays differ in length or any element (`Object.is`). */
10
+ function resetKeysChanged(a, b) {
11
+ return a.length !== b.length || a.some((value, index) => !Object.is(value, b[index]));
12
+ }
13
+
14
+ /**
15
+ * Generic error boundary: catches errors thrown while rendering its subtree,
16
+ * reports them through `onError`, and renders `fallback` instead of tearing down
17
+ * the surrounding tree. Pass `resetKeys` (e.g. the live-edited source) so a fixed
18
+ * input retries rendering after a previous crash.
19
+ *
20
+ * Implemented as a class because error boundaries require `getDerivedStateFromError`.
21
+ */
22
+ export class ErrorBoundary extends React.Component {
23
+ state = {
24
+ error: null,
25
+ resetKeys: this.props.resetKeys ?? []
26
+ };
27
+ static getDerivedStateFromError(error) {
28
+ return {
29
+ error: toError(error)
30
+ };
31
+ }
32
+ static getDerivedStateFromProps(props, state) {
33
+ const nextKeys = props.resetKeys ?? [];
34
+ if (!resetKeysChanged(state.resetKeys, nextKeys)) {
35
+ return null;
36
+ }
37
+ // Inputs changed — clear any caught error so the children render again.
38
+ return {
39
+ error: null,
40
+ resetKeys: nextKeys
41
+ };
42
+ }
43
+ componentDidCatch(error) {
44
+ this.props.onError?.(toError(error));
45
+ }
46
+ render() {
47
+ return this.state.error ? this.props.fallback ?? null : this.props.children;
48
+ }
49
+ }
@@ -0,0 +1,44 @@
1
+ import * as React from 'react';
2
+ import type { Scope } from "./types.mjs";
3
+ export interface RunnerProps {
4
+ /**
5
+ * Already-transpiled entry code (CommonJS, from the transpile worker). The
6
+ * Runner only evaluates + renders it; transpilation happens upstream (off the
7
+ * main thread), so a transpile error never reaches here.
8
+ */
9
+ transpiledCode: string;
10
+ /** Identifiers (and an `import` registry) exposed to the evaluated entry. */
11
+ scope?: Scope;
12
+ /**
13
+ * Called after every (re)render with the error that occurred while evaluating or
14
+ * rendering the entry, or `undefined` when it rendered cleanly.
15
+ */
16
+ onRendered?: (error?: Error) => void;
17
+ }
18
+ interface RunnerState {
19
+ element: React.ReactNode;
20
+ error: Error | null;
21
+ /** The transpiled code the current `element`/`error` was derived from. */
22
+ renderedCode: string | null;
23
+ /** The scope the current `element`/`error` was derived from (compared by reference). */
24
+ renderedScope: Scope | undefined;
25
+ }
26
+ /**
27
+ * Evaluates already-transpiled entry code and renders the React node it exports,
28
+ * doubling as an error boundary so a runtime error thrown while rendering that node
29
+ * is caught instead of tearing down the host tree. Evaluate-time errors (a throw in
30
+ * the module body) and render-time errors are both reported through `onRendered`.
31
+ *
32
+ * Implemented as a class because error boundaries require
33
+ * `getDerivedStateFromError`.
34
+ */
35
+ export declare class Runner extends React.Component<RunnerProps, RunnerState> {
36
+ state: RunnerState;
37
+ static getDerivedStateFromProps(props: RunnerProps, state: RunnerState): Partial<RunnerState> | null;
38
+ static getDerivedStateFromError(error: unknown): Partial<RunnerState>;
39
+ componentDidMount(): void;
40
+ componentDidUpdate(): void;
41
+ shouldComponentUpdate(nextProps: RunnerProps, nextState: RunnerState): boolean;
42
+ render(): React.ReactNode;
43
+ }
44
+ export {};
@@ -0,0 +1,71 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { instantiateElement } from "./instantiateElement.mjs";
5
+ /** Normalizes an unknown thrown value into an `Error`. */
6
+ function toError(thrown) {
7
+ return thrown instanceof Error ? thrown : new Error(String(thrown));
8
+ }
9
+
10
+ /**
11
+ * Evaluates already-transpiled entry code and renders the React node it exports,
12
+ * doubling as an error boundary so a runtime error thrown while rendering that node
13
+ * is caught instead of tearing down the host tree. Evaluate-time errors (a throw in
14
+ * the module body) and render-time errors are both reported through `onRendered`.
15
+ *
16
+ * Implemented as a class because error boundaries require
17
+ * `getDerivedStateFromError`.
18
+ */
19
+ export class Runner extends React.Component {
20
+ state = {
21
+ element: null,
22
+ error: null,
23
+ renderedCode: null,
24
+ renderedScope: undefined
25
+ };
26
+ static getDerivedStateFromProps(props, state) {
27
+ // Regenerate only when an input changed; unrelated re-renders keep the element.
28
+ if (props.transpiledCode === state.renderedCode && props.scope === state.renderedScope) {
29
+ return null;
30
+ }
31
+ try {
32
+ return {
33
+ element: instantiateElement(props.transpiledCode, props.scope),
34
+ error: null,
35
+ renderedCode: props.transpiledCode,
36
+ renderedScope: props.scope
37
+ };
38
+ } catch (error) {
39
+ return {
40
+ element: null,
41
+ error: toError(error),
42
+ renderedCode: props.transpiledCode,
43
+ renderedScope: props.scope
44
+ };
45
+ }
46
+ }
47
+ static getDerivedStateFromError(error) {
48
+ // A runtime error thrown while React rendered the generated node.
49
+ return {
50
+ error: toError(error)
51
+ };
52
+ }
53
+ componentDidMount() {
54
+ this.props.onRendered?.(this.state.error ?? undefined);
55
+ }
56
+ componentDidUpdate() {
57
+ this.props.onRendered?.(this.state.error ?? undefined);
58
+ }
59
+ shouldComponentUpdate(nextProps, nextState) {
60
+ return nextProps.transpiledCode !== this.props.transpiledCode || nextProps.scope !== this.props.scope || nextState.error !== this.state.error ||
61
+ // Re-render (so `componentDidUpdate` re-reports via `onRendered`) when the
62
+ // callback changes even though the code/scope didn't — e.g. restoring the
63
+ // source to the exact code the cached element last rendered. Without this,
64
+ // `getDerivedStateFromProps` short-circuits, `onRendered` never fires, and a
65
+ // pending error never clears. The regenerate itself is still skipped.
66
+ nextProps.onRendered !== this.props.onRendered;
67
+ }
68
+ render() {
69
+ return this.state.error ? null : this.state.element;
70
+ }
71
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Rewrites a source's relative imports (`./x`, `../x`) to absolute specifiers
3
+ * under the scope-import prefix, resolving each against the importing file's
4
+ * own directory. This lets every extra file be registered under a single absolute
5
+ * key that resolves regardless of where the file lives — e.g. `dir/file.ts`
6
+ * importing `../root` becomes `<prefix>root`, and `root.ts` importing `./dir/file`
7
+ * becomes `<prefix>dir/file`. External (bare) specifiers are left untouched.
8
+ *
9
+ * Only needed when extra files span subdirectories; flat demos resolve fine with
10
+ * their plain `./name` specifiers and should skip this. `fileName` is the file's
11
+ * path within the demo (e.g. `dir/file.ts`); the main source lives at the root.
12
+ */
13
+ export declare function absolutizeImports(source: string, fileName: string, prefix?: string): string;