@redocly/theme
Version:
Shared UI components lib
94 lines • 4.58 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.useCodePanel = useCodePanel;
const react_1 = require("react");
const contexts_1 = require("../../../core/contexts");
const hooks_1 = require("../../../core/hooks");
const ACTIVE_FILE_MOCK = {
content: [],
path: '',
basename: '',
metadata: {},
language: '',
};
function useCodePanel(files) {
const { activeStep } = (0, react_1.useContext)(contexts_1.CodeWalkthroughStepsContext);
const { areConditionsMet, populateInputsWithValue } = (0, react_1.useContext)(contexts_1.CodeWalkthroughControlsStateContext);
const { useCodeHighlight } = (0, hooks_1.useThemeHooks)();
const { highlight } = useCodeHighlight();
const findFileIndexByName = (0, react_1.useCallback)((name) => {
return files.findIndex((file) => file.path === name);
}, [files]);
const findFileIndexByStepId = (0, react_1.useCallback)((id) => files.findIndex((file) => file.metadata.steps.includes(id)), [files]);
const activeStepFileIndex = activeStep ? findFileIndexByStepId(activeStep) : 0;
const initialActiveFileIndex = activeStepFileIndex !== -1 ? activeStepFileIndex : 0;
const [activeFileIndex, setActiveFileIndex] = (0, react_1.useState)(initialActiveFileIndex);
(0, react_1.useEffect)(() => {
setActiveFileIndex(initialActiveFileIndex);
}, [initialActiveFileIndex, activeStep, files]);
const handleTabSwitch = (0, react_1.useCallback)((name) => {
const index = findFileIndexByName(name);
if (index !== -1) {
setActiveFileIndex(index);
}
}, [findFileIndexByName]);
const activeFile = files[activeFileIndex] ||
// Fallback to default. Needed when switching from language with more files to a language with less files
files[initialActiveFileIndex] ||
// Final fallback for dev mode when no files were added yet
ACTIVE_FILE_MOCK;
const highlightedCode = (0, react_1.useMemo)(() => {
const { highlightedLines, code, isWholeFileSelected } = getRenderableCode(activeFile, activeStep, areConditionsMet, populateInputsWithValue);
return highlight(code, activeFile.language, {
withLineNumbers: true,
// Shiki transformerMetaHighlight meta to highlight lines
// If the whole file is selected for a step, do not apply highlighting
highlight: isWholeFileSelected ? '' : `{${Array.from(highlightedLines).join(',')}}`,
customTransformer: {
// Add greyed-out class to lines that are not highlighted
line(hast, number) {
if (!highlightedLines.has(number)) {
this.addClassToHast(hast, 'greyed-out');
}
},
},
});
}, [activeFile, activeStep, highlight, areConditionsMet, populateInputsWithValue]);
return { activeFile, handleTabSwitch, highlightedCode };
}
function getRenderableCode(activeFile, activeStep, areConditionsMet, populateInputsWithValue) {
const codeLines = activeFile.content.flatMap((node) => getCodeLinesFromNode(node, activeStep, areConditionsMet, populateInputsWithValue));
const codeLinesContent = [];
const highlightedLines = new Set();
codeLines.forEach(({ lineContent, highlighted }, idx) => {
codeLinesContent.push(lineContent);
if (highlighted) {
highlightedLines.add(idx + 1);
}
});
return {
highlightedLines,
code: codeLinesContent.join('\n'),
isWholeFileSelected: highlightedLines.size === codeLinesContent.length,
};
}
/**
* Convert code node to code line objects with content to render and their highlighted status
*/
function getCodeLinesFromNode(node, activeStep, areConditionsMet, populateInputsWithValue, parentHighlighted = false) {
if (typeof node === 'string') {
const replacedNode = populateInputsWithValue(node);
return [{ lineContent: replacedNode, highlighted: parentHighlighted }];
}
else {
const shouldRenderChunk = areConditionsMet(node.condition);
const isHighlighted = parentHighlighted ||
(activeStep != null &&
node.condition.steps.length > 0 &&
node.condition.steps.includes(activeStep));
return shouldRenderChunk
? node.children.flatMap((child) => getCodeLinesFromNode(child, activeStep, areConditionsMet, populateInputsWithValue, isHighlighted))
: [];
}
}
//# sourceMappingURL=use-code-panel.js.map