@meowlynxsea/koi 0.1.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/LICENSE +34 -0
- package/NOTICE +35 -0
- package/README.md +15 -0
- package/bin/koi +12 -0
- package/dist/highlights-eq9cgrbb.scm +604 -0
- package/dist/highlights-ghv9g403.scm +205 -0
- package/dist/highlights-hk7bwhj4.scm +284 -0
- package/dist/highlights-r812a2qc.scm +150 -0
- package/dist/highlights-x6tmsnaa.scm +115 -0
- package/dist/injections-73j83es3.scm +27 -0
- package/dist/main.js +489918 -0
- package/dist/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
- package/dist/tree-sitter-markdown-411r6y9b.wasm +0 -0
- package/dist/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
- package/dist/tree-sitter-typescript-zxjzwt75.wasm +0 -0
- package/dist/tree-sitter-zig-e78zbjpm.wasm +0 -0
- package/package.json +51 -0
- package/src/agent/check-permissions.ts +239 -0
- package/src/agent/hooks/message-utils.ts +305 -0
- package/src/agent/hooks/types.ts +32 -0
- package/src/agent/hooks.ts +1560 -0
- package/src/agent/mode.ts +163 -0
- package/src/agent/monitor-registry.ts +308 -0
- package/src/agent/permission-ui.ts +71 -0
- package/src/agent/plan-ui.ts +74 -0
- package/src/agent/question-ui.ts +58 -0
- package/src/agent/session-fork.ts +299 -0
- package/src/agent/session-snapshots.ts +216 -0
- package/src/agent/session-store.ts +649 -0
- package/src/agent/session-tasks.ts +305 -0
- package/src/agent/session.ts +27 -0
- package/src/agent/subagent-registry.ts +176 -0
- package/src/agent/subagent.ts +194 -0
- package/src/agent/tool-orchestration.ts +55 -0
- package/src/agent/tools.ts +8 -0
- package/src/cli/args.ts +6 -0
- package/src/cli/commands.ts +5 -0
- package/src/commands/skills/index.ts +23 -0
- package/src/config/models.ts +6 -0
- package/src/config/settings.ts +392 -0
- package/src/main.tsx +64 -0
- package/src/services/mcp/client.ts +194 -0
- package/src/services/mcp/config.ts +232 -0
- package/src/services/mcp/connection-manager.ts +258 -0
- package/src/services/mcp/index.ts +80 -0
- package/src/services/mcp/mcp-commands.ts +114 -0
- package/src/services/mcp/stdio-transport.ts +246 -0
- package/src/services/mcp/types.ts +155 -0
- package/src/skills/SkillsMenu.tsx +370 -0
- package/src/skills/bundled/batch.ts +106 -0
- package/src/skills/bundled/debug.ts +86 -0
- package/src/skills/bundled/loremIpsum.ts +101 -0
- package/src/skills/bundled/remember.ts +97 -0
- package/src/skills/bundled/simplify.ts +100 -0
- package/src/skills/bundled/skillify.ts +123 -0
- package/src/skills/bundled/stuck.ts +101 -0
- package/src/skills/bundled/updateConfig.ts +228 -0
- package/src/skills/bundled.ts +46 -0
- package/src/skills/frontmatter.ts +179 -0
- package/src/skills/index.ts +87 -0
- package/src/skills/invoke.ts +231 -0
- package/src/skills/loader.ts +710 -0
- package/src/skills/substitution.ts +169 -0
- package/src/skills/types.ts +201 -0
- package/src/tools/agent.ts +143 -0
- package/src/tools/ask-user-question.ts +46 -0
- package/src/tools/bash.ts +148 -0
- package/src/tools/edit.ts +164 -0
- package/src/tools/glob.ts +102 -0
- package/src/tools/grep.ts +248 -0
- package/src/tools/index.ts +73 -0
- package/src/tools/list-mcp-resources.ts +74 -0
- package/src/tools/ls.ts +85 -0
- package/src/tools/mcp.ts +76 -0
- package/src/tools/monitor.ts +159 -0
- package/src/tools/plan-mode.ts +134 -0
- package/src/tools/read-mcp-resource.ts +79 -0
- package/src/tools/read.ts +137 -0
- package/src/tools/skill.ts +176 -0
- package/src/tools/task.ts +349 -0
- package/src/tools/types.ts +52 -0
- package/src/tools/webfetch-domains.ts +239 -0
- package/src/tools/webfetch.ts +533 -0
- package/src/tools/write.ts +101 -0
- package/src/tui/app.tsx +1178 -0
- package/src/tui/components/chat-panel.tsx +1071 -0
- package/src/tui/components/command-panel.tsx +261 -0
- package/src/tui/components/confirm-modal.tsx +135 -0
- package/src/tui/components/connect-modal.tsx +435 -0
- package/src/tui/components/connecting-modal.tsx +167 -0
- package/src/tui/components/edit-pending-modal.tsx +103 -0
- package/src/tui/components/exit-modal.tsx +131 -0
- package/src/tui/components/fork-modal.tsx +377 -0
- package/src/tui/components/image-preview-modal.tsx +141 -0
- package/src/tui/components/image-utils.ts +128 -0
- package/src/tui/components/info-bar.tsx +103 -0
- package/src/tui/components/input-box.tsx +352 -0
- package/src/tui/components/mcp/MCPSettings.tsx +386 -0
- package/src/tui/components/mcp/index.ts +7 -0
- package/src/tui/components/model-modal.tsx +310 -0
- package/src/tui/components/pending-area.tsx +88 -0
- package/src/tui/components/rename-modal.tsx +119 -0
- package/src/tui/components/session-modal.tsx +233 -0
- package/src/tui/components/side-bar.tsx +349 -0
- package/src/tui/components/tool-output.ts +6 -0
- package/src/tui/hooks/user-prompt-history.ts +114 -0
- package/src/tui/theme.ts +63 -0
- package/src/types/commands.ts +80 -0
- package/src/types/cross-spawn.d.ts +24 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command Panel Component
|
|
3
|
+
*
|
|
4
|
+
* A modal command palette with a single-line filter input and a scrollable
|
|
5
|
+
* list of sectioned commands. Opened with Ctrl+P or "/" in empty prompt.
|
|
6
|
+
* Closed with Ctrl+P, Esc, or clearing the input.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
10
|
+
import { useKeyboard, useTerminalDimensions } from "@opentui/react";
|
|
11
|
+
import { createTextAttributes, type KeyBinding } from "@opentui/core";
|
|
12
|
+
import type { TextareaRenderable } from "@opentui/core";
|
|
13
|
+
|
|
14
|
+
export interface CommandDef {
|
|
15
|
+
id: string;
|
|
16
|
+
label: string;
|
|
17
|
+
section: string;
|
|
18
|
+
action: () => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface CommandPanelProps {
|
|
22
|
+
isActive: boolean;
|
|
23
|
+
onClose: () => void;
|
|
24
|
+
commands: CommandDef[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface ListItem {
|
|
28
|
+
type: "header" | "command";
|
|
29
|
+
section?: string;
|
|
30
|
+
cmd?: CommandDef;
|
|
31
|
+
cmdIndex?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function CommandPanel({ isActive, onClose, commands }: CommandPanelProps) {
|
|
35
|
+
const { width, height } = useTerminalDimensions();
|
|
36
|
+
const inputRef = useRef<TextareaRenderable>(null);
|
|
37
|
+
const [filterText, setFilterText] = useState("");
|
|
38
|
+
const [selectedCmdIndex, setSelectedCmdIndex] = useState(0);
|
|
39
|
+
const scrollOffsetRef = useRef(0);
|
|
40
|
+
|
|
41
|
+
const panelWidth = Math.min(70, Math.max(40, Math.floor(width * 0.7)));
|
|
42
|
+
const listHeight = Math.min(12, Math.floor(height * 0.4));
|
|
43
|
+
|
|
44
|
+
// Reset when opened
|
|
45
|
+
useLayoutEffect(() => {
|
|
46
|
+
if (isActive) {
|
|
47
|
+
setFilterText("");
|
|
48
|
+
setSelectedCmdIndex(0);
|
|
49
|
+
scrollOffsetRef.current = 0;
|
|
50
|
+
const ta = inputRef.current;
|
|
51
|
+
if (ta) {
|
|
52
|
+
ta.editBuffer.replaceText("");
|
|
53
|
+
ta.focus();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}, [isActive]);
|
|
57
|
+
|
|
58
|
+
// Build filtered flat list
|
|
59
|
+
const query = filterText;
|
|
60
|
+
const { flatItems, cmdCount } = useMemo(() => {
|
|
61
|
+
let filtered = commands;
|
|
62
|
+
if (query) {
|
|
63
|
+
const q = query.toLowerCase();
|
|
64
|
+
// Filter and sort by match priority: id > label > section
|
|
65
|
+
filtered = commands
|
|
66
|
+
.map((cmd) => {
|
|
67
|
+
const idMatch = cmd.id.toLowerCase().includes(q);
|
|
68
|
+
const labelMatch = cmd.label.toLowerCase().includes(q);
|
|
69
|
+
const sectionMatch = cmd.section.toLowerCase().includes(q);
|
|
70
|
+
// Priority: 0 = id match (highest), 1 = label match, 2 = section match, 3 = no match
|
|
71
|
+
const priority = !idMatch && !labelMatch && !sectionMatch ? 3
|
|
72
|
+
: idMatch ? 0
|
|
73
|
+
: labelMatch ? 1
|
|
74
|
+
: 2;
|
|
75
|
+
return { cmd, priority };
|
|
76
|
+
})
|
|
77
|
+
.filter((item) => item.priority < 3)
|
|
78
|
+
.sort((a, b) => a.priority - b.priority)
|
|
79
|
+
.map((item) => item.cmd);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const grouped = new Map<string, CommandDef[]>();
|
|
83
|
+
for (const cmd of filtered) {
|
|
84
|
+
if (!grouped.has(cmd.section)) grouped.set(cmd.section, []);
|
|
85
|
+
grouped.get(cmd.section)!.push(cmd);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const items: ListItem[] = [];
|
|
89
|
+
let cmdIdx = 0;
|
|
90
|
+
for (const [section, cmds] of grouped) {
|
|
91
|
+
items.push({ type: "header", section });
|
|
92
|
+
for (const cmd of cmds) {
|
|
93
|
+
items.push({ type: "command", cmd, cmdIndex: cmdIdx });
|
|
94
|
+
cmdIdx++;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return { flatItems: items, cmdCount: cmdIdx };
|
|
98
|
+
}, [commands, query]);
|
|
99
|
+
|
|
100
|
+
// Effective scroll offset (synced from ref)
|
|
101
|
+
const effectiveScrollOffset = scrollOffsetRef.current;
|
|
102
|
+
|
|
103
|
+
// Global keyboard for navigation and close shortcuts
|
|
104
|
+
useKeyboard((key) => {
|
|
105
|
+
if (!isActive) return;
|
|
106
|
+
if (key.ctrl && key.name === "p") {
|
|
107
|
+
key.preventDefault();
|
|
108
|
+
key.stopPropagation();
|
|
109
|
+
onClose();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (key.name === "escape") {
|
|
113
|
+
key.preventDefault();
|
|
114
|
+
key.stopPropagation();
|
|
115
|
+
onClose();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Navigation with direct scroll calculation
|
|
120
|
+
if (key.name === "up" || key.name === "down") {
|
|
121
|
+
key.preventDefault();
|
|
122
|
+
key.stopPropagation();
|
|
123
|
+
|
|
124
|
+
const newIndex = key.name === "up"
|
|
125
|
+
? Math.max(0, selectedCmdIndex - 1)
|
|
126
|
+
: Math.min(cmdCount - 1, selectedCmdIndex + 1);
|
|
127
|
+
|
|
128
|
+
// Calculate scroll based on new index
|
|
129
|
+
const newFlatIndex = flatItems.findIndex(
|
|
130
|
+
(i) => i.type === "command" && i.cmdIndex === newIndex
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const currentScroll = scrollOffsetRef.current;
|
|
134
|
+
let newScrollOffset = currentScroll;
|
|
135
|
+
if (newFlatIndex !== -1) {
|
|
136
|
+
if (newFlatIndex < currentScroll) {
|
|
137
|
+
newScrollOffset = newFlatIndex;
|
|
138
|
+
} else if (newFlatIndex > currentScroll + listHeight - 1) {
|
|
139
|
+
newScrollOffset = newFlatIndex - listHeight + 1;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
console.log('[CommandPanel] Key press:', {
|
|
144
|
+
key: key.name,
|
|
145
|
+
newIndex,
|
|
146
|
+
newFlatIndex,
|
|
147
|
+
currentScroll,
|
|
148
|
+
listHeight,
|
|
149
|
+
newScrollOffset
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
scrollOffsetRef.current = newScrollOffset;
|
|
153
|
+
setSelectedCmdIndex(newIndex);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const handleContentChange = () => {
|
|
159
|
+
const text = inputRef.current?.editBuffer.getText() ?? "";
|
|
160
|
+
setFilterText(text);
|
|
161
|
+
setSelectedCmdIndex(0);
|
|
162
|
+
scrollOffsetRef.current = 0;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const handleSubmit = () => {
|
|
166
|
+
const selectedItem = flatItems.find(
|
|
167
|
+
(i) => i.type === "command" && i.cmdIndex === selectedCmdIndex
|
|
168
|
+
);
|
|
169
|
+
if (selectedItem?.cmd) {
|
|
170
|
+
onClose();
|
|
171
|
+
selectedItem.cmd.action();
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const keyBindings = useMemo<KeyBinding[]>(
|
|
176
|
+
() => [{ name: "return", action: "submit" }],
|
|
177
|
+
[]
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
if (!isActive) return null;
|
|
181
|
+
|
|
182
|
+
const visibleItems = flatItems.slice(effectiveScrollOffset, effectiveScrollOffset + listHeight);
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<box
|
|
186
|
+
position="absolute"
|
|
187
|
+
top={0}
|
|
188
|
+
left={0}
|
|
189
|
+
width="100%"
|
|
190
|
+
height="100%"
|
|
191
|
+
backgroundColor="#00000080"
|
|
192
|
+
alignItems="center"
|
|
193
|
+
justifyContent="center"
|
|
194
|
+
>
|
|
195
|
+
<box
|
|
196
|
+
width={panelWidth}
|
|
197
|
+
flexDirection="column"
|
|
198
|
+
borderStyle="rounded"
|
|
199
|
+
borderColor="#4a4a5a"
|
|
200
|
+
backgroundColor="#1a1a2e"
|
|
201
|
+
paddingX={1}
|
|
202
|
+
paddingY={1}
|
|
203
|
+
>
|
|
204
|
+
{/* Filter input */}
|
|
205
|
+
<textarea
|
|
206
|
+
ref={inputRef}
|
|
207
|
+
initialValue=""
|
|
208
|
+
focused={isActive}
|
|
209
|
+
showCursor
|
|
210
|
+
height={1}
|
|
211
|
+
wrapMode="none"
|
|
212
|
+
marginX={1}
|
|
213
|
+
textColor="#f8f8f2"
|
|
214
|
+
backgroundColor="#16213e"
|
|
215
|
+
onContentChange={handleContentChange}
|
|
216
|
+
onSubmit={handleSubmit}
|
|
217
|
+
keyBindings={keyBindings}
|
|
218
|
+
/>
|
|
219
|
+
|
|
220
|
+
{/* Separator */}
|
|
221
|
+
<box height={1} marginTop={1}>
|
|
222
|
+
<text fg="#4a4a5a">
|
|
223
|
+
{"─".repeat(panelWidth - 2)}
|
|
224
|
+
</text>
|
|
225
|
+
</box>
|
|
226
|
+
|
|
227
|
+
{/* Command list */}
|
|
228
|
+
<box height={listHeight} flexDirection="column" overflow="hidden">
|
|
229
|
+
{visibleItems.map((item, idx) => {
|
|
230
|
+
const flatIndex = effectiveScrollOffset + idx;
|
|
231
|
+
if (item.type === "header") {
|
|
232
|
+
return (
|
|
233
|
+
<box key={`h-${item.section}-${flatIndex}`} height={1}>
|
|
234
|
+
<text
|
|
235
|
+
fg="#ff79c6"
|
|
236
|
+
attributes={createTextAttributes({ bold: true })}
|
|
237
|
+
>
|
|
238
|
+
{item.section}
|
|
239
|
+
</text>
|
|
240
|
+
</box>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
const isSelected = item.cmdIndex === selectedCmdIndex;
|
|
244
|
+
return (
|
|
245
|
+
<box key={`c-${item.cmd!.id}-${flatIndex}`} height={1} backgroundColor={isSelected ? "#44475a" : undefined} paddingLeft={2}>
|
|
246
|
+
<text fg={isSelected ? "#ff79c6" : "#f8f8f2"}>
|
|
247
|
+
{`${item.cmd!.id} ${item.cmd!.label}`}
|
|
248
|
+
</text>
|
|
249
|
+
</box>
|
|
250
|
+
);
|
|
251
|
+
})}
|
|
252
|
+
{flatItems.length === 0 && (
|
|
253
|
+
<box height={1}>
|
|
254
|
+
<text fg="#6c6c7c">No commands found</text>
|
|
255
|
+
</box>
|
|
256
|
+
)}
|
|
257
|
+
</box>
|
|
258
|
+
</box>
|
|
259
|
+
</box>
|
|
260
|
+
);
|
|
261
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confirm Modal
|
|
3
|
+
*
|
|
4
|
+
* Generic confirmation dialog with customizable title, message, and buttons.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useState } from "react";
|
|
8
|
+
import { useKeyboard } from "@opentui/react";
|
|
9
|
+
import { createTextAttributes } from "@opentui/core";
|
|
10
|
+
import type { MouseEvent } from "@opentui/core";
|
|
11
|
+
|
|
12
|
+
interface ConfirmModalProps {
|
|
13
|
+
isActive: boolean;
|
|
14
|
+
title: string;
|
|
15
|
+
message: string;
|
|
16
|
+
confirmLabel?: string;
|
|
17
|
+
cancelLabel?: string;
|
|
18
|
+
onConfirm: () => void;
|
|
19
|
+
onCancel: () => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function Button({
|
|
23
|
+
label,
|
|
24
|
+
fgColor,
|
|
25
|
+
bgColor,
|
|
26
|
+
hoverBgColor,
|
|
27
|
+
isActive,
|
|
28
|
+
onClick,
|
|
29
|
+
}: {
|
|
30
|
+
label: string;
|
|
31
|
+
fgColor: string;
|
|
32
|
+
bgColor: string;
|
|
33
|
+
hoverBgColor: string;
|
|
34
|
+
isActive: boolean;
|
|
35
|
+
onClick: () => void;
|
|
36
|
+
}) {
|
|
37
|
+
const [hover, setHover] = useState(false);
|
|
38
|
+
const currentBg = hover ? hoverBgColor : bgColor;
|
|
39
|
+
|
|
40
|
+
const handleMouseUp = (e: MouseEvent) => {
|
|
41
|
+
if (isActive) {
|
|
42
|
+
e.stopPropagation();
|
|
43
|
+
onClick();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const handleMouseOver = () => {
|
|
48
|
+
if (isActive) setHover(true);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const handleMouseOut = () => {
|
|
52
|
+
if (isActive) setHover(false);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<box
|
|
57
|
+
paddingX={1}
|
|
58
|
+
backgroundColor={currentBg}
|
|
59
|
+
onMouseUp={handleMouseUp}
|
|
60
|
+
onMouseOver={handleMouseOver}
|
|
61
|
+
onMouseOut={handleMouseOut}
|
|
62
|
+
>
|
|
63
|
+
<text fg={fgColor} attributes={createTextAttributes({ bold: true })}>
|
|
64
|
+
{label}
|
|
65
|
+
</text>
|
|
66
|
+
</box>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function ConfirmModal({
|
|
71
|
+
isActive,
|
|
72
|
+
title,
|
|
73
|
+
message,
|
|
74
|
+
confirmLabel = "Yes",
|
|
75
|
+
cancelLabel = "No",
|
|
76
|
+
onConfirm,
|
|
77
|
+
onCancel,
|
|
78
|
+
}: ConfirmModalProps) {
|
|
79
|
+
useKeyboard((key) => {
|
|
80
|
+
if (!isActive) return;
|
|
81
|
+
if (key.name === "y" || key.name === "return") {
|
|
82
|
+
onConfirm();
|
|
83
|
+
} else if (key.name === "n" || key.name === "escape") {
|
|
84
|
+
onCancel();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (!isActive) return null;
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<box
|
|
92
|
+
position="absolute"
|
|
93
|
+
top={0}
|
|
94
|
+
left={0}
|
|
95
|
+
width="100%"
|
|
96
|
+
height="100%"
|
|
97
|
+
backgroundColor="#00000080"
|
|
98
|
+
alignItems="center"
|
|
99
|
+
justifyContent="center"
|
|
100
|
+
>
|
|
101
|
+
<box
|
|
102
|
+
borderStyle="rounded"
|
|
103
|
+
borderColor="#4a4a5a"
|
|
104
|
+
backgroundColor="#1a1a2e"
|
|
105
|
+
paddingX={2}
|
|
106
|
+
paddingY={1}
|
|
107
|
+
flexDirection="column"
|
|
108
|
+
alignItems="center"
|
|
109
|
+
>
|
|
110
|
+
<text attributes={createTextAttributes({ bold: true })} fg="#fb7185">
|
|
111
|
+
{title}
|
|
112
|
+
</text>
|
|
113
|
+
<text>{message}</text>
|
|
114
|
+
<box marginTop={1} flexDirection="row" gap={2}>
|
|
115
|
+
<Button
|
|
116
|
+
label={` ${confirmLabel} `}
|
|
117
|
+
fgColor="white"
|
|
118
|
+
bgColor="#f43f5e"
|
|
119
|
+
hoverBgColor="#fb7185"
|
|
120
|
+
isActive={isActive}
|
|
121
|
+
onClick={onConfirm}
|
|
122
|
+
/>
|
|
123
|
+
<Button
|
|
124
|
+
label={` ${cancelLabel} `}
|
|
125
|
+
fgColor="white"
|
|
126
|
+
bgColor="#2dd4bf"
|
|
127
|
+
hoverBgColor="#5eead4"
|
|
128
|
+
isActive={isActive}
|
|
129
|
+
onClick={onCancel}
|
|
130
|
+
/>
|
|
131
|
+
</box>
|
|
132
|
+
</box>
|
|
133
|
+
</box>
|
|
134
|
+
);
|
|
135
|
+
}
|