@usecrow/ui 0.1.43 → 0.1.45
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 +419 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +89 -65
- package/dist/index.d.ts +89 -65
- package/dist/index.js +419 -51
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -905,11 +905,44 @@ function useCrowAPI({ onIdentified, onReset } = {}) {
|
|
|
905
905
|
window.__crow_page_context = void 0;
|
|
906
906
|
console.log("[Crow] Context cleared");
|
|
907
907
|
break;
|
|
908
|
+
case "setIdentityTokenFetcher":
|
|
909
|
+
if (typeof opts !== "function") {
|
|
910
|
+
console.error("[Crow] setIdentityTokenFetcher() requires a function");
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
window.__crow_identity_token_fetcher = opts;
|
|
914
|
+
console.log("[Crow] Identity token fetcher registered");
|
|
915
|
+
break;
|
|
916
|
+
case "onToolResult":
|
|
917
|
+
if (typeof opts !== "function") {
|
|
918
|
+
console.error("[Crow] onToolResult() requires a function");
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
window.__crow_on_tool_result = opts;
|
|
922
|
+
console.log("[Crow] onToolResult callback registered");
|
|
923
|
+
break;
|
|
924
|
+
case "registerToolRenderers":
|
|
925
|
+
if (!opts || typeof opts !== "object") {
|
|
926
|
+
console.error("[Crow] registerToolRenderers() requires an object");
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
window.__crow_tool_renderers = {
|
|
930
|
+
...window.__crow_tool_renderers || {},
|
|
931
|
+
...opts
|
|
932
|
+
};
|
|
933
|
+
console.log("[Crow] Tool renderers registered");
|
|
934
|
+
break;
|
|
908
935
|
default:
|
|
909
936
|
console.warn(`[Crow] Unknown command: ${command}`);
|
|
910
937
|
}
|
|
911
938
|
};
|
|
912
939
|
console.log("[Crow] API ready");
|
|
940
|
+
const queue = window.__crow_queue;
|
|
941
|
+
if (queue?.length) {
|
|
942
|
+
console.log(`[Crow] Replaying ${queue.length} queued command(s)`);
|
|
943
|
+
queue.forEach(([cmd, opts]) => window.crow(cmd, opts));
|
|
944
|
+
window.__crow_queue = void 0;
|
|
945
|
+
}
|
|
913
946
|
const handleIdentified = () => onIdentifiedRef.current?.();
|
|
914
947
|
const handleReset = () => onResetRef.current?.();
|
|
915
948
|
window.addEventListener("crow:identified", handleIdentified);
|
|
@@ -1941,6 +1974,23 @@ function ThinkingBlock({
|
|
|
1941
1974
|
) })
|
|
1942
1975
|
] });
|
|
1943
1976
|
}
|
|
1977
|
+
function RenderedToolResult({ renderer, result, status }) {
|
|
1978
|
+
const domRef = React3.useRef(null);
|
|
1979
|
+
const rendered = renderer({ result, status });
|
|
1980
|
+
React3.useEffect(() => {
|
|
1981
|
+
if (domRef.current && rendered instanceof HTMLElement) {
|
|
1982
|
+
domRef.current.innerHTML = "";
|
|
1983
|
+
domRef.current.appendChild(rendered);
|
|
1984
|
+
}
|
|
1985
|
+
}, [rendered]);
|
|
1986
|
+
if (rendered instanceof HTMLElement) {
|
|
1987
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-mt-1.5 crow-mb-0.5", ref: domRef });
|
|
1988
|
+
}
|
|
1989
|
+
if (typeof rendered === "string") {
|
|
1990
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-mt-1.5 crow-mb-0.5", dangerouslySetInnerHTML: { __html: rendered } });
|
|
1991
|
+
}
|
|
1992
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-mt-1.5 crow-mb-0.5", children: rendered });
|
|
1993
|
+
}
|
|
1944
1994
|
function ToolCallBlock({
|
|
1945
1995
|
toolCall,
|
|
1946
1996
|
toolRenderers
|
|
@@ -1980,7 +2030,7 @@ function ToolCallBlock({
|
|
|
1980
2030
|
]
|
|
1981
2031
|
}
|
|
1982
2032
|
),
|
|
1983
|
-
hasCustomRender && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2033
|
+
hasCustomRender && /* @__PURE__ */ jsxRuntime.jsx(RenderedToolResult, { renderer: customRenderer, result: toolCall.result, status: toolCall.status }),
|
|
1984
2034
|
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: expanded && hasArgs && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1985
2035
|
framerMotion.motion.div,
|
|
1986
2036
|
{
|
|
@@ -2939,8 +2989,12 @@ function CrowWidget({
|
|
|
2939
2989
|
navigate,
|
|
2940
2990
|
onToolResult,
|
|
2941
2991
|
getIdentityToken,
|
|
2942
|
-
context
|
|
2992
|
+
context,
|
|
2993
|
+
toolRenderers
|
|
2943
2994
|
}) {
|
|
2995
|
+
const effectiveGetIdentityToken = getIdentityToken || window.__crow_identity_token_fetcher;
|
|
2996
|
+
const effectiveOnToolResult = onToolResult || window.__crow_on_tool_result;
|
|
2997
|
+
const effectiveToolRenderers = toolRenderers || window.__crow_tool_renderers;
|
|
2944
2998
|
const {
|
|
2945
2999
|
styles,
|
|
2946
3000
|
isLoading: isLoadingStyles,
|
|
@@ -3019,7 +3073,7 @@ function CrowWidget({
|
|
|
3019
3073
|
break;
|
|
3020
3074
|
}
|
|
3021
3075
|
},
|
|
3022
|
-
onToolResult,
|
|
3076
|
+
onToolResult: effectiveOnToolResult,
|
|
3023
3077
|
onToolCall: async (event) => {
|
|
3024
3078
|
if (event.type === "client_call" && event.toolName && event.toolCallId) {
|
|
3025
3079
|
try {
|
|
@@ -3118,11 +3172,11 @@ function CrowWidget({
|
|
|
3118
3172
|
}
|
|
3119
3173
|
}, [isLoadingStyles, onIdentify]);
|
|
3120
3174
|
React3.useEffect(() => {
|
|
3121
|
-
if (!
|
|
3175
|
+
if (!effectiveGetIdentityToken || isLoadingStyles) return;
|
|
3122
3176
|
let cancelled = false;
|
|
3123
3177
|
const identify = async () => {
|
|
3124
3178
|
try {
|
|
3125
|
-
const token = await
|
|
3179
|
+
const token = await effectiveGetIdentityToken();
|
|
3126
3180
|
if (!cancelled && token) {
|
|
3127
3181
|
window.crow?.("identify", { token });
|
|
3128
3182
|
}
|
|
@@ -3137,7 +3191,7 @@ function CrowWidget({
|
|
|
3137
3191
|
cancelled = true;
|
|
3138
3192
|
window.removeEventListener("crow:token-refresh-needed", handleRefresh);
|
|
3139
3193
|
};
|
|
3140
|
-
}, [
|
|
3194
|
+
}, [effectiveGetIdentityToken, isLoadingStyles]);
|
|
3141
3195
|
React3.useEffect(() => {
|
|
3142
3196
|
if (typeof window === "undefined") return;
|
|
3143
3197
|
if (context && Object.keys(context).length > 0) {
|
|
@@ -3324,7 +3378,8 @@ function CrowWidget({
|
|
|
3324
3378
|
messages: chat.messages,
|
|
3325
3379
|
activeToolCalls: chat.activeToolCalls,
|
|
3326
3380
|
isLoadingHistory: conversations.isLoadingHistory,
|
|
3327
|
-
isGenerating: chat.isLoading
|
|
3381
|
+
isGenerating: chat.isLoading,
|
|
3382
|
+
toolRenderers: effectiveToolRenderers
|
|
3328
3383
|
}
|
|
3329
3384
|
),
|
|
3330
3385
|
pendingConfirmation && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-px-4 crow-py-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3428,40 +3483,88 @@ function MessageIcon() {
|
|
|
3428
3483
|
}
|
|
3429
3484
|
);
|
|
3430
3485
|
}
|
|
3431
|
-
|
|
3432
|
-
isOpen,
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
}
|
|
3486
|
+
var CopilotToggleButton = React3.forwardRef(
|
|
3487
|
+
function CopilotToggleButton2({ isOpen, position, onClick, onMouseDown, isDragging }, ref) {
|
|
3488
|
+
const renderIcon = () => {
|
|
3489
|
+
if (!isOpen) return /* @__PURE__ */ jsxRuntime.jsx(MessageIcon, {});
|
|
3490
|
+
if (position === "right") return /* @__PURE__ */ jsxRuntime.jsx(ChevronRight2, {});
|
|
3491
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ChevronLeft, {});
|
|
3492
|
+
};
|
|
3493
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3494
|
+
"button",
|
|
3495
|
+
{
|
|
3496
|
+
ref,
|
|
3497
|
+
onClick,
|
|
3498
|
+
onMouseDown,
|
|
3499
|
+
className: `crow-copilot-toggle crow-copilot-toggle-${position} ${isOpen ? "open" : ""} ${isDragging ? "dragging" : ""}`,
|
|
3500
|
+
style: {
|
|
3501
|
+
cursor: isOpen ? "col-resize" : void 0
|
|
3502
|
+
},
|
|
3503
|
+
"aria-label": isOpen ? "Close Copilot" : "Open Copilot",
|
|
3504
|
+
title: isOpen ? "Close Copilot" : "Open Copilot",
|
|
3505
|
+
children: renderIcon()
|
|
3506
|
+
}
|
|
3507
|
+
);
|
|
3508
|
+
}
|
|
3509
|
+
);
|
|
3510
|
+
var DRAG_THRESHOLD = 5;
|
|
3511
|
+
var MIN_WIDTH = 280;
|
|
3512
|
+
var MAX_WIDTH = 800;
|
|
3452
3513
|
function CopilotContainer({
|
|
3453
3514
|
position,
|
|
3454
|
-
width,
|
|
3515
|
+
width: initialWidth,
|
|
3455
3516
|
defaultOpen,
|
|
3456
3517
|
children
|
|
3457
3518
|
}) {
|
|
3458
|
-
const [isOpen, setIsOpen] = React3.useState(
|
|
3519
|
+
const [isOpen, setIsOpen] = React3.useState(() => {
|
|
3520
|
+
try {
|
|
3521
|
+
const stored = sessionStorage.getItem("crow_copilot_open");
|
|
3522
|
+
if (stored !== null) return stored === "true";
|
|
3523
|
+
} catch {
|
|
3524
|
+
}
|
|
3525
|
+
return defaultOpen;
|
|
3526
|
+
});
|
|
3527
|
+
const [currentWidth, setCurrentWidth] = React3.useState(() => {
|
|
3528
|
+
try {
|
|
3529
|
+
const stored = sessionStorage.getItem("crow_copilot_width");
|
|
3530
|
+
if (stored) {
|
|
3531
|
+
const parsed = parseInt(stored, 10);
|
|
3532
|
+
if (parsed >= MIN_WIDTH && parsed <= MAX_WIDTH) return parsed;
|
|
3533
|
+
}
|
|
3534
|
+
} catch {
|
|
3535
|
+
}
|
|
3536
|
+
return initialWidth;
|
|
3537
|
+
});
|
|
3538
|
+
const [isDragging, setIsDragging] = React3.useState(false);
|
|
3539
|
+
React3.useEffect(() => {
|
|
3540
|
+
try {
|
|
3541
|
+
sessionStorage.setItem("crow_copilot_open", String(isOpen));
|
|
3542
|
+
} catch {
|
|
3543
|
+
}
|
|
3544
|
+
}, [isOpen]);
|
|
3545
|
+
React3.useEffect(() => {
|
|
3546
|
+
try {
|
|
3547
|
+
sessionStorage.setItem("crow_copilot_width", String(currentWidth));
|
|
3548
|
+
} catch {
|
|
3549
|
+
}
|
|
3550
|
+
}, [currentWidth]);
|
|
3551
|
+
const sidebarRef = React3.useRef(null);
|
|
3552
|
+
const toggleRef = React3.useRef(null);
|
|
3553
|
+
const dragStartXRef = React3.useRef(0);
|
|
3554
|
+
const dragStartWidthRef = React3.useRef(0);
|
|
3555
|
+
const hasDraggedRef = React3.useRef(false);
|
|
3556
|
+
const liveWidthRef = React3.useRef(initialWidth);
|
|
3557
|
+
const positionRef = React3.useRef(position);
|
|
3558
|
+
positionRef.current = position;
|
|
3559
|
+
React3.useEffect(() => {
|
|
3560
|
+
liveWidthRef.current = currentWidth;
|
|
3561
|
+
}, [currentWidth]);
|
|
3459
3562
|
React3.useEffect(() => {
|
|
3460
3563
|
document.documentElement.style.setProperty(
|
|
3461
3564
|
"--crow-copilot-width",
|
|
3462
|
-
`${
|
|
3565
|
+
`${currentWidth}px`
|
|
3463
3566
|
);
|
|
3464
|
-
}, [
|
|
3567
|
+
}, [currentWidth]);
|
|
3465
3568
|
React3.useEffect(() => {
|
|
3466
3569
|
const className = `crow-copilot-open-${position}`;
|
|
3467
3570
|
if (isOpen) {
|
|
@@ -3483,21 +3586,97 @@ function CopilotContainer({
|
|
|
3483
3586
|
delete window.crowCopilot;
|
|
3484
3587
|
};
|
|
3485
3588
|
}, []);
|
|
3589
|
+
const handleMouseMove = React3.useCallback(
|
|
3590
|
+
(e) => {
|
|
3591
|
+
const deltaX = e.clientX - dragStartXRef.current;
|
|
3592
|
+
if (!hasDraggedRef.current && Math.abs(deltaX) >= DRAG_THRESHOLD) {
|
|
3593
|
+
hasDraggedRef.current = true;
|
|
3594
|
+
document.body.style.transition = "none";
|
|
3595
|
+
document.body.style.cursor = "col-resize";
|
|
3596
|
+
document.body.style.userSelect = "none";
|
|
3597
|
+
document.body.classList.add("crow-copilot-resizing");
|
|
3598
|
+
if (sidebarRef.current) {
|
|
3599
|
+
sidebarRef.current.style.transition = "none";
|
|
3600
|
+
}
|
|
3601
|
+
if (toggleRef.current) {
|
|
3602
|
+
toggleRef.current.style.transition = "none";
|
|
3603
|
+
}
|
|
3604
|
+
setIsDragging(true);
|
|
3605
|
+
}
|
|
3606
|
+
if (!hasDraggedRef.current) return;
|
|
3607
|
+
const widthDelta = positionRef.current === "right" ? -deltaX : deltaX;
|
|
3608
|
+
const newWidth = Math.min(
|
|
3609
|
+
MAX_WIDTH,
|
|
3610
|
+
Math.max(MIN_WIDTH, dragStartWidthRef.current + widthDelta)
|
|
3611
|
+
);
|
|
3612
|
+
liveWidthRef.current = newWidth;
|
|
3613
|
+
const px = `${newWidth}px`;
|
|
3614
|
+
document.documentElement.style.setProperty("--crow-copilot-width", px);
|
|
3615
|
+
if (sidebarRef.current) {
|
|
3616
|
+
sidebarRef.current.style.width = px;
|
|
3617
|
+
}
|
|
3618
|
+
},
|
|
3619
|
+
[]
|
|
3620
|
+
// no deps — we use refs for everything to avoid stale closures
|
|
3621
|
+
);
|
|
3622
|
+
const handleMouseUp = React3.useCallback(() => {
|
|
3623
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
3624
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
3625
|
+
document.body.style.transition = "";
|
|
3626
|
+
document.body.style.cursor = "";
|
|
3627
|
+
document.body.style.userSelect = "";
|
|
3628
|
+
document.body.classList.remove("crow-copilot-resizing");
|
|
3629
|
+
if (sidebarRef.current) {
|
|
3630
|
+
sidebarRef.current.style.transition = "";
|
|
3631
|
+
}
|
|
3632
|
+
if (toggleRef.current) {
|
|
3633
|
+
toggleRef.current.style.transition = "";
|
|
3634
|
+
}
|
|
3635
|
+
if (hasDraggedRef.current) {
|
|
3636
|
+
setCurrentWidth(liveWidthRef.current);
|
|
3637
|
+
setIsDragging(false);
|
|
3638
|
+
} else {
|
|
3639
|
+
setIsDragging(false);
|
|
3640
|
+
setIsOpen((prev) => !prev);
|
|
3641
|
+
}
|
|
3642
|
+
}, [handleMouseMove]);
|
|
3643
|
+
const handleToggleMouseDown = React3.useCallback(
|
|
3644
|
+
(e) => {
|
|
3645
|
+
if (e.button !== 0 || !isOpen) return;
|
|
3646
|
+
e.preventDefault();
|
|
3647
|
+
e.stopPropagation();
|
|
3648
|
+
dragStartXRef.current = e.clientX;
|
|
3649
|
+
dragStartWidthRef.current = liveWidthRef.current;
|
|
3650
|
+
hasDraggedRef.current = false;
|
|
3651
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
3652
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
3653
|
+
},
|
|
3654
|
+
[isOpen, handleMouseMove, handleMouseUp]
|
|
3655
|
+
);
|
|
3656
|
+
const handleToggleClick = React3.useCallback(() => {
|
|
3657
|
+
if (!isOpen) {
|
|
3658
|
+
setIsOpen(true);
|
|
3659
|
+
}
|
|
3660
|
+
}, [isOpen]);
|
|
3486
3661
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3487
3662
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3488
3663
|
CopilotToggleButton,
|
|
3489
3664
|
{
|
|
3665
|
+
ref: toggleRef,
|
|
3490
3666
|
isOpen,
|
|
3491
3667
|
position,
|
|
3492
|
-
onClick:
|
|
3668
|
+
onClick: handleToggleClick,
|
|
3669
|
+
onMouseDown: handleToggleMouseDown,
|
|
3670
|
+
isDragging
|
|
3493
3671
|
}
|
|
3494
3672
|
),
|
|
3495
3673
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3496
3674
|
"div",
|
|
3497
3675
|
{
|
|
3676
|
+
ref: sidebarRef,
|
|
3498
3677
|
className: `crow-copilot-sidebar crow-copilot-sidebar-${position} ${isOpen ? "" : "closed"}`,
|
|
3499
|
-
style: { width: `${
|
|
3500
|
-
children: children({ close: () => setIsOpen(false) })
|
|
3678
|
+
style: { width: `${currentWidth}px` },
|
|
3679
|
+
children: children({ close: () => setIsOpen(false), currentWidth })
|
|
3501
3680
|
}
|
|
3502
3681
|
)
|
|
3503
3682
|
] });
|
|
@@ -3524,6 +3703,9 @@ function CrowCopilot({
|
|
|
3524
3703
|
getIdentityToken,
|
|
3525
3704
|
context
|
|
3526
3705
|
}) {
|
|
3706
|
+
const effectiveGetIdentityToken = getIdentityToken || window.__crow_identity_token_fetcher;
|
|
3707
|
+
const effectiveOnToolResult = onToolResult || window.__crow_on_tool_result;
|
|
3708
|
+
const effectiveToolRenderers = toolRenderers || window.__crow_tool_renderers;
|
|
3527
3709
|
const {
|
|
3528
3710
|
styles,
|
|
3529
3711
|
isLoading: isLoadingStyles,
|
|
@@ -3577,6 +3759,93 @@ function CrowCopilot({
|
|
|
3577
3759
|
window.crow?.("registerTools", autoTools);
|
|
3578
3760
|
}
|
|
3579
3761
|
}, [autoTools]);
|
|
3762
|
+
const embeddedInitialWidth = typeof width === "number" ? width : parseInt(String(width), 10) || 400;
|
|
3763
|
+
const [embeddedWidth, setEmbeddedWidth] = React3.useState(() => {
|
|
3764
|
+
try {
|
|
3765
|
+
const stored = sessionStorage.getItem("crow_embedded_width");
|
|
3766
|
+
if (stored) {
|
|
3767
|
+
const parsed = parseInt(stored, 10);
|
|
3768
|
+
if (parsed >= 280 && parsed <= 800) return parsed;
|
|
3769
|
+
}
|
|
3770
|
+
} catch {
|
|
3771
|
+
}
|
|
3772
|
+
return embeddedInitialWidth;
|
|
3773
|
+
});
|
|
3774
|
+
const [isCollapsed, setIsCollapsed] = React3.useState(() => {
|
|
3775
|
+
try {
|
|
3776
|
+
return sessionStorage.getItem("crow_embedded_collapsed") === "true";
|
|
3777
|
+
} catch {
|
|
3778
|
+
return false;
|
|
3779
|
+
}
|
|
3780
|
+
});
|
|
3781
|
+
React3.useEffect(() => {
|
|
3782
|
+
try {
|
|
3783
|
+
sessionStorage.setItem("crow_embedded_width", String(embeddedWidth));
|
|
3784
|
+
} catch {
|
|
3785
|
+
}
|
|
3786
|
+
}, [embeddedWidth]);
|
|
3787
|
+
React3.useEffect(() => {
|
|
3788
|
+
try {
|
|
3789
|
+
sessionStorage.setItem("crow_embedded_collapsed", String(isCollapsed));
|
|
3790
|
+
} catch {
|
|
3791
|
+
}
|
|
3792
|
+
}, [isCollapsed]);
|
|
3793
|
+
const embeddedContentRef = React3.useRef(null);
|
|
3794
|
+
const embeddedToggleRef = React3.useRef(null);
|
|
3795
|
+
const embeddedDragStartX = React3.useRef(0);
|
|
3796
|
+
const embeddedDragStartW = React3.useRef(0);
|
|
3797
|
+
const embeddedHasDragged = React3.useRef(false);
|
|
3798
|
+
const embeddedLiveWidth = React3.useRef(embeddedInitialWidth);
|
|
3799
|
+
const positionRef = React3.useRef(position);
|
|
3800
|
+
positionRef.current = position;
|
|
3801
|
+
React3.useEffect(() => {
|
|
3802
|
+
embeddedLiveWidth.current = embeddedWidth;
|
|
3803
|
+
}, [embeddedWidth]);
|
|
3804
|
+
const embeddedMouseMove = React3.useCallback((e) => {
|
|
3805
|
+
const dx = e.clientX - embeddedDragStartX.current;
|
|
3806
|
+
if (!embeddedHasDragged.current && Math.abs(dx) >= 5) {
|
|
3807
|
+
embeddedHasDragged.current = true;
|
|
3808
|
+
document.body.style.cursor = "col-resize";
|
|
3809
|
+
document.body.style.userSelect = "none";
|
|
3810
|
+
}
|
|
3811
|
+
if (!embeddedHasDragged.current) return;
|
|
3812
|
+
const delta = positionRef.current === "right" ? -dx : dx;
|
|
3813
|
+
const newW = Math.min(800, Math.max(280, embeddedDragStartW.current + delta));
|
|
3814
|
+
embeddedLiveWidth.current = newW;
|
|
3815
|
+
if (embeddedContentRef.current) {
|
|
3816
|
+
embeddedContentRef.current.style.width = `${newW}px`;
|
|
3817
|
+
}
|
|
3818
|
+
}, []);
|
|
3819
|
+
const embeddedMouseUp = React3.useCallback(() => {
|
|
3820
|
+
document.removeEventListener("mousemove", embeddedMouseMove);
|
|
3821
|
+
document.removeEventListener("mouseup", embeddedMouseUp);
|
|
3822
|
+
document.body.style.cursor = "";
|
|
3823
|
+
document.body.style.userSelect = "";
|
|
3824
|
+
if (embeddedHasDragged.current) {
|
|
3825
|
+
setEmbeddedWidth(embeddedLiveWidth.current);
|
|
3826
|
+
} else {
|
|
3827
|
+
setIsCollapsed((prev) => !prev);
|
|
3828
|
+
}
|
|
3829
|
+
}, [embeddedMouseMove]);
|
|
3830
|
+
const embeddedHandleMouseDown = React3.useCallback(
|
|
3831
|
+
(e) => {
|
|
3832
|
+
if (e.button !== 0) return;
|
|
3833
|
+
if (isCollapsed) return;
|
|
3834
|
+
e.preventDefault();
|
|
3835
|
+
e.stopPropagation();
|
|
3836
|
+
embeddedDragStartX.current = e.clientX;
|
|
3837
|
+
embeddedDragStartW.current = embeddedLiveWidth.current;
|
|
3838
|
+
embeddedHasDragged.current = false;
|
|
3839
|
+
document.addEventListener("mousemove", embeddedMouseMove);
|
|
3840
|
+
document.addEventListener("mouseup", embeddedMouseUp);
|
|
3841
|
+
},
|
|
3842
|
+
[isCollapsed, embeddedMouseMove, embeddedMouseUp]
|
|
3843
|
+
);
|
|
3844
|
+
const embeddedHandleClick = React3.useCallback(() => {
|
|
3845
|
+
if (isCollapsed) {
|
|
3846
|
+
setIsCollapsed(false);
|
|
3847
|
+
}
|
|
3848
|
+
}, [isCollapsed]);
|
|
3580
3849
|
const messagesContainerRef = React3.useRef(null);
|
|
3581
3850
|
const tabsScrollRef = React3.useRef(null);
|
|
3582
3851
|
const executeClientToolRef = React3.useRef(null);
|
|
@@ -3596,6 +3865,16 @@ function CrowCopilot({
|
|
|
3596
3865
|
const conversations = useConversations({ productId, apiUrl });
|
|
3597
3866
|
const [shouldRestoreHistory, setShouldRestoreHistory] = React3.useState(false);
|
|
3598
3867
|
const hasRestoredHistoryRef = React3.useRef(false);
|
|
3868
|
+
const activeConvStorageKey = `crow_active_conv_${productId}`;
|
|
3869
|
+
const pendingRestoreConvId = React3.useRef(null);
|
|
3870
|
+
const hasRestoredActiveConvRef = React3.useRef(false);
|
|
3871
|
+
if (pendingRestoreConvId.current === null) {
|
|
3872
|
+
try {
|
|
3873
|
+
pendingRestoreConvId.current = localStorage.getItem(activeConvStorageKey) || "";
|
|
3874
|
+
} catch {
|
|
3875
|
+
pendingRestoreConvId.current = "";
|
|
3876
|
+
}
|
|
3877
|
+
}
|
|
3599
3878
|
const chat = useChat({
|
|
3600
3879
|
productId,
|
|
3601
3880
|
apiUrl,
|
|
@@ -3627,7 +3906,7 @@ function CrowCopilot({
|
|
|
3627
3906
|
break;
|
|
3628
3907
|
}
|
|
3629
3908
|
},
|
|
3630
|
-
onToolResult,
|
|
3909
|
+
onToolResult: effectiveOnToolResult,
|
|
3631
3910
|
onToolCall: async (event) => {
|
|
3632
3911
|
if (event.type === "client_call" && event.toolName && event.toolCallId) {
|
|
3633
3912
|
try {
|
|
@@ -3682,6 +3961,32 @@ function CrowCopilot({
|
|
|
3682
3961
|
});
|
|
3683
3962
|
}
|
|
3684
3963
|
}, [shouldRestoreHistory, chat.conversationId, conversations, chat]);
|
|
3964
|
+
React3.useEffect(() => {
|
|
3965
|
+
if (isLoadingStyles || hasRestoredActiveConvRef.current) return;
|
|
3966
|
+
const timer = setTimeout(() => {
|
|
3967
|
+
if (hasRestoredActiveConvRef.current || isVerifiedUser) return;
|
|
3968
|
+
const savedId = pendingRestoreConvId.current;
|
|
3969
|
+
if (!savedId) return;
|
|
3970
|
+
hasRestoredActiveConvRef.current = true;
|
|
3971
|
+
pendingRestoreConvId.current = "";
|
|
3972
|
+
conversations.loadAnonymousConversationHistory(savedId).then((historyMessages) => {
|
|
3973
|
+
if (historyMessages.length > 0) {
|
|
3974
|
+
chat.loadMessages(historyMessages);
|
|
3975
|
+
chat.setConversationId(savedId);
|
|
3976
|
+
}
|
|
3977
|
+
}).catch(() => {
|
|
3978
|
+
});
|
|
3979
|
+
}, 500);
|
|
3980
|
+
return () => clearTimeout(timer);
|
|
3981
|
+
}, [isLoadingStyles]);
|
|
3982
|
+
React3.useEffect(() => {
|
|
3983
|
+
try {
|
|
3984
|
+
if (chat.conversationId) {
|
|
3985
|
+
localStorage.setItem(activeConvStorageKey, chat.conversationId);
|
|
3986
|
+
}
|
|
3987
|
+
} catch {
|
|
3988
|
+
}
|
|
3989
|
+
}, [chat.conversationId, activeConvStorageKey]);
|
|
3685
3990
|
React3.useEffect(() => {
|
|
3686
3991
|
if (variant === "floating") {
|
|
3687
3992
|
injectCopilotBodyStyles();
|
|
@@ -3715,6 +4020,19 @@ function CrowCopilot({
|
|
|
3715
4020
|
onIdentified: async () => {
|
|
3716
4021
|
setIsVerifiedUser(true);
|
|
3717
4022
|
await conversations.loadConversations();
|
|
4023
|
+
const savedId = pendingRestoreConvId.current;
|
|
4024
|
+
if (savedId && !hasRestoredActiveConvRef.current) {
|
|
4025
|
+
hasRestoredActiveConvRef.current = true;
|
|
4026
|
+
pendingRestoreConvId.current = "";
|
|
4027
|
+
try {
|
|
4028
|
+
const historyMessages = await conversations.loadConversationHistory(savedId);
|
|
4029
|
+
if (historyMessages.length > 0) {
|
|
4030
|
+
chat.loadMessages(historyMessages);
|
|
4031
|
+
chat.setConversationId(savedId);
|
|
4032
|
+
}
|
|
4033
|
+
} catch {
|
|
4034
|
+
}
|
|
4035
|
+
}
|
|
3718
4036
|
},
|
|
3719
4037
|
onReset: () => {
|
|
3720
4038
|
setIsVerifiedUser(false);
|
|
@@ -3773,11 +4091,11 @@ function CrowCopilot({
|
|
|
3773
4091
|
}
|
|
3774
4092
|
}, [isLoadingStyles, onReady]);
|
|
3775
4093
|
React3.useEffect(() => {
|
|
3776
|
-
if (!
|
|
4094
|
+
if (!effectiveGetIdentityToken || isLoadingStyles) return;
|
|
3777
4095
|
let cancelled = false;
|
|
3778
4096
|
const identify = async () => {
|
|
3779
4097
|
try {
|
|
3780
|
-
const token = await
|
|
4098
|
+
const token = await effectiveGetIdentityToken();
|
|
3781
4099
|
if (!cancelled && token) {
|
|
3782
4100
|
window.crow?.("identify", { token });
|
|
3783
4101
|
}
|
|
@@ -3792,7 +4110,7 @@ function CrowCopilot({
|
|
|
3792
4110
|
cancelled = true;
|
|
3793
4111
|
window.removeEventListener("crow:token-refresh-needed", handleRefresh);
|
|
3794
4112
|
};
|
|
3795
|
-
}, [
|
|
4113
|
+
}, [effectiveGetIdentityToken, isLoadingStyles]);
|
|
3796
4114
|
React3.useEffect(() => {
|
|
3797
4115
|
if (typeof window === "undefined") return;
|
|
3798
4116
|
if (context && Object.keys(context).length > 0) {
|
|
@@ -3966,7 +4284,7 @@ function CrowCopilot({
|
|
|
3966
4284
|
checkTabsOverflow();
|
|
3967
4285
|
}, [tabs.length, checkTabsOverflow]);
|
|
3968
4286
|
const widthStyle = typeof width === "number" ? `${width}px` : width;
|
|
3969
|
-
const renderCopilotContent = (overrideOnClose, forceShowClose) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4287
|
+
const renderCopilotContent = (overrideOnClose, forceShowClose, overrideWidth) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3970
4288
|
CopilotStyleProvider,
|
|
3971
4289
|
{
|
|
3972
4290
|
styles,
|
|
@@ -3977,7 +4295,7 @@ function CrowCopilot({
|
|
|
3977
4295
|
{
|
|
3978
4296
|
className: `crow-flex crow-flex-col crow-h-full ${position === "left" ? "crow-border-r" : "crow-border-l"} ${className || ""}`,
|
|
3979
4297
|
style: {
|
|
3980
|
-
width: widthStyle,
|
|
4298
|
+
width: overrideWidth ? typeof overrideWidth === "number" ? `${overrideWidth}px` : overrideWidth : widthStyle,
|
|
3981
4299
|
fontFamily: styles.typography.fontFamily,
|
|
3982
4300
|
fontSize: styles.typography.fontSize,
|
|
3983
4301
|
fontWeight: styles.typography.fontWeight,
|
|
@@ -4155,7 +4473,7 @@ function CrowCopilot({
|
|
|
4155
4473
|
activeToolCalls: chat.activeToolCalls,
|
|
4156
4474
|
isLoadingHistory: conversations.isLoadingHistory,
|
|
4157
4475
|
isGenerating: chat.isLoading,
|
|
4158
|
-
toolRenderers
|
|
4476
|
+
toolRenderers: effectiveToolRenderers
|
|
4159
4477
|
}
|
|
4160
4478
|
),
|
|
4161
4479
|
pendingConfirmation && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-px-4 crow-py-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4209,15 +4527,65 @@ function CrowCopilot({
|
|
|
4209
4527
|
}
|
|
4210
4528
|
);
|
|
4211
4529
|
const floatingWidth = typeof width === "number" ? width : parseInt(String(width), 10) || 400;
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4530
|
+
if (variant === "floating") {
|
|
4531
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ShadowContainer, { styles: WIDGET_CSS, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4532
|
+
CopilotContainer,
|
|
4533
|
+
{
|
|
4534
|
+
position,
|
|
4535
|
+
width: floatingWidth,
|
|
4536
|
+
defaultOpen,
|
|
4537
|
+
children: ({ close, currentWidth: resizedWidth }) => renderCopilotContent(close, true, resizedWidth)
|
|
4538
|
+
}
|
|
4539
|
+
) });
|
|
4540
|
+
}
|
|
4541
|
+
const isRight = position === "right";
|
|
4542
|
+
const edgeSide = isRight ? "left" : "right";
|
|
4543
|
+
const toggleIcon = isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#6b7280", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7.9 20A9 9 0 1 0 4 16.1L2 22Z" }) }) : /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#6b7280", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: isRight ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) : /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) });
|
|
4544
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", flexShrink: 0, height: "100%" }, children: [
|
|
4545
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4546
|
+
"button",
|
|
4547
|
+
{
|
|
4548
|
+
ref: embeddedToggleRef,
|
|
4549
|
+
onMouseDown: embeddedHandleMouseDown,
|
|
4550
|
+
onClick: embeddedHandleClick,
|
|
4551
|
+
style: {
|
|
4552
|
+
position: "absolute",
|
|
4553
|
+
[edgeSide]: "-12px",
|
|
4554
|
+
top: "50%",
|
|
4555
|
+
transform: "translateY(-50%)",
|
|
4556
|
+
zIndex: 10,
|
|
4557
|
+
width: "24px",
|
|
4558
|
+
height: "64px",
|
|
4559
|
+
display: "flex",
|
|
4560
|
+
alignItems: "center",
|
|
4561
|
+
justifyContent: "center",
|
|
4562
|
+
background: "#fff",
|
|
4563
|
+
border: "1px solid #e5e7eb",
|
|
4564
|
+
[isRight ? "borderRight" : "borderLeft"]: "none",
|
|
4565
|
+
borderRadius: isRight ? "8px 0 0 8px" : "0 8px 8px 0",
|
|
4566
|
+
cursor: isCollapsed ? "pointer" : "col-resize",
|
|
4567
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
|
|
4568
|
+
padding: 0,
|
|
4569
|
+
outline: "none"
|
|
4570
|
+
},
|
|
4571
|
+
"aria-label": isCollapsed ? "Open Copilot" : "Resize or close Copilot",
|
|
4572
|
+
children: toggleIcon
|
|
4573
|
+
}
|
|
4574
|
+
),
|
|
4575
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4576
|
+
"div",
|
|
4577
|
+
{
|
|
4578
|
+
ref: embeddedContentRef,
|
|
4579
|
+
style: {
|
|
4580
|
+
width: `${embeddedWidth}px`,
|
|
4581
|
+
height: "100%",
|
|
4582
|
+
display: isCollapsed ? "none" : "block",
|
|
4583
|
+
overflow: "hidden"
|
|
4584
|
+
},
|
|
4585
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ShadowContainer, { styles: WIDGET_CSS, children: renderCopilotContent(void 0, false, "100%") })
|
|
4586
|
+
}
|
|
4587
|
+
)
|
|
4588
|
+
] });
|
|
4221
4589
|
}
|
|
4222
4590
|
function PlusIcon({ className }) {
|
|
4223
4591
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|