@tangle-network/ui 11.33.0 → 11.35.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/CHANGELOG.md +19 -0
- package/dist/editor/document-editor-pane.d.ts +7 -1
- package/dist/editor/document-editor-pane.js +27 -12
- package/dist/editor/markdown-document-editor.js +30 -12
- package/dist/editor/source-markdown-editor.js +256 -0
- package/dist/editor/source-markdown.js +495 -0
- package/dist/files/file-artifact-pane.d.ts +2 -0
- package/dist/files/file-artifact-pane.js +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/markdown/markdown-table.js +1 -1
- package/dist/primitives/segmented-control.d.ts +6 -3
- package/dist/primitives/segmented-control.js +105 -56
- package/dist/run/inline-thinking-item.d.ts +7 -1
- package/dist/run/inline-thinking-item.js +6 -5
- package/dist/utils/format.d.ts +6 -0
- package/dist/utils/format.js +9 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +2 -2
- package/package.json +2 -2
- package/src/editor/document-editor-pane.tsx +54 -16
- package/src/editor/markdown-document-editor.tsx +33 -18
- package/src/editor/source-markdown-editor.test.tsx +156 -0
- package/src/editor/source-markdown-editor.ts +296 -0
- package/src/editor/source-markdown.fixtures.ts +90 -0
- package/src/editor/source-markdown.test.ts +235 -0
- package/src/editor/source-markdown.ts +627 -0
- package/src/files/file-artifact-pane.test.tsx +34 -1
- package/src/files/file-artifact-pane.tsx +3 -0
- package/src/markdown/markdown-table.test.tsx +9 -0
- package/src/markdown/markdown-table.tsx +5 -1
- package/src/primitives/segmented-control.stories.tsx +89 -0
- package/src/primitives/segmented-control.test.tsx +20 -7
- package/src/primitives/segmented-control.tsx +90 -29
- package/src/run/inline-thinking-item.test.tsx +29 -0
- package/src/run/inline-thinking-item.tsx +11 -4
- package/src/utils/format.test.ts +16 -1
- package/src/utils/format.ts +17 -0
- package/src/utils/index.ts +1 -1
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
import { marked } from "marked";
|
|
2
|
+
import TurndownService from "turndown";
|
|
3
|
+
//#region src/editor/source-markdown.ts
|
|
4
|
+
/**
|
|
5
|
+
* Source-preserving Markdown for the rich editor.
|
|
6
|
+
*
|
|
7
|
+
* The rich editor holds a ProseMirror document, and a document can only be
|
|
8
|
+
* turned back into Markdown by re-serializing it. Re-serializing rewrites
|
|
9
|
+
* whatever the reader did not touch: list markers, emphasis delimiters,
|
|
10
|
+
* escapes, blank lines, and every construct the editor has no node for (a GFM
|
|
11
|
+
* table became one run-on paragraph). This module keeps the original bytes
|
|
12
|
+
* instead.
|
|
13
|
+
*
|
|
14
|
+
* The file is split into its top-level blocks with `marked`'s lexer, whose
|
|
15
|
+
* token `raw` fields concatenate back to the source. Each block the editor can
|
|
16
|
+
* represent is rendered to HTML carrying a block id; every other block (a
|
|
17
|
+
* table, raw HTML, an image, a task list, a link definition) becomes one atomic
|
|
18
|
+
* source node that holds its raw text. On save:
|
|
19
|
+
*
|
|
20
|
+
* - a block whose node still equals the node it was parsed into is written
|
|
21
|
+
* back as its original bytes, with its original separator;
|
|
22
|
+
* - a block the reader changed is re-serialized, and the change is merged
|
|
23
|
+
* into the original bytes (a three-way merge against the block's own
|
|
24
|
+
* re-serialization), so only the edited span differs; the merge is kept only
|
|
25
|
+
* when it parses back to exactly what the reader sees, otherwise the block's
|
|
26
|
+
* re-serialization is written;
|
|
27
|
+
* - a block the reader added is re-serialized.
|
|
28
|
+
*
|
|
29
|
+
* This module is pure: the editor-specific half (ProseMirror nodes, schema,
|
|
30
|
+
* HTML) arrives through `SourceNode` callbacks, so it runs without tiptap.
|
|
31
|
+
*/
|
|
32
|
+
/** HTML attribute that carries a block id from the source HTML into the editor document. */
|
|
33
|
+
const BLOCK_ID_ATTRIBUTE = "data-md-block";
|
|
34
|
+
/** HTML attribute that carries a read-only block's raw Markdown. */
|
|
35
|
+
const SOURCE_RAW_ATTRIBUTE = "data-md-raw";
|
|
36
|
+
/** HTML attribute that carries a read-only block's kind, which picks its caption. */
|
|
37
|
+
const SOURCE_KIND_ATTRIBUTE = "data-md-kind";
|
|
38
|
+
const INLINE_TYPES = /* @__PURE__ */ new Set([
|
|
39
|
+
"text",
|
|
40
|
+
"strong",
|
|
41
|
+
"em",
|
|
42
|
+
"codespan",
|
|
43
|
+
"del",
|
|
44
|
+
"link",
|
|
45
|
+
"br",
|
|
46
|
+
"escape"
|
|
47
|
+
]);
|
|
48
|
+
let documentCounter = 0;
|
|
49
|
+
function readOnlyKind(token) {
|
|
50
|
+
switch (token.type) {
|
|
51
|
+
case "paragraph":
|
|
52
|
+
case "heading": return inlineReadOnlyKind(token.tokens);
|
|
53
|
+
case "code":
|
|
54
|
+
case "hr": return null;
|
|
55
|
+
case "blockquote": return blocksReadOnlyKind(token.tokens);
|
|
56
|
+
case "list":
|
|
57
|
+
for (const item of token.items) {
|
|
58
|
+
if (item.task) return "checklist";
|
|
59
|
+
const kind = blocksReadOnlyKind(item.tokens);
|
|
60
|
+
if (kind) return kind;
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
case "table": return "table";
|
|
64
|
+
case "html": return "html";
|
|
65
|
+
case "def": return "definition";
|
|
66
|
+
default: return "markdown";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function blocksReadOnlyKind(tokens) {
|
|
70
|
+
for (const token of tokens) {
|
|
71
|
+
if (token.type === "space") continue;
|
|
72
|
+
if (token.type === "text") {
|
|
73
|
+
const kind = inlineReadOnlyKind(token.tokens ?? []);
|
|
74
|
+
if (kind) return kind;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const kind = readOnlyKind(token);
|
|
78
|
+
if (kind) return kind;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
function inlineReadOnlyKind(tokens) {
|
|
83
|
+
for (const token of tokens ?? []) {
|
|
84
|
+
if (token.type === "image") return "image";
|
|
85
|
+
if (token.type === "html") return "html";
|
|
86
|
+
if (!INLINE_TYPES.has(token.type)) return "markdown";
|
|
87
|
+
const children = token.tokens;
|
|
88
|
+
if (children) {
|
|
89
|
+
const kind = inlineReadOnlyKind(children);
|
|
90
|
+
if (kind) return kind;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
function escapeAttribute(value) {
|
|
96
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
97
|
+
}
|
|
98
|
+
function sourceNodeHtml(block) {
|
|
99
|
+
return `<div ${BLOCK_ID_ATTRIBUTE}="${block.id}" ${SOURCE_KIND_ATTRIBUTE}="${block.kind}" ${SOURCE_RAW_ATTRIBUTE}="${escapeAttribute(block.raw)}"></div>`;
|
|
100
|
+
}
|
|
101
|
+
/** Renders one editable block, tagging its root element with the block id. */
|
|
102
|
+
function editableBlockHtml(token, id) {
|
|
103
|
+
const html = String(marked.parser([token], {
|
|
104
|
+
async: false,
|
|
105
|
+
gfm: true
|
|
106
|
+
})).trim();
|
|
107
|
+
if (!/^<[a-z][a-z0-9]*/i.test(html)) return null;
|
|
108
|
+
return html.replace(/^<([a-z][a-z0-9]*)/i, `<$1 ${BLOCK_ID_ATTRIBUTE}="${id}"`);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Maps offsets in the line-feed-normalized text back to the original text, so
|
|
112
|
+
* a file with CRLF line endings keeps them.
|
|
113
|
+
*/
|
|
114
|
+
function originalOffsets(original, normalized) {
|
|
115
|
+
if (original === normalized) return (offset) => offset;
|
|
116
|
+
const map = new Int32Array(normalized.length + 1);
|
|
117
|
+
let o = 0;
|
|
118
|
+
for (let n = 0; n < normalized.length; n++) {
|
|
119
|
+
map[n] = o;
|
|
120
|
+
o += original[o] === "\r" && original[o + 1] === "\n" ? 2 : 1;
|
|
121
|
+
}
|
|
122
|
+
map[normalized.length] = original.length;
|
|
123
|
+
return (offset) => map[offset];
|
|
124
|
+
}
|
|
125
|
+
function buildHtml(blocks, tokens) {
|
|
126
|
+
return blocks.map((block) => {
|
|
127
|
+
if (!block.editable) return sourceNodeHtml(block);
|
|
128
|
+
const token = tokens.get(block.id);
|
|
129
|
+
return (token && editableBlockHtml(token, block.id)) ?? sourceNodeHtml(block);
|
|
130
|
+
}).join("\n");
|
|
131
|
+
}
|
|
132
|
+
function finish(prefix, trailer, blocks, tokens, links) {
|
|
133
|
+
return {
|
|
134
|
+
prefix,
|
|
135
|
+
trailer,
|
|
136
|
+
blocks,
|
|
137
|
+
byId: new Map(blocks.map((block) => [block.id, block])),
|
|
138
|
+
html: buildHtml(blocks, tokens),
|
|
139
|
+
links,
|
|
140
|
+
tokens,
|
|
141
|
+
lineEnding: [
|
|
142
|
+
prefix,
|
|
143
|
+
trailer,
|
|
144
|
+
...blocks.map((block) => block.raw + block.gap)
|
|
145
|
+
].some((text) => text.includes("\r\n")) ? "\r\n" : "\n"
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/** The whole file as one read-only block: the fallback when it cannot be split faithfully. */
|
|
149
|
+
function wholeFileSource(markdown, nonce) {
|
|
150
|
+
const blocks = markdown.trim() ? [{
|
|
151
|
+
id: `${nonce}:0`,
|
|
152
|
+
index: 0,
|
|
153
|
+
raw: markdown,
|
|
154
|
+
gap: "",
|
|
155
|
+
editable: false,
|
|
156
|
+
kind: "markdown"
|
|
157
|
+
}] : [];
|
|
158
|
+
return finish(blocks.length ? "" : markdown, "", blocks, /* @__PURE__ */ new Map(), {});
|
|
159
|
+
}
|
|
160
|
+
/** Splits a Markdown file into source blocks and the editor HTML that carries them. */
|
|
161
|
+
function parseSourceMarkdown(markdown) {
|
|
162
|
+
const nonce = `m${(documentCounter += 1).toString(36)}`;
|
|
163
|
+
const normalized = markdown.replace(/\r\n?/g, "\n");
|
|
164
|
+
if (/\r(?!\n)/.test(markdown)) return wholeFileSource(markdown, nonce);
|
|
165
|
+
const tokens = marked.lexer(normalized, { gfm: true });
|
|
166
|
+
if (tokens.map((token) => token.raw).join("") !== normalized) return wholeFileSource(markdown, nonce);
|
|
167
|
+
const toOriginal = originalOffsets(markdown, normalized);
|
|
168
|
+
const slice = (start, end) => markdown.slice(toOriginal(start), toOriginal(end));
|
|
169
|
+
const blocks = [];
|
|
170
|
+
const blockTokens = /* @__PURE__ */ new Map();
|
|
171
|
+
let prefix = "";
|
|
172
|
+
let offset = 0;
|
|
173
|
+
for (const token of tokens) {
|
|
174
|
+
const start = offset;
|
|
175
|
+
offset += token.raw.length;
|
|
176
|
+
if (token.type === "space") {
|
|
177
|
+
if (blocks.length === 0) prefix += slice(start, offset);
|
|
178
|
+
else blocks[blocks.length - 1].gap += slice(start, offset);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
const body = token.raw.replace(/\n+$/, "");
|
|
182
|
+
const id = `${nonce}:${blocks.length}`;
|
|
183
|
+
const kind = readOnlyKind(token);
|
|
184
|
+
blocks.push({
|
|
185
|
+
id,
|
|
186
|
+
index: blocks.length,
|
|
187
|
+
raw: slice(start, start + body.length),
|
|
188
|
+
gap: slice(start + body.length, offset),
|
|
189
|
+
editable: kind === null,
|
|
190
|
+
kind: kind ?? token.type
|
|
191
|
+
});
|
|
192
|
+
blockTokens.set(id, token);
|
|
193
|
+
}
|
|
194
|
+
const last = blocks[blocks.length - 1];
|
|
195
|
+
const trailer = last ? last.gap : "";
|
|
196
|
+
return finish(prefix, trailer, blocks, blockTokens, { ...tokens.links });
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Returns a copy of `source` with the given blocks shown read-only. The editor
|
|
200
|
+
* calls this when its document could not hold a block faithfully.
|
|
201
|
+
*/
|
|
202
|
+
function withReadOnlyBlocks(source, ids) {
|
|
203
|
+
const blocks = source.blocks.map((block) => block.editable && ids.has(block.id) ? {
|
|
204
|
+
...block,
|
|
205
|
+
editable: false,
|
|
206
|
+
kind: "markdown"
|
|
207
|
+
} : block);
|
|
208
|
+
return finish(source.prefix, source.trailer, blocks, source.tokens, source.links);
|
|
209
|
+
}
|
|
210
|
+
/** The whole document read-only: the last fallback when the editor cannot map it. */
|
|
211
|
+
function asReadOnlyDocument(markdown) {
|
|
212
|
+
return wholeFileSource(markdown, `m${(documentCounter += 1).toString(36)}`);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* HTML for one block of Markdown, with no block ids, or null when the text is
|
|
216
|
+
* not a single editable block. `links` resolves reference links defined
|
|
217
|
+
* elsewhere in the file. Used to check that a merged block reads back as the
|
|
218
|
+
* reader's edit.
|
|
219
|
+
*/
|
|
220
|
+
function blockHtml(markdown, links = {}) {
|
|
221
|
+
const lexer = new marked.Lexer({ gfm: true });
|
|
222
|
+
Object.assign(lexer.tokens.links, links);
|
|
223
|
+
const tokens = lexer.lex(markdown.replace(/\r\n?/g, "\n")).filter((t) => t.type !== "space");
|
|
224
|
+
if (tokens.length !== 1 || readOnlyKind(tokens[0]) !== null) return null;
|
|
225
|
+
return String(marked.parser(tokens, {
|
|
226
|
+
async: false,
|
|
227
|
+
gfm: true
|
|
228
|
+
}));
|
|
229
|
+
}
|
|
230
|
+
function styleOf(raw) {
|
|
231
|
+
const bullet = /^[ \t]*([*+-])[ \t]+\S/m.exec(raw)?.[1];
|
|
232
|
+
const ordered = /^[ \t]*\d{1,9}([.)])[ \t]+\S/m.exec(raw)?.[1];
|
|
233
|
+
return {
|
|
234
|
+
bullet: bullet ?? "-",
|
|
235
|
+
orderedDelimiter: ordered ?? ".",
|
|
236
|
+
em: /(^|[^\w*_\\])_[^_\s]/.test(raw) && !/(^|[^\w*\\])\*[^*\s]/.test(raw) ? "_" : "*",
|
|
237
|
+
strong: /(^|[^\w\\])__[^_\s]/.test(raw) && !/\*\*[^*\s]/.test(raw) ? "__" : "**",
|
|
238
|
+
fence: /^[ \t]*~~~/m.test(raw) && !/^[ \t]*```/m.test(raw) ? "~~~" : "```"
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
const turndownCache = /* @__PURE__ */ new Map();
|
|
242
|
+
function turndownFor(style) {
|
|
243
|
+
const key = `${style.bullet}${style.orderedDelimiter}${style.em}${style.strong}${style.fence}`;
|
|
244
|
+
const cached = turndownCache.get(key);
|
|
245
|
+
if (cached) return cached;
|
|
246
|
+
const service = new TurndownService({
|
|
247
|
+
bulletListMarker: style.bullet,
|
|
248
|
+
codeBlockStyle: "fenced",
|
|
249
|
+
emDelimiter: style.em,
|
|
250
|
+
strongDelimiter: style.strong,
|
|
251
|
+
fence: style.fence,
|
|
252
|
+
headingStyle: "atx",
|
|
253
|
+
hr: "---"
|
|
254
|
+
});
|
|
255
|
+
service.addRule("listParagraph", {
|
|
256
|
+
filter: (node) => node.nodeName === "P" && node.parentNode?.nodeName === "LI" && Array.from(node.parentNode.children).filter((child) => child.nodeName === "P").length === 1,
|
|
257
|
+
replacement: (content) => `\n${content}\n`
|
|
258
|
+
});
|
|
259
|
+
service.addRule("listItem", {
|
|
260
|
+
filter: "li",
|
|
261
|
+
replacement(content, node) {
|
|
262
|
+
const element = node;
|
|
263
|
+
const parent = element.parentNode;
|
|
264
|
+
let prefix = `${style.bullet} `;
|
|
265
|
+
if (parent?.nodeName === "OL") {
|
|
266
|
+
const start = parent.getAttribute("start");
|
|
267
|
+
const index = Array.prototype.indexOf.call(parent.children, element);
|
|
268
|
+
prefix = `${(start ? Number(start) : 1) + index}${style.orderedDelimiter} `;
|
|
269
|
+
}
|
|
270
|
+
const indented = content.replace(/^\n+|\n+$/g, "").replace(/\n(?=[^\n])/g, `\n${" ".repeat(prefix.length)}`);
|
|
271
|
+
return prefix + indented + (element.nextSibling ? "\n" : "");
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
service.addRule("strikethrough", {
|
|
275
|
+
filter: [
|
|
276
|
+
"del",
|
|
277
|
+
"s",
|
|
278
|
+
"strike"
|
|
279
|
+
],
|
|
280
|
+
replacement: (content) => `~~${content}~~`
|
|
281
|
+
});
|
|
282
|
+
turndownCache.set(key, service);
|
|
283
|
+
return service;
|
|
284
|
+
}
|
|
285
|
+
/** Markdown for one block of editor HTML, written in the style of `sourceRaw`. */
|
|
286
|
+
function blockMarkdown(html, sourceRaw = "") {
|
|
287
|
+
return turndownFor(styleOf(sourceRaw)).turndown(html).replace(/^\n+|\n+$/g, "");
|
|
288
|
+
}
|
|
289
|
+
/** Edit cost past which a diff is abandoned, bounding the trace to a few MB. */
|
|
290
|
+
const MAX_DIFF_COST = 1200;
|
|
291
|
+
function pushOp(ops, op, text) {
|
|
292
|
+
if (!text) return;
|
|
293
|
+
const last = ops[ops.length - 1];
|
|
294
|
+
if (last && last[0] === op) last[1] += text;
|
|
295
|
+
else ops.push([op, text]);
|
|
296
|
+
}
|
|
297
|
+
/** Myers' O((N+M)D) diff of two strings with a common prefix and suffix removed. */
|
|
298
|
+
function myers(a, b, maxCost) {
|
|
299
|
+
const n = a.length;
|
|
300
|
+
const m = b.length;
|
|
301
|
+
if (n === 0) return m ? [[1, b]] : [];
|
|
302
|
+
if (m === 0) return [[-1, a]];
|
|
303
|
+
const limit = Math.min(n + m, maxCost);
|
|
304
|
+
const offset = limit + 1;
|
|
305
|
+
const v = new Int32Array(2 * limit + 3);
|
|
306
|
+
v[offset + 1] = 0;
|
|
307
|
+
const trace = [];
|
|
308
|
+
let found = -1;
|
|
309
|
+
for (let d = 0; d <= limit && found < 0; d++) {
|
|
310
|
+
trace.push(v.slice(offset - d - 1, offset + d + 2));
|
|
311
|
+
for (let k = -d; k <= d; k += 2) {
|
|
312
|
+
let x = k === -d || k !== d && v[offset + k - 1] < v[offset + k + 1] ? v[offset + k + 1] : v[offset + k - 1] + 1;
|
|
313
|
+
let y = x - k;
|
|
314
|
+
while (x < n && y < m && a.charCodeAt(x) === b.charCodeAt(y)) {
|
|
315
|
+
x++;
|
|
316
|
+
y++;
|
|
317
|
+
}
|
|
318
|
+
v[offset + k] = x;
|
|
319
|
+
if (x >= n && y >= m) {
|
|
320
|
+
found = d;
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (found < 0) return null;
|
|
326
|
+
const runs = [];
|
|
327
|
+
let x = n;
|
|
328
|
+
let y = m;
|
|
329
|
+
for (let d = found; d > 0; d--) {
|
|
330
|
+
const snapshot = trace[d];
|
|
331
|
+
const at = (k) => snapshot[k + d + 1];
|
|
332
|
+
const k = x - y;
|
|
333
|
+
const prevK = k === -d || k !== d && at(k - 1) < at(k + 1) ? k + 1 : k - 1;
|
|
334
|
+
const prevX = at(prevK);
|
|
335
|
+
const prevY = prevX - prevK;
|
|
336
|
+
const moveEndX = prevK === k + 1 ? prevX : prevX + 1;
|
|
337
|
+
if (x > moveEndX) runs.push([
|
|
338
|
+
0,
|
|
339
|
+
moveEndX,
|
|
340
|
+
x
|
|
341
|
+
]);
|
|
342
|
+
if (prevK === k + 1) runs.push([
|
|
343
|
+
1,
|
|
344
|
+
prevY,
|
|
345
|
+
prevY + 1
|
|
346
|
+
]);
|
|
347
|
+
else runs.push([
|
|
348
|
+
-1,
|
|
349
|
+
prevX,
|
|
350
|
+
prevX + 1
|
|
351
|
+
]);
|
|
352
|
+
x = prevX;
|
|
353
|
+
y = prevY;
|
|
354
|
+
}
|
|
355
|
+
if (x > 0) runs.push([
|
|
356
|
+
0,
|
|
357
|
+
0,
|
|
358
|
+
x
|
|
359
|
+
]);
|
|
360
|
+
const ops = [];
|
|
361
|
+
for (let i = runs.length - 1; i >= 0; i--) {
|
|
362
|
+
const [op, from, to] = runs[i];
|
|
363
|
+
pushOp(ops, op, op === 1 ? b.slice(from, to) : a.slice(from, to));
|
|
364
|
+
}
|
|
365
|
+
return ops;
|
|
366
|
+
}
|
|
367
|
+
/** Character diff from `a` to `b`, or null when it would cost more than the bound. */
|
|
368
|
+
function diffText(a, b, maxCost = MAX_DIFF_COST) {
|
|
369
|
+
let start = 0;
|
|
370
|
+
const shorter = Math.min(a.length, b.length);
|
|
371
|
+
while (start < shorter && a.charCodeAt(start) === b.charCodeAt(start)) start++;
|
|
372
|
+
let endA = a.length;
|
|
373
|
+
let endB = b.length;
|
|
374
|
+
while (endA > start && endB > start && a.charCodeAt(endA - 1) === b.charCodeAt(endB - 1)) {
|
|
375
|
+
endA--;
|
|
376
|
+
endB--;
|
|
377
|
+
}
|
|
378
|
+
const middle = myers(a.slice(start, endA), b.slice(start, endB), maxCost);
|
|
379
|
+
if (!middle) return null;
|
|
380
|
+
const ops = [];
|
|
381
|
+
pushOp(ops, 0, a.slice(0, start));
|
|
382
|
+
for (const [op, text] of middle) pushOp(ops, op, text);
|
|
383
|
+
pushOp(ops, 0, a.slice(endA));
|
|
384
|
+
return ops;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* For each boundary between characters of `canonical`, the matching boundary
|
|
388
|
+
* in `raw`, or -1 where the two texts disagree around it. A boundary that two
|
|
389
|
+
* matched runs both claim keeps the earlier one, so text typed at the end of a
|
|
390
|
+
* word lands before any syntax that only the source spells out.
|
|
391
|
+
*/
|
|
392
|
+
function boundaryMap(ops, canonicalLength, rawLength) {
|
|
393
|
+
const map = new Int32Array(canonicalLength + 1).fill(-1);
|
|
394
|
+
let c = 0;
|
|
395
|
+
let r = 0;
|
|
396
|
+
for (const [op, text] of ops) if (op === 0) {
|
|
397
|
+
for (let j = 0; j <= text.length; j++) if (map[c + j] < 0) map[c + j] = r + j;
|
|
398
|
+
c += text.length;
|
|
399
|
+
r += text.length;
|
|
400
|
+
} else if (op === -1) c += text.length;
|
|
401
|
+
else r += text.length;
|
|
402
|
+
if (map[0] < 0) map[0] = 0;
|
|
403
|
+
if (map[canonicalLength] < 0) map[canonicalLength] = rawLength;
|
|
404
|
+
return map;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Merges edits of one block into its original bytes. `raw` is the block as
|
|
408
|
+
* written; `canonical` is the Markdown of the node first parsed from it. The
|
|
409
|
+
* alignment of the two is computed once and reused for every later edit.
|
|
410
|
+
*/
|
|
411
|
+
function createBlockMerger(raw, canonical) {
|
|
412
|
+
let map;
|
|
413
|
+
const alignment = () => {
|
|
414
|
+
if (map === void 0) {
|
|
415
|
+
const ops = diffText(canonical, raw);
|
|
416
|
+
map = ops ? boundaryMap(ops, canonical.length, raw.length) : null;
|
|
417
|
+
}
|
|
418
|
+
return map;
|
|
419
|
+
};
|
|
420
|
+
return (edited) => {
|
|
421
|
+
if (edited === canonical) return raw;
|
|
422
|
+
if (raw === canonical) return edited;
|
|
423
|
+
const edit = diffText(canonical, edited);
|
|
424
|
+
const boundaries = alignment();
|
|
425
|
+
if (!edit || !boundaries) return null;
|
|
426
|
+
let out = "";
|
|
427
|
+
let rawCursor = 0;
|
|
428
|
+
let c = 0;
|
|
429
|
+
let hunkStart = -1;
|
|
430
|
+
let inserted = "";
|
|
431
|
+
const flush = () => {
|
|
432
|
+
if (hunkStart < 0) return true;
|
|
433
|
+
const from = boundaries[hunkStart];
|
|
434
|
+
const to = boundaries[c];
|
|
435
|
+
if (from < 0 || to < 0 || to < from || from < rawCursor) return false;
|
|
436
|
+
out += raw.slice(rawCursor, from) + inserted;
|
|
437
|
+
rawCursor = to;
|
|
438
|
+
hunkStart = -1;
|
|
439
|
+
inserted = "";
|
|
440
|
+
return true;
|
|
441
|
+
};
|
|
442
|
+
for (const [op, text] of edit) {
|
|
443
|
+
if (op === 0) {
|
|
444
|
+
if (!flush()) return null;
|
|
445
|
+
c += text.length;
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
if (hunkStart < 0) hunkStart = c;
|
|
449
|
+
if (op === -1) c += text.length;
|
|
450
|
+
else inserted += text;
|
|
451
|
+
}
|
|
452
|
+
if (!flush()) return null;
|
|
453
|
+
return out + raw.slice(rawCursor);
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
function withLineEnding(text, lineEnding) {
|
|
457
|
+
return lineEnding === "\n" ? text : text.replace(/\r?\n/g, lineEnding);
|
|
458
|
+
}
|
|
459
|
+
function editedBlockText(node) {
|
|
460
|
+
const edited = node.markdown();
|
|
461
|
+
const merged = node.merge(edited);
|
|
462
|
+
if (merged !== null && (merged === edited || node.reparses(merged))) return merged;
|
|
463
|
+
return edited;
|
|
464
|
+
}
|
|
465
|
+
/** Writes the editor document back as Markdown, keeping every untouched byte of `source`. */
|
|
466
|
+
function serializeSourceMarkdown(source, nodes) {
|
|
467
|
+
const pieces = [];
|
|
468
|
+
for (const node of nodes) {
|
|
469
|
+
const block = node.block;
|
|
470
|
+
let text;
|
|
471
|
+
if (block && (node.unchanged || !block.editable)) text = block.raw;
|
|
472
|
+
else if (block) text = withLineEnding(editedBlockText(node), source.lineEnding);
|
|
473
|
+
else text = withLineEnding(node.markdown(), source.lineEnding);
|
|
474
|
+
if (!text.trim()) continue;
|
|
475
|
+
pieces.push({
|
|
476
|
+
text,
|
|
477
|
+
block,
|
|
478
|
+
keepsSeparator: Boolean(block) && (node.unchanged || node.sameType)
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
let out = source.prefix;
|
|
482
|
+
pieces.forEach((piece, i) => {
|
|
483
|
+
out += piece.text;
|
|
484
|
+
const next = pieces[i + 1];
|
|
485
|
+
if (!next) {
|
|
486
|
+
out += source.blocks.length ? source.trailer : source.lineEnding;
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
const adjacent = piece.block && next.block && next.block.index === piece.block.index + 1;
|
|
490
|
+
out += adjacent && piece.keepsSeparator && next.keepsSeparator ? piece.block.gap : source.lineEnding + source.lineEnding;
|
|
491
|
+
});
|
|
492
|
+
return out;
|
|
493
|
+
}
|
|
494
|
+
//#endregion
|
|
495
|
+
export { BLOCK_ID_ATTRIBUTE, SOURCE_KIND_ATTRIBUTE, SOURCE_RAW_ATTRIBUTE, asReadOnlyDocument, blockHtml, blockMarkdown, createBlockMerger, diffText, parseSourceMarkdown, serializeSourceMarkdown, withReadOnlyBlocks };
|
|
@@ -7,6 +7,8 @@ export interface FileArtifactPaneEditorOptions {
|
|
|
7
7
|
enabled?: boolean;
|
|
8
8
|
/** Persisted baseline when content is the current draft. */
|
|
9
9
|
savedContent?: string;
|
|
10
|
+
/** Whether the draft has unsaved edits, when the host tracks that itself. Overrides `savedContent`. */
|
|
11
|
+
dirty?: boolean;
|
|
10
12
|
mode?: DocumentEditorMode;
|
|
11
13
|
defaultMode?: DocumentEditorMode;
|
|
12
14
|
onModeChange?: (mode: DocumentEditorMode) => void;
|
|
@@ -69,6 +69,7 @@ function FileArtifactPane({ filename, content, blobUrl, mimeType, size, onClose,
|
|
|
69
69
|
hideTitleBlock,
|
|
70
70
|
markdown: content ?? "",
|
|
71
71
|
savedMarkdown: editor.savedContent,
|
|
72
|
+
dirty: editor.dirty,
|
|
72
73
|
urlTransform,
|
|
73
74
|
mode: editor.mode,
|
|
74
75
|
defaultMode: editor.defaultMode,
|
package/dist/index.d.ts
CHANGED
|
@@ -115,7 +115,7 @@ import "./markdown.js";
|
|
|
115
115
|
import { addMessage, addParts, clearChat, isStreamingAtom, messagesAtom, partMapAtom, updatePart } from "./stores/chat-store.js";
|
|
116
116
|
import "./types.js";
|
|
117
117
|
import { copyText } from "./utils/copy-text.js";
|
|
118
|
-
import { formatBytes, formatDuration, formatUptime, truncateText } from "./utils/format.js";
|
|
118
|
+
import { formatBytes, formatDuration, formatUptime, plainTextFromMarkdown, truncateText } from "./utils/format.js";
|
|
119
119
|
import { timeAgo } from "./utils/time-ago.js";
|
|
120
120
|
import { TOOL_CATEGORY_ICONS, getToolCategory, getToolDisplayMetadata, getToolErrorText } from "./utils/tool-display.js";
|
|
121
121
|
import { cn } from "./lib/utils.js";
|
|
@@ -131,4 +131,4 @@ import { QuestionPreview, QuestionPreviewProps } from "./tool-previews/question-
|
|
|
131
131
|
import { DiffPreview, DiffPreviewProps } from "./tool-previews/diff-preview.js";
|
|
132
132
|
import { RedactedDocSegment, RedactedDocument, RedactedDocumentData, RedactedDocumentProps, RevealResult } from "./redaction/redacted-document.js";
|
|
133
133
|
import "./redaction.js";
|
|
134
|
-
export { ActiveProjectActivity, ActiveSessionActivityOptions, ActiveSessionConnectionOptions, ActiveSessionConnectionState, ActiveSessionReconnectState, ActiveSessionRecord, ActiveSessionStatus, ActiveSessionTransportMode, ActiveSessionsState, AgentBranding, AgentStreamEvent, AgentTimeline, type AgentTimelineArtifactItem, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, type AlertProps, AlertTitle, type AlertTone, AppendUserMessageOptions, ApplySdkEventOptions, ApprovalCard, type ApprovalCardProps, type ApprovalDiffFile, ApprovalDiffSummary, type ApprovalPlanStep, ArtifactPane, type ArtifactPaneProps, AuthHeader, type AuthHeaderProps, AuthUser, AutomationStreamEvent, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, BeginAssistantMessageOptions, BotStreamEvent, Button, type ButtonProps, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, type CalendarDate, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CardTitleProps, type CategoryTone, ChatAuthor, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, Checkbox, Chip, type ChipProps, CodeBlock, type CodeBlockProps, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, type CommandPreviewProps, CompleteAssistantMessageOptions, ConnectionState, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, CustomToolRenderer, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, type DiffPreviewProps, DisplayVariant, DropZone, type DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, ExpandedToolDetail, type ExpandedToolDetailProps, type FeedSegment, FileArtifactPane, type FileArtifactPaneProps, FileCard, type FileCardProps, type FileDetails, type FileFormat, FileList, type FileListItem, type FileListProps, type FileNode, FilePreview, type FilePreviewKind, type FilePreviewProps, type FileTabData, FileTabs, type FileTabsProps, FileTree, type FileTreeProps, type FileTreeVisibilityOptions, type FileUploader, FilterField, type FilterFieldProps, FinalTextPart, GitHubLoginButton, type GitHubLoginButtonProps, GlobResultsPreview, type GlobResultsPreviewProps, GrepResultsPreview, type GrepResultsPreviewProps, GroupedMessage, Heading, type HeadingProps, type HeadingVariant, HelpText, type HelpTextProps, IconTile, type IconTileProps, InlineCode, type InlineCodeProps, InlineThinkingItem, type InlineThinkingItemProps, InlineToolItem, type InlineToolItemProps, Input, type InputProps, Label, LiveDuration, LoginLayout, type LoginLayoutProps, Logo, type LogoProps, Markdown, type MarkdownLinkChip, type MarkdownLinkChipResolver, type MarkdownProps, MessageAuthor, type MessageAuthorProps, MessageList, type MessageListProps, type MessageRole, MessageRun, MessageUser, Metric, type MetricProps, MetricStrip, type MetricStripProps, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, type OpenUIAction, type OpenUIActionsNode, OpenUIArtifactRenderer, type OpenUIArtifactRendererProps, type OpenUIBadgeNode, type OpenUICardNode, type OpenUICodeNode, type OpenUIComponentNode, type OpenUIGridNode, type OpenUIHeadingNode, type OpenUIKeyValueNode, type OpenUIMarkdownNode, type OpenUIPrimitive, type OpenUISchemaIssue, type OpenUISchemaValidation, type OpenUISeparatorNode, type OpenUIStackNode, type OpenUIStatNode, type OpenUITableNode, type OpenUITextNode, PageHeader, type PageHeaderProps, PageShell, type PageShellProps, Pagination, type PaginationProps, PdfViewer, type PdfViewerConfig, type PdfViewerProps, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, type QuestionPreviewProps, RadioGroup, RadioGroupItem, RealtimeSessionOptions, RealtimeSessionRegistry, RealtimeSessionRegistryProps, RealtimeSessionState, RealtimeSessionTarget, ReasoningPart, type RedactedDocSegment, RedactedDocument, type RedactedDocumentData, type RedactedDocumentProps, RegisterActiveSessionOptions, type RevealResult, RichFileTree, type RichFileTreeGitEntry, type RichFileTreeGitStatus, type RichFileTreeProps, type RichFileTreeThemeVars, Run, RunGroup, type RunGroupProps, type RunPhase, RunPhaseList, RunRowShell, type RunRowShellProps, type RunRowStatus, RunRowStatusDot, RunStats, SSEEvent, SdkSessionAttachment, SdkSessionEvent, SdkSessionSeed, SegmentedControl, type SegmentedControlOption, type SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, SessionMessage, SessionPart, SessionProjectKey, type SessionUser, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, type SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, type StatCardProps, StatusPill, type StatusPillProps, type StatusTone, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, type TableProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, TangleKnot, TaskList, type TaskListItem, type TaskListProps, type TaskStatus, TaskStreamEvent, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TerminalStreamEvent, TextPart, TextShimmer, type TextShimmerProps, Textarea, type TextareaProps, ThemeToggle, ThinkingIndicator, type ThinkingIndicatorProps, TimeSelect, type TimeSelectProps, type Toast, ToastContainer, ToastProvider, type Tone, type ToneClasses, type ToolCallData, ToolCallFeed, type ToolCallFeedProps, type ToolCallStatus, type ToolCallType, ToolCategory, ToolDisplayMetadata, ToolPart, ToolState, ToolStatus, ToolTime, Toolbar, type ToolbarProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UploadFile, UploadProgress, type UploadProgressProps, UseAuthOptions, UseAuthResult, UseRunGroupsOptions, UseSSEStreamOptions, UseSSEStreamResult, UseSdkSessionOptions, UseSdkSessionReturn, UseToolCallStreamReturn, UserMenu, type UserMenuProps, UserMessage, type UserMessageProps, WebSearchPreview, type WebSearchPreviewProps, WriteFilePreview, type WriteFilePreviewProps, activeSessionsAtom, addMessage, addParts, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatCalendarDate, formatDuration, formatUptime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
|
|
134
|
+
export { ActiveProjectActivity, ActiveSessionActivityOptions, ActiveSessionConnectionOptions, ActiveSessionConnectionState, ActiveSessionReconnectState, ActiveSessionRecord, ActiveSessionStatus, ActiveSessionTransportMode, ActiveSessionsState, AgentBranding, AgentStreamEvent, AgentTimeline, type AgentTimelineArtifactItem, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, type AlertProps, AlertTitle, type AlertTone, AppendUserMessageOptions, ApplySdkEventOptions, ApprovalCard, type ApprovalCardProps, type ApprovalDiffFile, ApprovalDiffSummary, type ApprovalPlanStep, ArtifactPane, type ArtifactPaneProps, AuthHeader, type AuthHeaderProps, AuthUser, AutomationStreamEvent, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, BeginAssistantMessageOptions, BotStreamEvent, Button, type ButtonProps, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, type CalendarDate, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CardTitleProps, type CategoryTone, ChatAuthor, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, Checkbox, Chip, type ChipProps, CodeBlock, type CodeBlockProps, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, type CommandPreviewProps, CompleteAssistantMessageOptions, ConnectionState, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, CustomToolRenderer, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, type DiffPreviewProps, DisplayVariant, DropZone, type DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, ExpandedToolDetail, type ExpandedToolDetailProps, type FeedSegment, FileArtifactPane, type FileArtifactPaneProps, FileCard, type FileCardProps, type FileDetails, type FileFormat, FileList, type FileListItem, type FileListProps, type FileNode, FilePreview, type FilePreviewKind, type FilePreviewProps, type FileTabData, FileTabs, type FileTabsProps, FileTree, type FileTreeProps, type FileTreeVisibilityOptions, type FileUploader, FilterField, type FilterFieldProps, FinalTextPart, GitHubLoginButton, type GitHubLoginButtonProps, GlobResultsPreview, type GlobResultsPreviewProps, GrepResultsPreview, type GrepResultsPreviewProps, GroupedMessage, Heading, type HeadingProps, type HeadingVariant, HelpText, type HelpTextProps, IconTile, type IconTileProps, InlineCode, type InlineCodeProps, InlineThinkingItem, type InlineThinkingItemProps, InlineToolItem, type InlineToolItemProps, Input, type InputProps, Label, LiveDuration, LoginLayout, type LoginLayoutProps, Logo, type LogoProps, Markdown, type MarkdownLinkChip, type MarkdownLinkChipResolver, type MarkdownProps, MessageAuthor, type MessageAuthorProps, MessageList, type MessageListProps, type MessageRole, MessageRun, MessageUser, Metric, type MetricProps, MetricStrip, type MetricStripProps, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, type OpenUIAction, type OpenUIActionsNode, OpenUIArtifactRenderer, type OpenUIArtifactRendererProps, type OpenUIBadgeNode, type OpenUICardNode, type OpenUICodeNode, type OpenUIComponentNode, type OpenUIGridNode, type OpenUIHeadingNode, type OpenUIKeyValueNode, type OpenUIMarkdownNode, type OpenUIPrimitive, type OpenUISchemaIssue, type OpenUISchemaValidation, type OpenUISeparatorNode, type OpenUIStackNode, type OpenUIStatNode, type OpenUITableNode, type OpenUITextNode, PageHeader, type PageHeaderProps, PageShell, type PageShellProps, Pagination, type PaginationProps, PdfViewer, type PdfViewerConfig, type PdfViewerProps, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, type QuestionPreviewProps, RadioGroup, RadioGroupItem, RealtimeSessionOptions, RealtimeSessionRegistry, RealtimeSessionRegistryProps, RealtimeSessionState, RealtimeSessionTarget, ReasoningPart, type RedactedDocSegment, RedactedDocument, type RedactedDocumentData, type RedactedDocumentProps, RegisterActiveSessionOptions, type RevealResult, RichFileTree, type RichFileTreeGitEntry, type RichFileTreeGitStatus, type RichFileTreeProps, type RichFileTreeThemeVars, Run, RunGroup, type RunGroupProps, type RunPhase, RunPhaseList, RunRowShell, type RunRowShellProps, type RunRowStatus, RunRowStatusDot, RunStats, SSEEvent, SdkSessionAttachment, SdkSessionEvent, SdkSessionSeed, SegmentedControl, type SegmentedControlOption, type SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, SessionMessage, SessionPart, SessionProjectKey, type SessionUser, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, type SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, type StatCardProps, StatusPill, type StatusPillProps, type StatusTone, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, type TableProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, TangleKnot, TaskList, type TaskListItem, type TaskListProps, type TaskStatus, TaskStreamEvent, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TerminalStreamEvent, TextPart, TextShimmer, type TextShimmerProps, Textarea, type TextareaProps, ThemeToggle, ThinkingIndicator, type ThinkingIndicatorProps, TimeSelect, type TimeSelectProps, type Toast, ToastContainer, ToastProvider, type Tone, type ToneClasses, type ToolCallData, ToolCallFeed, type ToolCallFeedProps, type ToolCallStatus, type ToolCallType, ToolCategory, ToolDisplayMetadata, ToolPart, ToolState, ToolStatus, ToolTime, Toolbar, type ToolbarProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UploadFile, UploadProgress, type UploadProgressProps, UseAuthOptions, UseAuthResult, UseRunGroupsOptions, UseSSEStreamOptions, UseSSEStreamResult, UseSdkSessionOptions, UseSdkSessionReturn, UseToolCallStreamReturn, UserMenu, type UserMenuProps, UserMessage, type UserMessageProps, WebSearchPreview, type WebSearchPreviewProps, WriteFilePreview, type WriteFilePreviewProps, activeSessionsAtom, addMessage, addParts, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatCalendarDate, formatDuration, formatUptime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, plainTextFromMarkdown, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
|
package/dist/index.js
CHANGED
|
@@ -59,7 +59,7 @@ import { TOOL_CATEGORY_ICONS, getToolCategory, getToolDisplayMetadata, getToolEr
|
|
|
59
59
|
import { useRunGroups } from "./hooks/use-run-groups.js";
|
|
60
60
|
import { useRunCollapseState } from "./hooks/use-run-collapse-state.js";
|
|
61
61
|
import { useAutoScroll } from "./hooks/use-auto-scroll.js";
|
|
62
|
-
import { formatBytes, formatDuration, formatUptime, truncateText } from "./utils/format.js";
|
|
62
|
+
import { formatBytes, formatDuration, formatUptime, plainTextFromMarkdown, truncateText } from "./utils/format.js";
|
|
63
63
|
import { CommandPreview } from "./tool-previews/command-preview.js";
|
|
64
64
|
import { detectFileFormat, fileExtension, getCodeLanguage, getFormatLabel, getSyntaxLanguage, resolveFilePreviewKind } from "./files/file-format.js";
|
|
65
65
|
import { WriteFilePreview } from "./tool-previews/write-file-preview.js";
|
|
@@ -115,4 +115,4 @@ import { addMessage, addParts, clearChat, isStreamingAtom, messagesAtom, partMap
|
|
|
115
115
|
import { copyText } from "./utils/copy-text.js";
|
|
116
116
|
import { timeAgo } from "./utils/time-ago.js";
|
|
117
117
|
import { RedactedDocument } from "./redaction/redacted-document.js";
|
|
118
|
-
export { AgentTimeline, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, ApprovalCard, ApprovalDiffSummary, ArtifactPane, AuthHeader, Avatar, AvatarFallback, AvatarImage, Badge, Button, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ChatContainer, ChatMessage, Checkbox, Chip, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, DropZone, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, ExpandedToolDetail, FileArtifactPane, FileCard, FileList, FilePreview, FileTabs, FileTree, FilterField, GitHubLoginButton, GlobResultsPreview, GrepResultsPreview, Heading, HelpText, IconTile, InlineCode, InlineThinkingItem, InlineToolItem, Input, Label, LiveDuration, LoginLayout, Logo, Markdown, MessageAuthor, MessageList, Metric, MetricStrip, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, OpenUIArtifactRenderer, PageHeader, PageShell, Pagination, PdfViewer, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, RadioGroup, RadioGroupItem, RealtimeSessionRegistry, RedactedDocument, RichFileTree, RunGroup, RunPhaseList, RunRowShell, RunRowStatusDot, SegmentedControl, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, StatusPill, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TangleKnot, TaskList, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, Textarea, ThemeToggle, ThinkingIndicator, TimeSelect, ToastContainer, ToastProvider, ToolCallFeed, Toolbar, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadProgress, UserMenu, UserMessage, WebSearchPreview, WriteFilePreview, activeSessionsAtom, addMessage, addParts, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatCalendarDate, formatDuration, formatUptime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
|
|
118
|
+
export { AgentTimeline, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, ApprovalCard, ApprovalDiffSummary, ArtifactPane, AuthHeader, Avatar, AvatarFallback, AvatarImage, Badge, Button, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ChatContainer, ChatMessage, Checkbox, Chip, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, DropZone, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, ExpandedToolDetail, FileArtifactPane, FileCard, FileList, FilePreview, FileTabs, FileTree, FilterField, GitHubLoginButton, GlobResultsPreview, GrepResultsPreview, Heading, HelpText, IconTile, InlineCode, InlineThinkingItem, InlineToolItem, Input, Label, LiveDuration, LoginLayout, Logo, Markdown, MessageAuthor, MessageList, Metric, MetricStrip, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, OpenUIArtifactRenderer, PageHeader, PageShell, Pagination, PdfViewer, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, RadioGroup, RadioGroupItem, RealtimeSessionRegistry, RedactedDocument, RichFileTree, RunGroup, RunPhaseList, RunRowShell, RunRowStatusDot, SegmentedControl, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, StatusPill, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TangleKnot, TaskList, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, Textarea, ThemeToggle, ThinkingIndicator, TimeSelect, ToastContainer, ToastProvider, ToolCallFeed, Toolbar, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadProgress, UserMenu, UserMessage, WebSearchPreview, WriteFilePreview, activeSessionsAtom, addMessage, addParts, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatCalendarDate, formatDuration, formatUptime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, plainTextFromMarkdown, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
|
|
@@ -113,7 +113,7 @@ function MarkdownTable({ node, className, children, ...props }) {
|
|
|
113
113
|
};
|
|
114
114
|
}, [node]);
|
|
115
115
|
return /* @__PURE__ */ jsxs("div", {
|
|
116
|
-
className: "not-prose my-4 overflow-hidden rounded-lg border border-border bg-card",
|
|
116
|
+
className: "not-prose relative my-4 overflow-hidden rounded-lg border border-border bg-card",
|
|
117
117
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
118
118
|
className: "flex items-center justify-between gap-2 border-b border-border px-3 py-1",
|
|
119
119
|
children: [/* @__PURE__ */ jsx("span", {
|
|
@@ -24,9 +24,12 @@ import * as React from "react";
|
|
|
24
24
|
* - Every label keeps one weight. Selection is colour plus surface or
|
|
25
25
|
* underline, so changing the value never reflows the row.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* past it
|
|
27
|
+
* When the options outgrow the row they scroll sideways (the tabs variant
|
|
28
|
+
* always can; the row variant can when a host gives it `flex-nowrap
|
|
29
|
+
* overflow-x-auto`). A chevron button pinned to each edge with options past it
|
|
30
|
+
* shows that the strip scrolls and pages it on click or tap; touch and
|
|
31
|
+
* trackpad scroll it natively, and arrow keys move the selection, which is
|
|
32
|
+
* kept fully in view clear of the chevrons.
|
|
30
33
|
*/
|
|
31
34
|
export interface SegmentedControlOption<T extends string = string> {
|
|
32
35
|
value: T;
|