@agentiffai/design 0.1.10 → 0.1.12

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,5 +1,6 @@
1
- export { A as Action, c as ActionVariant, d as Actions, a as ActionsLayout, b as ActionsProps, f as AgentState, e as AgentStateProps, q as AssistantMessage, m as AssistantMessageProps, i as Button, B as ButtonProps, g as ButtonSize, h as ButtonVariant, r as FileAttachment, n as FileAttachmentProps, j as Footer, F as FooterProps, k as Header, H as HeaderProps, l as Input, I as InputProps, M as Message, s as Messages, t as MessagesList, u as MessagesListContainer, v as MessagesListContent, o as MessagesListProps, p as MessagesProps, x as Response, R as ResponseProps, y as StreamErrorMessage, S as StreamErrorMessageProps, E as StreamStatusIndicator, D as StreamStatusIndicatorProps, C as StreamingText, z as StreamingTextProps, J as Suggestions, G as SuggestionsProps, w as UserMessage, U as UserMessageProps, K as Window, W as WindowProps } from '../Window-CF5y1_Og.cjs';
1
+ export { A as Action, c as ActionVariant, d as Actions, a as ActionsLayout, b as ActionsProps, f as AgentState, e as AgentStateProps, q as AssistantMessage, m as AssistantMessageProps, i as Button, B as ButtonProps, g as ButtonSize, h as ButtonVariant, r as FileAttachment, n as FileAttachmentProps, j as Footer, F as FooterProps, k as Header, H as HeaderProps, l as Input, I as InputProps, M as Message, s as Messages, t as MessagesList, u as MessagesListContainer, v as MessagesListContent, o as MessagesListProps, p as MessagesProps, x as Response, R as ResponseProps, y as StreamErrorMessage, S as StreamErrorMessageProps, E as StreamStatusIndicator, D as StreamStatusIndicatorProps, C as StreamingText, z as StreamingTextProps, J as Suggestions, G as SuggestionsProps, w as UserMessage, U as UserMessageProps, K as Window, W as WindowProps } from '../Window-BcTRumpc.cjs';
2
2
  import { RenderMessageProps, AssistantMessageProps, InputProps, UserMessageProps } from '@copilotkit/react-ui';
3
+ import * as React from 'react';
3
4
  import React__default, { ReactNode } from 'react';
4
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
6
  import '@react-aria/button';
@@ -25,19 +26,7 @@ import 'styled-components/dist/types';
25
26
  */
26
27
  declare const ActionExecutionAdapter: React__default.FC<RenderMessageProps>;
27
28
 
28
- /**
29
- * Adapter component that bridges custom AssistantMessage with CopilotKit's expected interface
30
- *
31
- * This adapter:
32
- * 1. Converts CopilotKit's AssistantMessageProps to our custom component props
33
- * 2. Handles loading states by showing AssistantThinking component
34
- * 3. Extracts message content and renders with our styled component
35
- */
36
-
37
- /**
38
- * Adapter that converts CopilotKit's AssistantMessageProps to our custom component
39
- */
40
- declare const AssistantMessageAdapter: React__default.FC<AssistantMessageProps>;
29
+ declare const AssistantMessageAdapter: React.NamedExoticComponent<AssistantMessageProps>;
41
30
 
42
31
  /**
43
32
  * Adapter component that bridges custom Input with CopilotKit's expected interface
@@ -53,19 +42,7 @@ declare const AssistantMessageAdapter: React__default.FC<AssistantMessageProps>;
53
42
  */
54
43
  declare const InputAdapter: React__default.FC<InputProps>;
55
44
 
56
- /**
57
- * Adapter component that bridges custom UserMessage with CopilotKit's expected interface
58
- *
59
- * This adapter:
60
- * 1. Converts CopilotKit's UserMessageProps to our custom component props
61
- * 2. Extracts message content from CopilotKit's message object
62
- * 3. Handles image messages appropriately
63
- */
64
-
65
- /**
66
- * Adapter that converts CopilotKit's UserMessageProps to our custom component
67
- */
68
- declare const UserMessageAdapter: React__default.FC<UserMessageProps>;
45
+ declare const UserMessageAdapter: React.NamedExoticComponent<UserMessageProps>;
69
46
 
