@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.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 remarkPluginsDefault = [remarkGfm];
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(void 0);
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 () => mql.removeEventListener("change", onChange);
1022
+ return () => {
1023
+ mql.removeEventListener("change", onChange);
1024
+ window.removeEventListener("resize", onChange);
1025
+ };
978
1026
  }, []);
979
- return !!isMobile;
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 hidden md:block",
1324
+ className: "group peer text-sidebar-foreground",
1260
1325
  "data-state": state,
1261
- "data-collapsible": state === "collapsed" ? 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 w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
1272
- "group-data-[collapsible=offcanvas]:w-0",
1273
- "group-data-[side=right]:rotate-180",
1274
- variant === "floating" || variant === "inset" ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
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 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
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 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
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: (event) => {
1320
- onClick?.(event);
1321
- toggleSidebar();
1322
- },
1396
+ onClick: handleActivation,
1397
+ onTouchEnd: handleActivation,
1323
1398
  ...props,
1324
1399
  children: [
1325
1400
  /* @__PURE__ */ jsx11(PanelLeftIcon, {}),