@mui/internal-docs-infra 0.7.1-canary.4 → 0.8.1-canary.0

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 (52) hide show
  1. package/CodeHighlighter/CodeHighlighter.mjs +2 -2
  2. package/CodeHighlighter/types.d.mts +2 -2
  3. package/abstractCreateTypes/TypeCode.d.mts +43 -0
  4. package/abstractCreateTypes/TypeCode.mjs +166 -0
  5. package/abstractCreateTypes/abstractCreateTypes.d.mts +12 -0
  6. package/abstractCreateTypes/abstractCreateTypes.mjs +6 -2
  7. package/abstractCreateTypes/typesToJsx.d.mts +10 -0
  8. package/abstractCreateTypes/typesToJsx.mjs +216 -37
  9. package/cli/index.mjs +1 -1
  10. package/package.json +2 -2
  11. package/pipeline/hastUtils/fallbackFormat.d.mts +37 -0
  12. package/pipeline/hastUtils/fallbackFormat.mjs +144 -0
  13. package/pipeline/hastUtils/hastCompress.d.mts +20 -0
  14. package/pipeline/hastUtils/hastCompress.mjs +62 -0
  15. package/pipeline/hastUtils/hastCompression.d.mts +3 -0
  16. package/pipeline/hastUtils/hastCompression.mjs +3 -0
  17. package/pipeline/hastUtils/hastDecompress.d.mts +20 -0
  18. package/pipeline/hastUtils/hastDecompress.mjs +82 -0
  19. package/pipeline/hastUtils/hastDictionary.d.mts +54 -0
  20. package/pipeline/hastUtils/hastDictionary.mjs +124 -0
  21. package/pipeline/hastUtils/hastUtils.d.mts +3 -3
  22. package/pipeline/hastUtils/hastUtils.mjs +10 -11
  23. package/pipeline/hastUtils/index.d.mts +3 -1
  24. package/pipeline/hastUtils/index.mjs +3 -1
  25. package/pipeline/hastUtils/stripHighlightingSpans.d.mts +15 -0
  26. package/pipeline/hastUtils/stripHighlightingSpans.mjs +70 -0
  27. package/pipeline/loadCodeVariant/loadCodeVariant.mjs +5 -20
  28. package/pipeline/loadCodeVariant/transformSource.mjs +3 -18
  29. package/pipeline/loadPrecomputedCodeHighlighter/loadPrecomputedCodeHighlighter.d.mts +1 -1
  30. package/pipeline/loadPrecomputedCodeHighlighter/loadPrecomputedCodeHighlighter.mjs +1 -1
  31. package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.mjs +1 -1
  32. package/pipeline/loadServerTypes/hastTypeUtils.d.mts +13 -0
  33. package/pipeline/loadServerTypes/hastTypeUtils.mjs +27 -0
  34. package/pipeline/loadServerTypes/highlightTypes.d.mts +2 -1
  35. package/pipeline/loadServerTypes/highlightTypes.mjs +9 -9
  36. package/pipeline/loadServerTypes/highlightTypesMeta.d.mts +6 -10
  37. package/pipeline/loadServerTypes/highlightTypesMeta.mjs +49 -48
  38. package/pipeline/loadServerTypes/loadServerTypes.d.mts +11 -8
  39. package/pipeline/loadServerTypes/loadServerTypes.mjs +7 -7
  40. package/pipeline/parseSource/addLineGutters.mjs +10 -9
  41. package/pipeline/parseSource/createFrame.d.mts +1 -1
  42. package/pipeline/parseSource/createFrame.mjs +1 -5
  43. package/pipeline/parseSource/restructureFrames.mjs +1 -1
  44. package/pipeline/transformHtmlCodeBlock/transformHtmlCodeBlock.mjs +1 -1
  45. package/useCode/CodeComponentsContext.d.mts +6 -0
  46. package/useCode/CodeComponentsContext.mjs +8 -0
  47. package/useCode/Pre.mjs +36 -13
  48. package/useCode/index.d.mts +1 -0
  49. package/useCode/index.mjs +1 -0
  50. package/useCode/useFileNavigation.mjs +3 -4
  51. package/useCode/useSourceEnhancing.mjs +5 -6
  52. package/withDocsInfra/withDocsInfra.mjs +1 -1
