@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.
Files changed (319) hide show
  1. package/ChunkProvider/ChunkContext.d.mts +10 -0
  2. package/ChunkProvider/ChunkContext.mjs +15 -0
  3. package/ChunkProvider/ChunkProvider.d.mts +14 -0
  4. package/ChunkProvider/ChunkProvider.mjs +38 -0
  5. package/ChunkProvider/PreloadContext.d.mts +14 -0
  6. package/ChunkProvider/PreloadContext.mjs +18 -0
  7. package/ChunkProvider/PreloadProvider.d.mts +13 -0
  8. package/ChunkProvider/PreloadProvider.mjs +33 -0
  9. package/ChunkProvider/index.d.mts +7 -0
  10. package/ChunkProvider/index.mjs +7 -0
  11. package/ChunkProvider/types.d.mts +23 -0
  12. package/ChunkProvider/types.mjs +1 -0
  13. package/ChunkProvider/usePreload.d.mts +8 -0
  14. package/ChunkProvider/usePreload.mjs +21 -0
  15. package/CodeControllerContext/CodeControllerContext.d.mts +11 -0
  16. package/CodeControllerContext/CodeControllerContext.mjs +2 -1
  17. package/CodeHighlighter/CodeHighlighter.d.mts +15 -1
  18. package/CodeHighlighter/CodeHighlighter.mjs +97 -319
  19. package/CodeHighlighter/CodeHighlighterChunk.d.mts +42 -0
  20. package/CodeHighlighter/CodeHighlighterChunk.mjs +77 -0
  21. package/CodeHighlighter/CodeHighlighterClient.mjs +597 -128
  22. package/CodeHighlighter/CodeHighlighterContext.d.mts +57 -1
  23. package/CodeHighlighter/CodeHighlighterFallbackContext.d.mts +14 -2
  24. package/CodeHighlighter/CodeHighlighterFallbackContext.mjs +1 -3
  25. package/CodeHighlighter/CodeInitialSourceLoader.d.mts +10 -0
  26. package/CodeHighlighter/CodeInitialSourceLoader.mjs +108 -0
  27. package/CodeHighlighter/CodeSourceLoader.d.mts +11 -0
  28. package/CodeHighlighter/CodeSourceLoader.mjs +128 -0
  29. package/CodeHighlighter/buildCodeHighlighterChunkProps.d.mts +47 -0
  30. package/CodeHighlighter/buildCodeHighlighterChunkProps.mjs +61 -0
  31. package/CodeHighlighter/buildStringFallback.d.mts +29 -0
  32. package/CodeHighlighter/buildStringFallback.mjs +42 -0
  33. package/CodeHighlighter/codeToFallbackProps.d.mts +31 -2
  34. package/CodeHighlighter/codeToFallbackProps.mjs +347 -42
  35. package/CodeHighlighter/createClientProps.d.mts +17 -0
  36. package/CodeHighlighter/createClientProps.mjs +78 -0
  37. package/CodeHighlighter/errors.d.mts +6 -0
  38. package/CodeHighlighter/errors.mjs +10 -0
  39. package/CodeHighlighter/fallbackCompression.d.mts +96 -0
  40. package/CodeHighlighter/fallbackCompression.mjs +253 -0
  41. package/CodeHighlighter/fallbackFormat.d.mts +137 -0
  42. package/CodeHighlighter/fallbackFormat.mjs +422 -0
  43. package/CodeHighlighter/index.d.mts +4 -1
  44. package/CodeHighlighter/index.mjs +3 -1
  45. package/CodeHighlighter/mergeComments.d.mts +38 -0
  46. package/CodeHighlighter/mergeComments.mjs +80 -0
  47. package/CodeHighlighter/prepareInitialSource.d.mts +42 -0
  48. package/CodeHighlighter/prepareInitialSource.mjs +292 -0
  49. package/CodeHighlighter/resolveFallbackCritical.d.mts +23 -0
  50. package/CodeHighlighter/resolveFallbackCritical.mjs +44 -0
  51. package/CodeHighlighter/types.d.mts +272 -8
  52. package/CodeHighlighter/useCodeFallback.d.mts +94 -0
  53. package/CodeHighlighter/useCodeFallback.mjs +204 -0
  54. package/CodeHighlighter/useGrammarsReady.d.mts +18 -0
  55. package/CodeHighlighter/useGrammarsReady.mjs +45 -0
  56. package/CodeHighlighter/useSpeculativeCodePreload.d.mts +26 -0
  57. package/CodeHighlighter/useSpeculativeCodePreload.mjs +40 -0
  58. package/CodeHighlighter/useSpeculativeEditingPreload.d.mts +33 -0
  59. package/CodeHighlighter/useSpeculativeEditingPreload.mjs +58 -0
  60. package/CodeHighlighter/useSpeculativeGrammarPreload.d.mts +23 -0
  61. package/CodeHighlighter/useSpeculativeGrammarPreload.mjs +31 -0
  62. package/CodeHighlighter/useSpeculativeUseCodePreload.d.mts +22 -0
  63. package/CodeHighlighter/useSpeculativeUseCodePreload.mjs +41 -0
  64. package/CodeProvider/CodeContext.d.mts +47 -12
  65. package/CodeProvider/CodeContext.mjs +7 -0
  66. package/CodeProvider/CodeProvider.d.mts +4 -2
  67. package/CodeProvider/CodeProvider.mjs +40 -102
  68. package/CodeProvider/CodeProviderLazy.d.mts +40 -0
  69. package/CodeProvider/CodeProviderLazy.mjs +96 -0
  70. package/CodeProvider/constants.d.mts +26 -0
  71. package/CodeProvider/constants.mjs +24 -0
  72. package/CodeProvider/createParseSourceWorkerClient.d.mts +6 -0
  73. package/CodeProvider/createParseSourceWorkerClient.mjs +22 -2
  74. package/CodeProvider/index.d.mts +2 -1
  75. package/CodeProvider/index.mjs +9 -1
  76. package/CodeProvider/parseSourceWorker.mjs +33 -0
  77. package/CodeProvider/useCodeProviderValue.d.mts +54 -0
  78. package/CodeProvider/useCodeProviderValue.mjs +188 -0
  79. package/CoordinatedLazy/ChunkServerLoader.d.mts +25 -0
  80. package/CoordinatedLazy/ChunkServerLoader.mjs +97 -0
  81. package/CoordinatedLazy/CoordinatedContentContext.d.mts +15 -0
  82. package/CoordinatedLazy/CoordinatedContentContext.mjs +22 -0
  83. package/CoordinatedLazy/CoordinatedFallbackContext.d.mts +11 -0
  84. package/CoordinatedLazy/CoordinatedFallbackContext.mjs +13 -0
  85. package/CoordinatedLazy/CoordinatedGateContext.d.mts +14 -0
  86. package/CoordinatedLazy/CoordinatedGateContext.mjs +19 -0
  87. package/CoordinatedLazy/CoordinatedLazy.d.mts +14 -0
  88. package/CoordinatedLazy/CoordinatedLazy.mjs +86 -0
  89. package/CoordinatedLazy/CoordinatedLazyClient.d.mts +24 -0
  90. package/CoordinatedLazy/CoordinatedLazyClient.mjs +65 -0
  91. package/CoordinatedLazy/LazyContent.d.mts +26 -0
  92. package/CoordinatedLazy/LazyContent.mjs +80 -0
  93. package/CoordinatedLazy/LazyContentServer.d.mts +18 -0
  94. package/CoordinatedLazy/LazyContentServer.mjs +25 -0
  95. package/CoordinatedLazy/buildChunkRenderInputs.d.mts +8 -0
  96. package/CoordinatedLazy/buildChunkRenderInputs.mjs +35 -0
  97. package/CoordinatedLazy/createCoordinatedLazy.d.mts +32 -0
  98. package/CoordinatedLazy/createCoordinatedLazy.mjs +127 -0
  99. package/CoordinatedLazy/index.d.mts +14 -0
  100. package/CoordinatedLazy/index.mjs +18 -0
  101. package/CoordinatedLazy/resolveChunkRender.d.mts +26 -0
  102. package/CoordinatedLazy/resolveChunkRender.mjs +73 -0
  103. package/CoordinatedLazy/types.d.mts +408 -0
  104. package/CoordinatedLazy/types.mjs +1 -0
  105. package/CoordinatedLazy/useChunk.d.mts +30 -0
  106. package/CoordinatedLazy/useChunk.mjs +135 -0
  107. package/CoordinatedLazy/useCoordinatedFallback.d.mts +12 -0
  108. package/CoordinatedLazy/useCoordinatedFallback.mjs +40 -0
  109. package/CoordinatedLazy/useCoordinatedSwap.d.mts +16 -0
  110. package/CoordinatedLazy/useCoordinatedSwap.mjs +124 -0
  111. package/LICENSE +1 -1
  112. package/abstractCreateDemo/abstractCreateDemo.d.mts +54 -3
  113. package/abstractCreateDemo/abstractCreateDemo.mjs +47 -7
  114. package/abstractCreateDemo/resolveDemoFlag.d.mts +20 -0
  115. package/abstractCreateDemo/resolveDemoFlag.mjs +25 -0
  116. package/abstractCreateStream/abstractCreateStream.d.mts +18 -0
  117. package/abstractCreateStream/abstractCreateStream.mjs +45 -0
  118. package/abstractCreateStream/index.d.mts +2 -0
  119. package/abstractCreateStream/index.mjs +1 -0
  120. package/abstractCreateStream/types.d.mts +34 -0
  121. package/abstractCreateStream/types.mjs +1 -0
  122. package/abstractCreateTypes/TypeCode.mjs +12 -11
  123. package/abstractCreateTypes/typesToJsx.mjs +30 -9
  124. package/cli/ensureDemoClients.mjs +4 -148
  125. package/cli/ensureDemoPages.d.mts +45 -0
  126. package/cli/ensureDemoPages.mjs +99 -0
  127. package/cli/fileUtils/index.d.mts +11 -0
  128. package/cli/fileUtils/index.mjs +48 -0
  129. package/cli/findDemoIndexFiles.d.mts +15 -0
  130. package/cli/findDemoIndexFiles.mjs +121 -0
  131. package/cli/index.mjs +1 -1
  132. package/cli/loadNextConfig.d.mts +25 -0
  133. package/cli/loadNextConfig.mjs +60 -1
  134. package/cli/runBrowser.mjs +1 -1
  135. package/cli/runValidate.mjs +44 -1
  136. package/package.json +85 -5
  137. package/pipeline/enhanceCodeEmphasis/enhanceCodeEmphasis.mjs +30 -0
  138. package/pipeline/enhanceCodeEmphasis/enhanceCodeEmphasisLazy.d.mts +17 -0
  139. package/pipeline/enhanceCodeEmphasis/enhanceCodeEmphasisLazy.mjs +52 -0
  140. package/pipeline/hastUtils/frameFallbackFromSpans.d.mts +18 -0
  141. package/pipeline/hastUtils/frameFallbackFromSpans.mjs +24 -0
  142. package/pipeline/hastUtils/hast.d.mts +27 -0
  143. package/pipeline/hastUtils/hastCompression.d.mts +3 -1
  144. package/pipeline/hastUtils/hastCompression.mjs +9 -1
  145. package/pipeline/hastUtils/hastDecompress.mjs +10 -4
  146. package/pipeline/hastUtils/hastDictionary.mjs +9 -0
  147. package/pipeline/hastUtils/hastUtils.d.mts +4 -3
  148. package/pipeline/hastUtils/hastUtils.mjs +24 -12
  149. package/pipeline/hastUtils/index.d.mts +2 -1
  150. package/pipeline/hastUtils/index.mjs +2 -1
  151. package/pipeline/hastUtils/stripHighlightingSpans.d.mts +6 -2
  152. package/pipeline/hastUtils/stripHighlightingSpans.mjs +22 -10
  153. package/pipeline/lintJavascriptDemoFocus/lintJavascriptDemoFocus.mjs +10 -7
  154. package/pipeline/loadIsomorphicCodeVariant/applyCodeTransform.d.mts +31 -13
  155. package/pipeline/loadIsomorphicCodeVariant/applyCodeTransform.mjs +50 -55
  156. package/pipeline/loadIsomorphicCodeVariant/applyCodeTransformWithComments.d.mts +78 -0
  157. package/pipeline/loadIsomorphicCodeVariant/applyCodeTransformWithComments.mjs +405 -0
  158. package/pipeline/loadIsomorphicCodeVariant/computeHastDeltas.d.mts +5 -5
  159. package/pipeline/loadIsomorphicCodeVariant/computeHastDeltas.mjs +36 -66
  160. package/pipeline/loadIsomorphicCodeVariant/decodeHastSource.d.mts +23 -0
  161. package/pipeline/loadIsomorphicCodeVariant/decodeHastSource.mjs +92 -0
  162. package/pipeline/loadIsomorphicCodeVariant/decodeSource.d.mts +19 -0
  163. package/pipeline/loadIsomorphicCodeVariant/decodeSource.mjs +25 -0
  164. package/pipeline/loadIsomorphicCodeVariant/decodeSourceToText.d.mts +17 -0
  165. package/pipeline/loadIsomorphicCodeVariant/decodeSourceToText.mjs +26 -0
  166. package/pipeline/loadIsomorphicCodeVariant/diffHast.d.mts +26 -2
  167. package/pipeline/loadIsomorphicCodeVariant/diffHast.mjs +563 -19
  168. package/pipeline/loadIsomorphicCodeVariant/embedTransforms.d.mts +49 -0
  169. package/pipeline/loadIsomorphicCodeVariant/embedTransforms.mjs +152 -0
  170. package/pipeline/loadIsomorphicCodeVariant/findExpandingRanges.d.mts +51 -0
  171. package/pipeline/loadIsomorphicCodeVariant/findExpandingRanges.mjs +161 -0
  172. package/pipeline/loadIsomorphicCodeVariant/flattenCodeVariant.mjs +6 -3
  173. package/pipeline/loadIsomorphicCodeVariant/getAvailableTransforms.d.mts +12 -0
  174. package/pipeline/loadIsomorphicCodeVariant/getAvailableTransforms.mjs +44 -0
  175. package/pipeline/loadIsomorphicCodeVariant/getInitialVisibleSourceLines.d.mts +16 -0
  176. package/pipeline/loadIsomorphicCodeVariant/getInitialVisibleSourceLines.mjs +74 -0
  177. package/pipeline/loadIsomorphicCodeVariant/loadCodeFallback.mjs +17 -5
  178. package/pipeline/loadIsomorphicCodeVariant/loadIsomorphicCodeVariant.mjs +229 -15
  179. package/pipeline/loadIsomorphicCodeVariant/transformSource.d.mts +2 -2
  180. package/pipeline/loadIsomorphicCodeVariant/transformSource.mjs +56 -22
  181. package/pipeline/loadPrecomputedCodeHighlighter/loadPrecomputedCodeHighlighter.d.mts +18 -0
  182. package/pipeline/loadPrecomputedCodeHighlighter/loadPrecomputedCodeHighlighter.mjs +11 -7
  183. package/pipeline/loadServerTypes/hastTypeUtils.d.mts +2 -2
  184. package/pipeline/loadServerTypes/hastTypeUtils.mjs +4 -4
  185. package/pipeline/loadServerTypes/loadServerTypes.mjs +1 -1
  186. package/pipeline/loadServerTypesMeta/extractJSDocText.d.mts +14 -0
  187. package/pipeline/loadServerTypesMeta/extractJSDocText.mjs +60 -0
  188. package/pipeline/loadServerTypesMeta/processTypes.mjs +43 -46
  189. package/pipeline/loadServerTypesText/order.mjs +1 -1
  190. package/pipeline/loadServerTypesText/parseTypesMarkdown.mjs +3 -1
  191. package/pipeline/loaderUtils/index.d.mts +0 -1
  192. package/pipeline/loaderUtils/index.mjs +0 -1
  193. package/pipeline/loaderUtils/parseImportsAndComments.d.mts +5 -1
  194. package/pipeline/loaderUtils/parseImportsAndComments.mjs +19 -9
  195. package/pipeline/loaderUtils/resolveModulePath.mjs +23 -1
  196. package/pipeline/parseCreateFactoryCall/parseCreateFactoryCall.d.mts +12 -0
  197. package/pipeline/parseCreateFactoryCall/parseCreateFactoryCall.mjs +17 -13
  198. package/pipeline/parseSource/addLineGutters.mjs +45 -11
  199. package/pipeline/parseSource/calculateFrameRanges.d.mts +22 -0
  200. package/pipeline/parseSource/calculateFrameRanges.mjs +69 -25
  201. package/pipeline/parseSource/detectGrammarScopes.d.mts +13 -0
  202. package/pipeline/parseSource/detectGrammarScopes.mjs +35 -0
  203. package/pipeline/parseSource/extendSyntaxTokens.mjs +501 -43
  204. package/pipeline/parseSource/frameVisibility.d.mts +47 -0
  205. package/pipeline/parseSource/frameVisibility.mjs +114 -0
  206. package/pipeline/parseSource/grammarCache.d.mts +33 -0
  207. package/pipeline/parseSource/grammarCache.mjs +73 -0
  208. package/pipeline/parseSource/grammarLoaders.d.mts +14 -0
  209. package/pipeline/parseSource/grammarLoaders.mjs +24 -0
  210. package/pipeline/parseSource/grammarMaps.d.mts +21 -1
  211. package/pipeline/parseSource/grammarMaps.mjs +36 -0
  212. package/pipeline/parseSource/isFrameSpan.d.mts +19 -0
  213. package/pipeline/parseSource/isFrameSpan.mjs +24 -0
  214. package/pipeline/parseSource/parseSource.d.mts +41 -6
  215. package/pipeline/parseSource/parseSource.mjs +184 -36
  216. package/pipeline/parseSource/redistributeFrameFallbacks.d.mts +40 -0
  217. package/pipeline/parseSource/redistributeFrameFallbacks.mjs +138 -0
  218. package/pipeline/parseSource/restructureFrames.d.mts +5 -0
  219. package/pipeline/parseSource/restructureFrames.mjs +179 -16
  220. package/pipeline/syncPageIndex/metadataToMarkdown.mjs +6 -2
  221. package/pipeline/transformHtmlCodeBlock/transformHtmlCodeBlock.d.mts +26 -0
  222. package/pipeline/transformHtmlCodeBlock/transformHtmlCodeBlock.mjs +181 -114
  223. package/pipeline/transformHtmlCodeInline/removeSuffixFromHighlightedNodes.d.mts +12 -0
  224. package/pipeline/transformHtmlCodeInline/removeSuffixFromHighlightedNodes.mjs +52 -0
  225. package/pipeline/transformHtmlCodeInline/transformHtmlCodeInline.mjs +22 -1
  226. package/pipeline/transformTypescriptToJavascript/removeTypes.d.mts +5 -8
  227. package/pipeline/transformTypescriptToJavascript/removeTypes.mjs +27 -93
  228. package/useCode/EditableEngine.d.mts +233 -0
  229. package/useCode/EditableEngine.mjs +1712 -0
  230. package/useCode/EditingEngine.d.mts +13 -0
  231. package/useCode/EditingEngine.mjs +14 -0
  232. package/useCode/Pre.browser.mjs +5 -1
  233. package/useCode/Pre.d.mts +127 -1
  234. package/useCode/Pre.mjs +417 -165
  235. package/useCode/SourceEditingEngine.d.mts +50 -0
  236. package/useCode/SourceEditingEngine.mjs +461 -0
  237. package/useCode/TransformEngine.d.mts +39 -0
  238. package/useCode/TransformEngine.mjs +208 -0
  239. package/useCode/editingEngineCache.d.mts +29 -0
  240. package/useCode/editingEngineCache.mjs +68 -0
  241. package/useCode/sourceLineCounts.d.mts +80 -0
  242. package/useCode/sourceLineCounts.mjs +284 -0
  243. package/useCode/subscribeToggleNudge.d.mts +3 -0
  244. package/useCode/subscribeToggleNudge.mjs +95 -0
  245. package/useCode/transformEngineCache.d.mts +21 -0
  246. package/useCode/transformEngineCache.mjs +60 -0
  247. package/useCode/useCode.d.mts +140 -1
  248. package/useCode/useCode.mjs +250 -19
  249. package/useCode/useCodeUtils.d.mts +131 -20
  250. package/useCode/useCodeUtils.mjs +267 -194
  251. package/useCode/useCopyFunctionality.d.mts +13 -1
  252. package/useCode/useCopyFunctionality.mjs +39 -9
  253. package/useCode/useEditable.browser.mjs +10 -2
  254. package/useCode/useEditable.d.mts +27 -106
  255. package/useCode/useEditable.integration.browser.d.mts +1 -0
  256. package/useCode/useEditable.integration.browser.mjs +870 -0
  257. package/useCode/useEditable.mjs +198 -1247
  258. package/useCode/useEditableUtils.d.mts +50 -1
  259. package/useCode/useEditableUtils.mjs +29 -0
  260. package/useCode/useFileNavigation.d.mts +91 -3
  261. package/useCode/useFileNavigation.mjs +201 -41
  262. package/useCode/useHighlightGate.d.mts +17 -0
  263. package/useCode/useHighlightGate.mjs +147 -0
  264. package/useCode/useSourceEditing.d.mts +8 -0
  265. package/useCode/useSourceEditing.mjs +158 -314
  266. package/useCode/useSourceEnhancing.d.mts +5 -1
  267. package/useCode/useSourceEnhancing.mjs +22 -36
  268. package/useCode/useTransformManagement.d.mts +93 -5
  269. package/useCode/useTransformManagement.mjs +496 -28
  270. package/useCode/useTransitionPhase.d.mts +24 -0
  271. package/useCode/useTransitionPhase.mjs +49 -0
  272. package/useCode/useUIState.d.mts +2 -2
  273. package/useCode/useUIState.mjs +8 -8
  274. package/useCode/useVariantSelection.d.mts +130 -6
  275. package/useCode/useVariantSelection.mjs +529 -93
  276. package/useCodeWindow/useCodeWindow.d.mts +19 -2
  277. package/useCodeWindow/useCodeWindow.mjs +98 -71
  278. package/useCoordinated/coordinatePreference.d.mts +439 -0
  279. package/useCoordinated/coordinatePreference.mjs +951 -0
  280. package/useCoordinated/coordinatePreference.testUtils.d.mts +21 -0
  281. package/useCoordinated/coordinatePreference.testUtils.mjs +69 -0
  282. package/useCoordinated/createSettleGate.d.mts +96 -0
  283. package/useCoordinated/createSettleGate.mjs +171 -0
  284. package/useCoordinated/index.d.mts +8 -0
  285. package/useCoordinated/index.mjs +8 -0
  286. package/useCoordinated/layoutShiftGate.d.mts +24 -0
  287. package/useCoordinated/layoutShiftGate.mjs +79 -0
  288. package/useCoordinated/pageSettleGate.d.mts +11 -0
  289. package/useCoordinated/pageSettleGate.mjs +13 -0
  290. package/useCoordinated/scheduleTasks.d.mts +23 -0
  291. package/useCoordinated/scheduleTasks.mjs +45 -0
  292. package/useCoordinated/useCoordinated.d.mts +193 -0
  293. package/useCoordinated/useCoordinated.mjs +469 -0
  294. package/useCoordinated/useCoordinatedLazy.d.mts +17 -0
  295. package/useCoordinated/useCoordinatedLazy.mjs +38 -0
  296. package/useCoordinated/useCoordinatedLocalStorage.d.mts +16 -0
  297. package/useCoordinated/useCoordinatedLocalStorage.mjs +22 -0
  298. package/useCoordinated/useCoordinatedPreference.d.mts +20 -0
  299. package/useCoordinated/useCoordinatedPreference.mjs +26 -0
  300. package/useCoordinated/useSettleGate.d.mts +11 -0
  301. package/useCoordinated/useSettleGate.mjs +34 -0
  302. package/useDemo/exportVariant.d.mts +12 -5
  303. package/useDemo/exportVariant.mjs +59 -5
  304. package/useDemo/useDemo.d.mts +5 -2
  305. package/useScrollAnchor/useScrollAnchor.mjs +28 -5
  306. package/useStream/index.d.mts +6 -0
  307. package/useStream/index.mjs +6 -0
  308. package/useStream/streamChunks.d.mts +23 -0
  309. package/useStream/streamChunks.mjs +85 -0
  310. package/useStream/types.d.mts +45 -0
  311. package/useStream/types.mjs +1 -0
  312. package/useStream/useStream.d.mts +57 -0
  313. package/useStream/useStream.mjs +119 -0
  314. package/useStream/useStreamController.d.mts +15 -0
  315. package/useStream/useStreamController.mjs +90 -0
  316. package/withDocsInfra/withDocsInfra.d.mts +19 -0
  317. package/withDocsInfra/withDocsInfra.mjs +13 -5
  318. package/pipeline/loaderUtils/convertCommentsToOneIndexed.d.mts +0 -8
  319. package/pipeline/loaderUtils/convertCommentsToOneIndexed.mjs +0 -16
