@agent-native/core 0.38.0 → 0.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +8 -1
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/skills.d.ts +5 -4
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +450 -125
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/blocks/BlockView.d.ts +13 -4
- package/dist/client/blocks/BlockView.d.ts.map +1 -1
- package/dist/client/blocks/BlockView.js +34 -13
- package/dist/client/blocks/BlockView.js.map +1 -1
- package/dist/client/blocks/SchemaBlockEditor.d.ts.map +1 -1
- package/dist/client/blocks/SchemaBlockEditor.js +96 -3
- package/dist/client/blocks/SchemaBlockEditor.js.map +1 -1
- package/dist/client/blocks/index.d.ts +18 -1
- package/dist/client/blocks/index.d.ts.map +1 -1
- package/dist/client/blocks/index.js +26 -1
- package/dist/client/blocks/index.js.map +1 -1
- package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts +6 -0
- package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -0
- package/dist/client/blocks/library/AnnotatedCodeBlock.js +135 -0
- package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -0
- package/dist/client/blocks/library/ApiEndpointBlock.d.ts +20 -0
- package/dist/client/blocks/library/ApiEndpointBlock.d.ts.map +1 -0
- package/dist/client/blocks/library/ApiEndpointBlock.js +131 -0
- package/dist/client/blocks/library/ApiEndpointBlock.js.map +1 -0
- package/dist/client/blocks/library/DataModelBlock.d.ts +28 -0
- package/dist/client/blocks/library/DataModelBlock.d.ts.map +1 -0
- package/dist/client/blocks/library/DataModelBlock.js +222 -0
- package/dist/client/blocks/library/DataModelBlock.js.map +1 -0
- package/dist/client/blocks/library/DiffBlock.d.ts +6 -0
- package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -0
- package/dist/client/blocks/library/DiffBlock.js +293 -0
- package/dist/client/blocks/library/DiffBlock.js.map +1 -0
- package/dist/client/blocks/library/FileTreeBlock.d.ts +23 -0
- package/dist/client/blocks/library/FileTreeBlock.d.ts.map +1 -0
- package/dist/client/blocks/library/FileTreeBlock.js +225 -0
- package/dist/client/blocks/library/FileTreeBlock.js.map +1 -0
- package/dist/client/blocks/library/JsonExplorerBlock.d.ts +19 -0
- package/dist/client/blocks/library/JsonExplorerBlock.d.ts.map +1 -0
- package/dist/client/blocks/library/JsonExplorerBlock.js +171 -0
- package/dist/client/blocks/library/JsonExplorerBlock.js.map +1 -0
- package/dist/client/blocks/library/MermaidBlock.d.ts +17 -0
- package/dist/client/blocks/library/MermaidBlock.d.ts.map +1 -0
- package/dist/client/blocks/library/MermaidBlock.js +131 -0
- package/dist/client/blocks/library/MermaidBlock.js.map +1 -0
- package/dist/client/blocks/library/OpenApiSpecBlock.d.ts +19 -0
- package/dist/client/blocks/library/OpenApiSpecBlock.d.ts.map +1 -0
- package/dist/client/blocks/library/OpenApiSpecBlock.js +494 -0
- package/dist/client/blocks/library/OpenApiSpecBlock.js.map +1 -0
- package/dist/client/blocks/library/annotated-code.config.d.ts +58 -0
- package/dist/client/blocks/library/annotated-code.config.d.ts.map +1 -0
- package/dist/client/blocks/library/annotated-code.config.js +53 -0
- package/dist/client/blocks/library/annotated-code.config.js.map +1 -0
- package/dist/client/blocks/library/api-endpoint.config.d.ts +71 -0
- package/dist/client/blocks/library/api-endpoint.config.d.ts.map +1 -0
- package/dist/client/blocks/library/api-endpoint.config.js +91 -0
- package/dist/client/blocks/library/api-endpoint.config.js.map +1 -0
- package/dist/client/blocks/library/checklist.d.ts.map +1 -1
- package/dist/client/blocks/library/checklist.js +3 -1
- package/dist/client/blocks/library/checklist.js.map +1 -1
- package/dist/client/blocks/library/code-tabs.js +1 -1
- package/dist/client/blocks/library/code-tabs.js.map +1 -1
- package/dist/client/blocks/library/data-model.config.d.ts +72 -0
- package/dist/client/blocks/library/data-model.config.d.ts.map +1 -0
- package/dist/client/blocks/library/data-model.config.js +59 -0
- package/dist/client/blocks/library/data-model.config.js.map +1 -0
- package/dist/client/blocks/library/dev-doc-ui.d.ts +49 -0
- package/dist/client/blocks/library/dev-doc-ui.d.ts.map +1 -0
- package/dist/client/blocks/library/dev-doc-ui.js +50 -0
- package/dist/client/blocks/library/dev-doc-ui.js.map +1 -0
- package/dist/client/blocks/library/diff.config.d.ts +41 -0
- package/dist/client/blocks/library/diff.config.d.ts.map +1 -0
- package/dist/client/blocks/library/diff.config.js +34 -0
- package/dist/client/blocks/library/diff.config.js.map +1 -0
- package/dist/client/blocks/library/file-tree.config.d.ts +59 -0
- package/dist/client/blocks/library/file-tree.config.d.ts.map +1 -0
- package/dist/client/blocks/library/file-tree.config.js +45 -0
- package/dist/client/blocks/library/file-tree.config.js.map +1 -0
- package/dist/client/blocks/library/html.d.ts.map +1 -1
- package/dist/client/blocks/library/html.js +4 -1
- package/dist/client/blocks/library/html.js.map +1 -1
- package/dist/client/blocks/library/json-explorer.config.d.ts +46 -0
- package/dist/client/blocks/library/json-explorer.config.d.ts.map +1 -0
- package/dist/client/blocks/library/json-explorer.config.js +28 -0
- package/dist/client/blocks/library/json-explorer.config.js.map +1 -0
- package/dist/client/blocks/library/mermaid.config.d.ts +32 -0
- package/dist/client/blocks/library/mermaid.config.d.ts.map +1 -0
- package/dist/client/blocks/library/mermaid.config.js +24 -0
- package/dist/client/blocks/library/mermaid.config.js.map +1 -0
- package/dist/client/blocks/library/openapi-spec.config.d.ts +49 -0
- package/dist/client/blocks/library/openapi-spec.config.d.ts.map +1 -0
- package/dist/client/blocks/library/openapi-spec.config.js +24 -0
- package/dist/client/blocks/library/openapi-spec.config.js.map +1 -0
- package/dist/client/blocks/library/server-specs.d.ts +35 -0
- package/dist/client/blocks/library/server-specs.d.ts.map +1 -0
- package/dist/client/blocks/library/server-specs.js +171 -0
- package/dist/client/blocks/library/server-specs.js.map +1 -0
- package/dist/client/blocks/library/specs.d.ts +29 -0
- package/dist/client/blocks/library/specs.d.ts.map +1 -0
- package/dist/client/blocks/library/specs.js +229 -0
- package/dist/client/blocks/library/specs.js.map +1 -0
- package/dist/client/blocks/library/table.d.ts.map +1 -1
- package/dist/client/blocks/library/table.js +3 -1
- package/dist/client/blocks/library/table.js.map +1 -1
- package/dist/client/blocks/library/tabs.js +1 -1
- package/dist/client/blocks/library/tabs.js.map +1 -1
- package/dist/client/blocks/registry.d.ts +8 -0
- package/dist/client/blocks/registry.d.ts.map +1 -1
- package/dist/client/blocks/registry.js +15 -0
- package/dist/client/blocks/registry.js.map +1 -1
- package/dist/client/blocks/server.d.ts +9 -0
- package/dist/client/blocks/server.d.ts.map +1 -1
- package/dist/client/blocks/server.js +16 -0
- package/dist/client/blocks/server.js.map +1 -1
- package/dist/client/blocks/types.d.ts +40 -0
- package/dist/client/blocks/types.d.ts.map +1 -1
- package/dist/client/blocks/types.js.map +1 -1
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +10 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/DragHandle.d.ts +52 -0
- package/dist/client/rich-markdown-editor/DragHandle.d.ts.map +1 -0
- package/dist/client/rich-markdown-editor/DragHandle.js +403 -0
- package/dist/client/rich-markdown-editor/DragHandle.js.map +1 -0
- package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts +97 -0
- package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts.map +1 -0
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js +214 -0
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -0
- package/dist/client/rich-markdown-editor/RunId.d.ts +28 -0
- package/dist/client/rich-markdown-editor/RunId.d.ts.map +1 -0
- package/dist/client/rich-markdown-editor/RunId.js +60 -0
- package/dist/client/rich-markdown-editor/RunId.js.map +1 -0
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +25 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js +14 -5
- package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
- package/dist/client/rich-markdown-editor/gfmDoc.d.ts +24 -0
- package/dist/client/rich-markdown-editor/gfmDoc.d.ts.map +1 -0
- package/dist/client/rich-markdown-editor/gfmDoc.js +83 -0
- package/dist/client/rich-markdown-editor/gfmDoc.js.map +1 -0
- package/dist/client/rich-markdown-editor/index.d.ts +5 -0
- package/dist/client/rich-markdown-editor/index.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/index.js +5 -0
- package/dist/client/rich-markdown-editor/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/registrySlashCommands.d.ts +46 -0
- package/dist/client/rich-markdown-editor/registrySlashCommands.d.ts.map +1 -0
- package/dist/client/rich-markdown-editor/registrySlashCommands.js +13 -0
- package/dist/client/rich-markdown-editor/registrySlashCommands.js.map +1 -0
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +33 -0
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/docs/content/template-plan.md +19 -4
- package/docs/content/visual-plans.md +3 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DiffBlock.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/DiffBlock.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, useState } from \"react\";\nimport {\n IconColumns,\n IconDotsVertical,\n IconFileDiff,\n IconList,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport type { BlockEditProps, BlockReadProps } from \"../types.js\";\nimport type { DiffData, DiffMode } from \"./diff.config.js\";\nimport { DevInput, DevLabel, DevTextarea, DevSelect } from \"./dev-doc-ui.js\";\n\n/**\n * GitHub-style before/after diff block. The read renderer computes a line-level\n * diff, then renders it either unified (one column, `+`/`−` gutters) or split\n * (side-by-side). Long unchanged runs collapse into an expandable \"N unchanged\n * lines\" row (progressive disclosure). All colors are theme-aware: greens/reds\n * use Tailwind `light`/`dark:` pairs and the chrome uses the plan `--plan-*`\n * tokens, so the block reads correctly in BOTH modes.\n *\n * Lives in core so any app can register the dev-doc block. The line differ is\n * inlined (a small LCS-based `diffLines`) rather than pulling the `diff` package\n * into core, so core stays dependency-free; the output shape (`{ value, added,\n * removed }` change records) is identical to what the read renderer consumed\n * before.\n *\n * Editing is panel-driven (config-style, like the HTML block): two monospace\n * textareas (Before / After) plus filename, language, and mode controls.\n */\n\n/* ── Inline line differ (LCS) — replaces jsdiff `diffLines` ─────────────────── */\n\ninterface Change {\n value: string;\n added?: boolean;\n removed?: boolean;\n}\n\n/**\n * Split text into lines, each KEEPING its trailing newline (so the change\n * `value`s concatenate back to the original and `splitLines` below behaves the\n * same as it did against jsdiff output).\n */\nfunction toLineTokens(text: string): string[] {\n if (text === \"\") return [];\n const out: string[] = [];\n let start = 0;\n for (let i = 0; i < text.length; i += 1) {\n if (text[i] === \"\\n\") {\n out.push(text.slice(start, i + 1));\n start = i + 1;\n }\n }\n if (start < text.length) out.push(text.slice(start));\n return out;\n}\n\n/**\n * A minimal line-level diff producing jsdiff-compatible `Change[]` records\n * (`{ value }` for context, `{ value, added: true }`, `{ value, removed: true }`).\n * Uses a classic LCS table over line tokens; the inputs here are short code\n * snippets so the O(n·m) table is fine. Removed lines are emitted before added\n * lines within a change region, matching jsdiff's ordering.\n */\nfunction diffLines(before: string, after: string): Change[] {\n const a = toLineTokens(before);\n const b = toLineTokens(after);\n const n = a.length;\n const m = b.length;\n\n // LCS length table.\n const lcs: number[][] = Array.from({ length: n + 1 }, () =>\n new Array<number>(m + 1).fill(0),\n );\n for (let i = n - 1; i >= 0; i -= 1) {\n for (let j = m - 1; j >= 0; j -= 1) {\n lcs[i][j] =\n a[i] === b[j]\n ? lcs[i + 1][j + 1] + 1\n : Math.max(lcs[i + 1][j], lcs[i][j + 1]);\n }\n }\n\n const changes: Change[] = [];\n // Push a token onto the last change if same kind, else open a new change.\n const push = (value: string, kind: \"context\" | \"added\" | \"removed\") => {\n const last = changes[changes.length - 1];\n const sameKind =\n last &&\n Boolean(last.added) === (kind === \"added\") &&\n Boolean(last.removed) === (kind === \"removed\");\n if (sameKind) {\n last.value += value;\n } else {\n changes.push({\n value,\n added: kind === \"added\" ? true : undefined,\n removed: kind === \"removed\" ? true : undefined,\n });\n }\n };\n\n let i = 0;\n let j = 0;\n while (i < n && j < m) {\n if (a[i] === b[j]) {\n push(a[i], \"context\");\n i += 1;\n j += 1;\n } else if (lcs[i + 1][j] >= lcs[i][j + 1]) {\n push(a[i], \"removed\");\n i += 1;\n } else {\n push(b[j], \"added\");\n j += 1;\n }\n }\n while (i < n) {\n push(a[i], \"removed\");\n i += 1;\n }\n while (j < m) {\n push(b[j], \"added\");\n j += 1;\n }\n return changes;\n}\n\n/* ── Diff model ────────────────────────────────────────────────────────────── */\n\ntype DiffRowKind = \"context\" | \"added\" | \"removed\";\n\ninterface DiffRow {\n kind: DiffRowKind;\n /** Line number in the OLD file (omitted for added rows). */\n oldNo?: number;\n /** Line number in the NEW file (omitted for removed rows). */\n newNo?: number;\n text: string;\n}\n\n/** A contiguous run of context lines collapsed when longer than the threshold. */\ninterface CollapsedRun {\n collapsed: true;\n rows: DiffRow[];\n}\n\ntype DiffSegment = DiffRow | CollapsedRun;\n\n/** Number of context lines above which an unchanged run is collapsed. */\nconst COLLAPSE_THRESHOLD = 6;\n/** Context lines kept visible at each edge of a collapsed run. */\nconst CONTEXT_EDGE = 3;\n\n/**\n * Split a change `value` into individual lines. Most hunks carry a trailing\n * newline; drop the empty final element it produces so a 2-line change does not\n * render a phantom 3rd blank line.\n */\nfunction splitLines(value: string): string[] {\n const lines = value.split(\"\\n\");\n if (lines.length > 0 && lines[lines.length - 1] === \"\") lines.pop();\n return lines;\n}\n\n/** Flatten change objects into numbered diff rows. */\nfunction buildRows(changes: Change[]): DiffRow[] {\n const rows: DiffRow[] = [];\n let oldNo = 0;\n let newNo = 0;\n for (const change of changes) {\n const lines = splitLines(change.value);\n for (const text of lines) {\n if (change.added) {\n newNo += 1;\n rows.push({ kind: \"added\", newNo, text });\n } else if (change.removed) {\n oldNo += 1;\n rows.push({ kind: \"removed\", oldNo, text });\n } else {\n oldNo += 1;\n newNo += 1;\n rows.push({ kind: \"context\", oldNo, newNo, text });\n }\n }\n }\n return rows;\n}\n\n/**\n * Group rows into segments, collapsing interior runs of >COLLAPSE_THRESHOLD\n * context rows (keeping CONTEXT_EDGE visible at each side). Leading/trailing runs\n * collapse too, but keep only the inner edge visible.\n */\nfunction segmentRows(rows: DiffRow[]): DiffSegment[] {\n const segments: DiffSegment[] = [];\n let i = 0;\n while (i < rows.length) {\n if (rows[i].kind !== \"context\") {\n segments.push(rows[i]);\n i += 1;\n continue;\n }\n // Gather the full contiguous context run.\n let j = i;\n while (j < rows.length && rows[j].kind === \"context\") j += 1;\n const run = rows.slice(i, j);\n if (run.length <= COLLAPSE_THRESHOLD) {\n for (const row of run) segments.push(row);\n } else {\n const atStart = i === 0;\n const atEnd = j === rows.length;\n const head = atStart ? [] : run.slice(0, CONTEXT_EDGE);\n const tail = atEnd ? [] : run.slice(run.length - CONTEXT_EDGE);\n const hidden = run.slice(head.length, run.length - tail.length);\n for (const row of head) segments.push(row);\n if (hidden.length > 0) segments.push({ collapsed: true, rows: hidden });\n for (const row of tail) segments.push(row);\n }\n i = j;\n }\n return segments;\n}\n\n/* ── Theme-aware row styling (light + dark) ────────────────────────────────── */\n\nconst ROW_BG: Record<DiffRowKind, string> = {\n added: \"bg-emerald-500/10 dark:bg-emerald-400/15\",\n removed: \"bg-rose-500/10 dark:bg-rose-400/15\",\n context: \"\",\n};\n\nconst GUTTER_BG: Record<DiffRowKind, string> = {\n added: \"bg-emerald-500/15 dark:bg-emerald-400/20\",\n removed: \"bg-rose-500/15 dark:bg-rose-400/20\",\n context: \"bg-transparent\",\n};\n\nconst SIGN_COLOR: Record<DiffRowKind, string> = {\n added: \"text-emerald-700 dark:text-emerald-300\",\n removed: \"text-rose-700 dark:text-rose-300\",\n context: \"text-plan-muted\",\n};\n\nconst SIGN: Record<DiffRowKind, string> = {\n added: \"+\",\n removed: \"−\",\n context: \" \",\n};\n\nconst LINE_NO_CLASS =\n \"select-none px-2 text-right font-mono text-[11px] leading-5 text-plan-muted/70 tabular-nums\";\n\n/* ── Read ──────────────────────────────────────────────────────────────────── */\n\nfunction DiffRead({ data, blockId, title, summary }: BlockReadProps<DiffData>) {\n const [mode, setMode] = useState<DiffMode>(data.mode ?? \"unified\");\n const [expanded, setExpanded] = useState<Set<number>>(() => new Set());\n\n const rows = useMemo(\n () => buildRows(diffLines(data.before, data.after)),\n [data.before, data.after],\n );\n\n const added = rows.filter((r) => r.kind === \"added\").length;\n const removed = rows.filter((r) => r.kind === \"removed\").length;\n const unchanged = data.before === data.after;\n\n const toggleRun = (index: number) =>\n setExpanded((prev) => {\n const next = new Set(prev);\n if (next.has(index)) next.delete(index);\n else next.add(index);\n return next;\n });\n\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <div className=\"overflow-hidden rounded-lg border border-plan-line bg-plan-code\">\n {/* Header: filename, language chip, +/− counts, mode toggle. */}\n <div className=\"flex flex-wrap items-center gap-2 border-b border-plan-line bg-plan-block px-3 py-2\">\n <IconFileDiff className=\"size-4 shrink-0 text-plan-muted\" />\n <span className=\"min-w-0 truncate font-mono text-sm font-medium text-plan-text\">\n {data.filename || \"diff\"}\n </span>\n {data.language && (\n <span className=\"shrink-0 rounded border border-plan-line px-1.5 py-0.5 font-mono text-[11px] uppercase tracking-wide text-plan-muted\">\n {data.language}\n </span>\n )}\n <span className=\"ml-1 flex shrink-0 items-center gap-2 font-mono text-xs\">\n <span className=\"text-emerald-700 dark:text-emerald-300\">\n +{added}\n </span>\n <span className=\"text-rose-700 dark:text-rose-300\">−{removed}</span>\n </span>\n <div className=\"ml-auto flex shrink-0 items-center overflow-hidden rounded-md border border-plan-line\">\n <ModeButton\n active={mode === \"unified\"}\n onClick={() => setMode(\"unified\")}\n icon={<IconList className=\"size-3.5\" />}\n label=\"Unified\"\n />\n <ModeButton\n active={mode === \"split\"}\n onClick={() => setMode(\"split\")}\n icon={<IconColumns className=\"size-3.5\" />}\n label=\"Split\"\n />\n </div>\n </div>\n\n {/* Body. */}\n {unchanged ? (\n <div className=\"px-4 py-6 text-center font-mono text-sm text-plan-muted\">\n No changes\n </div>\n ) : mode === \"split\" ? (\n <SplitView rows={rows} />\n ) : (\n <UnifiedView\n rows={rows}\n expanded={expanded}\n onToggleRun={toggleRun}\n />\n )}\n </div>\n {summary && <p className=\"mt-5 text-plan-muted\">{summary}</p>}\n </section>\n );\n}\n\nfunction ModeButton({\n active,\n onClick,\n icon,\n label,\n}: {\n active: boolean;\n onClick: () => void;\n icon: React.ReactNode;\n label: string;\n}) {\n return (\n <button\n type=\"button\"\n data-plan-interactive\n onClick={onClick}\n aria-pressed={active}\n className={cn(\n \"flex cursor-pointer items-center gap-1 px-2 py-1 text-xs font-medium transition-colors\",\n active\n ? \"bg-plan-code text-plan-text\"\n : \"text-plan-muted hover:bg-plan-code/60 hover:text-plan-text\",\n )}\n >\n {icon}\n {label}\n </button>\n );\n}\n\n/* ── Unified view ──────────────────────────────────────────────────────────── */\n\nfunction UnifiedView({\n rows,\n expanded,\n onToggleRun,\n}: {\n rows: DiffRow[];\n expanded: Set<number>;\n onToggleRun: (index: number) => void;\n}) {\n const segments = useMemo(() => segmentRows(rows), [rows]);\n let runIndex = 0;\n return (\n <div className=\"overflow-x-auto\">\n <div className=\"min-w-full font-mono text-[13px] leading-5\">\n {segments.map((segment, idx) => {\n if (\"collapsed\" in segment) {\n const key = runIndex++;\n const open = expanded.has(key);\n return (\n <div key={`run-${key}`}>\n <CollapsedRow\n count={segment.rows.length}\n open={open}\n onClick={() => onToggleRun(key)}\n />\n {open &&\n segment.rows.map((row, ri) => (\n <UnifiedRow key={`run-${key}-${ri}`} row={row} />\n ))}\n </div>\n );\n }\n return <UnifiedRow key={idx} row={segment} />;\n })}\n </div>\n </div>\n );\n}\n\nfunction UnifiedRow({ row }: { row: DiffRow }) {\n return (\n <div className={cn(\"flex w-full\", ROW_BG[row.kind])}>\n <span className={cn(LINE_NO_CLASS, \"w-10\")}>{row.oldNo ?? \"\"}</span>\n <span className={cn(LINE_NO_CLASS, \"w-10\")}>{row.newNo ?? \"\"}</span>\n <span\n className={cn(\n \"w-6 shrink-0 select-none text-center font-semibold\",\n GUTTER_BG[row.kind],\n SIGN_COLOR[row.kind],\n )}\n >\n {SIGN[row.kind]}\n </span>\n <pre className=\"m-0 flex-1 overflow-visible whitespace-pre px-2 text-plan-text\">\n {row.text || \" \"}\n </pre>\n </div>\n );\n}\n\nfunction CollapsedRow({\n count,\n open,\n onClick,\n}: {\n count: number;\n open: boolean;\n onClick: () => void;\n}) {\n return (\n <button\n type=\"button\"\n data-plan-interactive\n onClick={onClick}\n className=\"flex w-full cursor-pointer items-center gap-2 border-y border-plan-line/60 bg-plan-block/50 px-3 py-1 text-left text-xs text-plan-muted transition-colors hover:bg-plan-block\"\n >\n <IconDotsVertical className=\"size-3.5 shrink-0\" />\n <span>\n {open ? \"Hide\" : \"Show\"} {count} unchanged line\n {count === 1 ? \"\" : \"s\"}\n </span>\n </button>\n );\n}\n\n/* ── Split (side-by-side) view ─────────────────────────────────────────────── */\n\ninterface SplitRow {\n left?: DiffRow;\n right?: DiffRow;\n}\n\n/**\n * Pair removed lines (left) with added lines (right) so a modification shows the\n * old and new side by side; context lines mirror on both columns. Leftover adds\n * or removes fall through as half-empty rows (GitHub split behavior).\n */\nfunction pairSplitRows(rows: DiffRow[]): SplitRow[] {\n const out: SplitRow[] = [];\n let i = 0;\n while (i < rows.length) {\n const row = rows[i];\n if (row.kind === \"context\") {\n out.push({ left: row, right: row });\n i += 1;\n continue;\n }\n // Collect a contiguous block of removed-then-added rows.\n const removed: DiffRow[] = [];\n const added: DiffRow[] = [];\n while (i < rows.length && rows[i].kind === \"removed\")\n removed.push(rows[i++]);\n while (i < rows.length && rows[i].kind === \"added\") added.push(rows[i++]);\n const max = Math.max(removed.length, added.length);\n for (let k = 0; k < max; k += 1) {\n out.push({ left: removed[k], right: added[k] });\n }\n }\n return out;\n}\n\nfunction SplitView({ rows }: { rows: DiffRow[] }) {\n const pairs = useMemo(() => pairSplitRows(rows), [rows]);\n return (\n <div className=\"overflow-x-auto\">\n <div className=\"grid min-w-full grid-cols-2 font-mono text-[13px] leading-5\">\n {pairs.map((pair, idx) => (\n <SplitRowView key={idx} pair={pair} />\n ))}\n </div>\n </div>\n );\n}\n\nfunction SplitRowView({ pair }: { pair: SplitRow }) {\n return (\n <>\n <SplitCell row={pair.left} side=\"old\" />\n <SplitCell row={pair.right} side=\"new\" />\n </>\n );\n}\n\nfunction SplitCell({ row, side }: { row?: DiffRow; side: \"old\" | \"new\" }) {\n if (!row) {\n return (\n <div\n className={cn(\n \"min-h-5 bg-plan-block/40\",\n side === \"old\" && \"border-r border-plan-line\",\n )}\n />\n );\n }\n const sign = side === \"old\" ? \"−\" : \"+\";\n const showSign = row.kind !== \"context\";\n return (\n <div\n className={cn(\n \"flex\",\n ROW_BG[row.kind],\n side === \"old\" && \"border-r border-plan-line\",\n )}\n >\n <span className={cn(LINE_NO_CLASS, \"w-10\")}>\n {side === \"old\" ? (row.oldNo ?? \"\") : (row.newNo ?? \"\")}\n </span>\n <span\n className={cn(\n \"w-5 shrink-0 select-none text-center font-semibold\",\n GUTTER_BG[row.kind],\n SIGN_COLOR[row.kind],\n )}\n >\n {showSign ? sign : \" \"}\n </span>\n <pre className=\"m-0 flex-1 overflow-visible whitespace-pre px-2 text-plan-text\">\n {row.text || \" \"}\n </pre>\n </div>\n );\n}\n\n/* ── Edit (panel) ──────────────────────────────────────────────────────────── */\n\nconst codeAreaClass = \"min-h-[140px] font-mono text-xs leading-5\";\n\nfunction DiffEdit({ data, onChange, editable }: BlockEditProps<DiffData>) {\n const patch = (next: Partial<DiffData>) => onChange({ ...data, ...next });\n const mode: DiffMode = data.mode ?? \"unified\";\n\n return (\n <div className=\"flex flex-col gap-3\" data-plan-interactive>\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <div className=\"flex flex-col gap-1.5\">\n <DevLabel htmlFor=\"diff-filename\" className=\"text-xs\">\n Filename\n </DevLabel>\n <DevInput\n id=\"diff-filename\"\n value={data.filename ?? \"\"}\n placeholder=\"src/add.ts\"\n disabled={!editable}\n onChange={(event) =>\n patch({ filename: event.target.value || undefined })\n }\n />\n </div>\n <div className=\"flex flex-col gap-1.5\">\n <DevLabel htmlFor=\"diff-language\" className=\"text-xs\">\n Language\n </DevLabel>\n <DevInput\n id=\"diff-language\"\n value={data.language ?? \"\"}\n placeholder=\"ts\"\n disabled={!editable}\n onChange={(event) =>\n patch({ language: event.target.value || undefined })\n }\n />\n </div>\n </div>\n\n <div className=\"flex flex-col gap-1.5\">\n <DevLabel className=\"text-xs\">Layout</DevLabel>\n <DevSelect\n value={mode}\n disabled={!editable}\n onValueChange={(value) => patch({ mode: value as DiffMode })}\n options={[\n { value: \"unified\", label: \"Unified\" },\n { value: \"split\", label: \"Split (side-by-side)\" },\n ]}\n />\n </div>\n\n <div className=\"flex flex-col gap-1.5\">\n <DevLabel htmlFor=\"diff-before\" className=\"text-xs\">\n Before\n </DevLabel>\n <DevTextarea\n id=\"diff-before\"\n spellCheck={false}\n className={codeAreaClass}\n value={data.before}\n disabled={!editable}\n onChange={(event) => patch({ before: event.target.value })}\n />\n </div>\n\n <div className=\"flex flex-col gap-1.5\">\n <DevLabel htmlFor=\"diff-after\" className=\"text-xs\">\n After\n </DevLabel>\n <DevTextarea\n id=\"diff-after\"\n spellCheck={false}\n className={codeAreaClass}\n value={data.after}\n disabled={!editable}\n onChange={(event) => patch({ after: event.target.value })}\n />\n </div>\n </div>\n );\n}\n\nexport { DiffRead, DiffEdit };\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { BlockEditProps, BlockReadProps } from "../types.js";
|
|
2
|
+
import type { FileTreeData } from "./file-tree.config.js";
|
|
3
|
+
/**
|
|
4
|
+
* Read-only renderer for a `file-tree` block — a VS Code / GitHub-explorer file
|
|
5
|
+
* and change tree. The flat `entries` are folded into a nested tree of
|
|
6
|
+
* collapsible folders (IconFolder + chevron) and files (IconFile) carrying a
|
|
7
|
+
* single-letter change badge (A/M/D/R). A file with a `note` or `snippet` is
|
|
8
|
+
* itself clickable and expands to show the note plus the snippet rendered as a
|
|
9
|
+
* fenced code block via `ctx.renderMarkdown`. A summary header tallies the change
|
|
10
|
+
* counts ("+N · ~M · −K"). Every color is theme-aware via Tailwind `dark:`
|
|
11
|
+
* variants / plan CSS vars, so the tree reads correctly in both modes.
|
|
12
|
+
*/
|
|
13
|
+
export declare function FileTreeRead({ data, blockId, title, summary, ctx, }: BlockReadProps<FileTreeData>): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
/**
|
|
15
|
+
* Panel editor for a `file-tree` block. A structured form: an optional title
|
|
16
|
+
* Input plus a list of file rows (add/remove), each carrying a path Input, a
|
|
17
|
+
* change Select, a note Input, an optional language Input, and a snippet
|
|
18
|
+
* Textarea. The folder tree is derived from the paths in the Read render, so the
|
|
19
|
+
* form stays flat and quick to edit. Renders BARE content (no `<section>`); the
|
|
20
|
+
* registry's panel surface supplies the popover chrome.
|
|
21
|
+
*/
|
|
22
|
+
export declare function FileTreeEdit({ data, onChange, editable, }: BlockEditProps<FileTreeData>): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
//# sourceMappingURL=FileTreeBlock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileTreeBlock.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/FileTreeBlock.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAEV,YAAY,EAEb,MAAM,uBAAuB,CAAC;AAgM/B;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,OAAO,EACP,KAAK,EACL,OAAO,EACP,GAAG,GACJ,EAAE,cAAc,CAAC,YAAY,CAAC,2CAgN9B;AAMD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,QAAQ,EACR,QAAQ,GACT,EAAE,cAAc,CAAC,YAAY,CAAC,2CAgI9B"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
|
+
import { IconChevronRight, IconFile, IconFolder, IconFolderOpen, IconPlus, IconTrash, } from "@tabler/icons-react";
|
|
4
|
+
import { cn } from "../../utils.js";
|
|
5
|
+
import { FILE_TREE_CHANGES } from "./file-tree.config.js";
|
|
6
|
+
import { DevInput, DevTextarea, DevSelect } from "./dev-doc-ui.js";
|
|
7
|
+
/**
|
|
8
|
+
* Read + Edit renderers for a `file-tree` block — a VS Code / GitHub-explorer
|
|
9
|
+
* file and change tree. Lives in core so any app can register the dev-doc block
|
|
10
|
+
* (no shadcn import; the editor's enum picker is the core `DevSelect`).
|
|
11
|
+
*/
|
|
12
|
+
/* ── Theme-aware change tokens ─────────────────────────────────────────────── */
|
|
13
|
+
/**
|
|
14
|
+
* Change-badge palette. Tinted background + saturated text in BOTH the `.dark`
|
|
15
|
+
* plan theme and light mode (never a dark-only palette). Each entry keeps legible
|
|
16
|
+
* contrast against the plan surface via Tailwind `dark:` variants.
|
|
17
|
+
*/
|
|
18
|
+
const CHANGE_BADGE = {
|
|
19
|
+
added: "bg-emerald-100 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300",
|
|
20
|
+
modified: "bg-blue-100 text-blue-700 dark:bg-blue-500/15 dark:text-blue-300",
|
|
21
|
+
removed: "bg-red-100 text-red-700 dark:bg-red-500/15 dark:text-red-300",
|
|
22
|
+
renamed: "bg-violet-100 text-violet-700 dark:bg-violet-500/15 dark:text-violet-300",
|
|
23
|
+
};
|
|
24
|
+
/** Single-letter glyph shown in the change badge (VS Code gutter convention). */
|
|
25
|
+
const CHANGE_GLYPH = {
|
|
26
|
+
added: "A",
|
|
27
|
+
modified: "M",
|
|
28
|
+
removed: "D",
|
|
29
|
+
renamed: "R",
|
|
30
|
+
};
|
|
31
|
+
/** Accent ink for the file name itself, echoing its change color. */
|
|
32
|
+
const CHANGE_NAME_INK = {
|
|
33
|
+
added: "text-emerald-700 dark:text-emerald-300",
|
|
34
|
+
modified: "text-blue-700 dark:text-blue-300",
|
|
35
|
+
removed: "text-red-600 line-through dark:text-red-300",
|
|
36
|
+
renamed: "text-violet-700 dark:text-violet-300",
|
|
37
|
+
};
|
|
38
|
+
const CHANGE_LABEL = {
|
|
39
|
+
added: "Added",
|
|
40
|
+
modified: "Modified",
|
|
41
|
+
removed: "Removed",
|
|
42
|
+
renamed: "Renamed",
|
|
43
|
+
};
|
|
44
|
+
/** Infer a fence language for a file's snippet from its `language` or extension. */
|
|
45
|
+
function fenceLanguage(entry) {
|
|
46
|
+
if (entry.language?.trim())
|
|
47
|
+
return entry.language.trim();
|
|
48
|
+
const ext = entry.path.split(".").pop()?.toLowerCase() ?? "";
|
|
49
|
+
const byExt = {
|
|
50
|
+
ts: "ts",
|
|
51
|
+
tsx: "tsx",
|
|
52
|
+
js: "js",
|
|
53
|
+
jsx: "jsx",
|
|
54
|
+
mjs: "js",
|
|
55
|
+
cjs: "js",
|
|
56
|
+
json: "json",
|
|
57
|
+
css: "css",
|
|
58
|
+
scss: "scss",
|
|
59
|
+
html: "html",
|
|
60
|
+
md: "md",
|
|
61
|
+
mdx: "md",
|
|
62
|
+
py: "python",
|
|
63
|
+
rb: "ruby",
|
|
64
|
+
go: "go",
|
|
65
|
+
rs: "rust",
|
|
66
|
+
sql: "sql",
|
|
67
|
+
sh: "bash",
|
|
68
|
+
yml: "yaml",
|
|
69
|
+
yaml: "yaml",
|
|
70
|
+
toml: "toml",
|
|
71
|
+
};
|
|
72
|
+
return byExt[ext] ?? "text";
|
|
73
|
+
}
|
|
74
|
+
/** Wrap a raw snippet in a fenced code block for `ctx.renderMarkdown`. */
|
|
75
|
+
function fence(snippet, language) {
|
|
76
|
+
// Never let the snippet's own content break out of the fence.
|
|
77
|
+
const safe = snippet.replace(/```/g, "ʼʼʼ");
|
|
78
|
+
return `\`\`\`${language}\n${safe.replace(/\s+$/, "")}\n\`\`\``;
|
|
79
|
+
}
|
|
80
|
+
function makeFolder(name, path) {
|
|
81
|
+
return { name, path, folders: new Map(), files: [], order: [] };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Build a nested folder tree from the flat `entries`. Folders are derived purely
|
|
85
|
+
* from the slash segments of each `path`; a single-segment path is a root file.
|
|
86
|
+
* Insertion order is preserved within each folder, with folders sorted before
|
|
87
|
+
* files at each level (the conventional explorer ordering).
|
|
88
|
+
*/
|
|
89
|
+
function buildTree(entries) {
|
|
90
|
+
const root = makeFolder("", "");
|
|
91
|
+
entries.forEach((entry, index) => {
|
|
92
|
+
const segments = entry.path.split("/").filter(Boolean);
|
|
93
|
+
if (segments.length === 0)
|
|
94
|
+
return;
|
|
95
|
+
const fileName = segments[segments.length - 1];
|
|
96
|
+
const folderSegments = segments.slice(0, -1);
|
|
97
|
+
let cursor = root;
|
|
98
|
+
let prefix = "";
|
|
99
|
+
for (const segment of folderSegments) {
|
|
100
|
+
prefix = prefix ? `${prefix}/${segment}` : segment;
|
|
101
|
+
let next = cursor.folders.get(segment);
|
|
102
|
+
if (!next) {
|
|
103
|
+
next = makeFolder(segment, prefix);
|
|
104
|
+
cursor.folders.set(segment, next);
|
|
105
|
+
cursor.order.push(`d:${segment}`);
|
|
106
|
+
}
|
|
107
|
+
cursor = next;
|
|
108
|
+
}
|
|
109
|
+
cursor.files.push({
|
|
110
|
+
kind: "file",
|
|
111
|
+
name: fileName,
|
|
112
|
+
path: entry.path,
|
|
113
|
+
entry,
|
|
114
|
+
index,
|
|
115
|
+
});
|
|
116
|
+
cursor.order.push(`f:${cursor.files.length - 1}`);
|
|
117
|
+
});
|
|
118
|
+
const materialize = (folder) => {
|
|
119
|
+
const nodes = [];
|
|
120
|
+
for (const key of folder.order) {
|
|
121
|
+
if (key.startsWith("d:")) {
|
|
122
|
+
const child = folder.folders.get(key.slice(2));
|
|
123
|
+
if (!child)
|
|
124
|
+
continue;
|
|
125
|
+
nodes.push({
|
|
126
|
+
kind: "folder",
|
|
127
|
+
name: child.name,
|
|
128
|
+
path: child.path,
|
|
129
|
+
children: materialize(child),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
const file = folder.files[Number(key.slice(2))];
|
|
134
|
+
if (file)
|
|
135
|
+
nodes.push(file);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Folders before files at this level (standard explorer ordering).
|
|
139
|
+
return [
|
|
140
|
+
...nodes.filter((node) => node.kind === "folder"),
|
|
141
|
+
...nodes.filter((node) => node.kind === "file"),
|
|
142
|
+
];
|
|
143
|
+
};
|
|
144
|
+
return materialize(root);
|
|
145
|
+
}
|
|
146
|
+
/* ── Read (IDE explorer) ───────────────────────────────────────────────────── */
|
|
147
|
+
const INDENT_STEP = 14; // px per nesting level — the explorer guide spacing.
|
|
148
|
+
/**
|
|
149
|
+
* Read-only renderer for a `file-tree` block — a VS Code / GitHub-explorer file
|
|
150
|
+
* and change tree. The flat `entries` are folded into a nested tree of
|
|
151
|
+
* collapsible folders (IconFolder + chevron) and files (IconFile) carrying a
|
|
152
|
+
* single-letter change badge (A/M/D/R). A file with a `note` or `snippet` is
|
|
153
|
+
* itself clickable and expands to show the note plus the snippet rendered as a
|
|
154
|
+
* fenced code block via `ctx.renderMarkdown`. A summary header tallies the change
|
|
155
|
+
* counts ("+N · ~M · −K"). Every color is theme-aware via Tailwind `dark:`
|
|
156
|
+
* variants / plan CSS vars, so the tree reads correctly in both modes.
|
|
157
|
+
*/
|
|
158
|
+
export function FileTreeRead({ data, blockId, title, summary, ctx, }) {
|
|
159
|
+
const entries = data.entries ?? [];
|
|
160
|
+
const tree = useMemo(() => buildTree(entries), [entries]);
|
|
161
|
+
// Folders default to fully expanded so the tree is useful at a glance.
|
|
162
|
+
const [collapsedFolders, setCollapsedFolders] = useState({});
|
|
163
|
+
// Files with a note/snippet collapse their detail by default (progressive
|
|
164
|
+
// disclosure) — keyed by the flat entry index so duplicate names never clash.
|
|
165
|
+
const [openFiles, setOpenFiles] = useState({});
|
|
166
|
+
const toggleFolder = (path) => setCollapsedFolders((current) => ({
|
|
167
|
+
...current,
|
|
168
|
+
[path]: !current[path],
|
|
169
|
+
}));
|
|
170
|
+
const toggleFile = (index) => setOpenFiles((current) => ({ ...current, [index]: !current[index] }));
|
|
171
|
+
// Change tally for the summary header.
|
|
172
|
+
const counts = useMemo(() => {
|
|
173
|
+
const tally = { added: 0, modified: 0, removed: 0, renamed: 0 };
|
|
174
|
+
for (const entry of entries) {
|
|
175
|
+
if (entry.change)
|
|
176
|
+
tally[entry.change] += 1;
|
|
177
|
+
}
|
|
178
|
+
return tally;
|
|
179
|
+
}, [entries]);
|
|
180
|
+
const changeTotal = counts.added + counts.modified + counts.removed + counts.renamed;
|
|
181
|
+
const renderNodes = (nodes, depth) => nodes.map((node) => {
|
|
182
|
+
const indent = depth * INDENT_STEP;
|
|
183
|
+
if (node.kind === "folder") {
|
|
184
|
+
const collapsed = collapsedFolders[node.path] ?? false;
|
|
185
|
+
return (_jsxs("div", { children: [_jsxs("button", { type: "button", "data-plan-interactive": true, "aria-expanded": !collapsed, onClick: () => toggleFolder(node.path), style: { paddingLeft: indent + 8 }, 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", children: [_jsx(IconChevronRight, { className: cn("size-3.5 shrink-0 text-plan-muted transition-transform", !collapsed && "rotate-90") }), collapsed ? (_jsx(IconFolder, { className: "size-4 shrink-0 text-amber-500 dark:text-amber-300" })) : (_jsx(IconFolderOpen, { className: "size-4 shrink-0 text-amber-500 dark:text-amber-300" })), _jsx("span", { className: "min-w-0 truncate font-medium text-plan-text", children: node.name })] }), !collapsed && _jsx("div", { children: renderNodes(node.children, depth + 1) })] }, `d:${node.path}`));
|
|
186
|
+
}
|
|
187
|
+
const { entry } = node;
|
|
188
|
+
const change = entry.change;
|
|
189
|
+
const hasDetail = Boolean(entry.note?.trim() || entry.snippet?.trim());
|
|
190
|
+
const isOpen = openFiles[node.index] ?? false;
|
|
191
|
+
return (_jsxs("div", { children: [_jsxs("button", { type: "button", "data-plan-interactive": true, disabled: !hasDetail, "aria-expanded": hasDetail ? isOpen : undefined, onClick: hasDetail ? () => toggleFile(node.index) : undefined, style: { paddingLeft: indent + 8 }, className: cn("group flex w-full items-center gap-1.5 rounded-md py-1 pr-2 text-left text-sm transition-colors", hasDetail ? "hover:bg-accent/40" : "cursor-default"), children: [hasDetail ? (_jsx(IconChevronRight, { className: cn("size-3.5 shrink-0 text-plan-muted transition-transform", isOpen && "rotate-90") })) : (_jsx("span", { className: "size-3.5 shrink-0", "aria-hidden": true })), _jsx(IconFile, { className: cn("size-4 shrink-0", change === "removed" ? "text-plan-muted" : "text-plan-muted/80") }), _jsx("span", { className: cn("min-w-0 truncate font-mono", change ? CHANGE_NAME_INK[change] : "text-plan-text"), children: node.name }), change && (_jsx("span", { title: CHANGE_LABEL[change], "aria-label": CHANGE_LABEL[change], className: cn("ml-1 flex size-4 shrink-0 items-center justify-center rounded text-[10px] font-bold leading-none", CHANGE_BADGE[change]), children: CHANGE_GLYPH[change] })), entry.note?.trim() && !isOpen && (_jsx("span", { className: "ml-1 min-w-0 flex-1 truncate text-xs text-plan-muted", children: entry.note }))] }), hasDetail && isOpen && (_jsxs("div", { style: { paddingLeft: indent + 8 + 20 }, className: "pb-2 pr-2 pt-0.5", children: [entry.note?.trim() && (_jsx("p", { className: "text-xs leading-relaxed text-plan-muted", children: entry.note })), entry.snippet?.trim() && (_jsx("div", { className: "mt-2 an-file-tree-snippet", children: ctx.renderMarkdown?.(fence(entry.snippet, fenceLanguage(entry))) }))] }))] }, `f:${node.index}`));
|
|
192
|
+
});
|
|
193
|
+
return (_jsxs("section", { className: "plan-block", "data-block-id": blockId, children: [title && _jsx("div", { className: "plan-block-label", children: title }), _jsxs("div", { className: "overflow-hidden rounded-xl border border-plan-line bg-plan-block", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2 border-b border-plan-line bg-accent/20 px-3 py-2", children: [data.title && (_jsx("span", { className: "text-sm font-semibold text-plan-text", children: data.title })), _jsxs("span", { className: "text-xs text-plan-muted", children: [entries.length, " ", entries.length === 1 ? "file" : "files"] }), changeTotal > 0 && (_jsxs("span", { className: "ml-auto flex items-center gap-2 font-mono text-xs", children: [counts.added > 0 && (_jsxs("span", { className: "text-emerald-600 dark:text-emerald-300", children: ["+", counts.added] })), counts.modified > 0 && (_jsxs("span", { className: "text-blue-600 dark:text-blue-300", children: ["~", counts.modified] })), counts.removed > 0 && (_jsxs("span", { className: "text-red-600 dark:text-red-300", children: ["\u2212", counts.removed] })), counts.renamed > 0 && (_jsxs("span", { className: "text-violet-600 dark:text-violet-300", children: ["\u00BB", counts.renamed] }))] }))] }), _jsx("div", { className: "py-1.5", children: tree.length > 0 ? (renderNodes(tree, 0)) : (_jsx("p", { className: "px-3 py-2 text-xs text-plan-muted", children: "No files yet." })) })] }), summary && _jsx("p", { className: "mt-5 text-plan-muted", children: summary })] }));
|
|
194
|
+
}
|
|
195
|
+
/* ── Edit (panel form) ─────────────────────────────────────────────────────── */
|
|
196
|
+
const fieldLabelClass = "text-xs font-medium text-muted-foreground";
|
|
197
|
+
/**
|
|
198
|
+
* Panel editor for a `file-tree` block. A structured form: an optional title
|
|
199
|
+
* Input plus a list of file rows (add/remove), each carrying a path Input, a
|
|
200
|
+
* change Select, a note Input, an optional language Input, and a snippet
|
|
201
|
+
* Textarea. The folder tree is derived from the paths in the Read render, so the
|
|
202
|
+
* form stays flat and quick to edit. Renders BARE content (no `<section>`); the
|
|
203
|
+
* registry's panel surface supplies the popover chrome.
|
|
204
|
+
*/
|
|
205
|
+
export function FileTreeEdit({ data, onChange, editable, }) {
|
|
206
|
+
const entries = data.entries ?? [];
|
|
207
|
+
const patchEntries = (next) => onChange({ ...data, entries: next });
|
|
208
|
+
const updateEntry = (index, next) => patchEntries(entries.map((entry, i) => (i === index ? { ...entry, ...next } : entry)));
|
|
209
|
+
const removeEntry = (index) => patchEntries(entries.filter((_, i) => i !== index));
|
|
210
|
+
const addEntry = () => patchEntries([...entries, { path: "src/new-file.ts", change: "added" }]);
|
|
211
|
+
return (_jsxs("div", { className: "flex flex-col gap-4", "data-plan-interactive": true, children: [_jsxs("label", { className: "flex flex-col gap-1.5", children: [_jsx("span", { className: fieldLabelClass, children: "Title (optional)" }), _jsx(DevInput, { className: "h-9", value: data.title ?? "", disabled: !editable, placeholder: "e.g. Files touched", onChange: (event) => onChange({ ...data, title: event.target.value || undefined }) })] }), _jsx("div", { className: "flex flex-col gap-3", children: entries.map((entry, index) => (_jsxs("div", { className: "flex flex-col gap-2 rounded-lg border border-input p-3", children: [_jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_120px_auto] gap-2", children: [_jsx(DevInput, { className: "h-8 font-mono text-xs", value: entry.path, disabled: !editable, placeholder: "src/routes/git.ts", onChange: (event) => updateEntry(index, { path: event.target.value }) }), _jsx(DevSelect, { className: "h-8", value: entry.change ?? "none", disabled: !editable, onValueChange: (value) => updateEntry(index, {
|
|
212
|
+
change: value === "none" ? undefined : value,
|
|
213
|
+
}), options: [
|
|
214
|
+
{ value: "none", label: "No change" },
|
|
215
|
+
...FILE_TREE_CHANGES.map((change) => ({
|
|
216
|
+
value: change,
|
|
217
|
+
label: CHANGE_LABEL[change],
|
|
218
|
+
})),
|
|
219
|
+
] }), editable && (_jsx("button", { type: "button", "data-plan-interactive": true, "aria-label": "Remove file", className: "flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/60 hover:text-foreground", onClick: () => removeEntry(index), children: _jsx(IconTrash, { className: "size-4" }) }))] }), _jsx(DevInput, { className: "h-8 text-xs", value: entry.note ?? "", disabled: !editable, placeholder: "Why this file changes", onChange: (event) => updateEntry(index, { note: event.target.value || undefined }) }), _jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_120px] gap-2", children: [_jsx(DevTextarea, { className: "min-h-[64px] font-mono text-xs", value: entry.snippet ?? "", disabled: !editable, placeholder: "Optional code snippet", onChange: (event) => updateEntry(index, {
|
|
220
|
+
snippet: event.target.value || undefined,
|
|
221
|
+
}) }), _jsx(DevInput, { className: "h-8 self-start font-mono text-xs", value: entry.language ?? "", disabled: !editable, placeholder: "language", onChange: (event) => updateEntry(index, {
|
|
222
|
+
language: event.target.value || undefined,
|
|
223
|
+
}) })] })] }, index))) }), editable && (_jsxs("button", { type: "button", "data-plan-interactive": true, 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", onClick: addEntry, children: [_jsx(IconPlus, { className: "size-4" }), "Add file"] }))] }));
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=FileTreeBlock.js.map
|
|
@@ -0,0 +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\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\n/* ── Read (IDE explorer) ───────────────────────────────────────────────────── */\n\nconst INDENT_STEP = 14; // px per nesting level — the explorer guide spacing.\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(() => 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 // 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 renderNodes = (nodes: TreeNode[], depth: number): React.ReactNode =>\n nodes.map((node) => {\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-amber-500 dark:text-amber-300\" />\n ) : (\n <IconFolderOpen className=\"size-4 shrink-0 text-amber-500 dark:text-amber-300\" />\n )}\n <span className=\"min-w-0 truncate font-medium text-plan-text\">\n {node.name}\n </span>\n </button>\n {!collapsed && <div>{renderNodes(node.children, depth + 1)}</div>}\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-mono\",\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 renderNodes(tree, 0)\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"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { BlockEditProps, BlockReadProps } from "../types.js";
|
|
2
|
+
import type { JsonExplorerData } from "./json-explorer.config.js";
|
|
3
|
+
/**
|
|
4
|
+
* Read-only renderer for a `json-explorer` block. Parses `data.json` defensively
|
|
5
|
+
* and renders the collapsible tree; on a parse error it shows the raw payload in
|
|
6
|
+
* a monospace block plus the error (never throws). An "Expand all / Collapse
|
|
7
|
+
* all" control toggles every node at once via a global pulse counter.
|
|
8
|
+
*/
|
|
9
|
+
export declare function JsonExplorerRead({ data, blockId, title, summary, }: BlockReadProps<JsonExplorerData>): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
/**
|
|
11
|
+
* Panel editor for a `json-explorer` block: a monospace textarea bound to the
|
|
12
|
+
* raw `json`, a "Format" button that pretty-prints via `JSON.parse` →
|
|
13
|
+
* `JSON.stringify(_, null, 2)` (guarded — shows an INLINE error, never
|
|
14
|
+
* `window.alert`), a `collapsedDepth` number input, and a `title` input. Renders
|
|
15
|
+
* BARE content (no `<section>`); the registry's panel surface supplies the
|
|
16
|
+
* popover chrome.
|
|
17
|
+
*/
|
|
18
|
+
export declare function JsonExplorerEdit({ data, onChange, editable, }: BlockEditProps<JsonExplorerData>): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
//# sourceMappingURL=JsonExplorerBlock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonExplorerBlock.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/JsonExplorerBlock.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAwOlE;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,OAAO,EACP,KAAK,EACL,OAAO,GACR,EAAE,cAAc,CAAC,gBAAgB,CAAC,2CA4ElC;AAID;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,QAAQ,EACR,QAAQ,GACT,EAAE,cAAc,CAAC,gBAAgB,CAAC,2CA+FlC"}
|