@mui/internal-docs-infra 0.2.3-canary.1 → 0.2.3-canary.11
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.
- package/esm/pipeline/loaderUtils/processRelativeImports.js +16 -3
- package/esm/useCode/Pre.js +31 -45
- package/esm/useCode/useCode.d.ts +13 -0
- package/esm/useCode/useCode.js +15 -6
- package/esm/useCode/useFileNavigation.d.ts +9 -3
- package/esm/useCode/useFileNavigation.js +124 -81
- package/esm/useCode/useUIState.d.ts +4 -1
- package/esm/useCode/useUIState.js +17 -2
- package/esm/useCode/useVariantSelection.d.ts +7 -2
- package/esm/useCode/useVariantSelection.js +139 -49
- package/esm/withDocsInfra/index.d.ts +2 -1
- package/esm/withDocsInfra/index.js +2 -1
- package/esm/withDocsInfra/withDeploymentConfig.d.ts +2 -0
- package/esm/withDocsInfra/withDeploymentConfig.js +71 -0
- package/esm/withDocsInfra/withDocsInfra.d.ts +2 -15
- package/esm/withDocsInfra/withDocsInfra.js +0 -2
- package/package.json +7 -4
|
@@ -36,8 +36,13 @@ function processFlatMode(importResult, resolvedPathsMap) {
|
|
|
36
36
|
var file = _fileMapping[_i];
|
|
37
37
|
var fileName = file.segments[file.segments.length - 1];
|
|
38
38
|
var isIndexFile = fileName.startsWith('index.');
|
|
39
|
+
var isUnderscoreIndexFile = fileName.startsWith('_index.');
|
|
39
40
|
var candidateName = void 0;
|
|
40
|
-
if (
|
|
41
|
+
if (isUnderscoreIndexFile) {
|
|
42
|
+
// Files starting with "_index." should be treated as direct index imports
|
|
43
|
+
// e.g., "../../dir/_index.module.css" -> "index.module.css"
|
|
44
|
+
candidateName = "index".concat(file.extension);
|
|
45
|
+
} else if (isIndexFile) {
|
|
41
46
|
// Check if the original import was a direct index file (e.g., "./index.ext")
|
|
42
47
|
var originalImportParts = file.originalImportPath.split('/');
|
|
43
48
|
var isDirectIndexImport = originalImportParts.length === 2 && originalImportParts[0] === '.' && originalImportParts[1].startsWith('index.');
|
|
@@ -131,9 +136,13 @@ function processFlatMode(importResult, resolvedPathsMap) {
|
|
|
131
136
|
var _file = _step.value;
|
|
132
137
|
var _fileName = _file.segments[_file.segments.length - 1];
|
|
133
138
|
var _isIndexFile = _fileName.startsWith('index.');
|
|
139
|
+
var _isUnderscoreIndexFile = _fileName.startsWith('_index.');
|
|
134
140
|
var distinguishingSegment = _file.segments[_distinguishingIndex];
|
|
135
141
|
var finalName = void 0;
|
|
136
|
-
if (
|
|
142
|
+
if (_isUnderscoreIndexFile) {
|
|
143
|
+
// Files starting with "_index." should always use "index" as the base name
|
|
144
|
+
finalName = "".concat(distinguishingSegment, "/index").concat(_file.extension);
|
|
145
|
+
} else if (_isIndexFile) {
|
|
137
146
|
// Check if this was a direct index import
|
|
138
147
|
var _originalImportParts = _file.originalImportPath.split('/');
|
|
139
148
|
var _isDirectIndexImport = _originalImportParts.length === 2 && _originalImportParts[0] === '.' && _originalImportParts[1].startsWith('index.');
|
|
@@ -202,9 +211,13 @@ function processFlatMode(importResult, resolvedPathsMap) {
|
|
|
202
211
|
var _file2 = _step3.value;
|
|
203
212
|
var _fileName2 = _file2.segments[_file2.segments.length - 1];
|
|
204
213
|
var _isIndexFile2 = _fileName2.startsWith('index.');
|
|
214
|
+
var _isUnderscoreIndexFile2 = _fileName2.startsWith('_index.');
|
|
205
215
|
var _distinguishingSegment = _file2.segments[distinguishingIndex];
|
|
206
216
|
var _finalName = void 0;
|
|
207
|
-
if (
|
|
217
|
+
if (_isUnderscoreIndexFile2) {
|
|
218
|
+
// Files starting with "_index." should always use "index" as the base name
|
|
219
|
+
_finalName = "".concat(_distinguishingSegment, "/index").concat(_file2.extension);
|
|
220
|
+
} else if (_isIndexFile2) {
|
|
208
221
|
// Check if this was a direct index import
|
|
209
222
|
var _originalImportParts2 = _file2.originalImportPath.split('/');
|
|
210
223
|
var _isDirectIndexImport2 = _originalImportParts2.length === 2 && _originalImportParts2[0] === '.' && _originalImportParts2[1].startsWith('index.');
|
package/esm/useCode/Pre.js
CHANGED
|
@@ -9,6 +9,35 @@ import { decompressSync, strFromU8 } from 'fflate';
|
|
|
9
9
|
import { decode } from 'uint8-to-base64';
|
|
10
10
|
import { hastToJsx } from "../pipeline/hastUtils/index.js";
|
|
11
11
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
var hastChildrenCache = new WeakMap();
|
|
13
|
+
var textChildrenCache = new WeakMap();
|
|
14
|
+
function renderCode(hastChildren, renderHast, text) {
|
|
15
|
+
if (renderHast) {
|
|
16
|
+
var jsx = hastChildrenCache.get(hastChildren);
|
|
17
|
+
if (!jsx) {
|
|
18
|
+
jsx = hastToJsx({
|
|
19
|
+
type: 'root',
|
|
20
|
+
children: hastChildren
|
|
21
|
+
});
|
|
22
|
+
hastChildrenCache.set(hastChildren, jsx);
|
|
23
|
+
}
|
|
24
|
+
return jsx;
|
|
25
|
+
}
|
|
26
|
+
if (text !== undefined) {
|
|
27
|
+
return text;
|
|
28
|
+
}
|
|
29
|
+
var txt = textChildrenCache.get(hastChildren);
|
|
30
|
+
if (!txt) {
|
|
31
|
+
txt = toText({
|
|
32
|
+
type: 'root',
|
|
33
|
+
children: hastChildren
|
|
34
|
+
}, {
|
|
35
|
+
whitespace: 'pre'
|
|
36
|
+
});
|
|
37
|
+
textChildrenCache.set(hastChildren, txt);
|
|
38
|
+
}
|
|
39
|
+
return txt;
|
|
40
|
+
}
|
|
12
41
|
export function Pre(_ref) {
|
|
13
42
|
var children = _ref.children,
|
|
14
43
|
className = _ref.className,
|
|
@@ -96,49 +125,6 @@ export function Pre(_ref) {
|
|
|
96
125
|
observer.current.observe(node);
|
|
97
126
|
}
|
|
98
127
|
}, []);
|
|
99
|
-
var hastChildrenCache = React.useMemo(function () {
|
|
100
|
-
return hast == null ? void 0 : hast.children.map(function () {
|
|
101
|
-
return null;
|
|
102
|
-
});
|
|
103
|
-
}, [hast]);
|
|
104
|
-
var textChildrenCache = React.useMemo(function () {
|
|
105
|
-
return hast == null ? void 0 : hast.children.map(function () {
|
|
106
|
-
return null;
|
|
107
|
-
});
|
|
108
|
-
}, [hast]);
|
|
109
|
-
var renderCode = React.useCallback(function (index, hastChildren, renderHast, text) {
|
|
110
|
-
if (renderHast) {
|
|
111
|
-
var _cached = hastChildrenCache == null ? void 0 : hastChildrenCache[index];
|
|
112
|
-
if (_cached) {
|
|
113
|
-
return _cached;
|
|
114
|
-
}
|
|
115
|
-
var jsx = hastToJsx({
|
|
116
|
-
type: 'root',
|
|
117
|
-
children: hastChildren
|
|
118
|
-
});
|
|
119
|
-
if (hastChildrenCache) {
|
|
120
|
-
hastChildrenCache[index] = jsx;
|
|
121
|
-
}
|
|
122
|
-
return jsx;
|
|
123
|
-
}
|
|
124
|
-
if (text !== undefined) {
|
|
125
|
-
return text;
|
|
126
|
-
}
|
|
127
|
-
var cached = textChildrenCache == null ? void 0 : textChildrenCache[index];
|
|
128
|
-
if (cached) {
|
|
129
|
-
return cached;
|
|
130
|
-
}
|
|
131
|
-
var txt = toText({
|
|
132
|
-
type: 'root',
|
|
133
|
-
children: hastChildren
|
|
134
|
-
}, {
|
|
135
|
-
whitespace: 'pre'
|
|
136
|
-
});
|
|
137
|
-
if (textChildrenCache) {
|
|
138
|
-
textChildrenCache[index] = txt;
|
|
139
|
-
}
|
|
140
|
-
return txt;
|
|
141
|
-
}, [hastChildrenCache, textChildrenCache]);
|
|
142
128
|
var frames = React.useMemo(function () {
|
|
143
129
|
return hast == null ? void 0 : hast.children.map(function (child, index) {
|
|
144
130
|
if (child.type !== 'element') {
|
|
@@ -151,7 +137,7 @@ export function Pre(_ref) {
|
|
|
151
137
|
className: "frame",
|
|
152
138
|
"data-frame": index,
|
|
153
139
|
ref: observeFrame,
|
|
154
|
-
children: renderCode(
|
|
140
|
+
children: renderCode(child.children, shouldHighlight && isVisible, (_child$properties = child.properties) != null && _child$properties.dataAsString ? String((_child$properties2 = child.properties) == null ? void 0 : _child$properties2.dataAsString) : undefined)
|
|
155
141
|
}, index);
|
|
156
142
|
}
|
|
157
143
|
return /*#__PURE__*/_jsx(React.Fragment, {
|
|
@@ -160,7 +146,7 @@ export function Pre(_ref) {
|
|
|
160
146
|
})
|
|
161
147
|
}, index);
|
|
162
148
|
});
|
|
163
|
-
}, [hast,
|
|
149
|
+
}, [hast, observeFrame, shouldHighlight, visibleFrames]);
|
|
164
150
|
return /*#__PURE__*/_jsx("pre", {
|
|
165
151
|
ref: bindIntersectionObserver,
|
|
166
152
|
className: className,
|
package/esm/useCode/useCode.d.ts
CHANGED
|
@@ -9,6 +9,19 @@ export type UseCodeOpts = {
|
|
|
9
9
|
githubUrlPrefix?: string;
|
|
10
10
|
initialVariant?: string;
|
|
11
11
|
initialTransform?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Controls hash removal behavior when user interacts with file tabs:
|
|
14
|
+
* - 'remove-hash': Remove entire hash (default)
|
|
15
|
+
* - 'remove-filename': Remove only filename, keep variant in hash
|
|
16
|
+
*/
|
|
17
|
+
fileHashMode?: 'remove-hash' | 'remove-filename';
|
|
18
|
+
/**
|
|
19
|
+
* Controls when to save hash variant to localStorage:
|
|
20
|
+
* - 'on-load': Save immediately when page loads with hash
|
|
21
|
+
* - 'on-interaction': Save only when user clicks a tab (default)
|
|
22
|
+
* - 'never': Never save hash variant to localStorage
|
|
23
|
+
*/
|
|
24
|
+
saveHashVariantToLocalStorage?: 'on-load' | 'on-interaction' | 'never';
|
|
12
25
|
};
|
|
13
26
|
type UserProps<T extends {} = {}> = T & {
|
|
14
27
|
name?: string;
|
package/esm/useCode/useCode.js
CHANGED
|
@@ -18,7 +18,11 @@ export function useCode(contentProps, opts) {
|
|
|
18
18
|
initialVariant = _ref.initialVariant,
|
|
19
19
|
initialTransform = _ref.initialTransform,
|
|
20
20
|
preClassName = _ref.preClassName,
|
|
21
|
-
preRef = _ref.preRef
|
|
21
|
+
preRef = _ref.preRef,
|
|
22
|
+
_ref$fileHashMode = _ref.fileHashMode,
|
|
23
|
+
fileHashMode = _ref$fileHashMode === void 0 ? 'remove-hash' : _ref$fileHashMode,
|
|
24
|
+
_ref$saveHashVariantT = _ref.saveHashVariantToLocalStorage,
|
|
25
|
+
saveHashVariantToLocalStorage = _ref$saveHashVariantT === void 0 ? 'on-interaction' : _ref$saveHashVariantT;
|
|
22
26
|
|
|
23
27
|
// Safely try to get context values - will be undefined if not in context
|
|
24
28
|
var context = useCodeHighlighterContextOptional();
|
|
@@ -58,9 +62,10 @@ export function useCode(contentProps, opts) {
|
|
|
58
62
|
});
|
|
59
63
|
}, [contentProps, context == null ? void 0 : context.url]);
|
|
60
64
|
|
|
61
|
-
// Sub-hook: UI State Management
|
|
65
|
+
// Sub-hook: UI State Management (needs slug to check for relevant hash)
|
|
62
66
|
var uiState = useUIState({
|
|
63
|
-
defaultOpen: defaultOpen
|
|
67
|
+
defaultOpen: defaultOpen,
|
|
68
|
+
mainSlug: userProps.slug
|
|
64
69
|
});
|
|
65
70
|
|
|
66
71
|
// Sub-hook: Variant Selection
|
|
@@ -68,7 +73,8 @@ export function useCode(contentProps, opts) {
|
|
|
68
73
|
effectiveCode: effectiveCode,
|
|
69
74
|
initialVariant: initialVariant,
|
|
70
75
|
variantType: contentProps.variantType,
|
|
71
|
-
mainSlug: userProps.slug
|
|
76
|
+
mainSlug: userProps.slug,
|
|
77
|
+
saveHashVariantToLocalStorage: saveHashVariantToLocalStorage
|
|
72
78
|
});
|
|
73
79
|
|
|
74
80
|
// Sub-hook: Transform Management
|
|
@@ -89,11 +95,14 @@ export function useCode(contentProps, opts) {
|
|
|
89
95
|
selectedVariantKey: variantSelection.selectedVariantKey,
|
|
90
96
|
selectVariant: variantSelection.selectVariantProgrammatic,
|
|
91
97
|
variantKeys: variantSelection.variantKeys,
|
|
92
|
-
initialVariant: initialVariant,
|
|
93
98
|
shouldHighlight: shouldHighlight,
|
|
94
99
|
preClassName: preClassName,
|
|
95
100
|
preRef: preRef,
|
|
96
|
-
effectiveCode: effectiveCode
|
|
101
|
+
effectiveCode: effectiveCode,
|
|
102
|
+
fileHashMode: fileHashMode,
|
|
103
|
+
saveHashVariantToLocalStorage: saveHashVariantToLocalStorage,
|
|
104
|
+
saveVariantToLocalStorage: variantSelection.saveVariantToLocalStorage,
|
|
105
|
+
hashVariant: variantSelection.hashVariant
|
|
97
106
|
});
|
|
98
107
|
|
|
99
108
|
// Sub-hook: Copy Functionality
|
|
@@ -22,11 +22,14 @@ interface UseFileNavigationProps {
|
|
|
22
22
|
selectedVariantKey?: string;
|
|
23
23
|
variantKeys?: string[];
|
|
24
24
|
shouldHighlight: boolean;
|
|
25
|
-
initialVariant?: string;
|
|
26
25
|
preClassName?: string;
|
|
27
26
|
preRef?: React.Ref<HTMLPreElement>;
|
|
28
27
|
effectiveCode?: Code;
|
|
29
28
|
selectVariant?: React.Dispatch<React.SetStateAction<string>>;
|
|
29
|
+
fileHashMode?: 'remove-hash' | 'remove-filename';
|
|
30
|
+
saveHashVariantToLocalStorage?: 'on-load' | 'on-interaction' | 'never';
|
|
31
|
+
saveVariantToLocalStorage?: (variant: string) => void;
|
|
32
|
+
hashVariant?: string | null;
|
|
30
33
|
}
|
|
31
34
|
export interface UseFileNavigationResult {
|
|
32
35
|
selectedFileName: string | undefined;
|
|
@@ -54,11 +57,14 @@ export declare function useFileNavigation({
|
|
|
54
57
|
mainSlug,
|
|
55
58
|
selectedVariantKey,
|
|
56
59
|
variantKeys,
|
|
57
|
-
initialVariant,
|
|
58
60
|
shouldHighlight,
|
|
59
61
|
preClassName,
|
|
60
62
|
preRef,
|
|
61
63
|
effectiveCode,
|
|
62
|
-
selectVariant
|
|
64
|
+
selectVariant,
|
|
65
|
+
fileHashMode,
|
|
66
|
+
saveHashVariantToLocalStorage,
|
|
67
|
+
saveVariantToLocalStorage,
|
|
68
|
+
hashVariant
|
|
63
69
|
}: UseFileNavigationProps): UseFileNavigationResult;
|
|
64
70
|
export {};
|
|
@@ -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
|
|
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
|
|
66
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
285
|
+
// Update hash when variant changes (user-initiated variant switch)
|
|
267
286
|
React.useEffect(function () {
|
|
268
|
-
|
|
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
|
-
//
|
|
273
|
-
|
|
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
|
-
//
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
//
|
|
289
|
-
if (
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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
|
-
|
|
322
|
+
} else {
|
|
323
|
+
// Remove entire hash
|
|
324
|
+
setHash(null);
|
|
296
325
|
}
|
|
297
|
-
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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
|
-
//
|
|
546
|
-
if (typeof window !== 'undefined' &&
|
|
547
|
-
|
|
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,
|
|
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
|
-
//
|
|
574
|
-
|
|
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
|
|
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
|
|
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,
|
|
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
|
-
|
|
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,6 +5,7 @@ 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[];
|
|
@@ -12,15 +13,19 @@ export interface UseVariantSelectionResult {
|
|
|
12
13
|
selectedVariant: VariantCode | null;
|
|
13
14
|
selectVariant: React.Dispatch<React.SetStateAction<string>>;
|
|
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
|
-
*
|
|
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 {};
|
|
@@ -3,16 +3,69 @@ import _typeof from "@babel/runtime/helpers/esm/typeof";
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { usePreference } from "../usePreference/index.js";
|
|
5
5
|
import { useUrlHashState } from "../useUrlHashState/index.js";
|
|
6
|
-
import { isHashRelevantToDemo } from "./useFileNavigation.js";
|
|
6
|
+
import { isHashRelevantToDemo, toKebabCase } from "./useFileNavigation.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Parses the variant name from a URL hash
|
|
10
|
+
* Hash formats:
|
|
11
|
+
* - slug:file.tsx -> "Default"
|
|
12
|
+
* - slug:variant:file.tsx -> "variant"
|
|
13
|
+
* - slug:variant -> "variant"
|
|
14
|
+
* @param urlHash - The URL hash (without '#')
|
|
15
|
+
* @param mainSlug - The main slug for the demo (optional, used to determine if hash is relevant for file selection)
|
|
16
|
+
* @param variantKeys - Available variant keys
|
|
17
|
+
* @returns The variant name or null if not found/parseable
|
|
18
|
+
*/
|
|
19
|
+
function parseVariantFromHash(urlHash, mainSlug, variantKeys) {
|
|
20
|
+
if (!urlHash) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
var parts = urlHash.split(':');
|
|
24
|
+
|
|
25
|
+
// If there are 3 parts (slug:variant:file), the variant is in the middle
|
|
26
|
+
if (parts.length === 3) {
|
|
27
|
+
var variantPart = parts[1];
|
|
28
|
+
// Find matching variant key (case-insensitive kebab match)
|
|
29
|
+
var matchingVariant = variantKeys.find(function (key) {
|
|
30
|
+
return toKebabCase(key) === variantPart.toLowerCase();
|
|
31
|
+
});
|
|
32
|
+
return matchingVariant || null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// If there are 2 parts, could be slug:variant or slug:file
|
|
36
|
+
if (parts.length === 2) {
|
|
37
|
+
var secondPart = parts[1];
|
|
38
|
+
// Try to match as a variant first
|
|
39
|
+
var _matchingVariant = variantKeys.find(function (key) {
|
|
40
|
+
return toKebabCase(key) === secondPart.toLowerCase();
|
|
41
|
+
});
|
|
42
|
+
if (_matchingVariant) {
|
|
43
|
+
return _matchingVariant;
|
|
44
|
+
}
|
|
45
|
+
// If no matching variant and it looks like a filename, assume Default
|
|
46
|
+
if (secondPart.includes('.')) {
|
|
47
|
+
return 'Default';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Just the slug with no other parts, assume Default
|
|
52
|
+
if (parts.length === 1) {
|
|
53
|
+
return 'Default';
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
7
57
|
/**
|
|
8
58
|
* Hook for managing variant selection and providing variant-related data
|
|
9
|
-
*
|
|
59
|
+
* Priority: URL hash > localStorage > initialVariant > first variant
|
|
60
|
+
* When hash has a variant, it overrides localStorage and is saved to localStorage
|
|
10
61
|
*/
|
|
11
62
|
export function useVariantSelection(_ref) {
|
|
12
63
|
var effectiveCode = _ref.effectiveCode,
|
|
13
64
|
initialVariant = _ref.initialVariant,
|
|
14
65
|
variantType = _ref.variantType,
|
|
15
|
-
mainSlug = _ref.mainSlug
|
|
66
|
+
mainSlug = _ref.mainSlug,
|
|
67
|
+
_ref$saveHashVariantT = _ref.saveHashVariantToLocalStorage,
|
|
68
|
+
saveHashVariantToLocalStorage = _ref$saveHashVariantT === void 0 ? 'on-interaction' : _ref$saveHashVariantT;
|
|
16
69
|
// Get variant keys from effective code
|
|
17
70
|
var variantKeys = React.useMemo(function () {
|
|
18
71
|
return Object.keys(effectiveCode).filter(function (key) {
|
|
@@ -21,14 +74,14 @@ export function useVariantSelection(_ref) {
|
|
|
21
74
|
});
|
|
22
75
|
}, [effectiveCode]);
|
|
23
76
|
|
|
24
|
-
//
|
|
25
|
-
// Only override localStorage if hash starts with this demo's slug
|
|
77
|
+
// Get URL hash and parse variant from it
|
|
26
78
|
var _useUrlHashState = useUrlHashState(),
|
|
27
|
-
_useUrlHashState2 = _slicedToArray(_useUrlHashState,
|
|
28
|
-
urlHash = _useUrlHashState2[0]
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
79
|
+
_useUrlHashState2 = _slicedToArray(_useUrlHashState, 2),
|
|
80
|
+
urlHash = _useUrlHashState2[0],
|
|
81
|
+
setUrlHash = _useUrlHashState2[1];
|
|
82
|
+
var hashVariant = React.useMemo(function () {
|
|
83
|
+
return parseVariantFromHash(urlHash, mainSlug, variantKeys);
|
|
84
|
+
}, [urlHash, mainSlug, variantKeys]);
|
|
32
85
|
|
|
33
86
|
// Use localStorage hook for variant persistence
|
|
34
87
|
var _usePreference = usePreference('variant', variantType || variantKeys, function () {
|
|
@@ -38,73 +91,103 @@ export function useVariantSelection(_ref) {
|
|
|
38
91
|
storedValue = _usePreference2[0],
|
|
39
92
|
setStoredValue = _usePreference2[1];
|
|
40
93
|
|
|
41
|
-
//
|
|
94
|
+
// Track if the last change was user-initiated (to prevent hash from overriding)
|
|
95
|
+
var isUserInitiatedChange = React.useRef(false);
|
|
96
|
+
// Track previous hash variant to detect hash changes
|
|
97
|
+
var prevHashVariant = React.useRef(hashVariant);
|
|
98
|
+
// Track previous storedValue to detect localStorage changes
|
|
99
|
+
var prevStoredValue = React.useRef(storedValue);
|
|
100
|
+
|
|
101
|
+
// Determine initial variant: hash > localStorage > initialVariant > first variant
|
|
42
102
|
var _React$useState = React.useState(function () {
|
|
43
|
-
//
|
|
103
|
+
// Priority 1: Hash variant
|
|
104
|
+
if (hashVariant && variantKeys.includes(hashVariant)) {
|
|
105
|
+
return hashVariant;
|
|
106
|
+
}
|
|
107
|
+
// Priority 2: localStorage
|
|
108
|
+
if (storedValue && variantKeys.includes(storedValue)) {
|
|
109
|
+
return storedValue;
|
|
110
|
+
}
|
|
111
|
+
// Priority 3: initialVariant prop
|
|
44
112
|
if (initialVariant && variantKeys.includes(initialVariant)) {
|
|
45
113
|
return initialVariant;
|
|
46
114
|
}
|
|
47
|
-
|
|
48
|
-
// Final fallback: use first available variant
|
|
115
|
+
// Priority 4: First available variant
|
|
49
116
|
return variantKeys[0] || '';
|
|
50
117
|
}),
|
|
51
118
|
_React$useState2 = _slicedToArray(_React$useState, 2),
|
|
52
119
|
selectedVariantKey = _React$useState2[0],
|
|
53
120
|
setSelectedVariantKeyState = _React$useState2[1];
|
|
54
121
|
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
var _React$useState3 = React.useState(false),
|
|
58
|
-
_React$useState4 = _slicedToArray(_React$useState3, 2),
|
|
59
|
-
hasInitialized = _React$useState4[0],
|
|
60
|
-
setHasInitialized = _React$useState4[1];
|
|
122
|
+
// Track selected variant key in a ref for use in effect without causing re-runs
|
|
123
|
+
var selectedVariantKeyRef = React.useRef(selectedVariantKey);
|
|
61
124
|
React.useEffect(function () {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
setHasInitialized(true);
|
|
125
|
+
selectedVariantKeyRef.current = selectedVariantKey;
|
|
126
|
+
});
|
|
66
127
|
|
|
67
|
-
|
|
68
|
-
|
|
128
|
+
// When hash changes and has a variant, override current selection
|
|
129
|
+
// When hash is removed, fall back to localStorage
|
|
130
|
+
React.useEffect(function () {
|
|
131
|
+
// Skip if this was a user-initiated change
|
|
132
|
+
if (isUserInitiatedChange.current) {
|
|
133
|
+
// Only reset the flag once the hash has actually been cleared
|
|
134
|
+
if (hashVariant === null && urlHash === null) {
|
|
135
|
+
isUserInitiatedChange.current = false;
|
|
136
|
+
}
|
|
137
|
+
prevHashVariant.current = hashVariant;
|
|
69
138
|
return;
|
|
70
139
|
}
|
|
71
140
|
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// Sync with localStorage changes (but don't override programmatic changes or when hash is present)
|
|
79
|
-
// Only sync when storedValue changes, not when selectedVariantKey changes
|
|
80
|
-
var prevStoredValue = React.useRef(storedValue);
|
|
81
|
-
React.useEffect(function () {
|
|
82
|
-
// Don't sync from localStorage when a relevant URL hash is present - hash takes absolute priority
|
|
83
|
-
if (hasRelevantUrlHash) {
|
|
141
|
+
// Only apply hash if it actually changed (not just a re-render with same hash)
|
|
142
|
+
var hashChanged = prevHashVariant.current !== hashVariant;
|
|
143
|
+
var storedValueChanged = prevStoredValue.current !== storedValue;
|
|
144
|
+
prevHashVariant.current = hashVariant;
|
|
145
|
+
prevStoredValue.current = storedValue;
|
|
146
|
+
if (!hashChanged && !storedValueChanged) {
|
|
84
147
|
return;
|
|
85
148
|
}
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
149
|
+
if (hashVariant && variantKeys.includes(hashVariant) && hashVariant !== selectedVariantKeyRef.current) {
|
|
150
|
+
// Hash has a variant - use it
|
|
151
|
+
setSelectedVariantKeyState(hashVariant);
|
|
152
|
+
// Save hash variant to localStorage based on configuration
|
|
153
|
+
if (saveHashVariantToLocalStorage === 'on-load' && hashVariant !== storedValue) {
|
|
154
|
+
setStoredValue(hashVariant);
|
|
90
155
|
}
|
|
156
|
+
} else if (!hashVariant && !urlHash &&
|
|
157
|
+
// Only fall back to localStorage when hash is truly empty
|
|
158
|
+
storedValue && variantKeys.includes(storedValue) && storedValue !== selectedVariantKeyRef.current) {
|
|
159
|
+
// Hash is empty but localStorage has a variant - use it
|
|
160
|
+
setSelectedVariantKeyState(storedValue);
|
|
91
161
|
}
|
|
92
|
-
}, [
|
|
162
|
+
}, [hashVariant, urlHash, variantKeys,
|
|
163
|
+
// Note: selectedVariantKey is intentionally NOT in dependencies
|
|
164
|
+
// to avoid effect running when user manually changes variant
|
|
165
|
+
storedValue, setStoredValue, saveHashVariantToLocalStorage]);
|
|
166
|
+
|
|
167
|
+
// Programmatic setter: doesn't save to localStorage (used for hash-driven changes)
|
|
93
168
|
var setSelectedVariantKeyProgrammatic = React.useCallback(function (value) {
|
|
94
169
|
var resolvedValue = typeof value === 'function' ? value(selectedVariantKey) : value;
|
|
95
170
|
if (variantKeys.includes(resolvedValue)) {
|
|
96
|
-
// Only update React state, not localStorage
|
|
97
|
-
// This prevents conflicts with hash-driven navigation
|
|
98
171
|
setSelectedVariantKeyState(resolvedValue);
|
|
99
172
|
}
|
|
100
173
|
}, [selectedVariantKey, variantKeys]);
|
|
174
|
+
|
|
175
|
+
// User setter: saves to localStorage (used for user-initiated changes like dropdown)
|
|
101
176
|
var setSelectedVariantKeyAsUser = React.useCallback(function (value) {
|
|
102
177
|
var resolvedValue = typeof value === 'function' ? value(selectedVariantKey) : value;
|
|
103
178
|
if (variantKeys.includes(resolvedValue)) {
|
|
179
|
+
// Mark as user-initiated to prevent hash effect from overriding
|
|
180
|
+
isUserInitiatedChange.current = true;
|
|
181
|
+
// Clear hash if it exists and is relevant to this demo
|
|
182
|
+
if (urlHash && mainSlug && isHashRelevantToDemo(urlHash, mainSlug)) {
|
|
183
|
+
setUrlHash(null);
|
|
184
|
+
// Update prevHashVariant to reflect that hash is now null
|
|
185
|
+
prevHashVariant.current = null;
|
|
186
|
+
}
|
|
104
187
|
setSelectedVariantKeyState(resolvedValue);
|
|
105
188
|
setStoredValue(resolvedValue);
|
|
106
189
|
}
|
|
107
|
-
}, [setStoredValue, selectedVariantKey, variantKeys]);
|
|
190
|
+
}, [setStoredValue, selectedVariantKey, variantKeys, urlHash, mainSlug, setUrlHash]);
|
|
108
191
|
var selectedVariant = React.useMemo(function () {
|
|
109
192
|
var variant = effectiveCode[selectedVariantKey];
|
|
110
193
|
if (variant && _typeof(variant) === 'object' && 'source' in variant) {
|
|
@@ -116,16 +199,23 @@ export function useVariantSelection(_ref) {
|
|
|
116
199
|
// Safety check: if selectedVariant doesn't exist, fall back to first variant
|
|
117
200
|
React.useEffect(function () {
|
|
118
201
|
if (!selectedVariant && variantKeys.length > 0) {
|
|
119
|
-
// Don't mark this as a user selection - it's just a fallback
|
|
120
|
-
// Use programmatic setter to avoid localStorage save
|
|
121
202
|
setSelectedVariantKeyProgrammatic(variantKeys[0]);
|
|
122
203
|
}
|
|
123
204
|
}, [selectedVariant, variantKeys, setSelectedVariantKeyProgrammatic]);
|
|
205
|
+
|
|
206
|
+
// Function to save variant to localStorage (used for on-interaction mode)
|
|
207
|
+
var saveVariantToLocalStorage = React.useCallback(function (variant) {
|
|
208
|
+
if (saveHashVariantToLocalStorage === 'on-interaction' && variant !== storedValue) {
|
|
209
|
+
setStoredValue(variant);
|
|
210
|
+
}
|
|
211
|
+
}, [saveHashVariantToLocalStorage, storedValue, setStoredValue]);
|
|
124
212
|
return {
|
|
125
213
|
variantKeys: variantKeys,
|
|
126
214
|
selectedVariantKey: selectedVariantKey,
|
|
127
215
|
selectedVariant: selectedVariant,
|
|
128
216
|
selectVariant: setSelectedVariantKeyAsUser,
|
|
129
|
-
selectVariantProgrammatic: setSelectedVariantKeyProgrammatic
|
|
217
|
+
selectVariantProgrammatic: setSelectedVariantKeyProgrammatic,
|
|
218
|
+
saveVariantToLocalStorage: saveVariantToLocalStorage,
|
|
219
|
+
hashVariant: hashVariant
|
|
130
220
|
};
|
|
131
221
|
}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from "./withDocsInfra.js";
|
|
1
|
+
export * from "./withDocsInfra.js";
|
|
2
|
+
export * from "./withDeploymentConfig.js";
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from "./withDocsInfra.js";
|
|
1
|
+
export * from "./withDocsInfra.js";
|
|
2
|
+
export * from "./withDeploymentConfig.js";
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
/**
|
|
4
|
+
* See the docs of the Netlify environment variables:
|
|
5
|
+
* https://docs.netlify.com/configure-builds/environment-variables/#build-metadata.
|
|
6
|
+
*
|
|
7
|
+
* A few comments:
|
|
8
|
+
* - process.env.CONTEXT === 'production' means that the branch in Netlify was configured as production.
|
|
9
|
+
* For example, the `master` branch of the Core team is considered a `production` build on Netlify based
|
|
10
|
+
* on https://app.netlify.com/sites/material-ui/settings/deploys#branches.
|
|
11
|
+
* - Each team has different site https://app.netlify.com/teams/mui/sites.
|
|
12
|
+
* The following logic must be compatible with all of them.
|
|
13
|
+
*/
|
|
14
|
+
var DEPLOY_ENV = 'development';
|
|
15
|
+
|
|
16
|
+
// Same as process.env.PULL_REQUEST_ID
|
|
17
|
+
if (process.env.CONTEXT === 'deploy-preview') {
|
|
18
|
+
DEPLOY_ENV = 'pull-request';
|
|
19
|
+
}
|
|
20
|
+
if (process.env.CONTEXT === 'production' || process.env.CONTEXT === 'branch-deploy') {
|
|
21
|
+
DEPLOY_ENV = 'production';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// The 'master' and 'next' branches are NEVER a production environment. We use these branches for staging.
|
|
25
|
+
if ((process.env.CONTEXT === 'production' || process.env.CONTEXT === 'branch-deploy') && (process.env.HEAD === 'master' || process.env.HEAD === 'next')) {
|
|
26
|
+
DEPLOY_ENV = 'staging';
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* ====================================================================================
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
process.env.DEPLOY_ENV = DEPLOY_ENV;
|
|
33
|
+
export function withDeploymentConfig(nextConfig) {
|
|
34
|
+
return _extends(_extends({
|
|
35
|
+
trailingSlash: true,
|
|
36
|
+
reactStrictMode: true
|
|
37
|
+
}, nextConfig), {}, {
|
|
38
|
+
env: _extends(_extends({
|
|
39
|
+
// production | staging | pull-request | development
|
|
40
|
+
DEPLOY_ENV: DEPLOY_ENV
|
|
41
|
+
}, nextConfig.env), {}, {
|
|
42
|
+
// https://docs.netlify.com/configure-builds/environment-variables/#git-metadata
|
|
43
|
+
// reference ID (also known as "SHA" or "hash") of the commit we're building.
|
|
44
|
+
COMMIT_REF: process.env.COMMIT_REF,
|
|
45
|
+
// ID of the PR and the Deploy Preview it generated (for example, 1211)
|
|
46
|
+
PULL_REQUEST_ID: process.env.REVIEW_ID,
|
|
47
|
+
// This can be set manually in the .env to see the ads in dev mode.
|
|
48
|
+
ENABLE_AD_IN_DEV_MODE: process.env.ENABLE_AD_IN_DEV_MODE,
|
|
49
|
+
// URL representing the unique URL for an individual deploy, e.g.
|
|
50
|
+
// https://5b243e66dd6a547b4fee73ae--petsof.netlify.app
|
|
51
|
+
SITE_DEPLOY_URL: process.env.DEPLOY_URL,
|
|
52
|
+
// Name of the site, its Netlify subdomain; for example, material-ui-docs
|
|
53
|
+
SITE_NAME: process.env.SITE_NAME,
|
|
54
|
+
// For template images
|
|
55
|
+
TEMPLATE_IMAGE_URL: ''
|
|
56
|
+
}),
|
|
57
|
+
experimental: _extends(_extends({
|
|
58
|
+
scrollRestoration: true,
|
|
59
|
+
workerThreads: false
|
|
60
|
+
}, process.env.CI ? {
|
|
61
|
+
cpus: process.env.NEXT_PARALLELISM ? parseInt(process.env.NEXT_PARALLELISM, 10) : os.availableParallelism()
|
|
62
|
+
} : {}), nextConfig.experimental),
|
|
63
|
+
eslint: _extends({
|
|
64
|
+
ignoreDuringBuilds: true
|
|
65
|
+
}, nextConfig.eslint),
|
|
66
|
+
typescript: _extends({
|
|
67
|
+
// Motivated by https://github.com/vercel/next.js/issues/7687
|
|
68
|
+
ignoreBuildErrors: true
|
|
69
|
+
}, nextConfig.typescript)
|
|
70
|
+
});
|
|
71
|
+
}
|
|
@@ -1,18 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
pageExtensions?: string[];
|
|
4
|
-
output?: 'export' | 'standalone' | undefined;
|
|
5
|
-
turbopack?: {
|
|
6
|
-
rules?: Record<string, {
|
|
7
|
-
loaders: {
|
|
8
|
-
loader: string;
|
|
9
|
-
options: Record<string, unknown>;
|
|
10
|
-
}[] | string[];
|
|
11
|
-
}>;
|
|
12
|
-
};
|
|
13
|
-
webpack?: (config: WebpackConfig, options: WebpackOptions) => WebpackConfig;
|
|
14
|
-
[key: string]: any;
|
|
15
|
-
}
|
|
1
|
+
import type { NextConfig } from 'next';
|
|
2
|
+
import type { RuleSetRule } from 'webpack';
|
|
16
3
|
export interface WebpackOptions {
|
|
17
4
|
buildId: string;
|
|
18
5
|
dev: boolean;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
3
3
|
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
|
4
|
-
// Define minimal NextConfig type to avoid importing from 'next'
|
|
5
|
-
|
|
6
4
|
// Define webpack options interface based on Next.js webpack function signature
|
|
7
5
|
|
|
8
6
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mui/internal-docs-infra",
|
|
3
|
-
"version": "0.2.3-canary.
|
|
3
|
+
"version": "0.2.3-canary.11",
|
|
4
4
|
"author": "MUI Team",
|
|
5
5
|
"description": "MUI Infra - internal documentation creation tools.",
|
|
6
6
|
"keywords": [
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"homepage": "https://github.com/mui/mui-public/tree/master/packages/docs-infra",
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@babel/runtime": "^7.28.4",
|
|
25
|
-
"@babel/standalone": "^7.28.
|
|
25
|
+
"@babel/standalone": "^7.28.5",
|
|
26
26
|
"@wooorm/starry-night": "^3.8.0",
|
|
27
27
|
"clipboard-copy": "^4.0.1",
|
|
28
28
|
"fflate": "^0.8.2",
|
|
@@ -45,6 +45,9 @@
|
|
|
45
45
|
"peerDependenciesMeta": {
|
|
46
46
|
"@types/react": {
|
|
47
47
|
"optional": true
|
|
48
|
+
},
|
|
49
|
+
"next": {
|
|
50
|
+
"optional": true
|
|
48
51
|
}
|
|
49
52
|
},
|
|
50
53
|
"publishConfig": {
|
|
@@ -53,7 +56,6 @@
|
|
|
53
56
|
"engines": {
|
|
54
57
|
"node": ">=22.12.0"
|
|
55
58
|
},
|
|
56
|
-
"gitSha": "8ad4cd1aec96d0977bb91fd233e4fd7cd3ebd298",
|
|
57
59
|
"type": "commonjs",
|
|
58
60
|
"exports": {
|
|
59
61
|
"./package.json": "./package.json",
|
|
@@ -226,5 +228,6 @@
|
|
|
226
228
|
}
|
|
227
229
|
},
|
|
228
230
|
"./esm": null
|
|
229
|
-
}
|
|
231
|
+
},
|
|
232
|
+
"gitSha": "fd9d593490ae2b177feb323402b9ba8f86bcf6d1"
|
|
230
233
|
}
|