@nextclaw/agent-chat-ui 0.3.10 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +187 -28
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -17,6 +17,19 @@ import { $applyNodeReplacement, $createLineBreakNode, $createParagraphNode, $cre
|
|
|
17
17
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
18
18
|
import ReactMarkdown from "react-markdown";
|
|
19
19
|
import remarkGfm from "remark-gfm";
|
|
20
|
+
import hljs from "highlight.js/lib/core";
|
|
21
|
+
import bash from "highlight.js/lib/languages/bash";
|
|
22
|
+
import css from "highlight.js/lib/languages/css";
|
|
23
|
+
import diff from "highlight.js/lib/languages/diff";
|
|
24
|
+
import javascript from "highlight.js/lib/languages/javascript";
|
|
25
|
+
import json from "highlight.js/lib/languages/json";
|
|
26
|
+
import markdown from "highlight.js/lib/languages/markdown";
|
|
27
|
+
import python from "highlight.js/lib/languages/python";
|
|
28
|
+
import shell from "highlight.js/lib/languages/shell";
|
|
29
|
+
import sql from "highlight.js/lib/languages/sql";
|
|
30
|
+
import typescript from "highlight.js/lib/languages/typescript";
|
|
31
|
+
import xml from "highlight.js/lib/languages/xml";
|
|
32
|
+
import yaml from "highlight.js/lib/languages/yaml";
|
|
20
33
|
//#region src/components/chat/hooks/use-active-item-scroll.ts
|
|
21
34
|
const defaultGetItemSelector = (index) => `[data-item-index="${index}"]`;
|
|
22
35
|
function useActiveItemScroll(params) {
|
|
@@ -632,24 +645,23 @@ function ChatInputBarSkillPicker(props) {
|
|
|
632
645
|
//#endregion
|
|
633
646
|
//#region src/components/chat/ui/chat-input-bar/chat-input-bar-toolbar.tsx
|
|
634
647
|
function ToolbarIcon({ icon }) {
|
|
635
|
-
|
|
636
|
-
if (icon === "brain") return /* @__PURE__ */ jsx(Brain, { className: "h-3.5 w-3.5 shrink-0 text-gray-500" });
|
|
637
|
-
return null;
|
|
648
|
+
return icon === "sparkles" ? /* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5 shrink-0 text-primary" }) : icon === "brain" ? /* @__PURE__ */ jsx(Brain, { className: "h-3.5 w-3.5 shrink-0 text-gray-500" }) : null;
|
|
638
649
|
}
|
|
639
650
|
function AccessoryIcon({ icon }) {
|
|
640
|
-
|
|
641
|
-
return /* @__PURE__ */ jsx(ToolbarIcon, { icon });
|
|
642
|
-
}
|
|
643
|
-
function resolveTriggerWidth(key) {
|
|
644
|
-
if (key === "model") return "min-w-0 flex-1";
|
|
645
|
-
if (key === "session-type" || key === "thinking") return "shrink-0";
|
|
646
|
-
return "";
|
|
651
|
+
return icon === "paperclip" ? /* @__PURE__ */ jsx(Paperclip, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ToolbarIcon, { icon });
|
|
647
652
|
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
+
const TRIGGER_WIDTH_BY_KEY = {
|
|
654
|
+
model: "min-w-0 flex-1 sm:min-w-[220px] sm:flex-none",
|
|
655
|
+
"session-type": "shrink-0",
|
|
656
|
+
thinking: "shrink-0"
|
|
657
|
+
};
|
|
658
|
+
const CONTENT_WIDTH_BY_KEY = {
|
|
659
|
+
model: "w-[min(18rem,calc(100vw-1rem))] sm:w-[320px]",
|
|
660
|
+
"session-type": "w-[220px]",
|
|
661
|
+
thinking: "w-[180px]"
|
|
662
|
+
};
|
|
663
|
+
function resolveMobileSelectedLabel(item) {
|
|
664
|
+
return item.key === "model" && item.selectedLabel ? item.selectedLabel.split("/").slice(1).join("/").trim() || item.selectedLabel : item.selectedLabel;
|
|
653
665
|
}
|
|
654
666
|
function ToolbarSelect({ item }) {
|
|
655
667
|
const { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue } = ChatUiPrimitives;
|
|
@@ -658,21 +670,29 @@ function ToolbarSelect({ item }) {
|
|
|
658
670
|
options: item.options
|
|
659
671
|
}] : []);
|
|
660
672
|
const hasOptions = groups.some((group) => group.options.length > 0);
|
|
673
|
+
const mobileSelectedLabel = resolveMobileSelectedLabel(item);
|
|
661
674
|
return /* @__PURE__ */ jsxs(Select, {
|
|
662
675
|
value: item.value,
|
|
663
676
|
onValueChange: item.onValueChange,
|
|
664
677
|
disabled: item.disabled,
|
|
665
678
|
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
666
|
-
className: `h-8 w-auto rounded-lg border-0 bg-transparent px-2 text-xs font-medium text-gray-600 shadow-none hover:bg-gray-100 focus:ring-0 sm:px-3 ${
|
|
679
|
+
className: `h-8 w-auto rounded-lg border-0 bg-transparent px-2 text-xs font-medium text-gray-600 shadow-none hover:bg-gray-100 focus:ring-0 sm:px-3 ${TRIGGER_WIDTH_BY_KEY[item.key] ?? ""}`,
|
|
667
680
|
children: item.selectedLabel ? /* @__PURE__ */ jsxs("div", {
|
|
668
681
|
className: "flex min-w-0 items-center gap-2 text-left",
|
|
669
|
-
children: [
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
682
|
+
children: [
|
|
683
|
+
/* @__PURE__ */ jsx(ToolbarIcon, { icon: item.icon }),
|
|
684
|
+
/* @__PURE__ */ jsx("span", {
|
|
685
|
+
className: "truncate text-xs font-semibold text-gray-700 sm:hidden",
|
|
686
|
+
children: mobileSelectedLabel
|
|
687
|
+
}),
|
|
688
|
+
/* @__PURE__ */ jsx("span", {
|
|
689
|
+
className: "hidden truncate text-xs font-semibold text-gray-700 sm:inline",
|
|
690
|
+
children: item.selectedLabel
|
|
691
|
+
})
|
|
692
|
+
]
|
|
673
693
|
}) : item.loading ? /* @__PURE__ */ jsx("div", { className: "h-3 w-24 animate-pulse rounded bg-gray-200" }) : /* @__PURE__ */ jsx(SelectValue, { placeholder: item.placeholder })
|
|
674
694
|
}), /* @__PURE__ */ jsxs(SelectContent, {
|
|
675
|
-
className:
|
|
695
|
+
className: CONTENT_WIDTH_BY_KEY[item.key] ?? "",
|
|
676
696
|
children: [!hasOptions ? item.loading ? /* @__PURE__ */ jsxs("div", {
|
|
677
697
|
className: "space-y-2 px-3 py-2",
|
|
678
698
|
children: [
|
|
@@ -2018,6 +2038,139 @@ function useCopyFeedback(params) {
|
|
|
2018
2038
|
};
|
|
2019
2039
|
}
|
|
2020
2040
|
//#endregion
|
|
2041
|
+
//#region src/components/chat/ui/chat-message-list/code-block/chat-code-syntax-highlighter.ts
|
|
2042
|
+
const PLAIN_TEXT_LANGUAGES = new Set([
|
|
2043
|
+
"text",
|
|
2044
|
+
"txt",
|
|
2045
|
+
"plain",
|
|
2046
|
+
"plaintext",
|
|
2047
|
+
"none",
|
|
2048
|
+
"output"
|
|
2049
|
+
]);
|
|
2050
|
+
const AUTO_DETECT_LANGUAGES = [
|
|
2051
|
+
"typescript",
|
|
2052
|
+
"javascript",
|
|
2053
|
+
"json",
|
|
2054
|
+
"bash",
|
|
2055
|
+
"shell",
|
|
2056
|
+
"python",
|
|
2057
|
+
"css",
|
|
2058
|
+
"xml",
|
|
2059
|
+
"markdown",
|
|
2060
|
+
"yaml",
|
|
2061
|
+
"sql",
|
|
2062
|
+
"diff"
|
|
2063
|
+
];
|
|
2064
|
+
const AUTO_DETECT_MIN_RELEVANCE = 4;
|
|
2065
|
+
const REGISTERED_LANGUAGES = [
|
|
2066
|
+
{
|
|
2067
|
+
name: "typescript",
|
|
2068
|
+
language: typescript,
|
|
2069
|
+
aliases: ["ts", "tsx"]
|
|
2070
|
+
},
|
|
2071
|
+
{
|
|
2072
|
+
name: "javascript",
|
|
2073
|
+
language: javascript,
|
|
2074
|
+
aliases: [
|
|
2075
|
+
"js",
|
|
2076
|
+
"jsx",
|
|
2077
|
+
"mjs",
|
|
2078
|
+
"cjs"
|
|
2079
|
+
]
|
|
2080
|
+
},
|
|
2081
|
+
{
|
|
2082
|
+
name: "json",
|
|
2083
|
+
language: json,
|
|
2084
|
+
aliases: ["jsonc"]
|
|
2085
|
+
},
|
|
2086
|
+
{
|
|
2087
|
+
name: "bash",
|
|
2088
|
+
language: bash,
|
|
2089
|
+
aliases: ["sh", "zsh"]
|
|
2090
|
+
},
|
|
2091
|
+
{
|
|
2092
|
+
name: "shell",
|
|
2093
|
+
language: shell,
|
|
2094
|
+
aliases: ["console", "terminal"]
|
|
2095
|
+
},
|
|
2096
|
+
{
|
|
2097
|
+
name: "python",
|
|
2098
|
+
language: python,
|
|
2099
|
+
aliases: ["py"]
|
|
2100
|
+
},
|
|
2101
|
+
{
|
|
2102
|
+
name: "css",
|
|
2103
|
+
language: css
|
|
2104
|
+
},
|
|
2105
|
+
{
|
|
2106
|
+
name: "xml",
|
|
2107
|
+
language: xml,
|
|
2108
|
+
aliases: ["html", "svg"]
|
|
2109
|
+
},
|
|
2110
|
+
{
|
|
2111
|
+
name: "markdown",
|
|
2112
|
+
language: markdown,
|
|
2113
|
+
aliases: ["md", "mdx"]
|
|
2114
|
+
},
|
|
2115
|
+
{
|
|
2116
|
+
name: "yaml",
|
|
2117
|
+
language: yaml,
|
|
2118
|
+
aliases: ["yml"]
|
|
2119
|
+
},
|
|
2120
|
+
{
|
|
2121
|
+
name: "sql",
|
|
2122
|
+
language: sql
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
name: "diff",
|
|
2126
|
+
language: diff,
|
|
2127
|
+
aliases: ["patch"]
|
|
2128
|
+
}
|
|
2129
|
+
];
|
|
2130
|
+
function escapeHtml(value) {
|
|
2131
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2132
|
+
}
|
|
2133
|
+
function normalizeLanguage(value) {
|
|
2134
|
+
return value.trim().toLowerCase();
|
|
2135
|
+
}
|
|
2136
|
+
var ChatCodeSyntaxHighlighter = class {
|
|
2137
|
+
constructor() {
|
|
2138
|
+
this.highlight = (code, language) => {
|
|
2139
|
+
const normalizedLanguage = normalizeLanguage(language);
|
|
2140
|
+
if (!code || PLAIN_TEXT_LANGUAGES.has(normalizedLanguage)) return this.createPlainTextResult(code, normalizedLanguage || "text");
|
|
2141
|
+
if (this.engine.getLanguage(normalizedLanguage)) {
|
|
2142
|
+
const result = this.engine.highlight(code, {
|
|
2143
|
+
language: normalizedLanguage,
|
|
2144
|
+
ignoreIllegals: true
|
|
2145
|
+
});
|
|
2146
|
+
return {
|
|
2147
|
+
html: result.value,
|
|
2148
|
+
language: result.language ?? normalizedLanguage,
|
|
2149
|
+
highlighted: true
|
|
2150
|
+
};
|
|
2151
|
+
}
|
|
2152
|
+
const autoDetected = this.engine.highlightAuto(code, AUTO_DETECT_LANGUAGES);
|
|
2153
|
+
if (autoDetected.language && autoDetected.relevance >= AUTO_DETECT_MIN_RELEVANCE) return {
|
|
2154
|
+
html: autoDetected.value,
|
|
2155
|
+
language: autoDetected.language,
|
|
2156
|
+
highlighted: true
|
|
2157
|
+
};
|
|
2158
|
+
return this.createPlainTextResult(code, normalizedLanguage || "text");
|
|
2159
|
+
};
|
|
2160
|
+
this.createPlainTextResult = (code, language) => ({
|
|
2161
|
+
html: escapeHtml(code),
|
|
2162
|
+
language,
|
|
2163
|
+
highlighted: false
|
|
2164
|
+
});
|
|
2165
|
+
this.engine = hljs.newInstance();
|
|
2166
|
+
REGISTERED_LANGUAGES.forEach((entry) => {
|
|
2167
|
+
this.engine.registerLanguage(entry.name, entry.language);
|
|
2168
|
+
if (entry.aliases) this.engine.registerAliases(entry.aliases, { languageName: entry.name });
|
|
2169
|
+
});
|
|
2170
|
+
}
|
|
2171
|
+
};
|
|
2172
|
+
const chatCodeSyntaxHighlighter = new ChatCodeSyntaxHighlighter();
|
|
2173
|
+
//#endregion
|
|
2021
2174
|
//#region src/components/chat/ui/chat-message-list/chat-code-block.tsx
|
|
2022
2175
|
const CODE_LANGUAGE_REGEX = /language-([a-z0-9-]+)/i;
|
|
2023
2176
|
function flattenNodeText(value) {
|
|
@@ -2032,9 +2185,14 @@ function normalizeCodeText(value) {
|
|
|
2032
2185
|
function resolveCodeLanguage(className) {
|
|
2033
2186
|
return (className ? CODE_LANGUAGE_REGEX.exec(className) : null)?.[1]?.toLowerCase() || "text";
|
|
2034
2187
|
}
|
|
2035
|
-
function ChatCodeBlock(
|
|
2036
|
-
const language = useMemo(() => resolveCodeLanguage(
|
|
2037
|
-
const codeText = useMemo(() => normalizeCodeText(
|
|
2188
|
+
function ChatCodeBlock({ className, children, texts }) {
|
|
2189
|
+
const language = useMemo(() => resolveCodeLanguage(className), [className]);
|
|
2190
|
+
const codeText = useMemo(() => normalizeCodeText(children), [children]);
|
|
2191
|
+
const highlightedCode = useMemo(() => chatCodeSyntaxHighlighter.highlight(codeText, language), [codeText, language]);
|
|
2192
|
+
const codeClassName = useMemo(() => {
|
|
2193
|
+
const highlightedLanguageClass = `language-${highlightedCode.language}`;
|
|
2194
|
+
return cn("hljs", className, className?.includes("language-") ? void 0 : highlightedLanguageClass);
|
|
2195
|
+
}, [className, highlightedCode.language]);
|
|
2038
2196
|
const { copied, copy } = useCopyFeedback({ text: codeText });
|
|
2039
2197
|
return /* @__PURE__ */ jsxs("div", {
|
|
2040
2198
|
className: "chat-codeblock",
|
|
@@ -2047,12 +2205,13 @@ function ChatCodeBlock(props) {
|
|
|
2047
2205
|
type: "button",
|
|
2048
2206
|
className: "chat-codeblock-copy",
|
|
2049
2207
|
onClick: () => void copy(),
|
|
2050
|
-
"aria-label": copied ?
|
|
2051
|
-
children: [copied ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ jsx("span", { children: copied ?
|
|
2208
|
+
"aria-label": copied ? texts.copiedCodeLabel : texts.copyCodeLabel,
|
|
2209
|
+
children: [copied ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ jsx("span", { children: copied ? texts.copiedCodeLabel : texts.copyCodeLabel })]
|
|
2052
2210
|
})]
|
|
2053
2211
|
}), /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", {
|
|
2054
|
-
className:
|
|
2055
|
-
|
|
2212
|
+
className: codeClassName,
|
|
2213
|
+
"data-highlighted": highlightedCode.highlighted ? "true" : "false",
|
|
2214
|
+
dangerouslySetInnerHTML: { __html: highlightedCode.html }
|
|
2056
2215
|
}) })]
|
|
2057
2216
|
});
|
|
2058
2217
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/agent-chat-ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.11",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Reusable Nextclaw agent chat UI primitives and default skin.",
|
|
6
6
|
"type": "module",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"@radix-ui/react-tooltip": "^1.1.11",
|
|
40
40
|
"class-variance-authority": "^0.7.1",
|
|
41
41
|
"clsx": "^2.1.1",
|
|
42
|
+
"highlight.js": "^11.11.1",
|
|
42
43
|
"lexical": "^0.43.0",
|
|
43
44
|
"lucide-react": "^0.462.0",
|
|
44
45
|
"react-markdown": "^10.1.0",
|