@usecrow/ui 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.
package/dist/index.cjs CHANGED
@@ -119,7 +119,9 @@ function useChat({
119
119
  message,
120
120
  conversation_id: conversationId,
121
121
  identity_token: identityToken,
122
- model: selectedModel
122
+ model: selectedModel,
123
+ user_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
124
+ user_local_time: (/* @__PURE__ */ new Date()).toLocaleString()
123
125
  }),
124
126
  signal: abortControllerRef.current.signal
125
127
  });
@@ -389,7 +391,9 @@ function useChat({
389
391
  tool_name: toolName,
390
392
  result,
391
393
  identity_token: identityToken,
392
- model: selectedModel
394
+ model: selectedModel,
395
+ user_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
396
+ user_local_time: (/* @__PURE__ */ new Date()).toLocaleString()
393
397
  })
394
398
  });
395
399
  if (!response.ok) {
@@ -648,6 +652,16 @@ function useWorkflow({
648
652
  exitWorkflow
649
653
  };
650
654
  }
655
+ var SDK_DEFAULT_TOOLS = {
656
+ refreshPage: async () => {
657
+ try {
658
+ window.location.reload();
659
+ return { status: "success", data: { message: "Page refresh initiated" } };
660
+ } catch (error) {
661
+ return { status: "error", error: String(error) };
662
+ }
663
+ }
664
+ };
651
665
  function useCrowAPI({ onIdentified, onReset } = {}) {
652
666
  const onIdentifiedRef = React3.useRef(onIdentified);
653
667
  const onResetRef = React3.useRef(onReset);
@@ -657,6 +671,15 @@ function useCrowAPI({ onIdentified, onReset } = {}) {
657
671
  onResetRef.current = onReset;
658
672
  });
659
673
  React3.useEffect(() => {
674
+ if (!window.__crow_client_tools) {
675
+ window.__crow_client_tools = {};
676
+ }
677
+ for (const [toolName, handler] of Object.entries(SDK_DEFAULT_TOOLS)) {
678
+ if (!window.__crow_client_tools[toolName]) {
679
+ window.__crow_client_tools[toolName] = handler;
680
+ console.log(`[Crow] Registered default tool: ${toolName}`);
681
+ }
682
+ }
660
683
  window.crow = function(command, options) {
661
684
  const opts = options;
662
685
  switch (command) {
@@ -1149,7 +1172,9 @@ function useWidgetStyles2() {
1149
1172
  const context = React3.useContext(WidgetStyleContext);
1150
1173
  return context?.styles ?? DEFAULT_WIDGET_STYLES;
1151
1174
  }
1152
- var CopilotStyleContext = React3.createContext(null);
1175
+ var CopilotStyleContext = React3.createContext(
1176
+ null
1177
+ );
1153
1178
  function CopilotStyleProvider({
1154
1179
  children,
1155
1180
  styles,
@@ -1175,6 +1200,7 @@ function useCopilotStyles2() {
1175
1200
  const context = React3.useContext(CopilotStyleContext);
1176
1201
  return context?.styles ?? DEFAULT_COPILOT_STYLES;
1177
1202
  }
1203
+ var PASSTHROUGH_KEYS = /* @__PURE__ */ new Set(["Escape", "Tab"]);
1178
1204
  function ShadowContainer({
1179
1205
  children,
1180
1206
  styles,
@@ -1189,6 +1215,51 @@ function ShadowContainer({
1189
1215
  setShadowRoot(shadow);
1190
1216
  }
1191
1217
  }, []);
1218
+ React3.useEffect(() => {
1219
+ if (!shadowRoot || !hostRef.current) return;
1220
+ const hostElement = hostRef.current;
1221
+ const stopPropagationHandler = (e) => {
1222
+ const keyEvent = e;
1223
+ if (keyEvent.key && PASSTHROUGH_KEYS.has(keyEvent.key)) {
1224
+ return;
1225
+ }
1226
+ e.stopPropagation();
1227
+ };
1228
+ shadowRoot.addEventListener("keydown", stopPropagationHandler);
1229
+ shadowRoot.addEventListener("keyup", stopPropagationHandler);
1230
+ shadowRoot.addEventListener("keypress", stopPropagationHandler);
1231
+ let lastFocusedElement = null;
1232
+ const trackFocus = (e) => {
1233
+ lastFocusedElement = e.target;
1234
+ };
1235
+ const protectFocus = (e) => {
1236
+ if (e.key && PASSTHROUGH_KEYS.has(e.key)) {
1237
+ return;
1238
+ }
1239
+ const path = e.composedPath();
1240
+ if (!path.includes(hostElement) && !path.includes(shadowRoot)) {
1241
+ return;
1242
+ }
1243
+ if (lastFocusedElement) {
1244
+ const elementToRestore = lastFocusedElement;
1245
+ queueMicrotask(() => {
1246
+ const activeInShadow = shadowRoot.activeElement;
1247
+ if (!activeInShadow) {
1248
+ elementToRestore.focus();
1249
+ }
1250
+ });
1251
+ }
1252
+ };
1253
+ shadowRoot.addEventListener("focusin", trackFocus);
1254
+ document.addEventListener("keydown", protectFocus, { capture: true });
1255
+ return () => {
1256
+ shadowRoot.removeEventListener("keydown", stopPropagationHandler);
1257
+ shadowRoot.removeEventListener("keyup", stopPropagationHandler);
1258
+ shadowRoot.removeEventListener("keypress", stopPropagationHandler);
1259
+ shadowRoot.removeEventListener("focusin", trackFocus);
1260
+ document.removeEventListener("keydown", protectFocus, { capture: true });
1261
+ };
1262
+ }, [shadowRoot]);
1192
1263
  return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: hostRef, id: hostId, className: hostClassName, children: shadowRoot && reactDom.createPortal(
1193
1264
  /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1194
1265
  /* @__PURE__ */ jsxRuntime.jsx("style", { children: styles }),
@@ -1382,7 +1453,14 @@ function StreamingText({
1382
1453
  ...props,
1383
1454
  children
1384
1455
  }
1385
- ) : /* @__PURE__ */ jsxRuntime.jsx("code", { className: `crow-text-gray-200 ${className || ""}`, ...props, children });
1456
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1457
+ "code",
1458
+ {
1459
+ className: `crow-text-gray-200 ${className || ""}`,
1460
+ ...props,
1461
+ children
1462
+ }
1463
+ );
1386
1464
  },
1387
1465
  pre: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "crow-bg-gray-800 crow-text-gray-200 crow-p-3 crow-rounded-lg crow-my-2 crow-overflow-x-auto crow-text-sm", children })
1388
1466
  },
@@ -1496,7 +1574,12 @@ function ShimmeringContent({ children }) {
1496
1574
  }
1497
1575
  );
1498
1576
  }
1499
- function ReasoningTrace({ thinking, isComplete, toolCalls = [], isWaiting = false }) {
1577
+ function ReasoningTrace({
1578
+ thinking,
1579
+ isComplete,
1580
+ toolCalls = [],
1581
+ isWaiting = false
1582
+ }) {
1500
1583
  const hasThinking = !!thinking && thinking.trim().length > 0;
1501
1584
  const hasToolCalls = toolCalls.length > 0;
1502
1585
  if (!isWaiting && !hasThinking && !hasToolCalls) return null;
@@ -1512,7 +1595,10 @@ function WaitingIndicator() {
1512
1595
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "crow-font-medium", children: /* @__PURE__ */ jsxRuntime.jsx(ShimmeringContent, { children: getRandomThinkingMessage() }) })
1513
1596
  ] });
