@invergent/agent-chat-react 2.8.2 → 2.8.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
@@ -364,20 +364,69 @@ function BrowserControlBar({
364
364
  )
365
365
  ] });
366
366
  }
367
+ function toWsUrl(src) {
368
+ const url = new URL(src, window.location.href);
369
+ if (url.protocol === "http:") {
370
+ url.protocol = "ws:";
371
+ } else if (url.protocol === "https:") {
372
+ url.protocol = "wss:";
373
+ }
374
+ return url.toString();
375
+ }
367
376
  function BrowserLiveView({
368
377
  src,
369
- testId = "browser-iframe"
378
+ testId = "browser-rfb",
379
+ onDisconnect
370
380
  }) {
371
- return /* @__PURE__ */ jsx(
372
- "iframe",
373
- {
374
- "data-testid": testId,
375
- title: "Browser live view",
376
- src,
377
- className: "h-full w-full border-0 bg-black",
378
- allow: "clipboard-read; clipboard-write"
379
- }
380
- );
381
+ const containerRef = useRef(null);
382
+ const onDisconnectRef = useRef(onDisconnect);
383
+ onDisconnectRef.current = onDisconnect;
384
+ const [state, setState] = useState("connecting");
385
+ useEffect(() => {
386
+ const container = containerRef.current;
387
+ if (!container) return;
388
+ setState("connecting");
389
+ let rfb;
390
+ let disposed = false;
391
+ const handleConnect = () => setState("connected");
392
+ const handleDisconnect = (event) => {
393
+ const detail = event.detail;
394
+ setState("disconnected");
395
+ onDisconnectRef.current?.(detail?.clean ?? false);
396
+ };
397
+ void import('@novnc/novnc').then((mod) => {
398
+ if (disposed || !containerRef.current) return;
399
+ const instance = new mod.default(containerRef.current, toWsUrl(src), {
400
+ wsProtocols: ["binary"]
401
+ });
402
+ instance.viewOnly = false;
403
+ instance.scaleViewport = true;
404
+ instance.addEventListener("connect", handleConnect);
405
+ instance.addEventListener("disconnect", handleDisconnect);
406
+ rfb = instance;
407
+ }).catch(() => {
408
+ if (!disposed) setState("disconnected");
409
+ });
410
+ return () => {
411
+ disposed = true;
412
+ if (rfb) {
413
+ rfb.removeEventListener("connect", handleConnect);
414
+ rfb.removeEventListener("disconnect", handleDisconnect);
415
+ rfb.disconnect();
416
+ }
417
+ };
418
+ }, [src]);
419
+ return /* @__PURE__ */ jsxs("div", { className: "relative h-full w-full bg-black", children: [
420
+ /* @__PURE__ */ jsx("div", { ref: containerRef, "data-testid": testId, className: "h-full w-full" }),
421
+ state !== "connected" && /* @__PURE__ */ jsx(
422
+ "div",
423
+ {
424
+ "data-testid": "browser-rfb-overlay",
425
+ className: "pointer-events-none absolute inset-0 flex items-center justify-center bg-black/70 text-sm text-muted-foreground",
426
+ children: state === "connecting" ? "Connecting to browser\u2026" : "Live view disconnected \u2014 take control again to reconnect."
427
+ }
428
+ )
429
+ ] });
381
430
  }
