@burojs/ui-shadcn 0.3.0 → 0.4.0
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/README.md +4 -2
- package/dist/index.cjs +15044 -16998
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3488 -3105
- package/dist/index.d.ts +3488 -3105
- package/dist/index.js +14965 -16860
- package/dist/index.js.map +1 -1
- package/dist/layout/theme-storage-key.cjs +5 -10
- package/dist/layout/theme-storage-key.cjs.map +1 -1
- package/dist/layout/theme-storage-key.d.cts +2 -23
- package/dist/layout/theme-storage-key.d.ts +2 -23
- package/dist/layout/theme-storage-key.js +5 -2
- package/dist/layout/theme-storage-key.js.map +1 -1
- package/dist/markdown/index.cjs +424 -511
- package/dist/markdown/index.cjs.map +1 -1
- package/dist/markdown/index.d.cts +1072 -34
- package/dist/markdown/index.d.ts +1072 -34
- package/dist/markdown/index.js +411 -459
- package/dist/markdown/index.js.map +1 -1
- package/dist/rich-text-IDFvyvRE.js +454 -0
- package/dist/rich-text-IDFvyvRE.js.map +1 -0
- package/dist/rich-text-lndbYqzR.cjs +457 -0
- package/dist/rich-text-lndbYqzR.cjs.map +1 -0
- package/dist/styles.css +14 -8
- package/dist/theme/theme-css.cjs +95 -96
- package/dist/theme/theme-css.cjs.map +1 -1
- package/dist/theme/theme-css.d.cts +10 -8
- package/dist/theme/theme-css.d.ts +10 -8
- package/dist/theme/theme-css.js +94 -94
- package/dist/theme/theme-css.js.map +1 -1
- package/dist/theme/theme-storage.cjs +34 -39
- package/dist/theme/theme-storage.cjs.map +1 -1
- package/dist/theme/theme-storage.d.cts +3 -1
- package/dist/theme/theme-storage.d.ts +3 -1
- package/dist/theme/theme-storage.js +33 -37
- package/dist/theme/theme-storage.js.map +1 -1
- package/dist/theme-storage-key-pYlp4aDS.d.cts +31 -0
- package/dist/theme-storage-key-pYlp4aDS.d.ts +31 -0
- package/dist/use-theme-BwPWinB2.cjs +246 -0
- package/dist/use-theme-BwPWinB2.cjs.map +1 -0
- package/dist/use-theme-IHmtrhEt.js +170 -0
- package/dist/use-theme-IHmtrhEt.js.map +1 -0
- package/package.json +10 -11
- package/dist/chunk-ABUQPOOE.js +0 -11
- package/dist/chunk-ABUQPOOE.js.map +0 -1
- package/dist/chunk-DBGGWBFG.cjs +0 -199
- package/dist/chunk-DBGGWBFG.cjs.map +0 -1
- package/dist/chunk-FMX4GLCQ.js +0 -6
- package/dist/chunk-FMX4GLCQ.js.map +0 -1
- package/dist/chunk-UC57Z243.js +0 -143
- package/dist/chunk-UC57Z243.js.map +0 -1
- package/dist/chunk-UPGPO75B.js +0 -164
- package/dist/chunk-UPGPO75B.js.map +0 -1
- package/dist/chunk-VXJAXJ3U.cjs +0 -8
- package/dist/chunk-VXJAXJ3U.cjs.map +0 -1
- package/dist/chunk-W7AEYE7A.cjs +0 -13
- package/dist/chunk-W7AEYE7A.cjs.map +0 -1
- package/dist/chunk-YF5IW525.cjs +0 -155
- package/dist/chunk-YF5IW525.cjs.map +0 -1
- package/dist/rich-text-6V7WZ3WV.cjs +0 -518
- package/dist/rich-text-6V7WZ3WV.cjs.map +0 -1
- package/dist/rich-text-N2FZEJJV.js +0 -491
- package/dist/rich-text-N2FZEJJV.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/markdown/anchor-link.tsx","../../src/lib/css-color.ts","../../src/markdown/mermaid.tsx","../../src/markdown/sanitize-schema.ts","../../src/markdown/video-directive.ts","../../src/primitives/accordion.tsx","../../src/markdown/faq.tsx","../../src/markdown/index.tsx"],"names":["useOptionalT","useState","useRef","useEffect","useCallback","docShareUrl","jsxs","cn","jsx","IconCheck","LinkIcon","useTheme","defaultSchema","visit","AccordionPrimitive","IconChevronDown","useMemo","docSlug","readDocHash","scrollToDocAnchor","Markdown","remarkGfm","remarkDirective","rehypeSlug","rehypeSanitize","Fragment","DOC_ID_PREFIX"],"mappings":"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","file":"index.cjs","sourcesContent":["'use client';\n\nimport { useOptionalT } from '@burojs/react';\nimport { IconCheck, IconLink as LinkIcon } from '@tabler/icons-react';\nimport { type JSX, type MouseEvent, useCallback, useEffect, useRef, useState } from 'react';\nimport { cn } from '../lib/cn.js';\nimport { docShareUrl } from './anchors.js';\n\nexport interface DocAnchorLinkProps {\n /** Bare slug, without `#`. */\n slug: string;\n /** Stop the click from reaching an enclosing control (the FAQ trigger). */\n stopPropagation?: boolean;\n className?: string;\n}\n\n/**\n * The « # » beside a heading or an FAQ question: BOTH a link and a copy button.\n *\n * It stays an `<a href=\"#slug\">` rather than becoming a `<button>`, and that is\n * not a technicality. An anchor can be middle-clicked, right-clicked →\n * \"copy link address\", dragged into another window, and reached by keyboard as\n * a link; a button can do none of that. Clicking it also still moves the page,\n * which is what the icon looks like it should do.\n *\n * On top of that it copies the ABSOLUTE url — scheme, path, `?area=`, `?topic=`\n * and the fragment — because that is the thing worth pasting. The href cannot\n * be the absolute url: it has to stay a fragment so the browser performs a\n * same-document navigation instead of a reload.\n *\n * Failure is silent BY DESIGN. `navigator.clipboard` is absent outside a secure\n * context and can reject on a permissions policy, and neither is worth an error\n * in front of a reader — the click still navigated, and the address bar now\n * holds the same link they were trying to obtain. The confirmation simply does\n * not appear.\n */\nexport function DocAnchorLink({\n slug,\n stopPropagation,\n className,\n}: DocAnchorLinkProps): JSX.Element {\n const t = useOptionalT();\n const [copied, setCopied] = useState(false);\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // A component can unmount while the confirmation is still showing — an\n // article swap does exactly that — and the timer must not outlive it.\n useEffect(\n () => () => {\n if (timer.current) clearTimeout(timer.current);\n },\n [],\n );\n\n const onClick = useCallback(\n (event: MouseEvent<HTMLAnchorElement>) => {\n // Only the plain left click is ours. Ctrl/Cmd/middle click means \"open\n // elsewhere\", and hijacking those is how a link stops behaving like one.\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;\n if (stopPropagation) event.stopPropagation();\n\n // NOT preventDefault: the fragment navigation is what scrolls the page.\n void navigator.clipboard\n ?.writeText(docShareUrl(slug))\n .then(() => {\n setCopied(true);\n if (timer.current) clearTimeout(timer.current);\n timer.current = setTimeout(() => setCopied(false), 1600);\n })\n .catch(() => {\n /* see the note above — the click still did the useful thing */\n });\n },\n [slug, stopPropagation],\n );\n\n const label = copied\n ? t('docPanel.linkCopied', { defaultValue: 'Link copied' })\n : t('docPanel.copyLink', { defaultValue: 'Copy link to this section' });\n\n return (\n <a\n href={`#${slug}`}\n onClick={onClick}\n title={label}\n aria-label={label}\n data-testid={`doc-anchor:${slug}`}\n data-copied={copied ? 'true' : undefined}\n className={cn(\n 'ml-2 inline-flex shrink-0 items-center rounded-sm p-0.5 align-middle no-underline',\n 'text-muted-foreground transition-opacity hover:text-foreground',\n // Hidden until the reader is at this heading — a permanent « # » beside\n // every heading reads as scaffolding. `focus-visible` keeps it\n // reachable by keyboard, where there is no hover to reveal it.\n 'opacity-0 group-hover/anchor:opacity-100 focus-visible:opacity-100',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring',\n copied && 'text-primary opacity-100',\n className,\n )}\n >\n {copied ? (\n <IconCheck className=\"size-3.5\" aria-hidden=\"true\" />\n ) : (\n <LinkIcon className=\"size-3.5\" aria-hidden=\"true\" />\n )}\n {/*\n The icon swap is invisible to a screen reader, which never saw the\n hover state to begin with. `role=\"status\"` announces the change once,\n politely, without moving focus.\n */}\n <span role=\"status\" className=\"sr-only\">\n {copied ? t('docPanel.linkCopied', { defaultValue: 'Link copied' }) : ''}\n </span>\n </a>\n );\n}\n","/**\n * Converting a theme token to a colour an OLD colour parser can read.\n *\n * The shadcn token contract is `oklch()` — every token in `styles.css`, and\n * every tweakcn theme an adopter drops in, is written that way. That is fine\n * for the browser, and fine for us, right up until a token has to be handed to\n * a third-party library that does its own colour parsing in JS. Mermaid is the\n * one such consumer we have: it bakes colours into the SVG at render time, so\n * it takes them as strings and runs them through `khroma`, which predates CSS\n * Color 4 and throws `Unsupported color format: \"oklch(1 0 0)\"`. Mermaid\n * catches nothing, so a single unreadable token takes the whole diagram down.\n *\n * Why convert here rather than any of the alternatives:\n *\n * - **Not a second set of hex tokens.** A `--mermaid-background` mirror of\n * every colour is a palette that silently drifts from the real one, and it\n * would not cover adopter themes at all.\n * - **Not the browser's own converter.** `getComputedStyle().color` keeps a\n * CSS Color 4 colour in its own space (`oklch(...)` in, `oklch(...)` out),\n * so it converts nothing. A `<canvas>` `fillStyle` round-trip DOES return\n * sRGB hex, but it needs a real 2D context — which jsdom has no\n * implementation of, so the conversion could then only be tested in a\n * browser, not in a unit test.\n * - **Plain maths, in a pure function.** No DOM, testable against known\n * values, and reusable the next time a JS library needs a token.\n */\n\n/** Matches `oklch(L C H)` / `oklch(L C H / A)`, tolerating any whitespace. */\nconst OKLCH = /^oklch\\(\\s*([^\\s/]+)\\s+([^\\s/]+)\\s+([^\\s/]+)\\s*(?:\\/\\s*([^\\s/]+)\\s*)?\\)$/i;\n\n/** Formats khroma already understands — passed through untouched. */\nconst KHROMA_SAFE = /^(#|rgba?\\(|hsla?\\(|[a-z]+$)/i;\n\n/**\n * Parses one oklch component. `none` is CSS Color 4's \"missing component\",\n * which behaves as 0 in every conversion. `pct` is the value a `50%` maps to\n * — 1 for lightness, 0.4 for chroma (the CSS-defined reference), 1 for alpha.\n */\nfunction component(raw: string, pct: number): number | null {\n if (raw.toLowerCase() === 'none') return 0;\n const percent = raw.endsWith('%');\n const n = Number.parseFloat(percent ? raw.slice(0, -1) : raw);\n if (!Number.isFinite(n)) return null;\n return percent ? (n / 100) * pct : n;\n}\n\n/** Parses the hue, which may carry an angle unit. */\nfunction hueDegrees(raw: string): number | null {\n if (raw.toLowerCase() === 'none') return 0;\n const match = /^(-?[\\d.]+)(deg|rad|grad|turn)?$/i.exec(raw);\n if (match === null) return null;\n const n = Number.parseFloat(match[1] as string);\n if (!Number.isFinite(n)) return null;\n switch ((match[2] ?? 'deg').toLowerCase()) {\n case 'rad':\n return (n * 180) / Math.PI;\n case 'grad':\n return n * 0.9;\n case 'turn':\n return n * 360;\n default:\n return n;\n }\n}\n\n/** Linear-light sRGB channel -> gamma-encoded 0-255, clamped into gamut. */\nfunction encode(channel: number): number {\n const v = channel <= 0.0031308 ? 12.92 * channel : 1.055 * channel ** (1 / 2.4) - 0.055;\n return Math.round(Math.min(1, Math.max(0, v)) * 255);\n}\n\nfunction hex2(value: number): string {\n return value.toString(16).padStart(2, '0');\n}\n\n/**\n * Converts an `oklch()` colour to sRGB hex, via Björn Ottosson's OKLab\n * matrices (the same ones the CSS spec publishes).\n *\n * Out-of-gamut colours — a vivid tweakcn accent, say — are clamped per\n * channel. Browsers gamut-MAP instead, which preserves hue slightly better,\n * but the difference only shows on colours sRGB cannot display at all, and a\n * clamped diagram colour beats no diagram.\n *\n * Returns `null` for anything that is not a well-formed `oklch()`.\n */\nexport function oklchToHex(value: string): string | null {\n const match = OKLCH.exec(value.trim());\n if (match === null) return null;\n\n const L = component(match[1] as string, 1);\n const C = component(match[2] as string, 0.4);\n const H = hueDegrees(match[3] as string);\n const A = match[4] === undefined ? 1 : component(match[4], 1);\n if (L === null || C === null || H === null || A === null) return null;\n\n const rad = (H * Math.PI) / 180;\n const a = C * Math.cos(rad);\n const b = C * Math.sin(rad);\n\n const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;\n const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;\n const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;\n\n const r = encode(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s);\n const g = encode(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s);\n const bl = encode(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s);\n\n const alpha = Math.min(1, Math.max(0, A));\n const suffix = alpha === 1 ? '' : hex2(Math.round(alpha * 255));\n return `#${hex2(r)}${hex2(g)}${hex2(bl)}${suffix}`;\n}\n\n/**\n * Normalises a theme token for a JS colour parser that predates CSS Color 4.\n *\n * Returns `null` — rather than the original string — when the value is\n * neither already-safe nor convertible (`lab()`, `color(display-p3 …)`, a\n * relative colour). Handing such a value on unchanged is what breaks mermaid\n * in the first place; the caller is expected to substitute its own fallback so\n * the diagram still renders, in approximately-right colours instead of not at\n * all.\n */\nexport function toLegacyColor(value: string): string | null {\n const trimmed = value.trim();\n if (trimmed === '') return null;\n if (KHROMA_SAFE.test(trimmed)) return trimmed;\n return oklchToHex(trimmed);\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { cn } from '../lib/cn.js';\nimport { toLegacyColor } from '../lib/css-color.js';\nimport { useTheme } from '../layout/use-theme.js';\n\n/**\n * A Mermaid diagram inside a documentation body.\n *\n * THREE things here are deliberate.\n *\n * **1. Mermaid is imported dynamically, inside an effect.** It is ~500 kB\n * gzipped — an order of magnitude more than the markdown renderer that hosts\n * it. The renderer already sits behind `React.lazy` so unified only loads when\n * someone opens an article; this adds a second gate so mermaid only loads when\n * that article actually contains a diagram. An adopter whose docs are all prose\n * never downloads it. It also keeps the package importable under SSR, where\n * mermaid touches `document` at module scope.\n *\n * **2. `securityLevel: 'strict'`.** Mermaid returns an SVG *string*, so it has\n * to reach the DOM through `dangerouslySetInnerHTML` — there is no other API.\n * That would normally hand the mutation-XSS class straight back to us, which\n * the markdown renderer went out of its way to avoid. Strict mode is what makes\n * it safe: mermaid runs its own DOMPurify pass over the output and disables\n * `click` bindings and inline HTML in node labels. It is NOT the default\n * (`'loose'` is), so leaving it unset would be the bug.\n *\n * **3. The theme is re-derived, and the diagram re-rendered, when the app's\n * theme changes.** Mermaid bakes colours into the SVG at render time; a diagram\n * drawn in light mode stays light-on-light forever after a switch to dark.\n * `useTheme()` (packages/ui-shadcn/src/layout/use-theme.ts) supplies the\n * resolved light/dark value and re-renders whenever it flips.\n */\nexport interface MermaidDiagramProps {\n /** Diagram source, verbatim from the fenced block. */\n code: string;\n className?: string;\n}\n\n/**\n * Read a resolved CSS colour off the document, in a form mermaid can parse.\n *\n * `getPropertyValue` returns a custom property's computed value as its literal\n * specified text, unparsed — since the token-contract refactor that text is\n * already a complete colour (`oklch(0.145 0 0)`, not a bare triple), so it is\n * never re-wrapped here. Wrapping it would nest invalidly (`hsl(hsl(...))`),\n * the same bug fixed at the other three call sites that hardcoded the\n * pre-refactor wrapper (data-table.tsx, sidebar.tsx,\n * relation-picker-dialog.tsx) — this one wasn't caught by that sweep because\n * it's assembled at runtime via `getPropertyValue`, not a literal string a\n * `grep \"hsl(var(\"` could find.\n *\n * What it IS re-written through is {@link toLegacyColor}: mermaid parses these\n * strings with khroma, which throws on `oklch()` — the format every shadcn\n * token and every tweakcn theme uses. See that module's docblock. A token that\n * can be neither parsed nor converted falls back to the hardcoded default, so\n * an exotic palette costs a diagram its exact colours, never the diagram.\n */\nfunction cssVar(styles: CSSStyleDeclaration, name: string, fallback: string): string {\n return toLegacyColor(styles.getPropertyValue(name)) ?? fallback;\n}\n\nlet seq = 0;\n\nexport function MermaidDiagram({ code, className }: MermaidDiagramProps): React.ReactElement {\n const [svg, setSvg] = useState<string | null>(null);\n const [failed, setFailed] = useState<string | null>(null);\n const { resolved: theme } = useTheme();\n // A stable id per instance: mermaid uses it for the SVG's internal ids, and\n // reusing one across two diagrams on a page makes their markers collide.\n const idRef = useRef<string | null>(null);\n idRef.current ??= `buro-mermaid-${(seq += 1)}`;\n\n useEffect(() => {\n let cancelled = false;\n\n void (async () => {\n try {\n const mermaid = (await import('mermaid')).default;\n const styles = getComputedStyle(document.documentElement);\n const dark = theme === 'dark';\n\n mermaid.initialize({\n startOnLoad: false,\n securityLevel: 'strict',\n fontFamily: 'inherit',\n theme: 'base',\n darkMode: dark,\n themeVariables: {\n background: cssVar(styles, '--background', dark ? '#0b0b0c' : '#ffffff'),\n primaryColor: cssVar(styles, '--muted', dark ? '#1c1c1f' : '#f4f4f5'),\n primaryTextColor: cssVar(styles, '--foreground', dark ? '#fafafa' : '#09090b'),\n primaryBorderColor: cssVar(styles, '--border', dark ? '#27272a' : '#e4e4e7'),\n lineColor: cssVar(styles, '--muted-foreground', dark ? '#a1a1aa' : '#71717a'),\n secondaryColor: cssVar(styles, '--secondary', dark ? '#18181b' : '#f4f4f5'),\n tertiaryColor: cssVar(styles, '--accent', dark ? '#18181b' : '#fafafa'),\n fontSize: '13px',\n },\n });\n\n // `parse` first: render() on a syntax error leaves an orphaned error\n // block in the document body, which is mermaid's behaviour and not\n // something we can clean up after the fact.\n await mermaid.parse(code);\n const { svg: out } = await mermaid.render(idRef.current as string, code);\n if (!cancelled) {\n setSvg(out);\n setFailed(null);\n }\n } catch (error) {\n if (!cancelled) {\n setSvg(null);\n setFailed(error instanceof Error ? error.message : String(error));\n }\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [code, theme]);\n\n if (failed !== null) {\n /*\n A broken diagram shows its SOURCE, not an error box. The reader of a\n handbook cannot act on \"Parse error on line 3\" — but the source is still\n the information the author meant to convey, and an author previewing their\n own page needs to see that it did not render. The message goes to the\n title attribute rather than the page.\n */\n return (\n <pre\n className={cn('overflow-x-auto rounded-md border border-dashed p-3 text-xs', className)}\n title={failed}\n data-testid=\"mermaid:failed\"\n >\n <code>{code}</code>\n </pre>\n );\n }\n\n if (svg === null) {\n return (\n <div\n className={cn('h-24 animate-pulse rounded-md border bg-muted/40', className)}\n data-testid=\"mermaid:loading\"\n aria-hidden=\"true\"\n />\n );\n }\n\n return (\n <figure\n className={cn(\n 'not-prose my-4 overflow-x-auto rounded-md border bg-card/40 text-card-foreground p-4',\n // Mermaid emits an intrinsic width; letting it scale down keeps a wide\n // graph inside the column instead of pushing the article sideways.\n '[&_svg]:mx-auto [&_svg]:h-auto [&_svg]:max-w-full',\n className,\n )}\n data-testid=\"mermaid:diagram\"\n // See the note above: mermaid's own DOMPurify pass under\n // `securityLevel: 'strict'` is what makes this safe.\n dangerouslySetInnerHTML={{ __html: svg }}\n />\n );\n}\n","import { type Options as SanitizeSchema, defaultSchema } from 'rehype-sanitize';\n\n/**\n * Sanitize schema for documentation bodies.\n *\n * The content is authored by the application's own developers, and that is\n * still not a reason to skip sanitizing: a body can arrive from a translation\n * branch or an external TMS, and — once bodies may be served from a backend —\n * from a database row. This is a threat model, not a hypothetical.\n *\n * Built on `hast-util-sanitize`'s `defaultSchema`, which mirrors GitHub's rules.\n * Two facts about that schema are load-bearing and worth stating rather than\n * rediscovering:\n *\n * - `strip: ['script']` and `protocols.src: ['http', 'https']` already come\n * from the default, so `<script>` and `javascript:` URLs are handled by the\n * schema itself rather than by a check of ours.\n * - `<video>`, `<audio>`, `<iframe>` and `<svg>` are ABSENT from `tagNames`,\n * which is why raw `<video>` in Markdown renders as nothing. We add `video`\n * deliberately, and reach it through a remark DIRECTIVE rather than through\n * `rehype-raw` — the latter costs ~60 kB gzip on its own, more than this\n * entire stack, and hands the whole raw-HTML surface back to the author.\n */\n\n/** Attributes a `::video` directive may set. Enumerated, never spread. */\nconst VIDEO_ATTRIBUTES = [\n 'src',\n 'poster',\n 'controls',\n 'loop',\n 'muted',\n 'autoPlay',\n 'playsInline',\n 'preload',\n 'width',\n 'height',\n] as const;\n\nexport const docSanitizeSchema: SanitizeSchema = {\n ...defaultSchema,\n // `source` and `picture` are ALREADY in defaultSchema — appending them would\n // be a harmless duplicate, but it would also be a sign the list was never\n // actually read.\n tagNames: [...(defaultSchema.tagNames ?? []), 'video'],\n attributes: {\n ...defaultSchema.attributes,\n video: [...VIDEO_ATTRIBUTES],\n // defaultSchema.attributes.source is ['srcSet']. Replacing it outright\n // would silently break <picture>, which the default explicitly supports.\n source: [...(defaultSchema.attributes?.source ?? []), 'src', 'type'],\n // `loading` is in neither `img` nor the `*` bucket, so lazy images need it\n // allowed explicitly or the attribute is stripped and every image in a\n // long article loads at once.\n img: [...(defaultSchema.attributes?.img ?? []), 'loading'],\n },\n};\n","import type { Root } from 'mdast';\nimport { visit } from 'unist-util-visit';\n\n/**\n * remark plugin turning `::video{src=… poster=…}` into a `<video>` node.\n *\n * Why a directive rather than raw HTML in the Markdown: `rehype-raw` costs\n * ~60 kB gzip — more than the rest of this stack combined — and re-opens the\n * entire raw-HTML surface to whoever writes a body. A directive costs ~5 kB and\n * exposes exactly one tag with exactly the attributes listed below.\n *\n * ⚠️ Attributes are copied BY NAME, never spread. A naive\n * `hProperties = { ...node.attributes }` lets the author through with `style`\n * (attacker-controlled CSS: overlay clickjacking, `background: url()`\n * exfiltration), `data-*`, and `srcDoc` — which becomes a real XSS the moment\n * anyone adds `iframe` to the allow-list. The sanitize schema is the second\n * line of defence; this is the first.\n */\n\nconst ALLOWED = ['src', 'poster', 'width', 'height'] as const;\n\ntype DirectiveNode = {\n type: string;\n name?: string;\n attributes?: Record<string, string | null | undefined>;\n data?: { hName?: string; hProperties?: Record<string, unknown> };\n};\n\nexport function remarkVideoDirective() {\n return (tree: Root): void => {\n visit(tree, (node) => {\n const directive = node as unknown as DirectiveNode;\n if (\n directive.type !== 'leafDirective' &&\n directive.type !== 'containerDirective' &&\n directive.type !== 'textDirective'\n ) {\n return;\n }\n if (directive.name !== 'video') return;\n\n const attrs = directive.attributes ?? {};\n const props: Record<string, unknown> = {\n // Always on: a video the reader cannot pause is hostile, and an\n // article that autoplays sound is worse.\n controls: true,\n preload: 'metadata',\n };\n for (const key of ALLOWED) {\n const value = attrs[key];\n if (typeof value === 'string' && value.length > 0) props[key] = value;\n }\n // No src means nothing to render; emitting an empty <video> would leave a\n // black rectangle in the middle of the article.\n if (typeof props.src !== 'string') return;\n\n directive.data = { ...directive.data, hName: 'video', hProperties: props };\n });\n };\n}\n","'use client';\n\nimport * as AccordionPrimitive from '@radix-ui/react-accordion';\nimport { IconChevronDown } from '@tabler/icons-react';\nimport type * as React from 'react';\nimport { cn } from '../lib/cn.js';\n\n/**\n * Accordion, on Radix.\n *\n * Chosen over the `Collapsible` already in this package because a list of\n * questions is a GROUP: Radix gives the header row arrow-key roving focus and\n * the `aria-controls` / `aria-expanded` pairing across items, which a pile of\n * independent collapsibles does not. Callers pass `type=\"multiple\"` for an FAQ —\n * reading one answer should never fold away the one above it.\n */\nconst Accordion = AccordionPrimitive.Root;\n\nfunction AccordionItem({\n className,\n ...props\n}: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>): React.ReactElement {\n return (\n <AccordionPrimitive.Item\n className={cn('border-b border-border/60 last:border-b-0', className)}\n {...props}\n />\n );\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>): React.ReactElement {\n return (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n className={cn(\n 'flex flex-1 items-start justify-between gap-3 py-3 text-left',\n 'text-[0.9375rem] font-medium leading-snug transition-colors',\n 'hover:text-primary focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring',\n 'rounded-sm [&[data-state=open]>svg]:rotate-180',\n className,\n )}\n {...props}\n >\n {children}\n <IconChevronDown\n className=\"mt-0.5 size-4 shrink-0 text-muted-foreground transition-transform duration-200\"\n aria-hidden=\"true\"\n />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n );\n}\n\nfunction AccordionContent({\n className,\n children,\n ...props\n}: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>): React.ReactElement {\n return (\n <AccordionPrimitive.Content\n className={cn(\n 'overflow-hidden',\n 'data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down',\n )}\n {...props}\n >\n <div className={cn('pb-3.5 pt-0', className)}>{children}</div>\n </AccordionPrimitive.Content>\n );\n}\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\n","'use client';\n\nimport { type JSX, useEffect, useMemo, useState } from 'react';\nimport {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from '../primitives/accordion.js';\nimport { cn } from '../lib/cn.js';\nimport { DocAnchorLink } from './anchor-link.js';\nimport { docSlug, readDocHash, scrollToDocAnchor } from './anchors.js';\nimport { DocMarkdown } from './index.js';\n\nexport interface FaqSection {\n /** Heading text, verbatim. */\n question: string;\n /** Everything under the heading, up to the next one. */\n answer: string;\n}\n\nexport interface SplitFaq {\n /** Prose before the first question, if the author wrote any. */\n preamble: string;\n sections: FaqSection[];\n}\n\n/**\n * Split an FAQ body into questions on its second-level headings.\n *\n * A separate function, and exported, because the failure mode is invisible: a\n * `##` inside a fenced block is a code comment in half a dozen languages, and a\n * naive `split(/^## /m)` tears an answer in half at that line and silently\n * promotes the remainder to a new question. Nothing throws — the page just\n * grows a question nobody wrote. Hence the fence tracking, and hence a unit\n * test that feeds it exactly that input.\n *\n * `##` and not `###` or `#`: the level is a convention this project already\n * follows in its FAQ bodies, and picking the shallowest heading present would\n * make an article's structure depend on what it happens to contain.\n */\nexport function splitFaq(markdown: string): SplitFaq {\n const lines = markdown.split('\\n');\n const preamble: string[] = [];\n const sections: FaqSection[] = [];\n let current: { question: string; answer: string[] } | undefined;\n let fence: string | undefined;\n\n for (const line of lines) {\n // ``` or ~~~, three or more, optionally with an info string. A fence closes\n // only on the SAME character it opened with.\n const fenceMatch = /^\\s{0,3}(`{3,}|~{3,})/.exec(line);\n if (fenceMatch?.[1] !== undefined) {\n const marker = fenceMatch[1][0] as string;\n if (fence === undefined) fence = marker;\n else if (fence === marker) fence = undefined;\n }\n\n const heading = fence === undefined ? /^##\\s+(.+?)\\s*$/.exec(line) : null;\n if (heading?.[1] !== undefined) {\n if (current) sections.push({ question: current.question, answer: current.answer.join('\\n') });\n current = { question: heading[1], answer: [] };\n continue;\n }\n\n if (current) current.answer.push(line);\n else preamble.push(line);\n }\n if (current) sections.push({ question: current.question, answer: current.answer.join('\\n') });\n\n return { preamble: preamble.join('\\n').trim(), sections };\n}\n\nexport interface DocFaqProps {\n /** Raw Markdown of an FAQ topic. */\n children: string;\n className?: string;\n}\n\n/**\n * An FAQ body rendered as a list of questions rather than a wall of prose.\n *\n * The whole point of the `faq` kind is that a reader arrives with ONE question\n * and needs to find it. Flowing the answers out full-length puts every other\n * answer between them and it; collapsed, the page becomes the index.\n *\n * `type=\"multiple\"` and no `defaultValue`: opening the second question must not\n * close the first — people compare answers — and starting with one open would\n * imply that question is the important one.\n *\n * A body with no `##` headings falls back to plain prose. That is not an error\n * case: an author is free to write an FAQ as a paragraph, and an accordion of\n * one item holding everything would be strictly worse than not having one.\n */\nexport function DocFaq({ children, className }: DocFaqProps): JSX.Element {\n const { preamble, sections } = splitFaq(children);\n const slugs = useMemo(() => sections.map((s) => docSlug(s.question)), [sections]);\n\n /*\n A question is a linkable thing. `?…#pochemu-knopka-ne-vidna` has to arrive\n at that answer OPEN — a link to a collapsed accordion row is a link to\n something the recipient still has to find.\n\n Controlled rather than `defaultValue`, so a hash arriving after mount (a\n second link pasted into the same tab) also opens its answer. `hashchange`\n is the event for exactly that and costs one listener.\n */\n const [open, setOpen] = useState<string[]>([]);\n useEffect(() => {\n if (typeof window === 'undefined') return;\n const sync = () => {\n // DECODED — `location.hash` is percent-encoded, and every slug here is\n // Cyrillic, so a raw comparison never matches.\n const id = readDocHash();\n if (id === '') return;\n const i = slugs.indexOf(id);\n if (i === -1) return;\n setOpen((prev) => (prev.includes(`q${i}`) ? prev : [...prev, `q${i}`]));\n // The answer expands after this, so the row's position is not final:\n // the settling scroller follows it.\n scrollToDocAnchor(id, document.body);\n };\n sync();\n window.addEventListener('hashchange', sync);\n return () => window.removeEventListener('hashchange', sync);\n }, [slugs]);\n\n if (sections.length === 0) return <DocMarkdown className={className}>{children}</DocMarkdown>;\n\n return (\n <div className={cn('flex flex-col', className)} data-testid=\"doc-faq\">\n {preamble !== '' && <DocMarkdown className=\"mb-2\">{preamble}</DocMarkdown>}\n <Accordion type=\"multiple\" value={open} onValueChange={setOpen} className=\"w-full\">\n {sections.map((s, i) => (\n <AccordionItem\n // Two questions with the same text is an authoring mistake, not a\n // crash: the index keeps the keys unique either way.\n key={`${i}-${s.question}`}\n value={`q${i}`}\n // The anchor. No `user-content-` prefix here: this markup is built\n // by React and never passes through rehype-sanitize, which is what\n // adds that prefix to headings. `findDocAnchor` knows both forms.\n id={slugs[i]}\n className=\"group/anchor scroll-mt-4\"\n data-testid={`doc-faq:item:${i}`}\n >\n <AccordionTrigger>\n <span className=\"min-w-0\">{s.question}</span>\n {/*\n `stopPropagation`: this sits inside the accordion's own trigger,\n so without it copying a link also folds the answer away.\n */}\n <DocAnchorLink slug={slugs[i] as string} stopPropagation className=\"ml-auto mr-1\" />\n </AccordionTrigger>\n <AccordionContent>\n <DocMarkdown className=\"prose-p:my-2 first:prose-p:mt-0 last:prose-p:mb-0\">\n {s.answer}\n </DocMarkdown>\n </AccordionContent>\n </AccordionItem>\n ))}\n </Accordion>\n </div>\n );\n}\n","'use client';\n\nimport type { JSX } from 'react';\nimport Markdown from 'react-markdown';\nimport rehypeSanitize from 'rehype-sanitize';\nimport rehypeSlug from 'rehype-slug';\nimport remarkDirective from 'remark-directive';\nimport remarkGfm from 'remark-gfm';\nimport { cn } from '../lib/cn.js';\nimport { DocAnchorLink } from './anchor-link.js';\nimport { DOC_ID_PREFIX } from './anchors.js';\nimport { MermaidDiagram } from './mermaid.js';\nimport { docSanitizeSchema } from './sanitize-schema.js';\nimport { remarkVideoDirective } from './video-directive.js';\n\nexport interface DocMarkdownProps {\n /** Raw Markdown source. */\n children: string;\n className?: string;\n}\n\n/**\n * Markdown renderer for documentation bodies.\n *\n * Lives behind the `@burojs/ui-shadcn/markdown` subpath and is reached with\n * `React.lazy`, so the ~54 kB gzip of unified/remark/rehype only arrives when a\n * reader actually opens an article. An app that never does pays nothing —\n * that comes from `exports` plus tree-shaking, not from where the packages sit\n * in the manifest.\n *\n * `react-markdown` rather than `marked`/`markdown-it`: those produce an HTML\n * STRING that has to go through `dangerouslySetInnerHTML`, which makes the\n * whole mutation-XSS class ours to defend. This path is\n * markdown → mdast → hast → createElement and never builds a string.\n *\n * Typography comes from `@tailwindcss/typography`. `prose-<theme>` modifiers\n * are avoided deliberately: in Tailwind v4 they override `prose-invert`, and\n * this project will migrate eventually.\n */\nexport function DocMarkdown({ children, className }: DocMarkdownProps): JSX.Element {\n return (\n <div\n className={cn(\n 'prose prose-sm max-w-none dark:prose-invert',\n // The default prose measure is wider than any panel we render into,\n // and its heading rhythm is tuned for a page rather than a column.\n 'prose-headings:scroll-mt-4 prose-headings:font-semibold',\n 'prose-h1:text-base prose-h2:text-[0.9375rem] prose-h3:text-sm',\n 'prose-p:leading-[1.65]',\n 'prose-a:font-medium prose-a:underline-offset-2',\n 'prose-img:rounded-md prose-img:border',\n 'prose-video:rounded-md prose-video:border prose-video:w-full',\n 'prose-table:text-[0.8125rem]',\n className,\n )}\n >\n <Markdown\n remarkPlugins={[remarkGfm, remarkDirective, remarkVideoDirective]}\n /*\n `rehypeSlug` BEFORE the sanitizer, so the ids exist by the time it\n runs — and so they go through it rather than around it.\n\n The sanitizer then renames every id to `user-content-<slug>`: that is\n `defaultSchema.clobberPrefix`, and it is a DOM-clobbering defence, not\n a formality. Without it an article containing `# forms` injects\n `document.forms` as an element into every script on the page. So the\n prefix stays, the URL hash stays clean, and `findDocAnchor()` is the\n single place that knows the two differ.\n */\n rehypePlugins={[rehypeSlug, [rehypeSanitize, docSanitizeSchema]]}\n components={{\n // Every link in a body leaves the app; routing is not involved, so\n // this stays a plain anchor and the package stays router-agnostic.\n a: ({ href, children: kids, ...rest }) => (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\" {...rest}>\n {kids}\n </a>\n ),\n // Long articles should not fetch every illustration up front. The\n // attribute has to be allow-listed in the schema too — it is in\n // neither `img` nor the `*` bucket by default.\n img: ({ ...rest }) => <img loading=\"lazy\" {...rest} alt={rest.alt ?? ''} />,\n // A wide GFM table must scroll inside its own box rather than push\n // the panel — or the page — sideways.\n table: ({ children: kids, ...rest }) => (\n <div className=\"overflow-x-auto\">\n <table {...rest}>{kids}</table>\n </div>\n ),\n /*\n ```mermaid blocks become diagrams; every other fence stays a code\n block. `language-*` on `code` is already allow-listed by\n rehype-sanitize's default schema, so no schema change is owed —\n and the diagram source reaches MermaidDiagram as TEXT, never as\n markup, which is what keeps the sanitized pipeline sanitized.\n */\n code: ({ className: cls, children: kids, ...rest }) => {\n if (/\\blanguage-mermaid\\b/.test(cls ?? '')) {\n return <MermaidDiagram code={String(kids).replace(/\\n$/, '')} />;\n }\n return (\n <code className={cls} {...rest}>\n {kids}\n </code>\n );\n },\n /*\n A heading is a linkable place, and an anchor nobody can see is an\n anchor nobody uses — so each one carries a « # » that appears on\n hover or focus and puts the fragment in the address bar.\n\n The id on the element is `user-content-<slug>` (the sanitizer's\n clobber prefix); the href is the BARE slug, because that is what a\n person pastes and what `findDocAnchor` resolves. Keeping the visible\n link clean is the whole reason those two are allowed to differ.\n */\n h2: ({ children: kids, id, ...rest }) => (\n <HeadingWithAnchor level={2} id={id} {...rest}>\n {kids}\n </HeadingWithAnchor>\n ),\n h3: ({ children: kids, id, ...rest }) => (\n <HeadingWithAnchor level={3} id={id} {...rest}>\n {kids}\n </HeadingWithAnchor>\n ),\n /*\n A mermaid diagram replaces the whole block, so the <pre> that\n react-markdown wraps it in would contribute a stray bordered box\n around the figure.\n */\n pre: ({ children: kids, ...rest }) => {\n const only = Array.isArray(kids) ? kids[0] : kids;\n const cls =\n typeof only === 'object' && only !== null && 'props' in only\n ? ((only as { props?: { className?: string } }).props?.className ?? '')\n : '';\n if (/\\blanguage-mermaid\\b/.test(cls)) return <>{kids}</>;\n return <pre {...rest}>{kids}</pre>;\n },\n }}\n >\n {children}\n </Markdown>\n </div>\n );\n}\n\nexport { docSanitizeSchema } from './sanitize-schema.js';\nexport { remarkVideoDirective } from './video-directive.js';\nexport { MermaidDiagram } from './mermaid.js';\nexport { DocFaq, splitFaq, type FaqSection, type SplitFaq } from './faq.js';\nexport { DocAnchorLink } from './anchor-link.js';\nexport {\n DOC_ID_PREFIX,\n docShareUrl,\n docSlug,\n findDocAnchor,\n readDocHash,\n scrollToDocAnchor,\n} from './anchors.js';\n\n/**\n * A heading that can be linked to.\n *\n * The anchor is hover- and focus-revealed rather than always visible: a\n * documentation page with a permanent « # » beside every heading reads as\n * scaffolding, and the one moment it is wanted is the moment someone is\n * pointing at that heading anyway.\n */\nfunction HeadingWithAnchor({\n level,\n id,\n children,\n ...rest\n}: {\n level: 2 | 3;\n id?: string;\n children?: React.ReactNode;\n} & React.HTMLAttributes<HTMLHeadingElement>): JSX.Element {\n const Tag = level === 2 ? 'h2' : 'h3';\n // Strip the sanitizer's clobber prefix back off for the visible link.\n const slug = id?.startsWith(DOC_ID_PREFIX) ? id.slice(DOC_ID_PREFIX.length) : id;\n return (\n <Tag id={id} className=\"group/anchor scroll-mt-4\" {...rest}>\n {children}\n {slug !== undefined && slug !== '' && <DocAnchorLink slug={slug} />}\n </Tag>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["useOptionalT","useState","useRef","useCallback","docShareUrl","cn","IconCheck","LinkIcon","useState","useTheme","useRef","cn","defaultSchema","AccordionPrimitive","cn","IconChevronDown","useMemo","docSlug","useState","readDocHash","cn","cn","Markdown","remarkGfm","remarkDirective","rehypeSlug","rehypeSanitize","DOC_ID_PREFIX"],"sources":["../../src/markdown/anchor-link.tsx","../../src/lib/css-color.ts","../../src/markdown/mermaid.tsx","../../src/markdown/sanitize-schema.ts","../../src/markdown/video-directive.ts","../../src/primitives/accordion.tsx","../../src/markdown/faq.tsx","../../src/markdown/index.tsx"],"sourcesContent":["'use client';\n\nimport { useOptionalT } from '@burojs/react';\nimport { IconCheck, IconLink as LinkIcon } from '@tabler/icons-react';\nimport { type JSX, type MouseEvent, useCallback, useEffect, useRef, useState } from 'react';\nimport { cn } from '../lib/cn.js';\nimport { docShareUrl } from './anchors.js';\n\nexport interface DocAnchorLinkProps {\n /** Bare slug, without `#`. */\n slug: string;\n /** Stop the click from reaching an enclosing control (the FAQ trigger). */\n stopPropagation?: boolean;\n className?: string;\n}\n\n/**\n * The « # » beside a heading or an FAQ question: BOTH a link and a copy button.\n *\n * It stays an `<a href=\"#slug\">` rather than becoming a `<button>`, and that is\n * not a technicality. An anchor can be middle-clicked, right-clicked →\n * \"copy link address\", dragged into another window, and reached by keyboard as\n * a link; a button can do none of that. Clicking it also still moves the page,\n * which is what the icon looks like it should do.\n *\n * On top of that it copies the ABSOLUTE url — scheme, path, `?area=`, `?topic=`\n * and the fragment — because that is the thing worth pasting. The href cannot\n * be the absolute url: it has to stay a fragment so the browser performs a\n * same-document navigation instead of a reload.\n *\n * Failure is silent BY DESIGN. `navigator.clipboard` is absent outside a secure\n * context and can reject on a permissions policy, and neither is worth an error\n * in front of a reader — the click still navigated, and the address bar now\n * holds the same link they were trying to obtain. The confirmation simply does\n * not appear.\n */\nexport function DocAnchorLink({\n slug,\n stopPropagation,\n className,\n}: DocAnchorLinkProps): JSX.Element {\n const t = useOptionalT();\n const [copied, setCopied] = useState(false);\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // A component can unmount while the confirmation is still showing — an\n // article swap does exactly that — and the timer must not outlive it.\n useEffect(\n () => () => {\n if (timer.current) clearTimeout(timer.current);\n },\n [],\n );\n\n const onClick = useCallback(\n (event: MouseEvent<HTMLAnchorElement>) => {\n // Only the plain left click is ours. Ctrl/Cmd/middle click means \"open\n // elsewhere\", and hijacking those is how a link stops behaving like one.\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;\n if (stopPropagation) event.stopPropagation();\n\n // NOT preventDefault: the fragment navigation is what scrolls the page.\n void navigator.clipboard\n ?.writeText(docShareUrl(slug))\n .then(() => {\n setCopied(true);\n if (timer.current) clearTimeout(timer.current);\n timer.current = setTimeout(() => setCopied(false), 1600);\n })\n .catch(() => {\n /* see the note above — the click still did the useful thing */\n });\n },\n [slug, stopPropagation],\n );\n\n const label = copied\n ? t('docPanel.linkCopied', { defaultValue: 'Link copied' })\n : t('docPanel.copyLink', { defaultValue: 'Copy link to this section' });\n\n return (\n <a\n href={`#${slug}`}\n onClick={onClick}\n title={label}\n aria-label={label}\n data-testid={`doc-anchor:${slug}`}\n data-copied={copied ? 'true' : undefined}\n className={cn(\n 'ml-2 inline-flex shrink-0 items-center rounded-sm p-0.5 align-middle no-underline',\n 'text-muted-foreground transition-opacity hover:text-foreground',\n // Hidden until the reader is at this heading — a permanent « # » beside\n // every heading reads as scaffolding. `focus-visible` keeps it\n // reachable by keyboard, where there is no hover to reveal it.\n 'opacity-0 group-hover/anchor:opacity-100 focus-visible:opacity-100',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring',\n copied && 'text-primary opacity-100',\n className,\n )}\n >\n {copied ? (\n <IconCheck className=\"size-3.5\" aria-hidden=\"true\" />\n ) : (\n <LinkIcon className=\"size-3.5\" aria-hidden=\"true\" />\n )}\n {/*\n The icon swap is invisible to a screen reader, which never saw the\n hover state to begin with. `role=\"status\"` announces the change once,\n politely, without moving focus.\n */}\n <span role=\"status\" className=\"sr-only\">\n {copied ? t('docPanel.linkCopied', { defaultValue: 'Link copied' }) : ''}\n </span>\n </a>\n );\n}\n","/**\n * Converting a theme token to a colour an OLD colour parser can read.\n *\n * The shadcn token contract is `oklch()` — every token in `styles.css`, and\n * every tweakcn theme an adopter drops in, is written that way. That is fine\n * for the browser, and fine for us, right up until a token has to be handed to\n * a third-party library that does its own colour parsing in JS. Mermaid is the\n * one such consumer we have: it bakes colours into the SVG at render time, so\n * it takes them as strings and runs them through `khroma`, which predates CSS\n * Color 4 and throws `Unsupported color format: \"oklch(1 0 0)\"`. Mermaid\n * catches nothing, so a single unreadable token takes the whole diagram down.\n *\n * Why convert here rather than any of the alternatives:\n *\n * - **Not a second set of hex tokens.** A `--mermaid-background` mirror of\n * every colour is a palette that silently drifts from the real one, and it\n * would not cover adopter themes at all.\n * - **Not the browser's own converter.** `getComputedStyle().color` keeps a\n * CSS Color 4 colour in its own space (`oklch(...)` in, `oklch(...)` out),\n * so it converts nothing. A `<canvas>` `fillStyle` round-trip DOES return\n * sRGB hex, but it needs a real 2D context — which jsdom has no\n * implementation of, so the conversion could then only be tested in a\n * browser, not in a unit test.\n * - **Plain maths, in a pure function.** No DOM, testable against known\n * values, and reusable the next time a JS library needs a token.\n */\n\n/** Matches `oklch(L C H)` / `oklch(L C H / A)`, tolerating any whitespace. */\nconst OKLCH = /^oklch\\(\\s*([^\\s/]+)\\s+([^\\s/]+)\\s+([^\\s/]+)\\s*(?:\\/\\s*([^\\s/]+)\\s*)?\\)$/i;\n\n/** Formats khroma already understands — passed through untouched. */\nconst KHROMA_SAFE = /^(#|rgba?\\(|hsla?\\(|[a-z]+$)/i;\n\n/**\n * Parses one oklch component. `none` is CSS Color 4's \"missing component\",\n * which behaves as 0 in every conversion. `pct` is the value a `50%` maps to\n * — 1 for lightness, 0.4 for chroma (the CSS-defined reference), 1 for alpha.\n */\nfunction component(raw: string, pct: number): number | null {\n if (raw.toLowerCase() === 'none') return 0;\n const percent = raw.endsWith('%');\n const n = Number.parseFloat(percent ? raw.slice(0, -1) : raw);\n if (!Number.isFinite(n)) return null;\n return percent ? (n / 100) * pct : n;\n}\n\n/** Parses the hue, which may carry an angle unit. */\nfunction hueDegrees(raw: string): number | null {\n if (raw.toLowerCase() === 'none') return 0;\n const match = /^(-?[\\d.]+)(deg|rad|grad|turn)?$/i.exec(raw);\n if (match === null) return null;\n const n = Number.parseFloat(match[1] as string);\n if (!Number.isFinite(n)) return null;\n switch ((match[2] ?? 'deg').toLowerCase()) {\n case 'rad':\n return (n * 180) / Math.PI;\n case 'grad':\n return n * 0.9;\n case 'turn':\n return n * 360;\n default:\n return n;\n }\n}\n\n/** Linear-light sRGB channel -> gamma-encoded 0-255, clamped into gamut. */\nfunction encode(channel: number): number {\n const v = channel <= 0.0031308 ? 12.92 * channel : 1.055 * channel ** (1 / 2.4) - 0.055;\n return Math.round(Math.min(1, Math.max(0, v)) * 255);\n}\n\nfunction hex2(value: number): string {\n return value.toString(16).padStart(2, '0');\n}\n\n/**\n * Converts an `oklch()` colour to sRGB hex, via Björn Ottosson's OKLab\n * matrices (the same ones the CSS spec publishes).\n *\n * Out-of-gamut colours — a vivid tweakcn accent, say — are clamped per\n * channel. Browsers gamut-MAP instead, which preserves hue slightly better,\n * but the difference only shows on colours sRGB cannot display at all, and a\n * clamped diagram colour beats no diagram.\n *\n * Returns `null` for anything that is not a well-formed `oklch()`.\n */\nexport function oklchToHex(value: string): string | null {\n const match = OKLCH.exec(value.trim());\n if (match === null) return null;\n\n const L = component(match[1] as string, 1);\n const C = component(match[2] as string, 0.4);\n const H = hueDegrees(match[3] as string);\n const A = match[4] === undefined ? 1 : component(match[4], 1);\n if (L === null || C === null || H === null || A === null) return null;\n\n const rad = (H * Math.PI) / 180;\n const a = C * Math.cos(rad);\n const b = C * Math.sin(rad);\n\n const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;\n const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;\n const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;\n\n const r = encode(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s);\n const g = encode(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s);\n const bl = encode(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s);\n\n const alpha = Math.min(1, Math.max(0, A));\n const suffix = alpha === 1 ? '' : hex2(Math.round(alpha * 255));\n return `#${hex2(r)}${hex2(g)}${hex2(bl)}${suffix}`;\n}\n\n/**\n * Normalises a theme token for a JS colour parser that predates CSS Color 4.\n *\n * Returns `null` — rather than the original string — when the value is\n * neither already-safe nor convertible (`lab()`, `color(display-p3 …)`, a\n * relative colour). Handing such a value on unchanged is what breaks mermaid\n * in the first place; the caller is expected to substitute its own fallback so\n * the diagram still renders, in approximately-right colours instead of not at\n * all.\n */\nexport function toLegacyColor(value: string): string | null {\n const trimmed = value.trim();\n if (trimmed === '') return null;\n if (KHROMA_SAFE.test(trimmed)) return trimmed;\n return oklchToHex(trimmed);\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { cn } from '../lib/cn.js';\nimport { toLegacyColor } from '../lib/css-color.js';\nimport { useTheme } from '../layout/use-theme.js';\n\n/**\n * A Mermaid diagram inside a documentation body.\n *\n * THREE things here are deliberate.\n *\n * **1. Mermaid is imported dynamically, inside an effect.** It is ~500 kB\n * gzipped — an order of magnitude more than the markdown renderer that hosts\n * it. The renderer already sits behind `React.lazy` so unified only loads when\n * someone opens an article; this adds a second gate so mermaid only loads when\n * that article actually contains a diagram. An adopter whose docs are all prose\n * never downloads it. It also keeps the package importable under SSR, where\n * mermaid touches `document` at module scope.\n *\n * **2. `securityLevel: 'strict'`.** Mermaid returns an SVG *string*, so it has\n * to reach the DOM through `dangerouslySetInnerHTML` — there is no other API.\n * That would normally hand the mutation-XSS class straight back to us, which\n * the markdown renderer went out of its way to avoid. Strict mode is what makes\n * it safe: mermaid runs its own DOMPurify pass over the output and disables\n * `click` bindings and inline HTML in node labels. It is NOT the default\n * (`'loose'` is), so leaving it unset would be the bug.\n *\n * **3. The theme is re-derived, and the diagram re-rendered, when the app's\n * theme changes.** Mermaid bakes colours into the SVG at render time; a diagram\n * drawn in light mode stays light-on-light forever after a switch to dark.\n * `useTheme()` (packages/ui-shadcn/src/layout/use-theme.ts) supplies the\n * resolved light/dark value and re-renders whenever it flips.\n */\nexport interface MermaidDiagramProps {\n /** Diagram source, verbatim from the fenced block. */\n code: string;\n className?: string;\n}\n\n/**\n * Read a resolved CSS colour off the document, in a form mermaid can parse.\n *\n * `getPropertyValue` returns a custom property's computed value as its literal\n * specified text, unparsed — since the token-contract refactor that text is\n * already a complete colour (`oklch(0.145 0 0)`, not a bare triple), so it is\n * never re-wrapped here. Wrapping it would nest invalidly (`hsl(hsl(...))`),\n * the same bug fixed at the other three call sites that hardcoded the\n * pre-refactor wrapper (data-table.tsx, sidebar.tsx,\n * relation-picker-dialog.tsx) — this one wasn't caught by that sweep because\n * it's assembled at runtime via `getPropertyValue`, not a literal string a\n * `grep \"hsl(var(\"` could find.\n *\n * What it IS re-written through is {@link toLegacyColor}: mermaid parses these\n * strings with khroma, which throws on `oklch()` — the format every shadcn\n * token and every tweakcn theme uses. See that module's docblock. A token that\n * can be neither parsed nor converted falls back to the hardcoded default, so\n * an exotic palette costs a diagram its exact colours, never the diagram.\n */\nfunction cssVar(styles: CSSStyleDeclaration, name: string, fallback: string): string {\n return toLegacyColor(styles.getPropertyValue(name)) ?? fallback;\n}\n\nlet seq = 0;\n\nexport function MermaidDiagram({ code, className }: MermaidDiagramProps): React.ReactElement {\n const [svg, setSvg] = useState<string | null>(null);\n const [failed, setFailed] = useState<string | null>(null);\n const { resolved: theme } = useTheme();\n // A stable id per instance: mermaid uses it for the SVG's internal ids, and\n // reusing one across two diagrams on a page makes their markers collide.\n const idRef = useRef<string | null>(null);\n idRef.current ??= `buro-mermaid-${(seq += 1)}`;\n\n useEffect(() => {\n let cancelled = false;\n\n void (async () => {\n try {\n const mermaid = (await import('mermaid')).default;\n const styles = getComputedStyle(document.documentElement);\n const dark = theme === 'dark';\n\n mermaid.initialize({\n startOnLoad: false,\n securityLevel: 'strict',\n fontFamily: 'inherit',\n theme: 'base',\n darkMode: dark,\n themeVariables: {\n background: cssVar(styles, '--background', dark ? '#0b0b0c' : '#ffffff'),\n primaryColor: cssVar(styles, '--muted', dark ? '#1c1c1f' : '#f4f4f5'),\n primaryTextColor: cssVar(styles, '--foreground', dark ? '#fafafa' : '#09090b'),\n primaryBorderColor: cssVar(styles, '--border', dark ? '#27272a' : '#e4e4e7'),\n lineColor: cssVar(styles, '--muted-foreground', dark ? '#a1a1aa' : '#71717a'),\n secondaryColor: cssVar(styles, '--secondary', dark ? '#18181b' : '#f4f4f5'),\n tertiaryColor: cssVar(styles, '--accent', dark ? '#18181b' : '#fafafa'),\n fontSize: '13px',\n },\n });\n\n // `parse` first: render() on a syntax error leaves an orphaned error\n // block in the document body, which is mermaid's behaviour and not\n // something we can clean up after the fact.\n await mermaid.parse(code);\n const { svg: out } = await mermaid.render(idRef.current as string, code);\n if (!cancelled) {\n setSvg(out);\n setFailed(null);\n }\n } catch (error) {\n if (!cancelled) {\n setSvg(null);\n setFailed(error instanceof Error ? error.message : String(error));\n }\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [code, theme]);\n\n if (failed !== null) {\n /*\n A broken diagram shows its SOURCE, not an error box. The reader of a\n handbook cannot act on \"Parse error on line 3\" — but the source is still\n the information the author meant to convey, and an author previewing their\n own page needs to see that it did not render. The message goes to the\n title attribute rather than the page.\n */\n return (\n <pre\n className={cn('overflow-x-auto rounded-md border border-dashed p-3 text-xs', className)}\n title={failed}\n data-testid=\"mermaid:failed\"\n >\n <code>{code}</code>\n </pre>\n );\n }\n\n if (svg === null) {\n return (\n <div\n className={cn('h-24 animate-pulse rounded-md border bg-muted/40', className)}\n data-testid=\"mermaid:loading\"\n aria-hidden=\"true\"\n />\n );\n }\n\n return (\n <figure\n className={cn(\n 'not-prose my-4 overflow-x-auto rounded-md border bg-card/40 text-card-foreground p-4',\n // Mermaid emits an intrinsic width; letting it scale down keeps a wide\n // graph inside the column instead of pushing the article sideways.\n '[&_svg]:mx-auto [&_svg]:h-auto [&_svg]:max-w-full',\n className,\n )}\n data-testid=\"mermaid:diagram\"\n // See the note above: mermaid's own DOMPurify pass under\n // `securityLevel: 'strict'` is what makes this safe.\n dangerouslySetInnerHTML={{ __html: svg }}\n />\n );\n}\n","import { type Options as SanitizeSchema, defaultSchema } from 'rehype-sanitize';\n\n/**\n * Sanitize schema for documentation bodies.\n *\n * The content is authored by the application's own developers, and that is\n * still not a reason to skip sanitizing: a body can arrive from a translation\n * branch or an external TMS, and — once bodies may be served from a backend —\n * from a database row. This is a threat model, not a hypothetical.\n *\n * Built on `hast-util-sanitize`'s `defaultSchema`, which mirrors GitHub's rules.\n * Two facts about that schema are load-bearing and worth stating rather than\n * rediscovering:\n *\n * - `strip: ['script']` and `protocols.src: ['http', 'https']` already come\n * from the default, so `<script>` and `javascript:` URLs are handled by the\n * schema itself rather than by a check of ours.\n * - `<video>`, `<audio>`, `<iframe>` and `<svg>` are ABSENT from `tagNames`,\n * which is why raw `<video>` in Markdown renders as nothing. We add `video`\n * deliberately, and reach it through a remark DIRECTIVE rather than through\n * `rehype-raw` — the latter costs ~60 kB gzip on its own, more than this\n * entire stack, and hands the whole raw-HTML surface back to the author.\n */\n\n/** Attributes a `::video` directive may set. Enumerated, never spread. */\nconst VIDEO_ATTRIBUTES = [\n 'src',\n 'poster',\n 'controls',\n 'loop',\n 'muted',\n 'autoPlay',\n 'playsInline',\n 'preload',\n 'width',\n 'height',\n] as const;\n\nexport const docSanitizeSchema: SanitizeSchema = {\n ...defaultSchema,\n // `source` and `picture` are ALREADY in defaultSchema — appending them would\n // be a harmless duplicate, but it would also be a sign the list was never\n // actually read.\n tagNames: [...(defaultSchema.tagNames ?? []), 'video'],\n attributes: {\n ...defaultSchema.attributes,\n video: [...VIDEO_ATTRIBUTES],\n // defaultSchema.attributes.source is ['srcSet']. Replacing it outright\n // would silently break <picture>, which the default explicitly supports.\n source: [...(defaultSchema.attributes?.source ?? []), 'src', 'type'],\n // `loading` is in neither `img` nor the `*` bucket, so lazy images need it\n // allowed explicitly or the attribute is stripped and every image in a\n // long article loads at once.\n img: [...(defaultSchema.attributes?.img ?? []), 'loading'],\n },\n};\n","import type { Root } from 'mdast';\nimport { visit } from 'unist-util-visit';\n\n/**\n * remark plugin turning `::video{src=… poster=…}` into a `<video>` node.\n *\n * Why a directive rather than raw HTML in the Markdown: `rehype-raw` costs\n * ~60 kB gzip — more than the rest of this stack combined — and re-opens the\n * entire raw-HTML surface to whoever writes a body. A directive costs ~5 kB and\n * exposes exactly one tag with exactly the attributes listed below.\n *\n * ⚠️ Attributes are copied BY NAME, never spread. A naive\n * `hProperties = { ...node.attributes }` lets the author through with `style`\n * (attacker-controlled CSS: overlay clickjacking, `background: url()`\n * exfiltration), `data-*`, and `srcDoc` — which becomes a real XSS the moment\n * anyone adds `iframe` to the allow-list. The sanitize schema is the second\n * line of defence; this is the first.\n */\n\nconst ALLOWED = ['src', 'poster', 'width', 'height'] as const;\n\ntype DirectiveNode = {\n type: string;\n name?: string;\n attributes?: Record<string, string | null | undefined>;\n data?: { hName?: string; hProperties?: Record<string, unknown> };\n};\n\nexport function remarkVideoDirective() {\n return (tree: Root): void => {\n visit(tree, (node) => {\n const directive = node as unknown as DirectiveNode;\n if (\n directive.type !== 'leafDirective' &&\n directive.type !== 'containerDirective' &&\n directive.type !== 'textDirective'\n ) {\n return;\n }\n if (directive.name !== 'video') return;\n\n const attrs = directive.attributes ?? {};\n const props: Record<string, unknown> = {\n // Always on: a video the reader cannot pause is hostile, and an\n // article that autoplays sound is worse.\n controls: true,\n preload: 'metadata',\n };\n for (const key of ALLOWED) {\n const value = attrs[key];\n if (typeof value === 'string' && value.length > 0) props[key] = value;\n }\n // No src means nothing to render; emitting an empty <video> would leave a\n // black rectangle in the middle of the article.\n if (typeof props.src !== 'string') return;\n\n directive.data = { ...directive.data, hName: 'video', hProperties: props };\n });\n };\n}\n","'use client';\n\nimport * as AccordionPrimitive from '@radix-ui/react-accordion';\nimport { IconChevronDown } from '@tabler/icons-react';\nimport type * as React from 'react';\nimport { cn } from '../lib/cn.js';\n\n/**\n * Accordion, on Radix.\n *\n * Chosen over the `Collapsible` already in this package because a list of\n * questions is a GROUP: Radix gives the header row arrow-key roving focus and\n * the `aria-controls` / `aria-expanded` pairing across items, which a pile of\n * independent collapsibles does not. Callers pass `type=\"multiple\"` for an FAQ —\n * reading one answer should never fold away the one above it.\n */\nconst Accordion = AccordionPrimitive.Root;\n\nfunction AccordionItem({\n className,\n ...props\n}: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>): React.ReactElement {\n return (\n <AccordionPrimitive.Item\n className={cn('border-b border-border/60 last:border-b-0', className)}\n {...props}\n />\n );\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>): React.ReactElement {\n return (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n className={cn(\n 'flex flex-1 items-start justify-between gap-3 py-3 text-left',\n 'text-[0.9375rem] font-medium leading-snug transition-colors',\n 'hover:text-primary focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring',\n 'rounded-sm [&[data-state=open]>svg]:rotate-180',\n className,\n )}\n {...props}\n >\n {children}\n <IconChevronDown\n className=\"mt-0.5 size-4 shrink-0 text-muted-foreground transition-transform duration-200\"\n aria-hidden=\"true\"\n />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n );\n}\n\nfunction AccordionContent({\n className,\n children,\n ...props\n}: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>): React.ReactElement {\n return (\n <AccordionPrimitive.Content\n className={cn(\n 'overflow-hidden',\n 'data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down',\n )}\n {...props}\n >\n <div className={cn('pb-3.5 pt-0', className)}>{children}</div>\n </AccordionPrimitive.Content>\n );\n}\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\n","'use client';\n\nimport { type JSX, useEffect, useMemo, useState } from 'react';\nimport {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from '../primitives/accordion.js';\nimport { cn } from '../lib/cn.js';\nimport { DocAnchorLink } from './anchor-link.js';\nimport { docSlug, readDocHash, scrollToDocAnchor } from './anchors.js';\nimport { DocMarkdown } from './index.js';\n\nexport interface FaqSection {\n /** Heading text, verbatim. */\n question: string;\n /** Everything under the heading, up to the next one. */\n answer: string;\n}\n\nexport interface SplitFaq {\n /** Prose before the first question, if the author wrote any. */\n preamble: string;\n sections: FaqSection[];\n}\n\n/**\n * Split an FAQ body into questions on its second-level headings.\n *\n * A separate function, and exported, because the failure mode is invisible: a\n * `##` inside a fenced block is a code comment in half a dozen languages, and a\n * naive `split(/^## /m)` tears an answer in half at that line and silently\n * promotes the remainder to a new question. Nothing throws — the page just\n * grows a question nobody wrote. Hence the fence tracking, and hence a unit\n * test that feeds it exactly that input.\n *\n * `##` and not `###` or `#`: the level is a convention this project already\n * follows in its FAQ bodies, and picking the shallowest heading present would\n * make an article's structure depend on what it happens to contain.\n */\nexport function splitFaq(markdown: string): SplitFaq {\n const lines = markdown.split('\\n');\n const preamble: string[] = [];\n const sections: FaqSection[] = [];\n let current: { question: string; answer: string[] } | undefined;\n let fence: string | undefined;\n\n for (const line of lines) {\n // ``` or ~~~, three or more, optionally with an info string. A fence closes\n // only on the SAME character it opened with.\n const fenceMatch = /^\\s{0,3}(`{3,}|~{3,})/.exec(line);\n if (fenceMatch?.[1] !== undefined) {\n const marker = fenceMatch[1][0] as string;\n if (fence === undefined) fence = marker;\n else if (fence === marker) fence = undefined;\n }\n\n const heading = fence === undefined ? /^##\\s+(.+?)\\s*$/.exec(line) : null;\n if (heading?.[1] !== undefined) {\n if (current) sections.push({ question: current.question, answer: current.answer.join('\\n') });\n current = { question: heading[1], answer: [] };\n continue;\n }\n\n if (current) current.answer.push(line);\n else preamble.push(line);\n }\n if (current) sections.push({ question: current.question, answer: current.answer.join('\\n') });\n\n return { preamble: preamble.join('\\n').trim(), sections };\n}\n\nexport interface DocFaqProps {\n /** Raw Markdown of an FAQ topic. */\n children: string;\n className?: string;\n}\n\n/**\n * An FAQ body rendered as a list of questions rather than a wall of prose.\n *\n * The whole point of the `faq` kind is that a reader arrives with ONE question\n * and needs to find it. Flowing the answers out full-length puts every other\n * answer between them and it; collapsed, the page becomes the index.\n *\n * `type=\"multiple\"` and no `defaultValue`: opening the second question must not\n * close the first — people compare answers — and starting with one open would\n * imply that question is the important one.\n *\n * A body with no `##` headings falls back to plain prose. That is not an error\n * case: an author is free to write an FAQ as a paragraph, and an accordion of\n * one item holding everything would be strictly worse than not having one.\n */\nexport function DocFaq({ children, className }: DocFaqProps): JSX.Element {\n const { preamble, sections } = splitFaq(children);\n const slugs = useMemo(() => sections.map((s) => docSlug(s.question)), [sections]);\n\n /*\n A question is a linkable thing. `?…#pochemu-knopka-ne-vidna` has to arrive\n at that answer OPEN — a link to a collapsed accordion row is a link to\n something the recipient still has to find.\n\n Controlled rather than `defaultValue`, so a hash arriving after mount (a\n second link pasted into the same tab) also opens its answer. `hashchange`\n is the event for exactly that and costs one listener.\n */\n const [open, setOpen] = useState<string[]>([]);\n useEffect(() => {\n if (typeof window === 'undefined') return;\n const sync = () => {\n // DECODED — `location.hash` is percent-encoded, and every slug here is\n // Cyrillic, so a raw comparison never matches.\n const id = readDocHash();\n if (id === '') return;\n const i = slugs.indexOf(id);\n if (i === -1) return;\n setOpen((prev) => (prev.includes(`q${i}`) ? prev : [...prev, `q${i}`]));\n // The answer expands after this, so the row's position is not final:\n // the settling scroller follows it.\n scrollToDocAnchor(id, document.body);\n };\n sync();\n window.addEventListener('hashchange', sync);\n return () => window.removeEventListener('hashchange', sync);\n }, [slugs]);\n\n if (sections.length === 0) return <DocMarkdown className={className}>{children}</DocMarkdown>;\n\n return (\n <div className={cn('flex flex-col', className)} data-testid=\"doc-faq\">\n {preamble !== '' && <DocMarkdown className=\"mb-2\">{preamble}</DocMarkdown>}\n <Accordion type=\"multiple\" value={open} onValueChange={setOpen} className=\"w-full\">\n {sections.map((s, i) => (\n <AccordionItem\n // Two questions with the same text is an authoring mistake, not a\n // crash: the index keeps the keys unique either way.\n key={`${i}-${s.question}`}\n value={`q${i}`}\n // The anchor. No `user-content-` prefix here: this markup is built\n // by React and never passes through rehype-sanitize, which is what\n // adds that prefix to headings. `findDocAnchor` knows both forms.\n id={slugs[i]}\n className=\"group/anchor scroll-mt-4\"\n data-testid={`doc-faq:item:${i}`}\n >\n <AccordionTrigger>\n <span className=\"min-w-0\">{s.question}</span>\n {/*\n `stopPropagation`: this sits inside the accordion's own trigger,\n so without it copying a link also folds the answer away.\n */}\n <DocAnchorLink slug={slugs[i] as string} stopPropagation className=\"ml-auto mr-1\" />\n </AccordionTrigger>\n <AccordionContent>\n <DocMarkdown className=\"prose-p:my-2 first:prose-p:mt-0 last:prose-p:mb-0\">\n {s.answer}\n </DocMarkdown>\n </AccordionContent>\n </AccordionItem>\n ))}\n </Accordion>\n </div>\n );\n}\n","'use client';\n\nimport type { JSX } from 'react';\nimport Markdown from 'react-markdown';\nimport rehypeSanitize from 'rehype-sanitize';\nimport rehypeSlug from 'rehype-slug';\nimport remarkDirective from 'remark-directive';\nimport remarkGfm from 'remark-gfm';\nimport { cn } from '../lib/cn.js';\nimport { DocAnchorLink } from './anchor-link.js';\nimport { DOC_ID_PREFIX } from './anchors.js';\nimport { MermaidDiagram } from './mermaid.js';\nimport { docSanitizeSchema } from './sanitize-schema.js';\nimport { remarkVideoDirective } from './video-directive.js';\n\nexport interface DocMarkdownProps {\n /** Raw Markdown source. */\n children: string;\n className?: string;\n}\n\n/**\n * Markdown renderer for documentation bodies.\n *\n * Lives behind the `@burojs/ui-shadcn/markdown` subpath and is reached with\n * `React.lazy`, so the ~54 kB gzip of unified/remark/rehype only arrives when a\n * reader actually opens an article. An app that never does pays nothing —\n * that comes from `exports` plus tree-shaking, not from where the packages sit\n * in the manifest.\n *\n * `react-markdown` rather than `marked`/`markdown-it`: those produce an HTML\n * STRING that has to go through `dangerouslySetInnerHTML`, which makes the\n * whole mutation-XSS class ours to defend. This path is\n * markdown → mdast → hast → createElement and never builds a string.\n *\n * Typography comes from `@tailwindcss/typography`. `prose-<theme>` modifiers\n * are avoided deliberately: in Tailwind v4 they override `prose-invert`, and\n * this project will migrate eventually.\n */\nexport function DocMarkdown({ children, className }: DocMarkdownProps): JSX.Element {\n return (\n <div\n className={cn(\n 'prose prose-sm max-w-none dark:prose-invert',\n // The default prose measure is wider than any panel we render into,\n // and its heading rhythm is tuned for a page rather than a column.\n 'prose-headings:scroll-mt-4 prose-headings:font-semibold',\n 'prose-h1:text-base prose-h2:text-[0.9375rem] prose-h3:text-sm',\n 'prose-p:leading-[1.65]',\n 'prose-a:font-medium prose-a:underline-offset-2',\n 'prose-img:rounded-md prose-img:border',\n 'prose-video:rounded-md prose-video:border prose-video:w-full',\n 'prose-table:text-[0.8125rem]',\n className,\n )}\n >\n <Markdown\n remarkPlugins={[remarkGfm, remarkDirective, remarkVideoDirective]}\n /*\n `rehypeSlug` BEFORE the sanitizer, so the ids exist by the time it\n runs — and so they go through it rather than around it.\n\n The sanitizer then renames every id to `user-content-<slug>`: that is\n `defaultSchema.clobberPrefix`, and it is a DOM-clobbering defence, not\n a formality. Without it an article containing `# forms` injects\n `document.forms` as an element into every script on the page. So the\n prefix stays, the URL hash stays clean, and `findDocAnchor()` is the\n single place that knows the two differ.\n */\n rehypePlugins={[rehypeSlug, [rehypeSanitize, docSanitizeSchema]]}\n components={{\n // Every link in a body leaves the app; routing is not involved, so\n // this stays a plain anchor and the package stays router-agnostic.\n a: ({ href, children: kids, ...rest }) => (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\" {...rest}>\n {kids}\n </a>\n ),\n // Long articles should not fetch every illustration up front. The\n // attribute has to be allow-listed in the schema too — it is in\n // neither `img` nor the `*` bucket by default.\n img: ({ ...rest }) => <img loading=\"lazy\" {...rest} alt={rest.alt ?? ''} />,\n // A wide GFM table must scroll inside its own box rather than push\n // the panel — or the page — sideways.\n table: ({ children: kids, ...rest }) => (\n <div className=\"overflow-x-auto\">\n <table {...rest}>{kids}</table>\n </div>\n ),\n /*\n ```mermaid blocks become diagrams; every other fence stays a code\n block. `language-*` on `code` is already allow-listed by\n rehype-sanitize's default schema, so no schema change is owed —\n and the diagram source reaches MermaidDiagram as TEXT, never as\n markup, which is what keeps the sanitized pipeline sanitized.\n */\n code: ({ className: cls, children: kids, ...rest }) => {\n if (/\\blanguage-mermaid\\b/.test(cls ?? '')) {\n return <MermaidDiagram code={String(kids).replace(/\\n$/, '')} />;\n }\n return (\n <code className={cls} {...rest}>\n {kids}\n </code>\n );\n },\n /*\n A heading is a linkable place, and an anchor nobody can see is an\n anchor nobody uses — so each one carries a « # » that appears on\n hover or focus and puts the fragment in the address bar.\n\n The id on the element is `user-content-<slug>` (the sanitizer's\n clobber prefix); the href is the BARE slug, because that is what a\n person pastes and what `findDocAnchor` resolves. Keeping the visible\n link clean is the whole reason those two are allowed to differ.\n */\n h2: ({ children: kids, id, ...rest }) => (\n <HeadingWithAnchor level={2} id={id} {...rest}>\n {kids}\n </HeadingWithAnchor>\n ),\n h3: ({ children: kids, id, ...rest }) => (\n <HeadingWithAnchor level={3} id={id} {...rest}>\n {kids}\n </HeadingWithAnchor>\n ),\n /*\n A mermaid diagram replaces the whole block, so the <pre> that\n react-markdown wraps it in would contribute a stray bordered box\n around the figure.\n */\n pre: ({ children: kids, ...rest }) => {\n const only = Array.isArray(kids) ? kids[0] : kids;\n const cls =\n typeof only === 'object' && only !== null && 'props' in only\n ? ((only as { props?: { className?: string } }).props?.className ?? '')\n : '';\n if (/\\blanguage-mermaid\\b/.test(cls)) return <>{kids}</>;\n return <pre {...rest}>{kids}</pre>;\n },\n }}\n >\n {children}\n </Markdown>\n </div>\n );\n}\n\nexport { docSanitizeSchema } from './sanitize-schema.js';\nexport { remarkVideoDirective } from './video-directive.js';\nexport { MermaidDiagram } from './mermaid.js';\nexport { DocFaq, splitFaq, type FaqSection, type SplitFaq } from './faq.js';\nexport { DocAnchorLink } from './anchor-link.js';\nexport {\n DOC_ID_PREFIX,\n docShareUrl,\n docSlug,\n findDocAnchor,\n readDocHash,\n scrollToDocAnchor,\n} from './anchors.js';\n\n/**\n * A heading that can be linked to.\n *\n * The anchor is hover- and focus-revealed rather than always visible: a\n * documentation page with a permanent « # » beside every heading reads as\n * scaffolding, and the one moment it is wanted is the moment someone is\n * pointing at that heading anyway.\n */\nfunction HeadingWithAnchor({\n level,\n id,\n children,\n ...rest\n}: {\n level: 2 | 3;\n id?: string;\n children?: React.ReactNode;\n} & React.HTMLAttributes<HTMLHeadingElement>): JSX.Element {\n const Tag = level === 2 ? 'h2' : 'h3';\n // Strip the sanitizer's clobber prefix back off for the visible link.\n const slug = id?.startsWith(DOC_ID_PREFIX) ? id.slice(DOC_ID_PREFIX.length) : id;\n return (\n <Tag id={id} className=\"group/anchor scroll-mt-4\" {...rest}>\n {children}\n {slug !== undefined && slug !== '' && <DocAnchorLink slug={slug} />}\n </Tag>\n );\n}\n"],"mappings":"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"}
|