@agent-native/core 0.42.0 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -56
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +24 -13
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills.d.ts +2 -6
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +8 -66
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/blocks/index.d.ts +11 -0
- package/dist/client/blocks/index.d.ts.map +1 -1
- package/dist/client/blocks/index.js +11 -0
- 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 +2 -2
- package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
- package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/DiffBlock.js +86 -21
- 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 +27 -4
- package/dist/client/blocks/library/FileTreeBlock.js.map +1 -1
- package/dist/client/blocks/library/JsonExplorerBlock.js +1 -1
- package/dist/client/blocks/library/JsonExplorerBlock.js.map +1 -1
- package/dist/client/blocks/library/MermaidBlock.js +1 -1
- package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
- package/dist/client/blocks/library/annotation-rail.d.ts +19 -0
- package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -1
- package/dist/client/blocks/library/annotation-rail.js +19 -0
- package/dist/client/blocks/library/annotation-rail.js.map +1 -1
- package/dist/client/blocks/library/callout.config.d.ts +29 -0
- package/dist/client/blocks/library/callout.config.d.ts.map +1 -0
- package/dist/client/blocks/library/callout.config.js +33 -0
- package/dist/client/blocks/library/callout.config.js.map +1 -0
- package/dist/client/blocks/library/callout.d.ts +20 -0
- package/dist/client/blocks/library/callout.d.ts.map +1 -0
- package/dist/client/blocks/library/callout.js +61 -0
- package/dist/client/blocks/library/callout.js.map +1 -0
- package/dist/client/blocks/library/checklist.d.ts.map +1 -1
- package/dist/client/blocks/library/checklist.js +3 -3
- package/dist/client/blocks/library/checklist.js.map +1 -1
- package/dist/client/blocks/library/decision.config.d.ts +37 -0
- package/dist/client/blocks/library/decision.config.d.ts.map +1 -0
- package/dist/client/blocks/library/decision.config.js +32 -0
- package/dist/client/blocks/library/decision.config.js.map +1 -0
- package/dist/client/blocks/library/decision.d.ts +19 -0
- package/dist/client/blocks/library/decision.d.ts.map +1 -0
- package/dist/client/blocks/library/decision.js +119 -0
- package/dist/client/blocks/library/decision.js.map +1 -0
- package/dist/client/blocks/library/diagram.config.d.ts +64 -0
- package/dist/client/blocks/library/diagram.config.d.ts.map +1 -0
- package/dist/client/blocks/library/diagram.config.js +111 -0
- package/dist/client/blocks/library/diagram.config.js.map +1 -0
- package/dist/client/blocks/library/diagram.d.ts +16 -0
- package/dist/client/blocks/library/diagram.d.ts.map +1 -0
- package/dist/client/blocks/library/diagram.js +261 -0
- package/dist/client/blocks/library/diagram.js.map +1 -0
- package/dist/client/blocks/library/question-form.config.d.ts +69 -0
- package/dist/client/blocks/library/question-form.config.d.ts.map +1 -0
- package/dist/client/blocks/library/question-form.config.js +58 -0
- package/dist/client/blocks/library/question-form.config.js.map +1 -0
- package/dist/client/blocks/library/question-form.d.ts +20 -0
- package/dist/client/blocks/library/question-form.d.ts.map +1 -0
- package/dist/client/blocks/library/question-form.js +286 -0
- package/dist/client/blocks/library/question-form.js.map +1 -0
- package/dist/client/blocks/library/sanitize-html.d.ts +5 -0
- package/dist/client/blocks/library/sanitize-html.d.ts.map +1 -0
- package/dist/client/blocks/library/sanitize-html.js +240 -0
- package/dist/client/blocks/library/sanitize-html.js.map +1 -0
- package/dist/client/blocks/library/server-specs.d.ts.map +1 -1
- package/dist/client/blocks/library/server-specs.js +59 -0
- 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 +11 -0
- package/dist/client/blocks/library/specs.js.map +1 -1
- package/dist/client/blocks/library/tabs.d.ts.map +1 -1
- package/dist/client/blocks/library/tabs.js +12 -12
- package/dist/client/blocks/library/tabs.js.map +1 -1
- package/dist/client/blocks/library/wireframe-kit.d.ts +260 -0
- package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -0
- package/dist/client/blocks/library/wireframe-kit.js +920 -0
- package/dist/client/blocks/library/wireframe-kit.js.map +1 -0
- package/dist/client/blocks/library/wireframe.config.d.ts +123 -0
- package/dist/client/blocks/library/wireframe.config.d.ts.map +1 -0
- package/dist/client/blocks/library/wireframe.config.js +294 -0
- package/dist/client/blocks/library/wireframe.config.js.map +1 -0
- package/dist/client/blocks/library/wireframe.d.ts +15 -0
- package/dist/client/blocks/library/wireframe.d.ts.map +1 -0
- package/dist/client/blocks/library/wireframe.js +206 -0
- package/dist/client/blocks/library/wireframe.js.map +1 -0
- package/dist/client/blocks/registry.d.ts +9 -0
- package/dist/client/blocks/registry.d.ts.map +1 -1
- package/dist/client/blocks/registry.js +12 -5
- package/dist/client/blocks/registry.js.map +1 -1
- package/dist/client/blocks/server.d.ts +1 -0
- package/dist/client/blocks/server.d.ts.map +1 -1
- package/dist/client/blocks/server.js +1 -0
- package/dist/client/blocks/server.js.map +1 -1
- package/dist/client/blocks/types.d.ts +8 -0
- package/dist/client/blocks/types.d.ts.map +1 -1
- package/dist/client/blocks/types.js.map +1 -1
- package/dist/client/rich-markdown-editor/DragHandle.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/DragHandle.js +77 -12
- package/dist/client/rich-markdown-editor/DragHandle.js.map +1 -1
- package/dist/styles/agent-native.css +1 -0
- package/dist/styles/blocks.css +1380 -0
- package/docs/content/plan-plugin.md +8 -8
- package/docs/content/pr-visual-recap.md +2 -2
- package/docs/content/template-plan.md +94 -17
- package/package.json +2 -1
- package/docs/content/visual-plans.md +0 -82
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileTreeBlock.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/FileTreeBlock.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, 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 // 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-sm 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-sm 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 className=\"plan-block\" data-block-id={blockId}>\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-sm 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 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"]}
|
|
@@ -153,7 +153,7 @@ export function JsonExplorerSurface({ data, className, label = "JSON", }) {
|
|
|
153
153
|
})), className: "rounded px-1.5 py-0.5 text-xs text-plan-muted transition-colors hover:bg-accent/60 hover:text-plan-text", children: "Expand all" }), _jsx("span", { className: "text-plan-muted", children: "\u00B7" }), _jsx("button", { type: "button", "data-plan-interactive": true, onClick: () => setPulse((prev) => ({
|
|
154
154
|
open: false,
|
|
155
155
|
nonce: (prev?.nonce ?? 0) + 1,
|
|
156
|
-
})), className: "rounded px-1.5 py-0.5 text-xs text-plan-muted transition-colors hover:bg-accent/60 hover:text-plan-text", children: "Collapse all" })] }))] }), _jsx("div", { className: "overflow-auto px-3 py-2.5 font-mono
|
|
156
|
+
})), className: "rounded px-1.5 py-0.5 text-xs text-plan-muted transition-colors hover:bg-accent/60 hover:text-plan-text", children: "Collapse all" })] }))] }), _jsx("div", { className: "overflow-auto px-3 py-2.5 font-mono [font-size:var(--plan-code-size)] text-plan-code-text", children: parsed.ok ? (_jsx(JsonNode
|
|
157
157
|
// Remount the whole tree when the global pulse fires so every node
|
|
158
158
|
// re-seeds from the new open/closed state cleanly.
|
|
159
159
|
, { value: parsed.value, depth: 0, collapsedDepth: collapsedDepth, forceOpen: pulse }, pulse?.nonce ?? 0)) : (_jsxs("div", { className: "space-y-2", children: [_jsx("pre", { className: "overflow-auto whitespace-pre-wrap break-words text-plan-code-text", children: data.json || "—" }), _jsxs("p", { className: "text-xs text-red-600 dark:text-red-300", children: ["Could not parse JSON: ", parsed.error] })] })) })] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonExplorerBlock.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/JsonExplorerBlock.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useId,\n useMemo,\n useState,\n type MouseEvent as ReactMouseEvent,\n} from \"react\";\nimport { IconChevronRight } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport type { BlockEditProps, BlockReadProps } from \"../types.js\";\nimport {\n JSON_EXPLORER_DEFAULT_COLLAPSED_DEPTH,\n JSON_EXPLORER_MAX_COLLAPSED_DEPTH,\n type JsonExplorerData,\n} from \"./json-explorer.config.js\";\nimport { DevInput, DevLabel, DevTextarea } from \"./dev-doc-ui.js\";\n\n/**\n * Read + Edit renderers for a `json-explorer` block — a browser-devtools /\n * Postman-style collapsible JSON tree. The raw JSON TEXT (`data.json`) is the\n * source of truth; the Read renderer parses it defensively and, on any parse\n * error, falls back to the raw text plus the error message (it never throws).\n * Lives in core so any app can register the dev-doc block (no shadcn import).\n *\n * Progressive disclosure is the whole point: object/array nodes show a chevron\n * and a one-line summary (\"{…} 3 keys\" / \"[…] 5 items\"); each node tracks its\n * own open/closed state (`useState`) seeded by `collapsedDepth` so deep payloads\n * stay scannable. Leaf values are type-colored (string = green, number = blue,\n * boolean = violet, null = muted); keys use a stable accent color; subtle indent\n * guide lines mark nesting.\n *\n * DARK/LIGHT: the plan editor toggles a `.dark` class on <html>. Every color\n * token — value types, keys, guide lines, chrome — uses Tailwind `dark:` variants\n * or the theme-aware plan CSS-var utilities, so the tree reads correctly in BOTH\n * modes (no hardcoded dark-only palette).\n */\n\n/* ── Theme-aware value-type color tokens ───────────────────────────────────── */\n\n/** String leaves: green in both modes. */\nconst STRING_CLASS = \"text-emerald-700 dark:text-emerald-300\";\n/** Number leaves: blue in both modes. */\nconst NUMBER_CLASS = \"text-blue-700 dark:text-blue-300\";\n/** Boolean leaves: violet in both modes. */\nconst BOOLEAN_CLASS = \"text-violet-700 dark:text-violet-300\";\n/** `null`/`undefined` leaves: muted (theme-aware plan var). */\nconst NULL_CLASS = \"text-plan-muted italic\";\n/** Object keys: a stable, saturated accent that reads in both modes. */\nconst KEY_CLASS = \"text-rose-700 dark:text-rose-300\";\n/** Structural punctuation (braces, brackets, commas, colons). */\nconst PUNCT_CLASS = \"text-plan-muted\";\n\nconst JSON_EXPLORER_DEPTH_PRESETS = [\n { label: \"Off\", value: 0 },\n { label: \"2 levels\", value: JSON_EXPLORER_DEFAULT_COLLAPSED_DEPTH },\n { label: \"3 levels\", value: 3 },\n { label: \"All\", value: JSON_EXPLORER_MAX_COLLAPSED_DEPTH },\n] as const;\n\nfunction clampCollapsedDepth(value: number): number {\n return Math.max(0, Math.min(JSON_EXPLORER_MAX_COLLAPSED_DEPTH, value));\n}\n\ntype JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\ntype JsonObject = { [key: string]: JsonValue };\n\ninterface ParseResult {\n ok: boolean;\n value?: JsonValue;\n error?: string;\n}\n\ninterface JsonTreePulse {\n open: boolean;\n nonce: number;\n}\n\nfunction parseJson(raw: string): ParseResult {\n const trimmed = raw.trim();\n if (!trimmed) {\n return { ok: false, error: \"Empty payload — add some JSON to explore.\" };\n }\n try {\n return { ok: true, value: JSON.parse(trimmed) as JsonValue };\n } catch (error) {\n return {\n ok: false,\n error: error instanceof Error ? error.message : \"Invalid JSON\",\n };\n }\n}\n\nfunction isContainer(value: JsonValue): value is JsonValue[] | JsonObject {\n return value !== null && typeof value === \"object\";\n}\n\n/** One-line summary for a collapsed container, devtools style. */\nfunction containerSummary(value: JsonValue[] | JsonObject): string {\n if (Array.isArray(value)) {\n const count = value.length;\n return `[…] ${count} ${count === 1 ? \"item\" : \"items\"}`;\n }\n const count = Object.keys(value).length;\n return `{…} ${count} ${count === 1 ? \"key\" : \"keys\"}`;\n}\n\n/** Render a leaf (primitive) value with its type color. */\nfunction LeafValue({ value }: { value: string | number | boolean | null }) {\n if (value === null) {\n return <span className={NULL_CLASS}>null</span>;\n }\n if (typeof value === \"string\") {\n return <span className={STRING_CLASS}>{JSON.stringify(value)}</span>;\n }\n if (typeof value === \"number\") {\n return <span className={NUMBER_CLASS}>{String(value)}</span>;\n }\n // boolean\n return <span className={BOOLEAN_CLASS}>{String(value)}</span>;\n}\n\ninterface JsonNodeProps {\n /** The object key or array index label for this node (root has none). */\n label?: string | number;\n value: JsonValue;\n depth: number;\n /** Depth beyond which nodes start collapsed. */\n collapsedDepth: number;\n /** Global or parent expand/collapse pulse — overrides per-node seed when changed. */\n forceOpen: JsonTreePulse | null;\n /** True when this node is followed by a sibling (renders a trailing comma). */\n trailingComma?: boolean;\n}\n\n/**\n * A single tree node. Containers (object/array) get their own collapse state,\n * seeded from `collapsedDepth` and re-seeded whenever the global expand/collapse\n * \"pulse\" (`forceOpen`) flips. Leaves render inline with their type color.\n */\nfunction JsonNode({\n label,\n value,\n depth,\n collapsedDepth,\n forceOpen,\n trailingComma,\n}: JsonNodeProps) {\n const seededOpen = forceOpen?.open ?? depth < collapsedDepth;\n // `forceOpen` is the global pulse: when the user hits expand/collapse all we\n // flip every node, but per-node toggles still win afterward.\n const [openState, setOpenState] = useState<{\n forceOpen: JsonTreePulse | null;\n open: boolean;\n }>({ forceOpen, open: seededOpen });\n const [subtreePulse, setSubtreePulse] = useState<JsonTreePulse | null>(null);\n\n let open = openState.open;\n if (forceOpen !== openState.forceOpen) {\n open = forceOpen?.open ?? openState.open;\n setOpenState({ forceOpen, open });\n }\n\n const handleToggle = (event: ReactMouseEvent<HTMLButtonElement>) => {\n const nextOpen = !open;\n setOpenState((prev) => ({ ...prev, open: nextOpen }));\n if (event.altKey) {\n setSubtreePulse((prev) => ({\n open: nextOpen,\n nonce: (prev?.nonce ?? 0) + 1,\n }));\n } else {\n setSubtreePulse(null);\n }\n };\n\n const keyEl =\n label !== undefined ? (\n <>\n <span className={KEY_CLASS}>\n {typeof label === \"number\" ? label : JSON.stringify(label)}\n </span>\n <span className={PUNCT_CLASS}>: </span>\n </>\n ) : null;\n\n if (!isContainer(value)) {\n return (\n <div className=\"flex items-start py-0.5 leading-relaxed\">\n <span className=\"select-none whitespace-pre\">{keyEl}</span>\n <LeafValue value={value} />\n {trailingComma && <span className={PUNCT_CLASS}>,</span>}\n </div>\n );\n }\n\n const isArray = Array.isArray(value);\n const entries: Array<[string | number, JsonValue]> = isArray\n ? (value as JsonValue[]).map((item, index) => [index, item])\n : Object.entries(value as JsonObject);\n const openBrace = isArray ? \"[\" : \"{\";\n const closeBrace = isArray ? \"]\" : \"}\";\n const empty = entries.length === 0;\n const childForceOpen = subtreePulse ?? forceOpen;\n const childPulseNonce = childForceOpen?.nonce ?? 0;\n\n return (\n <div className=\"leading-relaxed\">\n <button\n type=\"button\"\n data-plan-interactive\n aria-expanded={open}\n disabled={empty}\n onClick={handleToggle}\n className={cn(\n \"group flex w-full items-start gap-1 rounded py-0.5 text-left transition-colors\",\n !empty && \"hover:bg-accent/40\",\n empty && \"cursor-default\",\n )}\n >\n <IconChevronRight\n className={cn(\n \"mt-1 size-3.5 shrink-0 text-plan-muted transition-transform\",\n open && \"rotate-90\",\n empty && \"opacity-0\",\n )}\n />\n <span className=\"min-w-0 whitespace-pre-wrap break-words\">\n {keyEl}\n <span className={PUNCT_CLASS}>{openBrace}</span>\n {!open && !empty && (\n <span className=\"ml-1 text-plan-muted\">\n {containerSummary(value)}\n </span>\n )}\n {(!open || empty) && (\n <span className={PUNCT_CLASS}>\n {empty ? \"\" : \"…\"}\n {closeBrace}\n {trailingComma ? \",\" : \"\"}\n </span>\n )}\n </span>\n </button>\n\n {open && !empty && (\n <>\n {/* Indent guide: a subtle vertical rule marks the nesting level. */}\n <div className=\"ml-[7px] border-l border-plan-line pl-3.5\">\n {entries.map(([entryKey, entryValue], index) => (\n <JsonNode\n key={`${String(entryKey)}:${childPulseNonce}`}\n label={entryKey}\n value={entryValue}\n depth={depth + 1}\n collapsedDepth={collapsedDepth}\n forceOpen={childForceOpen}\n trailingComma={index < entries.length - 1}\n />\n ))}\n </div>\n <div className=\"flex items-start\">\n {/* Align the closing brace under the chevron column. */}\n <span className=\"ml-[18px] whitespace-pre\">\n <span className={PUNCT_CLASS}>{closeBrace}</span>\n {trailingComma && <span className={PUNCT_CLASS}>,</span>}\n </span>\n </div>\n </>\n )}\n </div>\n );\n}\n\n/* ── Read (collapsible devtools tree) ──────────────────────────────────────── */\n\n/**\n * Read-only renderer for a `json-explorer` block. Parses `data.json` defensively\n * and renders the collapsible tree; on a parse error it shows the raw payload in\n * a monospace block plus the error (never throws). An \"Expand all / Collapse\n * all\" control toggles every node at once via a global pulse counter.\n */\nexport function JsonExplorerRead({\n data,\n blockId,\n title,\n summary,\n}: BlockReadProps<JsonExplorerData>) {\n const heading = data.title ?? title;\n\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {heading && <div className=\"plan-block-label\">{heading}</div>}\n <JsonExplorerSurface data={data} />\n {summary && <p className=\"mt-5 text-plan-muted\">{summary}</p>}\n </section>\n );\n}\n\nexport function JsonExplorerSurface({\n data,\n className,\n label = \"JSON\",\n}: {\n data: Pick<JsonExplorerData, \"json\" | \"collapsedDepth\">;\n className?: string;\n label?: string;\n}) {\n const parsed = useMemo(() => parseJson(data.json), [data.json]);\n const collapsedDepth =\n data.collapsedDepth ?? JSON_EXPLORER_DEFAULT_COLLAPSED_DEPTH;\n // `pulse` carries a boolean (expand/collapse) plus a nonce so repeated clicks\n // of the same action still re-fire the reseed in each node.\n const [pulse, setPulse] = useState<{ open: boolean; nonce: number } | null>(\n null,\n );\n\n return (\n <div\n className={cn(\n \"overflow-hidden rounded-xl border border-plan-line bg-plan-code\",\n className,\n )}\n >\n <div className=\"flex items-center justify-between gap-2 border-b border-plan-line px-3 py-1.5\">\n <span className=\"font-mono text-xs uppercase tracking-wide text-plan-muted\">\n {label}\n </span>\n {parsed.ok && isContainer(parsed.value as JsonValue) && (\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n data-plan-interactive\n onClick={() =>\n setPulse((prev) => ({\n open: true,\n nonce: (prev?.nonce ?? 0) + 1,\n }))\n }\n className=\"rounded px-1.5 py-0.5 text-xs text-plan-muted transition-colors hover:bg-accent/60 hover:text-plan-text\"\n >\n Expand all\n </button>\n <span className=\"text-plan-muted\">·</span>\n <button\n type=\"button\"\n data-plan-interactive\n onClick={() =>\n setPulse((prev) => ({\n open: false,\n nonce: (prev?.nonce ?? 0) + 1,\n }))\n }\n className=\"rounded px-1.5 py-0.5 text-xs text-plan-muted transition-colors hover:bg-accent/60 hover:text-plan-text\"\n >\n Collapse all\n </button>\n </div>\n )}\n </div>\n <div className=\"overflow-auto px-3 py-2.5 font-mono text-sm text-plan-code-text\">\n {parsed.ok ? (\n <JsonNode\n // Remount the whole tree when the global pulse fires so every node\n // re-seeds from the new open/closed state cleanly.\n key={pulse?.nonce ?? 0}\n value={parsed.value as JsonValue}\n depth={0}\n collapsedDepth={collapsedDepth}\n forceOpen={pulse}\n />\n ) : (\n <div className=\"space-y-2\">\n <pre className=\"overflow-auto whitespace-pre-wrap break-words text-plan-code-text\">\n {data.json || \"—\"}\n </pre>\n <p className=\"text-xs text-red-600 dark:text-red-300\">\n Could not parse JSON: {parsed.error}\n </p>\n </div>\n )}\n </div>\n </div>\n );\n}\n\n/* ── Edit (panel form) ─────────────────────────────────────────────────────── */\n\n/**\n * Panel editor for a `json-explorer` block: a monospace textarea bound to the\n * raw `json`, a \"Format\" button that pretty-prints via `JSON.parse` →\n * `JSON.stringify(_, null, 2)` (guarded — shows an INLINE error, never\n * `window.alert`), an auto-expand depth picker/input, and a `title` input.\n * Renders BARE content (no `<section>`); the registry's panel surface supplies\n * the popover chrome.\n */\nexport function JsonExplorerEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<JsonExplorerData>) {\n const jsonId = useId();\n const titleId = useId();\n const depthId = useId();\n const [formatError, setFormatError] = useState<string | null>(null);\n const collapsedDepth =\n data.collapsedDepth ?? JSON_EXPLORER_DEFAULT_COLLAPSED_DEPTH;\n\n const setCollapsedDepth = (value: number) => {\n onChange({ ...data, collapsedDepth: clampCollapsedDepth(value) });\n };\n\n const handleFormat = () => {\n try {\n const formatted = JSON.stringify(JSON.parse(data.json), null, 2);\n setFormatError(null);\n onChange({ ...data, json: formatted });\n } catch (error) {\n setFormatError(\n error instanceof Error ? error.message : \"Invalid JSON — cannot format\",\n );\n }\n };\n\n return (\n <div className=\"grid gap-3\" data-plan-interactive>\n <div className=\"grid gap-1.5\">\n <DevLabel htmlFor={titleId}>Title</DevLabel>\n <DevInput\n id={titleId}\n value={data.title ?? \"\"}\n readOnly={!editable}\n onChange={(event) =>\n onChange({ ...data, title: event.target.value || undefined })\n }\n placeholder=\"Optional heading\"\n />\n </div>\n\n <div className=\"grid gap-1.5\">\n <div className=\"flex items-center justify-between\">\n <DevLabel htmlFor={jsonId}>JSON payload</DevLabel>\n {editable && (\n <button\n type=\"button\"\n data-plan-interactive\n onClick={handleFormat}\n className=\"inline-flex h-7 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md border border-input bg-background px-2 text-xs font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\"\n >\n Format\n </button>\n )}\n </div>\n <DevTextarea\n id={jsonId}\n value={data.json}\n readOnly={!editable}\n spellCheck={false}\n onChange={(event) => {\n setFormatError(null);\n onChange({ ...data, json: event.target.value });\n }}\n className=\"min-h-56 font-mono text-xs\"\n placeholder={'{\\n \"id\": \"abc123\",\\n \"active\": true\\n}'}\n />\n {formatError && (\n <p className=\"text-xs text-red-600 dark:text-red-300\">\n {formatError}\n </p>\n )}\n <p className=\"text-xs text-muted-foreground\">\n Raw JSON text is the source of truth. Use Format to pretty-print it.\n </p>\n </div>\n\n <div className=\"grid gap-1.5\">\n <DevLabel htmlFor={depthId}>Auto expand</DevLabel>\n <div className=\"flex flex-wrap gap-1\">\n {JSON_EXPLORER_DEPTH_PRESETS.map((preset) => {\n const active = collapsedDepth === preset.value;\n return (\n <button\n key={preset.label}\n type=\"button\"\n data-plan-interactive\n aria-pressed={active}\n disabled={!editable}\n onClick={() => setCollapsedDepth(preset.value)}\n className={cn(\n \"inline-flex h-7 items-center justify-center rounded-md border px-2 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n active\n ? \"border-primary bg-primary text-primary-foreground\"\n : \"border-input bg-background text-muted-foreground hover:bg-accent hover:text-accent-foreground\",\n )}\n >\n {preset.label}\n </button>\n );\n })}\n </div>\n <DevInput\n id={depthId}\n type=\"number\"\n min={0}\n max={JSON_EXPLORER_MAX_COLLAPSED_DEPTH}\n value={collapsedDepth}\n readOnly={!editable}\n onChange={(event) => {\n const next = Number.parseInt(event.target.value, 10);\n onChange({\n ...data,\n collapsedDepth: Number.isFinite(next)\n ? clampCollapsedDepth(next)\n : undefined,\n });\n }}\n className=\"w-24\"\n />\n <p className=\"text-xs text-muted-foreground\">\n Levels open automatically. Use 0 to start collapsed,{\" \"}\n {JSON_EXPLORER_MAX_COLLAPSED_DEPTH} for all.\n </p>\n </div>\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"JsonExplorerBlock.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/JsonExplorerBlock.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useId,\n useMemo,\n useState,\n type MouseEvent as ReactMouseEvent,\n} from \"react\";\nimport { IconChevronRight } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport type { BlockEditProps, BlockReadProps } from \"../types.js\";\nimport {\n JSON_EXPLORER_DEFAULT_COLLAPSED_DEPTH,\n JSON_EXPLORER_MAX_COLLAPSED_DEPTH,\n type JsonExplorerData,\n} from \"./json-explorer.config.js\";\nimport { DevInput, DevLabel, DevTextarea } from \"./dev-doc-ui.js\";\n\n/**\n * Read + Edit renderers for a `json-explorer` block — a browser-devtools /\n * Postman-style collapsible JSON tree. The raw JSON TEXT (`data.json`) is the\n * source of truth; the Read renderer parses it defensively and, on any parse\n * error, falls back to the raw text plus the error message (it never throws).\n * Lives in core so any app can register the dev-doc block (no shadcn import).\n *\n * Progressive disclosure is the whole point: object/array nodes show a chevron\n * and a one-line summary (\"{…} 3 keys\" / \"[…] 5 items\"); each node tracks its\n * own open/closed state (`useState`) seeded by `collapsedDepth` so deep payloads\n * stay scannable. Leaf values are type-colored (string = green, number = blue,\n * boolean = violet, null = muted); keys use a stable accent color; subtle indent\n * guide lines mark nesting.\n *\n * DARK/LIGHT: the plan editor toggles a `.dark` class on <html>. Every color\n * token — value types, keys, guide lines, chrome — uses Tailwind `dark:` variants\n * or the theme-aware plan CSS-var utilities, so the tree reads correctly in BOTH\n * modes (no hardcoded dark-only palette).\n */\n\n/* ── Theme-aware value-type color tokens ───────────────────────────────────── */\n\n/** String leaves: green in both modes. */\nconst STRING_CLASS = \"text-emerald-700 dark:text-emerald-300\";\n/** Number leaves: blue in both modes. */\nconst NUMBER_CLASS = \"text-blue-700 dark:text-blue-300\";\n/** Boolean leaves: violet in both modes. */\nconst BOOLEAN_CLASS = \"text-violet-700 dark:text-violet-300\";\n/** `null`/`undefined` leaves: muted (theme-aware plan var). */\nconst NULL_CLASS = \"text-plan-muted italic\";\n/** Object keys: a stable, saturated accent that reads in both modes. */\nconst KEY_CLASS = \"text-rose-700 dark:text-rose-300\";\n/** Structural punctuation (braces, brackets, commas, colons). */\nconst PUNCT_CLASS = \"text-plan-muted\";\n\nconst JSON_EXPLORER_DEPTH_PRESETS = [\n { label: \"Off\", value: 0 },\n { label: \"2 levels\", value: JSON_EXPLORER_DEFAULT_COLLAPSED_DEPTH },\n { label: \"3 levels\", value: 3 },\n { label: \"All\", value: JSON_EXPLORER_MAX_COLLAPSED_DEPTH },\n] as const;\n\nfunction clampCollapsedDepth(value: number): number {\n return Math.max(0, Math.min(JSON_EXPLORER_MAX_COLLAPSED_DEPTH, value));\n}\n\ntype JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\ntype JsonObject = { [key: string]: JsonValue };\n\ninterface ParseResult {\n ok: boolean;\n value?: JsonValue;\n error?: string;\n}\n\ninterface JsonTreePulse {\n open: boolean;\n nonce: number;\n}\n\nfunction parseJson(raw: string): ParseResult {\n const trimmed = raw.trim();\n if (!trimmed) {\n return { ok: false, error: \"Empty payload — add some JSON to explore.\" };\n }\n try {\n return { ok: true, value: JSON.parse(trimmed) as JsonValue };\n } catch (error) {\n return {\n ok: false,\n error: error instanceof Error ? error.message : \"Invalid JSON\",\n };\n }\n}\n\nfunction isContainer(value: JsonValue): value is JsonValue[] | JsonObject {\n return value !== null && typeof value === \"object\";\n}\n\n/** One-line summary for a collapsed container, devtools style. */\nfunction containerSummary(value: JsonValue[] | JsonObject): string {\n if (Array.isArray(value)) {\n const count = value.length;\n return `[…] ${count} ${count === 1 ? \"item\" : \"items\"}`;\n }\n const count = Object.keys(value).length;\n return `{…} ${count} ${count === 1 ? \"key\" : \"keys\"}`;\n}\n\n/** Render a leaf (primitive) value with its type color. */\nfunction LeafValue({ value }: { value: string | number | boolean | null }) {\n if (value === null) {\n return <span className={NULL_CLASS}>null</span>;\n }\n if (typeof value === \"string\") {\n return <span className={STRING_CLASS}>{JSON.stringify(value)}</span>;\n }\n if (typeof value === \"number\") {\n return <span className={NUMBER_CLASS}>{String(value)}</span>;\n }\n // boolean\n return <span className={BOOLEAN_CLASS}>{String(value)}</span>;\n}\n\ninterface JsonNodeProps {\n /** The object key or array index label for this node (root has none). */\n label?: string | number;\n value: JsonValue;\n depth: number;\n /** Depth beyond which nodes start collapsed. */\n collapsedDepth: number;\n /** Global or parent expand/collapse pulse — overrides per-node seed when changed. */\n forceOpen: JsonTreePulse | null;\n /** True when this node is followed by a sibling (renders a trailing comma). */\n trailingComma?: boolean;\n}\n\n/**\n * A single tree node. Containers (object/array) get their own collapse state,\n * seeded from `collapsedDepth` and re-seeded whenever the global expand/collapse\n * \"pulse\" (`forceOpen`) flips. Leaves render inline with their type color.\n */\nfunction JsonNode({\n label,\n value,\n depth,\n collapsedDepth,\n forceOpen,\n trailingComma,\n}: JsonNodeProps) {\n const seededOpen = forceOpen?.open ?? depth < collapsedDepth;\n // `forceOpen` is the global pulse: when the user hits expand/collapse all we\n // flip every node, but per-node toggles still win afterward.\n const [openState, setOpenState] = useState<{\n forceOpen: JsonTreePulse | null;\n open: boolean;\n }>({ forceOpen, open: seededOpen });\n const [subtreePulse, setSubtreePulse] = useState<JsonTreePulse | null>(null);\n\n let open = openState.open;\n if (forceOpen !== openState.forceOpen) {\n open = forceOpen?.open ?? openState.open;\n setOpenState({ forceOpen, open });\n }\n\n const handleToggle = (event: ReactMouseEvent<HTMLButtonElement>) => {\n const nextOpen = !open;\n setOpenState((prev) => ({ ...prev, open: nextOpen }));\n if (event.altKey) {\n setSubtreePulse((prev) => ({\n open: nextOpen,\n nonce: (prev?.nonce ?? 0) + 1,\n }));\n } else {\n setSubtreePulse(null);\n }\n };\n\n const keyEl =\n label !== undefined ? (\n <>\n <span className={KEY_CLASS}>\n {typeof label === \"number\" ? label : JSON.stringify(label)}\n </span>\n <span className={PUNCT_CLASS}>: </span>\n </>\n ) : null;\n\n if (!isContainer(value)) {\n return (\n <div className=\"flex items-start py-0.5 leading-relaxed\">\n <span className=\"select-none whitespace-pre\">{keyEl}</span>\n <LeafValue value={value} />\n {trailingComma && <span className={PUNCT_CLASS}>,</span>}\n </div>\n );\n }\n\n const isArray = Array.isArray(value);\n const entries: Array<[string | number, JsonValue]> = isArray\n ? (value as JsonValue[]).map((item, index) => [index, item])\n : Object.entries(value as JsonObject);\n const openBrace = isArray ? \"[\" : \"{\";\n const closeBrace = isArray ? \"]\" : \"}\";\n const empty = entries.length === 0;\n const childForceOpen = subtreePulse ?? forceOpen;\n const childPulseNonce = childForceOpen?.nonce ?? 0;\n\n return (\n <div className=\"leading-relaxed\">\n <button\n type=\"button\"\n data-plan-interactive\n aria-expanded={open}\n disabled={empty}\n onClick={handleToggle}\n className={cn(\n \"group flex w-full items-start gap-1 rounded py-0.5 text-left transition-colors\",\n !empty && \"hover:bg-accent/40\",\n empty && \"cursor-default\",\n )}\n >\n <IconChevronRight\n className={cn(\n \"mt-1 size-3.5 shrink-0 text-plan-muted transition-transform\",\n open && \"rotate-90\",\n empty && \"opacity-0\",\n )}\n />\n <span className=\"min-w-0 whitespace-pre-wrap break-words\">\n {keyEl}\n <span className={PUNCT_CLASS}>{openBrace}</span>\n {!open && !empty && (\n <span className=\"ml-1 text-plan-muted\">\n {containerSummary(value)}\n </span>\n )}\n {(!open || empty) && (\n <span className={PUNCT_CLASS}>\n {empty ? \"\" : \"…\"}\n {closeBrace}\n {trailingComma ? \",\" : \"\"}\n </span>\n )}\n </span>\n </button>\n\n {open && !empty && (\n <>\n {/* Indent guide: a subtle vertical rule marks the nesting level. */}\n <div className=\"ml-[7px] border-l border-plan-line pl-3.5\">\n {entries.map(([entryKey, entryValue], index) => (\n <JsonNode\n key={`${String(entryKey)}:${childPulseNonce}`}\n label={entryKey}\n value={entryValue}\n depth={depth + 1}\n collapsedDepth={collapsedDepth}\n forceOpen={childForceOpen}\n trailingComma={index < entries.length - 1}\n />\n ))}\n </div>\n <div className=\"flex items-start\">\n {/* Align the closing brace under the chevron column. */}\n <span className=\"ml-[18px] whitespace-pre\">\n <span className={PUNCT_CLASS}>{closeBrace}</span>\n {trailingComma && <span className={PUNCT_CLASS}>,</span>}\n </span>\n </div>\n </>\n )}\n </div>\n );\n}\n\n/* ── Read (collapsible devtools tree) ──────────────────────────────────────── */\n\n/**\n * Read-only renderer for a `json-explorer` block. Parses `data.json` defensively\n * and renders the collapsible tree; on a parse error it shows the raw payload in\n * a monospace block plus the error (never throws). An \"Expand all / Collapse\n * all\" control toggles every node at once via a global pulse counter.\n */\nexport function JsonExplorerRead({\n data,\n blockId,\n title,\n summary,\n}: BlockReadProps<JsonExplorerData>) {\n const heading = data.title ?? title;\n\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {heading && <div className=\"plan-block-label\">{heading}</div>}\n <JsonExplorerSurface data={data} />\n {summary && <p className=\"mt-5 text-plan-muted\">{summary}</p>}\n </section>\n );\n}\n\nexport function JsonExplorerSurface({\n data,\n className,\n label = \"JSON\",\n}: {\n data: Pick<JsonExplorerData, \"json\" | \"collapsedDepth\">;\n className?: string;\n label?: string;\n}) {\n const parsed = useMemo(() => parseJson(data.json), [data.json]);\n const collapsedDepth =\n data.collapsedDepth ?? JSON_EXPLORER_DEFAULT_COLLAPSED_DEPTH;\n // `pulse` carries a boolean (expand/collapse) plus a nonce so repeated clicks\n // of the same action still re-fire the reseed in each node.\n const [pulse, setPulse] = useState<{ open: boolean; nonce: number } | null>(\n null,\n );\n\n return (\n <div\n className={cn(\n \"overflow-hidden rounded-xl border border-plan-line bg-plan-code\",\n className,\n )}\n >\n <div className=\"flex items-center justify-between gap-2 border-b border-plan-line px-3 py-1.5\">\n <span className=\"font-mono text-xs uppercase tracking-wide text-plan-muted\">\n {label}\n </span>\n {parsed.ok && isContainer(parsed.value as JsonValue) && (\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n data-plan-interactive\n onClick={() =>\n setPulse((prev) => ({\n open: true,\n nonce: (prev?.nonce ?? 0) + 1,\n }))\n }\n className=\"rounded px-1.5 py-0.5 text-xs text-plan-muted transition-colors hover:bg-accent/60 hover:text-plan-text\"\n >\n Expand all\n </button>\n <span className=\"text-plan-muted\">·</span>\n <button\n type=\"button\"\n data-plan-interactive\n onClick={() =>\n setPulse((prev) => ({\n open: false,\n nonce: (prev?.nonce ?? 0) + 1,\n }))\n }\n className=\"rounded px-1.5 py-0.5 text-xs text-plan-muted transition-colors hover:bg-accent/60 hover:text-plan-text\"\n >\n Collapse all\n </button>\n </div>\n )}\n </div>\n <div className=\"overflow-auto px-3 py-2.5 font-mono [font-size:var(--plan-code-size)] text-plan-code-text\">\n {parsed.ok ? (\n <JsonNode\n // Remount the whole tree when the global pulse fires so every node\n // re-seeds from the new open/closed state cleanly.\n key={pulse?.nonce ?? 0}\n value={parsed.value as JsonValue}\n depth={0}\n collapsedDepth={collapsedDepth}\n forceOpen={pulse}\n />\n ) : (\n <div className=\"space-y-2\">\n <pre className=\"overflow-auto whitespace-pre-wrap break-words text-plan-code-text\">\n {data.json || \"—\"}\n </pre>\n <p className=\"text-xs text-red-600 dark:text-red-300\">\n Could not parse JSON: {parsed.error}\n </p>\n </div>\n )}\n </div>\n </div>\n );\n}\n\n/* ── Edit (panel form) ─────────────────────────────────────────────────────── */\n\n/**\n * Panel editor for a `json-explorer` block: a monospace textarea bound to the\n * raw `json`, a \"Format\" button that pretty-prints via `JSON.parse` →\n * `JSON.stringify(_, null, 2)` (guarded — shows an INLINE error, never\n * `window.alert`), an auto-expand depth picker/input, and a `title` input.\n * Renders BARE content (no `<section>`); the registry's panel surface supplies\n * the popover chrome.\n */\nexport function JsonExplorerEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<JsonExplorerData>) {\n const jsonId = useId();\n const titleId = useId();\n const depthId = useId();\n const [formatError, setFormatError] = useState<string | null>(null);\n const collapsedDepth =\n data.collapsedDepth ?? JSON_EXPLORER_DEFAULT_COLLAPSED_DEPTH;\n\n const setCollapsedDepth = (value: number) => {\n onChange({ ...data, collapsedDepth: clampCollapsedDepth(value) });\n };\n\n const handleFormat = () => {\n try {\n const formatted = JSON.stringify(JSON.parse(data.json), null, 2);\n setFormatError(null);\n onChange({ ...data, json: formatted });\n } catch (error) {\n setFormatError(\n error instanceof Error ? error.message : \"Invalid JSON — cannot format\",\n );\n }\n };\n\n return (\n <div className=\"grid gap-3\" data-plan-interactive>\n <div className=\"grid gap-1.5\">\n <DevLabel htmlFor={titleId}>Title</DevLabel>\n <DevInput\n id={titleId}\n value={data.title ?? \"\"}\n readOnly={!editable}\n onChange={(event) =>\n onChange({ ...data, title: event.target.value || undefined })\n }\n placeholder=\"Optional heading\"\n />\n </div>\n\n <div className=\"grid gap-1.5\">\n <div className=\"flex items-center justify-between\">\n <DevLabel htmlFor={jsonId}>JSON payload</DevLabel>\n {editable && (\n <button\n type=\"button\"\n data-plan-interactive\n onClick={handleFormat}\n className=\"inline-flex h-7 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md border border-input bg-background px-2 text-xs font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\"\n >\n Format\n </button>\n )}\n </div>\n <DevTextarea\n id={jsonId}\n value={data.json}\n readOnly={!editable}\n spellCheck={false}\n onChange={(event) => {\n setFormatError(null);\n onChange({ ...data, json: event.target.value });\n }}\n className=\"min-h-56 font-mono text-xs\"\n placeholder={'{\\n \"id\": \"abc123\",\\n \"active\": true\\n}'}\n />\n {formatError && (\n <p className=\"text-xs text-red-600 dark:text-red-300\">\n {formatError}\n </p>\n )}\n <p className=\"text-xs text-muted-foreground\">\n Raw JSON text is the source of truth. Use Format to pretty-print it.\n </p>\n </div>\n\n <div className=\"grid gap-1.5\">\n <DevLabel htmlFor={depthId}>Auto expand</DevLabel>\n <div className=\"flex flex-wrap gap-1\">\n {JSON_EXPLORER_DEPTH_PRESETS.map((preset) => {\n const active = collapsedDepth === preset.value;\n return (\n <button\n key={preset.label}\n type=\"button\"\n data-plan-interactive\n aria-pressed={active}\n disabled={!editable}\n onClick={() => setCollapsedDepth(preset.value)}\n className={cn(\n \"inline-flex h-7 items-center justify-center rounded-md border px-2 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n active\n ? \"border-primary bg-primary text-primary-foreground\"\n : \"border-input bg-background text-muted-foreground hover:bg-accent hover:text-accent-foreground\",\n )}\n >\n {preset.label}\n </button>\n );\n })}\n </div>\n <DevInput\n id={depthId}\n type=\"number\"\n min={0}\n max={JSON_EXPLORER_MAX_COLLAPSED_DEPTH}\n value={collapsedDepth}\n readOnly={!editable}\n onChange={(event) => {\n const next = Number.parseInt(event.target.value, 10);\n onChange({\n ...data,\n collapsedDepth: Number.isFinite(next)\n ? clampCollapsedDepth(next)\n : undefined,\n });\n }}\n className=\"w-24\"\n />\n <p className=\"text-xs text-muted-foreground\">\n Levels open automatically. Use 0 to start collapsed,{\" \"}\n {JSON_EXPLORER_MAX_COLLAPSED_DEPTH} for all.\n </p>\n </div>\n </div>\n );\n}\n"]}
|
|
@@ -125,7 +125,7 @@ function MermaidDiagram({ source, idSeed, }) {
|
|
|
125
125
|
return (_jsx("div", { className: "mt-2 flex min-h-24 items-center justify-center rounded-lg border border-plan-line bg-plan-code text-sm text-plan-muted", children: "Loading diagram\u2026" }));
|
|
126
126
|
}
|
|
127
127
|
if (state.error) {
|
|
128
|
-
return (_jsxs("div", { className: "mt-2 space-y-2", children: [_jsx("pre", { className: "overflow-auto rounded-lg border border-plan-line bg-plan-code px-3 py-2 font-mono
|
|
128
|
+
return (_jsxs("div", { className: "mt-2 space-y-2", children: [_jsx("pre", { className: "overflow-auto rounded-lg border border-plan-line bg-plan-code px-3 py-2 font-mono [font-size:var(--plan-code-size)] text-plan-code-text", children: source }), _jsxs("p", { className: "text-sm text-plan-muted", children: ["Could not render diagram: ", state.error] })] }));
|
|
129
129
|
}
|
|
130
130
|
if (!state.svg) {
|
|
131
131
|
return (_jsx("div", { className: "mt-2 flex min-h-24 items-center justify-center rounded-lg border border-plan-line bg-plan-code text-sm text-plan-muted", children: "Add a diagram definition to render it." }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MermaidBlock.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/MermaidBlock.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAG5D,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AA6BrD,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC;AAC7E,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAW;IACpC,IAAI,OAAO,SAAS,KAAK,WAAW;QAAE,OAAO,GAAG,CAAC;IACjD,MAAM,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IAClE,GAAG;SACA,gBAAgB,CAAC,uBAAuB,CAAC;SACzC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACpC,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC5D,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC9C,IACE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;gBACrB,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;oBAC1C,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,EAClC,CAAC;gBACD,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,eAAe,CAAC,SAAS,CAAC;AACvC,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,MAAc,EACd,MAAe;IAEf,MAAM,CAAC,EAAE,wBAAwB,EAAE,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACnE,MAAM,CAAC,mCAAmC,CAKxC;QACF,MAAM,CAAC,wBAAwB,CAW7B;KACH,CAAC,CAAC;IACH,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,MAAM,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACnE,MAAM,kBAAkB,GAAG,UAAU,CAAC,2BAA2B,CAAC,QAAQ,CAAC,CAAC;IAC5E,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,WAAW,CAAC;QACvC,QAAQ,EAAE,kBAAkB;QAC5B,QAAQ,EAAE;YACR,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;YAChC,mBAAmB,EAAE,aAAa;YAClC,kBAAkB,EAAE,MAAM;SAC3B;QACD,KAAK,EAAE,KAAK,IAAI,EAAE;KACnB,CAAC,CAAC;IACH,OAAO,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC1C,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,MAAc,EACd,EAAU,EACV,MAAe;IAEf,MAAM,OAAO,GACX,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAMzB,CAAC,OAAO,CAAC;IACV,OAAO,CAAC,UAAU,CAAC;QACjB,WAAW,EAAE,KAAK;QAClB,aAAa,EAAE,QAAQ;QACvB,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;KACnC,CAAC,CAAC;IACH,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACjD,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,8EAA8E;AAC9E,SAAS,SAAS;IAChB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,QAAQ,KAAK,WAAW;YAAE,OAAO;QAC5C,MAAM,IAAI,GAAG,QAAQ,CAAC,eAAe,CAAC;QACtC,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9D,IAAI,EAAE,CAAC;QACP,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC5C,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACzE,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;IACrC,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,cAAc,CAAC,EACtB,MAAM,EACN,MAAM,GAIP;IACC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,iCAAiC;IACjC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAqB,EAAE,CAAC,CAAC;IAE3D,8EAA8E;IAC9E,MAAM,QAAQ,GAAG,OAAO,CACtB,GAAG,EAAE,CAAC,WAAW,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,EAAE,EACzD,CAAC,MAAM,CAAC,CACT,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,QAAQ,CAAC,EAAE,CAAC,CAAC;YACb,OAAO;QACT,CAAC;QACD,CAAC,KAAK,IAAI,EAAE;YACV,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBACvD,IAAI,CAAC,SAAS;oBAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;YACpC,CAAC;YAAC,OAAO,eAAe,EAAE,CAAC;gBACzB,IAAI,CAAC;oBACH,uEAAuE;oBACvE,mDAAmD;oBACnD,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAChC,OAAO,EACP,GAAG,QAAQ,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,EACnC,MAAM,CACP,CAAC;oBACF,IAAI,CAAC,SAAS;wBAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;gBACpC,CAAC;gBAAC,OAAO,YAAY,EAAE,CAAC;oBACtB,MAAM,iBAAiB,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;oBACxD,MAAM,cAAc,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;oBAClD,IAAI,CAAC,SAAS,EAAE,CAAC;wBACf,QAAQ,CAAC;4BACP,KAAK,EACH,iBAAiB,KAAK,cAAc;gCAClC,CAAC,CAAC,cAAc;gCAChB,CAAC,CAAC,eAAe,iBAAiB,uBAAuB,cAAc,EAAE;yBAC9E,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC,CAAC;QACF,sEAAsE;QACtE,uCAAuC;IACzC,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAExC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CACL,cAAK,SAAS,EAAC,wHAAwH,sCAEjI,CACP,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO,CACL,eAAK,SAAS,EAAC,gBAAgB,aAC7B,cAAK,SAAS,EAAC,+GAA+G,YAC3H,MAAM,GACH,EACN,aAAG,SAAS,EAAC,yBAAyB,2CACT,KAAK,CAAC,KAAK,IACpC,IACA,CACP,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QACf,OAAO,CACL,cAAK,SAAS,EAAC,wHAAwH,uDAEjI,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,cACE,SAAS,EAAC,0EAA0E;QACpF,gEAAgE;QAChE,uBAAuB,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,EAAE,GAC9C,CACH,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,EAC1B,IAAI,EACJ,OAAO,EACP,KAAK,EACL,OAAO,GACqB;IAC5B,OAAO,CACL,mBAAS,SAAS,EAAC,YAAY,mBAAgB,OAAO,aACnD,KAAK,IAAI,cAAK,SAAS,EAAC,kBAAkB,YAAE,KAAK,GAAO,EACzD,KAAC,cAAc,IAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAI,EACvD,IAAI,CAAC,OAAO,IAAI,CACf,YAAG,SAAS,EAAC,8BAA8B,YAAE,IAAI,CAAC,OAAO,GAAK,CAC/D,EACA,OAAO,IAAI,YAAG,SAAS,EAAC,sBAAsB,YAAE,OAAO,GAAK,IACrD,CACX,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,EACR,QAAQ,GACoB;IAC5B,MAAM,QAAQ,GAAG,KAAK,EAAE,CAAC;IACzB,MAAM,SAAS,GAAG,KAAK,EAAE,CAAC;IAE1B,OAAO,CACL,eAAK,SAAS,EAAC,YAAY,4CACzB,eAAK,SAAS,EAAC,cAAc,aAC3B,KAAC,QAAQ,IAAC,OAAO,EAAE,QAAQ,+BAA2B,EACtD,mBACE,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,IAAI,CAAC,MAAM,EAClB,QAAQ,EAAE,CAAC,QAAQ,EACnB,UAAU,EAAE,KAAK,EACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,QAAQ,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAEnD,SAAS,EAAC,oQAAoQ,EAC9Q,WAAW,EAAE,0CAA0C,GACvD,EACF,YAAG,SAAS,EAAC,+BAA+B,+EAExC,IACA,EACN,eAAK,SAAS,EAAC,cAAc,aAC3B,KAAC,QAAQ,IAAC,OAAO,EAAE,SAAS,wBAAoB,EAChD,KAAC,QAAQ,IACP,EAAE,EAAE,SAAS,EACb,KAAK,EAAE,IAAI,CAAC,OAAO,IAAI,EAAE,EACzB,QAAQ,EAAE,CAAC,QAAQ,EACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,QAAQ,CAAC;4BACP,GAAG,IAAI;4BACP,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,SAAS;yBACzC,CAAC,EAEJ,WAAW,EAAC,kBAAkB,GAC9B,IACE,IACF,CACP,CAAC;AACJ,CAAC","sourcesContent":["import { useEffect, useId, useMemo, useState } from \"react\";\nimport type { BlockEditProps, BlockReadProps } from \"../types.js\";\nimport type { MermaidData } from \"./mermaid.config.js\";\nimport { DevInput, DevLabel } from \"./dev-doc-ui.js\";\n\n/**\n * Read + Edit renderers for a `mermaid` block — a Mermaid diagram definition\n * (flowchart, sequence, etc.) edited as raw text and rendered as an\n * Excalidraw-style SVG so it matches the plan's hand-drawn / sketchy house\n * style.\n * Lives in core so any app can register the dev-doc block; it stays app-agnostic\n * (no shadcn / next-themes import).\n *\n * The Mermaid and Excalidraw runtimes are browser-only,\n * so the Read renderer SSR-guards: it renders a lightweight placeholder until a\n * `useEffect` confirms it is mounted, then dynamically imports\n * `@excalidraw/mermaid-to-excalidraw` + `@excalidraw/excalidraw` and injects\n * the exported SVG. If Excalidraw conversion fails, it falls back to Mermaid's\n * hand-drawn renderer. Parse errors never throw; they show the raw source and\n * the error message.\n *\n * Dark mode: the plan editor toggles a `.dark` class on <html>. The Read renderer\n * reads `document.documentElement.classList.contains(\"dark\")` (re-checking on a\n * `MutationObserver` of the html class) and re-renders the diagram with matching\n * light/dark export settings.\n */\n\ninterface MermaidRenderState {\n svg?: string;\n error?: string;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : \"Failed to render diagram\";\n}\n\nfunction sanitizeSvgMarkup(svg: string): string {\n if (typeof DOMParser === \"undefined\") return svg;\n const doc = new DOMParser().parseFromString(svg, \"image/svg+xml\");\n doc\n .querySelectorAll(\"script, foreignObject\")\n .forEach((node) => node.remove());\n for (const element of Array.from(doc.querySelectorAll(\"*\"))) {\n for (const attr of Array.from(element.attributes)) {\n const name = attr.name.toLowerCase();\n const value = attr.value.trim().toLowerCase();\n if (\n name.startsWith(\"on\") ||\n ((name === \"href\" || name.endsWith(\":href\")) &&\n value.startsWith(\"javascript:\"))\n ) {\n element.removeAttribute(attr.name);\n }\n }\n }\n return doc.documentElement.outerHTML;\n}\n\nasync function renderExcalidrawSvg(\n source: string,\n isDark: boolean,\n): Promise<string> {\n const [{ parseMermaidToExcalidraw }, excalidraw] = await Promise.all([\n import(\"@excalidraw/mermaid-to-excalidraw\") as Promise<{\n parseMermaidToExcalidraw: (source: string) => Promise<{\n elements: unknown[];\n files?: Record<string, unknown>;\n }>;\n }>,\n import(\"@excalidraw/excalidraw\") as Promise<{\n convertToExcalidrawElements: (elements: unknown[]) => unknown[];\n exportToSvg: (options: {\n elements: unknown[];\n appState: {\n theme: \"dark\" | \"light\";\n viewBackgroundColor: string;\n exportWithDarkMode: boolean;\n };\n files: Record<string, unknown>;\n }) => Promise<{ outerHTML: string }>;\n }>,\n ]);\n const { elements, files } = await parseMermaidToExcalidraw(source);\n const excalidrawElements = excalidraw.convertToExcalidrawElements(elements);\n const svg = await excalidraw.exportToSvg({\n elements: excalidrawElements,\n appState: {\n theme: isDark ? \"dark\" : \"light\",\n viewBackgroundColor: \"transparent\",\n exportWithDarkMode: isDark,\n },\n files: files ?? {},\n });\n return sanitizeSvgMarkup(svg.outerHTML);\n}\n\nasync function renderMermaidSvg(\n source: string,\n id: string,\n isDark: boolean,\n): Promise<string> {\n const mermaid = (\n (await import(\"mermaid\")) as {\n default: {\n initialize: (config: Record<string, unknown>) => void;\n render: (id: string, source: string) => Promise<{ svg: string }>;\n };\n }\n ).default;\n mermaid.initialize({\n startOnLoad: false,\n securityLevel: \"strict\",\n look: \"handDrawn\",\n theme: isDark ? \"dark\" : \"neutral\",\n });\n const { svg } = await mermaid.render(id, source);\n return sanitizeSvgMarkup(svg);\n}\n\n/** Read the live dark-mode flag from the document root (next-themes-free). */\nfunction useIsDark(): boolean {\n const [isDark, setIsDark] = useState(false);\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n const root = document.documentElement;\n const read = () => setIsDark(root.classList.contains(\"dark\"));\n read();\n const observer = new MutationObserver(read);\n observer.observe(root, { attributes: true, attributeFilter: [\"class\"] });\n return () => observer.disconnect();\n }, []);\n return isDark;\n}\n\nfunction MermaidDiagram({\n source,\n idSeed,\n}: {\n source: string;\n idSeed: string;\n}) {\n const isDark = useIsDark();\n // Only render the diagram after mount: `mermaid` is client-only and SSR has no\n // DOM for it to measure against.\n const [mounted, setMounted] = useState(false);\n const [state, setState] = useState<MermaidRenderState>({});\n\n // A DOM-id-safe, stable-per-block render id. Mermaid requires a valid CSS id.\n const renderId = useMemo(\n () => `mermaid-${idSeed.replace(/[^a-zA-Z0-9_-]/g, \"-\")}`,\n [idSeed],\n );\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (!mounted) return;\n let cancelled = false;\n const trimmed = source.trim();\n if (!trimmed) {\n setState({});\n return;\n }\n (async () => {\n try {\n const svg = await renderExcalidrawSvg(trimmed, isDark);\n if (!cancelled) setState({ svg });\n } catch (excalidrawError) {\n try {\n // Fallback keeps diagrams usable if a Mermaid feature is not supported\n // by the Excalidraw converter in a given host app.\n const svg = await renderMermaidSvg(\n trimmed,\n `${renderId}-${isDark ? \"d\" : \"l\"}`,\n isDark,\n );\n if (!cancelled) setState({ svg });\n } catch (mermaidError) {\n const excalidrawMessage = errorMessage(excalidrawError);\n const mermaidMessage = errorMessage(mermaidError);\n if (!cancelled) {\n setState({\n error:\n excalidrawMessage === mermaidMessage\n ? mermaidMessage\n : `Excalidraw: ${excalidrawMessage}; Mermaid fallback: ${mermaidMessage}`,\n });\n }\n }\n }\n })();\n return () => {\n cancelled = true;\n };\n // Re-render when the source OR the resolved theme changes so toggling\n // dark/light updates the diagram live.\n }, [mounted, source, isDark, renderId]);\n\n if (!mounted) {\n return (\n <div className=\"mt-2 flex min-h-24 items-center justify-center rounded-lg border border-plan-line bg-plan-code text-sm text-plan-muted\">\n Loading diagram…\n </div>\n );\n }\n\n if (state.error) {\n return (\n <div className=\"mt-2 space-y-2\">\n <pre className=\"overflow-auto rounded-lg border border-plan-line bg-plan-code px-3 py-2 font-mono text-sm text-plan-code-text\">\n {source}\n </pre>\n <p className=\"text-sm text-plan-muted\">\n Could not render diagram: {state.error}\n </p>\n </div>\n );\n }\n\n if (!state.svg) {\n return (\n <div className=\"mt-2 flex min-h-24 items-center justify-center rounded-lg border border-plan-line bg-plan-code text-sm text-plan-muted\">\n Add a diagram definition to render it.\n </div>\n );\n }\n\n return (\n <div\n className=\"mt-2 flex justify-center overflow-auto [&_svg]:h-auto [&_svg]:max-w-full\"\n // Excalidraw and Mermaid output are sanitized before injection.\n dangerouslySetInnerHTML={{ __html: state.svg }}\n />\n );\n}\n\n/**\n * Read-only renderer for a `mermaid` block. Wraps the diagram in the standard\n * titled `plan-block` section + an optional muted caption, matching the plan\n * house style.\n */\nexport function MermaidRead({\n data,\n blockId,\n title,\n summary,\n}: BlockReadProps<MermaidData>) {\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <MermaidDiagram source={data.source} idSeed={blockId} />\n {data.caption && (\n <p className=\"mt-3 text-sm text-plan-muted\">{data.caption}</p>\n )}\n {summary && <p className=\"mt-5 text-plan-muted\">{summary}</p>}\n </section>\n );\n}\n\n/**\n * Edit renderer (panel surface) for a `mermaid` block: a monospace textarea for\n * the diagram source plus an optional caption input. Both commit immediately via\n * `onChange`. `editSurface: \"panel\"` means the registry renders the `Read` view\n * with a corner edit button that opens this form in the plan's shared popover, so\n * this renders only the form (the popover supplies the chrome and title).\n */\nexport function MermaidEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<MermaidData>) {\n const sourceId = useId();\n const captionId = useId();\n\n return (\n <div className=\"grid gap-3\" data-plan-interactive>\n <div className=\"grid gap-1.5\">\n <DevLabel htmlFor={sourceId}>Diagram source</DevLabel>\n <textarea\n id={sourceId}\n value={data.source}\n readOnly={!editable}\n spellCheck={false}\n onChange={(event) =>\n onChange({ ...data, source: event.target.value })\n }\n className=\"flex min-h-56 w-full rounded-md border border-input bg-transparent px-3 py-2 font-mono text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n placeholder={\"flowchart TD\\n A[Start] --> B{Decision}\"}\n />\n <p className=\"text-xs text-muted-foreground\">\n Mermaid syntax — flowcharts, sequence diagrams, and more.\n </p>\n </div>\n <div className=\"grid gap-1.5\">\n <DevLabel htmlFor={captionId}>Caption</DevLabel>\n <DevInput\n id={captionId}\n value={data.caption ?? \"\"}\n readOnly={!editable}\n onChange={(event) =>\n onChange({\n ...data,\n caption: event.target.value || undefined,\n })\n }\n placeholder=\"Optional caption\"\n />\n </div>\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MermaidBlock.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/MermaidBlock.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useId, useMemo, useState } from \"react\";\nimport type { BlockEditProps, BlockReadProps } from \"../types.js\";\nimport type { MermaidData } from \"./mermaid.config.js\";\nimport { DevInput, DevLabel } from \"./dev-doc-ui.js\";\n\n/**\n * Read + Edit renderers for a `mermaid` block — a Mermaid diagram definition\n * (flowchart, sequence, etc.) edited as raw text and rendered as an\n * Excalidraw-style SVG so it matches the plan's hand-drawn / sketchy house\n * style.\n * Lives in core so any app can register the dev-doc block; it stays app-agnostic\n * (no shadcn / next-themes import).\n *\n * The Mermaid and Excalidraw runtimes are browser-only,\n * so the Read renderer SSR-guards: it renders a lightweight placeholder until a\n * `useEffect` confirms it is mounted, then dynamically imports\n * `@excalidraw/mermaid-to-excalidraw` + `@excalidraw/excalidraw` and injects\n * the exported SVG. If Excalidraw conversion fails, it falls back to Mermaid's\n * hand-drawn renderer. Parse errors never throw; they show the raw source and\n * the error message.\n *\n * Dark mode: the plan editor toggles a `.dark` class on <html>. The Read renderer\n * reads `document.documentElement.classList.contains(\"dark\")` (re-checking on a\n * `MutationObserver` of the html class) and re-renders the diagram with matching\n * light/dark export settings.\n */\n\ninterface MermaidRenderState {\n svg?: string;\n error?: string;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : \"Failed to render diagram\";\n}\n\nfunction sanitizeSvgMarkup(svg: string): string {\n if (typeof DOMParser === \"undefined\") return svg;\n const doc = new DOMParser().parseFromString(svg, \"image/svg+xml\");\n doc\n .querySelectorAll(\"script, foreignObject\")\n .forEach((node) => node.remove());\n for (const element of Array.from(doc.querySelectorAll(\"*\"))) {\n for (const attr of Array.from(element.attributes)) {\n const name = attr.name.toLowerCase();\n const value = attr.value.trim().toLowerCase();\n if (\n name.startsWith(\"on\") ||\n ((name === \"href\" || name.endsWith(\":href\")) &&\n value.startsWith(\"javascript:\"))\n ) {\n element.removeAttribute(attr.name);\n }\n }\n }\n return doc.documentElement.outerHTML;\n}\n\nasync function renderExcalidrawSvg(\n source: string,\n isDark: boolean,\n): Promise<string> {\n const [{ parseMermaidToExcalidraw }, excalidraw] = await Promise.all([\n import(\"@excalidraw/mermaid-to-excalidraw\") as Promise<{\n parseMermaidToExcalidraw: (source: string) => Promise<{\n elements: unknown[];\n files?: Record<string, unknown>;\n }>;\n }>,\n import(\"@excalidraw/excalidraw\") as Promise<{\n convertToExcalidrawElements: (elements: unknown[]) => unknown[];\n exportToSvg: (options: {\n elements: unknown[];\n appState: {\n theme: \"dark\" | \"light\";\n viewBackgroundColor: string;\n exportWithDarkMode: boolean;\n };\n files: Record<string, unknown>;\n }) => Promise<{ outerHTML: string }>;\n }>,\n ]);\n const { elements, files } = await parseMermaidToExcalidraw(source);\n const excalidrawElements = excalidraw.convertToExcalidrawElements(elements);\n const svg = await excalidraw.exportToSvg({\n elements: excalidrawElements,\n appState: {\n theme: isDark ? \"dark\" : \"light\",\n viewBackgroundColor: \"transparent\",\n exportWithDarkMode: isDark,\n },\n files: files ?? {},\n });\n return sanitizeSvgMarkup(svg.outerHTML);\n}\n\nasync function renderMermaidSvg(\n source: string,\n id: string,\n isDark: boolean,\n): Promise<string> {\n const mermaid = (\n (await import(\"mermaid\")) as {\n default: {\n initialize: (config: Record<string, unknown>) => void;\n render: (id: string, source: string) => Promise<{ svg: string }>;\n };\n }\n ).default;\n mermaid.initialize({\n startOnLoad: false,\n securityLevel: \"strict\",\n look: \"handDrawn\",\n theme: isDark ? \"dark\" : \"neutral\",\n });\n const { svg } = await mermaid.render(id, source);\n return sanitizeSvgMarkup(svg);\n}\n\n/** Read the live dark-mode flag from the document root (next-themes-free). */\nfunction useIsDark(): boolean {\n const [isDark, setIsDark] = useState(false);\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n const root = document.documentElement;\n const read = () => setIsDark(root.classList.contains(\"dark\"));\n read();\n const observer = new MutationObserver(read);\n observer.observe(root, { attributes: true, attributeFilter: [\"class\"] });\n return () => observer.disconnect();\n }, []);\n return isDark;\n}\n\nfunction MermaidDiagram({\n source,\n idSeed,\n}: {\n source: string;\n idSeed: string;\n}) {\n const isDark = useIsDark();\n // Only render the diagram after mount: `mermaid` is client-only and SSR has no\n // DOM for it to measure against.\n const [mounted, setMounted] = useState(false);\n const [state, setState] = useState<MermaidRenderState>({});\n\n // A DOM-id-safe, stable-per-block render id. Mermaid requires a valid CSS id.\n const renderId = useMemo(\n () => `mermaid-${idSeed.replace(/[^a-zA-Z0-9_-]/g, \"-\")}`,\n [idSeed],\n );\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (!mounted) return;\n let cancelled = false;\n const trimmed = source.trim();\n if (!trimmed) {\n setState({});\n return;\n }\n (async () => {\n try {\n const svg = await renderExcalidrawSvg(trimmed, isDark);\n if (!cancelled) setState({ svg });\n } catch (excalidrawError) {\n try {\n // Fallback keeps diagrams usable if a Mermaid feature is not supported\n // by the Excalidraw converter in a given host app.\n const svg = await renderMermaidSvg(\n trimmed,\n `${renderId}-${isDark ? \"d\" : \"l\"}`,\n isDark,\n );\n if (!cancelled) setState({ svg });\n } catch (mermaidError) {\n const excalidrawMessage = errorMessage(excalidrawError);\n const mermaidMessage = errorMessage(mermaidError);\n if (!cancelled) {\n setState({\n error:\n excalidrawMessage === mermaidMessage\n ? mermaidMessage\n : `Excalidraw: ${excalidrawMessage}; Mermaid fallback: ${mermaidMessage}`,\n });\n }\n }\n }\n })();\n return () => {\n cancelled = true;\n };\n // Re-render when the source OR the resolved theme changes so toggling\n // dark/light updates the diagram live.\n }, [mounted, source, isDark, renderId]);\n\n if (!mounted) {\n return (\n <div className=\"mt-2 flex min-h-24 items-center justify-center rounded-lg border border-plan-line bg-plan-code text-sm text-plan-muted\">\n Loading diagram…\n </div>\n );\n }\n\n if (state.error) {\n return (\n <div className=\"mt-2 space-y-2\">\n <pre className=\"overflow-auto rounded-lg border border-plan-line bg-plan-code px-3 py-2 font-mono [font-size:var(--plan-code-size)] text-plan-code-text\">\n {source}\n </pre>\n <p className=\"text-sm text-plan-muted\">\n Could not render diagram: {state.error}\n </p>\n </div>\n );\n }\n\n if (!state.svg) {\n return (\n <div className=\"mt-2 flex min-h-24 items-center justify-center rounded-lg border border-plan-line bg-plan-code text-sm text-plan-muted\">\n Add a diagram definition to render it.\n </div>\n );\n }\n\n return (\n <div\n className=\"mt-2 flex justify-center overflow-auto [&_svg]:h-auto [&_svg]:max-w-full\"\n // Excalidraw and Mermaid output are sanitized before injection.\n dangerouslySetInnerHTML={{ __html: state.svg }}\n />\n );\n}\n\n/**\n * Read-only renderer for a `mermaid` block. Wraps the diagram in the standard\n * titled `plan-block` section + an optional muted caption, matching the plan\n * house style.\n */\nexport function MermaidRead({\n data,\n blockId,\n title,\n summary,\n}: BlockReadProps<MermaidData>) {\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <MermaidDiagram source={data.source} idSeed={blockId} />\n {data.caption && (\n <p className=\"mt-3 text-sm text-plan-muted\">{data.caption}</p>\n )}\n {summary && <p className=\"mt-5 text-plan-muted\">{summary}</p>}\n </section>\n );\n}\n\n/**\n * Edit renderer (panel surface) for a `mermaid` block: a monospace textarea for\n * the diagram source plus an optional caption input. Both commit immediately via\n * `onChange`. `editSurface: \"panel\"` means the registry renders the `Read` view\n * with a corner edit button that opens this form in the plan's shared popover, so\n * this renders only the form (the popover supplies the chrome and title).\n */\nexport function MermaidEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<MermaidData>) {\n const sourceId = useId();\n const captionId = useId();\n\n return (\n <div className=\"grid gap-3\" data-plan-interactive>\n <div className=\"grid gap-1.5\">\n <DevLabel htmlFor={sourceId}>Diagram source</DevLabel>\n <textarea\n id={sourceId}\n value={data.source}\n readOnly={!editable}\n spellCheck={false}\n onChange={(event) =>\n onChange({ ...data, source: event.target.value })\n }\n className=\"flex min-h-56 w-full rounded-md border border-input bg-transparent px-3 py-2 font-mono text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n placeholder={\"flowchart TD\\n A[Start] --> B{Decision}\"}\n />\n <p className=\"text-xs text-muted-foreground\">\n Mermaid syntax — flowcharts, sequence diagrams, and more.\n </p>\n </div>\n <div className=\"grid gap-1.5\">\n <DevLabel htmlFor={captionId}>Caption</DevLabel>\n <DevInput\n id={captionId}\n value={data.caption ?? \"\"}\n readOnly={!editable}\n onChange={(event) =>\n onChange({\n ...data,\n caption: event.target.value || undefined,\n })\n }\n placeholder=\"Optional caption\"\n />\n </div>\n </div>\n );\n}\n"]}
|
|
@@ -90,6 +90,25 @@ 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;
|
|
93
112
|
/** Whether a resolved list has at least one note worth rendering a rail for. */
|
|
94
113
|
export declare function hasRailAnnotations(items: ResolvedAnnotation[]): boolean;
|
|
95
114
|
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;AAED,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAEvE;AAED,MAAM,MAAM,sBAAsB,GAAG,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"annotation-rail.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/annotation-rail.tsx"],"names":[],"mappings":"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"}
|
|
@@ -113,6 +113,25 @@ 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
|
+
}
|
|
116
135
|
/** Whether a resolved list has at least one note worth rendering a rail for. */
|
|
117
136
|
export function hasRailAnnotations(items) {
|
|
118
137
|
return items.some((item) => item.range);
|