1514
1597
  }
1515
- function ThinkingBlock({ thinking, isComplete }) {
1598
+ function ThinkingBlock({
1599
+ thinking,
1600
+ isComplete
1601
+ }) {
1516
1602
  const [isExpanded, setIsExpanded] = React3.useState(!isComplete);
1517
1603
  React3.useLayoutEffect(() => {
1518
1604
  setIsExpanded(!isComplete);
@@ -1706,64 +1792,62 @@ function MessageList({
1706
1792
  msg.id
1707
1793
  )) });
1708
1794
  }
1709
- var MessagesContainer = React3.forwardRef(
1710
- ({ children }, ref) => {
1711
- const styles = useWidgetStyles2();
1712
- const internalRef = React3.useRef(null);
1713
- const lastScrollHeightRef = React3.useRef(0);
1714
- const isUserScrollingRef = React3.useRef(false);
1715
- const containerRef = ref || internalRef;
1716
- const isNearBottom = React3.useCallback(() => {
1717
- const container = containerRef.current;
1718
- if (!container) return true;
1719
- const threshold = 100;
1720
- return container.scrollHeight - container.scrollTop - container.clientHeight < threshold;
1721
- }, [containerRef]);
1722
- const scrollToBottom = React3.useCallback(() => {
1723
- const container = containerRef.current;
1724
- if (!container) return;
1725
- container.scrollTo({
1726
- top: container.scrollHeight,
1727
- behavior: "smooth"
1728
- });
1729
- }, [containerRef]);
1730
- React3.useEffect(() => {
1731
- const container = containerRef.current;
1732
- if (!container) return;
1733
- const handleScroll = () => {
1734
- isUserScrollingRef.current = !isNearBottom();
1735
- };
1736
- container.addEventListener("scroll", handleScroll, { passive: true });
1737
- return () => container.removeEventListener("scroll", handleScroll);
1738
- }, [containerRef, isNearBottom]);
1739
- React3.useEffect(() => {
1740
- const container = containerRef.current;
1741
- if (!container) return;
1742
- const currentHeight = container.scrollHeight;
1743
- const heightChanged = currentHeight !== lastScrollHeightRef.current;
1744
- if (heightChanged) {
1745
- lastScrollHeightRef.current = currentHeight;
1746
- if (!isUserScrollingRef.current || isNearBottom()) {
1747
- scrollToBottom();
1748
- }
1749
- }
1795
+ var MessagesContainer = React3.forwardRef(({ children }, ref) => {
1796
+ const styles = useWidgetStyles2();
1797
+ const internalRef = React3.useRef(null);
1798
+ const lastScrollHeightRef = React3.useRef(0);
1799
+ const isUserScrollingRef = React3.useRef(false);
1800
+ const containerRef = ref || internalRef;
1801
+ const isNearBottom = React3.useCallback(() => {
1802
+ const container = containerRef.current;
1803
+ if (!container) return true;
1804
+ const threshold = 100;
1805
+ return container.scrollHeight - container.scrollTop - container.clientHeight < threshold;
1806
+ }, [containerRef]);
1807
+ const scrollToBottom = React3.useCallback(() => {
1808
+ const container = containerRef.current;
1809
+ if (!container) return;
1810
+ container.scrollTo({
1811
+ top: container.scrollHeight,
1812
+ behavior: "smooth"
1750
1813
  });
1751
- return /* @__PURE__ */ jsxRuntime.jsx(
1752
- framerMotion.motion.div,
1753
- {
1754
- ref: containerRef,
1755
- id: MESSAGES_CONTAINER_ID,
1756
- initial: { opacity: 0 },
1757
- animate: { opacity: 1 },
1758
- exit: { opacity: 0 },
1759
- transition: { duration: styles.animations.duration },
1760
- className: "crow-relative crow-flex-1 crow-min-h-0 crow-rounded-2xl crow-mb-3 crow-overflow-y-auto crow-p-4 crow-space-y-3 crow-pointer-events-auto",
1761
- style: { background: styles.colors.messagesBackground },
1762
- children
1814
+ }, [containerRef]);
1815
+ React3.useEffect(() => {
1816
+ const container = containerRef.current;
1817
+ if (!container) return;
1818
+ const handleScroll = () => {
1819
+ isUserScrollingRef.current = !isNearBottom();
1820
+ };
1821
+ container.addEventListener("scroll", handleScroll, { passive: true });
1822
+ return () => container.removeEventListener("scroll", handleScroll);
1823
+ }, [containerRef, isNearBottom]);
1824
+ React3.useEffect(() => {
1825
+ const container = containerRef.current;
1826
+ if (!container) return;
1827
+ const currentHeight = container.scrollHeight;
1828
+ const heightChanged = currentHeight !== lastScrollHeightRef.current;
1829
+ if (heightChanged) {
1830
+ lastScrollHeightRef.current = currentHeight;
1831
+ if (!isUserScrollingRef.current || isNearBottom()) {
1832
+ scrollToBottom();
1763
1833
  }
1764
- );
1765
- }
1766
- );
1834
+ }
1835
+ });
1836
+ return /* @__PURE__ */ jsxRuntime.jsx(
1837
+ framerMotion.motion.div,
1838
+ {
1839
+ ref: containerRef,
1840
+ id: MESSAGES_CONTAINER_ID,
1841
+ initial: { opacity: 0 },
1842
+ animate: { opacity: 1 },
1843
+ exit: { opacity: 0 },
1844
+ transition: { duration: styles.animations.duration },
1845
+ className: "crow-relative crow-flex-1 crow-min-h-0 crow-rounded-2xl crow-mb-3 crow-overflow-y-auto crow-p-4 crow-space-y-3 crow-pointer-events-auto",
1846
+ style: { background: styles.colors.messagesBackground },
1847
+ children
1848
+ }
1849
+ );
1850
+ });
1767
1851
  MessagesContainer.displayName = "MessagesContainer";
1768
1852
  function ConversationList({
1769
1853
  conversations,
@@ -2035,7 +2119,13 @@ var PromptInput = React3__default.default.forwardRef(
2035
2119
  }
2036
2120
  );
2037
2121
  PromptInput.displayName = "PromptInput";
2038
- var PromptInputTextarea = ({ className, onKeyDown, disableAutosize = false, placeholder, ...props }) => {
2122
+ var PromptInputTextarea = ({
2123
+ className,
2124
+ onKeyDown,
2125
+ disableAutosize = false,
2126
+ placeholder,
2127
+ ...props
2128
+ }) => {
2039
2129
  const { value, setValue, maxHeight, onSubmit, disabled } = usePromptInput();
2040
2130
  const textareaRef = React3__default.default.useRef(null);
2041
2131
  React3__default.default.useEffect(() => {
@@ -2068,7 +2158,14 @@ var PromptInputActions = ({
2068
2158
  children,
2069
2159
  className,
2070
2160
  ...props
2071
- }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("crow-flex crow-items-center crow-gap-2", className), ...props, children });
2161
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
2162
+ "div",
2163
+ {
2164
+ className: cn("crow-flex crow-items-center crow-gap-2", className),
2165
+ ...props,
2166
+ children
2167
+ }
2168
+ );
2072
2169
  var PromptInputAction = ({
2073
2170
  tooltip,
2074
2171
  children,
@@ -2115,7 +2212,13 @@ var PromptInputBox = React3__default.default.forwardRef(
2115
2212
  disabled: isLoading,
2116
2213
  ref: ref || promptBoxRef,
2117
2214
  children: [
2118
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-transition-all crow-duration-300 crow-opacity-100", children: /* @__PURE__ */ jsxRuntime.jsx(PromptInputTextarea, { placeholder, className: "crow-text-base" }) }),
2215
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-transition-all crow-duration-300 crow-opacity-100", children: /* @__PURE__ */ jsxRuntime.jsx(
2216
+ PromptInputTextarea,
2217
+ {
2218
+ placeholder,
2219
+ className: "crow-text-base"
2220
+ }
2221
+ ) }),
2119
2222
  /* @__PURE__ */ jsxRuntime.jsxs(PromptInputActions, { className: "crow-flex crow-items-center crow-justify-between crow-gap-2 crow-p-0 crow-pt-1", children: [
2120
2223
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-flex crow-items-center", children: availableModels.length > 0 && onModelChange && /* @__PURE__ */ jsxRuntime.jsx(
2121
2224
  ModelSelector,
@@ -2148,10 +2251,21 @@ var PromptInputBox = React3__default.default.forwardRef(
2148
2251
  handleSubmit();
2149
2252
  }
2150
2253
  },
2151
- children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, { className: "crow-h-3.5 crow-w-3.5 crow-text-white", style: { fill: "white" } }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: cn(
2152
- "crow-h-3.5 crow-w-3.5",
2153
- hasContent ? "crow-text-white" : "crow-text-gray-400"
2154
- ) })
2254
+ children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(
2255
+ lucideReact.Square,
2256
+ {
2257
+ className: "crow-h-3.5 crow-w-3.5 crow-text-white",
2258
+ style: { fill: "white" }
2259
+ }
2260
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
2261
+ lucideReact.ArrowUp,
2262
+ {
2263
+ className: cn(
2264
+ "crow-h-3.5 crow-w-3.5",
2265
+ hasContent ? "crow-text-white" : "crow-text-gray-400"
2266
+ )
2267
+ }
2268
+ )
2155
2269
  }
2156
2270
  )
2157
2271
  }