@agent-native/toolkit 0.21.2 → 0.21.3-nightly-20260926043001

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.
@@ -1 +1 @@
1
- {"version":3,"file":"AgentComposerFrame.d.ts","sourceRoot":"","sources":["../../src/composer/AgentComposerFrame.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,kFAAkF;IAClF,iBAAiB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,SAAS,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAChC,aAAa,CAAC,EAAE,0BAA0B,CAAC;IAC3C,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;CACnD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,KAAK,EACL,SAAS,EACT,aAAyB,EACzB,OAAO,GACR,EAAE,uBAAuB,qBAgDzB"}
1
+ {"version":3,"file":"AgentComposerFrame.d.ts","sourceRoot":"","sources":["../../src/composer/AgentComposerFrame.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,kFAAkF;IAClF,iBAAiB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,SAAS,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAChC,aAAa,CAAC,EAAE,0BAA0B,CAAC;IAC3C,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;CACnD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,KAAK,EACL,SAAS,EACT,aAAyB,EACzB,OAAO,GACR,EAAE,uBAAuB,qBA+IzB"}
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ComposerPrimitive } from "@assistant-ui/react";
3
+ import { useEffect, useRef } from "react";
3
4
  import { cn } from "../utils.js";
4
5
  /**
5
6
  * The single visual shell for agent chat composition.
@@ -8,7 +9,90 @@ import { cn } from "../utils.js";
8
9
  * all render this same frame so the composer does not drift across products.
9
10
  */
10
11
  export function AgentComposerFrame({ children, attachedAccessory, className, workflowClassName, rootClassName, style, rootStyle, layoutVariant = "default", onClick, }) {
11
- const frame = (_jsx("div", { "data-agent-composer-variant": layoutVariant, "data-agent-composer-slot": "area", className: cn("agent-composer-area min-w-0 shrink-0 py-2", attachedAccessory != null && "relative z-10",
12
+ const frameRef = useRef(null);
13
+ useEffect(() => {
14
+ const frame = frameRef.current;
15
+ if (!frame)
16
+ return;
17
+ const shell = frame.closest(".agent-layout-shell, .agent-sidebar-shell");
18
+ const viewport = window.visualViewport;
19
+ if (!shell || !viewport)
20
+ return;
21
+ const activeShell = shell;
22
+ const activeViewport = viewport;
23
+ const viewportHeightProperty = "--agent-native-viewport-height";
24
+ const originalHeight = activeShell.style.getPropertyValue(viewportHeightProperty);
25
+ const originalPriority = activeShell.style.getPropertyPriority(viewportHeightProperty);
26
+ let keyboardViewportActive = false;
27
+ let listening = false;
28
+ let mounted = true;
29
+ const restoreHeight = () => {
30
+ if (originalHeight) {
31
+ activeShell.style.setProperty(viewportHeightProperty, originalHeight, originalPriority);
32
+ }
33
+ else {
34
+ activeShell.style.removeProperty(viewportHeightProperty);
35
+ }
36
+ };
37
+ const isEditor = (element) => element !== null &&
38
+ frame.contains(element) &&
39
+ element.closest('[contenteditable="true"]') !== null;
40
+ const stopListening = () => {
41
+ if (!listening)
42
+ return;
43
+ listening = false;
44
+ activeViewport.removeEventListener("resize", update);
45
+ window.removeEventListener("resize", update);
46
+ };
47
+ function update() {
48
+ if (!mounted)
49
+ return;
50
+ const height = `${activeViewport.height}px`;
51
+ const viewportShrunk = activeViewport.height + 1 < window.innerHeight;
52
+ if (isEditor(document.activeElement)) {
53
+ keyboardViewportActive = viewportShrunk;
54
+ if (viewportShrunk) {
55
+ activeShell.style.setProperty(viewportHeightProperty, height);
56
+ }
57
+ else {
58
+ restoreHeight();
59
+ }
60
+ return;
61
+ }
62
+ if (keyboardViewportActive && viewportShrunk) {
63
+ activeShell.style.setProperty(viewportHeightProperty, height);
64
+ return;
65
+ }
66
+ keyboardViewportActive = false;
67
+ restoreHeight();
68
+ stopListening();
69
+ }
70
+ const onFocusIn = (event) => {
71
+ if (!isEditor(event.target instanceof Element ? event.target : null))
72
+ return;
73
+ if (!listening) {
74
+ listening = true;
75
+ activeViewport.addEventListener("resize", update, { passive: true });
76
+ window.addEventListener("resize", update, { passive: true });
77
+ }
78
+ update();
79
+ };
80
+ const onFocusOut = (event) => {
81
+ if (!isEditor(event.target instanceof Element ? event.target : null))
82
+ return;
83
+ queueMicrotask(update);
84
+ };
85
+ frame.addEventListener("focusin", onFocusIn);
86
+ frame.addEventListener("focusout", onFocusOut);
87
+ return () => {
88
+ mounted = false;
89
+ frame.removeEventListener("focusin", onFocusIn);
90
+ frame.removeEventListener("focusout", onFocusOut);
91
+ stopListening();
92
+ restoreHeight();
93
+ };
94
+ }, []);
95
+ const frame = (_jsx("div", { ref: frameRef, "data-agent-composer-variant": layoutVariant, "data-agent-composer-slot": "area", className: cn("agent-composer-area min-w-0 shrink-0 py-2", attachedAccessory != null && "relative z-10",
12
96
  // Compact composers are nested in padded popovers; the default sidebar
13
97
  // frame is the only layout that needs its own horizontal inset.
14
98
  layoutVariant === "compact" ? "px-0" : "px-3", layoutVariant !== "default" && `agent-composer-area--${layoutVariant}`, className), style: style, onClick: onClick, children: _jsx(ComposerPrimitive.Root, { "data-agent-composer-variant": layoutVariant, "data-agent-composer-slot": "root", className: cn("agent-composer-root flex min-w-0 flex-col rounded-lg border border-input transition-colors", layoutVariant !== "default" &&
@@ -1 +1 @@
1
- {"version":3,"file":"AgentComposerFrame.js","sourceRoot":"","sources":["../../src/composer/AgentComposerFrame.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAgBjC;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,KAAK,EACL,SAAS,EACT,aAAa,GAAG,SAAS,EACzB,OAAO,GACiB;IACxB,MAAM,KAAK,GAAG,CACZ,6CAC+B,aAAa,8BACjB,MAAM,EAC/B,SAAS,EAAE,EAAE,CACX,2CAA2C,EAC3C,iBAAiB,IAAI,IAAI,IAAI,eAAe;QAC5C,uEAAuE;QACvE,gEAAgE;QAChE,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAC7C,aAAa,KAAK,SAAS,IAAI,wBAAwB,aAAa,EAAE,EACtE,SAAS,CACV,EACD,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,YAEhB,KAAC,iBAAiB,CAAC,IAAI,mCACQ,aAAa,8BACjB,MAAM,EAC/B,SAAS,EAAE,EAAE,CACX,4FAA4F,EAC5F,aAAa,KAAK,SAAS;gBACzB,wBAAwB,aAAa,EAAE,EACzC,aAAa,CACd,EACD,KAAK,EAAE,SAAS,YAEf,QAAQ,GACc,GACrB,CACP,CAAC;IAEF,IAAI,iBAAiB,IAAI,IAAI;QAAE,OAAO,KAAK,CAAC;IAE5C,OAAO,CACL,2CAC2B,UAAU,kCACN,MAAM,EACnC,SAAS,EAAE,EAAE,CACX,uDAAuD,EACvD,iBAAiB,CAClB,aAEA,iBAAiB,EACjB,KAAK,IACF,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"AgentComposerFrame.js","sourceRoot":"","sources":["../../src/composer/AgentComposerFrame.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=AgentComposerFrame.viewport.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentComposerFrame.viewport.spec.d.ts","sourceRoot":"","sources":["../../src/composer/AgentComposerFrame.viewport.spec.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,89 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // @vitest-environment happy-dom
3
+ import { act } from "react";
4
+ import { createRoot } from "react-dom/client";
5
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
6
+ vi.mock("@assistant-ui/react", () => ({
7
+ ComposerPrimitive: {
8
+ Root: ({ children, ...props }) => (_jsx("div", { ...props, children: children })),
9
+ },
10
+ }));
11
+ import { AgentComposerFrame } from "./AgentComposerFrame.js";
12
+ let container;
13
+ let root;
14
+ let viewportHeight;
15
+ let viewport;
16
+ let originalViewport;
17
+ let originalInnerHeight;
18
+ beforeEach(() => {
19
+ container = document.createElement("div");
20
+ document.body.appendChild(container);
21
+ root = createRoot(container);
22
+ viewportHeight = 800;
23
+ viewport = new EventTarget();
24
+ Object.defineProperty(viewport, "height", { get: () => viewportHeight });
25
+ originalViewport = Object.getOwnPropertyDescriptor(window, "visualViewport");
26
+ originalInnerHeight = Object.getOwnPropertyDescriptor(window, "innerHeight");
27
+ Object.defineProperty(window, "visualViewport", {
28
+ configurable: true,
29
+ value: viewport,
30
+ });
31
+ Object.defineProperty(window, "innerHeight", {
32
+ configurable: true,
33
+ value: 800,
34
+ });
35
+ });
36
+ afterEach(() => {
37
+ act(() => root.unmount());
38
+ container.remove();
39
+ if (originalViewport) {
40
+ Object.defineProperty(window, "visualViewport", originalViewport);
41
+ }
42
+ else {
43
+ Object.defineProperty(window, "visualViewport", {
44
+ configurable: true,
45
+ value: null,
46
+ });
47
+ }
48
+ if (originalInnerHeight) {
49
+ Object.defineProperty(window, "innerHeight", originalInnerHeight);
50
+ }
51
+ });
52
+ describe("AgentComposerFrame visual viewport sizing", () => {
53
+ it("keeps a focused composer above the keyboard and restores the shell height", async () => {
54
+ await act(async () => {
55
+ root.render(_jsx("div", { className: "agent-layout-shell", style: {
56
+ "--agent-native-viewport-height": "100%",
57
+ }, children: _jsx(AgentComposerFrame, { children: _jsx("div", { contentEditable: "true", "aria-label": "Message agent" }) }) }));
58
+ });
59
+ const shell = container.querySelector(".agent-layout-shell");
60
+ const editor = container.querySelector('[contenteditable="true"]');
61
+ await act(async () => editor.focus());
62
+ expect(shell.style.getPropertyValue("--agent-native-viewport-height")).toBe("100%");
63
+ await act(async () => {
64
+ viewportHeight = 360;
65
+ viewport.dispatchEvent(new Event("resize"));
66
+ });
67
+ expect(shell.style.getPropertyValue("--agent-native-viewport-height")).toBe("360px");
68
+ await act(async () => {
69
+ editor.blur();
70
+ await Promise.resolve();
71
+ });
72
+ expect(shell.style.getPropertyValue("--agent-native-viewport-height")).toBe("360px");
73
+ await act(async () => {
74
+ viewportHeight = 800;
75
+ viewport.dispatchEvent(new Event("resize"));
76
+ });
77
+ expect(shell.style.getPropertyValue("--agent-native-viewport-height")).toBe("100%");
78
+ });
79
+ it("does not resize the shell when focus stays outside the composer editor", async () => {
80
+ await act(async () => {
81
+ root.render(_jsx("div", { className: "agent-sidebar-shell", children: _jsx(AgentComposerFrame, { children: _jsx("button", { type: "button", children: "Attach" }) }) }));
82
+ });
83
+ const shell = container.querySelector(".agent-sidebar-shell");
84
+ const button = container.querySelector("button");
85
+ await act(async () => button.focus());
86
+ expect(shell.style.getPropertyValue("--agent-native-viewport-height")).toBe("");
87
+ });
88
+ });
89
+ //# sourceMappingURL=AgentComposerFrame.viewport.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentComposerFrame.viewport.spec.js","sourceRoot":"","sources":["../../src/composer/AgentComposerFrame.viewport.spec.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/toolkit",
3
- "version": "0.21.2",
3
+ "version": "0.21.3-nightly-20260926043001",
4
4
  "description": "Reusable app-building UI and helpers for Agent-Native apps.",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -1,4 +1,5 @@
1
1
  import { ComposerPrimitive } from "@assistant-ui/react";
2
+ import { useEffect, useRef } from "react";
2
3
  import type React from "react";
3
4
 
4
5
  import { cn } from "../utils.js";
@@ -34,8 +35,103 @@ export function AgentComposerFrame({
34
35
  layoutVariant = "default",
35
36
  onClick,
36
37
  }: AgentComposerFrameProps) {
38
+ const frameRef = useRef<HTMLDivElement>(null);
39
+
40
+ useEffect(() => {
41
+ const frame = frameRef.current;
42
+ if (!frame) return;
43
+
44
+ const shell = frame.closest<HTMLElement>(
45
+ ".agent-layout-shell, .agent-sidebar-shell",
46
+ );
47
+ const viewport = window.visualViewport;
48
+ if (!shell || !viewport) return;
49
+ const activeShell = shell;
50
+ const activeViewport = viewport;
51
+
52
+ const viewportHeightProperty = "--agent-native-viewport-height";
53
+ const originalHeight = activeShell.style.getPropertyValue(
54
+ viewportHeightProperty,
55
+ );
56
+ const originalPriority = activeShell.style.getPropertyPriority(
57
+ viewportHeightProperty,
58
+ );
59
+ let keyboardViewportActive = false;
60
+ let listening = false;
61
+ let mounted = true;
62
+
63
+ const restoreHeight = () => {
64
+ if (originalHeight) {
65
+ activeShell.style.setProperty(
66
+ viewportHeightProperty,
67
+ originalHeight,
68
+ originalPriority,
69
+ );
70
+ } else {
71
+ activeShell.style.removeProperty(viewportHeightProperty);
72
+ }
73
+ };
74
+ const isEditor = (element: Element | null) =>
75
+ element !== null &&
76
+ frame.contains(element) &&
77
+ element.closest('[contenteditable="true"]') !== null;
78
+ const stopListening = () => {
79
+ if (!listening) return;
80
+ listening = false;
81
+ activeViewport.removeEventListener("resize", update);
82
+ window.removeEventListener("resize", update);
83
+ };
84
+ function update() {
85
+ if (!mounted) return;
86
+ const height = `${activeViewport.height}px`;
87
+ const viewportShrunk = activeViewport.height + 1 < window.innerHeight;
88
+ if (isEditor(document.activeElement)) {
89
+ keyboardViewportActive = viewportShrunk;
90
+ if (viewportShrunk) {
91
+ activeShell.style.setProperty(viewportHeightProperty, height);
92
+ } else {
93
+ restoreHeight();
94
+ }
95
+ return;
96
+ }
97
+ if (keyboardViewportActive && viewportShrunk) {
98
+ activeShell.style.setProperty(viewportHeightProperty, height);
99
+ return;
100
+ }
101
+ keyboardViewportActive = false;
102
+ restoreHeight();
103
+ stopListening();
104
+ }
105
+ const onFocusIn = (event: FocusEvent) => {
106
+ if (!isEditor(event.target instanceof Element ? event.target : null))
107
+ return;
108
+ if (!listening) {
109
+ listening = true;
110
+ activeViewport.addEventListener("resize", update, { passive: true });
111
+ window.addEventListener("resize", update, { passive: true });
112
+ }
113
+ update();
114
+ };
115
+ const onFocusOut = (event: FocusEvent) => {
116
+ if (!isEditor(event.target instanceof Element ? event.target : null))
117
+ return;
118
+ queueMicrotask(update);
119
+ };
120
+
121
+ frame.addEventListener("focusin", onFocusIn);
122
+ frame.addEventListener("focusout", onFocusOut);
123
+ return () => {
124
+ mounted = false;
125
+ frame.removeEventListener("focusin", onFocusIn);
126
+ frame.removeEventListener("focusout", onFocusOut);
127
+ stopListening();
128
+ restoreHeight();
129
+ };
130
+ }, []);
131
+
37
132
  const frame = (
38
133
  <div
134
+ ref={frameRef}
39
135
  data-agent-composer-variant={layoutVariant}
40
136
  data-agent-composer-slot="area"
41
137
  className={cn(
@@ -0,0 +1,132 @@
1
+ // @vitest-environment happy-dom
2
+
3
+ import React, { act } from "react";
4
+ import { createRoot, type Root } from "react-dom/client";
5
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
6
+
7
+ vi.mock("@assistant-ui/react", () => ({
8
+ ComposerPrimitive: {
9
+ Root: ({ children, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
10
+ <div {...props}>{children}</div>
11
+ ),
12
+ },
13
+ }));
14
+
15
+ import { AgentComposerFrame } from "./AgentComposerFrame.js";
16
+
17
+ let container: HTMLDivElement;
18
+ let root: Root;
19
+ let viewportHeight: number;
20
+ let viewport: EventTarget;
21
+ let originalViewport: PropertyDescriptor | undefined;
22
+ let originalInnerHeight: PropertyDescriptor | undefined;
23
+
24
+ beforeEach(() => {
25
+ container = document.createElement("div");
26
+ document.body.appendChild(container);
27
+ root = createRoot(container);
28
+ viewportHeight = 800;
29
+ viewport = new EventTarget();
30
+ Object.defineProperty(viewport, "height", { get: () => viewportHeight });
31
+ originalViewport = Object.getOwnPropertyDescriptor(window, "visualViewport");
32
+ originalInnerHeight = Object.getOwnPropertyDescriptor(window, "innerHeight");
33
+ Object.defineProperty(window, "visualViewport", {
34
+ configurable: true,
35
+ value: viewport,
36
+ });
37
+ Object.defineProperty(window, "innerHeight", {
38
+ configurable: true,
39
+ value: 800,
40
+ });
41
+ });
42
+
43
+ afterEach(() => {
44
+ act(() => root.unmount());
45
+ container.remove();
46
+ if (originalViewport) {
47
+ Object.defineProperty(window, "visualViewport", originalViewport);
48
+ } else {
49
+ Object.defineProperty(window, "visualViewport", {
50
+ configurable: true,
51
+ value: null,
52
+ });
53
+ }
54
+ if (originalInnerHeight) {
55
+ Object.defineProperty(window, "innerHeight", originalInnerHeight);
56
+ }
57
+ });
58
+
59
+ describe("AgentComposerFrame visual viewport sizing", () => {
60
+ it("keeps a focused composer above the keyboard and restores the shell height", async () => {
61
+ await act(async () => {
62
+ root.render(
63
+ <div
64
+ className="agent-layout-shell"
65
+ style={
66
+ {
67
+ "--agent-native-viewport-height": "100%",
68
+ } as React.CSSProperties
69
+ }
70
+ >
71
+ <AgentComposerFrame>
72
+ <div contentEditable="true" aria-label="Message agent" />
73
+ </AgentComposerFrame>
74
+ </div>,
75
+ );
76
+ });
77
+
78
+ const shell = container.querySelector<HTMLElement>(".agent-layout-shell")!;
79
+ const editor = container.querySelector<HTMLElement>(
80
+ '[contenteditable="true"]',
81
+ )!;
82
+ await act(async () => editor.focus());
83
+ expect(shell.style.getPropertyValue("--agent-native-viewport-height")).toBe(
84
+ "100%",
85
+ );
86
+
87
+ await act(async () => {
88
+ viewportHeight = 360;
89
+ viewport.dispatchEvent(new Event("resize"));
90
+ });
91
+
92
+ expect(shell.style.getPropertyValue("--agent-native-viewport-height")).toBe(
93
+ "360px",
94
+ );
95
+
96
+ await act(async () => {
97
+ editor.blur();
98
+ await Promise.resolve();
99
+ });
100
+ expect(shell.style.getPropertyValue("--agent-native-viewport-height")).toBe(
101
+ "360px",
102
+ );
103
+
104
+ await act(async () => {
105
+ viewportHeight = 800;
106
+ viewport.dispatchEvent(new Event("resize"));
107
+ });
108
+ expect(shell.style.getPropertyValue("--agent-native-viewport-height")).toBe(
109
+ "100%",
110
+ );
111
+ });
112
+
113
+ it("does not resize the shell when focus stays outside the composer editor", async () => {
114
+ await act(async () => {
115
+ root.render(
116
+ <div className="agent-sidebar-shell">
117
+ <AgentComposerFrame>
118
+ <button type="button">Attach</button>
119
+ </AgentComposerFrame>
120
+ </div>,
121
+ );
122
+ });
123
+
124
+ const shell = container.querySelector<HTMLElement>(".agent-sidebar-shell")!;
125
+ const button = container.querySelector<HTMLButtonElement>("button")!;
126
+ await act(async () => button.focus());
127
+
128
+ expect(shell.style.getPropertyValue("--agent-native-viewport-height")).toBe(
129
+ "",
130
+ );
131
+ });
132
+ });