70
47
  /**
71
48
  * Complete CopilotSidebar Integration Example
@@ -1,5 +1,6 @@
1
- export { A as Action, c as ActionVariant, d as Actions, a as ActionsLayout, b as ActionsProps, f as AgentState, e as AgentStateProps, q as AssistantMessage, m as AssistantMessageProps, i as Button, B as ButtonProps, g as ButtonSize, h as ButtonVariant, r as FileAttachment, n as FileAttachmentProps, j as Footer, F as FooterProps, k as Header, H as HeaderProps, l as Input, I as InputProps, M as Message, s as Messages, t as MessagesList, u as MessagesListContainer, v as MessagesListContent, o as MessagesListProps, p as MessagesProps, x as Response, R as ResponseProps, y as StreamErrorMessage, S as StreamErrorMessageProps, E as StreamStatusIndicator, D as StreamStatusIndicatorProps, C as StreamingText, z as StreamingTextProps, J as Suggestions, G as SuggestionsProps, w as UserMessage, U as UserMessageProps, K as Window, W as WindowProps } from '../Window-CF5y1_Og.js';
1
+ export { A as Action, c as ActionVariant, d as Actions, a as ActionsLayout, b as ActionsProps, f as AgentState, e as AgentStateProps, q as AssistantMessage, m as AssistantMessageProps, i as Button, B as ButtonProps, g as ButtonSize, h as ButtonVariant, r as FileAttachment, n as FileAttachmentProps, j as Footer, F as FooterProps, k as Header, H as HeaderProps, l as Input, I as InputProps, M as Message, s as Messages, t as MessagesList, u as MessagesListContainer, v as MessagesListContent, o as MessagesListProps, p as MessagesProps, x as Response, R as ResponseProps, y as StreamErrorMessage, S as StreamErrorMessageProps, E as StreamStatusIndicator, D as StreamStatusIndicatorProps, C as StreamingText, z as StreamingTextProps, J as Suggestions, G as SuggestionsProps, w as UserMessage, U as UserMessageProps, K as Window, W as WindowProps } from '../Window-BcTRumpc.js';
2
2
  import { RenderMessageProps, AssistantMessageProps, InputProps, UserMessageProps } from '@copilotkit/react-ui';
3
+ import * as React from 'react';
3
4
  import React__default, { ReactNode } from 'react';
4
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
6
  import '@react-aria/button';
@@ -25,19 +26,7 @@ import 'styled-components/dist/types';
25
26
  */
26
27
  declare const ActionExecutionAdapter: React__default.FC<RenderMessageProps>;
27
28
 
28
- /**
29
- * Adapter component that bridges custom AssistantMessage with CopilotKit's expected interface
30
- *
31
- * This adapter:
32
- * 1. Converts CopilotKit's AssistantMessageProps to our custom component props
33
- * 2. Handles loading states by showing AssistantThinking component
34
- * 3. Extracts message content and renders with our styled component
35
- */
36
-
37
- /**
38
- * Adapter that converts CopilotKit's AssistantMessageProps to our custom component
39
- */
40
- declare const AssistantMessageAdapter: React__default.FC<AssistantMessageProps>;
29
+ declare const AssistantMessageAdapter: React.NamedExoticComponent<AssistantMessageProps>;
41
30
 
42
31
  /**
43
32
  * Adapter component that bridges custom Input with CopilotKit's expected interface
@@ -53,19 +42,7 @@ declare const AssistantMessageAdapter: React__default.FC<AssistantMessageProps>;
53
42
  */
54
43
  declare const InputAdapter: React__default.FC<InputProps>;
55
44
 
56
- /**
57
- * Adapter component that bridges custom UserMessage with CopilotKit's expected interface
58
- *
59
- * This adapter:
60
- * 1. Converts CopilotKit's UserMessageProps to our custom component props
61
- * 2. Extracts message content from CopilotKit's message object
62
- * 3. Handles image messages appropriately
63
- */
64
-
65
- /**
66
- * Adapter that converts CopilotKit's UserMessageProps to our custom component
67
- */
68
- declare const UserMessageAdapter: React__default.FC<UserMessageProps>;
45
+ declare const UserMessageAdapter: React.NamedExoticComponent<UserMessageProps>;
69
46
 
