@copilotz/chat-ui 0.1.1 → 0.1.4
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.cjs +102 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +103 -28
- package/dist/index.js.map +1 -1
- package/dist/styles.css +23 -54
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -237,9 +237,10 @@ var configUtils = {
|
|
|
237
237
|
};
|
|
238
238
|
|
|
239
239
|
// src/components/chat/Message.tsx
|
|
240
|
-
import { useState, useRef, memo } from "react";
|
|
240
|
+
import { useState, useRef, memo, Component } from "react";
|
|
241
241
|
import ReactMarkdown from "react-markdown";
|
|
242
242
|
import remarkGfm from "remark-gfm";
|
|
243
|
+
import remarkBreaks from "remark-breaks";
|
|
243
244
|
import rehypeHighlight from "rehype-highlight";
|
|
244
245
|
|
|
245
246
|
// src/components/ui/button.tsx
|
|
@@ -530,6 +531,24 @@ import {
|
|
|
530
531
|
ChevronDown
|
|
531
532
|
} from "lucide-react";
|
|
532
533
|
import { Fragment, jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
534
|
+
var MarkdownErrorBoundary = class extends Component {
|
|
535
|
+
constructor(props) {
|
|
536
|
+
super(props);
|
|
537
|
+
this.state = { hasError: false };
|
|
538
|
+
}
|
|
539
|
+
static getDerivedStateFromError(_error) {
|
|
540
|
+
return { hasError: true };
|
|
541
|
+
}
|
|
542
|
+
componentDidCatch(error, errorInfo) {
|
|
543
|
+
console.warn("[Markdown] Falling back to simple rendering due to:", error.message);
|
|
544
|
+
}
|
|
545
|
+
render() {
|
|
546
|
+
if (this.state.hasError) {
|
|
547
|
+
return this.props.fallback;
|
|
548
|
+
}
|
|
549
|
+
return this.props.children;
|
|
550
|
+
}
|
|
551
|
+
};
|
|
533
552
|
var ThinkingIndicator = memo(function ThinkingIndicator2({ label = "Thinking..." }) {
|
|
534
553
|
return /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 py-2", children: [
|
|
535
554
|
/* @__PURE__ */ jsxs2("div", { className: "flex gap-1", children: [
|
|
@@ -565,9 +584,38 @@ var markdownComponents = {
|
|
|
565
584
|
return !inline && match ? /* @__PURE__ */ jsx7("pre", { className: "relative", children: /* @__PURE__ */ jsx7("code", { className, ...props, children }) }) : /* @__PURE__ */ jsx7("code", { className: "bg-muted px-1 py-0.5 rounded text-sm", ...props, children });
|
|
566
585
|
}
|
|
567
586
|
};
|
|
568
|
-
var
|
|
587
|
+
var remarkPluginsWithGfm = [remarkGfm, remarkBreaks];
|
|
588
|
+
var remarkPluginsSimple = [remarkBreaks];
|
|
569
589
|
var rehypePluginsDefault = [rehypeHighlight];
|
|
570
590
|
var rehypePluginsEmpty = [];
|
|
591
|
+
var SimpleMarkdown = memo(function SimpleMarkdown2({
|
|
592
|
+
content,
|
|
593
|
+
isStreaming = false
|
|
594
|
+
}) {
|
|
595
|
+
return /* @__PURE__ */ jsx7(
|
|
596
|
+
ReactMarkdown,
|
|
597
|
+
{
|
|
598
|
+
remarkPlugins: remarkPluginsSimple,
|
|
599
|
+
rehypePlugins: isStreaming ? rehypePluginsEmpty : rehypePluginsDefault,
|
|
600
|
+
components: markdownComponents,
|
|
601
|
+
children: content
|
|
602
|
+
}
|
|
603
|
+
);
|
|
604
|
+
});
|
|
605
|
+
var FullMarkdown = memo(function FullMarkdown2({
|
|
606
|
+
content,
|
|
607
|
+
isStreaming = false
|
|
608
|
+
}) {
|
|
609
|
+
return /* @__PURE__ */ jsx7(
|
|
610
|
+
ReactMarkdown,
|
|
611
|
+
{
|
|
612
|
+
remarkPlugins: remarkPluginsWithGfm,
|
|
613
|
+
rehypePlugins: isStreaming ? rehypePluginsEmpty : rehypePluginsDefault,
|
|
614
|
+
components: markdownComponents,
|
|
615
|
+
children: content
|
|
616
|
+
}
|
|
617
|
+
);
|
|
618
|
+
});
|
|
571
619
|
var StreamingText = memo(function StreamingText2({
|
|
572
620
|
content,
|
|
573
621
|
isStreaming = false,
|
|
@@ -575,15 +623,7 @@ var StreamingText = memo(function StreamingText2({
|
|
|
575
623
|
}) {
|
|
576
624
|
const hasContent = content.trim().length > 0;
|
|
577
625
|
return /* @__PURE__ */ jsxs2("div", { className: "prose prose-sm max-w-none dark:prose-invert", children: [
|
|
578
|
-
hasContent ? /* @__PURE__ */ jsx7(
|
|
579
|
-
ReactMarkdown,
|
|
580
|
-
{
|
|
581
|
-
remarkPlugins: remarkPluginsDefault,
|
|
582
|
-
rehypePlugins: isStreaming ? rehypePluginsEmpty : rehypePluginsDefault,
|
|
583
|
-
components: markdownComponents,
|
|
584
|
-
children: content
|
|
585
|
-
}
|
|
586
|
-
) : isStreaming ? (
|
|
626
|
+
hasContent ? /* @__PURE__ */ jsx7(MarkdownErrorBoundary, { fallback: /* @__PURE__ */ jsx7(SimpleMarkdown, { content, isStreaming }), children: /* @__PURE__ */ jsx7(FullMarkdown, { content, isStreaming }) }) : isStreaming ? (
|
|
587
627
|
// Show thinking indicator while waiting for first token
|
|
588
628
|
/* @__PURE__ */ jsx7(ThinkingIndicator, { label: thinkingLabel })
|
|
589
629
|
) : null,
|
|
@@ -965,18 +1005,26 @@ import { PanelLeftIcon } from "lucide-react";
|
|
|
965
1005
|
// src/hooks/use-mobile.ts
|
|
966
1006
|
import * as React2 from "react";
|
|
967
1007
|
var MOBILE_BREAKPOINT = 768;
|
|
1008
|
+
function getInitialIsMobile() {
|
|
1009
|
+
if (typeof window === "undefined") return false;
|
|
1010
|
+
return window.innerWidth < MOBILE_BREAKPOINT;
|
|
1011
|
+
}
|
|
968
1012
|
function useIsMobile() {
|
|
969
|
-
const [isMobile, setIsMobile] = React2.useState(
|
|
1013
|
+
const [isMobile, setIsMobile] = React2.useState(getInitialIsMobile);
|
|
970
1014
|
React2.useEffect(() => {
|
|
971
1015
|
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
972
1016
|
const onChange = () => {
|
|
973
1017
|
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
974
1018
|
};
|
|
975
1019
|
mql.addEventListener("change", onChange);
|
|
1020
|
+
window.addEventListener("resize", onChange);
|
|
976
1021
|
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
977
|
-
return () =>
|
|
1022
|
+
return () => {
|
|
1023
|
+
mql.removeEventListener("change", onChange);
|
|
1024
|
+
window.removeEventListener("resize", onChange);
|
|
1025
|
+
};
|
|
978
1026
|
}, []);
|
|
979
|
-
return
|
|
1027
|
+
return isMobile;
|
|
980
1028
|
}
|
|
981
1029
|
|
|
982
1030
|
// src/components/ui/separator.tsx
|
|
@@ -1253,12 +1301,29 @@ function Sidebar({
|
|
|
1253
1301
|
}
|
|
1254
1302
|
) });
|
|
1255
1303
|
}
|
|
1304
|
+
const isCollapsed = state === "collapsed";
|
|
1305
|
+
const currentCollapsible = isCollapsed ? collapsible : "";
|
|
1306
|
+
const getGapWidth = () => {
|
|
1307
|
+
if (currentCollapsible === "offcanvas") return "0px";
|
|
1308
|
+
if (currentCollapsible === "icon") return SIDEBAR_WIDTH_ICON;
|
|
1309
|
+
return SIDEBAR_WIDTH;
|
|
1310
|
+
};
|
|
1311
|
+
const getContainerWidth = () => {
|
|
1312
|
+
if (currentCollapsible === "icon") return SIDEBAR_WIDTH_ICON;
|
|
1313
|
+
return SIDEBAR_WIDTH;
|
|
1314
|
+
};
|
|
1315
|
+
const getContainerOffset = () => {
|
|
1316
|
+
if (currentCollapsible === "offcanvas") {
|
|
1317
|
+
return side === "left" ? `calc(${SIDEBAR_WIDTH} * -1)` : `calc(${SIDEBAR_WIDTH} * -1)`;
|
|
1318
|
+
}
|
|
1319
|
+
return "0";
|
|
1320
|
+
};
|
|
1256
1321
|
return /* @__PURE__ */ jsxs4(
|
|
1257
1322
|
"div",
|
|
1258
1323
|
{
|
|
1259
|
-
className: "group peer text-sidebar-foreground
|
|
1324
|
+
className: "group peer text-sidebar-foreground",
|
|
1260
1325
|
"data-state": state,
|
|
1261
|
-
"data-collapsible":
|
|
1326
|
+
"data-collapsible": currentCollapsible,
|
|
1262
1327
|
"data-variant": variant,
|
|
1263
1328
|
"data-side": side,
|
|
1264
1329
|
"data-slot": "sidebar",
|
|
@@ -1268,11 +1333,10 @@ function Sidebar({
|
|
|
1268
1333
|
{
|
|
1269
1334
|
"data-slot": "sidebar-gap",
|
|
1270
1335
|
className: cn(
|
|
1271
|
-
"relative
|
|
1272
|
-
"group-data-[
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
)
|
|
1336
|
+
"relative bg-transparent transition-[width] duration-200 ease-linear",
|
|
1337
|
+
"group-data-[side=right]:rotate-180"
|
|
1338
|
+
),
|
|
1339
|
+
style: { width: getGapWidth() }
|
|
1276
1340
|
}
|
|
1277
1341
|
),
|
|
1278
1342
|
/* @__PURE__ */ jsx11(
|
|
@@ -1280,12 +1344,16 @@ function Sidebar({
|
|
|
1280
1344
|
{
|
|
1281
1345
|
"data-slot": "sidebar-container",
|
|
1282
1346
|
className: cn(
|
|
1283
|
-
"fixed inset-y-0 z-10
|
|
1284
|
-
side === "left" ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
|
|
1347
|
+
"fixed inset-y-0 z-10 h-screen transition-[left,right,width] duration-200 ease-linear",
|
|
1285
1348
|
// Adjust the padding for floating and inset variants.
|
|
1286
|
-
variant === "floating" || variant === "inset" ? "p-2
|
|
1349
|
+
variant === "floating" || variant === "inset" ? "p-2" : side === "left" ? "border-r" : "border-l",
|
|
1287
1350
|
className
|
|
1288
1351
|
),
|
|
1352
|
+
style: {
|
|
1353
|
+
display: "flex",
|
|
1354
|
+
width: getContainerWidth(),
|
|
1355
|
+
[side === "left" ? "left" : "right"]: getContainerOffset()
|
|
1356
|
+
},
|
|
1289
1357
|
...props,
|
|
1290
1358
|
children: /* @__PURE__ */ jsx11(
|
|
1291
1359
|
"div",
|
|
@@ -1308,6 +1376,15 @@ function SidebarTrigger({
|
|
|
1308
1376
|
...props
|
|
1309
1377
|
}) {
|
|
1310
1378
|
const { toggleSidebar } = useSidebar();
|
|
1379
|
+
const handleActivation = React4.useCallback((event) => {
|
|
1380
|
+
if (event.type === "touchend") {
|
|
1381
|
+
event.preventDefault();
|
|
1382
|
+
}
|
|
1383
|
+
if ("onClick" in event && onClick) {
|
|
1384
|
+
onClick(event);
|
|
1385
|
+
}
|
|
1386
|
+
toggleSidebar();
|
|
1387
|
+
}, [onClick, toggleSidebar]);
|
|
1311
1388
|
return /* @__PURE__ */ jsxs4(
|
|
1312
1389
|
Button,
|
|
1313
1390
|
{
|
|
@@ -1316,10 +1393,8 @@ function SidebarTrigger({
|
|
|
1316
1393
|
variant: "ghost",
|
|
1317
1394
|
size: "icon",
|
|
1318
1395
|
className: cn("size-7", className),
|
|
1319
|
-
onClick:
|
|
1320
|
-
|
|
1321
|
-
toggleSidebar();
|
|
1322
|
-
},
|
|
1396
|
+
onClick: handleActivation,
|
|
1397
|
+
onTouchEnd: handleActivation,
|
|
1323
1398
|
...props,
|
|
1324
1399
|
children: [
|
|
1325
1400
|
/* @__PURE__ */ jsx11(PanelLeftIcon, {}),
|