@invergent/agent-chat-react 2.8.2 → 2.8.5

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 CHANGED
@@ -553,20 +553,69 @@ function BrowserControlBar({
553
553
  )
554
554
  ] });
555
555
  }
556
+ function toWsUrl(src) {
557
+ const url = new URL(src, window.location.href);
558
+ if (url.protocol === "http:") {
559
+ url.protocol = "ws:";
560
+ } else if (url.protocol === "https:") {
561
+ url.protocol = "wss:";
562
+ }
563
+ return url.toString();
564
+ }
556
565
  function BrowserLiveView({
557
566
  src,
558
- testId = "browser-iframe"
567
+ testId = "browser-rfb",
568
+ onDisconnect
559
569
  }) {
560
- return /* @__PURE__ */ jsxRuntime.jsx(
561
- "iframe",
562
- {
563
- "data-testid": testId,
564
- title: "Browser live view",
565
- src,
566
- className: "h-full w-full border-0 bg-black",
567
- allow: "clipboard-read; clipboard-write"
568
- }
569
- );
570
+ const containerRef = react.useRef(null);
571
+ const onDisconnectRef = react.useRef(onDisconnect);
572
+ onDisconnectRef.current = onDisconnect;
573
+ const [state, setState] = react.useState("connecting");
574
+ react.useEffect(() => {
575
+ const container = containerRef.current;
576
+ if (!container) return;
577
+ setState("connecting");
578
+ let rfb;
579
+ let disposed = false;
580
+ const handleConnect = () => setState("connected");
581
+ const handleDisconnect = (event) => {
582
+ const detail = event.detail;
583
+ setState("disconnected");
584
+ onDisconnectRef.current?.(detail?.clean ?? false);
585
+ };
586
+ void import('@novnc/novnc').then((mod) => {
587
+ if (disposed || !containerRef.current) return;
588
+ const instance = new mod.default(containerRef.current, toWsUrl(src), {
589
+ wsProtocols: ["binary"]
590
+ });
591
+ instance.viewOnly = false;
592
+ instance.scaleViewport = true;
593
+ instance.addEventListener("connect", handleConnect);
594
+ instance.addEventListener("disconnect", handleDisconnect);
595
+ rfb = instance;
596
+ }).catch(() => {
597
+ if (!disposed) setState("disconnected");
598
+ });
599
+ return () => {
600
+ disposed = true;
601
+ if (rfb) {
602
+ rfb.removeEventListener("connect", handleConnect);
603
+ rfb.removeEventListener("disconnect", handleDisconnect);
604
+ rfb.disconnect();
605
+ }
606
+ };
607
+ }, [src]);
608
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative h-full w-full bg-black", children: [
609
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, "data-testid": testId, className: "h-full w-full" }),
610
+ state !== "connected" && /* @__PURE__ */ jsxRuntime.jsx(
611
+ "div",
612
+ {
613
+ "data-testid": "browser-rfb-overlay",
614
+ className: "pointer-events-none absolute inset-0 flex items-center justify-center bg-black/70 text-sm text-muted-foreground",
615
+ children: state === "connecting" ? "Connecting to browser\u2026" : "Live view disconnected \u2014 take control again to reconnect."
616
+ }
617
+ )
618
+ ] });
570
619
  }
571
620
 
572
621
  // src/components/browser/browser-status-dot.tsx
@@ -767,7 +816,13 @@ function BrowserPane({
767
816
  /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "bottom", children: "Full screen" })
768
817
  ] }) }) })
769
818
  ] }),
