@tangle-network/ui 11.11.8 → 11.13.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 +24 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/auth/auth.d.ts +53 -0
- package/dist/{auth-DOETfnd9.js → auth/auth.js} +7 -37
- package/dist/auth/login-layout.d.ts +20 -0
- package/dist/auth/login-layout.js +36 -0
- package/dist/auth.d.ts +2 -1
- package/dist/auth.js +2 -1
- package/dist/chat/agent-timeline.d.ts +83 -0
- package/dist/chat/agent-timeline.js +236 -0
- package/dist/chat/chat-container.d.ts +51 -0
- package/dist/chat/chat-container.js +309 -0
- package/dist/chat/chat-message.d.ts +22 -0
- package/dist/chat/chat-message.js +38 -0
- package/dist/chat/message-list.d.ts +32 -0
- package/dist/chat/message-list.js +37 -0
- package/dist/chat/thinking-indicator.d.ts +6 -0
- package/dist/chat/thinking-indicator.js +38 -0
- package/dist/chat/user-message.d.ts +21 -0
- package/dist/chat/user-message.js +42 -0
- package/dist/chat.d.ts +6 -1
- package/dist/chat.js +6 -1
- package/dist/editor/document-editor-pane.d.ts +37 -0
- package/dist/editor/document-editor-pane.js +199 -0
- package/dist/editor/editor-lazy.js +37 -0
- package/dist/editor/editor-loading.js +21 -0
- package/dist/editor/editor-peers.d.ts +6 -0
- package/dist/editor/editor-peers.js +155 -0
- package/dist/{document-editor-pane-DHM8DDhb.d.ts → editor/editor-provider.d.ts} +10 -47
- package/dist/editor/editor-provider.js +253 -0
- package/dist/editor/editor-toolbar.d.ts +11 -0
- package/dist/editor/editor-toolbar.js +106 -0
- package/dist/editor/markdown-conversion.js +23 -0
- package/dist/editor/markdown-document-editor.js +103 -0
- package/dist/editor/tiptap-editor.d.ts +45 -0
- package/dist/editor/tiptap-editor.js +271 -0
- package/dist/editor/use-editor.d.ts +67 -0
- package/dist/editor/use-editor.js +158 -0
- package/dist/editor.d.ts +6 -119
- package/dist/editor.js +5 -1
- package/dist/files/file-artifact-pane.d.ts +47 -0
- package/dist/files/file-artifact-pane.js +114 -0
- package/dist/files/file-format.d.ts +51 -0
- package/dist/{file-format-BgXbr-Ib.js → files/file-format.js} +1 -1
- package/dist/files/file-preview.d.ts +27 -0
- package/dist/files/file-preview.js +359 -0
- package/dist/files/file-tabs.d.ts +19 -0
- package/dist/files/file-tabs.js +48 -0
- package/dist/files/file-tree.d.ts +31 -0
- package/dist/files/file-tree.js +135 -0
- package/dist/files/rich-file-tree.d.ts +62 -0
- package/dist/files/rich-file-tree.js +122 -0
- package/dist/files.d.ts +6 -1
- package/dist/files.js +6 -2
- package/dist/hooks/use-auth.d.ts +40 -0
- package/dist/hooks/use-auth.js +91 -0
- package/dist/hooks/use-auto-scroll.d.ts +11 -0
- package/dist/hooks/use-auto-scroll.js +48 -0
- package/dist/hooks/use-dropdown-menu.d.ts +12 -0
- package/dist/hooks/use-dropdown-menu.js +31 -0
- package/dist/hooks/use-live-time.d.ts +7 -0
- package/dist/hooks/use-live-time.js +22 -0
- package/dist/hooks/use-realtime-session.d.ts +32 -0
- package/dist/hooks/use-realtime-session.js +235 -0
- package/dist/hooks/use-run-collapse-state.d.ts +13 -0
- package/dist/hooks/use-run-collapse-state.js +24 -0
- package/dist/hooks/use-run-groups.d.ts +11 -0
- package/dist/hooks/use-run-groups.js +85 -0
- package/dist/hooks/use-sdk-session.d.ts +59 -0
- package/dist/hooks/use-sdk-session.js +322 -0
- package/dist/hooks/use-sse-stream.d.ts +124 -0
- package/dist/hooks/use-sse-stream.js +229 -0
- package/dist/hooks/use-tool-call-stream.d.ts +23 -0
- package/dist/hooks/use-tool-call-stream.js +75 -0
- package/dist/hooks.d.ts +11 -49
- package/dist/hooks.js +10 -110
- package/dist/index.d.ts +99 -25
- package/dist/index.js +86 -36
- package/dist/lib/focus.d.ts +55 -0
- package/dist/{focus-BcE_SHqz.js → lib/focus.js} +1 -1
- package/dist/lib/utils.d.ts +4 -0
- package/dist/{utils-C_uf36nf.js → lib/utils.js} +1 -1
- package/dist/{code-block-B9miUPht.d.ts → markdown/code-block.d.ts} +5 -6
- package/dist/{code-block-B36KVUSN.js → markdown/code-block.js} +22 -47
- package/dist/{markdown-C0atSabr.d.ts → markdown/markdown.d.ts} +4 -5
- package/dist/{markdown-Db08KAYF.js → markdown/markdown.js} +3 -3
- package/dist/markdown.d.ts +2 -2
- package/dist/markdown.js +2 -2
- package/dist/{openui-artifact-renderer-fkBQaoLO.d.ts → openui/openui-artifact-renderer.d.ts} +20 -21
- package/dist/{openui-artifact-renderer-DG_i2lOR.js → openui/openui-artifact-renderer.js} +9 -7
- package/dist/{schema-BpW9rSSG.js → openui/schema-compiled.js} +2 -354
- package/dist/{schema-DAstk-J4.d.ts → openui/schema-data.d.ts} +3 -24
- package/dist/openui/schema-data.js +206 -0
- package/dist/openui-schema.d.ts +22 -3
- package/dist/openui-schema.js +138 -1
- package/dist/openui.d.ts +3 -2
- package/dist/openui.js +3 -2
- package/dist/{artifact-pane-BL_DFWNl.d.ts → primitives/artifact-pane.d.ts} +3 -4
- package/dist/{artifact-pane-DMXT9a8U.js → primitives/artifact-pane.js} +2 -2
- package/dist/primitives/avatar.d.ts +8 -0
- package/dist/primitives/avatar.js +25 -0
- package/dist/primitives/badge.d.ts +22 -0
- package/dist/primitives/badge.js +47 -0
- package/dist/{button-yoIv77e2.d.ts → primitives/button.d.ts} +2 -2
- package/dist/primitives/button.js +113 -0
- package/dist/primitives/card.d.ts +18 -0
- package/dist/primitives/card.js +52 -0
- package/dist/primitives/code-block.d.ts +6 -0
- package/dist/primitives/code-block.js +13 -0
- package/dist/primitives/dialog.d.ts +23 -0
- package/dist/primitives/dialog.js +59 -0
- package/dist/primitives/drop-zone.d.ts +23 -0
- package/dist/primitives/drop-zone.js +104 -0
- package/dist/primitives/dropdown-menu.d.ts +29 -0
- package/dist/{dropdown-menu-BpcLa5vF.js → primitives/dropdown-menu.js} +2 -23
- package/dist/primitives/empty-state.d.ts +11 -0
- package/dist/primitives/empty-state.js +32 -0
- package/dist/primitives/heading.d.ts +23 -0
- package/dist/primitives/heading.js +38 -0
- package/dist/primitives/input.d.ts +23 -0
- package/dist/primitives/input.js +110 -0
- package/dist/primitives/label.d.ts +6 -0
- package/dist/primitives/label.js +16 -0
- package/dist/primitives/metric-strip.d.ts +48 -0
- package/dist/primitives/metric-strip.js +52 -0
- package/dist/primitives/page-header.d.ts +25 -0
- package/dist/primitives/page-header.js +47 -0
- package/dist/primitives/page-shell.d.ts +14 -0
- package/dist/primitives/page-shell.js +17 -0
- package/dist/primitives/progress.d.ts +9 -0
- package/dist/primitives/progress.js +29 -0
- package/dist/primitives/segmented-control.d.ts +40 -0
- package/dist/primitives/segmented-control.js +57 -0
- package/dist/primitives/select.d.ts +15 -0
- package/dist/primitives/select.js +74 -0
- package/dist/primitives/sidebar-drop-zone.d.ts +21 -0
- package/dist/primitives/sidebar-drop-zone.js +88 -0
- package/dist/primitives/skeleton.d.ts +10 -0
- package/dist/primitives/skeleton.js +50 -0
- package/dist/primitives/stat-card.d.ts +16 -0
- package/dist/primitives/stat-card.js +60 -0
- package/dist/primitives/status-pill.d.ts +44 -0
- package/dist/primitives/status-pill.js +119 -0
- package/dist/primitives/switch.d.ts +6 -0
- package/dist/primitives/switch.js +16 -0
- package/dist/primitives/table.d.ts +22 -0
- package/dist/primitives/table.js +63 -0
- package/dist/primitives/tabs.d.ts +13 -0
- package/dist/{tabs-BVHR6NkO.js → primitives/tabs.js} +3 -3
- package/dist/primitives/terminal-display.d.ts +25 -0
- package/dist/primitives/terminal-display.js +109 -0
- package/dist/primitives/text-shimmer.d.ts +16 -0
- package/dist/{text-shimmer-BUUo6I-g.js → primitives/text-shimmer.js} +2 -2
- package/dist/primitives/theme-toggle.d.ts +11 -0
- package/dist/primitives/theme-toggle.js +154 -0
- package/dist/primitives/toast.d.ts +29 -0
- package/dist/primitives/toast.js +142 -0
- package/dist/primitives/toolbar.d.ts +55 -0
- package/dist/primitives/toolbar.js +37 -0
- package/dist/primitives/upload-progress.d.ts +23 -0
- package/dist/primitives/upload-progress.js +72 -0
- package/dist/primitives.d.ts +35 -5
- package/dist/primitives.js +35 -9
- package/dist/{index-COgqsFAQ.d.ts → redaction/redacted-document.d.ts} +6 -7
- package/dist/{redaction-CGGB2ENG.js → redaction/redacted-document.js} +2 -2
- package/dist/redaction.d.ts +1 -1
- package/dist/redaction.js +1 -1
- package/dist/run/expandable-content.js +41 -0
- package/dist/run/expanded-tool-detail.d.ts +12 -0
- package/dist/run/expanded-tool-detail.js +163 -0
- package/dist/run/inline-thinking-item.d.ts +11 -0
- package/dist/run/inline-thinking-item.js +60 -0
- package/dist/run/inline-tool-item.d.ts +25 -0
- package/dist/run/inline-tool-item.js +63 -0
- package/dist/run/run-group.d.ts +26 -0
- package/dist/{run-group-BWGeesgs.js → run/run-group.js} +9 -60
- package/dist/run/run-item-primitives.d.ts +5 -0
- package/dist/{run-ZsIKPA6J.js → run/run-item-primitives.js} +2 -2
- package/dist/run/run-row-shell.d.ts +53 -0
- package/dist/run/run-row-shell.js +114 -0
- package/dist/{tool-call-feed-BeB1_4pX.d.ts → run/tool-call-feed.d.ts} +7 -12
- package/dist/{tool-call-feed-BpmMLpPX.js → run/tool-call-feed.js} +4 -4
- package/dist/run/tool-call-step.d.ts +5 -0
- package/dist/run/tool-call-step.js +82 -0
- package/dist/run.d.ts +8 -2
- package/dist/run.js +7 -4
- package/dist/sdk-hooks.d.ts +8 -1
- package/dist/sdk-hooks.js +8 -2
- package/dist/stores/active-sessions-store.d.ts +83 -0
- package/dist/{active-sessions-store-Gt1R0rFG.js → stores/active-sessions-store.js} +1 -1
- package/dist/stores/chat-store.d.ts +14 -0
- package/dist/stores/chat-store.js +33 -0
- package/dist/stores.d.ts +3 -16
- package/dist/stores.js +2 -33
- package/dist/tool-previews/command-preview.d.ts +11 -0
- package/dist/tool-previews/command-preview.js +91 -0
- package/dist/tool-previews/diff-preview.d.ts +7 -0
- package/dist/tool-previews/diff-preview.js +76 -0
- package/dist/tool-previews/glob-results-preview.d.ts +7 -0
- package/dist/tool-previews/glob-results-preview.js +53 -0
- package/dist/tool-previews/grep-results-preview.d.ts +7 -0
- package/dist/tool-previews/grep-results-preview.js +99 -0
- package/dist/tool-previews/preview-primitives.js +58 -0
- package/dist/tool-previews/question-preview.d.ts +7 -0
- package/dist/tool-previews/question-preview.js +63 -0
- package/dist/tool-previews/web-search-preview.d.ts +7 -0
- package/dist/tool-previews/web-search-preview.js +78 -0
- package/dist/tool-previews/write-file-preview.d.ts +11 -0
- package/dist/tool-previews/write-file-preview.js +52 -0
- package/dist/tool-previews.d.ts +7 -1
- package/dist/tool-previews.js +7 -1
- package/dist/{branding-26d5ARIr.d.ts → types/branding.d.ts} +2 -3
- package/dist/{message-vhUI0c5G.d.ts → types/message.d.ts} +2 -3
- package/dist/{parts-5mhy9yJ3.d.ts → types/parts.d.ts} +8 -9
- package/dist/{run-OyWmIDqu.d.ts → types/run.d.ts} +9 -10
- package/dist/{tool-display-DgmL5rIU.d.ts → types/tool-display.d.ts} +5 -6
- package/dist/types.d.ts +5 -5
- package/dist/utils/copy-text.d.ts +7 -0
- package/dist/{utils-Bl_CZ0Qp.js → utils/copy-text.js} +1 -11
- package/dist/utils/format.d.ts +22 -0
- package/dist/{format-DfcLWqMa.js → utils/format.js} +1 -1
- package/dist/utils/time-ago.d.ts +3 -0
- package/dist/utils/time-ago.js +11 -0
- package/dist/utils/tool-display.d.ts +16 -0
- package/dist/{tool-display-BAuAVa43.js → utils/tool-display.js} +1 -1
- package/dist/utils.d.ts +6 -1
- package/dist/utils.js +6 -5
- package/package.json +2 -2
- package/src/editor/document-editor-pane.tsx +4 -1
- package/src/files/file-artifact-pane.test.tsx +23 -0
- package/src/files/file-artifact-pane.tsx +3 -0
- package/src/files/rich-file-tree.stories.tsx +1 -1
- package/src/files/rich-file-tree.tsx +12 -9
- package/src/markdown/code-block.test.tsx +46 -2
- package/src/markdown/code-block.tsx +23 -60
- package/src/markdown/markdown.test.tsx +3 -2
- package/src/primitives/button.stories.tsx +37 -1
- package/src/primitives/button.test.tsx +230 -0
- package/src/primitives/button.tsx +62 -14
- package/src/primitives/card-anatomy.stories.tsx +51 -0
- package/src/primitives/card.test.tsx +71 -0
- package/src/primitives/card.tsx +25 -13
- package/src/primitives/heading.stories.tsx +35 -0
- package/src/primitives/heading.test.tsx +56 -0
- package/src/primitives/heading.tsx +76 -0
- package/src/primitives/index.ts +8 -0
- package/src/primitives/input.stories.tsx +28 -0
- package/src/primitives/input.test.tsx +161 -0
- package/src/primitives/input.tsx +34 -28
- package/src/primitives/page-header.stories.tsx +51 -0
- package/src/primitives/page-header.test.tsx +48 -0
- package/src/primitives/page-header.tsx +35 -35
- package/src/primitives/page-shell.stories.tsx +89 -0
- package/src/primitives/page-shell.test.tsx +24 -0
- package/src/primitives/page-shell.tsx +26 -0
- package/src/primitives/table-wrapper.stories.tsx +54 -0
- package/src/primitives/table.test.tsx +72 -0
- package/src/primitives/table.tsx +33 -12
- package/src/primitives/theme-toggle.test.tsx +167 -0
- package/src/primitives/theme-toggle.tsx +111 -39
- package/dist/active-sessions-store-nl70ZnMC.d.ts +0 -84
- package/dist/button-C87nEe2R.js +0 -78
- package/dist/chat-DDvF2oGQ.js +0 -672
- package/dist/diff-preview-BcK3nRXb.js +0 -533
- package/dist/document-editor-pane-CsFbH2qo.js +0 -1279
- package/dist/files--Unn___t.js +0 -752
- package/dist/index-2UntyjBb.d.ts +0 -52
- package/dist/index-BgUHilZm.d.ts +0 -108
- package/dist/index-CPDET_s1.d.ts +0 -549
- package/dist/index-Cg6gYAqh.d.ts +0 -73
- package/dist/index-Cs7j8V7l.d.ts +0 -203
- package/dist/index-CyGSLGVF.d.ts +0 -234
- package/dist/index-DjKxO357.d.ts +0 -128
- package/dist/primitives-Bx59fT-U.js +0 -1239
- package/dist/table-Bss73DhB.js +0 -146
- package/dist/tool-call-step-DNebqhmX.js +0 -434
- package/dist/use-auto-scroll-C5Pjeqon.js +0 -153
- package/dist/use-sse-stream-DjqRuDft.js +0 -884
- package/dist/use-sse-stream-Dm6R5YWz.d.ts +0 -282
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ToolPart } from "../types/parts.js";
|
|
2
|
+
//#region src/tool-previews/question-preview.d.ts
|
|
3
|
+
export interface QuestionPreviewProps {
|
|
4
|
+
part: ToolPart;
|
|
5
|
+
}
|
|
6
|
+
export declare const QuestionPreview: import("react").MemoExoticComponent<({ part }: QuestionPreviewProps) => import("react").JSX.Element>;
|
|
7
|
+
//#endregion
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { PreviewCard, PreviewEmpty, PreviewError, PreviewLoading } from "./preview-primitives.js";
|
|
2
|
+
import { memo, useMemo } from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { MessageSquareQuote } from "lucide-react";
|
|
5
|
+
//#region src/tool-previews/question-preview.tsx
|
|
6
|
+
function toQuestionList(input) {
|
|
7
|
+
if (!input) return [];
|
|
8
|
+
if (typeof input === "string") return [input];
|
|
9
|
+
if (Array.isArray(input)) return input.map((item) => String(item)).filter(Boolean);
|
|
10
|
+
if (typeof input === "object") {
|
|
11
|
+
const record = input;
|
|
12
|
+
const value = record.questions ?? record.question ?? record.prompt;
|
|
13
|
+
if (Array.isArray(value)) return value.map((item) => String(item)).filter(Boolean);
|
|
14
|
+
if (typeof value === "string") return [value];
|
|
15
|
+
}
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
function toAnswerList(output) {
|
|
19
|
+
if (!output) return [];
|
|
20
|
+
if (typeof output === "string") return [output];
|
|
21
|
+
if (Array.isArray(output)) return output.map((item) => String(item)).filter(Boolean);
|
|
22
|
+
if (typeof output === "object") {
|
|
23
|
+
const record = output;
|
|
24
|
+
const value = record.answers ?? record.answer ?? record.response;
|
|
25
|
+
if (Array.isArray(value)) return value.map((item) => String(item)).filter(Boolean);
|
|
26
|
+
if (typeof value === "string") return [value];
|
|
27
|
+
}
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
const QuestionPreview = memo(({ part }) => {
|
|
31
|
+
const questions = useMemo(() => toQuestionList(part.state.input), [part.state.input]);
|
|
32
|
+
const answers = useMemo(() => toAnswerList(part.state.output), [part.state.output]);
|
|
33
|
+
return /* @__PURE__ */ jsxs(PreviewCard, {
|
|
34
|
+
icon: /* @__PURE__ */ jsx(MessageSquareQuote, { className: "h-4 w-4" }),
|
|
35
|
+
title: "Agent question",
|
|
36
|
+
description: questions.length > 1 ? `${questions.length} questions require attention` : void 0,
|
|
37
|
+
children: [
|
|
38
|
+
part.state.status === "running" ? /* @__PURE__ */ jsx(PreviewLoading, { label: "Waiting for an answer…" }) : null,
|
|
39
|
+
part.state.error ? /* @__PURE__ */ jsx(PreviewError, { error: part.state.error }) : null,
|
|
40
|
+
questions.length === 0 ? /* @__PURE__ */ jsx(PreviewEmpty, { label: "No question text was provided." }) : null,
|
|
41
|
+
questions.map((question, index) => /* @__PURE__ */ jsxs("div", {
|
|
42
|
+
className: "rounded-[var(--radius-md)] border border-border bg-muted px-3 py-3",
|
|
43
|
+
children: [
|
|
44
|
+
/* @__PURE__ */ jsxs("div", {
|
|
45
|
+
className: "text-xs font-semibold uppercase tracking-[0.08em] text-muted-foreground",
|
|
46
|
+
children: ["Question ", index + 1]
|
|
47
|
+
}),
|
|
48
|
+
/* @__PURE__ */ jsx("div", {
|
|
49
|
+
className: "mt-2 text-sm leading-relaxed text-foreground",
|
|
50
|
+
children: question
|
|
51
|
+
}),
|
|
52
|
+
/* @__PURE__ */ jsx("div", {
|
|
53
|
+
className: "mt-3 rounded-[var(--radius-sm)] border border-border bg-card px-3 py-2 text-sm text-foreground",
|
|
54
|
+
children: answers[index] ?? (part.state.status === "completed" ? "No answer recorded." : "Awaiting answer")
|
|
55
|
+
})
|
|
56
|
+
]
|
|
57
|
+
}, `${question}-${index}`))
|
|
58
|
+
]
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
QuestionPreview.displayName = "QuestionPreview";
|
|
62
|
+
//#endregion
|
|
63
|
+
export { QuestionPreview };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ToolPart } from "../types/parts.js";
|
|
2
|
+
//#region src/tool-previews/web-search-preview.d.ts
|
|
3
|
+
export interface WebSearchPreviewProps {
|
|
4
|
+
part: ToolPart;
|
|
5
|
+
}
|
|
6
|
+
export declare const WebSearchPreview: import("react").MemoExoticComponent<({ part }: WebSearchPreviewProps) => import("react").JSX.Element>;
|
|
7
|
+
//#endregion
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { focusRing } from "../lib/focus.js";
|
|
2
|
+
import { PreviewCard, PreviewEmpty, PreviewError, PreviewLoading } from "./preview-primitives.js";
|
|
3
|
+
import { memo, useMemo } from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { Globe } from "lucide-react";
|
|
6
|
+
//#region src/tool-previews/web-search-preview.tsx
|
|
7
|
+
function coerceString(value) {
|
|
8
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
9
|
+
}
|
|
10
|
+
function extractQuery(input, output) {
|
|
11
|
+
if (input && typeof input === "object") {
|
|
12
|
+
const record = input;
|
|
13
|
+
const query = coerceString(record.query) ?? coerceString(record.url);
|
|
14
|
+
if (query) return query;
|
|
15
|
+
}
|
|
16
|
+
if (output && typeof output === "object") return coerceString(output.query);
|
|
17
|
+
}
|
|
18
|
+
function parseResult(value) {
|
|
19
|
+
if (!value || typeof value !== "object") return null;
|
|
20
|
+
const record = value;
|
|
21
|
+
const title = coerceString(record.title) ?? coerceString(record.name) ?? "Untitled result";
|
|
22
|
+
const url = coerceString(record.url) ?? coerceString(record.link);
|
|
23
|
+
if (!url) return null;
|
|
24
|
+
return {
|
|
25
|
+
title,
|
|
26
|
+
url,
|
|
27
|
+
snippet: coerceString(record.snippet) ?? coerceString(record.description) ?? coerceString(record.text)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function extractResults(output) {
|
|
31
|
+
if (output && typeof output === "object") {
|
|
32
|
+
const record = output;
|
|
33
|
+
const candidate = record.results ?? record.items ?? record.output;
|
|
34
|
+
if (Array.isArray(candidate)) return candidate.map(parseResult).filter((value) => value !== null);
|
|
35
|
+
}
|
|
36
|
+
if (Array.isArray(output)) return output.map(parseResult).filter((value) => value !== null);
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
const WebSearchPreview = memo(({ part }) => {
|
|
40
|
+
const query = extractQuery(part.state.input, part.state.output);
|
|
41
|
+
const results = useMemo(() => extractResults(part.state.output), [part.state.output]);
|
|
42
|
+
return /* @__PURE__ */ jsxs(PreviewCard, {
|
|
43
|
+
icon: /* @__PURE__ */ jsx(Globe, { className: "h-4 w-4" }),
|
|
44
|
+
title: query ? `Web results for ${query}` : "Web results",
|
|
45
|
+
description: results.length > 0 ? `${results.length} result${results.length === 1 ? "" : "s"}` : void 0,
|
|
46
|
+
children: [
|
|
47
|
+
part.state.status === "running" ? /* @__PURE__ */ jsx(PreviewLoading, { label: "Searching the web…" }) : null,
|
|
48
|
+
part.state.error ? /* @__PURE__ */ jsx(PreviewError, { error: part.state.error }) : null,
|
|
49
|
+
part.state.status === "completed" && results.length === 0 ? /* @__PURE__ */ jsx(PreviewEmpty, { label: "No web results were returned." }) : null,
|
|
50
|
+
/* @__PURE__ */ jsx("div", {
|
|
51
|
+
className: "space-y-2",
|
|
52
|
+
children: results.map((result) => /* @__PURE__ */ jsxs("a", {
|
|
53
|
+
href: result.url,
|
|
54
|
+
target: "_blank",
|
|
55
|
+
rel: "noreferrer",
|
|
56
|
+
className: `block rounded-[var(--radius-md)] border border-border bg-muted/55 px-3 py-3 transition-colors hover:border-[var(--border-strong)] hover:bg-accent/50 ${focusRing}`,
|
|
57
|
+
children: [
|
|
58
|
+
/* @__PURE__ */ jsx("div", {
|
|
59
|
+
className: "text-sm font-medium text-foreground",
|
|
60
|
+
children: result.title
|
|
61
|
+
}),
|
|
62
|
+
/* @__PURE__ */ jsx("div", {
|
|
63
|
+
className: "mt-1 truncate text-xs text-primary",
|
|
64
|
+
children: result.url
|
|
65
|
+
}),
|
|
66
|
+
result.snippet ? /* @__PURE__ */ jsx("p", {
|
|
67
|
+
className: "mt-2 text-sm leading-relaxed text-muted-foreground",
|
|
68
|
+
children: result.snippet
|
|
69
|
+
}) : null
|
|
70
|
+
]
|
|
71
|
+
}, result.url))
|
|
72
|
+
})
|
|
73
|
+
]
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
WebSearchPreview.displayName = "WebSearchPreview";
|
|
77
|
+
//#endregion
|
|
78
|
+
export { WebSearchPreview };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ToolPart } from "../types/parts.js";
|
|
2
|
+
//#region src/tool-previews/write-file-preview.d.ts
|
|
3
|
+
export interface WriteFilePreviewProps {
|
|
4
|
+
part: ToolPart;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Preview for file write/create operations.
|
|
8
|
+
* Shows file path, line count, and the written content.
|
|
9
|
+
*/
|
|
10
|
+
export declare const WriteFilePreview: import("react").MemoExoticComponent<({ part }: WriteFilePreviewProps) => import("react").JSX.Element | null>;
|
|
11
|
+
//#endregion
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { CodeBlock, CopyButton } from "../markdown/code-block.js";
|
|
2
|
+
import { PreviewCard, PreviewError, PreviewLoading } from "./preview-primitives.js";
|
|
3
|
+
import { getSyntaxLanguage } from "../files/file-format.js";
|
|
4
|
+
import { memo } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { FileEdit } from "lucide-react";
|
|
7
|
+
//#region src/tool-previews/write-file-preview.tsx
|
|
8
|
+
function extractWriteContent(input) {
|
|
9
|
+
if (!input || typeof input !== "object") return null;
|
|
10
|
+
const obj = input;
|
|
11
|
+
return {
|
|
12
|
+
path: String(obj.file_path ?? obj.path ?? obj.filePath ?? "unknown"),
|
|
13
|
+
content: String(obj.content ?? obj.contents ?? obj.data ?? "")
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Preview for file write/create operations.
|
|
18
|
+
* Shows file path, line count, and the written content.
|
|
19
|
+
*/
|
|
20
|
+
const WriteFilePreview = memo(({ part }) => {
|
|
21
|
+
const write = extractWriteContent(part.state.input);
|
|
22
|
+
if (!write) return null;
|
|
23
|
+
const lineCount = write.content.split("\n").length;
|
|
24
|
+
const language = getSyntaxLanguage(write.path);
|
|
25
|
+
return /* @__PURE__ */ jsxs(PreviewCard, {
|
|
26
|
+
icon: /* @__PURE__ */ jsx(FileEdit, { className: "h-4 w-4" }),
|
|
27
|
+
title: "Write file",
|
|
28
|
+
description: write.path,
|
|
29
|
+
meta: /* @__PURE__ */ jsxs("span", {
|
|
30
|
+
className: "text-xs text-muted-foreground",
|
|
31
|
+
children: [
|
|
32
|
+
"+",
|
|
33
|
+
lineCount,
|
|
34
|
+
" line",
|
|
35
|
+
lineCount !== 1 ? "s" : ""
|
|
36
|
+
]
|
|
37
|
+
}),
|
|
38
|
+
children: [
|
|
39
|
+
part.state.status === "running" ? /* @__PURE__ */ jsx(PreviewLoading, { label: "Writing file…" }) : null,
|
|
40
|
+
part.state.error ? /* @__PURE__ */ jsx(PreviewError, { error: part.state.error }) : null,
|
|
41
|
+
/* @__PURE__ */ jsx(CodeBlock, {
|
|
42
|
+
code: write.content,
|
|
43
|
+
language,
|
|
44
|
+
className: "rounded-[var(--radius-md)]",
|
|
45
|
+
children: /* @__PURE__ */ jsx(CopyButton, { text: write.content })
|
|
46
|
+
})
|
|
47
|
+
]
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
WriteFilePreview.displayName = "WriteFilePreview";
|
|
51
|
+
//#endregion
|
|
52
|
+
export { WriteFilePreview };
|
package/dist/tool-previews.d.ts
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CommandPreview, CommandPreviewProps } from "./tool-previews/command-preview.js";
|
|
2
|
+
import { WriteFilePreview, WriteFilePreviewProps } from "./tool-previews/write-file-preview.js";
|
|
3
|
+
import { GrepResultsPreview, GrepResultsPreviewProps } from "./tool-previews/grep-results-preview.js";
|
|
4
|
+
import { GlobResultsPreview, GlobResultsPreviewProps } from "./tool-previews/glob-results-preview.js";
|
|
5
|
+
import { WebSearchPreview, WebSearchPreviewProps } from "./tool-previews/web-search-preview.js";
|
|
6
|
+
import { QuestionPreview, QuestionPreviewProps } from "./tool-previews/question-preview.js";
|
|
7
|
+
import { DiffPreview, DiffPreviewProps } from "./tool-previews/diff-preview.js";
|
|
2
8
|
export { CommandPreview, type CommandPreviewProps, DiffPreview, type DiffPreviewProps, GlobResultsPreview, type GlobResultsPreviewProps, GrepResultsPreview, type GrepResultsPreviewProps, QuestionPreview, type QuestionPreviewProps, WebSearchPreview, type WebSearchPreviewProps, WriteFilePreview, type WriteFilePreviewProps };
|
package/dist/tool-previews.js
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CommandPreview } from "./tool-previews/command-preview.js";
|
|
2
|
+
import { WriteFilePreview } from "./tool-previews/write-file-preview.js";
|
|
3
|
+
import { GrepResultsPreview } from "./tool-previews/grep-results-preview.js";
|
|
4
|
+
import { GlobResultsPreview } from "./tool-previews/glob-results-preview.js";
|
|
5
|
+
import { WebSearchPreview } from "./tool-previews/web-search-preview.js";
|
|
6
|
+
import { QuestionPreview } from "./tool-previews/question-preview.js";
|
|
7
|
+
import { DiffPreview } from "./tool-previews/diff-preview.js";
|
|
2
8
|
export { CommandPreview, DiffPreview, GlobResultsPreview, GrepResultsPreview, QuestionPreview, WebSearchPreview, WriteFilePreview };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/types/branding.d.ts
|
|
2
2
|
/** Visual branding for a run group header — injected by consuming app. */
|
|
3
|
-
interface AgentBranding {
|
|
3
|
+
export interface AgentBranding {
|
|
4
4
|
label: string;
|
|
5
5
|
accentClass: string;
|
|
6
6
|
bgClass: string;
|
|
@@ -10,5 +10,4 @@ interface AgentBranding {
|
|
|
10
10
|
iconClass: string;
|
|
11
11
|
textClass: string;
|
|
12
12
|
}
|
|
13
|
-
//#endregion
|
|
14
|
-
export { AgentBranding as t };
|
|
13
|
+
//#endregion
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/types/message.d.ts
|
|
2
2
|
/** A single message in a chat session. */
|
|
3
|
-
interface SessionMessage {
|
|
3
|
+
export interface SessionMessage {
|
|
4
4
|
id: string;
|
|
5
5
|
role: 'user' | 'assistant' | 'system';
|
|
6
6
|
sessionID?: string;
|
|
@@ -12,5 +12,4 @@ interface SessionMessage {
|
|
|
12
12
|
/** Monotonically increasing insertion index for stable ordering. */
|
|
13
13
|
_insertionIndex?: number;
|
|
14
14
|
}
|
|
15
|
-
//#endregion
|
|
16
|
-
export { SessionMessage as t };
|
|
15
|
+
//#endregion
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
//#region src/types/parts.d.ts
|
|
2
|
-
interface TextPart {
|
|
2
|
+
export interface TextPart {
|
|
3
3
|
type: 'text';
|
|
4
4
|
text: string;
|
|
5
5
|
/** If true this text was synthesised client-side (e.g. echo of user input). */
|
|
6
6
|
synthetic?: boolean;
|
|
7
7
|
}
|
|
8
|
-
type ToolStatus = 'pending' | 'running' | 'completed' | 'error';
|
|
9
|
-
interface ToolTime {
|
|
8
|
+
export type ToolStatus = 'pending' | 'running' | 'completed' | 'error';
|
|
9
|
+
export interface ToolTime {
|
|
10
10
|
start?: number;
|
|
11
11
|
end?: number;
|
|
12
12
|
}
|
|
13
|
-
interface ToolState {
|
|
13
|
+
export interface ToolState {
|
|
14
14
|
status: ToolStatus;
|
|
15
15
|
input?: unknown;
|
|
16
16
|
output?: unknown;
|
|
@@ -18,7 +18,7 @@ interface ToolState {
|
|
|
18
18
|
metadata?: Record<string, unknown>;
|
|
19
19
|
time?: ToolTime;
|
|
20
20
|
}
|
|
21
|
-
interface ToolPart {
|
|
21
|
+
export interface ToolPart {
|
|
22
22
|
type: 'tool';
|
|
23
23
|
/** Unique ID for this tool invocation. */
|
|
24
24
|
id: string;
|
|
@@ -27,11 +27,10 @@ interface ToolPart {
|
|
|
27
27
|
state: ToolState;
|
|
28
28
|
callID?: string;
|
|
29
29
|
}
|
|
30
|
-
interface ReasoningPart {
|
|
30
|
+
export interface ReasoningPart {
|
|
31
31
|
type: 'reasoning';
|
|
32
32
|
text: string;
|
|
33
33
|
time?: ToolTime;
|
|
34
34
|
}
|
|
35
|
-
type SessionPart = TextPart | ToolPart | ReasoningPart;
|
|
36
|
-
//#endregion
|
|
37
|
-
export { ToolState as a, ToolPart as i, SessionPart as n, ToolStatus as o, TextPart as r, ToolTime as s, ReasoningPart as t };
|
|
35
|
+
export type SessionPart = TextPart | ToolPart | ReasoningPart;
|
|
36
|
+
//#endregion
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SessionMessage } from "./message.js";
|
|
2
2
|
//#region src/types/run.d.ts
|
|
3
3
|
/** Broad category of a tool invocation, used for display grouping. */
|
|
4
|
-
type ToolCategory = "command" | "write" | "read" | "search" | "edit" | "task" | "web" | "todo" | "other";
|
|
5
|
-
interface RunStats {
|
|
4
|
+
export type ToolCategory = "command" | "write" | "read" | "search" | "edit" | "task" | "web" | "todo" | "other";
|
|
5
|
+
export interface RunStats {
|
|
6
6
|
toolCount: number;
|
|
7
7
|
messageCount: number;
|
|
8
8
|
thinkingDurationMs: number;
|
|
9
9
|
textPartCount: number;
|
|
10
10
|
toolCategories: Set<ToolCategory>;
|
|
11
11
|
}
|
|
12
|
-
interface FinalTextPart {
|
|
12
|
+
export interface FinalTextPart {
|
|
13
13
|
messageId: string;
|
|
14
14
|
partIndex: number;
|
|
15
15
|
text: string;
|
|
@@ -19,7 +19,7 @@ interface FinalTextPart {
|
|
|
19
19
|
* logical "turn" of the agent. Runs are collapsible in the UI and
|
|
20
20
|
* show a summary header when collapsed.
|
|
21
21
|
*/
|
|
22
|
-
interface Run {
|
|
22
|
+
export interface Run {
|
|
23
23
|
id: string;
|
|
24
24
|
messages: SessionMessage[];
|
|
25
25
|
isComplete: boolean;
|
|
@@ -28,14 +28,13 @@ interface Run {
|
|
|
28
28
|
summaryText: string | null;
|
|
29
29
|
finalTextPart: FinalTextPart | null;
|
|
30
30
|
}
|
|
31
|
-
interface MessageRun {
|
|
31
|
+
export interface MessageRun {
|
|
32
32
|
type: "run";
|
|
33
33
|
run: Run;
|
|
34
34
|
}
|
|
35
|
-
interface MessageUser {
|
|
35
|
+
export interface MessageUser {
|
|
36
36
|
type: "user";
|
|
37
37
|
message: SessionMessage;
|
|
38
38
|
}
|
|
39
|
-
type GroupedMessage = MessageRun | MessageUser;
|
|
40
|
-
//#endregion
|
|
41
|
-
export { Run as a, MessageUser as i, GroupedMessage as n, RunStats as o, MessageRun as r, ToolCategory as s, FinalTextPart as t };
|
|
39
|
+
export type GroupedMessage = MessageRun | MessageUser;
|
|
40
|
+
//#endregion
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ToolPart } from "./parts.js";
|
|
2
2
|
import { ReactNode } from "react";
|
|
3
3
|
//#region src/types/tool-display.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Variant-specific rendering instructions for tool output.
|
|
6
6
|
* Maps directly to specialised preview components.
|
|
7
7
|
*/
|
|
8
|
-
type DisplayVariant = "command" | "write-file" | "read-file" | "diff" | "question" | "web-search" | "grep" | "glob" | "default";
|
|
8
|
+
export type DisplayVariant = "command" | "write-file" | "read-file" | "diff" | "question" | "web-search" | "grep" | "glob" | "default";
|
|
9
9
|
/**
|
|
10
10
|
* Custom renderer for tool details. Return a ReactNode to override the
|
|
11
11
|
* default ExpandedToolDetail, or null to fall back to the built-in renderer.
|
|
12
12
|
*/
|
|
13
|
-
type CustomToolRenderer = (part: ToolPart) => ReactNode | null;
|
|
13
|
+
export type CustomToolRenderer = (part: ToolPart) => ReactNode | null;
|
|
14
14
|
/**
|
|
15
15
|
* Visual metadata for a tool invocation — computed from the tool name,
|
|
16
16
|
* input, and output by `getToolDisplayMetadata()`.
|
|
17
17
|
*/
|
|
18
|
-
interface ToolDisplayMetadata {
|
|
18
|
+
export interface ToolDisplayMetadata {
|
|
19
19
|
title: string;
|
|
20
20
|
description?: string;
|
|
21
21
|
inputTitle?: string;
|
|
@@ -28,5 +28,4 @@ interface ToolDisplayMetadata {
|
|
|
28
28
|
commandSnippet?: string;
|
|
29
29
|
targetPath?: string;
|
|
30
30
|
}
|
|
31
|
-
//#endregion
|
|
32
|
-
export { DisplayVariant as n, ToolDisplayMetadata as r, CustomToolRenderer as t };
|
|
31
|
+
//#endregion
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { SessionMessage } from "./types/message.js";
|
|
2
|
+
import { ReasoningPart, SessionPart, TextPart, ToolPart, ToolState, ToolStatus, ToolTime } from "./types/parts.js";
|
|
3
|
+
import { AgentBranding } from "./types/branding.js";
|
|
4
|
+
import { CustomToolRenderer, DisplayVariant, ToolDisplayMetadata } from "./types/tool-display.js";
|
|
5
|
+
import { FinalTextPart, GroupedMessage, MessageRun, MessageUser, Run, RunStats, ToolCategory } from "./types/run.js";
|
|
6
6
|
export { AgentBranding, CustomToolRenderer, DisplayVariant, FinalTextPart, GroupedMessage, MessageRun, MessageUser, ReasoningPart, Run, RunStats, SessionMessage, SessionPart, TextPart, ToolCategory, ToolDisplayMetadata, ToolPart, ToolState, ToolStatus, ToolTime };
|
|
@@ -24,14 +24,4 @@ async function copyText(text) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
//#endregion
|
|
27
|
-
|
|
28
|
-
function timeAgo(ts) {
|
|
29
|
-
const secs = Math.floor((Date.now() - ts) / 1e3);
|
|
30
|
-
if (secs < 5) return "just now";
|
|
31
|
-
if (secs < 60) return `${secs}s ago`;
|
|
32
|
-
const mins = Math.floor(secs / 60);
|
|
33
|
-
if (mins < 60) return `${mins}m ago`;
|
|
34
|
-
return `${Math.floor(mins / 60)}h ago`;
|
|
35
|
-
}
|
|
36
|
-
//#endregion
|
|
37
|
-
export { copyText as n, timeAgo as t };
|
|
27
|
+
export { copyText };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/utils/format.d.ts
|
|
2
|
+
/** Format a duration in milliseconds to a human-readable string. */
|
|
3
|
+
export declare function formatDuration(ms: number): string;
|
|
4
|
+
/** Truncate text to `max` characters, appending "..." if truncated. */
|
|
5
|
+
export declare function truncateText(text: string, max: number): string;
|
|
6
|
+
/**
|
|
7
|
+
* Format an uptime duration in milliseconds with progressive
|
|
8
|
+
* granularity, so short-lived sandboxes don't render as "0d 0h".
|
|
9
|
+
* - < 60s → "Ns"
|
|
10
|
+
* - < 60m → "Nm Ss"
|
|
11
|
+
* - < 24h → "Nh Mm"
|
|
12
|
+
* - otherwise → "Nd Hh"
|
|
13
|
+
*/
|
|
14
|
+
export declare function formatUptime(ms: number): string;
|
|
15
|
+
/**
|
|
16
|
+
* Format a byte count using binary units (KiB/MiB/GiB, surfaced as
|
|
17
|
+
* "KB/MB/GB" for readability). KB and MB use one decimal below 10 and
|
|
18
|
+
* round above; GB keeps two decimals below 10 so half-GB changes stay
|
|
19
|
+
* visible on memory dashboards, and drops to one decimal above.
|
|
20
|
+
*/
|
|
21
|
+
export declare function formatBytes(bytes: number): string;
|
|
22
|
+
//#endregion
|
|
@@ -51,4 +51,4 @@ function formatBytes(bytes) {
|
|
|
51
51
|
return `${gb < 10 ? gb.toFixed(2) : gb.toFixed(1)} GB`;
|
|
52
52
|
}
|
|
53
53
|
//#endregion
|
|
54
|
-
export {
|
|
54
|
+
export { formatBytes, formatDuration, formatUptime, truncateText };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/utils/time-ago.ts
|
|
2
|
+
function timeAgo(ts) {
|
|
3
|
+
const secs = Math.floor((Date.now() - ts) / 1e3);
|
|
4
|
+
if (secs < 5) return "just now";
|
|
5
|
+
if (secs < 60) return `${secs}s ago`;
|
|
6
|
+
const mins = Math.floor(secs / 60);
|
|
7
|
+
if (mins < 60) return `${mins}m ago`;
|
|
8
|
+
return `${Math.floor(mins / 60)}h ago`;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { timeAgo };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ToolPart } from "../types/parts.js";
|
|
2
|
+
import { ToolDisplayMetadata } from "../types/tool-display.js";
|
|
3
|
+
import { ToolCategory } from "../types/run.js";
|
|
4
|
+
//#region src/utils/tool-display.d.ts
|
|
5
|
+
export declare const TOOL_CATEGORY_ICONS: Record<ToolCategory, string>;
|
|
6
|
+
export declare function getToolCategory(toolName: string): ToolCategory;
|
|
7
|
+
/**
|
|
8
|
+
* Title is the bare verb ("Read", "Edit", "Shell"); the path, command, pattern
|
|
9
|
+
* or query lives in `description` only, so a row prints its subject once.
|
|
10
|
+
* `targetPath` / `commandSnippet` carry the untruncated value for consumers
|
|
11
|
+
* that need it (diff headers, expanded detail).
|
|
12
|
+
*/
|
|
13
|
+
export declare function getToolDisplayMetadata(part: ToolPart): ToolDisplayMetadata;
|
|
14
|
+
/** Extract error text from a tool part, if any. */
|
|
15
|
+
export declare function getToolErrorText(part: ToolPart, fallback?: string): string | undefined;
|
|
16
|
+
//#endregion
|
|
@@ -155,4 +155,4 @@ function getToolErrorText(part, fallback) {
|
|
|
155
155
|
return part.state.error || fallback;
|
|
156
156
|
}
|
|
157
157
|
//#endregion
|
|
158
|
-
export {
|
|
158
|
+
export { TOOL_CATEGORY_ICONS, getToolCategory, getToolDisplayMetadata, getToolErrorText };
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { copyText } from "./utils/copy-text.js";
|
|
2
|
+
import { formatBytes, formatDuration, formatUptime, truncateText } from "./utils/format.js";
|
|
3
|
+
import { timeAgo } from "./utils/time-ago.js";
|
|
4
|
+
import { TOOL_CATEGORY_ICONS, getToolCategory, getToolDisplayMetadata, getToolErrorText } from "./utils/tool-display.js";
|
|
5
|
+
import { cn } from "./lib/utils.js";
|
|
6
|
+
import { focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset } from "./lib/focus.js";
|
|
2
7
|
export { TOOL_CATEGORY_ICONS, cn, copyText, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatDuration, formatUptime, getToolCategory, getToolDisplayMetadata, getToolErrorText, timeAgo, truncateText };
|
package/dist/utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset } from "./lib/focus.js";
|
|
2
|
+
import { cn } from "./lib/utils.js";
|
|
3
|
+
import { TOOL_CATEGORY_ICONS, getToolCategory, getToolDisplayMetadata, getToolErrorText } from "./utils/tool-display.js";
|
|
4
|
+
import { formatBytes, formatDuration, formatUptime, truncateText } from "./utils/format.js";
|
|
5
|
+
import { copyText } from "./utils/copy-text.js";
|
|
6
|
+
import { timeAgo } from "./utils/time-ago.js";
|
|
6
7
|
export { TOOL_CATEGORY_ICONS, cn, copyText, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatDuration, formatUptime, getToolCategory, getToolDisplayMetadata, getToolErrorText, timeAgo, truncateText };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/ui",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.13.0",
|
|
4
4
|
"description": "Generic React UI components for Tangle products — primitives, chat, run, files, editor, markdown.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
"peerDependencies": {
|
|
143
143
|
"@hocuspocus/provider": ">=2.15.0 <5.0.0",
|
|
144
144
|
"@nanostores/react": ">=0.8.4 <3.0.0",
|
|
145
|
-
"@tangle-network/brand": "^1.
|
|
145
|
+
"@tangle-network/brand": "^1.10.0",
|
|
146
146
|
"@tiptap/core": ">=3.20.4 <4.0.0",
|
|
147
147
|
"@tiptap/extension-collaboration": ">=3.20.4 <4.0.0",
|
|
148
148
|
"@tiptap/extension-collaboration-caret": ">=3.7.0 <4.0.0",
|
|
@@ -37,6 +37,8 @@ export interface DocumentEditorPaneProps
|
|
|
37
37
|
tabs?: ArtifactPaneProps["tabs"];
|
|
38
38
|
toolbar?: ReactNode;
|
|
39
39
|
markdown?: string;
|
|
40
|
+
/** Persisted baseline when the host controls the current markdown draft. */
|
|
41
|
+
savedMarkdown?: string;
|
|
40
42
|
/** Transform Markdown links and images through the shared URL policy. */
|
|
41
43
|
urlTransform?: UrlTransform;
|
|
42
44
|
mode?: DocumentEditorMode;
|
|
@@ -191,6 +193,7 @@ export function DocumentEditorPane({
|
|
|
191
193
|
tabs,
|
|
192
194
|
toolbar,
|
|
193
195
|
markdown = "",
|
|
196
|
+
savedMarkdown,
|
|
194
197
|
urlTransform,
|
|
195
198
|
mode,
|
|
196
199
|
defaultMode = "preview",
|
|
@@ -212,7 +215,7 @@ export function DocumentEditorPane({
|
|
|
212
215
|
useState<DocumentEditorMode>(defaultMode);
|
|
213
216
|
const activeMode = mode ?? uncontrolledMode;
|
|
214
217
|
const isCollaborative = backend === "collaborative" && Boolean(collaboration);
|
|
215
|
-
const isDirty = normalizeMarkdown(draft) !== normalizeMarkdown(markdown);
|
|
218
|
+
const isDirty = normalizeMarkdown(draft) !== normalizeMarkdown(savedMarkdown ?? markdown);
|
|
216
219
|
const saveStateLabel = readOnly
|
|
217
220
|
? "Read only"
|
|
218
221
|
: isCollaborative
|
|
@@ -231,3 +231,26 @@ describe("parseCsv", () => {
|
|
|
231
231
|
expect(parseCsv("\n\n")).toEqual([]);
|
|
232
232
|
});
|
|
233
233
|
});
|
|
234
|
+
|
|
235
|
+
describe("FileArtifactPane controlled drafts", () => {
|
|
236
|
+
it("retains a host draft and saves it against the persisted baseline", async () => {
|
|
237
|
+
const onSave = vi.fn();
|
|
238
|
+
const draft = "# Unsaved source draft";
|
|
239
|
+
const props = {
|
|
240
|
+
filename: "notes.md",
|
|
241
|
+
content: draft,
|
|
242
|
+
editor: { enabled: true, savedContent: "# Saved notes", onSave },
|
|
243
|
+
};
|
|
244
|
+
const view = render(<FileArtifactPane {...props} />);
|
|
245
|
+
const save = await screen.findByRole("button", { name: "Save changes" });
|
|
246
|
+
expect(screen.getByRole("heading", { name: "Unsaved source draft" })).toBeVisible();
|
|
247
|
+
expect(screen.getByText("Unsaved changes")).toBeVisible();
|
|
248
|
+
expect(save).toBeEnabled();
|
|
249
|
+
fireEvent.click(save);
|
|
250
|
+
expect(onSave).toHaveBeenCalledWith(draft);
|
|
251
|
+
|
|
252
|
+
view.rerender(<FileArtifactPane {...props} editor={{ ...props.editor, savedContent: draft }} />);
|
|
253
|
+
expect(screen.getByText("Saved")).toBeVisible();
|
|
254
|
+
expect(save).toBeDisabled();
|
|
255
|
+
});
|
|
256
|
+
});
|
|
@@ -18,6 +18,8 @@ const LazyDocumentEditorPane = lazy(async () => {
|
|
|
18
18
|
|
|
19
19
|
export interface FileArtifactPaneEditorOptions {
|
|
20
20
|
enabled?: boolean;
|
|
21
|
+
/** Persisted baseline when content is the current draft. */
|
|
22
|
+
savedContent?: string;
|
|
21
23
|
mode?: DocumentEditorMode;
|
|
22
24
|
defaultMode?: DocumentEditorMode;
|
|
23
25
|
onModeChange?: (mode: DocumentEditorMode) => void;
|
|
@@ -155,6 +157,7 @@ export function FileArtifactPane({
|
|
|
155
157
|
headerClassName={headerClassName}
|
|
156
158
|
hideTitleBlock={hideTitleBlock}
|
|
157
159
|
markdown={content ?? ""}
|
|
160
|
+
savedMarkdown={editor.savedContent}
|
|
158
161
|
urlTransform={urlTransform}
|
|
159
162
|
mode={editor.mode}
|
|
160
163
|
defaultMode={editor.defaultMode}
|
|
@@ -8,7 +8,7 @@ const meta: Meta<typeof RichFileTree> = {
|
|
|
8
8
|
parameters: { layout: "padded", backgrounds: { default: "dark" } },
|
|
9
9
|
decorators: [
|
|
10
10
|
(Story) => (
|
|
11
|
-
<div className="w-[420px] h-[480px] rounded-xl border border-border bg-card overflow-hidden">
|
|
11
|
+
<div className="w-full max-w-[420px] h-[480px] rounded-xl border border-border bg-card overflow-hidden">
|
|
12
12
|
<Story />
|
|
13
13
|
</div>
|
|
14
14
|
),
|