@ai-me-chat/react 0.2.1 → 0.3.0
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 +375 -279
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -4
- package/dist/index.d.ts +23 -4
- package/dist/index.js +371 -276
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -13,20 +13,35 @@ function useAIMeContext() {
|
|
|
13
13
|
|
|
14
14
|
// src/provider.tsx
|
|
15
15
|
import { jsx } from "react/jsx-runtime";
|
|
16
|
-
function AIMeProvider({ endpoint, headers, onAction, children }) {
|
|
17
|
-
return /* @__PURE__ */ jsx(AIMeContext, { value: { endpoint, headers, onAction }, children });
|
|
16
|
+
function AIMeProvider({ endpoint, headers, onAction, stuckTimeout, children }) {
|
|
17
|
+
return /* @__PURE__ */ jsx(AIMeContext, { value: { endpoint, headers, onAction, stuckTimeout }, children });
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
// src/chat.tsx
|
|
21
|
-
import { useState as useState2, useRef as
|
|
21
|
+
import { useState as useState2, useRef as useRef3, useEffect as useEffect3, useCallback as useCallback3, useId as useId2, useMemo as useMemo2, Fragment } from "react";
|
|
22
22
|
|
|
23
23
|
// src/use-ai-me.ts
|
|
24
24
|
import { useChat } from "@ai-sdk/react";
|
|
25
25
|
import { DefaultChatTransport } from "ai";
|
|
26
|
-
import { useState, useCallback, useEffect, useRef } from "react";
|
|
26
|
+
import { useState, useCallback, useEffect, useRef, useMemo } from "react";
|
|
27
27
|
var STORAGE_KEY = "ai-me-messages";
|
|
28
|
+
function cleanAssistantText(text) {
|
|
29
|
+
return text.replace(/<tools>[\s\S]*?<\/tools>/g, "").trim();
|
|
30
|
+
}
|
|
31
|
+
function trimIncompleteToolCalls(messages) {
|
|
32
|
+
if (messages.length === 0) return messages;
|
|
33
|
+
const last = messages[messages.length - 1];
|
|
34
|
+
if (last.role !== "assistant") return messages;
|
|
35
|
+
const hasToolCall = last.parts.some((p) => p.type === "tool-call");
|
|
36
|
+
const hasToolResult = last.parts.some((p) => p.type === "tool-result");
|
|
37
|
+
if (hasToolCall && !hasToolResult) {
|
|
38
|
+
return messages.slice(0, -1);
|
|
39
|
+
}
|
|
40
|
+
return messages;
|
|
41
|
+
}
|
|
28
42
|
function useAIMe() {
|
|
29
|
-
const { endpoint, headers } = useAIMeContext();
|
|
43
|
+
const { endpoint, headers, stuckTimeout: configuredTimeout } = useAIMeContext();
|
|
44
|
+
const stuckTimeout = configuredTimeout ?? 3e4;
|
|
30
45
|
const [input, setInput] = useState("");
|
|
31
46
|
const initialized = useRef(false);
|
|
32
47
|
const chat = useChat({
|
|
@@ -35,6 +50,24 @@ function useAIMe() {
|
|
|
35
50
|
headers
|
|
36
51
|
})
|
|
37
52
|
});
|
|
53
|
+
const messages = useMemo(() => {
|
|
54
|
+
return chat.messages.map((m) => {
|
|
55
|
+
if (m.role !== "assistant") return m;
|
|
56
|
+
let changed = false;
|
|
57
|
+
const cleanedParts = m.parts.map((p) => {
|
|
58
|
+
if (p.type !== "text") return p;
|
|
59
|
+
const cleaned = cleanAssistantText(p.text);
|
|
60
|
+
if (cleaned === p.text) return p;
|
|
61
|
+
changed = true;
|
|
62
|
+
return { ...p, text: cleaned };
|
|
63
|
+
});
|
|
64
|
+
if (!changed) return m;
|
|
65
|
+
const nonEmptyParts = cleanedParts.filter(
|
|
66
|
+
(p) => p.type !== "text" || p.text.length > 0
|
|
67
|
+
);
|
|
68
|
+
return { ...m, parts: nonEmptyParts };
|
|
69
|
+
});
|
|
70
|
+
}, [chat.messages]);
|
|
38
71
|
useEffect(() => {
|
|
39
72
|
if (initialized.current) return;
|
|
40
73
|
initialized.current = true;
|
|
@@ -43,7 +76,10 @@ function useAIMe() {
|
|
|
43
76
|
if (stored) {
|
|
44
77
|
const parsed = JSON.parse(stored);
|
|
45
78
|
if (Array.isArray(parsed) && parsed.length > 0) {
|
|
46
|
-
|
|
79
|
+
const cleaned = trimIncompleteToolCalls(parsed);
|
|
80
|
+
if (cleaned.length > 0) {
|
|
81
|
+
chat.setMessages(cleaned);
|
|
82
|
+
}
|
|
47
83
|
}
|
|
48
84
|
}
|
|
49
85
|
} catch {
|
|
@@ -60,6 +96,14 @@ function useAIMe() {
|
|
|
60
96
|
} catch {
|
|
61
97
|
}
|
|
62
98
|
}, [chat.messages]);
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
if (stuckTimeout <= 0) return;
|
|
101
|
+
if (chat.status !== "submitted") return;
|
|
102
|
+
const timer = setTimeout(() => {
|
|
103
|
+
chat.stop();
|
|
104
|
+
}, stuckTimeout);
|
|
105
|
+
return () => clearTimeout(timer);
|
|
106
|
+
}, [chat.status, stuckTimeout, chat.stop]);
|
|
63
107
|
const handleInputChange = useCallback(
|
|
64
108
|
(e) => {
|
|
65
109
|
setInput(e.target.value);
|
|
@@ -84,7 +128,7 @@ function useAIMe() {
|
|
|
84
128
|
}, [chat]);
|
|
85
129
|
return {
|
|
86
130
|
/** Conversation messages */
|
|
87
|
-
messages
|
|
131
|
+
messages,
|
|
88
132
|
/** Current input value */
|
|
89
133
|
input,
|
|
90
134
|
/** Set input value */
|
|
@@ -104,7 +148,9 @@ function useAIMe() {
|
|
|
104
148
|
/** Set messages */
|
|
105
149
|
setMessages: chat.setMessages,
|
|
106
150
|
/** Clear all messages and session storage */
|
|
107
|
-
clearMessages
|
|
151
|
+
clearMessages,
|
|
152
|
+
/** Approve or reject a pending tool call (for confirmation flow) */
|
|
153
|
+
addToolApprovalResponse: chat.addToolApprovalResponse
|
|
108
154
|
};
|
|
109
155
|
}
|
|
110
156
|
|
|
@@ -306,8 +352,197 @@ var linkStyle = {
|
|
|
306
352
|
textUnderlineOffset: "2px"
|
|
307
353
|
};
|
|
308
354
|
|
|
355
|
+
// src/confirm.tsx
|
|
356
|
+
import { useRef as useRef2, useEffect as useEffect2, useId, useCallback as useCallback2 } from "react";
|
|
357
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
358
|
+
function AIMeConfirm({
|
|
359
|
+
action,
|
|
360
|
+
description,
|
|
361
|
+
parameters,
|
|
362
|
+
onConfirm,
|
|
363
|
+
onReject
|
|
364
|
+
}) {
|
|
365
|
+
const dialogRef = useRef2(null);
|
|
366
|
+
const cancelButtonRef = useRef2(null);
|
|
367
|
+
const titleId = useId();
|
|
368
|
+
const descriptionId = useId();
|
|
369
|
+
const handleKeyDown = useCallback2(
|
|
370
|
+
(e) => {
|
|
371
|
+
if (e.key === "Escape") {
|
|
372
|
+
e.preventDefault();
|
|
373
|
+
onReject();
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (e.key !== "Tab") return;
|
|
377
|
+
const dialog = dialogRef.current;
|
|
378
|
+
if (!dialog) return;
|
|
379
|
+
const focusable = dialog.querySelectorAll(
|
|
380
|
+
'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
381
|
+
);
|
|
382
|
+
if (focusable.length === 0) return;
|
|
383
|
+
const first = focusable[0];
|
|
384
|
+
const last = focusable[focusable.length - 1];
|
|
385
|
+
if (e.shiftKey) {
|
|
386
|
+
if (document.activeElement === first) {
|
|
387
|
+
e.preventDefault();
|
|
388
|
+
last.focus();
|
|
389
|
+
}
|
|
390
|
+
} else {
|
|
391
|
+
if (document.activeElement === last) {
|
|
392
|
+
e.preventDefault();
|
|
393
|
+
first.focus();
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
[onReject]
|
|
398
|
+
);
|
|
399
|
+
useEffect2(() => {
|
|
400
|
+
const previousFocus = document.activeElement;
|
|
401
|
+
cancelButtonRef.current?.focus();
|
|
402
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
403
|
+
return () => {
|
|
404
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
405
|
+
previousFocus?.focus();
|
|
406
|
+
};
|
|
407
|
+
}, [handleKeyDown]);
|
|
408
|
+
const overlayStyle = {
|
|
409
|
+
...defaultThemeVars,
|
|
410
|
+
position: "fixed",
|
|
411
|
+
inset: 0,
|
|
412
|
+
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
|
413
|
+
display: "flex",
|
|
414
|
+
alignItems: "center",
|
|
415
|
+
justifyContent: "center",
|
|
416
|
+
zIndex: 1e4,
|
|
417
|
+
fontFamily: "var(--ai-me-font)"
|
|
418
|
+
};
|
|
419
|
+
const dialogStyle = {
|
|
420
|
+
backgroundColor: "var(--ai-me-bg)",
|
|
421
|
+
borderRadius: "var(--ai-me-radius)",
|
|
422
|
+
padding: 24,
|
|
423
|
+
maxWidth: 420,
|
|
424
|
+
width: "90%",
|
|
425
|
+
boxShadow: "var(--ai-me-shadow)",
|
|
426
|
+
color: "var(--ai-me-text)"
|
|
427
|
+
};
|
|
428
|
+
const focusStyle = {
|
|
429
|
+
outline: "2px solid transparent",
|
|
430
|
+
outlineOffset: 2
|
|
431
|
+
};
|
|
432
|
+
function applyFocusRing(el) {
|
|
433
|
+
el.style.outline = "2px solid var(--ai-me-primary)";
|
|
434
|
+
el.style.outlineOffset = "2px";
|
|
435
|
+
}
|
|
436
|
+
function removeFocusRing(el) {
|
|
437
|
+
el.style.outline = "2px solid transparent";
|
|
438
|
+
el.style.outlineOffset = "2px";
|
|
439
|
+
}
|
|
440
|
+
return (
|
|
441
|
+
// Overlay is presentational — role and aria go on the inner dialog
|
|
442
|
+
/* @__PURE__ */ jsx3(
|
|
443
|
+
"div",
|
|
444
|
+
{
|
|
445
|
+
style: overlayStyle,
|
|
446
|
+
onClick: (e) => {
|
|
447
|
+
if (e.target === e.currentTarget) onReject();
|
|
448
|
+
},
|
|
449
|
+
"aria-hidden": "false",
|
|
450
|
+
children: /* @__PURE__ */ jsxs(
|
|
451
|
+
"div",
|
|
452
|
+
{
|
|
453
|
+
ref: dialogRef,
|
|
454
|
+
style: dialogStyle,
|
|
455
|
+
role: "alertdialog",
|
|
456
|
+
"aria-modal": "true",
|
|
457
|
+
"aria-labelledby": titleId,
|
|
458
|
+
"aria-describedby": descriptionId,
|
|
459
|
+
tabIndex: -1,
|
|
460
|
+
onClick: (e) => e.stopPropagation(),
|
|
461
|
+
children: [
|
|
462
|
+
/* @__PURE__ */ jsx3("h3", { id: titleId, style: { margin: "0 0 8px", fontSize: 16 }, children: "Confirm Action" }),
|
|
463
|
+
/* @__PURE__ */ jsx3("p", { style: { margin: "0 0 4px", fontSize: 14, fontWeight: 600 }, children: action }),
|
|
464
|
+
/* @__PURE__ */ jsx3(
|
|
465
|
+
"p",
|
|
466
|
+
{
|
|
467
|
+
id: descriptionId,
|
|
468
|
+
style: {
|
|
469
|
+
margin: "0 0 16px",
|
|
470
|
+
fontSize: 13,
|
|
471
|
+
color: "var(--ai-me-text-secondary)"
|
|
472
|
+
},
|
|
473
|
+
children: description
|
|
474
|
+
}
|
|
475
|
+
),
|
|
476
|
+
parameters && Object.keys(parameters).length > 0 && /* @__PURE__ */ jsx3(
|
|
477
|
+
"pre",
|
|
478
|
+
{
|
|
479
|
+
style: {
|
|
480
|
+
margin: "0 0 16px",
|
|
481
|
+
padding: 12,
|
|
482
|
+
backgroundColor: "var(--ai-me-bg-secondary)",
|
|
483
|
+
borderRadius: 8,
|
|
484
|
+
fontSize: 12,
|
|
485
|
+
overflow: "auto",
|
|
486
|
+
maxHeight: 200,
|
|
487
|
+
border: "1px solid var(--ai-me-border)"
|
|
488
|
+
},
|
|
489
|
+
children: JSON.stringify(parameters, null, 2)
|
|
490
|
+
}
|
|
491
|
+
),
|
|
492
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, justifyContent: "flex-end" }, children: [
|
|
493
|
+
/* @__PURE__ */ jsx3(
|
|
494
|
+
"button",
|
|
495
|
+
{
|
|
496
|
+
ref: cancelButtonRef,
|
|
497
|
+
type: "button",
|
|
498
|
+
onClick: onReject,
|
|
499
|
+
style: {
|
|
500
|
+
padding: "8px 16px",
|
|
501
|
+
border: "1px solid var(--ai-me-border)",
|
|
502
|
+
borderRadius: 8,
|
|
503
|
+
backgroundColor: "var(--ai-me-bg)",
|
|
504
|
+
color: "var(--ai-me-text)",
|
|
505
|
+
cursor: "pointer",
|
|
506
|
+
fontSize: 14,
|
|
507
|
+
...focusStyle
|
|
508
|
+
},
|
|
509
|
+
onFocus: (e) => applyFocusRing(e.currentTarget),
|
|
510
|
+
onBlur: (e) => removeFocusRing(e.currentTarget),
|
|
511
|
+
children: "Cancel"
|
|
512
|
+
}
|
|
513
|
+
),
|
|
514
|
+
/* @__PURE__ */ jsx3(
|
|
515
|
+
"button",
|
|
516
|
+
{
|
|
517
|
+
type: "button",
|
|
518
|
+
onClick: onConfirm,
|
|
519
|
+
style: {
|
|
520
|
+
padding: "8px 16px",
|
|
521
|
+
border: "none",
|
|
522
|
+
borderRadius: 8,
|
|
523
|
+
// #fff on var(--ai-me-primary) = #6366f1 → contrast ≈ 4.6:1 (passes AA)
|
|
524
|
+
backgroundColor: "var(--ai-me-primary)",
|
|
525
|
+
color: "#fff",
|
|
526
|
+
cursor: "pointer",
|
|
527
|
+
fontSize: 14,
|
|
528
|
+
...focusStyle
|
|
529
|
+
},
|
|
530
|
+
onFocus: (e) => applyFocusRing(e.currentTarget),
|
|
531
|
+
onBlur: (e) => removeFocusRing(e.currentTarget),
|
|
532
|
+
children: "Confirm"
|
|
533
|
+
}
|
|
534
|
+
)
|
|
535
|
+
] })
|
|
536
|
+
]
|
|
537
|
+
}
|
|
538
|
+
)
|
|
539
|
+
}
|
|
540
|
+
)
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
|
|
309
544
|
// src/chat.tsx
|
|
310
|
-
import { Fragment, jsx as
|
|
545
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
311
546
|
var srOnly = {
|
|
312
547
|
position: "absolute",
|
|
313
548
|
width: 1,
|
|
@@ -319,6 +554,12 @@ var srOnly = {
|
|
|
319
554
|
whiteSpace: "nowrap",
|
|
320
555
|
borderWidth: 0
|
|
321
556
|
};
|
|
557
|
+
function DefaultAIIcon() {
|
|
558
|
+
return /* @__PURE__ */ jsxs2("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
559
|
+
/* @__PURE__ */ jsx4("path", { d: "M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5Z" }),
|
|
560
|
+
/* @__PURE__ */ jsx4("path", { d: "M19 11l.75 2.25L22 14l-2.25.75L19 17l-.75-2.25L16 14l2.25-.75Z" })
|
|
561
|
+
] });
|
|
562
|
+
}
|
|
322
563
|
function AIMeChat({
|
|
323
564
|
position = "bottom-right",
|
|
324
565
|
theme,
|
|
@@ -327,15 +568,17 @@ function AIMeChat({
|
|
|
327
568
|
defaultOpen = false,
|
|
328
569
|
onToggle,
|
|
329
570
|
onToolComplete,
|
|
330
|
-
onMessageComplete
|
|
571
|
+
onMessageComplete,
|
|
572
|
+
triggerIcon,
|
|
573
|
+
renderConfirmation
|
|
331
574
|
}) {
|
|
332
575
|
const [open, setOpen] = useState2(defaultOpen);
|
|
333
|
-
const messagesEndRef =
|
|
334
|
-
const inputRef =
|
|
335
|
-
const panelRef =
|
|
336
|
-
const triggerRef =
|
|
337
|
-
const firedToolResults =
|
|
338
|
-
const prevStatus =
|
|
576
|
+
const messagesEndRef = useRef3(null);
|
|
577
|
+
const inputRef = useRef3(null);
|
|
578
|
+
const panelRef = useRef3(null);
|
|
579
|
+
const triggerRef = useRef3(null);
|
|
580
|
+
const firedToolResults = useRef3(/* @__PURE__ */ new Set());
|
|
581
|
+
const prevStatus = useRef3(null);
|
|
339
582
|
const {
|
|
340
583
|
messages,
|
|
341
584
|
input,
|
|
@@ -343,17 +586,18 @@ function AIMeChat({
|
|
|
343
586
|
handleSubmit,
|
|
344
587
|
status,
|
|
345
588
|
error,
|
|
346
|
-
setInput
|
|
589
|
+
setInput,
|
|
590
|
+
addToolApprovalResponse
|
|
347
591
|
} = useAIMe();
|
|
348
|
-
const titleId =
|
|
349
|
-
const messagesId =
|
|
592
|
+
const titleId = useId2();
|
|
593
|
+
const messagesId = useId2();
|
|
350
594
|
const isInline = position === "inline";
|
|
351
|
-
const toggleOpen =
|
|
595
|
+
const toggleOpen = useCallback3(() => {
|
|
352
596
|
const next = !open;
|
|
353
597
|
setOpen(next);
|
|
354
598
|
onToggle?.(next);
|
|
355
599
|
}, [open, onToggle]);
|
|
356
|
-
|
|
600
|
+
useEffect3(() => {
|
|
357
601
|
function handleKeyDown(e) {
|
|
358
602
|
if ((e.metaKey || e.ctrlKey) && e.key === ".") {
|
|
359
603
|
e.preventDefault();
|
|
@@ -363,10 +607,10 @@ function AIMeChat({
|
|
|
363
607
|
window.addEventListener("keydown", handleKeyDown);
|
|
364
608
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
365
609
|
}, [toggleOpen]);
|
|
366
|
-
|
|
610
|
+
useEffect3(() => {
|
|
367
611
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
368
612
|
}, [messages]);
|
|
369
|
-
|
|
613
|
+
useEffect3(() => {
|
|
370
614
|
if (!onToolComplete) return;
|
|
371
615
|
for (const message of messages) {
|
|
372
616
|
for (const part of message.parts) {
|
|
@@ -382,7 +626,7 @@ function AIMeChat({
|
|
|
382
626
|
}
|
|
383
627
|
}
|
|
384
628
|
}, [messages, onToolComplete]);
|
|
385
|
-
|
|
629
|
+
useEffect3(() => {
|
|
386
630
|
const prev = prevStatus.current;
|
|
387
631
|
prevStatus.current = status;
|
|
388
632
|
if (!onMessageComplete) return;
|
|
@@ -404,7 +648,7 @@ function AIMeChat({
|
|
|
404
648
|
toolCalls: toolCalls.length > 0 ? toolCalls : void 0
|
|
405
649
|
});
|
|
406
650
|
}, [status, messages, onMessageComplete]);
|
|
407
|
-
|
|
651
|
+
useEffect3(() => {
|
|
408
652
|
if (open) {
|
|
409
653
|
panelRef.current?.focus();
|
|
410
654
|
setTimeout(() => inputRef.current?.focus(), 0);
|
|
@@ -412,7 +656,7 @@ function AIMeChat({
|
|
|
412
656
|
triggerRef.current?.focus();
|
|
413
657
|
}
|
|
414
658
|
}, [open]);
|
|
415
|
-
|
|
659
|
+
useEffect3(() => {
|
|
416
660
|
if (!open || isInline) return;
|
|
417
661
|
function handleKeyDown(e) {
|
|
418
662
|
if (e.key === "Escape") {
|
|
@@ -444,6 +688,20 @@ function AIMeChat({
|
|
|
444
688
|
window.addEventListener("keydown", handleKeyDown);
|
|
445
689
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
446
690
|
}, [open, isInline, toggleOpen]);
|
|
691
|
+
const pendingToolCalls = useMemo2(() => {
|
|
692
|
+
const resultIds = /* @__PURE__ */ new Set();
|
|
693
|
+
const toolCalls = [];
|
|
694
|
+
for (const m of messages) {
|
|
695
|
+
for (const p of m.parts) {
|
|
696
|
+
if (p.type === "tool-result") {
|
|
697
|
+
resultIds.add(p.toolCallId);
|
|
698
|
+
} else if (p.type === "tool-call") {
|
|
699
|
+
toolCalls.push(p);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return toolCalls.filter((tc) => !resultIds.has(tc.toolCallId));
|
|
704
|
+
}, [messages]);
|
|
447
705
|
const themeVars = {
|
|
448
706
|
...defaultThemeVars,
|
|
449
707
|
...themeToVars(theme)
|
|
@@ -499,8 +757,8 @@ function AIMeChat({
|
|
|
499
757
|
zIndex: 9999
|
|
500
758
|
};
|
|
501
759
|
const isStreaming = status === "submitted" || status === "streaming";
|
|
502
|
-
return /* @__PURE__ */
|
|
503
|
-
/* @__PURE__ */
|
|
760
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
761
|
+
/* @__PURE__ */ jsx4(
|
|
504
762
|
"button",
|
|
505
763
|
{
|
|
506
764
|
ref: triggerRef,
|
|
@@ -510,10 +768,10 @@ function AIMeChat({
|
|
|
510
768
|
"aria-expanded": open,
|
|
511
769
|
"aria-controls": isInline ? void 0 : "ai-me-chat-panel",
|
|
512
770
|
type: "button",
|
|
513
|
-
children: /* @__PURE__ */
|
|
771
|
+
children: /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: triggerIcon ?? /* @__PURE__ */ jsx4(DefaultAIIcon, {}) })
|
|
514
772
|
}
|
|
515
773
|
),
|
|
516
|
-
/* @__PURE__ */
|
|
774
|
+
/* @__PURE__ */ jsxs2(
|
|
517
775
|
"div",
|
|
518
776
|
{
|
|
519
777
|
id: "ai-me-chat-panel",
|
|
@@ -525,7 +783,7 @@ function AIMeChat({
|
|
|
525
783
|
"aria-busy": isStreaming,
|
|
526
784
|
tabIndex: -1,
|
|
527
785
|
children: [
|
|
528
|
-
/* @__PURE__ */
|
|
786
|
+
/* @__PURE__ */ jsxs2(
|
|
529
787
|
"div",
|
|
530
788
|
{
|
|
531
789
|
style: {
|
|
@@ -537,8 +795,8 @@ function AIMeChat({
|
|
|
537
795
|
backgroundColor: "var(--ai-me-bg-secondary)"
|
|
538
796
|
},
|
|
539
797
|
children: [
|
|
540
|
-
/* @__PURE__ */
|
|
541
|
-
!isInline && /* @__PURE__ */
|
|
798
|
+
/* @__PURE__ */ jsx4("span", { id: titleId, style: { fontWeight: 600, fontSize: 14 }, children: "AI Assistant" }),
|
|
799
|
+
!isInline && /* @__PURE__ */ jsx4(
|
|
542
800
|
"button",
|
|
543
801
|
{
|
|
544
802
|
onClick: toggleOpen,
|
|
@@ -562,13 +820,13 @@ function AIMeChat({
|
|
|
562
820
|
},
|
|
563
821
|
"aria-label": "Close chat",
|
|
564
822
|
type: "button",
|
|
565
|
-
children: /* @__PURE__ */
|
|
823
|
+
children: /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "\u2715" })
|
|
566
824
|
}
|
|
567
825
|
)
|
|
568
826
|
]
|
|
569
827
|
}
|
|
570
828
|
),
|
|
571
|
-
/* @__PURE__ */
|
|
829
|
+
/* @__PURE__ */ jsx4(
|
|
572
830
|
"a",
|
|
573
831
|
{
|
|
574
832
|
href: "#ai-me-chat-input",
|
|
@@ -598,7 +856,7 @@ function AIMeChat({
|
|
|
598
856
|
children: "Skip to message input"
|
|
599
857
|
}
|
|
600
858
|
),
|
|
601
|
-
/* @__PURE__ */
|
|
859
|
+
/* @__PURE__ */ jsxs2(
|
|
602
860
|
"div",
|
|
603
861
|
{
|
|
604
862
|
id: messagesId,
|
|
@@ -614,9 +872,9 @@ function AIMeChat({
|
|
|
614
872
|
gap: 12
|
|
615
873
|
},
|
|
616
874
|
children: [
|
|
617
|
-
messages.length === 0 && /* @__PURE__ */
|
|
618
|
-
/* @__PURE__ */
|
|
619
|
-
suggestedPrompts && suggestedPrompts.length > 0 && /* @__PURE__ */
|
|
875
|
+
messages.length === 0 && /* @__PURE__ */ jsxs2("div", { style: { color: "var(--ai-me-text-secondary)", fontSize: 14 }, children: [
|
|
876
|
+
/* @__PURE__ */ jsx4("p", { children: welcomeMessage }),
|
|
877
|
+
suggestedPrompts && suggestedPrompts.length > 0 && /* @__PURE__ */ jsxs2(
|
|
620
878
|
"div",
|
|
621
879
|
{
|
|
622
880
|
style: {
|
|
@@ -626,8 +884,8 @@ function AIMeChat({
|
|
|
626
884
|
gap: 8
|
|
627
885
|
},
|
|
628
886
|
children: [
|
|
629
|
-
/* @__PURE__ */
|
|
630
|
-
suggestedPrompts.map((prompt) => /* @__PURE__ */
|
|
887
|
+
/* @__PURE__ */ jsx4("p", { style: { margin: "0 0 4px", fontSize: 12, fontWeight: 500 }, children: "Suggested questions:" }),
|
|
888
|
+
suggestedPrompts.map((prompt) => /* @__PURE__ */ jsx4(
|
|
631
889
|
"button",
|
|
632
890
|
{
|
|
633
891
|
type: "button",
|
|
@@ -664,7 +922,7 @@ function AIMeChat({
|
|
|
664
922
|
messages.map((m) => {
|
|
665
923
|
const hasTextContent = m.parts.some((p) => p.type === "text");
|
|
666
924
|
if (!hasTextContent && m.role === "assistant") return null;
|
|
667
|
-
return /* @__PURE__ */
|
|
925
|
+
return /* @__PURE__ */ jsxs2(
|
|
668
926
|
"div",
|
|
669
927
|
{
|
|
670
928
|
style: {
|
|
@@ -680,16 +938,16 @@ function AIMeChat({
|
|
|
680
938
|
wordBreak: "break-word"
|
|
681
939
|
},
|
|
682
940
|
children: [
|
|
683
|
-
/* @__PURE__ */
|
|
941
|
+
/* @__PURE__ */ jsx4("span", { style: srOnly, children: m.role === "user" ? "You: " : "Assistant: " }),
|
|
684
942
|
m.parts.map(
|
|
685
|
-
(p, i) => p.type === "text" ? /* @__PURE__ */
|
|
943
|
+
(p, i) => p.type === "text" ? /* @__PURE__ */ jsx4("span", { children: m.role === "assistant" ? renderMarkdown(p.text) : p.text }, i) : null
|
|
686
944
|
)
|
|
687
945
|
]
|
|
688
946
|
},
|
|
689
947
|
m.id
|
|
690
948
|
);
|
|
691
949
|
}),
|
|
692
|
-
status === "submitted" && /* @__PURE__ */
|
|
950
|
+
status === "submitted" && /* @__PURE__ */ jsx4(
|
|
693
951
|
"div",
|
|
694
952
|
{
|
|
695
953
|
"aria-label": "Assistant is thinking",
|
|
@@ -698,10 +956,10 @@ function AIMeChat({
|
|
|
698
956
|
color: "var(--ai-me-text-secondary)",
|
|
699
957
|
fontSize: 13
|
|
700
958
|
},
|
|
701
|
-
children: /* @__PURE__ */
|
|
959
|
+
children: /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "Thinking\u2026" })
|
|
702
960
|
}
|
|
703
961
|
),
|
|
704
|
-
error && /* @__PURE__ */
|
|
962
|
+
error && /* @__PURE__ */ jsx4(
|
|
705
963
|
"div",
|
|
706
964
|
{
|
|
707
965
|
role: "alert",
|
|
@@ -717,11 +975,11 @@ function AIMeChat({
|
|
|
717
975
|
children: "Something went wrong. Please try again."
|
|
718
976
|
}
|
|
719
977
|
),
|
|
720
|
-
/* @__PURE__ */
|
|
978
|
+
/* @__PURE__ */ jsx4("div", { ref: messagesEndRef, "aria-hidden": "true" })
|
|
721
979
|
]
|
|
722
980
|
}
|
|
723
981
|
),
|
|
724
|
-
/* @__PURE__ */
|
|
982
|
+
/* @__PURE__ */ jsxs2(
|
|
725
983
|
"form",
|
|
726
984
|
{
|
|
727
985
|
onSubmit: handleSubmit,
|
|
@@ -732,7 +990,7 @@ function AIMeChat({
|
|
|
732
990
|
gap: 8
|
|
733
991
|
},
|
|
734
992
|
children: [
|
|
735
|
-
/* @__PURE__ */
|
|
993
|
+
/* @__PURE__ */ jsx4(
|
|
736
994
|
"label",
|
|
737
995
|
{
|
|
738
996
|
htmlFor: "ai-me-chat-input",
|
|
@@ -740,7 +998,7 @@ function AIMeChat({
|
|
|
740
998
|
children: "Message to AI Assistant"
|
|
741
999
|
}
|
|
742
1000
|
),
|
|
743
|
-
/* @__PURE__ */
|
|
1001
|
+
/* @__PURE__ */ jsx4(
|
|
744
1002
|
"input",
|
|
745
1003
|
{
|
|
746
1004
|
id: "ai-me-chat-input",
|
|
@@ -771,7 +1029,7 @@ function AIMeChat({
|
|
|
771
1029
|
}
|
|
772
1030
|
}
|
|
773
1031
|
),
|
|
774
|
-
/* @__PURE__ */
|
|
1032
|
+
/* @__PURE__ */ jsx4(
|
|
775
1033
|
"button",
|
|
776
1034
|
{
|
|
777
1035
|
type: "submit",
|
|
@@ -806,13 +1064,38 @@ function AIMeChat({
|
|
|
806
1064
|
)
|
|
807
1065
|
]
|
|
808
1066
|
}
|
|
809
|
-
)
|
|
1067
|
+
),
|
|
1068
|
+
pendingToolCalls.map((tc) => {
|
|
1069
|
+
const onConfirm = () => addToolApprovalResponse({ id: tc.toolCallId, approved: true });
|
|
1070
|
+
const onCancel = () => addToolApprovalResponse({ id: tc.toolCallId, approved: false, reason: "User cancelled" });
|
|
1071
|
+
return renderConfirmation ? /* @__PURE__ */ jsx4(Fragment, { children: renderConfirmation({
|
|
1072
|
+
tool: {
|
|
1073
|
+
name: tc.toolName,
|
|
1074
|
+
httpMethod: "",
|
|
1075
|
+
path: "",
|
|
1076
|
+
description: tc.toolName
|
|
1077
|
+
},
|
|
1078
|
+
params: tc.args,
|
|
1079
|
+
onConfirm,
|
|
1080
|
+
onCancel
|
|
1081
|
+
}) }, tc.toolCallId) : /* @__PURE__ */ jsx4(
|
|
1082
|
+
AIMeConfirm,
|
|
1083
|
+
{
|
|
1084
|
+
action: tc.toolName,
|
|
1085
|
+
description: `Execute ${tc.toolName}?`,
|
|
1086
|
+
parameters: tc.args,
|
|
1087
|
+
onConfirm,
|
|
1088
|
+
onReject: onCancel
|
|
1089
|
+
},
|
|
1090
|
+
tc.toolCallId
|
|
1091
|
+
);
|
|
1092
|
+
})
|
|
810
1093
|
] });
|
|
811
1094
|
}
|
|
812
1095
|
|
|
813
1096
|
// src/command-palette.tsx
|
|
814
|
-
import { useState as useState3, useEffect as
|
|
815
|
-
import { Fragment as
|
|
1097
|
+
import { useState as useState3, useEffect as useEffect4, useRef as useRef4, useCallback as useCallback4, useId as useId3 } from "react";
|
|
1098
|
+
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
816
1099
|
var defaultCommands = [
|
|
817
1100
|
{
|
|
818
1101
|
id: "help",
|
|
@@ -859,14 +1142,14 @@ function AIMeCommandPalette({
|
|
|
859
1142
|
const [open, setOpen] = useState3(false);
|
|
860
1143
|
const [query, setQuery] = useState3("");
|
|
861
1144
|
const [selectedIndex, setSelectedIndex] = useState3(0);
|
|
862
|
-
const inputRef =
|
|
863
|
-
const listRef =
|
|
864
|
-
const dialogRef =
|
|
865
|
-
const previousFocusRef =
|
|
1145
|
+
const inputRef = useRef4(null);
|
|
1146
|
+
const listRef = useRef4(null);
|
|
1147
|
+
const dialogRef = useRef4(null);
|
|
1148
|
+
const previousFocusRef = useRef4(null);
|
|
866
1149
|
const { sendMessage } = useAIMe();
|
|
867
|
-
const titleId =
|
|
868
|
-
const inputId =
|
|
869
|
-
const toggle =
|
|
1150
|
+
const titleId = useId3();
|
|
1151
|
+
const inputId = useId3();
|
|
1152
|
+
const toggle = useCallback4(
|
|
870
1153
|
(next) => {
|
|
871
1154
|
setOpen(next);
|
|
872
1155
|
setQuery("");
|
|
@@ -875,7 +1158,7 @@ function AIMeCommandPalette({
|
|
|
875
1158
|
},
|
|
876
1159
|
[onToggle]
|
|
877
1160
|
);
|
|
878
|
-
|
|
1161
|
+
useEffect4(() => {
|
|
879
1162
|
function handleKeyDown2(e) {
|
|
880
1163
|
const metaMatch = shortcut.meta ? e.metaKey : true;
|
|
881
1164
|
const ctrlMatch = shortcut.ctrl ? e.ctrlKey : !shortcut.meta ? e.ctrlKey : true;
|
|
@@ -890,7 +1173,7 @@ function AIMeCommandPalette({
|
|
|
890
1173
|
window.addEventListener("keydown", handleKeyDown2);
|
|
891
1174
|
return () => window.removeEventListener("keydown", handleKeyDown2);
|
|
892
1175
|
}, [open, shortcut, toggle]);
|
|
893
|
-
|
|
1176
|
+
useEffect4(() => {
|
|
894
1177
|
if (open) {
|
|
895
1178
|
setTimeout(() => inputRef.current?.focus(), 0);
|
|
896
1179
|
} else {
|
|
@@ -900,7 +1183,7 @@ function AIMeCommandPalette({
|
|
|
900
1183
|
}
|
|
901
1184
|
}
|
|
902
1185
|
}, [open]);
|
|
903
|
-
|
|
1186
|
+
useEffect4(() => {
|
|
904
1187
|
if (!open) return;
|
|
905
1188
|
function handleFocusTrap(e) {
|
|
906
1189
|
if (e.key !== "Tab") return;
|
|
@@ -930,12 +1213,12 @@ function AIMeCommandPalette({
|
|
|
930
1213
|
const filtered = query.trim() ? commands.filter(
|
|
931
1214
|
(cmd) => cmd.label.toLowerCase().includes(query.toLowerCase()) || cmd.description?.toLowerCase().includes(query.toLowerCase()) || cmd.category?.toLowerCase().includes(query.toLowerCase())
|
|
932
1215
|
) : commands;
|
|
933
|
-
|
|
1216
|
+
useEffect4(() => {
|
|
934
1217
|
if (selectedIndex >= filtered.length) {
|
|
935
1218
|
setSelectedIndex(Math.max(0, filtered.length - 1));
|
|
936
1219
|
}
|
|
937
1220
|
}, [filtered.length, selectedIndex]);
|
|
938
|
-
|
|
1221
|
+
useEffect4(() => {
|
|
939
1222
|
const list = listRef.current;
|
|
940
1223
|
if (!list) return;
|
|
941
1224
|
const selected = list.children[selectedIndex];
|
|
@@ -980,8 +1263,8 @@ function AIMeCommandPalette({
|
|
|
980
1263
|
grouped.get(cat).push(cmd);
|
|
981
1264
|
}
|
|
982
1265
|
let flatIndex = 0;
|
|
983
|
-
return /* @__PURE__ */
|
|
984
|
-
/* @__PURE__ */
|
|
1266
|
+
return /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
1267
|
+
/* @__PURE__ */ jsx5(
|
|
985
1268
|
"div",
|
|
986
1269
|
{
|
|
987
1270
|
onClick: () => toggle(false),
|
|
@@ -994,7 +1277,7 @@ function AIMeCommandPalette({
|
|
|
994
1277
|
"aria-hidden": "true"
|
|
995
1278
|
}
|
|
996
1279
|
),
|
|
997
|
-
/* @__PURE__ */
|
|
1280
|
+
/* @__PURE__ */ jsxs3(
|
|
998
1281
|
"div",
|
|
999
1282
|
{
|
|
1000
1283
|
ref: dialogRef,
|
|
@@ -1022,10 +1305,10 @@ function AIMeCommandPalette({
|
|
|
1022
1305
|
"aria-labelledby": titleId,
|
|
1023
1306
|
tabIndex: -1,
|
|
1024
1307
|
children: [
|
|
1025
|
-
/* @__PURE__ */
|
|
1026
|
-
/* @__PURE__ */
|
|
1027
|
-
/* @__PURE__ */
|
|
1028
|
-
/* @__PURE__ */
|
|
1308
|
+
/* @__PURE__ */ jsx5("h2", { id: titleId, style: srOnly2, children: "Command Palette" }),
|
|
1309
|
+
/* @__PURE__ */ jsxs3("div", { style: { padding: "12px 16px", borderBottom: "1px solid var(--ai-me-border)" }, children: [
|
|
1310
|
+
/* @__PURE__ */ jsx5("label", { htmlFor: inputId, style: srOnly2, children: "Search commands or ask AI" }),
|
|
1311
|
+
/* @__PURE__ */ jsx5(
|
|
1029
1312
|
"input",
|
|
1030
1313
|
{
|
|
1031
1314
|
id: inputId,
|
|
@@ -1063,7 +1346,7 @@ function AIMeCommandPalette({
|
|
|
1063
1346
|
}
|
|
1064
1347
|
)
|
|
1065
1348
|
] }),
|
|
1066
|
-
/* @__PURE__ */
|
|
1349
|
+
/* @__PURE__ */ jsxs3(
|
|
1067
1350
|
"div",
|
|
1068
1351
|
{
|
|
1069
1352
|
id: "ai-me-cmd-listbox",
|
|
@@ -1072,7 +1355,7 @@ function AIMeCommandPalette({
|
|
|
1072
1355
|
role: "listbox",
|
|
1073
1356
|
"aria-label": "Commands",
|
|
1074
1357
|
children: [
|
|
1075
|
-
filtered.length === 0 && query.trim() && /* @__PURE__ */
|
|
1358
|
+
filtered.length === 0 && query.trim() && /* @__PURE__ */ jsxs3(
|
|
1076
1359
|
"div",
|
|
1077
1360
|
{
|
|
1078
1361
|
role: "option",
|
|
@@ -1092,8 +1375,8 @@ function AIMeCommandPalette({
|
|
|
1092
1375
|
),
|
|
1093
1376
|
Array.from(grouped.entries()).map(([category, items]) => (
|
|
1094
1377
|
// role="group" with aria-label for the category heading
|
|
1095
|
-
/* @__PURE__ */
|
|
1096
|
-
/* @__PURE__ */
|
|
1378
|
+
/* @__PURE__ */ jsxs3("div", { role: "group", "aria-label": category, children: [
|
|
1379
|
+
/* @__PURE__ */ jsx5(
|
|
1097
1380
|
"div",
|
|
1098
1381
|
{
|
|
1099
1382
|
"aria-hidden": "true",
|
|
@@ -1111,7 +1394,7 @@ function AIMeCommandPalette({
|
|
|
1111
1394
|
items.map((cmd) => {
|
|
1112
1395
|
const idx = flatIndex++;
|
|
1113
1396
|
const isSelected = idx === selectedIndex;
|
|
1114
|
-
return /* @__PURE__ */
|
|
1397
|
+
return /* @__PURE__ */ jsxs3(
|
|
1115
1398
|
"div",
|
|
1116
1399
|
{
|
|
1117
1400
|
id: `cmd-${cmd.id}`,
|
|
@@ -1144,10 +1427,10 @@ function AIMeCommandPalette({
|
|
|
1144
1427
|
},
|
|
1145
1428
|
children: [
|
|
1146
1429
|
cmd.icon && // Icon is decorative — label comes from cmd.label
|
|
1147
|
-
/* @__PURE__ */
|
|
1148
|
-
/* @__PURE__ */
|
|
1149
|
-
/* @__PURE__ */
|
|
1150
|
-
cmd.description && /* @__PURE__ */
|
|
1430
|
+
/* @__PURE__ */ jsx5("span", { "aria-hidden": "true", style: { fontSize: 16, flexShrink: 0 }, children: cmd.icon }),
|
|
1431
|
+
/* @__PURE__ */ jsxs3("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
1432
|
+
/* @__PURE__ */ jsx5("div", { style: { fontSize: 14, fontWeight: 500 }, children: cmd.label }),
|
|
1433
|
+
cmd.description && /* @__PURE__ */ jsx5(
|
|
1151
1434
|
"div",
|
|
1152
1435
|
{
|
|
1153
1436
|
style: {
|
|
@@ -1171,7 +1454,7 @@ function AIMeCommandPalette({
|
|
|
1171
1454
|
]
|
|
1172
1455
|
}
|
|
1173
1456
|
),
|
|
1174
|
-
/* @__PURE__ */
|
|
1457
|
+
/* @__PURE__ */ jsxs3(
|
|
1175
1458
|
"div",
|
|
1176
1459
|
{
|
|
1177
1460
|
"aria-hidden": "true",
|
|
@@ -1184,9 +1467,9 @@ function AIMeCommandPalette({
|
|
|
1184
1467
|
gap: 16
|
|
1185
1468
|
},
|
|
1186
1469
|
children: [
|
|
1187
|
-
/* @__PURE__ */
|
|
1188
|
-
/* @__PURE__ */
|
|
1189
|
-
/* @__PURE__ */
|
|
1470
|
+
/* @__PURE__ */ jsx5("span", { children: "\u2191\u2193 Navigate" }),
|
|
1471
|
+
/* @__PURE__ */ jsx5("span", { children: "\u21B5 Select" }),
|
|
1472
|
+
/* @__PURE__ */ jsx5("span", { children: "Esc Close" })
|
|
1190
1473
|
]
|
|
1191
1474
|
}
|
|
1192
1475
|
)
|
|
@@ -1195,200 +1478,12 @@ function AIMeCommandPalette({
|
|
|
1195
1478
|
)
|
|
1196
1479
|
] });
|
|
1197
1480
|
}
|
|
1198
|
-
|
|
1199
|
-
// src/confirm.tsx
|
|
1200
|
-
import { useRef as useRef4, useEffect as useEffect4, useId as useId3, useCallback as useCallback4 } from "react";
|
|
1201
|
-
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1202
|
-
function AIMeConfirm({
|
|
1203
|
-
action,
|
|
1204
|
-
description,
|
|
1205
|
-
parameters,
|
|
1206
|
-
onConfirm,
|
|
1207
|
-
onReject
|
|
1208
|
-
}) {
|
|
1209
|
-
const dialogRef = useRef4(null);
|
|
1210
|
-
const cancelButtonRef = useRef4(null);
|
|
1211
|
-
const titleId = useId3();
|
|
1212
|
-
const descriptionId = useId3();
|
|
1213
|
-
const handleKeyDown = useCallback4(
|
|
1214
|
-
(e) => {
|
|
1215
|
-
if (e.key === "Escape") {
|
|
1216
|
-
e.preventDefault();
|
|
1217
|
-
onReject();
|
|
1218
|
-
return;
|
|
1219
|
-
}
|
|
1220
|
-
if (e.key !== "Tab") return;
|
|
1221
|
-
const dialog = dialogRef.current;
|
|
1222
|
-
if (!dialog) return;
|
|
1223
|
-
const focusable = dialog.querySelectorAll(
|
|
1224
|
-
'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
1225
|
-
);
|
|
1226
|
-
if (focusable.length === 0) return;
|
|
1227
|
-
const first = focusable[0];
|
|
1228
|
-
const last = focusable[focusable.length - 1];
|
|
1229
|
-
if (e.shiftKey) {
|
|
1230
|
-
if (document.activeElement === first) {
|
|
1231
|
-
e.preventDefault();
|
|
1232
|
-
last.focus();
|
|
1233
|
-
}
|
|
1234
|
-
} else {
|
|
1235
|
-
if (document.activeElement === last) {
|
|
1236
|
-
e.preventDefault();
|
|
1237
|
-
first.focus();
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
},
|
|
1241
|
-
[onReject]
|
|
1242
|
-
);
|
|
1243
|
-
useEffect4(() => {
|
|
1244
|
-
const previousFocus = document.activeElement;
|
|
1245
|
-
cancelButtonRef.current?.focus();
|
|
1246
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
1247
|
-
return () => {
|
|
1248
|
-
window.removeEventListener("keydown", handleKeyDown);
|
|
1249
|
-
previousFocus?.focus();
|
|
1250
|
-
};
|
|
1251
|
-
}, [handleKeyDown]);
|
|
1252
|
-
const overlayStyle = {
|
|
1253
|
-
...defaultThemeVars,
|
|
1254
|
-
position: "fixed",
|
|
1255
|
-
inset: 0,
|
|
1256
|
-
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
|
1257
|
-
display: "flex",
|
|
1258
|
-
alignItems: "center",
|
|
1259
|
-
justifyContent: "center",
|
|
1260
|
-
zIndex: 1e4,
|
|
1261
|
-
fontFamily: "var(--ai-me-font)"
|
|
1262
|
-
};
|
|
1263
|
-
const dialogStyle = {
|
|
1264
|
-
backgroundColor: "var(--ai-me-bg)",
|
|
1265
|
-
borderRadius: "var(--ai-me-radius)",
|
|
1266
|
-
padding: 24,
|
|
1267
|
-
maxWidth: 420,
|
|
1268
|
-
width: "90%",
|
|
1269
|
-
boxShadow: "var(--ai-me-shadow)",
|
|
1270
|
-
color: "var(--ai-me-text)"
|
|
1271
|
-
};
|
|
1272
|
-
const focusStyle = {
|
|
1273
|
-
outline: "2px solid transparent",
|
|
1274
|
-
outlineOffset: 2
|
|
1275
|
-
};
|
|
1276
|
-
function applyFocusRing(el) {
|
|
1277
|
-
el.style.outline = "2px solid var(--ai-me-primary)";
|
|
1278
|
-
el.style.outlineOffset = "2px";
|
|
1279
|
-
}
|
|
1280
|
-
function removeFocusRing(el) {
|
|
1281
|
-
el.style.outline = "2px solid transparent";
|
|
1282
|
-
el.style.outlineOffset = "2px";
|
|
1283
|
-
}
|
|
1284
|
-
return (
|
|
1285
|
-
// Overlay is presentational — role and aria go on the inner dialog
|
|
1286
|
-
/* @__PURE__ */ jsx5(
|
|
1287
|
-
"div",
|
|
1288
|
-
{
|
|
1289
|
-
style: overlayStyle,
|
|
1290
|
-
onClick: (e) => {
|
|
1291
|
-
if (e.target === e.currentTarget) onReject();
|
|
1292
|
-
},
|
|
1293
|
-
"aria-hidden": "false",
|
|
1294
|
-
children: /* @__PURE__ */ jsxs3(
|
|
1295
|
-
"div",
|
|
1296
|
-
{
|
|
1297
|
-
ref: dialogRef,
|
|
1298
|
-
style: dialogStyle,
|
|
1299
|
-
role: "alertdialog",
|
|
1300
|
-
"aria-modal": "true",
|
|
1301
|
-
"aria-labelledby": titleId,
|
|
1302
|
-
"aria-describedby": descriptionId,
|
|
1303
|
-
tabIndex: -1,
|
|
1304
|
-
onClick: (e) => e.stopPropagation(),
|
|
1305
|
-
children: [
|
|
1306
|
-
/* @__PURE__ */ jsx5("h3", { id: titleId, style: { margin: "0 0 8px", fontSize: 16 }, children: "Confirm Action" }),
|
|
1307
|
-
/* @__PURE__ */ jsx5("p", { style: { margin: "0 0 4px", fontSize: 14, fontWeight: 600 }, children: action }),
|
|
1308
|
-
/* @__PURE__ */ jsx5(
|
|
1309
|
-
"p",
|
|
1310
|
-
{
|
|
1311
|
-
id: descriptionId,
|
|
1312
|
-
style: {
|
|
1313
|
-
margin: "0 0 16px",
|
|
1314
|
-
fontSize: 13,
|
|
1315
|
-
color: "var(--ai-me-text-secondary)"
|
|
1316
|
-
},
|
|
1317
|
-
children: description
|
|
1318
|
-
}
|
|
1319
|
-
),
|
|
1320
|
-
parameters && Object.keys(parameters).length > 0 && /* @__PURE__ */ jsx5(
|
|
1321
|
-
"pre",
|
|
1322
|
-
{
|
|
1323
|
-
style: {
|
|
1324
|
-
margin: "0 0 16px",
|
|
1325
|
-
padding: 12,
|
|
1326
|
-
backgroundColor: "var(--ai-me-bg-secondary)",
|
|
1327
|
-
borderRadius: 8,
|
|
1328
|
-
fontSize: 12,
|
|
1329
|
-
overflow: "auto",
|
|
1330
|
-
maxHeight: 200,
|
|
1331
|
-
border: "1px solid var(--ai-me-border)"
|
|
1332
|
-
},
|
|
1333
|
-
children: JSON.stringify(parameters, null, 2)
|
|
1334
|
-
}
|
|
1335
|
-
),
|
|
1336
|
-
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: 8, justifyContent: "flex-end" }, children: [
|
|
1337
|
-
/* @__PURE__ */ jsx5(
|
|
1338
|
-
"button",
|
|
1339
|
-
{
|
|
1340
|
-
ref: cancelButtonRef,
|
|
1341
|
-
type: "button",
|
|
1342
|
-
onClick: onReject,
|
|
1343
|
-
style: {
|
|
1344
|
-
padding: "8px 16px",
|
|
1345
|
-
border: "1px solid var(--ai-me-border)",
|
|
1346
|
-
borderRadius: 8,
|
|
1347
|
-
backgroundColor: "var(--ai-me-bg)",
|
|
1348
|
-
color: "var(--ai-me-text)",
|
|
1349
|
-
cursor: "pointer",
|
|
1350
|
-
fontSize: 14,
|
|
1351
|
-
...focusStyle
|
|
1352
|
-
},
|
|
1353
|
-
onFocus: (e) => applyFocusRing(e.currentTarget),
|
|
1354
|
-
onBlur: (e) => removeFocusRing(e.currentTarget),
|
|
1355
|
-
children: "Cancel"
|
|
1356
|
-
}
|
|
1357
|
-
),
|
|
1358
|
-
/* @__PURE__ */ jsx5(
|
|
1359
|
-
"button",
|
|
1360
|
-
{
|
|
1361
|
-
type: "button",
|
|
1362
|
-
onClick: onConfirm,
|
|
1363
|
-
style: {
|
|
1364
|
-
padding: "8px 16px",
|
|
1365
|
-
border: "none",
|
|
1366
|
-
borderRadius: 8,
|
|
1367
|
-
// #fff on var(--ai-me-primary) = #6366f1 → contrast ≈ 4.6:1 (passes AA)
|
|
1368
|
-
backgroundColor: "var(--ai-me-primary)",
|
|
1369
|
-
color: "#fff",
|
|
1370
|
-
cursor: "pointer",
|
|
1371
|
-
fontSize: 14,
|
|
1372
|
-
...focusStyle
|
|
1373
|
-
},
|
|
1374
|
-
onFocus: (e) => applyFocusRing(e.currentTarget),
|
|
1375
|
-
onBlur: (e) => removeFocusRing(e.currentTarget),
|
|
1376
|
-
children: "Confirm"
|
|
1377
|
-
}
|
|
1378
|
-
)
|
|
1379
|
-
] })
|
|
1380
|
-
]
|
|
1381
|
-
}
|
|
1382
|
-
)
|
|
1383
|
-
}
|
|
1384
|
-
)
|
|
1385
|
-
);
|
|
1386
|
-
}
|
|
1387
1481
|
export {
|
|
1388
1482
|
AIMeChat,
|
|
1389
1483
|
AIMeCommandPalette,
|
|
1390
1484
|
AIMeConfirm,
|
|
1391
1485
|
AIMeProvider,
|
|
1486
|
+
cleanAssistantText,
|
|
1392
1487
|
renderMarkdown,
|
|
1393
1488
|
useAIMe,
|
|
1394
1489
|
useAIMeContext
|