@agent-native/core 0.39.2 → 0.40.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 +1 -1
- package/dist/action.js +12 -0
- package/dist/action.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +5 -1
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/skills.d.ts +4 -3
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +756 -694
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/blocks/AiEditableField.d.ts +8 -0
- package/dist/client/blocks/AiEditableField.d.ts.map +1 -0
- package/dist/client/blocks/AiEditableField.js +10 -0
- package/dist/client/blocks/AiEditableField.js.map +1 -0
- package/dist/client/blocks/BlockView.d.ts +3 -3
- package/dist/client/blocks/BlockView.d.ts.map +1 -1
- package/dist/client/blocks/BlockView.js +15 -3
- package/dist/client/blocks/BlockView.js.map +1 -1
- package/dist/client/blocks/SchemaBlockEditor.js +2 -2
- package/dist/client/blocks/SchemaBlockEditor.js.map +1 -1
- package/dist/client/blocks/index.d.ts +5 -2
- package/dist/client/blocks/index.d.ts.map +1 -1
- package/dist/client/blocks/index.js +6 -3
- package/dist/client/blocks/index.js.map +1 -1
- package/dist/client/blocks/library/ApiEndpointBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/ApiEndpointBlock.js +20 -6
- package/dist/client/blocks/library/ApiEndpointBlock.js.map +1 -1
- package/dist/client/blocks/library/DiffBlock.d.ts +29 -0
- package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/DiffBlock.js +190 -30
- 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 +46 -7
- package/dist/client/blocks/library/FileTreeBlock.js.map +1 -1
- package/dist/client/blocks/library/HighlightedCode.d.ts +10 -0
- package/dist/client/blocks/library/HighlightedCode.d.ts.map +1 -0
- package/dist/client/blocks/library/HighlightedCode.js +92 -0
- package/dist/client/blocks/library/HighlightedCode.js.map +1 -0
- package/dist/client/blocks/library/JsonExplorerBlock.d.ts +9 -4
- package/dist/client/blocks/library/JsonExplorerBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/JsonExplorerBlock.js +66 -30
- package/dist/client/blocks/library/JsonExplorerBlock.js.map +1 -1
- package/dist/client/blocks/library/MermaidBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/MermaidBlock.js +73 -44
- package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
- package/dist/client/blocks/library/OpenApiSpecBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/OpenApiSpecBlock.js +3 -2
- package/dist/client/blocks/library/OpenApiSpecBlock.js.map +1 -1
- package/dist/client/blocks/library/checklist.d.ts.map +1 -1
- package/dist/client/blocks/library/checklist.js +1 -0
- package/dist/client/blocks/library/checklist.js.map +1 -1
- package/dist/client/blocks/library/code-tabs.d.ts.map +1 -1
- package/dist/client/blocks/library/code-tabs.js +183 -102
- package/dist/client/blocks/library/code-tabs.js.map +1 -1
- package/dist/client/blocks/library/columns.config.d.ts +60 -0
- package/dist/client/blocks/library/columns.config.d.ts.map +1 -0
- package/dist/client/blocks/library/columns.config.js +37 -0
- package/dist/client/blocks/library/columns.config.js.map +1 -0
- package/dist/client/blocks/library/columns.d.ts +25 -0
- package/dist/client/blocks/library/columns.d.ts.map +1 -0
- package/dist/client/blocks/library/columns.js +199 -0
- package/dist/client/blocks/library/columns.js.map +1 -0
- package/dist/client/blocks/library/dev-doc-ui.d.ts +2 -1
- package/dist/client/blocks/library/dev-doc-ui.d.ts.map +1 -1
- package/dist/client/blocks/library/dev-doc-ui.js +2 -1
- package/dist/client/blocks/library/dev-doc-ui.js.map +1 -1
- package/dist/client/blocks/library/html.d.ts +1 -1
- package/dist/client/blocks/library/html.d.ts.map +1 -1
- package/dist/client/blocks/library/html.js +34 -4
- package/dist/client/blocks/library/html.js.map +1 -1
- package/dist/client/blocks/library/json-explorer.config.d.ts +3 -1
- package/dist/client/blocks/library/json-explorer.config.d.ts.map +1 -1
- package/dist/client/blocks/library/json-explorer.config.js +30 -1
- package/dist/client/blocks/library/json-explorer.config.js.map +1 -1
- package/dist/client/blocks/library/server-specs.d.ts.map +1 -1
- package/dist/client/blocks/library/server-specs.js +13 -3
- package/dist/client/blocks/library/server-specs.js.map +1 -1
- package/dist/client/blocks/library/specs.d.ts +4 -4
- package/dist/client/blocks/library/specs.d.ts.map +1 -1
- package/dist/client/blocks/library/specs.js +21 -16
- package/dist/client/blocks/library/specs.js.map +1 -1
- package/dist/client/blocks/library/table.config.d.ts +3 -0
- package/dist/client/blocks/library/table.config.d.ts.map +1 -1
- package/dist/client/blocks/library/table.config.js +13 -1
- package/dist/client/blocks/library/table.config.js.map +1 -1
- package/dist/client/blocks/library/table.d.ts.map +1 -1
- package/dist/client/blocks/library/table.js +90 -9
- package/dist/client/blocks/library/table.js.map +1 -1
- package/dist/client/blocks/library/tabs.config.d.ts +16 -8
- package/dist/client/blocks/library/tabs.config.d.ts.map +1 -1
- package/dist/client/blocks/library/tabs.config.js +10 -4
- package/dist/client/blocks/library/tabs.config.js.map +1 -1
- package/dist/client/blocks/library/tabs.d.ts.map +1 -1
- package/dist/client/blocks/library/tabs.js +146 -21
- package/dist/client/blocks/library/tabs.js.map +1 -1
- package/dist/client/blocks/server.d.ts +2 -1
- 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 +99 -9
- 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 +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/BubbleToolbar.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/BubbleToolbar.js +13 -3
- package/dist/client/rich-markdown-editor/BubbleToolbar.js.map +1 -1
- package/dist/client/rich-markdown-editor/DragHandle.d.ts +49 -4
- package/dist/client/rich-markdown-editor/DragHandle.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/DragHandle.js +656 -88
- package/dist/client/rich-markdown-editor/DragHandle.js.map +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts +10 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js +180 -15
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +2 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js +3 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
- package/dist/client/rich-markdown-editor/SlashCommandMenu.d.ts +5 -0
- package/dist/client/rich-markdown-editor/SlashCommandMenu.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/SlashCommandMenu.js +33 -5
- package/dist/client/rich-markdown-editor/SlashCommandMenu.js.map +1 -1
- package/dist/client/rich-markdown-editor/index.d.ts +3 -3
- package/dist/client/rich-markdown-editor/index.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/index.js +2 -2
- package/dist/client/rich-markdown-editor/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/registrySlashCommands.d.ts +14 -0
- package/dist/client/rich-markdown-editor/registrySlashCommands.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/registrySlashCommands.js +38 -0
- package/dist/client/rich-markdown-editor/registrySlashCommands.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts +1 -0
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +4 -0
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +17 -1
- package/dist/db/client.js.map +1 -1
- package/dist/sharing/access.d.ts +4 -2
- package/dist/sharing/access.d.ts.map +1 -1
- package/dist/sharing/access.js +8 -3
- package/dist/sharing/access.js.map +1 -1
- package/dist/sharing/actions/set-resource-visibility.d.ts.map +1 -1
- package/dist/sharing/actions/set-resource-visibility.js +2 -3
- package/dist/sharing/actions/set-resource-visibility.js.map +1 -1
- package/dist/sharing/registry.d.ts +13 -0
- package/dist/sharing/registry.d.ts.map +1 -1
- package/dist/sharing/registry.js.map +1 -1
- package/dist/styles/rich-markdown-editor.css +15 -0
- package/package.json +16 -1
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import { IconCode, IconPlus,
|
|
2
|
+
import { useMemo, useRef, useState, } from "react";
|
|
3
|
+
import { IconCode, IconPencil, IconPlus, IconTrash } from "@tabler/icons-react";
|
|
4
|
+
import { common, createLowlight } from "lowlight";
|
|
4
5
|
import { cn } from "../../utils.js";
|
|
5
6
|
import { defineBlock } from "../types.js";
|
|
7
|
+
import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover.js";
|
|
8
|
+
import { CodeSurface } from "./HighlightedCode.js";
|
|
6
9
|
import { codeTabsSchema, codeTabsMdx, } from "./code-tabs.config.js";
|
|
7
10
|
/**
|
|
8
11
|
* Standard `code-tabs` block (STANDARD core library): a vertical file tab rail
|
|
@@ -11,34 +14,168 @@ import { codeTabsSchema, codeTabsMdx, } from "./code-tabs.config.js";
|
|
|
11
14
|
* generalized to the registry `Read`/`Edit` contract. Shareable by any app that
|
|
12
15
|
* registers the core block library.
|
|
13
16
|
*
|
|
14
|
-
* `Edit` is
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* services, so it stays portable across apps.
|
|
17
|
+
* `Edit` is hybrid: each tab's `code` field renders as a code-style monospace
|
|
18
|
+
* text area, while tab metadata (label/language/caption/add/remove) stays in a
|
|
19
|
+
* settings popover so the document surface only exposes authored content.
|
|
18
20
|
*/
|
|
21
|
+
/* ── Syntax highlighting helpers ──────────────────────────────────────────── */
|
|
22
|
+
const lowlight = createLowlight(common);
|
|
23
|
+
const LANGUAGE_ALIASES = {
|
|
24
|
+
cjs: "javascript",
|
|
25
|
+
cts: "typescript",
|
|
26
|
+
htm: "html",
|
|
27
|
+
js: "javascript",
|
|
28
|
+
jsonc: "json",
|
|
29
|
+
jsx: "jsx",
|
|
30
|
+
md: "markdown",
|
|
31
|
+
mdx: "markdown",
|
|
32
|
+
mjs: "javascript",
|
|
33
|
+
mts: "typescript",
|
|
34
|
+
py: "python",
|
|
35
|
+
rb: "ruby",
|
|
36
|
+
rs: "rust",
|
|
37
|
+
sh: "bash",
|
|
38
|
+
shell: "bash",
|
|
39
|
+
ts: "typescript",
|
|
40
|
+
tsx: "tsx",
|
|
41
|
+
yml: "yaml",
|
|
42
|
+
zsh: "bash",
|
|
43
|
+
};
|
|
44
|
+
const TOKEN_CLASS_NAMES = {
|
|
45
|
+
"hljs-addition": "text-emerald-700 dark:text-emerald-300",
|
|
46
|
+
"hljs-attr": "text-sky-700 dark:text-sky-300",
|
|
47
|
+
"hljs-attribute": "text-sky-700 dark:text-sky-300",
|
|
48
|
+
"hljs-built_in": "text-amber-700 dark:text-amber-300",
|
|
49
|
+
"hljs-bullet": "text-primary",
|
|
50
|
+
"hljs-comment": "text-muted-foreground italic",
|
|
51
|
+
"hljs-deletion": "text-destructive",
|
|
52
|
+
"hljs-doctag": "text-destructive",
|
|
53
|
+
"hljs-emphasis": "italic",
|
|
54
|
+
"hljs-formula": "text-destructive",
|
|
55
|
+
"hljs-keyword": "text-rose-700 dark:text-rose-300",
|
|
56
|
+
"hljs-link": "text-primary underline-offset-2",
|
|
57
|
+
"hljs-literal": "text-violet-700 dark:text-violet-300",
|
|
58
|
+
"hljs-meta": "text-primary",
|
|
59
|
+
"hljs-meta-string": "text-emerald-700 dark:text-emerald-300",
|
|
60
|
+
"hljs-name": "text-emerald-700 dark:text-emerald-300",
|
|
61
|
+
"hljs-number": "text-sky-700 dark:text-sky-300",
|
|
62
|
+
"hljs-params": "text-sky-700 dark:text-sky-300",
|
|
63
|
+
"hljs-property": "text-sky-700 dark:text-sky-300",
|
|
64
|
+
"hljs-quote": "text-muted-foreground italic",
|
|
65
|
+
"hljs-regexp": "text-emerald-700 dark:text-emerald-300",
|
|
66
|
+
"hljs-section": "text-violet-700 dark:text-violet-300",
|
|
67
|
+
"hljs-selector-attr": "text-primary",
|
|
68
|
+
"hljs-selector-class": "text-emerald-700 dark:text-emerald-300",
|
|
69
|
+
"hljs-selector-id": "text-emerald-700 dark:text-emerald-300",
|
|
70
|
+
"hljs-selector-pseudo": "text-primary",
|
|
71
|
+
"hljs-selector-tag": "text-emerald-700 dark:text-emerald-300",
|
|
72
|
+
"hljs-string": "text-emerald-700 dark:text-emerald-300",
|
|
73
|
+
"hljs-strong": "font-semibold",
|
|
74
|
+
"hljs-subst": "text-destructive",
|
|
75
|
+
"hljs-symbol": "text-primary",
|
|
76
|
+
"hljs-tag": "text-emerald-700 dark:text-emerald-300",
|
|
77
|
+
"hljs-template-variable": "text-amber-700 dark:text-amber-300",
|
|
78
|
+
"hljs-title": "text-violet-700 dark:text-violet-300",
|
|
79
|
+
"hljs-type": "text-amber-700 dark:text-amber-300",
|
|
80
|
+
"hljs-variable": "text-amber-700 dark:text-amber-300",
|
|
81
|
+
language_: "text-amber-700 dark:text-amber-300",
|
|
82
|
+
};
|
|
83
|
+
function normalizeCodeLanguage(value) {
|
|
84
|
+
const raw = value
|
|
85
|
+
?.trim()
|
|
86
|
+
.toLowerCase()
|
|
87
|
+
.replace(/^language-/, "");
|
|
88
|
+
if (!raw)
|
|
89
|
+
return null;
|
|
90
|
+
const normalized = LANGUAGE_ALIASES[raw] ?? raw;
|
|
91
|
+
return lowlight.registered(normalized) ? normalized : null;
|
|
92
|
+
}
|
|
93
|
+
function inferLanguageFromFilename(filename) {
|
|
94
|
+
const basename = filename?.split("/").pop()?.toLowerCase();
|
|
95
|
+
if (!basename)
|
|
96
|
+
return null;
|
|
97
|
+
if (basename === "dockerfile")
|
|
98
|
+
return normalizeCodeLanguage("bash");
|
|
99
|
+
const extension = basename.includes(".")
|
|
100
|
+
? basename.split(".").pop()
|
|
101
|
+
: undefined;
|
|
102
|
+
return normalizeCodeLanguage(extension);
|
|
103
|
+
}
|
|
104
|
+
function codeTabLanguage(tab) {
|
|
105
|
+
return (normalizeCodeLanguage(tab?.language) ??
|
|
106
|
+
inferLanguageFromFilename(tab?.label) ??
|
|
107
|
+
undefined);
|
|
108
|
+
}
|
|
109
|
+
function tokenClassName(value) {
|
|
110
|
+
const classes = Array.isArray(value)
|
|
111
|
+
? value
|
|
112
|
+
: typeof value === "string"
|
|
113
|
+
? value.split(/\s+/)
|
|
114
|
+
: [];
|
|
115
|
+
return classes
|
|
116
|
+
.map((className) => TOKEN_CLASS_NAMES[className] ?? "")
|
|
117
|
+
.filter(Boolean)
|
|
118
|
+
.join(" ");
|
|
119
|
+
}
|
|
120
|
+
function hastToReact(children, keyPrefix) {
|
|
121
|
+
return children.map((node, index) => {
|
|
122
|
+
if (node.type === "text")
|
|
123
|
+
return node.value ?? "";
|
|
124
|
+
if (node.type === "element") {
|
|
125
|
+
const key = `${keyPrefix}${index}`;
|
|
126
|
+
const renderedChildren = node.children?.length
|
|
127
|
+
? hastToReact(node.children, `${key}-`)
|
|
128
|
+
: null;
|
|
129
|
+
const className = tokenClassName(node.properties?.className);
|
|
130
|
+
return (_jsx("span", { className: className || undefined, children: renderedChildren }, key));
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function highlightCode(code, language) {
|
|
136
|
+
const normalized = normalizeCodeLanguage(language);
|
|
137
|
+
if (!normalized || normalized === "plaintext" || normalized === "text") {
|
|
138
|
+
return code;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
const tree = lowlight.highlight(normalized, code);
|
|
142
|
+
return hastToReact(tree.children ?? [], `${normalized}-`);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return code;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
19
148
|
/* ── Read (vertical tab rail + Shiki) ──────────────────────────────────────── */
|
|
20
149
|
function CodeTabsRead({ data, blockId, title }) {
|
|
21
150
|
const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? "");
|
|
22
151
|
const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];
|
|
23
152
|
return (_jsxs("section", { className: "plan-block", "data-block-id": blockId, children: [title && _jsx("div", { className: "plan-block-label", children: title }), _jsxs("div", { className: "grid overflow-hidden border-y border-plan-line md:grid-cols-[300px_minmax(0,1fr)]", children: [_jsx("div", { className: "border-plan-line md:border-r", children: data.tabs.map((tab) => (_jsxs("button", { type: "button", "data-plan-interactive": true, className: cn("flex w-full items-start gap-3 border-b border-plan-line px-4 py-4 text-left", tab.id === active?.id
|
|
24
|
-
? "bg-
|
|
25
|
-
: "text-plan-muted hover:bg-accent/30"), onClick: () => setActiveId(tab.id), children: [_jsx(IconCode, { className: "mt-0.5 size-4 shrink-0" }), _jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: "block truncate font-mono text-sm font-semibold", children: tab.label }), tab.caption && (_jsx("span", { className: "mt-1 block text-xs leading-5", children: tab.caption }))] })] }, tab.id))) }), _jsx("div", { className: "min-w-0 p-5", children: active && (_jsxs(_Fragment, { children: [_jsx("h3", { className: "text-2xl font-semibold tracking-tight", children: active.label }), active.caption && (_jsx("p", { className: "mt-2 text-plan-muted", children: active.caption })), _jsx(CodeSurface, { code: active.code, language: active
|
|
26
|
-
}
|
|
27
|
-
function CodeSurface({ code, language, className, }) {
|
|
28
|
-
return (_jsx("div", { className: cn("plan-code-surface", className ?? "mt-5"), children: _jsx(HighlightedCode, { code: code, language: language }) }));
|
|
153
|
+
? "bg-primary/10 text-plan-text dark:bg-primary/20"
|
|
154
|
+
: "text-plan-muted hover:bg-accent/30"), onClick: () => setActiveId(tab.id), children: [_jsx(IconCode, { className: "mt-0.5 size-4 shrink-0" }), _jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: "block truncate font-mono text-sm font-semibold", children: tab.label }), tab.caption && (_jsx("span", { className: "mt-1 block text-xs leading-5", children: tab.caption }))] })] }, tab.id))) }), _jsx("div", { className: "min-w-0 p-5", children: active && (_jsxs(_Fragment, { children: [_jsx("h3", { className: "text-2xl font-semibold tracking-tight", children: active.label }), active.caption && (_jsx("p", { className: "mt-2 text-plan-muted", children: active.caption })), _jsx(CodeSurface, { code: active.code, language: codeTabLanguage(active) })] })) })] })] }));
|
|
29
155
|
}
|
|
30
156
|
/* ── Edit (code text areas per tab) ────────────────────────────────────────── */
|
|
31
|
-
const inputClass = "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm
|
|
32
|
-
const codeAreaClass = "flex min-h-[140px] w-full rounded-md border border-input bg-transparent px-3 py-2 font-mono text-xs leading-5 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";
|
|
157
|
+
const inputClass = "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50";
|
|
33
158
|
/** Mint a reasonably-unique code-tab id without pulling a dep into core. */
|
|
34
159
|
function newCodeTabId() {
|
|
35
160
|
return `code-tab-${Math.random().toString(36).slice(2, 10)}`;
|
|
36
161
|
}
|
|
162
|
+
function HighlightedCodeTextarea({ value, language, label, editable, onChange, }) {
|
|
163
|
+
const highlightLayerRef = useRef(null);
|
|
164
|
+
const resolvedLanguage = normalizeCodeLanguage(language) ?? inferLanguageFromFilename(label);
|
|
165
|
+
const highlighted = useMemo(() => highlightCode(value, resolvedLanguage ?? undefined), [resolvedLanguage, value]);
|
|
166
|
+
const syncScroll = (event) => {
|
|
167
|
+
const layer = highlightLayerRef.current;
|
|
168
|
+
if (!layer)
|
|
169
|
+
return;
|
|
170
|
+
layer.scrollTop = event.currentTarget.scrollTop;
|
|
171
|
+
layer.scrollLeft = event.currentTarget.scrollLeft;
|
|
172
|
+
};
|
|
173
|
+
return (_jsxs("div", { className: cn("relative min-h-[140px] overflow-hidden rounded-md border border-input bg-background text-foreground focus-within:ring-1 focus-within:ring-ring", !editable && "cursor-not-allowed opacity-50"), "data-code-tabs-highlighted-editor": true, children: [_jsx("pre", { ref: highlightLayerRef, "aria-hidden": "true", className: "pointer-events-none absolute inset-0 m-0 overflow-hidden whitespace-pre px-3 py-2 font-mono text-xs leading-5", "data-code-tabs-highlight-layer": true, children: _jsxs("code", { children: [highlighted, value.endsWith("\n") ? " " : null] }) }), _jsx("textarea", { "data-plan-interactive": true, spellCheck: false, wrap: "off", className: cn("relative z-10 block min-h-[140px] w-full resize-y overflow-auto rounded-md border-0 bg-transparent px-3 py-2 font-mono text-xs leading-5 caret-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed", value ? "text-transparent" : "text-muted-foreground"), value: value, disabled: !editable, onChange: onChange, onScroll: syncScroll })] }));
|
|
174
|
+
}
|
|
37
175
|
/**
|
|
38
|
-
* Editor: a file-tab strip (one tab active at a time)
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* full form vertically. Add/remove/rename keep the schema's 1..12 bounds.
|
|
176
|
+
* Editor: a file-tab strip (one tab active at a time) with the active tab's code
|
|
177
|
+
* editable inline. Tab metadata is edited from the settings popover, mirroring
|
|
178
|
+
* the standard `tabs` block and keeping schema-ish controls out of the document.
|
|
42
179
|
*/
|
|
43
180
|
function CodeTabsEdit({ data, onChange, editable, }) {
|
|
44
181
|
const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? "");
|
|
@@ -63,92 +200,35 @@ function CodeTabsEdit({ data, onChange, editable, }) {
|
|
|
63
200
|
]);
|
|
64
201
|
setActiveId(id);
|
|
65
202
|
};
|
|
66
|
-
return (_jsxs("div", { className: "an-code-tabs-editor flex flex-col gap-4", children: [_jsxs("div", { className: "flex
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
caption: event.target.value || undefined,
|
|
73
|
-
}) })] }), _jsxs("label", { className: "flex flex-col gap-1.5", children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Code" }), _jsx("textarea", { "data-plan-interactive": true, spellCheck: false, className: codeAreaClass, value: active.code, disabled: !editable, onChange: (event) => updateTab(active.id, { code: event.target.value }) })] })] }))] }));
|
|
203
|
+
return (_jsxs("div", { className: "an-code-tabs-editor flex min-w-0 flex-col gap-4", children: [_jsxs("div", { className: "flex w-full min-w-0 items-start gap-2", children: [_jsx("div", { className: "flex w-full min-w-0 flex-1 flex-nowrap items-center gap-1 overflow-x-auto", role: "tablist", "data-plan-interactive": true, children: data.tabs.map((tab) => {
|
|
204
|
+
const selected = tab.id === active?.id;
|
|
205
|
+
return (_jsxs("button", { type: "button", role: "tab", "aria-selected": selected, onClick: () => setActiveId(tab.id), className: cn("flex shrink-0 items-center gap-2 whitespace-nowrap rounded-lg border border-transparent px-3 py-2 font-mono text-sm font-semibold transition-colors", selected
|
|
206
|
+
? "bg-primary/10 text-plan-text dark:bg-primary/20"
|
|
207
|
+
: "text-plan-muted hover:bg-plan-block/60 hover:text-plan-text"), children: [_jsx(IconCode, { className: "size-4 shrink-0" }), tab.label] }, tab.id));
|
|
208
|
+
}) }), editable && (_jsx(CodeTabsSettingsPopover, { active: active, tabs: data.tabs, onUpdate: updateTab, onAdd: addTab, onRemove: removeTab }))] }), active && (_jsxs("label", { className: "flex flex-col gap-1.5", children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Code" }), _jsx(HighlightedCodeTextarea, { value: active.code, editable: editable, label: active.label, language: active.language, onChange: (event) => updateTab(active.id, { code: event.target.value }) })] }))] }));
|
|
74
209
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
import("shiki/langs/yaml.mjs"),
|
|
98
|
-
import("shiki/langs/sql.mjs"),
|
|
99
|
-
],
|
|
100
|
-
engine: createOnigurumaEngine(import("shiki/wasm")),
|
|
101
|
-
});
|
|
102
|
-
})().catch((error) => {
|
|
103
|
-
highlighterLoader = null;
|
|
104
|
-
throw error;
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
return highlighterLoader;
|
|
108
|
-
}
|
|
109
|
-
const LANG_ALIASES = {
|
|
110
|
-
js: "javascript",
|
|
111
|
-
ts: "typescript",
|
|
112
|
-
sh: "bash",
|
|
113
|
-
shell: "bash",
|
|
114
|
-
zsh: "bash",
|
|
115
|
-
py: "python",
|
|
116
|
-
yml: "yaml",
|
|
117
|
-
md: "markdown",
|
|
118
|
-
};
|
|
119
|
-
function HighlightedCode({ code, language, }) {
|
|
120
|
-
const [html, setHtml] = useState(null);
|
|
121
|
-
useEffect(() => {
|
|
122
|
-
let cancelled = false;
|
|
123
|
-
loadHighlighter()
|
|
124
|
-
.then((highlighter) => {
|
|
125
|
-
const requested = (language || "text").toLowerCase();
|
|
126
|
-
const resolved = LANG_ALIASES[requested] ?? requested;
|
|
127
|
-
const loaded = highlighter.getLoadedLanguages();
|
|
128
|
-
const lang = loaded.includes(resolved) ? resolved : "text";
|
|
129
|
-
return highlighter.codeToHtml(code, {
|
|
130
|
-
lang,
|
|
131
|
-
theme: "github-dark-default",
|
|
132
|
-
});
|
|
133
|
-
})
|
|
134
|
-
.then((out) => {
|
|
135
|
-
if (!cancelled)
|
|
136
|
-
setHtml(out);
|
|
137
|
-
})
|
|
138
|
-
.catch(() => {
|
|
139
|
-
if (!cancelled)
|
|
140
|
-
setHtml(null);
|
|
141
|
-
});
|
|
142
|
-
return () => {
|
|
143
|
-
cancelled = true;
|
|
144
|
-
};
|
|
145
|
-
}, [code, language]);
|
|
146
|
-
if (html) {
|
|
147
|
-
// Shiki output is generated from plain text by the highlighter itself —
|
|
148
|
-
// it is NOT agent-authored HTML, so this is safe (mirrors core chat).
|
|
149
|
-
return (_jsx("div", { className: "plan-shiki", dangerouslySetInnerHTML: { __html: html } }));
|
|
150
|
-
}
|
|
151
|
-
return (_jsx("pre", { children: _jsx("code", { className: language ? `language-${language}` : undefined, children: code }) }));
|
|
210
|
+
function CodeTabsSettingsPopover({ active, tabs, onUpdate, onAdd, onRemove, }) {
|
|
211
|
+
return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { type: "button", "data-plan-interactive": true, "aria-label": "Edit code tabs", className: "flex size-8 shrink-0 items-center justify-center rounded-md text-plan-muted transition-colors hover:text-plan-text focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", children: _jsx(IconPencil, { className: "size-4" }) }) }), _jsxs(PopoverContent, { align: "end", side: "bottom", className: "w-80 p-0", "data-plan-interactive": true, children: [_jsxs("div", { className: "border-b border-border px-3 py-2", children: [_jsx("div", { className: "text-sm font-semibold text-foreground", children: "Code tab settings" }), _jsx("div", { className: "text-xs text-muted-foreground", children: "Rename the active tab or manage its metadata." })] }), _jsxs("div", { className: "grid gap-3 p-3", children: [_jsxs("label", { className: "grid gap-1.5", children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Active tab label" }), _jsx("input", { type: "text", "data-plan-interactive": true, className: inputClass, value: active?.label ?? "", disabled: !active, onChange: (event) => {
|
|
212
|
+
if (!active)
|
|
213
|
+
return;
|
|
214
|
+
onUpdate(active.id, { label: event.target.value });
|
|
215
|
+
} })] }), _jsxs("label", { className: "grid gap-1.5", children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Language" }), _jsx("input", { type: "text", "data-plan-interactive": true, className: inputClass, value: active?.language ?? "", disabled: !active, onChange: (event) => {
|
|
216
|
+
if (!active)
|
|
217
|
+
return;
|
|
218
|
+
onUpdate(active.id, {
|
|
219
|
+
language: event.target.value || undefined,
|
|
220
|
+
});
|
|
221
|
+
} })] }), _jsxs("label", { className: "grid gap-1.5", children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Caption" }), _jsx("input", { type: "text", "data-plan-interactive": true, className: inputClass, value: active?.caption ?? "", disabled: !active, onChange: (event) => {
|
|
222
|
+
if (!active)
|
|
223
|
+
return;
|
|
224
|
+
onUpdate(active.id, {
|
|
225
|
+
caption: event.target.value || undefined,
|
|
226
|
+
});
|
|
227
|
+
} })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("button", { type: "button", "data-plan-interactive": true, disabled: tabs.length >= 12, onClick: onAdd, className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50", children: [_jsx(IconPlus, { className: "size-3.5" }), "Add tab"] }), _jsxs("button", { type: "button", "data-plan-interactive": true, disabled: !active || tabs.length <= 1, onClick: () => {
|
|
228
|
+
if (!active)
|
|
229
|
+
return;
|
|
230
|
+
onRemove(active.id);
|
|
231
|
+
}, className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-destructive transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-50", children: [_jsx(IconTrash, { className: "size-3.5" }), "Remove current"] })] })] })] })] }));
|
|
152
232
|
}
|
|
153
233
|
/* ── Spec ──────────────────────────────────────────────────────────────────── */
|
|
154
234
|
export const codeTabsBlock = defineBlock({
|
|
@@ -158,6 +238,7 @@ export const codeTabsBlock = defineBlock({
|
|
|
158
238
|
Read: CodeTabsRead,
|
|
159
239
|
Edit: CodeTabsEdit,
|
|
160
240
|
placement: ["block"],
|
|
241
|
+
editSurface: "inline",
|
|
161
242
|
label: "Code tabs",
|
|
162
243
|
icon: IconCode,
|
|
163
244
|
description: "A vertical file tab rail of syntax-highlighted code snippets, one tab per file with an optional language and caption.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-tabs.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/code-tabs.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useState } from \"react\";\nimport { IconCode, IconPlus, IconX } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport { defineBlock } from \"../types.js\";\nimport type { BlockReadProps, BlockEditProps } from \"../types.js\";\nimport {\n codeTabsSchema,\n codeTabsMdx,\n type CodeTabsData,\n type CodeTabsTab,\n} from \"./code-tabs.config.js\";\n\n/**\n * Standard `code-tabs` block (STANDARD core library): a vertical file tab rail\n * with Shiki-highlighted code panes. Moved verbatim from the plan\n * `CodeTabsBlock` (`DocumentArea.tsx`) so its rendered output is unchanged, then\n * generalized to the registry `Read`/`Edit` contract. Shareable by any app that\n * registers the core block library.\n *\n * `Edit` is schema-driven in spirit: each tab's `code` field renders as a\n * code-style monospace text area (the plain auto-editor can't descend into the\n * `tabs` array), plus label/language/caption inputs. The component owns no app\n * services, so it stays portable across apps.\n */\n\n/* ── Read (vertical tab rail + Shiki) ──────────────────────────────────────── */\n\nfunction CodeTabsRead({ data, blockId, title }: BlockReadProps<CodeTabsData>) {\n const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? \"\");\n const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <div className=\"grid overflow-hidden border-y border-plan-line md:grid-cols-[300px_minmax(0,1fr)]\">\n <div className=\"border-plan-line md:border-r\">\n {data.tabs.map((tab) => (\n <button\n key={tab.id}\n type=\"button\"\n data-plan-interactive\n className={cn(\n \"flex w-full items-start gap-3 border-b border-plan-line px-4 py-4 text-left\",\n tab.id === active?.id\n ? \"bg-plan-block text-plan-text shadow-[inset_3px_0_0_hsl(var(--ring))]\"\n : \"text-plan-muted hover:bg-accent/30\",\n )}\n onClick={() => setActiveId(tab.id)}\n >\n <IconCode className=\"mt-0.5 size-4 shrink-0\" />\n <span className=\"min-w-0\">\n <span className=\"block truncate font-mono text-sm font-semibold\">\n {tab.label}\n </span>\n {tab.caption && (\n <span className=\"mt-1 block text-xs leading-5\">\n {tab.caption}\n </span>\n )}\n </span>\n </button>\n ))}\n </div>\n <div className=\"min-w-0 p-5\">\n {active && (\n <>\n <h3 className=\"text-2xl font-semibold tracking-tight\">\n {active.label}\n </h3>\n {active.caption && (\n <p className=\"mt-2 text-plan-muted\">{active.caption}</p>\n )}\n <CodeSurface code={active.code} language={active.language} />\n </>\n )}\n </div>\n </div>\n </section>\n );\n}\n\nfunction CodeSurface({\n code,\n language,\n className,\n}: {\n code: string;\n language?: string;\n className?: string;\n}) {\n return (\n <div className={cn(\"plan-code-surface\", className ?? \"mt-5\")}>\n <HighlightedCode code={code} language={language} />\n </div>\n );\n}\n\n/* ── Edit (code text areas per tab) ────────────────────────────────────────── */\n\nconst inputClass =\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\";\n\nconst codeAreaClass =\n \"flex min-h-[140px] w-full rounded-md border border-input bg-transparent px-3 py-2 font-mono text-xs leading-5 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\n/** Mint a reasonably-unique code-tab id without pulling a dep into core. */\nfunction newCodeTabId(): string {\n return `code-tab-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/**\n * Editor: a file-tab strip (one tab active at a time) whose active tab exposes\n * label/language/caption/code fields — mirroring the read renderer's tabbed\n * layout and the standard `tabs` block editor instead of stacking every tab's\n * full form vertically. Add/remove/rename keep the schema's 1..12 bounds.\n */\nfunction CodeTabsEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<CodeTabsData>) {\n const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? \"\");\n const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];\n\n const commit = (tabs: CodeTabsTab[]) => onChange({ tabs });\n\n const updateTab = (id: string, patch: Partial<CodeTabsTab>) =>\n commit(\n data.tabs.map((tab) => (tab.id === id ? { ...tab, ...patch } : tab)),\n );\n\n const removeTab = (id: string) => {\n const next = data.tabs.filter((tab) => tab.id !== id);\n if (next.length === 0) return; // tabs must keep at least one (schema min 1)\n commit(next);\n if (activeId === id) setActiveId(next[0]?.id ?? \"\");\n };\n\n const addTab = () => {\n if (data.tabs.length >= 12) return; // schema max\n const id = newCodeTabId();\n commit([\n ...data.tabs,\n { id, label: `file-${data.tabs.length + 1}.ts`, code: \"\" },\n ]);\n setActiveId(id);\n };\n\n return (\n <div className=\"an-code-tabs-editor flex flex-col gap-4\">\n <div\n className=\"flex max-w-full flex-wrap items-center gap-1 overflow-x-auto\"\n role=\"tablist\"\n data-plan-interactive\n >\n {data.tabs.map((tab) => {\n const selected = tab.id === active?.id;\n return (\n <div\n key={tab.id}\n className={cn(\n \"group flex items-center gap-1 rounded-lg pr-1 transition-colors\",\n selected ? \"bg-plan-block shadow-sm\" : \"hover:bg-plan-block/60\",\n )}\n >\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n onClick={() => setActiveId(tab.id)}\n className={cn(\n \"flex items-center gap-2 rounded-lg px-3 py-2 font-mono text-sm font-semibold transition-colors\",\n selected ? \"text-plan-text\" : \"text-plan-muted\",\n )}\n >\n <IconCode className=\"size-4 shrink-0\" />\n {tab.label}\n </button>\n {editable && data.tabs.length > 1 && (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={`Remove ${tab.label}`}\n className={cn(\n \"flex size-6 shrink-0 items-center justify-center rounded text-plan-muted transition-opacity\",\n \"opacity-0 group-hover:opacity-100 group-focus-within:opacity-100\",\n \"hover:bg-muted hover:text-foreground\",\n )}\n onClick={() => removeTab(tab.id)}\n >\n <IconX className=\"size-3.5 shrink-0\" />\n </button>\n )}\n </div>\n );\n })}\n {editable && data.tabs.length < 12 && (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label=\"Add tab\"\n className=\"flex items-center gap-1.5 rounded-md px-2 py-2 text-sm text-plan-muted hover:bg-plan-block/60 hover:text-plan-text\"\n onClick={addTab}\n >\n <IconPlus className=\"size-4\" />\n Add tab\n </button>\n )}\n </div>\n {active && (\n <div className=\"flex flex-col gap-2\">\n <div className=\"grid gap-2 md:grid-cols-2\">\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Label\n </span>\n <input\n type=\"text\"\n data-plan-interactive\n className={inputClass}\n value={active.label}\n disabled={!editable}\n onChange={(event) =>\n updateTab(active.id, { label: event.target.value })\n }\n />\n </label>\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Language\n </span>\n <input\n type=\"text\"\n data-plan-interactive\n className={inputClass}\n value={active.language ?? \"\"}\n disabled={!editable}\n onChange={(event) =>\n updateTab(active.id, {\n language: event.target.value || undefined,\n })\n }\n />\n </label>\n </div>\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Caption\n </span>\n <input\n type=\"text\"\n data-plan-interactive\n className={inputClass}\n value={active.caption ?? \"\"}\n disabled={!editable}\n onChange={(event) =>\n updateTab(active.id, {\n caption: event.target.value || undefined,\n })\n }\n />\n </label>\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Code\n </span>\n <textarea\n data-plan-interactive\n spellCheck={false}\n className={codeAreaClass}\n value={active.code}\n disabled={!editable}\n onChange={(event) =>\n updateTab(active.id, { code: event.target.value })\n }\n />\n </label>\n </div>\n )}\n </div>\n );\n}\n\n/* ── Shiki syntax highlighting (lazy-loaded, single dark theme) ────────────── */\ntype ShikiHighlighter = {\n codeToHtml: (\n code: string,\n options: { lang: string; theme: string },\n ) => string | Promise<string>;\n getLoadedLanguages: () => string[];\n};\n\nlet highlighterLoader: Promise<ShikiHighlighter> | null = null;\nfunction loadHighlighter(): Promise<ShikiHighlighter> {\n if (!highlighterLoader) {\n highlighterLoader = (async () => {\n const [{ createHighlighterCore }, { createOnigurumaEngine }] =\n await Promise.all([\n import(\"shiki/core\"),\n import(\"shiki/engine/oniguruma\"),\n ]);\n return createHighlighterCore({\n themes: [import(\"shiki/themes/github-dark-default.mjs\")],\n langs: [\n import(\"shiki/langs/javascript.mjs\"),\n import(\"shiki/langs/typescript.mjs\"),\n import(\"shiki/langs/jsx.mjs\"),\n import(\"shiki/langs/tsx.mjs\"),\n import(\"shiki/langs/json.mjs\"),\n import(\"shiki/langs/css.mjs\"),\n import(\"shiki/langs/html.mjs\"),\n import(\"shiki/langs/markdown.mjs\"),\n import(\"shiki/langs/bash.mjs\"),\n import(\"shiki/langs/shellscript.mjs\"),\n import(\"shiki/langs/python.mjs\"),\n import(\"shiki/langs/yaml.mjs\"),\n import(\"shiki/langs/sql.mjs\"),\n ],\n engine: createOnigurumaEngine(import(\"shiki/wasm\")),\n }) as unknown as Promise<ShikiHighlighter>;\n })().catch((error) => {\n highlighterLoader = null;\n throw error;\n });\n }\n return highlighterLoader;\n}\n\nconst LANG_ALIASES: Record<string, string> = {\n js: \"javascript\",\n ts: \"typescript\",\n sh: \"bash\",\n shell: \"bash\",\n zsh: \"bash\",\n py: \"python\",\n yml: \"yaml\",\n md: \"markdown\",\n};\n\nfunction HighlightedCode({\n code,\n language,\n}: {\n code: string;\n language?: string;\n}) {\n const [html, setHtml] = useState<string | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n loadHighlighter()\n .then((highlighter) => {\n const requested = (language || \"text\").toLowerCase();\n const resolved = LANG_ALIASES[requested] ?? requested;\n const loaded = highlighter.getLoadedLanguages();\n const lang = loaded.includes(resolved) ? resolved : \"text\";\n return highlighter.codeToHtml(code, {\n lang,\n theme: \"github-dark-default\",\n });\n })\n .then((out) => {\n if (!cancelled) setHtml(out as string);\n })\n .catch(() => {\n if (!cancelled) setHtml(null);\n });\n return () => {\n cancelled = true;\n };\n }, [code, language]);\n\n if (html) {\n // Shiki output is generated from plain text by the highlighter itself —\n // it is NOT agent-authored HTML, so this is safe (mirrors core chat).\n return (\n <div className=\"plan-shiki\" dangerouslySetInnerHTML={{ __html: html }} />\n );\n }\n return (\n <pre>\n <code className={language ? `language-${language}` : undefined}>\n {code}\n </code>\n </pre>\n );\n}\n\n/* ── Spec ──────────────────────────────────────────────────────────────────── */\n\nexport const codeTabsBlock = defineBlock<CodeTabsData>({\n type: \"code-tabs\",\n schema: codeTabsSchema,\n mdx: codeTabsMdx,\n Read: CodeTabsRead,\n Edit: CodeTabsEdit,\n placement: [\"block\"],\n label: \"Code tabs\",\n icon: IconCode,\n description:\n \"A vertical file tab rail of syntax-highlighted code snippets, one tab per file with an optional language and caption.\",\n});\n"]}
|
|
1
|
+
{"version":3,"file":"code-tabs.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/code-tabs.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type ReactNode,\n type UIEvent,\n} from \"react\";\nimport { IconCode, IconPencil, IconPlus, IconTrash } from \"@tabler/icons-react\";\nimport { common, createLowlight } from \"lowlight\";\nimport { cn } from \"../../utils.js\";\nimport { defineBlock } from \"../types.js\";\nimport type { BlockReadProps, BlockEditProps } from \"../types.js\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"../../components/ui/popover.js\";\nimport { CodeSurface } from \"./HighlightedCode.js\";\nimport {\n codeTabsSchema,\n codeTabsMdx,\n type CodeTabsData,\n type CodeTabsTab,\n} from \"./code-tabs.config.js\";\n\n/**\n * Standard `code-tabs` block (STANDARD core library): a vertical file tab rail\n * with Shiki-highlighted code panes. Moved verbatim from the plan\n * `CodeTabsBlock` (`DocumentArea.tsx`) so its rendered output is unchanged, then\n * generalized to the registry `Read`/`Edit` contract. Shareable by any app that\n * registers the core block library.\n *\n * `Edit` is hybrid: each tab's `code` field renders as a code-style monospace\n * text area, while tab metadata (label/language/caption/add/remove) stays in a\n * settings popover so the document surface only exposes authored content.\n */\n\n/* ── Syntax highlighting helpers ──────────────────────────────────────────── */\n\nconst lowlight = createLowlight(common);\n\ntype LowlightNode = {\n type: string;\n value?: string;\n properties?: {\n className?: string[] | string;\n };\n children?: LowlightNode[];\n};\n\nconst LANGUAGE_ALIASES: Record<string, string> = {\n cjs: \"javascript\",\n cts: \"typescript\",\n htm: \"html\",\n js: \"javascript\",\n jsonc: \"json\",\n jsx: \"jsx\",\n md: \"markdown\",\n mdx: \"markdown\",\n mjs: \"javascript\",\n mts: \"typescript\",\n py: \"python\",\n rb: \"ruby\",\n rs: \"rust\",\n sh: \"bash\",\n shell: \"bash\",\n ts: \"typescript\",\n tsx: \"tsx\",\n yml: \"yaml\",\n zsh: \"bash\",\n};\n\nconst TOKEN_CLASS_NAMES: Record<string, string> = {\n \"hljs-addition\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-attr\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-attribute\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-built_in\": \"text-amber-700 dark:text-amber-300\",\n \"hljs-bullet\": \"text-primary\",\n \"hljs-comment\": \"text-muted-foreground italic\",\n \"hljs-deletion\": \"text-destructive\",\n \"hljs-doctag\": \"text-destructive\",\n \"hljs-emphasis\": \"italic\",\n \"hljs-formula\": \"text-destructive\",\n \"hljs-keyword\": \"text-rose-700 dark:text-rose-300\",\n \"hljs-link\": \"text-primary underline-offset-2\",\n \"hljs-literal\": \"text-violet-700 dark:text-violet-300\",\n \"hljs-meta\": \"text-primary\",\n \"hljs-meta-string\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-name\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-number\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-params\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-property\": \"text-sky-700 dark:text-sky-300\",\n \"hljs-quote\": \"text-muted-foreground italic\",\n \"hljs-regexp\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-section\": \"text-violet-700 dark:text-violet-300\",\n \"hljs-selector-attr\": \"text-primary\",\n \"hljs-selector-class\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-selector-id\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-selector-pseudo\": \"text-primary\",\n \"hljs-selector-tag\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-string\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-strong\": \"font-semibold\",\n \"hljs-subst\": \"text-destructive\",\n \"hljs-symbol\": \"text-primary\",\n \"hljs-tag\": \"text-emerald-700 dark:text-emerald-300\",\n \"hljs-template-variable\": \"text-amber-700 dark:text-amber-300\",\n \"hljs-title\": \"text-violet-700 dark:text-violet-300\",\n \"hljs-type\": \"text-amber-700 dark:text-amber-300\",\n \"hljs-variable\": \"text-amber-700 dark:text-amber-300\",\n language_: \"text-amber-700 dark:text-amber-300\",\n};\n\nfunction normalizeCodeLanguage(value?: string | null): string | null {\n const raw = value\n ?.trim()\n .toLowerCase()\n .replace(/^language-/, \"\");\n if (!raw) return null;\n const normalized = LANGUAGE_ALIASES[raw] ?? raw;\n return lowlight.registered(normalized) ? normalized : null;\n}\n\nfunction inferLanguageFromFilename(filename?: string | null): string | null {\n const basename = filename?.split(\"/\").pop()?.toLowerCase();\n if (!basename) return null;\n if (basename === \"dockerfile\") return normalizeCodeLanguage(\"bash\");\n const extension = basename.includes(\".\")\n ? basename.split(\".\").pop()\n : undefined;\n return normalizeCodeLanguage(extension);\n}\n\nfunction codeTabLanguage(tab?: CodeTabsTab): string | undefined {\n return (\n normalizeCodeLanguage(tab?.language) ??\n inferLanguageFromFilename(tab?.label) ??\n undefined\n );\n}\n\nfunction tokenClassName(value: string[] | string | undefined): string {\n const classes = Array.isArray(value)\n ? value\n : typeof value === \"string\"\n ? value.split(/\\s+/)\n : [];\n return classes\n .map((className) => TOKEN_CLASS_NAMES[className] ?? \"\")\n .filter(Boolean)\n .join(\" \");\n}\n\nfunction hastToReact(children: LowlightNode[], keyPrefix: string): ReactNode[] {\n return children.map((node, index) => {\n if (node.type === \"text\") return node.value ?? \"\";\n if (node.type === \"element\") {\n const key = `${keyPrefix}${index}`;\n const renderedChildren = node.children?.length\n ? hastToReact(node.children, `${key}-`)\n : null;\n const className = tokenClassName(node.properties?.className);\n return (\n <span key={key} className={className || undefined}>\n {renderedChildren}\n </span>\n );\n }\n return null;\n });\n}\n\nfunction highlightCode(code: string, language?: string): ReactNode {\n const normalized = normalizeCodeLanguage(language);\n if (!normalized || normalized === \"plaintext\" || normalized === \"text\") {\n return code;\n }\n try {\n const tree = lowlight.highlight(normalized, code) as LowlightNode;\n return hastToReact(tree.children ?? [], `${normalized}-`);\n } catch {\n return code;\n }\n}\n\n/* ── Read (vertical tab rail + Shiki) ──────────────────────────────────────── */\n\nfunction CodeTabsRead({ data, blockId, title }: BlockReadProps<CodeTabsData>) {\n const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? \"\");\n const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <div className=\"grid overflow-hidden border-y border-plan-line md:grid-cols-[300px_minmax(0,1fr)]\">\n <div className=\"border-plan-line md:border-r\">\n {data.tabs.map((tab) => (\n <button\n key={tab.id}\n type=\"button\"\n data-plan-interactive\n className={cn(\n \"flex w-full items-start gap-3 border-b border-plan-line px-4 py-4 text-left\",\n tab.id === active?.id\n ? \"bg-primary/10 text-plan-text dark:bg-primary/20\"\n : \"text-plan-muted hover:bg-accent/30\",\n )}\n onClick={() => setActiveId(tab.id)}\n >\n <IconCode className=\"mt-0.5 size-4 shrink-0\" />\n <span className=\"min-w-0\">\n <span className=\"block truncate font-mono text-sm font-semibold\">\n {tab.label}\n </span>\n {tab.caption && (\n <span className=\"mt-1 block text-xs leading-5\">\n {tab.caption}\n </span>\n )}\n </span>\n </button>\n ))}\n </div>\n <div className=\"min-w-0 p-5\">\n {active && (\n <>\n <h3 className=\"text-2xl font-semibold tracking-tight\">\n {active.label}\n </h3>\n {active.caption && (\n <p className=\"mt-2 text-plan-muted\">{active.caption}</p>\n )}\n <CodeSurface\n code={active.code}\n language={codeTabLanguage(active)}\n />\n </>\n )}\n </div>\n </div>\n </section>\n );\n}\n\n/* ── Edit (code text areas per tab) ────────────────────────────────────────── */\n\nconst inputClass =\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\";\n\n/** Mint a reasonably-unique code-tab id without pulling a dep into core. */\nfunction newCodeTabId(): string {\n return `code-tab-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction HighlightedCodeTextarea({\n value,\n language,\n label,\n editable,\n onChange,\n}: {\n value: string;\n language?: string;\n label?: string;\n editable: boolean;\n onChange: (event: ChangeEvent<HTMLTextAreaElement>) => void;\n}) {\n const highlightLayerRef = useRef<HTMLPreElement>(null);\n const resolvedLanguage =\n normalizeCodeLanguage(language) ?? inferLanguageFromFilename(label);\n const highlighted = useMemo(\n () => highlightCode(value, resolvedLanguage ?? undefined),\n [resolvedLanguage, value],\n );\n\n const syncScroll = (event: UIEvent<HTMLTextAreaElement>) => {\n const layer = highlightLayerRef.current;\n if (!layer) return;\n layer.scrollTop = event.currentTarget.scrollTop;\n layer.scrollLeft = event.currentTarget.scrollLeft;\n };\n\n return (\n <div\n className={cn(\n \"relative min-h-[140px] overflow-hidden rounded-md border border-input bg-background text-foreground focus-within:ring-1 focus-within:ring-ring\",\n !editable && \"cursor-not-allowed opacity-50\",\n )}\n data-code-tabs-highlighted-editor\n >\n <pre\n ref={highlightLayerRef}\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-0 m-0 overflow-hidden whitespace-pre px-3 py-2 font-mono text-xs leading-5\"\n data-code-tabs-highlight-layer\n >\n <code>\n {highlighted}\n {value.endsWith(\"\\n\") ? \" \" : null}\n </code>\n </pre>\n <textarea\n data-plan-interactive\n spellCheck={false}\n wrap=\"off\"\n className={cn(\n \"relative z-10 block min-h-[140px] w-full resize-y overflow-auto rounded-md border-0 bg-transparent px-3 py-2 font-mono text-xs leading-5 caret-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed\",\n value ? \"text-transparent\" : \"text-muted-foreground\",\n )}\n value={value}\n disabled={!editable}\n onChange={onChange}\n onScroll={syncScroll}\n />\n </div>\n );\n}\n\n/**\n * Editor: a file-tab strip (one tab active at a time) with the active tab's code\n * editable inline. Tab metadata is edited from the settings popover, mirroring\n * the standard `tabs` block and keeping schema-ish controls out of the document.\n */\nfunction CodeTabsEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<CodeTabsData>) {\n const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? \"\");\n const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];\n\n const commit = (tabs: CodeTabsTab[]) => onChange({ tabs });\n\n const updateTab = (id: string, patch: Partial<CodeTabsTab>) =>\n commit(\n data.tabs.map((tab) => (tab.id === id ? { ...tab, ...patch } : tab)),\n );\n\n const removeTab = (id: string) => {\n const next = data.tabs.filter((tab) => tab.id !== id);\n if (next.length === 0) return; // tabs must keep at least one (schema min 1)\n commit(next);\n if (activeId === id) setActiveId(next[0]?.id ?? \"\");\n };\n\n const addTab = () => {\n if (data.tabs.length >= 12) return; // schema max\n const id = newCodeTabId();\n commit([\n ...data.tabs,\n { id, label: `file-${data.tabs.length + 1}.ts`, code: \"\" },\n ]);\n setActiveId(id);\n };\n\n return (\n <div className=\"an-code-tabs-editor flex min-w-0 flex-col gap-4\">\n <div className=\"flex w-full min-w-0 items-start gap-2\">\n <div\n className=\"flex w-full min-w-0 flex-1 flex-nowrap items-center gap-1 overflow-x-auto\"\n role=\"tablist\"\n data-plan-interactive\n >\n {data.tabs.map((tab) => {\n const selected = tab.id === active?.id;\n return (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n onClick={() => setActiveId(tab.id)}\n className={cn(\n \"flex shrink-0 items-center gap-2 whitespace-nowrap rounded-lg border border-transparent px-3 py-2 font-mono text-sm font-semibold transition-colors\",\n selected\n ? \"bg-primary/10 text-plan-text dark:bg-primary/20\"\n : \"text-plan-muted hover:bg-plan-block/60 hover:text-plan-text\",\n )}\n >\n <IconCode className=\"size-4 shrink-0\" />\n {tab.label}\n </button>\n );\n })}\n </div>\n {editable && (\n <CodeTabsSettingsPopover\n active={active}\n tabs={data.tabs}\n onUpdate={updateTab}\n onAdd={addTab}\n onRemove={removeTab}\n />\n )}\n </div>\n {active && (\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Code\n </span>\n <HighlightedCodeTextarea\n value={active.code}\n editable={editable}\n label={active.label}\n language={active.language}\n onChange={(event) =>\n updateTab(active.id, { code: event.target.value })\n }\n />\n </label>\n )}\n </div>\n );\n}\n\nfunction CodeTabsSettingsPopover({\n active,\n tabs,\n onUpdate,\n onAdd,\n onRemove,\n}: {\n active: CodeTabsTab | undefined;\n tabs: CodeTabsTab[];\n onUpdate: (id: string, patch: Partial<CodeTabsTab>) => void;\n onAdd: () => void;\n onRemove: (id: string) => void;\n}) {\n return (\n <Popover>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n data-plan-interactive\n aria-label=\"Edit code tabs\"\n className=\"flex size-8 shrink-0 items-center justify-center rounded-md text-plan-muted transition-colors hover:text-plan-text focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n >\n <IconPencil className=\"size-4\" />\n </button>\n </PopoverTrigger>\n <PopoverContent\n align=\"end\"\n side=\"bottom\"\n className=\"w-80 p-0\"\n data-plan-interactive\n >\n <div className=\"border-b border-border px-3 py-2\">\n <div className=\"text-sm font-semibold text-foreground\">\n Code tab settings\n </div>\n <div className=\"text-xs text-muted-foreground\">\n Rename the active tab or manage its metadata.\n </div>\n </div>\n <div className=\"grid gap-3 p-3\">\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Active tab label\n </span>\n <input\n type=\"text\"\n data-plan-interactive\n className={inputClass}\n value={active?.label ?? \"\"}\n disabled={!active}\n onChange={(event) => {\n if (!active) return;\n onUpdate(active.id, { label: event.target.value });\n }}\n />\n </label>\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Language\n </span>\n <input\n type=\"text\"\n data-plan-interactive\n className={inputClass}\n value={active?.language ?? \"\"}\n disabled={!active}\n onChange={(event) => {\n if (!active) return;\n onUpdate(active.id, {\n language: event.target.value || undefined,\n });\n }}\n />\n </label>\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Caption\n </span>\n <input\n type=\"text\"\n data-plan-interactive\n className={inputClass}\n value={active?.caption ?? \"\"}\n disabled={!active}\n onChange={(event) => {\n if (!active) return;\n onUpdate(active.id, {\n caption: event.target.value || undefined,\n });\n }}\n />\n </label>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n data-plan-interactive\n disabled={tabs.length >= 12}\n onClick={onAdd}\n className=\"inline-flex h-8 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <IconPlus className=\"size-3.5\" />\n Add tab\n </button>\n <button\n type=\"button\"\n data-plan-interactive\n disabled={!active || tabs.length <= 1}\n onClick={() => {\n if (!active) return;\n onRemove(active.id);\n }}\n className=\"inline-flex h-8 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-destructive transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <IconTrash className=\"size-3.5\" />\n Remove current\n </button>\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\n/* ── Spec ──────────────────────────────────────────────────────────────────── */\n\nexport const codeTabsBlock = defineBlock<CodeTabsData>({\n type: \"code-tabs\",\n schema: codeTabsSchema,\n mdx: codeTabsMdx,\n Read: CodeTabsRead,\n Edit: CodeTabsEdit,\n placement: [\"block\"],\n editSurface: \"inline\",\n label: \"Code tabs\",\n icon: IconCode,\n description:\n \"A vertical file tab rail of syntax-highlighted code snippets, one tab per file with an optional language and caption.\",\n});\n"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { BlockMdxConfig } from "../types.js";
|
|
3
|
+
import type { NestedBlock } from "../types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Pure (React-free) part of the standard `columns` block: its data schema and
|
|
6
|
+
* MDX round-trip config. Shared by the server MDX adapter (a plan/content app
|
|
7
|
+
* registers it via `@agent-native/core/blocks/server`) and the full client spec
|
|
8
|
+
* (`columns.tsx`). Keeping this React-free means importing it into a server
|
|
9
|
+
* module never pulls React into the Nitro/SSR bundle.
|
|
10
|
+
*
|
|
11
|
+
* `columns` is a STANDARD library block: a multi-column side-by-side container
|
|
12
|
+
* where each column holds a list of child blocks and an optional header label
|
|
13
|
+
* (e.g. "Before"/"After"). The children are rendered RECURSIVELY through the
|
|
14
|
+
* app's own block dispatcher (`ctx.renderBlock`), so registered children render
|
|
15
|
+
* via their spec and unconverted children still fall through the app's legacy
|
|
16
|
+
* switch — the coexistence seam. It mirrors `tabs` exactly, only laid out as a
|
|
17
|
+
* grid instead of a pill rail.
|
|
18
|
+
*
|
|
19
|
+
* Its schema MUST stay data-compatible with the plan `columns` branch of
|
|
20
|
+
* `planBlockSchema` (`columns[]` of `{ id, label?, blocks: Block[] }`). The
|
|
21
|
+
* registry MDX config below keeps the compact self-closing `<Columns …
|
|
22
|
+
* columns={[…]} />` encoding for generic apps and backward compatibility. The
|
|
23
|
+
* Plan app also accepts and exports a more human-editable source form:
|
|
24
|
+
* `<Columns><Column label="Before">…markdown and block components…</Column></Columns>`.
|
|
25
|
+
*/
|
|
26
|
+
/** One column: an optional label and the child blocks it contains. */
|
|
27
|
+
export interface ColumnsColumn {
|
|
28
|
+
id: string;
|
|
29
|
+
/** Optional per-column header (e.g. "Before"/"After"). */
|
|
30
|
+
label?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Child blocks. Typed loosely as {@link NestedBlock} because the app owns the
|
|
33
|
+
* authoritative recursive block union (`planBlockSchema`); the columns spec
|
|
34
|
+
* only validates the column envelope (`id`/`label`) and passes children
|
|
35
|
+
* through.
|
|
36
|
+
*/
|
|
37
|
+
blocks: NestedBlock[];
|
|
38
|
+
}
|
|
39
|
+
export interface ColumnsData {
|
|
40
|
+
columns: ColumnsColumn[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Child blocks are validated by the app's own recursive `planBlockSchema` when
|
|
44
|
+
* the plan persists; here they pass through untyped (`z.any()`) so core never
|
|
45
|
+
* needs to import an app-specific block union. The column envelope (`id`/`label`)
|
|
46
|
+
* mirrors the plan columns schema bounds exactly; a layout can temporarily have
|
|
47
|
+
* one remaining column after deleting another column's final block, and tops
|
|
48
|
+
* out at four to stay legible.
|
|
49
|
+
*/
|
|
50
|
+
export declare const columnsSchema: z.ZodType<ColumnsData>;
|
|
51
|
+
/**
|
|
52
|
+
* MDX config: `columns` is a single JSON-encoded attribute and the block is
|
|
53
|
+
* self-closing — the `<Columns id … columns={[…]} />` form. The entire `columns`
|
|
54
|
+
* array (labels + nested child blocks) is one JSON prop; child blocks are NOT
|
|
55
|
+
* serialized as nested MDX, mirroring how `tabs` encodes its `tabs` array.
|
|
56
|
+
* `toAttrs` returns only `columns`; `fromAttrs` reads the `columns` array
|
|
57
|
+
* (defaulting to `[]` for backward-compat with malformed/empty stored blocks).
|
|
58
|
+
*/
|
|
59
|
+
export declare const columnsMdx: BlockMdxConfig<ColumnsData>;
|
|
60
|
+
//# sourceMappingURL=columns.config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"columns.config.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/columns.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAKD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,EAWT,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;AAExC;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,EAAE,cAAc,CAAC,WAAW,CAMlD,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Matches the plan `idSchema` (`z.string().trim().min(1).max(120)`). */
|
|
3
|
+
const columnIdSchema = z.string().trim().min(1).max(120);
|
|
4
|
+
/**
|
|
5
|
+
* Child blocks are validated by the app's own recursive `planBlockSchema` when
|
|
6
|
+
* the plan persists; here they pass through untyped (`z.any()`) so core never
|
|
7
|
+
* needs to import an app-specific block union. The column envelope (`id`/`label`)
|
|
8
|
+
* mirrors the plan columns schema bounds exactly; a layout can temporarily have
|
|
9
|
+
* one remaining column after deleting another column's final block, and tops
|
|
10
|
+
* out at four to stay legible.
|
|
11
|
+
*/
|
|
12
|
+
export const columnsSchema = z.object({
|
|
13
|
+
columns: z
|
|
14
|
+
.array(z.object({
|
|
15
|
+
id: columnIdSchema,
|
|
16
|
+
label: z.string().trim().min(1).max(120).optional(),
|
|
17
|
+
blocks: z.array(z.any()).max(40),
|
|
18
|
+
}))
|
|
19
|
+
.min(1)
|
|
20
|
+
.max(4),
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* MDX config: `columns` is a single JSON-encoded attribute and the block is
|
|
24
|
+
* self-closing — the `<Columns id … columns={[…]} />` form. The entire `columns`
|
|
25
|
+
* array (labels + nested child blocks) is one JSON prop; child blocks are NOT
|
|
26
|
+
* serialized as nested MDX, mirroring how `tabs` encodes its `tabs` array.
|
|
27
|
+
* `toAttrs` returns only `columns`; `fromAttrs` reads the `columns` array
|
|
28
|
+
* (defaulting to `[]` for backward-compat with malformed/empty stored blocks).
|
|
29
|
+
*/
|
|
30
|
+
export const columnsMdx = {
|
|
31
|
+
tag: "Columns",
|
|
32
|
+
toAttrs: (data) => ({ columns: data.columns }),
|
|
33
|
+
fromAttrs: (attrs) => ({
|
|
34
|
+
columns: (attrs.array("columns") ?? []),
|
|
35
|
+
}),
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=columns.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"columns.config.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/columns.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA6CxB,yEAAyE;AACzE,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEzD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,CAAC;SACP,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,EAAE,EAAE,cAAc;QAClB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;QACnD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;KACjC,CAAC,CACH;SACA,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,CAAC,CAAC;CACV,CAAsC,CAAC;AAExC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,UAAU,GAAgC;IACrD,GAAG,EAAE,SAAS;IACd,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;IAC9C,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACrB,OAAO,EAAE,CAAC,KAAK,CAAC,KAAK,CAAgB,SAAS,CAAC,IAAI,EAAE,CAAoB;KAC1E,CAAC;CACH,CAAC","sourcesContent":["import { z } from \"zod\";\nimport type { BlockMdxConfig } from \"../types.js\";\nimport type { NestedBlock } from \"../types.js\";\n\n/**\n * Pure (React-free) part of the standard `columns` block: its data schema and\n * MDX round-trip config. Shared by the server MDX adapter (a plan/content app\n * registers it via `@agent-native/core/blocks/server`) and the full client spec\n * (`columns.tsx`). Keeping this React-free means importing it into a server\n * module never pulls React into the Nitro/SSR bundle.\n *\n * `columns` is a STANDARD library block: a multi-column side-by-side container\n * where each column holds a list of child blocks and an optional header label\n * (e.g. \"Before\"/\"After\"). The children are rendered RECURSIVELY through the\n * app's own block dispatcher (`ctx.renderBlock`), so registered children render\n * via their spec and unconverted children still fall through the app's legacy\n * switch — the coexistence seam. It mirrors `tabs` exactly, only laid out as a\n * grid instead of a pill rail.\n *\n * Its schema MUST stay data-compatible with the plan `columns` branch of\n * `planBlockSchema` (`columns[]` of `{ id, label?, blocks: Block[] }`). The\n * registry MDX config below keeps the compact self-closing `<Columns …\n * columns={[…]} />` encoding for generic apps and backward compatibility. The\n * Plan app also accepts and exports a more human-editable source form:\n * `<Columns><Column label=\"Before\">…markdown and block components…</Column></Columns>`.\n */\n\n/** One column: an optional label and the child blocks it contains. */\nexport interface ColumnsColumn {\n id: string;\n /** Optional per-column header (e.g. \"Before\"/\"After\"). */\n label?: string;\n /**\n * Child blocks. Typed loosely as {@link NestedBlock} because the app owns the\n * authoritative recursive block union (`planBlockSchema`); the columns spec\n * only validates the column envelope (`id`/`label`) and passes children\n * through.\n */\n blocks: NestedBlock[];\n}\n\nexport interface ColumnsData {\n columns: ColumnsColumn[];\n}\n\n/** Matches the plan `idSchema` (`z.string().trim().min(1).max(120)`). */\nconst columnIdSchema = z.string().trim().min(1).max(120);\n\n/**\n * Child blocks are validated by the app's own recursive `planBlockSchema` when\n * the plan persists; here they pass through untyped (`z.any()`) so core never\n * needs to import an app-specific block union. The column envelope (`id`/`label`)\n * mirrors the plan columns schema bounds exactly; a layout can temporarily have\n * one remaining column after deleting another column's final block, and tops\n * out at four to stay legible.\n */\nexport const columnsSchema = z.object({\n columns: z\n .array(\n z.object({\n id: columnIdSchema,\n label: z.string().trim().min(1).max(120).optional(),\n blocks: z.array(z.any()).max(40),\n }),\n )\n .min(1)\n .max(4),\n}) as unknown as z.ZodType<ColumnsData>;\n\n/**\n * MDX config: `columns` is a single JSON-encoded attribute and the block is\n * self-closing — the `<Columns id … columns={[…]} />` form. The entire `columns`\n * array (labels + nested child blocks) is one JSON prop; child blocks are NOT\n * serialized as nested MDX, mirroring how `tabs` encodes its `tabs` array.\n * `toAttrs` returns only `columns`; `fromAttrs` reads the `columns` array\n * (defaulting to `[]` for backward-compat with malformed/empty stored blocks).\n */\nexport const columnsMdx: BlockMdxConfig<ColumnsData> = {\n tag: \"Columns\",\n toAttrs: (data) => ({ columns: data.columns }),\n fromAttrs: (attrs) => ({\n columns: (attrs.array<ColumnsColumn>(\"columns\") ?? []) as ColumnsColumn[],\n }),\n};\n"]}
|