70
47
  /**
71
48
  * Complete CopilotSidebar Integration Example
@@ -1,9 +1,9 @@
1
1
  import { useButton } from '@react-aria/button';
2
- import { useRef, useState, useEffect } from 'react';
2
+ import { memo, useState, useRef, useEffect, useCallback } from 'react';
3
3
  import styled4, { css, keyframes, createGlobalStyle } from 'styled-components';
4
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
- import { useTextField } from '@react-aria/textfield';
4
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
5
  import { CopilotSidebar, useChatContext } from '@copilotkit/react-ui';
6
+ import { useTextField } from '@react-aria/textfield';
7
7
 
8
8
  // src/components/copilotkit/Button/Button.tsx
9
9
 
@@ -127,6 +127,8 @@ var tokens = {
127
127
  lg: "0.75rem",
128
128
  // 12px
129
129
  xl: "1rem",
130
+ // 16px
131
+ "2xl": "1.5rem",
130
132
  // 24px
131
133
  full: "9999px"
132
134
  // Fully rounded
@@ -627,7 +629,16 @@ var ActionExecutionAdapter = ({ message, inProgress }) => {
627
629
  return null;
628
630
  }
629
631
  const toolName = message.name;
630
- const toolArgs = message.arguments || {};
632
+ let toolArgs = {};
633
+ if (typeof message.arguments === "string") {
634
+ try {
635
+ toolArgs = JSON.parse(message.arguments);
636
+ } catch {
637
+ toolArgs = {};
638
+ }
639
+ } else if (message.arguments && typeof message.arguments === "object") {
640
+ toolArgs = message.arguments;
641
+ }
631
642
  const state = inProgress ? "thinking" : "responding";
632
643
  const statusMessage = getToolMessage(toolName, toolArgs);
633
644
  return /* @__PURE__ */ jsxs(Container, { "data-testid": "action-execution-message", children: [
@@ -815,6 +826,9 @@ var Container3 = styled4.div`
815
826
  white-space: pre-wrap;
816
827
  word-break: break-word;
817
828
  line-height: ${tokens.typography.lineHeight.normal};
829
+ /* Performance optimizations for streaming text */
830
+ text-rendering: optimizeSpeed;
831
+ contain: content;
818
832
  `;
819
833
  var Cursor = styled4.span`
820
834
  display: inline-block;
@@ -836,7 +850,7 @@ var Cursor = styled4.span`
836
850
  }
837
851
  }
838
852
  `;
839
- var StreamingText2 = ({
853
+ var StreamingTextBase = ({
840
854
  content,
841
855
  isStreaming = false,
842
856
  typingSpeed: _typingSpeed = 50,
@@ -846,25 +860,27 @@ var StreamingText2 = ({
846
860
  onStreamComplete,
847
861
  className
848
862
  }) => {
849
- const [displayedText, setDisplayedText] = useState("");
863
+ const [displayedText, setDisplayedText] = useState(content);
864
+ const wasStreamingRef = useRef(isStreaming);
865
+ const completionCalledRef = useRef(false);
850
866
  useEffect(() => {
851
- if (isStreaming) {
852
- setDisplayedText(content);
853
- return;
867
+ setDisplayedText(content);
868
+ if (wasStreamingRef.current && !isStreaming && !completionCalledRef.current) {
869
+ completionCalledRef.current = true;
870
+ onStreamComplete?.();
854
871
  }
855
- if (!isStreaming && displayedText !== content) {
856
- setDisplayedText(content);
857
- if (onStreamComplete) {
858
- onStreamComplete();
859
- }
872
+ if (isStreaming) {
873
+ completionCalledRef.current = false;
860
874
  }
861
- }, [content, isStreaming, onStreamComplete, displayedText]);
875
+ wasStreamingRef.current = isStreaming;
876
+ }, [content, isStreaming, onStreamComplete]);
862
877
  const showCursor = isStreaming && cursor;
863
878
  return /* @__PURE__ */ jsxs(Container3, { variant, className, children: [
864
879
  displayedText,
865
880
  showCursor && /* @__PURE__ */ jsx(Cursor, {})
866
881
  ] });
867
882
  };
883
+ var StreamingText2 = memo(StreamingTextBase);
868
884
  StreamingText2.displayName = "StreamingText";
869
885
  var MessageContainer = styled4.div`
870
886
  display: flex;
@@ -872,20 +888,9 @@ var MessageContainer = styled4.div`
872
888
  align-items: flex-start;
873
889
  padding: ${tokens.spacing.sm} 0;
874
890
  max-width: 100%;
875
-
876
- /* Fade in and slide up animation */
877
- animation: fadeInSlideUp ${tokens.animation.duration.medium} ease-out;
878
-
879
- @keyframes fadeInSlideUp {
880
- from {
881
- opacity: 0;
882
- transform: translateY(${tokens.spacing.sm});
883
- }
884
- to {
885
- opacity: 1;
886
- transform: translateY(0);
887
- }
888
- }
891
+ /* GPU acceleration hint for smooth rendering during streaming */
892
+ will-change: contents;
893
+ contain: content;
889
894
  `;
890
895
  var AvatarContainer = styled4.div`
891
896
  flex-shrink: 0;
@@ -920,9 +925,8 @@ var ContentContainer = styled4.div`
920
925
  min-width: 0;
921
926
  `;
922
927
  var MessageContent = styled4.div`
923
- background-color: ${tokens.colors.surface.glass};
924
- backdrop-filter: blur(10px);
925
- -webkit-backdrop-filter: blur(10px);
928
+ /* Use solid color instead of backdrop-filter for performance during streaming */
929
+ background-color: ${tokens.colors.surface.elevated};
926
930
  padding: ${tokens.spacing.sm} ${tokens.spacing.md};
927
931
  border-radius: ${tokens.borderRadius.lg};
928
932
  border-top-left-radius: ${tokens.borderRadius.sm};
@@ -932,24 +936,25 @@ var MessageContent = styled4.div`
932
936
  font-family: ${tokens.typography.fontFamily.primary};
933
937
  word-wrap: break-word;
934
938
  white-space: pre-wrap;
939
+ /* Optimize text rendering */
940
+ text-rendering: optimizeSpeed;
935
941
  `;
936
942
  var LoadingDots3 = styled4.div`
937
943
  display: flex;
938
944
  gap: ${tokens.spacing.xs};
939
945
  padding: ${tokens.spacing.sm} ${tokens.spacing.md};
940
- background-color: ${tokens.colors.surface.glass};
941
- backdrop-filter: blur(10px);
942
- -webkit-backdrop-filter: blur(10px);
946
+ /* Use solid color instead of backdrop-filter for performance */
947
+ background-color: ${tokens.colors.surface.elevated};
943
948
  border-radius: ${tokens.borderRadius.lg};
944
949
  border-top-left-radius: ${tokens.borderRadius.sm};
945
950
  width: fit-content;
946
951
  `;
947
- var bounce = keyframes`
948
- 0%, 60%, 100% {
949
- transform: translateY(0);
952
+ var pulse2 = keyframes`
953
+ 0%, 100% {
954
+ opacity: 0.4;
950
955
  }
951
- 30% {
952
- transform: translateY(-${tokens.spacing.sm});
956
+ 50% {
957
+ opacity: 1;
953
958
  }
954
959
  `;
955
960
  var LoadingDot = styled4.div`
@@ -957,7 +962,8 @@ var LoadingDot = styled4.div`
957
962
  height: ${tokens.spacing.sm};
958
963
  border-radius: ${tokens.borderRadius.full};
959
964
  background-color: ${tokens.colors.text.tertiary};
960
- animation: ${bounce} 1.4s ease-in-out infinite;
965
+ /* Use simple opacity animation instead of transform bounce */
966
+ animation: ${pulse2} 1.4s ease-in-out infinite;
961
967
  animation-delay: ${(props) => props.delay}s;
962
968
  `;
963
969
  var FileAttachmentContainer = styled4.div`
@@ -1152,7 +1158,7 @@ var StreamingIndicator = styled4.span`
1152
1158
  }
1153
1159
  }
