@agent-native/core 0.43.0 → 0.44.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/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +71 -10
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.js +1 -1
- package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +2 -13
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills.d.ts +2 -2
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +13 -13
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +76 -18
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/blocks/index.d.ts +0 -2
- package/dist/client/blocks/index.d.ts.map +1 -1
- package/dist/client/blocks/index.js +0 -2
- package/dist/client/blocks/index.js.map +1 -1
- package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/AnnotatedCodeBlock.js +1 -1
- package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
- package/dist/client/blocks/library/ApiEndpointBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/ApiEndpointBlock.js +1 -1
- package/dist/client/blocks/library/ApiEndpointBlock.js.map +1 -1
- package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/DiffBlock.js +68 -24
- package/dist/client/blocks/library/DiffBlock.js.map +1 -1
- package/dist/client/blocks/library/FileTreeBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/FileTreeBlock.js +4 -0
- package/dist/client/blocks/library/FileTreeBlock.js.map +1 -1
- package/dist/client/blocks/library/annotation-rail.d.ts +0 -19
- package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -1
- package/dist/client/blocks/library/annotation-rail.js +0 -19
- package/dist/client/blocks/library/annotation-rail.js.map +1 -1
- package/dist/client/blocks/library/code-tabs.js +1 -1
- package/dist/client/blocks/library/code-tabs.js.map +1 -1
- package/dist/client/blocks/library/server-specs.d.ts.map +1 -1
- package/dist/client/blocks/library/server-specs.js +0 -10
- package/dist/client/blocks/library/server-specs.js.map +1 -1
- package/dist/client/blocks/library/specs.d.ts.map +1 -1
- package/dist/client/blocks/library/specs.js +0 -2
- package/dist/client/blocks/library/specs.js.map +1 -1
- package/dist/client/blocks/library/wireframe.config.d.ts.map +1 -1
- package/dist/client/blocks/library/wireframe.config.js +19 -2
- package/dist/client/blocks/library/wireframe.config.js.map +1 -1
- package/dist/client/blocks/mdx.d.ts.map +1 -1
- package/dist/client/blocks/mdx.js +11 -0
- package/dist/client/blocks/mdx.js.map +1 -1
- package/dist/client/rich-markdown-editor/DragHandle.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/DragHandle.js +35 -72
- package/dist/client/rich-markdown-editor/DragHandle.js.map +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +9 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js +3 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
- package/dist/client/rich-markdown-editor/extensions.d.ts +13 -1
- package/dist/client/rich-markdown-editor/extensions.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/extensions.js +4 -2
- package/dist/client/rich-markdown-editor/extensions.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +11 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +30 -14
- package/dist/server/poll.js.map +1 -1
- package/dist/styles/blocks.css +10 -2
- package/dist/templates/default/.agents/skills/storing-data/SKILL.md +2 -0
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +141 -0
- package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +2 -0
- package/package.json +1 -1
- package/src/templates/default/.agents/skills/storing-data/SKILL.md +2 -0
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +141 -0
- package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +2 -0
- package/dist/client/blocks/library/decision.config.d.ts +0 -37
- package/dist/client/blocks/library/decision.config.d.ts.map +0 -1
- package/dist/client/blocks/library/decision.config.js +0 -32
- package/dist/client/blocks/library/decision.config.js.map +0 -1
- package/dist/client/blocks/library/decision.d.ts +0 -19
- package/dist/client/blocks/library/decision.d.ts.map +0 -1
- package/dist/client/blocks/library/decision.js +0 -119
- package/dist/client/blocks/library/decision.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileTreeBlock.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/FileTreeBlock.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n IconChevronRight,\n IconFile,\n IconFolder,\n IconFolderOpen,\n IconPlus,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport type { BlockEditProps, BlockReadProps } from \"../types.js\";\nimport type {\n FileTreeChange,\n FileTreeData,\n FileTreeEntry,\n} from \"./file-tree.config.js\";\nimport { FILE_TREE_CHANGES } from \"./file-tree.config.js\";\nimport { DevInput, DevTextarea, DevSelect } from \"./dev-doc-ui.js\";\n\n/**\n * Read + Edit renderers for a `file-tree` block — a VS Code / GitHub-explorer\n * file and change tree. Lives in core so any app can register the dev-doc block\n * (no shadcn import; the editor's enum picker is the core `DevSelect`).\n */\n\n/* ── Theme-aware change tokens ─────────────────────────────────────────────── */\n\n/**\n * Change-badge palette. Tinted background + saturated text in BOTH the `.dark`\n * plan theme and light mode (never a dark-only palette). Each entry keeps legible\n * contrast against the plan surface via Tailwind `dark:` variants.\n */\nconst CHANGE_BADGE: Record<FileTreeChange, string> = {\n added:\n \"bg-emerald-100 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300\",\n modified: \"bg-blue-100 text-blue-700 dark:bg-blue-500/15 dark:text-blue-300\",\n removed: \"bg-red-100 text-red-700 dark:bg-red-500/15 dark:text-red-300\",\n renamed:\n \"bg-violet-100 text-violet-700 dark:bg-violet-500/15 dark:text-violet-300\",\n};\n\n/** Single-letter glyph shown in the change badge (VS Code gutter convention). */\nconst CHANGE_GLYPH: Record<FileTreeChange, string> = {\n added: \"A\",\n modified: \"M\",\n removed: \"D\",\n renamed: \"R\",\n};\n\n/** Accent ink for the file name itself, echoing its change color. */\nconst CHANGE_NAME_INK: Record<FileTreeChange, string> = {\n added: \"text-emerald-700 dark:text-emerald-300\",\n modified: \"text-blue-700 dark:text-blue-300\",\n removed: \"text-red-600 line-through dark:text-red-300\",\n renamed: \"text-violet-700 dark:text-violet-300\",\n};\n\nconst CHANGE_LABEL: Record<FileTreeChange, string> = {\n added: \"Added\",\n modified: \"Modified\",\n removed: \"Removed\",\n renamed: \"Renamed\",\n};\n\n/** Infer a fence language for a file's snippet from its `language` or extension. */\nfunction fenceLanguage(entry: FileTreeEntry): string {\n if (entry.language?.trim()) return entry.language.trim();\n const ext = entry.path.split(\".\").pop()?.toLowerCase() ?? \"\";\n const byExt: Record<string, string> = {\n ts: \"ts\",\n tsx: \"tsx\",\n js: \"js\",\n jsx: \"jsx\",\n mjs: \"js\",\n cjs: \"js\",\n json: \"json\",\n css: \"css\",\n scss: \"scss\",\n html: \"html\",\n md: \"md\",\n mdx: \"md\",\n py: \"python\",\n rb: \"ruby\",\n go: \"go\",\n rs: \"rust\",\n sql: \"sql\",\n sh: \"bash\",\n yml: \"yaml\",\n yaml: \"yaml\",\n toml: \"toml\",\n };\n return byExt[ext] ?? \"text\";\n}\n\n/** Wrap a raw snippet in a fenced code block for `ctx.renderMarkdown`. */\nfunction fence(snippet: string, language: string): string {\n // Never let the snippet's own content break out of the fence.\n const safe = snippet.replace(/```/g, \"ʼʼʼ\");\n return `\\`\\`\\`${language}\\n${safe.replace(/\\s+$/, \"\")}\\n\\`\\`\\``;\n}\n\n/* ── Tree construction (flat paths → nested folders) ───────────────────────── */\n\ninterface FileLeaf {\n kind: \"file\";\n /** Last path segment. */\n name: string;\n /** Full slash path, used as a stable key + anchor. */\n path: string;\n entry: FileTreeEntry;\n /** Index in the original flat `entries` (stable per-file disclosure key). */\n index: number;\n}\n\ninterface FolderNode {\n kind: \"folder\";\n name: string;\n /** Full slash path of the folder, used as a stable key. */\n path: string;\n children: TreeNode[];\n}\n\ntype TreeNode = FolderNode | FileLeaf;\n\ninterface VisibleTreeRow {\n node: TreeNode;\n depth: number;\n}\n\n/** A folder being assembled while we walk the paths (children keyed by name). */\ninterface FolderBuild {\n name: string;\n path: string;\n folders: Map<string, FolderBuild>;\n files: FileLeaf[];\n /** Insertion order of child names (folders + files) for stable rendering. */\n order: string[];\n}\n\nfunction makeFolder(name: string, path: string): FolderBuild {\n return { name, path, folders: new Map(), files: [], order: [] };\n}\n\n/**\n * Build a nested folder tree from the flat `entries`. Folders are derived purely\n * from the slash segments of each `path`; a single-segment path is a root file.\n * Insertion order is preserved within each folder, with folders sorted before\n * files at each level (the conventional explorer ordering).\n */\nfunction buildTree(entries: FileTreeEntry[]): TreeNode[] {\n const root = makeFolder(\"\", \"\");\n\n entries.forEach((entry, index) => {\n const segments = entry.path.split(\"/\").filter(Boolean);\n if (segments.length === 0) return;\n const fileName = segments[segments.length - 1] as string;\n const folderSegments = segments.slice(0, -1);\n\n let cursor = root;\n let prefix = \"\";\n for (const segment of folderSegments) {\n prefix = prefix ? `${prefix}/${segment}` : segment;\n let next = cursor.folders.get(segment);\n if (!next) {\n next = makeFolder(segment, prefix);\n cursor.folders.set(segment, next);\n cursor.order.push(`d:${segment}`);\n }\n cursor = next;\n }\n\n cursor.files.push({\n kind: \"file\",\n name: fileName,\n path: entry.path,\n entry,\n index,\n });\n cursor.order.push(`f:${cursor.files.length - 1}`);\n });\n\n const materialize = (folder: FolderBuild): TreeNode[] => {\n const nodes: TreeNode[] = [];\n for (const key of folder.order) {\n if (key.startsWith(\"d:\")) {\n const child = folder.folders.get(key.slice(2));\n if (!child) continue;\n nodes.push({\n kind: \"folder\",\n name: child.name,\n path: child.path,\n children: materialize(child),\n });\n } else {\n const file = folder.files[Number(key.slice(2))];\n if (file) nodes.push(file);\n }\n }\n // Folders before files at this level (standard explorer ordering).\n return [\n ...nodes.filter((node) => node.kind === \"folder\"),\n ...nodes.filter((node) => node.kind === \"file\"),\n ];\n };\n\n return materialize(root);\n}\n\nfunction compactFolderNode(folder: FolderNode): FolderNode {\n const names = [folder.name];\n let path = folder.path;\n let children = folder.children;\n\n while (children.length === 1 && children[0]?.kind === \"folder\") {\n const child = children[0];\n names.push(child.name);\n path = child.path;\n children = child.children;\n }\n\n return {\n kind: \"folder\",\n name: names.join(\"/\"),\n path,\n children: compactTree(children),\n };\n}\n\nfunction compactTree(nodes: TreeNode[]): TreeNode[] {\n return nodes.map((node) =>\n node.kind === \"folder\" ? compactFolderNode(node) : node,\n );\n}\n\nfunction flattenVisibleRows(\n nodes: TreeNode[],\n collapsedFolders: Record<string, boolean>,\n depth = 0,\n): VisibleTreeRow[] {\n const rows: VisibleTreeRow[] = [];\n\n for (const node of nodes) {\n rows.push({ node, depth });\n if (node.kind === \"folder\" && !(collapsedFolders[node.path] ?? false)) {\n rows.push(\n ...flattenVisibleRows(node.children, collapsedFolders, depth + 1),\n );\n }\n }\n\n return rows;\n}\n\n/* ── Read (IDE explorer) ───────────────────────────────────────────────────── */\n\nconst INDENT_STEP = 14; // px per nesting level — the explorer guide spacing.\nconst DEFAULT_VISIBLE_TREE_ROWS = 10;\n\n/**\n * Read-only renderer for a `file-tree` block — a VS Code / GitHub-explorer file\n * and change tree. The flat `entries` are folded into a nested tree of\n * collapsible folders (IconFolder + chevron) and files (IconFile) carrying a\n * single-letter change badge (A/M/D/R). A file with a `note` or `snippet` is\n * itself clickable and expands to show the note plus the snippet rendered as a\n * fenced code block via `ctx.renderMarkdown`. A summary header tallies the change\n * counts (\"+N · ~M · −K\"). Every color is theme-aware via Tailwind `dark:`\n * variants / plan CSS vars, so the tree reads correctly in both modes.\n */\nexport function FileTreeRead({\n data,\n blockId,\n title,\n summary,\n ctx,\n}: BlockReadProps<FileTreeData>) {\n const entries = data.entries ?? [];\n const tree = useMemo(() => compactTree(buildTree(entries)), [entries]);\n\n // Folders default to fully expanded so the tree is useful at a glance.\n const [collapsedFolders, setCollapsedFolders] = useState<\n Record<string, boolean>\n >({});\n const [showAllRows, setShowAllRows] = useState(false);\n // Files with a note/snippet collapse their detail by default (progressive\n // disclosure) — keyed by the flat entry index so duplicate names never clash.\n const [openFiles, setOpenFiles] = useState<Record<number, boolean>>({});\n\n const toggleFolder = (path: string) =>\n setCollapsedFolders((current) => ({\n ...current,\n [path]: !current[path],\n }));\n const toggleFile = (index: number) =>\n setOpenFiles((current) => ({ ...current, [index]: !current[index] }));\n\n // The recap \"Files touched\" left rail (only) widens into the document as a\n // flyout while the tree is the reader's active focus AND a file's detail is\n // open, then collapses back to a slim rail when they click elsewhere or close\n // the last open file. `data-files-expanded` on the root drives the rail width\n // via CSS (`:has()`); it is inert anywhere the tree renders inline.\n const rootRef = useRef<HTMLElement>(null);\n const [active, setActive] = useState(false);\n const anyFileOpen = useMemo(\n () => Object.values(openFiles).some(Boolean),\n [openFiles],\n );\n const railExpanded = active && anyFileOpen;\n\n useEffect(() => {\n if (!railExpanded) return;\n const onPointerDown = (event: PointerEvent) => {\n const root = rootRef.current;\n if (\n root &&\n event.target instanceof Node &&\n !root.contains(event.target)\n ) {\n setActive(false);\n }\n };\n document.addEventListener(\"pointerdown\", onPointerDown, true);\n return () =>\n document.removeEventListener(\"pointerdown\", onPointerDown, true);\n }, [railExpanded]);\n\n // Change tally for the summary header.\n const counts = useMemo(() => {\n const tally = { added: 0, modified: 0, removed: 0, renamed: 0 };\n for (const entry of entries) {\n if (entry.change) tally[entry.change] += 1;\n }\n return tally;\n }, [entries]);\n const changeTotal =\n counts.added + counts.modified + counts.removed + counts.renamed;\n\n const visibleRows = useMemo(\n () => flattenVisibleRows(tree, collapsedFolders),\n [collapsedFolders, tree],\n );\n const shouldLimitRows = visibleRows.length > DEFAULT_VISIBLE_TREE_ROWS;\n const displayedRows =\n showAllRows || !shouldLimitRows\n ? visibleRows\n : visibleRows.slice(0, DEFAULT_VISIBLE_TREE_ROWS);\n\n const renderRow = ({ node, depth }: VisibleTreeRow): React.ReactNode => {\n const indent = depth * INDENT_STEP;\n if (node.kind === \"folder\") {\n const collapsed = collapsedFolders[node.path] ?? false;\n return (\n <div key={`d:${node.path}`}>\n <button\n type=\"button\"\n data-plan-interactive\n aria-expanded={!collapsed}\n onClick={() => toggleFolder(node.path)}\n style={{ paddingLeft: indent + 8 }}\n className=\"flex w-full items-center gap-1.5 rounded-md py-1 pr-2 text-left text-[13px] transition-colors hover:bg-accent/40\"\n >\n <IconChevronRight\n className={cn(\n \"size-3.5 shrink-0 text-plan-muted transition-transform\",\n !collapsed && \"rotate-90\",\n )}\n />\n {collapsed ? (\n <IconFolder className=\"size-4 shrink-0 text-plan-muted\" />\n ) : (\n <IconFolderOpen className=\"size-4 shrink-0 text-plan-muted\" />\n )}\n <span className=\"min-w-0 truncate font-medium text-plan-text\">\n {node.name}\n </span>\n </button>\n </div>\n );\n }\n\n const { entry } = node;\n const change = entry.change;\n const hasDetail = Boolean(entry.note?.trim() || entry.snippet?.trim());\n const isOpen = openFiles[node.index] ?? false;\n\n return (\n <div key={`f:${node.index}`}>\n <button\n type=\"button\"\n data-plan-interactive\n disabled={!hasDetail}\n aria-expanded={hasDetail ? isOpen : undefined}\n onClick={hasDetail ? () => toggleFile(node.index) : undefined}\n style={{ paddingLeft: indent + 8 }}\n className={cn(\n \"group flex w-full items-center gap-1.5 rounded-md py-1 pr-2 text-left text-[13px] transition-colors\",\n hasDetail ? \"hover:bg-accent/40\" : \"cursor-default\",\n )}\n >\n {/* Chevron slot — present only for files with expandable detail so\n everything stays aligned with the folder rows above. */}\n {hasDetail ? (\n <IconChevronRight\n className={cn(\n \"size-3.5 shrink-0 text-plan-muted transition-transform\",\n isOpen && \"rotate-90\",\n )}\n />\n ) : (\n <span className=\"size-3.5 shrink-0\" aria-hidden />\n )}\n <IconFile\n className={cn(\n \"size-4 shrink-0\",\n change === \"removed\" ? \"text-plan-muted\" : \"text-plan-muted/80\",\n )}\n />\n <span\n className={cn(\n \"min-w-0 truncate font-medium\",\n change ? CHANGE_NAME_INK[change] : \"text-plan-text\",\n )}\n >\n {node.name}\n </span>\n {change && (\n <span\n title={CHANGE_LABEL[change]}\n aria-label={CHANGE_LABEL[change]}\n className={cn(\n \"ml-1 flex size-4 shrink-0 items-center justify-center rounded text-[10px] font-bold leading-none\",\n CHANGE_BADGE[change],\n )}\n >\n {CHANGE_GLYPH[change]}\n </span>\n )}\n {entry.note?.trim() && !isOpen && (\n <span className=\"ml-1 min-w-0 flex-1 truncate text-xs text-plan-muted\">\n {entry.note}\n </span>\n )}\n </button>\n\n {/* Expanded file detail: the note + a fenced snippet. */}\n {hasDetail && isOpen && (\n <div\n style={{ paddingLeft: indent + 8 + 20 }}\n className=\"pb-2 pr-2 pt-0.5\"\n >\n {entry.note?.trim() && (\n <p className=\"text-xs leading-relaxed text-plan-muted\">\n {entry.note}\n </p>\n )}\n {entry.snippet?.trim() && (\n <div className=\"mt-2 an-file-tree-snippet\">\n {ctx.renderMarkdown?.(\n fence(entry.snippet, fenceLanguage(entry)),\n )}\n </div>\n )}\n </div>\n )}\n </div>\n );\n };\n\n return (\n <section\n ref={rootRef}\n className=\"plan-block\"\n data-block-id={blockId}\n data-files-expanded={railExpanded ? \"\" : undefined}\n onPointerDown={() => setActive(true)}\n >\n {title && <div className=\"plan-block-label\">{title}</div>}\n\n <div className=\"overflow-hidden rounded-xl border border-plan-line bg-plan-block\">\n {/* Summary header: file count + change tally. */}\n <div className=\"flex flex-wrap items-center gap-2 border-b border-plan-line bg-accent/20 px-3 py-2\">\n {data.title && (\n <span className=\"text-[13px] font-semibold text-plan-text\">\n {data.title}\n </span>\n )}\n <span className=\"text-xs text-plan-muted\">\n {entries.length} {entries.length === 1 ? \"file\" : \"files\"}\n </span>\n {changeTotal > 0 && (\n <span className=\"ml-auto flex items-center gap-2 font-mono text-xs\">\n {counts.added > 0 && (\n <span className=\"text-emerald-600 dark:text-emerald-300\">\n +{counts.added}\n </span>\n )}\n {counts.modified > 0 && (\n <span className=\"text-blue-600 dark:text-blue-300\">\n ~{counts.modified}\n </span>\n )}\n {counts.removed > 0 && (\n <span className=\"text-red-600 dark:text-red-300\">\n −{counts.removed}\n </span>\n )}\n {counts.renamed > 0 && (\n <span className=\"text-violet-600 dark:text-violet-300\">\n »{counts.renamed}\n </span>\n )}\n </span>\n )}\n </div>\n\n {/* The tree itself. */}\n <div className=\"py-1.5\">\n {tree.length > 0 ? (\n <>\n {displayedRows.map(renderRow)}\n {shouldLimitRows && (\n <div className=\"px-2 pt-1\">\n <button\n type=\"button\"\n data-plan-interactive\n aria-expanded={showAllRows}\n onClick={() => setShowAllRows((current) => !current)}\n className=\"flex h-8 w-full items-center justify-center gap-1.5 rounded-md text-xs font-medium text-plan-muted transition-colors hover:bg-accent/40 hover:text-plan-text\"\n >\n <IconChevronRight\n className={cn(\n \"size-3.5 shrink-0 transition-transform\",\n showAllRows ? \"-rotate-90\" : \"rotate-90\",\n )}\n />\n {showAllRows\n ? \"Show fewer\"\n : `Show all ${visibleRows.length} rows`}\n </button>\n </div>\n )}\n </>\n ) : (\n <p className=\"px-3 py-2 text-xs text-plan-muted\">No files yet.</p>\n )}\n </div>\n </div>\n\n {summary && <p className=\"mt-5 text-plan-muted\">{summary}</p>}\n </section>\n );\n}\n\n/* ── Edit (panel form) ─────────────────────────────────────────────────────── */\n\nconst fieldLabelClass = \"text-xs font-medium text-muted-foreground\";\n\n/**\n * Panel editor for a `file-tree` block. A structured form: an optional title\n * Input plus a list of file rows (add/remove), each carrying a path Input, a\n * change Select, a note Input, an optional language Input, and a snippet\n * Textarea. The folder tree is derived from the paths in the Read render, so the\n * form stays flat and quick to edit. Renders BARE content (no `<section>`); the\n * registry's panel surface supplies the popover chrome.\n */\nexport function FileTreeEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<FileTreeData>) {\n const entries = data.entries ?? [];\n\n const patchEntries = (next: FileTreeEntry[]) =>\n onChange({ ...data, entries: next });\n\n const updateEntry = (index: number, next: Partial<FileTreeEntry>) =>\n patchEntries(\n entries.map((entry, i) => (i === index ? { ...entry, ...next } : entry)),\n );\n\n const removeEntry = (index: number) =>\n patchEntries(entries.filter((_, i) => i !== index));\n\n const addEntry = () =>\n patchEntries([...entries, { path: \"src/new-file.ts\", change: \"added\" }]);\n\n return (\n <div className=\"flex flex-col gap-4\" data-plan-interactive>\n <label className=\"flex flex-col gap-1.5\">\n <span className={fieldLabelClass}>Title (optional)</span>\n <DevInput\n className=\"h-9\"\n value={data.title ?? \"\"}\n disabled={!editable}\n placeholder=\"e.g. Files touched\"\n onChange={(event) =>\n onChange({ ...data, title: event.target.value || undefined })\n }\n />\n </label>\n\n <div className=\"flex flex-col gap-3\">\n {entries.map((entry, index) => (\n <div\n key={index}\n className=\"flex flex-col gap-2 rounded-lg border border-input p-3\"\n >\n <div className=\"grid grid-cols-[minmax(0,1fr)_120px_auto] gap-2\">\n <DevInput\n className=\"h-8 font-mono text-xs\"\n value={entry.path}\n disabled={!editable}\n placeholder=\"src/routes/git.ts\"\n onChange={(event) =>\n updateEntry(index, { path: event.target.value })\n }\n />\n <DevSelect\n className=\"h-8\"\n value={entry.change ?? \"none\"}\n disabled={!editable}\n onValueChange={(value) =>\n updateEntry(index, {\n change:\n value === \"none\" ? undefined : (value as FileTreeChange),\n })\n }\n options={[\n { value: \"none\", label: \"No change\" },\n ...FILE_TREE_CHANGES.map((change) => ({\n value: change,\n label: CHANGE_LABEL[change],\n })),\n ]}\n />\n {editable && (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label=\"Remove file\"\n className=\"flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/60 hover:text-foreground\"\n onClick={() => removeEntry(index)}\n >\n <IconTrash className=\"size-4\" />\n </button>\n )}\n </div>\n <DevInput\n className=\"h-8 text-xs\"\n value={entry.note ?? \"\"}\n disabled={!editable}\n placeholder=\"Why this file changes\"\n onChange={(event) =>\n updateEntry(index, { note: event.target.value || undefined })\n }\n />\n <div className=\"grid grid-cols-[minmax(0,1fr)_120px] gap-2\">\n <DevTextarea\n className=\"min-h-[64px] font-mono text-xs\"\n value={entry.snippet ?? \"\"}\n disabled={!editable}\n placeholder=\"Optional code snippet\"\n onChange={(event) =>\n updateEntry(index, {\n snippet: event.target.value || undefined,\n })\n }\n />\n <DevInput\n className=\"h-8 self-start font-mono text-xs\"\n value={entry.language ?? \"\"}\n disabled={!editable}\n placeholder=\"language\"\n onChange={(event) =>\n updateEntry(index, {\n language: event.target.value || undefined,\n })\n }\n />\n </div>\n </div>\n ))}\n </div>\n\n {editable && (\n <button\n type=\"button\"\n data-plan-interactive\n className=\"flex items-center justify-center gap-1.5 rounded-md border border-dashed border-input py-2 text-sm text-muted-foreground hover:bg-accent/40 hover:text-foreground\"\n onClick={addEntry}\n >\n <IconPlus className=\"size-4\" />\n Add file\n </button>\n )}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"FileTreeBlock.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/FileTreeBlock.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n IconChevronRight,\n IconFile,\n IconFolder,\n IconFolderOpen,\n IconPlus,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport type { BlockEditProps, BlockReadProps } from \"../types.js\";\nimport type {\n FileTreeChange,\n FileTreeData,\n FileTreeEntry,\n} from \"./file-tree.config.js\";\nimport { FILE_TREE_CHANGES } from \"./file-tree.config.js\";\nimport { DevInput, DevTextarea, DevSelect } from \"./dev-doc-ui.js\";\n\n/**\n * Read + Edit renderers for a `file-tree` block — a VS Code / GitHub-explorer\n * file and change tree. Lives in core so any app can register the dev-doc block\n * (no shadcn import; the editor's enum picker is the core `DevSelect`).\n */\n\n/* ── Theme-aware change tokens ─────────────────────────────────────────────── */\n\n/**\n * Change-badge palette. Tinted background + saturated text in BOTH the `.dark`\n * plan theme and light mode (never a dark-only palette). Each entry keeps legible\n * contrast against the plan surface via Tailwind `dark:` variants.\n */\nconst CHANGE_BADGE: Record<FileTreeChange, string> = {\n added:\n \"bg-emerald-100 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300\",\n modified: \"bg-blue-100 text-blue-700 dark:bg-blue-500/15 dark:text-blue-300\",\n removed: \"bg-red-100 text-red-700 dark:bg-red-500/15 dark:text-red-300\",\n renamed:\n \"bg-violet-100 text-violet-700 dark:bg-violet-500/15 dark:text-violet-300\",\n};\n\n/** Single-letter glyph shown in the change badge (VS Code gutter convention). */\nconst CHANGE_GLYPH: Record<FileTreeChange, string> = {\n added: \"A\",\n modified: \"M\",\n removed: \"D\",\n renamed: \"R\",\n};\n\n/** Accent ink for the file name itself, echoing its change color. */\nconst CHANGE_NAME_INK: Record<FileTreeChange, string> = {\n added: \"text-emerald-700 dark:text-emerald-300\",\n modified: \"text-blue-700 dark:text-blue-300\",\n removed: \"text-red-600 line-through dark:text-red-300\",\n renamed: \"text-violet-700 dark:text-violet-300\",\n};\n\nconst CHANGE_LABEL: Record<FileTreeChange, string> = {\n added: \"Added\",\n modified: \"Modified\",\n removed: \"Removed\",\n renamed: \"Renamed\",\n};\n\n/** Infer a fence language for a file's snippet from its `language` or extension. */\nfunction fenceLanguage(entry: FileTreeEntry): string {\n if (entry.language?.trim()) return entry.language.trim();\n const ext = entry.path.split(\".\").pop()?.toLowerCase() ?? \"\";\n const byExt: Record<string, string> = {\n ts: \"ts\",\n tsx: \"tsx\",\n js: \"js\",\n jsx: \"jsx\",\n mjs: \"js\",\n cjs: \"js\",\n json: \"json\",\n css: \"css\",\n scss: \"scss\",\n html: \"html\",\n md: \"md\",\n mdx: \"md\",\n py: \"python\",\n rb: \"ruby\",\n go: \"go\",\n rs: \"rust\",\n sql: \"sql\",\n sh: \"bash\",\n yml: \"yaml\",\n yaml: \"yaml\",\n toml: \"toml\",\n };\n return byExt[ext] ?? \"text\";\n}\n\n/** Wrap a raw snippet in a fenced code block for `ctx.renderMarkdown`. */\nfunction fence(snippet: string, language: string): string {\n // Never let the snippet's own content break out of the fence.\n const safe = snippet.replace(/```/g, \"ʼʼʼ\");\n return `\\`\\`\\`${language}\\n${safe.replace(/\\s+$/, \"\")}\\n\\`\\`\\``;\n}\n\n/* ── Tree construction (flat paths → nested folders) ───────────────────────── */\n\ninterface FileLeaf {\n kind: \"file\";\n /** Last path segment. */\n name: string;\n /** Full slash path, used as a stable key + anchor. */\n path: string;\n entry: FileTreeEntry;\n /** Index in the original flat `entries` (stable per-file disclosure key). */\n index: number;\n}\n\ninterface FolderNode {\n kind: \"folder\";\n name: string;\n /** Full slash path of the folder, used as a stable key. */\n path: string;\n children: TreeNode[];\n}\n\ntype TreeNode = FolderNode | FileLeaf;\n\ninterface VisibleTreeRow {\n node: TreeNode;\n depth: number;\n}\n\n/** A folder being assembled while we walk the paths (children keyed by name). */\ninterface FolderBuild {\n name: string;\n path: string;\n folders: Map<string, FolderBuild>;\n files: FileLeaf[];\n /** Insertion order of child names (folders + files) for stable rendering. */\n order: string[];\n}\n\nfunction makeFolder(name: string, path: string): FolderBuild {\n return { name, path, folders: new Map(), files: [], order: [] };\n}\n\n/**\n * Build a nested folder tree from the flat `entries`. Folders are derived purely\n * from the slash segments of each `path`; a single-segment path is a root file.\n * Insertion order is preserved within each folder, with folders sorted before\n * files at each level (the conventional explorer ordering).\n */\nfunction buildTree(entries: FileTreeEntry[]): TreeNode[] {\n const root = makeFolder(\"\", \"\");\n\n entries.forEach((entry, index) => {\n const segments = entry.path.split(\"/\").filter(Boolean);\n if (segments.length === 0) return;\n const fileName = segments[segments.length - 1] as string;\n const folderSegments = segments.slice(0, -1);\n\n let cursor = root;\n let prefix = \"\";\n for (const segment of folderSegments) {\n prefix = prefix ? `${prefix}/${segment}` : segment;\n let next = cursor.folders.get(segment);\n if (!next) {\n next = makeFolder(segment, prefix);\n cursor.folders.set(segment, next);\n cursor.order.push(`d:${segment}`);\n }\n cursor = next;\n }\n\n cursor.files.push({\n kind: \"file\",\n name: fileName,\n path: entry.path,\n entry,\n index,\n });\n cursor.order.push(`f:${cursor.files.length - 1}`);\n });\n\n const materialize = (folder: FolderBuild): TreeNode[] => {\n const nodes: TreeNode[] = [];\n for (const key of folder.order) {\n if (key.startsWith(\"d:\")) {\n const child = folder.folders.get(key.slice(2));\n if (!child) continue;\n nodes.push({\n kind: \"folder\",\n name: child.name,\n path: child.path,\n children: materialize(child),\n });\n } else {\n const file = folder.files[Number(key.slice(2))];\n if (file) nodes.push(file);\n }\n }\n // Folders before files at this level (standard explorer ordering).\n return [\n ...nodes.filter((node) => node.kind === \"folder\"),\n ...nodes.filter((node) => node.kind === \"file\"),\n ];\n };\n\n return materialize(root);\n}\n\nfunction compactFolderNode(folder: FolderNode): FolderNode {\n const names = [folder.name];\n let path = folder.path;\n let children = folder.children;\n\n while (children.length === 1 && children[0]?.kind === \"folder\") {\n const child = children[0];\n names.push(child.name);\n path = child.path;\n children = child.children;\n }\n\n return {\n kind: \"folder\",\n name: names.join(\"/\"),\n path,\n children: compactTree(children),\n };\n}\n\nfunction compactTree(nodes: TreeNode[]): TreeNode[] {\n return nodes.map((node) =>\n node.kind === \"folder\" ? compactFolderNode(node) : node,\n );\n}\n\nfunction flattenVisibleRows(\n nodes: TreeNode[],\n collapsedFolders: Record<string, boolean>,\n depth = 0,\n): VisibleTreeRow[] {\n const rows: VisibleTreeRow[] = [];\n\n for (const node of nodes) {\n rows.push({ node, depth });\n if (node.kind === \"folder\" && !(collapsedFolders[node.path] ?? false)) {\n rows.push(\n ...flattenVisibleRows(node.children, collapsedFolders, depth + 1),\n );\n }\n }\n\n return rows;\n}\n\n/* ── Read (IDE explorer) ───────────────────────────────────────────────────── */\n\nconst INDENT_STEP = 14; // px per nesting level — the explorer guide spacing.\nconst DEFAULT_VISIBLE_TREE_ROWS = 10;\n\n/**\n * Read-only renderer for a `file-tree` block — a VS Code / GitHub-explorer file\n * and change tree. The flat `entries` are folded into a nested tree of\n * collapsible folders (IconFolder + chevron) and files (IconFile) carrying a\n * single-letter change badge (A/M/D/R). A file with a `note` or `snippet` is\n * itself clickable and expands to show the note plus the snippet rendered as a\n * fenced code block via `ctx.renderMarkdown`. A summary header tallies the change\n * counts (\"+N · ~M · −K\"). Every color is theme-aware via Tailwind `dark:`\n * variants / plan CSS vars, so the tree reads correctly in both modes.\n */\nexport function FileTreeRead({\n data,\n blockId,\n title,\n summary,\n ctx,\n}: BlockReadProps<FileTreeData>) {\n const entries = data.entries ?? [];\n const tree = useMemo(() => compactTree(buildTree(entries)), [entries]);\n\n // Folders default to fully expanded so the tree is useful at a glance.\n const [collapsedFolders, setCollapsedFolders] = useState<\n Record<string, boolean>\n >({});\n const [showAllRows, setShowAllRows] = useState(false);\n // Files with a note/snippet collapse their detail by default (progressive\n // disclosure) — keyed by the flat entry index so duplicate names never clash.\n const [openFiles, setOpenFiles] = useState<Record<number, boolean>>({});\n\n const toggleFolder = (path: string) =>\n setCollapsedFolders((current) => ({\n ...current,\n [path]: !current[path],\n }));\n const toggleFile = (index: number) =>\n setOpenFiles((current) => ({ ...current, [index]: !current[index] }));\n\n // The recap \"Files touched\" left rail (only) widens into the document as a\n // flyout while the tree is the reader's active focus AND a file's detail is\n // open, then collapses back to a slim rail when they click elsewhere or close\n // the last open file. `data-files-expanded` on the root drives the rail width\n // via CSS (`:has()`); it is inert anywhere the tree renders inline.\n const rootRef = useRef<HTMLElement>(null);\n const [active, setActive] = useState(false);\n const anyFileOpen = useMemo(\n () => Object.values(openFiles).some(Boolean),\n [openFiles],\n );\n const railExpanded = active && anyFileOpen;\n\n useEffect(() => {\n if (!railExpanded) return;\n const onPointerDown = (event: PointerEvent) => {\n const root = rootRef.current;\n if (\n root &&\n event.target instanceof Node &&\n !root.contains(event.target)\n ) {\n // Clicking away collapses the rail and closes any open file detail, so\n // it returns to the clean slim state rather than leaving notes open in\n // the cramped width.\n setActive(false);\n setOpenFiles({});\n }\n };\n document.addEventListener(\"pointerdown\", onPointerDown, true);\n return () =>\n document.removeEventListener(\"pointerdown\", onPointerDown, true);\n }, [railExpanded]);\n\n // Change tally for the summary header.\n const counts = useMemo(() => {\n const tally = { added: 0, modified: 0, removed: 0, renamed: 0 };\n for (const entry of entries) {\n if (entry.change) tally[entry.change] += 1;\n }\n return tally;\n }, [entries]);\n const changeTotal =\n counts.added + counts.modified + counts.removed + counts.renamed;\n\n const visibleRows = useMemo(\n () => flattenVisibleRows(tree, collapsedFolders),\n [collapsedFolders, tree],\n );\n const shouldLimitRows = visibleRows.length > DEFAULT_VISIBLE_TREE_ROWS;\n const displayedRows =\n showAllRows || !shouldLimitRows\n ? visibleRows\n : visibleRows.slice(0, DEFAULT_VISIBLE_TREE_ROWS);\n\n const renderRow = ({ node, depth }: VisibleTreeRow): React.ReactNode => {\n const indent = depth * INDENT_STEP;\n if (node.kind === \"folder\") {\n const collapsed = collapsedFolders[node.path] ?? false;\n return (\n <div key={`d:${node.path}`}>\n <button\n type=\"button\"\n data-plan-interactive\n aria-expanded={!collapsed}\n onClick={() => toggleFolder(node.path)}\n style={{ paddingLeft: indent + 8 }}\n className=\"flex w-full items-center gap-1.5 rounded-md py-1 pr-2 text-left text-[13px] transition-colors hover:bg-accent/40\"\n >\n <IconChevronRight\n className={cn(\n \"size-3.5 shrink-0 text-plan-muted transition-transform\",\n !collapsed && \"rotate-90\",\n )}\n />\n {collapsed ? (\n <IconFolder className=\"size-4 shrink-0 text-plan-muted\" />\n ) : (\n <IconFolderOpen className=\"size-4 shrink-0 text-plan-muted\" />\n )}\n <span className=\"min-w-0 truncate font-medium text-plan-text\">\n {node.name}\n </span>\n </button>\n </div>\n );\n }\n\n const { entry } = node;\n const change = entry.change;\n const hasDetail = Boolean(entry.note?.trim() || entry.snippet?.trim());\n const isOpen = openFiles[node.index] ?? false;\n\n return (\n <div key={`f:${node.index}`}>\n <button\n type=\"button\"\n data-plan-interactive\n disabled={!hasDetail}\n aria-expanded={hasDetail ? isOpen : undefined}\n onClick={hasDetail ? () => toggleFile(node.index) : undefined}\n style={{ paddingLeft: indent + 8 }}\n className={cn(\n \"group flex w-full items-center gap-1.5 rounded-md py-1 pr-2 text-left text-[13px] transition-colors\",\n hasDetail ? \"hover:bg-accent/40\" : \"cursor-default\",\n )}\n >\n {/* Chevron slot — present only for files with expandable detail so\n everything stays aligned with the folder rows above. */}\n {hasDetail ? (\n <IconChevronRight\n className={cn(\n \"size-3.5 shrink-0 text-plan-muted transition-transform\",\n isOpen && \"rotate-90\",\n )}\n />\n ) : (\n <span className=\"size-3.5 shrink-0\" aria-hidden />\n )}\n <IconFile\n className={cn(\n \"size-4 shrink-0\",\n change === \"removed\" ? \"text-plan-muted\" : \"text-plan-muted/80\",\n )}\n />\n <span\n className={cn(\n \"min-w-0 truncate font-medium\",\n change ? CHANGE_NAME_INK[change] : \"text-plan-text\",\n )}\n >\n {node.name}\n </span>\n {change && (\n <span\n title={CHANGE_LABEL[change]}\n aria-label={CHANGE_LABEL[change]}\n className={cn(\n \"ml-1 flex size-4 shrink-0 items-center justify-center rounded text-[10px] font-bold leading-none\",\n CHANGE_BADGE[change],\n )}\n >\n {CHANGE_GLYPH[change]}\n </span>\n )}\n {entry.note?.trim() && !isOpen && (\n <span className=\"ml-1 min-w-0 flex-1 truncate text-xs text-plan-muted\">\n {entry.note}\n </span>\n )}\n </button>\n\n {/* Expanded file detail: the note + a fenced snippet. */}\n {hasDetail && isOpen && (\n <div\n style={{ paddingLeft: indent + 8 + 20 }}\n className=\"pb-2 pr-2 pt-0.5\"\n >\n {entry.note?.trim() && (\n <p className=\"text-xs leading-relaxed text-plan-muted\">\n {entry.note}\n </p>\n )}\n {entry.snippet?.trim() && (\n <div className=\"mt-2 an-file-tree-snippet\">\n {ctx.renderMarkdown?.(\n fence(entry.snippet, fenceLanguage(entry)),\n )}\n </div>\n )}\n </div>\n )}\n </div>\n );\n };\n\n return (\n <section\n ref={rootRef}\n className=\"plan-block\"\n data-block-id={blockId}\n data-files-expanded={railExpanded ? \"\" : undefined}\n onPointerDown={() => setActive(true)}\n >\n {title && <div className=\"plan-block-label\">{title}</div>}\n\n <div className=\"overflow-hidden rounded-xl border border-plan-line bg-plan-block\">\n {/* Summary header: file count + change tally. */}\n <div className=\"flex flex-wrap items-center gap-2 border-b border-plan-line bg-accent/20 px-3 py-2\">\n {data.title && (\n <span className=\"text-[13px] font-semibold text-plan-text\">\n {data.title}\n </span>\n )}\n <span className=\"text-xs text-plan-muted\">\n {entries.length} {entries.length === 1 ? \"file\" : \"files\"}\n </span>\n {changeTotal > 0 && (\n <span className=\"ml-auto flex items-center gap-2 font-mono text-xs\">\n {counts.added > 0 && (\n <span className=\"text-emerald-600 dark:text-emerald-300\">\n +{counts.added}\n </span>\n )}\n {counts.modified > 0 && (\n <span className=\"text-blue-600 dark:text-blue-300\">\n ~{counts.modified}\n </span>\n )}\n {counts.removed > 0 && (\n <span className=\"text-red-600 dark:text-red-300\">\n −{counts.removed}\n </span>\n )}\n {counts.renamed > 0 && (\n <span className=\"text-violet-600 dark:text-violet-300\">\n »{counts.renamed}\n </span>\n )}\n </span>\n )}\n </div>\n\n {/* The tree itself. */}\n <div className=\"py-1.5\">\n {tree.length > 0 ? (\n <>\n {displayedRows.map(renderRow)}\n {shouldLimitRows && (\n <div className=\"px-2 pt-1\">\n <button\n type=\"button\"\n data-plan-interactive\n aria-expanded={showAllRows}\n onClick={() => setShowAllRows((current) => !current)}\n className=\"flex h-8 w-full items-center justify-center gap-1.5 rounded-md text-xs font-medium text-plan-muted transition-colors hover:bg-accent/40 hover:text-plan-text\"\n >\n <IconChevronRight\n className={cn(\n \"size-3.5 shrink-0 transition-transform\",\n showAllRows ? \"-rotate-90\" : \"rotate-90\",\n )}\n />\n {showAllRows\n ? \"Show fewer\"\n : `Show all ${visibleRows.length} rows`}\n </button>\n </div>\n )}\n </>\n ) : (\n <p className=\"px-3 py-2 text-xs text-plan-muted\">No files yet.</p>\n )}\n </div>\n </div>\n\n {summary && <p className=\"mt-5 text-plan-muted\">{summary}</p>}\n </section>\n );\n}\n\n/* ── Edit (panel form) ─────────────────────────────────────────────────────── */\n\nconst fieldLabelClass = \"text-xs font-medium text-muted-foreground\";\n\n/**\n * Panel editor for a `file-tree` block. A structured form: an optional title\n * Input plus a list of file rows (add/remove), each carrying a path Input, a\n * change Select, a note Input, an optional language Input, and a snippet\n * Textarea. The folder tree is derived from the paths in the Read render, so the\n * form stays flat and quick to edit. Renders BARE content (no `<section>`); the\n * registry's panel surface supplies the popover chrome.\n */\nexport function FileTreeEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<FileTreeData>) {\n const entries = data.entries ?? [];\n\n const patchEntries = (next: FileTreeEntry[]) =>\n onChange({ ...data, entries: next });\n\n const updateEntry = (index: number, next: Partial<FileTreeEntry>) =>\n patchEntries(\n entries.map((entry, i) => (i === index ? { ...entry, ...next } : entry)),\n );\n\n const removeEntry = (index: number) =>\n patchEntries(entries.filter((_, i) => i !== index));\n\n const addEntry = () =>\n patchEntries([...entries, { path: \"src/new-file.ts\", change: \"added\" }]);\n\n return (\n <div className=\"flex flex-col gap-4\" data-plan-interactive>\n <label className=\"flex flex-col gap-1.5\">\n <span className={fieldLabelClass}>Title (optional)</span>\n <DevInput\n className=\"h-9\"\n value={data.title ?? \"\"}\n disabled={!editable}\n placeholder=\"e.g. Files touched\"\n onChange={(event) =>\n onChange({ ...data, title: event.target.value || undefined })\n }\n />\n </label>\n\n <div className=\"flex flex-col gap-3\">\n {entries.map((entry, index) => (\n <div\n key={index}\n className=\"flex flex-col gap-2 rounded-lg border border-input p-3\"\n >\n <div className=\"grid grid-cols-[minmax(0,1fr)_120px_auto] gap-2\">\n <DevInput\n className=\"h-8 font-mono text-xs\"\n value={entry.path}\n disabled={!editable}\n placeholder=\"src/routes/git.ts\"\n onChange={(event) =>\n updateEntry(index, { path: event.target.value })\n }\n />\n <DevSelect\n className=\"h-8\"\n value={entry.change ?? \"none\"}\n disabled={!editable}\n onValueChange={(value) =>\n updateEntry(index, {\n change:\n value === \"none\" ? undefined : (value as FileTreeChange),\n })\n }\n options={[\n { value: \"none\", label: \"No change\" },\n ...FILE_TREE_CHANGES.map((change) => ({\n value: change,\n label: CHANGE_LABEL[change],\n })),\n ]}\n />\n {editable && (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label=\"Remove file\"\n className=\"flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/60 hover:text-foreground\"\n onClick={() => removeEntry(index)}\n >\n <IconTrash className=\"size-4\" />\n </button>\n )}\n </div>\n <DevInput\n className=\"h-8 text-xs\"\n value={entry.note ?? \"\"}\n disabled={!editable}\n placeholder=\"Why this file changes\"\n onChange={(event) =>\n updateEntry(index, { note: event.target.value || undefined })\n }\n />\n <div className=\"grid grid-cols-[minmax(0,1fr)_120px] gap-2\">\n <DevTextarea\n className=\"min-h-[64px] font-mono text-xs\"\n value={entry.snippet ?? \"\"}\n disabled={!editable}\n placeholder=\"Optional code snippet\"\n onChange={(event) =>\n updateEntry(index, {\n snippet: event.target.value || undefined,\n })\n }\n />\n <DevInput\n className=\"h-8 self-start font-mono text-xs\"\n value={entry.language ?? \"\"}\n disabled={!editable}\n placeholder=\"language\"\n onChange={(event) =>\n updateEntry(index, {\n language: event.target.value || undefined,\n })\n }\n />\n </div>\n </div>\n ))}\n </div>\n\n {editable && (\n <button\n type=\"button\"\n data-plan-interactive\n className=\"flex items-center justify-center gap-1.5 rounded-md border border-dashed border-input py-2 text-sm text-muted-foreground hover:bg-accent/40 hover:text-foreground\"\n onClick={addEntry}\n >\n <IconPlus className=\"size-4\" />\n Add file\n </button>\n )}\n </div>\n );\n}\n"]}
|
|
@@ -90,25 +90,6 @@ export declare function AnnotationNoteRail<A extends RailAnnotation>({ items, ac
|
|
|
90
90
|
/** Show a leading numbered pip on each card (diff block). */
|
|
91
91
|
showMarker?: boolean;
|
|
92
92
|
}): import("react/jsx-runtime").JSX.Element;
|
|
93
|
-
/**
|
|
94
|
-
* A single line-anchored note rendered INLINE in the diff flow — full-width,
|
|
95
|
-
* directly under the line it annotates — instead of in a side rail (the
|
|
96
|
-
* GitHub-review affordance). The diff block places one of these after the first
|
|
97
|
-
* row of each annotation's range, so the numbered `①`/`②` row marker and the note
|
|
98
|
-
* read together in one column. It carries the same marker pip, line range,
|
|
99
|
-
* optional label, and markdown `note` as a rail card, and the same two-way hover
|
|
100
|
-
* wiring (`active` / `onActiveChange`) so the row and its note cross-highlight.
|
|
101
|
-
*
|
|
102
|
-
* The outer band is `min-w-full` so the amber wash spans the diff's full scroll
|
|
103
|
-
* width; the content is `sticky left-0` with a readable `max-w` so the note stays
|
|
104
|
-
* pinned and legible while long code lines scroll horizontally beneath it.
|
|
105
|
-
*/
|
|
106
|
-
export declare function InlineAnnotationNote<A extends RailAnnotation>({ item, active, onActiveChange, ctx, }: {
|
|
107
|
-
item: ResolvedAnnotation<A>;
|
|
108
|
-
active: boolean;
|
|
109
|
-
onActiveChange: (index: number | null) => void;
|
|
110
|
-
ctx: BlockRenderContext;
|
|
111
|
-
}): import("react/jsx-runtime").JSX.Element;
|
|
112
93
|
/** Whether a resolved list has at least one note worth rendering a rail for. */
|
|
113
94
|
export declare function hasRailAnnotations(items: ResolvedAnnotation[]): boolean;
|
|
114
95
|
export type AnnotationRailChildren = ReactNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"annotation-rail.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/annotation-rail.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEhD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUvC;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc;IAC3E,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,CAAC,CAAC;IACd,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC9C;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,cAAc,EACzD,WAAW,EAAE,CAAC,EAAE,GAAG,SAAS,EAC5B,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC,KAAK,MAAM,GACtC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAOzB;AAED,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,cAAc,EACzD,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,GAChC,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,CAWtC;AAED,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAK3D;AAID;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,EACN,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,2CAeA;AAID;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,cAAc,EAAE,EAC3D,KAAK,EACL,WAAW,EACX,cAAc,EACd,GAAG,EACH,SAAS,EACT,UAAkB,GACnB,EAAE;IACD,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/C,GAAG,EAAE,kBAAkB,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,2CAsDA;
|
|
1
|
+
{"version":3,"file":"annotation-rail.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/annotation-rail.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEhD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUvC;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc;IAC3E,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,CAAC,CAAC;IACd,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC9C;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,cAAc,EACzD,WAAW,EAAE,CAAC,EAAE,GAAG,SAAS,EAC5B,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC,KAAK,MAAM,GACtC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAOzB;AAED,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,cAAc,EACzD,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,GAChC,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,CAWtC;AAED,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAK3D;AAID;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,EACN,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,2CAeA;AAID;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,cAAc,EAAE,EAC3D,KAAK,EACL,WAAW,EACX,cAAc,EACd,GAAG,EACH,SAAS,EACT,UAAkB,GACnB,EAAE;IACD,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/C,GAAG,EAAE,kBAAkB,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,2CAsDA;AAED,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAEvE;AAED,MAAM,MAAM,sBAAsB,GAAG,SAAS,CAAC"}
|
|
@@ -113,25 +113,6 @@ export function AnnotationNoteRail({ items, activeIndex, onActiveChange, ctx, cl
|
|
|
113
113
|
: "border-plan-line bg-plan-block/40 hover:border-amber-400/50"), children: [_jsxs("div", { className: cn("flex flex-wrap gap-x-2 gap-y-0.5", showMarker ? "items-center" : "items-baseline"), children: [showMarker && (_jsx(AnnotationGutterMarker, { marker: item.marker, active: isActive })), _jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wide text-plan-muted", children: rangeLabel(item) }), item.annotation.label && (_jsx("span", { className: "text-[13px] font-semibold text-plan-text", children: item.annotation.label }))] }), _jsx("div", { className: "plan-annotation-note mt-1 text-[13px] leading-relaxed text-plan-text/85", children: ctx.renderMarkdown ? (ctx.renderMarkdown(item.annotation.note)) : (_jsx("p", { children: item.annotation.note })) })] }, item.index));
|
|
114
114
|
}) }));
|
|
115
115
|
}
|
|
116
|
-
/* ── Inline note (GitHub-style) ─────────────────────────────────────────────── */
|
|
117
|
-
/**
|
|
118
|
-
* A single line-anchored note rendered INLINE in the diff flow — full-width,
|
|
119
|
-
* directly under the line it annotates — instead of in a side rail (the
|
|
120
|
-
* GitHub-review affordance). The diff block places one of these after the first
|
|
121
|
-
* row of each annotation's range, so the numbered `①`/`②` row marker and the note
|
|
122
|
-
* read together in one column. It carries the same marker pip, line range,
|
|
123
|
-
* optional label, and markdown `note` as a rail card, and the same two-way hover
|
|
124
|
-
* wiring (`active` / `onActiveChange`) so the row and its note cross-highlight.
|
|
125
|
-
*
|
|
126
|
-
* The outer band is `min-w-full` so the amber wash spans the diff's full scroll
|
|
127
|
-
* width; the content is `sticky left-0` with a readable `max-w` so the note stays
|
|
128
|
-
* pinned and legible while long code lines scroll horizontally beneath it.
|
|
129
|
-
*/
|
|
130
|
-
export function InlineAnnotationNote({ item, active, onActiveChange, ctx, }) {
|
|
131
|
-
return (_jsx("div", { onMouseEnter: () => onActiveChange(item.index), onMouseLeave: () => onActiveChange(null), className: cn("min-w-full border-y transition-colors", active
|
|
132
|
-
? "border-amber-400/60 bg-amber-100/70 dark:border-amber-300/40 dark:bg-amber-300/[0.12]"
|
|
133
|
-
: "border-amber-400/30 bg-amber-50/70 dark:border-amber-300/20 dark:bg-amber-300/[0.06]"), children: _jsxs("div", { className: "sticky left-0 flex max-w-[44rem] gap-2.5 whitespace-normal px-3 py-2.5 font-sans", children: [_jsx(AnnotationGutterMarker, { marker: item.marker, active: active }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-0.5", children: [_jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wide text-plan-muted", children: rangeLabel(item) }), item.annotation.label && (_jsx("span", { className: "text-[13px] font-semibold text-plan-text", children: item.annotation.label }))] }), _jsx("div", { className: "plan-annotation-note mt-1 text-[13px] leading-relaxed text-plan-text/85", children: ctx.renderMarkdown ? (ctx.renderMarkdown(item.annotation.note)) : (_jsx("p", { children: item.annotation.note })) })] })] }) }));
|
|
134
|
-
}
|
|
135
116
|
/** Whether a resolved list has at least one note worth rendering a rail for. */
|
|
136
117
|
export function hasRailAnnotations(items) {
|
|
137
118
|
return items.some((item) => item.range);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"annotation-rail.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/annotation-rail.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAkB,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAGpC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,kFAAkF;AAElF;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,SAAiB;IAEjB,MAAM,KAAK,GAAG,gCAAgC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,IAAI,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACnE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAClE,IAAI,KAAK,GAAG,GAAG;QAAE,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7C,mCAAmC;IACnC,IAAI,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,SAAS;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC;AACtE,CAAC;AAkBD;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,WAA4B,EAC5B,YAAuC;IAEvC,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACrD,KAAK;QACL,MAAM,EAAE,KAAK,GAAG,CAAC;QACjB,UAAU;QACV,KAAK,EAAE,cAAc,CAAC,UAAU,CAAC,KAAK,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC;KAClE,CAAC,CAAC,CAAC;AACN,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,kBAAkB,CAChC,QAAiC;IAEjC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAmC,CAAC;IACvD,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,SAAS;QAC1B,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChB,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,UAAU,CAAC,IAAwB;IACjD,IAAI,CAAC,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IACzD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG;QACxC,CAAC,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;QAC5B,CAAC,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;AACpD,CAAC;AAED,kFAAkF;AAElF;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,EACrC,MAAM,EACN,MAAM,EACN,SAAS,GAKV;IACC,OAAO,CACL,oCAEE,SAAS,EAAE,EAAE,CACX,gJAAgJ,EAChJ,MAAM;YACJ,CAAC,CAAC,+DAA+D;YACjE,CAAC,CAAC,yEAAyE,EAC7E,SAAS,CACV,YAEA,MAAM,GACF,CACR,CAAC;AACJ,CAAC;AAED,kFAAkF;AAElF;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAA2B,EAC3D,KAAK,EACL,WAAW,EACX,cAAc,EACd,GAAG,EACH,SAAS,EACT,UAAU,GAAG,KAAK,GASnB;IACC,MAAM,eAAe,GAAG,OAAO,CAC7B,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EACxC,CAAC,KAAK,CAAC,CACR,CAAC;IACF,OAAO,CACL,cAAK,SAAS,EAAE,EAAE,CAAC,uBAAuB,EAAE,SAAS,CAAC,YACnD,eAAe,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YAC5B,MAAM,QAAQ,GAAG,WAAW,KAAK,IAAI,CAAC,KAAK,CAAC;YAC5C,OAAO,CACL,eAEE,YAAY,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,EAC9C,YAAY,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,EACxC,SAAS,EAAE,EAAE,CACX,mDAAmD,EACnD,QAAQ;oBACN,CAAC,CAAC,mFAAmF;oBACrF,CAAC,CAAC,6DAA6D,CAClE,aAED,eACE,SAAS,EAAE,EAAE,CACX,kCAAkC,EAClC,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,gBAAgB,CAC/C,aAEA,UAAU,IAAI,CACb,KAAC,sBAAsB,IACrB,MAAM,EAAE,IAAI,CAAC,MAAM,EACnB,MAAM,EAAE,QAAQ,GAChB,CACH,EACD,eAAM,SAAS,EAAC,mEAAmE,YAChF,UAAU,CAAC,IAAI,CAAC,GACZ,EACN,IAAI,CAAC,UAAU,CAAC,KAAK,IAAI,CACxB,eAAM,SAAS,EAAC,0CAA0C,YACvD,IAAI,CAAC,UAAU,CAAC,KAAK,GACjB,CACR,IACG,EACN,cAAK,SAAS,EAAC,yEAAyE,YACrF,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CACpB,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CACzC,CAAC,CAAC,CAAC,CACF,sBAAI,IAAI,CAAC,UAAU,CAAC,IAAI,GAAK,CAC9B,GACG,KArCD,IAAI,CAAC,KAAK,CAsCX,CACP,CAAC;QACJ,CAAC,CAAC,GACE,CACP,CAAC;AACJ,CAAC;AAED,mFAAmF;AAEnF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAA2B,EAC7D,IAAI,EACJ,MAAM,EACN,cAAc,EACd,GAAG,GAMJ;IACC,OAAO,CACL,cACE,YAAY,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,EAC9C,YAAY,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,EACxC,SAAS,EAAE,EAAE,CACX,uCAAuC,EACvC,MAAM;YACJ,CAAC,CAAC,uFAAuF;YACzF,CAAC,CAAC,sFAAsF,CAC3F,YAED,eAAK,SAAS,EAAC,kFAAkF,aAC/F,KAAC,sBAAsB,IAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAI,EAC/D,eAAK,SAAS,EAAC,gBAAgB,aAC7B,eAAK,SAAS,EAAC,iDAAiD,aAC9D,eAAM,SAAS,EAAC,mEAAmE,YAChF,UAAU,CAAC,IAAI,CAAC,GACZ,EACN,IAAI,CAAC,UAAU,CAAC,KAAK,IAAI,CACxB,eAAM,SAAS,EAAC,0CAA0C,YACvD,IAAI,CAAC,UAAU,CAAC,KAAK,GACjB,CACR,IACG,EACN,cAAK,SAAS,EAAC,yEAAyE,YACrF,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CACpB,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CACzC,CAAC,CAAC,CAAC,CACF,sBAAI,IAAI,CAAC,UAAU,CAAC,IAAI,GAAK,CAC9B,GACG,IACF,IACF,GACF,CACP,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,kBAAkB,CAAC,KAA2B;IAC5D,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC1C,CAAC","sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport { cn } from \"../../utils.js\";\nimport type { BlockRenderContext } from \"../types.js\";\n\n/**\n * Shared line-anchored annotation UI for the `annotated-code` and `diff` blocks.\n *\n * Both blocks render a numbered code surface plus a side \"rail\" of notes, where\n * each note targets a 1-based `lines` ref (`\"3\"` or `\"3-5\"`) and hovering a code\n * line ↔ its note cross-highlights. This module owns the pure pieces that were\n * identical between them so neither block forks the behavior:\n *\n * - `parseLineRange` — the forgiving 1-based `lines` range parser.\n * - `resolveAnnotations` / `buildLineMarkerMap` — turn a raw annotation list\n * into stable, marker-numbered, range-resolved records and a line→markers map.\n * - `rangeLabel` — the human \"Line 8\" / \"Lines 3–6\" label.\n * - `AnnotationGutterMarker` — the numbered amber pip placed on an annotated row\n * (used by the diff grid; the annotated-code surface uses its own rail bar).\n * - `AnnotationNoteRail` — the responsive list of note cards with two-way hover.\n * `showMarker` opts the diff block into a leading numbered pip on each card so\n * a note can be matched to its `①`/`②` row marker; annotated-code omits it to\n * keep its original card chrome.\n *\n * `AnnotatedCodeBlock` annotates a single code surface; `DiffBlock` annotates a\n * before/after grid (each annotation also carries a `side`). The shared types\n * here are intentionally minimal — callers pass their own `side` handling and\n * decide which rows a marker lands on; this module only owns the parsing, the\n * resolved-record shape, and the rendered marker + rail chrome.\n */\n\n/* ── Line-ref parsing ──────────────────────────────────────────────────────── */\n\n/**\n * Parse a 1-based `lines` ref (`\"3\"` or `\"3-5\"`) into an inclusive `[start,end]`\n * pair, clamped to `[1, lineCount]`. Returns `null` for malformed or fully\n * out-of-range refs so callers can ignore them gracefully. A reversed range\n * (`\"5-3\"`) is normalized; a partially out-of-range range is clamped.\n */\nexport function parseLineRange(\n ref: string,\n lineCount: number,\n): { start: number; end: number } | null {\n const match = /^\\s*(\\d+)\\s*(?:-\\s*(\\d+)\\s*)?$/.exec(ref);\n if (!match) return null;\n let start = Number.parseInt(match[1], 10);\n let end = match[2] != null ? Number.parseInt(match[2], 10) : start;\n if (!Number.isFinite(start) || !Number.isFinite(end)) return null;\n if (start > end) [start, end] = [end, start];\n // Fully outside the file → ignore.\n if (end < 1 || start > lineCount) return null;\n return { start: Math.max(1, start), end: Math.min(lineCount, end) };\n}\n\n/** The minimal annotation shape the rail needs (a superset works too). */\nexport interface RailAnnotation {\n lines: string;\n label?: string;\n note: string;\n}\n\nexport interface ResolvedAnnotation<A extends RailAnnotation = RailAnnotation> {\n /** Index in the original `annotations` array (stable hover key). */\n index: number;\n /** 1-based marker number (authoring order). */\n marker: number;\n annotation: A;\n range: { start: number; end: number } | null;\n}\n\n/**\n * Resolve a raw annotation list into stable, marker-numbered records, parsing\n * each `lines` ref against `lineCount`. `lineCountFor` lets the diff block pick a\n * per-annotation line count (before-side vs after-side); annotated-code passes a\n * single constant. Markers are authoring-order, 1-based, and assigned to ALL\n * annotations (even unresolved ones) so numbering is stable regardless of which\n * refs happen to match.\n */\nexport function resolveAnnotations<A extends RailAnnotation>(\n annotations: A[] | undefined,\n lineCountFor: (annotation: A) => number,\n): ResolvedAnnotation<A>[] {\n return (annotations ?? []).map((annotation, index) => ({\n index,\n marker: index + 1,\n annotation,\n range: parseLineRange(annotation.lines, lineCountFor(annotation)),\n }));\n}\n\n/** Map a 1-based line number → the resolved annotations covering it. */\nexport function buildLineMarkerMap<A extends RailAnnotation>(\n resolved: ResolvedAnnotation<A>[],\n): Map<number, ResolvedAnnotation<A>[]> {\n const map = new Map<number, ResolvedAnnotation<A>[]>();\n for (const item of resolved) {\n if (!item.range) continue;\n for (let n = item.range.start; n <= item.range.end; n += 1) {\n const list = map.get(n) ?? [];\n list.push(item);\n map.set(n, list);\n }\n }\n return map;\n}\n\n/** Human label for a resolved annotation's line span (\"Line 8\" / \"Lines 3–6\"). */\nexport function rangeLabel(item: ResolvedAnnotation): string {\n if (!item.range) return `Lines ${item.annotation.lines}`;\n return item.range.start === item.range.end\n ? `Line ${item.range.start}`\n : `Lines ${item.range.start}–${item.range.end}`;\n}\n\n/* ── Marker ────────────────────────────────────────────────────────────────── */\n\n/**\n * The numbered amber pip rendered on an annotated code row's gutter. `active`\n * brightens it when its note (or a co-located row) is hovered.\n */\nexport function AnnotationGutterMarker({\n marker,\n active,\n className,\n}: {\n marker: number;\n active: boolean;\n className?: string;\n}) {\n return (\n <span\n aria-hidden\n className={cn(\n \"inline-flex size-[15px] shrink-0 items-center justify-center rounded-full text-[9px] font-semibold leading-none tabular-nums transition-colors\",\n active\n ? \"bg-amber-500 text-white dark:bg-amber-400 dark:text-amber-950\"\n : \"bg-amber-400/25 text-amber-700 dark:bg-amber-300/20 dark:text-amber-300\",\n className,\n )}\n >\n {marker}\n </span>\n );\n}\n\n/* ── Note rail ─────────────────────────────────────────────────────────────── */\n\n/**\n * The responsive list of line-anchored note cards. Each card shows its marker\n * pip, the resolved line span (\"Line 8\"), an optional label, and the markdown\n * `note` (via `ctx.renderMarkdown`). Hovering a card sets the active index;\n * `activeIndex` driven from outside lets a hovered code row light its card and\n * vice-versa. Only annotations whose `range` resolved are listed.\n */\nexport function AnnotationNoteRail<A extends RailAnnotation>({\n items,\n activeIndex,\n onActiveChange,\n ctx,\n className,\n showMarker = false,\n}: {\n items: ResolvedAnnotation<A>[];\n activeIndex: number | null;\n onActiveChange: (index: number | null) => void;\n ctx: BlockRenderContext;\n className?: string;\n /** Show a leading numbered pip on each card (diff block). */\n showMarker?: boolean;\n}) {\n const sideAnnotations = useMemo(\n () => items.filter((item) => item.range),\n [items],\n );\n return (\n <div className={cn(\"flex flex-col gap-2.5\", className)}>\n {sideAnnotations.map((item) => {\n const isActive = activeIndex === item.index;\n return (\n <div\n key={item.index}\n onMouseEnter={() => onActiveChange(item.index)}\n onMouseLeave={() => onActiveChange(null)}\n className={cn(\n \"rounded-lg border px-3.5 py-2.5 transition-colors\",\n isActive\n ? \"border-amber-400/70 bg-amber-50 dark:border-amber-300/40 dark:bg-amber-300/[0.08]\"\n : \"border-plan-line bg-plan-block/40 hover:border-amber-400/50\",\n )}\n >\n <div\n className={cn(\n \"flex flex-wrap gap-x-2 gap-y-0.5\",\n showMarker ? \"items-center\" : \"items-baseline\",\n )}\n >\n {showMarker && (\n <AnnotationGutterMarker\n marker={item.marker}\n active={isActive}\n />\n )}\n <span className=\"text-[11px] font-semibold uppercase tracking-wide text-plan-muted\">\n {rangeLabel(item)}\n </span>\n {item.annotation.label && (\n <span className=\"text-[13px] font-semibold text-plan-text\">\n {item.annotation.label}\n </span>\n )}\n </div>\n <div className=\"plan-annotation-note mt-1 text-[13px] leading-relaxed text-plan-text/85\">\n {ctx.renderMarkdown ? (\n ctx.renderMarkdown(item.annotation.note)\n ) : (\n <p>{item.annotation.note}</p>\n )}\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n\n/* ── Inline note (GitHub-style) ─────────────────────────────────────────────── */\n\n/**\n * A single line-anchored note rendered INLINE in the diff flow — full-width,\n * directly under the line it annotates — instead of in a side rail (the\n * GitHub-review affordance). The diff block places one of these after the first\n * row of each annotation's range, so the numbered `①`/`②` row marker and the note\n * read together in one column. It carries the same marker pip, line range,\n * optional label, and markdown `note` as a rail card, and the same two-way hover\n * wiring (`active` / `onActiveChange`) so the row and its note cross-highlight.\n *\n * The outer band is `min-w-full` so the amber wash spans the diff's full scroll\n * width; the content is `sticky left-0` with a readable `max-w` so the note stays\n * pinned and legible while long code lines scroll horizontally beneath it.\n */\nexport function InlineAnnotationNote<A extends RailAnnotation>({\n item,\n active,\n onActiveChange,\n ctx,\n}: {\n item: ResolvedAnnotation<A>;\n active: boolean;\n onActiveChange: (index: number | null) => void;\n ctx: BlockRenderContext;\n}) {\n return (\n <div\n onMouseEnter={() => onActiveChange(item.index)}\n onMouseLeave={() => onActiveChange(null)}\n className={cn(\n \"min-w-full border-y transition-colors\",\n active\n ? \"border-amber-400/60 bg-amber-100/70 dark:border-amber-300/40 dark:bg-amber-300/[0.12]\"\n : \"border-amber-400/30 bg-amber-50/70 dark:border-amber-300/20 dark:bg-amber-300/[0.06]\",\n )}\n >\n <div className=\"sticky left-0 flex max-w-[44rem] gap-2.5 whitespace-normal px-3 py-2.5 font-sans\">\n <AnnotationGutterMarker marker={item.marker} active={active} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-baseline gap-x-2 gap-y-0.5\">\n <span className=\"text-[11px] font-semibold uppercase tracking-wide text-plan-muted\">\n {rangeLabel(item)}\n </span>\n {item.annotation.label && (\n <span className=\"text-[13px] font-semibold text-plan-text\">\n {item.annotation.label}\n </span>\n )}\n </div>\n <div className=\"plan-annotation-note mt-1 text-[13px] leading-relaxed text-plan-text/85\">\n {ctx.renderMarkdown ? (\n ctx.renderMarkdown(item.annotation.note)\n ) : (\n <p>{item.annotation.note}</p>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n\n/** Whether a resolved list has at least one note worth rendering a rail for. */\nexport function hasRailAnnotations(items: ResolvedAnnotation[]): boolean {\n return items.some((item) => item.range);\n}\n\nexport type AnnotationRailChildren = ReactNode;\n"]}
|
|
1
|
+
{"version":3,"file":"annotation-rail.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/annotation-rail.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAkB,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAGpC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,kFAAkF;AAElF;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,SAAiB;IAEjB,MAAM,KAAK,GAAG,gCAAgC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,IAAI,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACnE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAClE,IAAI,KAAK,GAAG,GAAG;QAAE,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7C,mCAAmC;IACnC,IAAI,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,SAAS;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC;AACtE,CAAC;AAkBD;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,WAA4B,EAC5B,YAAuC;IAEvC,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACrD,KAAK;QACL,MAAM,EAAE,KAAK,GAAG,CAAC;QACjB,UAAU;QACV,KAAK,EAAE,cAAc,CAAC,UAAU,CAAC,KAAK,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC;KAClE,CAAC,CAAC,CAAC;AACN,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,kBAAkB,CAChC,QAAiC;IAEjC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAmC,CAAC;IACvD,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,SAAS;QAC1B,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChB,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,UAAU,CAAC,IAAwB;IACjD,IAAI,CAAC,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IACzD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG;QACxC,CAAC,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;QAC5B,CAAC,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;AACpD,CAAC;AAED,kFAAkF;AAElF;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,EACrC,MAAM,EACN,MAAM,EACN,SAAS,GAKV;IACC,OAAO,CACL,oCAEE,SAAS,EAAE,EAAE,CACX,gJAAgJ,EAChJ,MAAM;YACJ,CAAC,CAAC,+DAA+D;YACjE,CAAC,CAAC,yEAAyE,EAC7E,SAAS,CACV,YAEA,MAAM,GACF,CACR,CAAC;AACJ,CAAC;AAED,kFAAkF;AAElF;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAA2B,EAC3D,KAAK,EACL,WAAW,EACX,cAAc,EACd,GAAG,EACH,SAAS,EACT,UAAU,GAAG,KAAK,GASnB;IACC,MAAM,eAAe,GAAG,OAAO,CAC7B,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EACxC,CAAC,KAAK,CAAC,CACR,CAAC;IACF,OAAO,CACL,cAAK,SAAS,EAAE,EAAE,CAAC,uBAAuB,EAAE,SAAS,CAAC,YACnD,eAAe,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YAC5B,MAAM,QAAQ,GAAG,WAAW,KAAK,IAAI,CAAC,KAAK,CAAC;YAC5C,OAAO,CACL,eAEE,YAAY,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,EAC9C,YAAY,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,EACxC,SAAS,EAAE,EAAE,CACX,mDAAmD,EACnD,QAAQ;oBACN,CAAC,CAAC,mFAAmF;oBACrF,CAAC,CAAC,6DAA6D,CAClE,aAED,eACE,SAAS,EAAE,EAAE,CACX,kCAAkC,EAClC,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,gBAAgB,CAC/C,aAEA,UAAU,IAAI,CACb,KAAC,sBAAsB,IACrB,MAAM,EAAE,IAAI,CAAC,MAAM,EACnB,MAAM,EAAE,QAAQ,GAChB,CACH,EACD,eAAM,SAAS,EAAC,mEAAmE,YAChF,UAAU,CAAC,IAAI,CAAC,GACZ,EACN,IAAI,CAAC,UAAU,CAAC,KAAK,IAAI,CACxB,eAAM,SAAS,EAAC,0CAA0C,YACvD,IAAI,CAAC,UAAU,CAAC,KAAK,GACjB,CACR,IACG,EACN,cAAK,SAAS,EAAC,yEAAyE,YACrF,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CACpB,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CACzC,CAAC,CAAC,CAAC,CACF,sBAAI,IAAI,CAAC,UAAU,CAAC,IAAI,GAAK,CAC9B,GACG,KArCD,IAAI,CAAC,KAAK,CAsCX,CACP,CAAC;QACJ,CAAC,CAAC,GACE,CACP,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,kBAAkB,CAAC,KAA2B;IAC5D,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC1C,CAAC","sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport { cn } from \"../../utils.js\";\nimport type { BlockRenderContext } from \"../types.js\";\n\n/**\n * Shared line-anchored annotation UI for the `annotated-code` and `diff` blocks.\n *\n * Both blocks render a numbered code surface plus a side \"rail\" of notes, where\n * each note targets a 1-based `lines` ref (`\"3\"` or `\"3-5\"`) and hovering a code\n * line ↔ its note cross-highlights. This module owns the pure pieces that were\n * identical between them so neither block forks the behavior:\n *\n * - `parseLineRange` — the forgiving 1-based `lines` range parser.\n * - `resolveAnnotations` / `buildLineMarkerMap` — turn a raw annotation list\n * into stable, marker-numbered, range-resolved records and a line→markers map.\n * - `rangeLabel` — the human \"Line 8\" / \"Lines 3–6\" label.\n * - `AnnotationGutterMarker` — the numbered amber pip placed on an annotated row\n * (used by the diff grid; the annotated-code surface uses its own rail bar).\n * - `AnnotationNoteRail` — the responsive list of note cards with two-way hover.\n * `showMarker` opts the diff block into a leading numbered pip on each card so\n * a note can be matched to its `①`/`②` row marker; annotated-code omits it to\n * keep its original card chrome.\n *\n * `AnnotatedCodeBlock` annotates a single code surface; `DiffBlock` annotates a\n * before/after grid (each annotation also carries a `side`). The shared types\n * here are intentionally minimal — callers pass their own `side` handling and\n * decide which rows a marker lands on; this module only owns the parsing, the\n * resolved-record shape, and the rendered marker + rail chrome.\n */\n\n/* ── Line-ref parsing ──────────────────────────────────────────────────────── */\n\n/**\n * Parse a 1-based `lines` ref (`\"3\"` or `\"3-5\"`) into an inclusive `[start,end]`\n * pair, clamped to `[1, lineCount]`. Returns `null` for malformed or fully\n * out-of-range refs so callers can ignore them gracefully. A reversed range\n * (`\"5-3\"`) is normalized; a partially out-of-range range is clamped.\n */\nexport function parseLineRange(\n ref: string,\n lineCount: number,\n): { start: number; end: number } | null {\n const match = /^\\s*(\\d+)\\s*(?:-\\s*(\\d+)\\s*)?$/.exec(ref);\n if (!match) return null;\n let start = Number.parseInt(match[1], 10);\n let end = match[2] != null ? Number.parseInt(match[2], 10) : start;\n if (!Number.isFinite(start) || !Number.isFinite(end)) return null;\n if (start > end) [start, end] = [end, start];\n // Fully outside the file → ignore.\n if (end < 1 || start > lineCount) return null;\n return { start: Math.max(1, start), end: Math.min(lineCount, end) };\n}\n\n/** The minimal annotation shape the rail needs (a superset works too). */\nexport interface RailAnnotation {\n lines: string;\n label?: string;\n note: string;\n}\n\nexport interface ResolvedAnnotation<A extends RailAnnotation = RailAnnotation> {\n /** Index in the original `annotations` array (stable hover key). */\n index: number;\n /** 1-based marker number (authoring order). */\n marker: number;\n annotation: A;\n range: { start: number; end: number } | null;\n}\n\n/**\n * Resolve a raw annotation list into stable, marker-numbered records, parsing\n * each `lines` ref against `lineCount`. `lineCountFor` lets the diff block pick a\n * per-annotation line count (before-side vs after-side); annotated-code passes a\n * single constant. Markers are authoring-order, 1-based, and assigned to ALL\n * annotations (even unresolved ones) so numbering is stable regardless of which\n * refs happen to match.\n */\nexport function resolveAnnotations<A extends RailAnnotation>(\n annotations: A[] | undefined,\n lineCountFor: (annotation: A) => number,\n): ResolvedAnnotation<A>[] {\n return (annotations ?? []).map((annotation, index) => ({\n index,\n marker: index + 1,\n annotation,\n range: parseLineRange(annotation.lines, lineCountFor(annotation)),\n }));\n}\n\n/** Map a 1-based line number → the resolved annotations covering it. */\nexport function buildLineMarkerMap<A extends RailAnnotation>(\n resolved: ResolvedAnnotation<A>[],\n): Map<number, ResolvedAnnotation<A>[]> {\n const map = new Map<number, ResolvedAnnotation<A>[]>();\n for (const item of resolved) {\n if (!item.range) continue;\n for (let n = item.range.start; n <= item.range.end; n += 1) {\n const list = map.get(n) ?? [];\n list.push(item);\n map.set(n, list);\n }\n }\n return map;\n}\n\n/** Human label for a resolved annotation's line span (\"Line 8\" / \"Lines 3–6\"). */\nexport function rangeLabel(item: ResolvedAnnotation): string {\n if (!item.range) return `Lines ${item.annotation.lines}`;\n return item.range.start === item.range.end\n ? `Line ${item.range.start}`\n : `Lines ${item.range.start}–${item.range.end}`;\n}\n\n/* ── Marker ────────────────────────────────────────────────────────────────── */\n\n/**\n * The numbered amber pip rendered on an annotated code row's gutter. `active`\n * brightens it when its note (or a co-located row) is hovered.\n */\nexport function AnnotationGutterMarker({\n marker,\n active,\n className,\n}: {\n marker: number;\n active: boolean;\n className?: string;\n}) {\n return (\n <span\n aria-hidden\n className={cn(\n \"inline-flex size-[15px] shrink-0 items-center justify-center rounded-full text-[9px] font-semibold leading-none tabular-nums transition-colors\",\n active\n ? \"bg-amber-500 text-white dark:bg-amber-400 dark:text-amber-950\"\n : \"bg-amber-400/25 text-amber-700 dark:bg-amber-300/20 dark:text-amber-300\",\n className,\n )}\n >\n {marker}\n </span>\n );\n}\n\n/* ── Note rail ─────────────────────────────────────────────────────────────── */\n\n/**\n * The responsive list of line-anchored note cards. Each card shows its marker\n * pip, the resolved line span (\"Line 8\"), an optional label, and the markdown\n * `note` (via `ctx.renderMarkdown`). Hovering a card sets the active index;\n * `activeIndex` driven from outside lets a hovered code row light its card and\n * vice-versa. Only annotations whose `range` resolved are listed.\n */\nexport function AnnotationNoteRail<A extends RailAnnotation>({\n items,\n activeIndex,\n onActiveChange,\n ctx,\n className,\n showMarker = false,\n}: {\n items: ResolvedAnnotation<A>[];\n activeIndex: number | null;\n onActiveChange: (index: number | null) => void;\n ctx: BlockRenderContext;\n className?: string;\n /** Show a leading numbered pip on each card (diff block). */\n showMarker?: boolean;\n}) {\n const sideAnnotations = useMemo(\n () => items.filter((item) => item.range),\n [items],\n );\n return (\n <div className={cn(\"flex flex-col gap-2.5\", className)}>\n {sideAnnotations.map((item) => {\n const isActive = activeIndex === item.index;\n return (\n <div\n key={item.index}\n onMouseEnter={() => onActiveChange(item.index)}\n onMouseLeave={() => onActiveChange(null)}\n className={cn(\n \"rounded-lg border px-3.5 py-2.5 transition-colors\",\n isActive\n ? \"border-amber-400/70 bg-amber-50 dark:border-amber-300/40 dark:bg-amber-300/[0.08]\"\n : \"border-plan-line bg-plan-block/40 hover:border-amber-400/50\",\n )}\n >\n <div\n className={cn(\n \"flex flex-wrap gap-x-2 gap-y-0.5\",\n showMarker ? \"items-center\" : \"items-baseline\",\n )}\n >\n {showMarker && (\n <AnnotationGutterMarker\n marker={item.marker}\n active={isActive}\n />\n )}\n <span className=\"text-[11px] font-semibold uppercase tracking-wide text-plan-muted\">\n {rangeLabel(item)}\n </span>\n {item.annotation.label && (\n <span className=\"text-[13px] font-semibold text-plan-text\">\n {item.annotation.label}\n </span>\n )}\n </div>\n <div className=\"plan-annotation-note mt-1 text-[13px] leading-relaxed text-plan-text/85\">\n {ctx.renderMarkdown ? (\n ctx.renderMarkdown(item.annotation.note)\n ) : (\n <p>{item.annotation.note}</p>\n )}\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n\n/** Whether a resolved list has at least one note worth rendering a rail for. */\nexport function hasRailAnnotations(items: ResolvedAnnotation[]): boolean {\n return items.some((item) => item.range);\n}\n\nexport type AnnotationRailChildren = ReactNode;\n"]}
|
|
@@ -190,7 +190,7 @@ function HighlightedCodeTextarea({ value, language, label, editable, onChange, }
|
|
|
190
190
|
layer.scrollTop = event.currentTarget.scrollTop;
|
|
191
191
|
layer.scrollLeft = event.currentTarget.scrollLeft;
|
|
192
192
|
};
|
|
193
|
-
return (_jsxs("div", { className: cn("relative min-h-[140px] overflow-hidden rounded-md border border-input bg-background text-foreground focus-within:ring-1 focus-within:ring-ring", !editable && "cursor-not-allowed opacity-50"), "data-code-tabs-highlighted-editor": true, children: [_jsx("pre", { ref: highlightLayerRef, "aria-hidden": "true", className: "pointer-events-none absolute inset-0 m-0 overflow-hidden whitespace-pre px-3 py-2 font-mono
|
|
193
|
+
return (_jsxs("div", { className: cn("relative min-h-[140px] overflow-hidden rounded-md border border-input bg-background text-foreground focus-within:ring-1 focus-within:ring-ring", !editable && "cursor-not-allowed opacity-50"), "data-code-tabs-highlighted-editor": true, children: [_jsx("pre", { ref: highlightLayerRef, "aria-hidden": "true", className: "pointer-events-none absolute inset-0 m-0 overflow-hidden whitespace-pre px-3 py-2 font-mono [font-size:var(--plan-code-size)] leading-5", "data-code-tabs-highlight-layer": true, children: _jsxs("code", { children: [highlighted, value.endsWith("\n") ? " " : null] }) }), _jsx("textarea", { "data-plan-interactive": true, spellCheck: false, wrap: "off", className: cn("relative z-10 block min-h-[140px] w-full resize-y overflow-auto rounded-md border-0 bg-transparent px-3 py-2 font-mono [font-size:var(--plan-code-size)] leading-5 caret-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed", value ? "text-transparent" : "text-muted-foreground"), value: value, disabled: !editable, onChange: onChange, onScroll: syncScroll })] }));
|
|
194
194
|
}
|
|
195
195
|
/**
|
|
196
196
|
* Editor: a file-tab strip (one tab active at a time) with the active tab's code
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-tabs.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/code-tabs.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type ReactNode,\n type UIEvent,\n} from \"react\";\nimport { IconCode, IconPencil, IconPlus, IconTrash } from \"@tabler/icons-react\";\nimport { common, createLowlight } from \"lowlight\";\nimport { cn } from \"../../utils.js\";\nimport { defineBlock } from \"../types.js\";\nimport type { BlockReadProps, BlockEditProps } from \"../types.js\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"../../components/ui/popover.js\";\nimport { CodeSurface, DEFAULT_CODE_MAX_LINES } from \"./HighlightedCode.js\";\nimport {\n codeTabsSchema,\n codeTabsMdx,\n type CodeTabsData,\n type CodeTabsTab,\n} from \"./code-tabs.config.js\";\n\n/**\n * Standard `code-tabs` block (STANDARD core library): a vertical file tab rail\n * with Shiki-highlighted code panes. Moved verbatim from the plan\n * `CodeTabsBlock` (`DocumentArea.tsx`) so its rendered output is unchanged, then\n * generalized to the registry `Read`/`Edit` contract. Shareable by any app that\n * registers the core block library.\n *\n * `Edit` is hybrid: each tab's `code` field renders as a code-style monospace\n * text area, while tab metadata (label/language/caption/add/remove) stays in a\n * settings popover so the document surface only exposes authored content.\n */\n\n/* ── Syntax highlighting helpers ──────────────────────────────────────────── */\n\nconst lowlight = createLowlight(common);\n\ntype LowlightNode = {\n type: string;\n value?: string;\n properties?: {\n className?: string[] | string;\n };\n children?: LowlightNode[];\n};\n\nconst LANGUAGE_ALIASES: Record<string, string> = {\n cjs: \"javascript\",\n cts: \"typescript\",\n htm: \"html\",\n js: \"javascript\",\n jsonc: \"json\",\n jsx: \"jsx\",\n md: \"markdown\",\n mdx: \"markdown\",\n mjs: \"javascript\",\n mts: \"typescript\",\n py: \"python\",\n rb: \"ruby\",\n rs: \"rust\",\n sh: \"bash\",\n shell: \"bash\",\n ts: \"typescript\",\n tsx: \"tsx\",\n yml: \"yaml\",\n zsh: \"bash\",\n};\n\nconst TOKEN_CLASS_NAMES: Record<string, string> = {\n \"hljs-addition\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-attr\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-attribute\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-built_in\": \"text-amber-700 dark:text-amber-300\",\n \"hljs-bullet\": \"text-primary\",\n \"hljs-comment\": \"text-muted-foreground italic\",\n \"hljs-deletion\": \"text-destructive\",\n \"hljs-doctag\": \"text-destructive\",\n \"hljs-emphasis\": \"italic\",\n \"hljs-formula\": \"text-destructive\",\n \"hljs-keyword\": \"text-rose-700 dark:text-rose-300\",\n \"hljs-link\": \"text-primary underline-offset-2\",\n \"hljs-literal\": \"text-violet-700 dark:text-violet-300\",\n \"hljs-meta\": \"text-primary\",\n \"hljs-meta-string\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-name\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-number\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-params\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-property\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-quote\": \"text-muted-foreground italic\",\n \"hljs-regexp\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-section\": \"text-violet-700 dark:text-violet-300\",\n \"hljs-selector-attr\": \"text-primary\",\n \"hljs-selector-class\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-selector-id\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-selector-pseudo\": \"text-primary\",\n \"hljs-selector-tag\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-string\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-strong\": \"font-semibold\",\n \"hljs-subst\": \"text-destructive\",\n \"hljs-symbol\": \"text-primary\",\n \"hljs-tag\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-template-variable\": \"text-amber-700 dark:text-amber-300\",\n \"hljs-title\": \"text-violet-700 dark:text-violet-300\",\n \"hljs-type\": \"text-amber-700 dark:text-amber-300\",\n \"hljs-variable\": \"text-amber-700 dark:text-amber-300\",\n language_: \"text-amber-700 dark:text-amber-300\",\n};\n\nfunction normalizeCodeLanguage(value?: string | null): string | null {\n const raw = value\n ?.trim()\n .toLowerCase()\n .replace(/^language-/, \"\");\n if (!raw) return null;\n const normalized = LANGUAGE_ALIASES[raw] ?? raw;\n return lowlight.registered(normalized) ? normalized : null;\n}\n\nfunction inferLanguageFromFilename(filename?: string | null): string | null {\n const basename = filename?.split(\"/\").pop()?.toLowerCase();\n if (!basename) return null;\n if (basename === \"dockerfile\") return normalizeCodeLanguage(\"bash\");\n const extension = basename.includes(\".\")\n ? basename.split(\".\").pop()\n : undefined;\n return normalizeCodeLanguage(extension);\n}\n\nfunction codeTabLanguage(tab?: CodeTabsTab): string | undefined {\n return (\n normalizeCodeLanguage(tab?.language) ??\n inferLanguageFromFilename(tab?.label) ??\n undefined\n );\n}\n\nfunction tokenClassName(value: string[] | string | undefined): string {\n const classes = Array.isArray(value)\n ? value\n : typeof value === \"string\"\n ? value.split(/\\s+/)\n : [];\n return classes\n .map((className) => TOKEN_CLASS_NAMES[className] ?? \"\")\n .filter(Boolean)\n .join(\" \");\n}\n\nfunction hastToReact(children: LowlightNode[], keyPrefix: string): ReactNode[] {\n return children.map((node, index) => {\n if (node.type === \"text\") return node.value ?? \"\";\n if (node.type === \"element\") {\n const key = `${keyPrefix}${index}`;\n const renderedChildren = node.children?.length\n ? hastToReact(node.children, `${key}-`)\n : null;\n const className = tokenClassName(node.properties?.className);\n return (\n <span key={key} className={className || undefined}>\n {renderedChildren}\n </span>\n );\n }\n return null;\n });\n}\n\nfunction highlightCode(code: string, language?: string): ReactNode {\n const normalized = normalizeCodeLanguage(language);\n if (!normalized || normalized === \"plaintext\" || normalized === \"text\") {\n return code;\n }\n try {\n const tree = lowlight.highlight(normalized, code) as LowlightNode;\n return hastToReact(tree.children ?? [], `${normalized}-`);\n } catch {\n return code;\n }\n}\n\n/* ── Read (vertical tab rail + Shiki) ──────────────────────────────────────── */\n\nfunction CodeTabsRead({ data, blockId, title }: BlockReadProps<CodeTabsData>) {\n const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? \"\");\n const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <div className=\"grid overflow-hidden border-y border-plan-line md:grid-cols-[300px_minmax(0,1fr)]\">\n <div className=\"border-plan-line md:border-r\">\n {data.tabs.map((tab) => (\n <button\n key={tab.id}\n type=\"button\"\n data-plan-interactive\n className={cn(\n \"flex w-full items-start gap-3 border-b border-plan-line px-4 py-4 text-left\",\n tab.id === active?.id\n ? \"bg-primary/10 text-plan-text dark:bg-primary/20\"\n : \"text-plan-muted hover:bg-accent/30\",\n )}\n onClick={() => setActiveId(tab.id)}\n >\n <IconCode className=\"mt-0.5 size-4 shrink-0\" />\n <span className=\"min-w-0\">\n <span className=\"block truncate font-mono text-sm font-semibold\">\n {tab.label}\n </span>\n {tab.caption && (\n <span className=\"mt-1 block text-xs leading-5\">\n {tab.caption}\n </span>\n )}\n </span>\n </button>\n ))}\n </div>\n <div className=\"min-w-0 p-5\">\n {active && (\n <>\n <h3 className=\"text-2xl font-semibold tracking-tight\">\n {active.label}\n </h3>\n {active.caption && (\n <p className=\"mt-2 text-plan-muted\">{active.caption}</p>\n )}\n <CodeSurface\n code={active.code}\n language={codeTabLanguage(active)}\n maxLines={active.maxLines}\n />\n </>\n )}\n </div>\n </div>\n </section>\n );\n}\n\n/* ── Edit (code text areas per tab) ────────────────────────────────────────── */\n\nconst inputClass =\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\";\n\n/** Language options for the per-tab picker; \"\" is the Auto-detect sentinel. */\nconst CODE_TAB_LANGUAGES: ReadonlyArray<{ value: string; label: string }> = [\n { value: \"\", label: \"Auto\" },\n { value: \"typescript\", label: \"TypeScript\" },\n { value: \"javascript\", label: \"JavaScript\" },\n { value: \"tsx\", label: \"TSX\" },\n { value: \"jsx\", label: \"JSX\" },\n { value: \"json\", label: \"JSON\" },\n { value: \"html\", label: \"HTML\" },\n { value: \"css\", label: \"CSS\" },\n { value: \"bash\", label: \"Bash\" },\n { value: \"python\", label: \"Python\" },\n { value: \"sql\", label: \"SQL\" },\n { value: \"yaml\", label: \"YAML\" },\n { value: \"markdown\", label: \"Markdown\" },\n { value: \"graphql\", label: \"GraphQL\" },\n { value: \"go\", label: \"Go\" },\n { value: \"rust\", label: \"Rust\" },\n { value: \"diff\", label: \"Diff\" },\n];\n\n/** Mint a reasonably-unique code-tab id without pulling a dep into core. */\nfunction newCodeTabId(): string {\n return `code-tab-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction HighlightedCodeTextarea({\n value,\n language,\n label,\n editable,\n onChange,\n}: {\n value: string;\n language?: string;\n label?: string;\n editable: boolean;\n onChange: (event: ChangeEvent<HTMLTextAreaElement>) => void;\n}) {\n const highlightLayerRef = useRef<HTMLPreElement>(null);\n const resolvedLanguage =\n normalizeCodeLanguage(language) ?? inferLanguageFromFilename(label);\n const highlighted = useMemo(\n () => highlightCode(value, resolvedLanguage ?? undefined),\n [resolvedLanguage, value],\n );\n\n const syncScroll = (event: UIEvent<HTMLTextAreaElement>) => {\n const layer = highlightLayerRef.current;\n if (!layer) return;\n layer.scrollTop = event.currentTarget.scrollTop;\n layer.scrollLeft = event.currentTarget.scrollLeft;\n };\n\n return (\n <div\n className={cn(\n \"relative min-h-[140px] overflow-hidden rounded-md border border-input bg-background text-foreground focus-within:ring-1 focus-within:ring-ring\",\n !editable && \"cursor-not-allowed opacity-50\",\n )}\n data-code-tabs-highlighted-editor\n >\n <pre\n ref={highlightLayerRef}\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-0 m-0 overflow-hidden whitespace-pre px-3 py-2 font-mono text-xs leading-5\"\n data-code-tabs-highlight-layer\n >\n <code>\n {highlighted}\n {value.endsWith(\"\\n\") ? \" \" : null}\n </code>\n </pre>\n <textarea\n data-plan-interactive\n spellCheck={false}\n wrap=\"off\"\n className={cn(\n \"relative z-10 block min-h-[140px] w-full resize-y overflow-auto rounded-md border-0 bg-transparent px-3 py-2 font-mono text-xs leading-5 caret-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed\",\n value ? \"text-transparent\" : \"text-muted-foreground\",\n )}\n value={value}\n disabled={!editable}\n onChange={onChange}\n onScroll={syncScroll}\n />\n </div>\n );\n}\n\n/**\n * Editor: a file-tab strip (one tab active at a time) with the active tab's code\n * editable inline. Tab metadata is edited from the settings popover, mirroring\n * the standard `tabs` block and keeping schema-ish controls out of the document.\n */\nfunction CodeTabsEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<CodeTabsData>) {\n const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? \"\");\n const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];\n\n const commit = (tabs: CodeTabsTab[]) => onChange({ tabs });\n\n const updateTab = (id: string, patch: Partial<CodeTabsTab>) =>\n commit(\n data.tabs.map((tab) => (tab.id === id ? { ...tab, ...patch } : tab)),\n );\n\n const removeTab = (id: string) => {\n const next = data.tabs.filter((tab) => tab.id !== id);\n if (next.length === 0) return; // tabs must keep at least one (schema min 1)\n commit(next);\n if (activeId === id) setActiveId(next[0]?.id ?? \"\");\n };\n\n const addTab = () => {\n if (data.tabs.length >= 12) return; // schema max\n const id = newCodeTabId();\n commit([\n ...data.tabs,\n { id, label: `file-${data.tabs.length + 1}.ts`, code: \"\" },\n ]);\n setActiveId(id);\n };\n\n return (\n <div className=\"an-code-tabs-editor flex min-w-0 flex-col gap-4\">\n <div className=\"flex w-full min-w-0 items-start gap-2\">\n <div\n className=\"flex w-full min-w-0 flex-1 flex-nowrap items-center gap-1 overflow-x-auto\"\n role=\"tablist\"\n data-plan-interactive\n >\n {data.tabs.map((tab) => {\n const selected = tab.id === active?.id;\n return (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n onClick={() => setActiveId(tab.id)}\n className={cn(\n \"flex shrink-0 items-center gap-2 whitespace-nowrap rounded-lg border border-transparent px-3 py-2 font-mono text-sm font-semibold transition-colors\",\n selected\n ? \"bg-primary/10 text-plan-text dark:bg-primary/20\"\n : \"text-plan-muted hover:bg-plan-block/60 hover:text-plan-text\",\n )}\n >\n <IconCode className=\"size-4 shrink-0\" />\n {tab.label}\n </button>\n );\n })}\n </div>\n {editable && (\n <CodeTabsSettingsPopover\n active={active}\n tabs={data.tabs}\n onUpdate={updateTab}\n onAdd={addTab}\n onRemove={removeTab}\n />\n )}\n </div>\n {active && (\n <HighlightedCodeTextarea\n value={active.code}\n editable={editable}\n label={active.label}\n language={active.language}\n onChange={(event) =>\n updateTab(active.id, { code: event.target.value })\n }\n />\n )}\n </div>\n );\n}\n\nfunction CodeTabsSettingsPopover({\n active,\n tabs,\n onUpdate,\n onAdd,\n onRemove,\n}: {\n active: CodeTabsTab | undefined;\n tabs: CodeTabsTab[];\n onUpdate: (id: string, patch: Partial<CodeTabsTab>) => void;\n onAdd: () => void;\n onRemove: (id: string) => void;\n}) {\n return (\n <Popover>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n data-plan-interactive\n aria-label=\"Edit code tabs\"\n className=\"flex size-8 shrink-0 items-center justify-center rounded-md text-plan-muted transition-colors hover:text-plan-text focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n >\n <IconPencil className=\"size-4\" />\n </button>\n </PopoverTrigger>\n <PopoverContent\n align=\"end\"\n side=\"bottom\"\n className=\"w-80 p-0\"\n data-plan-interactive\n >\n <div className=\"border-b border-border px-3 py-2\">\n <div className=\"text-sm font-semibold text-foreground\">\n Code tab settings\n </div>\n <div className=\"text-xs text-muted-foreground\">\n Rename the active tab or manage its metadata.\n </div>\n </div>\n <div className=\"grid gap-3 p-3\">\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Active tab label\n </span>\n <input\n type=\"text\"\n data-plan-interactive\n className={inputClass}\n value={active?.label ?? \"\"}\n disabled={!active}\n onChange={(event) => {\n if (!active) return;\n onUpdate(active.id, { label: event.target.value });\n }}\n />\n </label>\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Language\n </span>\n <select\n data-plan-interactive\n className={inputClass}\n value={active?.language ?? \"\"}\n disabled={!active}\n onChange={(event) => {\n if (!active) return;\n onUpdate(active.id, {\n language: event.target.value || undefined,\n });\n }}\n >\n {CODE_TAB_LANGUAGES.map((option) => (\n <option key={option.value || \"auto\"} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </label>\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Caption\n </span>\n <input\n type=\"text\"\n data-plan-interactive\n className={inputClass}\n value={active?.caption ?? \"\"}\n disabled={!active}\n onChange={(event) => {\n if (!active) return;\n onUpdate(active.id, {\n caption: event.target.value || undefined,\n });\n }}\n />\n </label>\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Max lines before expand\n </span>\n <input\n type=\"number\"\n min={0}\n step={1}\n data-plan-interactive\n className={inputClass}\n placeholder={`${DEFAULT_CODE_MAX_LINES} (default) · 0 = no limit`}\n value={active?.maxLines ?? \"\"}\n disabled={!active}\n onChange={(event) => {\n if (!active) return;\n const raw = event.target.value.trim();\n const parsed = raw === \"\" ? undefined : Number(raw);\n onUpdate(active.id, {\n maxLines:\n parsed === undefined || Number.isNaN(parsed)\n ? undefined\n : Math.max(0, Math.min(2000, Math.floor(parsed))),\n });\n }}\n />\n </label>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n data-plan-interactive\n disabled={tabs.length >= 12}\n onClick={onAdd}\n className=\"inline-flex h-8 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <IconPlus className=\"size-3.5\" />\n Add tab\n </button>\n <button\n type=\"button\"\n data-plan-interactive\n disabled={!active || tabs.length <= 1}\n onClick={() => {\n if (!active) return;\n onRemove(active.id);\n }}\n className=\"inline-flex h-8 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-destructive transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <IconTrash className=\"size-3.5\" />\n Remove current\n </button>\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\n/* ── Spec ──────────────────────────────────────────────────────────────────── */\n\nexport const codeTabsBlock = defineBlock<CodeTabsData>({\n type: \"code-tabs\",\n schema: codeTabsSchema,\n mdx: codeTabsMdx,\n Read: CodeTabsRead,\n Edit: CodeTabsEdit,\n placement: [\"block\"],\n editSurface: \"inline\",\n label: \"Code tabs\",\n icon: IconCode,\n description:\n \"A vertical file tab rail of syntax-highlighted code snippets, one tab per file with an optional language and caption.\",\n});\n"]}
|
|
1
|
+
{"version":3,"file":"code-tabs.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/code-tabs.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,OAAO,EACP,MAAM,EACN,QAAQ,GAIT,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EACL,OAAO,EACP,cAAc,EACd,cAAc,GACf,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EACL,cAAc,EACd,WAAW,GAGZ,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;;GAUG;AAEH,iFAAiF;AAEjF,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;AAWxC,MAAM,gBAAgB,GAA2B;IAC/C,GAAG,EAAE,YAAY;IACjB,GAAG,EAAE,YAAY;IACjB,GAAG,EAAE,MAAM;IACX,EAAE,EAAE,YAAY;IAChB,KAAK,EAAE,MAAM;IACb,GAAG,EAAE,KAAK;IACV,EAAE,EAAE,UAAU;IACd,GAAG,EAAE,UAAU;IACf,GAAG,EAAE,YAAY;IACjB,GAAG,EAAE,YAAY;IACjB,EAAE,EAAE,QAAQ;IACZ,EAAE,EAAE,MAAM;IACV,EAAE,EAAE,MAAM;IACV,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,MAAM;IACb,EAAE,EAAE,YAAY;IAChB,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;CACZ,CAAC;AAEF,MAAM,iBAAiB,GAA2B;IAChD,eAAe,EAAE,wCAAwC;IACzD,WAAW,EAAE,gCAAgC;IAC7C,gBAAgB,EAAE,gCAAgC;IAClD,eAAe,EAAE,oCAAoC;IACrD,aAAa,EAAE,cAAc;IAC7B,cAAc,EAAE,8BAA8B;IAC9C,eAAe,EAAE,kBAAkB;IACnC,aAAa,EAAE,kBAAkB;IACjC,eAAe,EAAE,QAAQ;IACzB,cAAc,EAAE,kBAAkB;IAClC,cAAc,EAAE,kCAAkC;IAClD,WAAW,EAAE,iCAAiC;IAC9C,cAAc,EAAE,sCAAsC;IACtD,WAAW,EAAE,cAAc;IAC3B,kBAAkB,EAAE,wCAAwC;IAC5D,WAAW,EAAE,wCAAwC;IACrD,aAAa,EAAE,gCAAgC;IAC/C,aAAa,EAAE,gCAAgC;IAC/C,eAAe,EAAE,gCAAgC;IACjD,YAAY,EAAE,8BAA8B;IAC5C,aAAa,EAAE,wCAAwC;IACvD,cAAc,EAAE,sCAAsC;IACtD,oBAAoB,EAAE,cAAc;IACpC,qBAAqB,EAAE,wCAAwC;IAC/D,kBAAkB,EAAE,wCAAwC;IAC5D,sBAAsB,EAAE,cAAc;IACtC,mBAAmB,EAAE,wCAAwC;IAC7D,aAAa,EAAE,wCAAwC;IACvD,aAAa,EAAE,eAAe;IAC9B,YAAY,EAAE,kBAAkB;IAChC,aAAa,EAAE,cAAc;IAC7B,UAAU,EAAE,wCAAwC;IACpD,wBAAwB,EAAE,oCAAoC;IAC9D,YAAY,EAAE,sCAAsC;IACpD,WAAW,EAAE,oCAAoC;IACjD,eAAe,EAAE,oCAAoC;IACrD,SAAS,EAAE,oCAAoC;CAChD,CAAC;AAEF,SAAS,qBAAqB,CAAC,KAAqB;IAClD,MAAM,GAAG,GAAG,KAAK;QACf,EAAE,IAAI,EAAE;SACP,WAAW,EAAE;SACb,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,UAAU,GAAG,gBAAgB,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;IAChD,OAAO,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC;AAED,SAAS,yBAAyB,CAAC,QAAwB;IACzD,MAAM,QAAQ,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,CAAC;IAC3D,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,IAAI,QAAQ,KAAK,YAAY;QAAE,OAAO,qBAAqB,CAAC,MAAM,CAAC,CAAC;IACpE,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;QACtC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE;QAC3B,CAAC,CAAC,SAAS,CAAC;IACd,OAAO,qBAAqB,CAAC,SAAS,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,eAAe,CAAC,GAAiB;IACxC,OAAO,CACL,qBAAqB,CAAC,GAAG,EAAE,QAAQ,CAAC;QACpC,yBAAyB,CAAC,GAAG,EAAE,KAAK,CAAC;QACrC,SAAS,CACV,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,KAAoC;IAC1D,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAClC,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ;YACzB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC;YACpB,CAAC,CAAC,EAAE,CAAC;IACT,OAAO,OAAO;SACX,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;SACtD,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,SAAS,WAAW,CAAC,QAAwB,EAAE,SAAiB;IAC9D,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAClC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAClD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5B,MAAM,GAAG,GAAG,GAAG,SAAS,GAAG,KAAK,EAAE,CAAC;YACnC,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM;gBAC5C,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,GAAG,CAAC;gBACvC,CAAC,CAAC,IAAI,CAAC;YACT,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;YAC7D,OAAO,CACL,eAAgB,SAAS,EAAE,SAAS,IAAI,SAAS,YAC9C,gBAAgB,IADR,GAAG,CAEP,CACR,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,aAAa,CAAC,IAAY,EAAE,QAAiB;IACpD,MAAM,UAAU,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACnD,IAAI,CAAC,UAAU,IAAI,UAAU,KAAK,WAAW,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QACvE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAiB,CAAC;QAClE,OAAO,WAAW,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,EAAE,GAAG,UAAU,GAAG,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,kFAAkF;AAElF,SAAS,YAAY,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAgC;IAC1E,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,QAAQ,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5E,OAAO,CACL,mBAAS,SAAS,EAAC,YAAY,mBAAgB,OAAO,aACnD,KAAK,IAAI,cAAK,SAAS,EAAC,kBAAkB,YAAE,KAAK,GAAO,EACzD,eAAK,SAAS,EAAC,mFAAmF,aAChG,cAAK,SAAS,EAAC,8BAA8B,YAC1C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACtB,kBAEE,IAAI,EAAC,QAAQ,iCAEb,SAAS,EAAE,EAAE,CACX,6EAA6E,EAC7E,GAAG,CAAC,EAAE,KAAK,MAAM,EAAE,EAAE;gCACnB,CAAC,CAAC,iDAAiD;gCACnD,CAAC,CAAC,oCAAoC,CACzC,EACD,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAElC,KAAC,QAAQ,IAAC,SAAS,EAAC,wBAAwB,GAAG,EAC/C,gBAAM,SAAS,EAAC,SAAS,aACvB,eAAM,SAAS,EAAC,gDAAgD,YAC7D,GAAG,CAAC,KAAK,GACL,EACN,GAAG,CAAC,OAAO,IAAI,CACd,eAAM,SAAS,EAAC,8BAA8B,YAC3C,GAAG,CAAC,OAAO,GACP,CACR,IACI,KArBF,GAAG,CAAC,EAAE,CAsBJ,CACV,CAAC,GACE,EACN,cAAK,SAAS,EAAC,aAAa,YACzB,MAAM,IAAI,CACT,8BACE,aAAI,SAAS,EAAC,uCAAuC,YAClD,MAAM,CAAC,KAAK,GACV,EACJ,MAAM,CAAC,OAAO,IAAI,CACjB,YAAG,SAAS,EAAC,sBAAsB,YAAE,MAAM,CAAC,OAAO,GAAK,CACzD,EACD,KAAC,WAAW,IACV,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,QAAQ,EAAE,eAAe,CAAC,MAAM,CAAC,EACjC,QAAQ,EAAE,MAAM,CAAC,QAAQ,GACzB,IACD,CACJ,GACG,IACF,IACE,CACX,CAAC;AACJ,CAAC;AAED,kFAAkF;AAElF,MAAM,UAAU,GACd,6PAA6P,CAAC;AAEhQ,+EAA+E;AAC/E,MAAM,kBAAkB,GAAoD;IAC1E,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;IAC5B,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE;IAC5C,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE;IAC5C,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;IAC9B,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;IAC9B,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;IAChC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;IAChC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;IAC9B,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;IAChC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;IACpC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;IAC9B,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;IAChC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;IACxC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;IACtC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;IAC5B,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;IAChC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;CACjC,CAAC;AAEF,4EAA4E;AAC5E,SAAS,YAAY;IACnB,OAAO,YAAY,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AAC/D,CAAC;AAED,SAAS,uBAAuB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,QAAQ,GAOT;IACC,MAAM,iBAAiB,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IACvD,MAAM,gBAAgB,GACpB,qBAAqB,CAAC,QAAQ,CAAC,IAAI,yBAAyB,CAAC,KAAK,CAAC,CAAC;IACtE,MAAM,WAAW,GAAG,OAAO,CACzB,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,gBAAgB,IAAI,SAAS,CAAC,EACzD,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAC1B,CAAC;IAEF,MAAM,UAAU,GAAG,CAAC,KAAmC,EAAE,EAAE;QACzD,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,CAAC;QACxC,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC;QAChD,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC;IACpD,CAAC,CAAC;IAEF,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CACX,gJAAgJ,EAChJ,CAAC,QAAQ,IAAI,+BAA+B,CAC7C,wDAGD,cACE,GAAG,EAAE,iBAAiB,iBACV,MAAM,EAClB,SAAS,EAAC,yIAAyI,oDAGnJ,2BACG,WAAW,EACX,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAC7B,GACH,EACN,kDAEE,UAAU,EAAE,KAAK,EACjB,IAAI,EAAC,KAAK,EACV,SAAS,EAAE,EAAE,CACX,gQAAgQ,EAChQ,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,uBAAuB,CACrD,EACD,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,QAAQ,EACnB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,UAAU,GACpB,IACE,CACP,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,EACpB,IAAI,EACJ,QAAQ,EACR,QAAQ,GACqB;IAC7B,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,QAAQ,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAE5E,MAAM,MAAM,GAAG,CAAC,IAAmB,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3D,MAAM,SAAS,GAAG,CAAC,EAAU,EAAE,KAA2B,EAAE,EAAE,CAC5D,MAAM,CACJ,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CACrE,CAAC;IAEJ,MAAM,SAAS,GAAG,CAAC,EAAU,EAAE,EAAE;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACtD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,6CAA6C;QAC5E,MAAM,CAAC,IAAI,CAAC,CAAC;QACb,IAAI,QAAQ,KAAK,EAAE;YAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,GAAG,EAAE;QAClB,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE;YAAE,OAAO,CAAC,aAAa;QACjD,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC;QAC1B,MAAM,CAAC;YACL,GAAG,IAAI,CAAC,IAAI;YACZ,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE;SAC3D,CAAC,CAAC;QACH,WAAW,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAC,iDAAiD,aAC9D,eAAK,SAAS,EAAC,uCAAuC,aACpD,cACE,SAAS,EAAC,2EAA2E,EACrF,IAAI,EAAC,SAAS,2CAGb,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;4BACrB,MAAM,QAAQ,GAAG,GAAG,CAAC,EAAE,KAAK,MAAM,EAAE,EAAE,CAAC;4BACvC,OAAO,CACL,kBAEE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,KAAK,mBACK,QAAQ,EACvB,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,EAClC,SAAS,EAAE,EAAE,CACX,qJAAqJ,EACrJ,QAAQ;oCACN,CAAC,CAAC,iDAAiD;oCACnD,CAAC,CAAC,6DAA6D,CAClE,aAED,KAAC,QAAQ,IAAC,SAAS,EAAC,iBAAiB,GAAG,EACvC,GAAG,CAAC,KAAK,KAbL,GAAG,CAAC,EAAE,CAcJ,CACV,CAAC;wBACJ,CAAC,CAAC,GACE,EACL,QAAQ,IAAI,CACX,KAAC,uBAAuB,IACtB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,IAAI,CAAC,IAAI,EACf,QAAQ,EAAE,SAAS,EACnB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,SAAS,GACnB,CACH,IACG,EACL,MAAM,IAAI,CACT,KAAC,uBAAuB,IACtB,KAAK,EAAE,MAAM,CAAC,IAAI,EAClB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,CAAC,KAAK,EACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ,EACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,SAAS,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GAEpD,CACH,IACG,CACP,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAAC,EAC/B,MAAM,EACN,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,QAAQ,GAOT;IACC,OAAO,CACL,MAAC,OAAO,eACN,KAAC,cAAc,IAAC,OAAO,kBACrB,iBACE,IAAI,EAAC,QAAQ,+CAEF,gBAAgB,EAC3B,SAAS,EAAC,4LAA4L,YAEtM,KAAC,UAAU,IAAC,SAAS,EAAC,QAAQ,GAAG,GAC1B,GACM,EACjB,MAAC,cAAc,IACb,KAAK,EAAC,KAAK,EACX,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,UAAU,4CAGpB,eAAK,SAAS,EAAC,kCAAkC,aAC/C,cAAK,SAAS,EAAC,uCAAuC,kCAEhD,EACN,cAAK,SAAS,EAAC,+BAA+B,8DAExC,IACF,EACN,eAAK,SAAS,EAAC,gBAAgB,aAC7B,iBAAO,SAAS,EAAC,cAAc,aAC7B,eAAM,SAAS,EAAC,2CAA2C,iCAEpD,EACP,gBACE,IAAI,EAAC,MAAM,iCAEX,SAAS,EAAE,UAAU,EACrB,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,EAC1B,QAAQ,EAAE,CAAC,MAAM,EACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;4CAClB,IAAI,CAAC,MAAM;gDAAE,OAAO;4CACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;wCACrD,CAAC,GACD,IACI,EACR,iBAAO,SAAS,EAAC,cAAc,aAC7B,eAAM,SAAS,EAAC,2CAA2C,yBAEpD,EACP,gDAEE,SAAS,EAAE,UAAU,EACrB,KAAK,EAAE,MAAM,EAAE,QAAQ,IAAI,EAAE,EAC7B,QAAQ,EAAE,CAAC,MAAM,EACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;4CAClB,IAAI,CAAC,MAAM;gDAAE,OAAO;4CACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,EAAE;gDAClB,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,SAAS;6CAC1C,CAAC,CAAC;wCACL,CAAC,YAEA,kBAAkB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAClC,iBAAqC,KAAK,EAAE,MAAM,CAAC,KAAK,YACrD,MAAM,CAAC,KAAK,IADF,MAAM,CAAC,KAAK,IAAI,MAAM,CAE1B,CACV,CAAC,GACK,IACH,EACR,iBAAO,SAAS,EAAC,cAAc,aAC7B,eAAM,SAAS,EAAC,2CAA2C,wBAEpD,EACP,gBACE,IAAI,EAAC,MAAM,iCAEX,SAAS,EAAE,UAAU,EACrB,KAAK,EAAE,MAAM,EAAE,OAAO,IAAI,EAAE,EAC5B,QAAQ,EAAE,CAAC,MAAM,EACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;4CAClB,IAAI,CAAC,MAAM;gDAAE,OAAO;4CACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,EAAE;gDAClB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,SAAS;6CACzC,CAAC,CAAC;wCACL,CAAC,GACD,IACI,EACR,iBAAO,SAAS,EAAC,cAAc,aAC7B,eAAM,SAAS,EAAC,2CAA2C,wCAEpD,EACP,gBACE,IAAI,EAAC,QAAQ,EACb,GAAG,EAAE,CAAC,EACN,IAAI,EAAE,CAAC,iCAEP,SAAS,EAAE,UAAU,EACrB,WAAW,EAAE,GAAG,sBAAsB,2BAA2B,EACjE,KAAK,EAAE,MAAM,EAAE,QAAQ,IAAI,EAAE,EAC7B,QAAQ,EAAE,CAAC,MAAM,EACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;4CAClB,IAAI,CAAC,MAAM;gDAAE,OAAO;4CACpB,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;4CACtC,MAAM,MAAM,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;4CACpD,QAAQ,CAAC,MAAM,CAAC,EAAE,EAAE;gDAClB,QAAQ,EACN,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;oDAC1C,CAAC,CAAC,SAAS;oDACX,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;6CACtD,CAAC,CAAC;wCACL,CAAC,GACD,IACI,EACR,eAAK,SAAS,EAAC,yBAAyB,aACtC,kBACE,IAAI,EAAC,QAAQ,iCAEb,QAAQ,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE,EAC3B,OAAO,EAAE,KAAK,EACd,SAAS,EAAC,mMAAmM,aAE7M,KAAC,QAAQ,IAAC,SAAS,EAAC,UAAU,GAAG,eAE1B,EACT,kBACE,IAAI,EAAC,QAAQ,iCAEb,QAAQ,EAAE,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EACrC,OAAO,EAAE,GAAG,EAAE;4CACZ,IAAI,CAAC,MAAM;gDAAE,OAAO;4CACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;wCACtB,CAAC,EACD,SAAS,EAAC,4MAA4M,aAEtN,KAAC,SAAS,IAAC,SAAS,EAAC,UAAU,GAAG,sBAE3B,IACL,IACF,IACS,IACT,CACX,CAAC;AACJ,CAAC;AAED,kFAAkF;AAElF,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAe;IACrD,IAAI,EAAE,WAAW;IACjB,MAAM,EAAE,cAAc;IACtB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,YAAY;IAClB,SAAS,EAAE,CAAC,OAAO,CAAC;IACpB,WAAW,EAAE,QAAQ;IACrB,KAAK,EAAE,WAAW;IAClB,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,uHAAuH;CAC1H,CAAC,CAAC","sourcesContent":["import {\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type ReactNode,\n type UIEvent,\n} from \"react\";\nimport { IconCode, IconPencil, IconPlus, IconTrash } from \"@tabler/icons-react\";\nimport { common, createLowlight } from \"lowlight\";\nimport { cn } from \"../../utils.js\";\nimport { defineBlock } from \"../types.js\";\nimport type { BlockReadProps, BlockEditProps } from \"../types.js\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"../../components/ui/popover.js\";\nimport { CodeSurface, DEFAULT_CODE_MAX_LINES } from \"./HighlightedCode.js\";\nimport {\n codeTabsSchema,\n codeTabsMdx,\n type CodeTabsData,\n type CodeTabsTab,\n} from \"./code-tabs.config.js\";\n\n/**\n * Standard `code-tabs` block (STANDARD core library): a vertical file tab rail\n * with Shiki-highlighted code panes. Moved verbatim from the plan\n * `CodeTabsBlock` (`DocumentArea.tsx`) so its rendered output is unchanged, then\n * generalized to the registry `Read`/`Edit` contract. Shareable by any app that\n * registers the core block library.\n *\n * `Edit` is hybrid: each tab's `code` field renders as a code-style monospace\n * text area, while tab metadata (label/language/caption/add/remove) stays in a\n * settings popover so the document surface only exposes authored content.\n */\n\n/* ── Syntax highlighting helpers ──────────────────────────────────────────── */\n\nconst lowlight = createLowlight(common);\n\ntype LowlightNode = {\n type: string;\n value?: string;\n properties?: {\n className?: string[] | string;\n };\n children?: LowlightNode[];\n};\n\nconst LANGUAGE_ALIASES: Record<string, string> = {\n cjs: \"javascript\",\n cts: \"typescript\",\n htm: \"html\",\n js: \"javascript\",\n jsonc: \"json\",\n jsx: \"jsx\",\n md: \"markdown\",\n mdx: \"markdown\",\n mjs: \"javascript\",\n mts: \"typescript\",\n py: \"python\",\n rb: \"ruby\",\n rs: \"rust\",\n sh: \"bash\",\n shell: \"bash\",\n ts: \"typescript\",\n tsx: \"tsx\",\n yml: \"yaml\",\n zsh: \"bash\",\n};\n\nconst TOKEN_CLASS_NAMES: Record<string, string> = {\n \"hljs-addition\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-attr\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-attribute\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-built_in\": \"text-amber-700 dark:text-amber-300\",\n \"hljs-bullet\": \"text-primary\",\n \"hljs-comment\": \"text-muted-foreground italic\",\n \"hljs-deletion\": \"text-destructive\",\n \"hljs-doctag\": \"text-destructive\",\n \"hljs-emphasis\": \"italic\",\n \"hljs-formula\": \"text-destructive\",\n \"hljs-keyword\": \"text-rose-700 dark:text-rose-300\",\n \"hljs-link\": \"text-primary underline-offset-2\",\n \"hljs-literal\": \"text-violet-700 dark:text-violet-300\",\n \"hljs-meta\": \"text-primary\",\n \"hljs-meta-string\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-name\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-number\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-params\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-property\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-quote\": \"text-muted-foreground italic\",\n \"hljs-regexp\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-section\": \"text-violet-700 dark:text-violet-300\",\n \"hljs-selector-attr\": \"text-primary\",\n \"hljs-selector-class\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-selector-id\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-selector-pseudo\": \"text-primary\",\n \"hljs-selector-tag\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-string\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-strong\": \"font-semibold\",\n \"hljs-subst\": \"text-destructive\",\n \"hljs-symbol\": \"text-primary\",\n \"hljs-tag\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-template-variable\": \"text-amber-700 dark:text-amber-300\",\n \"hljs-title\": \"text-violet-700 dark:text-violet-300\",\n \"hljs-type\": \"text-amber-700 dark:text-amber-300\",\n \"hljs-variable\": \"text-amber-700 dark:text-amber-300\",\n language_: \"text-amber-700 dark:text-amber-300\",\n};\n\nfunction normalizeCodeLanguage(value?: string | null): string | null {\n const raw = value\n ?.trim()\n .toLowerCase()\n .replace(/^language-/, \"\");\n if (!raw) return null;\n const normalized = LANGUAGE_ALIASES[raw] ?? raw;\n return lowlight.registered(normalized) ? normalized : null;\n}\n\nfunction inferLanguageFromFilename(filename?: string | null): string | null {\n const basename = filename?.split(\"/\").pop()?.toLowerCase();\n if (!basename) return null;\n if (basename === \"dockerfile\") return normalizeCodeLanguage(\"bash\");\n const extension = basename.includes(\".\")\n ? basename.split(\".\").pop()\n : undefined;\n return normalizeCodeLanguage(extension);\n}\n\nfunction codeTabLanguage(tab?: CodeTabsTab): string | undefined {\n return (\n normalizeCodeLanguage(tab?.language) ??\n inferLanguageFromFilename(tab?.label) ??\n undefined\n );\n}\n\nfunction tokenClassName(value: string[] | string | undefined): string {\n const classes = Array.isArray(value)\n ? value\n : typeof value === \"string\"\n ? value.split(/\\s+/)\n : [];\n return classes\n .map((className) => TOKEN_CLASS_NAMES[className] ?? \"\")\n .filter(Boolean)\n .join(\" \");\n}\n\nfunction hastToReact(children: LowlightNode[], keyPrefix: string): ReactNode[] {\n return children.map((node, index) => {\n if (node.type === \"text\") return node.value ?? \"\";\n if (node.type === \"element\") {\n const key = `${keyPrefix}${index}`;\n const renderedChildren = node.children?.length\n ? hastToReact(node.children, `${key}-`)\n : null;\n const className = tokenClassName(node.properties?.className);\n return (\n <span key={key} className={className || undefined}>\n {renderedChildren}\n </span>\n );\n }\n return null;\n });\n}\n\nfunction highlightCode(code: string, language?: string): ReactNode {\n const normalized = normalizeCodeLanguage(language);\n if (!normalized || normalized === \"plaintext\" || normalized === \"text\") {\n return code;\n }\n try {\n const tree = lowlight.highlight(normalized, code) as LowlightNode;\n return hastToReact(tree.children ?? [], `${normalized}-`);\n } catch {\n return code;\n }\n}\n\n/* ── Read (vertical tab rail + Shiki) ──────────────────────────────────────── */\n\nfunction CodeTabsRead({ data, blockId, title }: BlockReadProps<CodeTabsData>) {\n const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? \"\");\n const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <div className=\"grid overflow-hidden border-y border-plan-line md:grid-cols-[300px_minmax(0,1fr)]\">\n <div className=\"border-plan-line md:border-r\">\n {data.tabs.map((tab) => (\n <button\n key={tab.id}\n type=\"button\"\n data-plan-interactive\n className={cn(\n \"flex w-full items-start gap-3 border-b border-plan-line px-4 py-4 text-left\",\n tab.id === active?.id\n ? \"bg-primary/10 text-plan-text dark:bg-primary/20\"\n : \"text-plan-muted hover:bg-accent/30\",\n )}\n onClick={() => setActiveId(tab.id)}\n >\n <IconCode className=\"mt-0.5 size-4 shrink-0\" />\n <span className=\"min-w-0\">\n <span className=\"block truncate font-mono text-sm font-semibold\">\n {tab.label}\n </span>\n {tab.caption && (\n <span className=\"mt-1 block text-xs leading-5\">\n {tab.caption}\n </span>\n )}\n </span>\n </button>\n ))}\n </div>\n <div className=\"min-w-0 p-5\">\n {active && (\n <>\n <h3 className=\"text-2xl font-semibold tracking-tight\">\n {active.label}\n </h3>\n {active.caption && (\n <p className=\"mt-2 text-plan-muted\">{active.caption}</p>\n )}\n <CodeSurface\n code={active.code}\n language={codeTabLanguage(active)}\n maxLines={active.maxLines}\n />\n </>\n )}\n </div>\n </div>\n </section>\n );\n}\n\n/* ── Edit (code text areas per tab) ────────────────────────────────────────── */\n\nconst inputClass =\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\";\n\n/** Language options for the per-tab picker; \"\" is the Auto-detect sentinel. */\nconst CODE_TAB_LANGUAGES: ReadonlyArray<{ value: string; label: string }> = [\n { value: \"\", label: \"Auto\" },\n { value: \"typescript\", label: \"TypeScript\" },\n { value: \"javascript\", label: \"JavaScript\" },\n { value: \"tsx\", label: \"TSX\" },\n { value: \"jsx\", label: \"JSX\" },\n { value: \"json\", label: \"JSON\" },\n { value: \"html\", label: \"HTML\" },\n { value: \"css\", label: \"CSS\" },\n { value: \"bash\", label: \"Bash\" },\n { value: \"python\", label: \"Python\" },\n { value: \"sql\", label: \"SQL\" },\n { value: \"yaml\", label: \"YAML\" },\n { value: \"markdown\", label: \"Markdown\" },\n { value: \"graphql\", label: \"GraphQL\" },\n { value: \"go\", label: \"Go\" },\n { value: \"rust\", label: \"Rust\" },\n { value: \"diff\", label: \"Diff\" },\n];\n\n/** Mint a reasonably-unique code-tab id without pulling a dep into core. */\nfunction newCodeTabId(): string {\n return `code-tab-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction HighlightedCodeTextarea({\n value,\n language,\n label,\n editable,\n onChange,\n}: {\n value: string;\n language?: string;\n label?: string;\n editable: boolean;\n onChange: (event: ChangeEvent<HTMLTextAreaElement>) => void;\n}) {\n const highlightLayerRef = useRef<HTMLPreElement>(null);\n const resolvedLanguage =\n normalizeCodeLanguage(language) ?? inferLanguageFromFilename(label);\n const highlighted = useMemo(\n () => highlightCode(value, resolvedLanguage ?? undefined),\n [resolvedLanguage, value],\n );\n\n const syncScroll = (event: UIEvent<HTMLTextAreaElement>) => {\n const layer = highlightLayerRef.current;\n if (!layer) return;\n layer.scrollTop = event.currentTarget.scrollTop;\n layer.scrollLeft = event.currentTarget.scrollLeft;\n };\n\n return (\n <div\n className={cn(\n \"relative min-h-[140px] overflow-hidden rounded-md border border-input bg-background text-foreground focus-within:ring-1 focus-within:ring-ring\",\n !editable && \"cursor-not-allowed opacity-50\",\n )}\n data-code-tabs-highlighted-editor\n >\n <pre\n ref={highlightLayerRef}\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-0 m-0 overflow-hidden whitespace-pre px-3 py-2 font-mono [font-size:var(--plan-code-size)] leading-5\"\n data-code-tabs-highlight-layer\n >\n <code>\n {highlighted}\n {value.endsWith(\"\\n\") ? \" \" : null}\n </code>\n </pre>\n <textarea\n data-plan-interactive\n spellCheck={false}\n wrap=\"off\"\n className={cn(\n \"relative z-10 block min-h-[140px] w-full resize-y overflow-auto rounded-md border-0 bg-transparent px-3 py-2 font-mono [font-size:var(--plan-code-size)] leading-5 caret-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed\",\n value ? \"text-transparent\" : \"text-muted-foreground\",\n )}\n value={value}\n disabled={!editable}\n onChange={onChange}\n onScroll={syncScroll}\n />\n </div>\n );\n}\n\n/**\n * Editor: a file-tab strip (one tab active at a time) with the active tab's code\n * editable inline. Tab metadata is edited from the settings popover, mirroring\n * the standard `tabs` block and keeping schema-ish controls out of the document.\n */\nfunction CodeTabsEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<CodeTabsData>) {\n const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? \"\");\n const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];\n\n const commit = (tabs: CodeTabsTab[]) => onChange({ tabs });\n\n const updateTab = (id: string, patch: Partial<CodeTabsTab>) =>\n commit(\n data.tabs.map((tab) => (tab.id === id ? { ...tab, ...patch } : tab)),\n );\n\n const removeTab = (id: string) => {\n const next = data.tabs.filter((tab) => tab.id !== id);\n if (next.length === 0) return; // tabs must keep at least one (schema min 1)\n commit(next);\n if (activeId === id) setActiveId(next[0]?.id ?? \"\");\n };\n\n const addTab = () => {\n if (data.tabs.length >= 12) return; // schema max\n const id = newCodeTabId();\n commit([\n ...data.tabs,\n { id, label: `file-${data.tabs.length + 1}.ts`, code: \"\" },\n ]);\n setActiveId(id);\n };\n\n return (\n <div className=\"an-code-tabs-editor flex min-w-0 flex-col gap-4\">\n <div className=\"flex w-full min-w-0 items-start gap-2\">\n <div\n className=\"flex w-full min-w-0 flex-1 flex-nowrap items-center gap-1 overflow-x-auto\"\n role=\"tablist\"\n data-plan-interactive\n >\n {data.tabs.map((tab) => {\n const selected = tab.id === active?.id;\n return (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n onClick={() => setActiveId(tab.id)}\n className={cn(\n \"flex shrink-0 items-center gap-2 whitespace-nowrap rounded-lg border border-transparent px-3 py-2 font-mono text-sm font-semibold transition-colors\",\n selected\n ? \"bg-primary/10 text-plan-text dark:bg-primary/20\"\n : \"text-plan-muted hover:bg-plan-block/60 hover:text-plan-text\",\n )}\n >\n <IconCode className=\"size-4 shrink-0\" />\n {tab.label}\n </button>\n );\n })}\n </div>\n {editable && (\n <CodeTabsSettingsPopover\n active={active}\n tabs={data.tabs}\n onUpdate={updateTab}\n onAdd={addTab}\n onRemove={removeTab}\n />\n )}\n </div>\n {active && (\n <HighlightedCodeTextarea\n value={active.code}\n editable={editable}\n label={active.label}\n language={active.language}\n onChange={(event) =>\n updateTab(active.id, { code: event.target.value })\n }\n />\n )}\n </div>\n );\n}\n\nfunction CodeTabsSettingsPopover({\n active,\n tabs,\n onUpdate,\n onAdd,\n onRemove,\n}: {\n active: CodeTabsTab | undefined;\n tabs: CodeTabsTab[];\n onUpdate: (id: string, patch: Partial<CodeTabsTab>) => void;\n onAdd: () => void;\n onRemove: (id: string) => void;\n}) {\n return (\n <Popover>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n data-plan-interactive\n aria-label=\"Edit code tabs\"\n className=\"flex size-8 shrink-0 items-center justify-center rounded-md text-plan-muted transition-colors hover:text-plan-text focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n >\n <IconPencil className=\"size-4\" />\n </button>\n </PopoverTrigger>\n <PopoverContent\n align=\"end\"\n side=\"bottom\"\n className=\"w-80 p-0\"\n data-plan-interactive\n >\n <div className=\"border-b border-border px-3 py-2\">\n <div className=\"text-sm font-semibold text-foreground\">\n Code tab settings\n </div>\n <div className=\"text-xs text-muted-foreground\">\n Rename the active tab or manage its metadata.\n </div>\n </div>\n <div className=\"grid gap-3 p-3\">\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Active tab label\n </span>\n <input\n type=\"text\"\n data-plan-interactive\n className={inputClass}\n value={active?.label ?? \"\"}\n disabled={!active}\n onChange={(event) => {\n if (!active) return;\n onUpdate(active.id, { label: event.target.value });\n }}\n />\n </label>\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Language\n </span>\n <select\n data-plan-interactive\n className={inputClass}\n value={active?.language ?? \"\"}\n disabled={!active}\n onChange={(event) => {\n if (!active) return;\n onUpdate(active.id, {\n language: event.target.value || undefined,\n });\n }}\n >\n {CODE_TAB_LANGUAGES.map((option) => (\n <option key={option.value || \"auto\"} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </label>\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Caption\n </span>\n <input\n type=\"text\"\n data-plan-interactive\n className={inputClass}\n value={active?.caption ?? \"\"}\n disabled={!active}\n onChange={(event) => {\n if (!active) return;\n onUpdate(active.id, {\n caption: event.target.value || undefined,\n });\n }}\n />\n </label>\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Max lines before expand\n </span>\n <input\n type=\"number\"\n min={0}\n step={1}\n data-plan-interactive\n className={inputClass}\n placeholder={`${DEFAULT_CODE_MAX_LINES} (default) · 0 = no limit`}\n value={active?.maxLines ?? \"\"}\n disabled={!active}\n onChange={(event) => {\n if (!active) return;\n const raw = event.target.value.trim();\n const parsed = raw === \"\" ? undefined : Number(raw);\n onUpdate(active.id, {\n maxLines:\n parsed === undefined || Number.isNaN(parsed)\n ? undefined\n : Math.max(0, Math.min(2000, Math.floor(parsed))),\n });\n }}\n />\n </label>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n data-plan-interactive\n disabled={tabs.length >= 12}\n onClick={onAdd}\n className=\"inline-flex h-8 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <IconPlus className=\"size-3.5\" />\n Add tab\n </button>\n <button\n type=\"button\"\n data-plan-interactive\n disabled={!active || tabs.length <= 1}\n onClick={() => {\n if (!active) return;\n onRemove(active.id);\n }}\n className=\"inline-flex h-8 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-destructive transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <IconTrash className=\"size-3.5\" />\n Remove current\n </button>\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\n/* ── Spec ──────────────────────────────────────────────────────────────────── */\n\nexport const codeTabsBlock = defineBlock<CodeTabsData>({\n type: \"code-tabs\",\n schema: codeTabsSchema,\n mdx: codeTabsMdx,\n Read: CodeTabsRead,\n Edit: CodeTabsEdit,\n placement: [\"block\"],\n editSurface: \"inline\",\n label: \"Code tabs\",\n icon: IconCode,\n description:\n \"A vertical file tab rail of syntax-highlighted code snippets, one tab per file with an optional language and caption.\",\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-specs.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/server-specs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"server-specs.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/server-specs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAuFpE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,CAAC,GAAG,CAAC,EA4M/C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,2BAA2B,GAAG,MAAM,CAC9C,MAAM,EACN,OAAO,CACL,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,aAAa,GAAG,kBAAkB,CAAC,CAC5E,CACF,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,aAAa,EACvB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,2BAA2B,CAAA;CAAO,GACxD,IAAI,CAON"}
|
|
@@ -11,7 +11,6 @@ import { htmlSchema, htmlMdx } from "./html.config.js";
|
|
|
11
11
|
import { tabsSchema, tabsMdx } from "./tabs.config.js";
|
|
12
12
|
import { columnsSchema, columnsMdx, } from "./columns.config.js";
|
|
13
13
|
import { calloutSchema, calloutMdx, } from "./callout.config.js";
|
|
14
|
-
import { decisionSchema, decisionMdx, } from "./decision.config.js";
|
|
15
14
|
import { questionFormSchema, questionFormMdx, visualQuestionsSchema, visualQuestionsMdx, } from "./question-form.config.js";
|
|
16
15
|
import { diagramSchema, diagramMdx, } from "./diagram.config.js";
|
|
17
16
|
import { wireframeSchema, wireframeMdx, } from "./wireframe.config.js";
|
|
@@ -115,15 +114,6 @@ export const libraryBlockConfigs = [
|
|
|
115
114
|
label: "Callout",
|
|
116
115
|
description: "An emphasized note with a tone (info/decision/risk/warning/success) and a markdown body.",
|
|
117
116
|
}),
|
|
118
|
-
defineBlock({
|
|
119
|
-
type: "decision",
|
|
120
|
-
schema: decisionSchema,
|
|
121
|
-
mdx: decisionMdx,
|
|
122
|
-
Read: ServerReadStub,
|
|
123
|
-
placement: ["block"],
|
|
124
|
-
label: "Decision",
|
|
125
|
-
description: "A decision prompt with editable option cards and an authored recommended choice.",
|
|
126
|
-
}),
|
|
127
117
|
defineBlock({
|
|
128
118
|
type: "question-form",
|
|
129
119
|
schema: questionFormSchema,
|