UNPKG

@mui/internal-docs-infra

Version:

MUI Infra - internal documentation creation tools.

109 lines (106 loc) 4.01 kB
import * as React from 'react'; import { stringOrHastToString } from "../pipeline/hastUtils/index.mjs"; import { useCopier } from "../useCopier/index.mjs"; import { generateVariantMarkdown } from "./generateVariantMarkdown.mjs"; export function collectVariantFiles(selectedVariant, transformedFiles, fallbacks) { if (!selectedVariant) { return []; } // Resolve per-file DEFLATE dictionaries from both places a fallback can // arrive (mirrors `resolvedFallbacks` in `useFileNavigation`): the passed // `fallbacks` (hoisted from a `ContentLoading` component) and the variant's // own per-file `fallback` fields (kept on `Code` when not stripped — e.g. the // standalone `useCode`/`useDemo` path with no `CodeHighlighter` context, so // `context?.fallbacks` is undefined). Without this merge, copy-as-markdown // throws on a `hastCompressed` source whose dictionary lives on the // `VariantCode`. The variant copy wins so the full text — the dictionary // `hastCompressed` needs — is used when a `fallbackCollapsed` block hoisted // only the visible window. const resolvedFallbacks = { ...fallbacks }; if (selectedVariant.fileName && selectedVariant.fallback) { resolvedFallbacks[selectedVariant.fileName] = selectedVariant.fallback; } for (const [name, fileData] of Object.entries(selectedVariant.extraFiles || {})) { if (typeof fileData === 'object' && fileData?.fallback) { resolvedFallbacks[name] = fileData.fallback; } } // When a transform has produced files, prefer them so the copied snippet // matches what the user is currently viewing. Files the transform actually // rewrote are live HAST (already decoded), but files it left untouched are // passed through as their ORIGINAL source, which may still be `hastCompressed` // and needs its dictionary — resolved here by `originalName`. if (transformedFiles && transformedFiles.files.length > 0) { return transformedFiles.files.map(file => ({ name: file.name, source: stringOrHastToString(file.source, resolvedFallbacks[file.originalName]) })); } const files = []; if (selectedVariant.fileName && selectedVariant.source !== undefined) { files.push({ name: selectedVariant.fileName, // `resolvedFallbacks` is the active variant's per-file dictionary map, so // it decodes a `hastCompressed` source in both the hoisted and the // on-`VariantCode` cases. source: stringOrHastToString(selectedVariant.source, resolvedFallbacks[selectedVariant.fileName]) }); } if (selectedVariant.extraFiles) { for (const [name, fileData] of Object.entries(selectedVariant.extraFiles)) { if (typeof fileData === 'string') { files.push({ name, source: fileData }); } else if (fileData && typeof fileData === 'object' && fileData.source !== undefined) { files.push({ name, source: stringOrHastToString(fileData.source, resolvedFallbacks[name]) }); } } } return files; } /** * Hook for managing copy-to-clipboard functionality */ export function useCopyFunctionality({ selectedFile, selectedVariant, transformedFiles, fallbacks, selectedFileFallback, title, copyOpts }) { const sourceFileToText = React.useCallback(() => { if (!selectedFile) { return undefined; } return stringOrHastToString(selectedFile, selectedFileFallback); }, [selectedFile, selectedFileFallback]); const variantToMarkdown = React.useCallback(() => { const files = collectVariantFiles(selectedVariant, transformedFiles, fallbacks); if (files.length === 0) { return undefined; } return generateVariantMarkdown({ title, files }); }, [selectedVariant, transformedFiles, fallbacks, title]); const { copy } = useCopier(sourceFileToText, copyOpts); const { copy: copyMarkdown } = useCopier(variantToMarkdown, copyOpts); return { copy, copyMarkdown }; }