@@ -1,6 +1,50 @@
1
1
  import * as React from 'react';
2
- import { getAvailableTransforms, createTransformedFiles } from "./useCodeUtils.mjs";
2
+ // `decodeHastSource` and `frameFallbackFromSpans` are already part of the
3
+ // always-loaded `useCode` shell (via `Pre`, `sourceLineCounts`,
4
+ // `useFileNavigation`, `useSourceEnhancing`). Passing them into the lazy
5
+ // transform engine keeps the engine chunk from statically pulling them (and
6
+ // `hastDecompress`) — they stay counted in this shell instead of being hoisted.
7
+ import { decodeHastSource } from "../pipeline/loadIsomorphicCodeVariant/decodeHastSource.mjs";
8
+ import { frameFallbackFromSpans } from "../pipeline/hastUtils/index.mjs";
9
+ import { getAvailableTransforms, getApplicableTransforms, transformHasCollapsePlaceholder } from "./useCodeUtils.mjs";
10
+ import { peekTransformEngine, loadTransformEngine, preloadTransformEngine, resetTransformEngineCache } from "./transformEngineCache.mjs";
11
+ import { useCodeContext } from "../CodeProvider/CodeContext.mjs";
3
12
  import { usePreference } from "../usePreference/index.mjs";
13
+ import { useCoordinated } from "../useCoordinated/index.mjs";
14
+ import { useHighlightGate } from "./useHighlightGate.mjs";
15
+ import { useTransitionPhase } from "./useTransitionPhase.mjs";
16
+
17
+ // Stable identity for the hast helpers handed to the transform engine; both are
18
+ // module-level functions, so this never needs to change.
19
+ const transformRuntimeDeps = {
20
+ decode: decodeHastSource,
21
+ frameFallbackFromSpans
22
+ };
23
+
24
+ // The transform applier (`createTransformedFiles`, which pulls the `jsondiffpatch`
25
+ // chunk) is loaded on demand and cached in the light `./transformEngineCache`
26
+ // module — shared so `CodeHighlighter`'s speculative preload can prime it before
27
+ // the first transform-bearing block renders. Re-exported for tests and warming.
28
+ export { preloadTransformEngine, resetTransformEngineCache };
29
+
30
+ /**
31
+ * Minimum coordinator barrier wait used when `transformDelay` is unset
32
+ * or zero but a layout-shift-prone swap still needs to land on the
33
+ * same frame as peer demos. One animation frame at ~60fps so the
34
+ * coordinated paint feels instantaneous but every peer commits
35
+ * together — otherwise multiple sibling demos on the page would each
36
+ * trigger their own layout shift in sequence.
37
+ */
38
+ const MIN_TRANSFORM_WAIT_MS = 16;
39
+
40
+ /**
41
+ * Time after an originator's announce by which all peers should have
42
+ * acked their preload. The barrier fires `onWaitingForPeers` at this
43
+ * boundary so consumers can surface a transient loading indicator,
44
+ * but does NOT force-commit — the wait continues up to
45
+ * `ultimateTimeoutMs` (10s) for slow peers.
46
+ */
47
+ const TRANSFORM_GRACE_PERIOD_MS = 300;
4
48
  /**
5
49
  * Hook for managing code transforms and their application
6
50
  * Uses the useLocalStorage hook for local storage persistence of transform preferences
@@ -10,7 +54,11 @@ export function useTransformManagement({
10
54
  effectiveCode,
11
55
  selectedVariantKey,
12
56
  selectedVariant,
13
- initialTransform
57
+ initialTransform,
58
+ transformDelay,
59
+ transformLayoutShift,
60
+ selectedFileName,
61
+ expanded
14
62
  }) {
15
63
  // Transform state - get available transforms from context or from the effective code data
16
64
  const availableTransforms = React.useMemo(() => {
@@ -23,46 +71,466 @@ export function useTransformManagement({
23
71
  return getAvailableTransforms(effectiveCode, selectedVariantKey);
24
72
  }, [context?.availableTransforms, effectiveCode, selectedVariantKey]);
25
73
 
26
- // Use localStorage hook for transform persistence - this is our single source of truth
27
- const [storedValue, setStoredValue] = usePreference('transform', availableTransforms.length === 1 ? availableTransforms[0] : availableTransforms, () => {
28
- // Don't use initialTransform as the fallback - localStorage should always take precedence
29
- // We'll handle the initial transform separately below
30
- return null;
31
- });
74
+ // Lazily-resolved transform engine (the `jsondiffpatch`-pulling applier).
75
+ // Initialized synchronously from the module cache so a warmed block (a later
76
+ // block on the page, or a test pre-warm) builds transforms in the same commit.
77
+ const {
78
+ transformEngineLoader
79
+ } = useCodeContext();
80
+ const [transformEngine, setTransformEngine] = React.useState(() => peekTransformEngine() ?? null);
81
+
82
+ // Resolve the engine once the block actually has transforms. Read-only /
83
+ // no-transform blocks skip this entirely and never pull the chunk. Adopts a
84
+ // cache another block already warmed, otherwise loads via the accessor
85
+ // (deduped page-wide) or the built-in import. Fail open.
86
+ React.useEffect(() => {
87
+ if (transformEngine || availableTransforms.length === 0) {
88
+ return undefined;
89
+ }
90
+ const warm = peekTransformEngine();
91
+ if (warm) {
92
+ // Adopt a sibling-warmed engine synchronously; the surrounding effect is a
93
+ // real async load. `peekTransformEngine()` is an impure read of a
94
+ // module-mutable cache, so this cannot be derived during render.
95
+ // eslint-disable-next-line react-hooks/set-state-in-effect
96
+ setTransformEngine(() => warm);
97
+ return undefined;
98
+ }
99
+ let cancelled = false;
100
+ // `preloadTransformEngine` caches the resolved applier (and DEBUG-logs a load
101
+ // failure), so we just read it back once it settles.
102
+ preloadTransformEngine(transformEngineLoader).then(() => {
103
+ if (cancelled) {
104
+ return;
105
+ }
106
+ const create = peekTransformEngine();
107
+ if (create) {
108
+ setTransformEngine(() => create);
109
+ }
110
+ });
111
+ return () => {
112
+ cancelled = true;
113
+ };
114
+ }, [transformEngine, availableTransforms.length, transformEngineLoader]);
115
+
116
+ // Broader set used to resolve a stored preference *and* to derive the
117
+ // localStorage key: includes rename-only transforms (manifest entries
118
+ // with `hasDelta: false`) so a user preference like 'js' still applies
119
+ // the `.ts` → `.js` rename even when the toggle is hidden because
120
+ // there's no source-level delta. We always compute this from
121
+ // `effectiveCode` — `context.availableTransforms` is the *visible*
122
+ // toggle list (filtered by `hasDelta`) and is intentionally not used
123
+ // here, otherwise rename-only entries would be dropped from
124
+ // resolution and the storage key would shift whenever a transform's
125
+ // visibility changed between sibling demos.
126
+ const applicableTransforms = React.useMemo(() => getApplicableTransforms(effectiveCode, selectedVariantKey), [effectiveCode, selectedVariantKey]);
127
+
128
+ // Coordinator key. Demos sharing the same applicable transform set
129
+ // belong to the same coordination group: a user click in one demo
130
+ // triggers a synchronized barrier across all of them. `null` only
131
+ // when there are no applicable transforms at all (nothing to swap),
132
+ // otherwise we always join — even single-transform demos benefit
133
+ // from coordinating with sibling instances that share the same
134
+ // toggle (e.g. an entire docs page of JS/TS-only demos).
135
+ const coordinatorKey = React.useMemo(() => applicableTransforms.length >= 1 ? [...applicableTransforms].sort().join(':') : null, [applicableTransforms]);
136
+
137
+ // Stable per-hook identity used by the coordinator to track which
138
+ // demos have acked the current barrier. `React.useId` gives us a
139
+ // unique-per-mount string without the impure `Math.random()` /
140
+ // `Date.now()` dance, and stays stable across re-renders.
141
+ const demoId = React.useId();
32
142
 
33
- // Handle validation manually - empty string means "no transform selected"
34
- const selectedTransform = React.useMemo(() => {
35
- // If we have a stored value (including empty string), use it
36
- if (storedValue !== null) {
37
- if (storedValue === '') {
143
+ // Result of the off-critical-path `createTransformedFiles` call.
144
+ // Populated by `useCoordinated`'s `onCommit` so React batches the
145
+ // precomputed payload install with the committedValue flip into a
146
+ // single re-render in which the `transformedFiles` memo finds a
147
+ // matching cache entry and avoids re-running
148
+ // `createTransformedFiles` synchronously in the swap commit.
149
+ const [precomputed, setPrecomputed] = React.useState(null);
150
+
151
+ // Raw localStorage preference (string or empty/null encoding). The
152
+ // key is derived from `applicableTransforms` (the full set, includes
153
+ // rename-only entries) so demos with only rename-only transforms
154
+ // still participate in persistence and so a transform becoming
155
+ // rename-only doesn't move it to a different storage bucket.
156
+ const [storedValue, setStoredValue] = usePreference('transform', applicableTransforms.length === 1 ? applicableTransforms[0] : applicableTransforms,
157
+ // Don't use `initialTransform` as the fallback — localStorage
158
+ // should always take precedence. The initial-transform resolution
159
+ // happens below in `resolveTransform`.
160
+ () => null);
161
+
162
+ // Resolve a stored/initial value into a valid transform name (or null).
163
+ // Resolution uses `applicableTransforms` (which includes rename-only
164
+ // entries) so a stored preference can still apply a rename even when
165
+ // the toggle is hidden because no actual code delta exists.
166
+ const resolveTransform = React.useCallback(stored => {
167
+ if (stored !== null) {
168
+ if (stored === '') {
38
169
  return null;
39
170
  }
40
- // Validate the stored value
41
- if (!availableTransforms.includes(storedValue)) {
171
+ if (!applicableTransforms.includes(stored)) {
42
172
  return null;
43
173
  }
44
- return storedValue;
174
+ return stored;
45
175
  }
46
-
47
- // If no stored value and we have an initial transform, use it (but don't store it yet)
48
- if (initialTransform && availableTransforms.includes(initialTransform)) {
176
+ if (initialTransform && applicableTransforms.includes(initialTransform)) {
49
177
  return initialTransform;
50
178
  }
51
179
  return null;
52
- }, [storedValue, availableTransforms, initialTransform]);
53
- const setSelectedTransformAsUser = React.useCallback(value => {
54
- const valueToStore = value === null ? '' : value;
55
- setStoredValue(valueToStore);
180
+ }, [applicableTransforms, initialTransform]);
181
+
182
+ // While the highlighter has not yet produced parsed HAST for the
183
+ // transformed variant (`context.deferHighlight === true`), gate the
184
+ // localStorage-restored value behind the SSR-safe `null`. Without
185
+ // this gate, a refresh of a page whose stored preference selects a
186
+ // transform commits the swap during hydration — before
187
+ // `useCodeParsing` has run `parseCode` — so `<Pre>` paints the
188
+ // transformed source as unhighlighted plain text with a different
189
+ // frame structure, the collapse animation runs against that
190
+ // intermediate tree, and then `parseCode` resolves a frame or two
191
+ // later and the DOM rebuilds with full highlighting, producing a
192
+ // visible post-animation jump. Holding the underlying value at the
193
+ // SSR-safe default means `<Pre>` keeps rendering exactly what the
194
+ // server emitted until the highlighter is ready; the moment
195
+ // `deferHighlight` flips false, the receiver flow opens its barrier
196
+ // and the collapse animation plays once, against a fully-parsed
197
+ // target tree.
198
+ const effectiveStoredValue = context?.deferHighlight ? null : storedValue;
199
+
200
+ // Resolved view of the raw preference. This is the value
201
+ // `useCoordinated` sees as its "external source of truth"; when it
202
+ // changes from outside (peer broadcast, other tab, applicable
203
+ // transforms re-resolution, or the highlighter becoming ready) the
204
+ // hook's receiver flow opens a barrier so every demo on the page
205
+ // commits the swap together.
206
+ const resolvedStoredValue = React.useMemo(() => resolveTransform(effectiveStoredValue), [resolveTransform, effectiveStoredValue]);
207
+
208
+ // Wrap the storage setter so the `useCoordinated` tuple signature
209
+ // matches (`string | null` in, void out). `null` is encoded as `''`
210
+ // so the raw preference can distinguish "explicitly cleared"
211
+ // (empty string) from "never set / hydration placeholder" (null).
212
+ const setResolvedStoredValue = React.useCallback(next => {
213
+ setStoredValue(next === null ? '' : next);
56
214
  }, [setStoredValue]);
57
215
 
58
- // Memoize all transformed files based on selectedTransform
216
+ // Stable tuple identity so `useCoordinated` doesn't churn its
217
+ // dependency arrays when this hook re-renders with the same value.
218
+ // The setter passed here is a no-op: storage writes are performed
219
+ // *eagerly* by `setSelectedTransformAsUser` (so user intent is
220
+ // persisted immediately on click and broadcast to peers in the same
221
+ // tick), not lazily on barrier commit. The engine sees the eager
222
+ // write echo back through `usePreference` and dedupes it via its
223
+ // `inFlightTargetRef` guard so the receiver flow doesn't double-fire.
224
+ const underlying = React.useMemo(() => [resolvedStoredValue, () => {}], [resolvedStoredValue]);
225
+
226
+ // Barrier wait length. Falls back to one frame when `transformDelay`
227
+ // isn't configured so peers still align on the same paint without
228
+ // making the click feel sluggish.
229
+ const hasDelay = typeof transformDelay === 'number' && transformDelay > 0;
230
+
231
+ // Latest committed transform — read by `causesLayoutShift` to
232
+ // classify the *outgoing* tree's collapse placeholders. Assigned
233
+ // after the `useCoordinated` call below so the ref always reflects
234
+ // the value the engine just committed.
235
+ const committedRef = React.useRef(resolvedStoredValue);
236
+
237
+ // Tracks the previous render's committed transform so we can decide
238
+ // the originator's `minWaitMs` synchronously inside
239
+ // `selectTransformDispatch`: leaving a non-null transform needs the
240
+ // pre-swap expand window, but `null → X` commits immediately.
241
+ const prevCommittedTransformRef = React.useRef(resolvedStoredValue);
242
+
243
+ // Latest props read by the engine's `causesLayoutShift` / `preload`
244
+ // / `onCommit` callbacks. Kept in a ref so those callbacks can be
245
+ // referentially stable (the engine captures them at announce time
246
+ // via the hook's internal callback ref, and a churn here would
247
+ // restart in-flight barriers).
248
+ const layoutShiftPropsRef = React.useRef({
249
+ selectedVariant,
250
+ transformLayoutShift,
251
+ selectedFileName,
252
+ expanded,
253
+ fallbacks: context?.fallbacks
254
+ });
255
+ // eslint-disable-next-line react-hooks/refs
256
+ layoutShiftPropsRef.current = {
257
+ selectedVariant,
258
+ transformLayoutShift,
259
+ selectedFileName,
260
+ expanded,
261
+ fallbacks: context?.fallbacks
262
+ };
263
+
264
+ // Plumb classifier props through `transformHasCollapsePlaceholder`
265
+ // on every render. The engine's `causesLayoutShift` callback is
266
+ // only invoked when a swap is actually announced, but consumers
267
+ // (and tests) rely on the classifier observing prop changes
268
+ // eagerly — both to validate plumbing and to surface any heavier
269
+ // diagnostic side effects the classifier might perform.
270
+ React.useMemo(() => transformHasCollapsePlaceholder(selectedVariant, resolvedStoredValue, {
271
+ mode: transformLayoutShift,
272
+ selectedFileName,
273
+ expanded
274
+ }), [selectedVariant, resolvedStoredValue, transformLayoutShift, selectedFileName, expanded]);
275
+
276
+ // A swap "causes layout shift" — and therefore needs the synchronous
277
+ // barrier path — when either the incoming or the outgoing tree
278
+ // carries `.collapse` placeholders that need to animate. Peers
279
+ // without layout shift get routed to the engine's lazy path and
280
+ // commit after `lazyMinWaitMs` (`effectiveDelay * 2` below) so their
281
+ // commit lands after the originator's full expand → swap → collapse
282
+ // window has played out.
283
+ const causesLayoutShift = React.useCallback(target => {
284
+ const props = layoutShiftPropsRef.current;
285
+ const incoming = transformHasCollapsePlaceholder(props.selectedVariant, target, {
286
+ mode: props.transformLayoutShift,
287
+ selectedFileName: props.selectedFileName,
288
+ expanded: props.expanded
289
+ });
290
+ if (incoming) {
291
+ return true;
292
+ }
293
+ return transformHasCollapsePlaceholder(props.selectedVariant, committedRef.current, {
294
+ mode: props.transformLayoutShift,
295
+ selectedFileName: props.selectedFileName,
296
+ expanded: props.expanded
297
+ });
298
+ }, []);
299
+ // Hold the originator's coordinator barrier open while the
300
+ // highlighter pipeline (sync `parseCode` + async `computeHastDeltas`)
301
+ // is still in flight. The receiver flow already masks the stored
302
+ // value through `effectiveStoredValue`, but an interactive click
303
+ // flows through `useCoordinated` directly and would otherwise commit
304
+ // after `transformDelay` even when `transformedCode` hasn't landed —
305
+ // painting the incoming tree from un-deltaed source then snapping to
306
+ // the deltaed version a frame later. See `useHighlightGate` for how
307
+ // the gate plumbs into the engine's `preload` slot.
308
+ const awaitHighlight = useHighlightGate(!!context?.deferHighlight);
309
+
310
+ // Off-critical-path build of the next file tree. Runs in the engine's
311
+ // `preload` slot so the originator's barrier holds open until the
312
+ // payload is ready, and the result is committed atomically with the
313
+ // value flip in `onCommit`.
314
+ //
315
+ // Synchronous fast path when the highlighter is ready: the engine
316
+ // fires the preload immediately (no microtask hop) so the result is
317
+ // available the moment `onCommit` runs inside the same `act(...)`
318
+ // callback as the timer fire.
319
+ //
320
+ // Async path when `context.deferHighlight === true`: we await the
321
+ // gate so the barrier's wait extends until the incoming tree can
322
+ // paint with its full transform deltas applied. The engine's
323
+ // `signal` is forwarded so a superseding announce can supersede the
324
+ // wait instead of leaking it.
325
+ const preload = React.useCallback((target, signal) => {
326
+ const buildResult = create => {
327
+ const props = layoutShiftPropsRef.current;
328
+ return {
329
+ variant: props.selectedVariant,
330
+ transform: target,
331
+ result: create(props.selectedVariant, target, transformRuntimeDeps, props.fallbacks)
332
+ };
333
+ };
334
+ // Resolve the engine: synchronously from the warm module cache, otherwise
335
+ // via the loader (defer-if-cold — the coordinator barrier holds the swap
336
+ // open until this promise resolves).
337
+ const wait = awaitHighlight(signal);
338
+ // Sync from the warm cache, else load (and cache) via the accessor.
339
+ const engine = loadTransformEngine(transformEngineLoader);
340
+ // Fully synchronous fast path: highlighter ready and engine already warm.
341
+ if (wait === null && typeof engine === 'function') {
342
+ return buildResult(engine);
343
+ }
344
+ return Promise.all([wait ?? Promise.resolve(), Promise.resolve(engine)]).then(([, create]) => buildResult(create));
345
+ }, [awaitHighlight, transformEngineLoader]);
346
+ const onCommit = React.useCallback((_target, preloaded) => {
347
+ if (preloaded) {
348
+ setPrecomputed(preloaded);
349
+ }
350
+ }, []);
351
+ const [delayedAppliedTransform, selectTransformDispatch, coordinationExtras] = useCoordinated(underlying, {
352
+ channelKey: coordinatorKey,
353
+ peerId: demoId,
354
+ causesLayoutShift,
355
+ preload,
356
+ onCommit,
357
+ // eslint-disable-next-line react-hooks/refs
358
+ minWaitMs: hasDelay && prevCommittedTransformRef.current !== null ? transformDelay : 0,
359
+ multiPeerExtraMinWaitMs: hasDelay ? 0 : MIN_TRANSFORM_WAIT_MS,
360
+ lazyMinWaitMs: hasDelay ? transformDelay : 0,
361
+ gracePeriodMs: TRANSFORM_GRACE_PERIOD_MS
362
+ });
363
+
364
+ // Keep the outgoing-tree probe in sync with whatever the engine just
365
+ // committed. Mutating a ref during render is safe — React tolerates
366
+ // it as long as the value derives deterministically from inputs of
367
+ // the current render.
368
+ // eslint-disable-next-line react-hooks/refs
369
+ committedRef.current = delayedAppliedTransform;
370
+ // eslint-disable-next-line react-hooks/refs
371
+ prevCommittedTransformRef.current = delayedAppliedTransform;
372
+
373
+ // User-facing "intent" value: updates synchronously on a local
374
+ // click (the engine sets `pendingValue` inside `runCoordination`
375
+ // before yielding) and on a peer broadcast (receiver flow likewise
376
+ // sets `pendingValue` synchronously when opening its barrier).
377
+ const selectedTransform = coordinationExtras.pendingValue;
378
+
379
+ // Surfaced by the engine only on the originator and only once the
380
+ // grace period has elapsed without convergence. `null` is a valid
381
+ // pending target (swap back to the un-transformed original);
382
+ // `undefined` means nothing is pending or we're still inside the
383
+ // grace window.
384
+ const pendingTransform = coordinationExtras.isWaitingForPeers ? coordinationExtras.pendingValue : undefined;
385
+
386
+ // No-op when called with the value already in flight / committed —
387
+ // otherwise the engine would open a fresh (redundant) barrier and
388
+ // re-announce, briefly toggling `isCoordinating` on peers. The
389
+ // storage write happens *before* the engine dispatch so user intent
390
+ // is broadcast to peer demos on the same tick as the click (every
391
+ // demo enters its expand → swap → collapse window together), even
392
+ // when this demo's own visible swap is gated by `transformDelay`.
393
+ //
394
+ // Validation differs from `resolveTransform`: an explicit `null`
395
+ // here means "user cleared the transform" — never re-resolved to
396
+ // `initialTransform` (which `resolveTransform` only consults for
397
+ // hydration of a never-set stored value).
398
+ const setSelectedTransformAsUser = React.useCallback(value => {
399
+ const resolved = value === null || applicableTransforms.includes(value) ? value : null;
400
+ if (resolved === selectedTransform) {
401
+ return;
402
+ }
403
+ // Start local coordination from the user action first so this demo
404
+ // is always treated as the originator (which drives waiting affordances
405
+ // like pendingTransform), then broadcast the persisted preference.
406
+ selectTransformDispatch(resolved);
407
+ setResolvedStoredValue(resolved);
408
+ }, [applicableTransforms, selectedTransform, setResolvedStoredValue, selectTransformDispatch]);
409
+
410
+ // Post-swap `data-transforming` (`'expanded'` paused → `'collapsing'`
411
+ // active) window. Fires whenever the committed transform swaps to a
412
+ // non-null value:
413
+ //
414
+ // - `null → A` when A has no `.collapse` placeholders the
415
+ // barrier's `minWaitMs` already played out; this
416
+ // window is the only animation hook on the
417
+ // incoming tree.
418
+ // - `A → B` the pre-swap (`'collapsed'` → `'expanding'`)
419
+ // window opened by the barrier covered the
420
+ // outgoing tree; the post-swap window adds a
421
+ // matching trailing animation hook, giving
422
+ // transform-to-transform a `2 × transformDelay`
423
+ // total window (expand → swap → collapse) so
424
+ // consumer CSS can animate both the outgoing
425
+ // and the incoming tree.
426
+ // - `A → null` does not arm the window — the trailing
427
+ // untransformed tree has nothing to enter-
428
+ // animate.
429
+ //
430
+ // Detected during render so the flag lands on the same paint as the
431
+ // new tree, then cleared after `transformDelay` ms.
432
+ const [postSwapWindowActive, setPostSwapWindowActive] = React.useState(false);
433
+ // Seed with a sentinel (`undefined`) rather than the committed value so a
434
+ // transform that is ALREADY applied on the first render — restored from a
435
+ // saved localStorage preference, or a demo `initialTransform` default — reads
436
+ // as a null→X swap and arms the post-swap window, animating the swap the same
437
+ // way a manual toggle does. A null initial transform compares equal-to-null
438
+ // below (`delayedAppliedTransform !== null` is false), so a no-transform mount
439
+ // still does not animate.
440
+ const [prevAppliedTransform, setPrevAppliedTransform] = React.useState(undefined);
441
+ if (prevAppliedTransform !== delayedAppliedTransform) {
442
+ setPrevAppliedTransform(delayedAppliedTransform);
443
+ if (delayedAppliedTransform !== null && hasDelay) {
444
+ setPostSwapWindowActive(true);
445
+ }
446
+ }
447
+ // The window only ever opens under `hasDelay` (line above), so an open window
448
+ // when `!hasDelay` means `hasDelay` flipped true→false — a derivable invariant,
449
+ // not a side-effect. Clear it during render so it lands on the same commit.
450
+ if (postSwapWindowActive && !hasDelay) {
451
+ setPostSwapWindowActive(false);
452
+ }
453
+ React.useEffect(() => {
454
+ if (!postSwapWindowActive) {
455
+ return undefined;
456
+ }
457
+ // `delayedAppliedTransform` is in the dep array so a fresh swap
458
+ // during an already-open window (A → B → C in rapid succession)
459
+ // re-arms the timer for the full `transformDelay` instead of
460
+ // inheriting whatever was left over from B's window.
461
+ const timerId = setTimeout(() => setPostSwapWindowActive(false), transformDelay);
462
+ return () => clearTimeout(timerId);
463
+ // `hasDelay` is intentionally not a dependency: the body never reads it (the
464
+ // `!hasDelay` window teardown is the render-time clear above).
465
+ }, [postSwapWindowActive, transformDelay, delayedAppliedTransform]);
466
+
467
+ // If both phases are technically eligible (e.g. user clicked a third
468
+ // target during a post-swap window), the pending pre-swap takes
469
+ // priority — the visible tree IS the just-applied one and it needs
470
+ // to expand out for the next swap. When `transformDelay` is not
471
+ // configured, no animation window is opening (any coordinator wait
472
+ // is the one-frame `MIN_TRANSFORM_WAIT_MS`, too short to animate)
473
+ // so the phase stays `null` even if `delayedAppliedTransform`
474
+ // briefly lags `selectedTransform`.
475
+ //
476
+ // Each phase enters a "paused" value first (`'collapsed'` for the
477
+ // pre-swap window, `'expanded'` for the post-swap window). The
478
+ // rendered `<Pre>` calls `notifyTransformTransitionReady` once it
479
+ // has painted the new tree at that paused value, flipping
480
+ // `transformTransitionReady` to `true` which advances the phase to
481
+ // the matching active value (`'expanding'` / `'collapsing'`). The
482
+ // readiness flag is keyed on the current paused window so each new
483
+ // swap starts with a fresh wait.
484
+ const transformTransitionWindowKey = `${String(delayedAppliedTransform)}|${String(selectedTransform)}|${postSwapWindowActive ? '1' : '0'}`;
485
+ const {
486
+ ready: transformTransitionReady,
487
+ notify: notifyTransformTransitionReady
488
+ } = useTransitionPhase(transformTransitionWindowKey);
489
+ const transformingPhase = (() => {
490
+ if (!hasDelay) {
491
+ return null;
492
+ }
493
+ // `null -> transform` should never expose a pre-swap 'expanding' frame.
494
+ // During hydration restore, `pendingValue` can flip to the stored
495
+ // transform one render before commit; treating that as 'expanding' causes
496
+ // a visible double animation (expand then collapse). Only non-null
497
+ // outgoing trees need the pre-swap expand phase.
498
+ if (delayedAppliedTransform !== selectedTransform && delayedAppliedTransform !== null) {
499
+ return transformTransitionReady ? 'expanding' : 'collapsed';
500
+ }
501
+ if (postSwapWindowActive) {
502
+ return transformTransitionReady ? 'collapsing' : 'expanded';
503
+ }
504
+ return null;
505
+ })();
506
+
507
+ // Memoize all transformed files based on the *committed* transform
508
+ // so the rendered tree stays put during the `transformDelay` window.
509
+ // Prefer the precomputed result captured by `useCoordinated`'s
510
+ // `onCommit` when its `(variant, transform)` keys match the values
511
+ // about to be rendered.
59
512
  const transformedFiles = React.useMemo(() => {
60
- return createTransformedFiles(selectedVariant, selectedTransform);
61
- }, [selectedVariant, selectedTransform]);
62
- return {
513
+ if (precomputed && precomputed.variant === selectedVariant && precomputed.transform === delayedAppliedTransform) {
514
+ return precomputed.result;
515
+ }
516
+ // The engine hasn't resolved yet (cold). Defer this render's build — the
517
+ // resolve effect re-renders once it's ready, and the (un-transformed)
518
+ // original files render for the one intervening tick. `createTransformedFiles`
519
+ // returns `undefined` for a null transform anyway, so a no-transform block
520
+ // (engine never loaded) correctly yields `undefined` here.
521
+ if (!transformEngine) {
522
+ return undefined;
523
+ }
524
+ return transformEngine(selectedVariant, delayedAppliedTransform, transformRuntimeDeps, context?.fallbacks);
525
+ }, [precomputed, selectedVariant, delayedAppliedTransform, context?.fallbacks, transformEngine]);
526
+ const result = {
63
527
  availableTransforms,
64
528
  selectedTransform,
65
529
  transformedFiles,
66
- selectTransform: setSelectedTransformAsUser
530
+ selectTransform: setSelectedTransformAsUser,
531
+ transformingPhase,
532
+ notifyTransformTransitionReady,
533
+ pendingTransform
67
534
  };
535
+ return result;
68
536
  }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Four-state paused→active animation phase shared by
3
+ * `useTransformManagement` and `useVariantSelection`. Each swap
4
+ * window enters a "paused" value first (`'collapsed'` pre-swap or
5
+ * `'expanded'` post-swap) so the rendered `<Pre>` can settle into
6
+ * the animation start state; the host then advances to the matching
7
+ * active value (`'expanding'` / `'collapsing'`) once readiness fires.
8
+ */
9
+ export type TransitionPhase = 'collapsed' | 'expanding' | 'expanded' | 'collapsing' | null;
10
+ /**
11
+ * Tracks the paused→active handshake for a single phase source.
12
+ *
13
+ * `windowKey` is an opaque identifier the caller composes from
14
+ * whatever uniquely identifies the current swap window (typically
15
+ * `(from, to, postSwap)`). The readiness flag is keyed against it so
16
+ * every new window starts with a fresh wait — `notify()` only marks
17
+ * the current window ready, and a subsequent window flip
18
+ * automatically falls back to "not ready" without any explicit
19
+ * reset.
20
+ */
21
+ export declare function useTransitionPhase(windowKey: string): {
22
+ ready: boolean;
23
+ notify: () => void;
24
+ };
@@ -0,0 +1,49 @@
1
+ import * as React from 'react';
2
+
3
+ /**
4
+ * Four-state paused→active animation phase shared by
5
+ * `useTransformManagement` and `useVariantSelection`. Each swap
6
+ * window enters a "paused" value first (`'collapsed'` pre-swap or
7
+ * `'expanded'` post-swap) so the rendered `<Pre>` can settle into
8
+ * the animation start state; the host then advances to the matching
9
+ * active value (`'expanding'` / `'collapsing'`) once readiness fires.
10
+ */
11
+
12
+ /**
13
+ * Tracks the paused→active handshake for a single phase source.
14
+ *
15
+ * `windowKey` is an opaque identifier the caller composes from
16
+ * whatever uniquely identifies the current swap window (typically
17
+ * `(from, to, postSwap)`). The readiness flag is keyed against it so
18
+ * every new window starts with a fresh wait — `notify()` only marks
19
+ * the current window ready, and a subsequent window flip
20
+ * automatically falls back to "not ready" without any explicit
21
+ * reset.
22
+ */
23
+ export function useTransitionPhase(windowKey) {
24
+ const [state, setState] = React.useState({
25
+ key: windowKey,
26
+ ready: false
27
+ });
28
+ // React's recommended pattern for resetting state when an input
29
+ // changes: a guarded `setState` during render. This guarantees
30
+ // each new window starts at not-ready, even if the same key value
31
+ // recurs along an unusual swap path.
32
+ if (state.key !== windowKey) {
33
+ setState({
34
+ key: windowKey,
35
+ ready: false
36
+ });
37
+ }
38
+ const ready = state.key === windowKey && state.ready;
39
+ const notify = React.useCallback(() => {
40
+ setState(prev => prev.key === windowKey ? {
41
+ key: windowKey,
42
+ ready: true
43
+ } : prev);
44
+ }, [windowKey]);
45
+ return {
46
+ ready,
47
+ notify
48
+ };
49
+ }
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  interface UseUIStateProps {
3
- defaultOpen?: boolean;
3
+ initialExpanded?: boolean;
4
4
  mainSlug?: string;
5
5
  }
6
6
  export interface UseUIStateResult {
@@ -13,7 +13,7 @@ export interface UseUIStateResult {
13
13
  * Auto-expands if there's a relevant hash for this demo
14
14
  */
15
15
  export declare function useUIState({
16
- defaultOpen,
16
+ initialExpanded,
17
17
  mainSlug
18
18
  }: UseUIStateProps): UseUIStateResult;
19
19
  export {};