@mui/internal-docs-infra 0.11.1-canary.9 → 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 +84 -4
  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
@@ -0,0 +1,193 @@
1
+ import * as React from 'react';
2
+ import { type ChannelKey, type PeerId } from "./coordinatePreference.mjs";
3
+ /**
4
+ * Options for {@link useCoordinated}. See `coordinatePreference` for
5
+ * the underlying semantics; only React-specific behaviors are
6
+ * documented here.
7
+ */
8
+ export interface UseCoordinatedOptions<TValue, TPreload> {
9
+ /**
10
+ * Coordination scope. All peers (component instances) that share a
11
+ * `channelKey` participate in the same layout-shift barrier. Pass
12
+ * `null` to opt out of coordination entirely (the hook becomes a
13
+ * plain pass-through of the underlying `[value, setValue]`).
14
+ */
15
+ channelKey: ChannelKey | null;
16
+ /**
17
+ * Stable identifier for *this* peer within the channel. Defaults to
18
+ * a freshly generated id on mount. Override when stable cross-mount
19
+ * identity matters (e.g. for analytics / debugging).
20
+ */
21
+ peerId?: PeerId;
22
+ /**
23
+ * Return `true` when applying this target would visibly shift
24
+ * layout — the peer joins the channel-wide barrier so all such
25
+ * peers commit together. Return `false` for non-disruptive changes
26
+ * — the peer commits lazily on its own self-serial chain. See
27
+ * `coordinatePreference` for the full semantics.
28
+ */
29
+ causesLayoutShift: (target: TValue) => boolean;
30
+ /**
31
+ * Optional async work to run before the barrier commits (for
32
+ * `causesLayoutShift === true`) or before a lazy commit (for
33
+ * `false`). The resolved value is handed to `onCommit`.
34
+ */
35
+ preload?: (target: TValue, signal: AbortSignal) => TPreload | Promise<TPreload>;
36
+ /**
37
+ * Hook fired inside the coordinated commit, before the visible
38
+ * value flips. Useful for installing precomputed payloads into
39
+ * neighboring state. The visible `value` returned from this hook
40
+ * always lags `pendingValue` until coordination settles, so this
41
+ * runs *with* the value flip, not before it.
42
+ *
43
+ * Also fires once on first mount, with the initial preloaded
44
+ * payload, so consumers can install precomputed state on hydration
45
+ * without a separate code path.
46
+ *
47
+ * Under normal conditions `preloaded` is whatever this peer's
48
+ * `preload` resolved to. It may still be `undefined` when:
49
+ * - the barrier force-resolved at `ultimateTimeoutMs` (a sibling
50
+ * peer crashed / hung; accompanied by a console warning),
51
+ * - `preload` threw (logged via `console.error`, treated as a
52
+ * no-op so the rest of the channel still commits), or
53
+ * - `preload` explicitly returned `undefined`.
54
+ *
55
+ * Handlers should tolerate the undefined case and fall back to a
56
+ * synchronous render path rather than throwing.
57
+ */
58
+ onCommit?: (target: TValue, preloaded: TPreload | undefined) => void;
59
+ /**
60
+ * See {@link AnnounceOptions.minWaitMs}.
61
+ */
62
+ minWaitMs?: number;
63
+ /**
64
+ * See {@link AnnounceOptions.multiPeerExtraMinWaitMs}.
65
+ */
66
+ multiPeerExtraMinWaitMs?: number;
67
+ /**
68
+ * See {@link AnnounceOptions.lazyMinWaitMs}.
69
+ */
70
+ lazyMinWaitMs?: number;
71
+ /**
72
+ * See {@link AnnounceOptions.gracePeriodMs}.
73
+ */
74
+ gracePeriodMs?: number;
75
+ /**
76
+ * See {@link AnnounceOptions.ultimateTimeoutMs}.
77
+ */
78
+ ultimateTimeoutMs?: number;
79
+ /**
80
+ * Controls whether `isCoordinating` flips *during* the preload
81
+ * or *after* it. `pendingValue` (the user-facing "intent"
82
+ * signal) always flips synchronously regardless of this flag —
83
+ * toolbars and other affordances stay responsive on click.
84
+ *
85
+ * - `false` (default) — defer `isCoordinating` until the
86
+ * originator's `preload` settles. Use this when the preload
87
+ * is CPU-bound (parsing, syntax highlighting, layout
88
+ * measurement, etc.) and the consumer drives a visible
89
+ * animation off `isCoordinating`. Running the animation
90
+ * concurrently with the preload would steal main-thread time
91
+ * from the compositor and produce a janky transition; with
92
+ * the flip deferred the animation only starts once the heavy
93
+ * work is done.
94
+ * - `true` — flip `isCoordinating` synchronously on the
95
+ * originating setter call, so the animation runs in parallel
96
+ * with the preload. Use this when the preload is I/O-bound
97
+ * (network fetches, `localStorage` reads, etc.) so the
98
+ * animation and the I/O roundtrip overlap.
99
+ *
100
+ * The coordinator always yields to the browser (via
101
+ * `scheduler.yield()` when available, otherwise a `setTimeout`
102
+ * macrotask) before invoking `preload`, so even synchronous
103
+ * preloads settle one macrotask after the originating setter
104
+ * call. This lets the intermediate loading state paint before
105
+ * the (potentially CPU-bound) preload monopolizes the main
106
+ * thread. This flag has no effect when `preload` is omitted;
107
+ * the flip is synchronous either way.
108
+ *
109
+ * Only the originator's flip is affected. Sibling peers picked
110
+ * up via `notifySiblings` still observe the receiver flow's
111
+ * synchronous flip, because their `isCoordinating` is driven
112
+ * by the originator's broadcast rather than a local click.
113
+ */
114
+ animateDuringPreload?: boolean;
115
+ /**
116
+ * Scheduling priority for lazy-path commits.
117
+ *
118
+ * - `'idle'` (default) — lazy-path commits are deferred via
119
+ * `requestIdleCallback` so the browser can yield to in-flight
120
+ * paints and input. Use when the lazy peer's commit itself is
121
+ * main-thread heavy (DOM reconciliation of a freshly
122
+ * transformed tree, etc.).
123
+ * - `'normal'` — the commit lands as soon as the preload
124
+ * resolves. Use for I/O-bound `preload`s where the commit is
125
+ * cheap and you want each peer's swap to surface immediately;
126
+ * otherwise idle scheduling can cluster commits together near
127
+ * the slowest peer's settle.
128
+ *
129
+ * Has no effect when this peer takes the barrier path — barrier
130
+ * commits are batched synchronously inside the barrier's resolve
131
+ * microtask regardless.
132
+ */
133
+ lazyCommitPriority?: 'idle' | 'normal';
134
+ }
135
+ export interface UseCoordinatedExtras<TValue> {
136
+ /**
137
+ * The most recently announced target value. Equals the committed
138
+ * `value` when no coordination is in flight. Useful for showing an
139
+ * optimistic preview UI (toolbar selection, etc.) that should react
140
+ * instantly to a click even when the visible content has a pending
141
+ * barrier.
142
+ */
143
+ pendingValue: TValue;
144
+ /**
145
+ * `true` while a coordination is in flight that this peer can drive
146
+ * an animation off of. For receivers and barrier joiners that lands
147
+ * synchronously with the announce. For originators the flip is
148
+ * controlled by `animateDuringPreload`: with the default
149
+ * `animateDuringPreload: false`, `isCoordinating` stays `false`
150
+ * until the originator's `preload` settles, then flips `true` for
151
+ * the remainder of the barrier; with `animateDuringPreload: true`,
152
+ * it flips synchronously on the originating setter call so the
153
+ * animation overlaps with an I/O-bound preload. Use
154
+ * {@link pendingValue} to drive intent-based affordances (toolbar
155
+ * selection, etc.) that should react instantly to a click
156
+ * regardless of this flag. Surfaces as `data-coordinating` on
157
+ * consumers.
158
+ */
159
+ isCoordinating: boolean;
160
+ /**
161
+ * `true` once the grace period has elapsed with the barrier still
162
+ * unresolved. Only set on the originating peer. Surface as a
163
+ * "waiting" affordance to the user.
164
+ */
165
+ isWaitingForPeers: boolean;
166
+ }
167
+ /**
168
+ * Coordinate a piece of state across sibling component instances on
169
+ * the same channel, so that visually disruptive value changes commit
170
+ * in a single layout pass rather than independently. Designed as a
171
+ * thin wrapper around any `useState`-shaped primitive (e.g.
172
+ * `useLocalStorageState`, `usePreference`, plain `useState`).
173
+ *
174
+ * **Originator flow** — calling the returned `setValue`:
175
+ * 1. `pendingValue` updates synchronously to the requested target
176
+ * 2. The coordinator runs `preload` (per phase rules) and waits for
177
+ * sibling peers (phase 1 only)
178
+ * 3. When the barrier resolves, the underlying `setValue` is called
179
+ * and this hook's visible `value` flips, so the swap is
180
+ * consistent with the optional `onCommit` side-effect
181
+ *
182
+ * **Receiver flow** — when the underlying `value` changes from outside
183
+ * (e.g. a storage event from another tab):
184
+ * 1. `pendingValue` updates to match
185
+ * 2. Coordination runs locally (this tab's peers run their own
186
+ * phase-1 barrier)
187
+ * 3. The visible `value` returned by this hook is held at the
188
+ * previous value until the barrier resolves, then flips
189
+ *
190
+ * Pass `channelKey: null` to disable coordination — the hook becomes
191
+ * a transparent pass-through of the underlying tuple.
192
+ */
193
+ export declare function useCoordinated<TValue, TPreload = void>(underlying: [TValue, (next: TValue) => void], options: UseCoordinatedOptions<TValue, TPreload>): [TValue, React.Dispatch<React.SetStateAction<TValue>>, UseCoordinatedExtras<TValue>];
@@ -0,0 +1,469 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { registerPeer, reportValue, announceTarget, getBarrierAnnounceTime } from "./coordinatePreference.mjs";
5
+ import { whenLayoutShiftsSettled, layoutShiftsSettled } from "./layoutShiftGate.mjs";
6
+
7
+ /**
8
+ * Options for {@link useCoordinated}. See `coordinatePreference` for
9
+ * the underlying semantics; only React-specific behaviors are
10
+ * documented here.
11
+ */
12
+
13
+ let nextAutoPeerId = 0;
14
+ function generatePeerId() {
15
+ nextAutoPeerId += 1;
16
+ return `peer-${nextAutoPeerId}`;
17
+ }
18
+
19
+ /**
20
+ * Coordinate a piece of state across sibling component instances on
21
+ * the same channel, so that visually disruptive value changes commit
22
+ * in a single layout pass rather than independently. Designed as a
23
+ * thin wrapper around any `useState`-shaped primitive (e.g.
24
+ * `useLocalStorageState`, `usePreference`, plain `useState`).
25
+ *
26
+ * **Originator flow** — calling the returned `setValue`:
27
+ * 1. `pendingValue` updates synchronously to the requested target
28
+ * 2. The coordinator runs `preload` (per phase rules) and waits for
29
+ * sibling peers (phase 1 only)
30
+ * 3. When the barrier resolves, the underlying `setValue` is called
31
+ * and this hook's visible `value` flips, so the swap is
32
+ * consistent with the optional `onCommit` side-effect
33
+ *
34
+ * **Receiver flow** — when the underlying `value` changes from outside
35
+ * (e.g. a storage event from another tab):
36
+ * 1. `pendingValue` updates to match
37
+ * 2. Coordination runs locally (this tab's peers run their own
38
+ * phase-1 barrier)
39
+ * 3. The visible `value` returned by this hook is held at the
40
+ * previous value until the barrier resolves, then flips
41
+ *
42
+ * Pass `channelKey: null` to disable coordination — the hook becomes
43
+ * a transparent pass-through of the underlying tuple.
44
+ */
45
+ export function useCoordinated(underlying, options) {
46
+ const [underlyingValue, setUnderlyingValue] = underlying;
47
+ const {
48
+ channelKey,
49
+ peerId: explicitPeerId,
50
+ causesLayoutShift,
51
+ preload,
52
+ onCommit,
53
+ minWaitMs,
54
+ multiPeerExtraMinWaitMs,
55
+ lazyMinWaitMs,
56
+ gracePeriodMs,
57
+ ultimateTimeoutMs,
58
+ animateDuringPreload = false,
59
+ lazyCommitPriority = 'idle'
60
+ } = options;
61
+
62
+ // Stable peer id for the lifetime of the mounted component. Held in a ref so an
63
+ // auto-generated fallback stays stable across renders, an explicit `peerId` prop
64
+ // wins and resyncs on change, and an explicit id later removed keeps the last
65
+ // explicit value. The registration effect keys off [channelKey, peerId].
66
+ /* eslint-disable react-hooks/refs -- deliberate stable-id ref: lazy init + explicit-prop resync during render; the ref is identity memory, never read for rendering output */
67
+ const peerIdRef = React.useRef(null);
68
+ if (peerIdRef.current === null) {
69
+ peerIdRef.current = explicitPeerId ?? generatePeerId();
70
+ } else if (explicitPeerId !== undefined && explicitPeerId !== peerIdRef.current) {
71
+ peerIdRef.current = explicitPeerId;
72
+ }
73
+ const peerId = peerIdRef.current;
74
+ /* eslint-enable react-hooks/refs */
75
+
76
+ // The visible (committed) value. Lags `underlyingValue` while a
77
+ // phase-1 barrier is open in the receiver flow.
78
+ const [committedValue, setCommittedValue] = React.useState(underlyingValue);
79
+ // The latest target value (originator click or external change).
80
+ const [pendingValue, setPendingValue] = React.useState(underlyingValue);
81
+ const [isCoordinating, setIsCoordinating] = React.useState(false);
82
+ const [isWaitingForPeers, setIsWaitingForPeers] = React.useState(false);
83
+
84
+ // Keep latest callbacks in a ref so we don't re-register the peer
85
+ // when the consumer passes inline functions.
86
+ const callbacksRef = React.useRef({
87
+ causesLayoutShift,
88
+ preload,
89
+ onCommit,
90
+ setUnderlyingValue
91
+ });
92
+ /* eslint-disable react-hooks/refs -- latest-ref pattern: cache current callbacks for the once-registered peer and long-lived runCoordination closure; intentionally excluded from effect/useCallback deps to avoid re-registering on inline-function identity churn */
93
+ callbacksRef.current.causesLayoutShift = causesLayoutShift;
94
+ callbacksRef.current.preload = preload;
95
+ callbacksRef.current.onCommit = onCommit;
96
+ callbacksRef.current.setUnderlyingValue = setUnderlyingValue;
97
+ /* eslint-enable react-hooks/refs */
98
+
99
+ const timingRef = React.useRef({
100
+ minWaitMs,
101
+ multiPeerExtraMinWaitMs,
102
+ lazyMinWaitMs,
103
+ gracePeriodMs,
104
+ ultimateTimeoutMs,
105
+ animateDuringPreload,
106
+ lazyCommitPriority
107
+ });
108
+ /* eslint-disable react-hooks/refs -- latest-ref pattern: cache current timing options for the once-registered peer and long-lived runCoordination closure; intentionally excluded from effect/useCallback deps to avoid re-registering on option identity churn */
109
+ timingRef.current.minWaitMs = minWaitMs;
110
+ timingRef.current.multiPeerExtraMinWaitMs = multiPeerExtraMinWaitMs;
111
+ timingRef.current.lazyMinWaitMs = lazyMinWaitMs;
112
+ timingRef.current.gracePeriodMs = gracePeriodMs;
113
+ timingRef.current.ultimateTimeoutMs = ultimateTimeoutMs;
114
+ timingRef.current.animateDuringPreload = animateDuringPreload;
115
+ timingRef.current.lazyCommitPriority = lazyCommitPriority;
116
+ /* eslint-enable react-hooks/refs */
117
+
118
+ // In-flight handle so we can cancel/supersede.
119
+ const handleRef = React.useRef(null);
120
+ // Track the value we last asked the underlying primitive to take —
121
+ // when we see it echoed back via `underlyingValue` we skip the
122
+ // receiver flow so we don't double-coordinate our own writes.
123
+ const lastWrittenRef = React.useRef({
124
+ has: false
125
+ });
126
+ // The latest target the coordinator is working on; used to dedupe
127
+ // re-entrant effect runs when `underlyingValue` changes mid-flight.
128
+ const inFlightTargetRef = React.useRef({
129
+ has: false
130
+ });
131
+
132
+ // Forward-declared ref so the peer registration's `onSiblingAnnounce`
133
+ // can call the latest `runCoordination` without re-registering the
134
+ // peer every time the callback identity changes.
135
+ const runCoordinationRef = React.useRef(null);
136
+ // Register / unregister this peer with the channel.
137
+ React.useInsertionEffect(() => {
138
+ if (channelKey === null) {
139
+ return undefined;
140
+ }
141
+ const unregister = registerPeer(channelKey, peerId, target => {
142
+ runCoordinationRef.current?.(target, false);
143
+ });
144
+ reportValue(channelKey, peerId, committedValue);
145
+ return () => {
146
+ const handle = handleRef.current;
147
+ handleRef.current = null;
148
+ if (handle) {
149
+ handle.cancel();
150
+ }
151
+ inFlightTargetRef.current = {
152
+ has: false
153
+ };
154
+ unregister();
155
+ };
156
+ }, [channelKey, peerId]);
157
+
158
+ // Tell the coordinator our latest committed value so it can skip
159
+ // already-at-target peers when classifying barrier expectations.
160
+ React.useInsertionEffect(() => {
161
+ if (channelKey === null) {
162
+ return;
163
+ }
164
+ reportValue(channelKey, peerId, committedValue);
165
+ }, [channelKey, peerId, committedValue]);
166
+ const runCoordination = React.useCallback((target, isOriginator) => {
167
+ if (channelKey === null) {
168
+ // Keep `inFlightTargetRef` in sync so two synchronous calls
169
+ // like `setValue(p => p + 1); setValue(p => p + 1)` see the
170
+ // freshest base — `setPendingValue` is async, so the second
171
+ // updater would otherwise read the pre-render value and
172
+ // collapse to a single increment. The receiver-flow effect
173
+ // resets the ref on every external `underlyingValue` change,
174
+ // and `runCoordination` overwrites it on every subsequent
175
+ // call, so this won't leak across coordination cycles.
176
+ inFlightTargetRef.current = {
177
+ has: true,
178
+ value: target
179
+ };
180
+ setPendingValue(target);
181
+ setCommittedValue(target);
182
+ if (isOriginator) {
183
+ lastWrittenRef.current = {
184
+ has: true,
185
+ value: target
186
+ };
187
+ callbacksRef.current.setUnderlyingValue(target);
188
+ }
189
+ callbacksRef.current.onCommit?.(target, undefined);
190
+ return;
191
+ }
192
+ // Dedupe: if we're already coordinating exactly this target
193
+ // (e.g. a sibling-announce notification arrived after we
194
+ // already kicked off our own receiver-flow announce, our own
195
+ // originator-flow `announceTarget` call is still on the stack,
196
+ // or the user clicked the same value twice in quick
197
+ // succession), skip restarting the announcement. Without this
198
+ // the second call would cancel our in-flight handle and we'd
199
+ // lose our place in the barrier — or, when the dedupe also
200
+ // fires re-entrantly mid-announce, we'd recurse forever.
201
+ if (inFlightTargetRef.current.has && Object.is(inFlightTargetRef.current.value, target)) {
202
+ return;
203
+ }
204
+ // Supersede any in-flight announcement.
205
+ const previousHandle = handleRef.current;
206
+ if (previousHandle) {
207
+ previousHandle.cancel();
208
+ }
209
+ inFlightTargetRef.current = {
210
+ has: true,
211
+ value: target
212
+ };
213
+ // `pendingValue` is the user-facing "intent" signal and
214
+ // always flips synchronously so toolbars / pickers stay
215
+ // responsive on click. `isCoordinating` is what consumers
216
+ // typically gate an animation on — when
217
+ // `animateDuringPreload === false` we hold it until the
218
+ // originator's preload settles so a CPU-bound preload
219
+ // doesn't steal main-thread time from the animation that
220
+ // follows. The coordinator yields to the browser before
221
+ // invoking `preload`, so even sync preloads settle one
222
+ // macrotask later; receivers flip in the same tick
223
+ // regardless of the flag.
224
+ setPendingValue(target);
225
+ // Always clear stale waiting state from any previous
226
+ // coordination cycle synchronously — otherwise a later
227
+ // `onWaitingForPeers` (which fires from a timer relative to
228
+ // the announce) could be overwritten when we flip
229
+ // `isCoordinating`.
230
+ setIsWaitingForPeers(false);
231
+ const deferFlipForPreload = isOriginator && !timingRef.current.animateDuringPreload && callbacksRef.current.preload !== undefined;
232
+ let coordinatingFlipped = false;
233
+ const flipCoordinating = () => {
234
+ if (coordinatingFlipped) {
235
+ return;
236
+ }
237
+ coordinatingFlipped = true;
238
+ setIsCoordinating(true);
239
+ };
240
+ if (!deferFlipForPreload) {
241
+ flipCoordinating();
242
+ }
243
+ const userPreload = callbacksRef.current.preload;
244
+ const flipWrappedPreload = deferFlipForPreload ? (preloadTarget, signal) => {
245
+ // Wrap the user's preload so we flip `isCoordinating`
246
+ // the instant it settles — whether sync or async —
247
+ // but not before. Errors still flip; the engine logs
248
+ // them and treats the result as `undefined`, and the
249
+ // consumer expects the signal to converge regardless
250
+ // of the preload outcome.
251
+ let result;
252
+ let threw;
253
+ let didThrow = false;
254
+ try {
255
+ result = userPreload(preloadTarget, signal);
256
+ } catch (err) {
257
+ didThrow = true;
258
+ threw = err;
259
+ }
260
+ const isThenable = !didThrow && result !== null && result !== undefined && typeof result.then === 'function';
261
+ if (!isThenable) {
262
+ if (!signal.aborted) {
263
+ flipCoordinating();
264
+ }
265
+ if (didThrow) {
266
+ throw threw;
267
+ }
268
+ return result;
269
+ }
270
+ return result.then(value => {
271
+ if (!signal.aborted) {
272
+ flipCoordinating();
273
+ }
274
+ return value;
275
+ }, err => {
276
+ if (!signal.aborted) {
277
+ flipCoordinating();
278
+ }
279
+ throw err;
280
+ });
281
+ } : userPreload;
282
+
283
+ // Automatically hold the *commit* until the page's initial layout-shift
284
+ // sources have settled (see `layoutShiftGate`), for layout-shifting
285
+ // targets only. The consumer's preload still starts immediately and flips
286
+ // `isCoordinating` on its own settle — the gate wait runs in parallel and
287
+ // only delays the commit, so the first page-wide transform/variant change
288
+ // lands as one unified update. A no-op when nothing has registered with
289
+ // the gate (`whenLayoutShiftsSettled` returns `null`), so plain
290
+ // `useCoordinated` consumers are unaffected.
291
+ let wrappedPreload;
292
+ if (userPreload) {
293
+ wrappedPreload = (preloadTarget, signal) => {
294
+ const inner = flipWrappedPreload(preloadTarget, signal);
295
+ const gateWait = callbacksRef.current.causesLayoutShift(preloadTarget) ? whenLayoutShiftsSettled(signal) : null;
296
+ if (gateWait === null) {
297
+ return inner;
298
+ }
299
+ return Promise.all([gateWait, Promise.resolve(inner)]).then(([, result]) => result);
300
+ };
301
+ } else if (!layoutShiftsSettled() && callbacksRef.current.causesLayoutShift(target)) {
302
+ // No user preload, but the target shifts layout and the gate is still
303
+ // closed: synthesize a preload that only awaits the gate so the commit
304
+ // still holds until the page settles (the gate is otherwise consulted
305
+ // only inside the user-preload wrapper, so without this branch a
306
+ // layout-shifting peer with no preload would skip coordination entirely).
307
+ // Once the gate has opened
308
+ // this branch is skipped, so steady-state layout-shifting commits keep
309
+ // the synchronous fast path. The gate wait rejects `AbortError` on
310
+ // supersede, which propagates into the engine's `await preload(...)`
311
+ // and is swallowed there because the signal is aborted — exactly like
312
+ // the user-preload path above.
313
+ wrappedPreload = (preloadTarget, signal) => {
314
+ const gateWait = callbacksRef.current.causesLayoutShift(preloadTarget) ? whenLayoutShiftsSettled(signal) : null;
315
+ if (gateWait === null) {
316
+ return undefined;
317
+ }
318
+ return gateWait.then(() => undefined);
319
+ };
320
+ }
321
+ const handle = announceTarget(channelKey, peerId, target, {
322
+ causesLayoutShift: callbacksRef.current.causesLayoutShift,
323
+ preload: wrappedPreload,
324
+ onCommit: (committedTarget, preloaded) => {
325
+ // Side-effect first so consumers can install precomputed
326
+ // payloads before the value flip becomes visible.
327
+ callbacksRef.current.onCommit?.(committedTarget, preloaded);
328
+ // If the engine force-resolved the barrier while our
329
+ // deferred preload was still in flight (e.g. at
330
+ // `ultimateTimeoutMs`), `flipCoordinating` may not have
331
+ // run — flush it now so `isCoordinating` reaches the
332
+ // true → false transition consumers expect at least
333
+ // once per cycle.
334
+ flipCoordinating();
335
+ if (isOriginator) {
336
+ lastWrittenRef.current = {
337
+ has: true,
338
+ value: committedTarget
339
+ };
340
+ callbacksRef.current.setUnderlyingValue(committedTarget);
341
+ }
342
+ setCommittedValue(committedTarget);
343
+ // Clear coordination flags synchronously alongside the
344
+ // value flip so the next render reflects both at once.
345
+ setIsCoordinating(false);
346
+ setIsWaitingForPeers(false);
347
+ },
348
+ minWaitMs: timingRef.current.minWaitMs,
349
+ multiPeerExtraMinWaitMs: timingRef.current.multiPeerExtraMinWaitMs,
350
+ lazyMinWaitMs: timingRef.current.lazyMinWaitMs,
351
+ gracePeriodMs: timingRef.current.gracePeriodMs,
352
+ ultimateTimeoutMs: timingRef.current.ultimateTimeoutMs,
353
+ lazyCommitPriority: timingRef.current.lazyCommitPriority,
354
+ onWaitingForPeers: () => {
355
+ setIsWaitingForPeers(true);
356
+ },
357
+ isOriginator,
358
+ // Non-originators (e.g. storage echoes) anchor to the
359
+ // originator's announce time if a barrier is already open
360
+ // so late joiners share the same wall-clock deadline.
361
+ announceTime: !isOriginator && getBarrierAnnounceTime(channelKey, target) || Date.now()
362
+ });
363
+ handleRef.current = handle;
364
+ handle.settled.then(() => {
365
+ if (handleRef.current === handle) {
366
+ handleRef.current = null;
367
+ inFlightTargetRef.current = {
368
+ has: false
369
+ };
370
+ setIsCoordinating(false);
371
+ setIsWaitingForPeers(false);
372
+ }
373
+ });
374
+ }, [channelKey, peerId]);
375
+
376
+ // Keep the ref pointed at the latest `runCoordination` so the
377
+ // peer-registration callback (set once at mount) always invokes
378
+ // the current closure.
379
+ // eslint-disable-next-line react-hooks/refs -- forward-declared latest-ref: the once-registered peer callback must invoke the current runCoordination closure without re-registering
380
+ runCoordinationRef.current = runCoordination;
381
+
382
+ // Receiver flow: external `underlyingValue` change that we did not
383
+ // originate. Trigger a local coordination so this tab's peers commit
384
+ // together. Uses `useLayoutEffect` so the announcement lands in the
385
+ // same synchronous flush as the originator's broadcast — otherwise
386
+ // a sibling peer's `runCoordination` would slip past whatever
387
+ // `setTimeout` cadence the test (or browser) is driving and miss
388
+ // the originator's barrier window.
389
+ React.useLayoutEffect(() => {
390
+ if (channelKey === null) {
391
+ // Coordination disabled: the hook is a transparent pass-through,
392
+ // so the visible value / pending value are derived directly from
393
+ // `underlyingValue` at the return rather than mirrored into state.
394
+ // Only reset the in-flight ref here.
395
+ inFlightTargetRef.current = {
396
+ has: false
397
+ };
398
+ return;
399
+ }
400
+ if (lastWrittenRef.current.has) {
401
+ if (Object.is(lastWrittenRef.current.value, underlyingValue)) {
402
+ // Echo of our own write — already coordinated. Treat the
403
+ // sentinel as one-shot: consume it here so a *subsequent*
404
+ // external write that happens to round-trip to the same
405
+ // value (e.g. local→`b`, external→`c`, external→`b`) is
406
+ // recognized as a genuine external change rather than
407
+ // misclassified as another echo.
408
+ lastWrittenRef.current = {
409
+ has: false
410
+ };
411
+ return;
412
+ }
413
+ // Sentinel is stale: the underlying moved to something other
414
+ // than what we last wrote, so an earlier no-op originator
415
+ // write (which produced no echo) must have left the sentinel
416
+ // armed. Clear it now so a later external round-trip back to
417
+ // that value isn't suppressed.
418
+ lastWrittenRef.current = {
419
+ has: false
420
+ };
421
+ }
422
+ if (handleRef.current && inFlightTargetRef.current.has && Object.is(inFlightTargetRef.current.value, underlyingValue) && Object.is(pendingValue, underlyingValue)) {
423
+ // Already coordinating this target.
424
+ return;
425
+ }
426
+ if (Object.is(committedValue, underlyingValue)) {
427
+ // No external change to react to. We deliberately skip running
428
+ // `preload` on mount when the underlying value already matches
429
+ // our committed value: preload only needs to run when the value
430
+ // changes out from under us without the consumer calling the
431
+ // setter (e.g. a hydration write from `localStorage` or a
432
+ // parent state update). After the consumer interacts with the
433
+ // setter, the originator flow drives every cycle.
434
+ return;
435
+ }
436
+ // eslint-disable-next-line react-hooks/set-state-in-effect -- receiver flow: runCoordination drives the coordination state machine in response to an external underlyingValue change; this is the genuine effect side-effect, not derivable during render
437
+ runCoordination(underlyingValue, false);
438
+ // eslint-disable-next-line react-hooks/exhaustive-deps
439
+ }, [channelKey, underlyingValue, runCoordination]);
440
+ const coordinatedSetValue = React.useCallback(action => {
441
+ // Functional updaters need to see the latest target — even
442
+ // before React has re-rendered with the new `pendingValue` —
443
+ // so that bursts like `setValue(p => p + 1); setValue(p => p +
444
+ // 1)` compose to +2 instead of +1. `inFlightTargetRef` is
445
+ // updated synchronously inside `runCoordination` before
446
+ // `announceTarget` runs, so it's the freshest source.
447
+ const base = inFlightTargetRef.current.has ? inFlightTargetRef.current.value : pendingValue;
448
+ const next = typeof action === 'function' ? action(base) : action;
449
+ runCoordination(next, true);
450
+ }, [pendingValue, runCoordination]);
451
+ const extras = React.useMemo(() => ({
452
+ pendingValue,
453
+ isCoordinating,
454
+ isWaitingForPeers
455
+ }), [pendingValue, isCoordinating, isWaitingForPeers]);
456
+
457
+ // When coordination is disabled the hook is a transparent
458
+ // pass-through: derive the visible value, pending value, and inert
459
+ // coordination flags straight from `underlyingValue` rather than
460
+ // mirroring it into `committedValue` / `pendingValue` state.
461
+ if (channelKey === null) {
462
+ return [underlyingValue, coordinatedSetValue, {
463
+ pendingValue: underlyingValue,
464
+ isCoordinating: false,
465
+ isWaitingForPeers: false
466
+ }];
467
+ }
468
+ return [committedValue, coordinatedSetValue, extras];
469
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Declares the calling component as a source of an initial, post-hydration
3
+ * layout shift — e.g. a code block that swaps from its plain fallback to
4
+ * highlighted (and focus-collapsed) output once it hydrates.
5
+ *
6
+ * While any registered source is unsettled, {@link useCoordinated} holds its
7
+ * layout-shifting commits, so a page-wide transform/variant change lands as a
8
+ * single unified update instead of a cascade as blocks swap in at staggered
9
+ * idle times. The host doesn't wire anything into its coordinated hooks — this
10
+ * registration is the only opt-in.
11
+ *
12
+ * Pass `settled: true` once the component has reached its stable
13
+ * post-hydration layout. Registration happens on mount and is released on
14
+ * unmount, so a component that unmounts before it settles can't hold the gate
15
+ * open for the rest of the page.
16
+ */
17
+ export declare function useCoordinatedLazy(settled: boolean): void;