1154
1160
  `;
1155
- var AssistantMessage = ({
1161
+ var AssistantMessageBase = ({
1156
1162
  content = "",
1157
1163
  avatarUrl,
1158
1164
  avatarInitials: _avatarInitials = "AI",
@@ -1199,7 +1205,9 @@ var AssistantMessage = ({
1199
1205
  /* @__PURE__ */ jsx(ContentContainer, { children: renderContent() })
1200
1206
  ] });
1201
1207
  };
1202
- var AssistantMessageAdapter = ({
1208
+ var AssistantMessage = memo(AssistantMessageBase);
1209
+ AssistantMessage.displayName = "AssistantMessage";
1210
+ var AssistantMessageAdapterBase = ({
1203
1211
  message,
1204
1212
  isLoading,
1205
1213
  isGenerating
@@ -1229,6 +1237,7 @@ var AssistantMessageAdapter = ({
1229
1237
  }
1230
1238
  );
1231
1239
  };
1240
+ var AssistantMessageAdapter = memo(AssistantMessageAdapterBase);
1232
1241
  AssistantMessageAdapter.displayName = "AssistantMessageAdapter";
1233
1242
  var ChatInputContainer = styled4.div`
1234
1243
  display: flex;
@@ -1262,7 +1271,7 @@ var SuggestionButton = styled4.button`
1262
1271
  font-weight: ${tokens.typography.fontWeight.regular};
1263
1272
  text-align: center;
1264
1273
  border: 1px solid ${tokens.colors.border.default};
1265
- border-radius: 20px;
1274
+ border-radius: ${tokens.borderRadius.full};
1266
1275
  cursor: pointer;
1267
1276
  transition: all ${tokens.transitions.fast};
1268
1277
  white-space: nowrap;
@@ -1296,9 +1305,9 @@ var SuggestionButton = styled4.button`
1296
1305
  `;
1297
1306
  var InputWrapper = styled4.div`
