@mui/internal-docs-infra
Version:
MUI Infra - internal documentation creation tools.
925 lines (879 loc) • 38.3 kB
JavaScript
'use client';
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import _typeof from "@babel/runtime/helpers/esm/typeof";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _createForOfIteratorHelper from "@babel/runtime/helpers/esm/createForOfIteratorHelper";
import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import * as React from 'react';
import { useCodeContext } from "../CodeProvider/CodeContext.js";
import { CodeHighlighterContext } from "./CodeHighlighterContext.js";
import { CodeErrorsContext } from "../useErrors/ErrorsContext.js";
import { maybeInitialData } from "./maybeInitialData.js";
import { loadFallbackCode } from "./loadFallbackCode.js";
import { hasAllVariants } from "./hasAllVariants.js";
import { loadVariant } from "./loadVariant.js";
import { CodeHighlighterFallbackContext } from "./CodeHighlighterFallbackContext.js";
import { useControlledCode } from "../CodeControllerContext/index.js";
import { codeToFallbackProps } from "./codeToFallbackProps.js";
import { parseCode } from "./parseCode.js";
import { applyTransforms, getAvailableTransforms } from "./transformCode.js";
import { parseControlledCode } from "./parseControlledCode.js";
import { useOnHydrate } from "../useOnHydrate/index.js";
import { useOnIdle } from "../useOnIdle/index.js";
import { mergeMetadata } from "./mergeMetadata.js";
import { jsx as _jsx } from "react/jsx-runtime";
var DEBUG = false; // Set to true for debugging purposes
function useInitialData(_ref) {
var variants = _ref.variants,
variantName = _ref.variantName,
code = _ref.code,
setCode = _ref.setCode,
fileName = _ref.fileName,
url = _ref.url,
highlightAt = _ref.highlightAt,
fallbackUsesExtraFiles = _ref.fallbackUsesExtraFiles,
fallbackUsesAllVariants = _ref.fallbackUsesAllVariants,
isControlled = _ref.isControlled,
globalsCode = _ref.globalsCode,
setProcessedGlobalsCode = _ref.setProcessedGlobalsCode,
setErrors = _ref.setErrors;
var _useCodeContext = useCodeContext(),
sourceParser = _useCodeContext.sourceParser,
loadCodeMeta = _useCodeContext.loadCodeMeta,
loadVariantMeta = _useCodeContext.loadVariantMeta,
loadSource = _useCodeContext.loadSource;
var _React$useMemo = React.useMemo(function () {
return maybeInitialData(variants, variantName, code, fileName, highlightAt === 'init', fallbackUsesExtraFiles, fallbackUsesAllVariants);
}, [variants, variantName, code, fileName, highlightAt, fallbackUsesExtraFiles, fallbackUsesAllVariants]),
initialData = _React$useMemo.initialData,
reason = _React$useMemo.reason;
// TODO: fallbackInitialRenderOnly option? this would mean we can't fetch fallback data on the client side
// Load initial data if not provided
React.useEffect(function () {
if (initialData || isControlled) {
return;
}
if (!url) {
// URL is required for loading fallback data
var urlError = new Error('URL is required for loading fallback data when no initial code is provided');
console.error('CodeHighlighterClient: URL is required for loading fallback data', urlError);
setErrors(function (prev) {
return [].concat(_toConsumableArray(prev), [urlError]);
});
return;
}
// TODO: abort controller
_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
var loaded;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
if (DEBUG) {
// eslint-disable-next-line no-console
console.log('Loading initial data for CodeHighlighterClient: ', reason);
}
_context.next = 3;
return loadFallbackCode(url, variantName, code, highlightAt === 'init', fallbackUsesExtraFiles, fallbackUsesAllVariants, sourceParser, loadSource, loadVariantMeta, loadCodeMeta, fileName, variants, globalsCode // Let loadFallbackCode handle processing
)["catch"](function (error) {
return {
error: error
};
});
case 3:
loaded = _context.sent;
if ('error' in loaded) {
setErrors(function (prev) {
return [].concat(_toConsumableArray(prev), [loaded.error]);
});
} else {
setCode(loaded.code);
// Store processed globalsCode from loadFallbackCode result
if (loaded.processedGlobalsCode) {
setProcessedGlobalsCode(loaded.processedGlobalsCode);
}
}
case 5:
case "end":
return _context.stop();
}
}, _callee);
}))();
}, [initialData, reason, isControlled, variantName, code, setCode, highlightAt, url, sourceParser, loadSource, loadVariantMeta, loadCodeMeta, fallbackUsesExtraFiles, fallbackUsesAllVariants, fileName, variants, globalsCode, setProcessedGlobalsCode, setErrors]);
}
function useAllVariants(_ref3) {
var readyForContent = _ref3.readyForContent,
variants = _ref3.variants,
isControlled = _ref3.isControlled,
url = _ref3.url,
code = _ref3.code,
setCode = _ref3.setCode,
processedGlobalsCode = _ref3.processedGlobalsCode,
globalsCode = _ref3.globalsCode,
setProcessedGlobalsCode = _ref3.setProcessedGlobalsCode,
setErrors = _ref3.setErrors;
var _useCodeContext2 = useCodeContext(),
loadCodeMeta = _useCodeContext2.loadCodeMeta,
loadVariantMeta = _useCodeContext2.loadVariantMeta,
loadSource = _useCodeContext2.loadSource;
React.useEffect(function () {
if (readyForContent || isControlled) {
return;
}
if (!url) {
// URL is required for loading variants
return;
}
// TODO: abort controller
_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee3() {
var loadedCode, globalsCodeObjects, result, resultCode, errors, _iterator, _step, item;
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
while (1) switch (_context3.prev = _context3.next) {
case 0:
_context3.prev = 0;
loadedCode = code;
if (loadedCode) {
_context3.next = 8;
break;
}
if (loadCodeMeta) {
_context3.next = 5;
break;
}
throw new Error('"loadCodeMeta" function is required when no code is provided');
case 5:
_context3.next = 7;
return loadCodeMeta(url);
case 7:
loadedCode = _context3.sent;
case 8:
// Use the already-processed globalsCode from state, or process it if not available
globalsCodeObjects = [];
if (!processedGlobalsCode) {
_context3.next = 13;
break;
}
// Use the already-processed globalsCode from state
globalsCodeObjects = processedGlobalsCode;
_context3.next = 18;
break;
case 13:
if (!(globalsCode && globalsCode.length > 0)) {
_context3.next = 18;
break;
}
_context3.next = 16;
return Promise.all(globalsCode.map(/*#__PURE__*/function () {
var _ref5 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee2(item) {
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
if (!(typeof item === 'string')) {
_context2.next = 4;
break;
}
if (loadCodeMeta) {
_context2.next = 3;
break;
}
throw new Error('"loadCodeMeta" function is required for string URLs in globalsCode');
case 3:
return _context2.abrupt("return", loadCodeMeta(item));
case 4:
return _context2.abrupt("return", item);
case 5:
case "end":
return _context2.stop();
}
}, _callee2);
}));
return function (_x) {
return _ref5.apply(this, arguments);
};
}()));
case 16:
globalsCodeObjects = _context3.sent;
// Store processed globalsCode in state for future use
setProcessedGlobalsCode(globalsCodeObjects);
case 18:
_context3.next = 20;
return Promise.all(variants.map(function (name) {
// Resolve globalsCode for this specific variant
var globalsForVariant = globalsCodeObjects.map(function (codeObj) {
// Only include if this variant exists in the globalsCode
return codeObj[name];
}).filter(function (item) {
return Boolean(item);
});
return loadVariant(url, name, loadedCode[name], undefined,
// sourceParser - skip parsing
loadSource, loadVariantMeta, undefined,
// sourceTransformers - skip transforming
{
disableParsing: true,
disableTransforms: true,
globalsCode: globalsForVariant
}).then(function (variant) {
return {
name: name,
variant: variant
};
})["catch"](function (error) {
return {
error: error
};
});
}));
case 20:
result = _context3.sent;
resultCode = {};
errors = [];
_iterator = _createForOfIteratorHelper(result);
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
item = _step.value;
if ('error' in item) {
errors.push(item.error);
} else {
resultCode[item.name] = item.variant.code;
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
if (errors.length > 0) {
console.error('CodeHighlighterClient: Failed to load variants', errors);
// Add individual errors for specific error reporting
setErrors(function (prev) {
return [].concat(_toConsumableArray(prev), errors);
});
} else {
setCode(resultCode);
}
_context3.next = 32;
break;
case 28:
_context3.prev = 28;
_context3.t0 = _context3["catch"](0);
console.error('CodeHighlighterClient: Failed to load all variants', _context3.t0);
setErrors(function (prev) {
return [].concat(_toConsumableArray(prev), [_context3.t0 instanceof Error ? _context3.t0 : new Error(String(_context3.t0))]);
});
case 32:
case "end":
return _context3.stop();
}
}, _callee3, null, [[0, 28]]);
}))();
}, [readyForContent, isControlled, variants, url, code, setCode, loadSource, loadVariantMeta, loadCodeMeta, processedGlobalsCode, globalsCode, setProcessedGlobalsCode, setErrors]);
return {
readyForContent: readyForContent
};
}
function useCodeParsing(_ref6) {
var code = _ref6.code,
readyForContent = _ref6.readyForContent,
highlightAt = _ref6.highlightAt;
var _useCodeContext3 = useCodeContext(),
parseSource = _useCodeContext3.parseSource;
// Use timing hooks to determine when to highlight
var isHydrated = useOnHydrate();
var isIdle = useOnIdle();
// Determine if we should highlight based on the highlightAt setting
var shouldHighlight = React.useMemo(function () {
if (!readyForContent) {
return false;
}
switch (highlightAt) {
case 'hydration':
return isHydrated;
case 'idle':
return isIdle;
case 'init':
default:
return true;
}
}, [readyForContent, highlightAt, isHydrated, isIdle]);
// Parse the internal code state when ready and timing conditions are met
var parsedCode = React.useMemo(function () {
if (!code || !shouldHighlight || !parseSource) {
return undefined;
}
return parseCode(code, parseSource);
}, [code, shouldHighlight, parseSource]);
var deferHighlight = !shouldHighlight;
return {
parsedCode: parsedCode,
deferHighlight: deferHighlight
};
}
function useCodeTransforms(_ref7) {
var parsedCode = _ref7.parsedCode,
variantName = _ref7.variantName;
var _useCodeContext4 = useCodeContext(),
sourceParser = _useCodeContext4.sourceParser;
var _React$useState = React.useState(undefined),
_React$useState2 = _slicedToArray(_React$useState, 2),
transformedCode = _React$useState2[0],
setTransformedCode = _React$useState2[1];
// Get available transforms from the current variant (separate memo for efficiency)
var availableTransforms = React.useMemo(function () {
return getAvailableTransforms(parsedCode, variantName);
}, [parsedCode, variantName]);
// Effect to compute transformations for all variants
React.useEffect(function () {
if (!parsedCode || !sourceParser) {
setTransformedCode(parsedCode);
return;
}
// Process transformations for all variants
_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee4() {
var parseSource, enhanced;
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
while (1) switch (_context4.prev = _context4.next) {
case 0:
_context4.prev = 0;
_context4.next = 3;
return sourceParser;
case 3:
parseSource = _context4.sent;
_context4.next = 6;
return applyTransforms(parsedCode, parseSource);
case 6:
enhanced = _context4.sent;
setTransformedCode(enhanced);
_context4.next = 14;
break;
case 10:
_context4.prev = 10;
_context4.t0 = _context4["catch"](0);
console.error('Failed to process transforms:', _context4.t0);
setTransformedCode(parsedCode);
case 14:
case "end":
return _context4.stop();
}
}, _callee4, null, [[0, 10]]);
}))();
}, [parsedCode, sourceParser]);
return {
transformedCode: transformedCode,
availableTransforms: availableTransforms
};
}
function useControlledCodeParsing(_ref9) {
var controlledCode = _ref9.controlledCode;
var _useCodeContext5 = useCodeContext(),
parseSource = _useCodeContext5.parseSource;
// Parse the controlled code separately (no need to check readyForContent)
var parsedControlledCode = React.useMemo(function () {
if (!controlledCode || !parseSource) {
return undefined;
}
return parseControlledCode(controlledCode, parseSource);
}, [controlledCode, parseSource]);
return {
parsedControlledCode: parsedControlledCode
};
}
function useGlobalsCodeMerging(_ref0) {
var code = _ref0.code,
globalsCode = _ref0.globalsCode,
processedGlobalsCode = _ref0.processedGlobalsCode,
setProcessedGlobalsCode = _ref0.setProcessedGlobalsCode,
readyForContent = _ref0.readyForContent,
variants = _ref0.variants;
var _useCodeContext6 = useCodeContext(),
loadCodeMeta = _useCodeContext6.loadCodeMeta,
loadSource = _useCodeContext6.loadSource,
loadVariantMeta = _useCodeContext6.loadVariantMeta;
// Set processedGlobalsCode if we have ready Code objects but haven't stored them yet
React.useEffect(function () {
if (!globalsCode || processedGlobalsCode) {
return; // No globals or already processed
}
// Check if all items are already Code objects (precomputed)
if (globalsCode.every(function (item) {
return _typeof(item) === 'object';
})) {
var codeObjects = globalsCode;
// Check if all Code objects have all their own variants
var allReady = codeObjects.every(function (codeObj) {
return hasAllVariants(Object.keys(codeObj), codeObj);
});
if (allReady) {
setProcessedGlobalsCode(codeObjects);
return;
}
// If not all ready, fall through to loading logic below
}
// Need to load string URLs or load missing variants
_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee8() {
var basicCodeObjects, fullyLoadedCodeObjects;
return _regeneratorRuntime().wrap(function _callee8$(_context8) {
while (1) switch (_context8.prev = _context8.next) {
case 0:
_context8.prev = 0;
_context8.next = 3;
return Promise.all(globalsCode.map(/*#__PURE__*/function () {
var _ref10 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee5(item) {
return _regeneratorRuntime().wrap(function _callee5$(_context5) {
while (1) switch (_context5.prev = _context5.next) {
case 0:
if (!(typeof item === 'string')) {
_context5.next = 8;
break;
}
if (loadCodeMeta) {
_context5.next = 3;
break;
}
throw new Error('"loadCodeMeta" function is required for string URLs in globalsCode');
case 3:
_context5.next = 5;
return loadCodeMeta(item);
case 5:
_context5.t0 = _context5.sent;
_context5.t1 = item;
return _context5.abrupt("return", {
codeObj: _context5.t0,
originalUrl: _context5.t1
});
case 8:
return _context5.abrupt("return", {
codeObj: item,
originalUrl: undefined
});
case 9:
case "end":
return _context5.stop();
}
}, _callee5);
}));
return function (_x2) {
return _ref10.apply(this, arguments);
};
}()));
case 3:
basicCodeObjects = _context8.sent;
_context8.next = 6;
return Promise.all(basicCodeObjects.map(/*#__PURE__*/function () {
var _ref12 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee7(_ref11) {
var codeObj, originalUrl, loadedVariants;
return _regeneratorRuntime().wrap(function _callee7$(_context7) {
while (1) switch (_context7.prev = _context7.next) {
case 0:
codeObj = _ref11.codeObj, originalUrl = _ref11.originalUrl;
if (!hasAllVariants(variants, codeObj)) {
_context7.next = 3;
break;
}
return _context7.abrupt("return", codeObj);
case 3:
// Need to load missing variants
loadedVariants = _objectSpread({}, codeObj);
_context7.next = 6;
return Promise.all(variants.map(/*#__PURE__*/function () {
var _ref13 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee6(variantName) {
var result;
return _regeneratorRuntime().wrap(function _callee6$(_context6) {
while (1) switch (_context6.prev = _context6.next) {
case 0:
if (!(codeObj[variantName] && _typeof(codeObj[variantName]) === 'object')) {
_context6.next = 2;
break;
}
return _context6.abrupt("return");
case 2:
_context6.prev = 2;
_context6.next = 5;
return loadVariant(originalUrl || '',
// Use the original URL if available
variantName, codeObj[variantName],
// May be undefined or string
undefined,
// sourceParser - skip parsing for now
loadSource, loadVariantMeta, undefined,
// sourceTransformers - skip transforming
{
disableParsing: true,
disableTransforms: true
});
case 5:
result = _context6.sent;
loadedVariants[variantName] = result.code;
_context6.next = 12;
break;
case 9:
_context6.prev = 9;
_context6.t0 = _context6["catch"](2);
console.warn("Failed to load variant ".concat(variantName, " for globalsCode:"), _context6.t0);
// Keep the original variant data (may be undefined)
case 12:
case "end":
return _context6.stop();
}
}, _callee6, null, [[2, 9]]);
}));
return function (_x4) {
return _ref13.apply(this, arguments);
};
}()));
case 6:
return _context7.abrupt("return", loadedVariants);
case 7:
case "end":
return _context7.stop();
}
}, _callee7);
}));
return function (_x3) {
return _ref12.apply(this, arguments);
};
}()));
case 6:
fullyLoadedCodeObjects = _context8.sent;
setProcessedGlobalsCode(fullyLoadedCodeObjects);
_context8.next = 13;
break;
case 10:
_context8.prev = 10;
_context8.t0 = _context8["catch"](0);
console.warn('Failed to load globalsCode:', _context8.t0);
case 13:
case "end":
return _context8.stop();
}
}, _callee8, null, [[0, 10]]);
}))();
}, [globalsCode, processedGlobalsCode, setProcessedGlobalsCode, loadCodeMeta, loadSource, loadVariantMeta, variants]);
// Determine globalsCodeObjects to use (prefer processed, fallback to direct if ready)
var globalsCodeObjects = React.useMemo(function () {
if (processedGlobalsCode) {
return processedGlobalsCode;
}
if (globalsCode && globalsCode.every(function (item) {
return _typeof(item) === 'object';
})) {
var codeObjects = globalsCode;
var allGlobalsReady = codeObjects.every(function (codeObj) {
return hasAllVariants(Object.keys(codeObj), codeObj);
});
if (allGlobalsReady) {
return codeObjects;
}
}
return undefined;
}, [processedGlobalsCode, globalsCode]);
// Merge globalsCode with code when ready
return React.useMemo(function () {
// If no globalsCode or code not ready, return as-is
if (!globalsCode || !code || !readyForContent) {
return code;
}
// If globalsCodeObjects isn't ready yet, return unmerged code for now
if (!globalsCodeObjects) {
return code;
}
// For precomputed code, do simple synchronous merging of extraFiles
var mergedCode = _objectSpread({}, code);
var hasChanges = false;
variants.forEach(function (variant) {
var variantData = code[variant];
if (!variantData || typeof variantData === 'string') {
return;
}
// Get globalsCode for this variant (only exact matches, no fallback)
var globalsForVariant = globalsCodeObjects.map(function (codeObj) {
return codeObj[variant];
}).filter(function (item) {
return Boolean(item) && _typeof(item) === 'object';
});
if (globalsForVariant.length > 0) {
// Use mergeMetadata for sophisticated globals merging with proper positioning
var currentVariant = variantData;
globalsForVariant.forEach(function (globalVariant) {
if (globalVariant.extraFiles) {
// Convert globals extraFiles to metadata format for mergeMetadata
var globalsMetadata = {};
for (var _i = 0, _Object$entries = Object.entries(globalVariant.extraFiles); _i < _Object$entries.length; _i++) {
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
key = _Object$entries$_i[0],
value = _Object$entries$_i[1];
if (typeof value === 'string') {
globalsMetadata[key] = {
source: value
};
} else {
globalsMetadata[key] = _objectSpread({}, value);
}
}
// Use mergeMetadata to properly position and merge the globals
currentVariant = mergeMetadata(currentVariant, globalsMetadata);
}
});
// Only update if the variant actually changed
if (currentVariant !== variantData) {
mergedCode[variant] = currentVariant;
hasChanges = true;
}
}
});
// Return merged code if we made changes, otherwise return original code
return hasChanges ? mergedCode : code;
}, [code, globalsCode, globalsCodeObjects, readyForContent, variants]);
}
function usePropsCodeGlobalsMerging(_ref14) {
var code = _ref14.code,
globalsCode = _ref14.globalsCode,
processedGlobalsCode = _ref14.processedGlobalsCode,
variants = _ref14.variants;
// For props.code, always do synchronous merging if possible
// We don't want to cache this in state since props.code can change frequently
return React.useMemo(function () {
if (!code || !globalsCode || !processedGlobalsCode) {
return code; // No merge needed or not ready
}
// Use processedGlobalsCode for synchronous merging
var globalsCodeObjects = processedGlobalsCode;
// For props.code (controlled), do simple synchronous merging
var mergedCode = _objectSpread({}, code);
var hasChanges = false;
variants.forEach(function (variant) {
var variantData = code[variant];
if (!variantData || typeof variantData === 'string') {
return;
}
// Get globalsCode for this variant (only exact matches, no fallback)
var globalsForVariant = globalsCodeObjects.map(function (codeObj) {
return codeObj[variant];
}).filter(function (item) {
return Boolean(item) && _typeof(item) === 'object';
});
if (globalsForVariant.length > 0) {
// Use mergeMetadata for sophisticated globals merging with proper positioning
var currentVariant = variantData;
globalsForVariant.forEach(function (globalVariant) {
if (globalVariant.extraFiles) {
// Convert globals extraFiles to metadata format for mergeMetadata
var globalsMetadata = {};
for (var _i2 = 0, _Object$entries2 = Object.entries(globalVariant.extraFiles); _i2 < _Object$entries2.length; _i2++) {
var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
key = _Object$entries2$_i[0],
value = _Object$entries2$_i[1];
if (typeof value === 'string') {
globalsMetadata[key] = {
source: value
};
} else {
globalsMetadata[key] = _objectSpread({}, value);
}
}
// Use mergeMetadata to properly position and merge the globals
currentVariant = mergeMetadata(currentVariant, globalsMetadata);
}
});
// Only update if the variant actually changed
if (currentVariant !== variantData) {
mergedCode[variant] = currentVariant;
hasChanges = true;
}
}
});
// Return merged code if we made changes, otherwise return original code
return hasChanges ? mergedCode : code;
}, [code, globalsCode, processedGlobalsCode, variants]);
}
export function CodeHighlighterClient(props) {
var _useControlledCode = useControlledCode(),
controlledCode = _useControlledCode.controlledCode,
controlledSelection = _useControlledCode.controlledSelection,
controlledSetCode = _useControlledCode.controlledSetCode,
controlledSetSelection = _useControlledCode.controlledSetSelection,
controlledComponents = _useControlledCode.controlledComponents;
var isControlled = Boolean(props.code || controlledCode);
// TODO: props.code is for controlled components, props.precompute is for precomputed code
// props.code should only be highlighted, but no additional fetching should be done
// this is the case with live demos where the code can be edited by the user
// then maybe props.code shouldn't allow highlighted code, only strings?
// this is a code highlighter afterall, why would they want to control the highlighting aspect?
// TODO: should we empty this state if controlled?
var _React$useState3 = React.useState(_typeof(props.precompute) === 'object' ? props.precompute : undefined),
_React$useState4 = _slicedToArray(_React$useState3, 2),
code = _React$useState4[0],
setCode = _React$useState4[1];
// Sync code state with precompute prop changes (for hot-reload)
React.useEffect(function () {
if (_typeof(props.precompute) === 'object') {
setCode(props.precompute);
} else if (props.precompute === undefined) {
// Only reset to undefined if precompute is explicitly undefined
setCode(undefined);
}
}, [props.precompute]);
// State to store processed globalsCode to avoid duplicate loading
var _React$useState5 = React.useState(undefined),
_React$useState6 = _slicedToArray(_React$useState5, 2),
processedGlobalsCode = _React$useState6[0],
setProcessedGlobalsCode = _React$useState6[1];
// Error state for handling various loading and processing errors
var _React$useState7 = React.useState([]),
_React$useState8 = _slicedToArray(_React$useState7, 2),
errors = _React$useState8[0],
setErrors = _React$useState8[1];
var activeCode = controlledCode || props.code || code;
var variants = React.useMemo(function () {
return props.variants || Object.keys(props.components || activeCode || {});
}, [props.variants, props.components, activeCode]);
// TODO: if using props.variant, then the variant is controlled and we can't use our own state
// does props.variant make any sense instead of controlledSelection?.variant?
var _React$useState9 = React.useState({
variant: props.initialVariant || props.defaultVariant || variants[0]
}),
_React$useState0 = _slicedToArray(_React$useState9, 2),
selection = _React$useState0[0],
setSelection = _React$useState0[1];
var variantName = (controlledSelection == null ? void 0 : controlledSelection.variant) || props.variant || selection.variant;
var initialFilename;
if (_typeof(activeCode == null ? void 0 : activeCode[variantName]) === 'object') {
var variant = activeCode[variantName];
initialFilename = variant != null && variant.filesOrder ? variant.filesOrder[0] : variant == null ? void 0 : variant.fileName;
}
var fileName = (controlledSelection == null ? void 0 : controlledSelection.fileName) || props.fileName || initialFilename;
var url = props.url,
highlightAt = props.highlightAt,
fallbackUsesExtraFiles = props.fallbackUsesExtraFiles,
fallbackUsesAllVariants = props.fallbackUsesAllVariants;
useInitialData({
variants: variants,
variantName: variantName,
code: code,
setCode: setCode,
fileName: fileName,
url: url,
highlightAt: highlightAt,
fallbackUsesExtraFiles: fallbackUsesExtraFiles,
fallbackUsesAllVariants: fallbackUsesAllVariants,
isControlled: isControlled,
globalsCode: props.globalsCode,
setProcessedGlobalsCode: setProcessedGlobalsCode,
setErrors: setErrors
});
var readyForContent = React.useMemo(function () {
if (!code) {
return false;
}
return hasAllVariants(variants, code);
}, [code, variants]);
// Separate check for activeCode to determine when to show fallback
var activeCodeReady = React.useMemo(function () {
if (!activeCode) {
return false;
}
// Controlled code is always ready since it comes from editing already-ready code
if (controlledCode) {
return true;
}
// For regular code, use the existing hasAllVariants function
var regularCode = props.code || code;
return regularCode ? hasAllVariants(variants, regularCode) : false;
}, [activeCode, controlledCode, variants, props.code, code]);
useAllVariants({
readyForContent: readyForContent,
variants: variants,
isControlled: isControlled,
url: url,
code: code,
setCode: setCode,
processedGlobalsCode: processedGlobalsCode,
globalsCode: props.globalsCode,
setProcessedGlobalsCode: setProcessedGlobalsCode,
setErrors: setErrors
});
// Merge globalsCode with internal state code (fetched data) - this should be stable once ready
var stateCodeWithGlobals = useGlobalsCodeMerging({
code: code,
// Only use internal state, not props.code
globalsCode: props.globalsCode,
processedGlobalsCode: processedGlobalsCode,
setProcessedGlobalsCode: setProcessedGlobalsCode,
readyForContent: readyForContent,
variants: variants
});
// For props.code (controlled), always re-merge when it changes (don't cache in state)
var propsCodeWithGlobals = usePropsCodeGlobalsMerging({
code: props.code,
globalsCode: props.globalsCode,
processedGlobalsCode: processedGlobalsCode,
variants: variants
});
// Use props.code result if available, otherwise use state code result
var codeWithGlobals = propsCodeWithGlobals || stateCodeWithGlobals;
var _useCodeParsing = useCodeParsing({
code: codeWithGlobals,
readyForContent: readyForContent || Boolean(props.code),
highlightAt: highlightAt
}),
parsedCode = _useCodeParsing.parsedCode,
deferHighlight = _useCodeParsing.deferHighlight;
var _useCodeTransforms = useCodeTransforms({
parsedCode: parsedCode,
variantName: variantName
}),
transformedCode = _useCodeTransforms.transformedCode,
availableTransforms = _useCodeTransforms.availableTransforms;
var _useControlledCodePar = useControlledCodeParsing({
controlledCode: controlledCode
}),
parsedControlledCode = _useControlledCodePar.parsedControlledCode;
// Determine the final overlaid code (controlled takes precedence)
var overlaidCode = parsedControlledCode || transformedCode || codeWithGlobals;
// For fallback context, use the processed code or fall back to non-controlled code
var codeForFallback = overlaidCode || (controlledCode ? undefined : props.code || code);
var fallbackContext = React.useMemo(function () {
return codeToFallbackProps(variantName, codeForFallback, fileName, props.fallbackUsesExtraFiles, props.fallbackUsesAllVariants);
}, [variantName, codeForFallback, fileName, props.fallbackUsesExtraFiles, props.fallbackUsesAllVariants]);
var context = React.useMemo(function () {
return {
code: overlaidCode,
// Use processed/transformed code
setCode: controlledSetCode,
selection: controlledSelection || selection,
setSelection: controlledSetSelection || setSelection,
components: controlledComponents || props.components,
availableTransforms: isControlled ? [] : availableTransforms,
url: props.url,
deferHighlight: deferHighlight,
setErrors: setErrors
};
}, [overlaidCode, controlledSetCode, selection, controlledSelection, controlledSetSelection, controlledComponents, props.components, isControlled, availableTransforms, props.url, deferHighlight, setErrors]);
if (!props.variants && !props.components && !activeCode) {
throw new Error('CodeHighlighterClient requires either `variants`, `components`, or `code` to be provided.');
}
var errorsContextValue = React.useMemo(function () {
return {
errors: errors
};
}, [errors]);
// If there are errors and an errorHandler, show the errorHandler
if (errors.length > 0 && props.errorHandler) {
return /*#__PURE__*/_jsx(CodeErrorsContext.Provider, {
value: errorsContextValue,
children: props.errorHandler
});
}
var fallback = props.fallback;
if (fallback && !props.skipFallback && !activeCodeReady) {
return /*#__PURE__*/_jsx(CodeHighlighterFallbackContext.Provider, {
value: fallbackContext,
children: fallback
});
}
return /*#__PURE__*/_jsx(CodeHighlighterContext.Provider, {
value: context,
children: props.children
});
}