@mui/internal-docs-infra 0.2.3-canary.9 → 0.3.1-canary.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 (156) hide show
  1. package/README.md +3 -2
  2. package/esm/CodeHighlighter/CodeHighlighter.js +16 -16
  3. package/esm/CodeHighlighter/CodeHighlighterClient.js +33 -33
  4. package/esm/CodeHighlighter/errors.js +3 -3
  5. package/esm/CodeHighlighter/types.d.ts +1 -1
  6. package/esm/CodeProvider/CodeContext.d.ts +4 -4
  7. package/esm/CodeProvider/CodeProvider.js +7 -7
  8. package/esm/cli/index.d.ts +1 -0
  9. package/esm/cli/index.js +6 -0
  10. package/esm/cli/runValidate.d.ts +8 -0
  11. package/esm/cli/runValidate.js +297 -0
  12. package/esm/createSitemap/createSitemap.d.ts +23 -0
  13. package/esm/createSitemap/createSitemap.js +45 -0
  14. package/esm/createSitemap/index.d.ts +1 -0
  15. package/esm/createSitemap/index.js +1 -0
  16. package/esm/createSitemap/types.d.ts +68 -0
  17. package/esm/createSitemap/types.js +1 -0
  18. package/esm/pipeline/getFileConventions/fileConventions.d.ts +4 -0
  19. package/esm/pipeline/getFileConventions/fileConventions.js +4 -0
  20. package/esm/pipeline/getFileConventions/getFileConventions.d.ts +4 -0
  21. package/esm/pipeline/getFileConventions/getFileConventions.js +17 -0
  22. package/esm/pipeline/getFileConventions/index.d.ts +1 -0
  23. package/esm/pipeline/getFileConventions/index.js +1 -0
  24. package/esm/{CodeHighlighter/addPathsToVariant.d.ts → pipeline/loadCodeVariant/addCodeVariantPaths.d.ts} +1 -1
  25. package/esm/{CodeHighlighter/applyTransform.d.ts → pipeline/loadCodeVariant/applyCodeTransform.d.ts} +3 -3
  26. package/esm/{CodeHighlighter/applyTransform.js → pipeline/loadCodeVariant/applyCodeTransform.js} +4 -4
  27. package/esm/{CodeHighlighter → pipeline/loadCodeVariant}/calculateMainFilePath.js +1 -1
  28. package/esm/{CodeHighlighter/transformCode.d.ts → pipeline/loadCodeVariant/computeHastDeltas.d.ts} +9 -5
  29. package/esm/{CodeHighlighter/transformCode.js → pipeline/loadCodeVariant/computeHastDeltas.js} +20 -16
  30. package/esm/pipeline/loadCodeVariant/diffHast.d.ts +3 -0
  31. package/esm/{CodeHighlighter/transformParsedSource.js → pipeline/loadCodeVariant/diffHast.js} +5 -5
  32. package/esm/{CodeHighlighter/examineVariant.d.ts → pipeline/loadCodeVariant/examineCodeVariant.d.ts} +2 -2
  33. package/esm/{CodeHighlighter/examineVariant.js → pipeline/loadCodeVariant/examineCodeVariant.js} +1 -1
  34. package/esm/{useDemo/flattenVariant.d.ts → pipeline/loadCodeVariant/flattenCodeVariant.d.ts} +2 -2
  35. package/esm/{useDemo/flattenVariant.js → pipeline/loadCodeVariant/flattenCodeVariant.js} +3 -3
  36. package/esm/{CodeHighlighter/hasAllVariants.d.ts → pipeline/loadCodeVariant/hasAllCodeVariants.d.ts} +1 -1
  37. package/esm/pipeline/loadCodeVariant/index.d.ts +10 -0
  38. package/esm/pipeline/loadCodeVariant/index.js +17 -0
  39. package/esm/{CodeHighlighter/loadFallbackCode.d.ts → pipeline/loadCodeVariant/loadCodeFallback.d.ts} +2 -2
  40. package/esm/{CodeHighlighter/loadFallbackCode.js → pipeline/loadCodeVariant/loadCodeFallback.js} +180 -106
  41. package/esm/{CodeHighlighter/loadVariant.d.ts → pipeline/loadCodeVariant/loadCodeVariant.d.ts} +2 -2
  42. package/esm/{CodeHighlighter/loadVariant.js → pipeline/loadCodeVariant/loadCodeVariant.js} +141 -55
  43. package/esm/{CodeHighlighter/maybeInitialData.d.ts → pipeline/loadCodeVariant/maybeCodeInitialData.d.ts} +6 -6
  44. package/esm/{CodeHighlighter/maybeInitialData.js → pipeline/loadCodeVariant/maybeCodeInitialData.js} +6 -6
  45. package/esm/{CodeHighlighter/mergeMetadata.d.ts → pipeline/loadCodeVariant/mergeCodeMetadata.d.ts} +3 -3
  46. package/esm/{CodeHighlighter/mergeMetadata.js → pipeline/loadCodeVariant/mergeCodeMetadata.js} +3 -3
  47. package/esm/{CodeHighlighter → pipeline/loadCodeVariant}/parseCode.d.ts +1 -1
  48. package/esm/{CodeHighlighter → pipeline/loadCodeVariant}/transformSource.d.ts +1 -1
  49. package/esm/pipeline/loadPrecomputedCodeHighlighter/loadPrecomputedCodeHighlighter.d.ts +5 -0
  50. package/esm/pipeline/loadPrecomputedCodeHighlighter/loadPrecomputedCodeHighlighter.js +94 -16
  51. package/esm/pipeline/loadPrecomputedCodeHighlighter/parseCreateFactoryCall.js +3 -3
  52. package/esm/pipeline/loadPrecomputedCodeHighlighter/performanceLogger.d.ts +30 -0
  53. package/esm/pipeline/loadPrecomputedCodeHighlighter/performanceLogger.js +77 -0
  54. package/esm/pipeline/loadPrecomputedCodeHighlighterClient/loadPrecomputedCodeHighlighterClient.js +24 -14
  55. package/esm/pipeline/loadPrecomputedSitemap/index.d.ts +2 -0
  56. package/esm/pipeline/loadPrecomputedSitemap/index.js +4 -0
  57. package/esm/pipeline/loadPrecomputedSitemap/loadPrecomputedSitemap.d.ts +10 -0
  58. package/esm/pipeline/loadPrecomputedSitemap/loadPrecomputedSitemap.js +220 -0
  59. package/esm/pipeline/loadServerCodeMeta/index.d.ts +2 -1
  60. package/esm/pipeline/loadServerCodeMeta/index.js +2 -1
  61. package/esm/pipeline/loadServerCodeMeta/loadServerCodeMeta.d.ts +1 -1
  62. package/esm/pipeline/loadServerCodeMeta/loadServerCodeMeta.js +7 -5
  63. package/esm/pipeline/{loaderUtils → loadServerCodeMeta}/resolveModulePathWithFs.d.ts +3 -3
  64. package/esm/pipeline/{loaderUtils → loadServerCodeMeta}/resolveModulePathWithFs.js +14 -8
  65. package/esm/pipeline/loadServerPageIndex/index.d.ts +2 -0
  66. package/esm/pipeline/loadServerPageIndex/index.js +1 -0
  67. package/esm/pipeline/loadServerPageIndex/loadServerPageIndex.d.ts +51 -0
  68. package/esm/pipeline/loadServerPageIndex/loadServerPageIndex.js +176 -0
  69. package/esm/pipeline/loadServerSitemap/index.d.ts +2 -0
  70. package/esm/pipeline/loadServerSitemap/index.js +1 -0
  71. package/esm/pipeline/loadServerSitemap/loadServerSitemap.d.ts +39 -0
  72. package/esm/pipeline/loadServerSitemap/loadServerSitemap.js +170 -0
  73. package/esm/pipeline/loadServerSource/loadServerSource.js +18 -15
  74. package/esm/pipeline/loaderUtils/externalsToPackages.js +1 -1
  75. package/esm/pipeline/loaderUtils/extractNameAndSlugFromUrl.d.ts +0 -9
  76. package/esm/pipeline/loaderUtils/extractNameAndSlugFromUrl.js +7 -7
  77. package/esm/pipeline/loaderUtils/fileUrlToPortablePath.d.ts +44 -0
  78. package/esm/pipeline/loaderUtils/fileUrlToPortablePath.js +80 -0
  79. package/esm/pipeline/loaderUtils/index.d.ts +2 -1
  80. package/esm/pipeline/loaderUtils/index.js +2 -1
  81. package/esm/pipeline/loaderUtils/parseImportsAndComments.d.ts +10 -6
  82. package/esm/pipeline/loaderUtils/parseImportsAndComments.js +17 -12
  83. package/esm/pipeline/loaderUtils/processRelativeImports.d.ts +1 -1
  84. package/esm/pipeline/loaderUtils/processRelativeImports.js +44 -27
  85. package/esm/pipeline/loaderUtils/resolveModulePath.d.ts +5 -5
  86. package/esm/pipeline/loaderUtils/resolveModulePath.js +40 -37
  87. package/esm/pipeline/loaderUtils/rewriteImports.d.ts +36 -0
  88. package/esm/pipeline/loaderUtils/rewriteImports.js +139 -8
  89. package/esm/pipeline/syncPageIndex/createMarkdownNodes.d.ts +76 -0
  90. package/esm/pipeline/syncPageIndex/createMarkdownNodes.js +305 -0
  91. package/esm/pipeline/syncPageIndex/index.d.ts +1 -0
  92. package/esm/pipeline/syncPageIndex/index.js +1 -0
  93. package/esm/pipeline/syncPageIndex/mergeMetadataMarkdown.d.ts +58 -0
  94. package/esm/pipeline/syncPageIndex/mergeMetadataMarkdown.js +214 -0
  95. package/esm/pipeline/syncPageIndex/metadataToMarkdown.d.ts +67 -0
  96. package/esm/pipeline/syncPageIndex/metadataToMarkdown.js +1486 -0
  97. package/esm/pipeline/syncPageIndex/syncPageIndex.d.ts +108 -0
  98. package/esm/pipeline/syncPageIndex/syncPageIndex.js +540 -0
  99. package/esm/pipeline/transformHtmlCodePrecomputed/transformHtmlCodePrecomputed.d.ts +2 -2
  100. package/esm/pipeline/transformHtmlCodePrecomputed/transformHtmlCodePrecomputed.js +5 -5
  101. package/esm/pipeline/transformMarkdownBlockquoteCallouts/index.d.ts +2 -0
  102. package/esm/pipeline/transformMarkdownBlockquoteCallouts/index.js +4 -0
  103. package/esm/pipeline/transformMarkdownBlockquoteCallouts/transformMarkdownBlockquoteCallouts.d.ts +16 -0
  104. package/esm/pipeline/transformMarkdownBlockquoteCallouts/transformMarkdownBlockquoteCallouts.js +58 -0
  105. package/esm/pipeline/transformMarkdownDemoLinks/index.d.ts +2 -0
  106. package/esm/pipeline/transformMarkdownDemoLinks/index.js +4 -0
  107. package/esm/pipeline/transformMarkdownDemoLinks/transformMarkdownDemoLinks.d.ts +26 -0
  108. package/esm/pipeline/transformMarkdownDemoLinks/transformMarkdownDemoLinks.js +107 -0
  109. package/esm/pipeline/transformMarkdownMetadata/index.d.ts +2 -0
  110. package/esm/pipeline/transformMarkdownMetadata/index.js +4 -0
  111. package/esm/pipeline/transformMarkdownMetadata/transformMarkdownMetadata.d.ts +3 -0
  112. package/esm/pipeline/transformMarkdownMetadata/transformMarkdownMetadata.js +1010 -0
  113. package/esm/pipeline/transformMarkdownMetadata/types.d.ts +110 -0
  114. package/esm/pipeline/transformMarkdownMetadata/types.js +1 -0
  115. package/esm/pipeline/transformMarkdownRelativePaths/index.d.ts +2 -0
  116. package/esm/pipeline/transformMarkdownRelativePaths/index.js +4 -0
  117. package/esm/pipeline/transformMarkdownRelativePaths/transformMarkdownRelativePaths.d.ts +15 -0
  118. package/esm/pipeline/transformMarkdownRelativePaths/transformMarkdownRelativePaths.js +43 -0
  119. package/esm/useCode/Pre.js +15 -2
  120. package/esm/useCode/useCode.d.ts +15 -2
  121. package/esm/useCode/useCode.js +15 -6
  122. package/esm/useCode/useCodeUtils.js +3 -3
  123. package/esm/useCode/useFileNavigation.d.ts +9 -3
  124. package/esm/useCode/useFileNavigation.js +124 -81
  125. package/esm/useCode/useUIState.d.ts +4 -1
  126. package/esm/useCode/useUIState.js +17 -2
  127. package/esm/useCode/useVariantSelection.d.ts +8 -3
  128. package/esm/useCode/useVariantSelection.js +144 -52
  129. package/esm/useCopier/index.js +5 -4
  130. package/esm/useDemo/createCodeSandbox.d.ts +1 -1
  131. package/esm/useDemo/createStackBlitz.d.ts +1 -1
  132. package/esm/useDemo/exportVariant.js +13 -11
  133. package/esm/useDemo/index.d.ts +1 -1
  134. package/esm/useDemo/index.js +1 -1
  135. package/esm/useDemo/useDemo.d.ts +5 -5
  136. package/esm/useDemo/useDemo.js +6 -6
  137. package/esm/useErrors/useErrors.d.ts +1 -1
  138. package/esm/useErrors/useErrors.js +6 -2
  139. package/esm/useSearch/index.d.ts +1 -0
  140. package/esm/useSearch/index.js +1 -0
  141. package/esm/useSearch/types.d.ts +165 -0
  142. package/esm/useSearch/types.js +1 -0
  143. package/esm/useSearch/useSearch.d.ts +56 -0
  144. package/esm/useSearch/useSearch.js +647 -0
  145. package/esm/withDocsInfra/withDeploymentConfig.js +4 -2
  146. package/esm/withDocsInfra/withDocsInfra.d.ts +39 -0
  147. package/esm/withDocsInfra/withDocsInfra.js +94 -14
  148. package/package.json +105 -5
  149. package/esm/CodeHighlighter/transformParsedSource.d.ts +0 -3
  150. /package/esm/{CodeHighlighter/addPathsToVariant.js → pipeline/loadCodeVariant/addCodeVariantPaths.js} +0 -0
  151. /package/esm/{CodeHighlighter → pipeline/loadCodeVariant}/calculateMainFilePath.d.ts +0 -0
  152. /package/esm/{CodeHighlighter/hasAllVariants.js → pipeline/loadCodeVariant/hasAllCodeVariants.js} +0 -0
  153. /package/esm/{CodeHighlighter → pipeline/loadCodeVariant}/parseCode.js +0 -0
  154. /package/esm/{CodeHighlighter → pipeline/loadCodeVariant}/pathUtils.d.ts +0 -0
  155. /package/esm/{CodeHighlighter → pipeline/loadCodeVariant}/pathUtils.js +0 -0
  156. /package/esm/{CodeHighlighter → pipeline/loadCodeVariant}/transformSource.js +0 -0