382
431
  function BrowserStatusDot({
383
432
  status
@@ -572,7 +621,13 @@ function BrowserPane({
572
621
  /* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: "Full screen" })
573
622
  ] }) }) })
574
623
  ] }),
575
- /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 bg-black", children: state.status === "provisioning" ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Starting browser..." }) : state.status === "closed" ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Browser closed." }) : canUseLiveView ? /* @__PURE__ */ jsx(BrowserLiveView, { src: liveViewUrl }) : previewSnapshot ? /* @__PURE__ */ jsx(
624
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 bg-black", children: state.status === "provisioning" ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Starting browser..." }) : state.status === "closed" ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Browser closed." }) : canUseLiveView ? /* @__PURE__ */ jsx(
625
+ BrowserLiveView,
626
+ {
627
+ src: liveViewUrl,
628
+ onDisconnect: () => setLocalControlActive(false)
629
+ }
630
+ ) : previewSnapshot ? /* @__PURE__ */ jsx(
576
631
  BrowserPreviewImage,
577
632
  {
578
633
  src: previewSnapshot.src,
@@ -616,7 +671,8 @@ function BrowserPane({
616
671
  BrowserLiveView,
617
672
  {
618
673
  src: liveViewUrl,
619
- testId: "browser-fullscreen-iframe"
674
+ testId: "browser-fullscreen-rfb",
675
+ onDisconnect: () => setLocalControlActive(false)
620
676
  }
621
677
  ) : previewSnapshot ? /* @__PURE__ */ jsx(
622
678
  BrowserPreviewImage,
@@ -715,6 +771,36 @@ var ConversationScrollButton = ({
715
771
  }
716
772
  );
717
773
  };
774
+ var buttonGroupVariants = cva(
775
+ "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",
776
+ {
777
+ variants: {
778
+ orientation: {
779
+ 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!",
780
+ 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!"
781
+ }
782
+ },
783
+ defaultVariants: {
784
+ orientation: "horizontal"
785
+ }
786
+ }
787
+ );
788
+ function ButtonGroup({
789
+ className,
790
+ orientation,
791
+ ...props
792
+ }) {
793
+ return /* @__PURE__ */ jsx(
794
+ "div",
795
+ {
796
+ role: "group",
797
+ "data-slot": "button-group",
798
+ "data-orientation": orientation,
799
+ className: cn(buttonGroupVariants({ orientation }), className),
800
+ ...props
801
+ }
802
+ );
803
+ }
718
804
 
719
805
  // src/lib/oauth-popup.ts
720
806
  function openOAuthPopup(url) {
@@ -777,8 +863,8 @@ var Message = ({ className, from, ...props }) => /* @__PURE__ */ jsx(
777
863
  "div",
778
864
  {
779
865
  className: cn(
780
- "group flex w-full flex-col gap-2",
781
- from === "user" ? "is-user max-w-[85%]" : "is-assistant max-w-full",
866
+ "group flex flex-col gap-2",
867
+ from === "user" ? "is-user ml-auto max-w-[85%]" : "is-assistant max-w-full",
782
868
  className
783
869
  ),
784
870
  ...props
@@ -5377,7 +5463,7 @@ var PromptInput = ({
5377
5463
  onSubmit: handleSubmit,
5378
5464
  ref: formRef,
5379
5465
  ...props,
5380
- children: /* @__PURE__ */ 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 })
5466
+ children: /* @__PURE__ */ 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 })
5381
5467
  }
5382
5468
  )
5383
5469
  ] });
@@ -5512,7 +5598,7 @@ var PromptInputButton = ({
5512
5598
  InputGroupButton,
5513
5599
  {
5514
5600
  className: cn(
5515
- "rounded-sm border border-input/70 text-foreground hover:bg-accent",
5601
+ "rounded-sm border border-input/70 text-foreground bg-accent",
5516
5602
  newSize === "icon-sm" && "size-9",
5517
5603
  className
5518
5604
  ),
@@ -5570,7 +5656,7 @@ var PromptInputSubmit = ({
5570
5656
  InputGroupButton,
5571
5657
  {
5572
5658
  "aria-label": isGenerating ? "Stop" : "Submit",
5573
- className: cn("rounded-full", className),
5659
+ className: cn("rounded-full bg-amber-400 hover:bg-amber-500 text-black", className),
5574
5660
  onClick: handleClick,
5575
5661
  size,
5576
5662
  type: isGenerating && onStop ? "button" : "submit",
@@ -6740,29 +6826,32 @@ function ChatComposerInner({
6740
6826
  ] }),
6741
6827
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6742
6828
  onViewModeChange && /* @__PURE__ */ jsxs(
6743
- "div",
6829
+ ButtonGroup,
6744
6830
  {
6745
- role: "group",
6746
6831
  "aria-label": "Chat view mode",
6747
- className: "inline-flex overflow-hidden rounded-md border border-border",
6832
+ className: "overflow-hidden rounded-md border border-border",
6748
6833
  children: [
6749
6834
  /* @__PURE__ */ jsx(
6750
- "button",
6835
+ Button,
6751
6836
  {
6752
6837
  type: "button",
6838
+ size: "xs",
6839
+ className: "capitalize font-normal",
6840
+ variant: viewMode === "simple" ? "secondary" : "ghost",
6753
6841
  "aria-pressed": viewMode === "simple",
6754
6842
  onClick: () => onViewModeChange("simple"),
6755
- 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",
6756
6843
  children: "Simple"
6757
6844
  }
6758
6845
  ),
6759
6846
  /* @__PURE__ */ jsx(
6760
- "button",
6847
+ Button,
6761
6848
  {
6762
6849
  type: "button",
6850
+ size: "xs",
6851
+ className: "capitalize font-normal",
6852
+ variant: viewMode === "expert" ? "secondary" : "ghost",
6763
6853
  "aria-pressed": viewMode === "expert",
6764
6854
  onClick: () => onViewModeChange("expert"),
6765
- 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",
6766
6855
  children: "Advanced"
6767
6856
  }
6768
6857
  )
@@ -6774,7 +6863,7 @@ function ChatComposerInner({
6774
6863
  {
6775
6864
  status,
6776
6865
  onStop,
6777
- className: "md:size-8"
6866
+ className: "size-10"
6778
6867
  }
6779
6868
  )
6780
6869
  ] })