@ai-me-chat/react 0.0.1

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.js ADDED
@@ -0,0 +1,1349 @@
1
+ "use client";
2
+
3
+ // src/context.tsx
4
+ import { createContext, useContext } from "react";
5
+ var AIMeContext = createContext(null);
6
+ function useAIMeContext() {
7
+ const ctx = useContext(AIMeContext);
8
+ if (!ctx) {
9
+ throw new Error("useAIMe must be used within an <AIMeProvider>");
10
+ }
11
+ return ctx;
12
+ }
13
+
14
+ // src/provider.tsx
15
+ import { jsx } from "react/jsx-runtime";
16
+ function AIMeProvider({ endpoint, headers, children }) {
17
+ return /* @__PURE__ */ jsx(AIMeContext, { value: { endpoint, headers }, children });
18
+ }
19
+
20
+ // src/chat.tsx
21
+ import { useState as useState2, useRef as useRef2, useEffect as useEffect2, useCallback as useCallback2, useId } from "react";
22
+
23
+ // src/use-ai-me.ts
24
+ import { useChat } from "@ai-sdk/react";
25
+ import { DefaultChatTransport } from "ai";
26
+ import { useState, useCallback, useEffect, useRef } from "react";
27
+ var STORAGE_KEY = "ai-me-messages";
28
+ function useAIMe() {
29
+ const { endpoint, headers } = useAIMeContext();
30
+ const [input, setInput] = useState("");
31
+ const initialized = useRef(false);
32
+ const chat = useChat({
33
+ transport: new DefaultChatTransport({
34
+ api: endpoint,
35
+ headers
36
+ })
37
+ });
38
+ useEffect(() => {
39
+ if (initialized.current) return;
40
+ initialized.current = true;
41
+ try {
42
+ const stored = sessionStorage.getItem(STORAGE_KEY);
43
+ if (stored) {
44
+ const parsed = JSON.parse(stored);
45
+ if (Array.isArray(parsed) && parsed.length > 0) {
46
+ chat.setMessages(parsed);
47
+ }
48
+ }
49
+ } catch {
50
+ }
51
+ }, []);
52
+ useEffect(() => {
53
+ if (!initialized.current) return;
54
+ try {
55
+ if (chat.messages.length > 0) {
56
+ sessionStorage.setItem(STORAGE_KEY, JSON.stringify(chat.messages));
57
+ } else {
58
+ sessionStorage.removeItem(STORAGE_KEY);
59
+ }
60
+ } catch {
61
+ }
62
+ }, [chat.messages]);
63
+ const handleInputChange = useCallback(
64
+ (e) => {
65
+ setInput(e.target.value);
66
+ },
67
+ []
68
+ );
69
+ const handleSubmit = useCallback(
70
+ (e) => {
71
+ e?.preventDefault();
72
+ if (!input.trim()) return;
73
+ chat.sendMessage({ text: input });
74
+ setInput("");
75
+ },
76
+ [input, chat]
77
+ );
78
+ const clearMessages = useCallback(() => {
79
+ chat.setMessages([]);
80
+ try {
81
+ sessionStorage.removeItem(STORAGE_KEY);
82
+ } catch {
83
+ }
84
+ }, [chat]);
85
+ return {
86
+ /** Conversation messages */
87
+ messages: chat.messages,
88
+ /** Current input value */
89
+ input,
90
+ /** Set input value */
91
+ setInput,
92
+ /** Handle input change */
93
+ handleInputChange,
94
+ /** Submit the current message */
95
+ handleSubmit,
96
+ /** Send a message directly */
97
+ sendMessage: chat.sendMessage,
98
+ /** Chat status: "ready" | "submitted" | "streaming" */
99
+ status: chat.status,
100
+ /** Error if any */
101
+ error: chat.error,
102
+ /** Stop streaming */
103
+ stop: chat.stop,
104
+ /** Set messages */
105
+ setMessages: chat.setMessages,
106
+ /** Clear all messages and session storage */
107
+ clearMessages
108
+ };
109
+ }
110
+
111
+ // src/styles.ts
112
+ var defaultThemeVars = {
113
+ "--ai-me-primary": "#6366f1",
114
+ "--ai-me-primary-hover": "#4f46e5",
115
+ "--ai-me-bg": "#ffffff",
116
+ "--ai-me-bg-secondary": "#f9fafb",
117
+ "--ai-me-text": "#111827",
118
+ "--ai-me-text-secondary": "#6b7280",
119
+ "--ai-me-border": "#e5e7eb",
120
+ "--ai-me-radius": "12px",
121
+ "--ai-me-font": "system-ui, -apple-system, sans-serif",
122
+ "--ai-me-shadow": "0 4px 24px rgba(0, 0, 0, 0.12)"
123
+ };
124
+ function themeToVars(theme) {
125
+ if (!theme) return {};
126
+ const vars = {};
127
+ if (theme.primaryColor) vars["--ai-me-primary"] = theme.primaryColor;
128
+ if (theme.backgroundColor) vars["--ai-me-bg"] = theme.backgroundColor;
129
+ if (theme.textColor) vars["--ai-me-text"] = theme.textColor;
130
+ if (theme.borderRadius) vars["--ai-me-radius"] = theme.borderRadius;
131
+ if (theme.fontFamily) vars["--ai-me-font"] = theme.fontFamily;
132
+ return vars;
133
+ }
134
+
135
+ // src/markdown.tsx
136
+ import { jsx as jsx2 } from "react/jsx-runtime";
137
+ function renderMarkdown(text) {
138
+ const lines = text.split("\n");
139
+ const result = [];
140
+ let i = 0;
141
+ while (i < lines.length) {
142
+ const line = lines[i];
143
+ if (line.trimStart().startsWith("```")) {
144
+ const lang = line.trimStart().slice(3).trim();
145
+ const codeLines = [];
146
+ i++;
147
+ while (i < lines.length && !lines[i].trimStart().startsWith("```")) {
148
+ codeLines.push(lines[i]);
149
+ i++;
150
+ }
151
+ i++;
152
+ result.push(
153
+ /* @__PURE__ */ jsx2(
154
+ "pre",
155
+ {
156
+ style: codeBlockStyle,
157
+ "data-lang": lang || void 0,
158
+ children: /* @__PURE__ */ jsx2("code", { children: codeLines.join("\n") })
159
+ },
160
+ `code-${result.length}`
161
+ )
162
+ );
163
+ continue;
164
+ }
165
+ if (/^[\s]*[-*]\s/.test(line)) {
166
+ const listItems = [];
167
+ while (i < lines.length && /^[\s]*[-*]\s/.test(lines[i])) {
168
+ listItems.push(
169
+ /* @__PURE__ */ jsx2("li", { style: { marginBottom: 2 }, children: renderInline(lines[i].replace(/^[\s]*[-*]\s/, "")) }, listItems.length)
170
+ );
171
+ i++;
172
+ }
173
+ result.push(
174
+ /* @__PURE__ */ jsx2(
175
+ "ul",
176
+ {
177
+ style: { margin: "4px 0", paddingLeft: 20, listStyleType: "disc" },
178
+ children: listItems
179
+ },
180
+ `ul-${result.length}`
181
+ )
182
+ );
183
+ continue;
184
+ }
185
+ if (/^[\s]*\d+\.\s/.test(line)) {
186
+ const listItems = [];
187
+ while (i < lines.length && /^[\s]*\d+\.\s/.test(lines[i])) {
188
+ listItems.push(
189
+ /* @__PURE__ */ jsx2("li", { style: { marginBottom: 2 }, children: renderInline(lines[i].replace(/^[\s]*\d+\.\s/, "")) }, listItems.length)
190
+ );
191
+ i++;
192
+ }
193
+ result.push(
194
+ /* @__PURE__ */ jsx2(
195
+ "ol",
196
+ {
197
+ style: { margin: "4px 0", paddingLeft: 20 },
198
+ children: listItems
199
+ },
200
+ `ol-${result.length}`
201
+ )
202
+ );
203
+ continue;
204
+ }
205
+ const headingMatch = /^(#{1,6})\s+(.+)$/.exec(line);
206
+ if (headingMatch) {
207
+ const level = Math.max(headingMatch[1].length, 3);
208
+ const fontSize = { 3: 15, 4: 14, 5: 13, 6: 13 }[level] ?? 14;
209
+ result.push(
210
+ /* @__PURE__ */ jsx2(
211
+ "p",
212
+ {
213
+ style: { fontWeight: 600, fontSize, margin: "8px 0 4px" },
214
+ children: renderInline(headingMatch[2])
215
+ },
216
+ `h-${result.length}`
217
+ )
218
+ );
219
+ i++;
220
+ continue;
221
+ }
222
+ if (line.trim() === "") {
223
+ i++;
224
+ continue;
225
+ }
226
+ result.push(
227
+ /* @__PURE__ */ jsx2(
228
+ "span",
229
+ {
230
+ style: { display: "block", marginBottom: 2 },
231
+ children: renderInline(line)
232
+ },
233
+ `p-${result.length}`
234
+ )
235
+ );
236
+ i++;
237
+ }
238
+ return result;
239
+ }
240
+ function renderInline(text) {
241
+ const result = [];
242
+ const pattern = /(`[^`]+`|\*\*[^*]+\*\*|\*[^*]+\*|\[[^\]]+\]\([^)]+\))/g;
243
+ let lastIndex = 0;
244
+ let match;
245
+ while ((match = pattern.exec(text)) !== null) {
246
+ if (match.index > lastIndex) {
247
+ result.push(text.slice(lastIndex, match.index));
248
+ }
249
+ const token = match[0];
250
+ if (token.startsWith("`")) {
251
+ result.push(
252
+ /* @__PURE__ */ jsx2("code", { style: inlineCodeStyle, children: token.slice(1, -1) }, result.length)
253
+ );
254
+ } else if (token.startsWith("**")) {
255
+ result.push(
256
+ /* @__PURE__ */ jsx2("strong", { children: token.slice(2, -2) }, result.length)
257
+ );
258
+ } else if (token.startsWith("*")) {
259
+ result.push(/* @__PURE__ */ jsx2("em", { children: token.slice(1, -1) }, result.length));
260
+ } else if (token.startsWith("[")) {
261
+ const linkMatch = /\[([^\]]+)\]\(([^)]+)\)/.exec(token);
262
+ if (linkMatch) {
263
+ result.push(
264
+ /* @__PURE__ */ jsx2(
265
+ "a",
266
+ {
267
+ href: linkMatch[2],
268
+ target: "_blank",
269
+ rel: "noopener noreferrer",
270
+ style: linkStyle,
271
+ children: linkMatch[1]
272
+ },
273
+ result.length
274
+ )
275
+ );
276
+ }
277
+ }
278
+ lastIndex = match.index + token.length;
279
+ }
280
+ if (lastIndex < text.length) {
281
+ result.push(text.slice(lastIndex));
282
+ }
283
+ return result;
284
+ }
285
+ var codeBlockStyle = {
286
+ margin: "6px 0",
287
+ padding: "10px 12px",
288
+ borderRadius: 6,
289
+ backgroundColor: "rgba(0,0,0,0.15)",
290
+ fontSize: 12,
291
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
292
+ overflow: "auto",
293
+ whiteSpace: "pre",
294
+ lineHeight: 1.5
295
+ };
296
+ var inlineCodeStyle = {
297
+ padding: "1px 5px",
298
+ borderRadius: 3,
299
+ backgroundColor: "rgba(0,0,0,0.12)",
300
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
301
+ fontSize: "0.9em"
302
+ };
303
+ var linkStyle = {
304
+ color: "var(--ai-me-primary, #6366f1)",
305
+ textDecoration: "underline",
306
+ textUnderlineOffset: "2px"
307
+ };
308
+
309
+ // src/chat.tsx
310
+ import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
311
+ var srOnly = {
312
+ position: "absolute",
313
+ width: 1,
314
+ height: 1,
315
+ padding: 0,
316
+ margin: -1,
317
+ overflow: "hidden",
318
+ clip: "rect(0,0,0,0)",
319
+ whiteSpace: "nowrap",
320
+ borderWidth: 0
321
+ };
322
+ function AIMeChat({
323
+ position = "bottom-right",
324
+ theme,
325
+ welcomeMessage = "Hi! I can help you navigate and use this app. What would you like to do?",
326
+ suggestedPrompts,
327
+ defaultOpen = false,
328
+ onToggle
329
+ }) {
330
+ const [open, setOpen] = useState2(defaultOpen);
331
+ const messagesEndRef = useRef2(null);
332
+ const inputRef = useRef2(null);
333
+ const panelRef = useRef2(null);
334
+ const triggerRef = useRef2(null);
335
+ const {
336
+ messages,
337
+ input,
338
+ handleInputChange,
339
+ handleSubmit,
340
+ status,
341
+ error,
342
+ setInput
343
+ } = useAIMe();
344
+ const titleId = useId();
345
+ const messagesId = useId();
346
+ const isInline = position === "inline";
347
+ const toggleOpen = useCallback2(() => {
348
+ const next = !open;
349
+ setOpen(next);
350
+ onToggle?.(next);
351
+ }, [open, onToggle]);
352
+ useEffect2(() => {
353
+ function handleKeyDown(e) {
354
+ if ((e.metaKey || e.ctrlKey) && e.key === ".") {
355
+ e.preventDefault();
356
+ toggleOpen();
357
+ }
358
+ }
359
+ window.addEventListener("keydown", handleKeyDown);
360
+ return () => window.removeEventListener("keydown", handleKeyDown);
361
+ }, [toggleOpen]);
362
+ useEffect2(() => {
363
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
364
+ }, [messages]);
365
+ useEffect2(() => {
366
+ if (open) {
367
+ panelRef.current?.focus();
368
+ setTimeout(() => inputRef.current?.focus(), 0);
369
+ } else {
370
+ triggerRef.current?.focus();
371
+ }
372
+ }, [open]);
373
+ useEffect2(() => {
374
+ if (!open || isInline) return;
375
+ function handleKeyDown(e) {
376
+ if (e.key === "Escape") {
377
+ e.preventDefault();
378
+ toggleOpen();
379
+ return;
380
+ }
381
+ if (e.key !== "Tab") return;
382
+ const panel = panelRef.current;
383
+ if (!panel) return;
384
+ const focusable = panel.querySelectorAll(
385
+ 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])'
386
+ );
387
+ if (focusable.length === 0) return;
388
+ const first = focusable[0];
389
+ const last = focusable[focusable.length - 1];
390
+ if (e.shiftKey) {
391
+ if (document.activeElement === first) {
392
+ e.preventDefault();
393
+ last.focus();
394
+ }
395
+ } else {
396
+ if (document.activeElement === last) {
397
+ e.preventDefault();
398
+ first.focus();
399
+ }
400
+ }
401
+ }
402
+ window.addEventListener("keydown", handleKeyDown);
403
+ return () => window.removeEventListener("keydown", handleKeyDown);
404
+ }, [open, isInline, toggleOpen]);
405
+ const themeVars = {
406
+ ...defaultThemeVars,
407
+ ...themeToVars(theme)
408
+ };
409
+ const panelStyle = isInline ? {
410
+ ...themeVars,
411
+ width: "100%",
412
+ height: "100%",
413
+ display: "flex",
414
+ flexDirection: "column",
415
+ fontFamily: "var(--ai-me-font)",
416
+ color: "var(--ai-me-text)",
417
+ backgroundColor: "var(--ai-me-bg)",
418
+ borderRadius: "var(--ai-me-radius)",
419
+ border: "1px solid var(--ai-me-border)",
420
+ overflow: "hidden"
421
+ } : {
422
+ ...themeVars,
423
+ position: "fixed",
424
+ bottom: 24,
425
+ ...position === "bottom-right" ? { right: 24 } : { left: 24 },
426
+ width: 380,
427
+ maxHeight: "70vh",
428
+ display: open ? "flex" : "none",
429
+ flexDirection: "column",
430
+ fontFamily: "var(--ai-me-font)",
431
+ color: "var(--ai-me-text)",
432
+ backgroundColor: "var(--ai-me-bg)",
433
+ borderRadius: "var(--ai-me-radius)",
434
+ boxShadow: "var(--ai-me-shadow)",
435
+ border: "1px solid var(--ai-me-border)",
436
+ overflow: "hidden",
437
+ zIndex: 9999
438
+ };
439
+ const triggerStyle = {
440
+ ...themeVars,
441
+ position: "fixed",
442
+ bottom: 24,
443
+ ...position === "bottom-right" ? { right: 24 } : { left: 24 },
444
+ width: 56,
445
+ height: 56,
446
+ borderRadius: "50%",
447
+ backgroundColor: "var(--ai-me-primary)",
448
+ color: "#fff",
449
+ border: "none",
450
+ cursor: "pointer",
451
+ display: isInline || open ? "none" : "flex",
452
+ alignItems: "center",
453
+ justifyContent: "center",
454
+ boxShadow: "var(--ai-me-shadow)",
455
+ fontSize: 24,
456
+ zIndex: 9999
457
+ };
458
+ const isStreaming = status === "submitted" || status === "streaming";
459
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
460
+ /* @__PURE__ */ jsx3(
461
+ "button",
462
+ {
463
+ ref: triggerRef,
464
+ onClick: toggleOpen,
465
+ style: triggerStyle,
466
+ "aria-label": "Open AI chat",
467
+ "aria-expanded": open,
468
+ "aria-controls": isInline ? void 0 : "ai-me-chat-panel",
469
+ type: "button",
470
+ children: /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\u{1F4AC}" })
471
+ }
472
+ ),
473
+ /* @__PURE__ */ jsxs(
474
+ "div",
475
+ {
476
+ id: "ai-me-chat-panel",
477
+ ref: panelRef,
478
+ style: panelStyle,
479
+ role: "dialog",
480
+ "aria-modal": isInline ? void 0 : "true",
481
+ "aria-labelledby": titleId,
482
+ "aria-busy": isStreaming,
483
+ tabIndex: -1,
484
+ children: [
485
+ /* @__PURE__ */ jsxs(
486
+ "div",
487
+ {
488
+ style: {
489
+ padding: "12px 16px",
490
+ borderBottom: "1px solid var(--ai-me-border)",
491
+ display: "flex",
492
+ alignItems: "center",
493
+ justifyContent: "space-between",
494
+ backgroundColor: "var(--ai-me-bg-secondary)"
495
+ },
496
+ children: [
497
+ /* @__PURE__ */ jsx3("span", { id: titleId, style: { fontWeight: 600, fontSize: 14 }, children: "AI Assistant" }),
498
+ !isInline && /* @__PURE__ */ jsx3(
499
+ "button",
500
+ {
501
+ onClick: toggleOpen,
502
+ style: {
503
+ background: "none",
504
+ border: "none",
505
+ cursor: "pointer",
506
+ fontSize: 18,
507
+ color: "var(--ai-me-text-secondary)",
508
+ padding: 4,
509
+ borderRadius: 4,
510
+ // Visible focus indicator without outline:none
511
+ outline: "2px solid transparent",
512
+ outlineOffset: 2
513
+ },
514
+ onFocus: (e) => {
515
+ e.currentTarget.style.outline = "2px solid var(--ai-me-primary)";
516
+ },
517
+ onBlur: (e) => {
518
+ e.currentTarget.style.outline = "2px solid transparent";
519
+ },
520
+ "aria-label": "Close chat",
521
+ type: "button",
522
+ children: /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\u2715" })
523
+ }
524
+ )
525
+ ]
526
+ }
527
+ ),
528
+ /* @__PURE__ */ jsx3(
529
+ "a",
530
+ {
531
+ href: "#ai-me-chat-input",
532
+ style: {
533
+ ...srOnly
534
+ // Reveal on focus so keyboard users can see it
535
+ },
536
+ onFocus: (e) => {
537
+ Object.assign(e.currentTarget.style, {
538
+ position: "static",
539
+ width: "auto",
540
+ height: "auto",
541
+ padding: "4px 8px",
542
+ margin: 0,
543
+ overflow: "visible",
544
+ clip: "auto",
545
+ whiteSpace: "normal",
546
+ backgroundColor: "var(--ai-me-primary)",
547
+ color: "#fff",
548
+ fontSize: 12,
549
+ borderRadius: 4
550
+ });
551
+ },
552
+ onBlur: (e) => {
553
+ Object.assign(e.currentTarget.style, srOnly);
554
+ },
555
+ children: "Skip to message input"
556
+ }
557
+ ),
558
+ /* @__PURE__ */ jsxs(
559
+ "div",
560
+ {
561
+ id: messagesId,
562
+ "aria-live": "polite",
563
+ "aria-label": "Conversation",
564
+ "aria-relevant": "additions",
565
+ style: {
566
+ flex: 1,
567
+ overflowY: "auto",
568
+ padding: 16,
569
+ display: "flex",
570
+ flexDirection: "column",
571
+ gap: 12
572
+ },
573
+ children: [
574
+ messages.length === 0 && /* @__PURE__ */ jsxs("div", { style: { color: "var(--ai-me-text-secondary)", fontSize: 14 }, children: [
575
+ /* @__PURE__ */ jsx3("p", { children: welcomeMessage }),
576
+ suggestedPrompts && suggestedPrompts.length > 0 && /* @__PURE__ */ jsxs(
577
+ "div",
578
+ {
579
+ style: {
580
+ marginTop: 12,
581
+ display: "flex",
582
+ flexDirection: "column",
583
+ gap: 8
584
+ },
585
+ children: [
586
+ /* @__PURE__ */ jsx3("p", { style: { margin: "0 0 4px", fontSize: 12, fontWeight: 500 }, children: "Suggested questions:" }),
587
+ suggestedPrompts.map((prompt) => /* @__PURE__ */ jsx3(
588
+ "button",
589
+ {
590
+ type: "button",
591
+ onClick: () => {
592
+ setInput(prompt);
593
+ inputRef.current?.focus();
594
+ },
595
+ style: {
596
+ padding: "8px 12px",
597
+ border: "1px solid var(--ai-me-border)",
598
+ borderRadius: 8,
599
+ background: "var(--ai-me-bg)",
600
+ cursor: "pointer",
601
+ textAlign: "left",
602
+ fontSize: 13,
603
+ color: "var(--ai-me-text)",
604
+ outline: "2px solid transparent",
605
+ outlineOffset: 2
606
+ },
607
+ onFocus: (e) => {
608
+ e.currentTarget.style.outline = "2px solid var(--ai-me-primary)";
609
+ },
610
+ onBlur: (e) => {
611
+ e.currentTarget.style.outline = "2px solid transparent";
612
+ },
613
+ children: prompt
614
+ },
615
+ prompt
616
+ ))
617
+ ]
618
+ }
619
+ )
620
+ ] }),
621
+ messages.map((m) => /* @__PURE__ */ jsxs(
622
+ "div",
623
+ {
624
+ style: {
625
+ alignSelf: m.role === "user" ? "flex-end" : "flex-start",
626
+ maxWidth: "85%",
627
+ padding: "8px 12px",
628
+ borderRadius: 8,
629
+ backgroundColor: m.role === "user" ? "var(--ai-me-primary)" : "var(--ai-me-bg-secondary)",
630
+ color: m.role === "user" ? "#fff" : "var(--ai-me-text)",
631
+ fontSize: 14,
632
+ lineHeight: 1.5,
633
+ whiteSpace: "pre-wrap",
634
+ wordBreak: "break-word"
635
+ },
636
+ children: [
637
+ /* @__PURE__ */ jsx3("span", { style: srOnly, children: m.role === "user" ? "You: " : "Assistant: " }),
638
+ m.parts.map(
639
+ (p, i) => p.type === "text" ? /* @__PURE__ */ jsx3("span", { children: m.role === "assistant" ? renderMarkdown(p.text) : p.text }, i) : null
640
+ )
641
+ ]
642
+ },
643
+ m.id
644
+ )),
645
+ status === "submitted" && /* @__PURE__ */ jsx3(
646
+ "div",
647
+ {
648
+ "aria-label": "Assistant is thinking",
649
+ style: {
650
+ alignSelf: "flex-start",
651
+ color: "var(--ai-me-text-secondary)",
652
+ fontSize: 13
653
+ },
654
+ children: /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "Thinking\u2026" })
655
+ }
656
+ ),
657
+ error && /* @__PURE__ */ jsx3(
658
+ "div",
659
+ {
660
+ role: "alert",
661
+ style: {
662
+ padding: "8px 12px",
663
+ borderRadius: 8,
664
+ backgroundColor: "#fef2f2",
665
+ // #dc2626 on #fef2f2 ≈ 5.1:1 — passes AA for normal text
666
+ color: "#dc2626",
667
+ fontSize: 13,
668
+ border: "1px solid #fca5a5"
669
+ },
670
+ children: "Something went wrong. Please try again."
671
+ }
672
+ ),
673
+ /* @__PURE__ */ jsx3("div", { ref: messagesEndRef, "aria-hidden": "true" })
674
+ ]
675
+ }
676
+ ),
677
+ /* @__PURE__ */ jsxs(
678
+ "form",
679
+ {
680
+ onSubmit: handleSubmit,
681
+ style: {
682
+ padding: "12px 16px",
683
+ borderTop: "1px solid var(--ai-me-border)",
684
+ display: "flex",
685
+ gap: 8
686
+ },
687
+ children: [
688
+ /* @__PURE__ */ jsx3(
689
+ "label",
690
+ {
691
+ htmlFor: "ai-me-chat-input",
692
+ style: srOnly,
693
+ children: "Message to AI Assistant"
694
+ }
695
+ ),
696
+ /* @__PURE__ */ jsx3(
697
+ "input",
698
+ {
699
+ id: "ai-me-chat-input",
700
+ ref: inputRef,
701
+ value: input,
702
+ onChange: handleInputChange,
703
+ placeholder: "Ask anything\u2026",
704
+ disabled: status !== "ready",
705
+ "aria-disabled": status !== "ready",
706
+ style: {
707
+ flex: 1,
708
+ padding: "8px 12px",
709
+ border: "1px solid var(--ai-me-border)",
710
+ borderRadius: 8,
711
+ fontSize: 14,
712
+ fontFamily: "var(--ai-me-font)",
713
+ // Do NOT use outline:none — use outline with transparent color + focus handler
714
+ outline: "2px solid transparent",
715
+ outlineOffset: 2,
716
+ backgroundColor: "var(--ai-me-bg)",
717
+ color: "var(--ai-me-text)"
718
+ },
719
+ onFocus: (e) => {
720
+ e.currentTarget.style.outline = "2px solid var(--ai-me-primary)";
721
+ },
722
+ onBlur: (e) => {
723
+ e.currentTarget.style.outline = "2px solid transparent";
724
+ }
725
+ }
726
+ ),
727
+ /* @__PURE__ */ jsx3(
728
+ "button",
729
+ {
730
+ type: "submit",
731
+ disabled: status !== "ready" || !input.trim(),
732
+ "aria-disabled": status !== "ready" || !input.trim(),
733
+ style: {
734
+ padding: "8px 16px",
735
+ backgroundColor: "var(--ai-me-primary)",
736
+ color: "#fff",
737
+ border: "none",
738
+ borderRadius: 8,
739
+ cursor: status === "ready" && input.trim() ? "pointer" : "not-allowed",
740
+ fontSize: 14,
741
+ fontFamily: "var(--ai-me-font)",
742
+ opacity: status === "ready" && input.trim() ? 1 : 0.5,
743
+ outline: "2px solid transparent",
744
+ outlineOffset: 2
745
+ },
746
+ onFocus: (e) => {
747
+ e.currentTarget.style.outline = "2px solid var(--ai-me-primary)";
748
+ e.currentTarget.style.outlineOffset = "2px";
749
+ },
750
+ onBlur: (e) => {
751
+ e.currentTarget.style.outline = "2px solid transparent";
752
+ },
753
+ "aria-label": "Send message",
754
+ children: "Send"
755
+ }
756
+ )
757
+ ]
758
+ }
759
+ )
760
+ ]
761
+ }
762
+ )
763
+ ] });
764
+ }
765
+
766
+ // src/command-palette.tsx
767
+ import { useState as useState3, useEffect as useEffect3, useRef as useRef3, useCallback as useCallback3, useId as useId2 } from "react";
768
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
769
+ var defaultCommands = [
770
+ {
771
+ id: "help",
772
+ label: "Ask AI for help",
773
+ description: "Get assistance with any task",
774
+ category: "AI",
775
+ icon: "\u{1F4A1}",
776
+ action: "What can you help me with?"
777
+ },
778
+ {
779
+ id: "list-actions",
780
+ label: "List available actions",
781
+ description: "Show all API actions the AI can perform",
782
+ category: "AI",
783
+ icon: "\u{1F4CB}",
784
+ action: "What actions can you perform? List them all."
785
+ },
786
+ {
787
+ id: "recent-activity",
788
+ label: "Show recent activity",
789
+ description: "Summarize recent actions and changes",
790
+ category: "AI",
791
+ icon: "\u{1F550}",
792
+ action: "What has happened recently? Summarize recent activity."
793
+ }
794
+ ];
795
+ var srOnly2 = {
796
+ position: "absolute",
797
+ width: 1,
798
+ height: 1,
799
+ padding: 0,
800
+ margin: -1,
801
+ overflow: "hidden",
802
+ clip: "rect(0,0,0,0)",
803
+ whiteSpace: "nowrap",
804
+ borderWidth: 0
805
+ };
806
+ function AIMeCommandPalette({
807
+ commands = defaultCommands,
808
+ theme,
809
+ shortcut = { key: "k", meta: true },
810
+ onToggle
811
+ }) {
812
+ const [open, setOpen] = useState3(false);
813
+ const [query, setQuery] = useState3("");
814
+ const [selectedIndex, setSelectedIndex] = useState3(0);
815
+ const inputRef = useRef3(null);
816
+ const listRef = useRef3(null);
817
+ const dialogRef = useRef3(null);
818
+ const previousFocusRef = useRef3(null);
819
+ const { sendMessage } = useAIMe();
820
+ const titleId = useId2();
821
+ const inputId = useId2();
822
+ const toggle = useCallback3(
823
+ (next) => {
824
+ setOpen(next);
825
+ setQuery("");
826
+ setSelectedIndex(0);
827
+ onToggle?.(next);
828
+ },
829
+ [onToggle]
830
+ );
831
+ useEffect3(() => {
832
+ function handleKeyDown2(e) {
833
+ const metaMatch = shortcut.meta ? e.metaKey : true;
834
+ const ctrlMatch = shortcut.ctrl ? e.ctrlKey : !shortcut.meta ? e.ctrlKey : true;
835
+ if ((metaMatch || ctrlMatch) && e.key === shortcut.key) {
836
+ e.preventDefault();
837
+ if (!open) {
838
+ previousFocusRef.current = document.activeElement;
839
+ }
840
+ toggle(!open);
841
+ }
842
+ }
843
+ window.addEventListener("keydown", handleKeyDown2);
844
+ return () => window.removeEventListener("keydown", handleKeyDown2);
845
+ }, [open, shortcut, toggle]);
846
+ useEffect3(() => {
847
+ if (open) {
848
+ setTimeout(() => inputRef.current?.focus(), 0);
849
+ } else {
850
+ if (previousFocusRef.current) {
851
+ previousFocusRef.current.focus();
852
+ previousFocusRef.current = null;
853
+ }
854
+ }
855
+ }, [open]);
856
+ useEffect3(() => {
857
+ if (!open) return;
858
+ function handleFocusTrap(e) {
859
+ if (e.key !== "Tab") return;
860
+ const dialog = dialogRef.current;
861
+ if (!dialog) return;
862
+ const focusable = dialog.querySelectorAll(
863
+ 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])'
864
+ );
865
+ if (focusable.length === 0) return;
866
+ const first = focusable[0];
867
+ const last = focusable[focusable.length - 1];
868
+ if (e.shiftKey) {
869
+ if (document.activeElement === first) {
870
+ e.preventDefault();
871
+ last.focus();
872
+ }
873
+ } else {
874
+ if (document.activeElement === last) {
875
+ e.preventDefault();
876
+ first.focus();
877
+ }
878
+ }
879
+ }
880
+ window.addEventListener("keydown", handleFocusTrap);
881
+ return () => window.removeEventListener("keydown", handleFocusTrap);
882
+ }, [open]);
883
+ const filtered = query.trim() ? commands.filter(
884
+ (cmd) => cmd.label.toLowerCase().includes(query.toLowerCase()) || cmd.description?.toLowerCase().includes(query.toLowerCase()) || cmd.category?.toLowerCase().includes(query.toLowerCase())
885
+ ) : commands;
886
+ useEffect3(() => {
887
+ if (selectedIndex >= filtered.length) {
888
+ setSelectedIndex(Math.max(0, filtered.length - 1));
889
+ }
890
+ }, [filtered.length, selectedIndex]);
891
+ useEffect3(() => {
892
+ const list = listRef.current;
893
+ if (!list) return;
894
+ const selected = list.children[selectedIndex];
895
+ selected?.scrollIntoView({ block: "nearest" });
896
+ }, [selectedIndex]);
897
+ function executeCommand(cmd) {
898
+ toggle(false);
899
+ if (typeof cmd.action === "string") {
900
+ sendMessage({ text: cmd.action });
901
+ } else {
902
+ cmd.action();
903
+ }
904
+ }
905
+ function handleKeyDown(e) {
906
+ if (e.key === "ArrowDown") {
907
+ e.preventDefault();
908
+ setSelectedIndex((prev) => Math.min(prev + 1, filtered.length - 1));
909
+ } else if (e.key === "ArrowUp") {
910
+ e.preventDefault();
911
+ setSelectedIndex((prev) => Math.max(prev - 1, 0));
912
+ } else if (e.key === "Enter") {
913
+ e.preventDefault();
914
+ if (filtered[selectedIndex]) {
915
+ executeCommand(filtered[selectedIndex]);
916
+ } else if (query.trim()) {
917
+ toggle(false);
918
+ sendMessage({ text: query });
919
+ }
920
+ } else if (e.key === "Escape") {
921
+ toggle(false);
922
+ }
923
+ }
924
+ if (!open) return null;
925
+ const themeVars = {
926
+ ...defaultThemeVars,
927
+ ...themeToVars(theme)
928
+ };
929
+ const grouped = /* @__PURE__ */ new Map();
930
+ for (const cmd of filtered) {
931
+ const cat = cmd.category ?? "Actions";
932
+ if (!grouped.has(cat)) grouped.set(cat, []);
933
+ grouped.get(cat).push(cmd);
934
+ }
935
+ let flatIndex = 0;
936
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
937
+ /* @__PURE__ */ jsx4(
938
+ "div",
939
+ {
940
+ onClick: () => toggle(false),
941
+ style: {
942
+ position: "fixed",
943
+ inset: 0,
944
+ backgroundColor: "rgba(0,0,0,0.5)",
945
+ zIndex: 99998
946
+ },
947
+ "aria-hidden": "true"
948
+ }
949
+ ),
950
+ /* @__PURE__ */ jsxs2(
951
+ "div",
952
+ {
953
+ ref: dialogRef,
954
+ style: {
955
+ ...themeVars,
956
+ position: "fixed",
957
+ top: "20%",
958
+ left: "50%",
959
+ transform: "translateX(-50%)",
960
+ width: "min(520px, 90vw)",
961
+ maxHeight: "60vh",
962
+ display: "flex",
963
+ flexDirection: "column",
964
+ backgroundColor: "var(--ai-me-bg)",
965
+ borderRadius: "var(--ai-me-radius)",
966
+ border: "1px solid var(--ai-me-border)",
967
+ boxShadow: "0 24px 48px rgba(0,0,0,0.3)",
968
+ overflow: "hidden",
969
+ zIndex: 99999,
970
+ fontFamily: "var(--ai-me-font)",
971
+ color: "var(--ai-me-text)"
972
+ },
973
+ role: "dialog",
974
+ "aria-modal": "true",
975
+ "aria-labelledby": titleId,
976
+ tabIndex: -1,
977
+ children: [
978
+ /* @__PURE__ */ jsx4("h2", { id: titleId, style: srOnly2, children: "Command Palette" }),
979
+ /* @__PURE__ */ jsxs2("div", { style: { padding: "12px 16px", borderBottom: "1px solid var(--ai-me-border)" }, children: [
980
+ /* @__PURE__ */ jsx4("label", { htmlFor: inputId, style: srOnly2, children: "Search commands or ask AI" }),
981
+ /* @__PURE__ */ jsx4(
982
+ "input",
983
+ {
984
+ id: inputId,
985
+ ref: inputRef,
986
+ value: query,
987
+ onChange: (e) => {
988
+ setQuery(e.target.value);
989
+ setSelectedIndex(0);
990
+ },
991
+ onKeyDown: handleKeyDown,
992
+ placeholder: "Type a command or ask AI...",
993
+ style: {
994
+ width: "100%",
995
+ padding: "8px 0",
996
+ border: "none",
997
+ // Do NOT suppress the outline entirely — use transparent + focus handler
998
+ outline: "2px solid transparent",
999
+ outlineOffset: 2,
1000
+ fontSize: 15,
1001
+ fontFamily: "var(--ai-me-font)",
1002
+ backgroundColor: "transparent",
1003
+ color: "var(--ai-me-text)"
1004
+ },
1005
+ onFocus: (e) => {
1006
+ e.currentTarget.style.outline = "2px solid var(--ai-me-primary)";
1007
+ },
1008
+ onBlur: (e) => {
1009
+ e.currentTarget.style.outline = "2px solid transparent";
1010
+ },
1011
+ role: "combobox",
1012
+ "aria-expanded": "true",
1013
+ "aria-autocomplete": "list",
1014
+ "aria-controls": "ai-me-cmd-listbox",
1015
+ "aria-activedescendant": filtered[selectedIndex] ? `cmd-${filtered[selectedIndex].id}` : void 0
1016
+ }
1017
+ )
1018
+ ] }),
1019
+ /* @__PURE__ */ jsxs2(
1020
+ "div",
1021
+ {
1022
+ id: "ai-me-cmd-listbox",
1023
+ ref: listRef,
1024
+ style: { overflowY: "auto", padding: "8px 0" },
1025
+ role: "listbox",
1026
+ "aria-label": "Commands",
1027
+ children: [
1028
+ filtered.length === 0 && query.trim() && /* @__PURE__ */ jsxs2(
1029
+ "div",
1030
+ {
1031
+ role: "option",
1032
+ "aria-selected": "false",
1033
+ style: {
1034
+ padding: "16px",
1035
+ textAlign: "center",
1036
+ fontSize: 13,
1037
+ color: "var(--ai-me-text-secondary)"
1038
+ },
1039
+ children: [
1040
+ "Press Enter to ask AI: \u201C",
1041
+ query,
1042
+ "\u201D"
1043
+ ]
1044
+ }
1045
+ ),
1046
+ Array.from(grouped.entries()).map(([category, items]) => (
1047
+ // role="group" with aria-label for the category heading
1048
+ /* @__PURE__ */ jsxs2("div", { role: "group", "aria-label": category, children: [
1049
+ /* @__PURE__ */ jsx4(
1050
+ "div",
1051
+ {
1052
+ "aria-hidden": "true",
1053
+ style: {
1054
+ padding: "6px 16px 4px",
1055
+ fontSize: 11,
1056
+ fontWeight: 500,
1057
+ textTransform: "uppercase",
1058
+ letterSpacing: "0.06em",
1059
+ color: "var(--ai-me-text-secondary)"
1060
+ },
1061
+ children: category
1062
+ }
1063
+ ),
1064
+ items.map((cmd) => {
1065
+ const idx = flatIndex++;
1066
+ const isSelected = idx === selectedIndex;
1067
+ return /* @__PURE__ */ jsxs2(
1068
+ "div",
1069
+ {
1070
+ id: `cmd-${cmd.id}`,
1071
+ role: "option",
1072
+ "aria-selected": isSelected,
1073
+ onClick: () => executeCommand(cmd),
1074
+ onMouseEnter: () => setSelectedIndex(idx),
1075
+ tabIndex: isSelected ? 0 : -1,
1076
+ onKeyDown: (e) => {
1077
+ if (e.key === "Enter" || e.key === " ") {
1078
+ e.preventDefault();
1079
+ executeCommand(cmd);
1080
+ }
1081
+ },
1082
+ style: {
1083
+ padding: "8px 16px",
1084
+ cursor: "pointer",
1085
+ display: "flex",
1086
+ alignItems: "center",
1087
+ gap: 10,
1088
+ backgroundColor: isSelected ? "var(--ai-me-bg-secondary)" : "transparent",
1089
+ outline: "2px solid transparent",
1090
+ outlineOffset: -2
1091
+ },
1092
+ onFocus: (e) => {
1093
+ e.currentTarget.style.outline = "2px solid var(--ai-me-primary)";
1094
+ },
1095
+ onBlur: (e) => {
1096
+ e.currentTarget.style.outline = "2px solid transparent";
1097
+ },
1098
+ children: [
1099
+ cmd.icon && // Icon is decorative — label comes from cmd.label
1100
+ /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", style: { fontSize: 16, flexShrink: 0 }, children: cmd.icon }),
1101
+ /* @__PURE__ */ jsxs2("div", { style: { flex: 1, minWidth: 0 }, children: [
1102
+ /* @__PURE__ */ jsx4("div", { style: { fontSize: 14, fontWeight: 500 }, children: cmd.label }),
1103
+ cmd.description && /* @__PURE__ */ jsx4(
1104
+ "div",
1105
+ {
1106
+ style: {
1107
+ fontSize: 12,
1108
+ color: "var(--ai-me-text-secondary)",
1109
+ whiteSpace: "nowrap",
1110
+ overflow: "hidden",
1111
+ textOverflow: "ellipsis"
1112
+ },
1113
+ children: cmd.description
1114
+ }
1115
+ )
1116
+ ] })
1117
+ ]
1118
+ },
1119
+ cmd.id
1120
+ );
1121
+ })
1122
+ ] }, category)
1123
+ ))
1124
+ ]
1125
+ }
1126
+ ),
1127
+ /* @__PURE__ */ jsxs2(
1128
+ "div",
1129
+ {
1130
+ "aria-hidden": "true",
1131
+ style: {
1132
+ padding: "8px 16px",
1133
+ borderTop: "1px solid var(--ai-me-border)",
1134
+ fontSize: 11,
1135
+ color: "var(--ai-me-text-secondary)",
1136
+ display: "flex",
1137
+ gap: 16
1138
+ },
1139
+ children: [
1140
+ /* @__PURE__ */ jsx4("span", { children: "\u2191\u2193 Navigate" }),
1141
+ /* @__PURE__ */ jsx4("span", { children: "\u21B5 Select" }),
1142
+ /* @__PURE__ */ jsx4("span", { children: "Esc Close" })
1143
+ ]
1144
+ }
1145
+ )
1146
+ ]
1147
+ }
1148
+ )
1149
+ ] });
1150
+ }
1151
+
1152
+ // src/confirm.tsx
1153
+ import { useRef as useRef4, useEffect as useEffect4, useId as useId3, useCallback as useCallback4 } from "react";
1154
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1155
+ function AIMeConfirm({
1156
+ action,
1157
+ description,
1158
+ parameters,
1159
+ onConfirm,
1160
+ onReject
1161
+ }) {
1162
+ const dialogRef = useRef4(null);
1163
+ const cancelButtonRef = useRef4(null);
1164
+ const titleId = useId3();
1165
+ const descriptionId = useId3();
1166
+ const handleKeyDown = useCallback4(
1167
+ (e) => {
1168
+ if (e.key === "Escape") {
1169
+ e.preventDefault();
1170
+ onReject();
1171
+ return;
1172
+ }
1173
+ if (e.key !== "Tab") return;
1174
+ const dialog = dialogRef.current;
1175
+ if (!dialog) return;
1176
+ const focusable = dialog.querySelectorAll(
1177
+ 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])'
1178
+ );
1179
+ if (focusable.length === 0) return;
1180
+ const first = focusable[0];
1181
+ const last = focusable[focusable.length - 1];
1182
+ if (e.shiftKey) {
1183
+ if (document.activeElement === first) {
1184
+ e.preventDefault();
1185
+ last.focus();
1186
+ }
1187
+ } else {
1188
+ if (document.activeElement === last) {
1189
+ e.preventDefault();
1190
+ first.focus();
1191
+ }
1192
+ }
1193
+ },
1194
+ [onReject]
1195
+ );
1196
+ useEffect4(() => {
1197
+ const previousFocus = document.activeElement;
1198
+ cancelButtonRef.current?.focus();
1199
+ window.addEventListener("keydown", handleKeyDown);
1200
+ return () => {
1201
+ window.removeEventListener("keydown", handleKeyDown);
1202
+ previousFocus?.focus();
1203
+ };
1204
+ }, [handleKeyDown]);
1205
+ const overlayStyle = {
1206
+ ...defaultThemeVars,
1207
+ position: "fixed",
1208
+ inset: 0,
1209
+ backgroundColor: "rgba(0, 0, 0, 0.4)",
1210
+ display: "flex",
1211
+ alignItems: "center",
1212
+ justifyContent: "center",
1213
+ zIndex: 1e4,
1214
+ fontFamily: "var(--ai-me-font)"
1215
+ };
1216
+ const dialogStyle = {
1217
+ backgroundColor: "var(--ai-me-bg)",
1218
+ borderRadius: "var(--ai-me-radius)",
1219
+ padding: 24,
1220
+ maxWidth: 420,
1221
+ width: "90%",
1222
+ boxShadow: "var(--ai-me-shadow)",
1223
+ color: "var(--ai-me-text)"
1224
+ };
1225
+ const focusStyle = {
1226
+ outline: "2px solid transparent",
1227
+ outlineOffset: 2
1228
+ };
1229
+ function applyFocusRing(el) {
1230
+ el.style.outline = "2px solid var(--ai-me-primary)";
1231
+ el.style.outlineOffset = "2px";
1232
+ }
1233
+ function removeFocusRing(el) {
1234
+ el.style.outline = "2px solid transparent";
1235
+ el.style.outlineOffset = "2px";
1236
+ }
1237
+ return (
1238
+ // Overlay is presentational — role and aria go on the inner dialog
1239
+ /* @__PURE__ */ jsx5(
1240
+ "div",
1241
+ {
1242
+ style: overlayStyle,
1243
+ onClick: (e) => {
1244
+ if (e.target === e.currentTarget) onReject();
1245
+ },
1246
+ "aria-hidden": "false",
1247
+ children: /* @__PURE__ */ jsxs3(
1248
+ "div",
1249
+ {
1250
+ ref: dialogRef,
1251
+ style: dialogStyle,
1252
+ role: "alertdialog",
1253
+ "aria-modal": "true",
1254
+ "aria-labelledby": titleId,
1255
+ "aria-describedby": descriptionId,
1256
+ tabIndex: -1,
1257
+ onClick: (e) => e.stopPropagation(),
1258
+ children: [
1259
+ /* @__PURE__ */ jsx5("h3", { id: titleId, style: { margin: "0 0 8px", fontSize: 16 }, children: "Confirm Action" }),
1260
+ /* @__PURE__ */ jsx5("p", { style: { margin: "0 0 4px", fontSize: 14, fontWeight: 600 }, children: action }),
1261
+ /* @__PURE__ */ jsx5(
1262
+ "p",
1263
+ {
1264
+ id: descriptionId,
1265
+ style: {
1266
+ margin: "0 0 16px",
1267
+ fontSize: 13,
1268
+ color: "var(--ai-me-text-secondary)"
1269
+ },
1270
+ children: description
1271
+ }
1272
+ ),
1273
+ parameters && Object.keys(parameters).length > 0 && /* @__PURE__ */ jsx5(
1274
+ "pre",
1275
+ {
1276
+ style: {
1277
+ margin: "0 0 16px",
1278
+ padding: 12,
1279
+ backgroundColor: "var(--ai-me-bg-secondary)",
1280
+ borderRadius: 8,
1281
+ fontSize: 12,
1282
+ overflow: "auto",
1283
+ maxHeight: 200,
1284
+ border: "1px solid var(--ai-me-border)"
1285
+ },
1286
+ children: JSON.stringify(parameters, null, 2)
1287
+ }
1288
+ ),
1289
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: 8, justifyContent: "flex-end" }, children: [
1290
+ /* @__PURE__ */ jsx5(
1291
+ "button",
1292
+ {
1293
+ ref: cancelButtonRef,
1294
+ type: "button",
1295
+ onClick: onReject,
1296
+ style: {
1297
+ padding: "8px 16px",
1298
+ border: "1px solid var(--ai-me-border)",
1299
+ borderRadius: 8,
1300
+ backgroundColor: "var(--ai-me-bg)",
1301
+ color: "var(--ai-me-text)",
1302
+ cursor: "pointer",
1303
+ fontSize: 14,
1304
+ ...focusStyle
1305
+ },
1306
+ onFocus: (e) => applyFocusRing(e.currentTarget),
1307
+ onBlur: (e) => removeFocusRing(e.currentTarget),
1308
+ children: "Cancel"
1309
+ }
1310
+ ),
1311
+ /* @__PURE__ */ jsx5(
1312
+ "button",
1313
+ {
1314
+ type: "button",
1315
+ onClick: onConfirm,
1316
+ style: {
1317
+ padding: "8px 16px",
1318
+ border: "none",
1319
+ borderRadius: 8,
1320
+ // #fff on var(--ai-me-primary) = #6366f1 → contrast ≈ 4.6:1 (passes AA)
1321
+ backgroundColor: "var(--ai-me-primary)",
1322
+ color: "#fff",
1323
+ cursor: "pointer",
1324
+ fontSize: 14,
1325
+ ...focusStyle
1326
+ },
1327
+ onFocus: (e) => applyFocusRing(e.currentTarget),
1328
+ onBlur: (e) => removeFocusRing(e.currentTarget),
1329
+ children: "Confirm"
1330
+ }
1331
+ )
1332
+ ] })
1333
+ ]
1334
+ }
1335
+ )
1336
+ }
1337
+ )
1338
+ );
1339
+ }
1340
+ export {
1341
+ AIMeChat,
1342
+ AIMeCommandPalette,
1343
+ AIMeConfirm,
1344
+ AIMeProvider,
1345
+ renderMarkdown,
1346
+ useAIMe,
1347
+ useAIMeContext
1348
+ };
1349
+ //# sourceMappingURL=index.js.map