@@ -37,13 +37,13 @@ export function isHashRelevantToDemo(urlHash, mainSlug) {
37
37
 
38
38
  /**
39
39
  * Generates a file slug based on main slug, file name, and variant name
40
+ * All variants except "Default" include the variant name in the hash
40
41
  * @param mainSlug - The main component/demo slug
41
42
  * @param fileName - The file name
42
43
  * @param variantName - The variant name
43
- * @param isInitialVariant - Whether this is the initial/default variant
44
44
  * @returns Generated file slug
45
45
  */
46
- function generateFileSlug(mainSlug, fileName, variantName, isInitialVariant) {
46
+ function generateFileSlug(mainSlug, fileName, variantName) {
47
47
  // Extract base name from filename (strip extension)
48
48
  var lastDotIndex = fileName.lastIndexOf('.');
49
49
  var baseName = lastDotIndex !== -1 ? fileName.substring(0, lastDotIndex) : fileName;
@@ -62,8 +62,9 @@ function generateFileSlug(mainSlug, fileName, variantName, isInitialVariant) {
62
62
  return kebabFileName;
63
63
  }
64
64
 
65
- // Format: mainSlug:fileName.ext (for initial variant) or mainSlug:variantName:fileName.ext
66
- if (isInitialVariant) {
65
+ // Format: mainSlug:fileName.ext (for Default variant) or mainSlug:variantName:fileName.ext
66
+ // "Default" variant is treated specially and doesn't include variant name in hash
67
+ if (variantName === 'Default') {
67
68
  return "".concat(kebabMainSlug, ":").concat(kebabFileName);
68
69
  }
69
70
  return "".concat(kebabMainSlug, ":").concat(kebabVariantName, ":").concat(kebabFileName);
@@ -80,29 +81,23 @@ export function useFileNavigation(_ref) {
80
81
  selectedVariantKey = _ref$selectedVariantK === void 0 ? '' : _ref$selectedVariantK,
81
82
  _ref$variantKeys = _ref.variantKeys,
82
83
  variantKeys = _ref$variantKeys === void 0 ? [] : _ref$variantKeys,
83
- initialVariant = _ref.initialVariant,
84
84
  shouldHighlight = _ref.shouldHighlight,
85
85
  preClassName = _ref.preClassName,
86
86
  preRef = _ref.preRef,
87
87
  effectiveCode = _ref.effectiveCode,
88
- selectVariant = _ref.selectVariant;
88
+ selectVariant = _ref.selectVariant,
89
+ _ref$fileHashMode = _ref.fileHashMode,
90
+ fileHashMode = _ref$fileHashMode === void 0 ? 'remove-hash' : _ref$fileHashMode,
91
+ _ref$saveHashVariantT = _ref.saveHashVariantToLocalStorage,
92
+ saveHashVariantToLocalStorage = _ref$saveHashVariantT === void 0 ? 'on-interaction' : _ref$saveHashVariantT,
93
+ saveVariantToLocalStorage = _ref.saveVariantToLocalStorage,
94
+ hashVariant = _ref.hashVariant;
89
95
  // Keep selectedFileName as untransformed filename for internal tracking
90
96
  var _React$useState = React.useState(selectedVariant == null ? void 0 : selectedVariant.fileName),
91
97
  _React$useState2 = _slicedToArray(_React$useState, 2),
92
98
  selectedFileNameInternal = _React$useState2[0],
93
99
  setSelectedFileNameInternal = _React$useState2[1];
94
100
 
95
- // Track user interaction locally
96
- var _React$useState3 = React.useState(false),
97
- _React$useState4 = _slicedToArray(_React$useState3, 2),
98
- hasUserInteraction = _React$useState4[0],
99
- setHasUserInteraction = _React$useState4[1];
100
-
101
- // Helper to mark user interaction
102
- var markUserInteraction = React.useCallback(function () {
103
- setHasUserInteraction(true);
104
- }, []);
105
-
106
101
  // Use the simplified URL hash hook
107
102
  var _useUrlHashState = useUrlHashState(),
108
103
  _useUrlHashState2 = _slicedToArray(_useUrlHashState, 2),
@@ -113,6 +108,37 @@ export function useFileNavigation(_ref) {
113
108
  var pendingFileSelection = React.useRef(null);
114
109
  var justCompletedPendingSelection = React.useRef(false);
115
110
 
111
+ // Track the previous variant key to detect user-initiated changes
112
+ var prevVariantKeyRef = React.useRef(selectedVariantKey);
113
+ var _React$useState3 = React.useState(selectedVariantKey),
114
+ _React$useState4 = _slicedToArray(_React$useState3, 2),
115
+ prevVariantKeyState = _React$useState4[0],
116
+ setPrevVariantKeyState = _React$useState4[1];
117
+ var isInitialMount = React.useRef(true);
118
+
119
+ // Detect if the current variant change was driven by a hash change
120
+ // A variant change is hash-driven if the hash has a variant that matches where we're going
121
+ // AND we weren't already on that variant (i.e., the hash is what triggered the change)
122
+ var _React$useState5 = React.useState(hashVariant || null),
123
+ _React$useState6 = _slicedToArray(_React$useState5, 2),
124
+ prevHashVariant = _React$useState6[0],
125
+ setPrevHashVariant = _React$useState6[1];
126
+ var isHashDrivenVariantChange = hashVariant === selectedVariantKey && prevVariantKeyState !== selectedVariantKey;
127
+
128
+ // Update prevHashVariant when hashVariant changes
129
+ React.useEffect(function () {
130
+ if (hashVariant !== prevHashVariant) {
131
+ setPrevHashVariant(hashVariant || null);
132
+ }
133
+ }, [hashVariant, prevHashVariant]);
134
+
135
+ // Update prevVariantKeyState when variant changes
136
+ React.useEffect(function () {
137
+ if (selectedVariantKey !== prevVariantKeyState) {
138
+ setPrevVariantKeyState(selectedVariantKey);
139
+ }
140
+ }, [selectedVariantKey, prevVariantKeyState]);
141
+
116
142
  // Helper function to check URL hash and switch to matching file
117
143
  var checkUrlHashAndSelectFile = React.useCallback(function () {
118
144
  if (!hash) {
@@ -125,11 +151,9 @@ export function useFileNavigation(_ref) {
125
151
 
126
152
  // Step 1: Check current variant (if we have one)
127
153
  if (selectedVariant) {
128
- var isInitialVariant = initialVariant ? selectedVariantKey === initialVariant : variantKeys.length === 0 || selectedVariantKey === variantKeys[0];
129
-
130
154
  // Check main file
131
155
  if (selectedVariant.fileName) {
132
- var mainFileSlug = generateFileSlug(mainSlug, selectedVariant.fileName, selectedVariantKey, isInitialVariant);
156
+ var mainFileSlug = generateFileSlug(mainSlug, selectedVariant.fileName, selectedVariantKey);
133
157
  if (hash === mainFileSlug) {
134
158
  matchingFileName = selectedVariant.fileName;
135
159
  matchingVariantKey = selectedVariantKey;
@@ -140,7 +164,7 @@ export function useFileNavigation(_ref) {
140
164
  if (!matchingFileName && selectedVariant.extraFiles) {
141
165
  for (var _i = 0, _Object$keys = Object.keys(selectedVariant.extraFiles); _i < _Object$keys.length; _i++) {
142
166
  var fileName = _Object$keys[_i];
143
- var fileSlug = generateFileSlug(mainSlug, fileName, selectedVariantKey, isInitialVariant);
167
+ var fileSlug = generateFileSlug(mainSlug, fileName, selectedVariantKey);
144
168
  if (hash === fileSlug) {
145
169
  matchingFileName = fileName;
146
170
  matchingVariantKey = selectedVariantKey;
@@ -156,7 +180,7 @@ export function useFileNavigation(_ref) {
156
180
  try {
157
181
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
158
182
  var file = _step.value;
159
- var _fileSlug = generateFileSlug(mainSlug, file.originalName, selectedVariantKey, isInitialVariant);
183
+ var _fileSlug = generateFileSlug(mainSlug, file.originalName, selectedVariantKey);
160
184
  if (hash === _fileSlug) {
161
185
  matchingFileName = file.originalName;
162
186
  matchingVariantKey = selectedVariantKey;
@@ -181,11 +205,10 @@ export function useFileNavigation(_ref) {
181
205
  if (variantKey === selectedVariantKey || !variant || typeof variant === 'string') {
182
206
  continue;
183
207
  }
184
- var _isInitialVariant = initialVariant ? variantKey === initialVariant : variantKeys.length === 0 || variantKey === variantKeys[0];
185
208
 
186
209
  // Check main file
187
210
  if (variant.fileName) {
188
- var _mainFileSlug = generateFileSlug(mainSlug, variant.fileName, variantKey, _isInitialVariant);
211
+ var _mainFileSlug = generateFileSlug(mainSlug, variant.fileName, variantKey);
189
212
  if (hash === _mainFileSlug) {
190
213
  matchingFileName = variant.fileName;
191
214
  matchingVariantKey = variantKey;
@@ -197,7 +220,7 @@ export function useFileNavigation(_ref) {
197
220
  if (!matchingFileName && variant.extraFiles) {
198
221
  for (var _i3 = 0, _Object$keys2 = Object.keys(variant.extraFiles); _i3 < _Object$keys2.length; _i3++) {
199
222
  var _fileName = _Object$keys2[_i3];
200
- var _fileSlug2 = generateFileSlug(mainSlug, _fileName, variantKey, _isInitialVariant);
223
+ var _fileSlug2 = generateFileSlug(mainSlug, _fileName, variantKey);
201
224
  if (hash === _fileSlug2) {
202
225
  matchingFileName = _fileName;
203
226
  matchingVariantKey = variantKey;
@@ -223,16 +246,13 @@ export function useFileNavigation(_ref) {
223
246
  // Set the file if we're in the correct variant
224
247
  pendingFileSelection.current = null;
225
248
  setSelectedFileNameInternal(matchingFileName);
226
- markUserInteraction();
227
249
  }
228
- }, [hash, selectedVariant, selectedVariantKey, variantKeys, initialVariant, mainSlug, transformedFiles, effectiveCode, selectVariant, markUserInteraction]);
250
+ }, [hash, selectedVariant, selectedVariantKey, mainSlug, transformedFiles, effectiveCode, selectVariant]);
229
251
 
230
252
  // Run hash check when URL hash changes to select the matching file
231
- // Only depends on hash to avoid re-running when the callback recreates due to variant state changes
232
253
  React.useEffect(function () {
233
254
  checkUrlHashAndSelectFile();
234
- // eslint-disable-next-line react-hooks/exhaustive-deps
235
- }, [hash]);
255
+ }, [checkUrlHashAndSelectFile]);
236
256
 
237
257
  // When variant switches with a pending file selection, complete the file selection
238
258
  React.useEffect(function () {
@@ -241,11 +261,10 @@ export function useFileNavigation(_ref) {
241
261
  pendingFileSelection.current = null;
242
262
  justCompletedPendingSelection.current = true;
243
263
  setSelectedFileNameInternal(fileToSelect);
244
- markUserInteraction();
245
264
  } else {
246
265
  justCompletedPendingSelection.current = false;
247
266
  }
248
- }, [selectedVariantKey, selectedVariant, markUserInteraction]);
267
+ }, [selectedVariantKey, selectedVariant]);
249
268
 
250
269
  // Reset selectedFileName when variant changes
251
270
  React.useEffect(function () {
@@ -263,38 +282,49 @@ export function useFileNavigation(_ref) {
263
282
  }
264
283
  }, [selectedVariant, selectedFileNameInternal]);
265
284
 
266
- // Update URL when variant changes (to reflect new slug for current file)
285
+ // Update hash when variant changes (user-initiated variant switch)
267
286
  React.useEffect(function () {
268
- if (!selectedVariant || typeof window === 'undefined' || !selectedFileNameInternal || !hasUserInteraction) {
287
+ // Skip on initial mount - let hash-driven navigation handle it
288
+ if (isInitialMount.current) {
289
+ isInitialMount.current = false;
290
+ prevVariantKeyRef.current = selectedVariantKey;
269
291
  return;
270
292
  }
271
293
 
272
- // Determine if this is the initial variant
273
- var isInitialVariant = initialVariant ? selectedVariantKey === initialVariant : variantKeys.length === 0 || selectedVariantKey === variantKeys[0];
294
+ // Only update hash if there's already a relevant hash present
295
+ if (typeof window === 'undefined' || !isHashRelevantToDemo(hash, mainSlug)) {
296
+ prevVariantKeyRef.current = selectedVariantKey;
297
+ return;
298
+ }
274
299
 
275
- // Generate the new slug for the currently selected file
276
- var fileSlug = '';
277
- if (transformedFiles) {
278
- var file = transformedFiles.files.find(function (f) {
279
- return f.originalName === selectedFileNameInternal;
280
- });
281
- if (file) {
282
- fileSlug = generateFileSlug(mainSlug, file.originalName, selectedVariantKey, isInitialVariant);
283
- }
284
- } else {
285
- fileSlug = generateFileSlug(mainSlug, selectedFileNameInternal, selectedVariantKey, isInitialVariant);
300
+ // Skip if variant hasn't actually changed
301
+ if (prevVariantKeyRef.current === selectedVariantKey) {
302
+ return;
286
303
  }
287
304
 
288
- // Only update the URL hash if it's different from current hash
289
- if (fileSlug && hash !== fileSlug) {
290
- // Only update if current hash is for the same demo (starts with mainSlug)
291
- // Don't set hash if there's no existing hash - variant changes shouldn't add hashes
292
- if (isHashRelevantToDemo(hash, mainSlug)) {
293
- setHash(fileSlug);
305
+ // Skip if this is a hash-driven variant change (hash is driving the variant selection)
306
+ if (pendingFileSelection.current || justCompletedPendingSelection.current || isHashDrivenVariantChange) {
307
+ prevVariantKeyRef.current = selectedVariantKey;
308
+ return;
309
+ }
310
+
311
+ // User switched variants, update hash based on fileHashMode
312
+ // Note: localStorage is already saved by setSelectedVariantKeyAsUser
313
+ if (fileHashMode === 'remove-filename') {
314
+ // Keep variant in hash: mainSlug or mainSlug:variant (for non-Default variants)
315
+ var kebabMainSlug = toKebabCase(mainSlug);
316
+ if (selectedVariantKey === 'Default') {
317
+ setHash(kebabMainSlug);
318
+ } else {
319
+ var kebabVariantName = toKebabCase(selectedVariantKey);
320
+ setHash("".concat(kebabMainSlug, ":").concat(kebabVariantName));
294
321
  }
295
- // Otherwise, don't update - either no hash exists or hash is for a different demo
322
+ } else {
323
+ // Remove entire hash
324
+ setHash(null);
296
325
  }
297
- }, [selectedVariant, selectedFileNameInternal, transformedFiles, mainSlug, selectedVariantKey, variantKeys, initialVariant, hasUserInteraction, setHash, hash]);
326
+ prevVariantKeyRef.current = selectedVariantKey;
327
+ }, [selectedVariantKey, hash, mainSlug, fileHashMode, setHash, isHashDrivenVariantChange]);
298
328
 
299
329
  // Compute the displayed filename (transformed if applicable)
300
330
  var selectedFileName = React.useMemo(function () {
@@ -446,15 +476,12 @@ export function useFileNavigation(_ref) {
446
476
  return [];
447
477
  }
448
478
 
449
- // Determine if this is the initial variant
450
- var isInitialVariant = initialVariant ? selectedVariantKey === initialVariant : variantKeys.length === 0 || selectedVariantKey === variantKeys[0];
451
-
452
479
  // If we have transformed files, use them
453
480
  if (transformedFiles) {
454
481
  return transformedFiles.files.map(function (f) {
455
482
  return {
456
483
  name: f.name,
457
- slug: generateFileSlug(mainSlug, f.originalName, selectedVariantKey, isInitialVariant),
484
+ slug: generateFileSlug(mainSlug, f.originalName, selectedVariantKey),
458
485
  component: f.component
459
486
  };
460
487
  });
@@ -467,7 +494,7 @@ export function useFileNavigation(_ref) {
467
494
  if (selectedVariant.fileName && selectedVariant.source) {
468
495
  result.push({
469
496
  name: selectedVariant.fileName,
470
- slug: generateFileSlug(mainSlug, selectedVariant.fileName, selectedVariantKey, isInitialVariant),
497
+ slug: generateFileSlug(mainSlug, selectedVariant.fileName, selectedVariantKey),
471
498
  component: /*#__PURE__*/_jsx(Pre, {
472
499
  className: preClassName,
473
500
  ref: preRef,
@@ -494,7 +521,7 @@ export function useFileNavigation(_ref) {
494
521
  }
495
522
  result.push({
496
523
  name: fileName,
497
- slug: generateFileSlug(mainSlug, fileName, selectedVariantKey, isInitialVariant),
524
+ slug: generateFileSlug(mainSlug, fileName, selectedVariantKey),
498
525
  component: /*#__PURE__*/_jsx(Pre, {
499
526
  className: preClassName,
500
527
  ref: preRef,
@@ -505,7 +532,7 @@ export function useFileNavigation(_ref) {
505
532
  });
506
533
  }
507
534
  return result;
508
- }, [selectedVariant, transformedFiles, mainSlug, selectedVariantKey, variantKeys, initialVariant, shouldHighlight, preClassName, preRef]);
535
+ }, [selectedVariant, transformedFiles, mainSlug, selectedVariantKey, shouldHighlight, preClassName, preRef]);
509
536
 
510
537
  // Create a wrapper for selectFileName that handles transformed filenames and URL updates
511
538
  var selectFileName = React.useCallback(function (fileName) {
@@ -513,10 +540,6 @@ export function useFileNavigation(_ref) {
513
540
  return;
514
541
  }
515
542
  var targetFileName = fileName;
516
- var fileSlug = '';
517
-
518
- // Determine if this is the initial variant
519
- var isInitialVariant = initialVariant ? selectedVariantKey === initialVariant : variantKeys.length === 0 || selectedVariantKey === variantKeys[0];
520
543
 
521
544
  // If we have transformed files, we need to reverse-lookup the original filename
522
545
  if (transformedFiles) {
@@ -526,7 +549,6 @@ export function useFileNavigation(_ref) {
526
549
  });
527
550
  if (fileByTransformedName) {
528
551
  targetFileName = fileByTransformedName.originalName;
529
- fileSlug = generateFileSlug(mainSlug, fileByTransformedName.originalName, selectedVariantKey, isInitialVariant);
530
552
  } else {
531
553
  // Check if the fileName is already an original name
532
554
  var fileByOriginalName = transformedFiles.files.find(function (f) {
@@ -534,21 +556,32 @@ export function useFileNavigation(_ref) {
534
556
  });
535
557
  if (fileByOriginalName) {
536
558
  targetFileName = fileName;
537
- fileSlug = generateFileSlug(mainSlug, fileName, selectedVariantKey, isInitialVariant);
538
559
  }
539
560
  }
540
- } else {
541
- // No transformed files, generate slug directly
542
- fileSlug = generateFileSlug(mainSlug, fileName, selectedVariantKey, isInitialVariant);
543
561
  }
544
562
 
545
- // Update the URL hash without adding to history (replaceState)
546
- if (typeof window !== 'undefined' && fileSlug && hash !== fileSlug) {
547
- setHash(fileSlug); // Use the new URL hash hook
563
+ // Handle hash removal based on fileHashMode
564
+ if (typeof window !== 'undefined' && isHashRelevantToDemo(hash, mainSlug)) {
565
+ // Save variant to localStorage if on-interaction mode (clicking a tab counts as interaction)
566
+ if (saveVariantToLocalStorage && saveHashVariantToLocalStorage === 'on-interaction') {
567
+ saveVariantToLocalStorage(selectedVariantKey);
568
+ }
569
+ if (fileHashMode === 'remove-filename') {
570
+ // Keep variant in hash: mainSlug or mainSlug:variant (for non-Default variants)
571
+ var kebabMainSlug = toKebabCase(mainSlug);
572
+ if (selectedVariantKey === 'Default') {
573
+ setHash(kebabMainSlug);
574
+ } else {
575
+ var kebabVariantName = toKebabCase(selectedVariantKey);
576
+ setHash("".concat(kebabMainSlug, ":").concat(kebabVariantName));
577
+ }
578
+ } else {
579
+ // Remove entire hash
580
+ setHash(null);
581
+ }
548
582
  }
549
- markUserInteraction(); // Mark that user has made an explicit selection
550
583
  setSelectedFileNameInternal(targetFileName);
551
- }, [selectedVariant, transformedFiles, mainSlug, selectedVariantKey, variantKeys, initialVariant, setHash, markUserInteraction, hash]);
584
+ }, [selectedVariant, transformedFiles, mainSlug, selectedVariantKey, fileHashMode, hash, setHash, saveHashVariantToLocalStorage, saveVariantToLocalStorage]);
552
585
 
553
586
  // Memoized array of all file slugs for all variants
554
587
  var allFilesSlugs = React.useMemo(function () {
@@ -570,14 +603,24 @@ export function useFileNavigation(_ref) {
570
603
  return 1; // continue
571
604
  }
572
605
 
573
- // Determine if this is the initial variant
574
- var isInitialVariant = initialVariant ? variantKey === initialVariant : variantKeys.length === 0 || variantKey === variantKeys[0];
606
+ // Add variant-only slug (points to main file of the variant)
607
+ // Skip for Default variant since it doesn't have variant name in hash
608
+ if (variant.fileName && variantKey !== 'Default') {
609
+ var kebabMainSlug = toKebabCase(mainSlug);
610
+ var kebabVariantName = toKebabCase(variantKey);
611
+ var variantOnlySlug = "".concat(kebabMainSlug, ":").concat(kebabVariantName);
612
+ result.push({
613
+ fileName: variant.fileName,
614
+ slug: variantOnlySlug,
615
+ variantName: variantKey
616
+ });
617
+ }
575
618
 
576
619
  // Add main file if it exists
577
620
  if (variant.fileName) {
578
621
  result.push({
579
622
  fileName: variant.fileName,
580
- slug: generateFileSlug(mainSlug, variant.fileName, variantKey, isInitialVariant),
623
+ slug: generateFileSlug(mainSlug, variant.fileName, variantKey),
581
624
  variantName: variantKey
582
625
  });
583
626
  }
@@ -587,7 +630,7 @@ export function useFileNavigation(_ref) {
587
630
  Object.keys(variant.extraFiles).forEach(function (fileName) {
588
631
  result.push({
589
632
  fileName: fileName,
590
- slug: generateFileSlug(mainSlug, fileName, variantKey, isInitialVariant),
633
+ slug: generateFileSlug(mainSlug, fileName, variantKey),
591
634
  variantName: variantKey
592
635
  });
593
636
  });
@@ -602,7 +645,7 @@ export function useFileNavigation(_ref) {
602
645
  _iterator2.f();
603
646
  }
604
647
  return result;
605
- }, [effectiveCode, variantKeys, initialVariant, mainSlug]);
648
+ }, [effectiveCode, variantKeys, mainSlug]);
606
649
  return {
607
650
  selectedFileName: selectedFileName,
608
651
  selectedFile: selectedFile,
@@ -1,6 +1,7 @@
1
1
  import * as React from 'react';
2
2
  interface UseUIStateProps {
3
3
  defaultOpen?: boolean;
4
+ mainSlug?: string;
4
5
  }
5
6
  export interface UseUIStateResult {
6
7
  expanded: boolean;
@@ -9,8 +10,10 @@ export interface UseUIStateResult {
9
10
  }
10
11
  /**
11
12
  * Hook for managing UI state like expansion and focus
13
+ * Auto-expands if there's a relevant hash for this demo
12
14
  */
13
15
  export declare function useUIState({
14
- defaultOpen
16
+ defaultOpen,
17
+ mainSlug
15
18
  }: UseUIStateProps): UseUIStateResult;
16
19
  export {};
@@ -1,18 +1,33 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
2
  import * as React from 'react';
3
+ import { useUrlHashState } from "../useUrlHashState/index.js";
4
+ import { isHashRelevantToDemo } from "./useFileNavigation.js";
3
5
  /**
4
6
  * Hook for managing UI state like expansion and focus
7
+ * Auto-expands if there's a relevant hash for this demo
5
8
  */
6
9
  export function useUIState(_ref) {
7
10
  var _ref$defaultOpen = _ref.defaultOpen,
8
- defaultOpen = _ref$defaultOpen === void 0 ? false : _ref$defaultOpen;
9
- var _React$useState = React.useState(defaultOpen),
11
+ defaultOpen = _ref$defaultOpen === void 0 ? false : _ref$defaultOpen,
12
+ mainSlug = _ref.mainSlug;
13
+ var _useUrlHashState = useUrlHashState(),
14
+ _useUrlHashState2 = _slicedToArray(_useUrlHashState, 1),
15
+ hash = _useUrlHashState2[0];
16
+ var hasRelevantHash = isHashRelevantToDemo(hash, mainSlug);
17
+ var _React$useState = React.useState(defaultOpen || hasRelevantHash),
10
18
  _React$useState2 = _slicedToArray(_React$useState, 2),
11
19
  expanded = _React$useState2[0],
12
20
  setExpanded = _React$useState2[1];
13
21
  var expand = React.useCallback(function () {
14
22
  return setExpanded(true);
15
23
  }, []);
24
+
25
+ // Auto-expand if hash becomes relevant
26
+ React.useEffect(function () {
27
+ if (hasRelevantHash && !expanded) {
28
+ setExpanded(true);
29
+ }
30
+ }, [hasRelevantHash, expanded]);
16
31
  return {
17
32
  expanded: expanded,
18
33
  expand: expand,
@@ -5,22 +5,27 @@ interface UseVariantSelectionProps {
5
5
  initialVariant?: string;
6
6
  variantType?: string;
7
7
  mainSlug?: string;
8
+ saveHashVariantToLocalStorage?: 'on-load' | 'on-interaction' | 'never';
8
9
  }
9
10
  export interface UseVariantSelectionResult {
10
11
  variantKeys: string[];
11
12
  selectedVariantKey: string;
12
13
  selectedVariant: VariantCode | null;
13
- selectVariant: React.Dispatch<React.SetStateAction<string>>;
14
+ selectVariant: React.Dispatch<React.SetStateAction<string | null>>;
14
15
  selectVariantProgrammatic: React.Dispatch<React.SetStateAction<string>>;
16
+ saveVariantToLocalStorage: (variant: string) => void;
17
+ hashVariant: string | null;
15
18
  }
16
19
  /**
17
20
  * Hook for managing variant selection and providing variant-related data
18
- * Uses React state as source of truth, with localStorage for persistence
21
+ * Priority: URL hash > localStorage > initialVariant > first variant
22
+ * When hash has a variant, it overrides localStorage and is saved to localStorage
19
23
  */
20
24
  export declare function useVariantSelection({
21
25
  effectiveCode,
22
26
  initialVariant,
23
27
  variantType,
24
- mainSlug
28
+ mainSlug,
29
+ saveHashVariantToLocalStorage
25
30
  }: UseVariantSelectionProps): UseVariantSelectionResult;
26
31
  export {};