1298
1307
  display: flex;
1299
- align-items: center;
1300
- gap: 10px;
1301
- padding: 10px 14px;
1308
+ align-items: flex-end; /* Align button to bottom when textarea expands */
1309
+ gap: ${tokens.spacing.sm};
1310
+ padding: ${tokens.spacing.sm} ${tokens.spacing.md};
1302
1311
  background-color: rgba(25, 25, 25, 0.4);
1303
1312
  border: 1px solid ${tokens.colors.border.subtle};
1304
1313
  border-radius: ${tokens.borderRadius.lg};
@@ -1312,7 +1321,7 @@ var InputWrapper = styled4.div`
1312
1321
  background-color: rgba(50, 50, 52, 0.6);
1313
1322
  }
1314
1323
  `;
1315
- var InputField = styled4.input`
1324
+ var InputField = styled4.textarea`
1316
1325
  flex: 1;
1317
1326
  border: none;
1318
1327
  outline: none;
@@ -1320,6 +1329,13 @@ var InputField = styled4.input`
1320
1329
  font-size: ${tokens.typography.fontSize.sm};
1321
1330
  color: ${tokens.colors.text.secondary};
1322
1331
  background: transparent;
1332
+ resize: none; /* Disable manual resize, we auto-resize */
1333
+ min-height: 24px; /* Single line height */
1334
+ max-height: 150px; /* Max ~6 lines before scrolling */
1335
+ overflow-y: auto;
1336
+ line-height: 1.5;
1337
+ padding: 0;
1338
+ margin: 0;
1323
1339
 
1324
1340
  &::placeholder {
1325
1341
  color: ${tokens.colors.text.tertiary};
@@ -1375,31 +1391,29 @@ var ChatInput = ({
1375
1391
  isReadOnly = false,
1376
1392
  autoFocus = false,
1377
1393
  className,
1378
- "aria-label": ariaLabel = "Chat message input",
1379
- ...ariaProps
1394
+ "aria-label": ariaLabel = "Chat message input"
1395
+ // Note: Additional AriaTextFieldProps are accepted but not spread to textarea
1396
+ // since useTextField is not compatible with textarea elements
1380
1397
  }) => {
1381
1398
  const [internalValue, setInternalValue] = useState(value);
1382
1399
  const inputRef = useRef(null);
1383
1400
  const currentValue = value !== void 0 ? value : internalValue;
1384
1401
  const setValue = onChange || setInternalValue;
1385
- const { inputProps } = useTextField(
1386
- {
1387
- ...ariaProps,
1388
- "aria-label": ariaLabel,
1389
- value: currentValue,
1390
- onChange: (newValue) => {
1391
- setValue(newValue);
1392
- },
1393
- isDisabled,
1394
- isReadOnly
1395
- },
1396
- inputRef
1397
- );
1402
+ const autoResize = useCallback(() => {
1403
+ const textarea = inputRef.current;
1404
+ if (textarea) {
1405
+ textarea.style.height = "auto";
1406
+ textarea.style.height = `${textarea.scrollHeight}px`;
1407
+ }
1408
+ }, []);
1409
+ useEffect(() => {
1410
+ autoResize();
1411
+ }, [currentValue, autoResize]);
1398
1412
  const handleDirectChange = (e) => {
1399
1413
  setValue(e.target.value);
1400
1414
  };
1401
1415
  const handleKeyDown = (e) => {
1402
- if (e.key === "Enter") {
1416
+ if (e.key === "Enter" && !e.shiftKey) {
1403
1417
  e.preventDefault();
1404
1418
  handleSubmit();
1405
1419
  }
@@ -1408,6 +1422,9 @@ var ChatInput = ({
1408
1422
  if (currentValue.trim() && onSubmit && !isDisabled && !isReadOnly) {
1409
1423
  onSubmit(currentValue.trim());
1410
1424
  setValue("");
1425
+ if (inputRef.current) {
1426
+ inputRef.current.style.height = "auto";
1427
+ }
1411
1428
  inputRef.current?.focus();
1412
1429
  }
1413
1430
  };
@@ -1431,16 +1448,16 @@ var ChatInput = ({
1431
1448
  /* @__PURE__ */ jsx(
1432
1449
  InputField,
1433
1450
  {
1434
- ...inputProps,
1435
1451
  ref: inputRef,
1436
- type: "text",
1452
+ "aria-label": ariaLabel,
1437
1453
  placeholder,
1438
1454
  onKeyDown: handleKeyDown,
1439
1455
  onChange: handleDirectChange,
1440
1456
  autoFocus,
1441
1457
  disabled: isDisabled,
1442
1458
  readOnly: isReadOnly,
1443
- value: currentValue
1459
+ value: currentValue,
1460
+ rows: 1
1444
1461
  }
1445
1462
  ),
1446
1463
  /* @__PURE__ */ jsx(
@@ -1588,7 +1605,7 @@ var StyledUserMessage = styled4.button`
1588
1605
  && {
1589
1606
  background: ${tokens.colors.message.user} !important;
1590
1607
  color: ${tokens.colors.text.primary} !important;
1591
- border-radius: ${tokens.borderRadius.full} !important; /* Pill shape - fully rounded ends */
1608
+ border-radius: ${tokens.borderRadius["2xl"]} !important; /* Rounded corners that work for multi-line */
1592
1609
  }