@@ -109,7 +109,7 @@ async function CodeSourceLoader(props) {
109
109
  }
110
110
  }
111
111
  }
112
- let output = 'hastGzip';
112
+ let output = 'hastCompressed';
113
113
  if (props.deferParsing === 'json') {
114
114
  output = 'hastJson';
115
115
  } else if (props.deferParsing === 'none') {
@@ -248,7 +248,7 @@ async function CodeInitialSourceLoader(props) {
248
248
  if (!url) {
249
249
  throw new Errors.ErrorCodeHighlighterServerMissingUrl();
250
250
  }
251
- let output = 'hastGzip';
251
+ let output = 'hastCompressed';
252
252
  if (props.deferParsing === 'json') {
253
253
  output = 'hastJson';
254
254
  } else if (props.deferParsing === 'none') {
@@ -29,7 +29,7 @@ export interface HastRoot extends Root {
29
29
  export type VariantSource = string | HastRoot | {
30
30
  hastJson: string;
31
31
  } | {
32
- hastGzip: string;
32
+ hastCompressed: string;
33
33
  };
34
34
  /**
35
35
  * Additional files associated with a code variant.
@@ -182,7 +182,7 @@ export interface LoadFileOptions {
182
182
  /** Output format for the loaded file
183
183
  * @default 'hast'
184
184
  */
185
- output?: 'hast' | 'hastJson' | 'hastGzip';
185
+ output?: 'hast' | 'hastJson' | 'hastCompressed';
186
186
  }
187
187
  /**
188
188
  * Options for the loadCodeVariant function, extending LoadFileOptions with required function dependencies
@@ -0,0 +1,43 @@
1
+ import * as React from 'react';
2
+ import type { FallbackNode } from "../pipeline/hastUtils/fallbackFormat.mjs";
3
+ type HighlightAt = 'hydration' | 'idle' | 'visible';
4
+ interface TypeCodeProps {
5
+ /** JSON-serialized HAST tree (root > pre > code > children). */
6
+ hastJson?: string;
7
+ /** DEFLATE-compressed, base64-encoded HAST tree. */
8
+ hastCompressed?: string;
9
+ /** When to replace the fallback with the fully-highlighted version. */
10
+ highlightAt: HighlightAt;
11
+ /**
12
+ * Links-only fallback (code children with highlighting spans stripped),
13
+ * in compact `FallbackNode[]` format.
14
+ * Serves two purposes:
15
+ * 1. Rendered as the initial display until the full highlight is ready.
16
+ * 2. Its text content is used as a DEFLATE dictionary for decompression
17
+ * when `hastCompressed` was compressed with that same text dictionary.
18
+ */
19
+ fallback?: FallbackNode[];
20
+ /** Props for the `<code>` element wrapper (className, etc.). */
21
+ codeProps?: Record<string, unknown>;
22
+ }
23
+ /**
24
+ * Renders a links-only fallback on the server and replaces it with the
25
+ * fully syntax-highlighted version on the client at the configured time.
26
+ *
27
+ * When `fallback` is provided, it is converted to HAST and rendered for the
28
+ * initial display. Its text content is derived (via `fallbackToText`) to serve
29
+ * as the DEFLATE dictionary for decompressing `hastCompressed`.
30
+ *
31
+ * - `'hydration'`: parse immediately on mount.
32
+ * - `'idle'`: defer to `requestIdleCallback` regardless of visibility.
33
+ * - `'visible'`: wait until the element enters the viewport (IntersectionObserver),
34
+ * then defer to `requestIdleCallback` to avoid blocking scroll or paint.
35
+ */
36
+ export declare function TypeCode({
37
+ hastJson,
38
+ hastCompressed,
39
+ highlightAt,
40
+ fallback,
41
+ codeProps
42
+ }: TypeCodeProps): React.DetailedReactHTMLElement<React.HTMLAttributes<HTMLElement>, HTMLElement> | React.DetailedReactHTMLElement<Record<string, unknown>, HTMLElement>;
43
+ export {};
@@ -0,0 +1,166 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { decompressHast, hastToJsx } from "../pipeline/hastUtils/index.mjs";
5
+ import { useCodeComponents } from "../useCode/CodeComponentsContext.mjs";
6
+ import { fallbackToHast, fallbackToText } from "../pipeline/hastUtils/fallbackFormat.mjs";
7
+ /**
8
+ * Find the children of the first `<code>` element in a parsed HAST tree.
9
+ */
10
+ function findCodeChildren(node) {
11
+ if (node.type === 'element' && node.tagName === 'code') {
12
+ return node.children;
13
+ }
14
+ for (const child of node.children) {
15
+ if (child.type === 'element') {
16
+ const found = findCodeChildren(child);
17
+ if (found) {
18
+ return found;
19
+ }
20
+ }
21
+ }
22
+ return null;
23
+ }
24
+
25
+ /**
26
+ * Renders a links-only fallback on the server and replaces it with the
27
+ * fully syntax-highlighted version on the client at the configured time.
28
+ *
29
+ * When `fallback` is provided, it is converted to HAST and rendered for the
30
+ * initial display. Its text content is derived (via `fallbackToText`) to serve
31
+ * as the DEFLATE dictionary for decompressing `hastCompressed`.
32
+ *
33
+ * - `'hydration'`: parse immediately on mount.
34
+ * - `'idle'`: defer to `requestIdleCallback` regardless of visibility.
35
+ * - `'visible'`: wait until the element enters the viewport (IntersectionObserver),
36
+ * then defer to `requestIdleCallback` to avoid blocking scroll or paint.
37
+ */
38
+ export function TypeCode({
39
+ hastJson,
40
+ hastCompressed,
41
+ highlightAt,
42
+ fallback,
43
+ codeProps
44
+ }) {
45
+ const components = useCodeComponents();
46
+ // Determine the effective mode: fall back to 'idle' when IntersectionObserver
47
+ // is unavailable (progressive enhancement for older browsers/runtimes).
48
+ const effectiveMode = highlightAt === 'visible' && (typeof IntersectionObserver === 'undefined' || typeof ResizeObserver === 'undefined') ? 'idle' : highlightAt;
49
+ const [hast, setHast] = React.useState(null);
50
+ const [isVisible, setIsVisible] = React.useState(effectiveMode !== 'visible');
51
+ const [codeElement, setCodeElement] = React.useState(null);
52
+
53
+ // Synchronize visibility state when the effective mode changes.
54
+ React.useEffect(() => {
55
+ setIsVisible(effectiveMode !== 'visible');
56
+ }, [effectiveMode]);
57
+
58
+ // Convert compact fallback to HAST for rendering.
59
+ const fallbackHastRoot = React.useMemo(() => fallback ? fallbackToHast(fallback) : undefined, [fallback]);
60
+
61
+ // Derive text dictionary from fallback for decompression.
62
+ const textDictionary = React.useMemo(() => fallback ? fallbackToText(fallback) : undefined, [fallback]);
63
+
64
+ // Render fallback HAST as JSX for initial display.
65
+ const fallbackJsx = React.useMemo(() => fallbackHastRoot ? hastToJsx(fallbackHastRoot, components) : null, [fallbackHastRoot, components]);
66
+
67
+ // Observe visibility for 'visible' mode: decompress when scrolled into view,
68
+ // release expanded HAST when scrolled away to reduce memory pressure.
69
+ //
70
+ // Three complementary observers cover different visibility triggers:
71
+ // - IntersectionObserver: scroll-based viewport entry/exit.
72
+ // - ResizeObserver: ancestor layout changes (CSS-based tabs, accordions)
73
+ // that resize the element without necessarily triggering IO.
74
+ // - Document 'toggle' listener (capture phase): native <details> elements
75
+ // whose toggle event does not bubble and may not trigger IO or RO.
76
+ React.useEffect(() => {
77
+ if (effectiveMode !== 'visible' || !codeElement) {
78
+ return undefined;
79
+ }
80
+ const updateVisibility = inViewport => {
81
+ if (inViewport) {
82
+ setIsVisible(true);
83
+ } else {
84
+ setIsVisible(false);
85
+ setHast(null);
86
+ }
87
+ };
88
+ const io = new IntersectionObserver(([entry]) => {
89
+ updateVisibility(entry.isIntersecting);
90
+ });
91
+ io.observe(codeElement);
92
+
93
+ // Force IO to re-evaluate without a synchronous getBoundingClientRect call.
94
+ const nudgeObserver = () => {
95
+ io.unobserve(codeElement);
96
+ io.observe(codeElement);
97
+ };
98
+ const ro = new ResizeObserver(nudgeObserver);
99
+ ro.observe(codeElement);
100
+
101
+ // Native <details> toggle events don't bubble, but capture-phase
102
+ // listeners on the document still intercept them. Re-check visibility
103
+ // whenever any <details> on the page opens or closes.
104
+ document.addEventListener('toggle', nudgeObserver, true);
105
+ return () => {
106
+ io.disconnect();
107
+ ro.disconnect();
108
+ document.removeEventListener('toggle', nudgeObserver, true);
109
+ };
110
+ }, [effectiveMode, codeElement]);
111
+
112
+ // Parse and decompress once visible.
113
+ React.useEffect(() => {
114
+ if (!isVisible) {
115
+ return undefined;
116
+ }
117
+ const parse = () => {
118
+ if (hastCompressed == null && hastJson == null) {
119
+ return;
120
+ }
121
+ try {
122
+ const raw = hastCompressed ? decompressHast(hastCompressed, textDictionary) : hastJson;
123
+ const parsed = JSON.parse(raw);
124
+
125
+ // Extract code element's children from the full tree.
126
+ const root = parsed.type === 'root' ? parsed : {
127
+ type: 'root',
128
+ children: Array.isArray(parsed) ? parsed : [parsed]
129
+ };
130
+ const codeChildren = findCodeChildren(root);
131
+ const hastRoot = {
132
+ type: 'root',
133
+ children: codeChildren ?? root.children
134
+ };
135
+ setHast(hastRoot);
136
+ } catch (error) {
137
+ console.warn('Failed to parse highlighted code HAST; rendering fallback instead.', error);
138
+ }
139
+ };
140
+ if (effectiveMode === 'hydration') {
141
+ parse();
142
+ return undefined;
143
+ }
144
+
145
+ // 'idle' and 'visible' both defer to idle time to avoid blocking the main thread.
146
+ if (typeof requestIdleCallback !== 'undefined') {
147
+ const id = requestIdleCallback(parse, {
148
+ timeout: 2000
149
+ });
150
+ return () => cancelIdleCallback(id);
151
+ }
152
+ const id = setTimeout(parse, 0);
153
+ return () => clearTimeout(id);
154
+ }, [isVisible, hastJson, hastCompressed, effectiveMode, textDictionary]);
155
+ const highlighted = React.useMemo(() => hast !== null ? hastToJsx(hast, components) : null, [hast, components]);
156
+ const content = highlighted ?? fallbackJsx;
157
+
158
+ // 'hydration' and 'idle' parse without visibility gating — no observer needed.
159
+ if (effectiveMode !== 'visible') {
160
+ return /*#__PURE__*/React.createElement('code', codeProps, content);
161
+ }
162
+ return /*#__PURE__*/React.createElement('code', {
163
+ ...codeProps,
164
+ ref: setCodeElement
165
+ }, content);
166
+ }
@@ -97,6 +97,12 @@ export type TypesTableMeta = {
97
97
  * Pass an empty array to disable all inline enhancers.
98
98
  */
99
99
  enhancersInline?: PluggableList;
100
+ /**
101
+ * Controls when expensive detailedType and formattedCode HAST fields are
102
+ * converted to fully-highlighted JSX.
103
+ * When set, overrides the factory-level highlightAt.
104
+ */
105
+ highlightAt?: TypesJsxOptions['highlightAt'];
100
106
  /**
101
107
  * Custom component tag name to use instead of `<a>` for type reference links.
102
108
  * When set, enhanceCodeTypes emits elements with this tag name,
@@ -243,6 +249,12 @@ export type AbstractCreateTypesOptions<T extends {} = {}> = {
243
249
  * Can be overridden by TypesTableMeta.defaultImportSlug.
244
250
  */
245
251
  defaultImportSlug?: string;
252
+ /**
253
+ * Controls when expensive detailedType and formattedCode HAST fields are
254
+ * converted to fully-highlighted JSX.
255
+ * Can be overridden by TypesTableMeta.highlightAt.
256
+ */
257
+ highlightAt?: TypesJsxOptions['highlightAt'];
246
258
  };
247
259
  export declare function abstractCreateTypes<T extends {}>(options: AbstractCreateTypesOptions<T>, url: string, meta: TypesTableMeta | undefined, exportName?: string): React.ComponentType<T>;
248
260
  export declare function createTypesFactory<T extends {}>(options: AbstractCreateTypesOptions<T>): (url: string, typeDef: object, meta?: TypesTableMeta | undefined) => React.ComponentType<T>;
@@ -42,6 +42,7 @@ export function abstractCreateTypes(options, url, meta, exportName) {
42
42
  const ShortTypeCode = meta.ShortTypeCode ?? options.ShortTypeCode;
43
43
  const DefaultCode = meta.DefaultCode ?? options.DefaultCode;
44
44
  const RawTypePre = meta.RawTypePre ?? options.RawTypePre;
45
+ const highlightAt = meta.highlightAt ?? options.highlightAt;
45
46
 
46
47
  // Enhancers from meta completely override options.enhancers if set
47
48
  // Use DEFAULT_ENHANCERS if neither meta nor options specify enhancers
@@ -126,7 +127,8 @@ export function abstractCreateTypes(options, url, meta, exportName) {
126
127
  DefaultCode,
127
128
  RawTypePre,
128
129
  enhancers,
129
- enhancersInline
130
+ enhancersInline,
131
+ highlightAt
130
132
  },
131
133
  // Include additionalTypes for:
132
134
  // 1. Single component mode (createTypes)
@@ -213,6 +215,7 @@ function createAdditionalTypesComponent(options, url, meta) {
213
215
  const ShortTypeCode = meta.ShortTypeCode ?? options.ShortTypeCode;
214
216
  const DefaultCode = meta.DefaultCode ?? options.DefaultCode;
215
217
  const RawTypePre = meta.RawTypePre ?? options.RawTypePre;
218
+ const highlightAt = meta.highlightAt ?? options.highlightAt;
216
219
 
217
220
  // Enhancers from meta completely override options.enhancers if set
218
221
  // Use DEFAULT_ENHANCERS if neither meta nor options specify enhancers
@@ -273,7 +276,8 @@ function createAdditionalTypesComponent(options, url, meta) {
273
276
  DefaultCode,
274
277
  RawTypePre,
275
278
  enhancers,
276
- enhancersInline
279
+ enhancersInline,
280
+ highlightAt
277
281
  }), []);
278
282
  return /*#__PURE__*/_jsx(options.TypesTable, {
279
283
  ...props,
@@ -1,3 +1,4 @@
1
+ import * as React from 'react';
1
2
  import type { PluggableList } from 'unified';
2
3
  import type { HighlightedComponentTypeMeta, HighlightedHookTypeMeta, HighlightedFunctionTypeMeta, HighlightedClassTypeMeta, HighlightedRawTypeMeta, HighlightedEnumMemberMeta, HighlightedTypesMeta, HighlightedProperty, HighlightedParameter, HighlightedMethod, HighlightedClassProperty } from "../pipeline/loadServerTypes/index.mjs";
3
4
  import type { FormattedEnumMember } from "../pipeline/loadServerTypesMeta/index.mjs";
@@ -56,6 +57,15 @@ export type TypesJsxOptions = {
56
57
  * Applied instead of the full enhancers for these compact fields.
57
58
  */
58
59
  enhancersInline?: PluggableList;
60
+ /**
61
+ * Controls when expensive detailedType and formattedCode HAST fields are
62
+ * converted to fully-highlighted JSX.
63
+ * - `'init'`: convert immediately during SSG
64
+ * - `'hydration'`: server-render a links-only fallback, highlight on client mount
65
+ * - `'idle'`: server-render a links-only fallback, highlight when browser is idle
66
+ * - `'visible'`: server-render a links-only fallback, highlight when scrolled into view (default)
67
+ */
68
+ highlightAt?: 'init' | 'hydration' | 'idle' | 'visible';
59
69
  };
60
70
  /**
61
71
  * An enhanced property with HAST fields converted to React nodes.