@braincrew-lab/langchain-canvas 0.1.11 → 0.1.12
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.
|
@@ -67,6 +67,16 @@ function ChartRenderer({ artifact }) {
|
|
|
67
67
|
/* @__PURE__ */ jsx("input", { type: "checkbox", checked: !!options?.stacked, onChange: (e) => patch({ options: { ...options, stacked: e.target.checked } }) }),
|
|
68
68
|
"Stacked"
|
|
69
69
|
] }),
|
|
70
|
+
/* @__PURE__ */ jsx(
|
|
71
|
+
"input",
|
|
72
|
+
{
|
|
73
|
+
className: "cv-chart__title-input",
|
|
74
|
+
value: options?.title ?? "",
|
|
75
|
+
placeholder: "Chart title\u2026",
|
|
76
|
+
onChange: (e) => patch({ options: { ...options, title: e.target.value || void 0 } }),
|
|
77
|
+
title: "Chart title"
|
|
78
|
+
}
|
|
79
|
+
),
|
|
70
80
|
/* @__PURE__ */ jsx("span", { className: "cv-chart__spacer" }),
|
|
71
81
|
/* @__PURE__ */ jsx("button", { className: `cv-edit-btn ${editing ? "is-primary" : ""}`, onClick: () => setEditing((v) => !v), children: editing ? "Done" : "Edit data" })
|
|
72
82
|
] }),
|
|
@@ -128,9 +138,12 @@ function DataGrid({
|
|
|
128
138
|
}
|
|
129
139
|
function toEChartsOption(chart, rows, xKey, series, options) {
|
|
130
140
|
const AXIS = "#9aa4b2";
|
|
141
|
+
const titleBlock = options?.title ? { title: { text: options.title, left: "center", top: 2, textStyle: { color: AXIS, fontSize: 15, fontWeight: 600 } } } : {};
|
|
142
|
+
const hasTitle = !!options?.title;
|
|
131
143
|
if (chart === "pie") {
|
|
132
144
|
const valueKey = series[0]?.key ?? "value";
|
|
133
145
|
return {
|
|
146
|
+
...titleBlock,
|
|
134
147
|
tooltip: { trigger: "item" },
|
|
135
148
|
legend: { bottom: 0, textStyle: { color: AXIS } },
|
|
136
149
|
series: [
|
|
@@ -151,9 +164,10 @@ function toEChartsOption(chart, rows, xKey, series, options) {
|
|
|
151
164
|
}
|
|
152
165
|
const stacked = (chart === "bar" || chart === "area") && !!options?.stacked;
|
|
153
166
|
return {
|
|
167
|
+
...titleBlock,
|
|
154
168
|
tooltip: { trigger: "axis" },
|
|
155
169
|
legend: { bottom: 0, textStyle: { color: AXIS } },
|
|
156
|
-
grid: { left: 8, right: 16, top: 24, bottom: 40, containLabel: true },
|
|
170
|
+
grid: { left: 8, right: 16, top: hasTitle ? 44 : 24, bottom: 40, containLabel: true },
|
|
157
171
|
xAxis: {
|
|
158
172
|
type: "category",
|
|
159
173
|
data: rows.map((r) => String(r[xKey] ?? "")),
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { useArtifactPatch } from './chunk-TERWLUW3.js';
|
|
2
|
+
import './chunk-KKLWKR5G.js';
|
|
3
|
+
import { useState, useRef } from 'react';
|
|
4
|
+
import ReactMarkdown from 'react-markdown';
|
|
5
|
+
import remarkGfm from 'remark-gfm';
|
|
6
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
function wordStats(text) {
|
|
9
|
+
const words = text.trim() ? text.trim().split(/\s+/).length : 0;
|
|
10
|
+
return { words, minutes: Math.max(1, Math.round(words / 200)) };
|
|
11
|
+
}
|
|
12
|
+
function DocumentRenderer({ artifact }) {
|
|
13
|
+
const { content } = artifact.data;
|
|
14
|
+
const patch = useArtifactPatch(artifact.id);
|
|
15
|
+
const [draft, setDraft] = useState(null);
|
|
16
|
+
const taRef = useRef(null);
|
|
17
|
+
const editing = draft !== null;
|
|
18
|
+
const commit = () => {
|
|
19
|
+
if (draft !== null && draft !== content) patch({ content: draft });
|
|
20
|
+
setDraft(null);
|
|
21
|
+
};
|
|
22
|
+
const apply = (fn) => {
|
|
23
|
+
const ta = taRef.current;
|
|
24
|
+
if (!ta || draft === null) return;
|
|
25
|
+
const { text, a, b } = fn(draft, ta.selectionStart, ta.selectionEnd);
|
|
26
|
+
setDraft(text);
|
|
27
|
+
requestAnimationFrame(() => {
|
|
28
|
+
ta.focus();
|
|
29
|
+
ta.setSelectionRange(a, b);
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
const wrap = (mark) => apply((full, s, e) => ({ text: full.slice(0, s) + mark + full.slice(s, e) + mark + full.slice(e), a: s + mark.length, b: e + mark.length }));
|
|
33
|
+
const link = () => apply((full, s, e) => {
|
|
34
|
+
const label = full.slice(s, e) || "link";
|
|
35
|
+
const ins = `[${label}](https://)`;
|
|
36
|
+
const urlAt = s + label.length + 3;
|
|
37
|
+
return { text: full.slice(0, s) + ins + full.slice(e), a: urlAt, b: urlAt + 8 };
|
|
38
|
+
});
|
|
39
|
+
const prefixLines = (prefix) => apply((full, s, e) => {
|
|
40
|
+
const start = full.lastIndexOf("\n", s - 1) + 1;
|
|
41
|
+
const nl = full.indexOf("\n", e);
|
|
42
|
+
const end = nl === -1 ? full.length : nl;
|
|
43
|
+
const block = full.slice(start, end).split("\n").map((l) => prefix + l).join("\n");
|
|
44
|
+
return { text: full.slice(0, start) + block + full.slice(end), a: start, b: start + block.length };
|
|
45
|
+
});
|
|
46
|
+
const { words, minutes } = wordStats(editing ? draft ?? "" : content);
|
|
47
|
+
return /* @__PURE__ */ jsxs("div", { className: "cv-word", children: [
|
|
48
|
+
editing && /* @__PURE__ */ jsxs("div", { className: "cv-doc-bar cv-chrome", onMouseDown: (e) => e.preventDefault(), children: [
|
|
49
|
+
/* @__PURE__ */ jsx("button", { title: "Bold", onMouseDown: (e) => {
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
wrap("**");
|
|
52
|
+
}, children: /* @__PURE__ */ jsx("b", { children: "B" }) }),
|
|
53
|
+
/* @__PURE__ */ jsx("button", { title: "Italic", onMouseDown: (e) => {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
wrap("*");
|
|
56
|
+
}, children: /* @__PURE__ */ jsx("i", { children: "I" }) }),
|
|
57
|
+
/* @__PURE__ */ jsx("button", { title: "Inline code", onMouseDown: (e) => {
|
|
58
|
+
e.preventDefault();
|
|
59
|
+
wrap("`");
|
|
60
|
+
}, children: "<>" }),
|
|
61
|
+
/* @__PURE__ */ jsx("span", { className: "cv-doc-bar__sep" }),
|
|
62
|
+
/* @__PURE__ */ jsx("button", { title: "Heading 1", onMouseDown: (e) => {
|
|
63
|
+
e.preventDefault();
|
|
64
|
+
prefixLines("# ");
|
|
65
|
+
}, children: "H1" }),
|
|
66
|
+
/* @__PURE__ */ jsx("button", { title: "Heading 2", onMouseDown: (e) => {
|
|
67
|
+
e.preventDefault();
|
|
68
|
+
prefixLines("## ");
|
|
69
|
+
}, children: "H2" }),
|
|
70
|
+
/* @__PURE__ */ jsx("button", { title: "Bullet list", onMouseDown: (e) => {
|
|
71
|
+
e.preventDefault();
|
|
72
|
+
prefixLines("- ");
|
|
73
|
+
}, children: "\u2022" }),
|
|
74
|
+
/* @__PURE__ */ jsx("button", { title: "Numbered list", onMouseDown: (e) => {
|
|
75
|
+
e.preventDefault();
|
|
76
|
+
prefixLines("1. ");
|
|
77
|
+
}, children: "1." }),
|
|
78
|
+
/* @__PURE__ */ jsx("button", { title: "Quote", onMouseDown: (e) => {
|
|
79
|
+
e.preventDefault();
|
|
80
|
+
prefixLines("> ");
|
|
81
|
+
}, children: "\u275D" }),
|
|
82
|
+
/* @__PURE__ */ jsx("button", { title: "Link", onMouseDown: (e) => {
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
link();
|
|
85
|
+
}, children: "\u{1F517}" }),
|
|
86
|
+
/* @__PURE__ */ jsx("span", { className: "cv-doc-bar__spacer" }),
|
|
87
|
+
/* @__PURE__ */ jsxs("span", { className: "cv-doc-bar__count", children: [
|
|
88
|
+
words,
|
|
89
|
+
" words \xB7 ",
|
|
90
|
+
minutes,
|
|
91
|
+
" min read"
|
|
92
|
+
] }),
|
|
93
|
+
/* @__PURE__ */ jsx("button", { className: "cv-doc-bar__done", onMouseDown: (e) => {
|
|
94
|
+
e.preventDefault();
|
|
95
|
+
commit();
|
|
96
|
+
}, children: "Done" })
|
|
97
|
+
] }),
|
|
98
|
+
/* @__PURE__ */ jsx("div", { className: "cv-word__page", children: editing ? /* @__PURE__ */ jsx(
|
|
99
|
+
"textarea",
|
|
100
|
+
{
|
|
101
|
+
ref: taRef,
|
|
102
|
+
className: "cv-doc-editor",
|
|
103
|
+
value: draft,
|
|
104
|
+
autoFocus: true,
|
|
105
|
+
onBlur: commit,
|
|
106
|
+
onChange: (e) => setDraft(e.target.value)
|
|
107
|
+
}
|
|
108
|
+
) : /* @__PURE__ */ jsxs(
|
|
109
|
+
"article",
|
|
110
|
+
{
|
|
111
|
+
className: "cv-doc",
|
|
112
|
+
title: "Click to edit",
|
|
113
|
+
onClick: () => artifact.status !== "streaming" && setDraft(content),
|
|
114
|
+
children: [
|
|
115
|
+
/* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: content }),
|
|
116
|
+
artifact.status === "streaming" && /* @__PURE__ */ jsx("span", { className: "cv-caret", "aria-hidden": true })
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
) })
|
|
120
|
+
] });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export { DocumentRenderer };
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -2111,8 +2111,8 @@ function HtmlRenderer({ artifact: artifact2 }) {
|
|
|
2111
2111
|
}
|
|
2112
2112
|
|
|
2113
2113
|
// src/components/renderers/index.ts
|
|
2114
|
-
var ChartRenderer = lazy(() => import('./ChartRenderer-
|
|
2115
|
-
var DocumentRenderer = lazy(() => import('./DocumentRenderer-
|
|
2114
|
+
var ChartRenderer = lazy(() => import('./ChartRenderer-CWV2OX3S.js').then((m) => ({ default: m.ChartRenderer })));
|
|
2115
|
+
var DocumentRenderer = lazy(() => import('./DocumentRenderer-KJ6FTGKH.js').then((m) => ({ default: m.DocumentRenderer })));
|
|
2116
2116
|
var TableRenderer = lazy(() => import('./TableRenderer-ZF7MVA7I.js').then((m) => ({ default: m.TableRenderer })));
|
|
2117
2117
|
var SlidesRenderer = lazy(() => import('./SlidesRenderer-7ICJQHYT.js').then((m) => ({ default: m.SlidesRenderer })));
|
|
2118
2118
|
var builtinRenderers = {
|
package/dist/styles.css
CHANGED
|
@@ -295,6 +295,21 @@
|
|
|
295
295
|
|
|
296
296
|
/* --- Word viewer (document page) ---------------------------------------------- */
|
|
297
297
|
|
|
298
|
+
.cv-doc-bar {
|
|
299
|
+
position: sticky; top: 0; z-index: 5; display: flex; align-items: center; gap: 4px;
|
|
300
|
+
max-width: 816px; margin: 0 auto 12px; padding: 6px 8px;
|
|
301
|
+
border: 1px solid var(--cv-border); border-radius: 10px; background: var(--cv-surface);
|
|
302
|
+
flex-wrap: wrap;
|
|
303
|
+
}
|
|
304
|
+
.cv-doc-bar button {
|
|
305
|
+
border: 0; background: transparent; color: var(--cv-text); font: inherit; font-size: 13px;
|
|
306
|
+
min-width: 28px; height: 28px; padding: 0 8px; border-radius: 6px; cursor: pointer;
|
|
307
|
+
}
|
|
308
|
+
.cv-doc-bar button:hover { background: var(--cv-surface-2, rgba(120,120,140,0.12)); }
|
|
309
|
+
.cv-doc-bar__sep { width: 1px; height: 18px; background: var(--cv-border); margin: 0 4px; }
|
|
310
|
+
.cv-doc-bar__spacer { flex: 1; }
|
|
311
|
+
.cv-doc-bar__count { font-size: 12px; color: var(--cv-muted); white-space: nowrap; }
|
|
312
|
+
.cv-doc-bar__done { background: var(--cv-accent) !important; color: #fff; font-weight: 600; }
|
|
298
313
|
.cv-word { background: #edeef1; padding: 28px 16px; min-height: 100%; }
|
|
299
314
|
.cv-word .cv-edit-toolbar { max-width: 816px; margin: 0 auto 12px; }
|
|
300
315
|
.cv-word__page {
|
|
@@ -690,6 +705,12 @@
|
|
|
690
705
|
.cv-chart__types .cv-edit-btn { text-transform: capitalize; }
|
|
691
706
|
.cv-chart__stack { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--cv-muted); cursor: pointer; }
|
|
692
707
|
.cv-chart__spacer { flex: 1; }
|
|
708
|
+
.cv-chart__title-input {
|
|
709
|
+
font: inherit; font-size: 13px; padding: 5px 10px; border-radius: 7px;
|
|
710
|
+
border: 1px solid var(--cv-border); background: var(--cv-bg); color: var(--cv-text);
|
|
711
|
+
min-width: 120px; max-width: 220px;
|
|
712
|
+
}
|
|
713
|
+
.cv-chart__title-input:focus { outline: none; border-color: var(--cv-accent); }
|
|
693
714
|
|
|
694
715
|
/* --- chart editor ------------------------------------------------------------- */
|
|
695
716
|
.cv-chart__editor {
|
package/package.json
CHANGED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { useArtifactPatch } from './chunk-TERWLUW3.js';
|
|
2
|
-
import './chunk-KKLWKR5G.js';
|
|
3
|
-
import { useState } from 'react';
|
|
4
|
-
import ReactMarkdown from 'react-markdown';
|
|
5
|
-
import remarkGfm from 'remark-gfm';
|
|
6
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
7
|
-
|
|
8
|
-
function DocumentRenderer({ artifact }) {
|
|
9
|
-
const { content } = artifact.data;
|
|
10
|
-
const patch = useArtifactPatch(artifact.id);
|
|
11
|
-
const [draft, setDraft] = useState(null);
|
|
12
|
-
const editing = draft !== null;
|
|
13
|
-
const commit = () => {
|
|
14
|
-
if (draft !== null && draft !== content) patch({ content: draft });
|
|
15
|
-
setDraft(null);
|
|
16
|
-
};
|
|
17
|
-
return /* @__PURE__ */ jsx("div", { className: "cv-word", children: /* @__PURE__ */ jsx("div", { className: "cv-word__page", children: editing ? /* @__PURE__ */ jsx(
|
|
18
|
-
"textarea",
|
|
19
|
-
{
|
|
20
|
-
className: "cv-doc-editor",
|
|
21
|
-
value: draft,
|
|
22
|
-
autoFocus: true,
|
|
23
|
-
onBlur: commit,
|
|
24
|
-
onChange: (e) => setDraft(e.target.value)
|
|
25
|
-
}
|
|
26
|
-
) : /* @__PURE__ */ jsxs(
|
|
27
|
-
"article",
|
|
28
|
-
{
|
|
29
|
-
className: "cv-doc",
|
|
30
|
-
title: "Click to edit",
|
|
31
|
-
onClick: () => artifact.status !== "streaming" && setDraft(content),
|
|
32
|
-
children: [
|
|
33
|
-
/* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: content }),
|
|
34
|
-
artifact.status === "streaming" && /* @__PURE__ */ jsx("span", { className: "cv-caret", "aria-hidden": true })
|
|
35
|
-
]
|
|
36
|
-
}
|
|
37
|
-
) }) });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export { DocumentRenderer };
|