770
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 bg-black", children: state.status === "provisioning" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Starting browser..." }) : state.status === "closed" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Browser closed." }) : canUseLiveView ? /* @__PURE__ */ jsxRuntime.jsx(BrowserLiveView, { src: liveViewUrl }) : previewSnapshot ? /* @__PURE__ */ jsxRuntime.jsx(
819
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 bg-black", children: state.status === "provisioning" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Starting browser..." }) : state.status === "closed" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Browser closed." }) : canUseLiveView ? /* @__PURE__ */ jsxRuntime.jsx(
820
+ BrowserLiveView,
821
+ {
822
+ src: liveViewUrl,
823
+ onDisconnect: () => setLocalControlActive(false)
824
+ }
825
+ ) : previewSnapshot ? /* @__PURE__ */ jsxRuntime.jsx(
771
826
  BrowserPreviewImage,
772
827
  {
773
828
  src: previewSnapshot.src,
@@ -811,7 +866,8 @@ function BrowserPane({
811
866
  BrowserLiveView,
812
867
  {
813
868
  src: liveViewUrl,
814
- testId: "browser-fullscreen-iframe"
869
+ testId: "browser-fullscreen-rfb",
870
+ onDisconnect: () => setLocalControlActive(false)
815
871
  }
816
872
  ) : previewSnapshot ? /* @__PURE__ */ jsxRuntime.jsx(
817
873
  BrowserPreviewImage,
@@ -914,6 +970,39 @@ var ConversationScrollButton = ({
914
970
  );
915
971
  };
916
972
 
973
+ // src/components/ui/button-group.tsx
974
+ init_utils();
975
+ var buttonGroupVariants = classVarianceAuthority.cva(
976
+ "group/button-group flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 *:data-[slot=input]:px-4 has-[>[data-variant=outline]]:*:data-[slot=input-group]:border-border has-[>[data-variant=outline]]:*:data-[slot=input-group]:px-2.5 has-[>[data-variant=outline]]:*:data-[slot=select-trigger]:border-border has-[>[data-variant=outline]]:*:[[role=combobox]]:px-2.5 has-[>[data-variant=outline]]:[&>[data-slot=input-group]:has(:focus-visible)]:border-ring has-[>[data-variant=outline]]:[&>[data-slot=select-trigger]:focus-visible]:border-ring has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-none [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[>[data-variant=outline]]:[&>input]:border-border has-[>[data-variant=outline]]:[&>input:focus-visible]:border-ring",
977
+ {
978
+ variants: {
979
+ orientation: {
980
+ horizontal: "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-none!",
981
+ vertical: "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-none!"
982
+ }
983
+ },
984
+ defaultVariants: {
985
+ orientation: "horizontal"
986
+ }
987
+ }
988
+ );
989
+ function ButtonGroup({
990
+ className,
991
+ orientation,
992
+ ...props
993
+ }) {
994
+ return /* @__PURE__ */ jsxRuntime.jsx(
995
+ "div",
996
+ {
997
+ role: "group",
998
+ "data-slot": "button-group",
999
+ "data-orientation": orientation,
1000
+ className: cn(buttonGroupVariants({ orientation }), className),
1001
+ ...props
1002
+ }
1003
+ );
1004
+ }
1005
+
917
1006
  // src/components/ai-elements/message.tsx
918
1007
  init_utils();
919
1008
 
@@ -978,8 +1067,8 @@ var Message = ({ className, from, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
978
1067
  "div",
979
1068
  {
980
1069
  className: cn(
981
- "group flex w-full flex-col gap-2",
982
- from === "user" ? "is-user max-w-[85%]" : "is-assistant max-w-full",
1070
+ "group flex flex-col gap-2",
1071
+ from === "user" ? "is-user ml-auto max-w-[85%]" : "is-assistant max-w-full",
983
1072
  className
984
1073
  ),
985
1074
  ...props
@@ -5648,7 +5737,7 @@ var PromptInput = ({
5648
5737
  onSubmit: handleSubmit,
5649
5738
  ref: formRef,
5650
5739
  ...props,
5651
- children: /* @__PURE__ */ jsxRuntime.jsx(InputGroup, { className: "overflow-hidden rounded-3xl border border-input bg-white px-3 py-1 shadow-sm dark:bg-card dark:shadow-none dark:ring-1 dark:ring-white/5 has-[textarea]:rounded-3xl has-[>[data-align=block-end]]:rounded-3xl has-[>[data-align=block-start]]:rounded-3xl", children })
5740
+ children: /* @__PURE__ */ jsxRuntime.jsx(InputGroup, { className: "overflow-hidden rounded-3xl border border-input bg-white px-4 py-2 shadow-sm dark:bg-card dark:shadow-none dark:ring-1 dark:ring-white/5 has-[textarea]:rounded-3xl has-[>[data-align=block-end]]:rounded-3xl has-[>[data-align=block-start]]:rounded-3xl", children })
5652
5741
  }
5653
5742
  )
5654
5743
  ] });
@@ -5783,7 +5872,7 @@ var PromptInputButton = ({
5783
5872
  InputGroupButton,
5784
5873
  {
5785
5874
  className: cn(
5786
- "rounded-sm border border-input/70 text-foreground hover:bg-accent",
5875
+ "rounded-sm border border-input/70 text-foreground bg-accent",
5787
5876
  newSize === "icon-sm" && "size-9",
5788
5877
  className
5789
5878
  ),
@@ -5841,7 +5930,7 @@ var PromptInputSubmit = ({
5841
5930
  InputGroupButton,
5842
5931
  {
5843
5932
  "aria-label": isGenerating ? "Stop" : "Submit",
5844
- className: cn("rounded-full", className),
5933
+ className: cn("rounded-full bg-amber-400 hover:bg-amber-500 text-black", className),
5845
5934
  onClick: handleClick,
5846
5935
  size,
5847
5936
  type: isGenerating && onStop ? "button" : "submit",
@@ -7026,29 +7115,32 @@ function ChatComposerInner({
7026
7115
  ] }),
7027
7116
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7028
7117
  onViewModeChange && /* @__PURE__ */ jsxRuntime.jsxs(
7029
- "div",
7118
+ ButtonGroup,
7030
7119
  {
7031
- role: "group",
7032
7120
  "aria-label": "Chat view mode",
7033
- className: "inline-flex overflow-hidden rounded-md border border-border",
7121
+ className: "overflow-hidden rounded-md border border-border",
7034
7122
  children: [
7035
7123
  /* @__PURE__ */ jsxRuntime.jsx(
7036
- "button",
7124
+ Button,
7037
7125
  {
7038
7126
  type: "button",
7127
+ size: "xs",
7128
+ className: "capitalize font-normal",
7129
+ variant: viewMode === "simple" ? "secondary" : "ghost",
7039
7130
  "aria-pressed": viewMode === "simple",
7040
7131
  onClick: () => onViewModeChange("simple"),
7041
- className: viewMode === "simple" ? "bg-accent px-2 py-1 text-xs text-foreground" : "px-2 py-1 text-xs text-muted-foreground hover:text-foreground",
7042
7132
  children: "Simple"
7043
7133
  }
7044
7134
  ),
7045
7135
  /* @__PURE__ */ jsxRuntime.jsx(
7046
- "button",
7136
+ Button,
7047
7137
  {
7048
7138
  type: "button",
7139
+ size: "xs",
7140
+ className: "capitalize font-normal",
7141
+ variant: viewMode === "expert" ? "secondary" : "ghost",
7049
7142
  "aria-pressed": viewMode === "expert",
7050
7143
  onClick: () => onViewModeChange("expert"),
7051
- className: viewMode === "expert" ? "bg-accent px-2 py-1 text-xs text-foreground" : "px-2 py-1 text-xs text-muted-foreground hover:text-foreground",
7052
7144
  children: "Advanced"
7053
7145
  }
7054
7146
  )
@@ -7060,7 +7152,7 @@ function ChatComposerInner({
7060
7152
  {
7061
7153
  status,
7062
7154
  onStop,
7063
- className: "md:size-8"
7155
+ className: "size-10"
7064
7156
  }
7065
7157
  )
7066
7158
  ] })