UNPKG

@mui/internal-docs-infra

Version:

MUI Infra - internal documentation creation tools.

232 lines 11 kB
import * as React from 'react'; import type { ContentProps, SourceEnhancers } from "../CodeHighlighter/types.mjs"; import { type UseCopierOpts } from "../useCopier/index.mjs"; export type UseCodeOpts = { preClassName?: string; copy?: UseCopierOpts; githubUrlPrefix?: string; initialVariant?: string; initialTransform?: string; /** * Controls hash removal behavior when user interacts with file tabs: * - 'remove-hash': Remove entire hash (default) * - 'remove-filename': Remove only filename, keep variant in hash */ fileHashMode?: 'remove-hash' | 'remove-filename'; /** * Controls when to save hash variant to localStorage: * - 'on-load': Save immediately when page loads with hash * - 'on-interaction': Save only when user clicks a tab (default) * - 'never': Never save hash variant to localStorage */ saveHashVariantToLocalStorage?: 'on-load' | 'on-interaction' | 'never'; /** * Array of enhancer functions to apply to parsed HAST sources. * Enhancers receive the HAST root, comments extracted from source, and filename. * Runs asynchronously when code changes. */ sourceEnhancers?: SourceEnhancers; /** * Disables editing of the code block even when a CodeControllerContext is present. */ disabled?: boolean; /** * Called when the code block is asked to expand its collapsed window — most * importantly from the editor itself, when the caret navigates past the * visible region (e.g. `ArrowUp` at the top of a collapsed block). Fires * synchronously, *before* the expansion re-renders, so a host can capture the * still-collapsed layout and engage a scroll anchor (e.g. `useCodeWindow`'s * `anchorScroll('expand')`) — matching the timing of a click on the expand * toggle. Without this, keyboard-driven expansion would jump the viewport * instead of smoothly anchoring it. */ onExpand?: () => void; /** * Delay in milliseconds between a transform change and the actual swap * of the rendered file tree to the new transform. `selectedTransform` * still updates synchronously so UI controls reflect the change * immediately — whether triggered by a user click in this demo or * received as an external broadcast from a peer demo. While the swap * is pending the rendered `<pre>` element receives a `data-transforming` * attribute so consumer CSS can run an exit animation — most notably * expanding `.collapse` placeholders back to their original height — * before the new tree replaces them. When omitted or `0`, the new * transform commits synchronously (default behavior). */ transformDelay?: number; /** * Delay in milliseconds between a variant change and the actual * swap of the rendered file tree to the new variant. `selectedVariant` * still updates synchronously so UI controls (tabs, dropdowns) * reflect the change immediately — whether triggered by a user * click in this demo or received as an external broadcast from a * peer demo. While the swap is pending the rendered `<pre>` element * receives a `data-transforming` attribute, and `<Pre>` appends a * bridge `<span class="collapse">` to the shorter of the two * variants' rendered tree so consumer CSS can animate between the * two heights before the swap commits. When omitted or `0`, the * new variant commits synchronously (default behavior). */ variantSwapDelay?: number; /** * Controls which transforms are treated as layout-affecting (phase 1, * coordinated barrier) versus non-layout (phase 2, deferred). All * options consult the precomputed `hasCollapse` / * `hasCollapseInFocus` flags on each transform manifest entry — no * tree walking happens at runtime. * * - `'all'` — Phase 1 if *any* file (main or `extraFiles`) in the * selected variant has `hasCollapse: true`. Most conservative; * matches the historical pre-`transformLayoutShift` behavior. * - `'selected'` (default) — Phase 1 only when the currently * rendered file's transform has `hasCollapse: true`. Avoids * coordinating swaps that wouldn't visibly shift the rendered * pre. * - `'focus'` — Like `'selected'`, but while the surrounding code * block is *collapsed* (un-expanded), use `hasCollapseInFocus` * instead of `hasCollapse`. A `.collapse` placeholder outside * the initially-visible region (the lines covered by * `data-frame-type` ∈ `'highlighted' | 'focus' | 'padding-top' | * 'padding-bottom'`) won't trigger the coordinated barrier * because the user can't see the resulting layout shift. Falls * back to `'selected'`-style behavior when expanded. */ transformLayoutShift?: 'all' | 'selected' | 'focus'; /** * When `true`, throws synchronously during render if any transform * on any variant has `hasCollapseInFocus: true` — i.e. its * `.collapse` placeholder lands inside the focus region that is * visible while the surrounding code block is un-expanded. The * thrown error names the offending variant/file/transform so the * demo author can narrow the `@focus` (or `@padding`) markers, or * shrink the transform's edit range, until the placeholder lands * outside the initially-visible window. Pair with * `transformLayoutShift: 'focus'` to guarantee no coordinated * barrier swaps fire while the block is collapsed. */ strictCollapseInFocus?: boolean; /** * Controls which variant swaps are treated as layout-affecting * (phase 1, coordinated barrier) versus non-layout (phase 2, * deferred). The check consults `totalLines` / `focusedLines` * metadata precomputed by the pipeline — no tree walking happens * at runtime. * * - `'all'` — Phase 1 when the sum of `totalLines` across every * file (main + `extraFiles`) differs between the from-variant * and the to-variant. Useful when the rendering surface shows * all files simultaneously. * - `'selected'` (default) — Phase 1 when the currently selected * file's `totalLines` differs between the two variants (or * the file is missing from one side). Avoids coordinating * swaps that wouldn't visibly shift the rendered pre. * - `'focus'` — Like `'selected'`, but while the surrounding * code block is *collapsed* (un-expanded), compare * `focusedLines` (the size of the visible window when * collapsed) instead of `totalLines`. Recommended for demos * that use `@focus` / `@padding` markers to collapse to a * specific region. */ variantLayoutShift?: 'all' | 'selected' | 'focus'; /** * When `true`, throws synchronously during render if any two * variants declare a file with the same name but a different * `focusedLines` count. Pair with `variantLayoutShift: 'focus'` * to guarantee no coordinated barrier swaps fire while the block * is collapsed: when every shared file's focused window matches * across variants, switching variants can never shift the * collapsed pre's height. The thrown error names the offending * variants / file so the demo author can align the * `@focus` / `@padding` markers. */ strictMatchingVariantFocusedLines?: boolean; }; type UserProps<T extends {} = {}> = T & { name?: string; slug?: string; }; export interface UseCodeResult<T extends {} = {}> { variants: string[]; selectedVariant: string; selectVariant: (variant: string | null) => void; files: Array<{ name: string; slug?: string; component: React.ReactNode; }>; selectedFile: React.ReactNode; selectedFileLines: number; selectedFileName: string | undefined; /** * URL of the currently selected file, derived from the selected variant's * `url`, the file's name, and its `relativeUrl` (when set). `undefined` when * the variant has no `url` or the URL cannot be resolved. */ selectedFileUrl: string | undefined; /** * Slug for the currently selected file. Always derived from the canonical * (original) file name — transforms are a view preference and do not * produce separate slugs. Useful for building permalinks (e.g. `#${slug}`) * that survive transform changes. */ selectedFileSlug: string | undefined; selectFileName: (fileName: string) => void; allFilesSlugs: Array<{ fileName: string; slug: string; variantName: string; }>; expanded: boolean; expand: () => void; setExpanded: (expanded: boolean) => void; copy: (event: React.MouseEvent<Element>) => Promise<void>; /** * Copies all files in the current variant to the clipboard as a Markdown * snippet (heading + per-file fenced code blocks). */ copyMarkdown: (event: React.MouseEvent<Element>) => Promise<void>; availableTransforms: string[]; selectedTransform: string | null | undefined; selectTransform: (transformName: string | null) => void; /** * Target of an in-flight transform swap that is still waiting on * slow peers to catch up. `undefined` when no swap is pending or * shortly after one commits. Otherwise mirrors the shape of * `selectedTransform`: `null` for a pending swap back to the * un-transformed original, or the transform name for a pending * swap to that transform. Consumers can check * `pendingTransform !== undefined` to render a generic loading * indicator, or read the value to render something like * `` `Switching to ${pendingTransform ?? 'original'}…` ``. Only * populated on the demo that originated the change — peer demos * receiving the broadcast keep this `undefined` so the indicator * stays anchored to the demo the user interacted with. */ pendingTransform: string | null | undefined; /** * Replace the source of the currently selected file (or `fileName` when * provided) in the controlled code. Internal hooks may pass additional * arguments (caret position, pre-parsed HAST) that are not part of the * public contract. */ setSource?: (source: string, fileName?: string) => void; /** * Clears the entire controlled code state back to `undefined`, discarding * user edits across **all variants and files** owned by the surrounding * `CodeControllerContext` (not just the currently selected file or * variant). Only available when a `CodeControllerContext` with `setCode` * is in scope and editing is not disabled. */ reset?: () => void; /** * Re-fetches the block's data on the client by re-running the full variant * loader, then swaps in the fresh result while keeping the current highlighted * output visible until the new tree lands (stale-while-revalidate). Invalidates * the pre-parsed HAST cache. `undefined` (or a no-op) for a block with no `url` * to re-fetch from, or with no `CodeProvider` in scope. */ refresh?: () => void; userProps: UserProps<T>; } export declare function useCode<T extends {} = {}>(contentProps: ContentProps<T>, opts?: UseCodeOpts): UseCodeResult<T>; export {};