1593
1610
 
1594
1611
  /* Subtle shadow and glow effect */
@@ -1668,7 +1685,7 @@ var StyledUserMessage = styled4.button`
1668
1685
  }
1669
1686
  }
1670
1687
  `;
1671
- function UserMessage({
1688
+ function UserMessageBase({
1672
1689
  children,
1673
1690
  className,
1674
1691
  isPressed = false,
@@ -1699,28 +1716,17 @@ function UserMessage({
1699
1716
  }
1700
1717
  );
1701
1718
  }
1719
+ var UserMessage = memo(UserMessageBase);
1702
1720
  UserMessage.displayName = "UserMessage";
1703
1721
  var UserMessageWrapper = styled4.div`
1704
1722
  display: flex;
1705
1723
  justify-content: flex-end;
1706
1724
  width: 100%;
1707
1725
  padding: ${tokens.spacing.sm} 0;
1708
-
1709
- /* Fade in and slide up animation */
1710
- animation: fadeInSlideUp ${tokens.animation.duration.medium} ease-out;
1711
-
1712
- @keyframes fadeInSlideUp {
1713
- from {
1714
- opacity: 0;
1715
- transform: translateY(${tokens.spacing.sm});
1716
- }
1717
- to {
1718
- opacity: 1;
1719
- transform: translateY(0);
1720
- }
1721
- }
1726
+ /* Performance optimization - isolate layout/paint */
1727
+ contain: content;
1722
1728
  `;
1723
- var UserMessageAdapter = ({
1729
+ var UserMessageAdapterBase = ({
1724
1730
  message,
1725
1731
  ImageRenderer
1726
1732
  }) => {
@@ -1730,8 +1736,9 @@ var UserMessageAdapter = ({
1730
1736
  const content = message?.content || "";
1731
1737
  return /* @__PURE__ */ jsx(UserMessageWrapper, { children: /* @__PURE__ */ jsx(UserMessage, { children: content }) });
1732
1738
  };
1739
+ var UserMessageAdapter = memo(UserMessageAdapterBase);
1733
1740
  UserMessageAdapter.displayName = "UserMessageAdapter";
1734
- var pulse2 = keyframes`
1741
+ var pulse3 = keyframes`
1735
1742
  0%, 100% {
1736
1743
  opacity: 1;
1737
1744
  transform: scale(1);
@@ -1815,7 +1822,7 @@ var StatusDot = styled4.div`
1815
1822
  return tokens.colors.connection.reconnecting;
1816
1823
  }
1817
1824
  }};
1818
- animation: ${(props) => props.status === "streaming" ? pulse2 : "none"} 2s ease-in-out infinite;
1825
+ animation: ${(props) => props.status === "streaming" ? pulse3 : "none"} 2s ease-in-out infinite;
1819
1826
  flex-shrink: 0;
1820
1827
  `;
1821
1828
  var Label = styled4.span`
@@ -2331,8 +2338,8 @@ var StyledChatButton = styled4.button`
2331
2338
  height: 36px;
2332
2339
  border-radius: 18px;
2333
2340
  border: none;
2334
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
2335
- box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
2341
+ background: linear-gradient(135deg, ${tokens.colors.primary} 0%, ${tokens.colors.accent} 100%);
2342
+ box-shadow: 0 4px 12px rgba(44, 176, 171, 0.4);
2336
2343
  display: flex;
2337
2344
  align-items: center;
2338
2345
  justify-content: center;
@@ -2342,7 +2349,7 @@ var StyledChatButton = styled4.button`
2342
2349
 
2343
2350
  &:hover {
2344
2351
  transform: scale(1.05);
2345
- box-shadow: 0 6px 16px rgba(102, 126, 234, 0.5);
2352
+ box-shadow: 0 6px 16px rgba(44, 176, 171, 0.5);
2346
2353
  }
2347
2354
 
2348
2355
  &:active {
@@ -2454,16 +2461,24 @@ var CustomCopilotSidebar = ({
2454
2461
  };
2455
2462
  CustomCopilotSidebar.displayName = "CustomCopilotSidebar";
2456
2463
  var GlobalSidebarStyles2 = createGlobalStyle`
2464
+ /* Override CopilotKit's content wrapper to respect safe areas in landscape */
2465
+ @media (orientation: landscape) {
2466
+ .copilotKitSidebarContentWrapper {
2467
+ right: env(safe-area-inset-right, 0px) !important;
2468
+ left: env(safe-area-inset-left, 0px) !important;
2469
+ }
2470
+ }
2471
+
2457
2472
  /* Override CopilotKit's default positioning - keep sidebar container in place */
2458
2473
  /* z-index must be higher than NavHorizontal (sticky: 1020) for button to show above nav */
2459
2474
  .copilotKitSidebar {
2460
2475
  position: fixed !important;
2461
- top: 0 !important;
2462
- right: 0 !important;
2463
- bottom: 0 !important;
2464
- left: 0 !important;
2465
- width: 100vw !important;
2466
- height: 100vh !important;
2476
+ top: calc(var(--safe-area-top, 0px) + 8px) !important;
2477
+ right: calc(var(--safe-area-right, 0px) + 8px) !important;
2478
+ bottom: calc(var(--safe-area-bottom, 0px) + 8px) !important;
2479
+ left: calc(var(--safe-area-left, 0px) + 8px) !important;
2480
+ width: auto !important;
2481
+ height: auto !important;
2467
2482
  pointer-events: none !important;
2468
2483
  z-index: ${tokens.zIndex.fixed} !important;
2469
2484
  }
@@ -2478,16 +2493,19 @@ var GlobalSidebarStyles2 = createGlobalStyle`
2478
2493
  .copilotKitSidebar [role="dialog"] {
2479
2494
  /* Override CopilotKit defaults for mobile */
2480
2495
  position: fixed !important;
2481
- top: ${tokens.spacing.sm} !important;
2482
- right: ${tokens.spacing.sm} !important;
2483
- /* Reserve space for Android nav buttons - matches NavHorizontal approach */
2484
- bottom: max(90px, env(safe-area-inset-bottom, 90px)) !important;
2485
- left: ${tokens.spacing.sm} !important;
2486
- width: calc(100vw - ${tokens.spacing.lg}) !important;
2487
- /* Adjust height to account for bottom safe area */
2488
- height: calc(100vh - ${tokens.spacing.lg} - max(80px, env(safe-area-inset-bottom, 80px))) !important;
2489
- max-width: calc(100vw - ${tokens.spacing.lg}) !important;
2490
- max-height: calc(100vh - ${tokens.spacing.lg} - max(80px, env(safe-area-inset-bottom, 80px))) !important;
2496
+ /* TOP: Account for status bar safe area (Android notch/status bar) */
2497
+ top: calc(${tokens.spacing.sm} + env(safe-area-inset-top, 0px)) !important;
2498
+ /* RIGHT: Account for landscape notch on right side */
2499
+ right: calc(${tokens.spacing.sm} + env(safe-area-inset-right, 0px)) !important;
2500
+ /* BOTTOM: Account for horizontal navbar (52px) + safe area for Android nav buttons */
2501
+ bottom: calc(52px + ${tokens.spacing.sm} + env(safe-area-inset-bottom, 0px)) !important;
2502
+ /* LEFT: Account for landscape notch on left side */
2503
+ left: calc(${tokens.spacing.sm} + env(safe-area-inset-left, 0px)) !important;
2504
+ width: calc(100vw - ${tokens.spacing.lg} - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)) !important;
2505
+ /* Adjust height to account for top, bottom safe areas, and navbar */
2506
+ height: calc(100vh - ${tokens.spacing.lg} - env(safe-area-inset-top, 0px) - 52px - env(safe-area-inset-bottom, 0px)) !important;
2507
+ max-width: calc(100vw - ${tokens.spacing.lg} - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)) !important;
2508
+ max-height: calc(100vh - ${tokens.spacing.lg} - env(safe-area-inset-top, 0px) - 52px - env(safe-area-inset-bottom, 0px)) !important;
2491
2509
  margin: 0 !important;
2492
2510
  border-radius: ${tokens.borderRadius.xl} !important;
2493
2511
 
@@ -2523,16 +2541,18 @@ var GlobalSidebarStyles2 = createGlobalStyle`
2523
2541
  @media (min-width: ${tokens.breakpoints.mobile}px) {
2524
2542
  .copilotKitSidebar [role="dialog"] {
2525
2543
  inset: auto !important;
2526
- top: ${tokens.spacing.sm} !important;
2527
- right: ${tokens.spacing.sm} !important;
2528
- /* Reserve space for Android nav buttons on desktop too */
2529
- bottom: max(90px, env(safe-area-inset-bottom, 90px)) !important;
2544
+ /* TOP: Account for status bar safe area */
2545
+ top: calc(${tokens.spacing.sm} + env(safe-area-inset-top, 0px)) !important;
2546
+ /* RIGHT: Account for landscape notch on right side */
2547
+ right: calc(${tokens.spacing.sm} + env(safe-area-inset-right, 0px)) !important;
2548
+ /* BOTTOM: Account for horizontal navbar (52px) + safe area */
2549
+ bottom: calc(52px + ${tokens.spacing.sm} + env(safe-area-inset-bottom, 0px)) !important;
2530
2550
  left: auto !important;
2531
2551
  width: 28rem !important;
2532
- /* Adjust height to account for bottom safe area */
2533
- height: calc(100vh - ${tokens.spacing.lg} - max(80px, env(safe-area-inset-bottom, 80px))) !important;
2552
+ /* Adjust height to account for top, bottom safe areas, and navbar */
2553
+ height: calc(100vh - ${tokens.spacing.lg} - env(safe-area-inset-top, 0px) - 52px - env(safe-area-inset-bottom, 0px)) !important;
2534
2554
  max-width: 28rem !important;
2535
- max-height: calc(100vh - ${tokens.spacing.lg} - max(80px, env(safe-area-inset-bottom, 80px))) !important;
2555
+ max-height: calc(100vh - ${tokens.spacing.lg} - env(safe-area-inset-top, 0px) - 52px - env(safe-area-inset-bottom, 0px)) !important;
2536
2556
  }
2537
2557
  }
2538
2558
 
@@ -2552,25 +2572,27 @@ var GlobalSidebarStyles2 = createGlobalStyle`
2552
2572
  }
2553
2573
  }
2554
2574
 
2575
+ /* Position chat button with safe area on landscape (right side for Android controls) */
2576
+ @media (orientation: landscape) {
2577
+ .copilotKitSidebarContentWrapper {
2578
+ button[aria-label="Open chat"],
2579
+ button[aria-label="Close chat"] {
2580
+ bottom: calc(var(--safe-area-bottom, 0px) + 8px) !important;
2581
+ right: calc(var(--safe-area-right, 0px) + 8px) !important;
2582
+ z-index: 2000 !important;
2583
+ }
2584
+ }
2585
+ }
2586
+
2555
2587
  /* Fix messages container background */
2556
2588
  .copilotKitMessages {
2557
2589
  background-color: transparent !important;
2558
2590
  }
2559
2591
 
2560
- /* Fade-in animation for new messages */
2561
- @keyframes messagesFadeIn {
2562
- from {
2563
- opacity: 0;
2564
- transform: translateY(${tokens.spacing.sm});
2565
- }
2566
- to {
2567
- opacity: 1;
2568
- transform: translateY(0);
2569
- }
2570
- }
2571
-
2592
+ /* Performance optimization for messages - no animations to reduce jitter during streaming */
2572
2593
  .copilotKitMessage {
2573
- animation: messagesFadeIn 0.3s ease-out;
2594
+ /* contain: content isolates layout/paint to this element */
2595
+ contain: content;
2574
2596
  }
2575
2597
 
2576
2598
  /* Override CopilotKit suggestions to be single-row with horizontal scroll */
@@ -2622,8 +2644,8 @@ var GlobalSidebarStyles2 = createGlobalStyle`
2622
2644
  `;
2623
2645
  var StyledChatButton2 = styled4.button`
2624
2646
  position: fixed;
2625
- bottom: ${tokens.spacing.sm};
2626
- right: ${tokens.spacing.sm};
2647
+ bottom: calc(${tokens.spacing.sm} + env(safe-area-inset-bottom, 0px));
2648
+ right: calc(${tokens.spacing.sm} + env(safe-area-inset-right, 0px));
2627
2649
  width: 36px;
2628
2650
  height: 36px;
2629
2651
  border-radius: ${tokens.borderRadius.full};