@copilotkit/react-ui 1.4.7 → 1.4.8-next.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/CHANGELOG.md +21 -0
- package/dist/{chunk-4T3TMQNJ.mjs → chunk-BH6PCAAL.mjs} +38 -2
- package/dist/chunk-BH6PCAAL.mjs.map +1 -0
- package/dist/{chunk-63ZKP62F.mjs → chunk-E5SSVET3.mjs} +3 -3
- package/dist/{chunk-4LUMV4YO.mjs → chunk-EMQEEXUB.mjs} +8 -3
- package/dist/chunk-EMQEEXUB.mjs.map +1 -0
- package/dist/{chunk-VYKDFXGS.mjs → chunk-FUDBUYBG.mjs} +2 -2
- package/dist/chunk-ICGZEGHQ.mjs +155 -0
- package/dist/chunk-ICGZEGHQ.mjs.map +1 -0
- package/dist/{chunk-DHGDU64D.mjs → chunk-T35X2SFE.mjs} +3 -3
- package/dist/{chunk-2B57NCBA.mjs → chunk-TTYR7XPN.mjs} +2 -2
- package/dist/{chunk-TKFQ7VQR.mjs → chunk-ZQFKJLQ6.mjs} +2 -2
- package/dist/components/chat/Chat.js +123 -4
- package/dist/components/chat/Chat.js.map +1 -1
- package/dist/components/chat/Chat.mjs +5 -5
- package/dist/components/chat/Input.js +7 -2
- package/dist/components/chat/Input.js.map +1 -1
- package/dist/components/chat/Input.mjs +1 -1
- package/dist/components/chat/Modal.js +123 -4
- package/dist/components/chat/Modal.js.map +1 -1
- package/dist/components/chat/Modal.mjs +6 -6
- package/dist/components/chat/Popup.js +123 -4
- package/dist/components/chat/Popup.js.map +1 -1
- package/dist/components/chat/Popup.mjs +7 -7
- package/dist/components/chat/Sidebar.js +123 -4
- package/dist/components/chat/Sidebar.js.map +1 -1
- package/dist/components/chat/Sidebar.mjs +7 -7
- package/dist/components/chat/index.js +123 -4
- package/dist/components/chat/index.js.map +1 -1
- package/dist/components/chat/index.mjs +8 -8
- package/dist/components/dev-console/console.js +116 -2
- package/dist/components/dev-console/console.js.map +1 -1
- package/dist/components/dev-console/console.mjs +3 -3
- package/dist/components/dev-console/index.js +116 -2
- package/dist/components/dev-console/index.js.map +1 -1
- package/dist/components/dev-console/index.mjs +3 -3
- package/dist/components/help-modal/icons.d.ts +4 -1
- package/dist/components/help-modal/icons.js +39 -2
- package/dist/components/help-modal/icons.js.map +1 -1
- package/dist/components/help-modal/icons.mjs +5 -3
- package/dist/components/help-modal/index.js +136 -2
- package/dist/components/help-modal/index.js.map +1 -1
- package/dist/components/help-modal/index.mjs +2 -2
- package/dist/components/help-modal/modal.js +136 -2
- package/dist/components/help-modal/modal.js.map +1 -1
- package/dist/components/help-modal/modal.mjs +2 -2
- package/dist/components/index.js +123 -4
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +8 -8
- package/dist/index.js +123 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8 -8
- package/package.json +4 -4
- package/src/components/chat/Input.tsx +9 -2
- package/src/components/help-modal/icons.tsx +28 -0
- package/src/components/help-modal/modal.tsx +90 -27
- package/dist/chunk-4LUMV4YO.mjs.map +0 -1
- package/dist/chunk-4T3TMQNJ.mjs.map +0 -1
- package/dist/chunk-WOUWNTAV.mjs +0 -72
- package/dist/chunk-WOUWNTAV.mjs.map +0 -1
- /package/dist/{chunk-63ZKP62F.mjs.map → chunk-E5SSVET3.mjs.map} +0 -0
- /package/dist/{chunk-VYKDFXGS.mjs.map → chunk-FUDBUYBG.mjs.map} +0 -0
- /package/dist/{chunk-DHGDU64D.mjs.map → chunk-T35X2SFE.mjs.map} +0 -0
- /package/dist/{chunk-2B57NCBA.mjs.map → chunk-TTYR7XPN.mjs.map} +0 -0
- /package/dist/{chunk-TKFQ7VQR.mjs.map → chunk-ZQFKJLQ6.mjs.map} +0 -0
|
@@ -2,20 +2,20 @@ import {
|
|
|
2
2
|
CopilotChat,
|
|
3
3
|
WrappedCopilotChat,
|
|
4
4
|
useCopilotChatLogic
|
|
5
|
-
} from "../../chunk-
|
|
5
|
+
} from "../../chunk-T35X2SFE.mjs";
|
|
6
6
|
import "../../chunk-6INMITFA.mjs";
|
|
7
7
|
import "../../chunk-RU73BEZM.mjs";
|
|
8
8
|
import "../../chunk-V7W6IM2V.mjs";
|
|
9
9
|
import "../../chunk-OMTPWC7T.mjs";
|
|
10
10
|
import "../../chunk-ZABXREBH.mjs";
|
|
11
11
|
import "../../chunk-RJCZRKTV.mjs";
|
|
12
|
-
import "../../chunk-
|
|
12
|
+
import "../../chunk-TTYR7XPN.mjs";
|
|
13
13
|
import "../../chunk-4FIGRRFS.mjs";
|
|
14
14
|
import "../../chunk-KXE2JCUH.mjs";
|
|
15
|
-
import "../../chunk-
|
|
16
|
-
import "../../chunk-
|
|
15
|
+
import "../../chunk-ICGZEGHQ.mjs";
|
|
16
|
+
import "../../chunk-BH6PCAAL.mjs";
|
|
17
17
|
import "../../chunk-OTPAZXVR.mjs";
|
|
18
|
-
import "../../chunk-
|
|
18
|
+
import "../../chunk-EMQEEXUB.mjs";
|
|
19
19
|
import "../../chunk-YQFVRDNC.mjs";
|
|
20
20
|
import "../../chunk-YQ3D5IQV.mjs";
|
|
21
21
|
import "../../chunk-RKPANT3F.mjs";
|
|
@@ -271,7 +271,10 @@ var Input = ({ inProgress, onSend, isVisible = false }) => {
|
|
|
271
271
|
});
|
|
272
272
|
const sendIcon = inProgress || pushToTalkState === "transcribing" ? context.icons.activityIcon : context.icons.sendIcon;
|
|
273
273
|
const showPushToTalk = pushToTalkConfigured && (pushToTalkState === "idle" || pushToTalkState === "recording") && !inProgress;
|
|
274
|
-
const
|
|
274
|
+
const canSend = () => {
|
|
275
|
+
return !inProgress && text.trim().length > 0 && pushToTalkState === "idle";
|
|
276
|
+
};
|
|
277
|
+
const sendDisabled = !canSend();
|
|
275
278
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "copilotKitInput", onClick: handleDivClick, children: [
|
|
276
279
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
277
280
|
Textarea_default,
|
|
@@ -285,7 +288,9 @@ var Input = ({ inProgress, onSend, isVisible = false }) => {
|
|
|
285
288
|
onKeyDown: (event) => {
|
|
286
289
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
287
290
|
event.preventDefault();
|
|
288
|
-
|
|
291
|
+
if (canSend()) {
|
|
292
|
+
send();
|
|
293
|
+
}
|
|
289
294
|
}
|
|
290
295
|
}
|
|
291
296
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/chat/Input.tsx","../../../src/components/chat/ChatContext.tsx","../../../src/components/chat/Textarea.tsx","../../../src/hooks/use-push-to-talk.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport { InputProps } from \"./props\";\nimport { useChatContext } from \"./ChatContext\";\nimport AutoResizingTextarea from \"./Textarea\";\nimport { usePushToTalk } from \"../../hooks/use-push-to-talk\";\nimport { useCopilotContext } from \"@copilotkit/react-core\";\n\nexport const Input = ({ inProgress, onSend, isVisible = false }: InputProps) => {\n const context = useChatContext();\n const copilotContext = useCopilotContext();\n\n const pushToTalkConfigured =\n copilotContext.copilotApiConfig.textToSpeechUrl !== undefined &&\n copilotContext.copilotApiConfig.transcribeAudioUrl !== undefined;\n\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n const handleDivClick = (event: React.MouseEvent<HTMLDivElement>) => {\n // Check if the clicked element is not the textarea itself\n if (event.target !== event.currentTarget) return;\n\n textareaRef.current?.focus();\n };\n\n const [text, setText] = useState(\"\");\n const send = () => {\n if (inProgress) return;\n onSend(text);\n setText(\"\");\n\n textareaRef.current?.focus();\n };\n\n useEffect(() => {\n if (isVisible) {\n textareaRef.current?.focus();\n }\n }, [isVisible]);\n\n const { pushToTalkState, setPushToTalkState } = usePushToTalk({\n sendFunction: onSend,\n inProgress,\n });\n\n const sendIcon =\n inProgress || pushToTalkState === \"transcribing\"\n ? context.icons.activityIcon\n : context.icons.sendIcon;\n const showPushToTalk =\n pushToTalkConfigured &&\n (pushToTalkState === \"idle\" || pushToTalkState === \"recording\") &&\n !inProgress;\n const sendDisabled = inProgress || text.length === 0 || pushToTalkState !== \"idle\";\n\n return (\n <div className=\"copilotKitInput\" onClick={handleDivClick}>\n <AutoResizingTextarea\n ref={textareaRef}\n placeholder={context.labels.placeholder}\n autoFocus={true}\n maxRows={5}\n value={text}\n onChange={(event) => setText(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n send();\n }\n }}\n />\n <div className=\"copilotKitInputControls\">\n {showPushToTalk && (\n <button\n onClick={() =>\n setPushToTalkState(pushToTalkState === \"idle\" ? \"recording\" : \"transcribing\")\n }\n className={pushToTalkState === \"recording\" ? \"copilotKitPushToTalkRecording\" : \"\"}\n >\n {context.icons.pushToTalkIcon}\n </button>\n )}\n <button\n disabled={sendDisabled}\n onClick={send}\n data-copilotkit-in-progress={!!inProgress}\n data-testid={inProgress ? \"copilot-chat-request-in-progress\" : undefined}\n >\n {sendIcon}\n </button>\n </div>\n </div>\n );\n};\n","import React, { useMemo, useState } from \"react\";\nimport * as DefaultIcons from \"./Icons\";\n\n/**\n * Icons for CopilotChat component.\n */\nexport interface CopilotChatIcons {\n /**\n * The icon to use for the open chat button.\n * @default <OpenIcon />\n */\n openIcon?: React.ReactNode;\n\n /**\n * The icon to use for the close chat button.\n * @default <CloseIcon />\n */\n closeIcon?: React.ReactNode;\n\n /**\n * The icon to use for the close chat button in the header.\n * @default <HeaderCloseIcon />\n */\n headerCloseIcon?: React.ReactNode;\n\n /**\n * The icon to use for the send button.\n * @default <SendIcon />\n */\n sendIcon?: React.ReactNode;\n\n /**\n * The icon to use for the activity indicator.\n * @default <ActivityIcon />\n */\n activityIcon?: React.ReactNode;\n\n /**\n * The icon to use for the spinner.\n * @default <SpinnerIcon />\n */\n spinnerIcon?: React.ReactNode;\n\n /**\n * The icon to use for the stop button.\n * @default <StopIcon />\n */\n stopIcon?: React.ReactNode;\n\n /**\n * The icon to use for the regenerate button.\n * @default <RegenerateIcon />\n */\n regenerateIcon?: React.ReactNode;\n\n /**\n * The icons to use for push to talk.\n * @default <PushToTalkIcon />\n */\n\n pushToTalkIcon?: React.ReactNode;\n}\n\n/**\n * Labels for CopilotChat component.\n */\nexport interface CopilotChatLabels {\n /**\n * The initial message(s) to display in the chat window.\n */\n initial?: string | string[];\n\n /**\n * The title to display in the header.\n * @default \"CopilotKit\"\n */\n title?: string;\n\n /**\n * The placeholder to display in the input.\n * @default \"Type a message...\"\n */\n placeholder?: string;\n\n /**\n * The message to display when an error occurs.\n * @default \"❌ An error occurred. Please try again.\"\n */\n error?: string;\n\n /**\n * The label to display on the stop button.\n * @default \"Stop generating\"\n */\n stopGenerating?: string;\n\n /**\n * The label to display on the regenerate button.\n * @default \"Regenerate response\"\n */\n regenerateResponse?: string;\n}\n\ninterface ChatContext {\n labels: Required<CopilotChatLabels>;\n icons: Required<CopilotChatIcons>;\n open: boolean;\n setOpen: (open: boolean) => void;\n}\n\nexport const ChatContext = React.createContext<ChatContext | undefined>(undefined);\n\nexport function useChatContext(): ChatContext {\n const context = React.useContext(ChatContext);\n if (context === undefined) {\n throw new Error(\n \"Context not found. Did you forget to wrap your app in a <ChatContextProvider> component?\",\n );\n }\n return context;\n}\n\ninterface ChatContextProps {\n // temperature?: number;\n // instructions?: string;\n // maxFeedback?: number;\n labels?: CopilotChatLabels;\n icons?: CopilotChatIcons;\n children?: React.ReactNode;\n open: boolean;\n setOpen: (open: boolean) => void;\n}\n\nexport const ChatContextProvider = ({\n // temperature,\n // instructions,\n // maxFeedback,\n labels,\n icons,\n children,\n open,\n setOpen,\n}: ChatContextProps) => {\n const memoizedLabels = useMemo(\n () => ({\n ...{\n initial: \"\",\n title: \"CopilotKit\",\n placeholder: \"Type a message...\",\n error: \"❌ An error occurred. Please try again.\",\n stopGenerating: \"Stop generating\",\n regenerateResponse: \"Regenerate response\",\n },\n ...labels,\n }),\n [labels],\n );\n\n const memoizedIcons = useMemo(\n () => ({\n ...{\n openIcon: DefaultIcons.OpenIcon,\n closeIcon: DefaultIcons.CloseIcon,\n headerCloseIcon: DefaultIcons.HeaderCloseIcon,\n sendIcon: DefaultIcons.SendIcon,\n activityIcon: DefaultIcons.ActivityIcon,\n spinnerIcon: DefaultIcons.SpinnerIcon,\n stopIcon: DefaultIcons.StopIcon,\n regenerateIcon: DefaultIcons.RegenerateIcon,\n pushToTalkIcon: DefaultIcons.PushToTalkIcon,\n },\n ...icons,\n }),\n [icons],\n );\n\n const context = useMemo(\n () => ({\n labels: memoizedLabels,\n icons: memoizedIcons,\n open,\n setOpen,\n }),\n [memoizedLabels, memoizedIcons, open, setOpen],\n );\n\n return <ChatContext.Provider value={context}>{children}</ChatContext.Provider>;\n};\n","import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle } from \"react\";\n\ninterface AutoResizingTextareaProps {\n maxRows?: number;\n placeholder?: string;\n value: string;\n onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;\n onKeyDown?: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;\n autoFocus?: boolean;\n}\n\nconst AutoResizingTextarea = forwardRef<HTMLTextAreaElement, AutoResizingTextareaProps>(\n ({ maxRows = 1, placeholder, value, onChange, onKeyDown, autoFocus }, ref) => {\n const internalTextareaRef = useRef<HTMLTextAreaElement>(null);\n const [maxHeight, setMaxHeight] = useState<number>(0);\n\n useImperativeHandle(ref, () => internalTextareaRef.current as HTMLTextAreaElement);\n\n useEffect(() => {\n const calculateMaxHeight = () => {\n const textarea = internalTextareaRef.current;\n if (textarea) {\n textarea.style.height = \"auto\";\n const singleRowHeight = textarea.scrollHeight;\n setMaxHeight(singleRowHeight * maxRows);\n if (autoFocus) {\n textarea.focus();\n }\n }\n };\n\n calculateMaxHeight();\n }, [maxRows]);\n\n useEffect(() => {\n const textarea = internalTextareaRef.current;\n if (textarea) {\n textarea.style.height = \"auto\";\n textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;\n }\n }, [value, maxHeight]);\n\n return (\n <textarea\n ref={internalTextareaRef}\n value={value}\n onChange={onChange}\n onKeyDown={onKeyDown}\n placeholder={placeholder}\n style={{\n overflow: \"auto\",\n resize: \"none\",\n maxHeight: `${maxHeight}px`,\n }}\n rows={1}\n />\n );\n },\n);\n\nexport default AutoResizingTextarea;\n","import { useCopilotContext, useCopilotMessagesContext } from \"@copilotkit/react-core\";\nimport { Message, TextMessage } from \"@copilotkit/runtime-client-gql\";\nimport { MutableRefObject, useEffect, useRef, useState } from \"react\";\n\nexport const checkMicrophonePermission = async () => {\n try {\n const permissionStatus = await navigator.permissions.query({\n name: \"microphone\" as PermissionName,\n });\n if (permissionStatus.state === \"granted\") {\n return true;\n } else {\n return false;\n }\n } catch (err) {\n console.error(\"Error checking microphone permission\", err);\n }\n};\n\nexport const requestMicAndPlaybackPermission = async () => {\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n const audioContext = new window.AudioContext();\n await audioContext.resume();\n return { stream, audioContext };\n } catch (err) {\n console.error(\"Error requesting microphone and playback permissions\", err);\n return null;\n }\n};\n\nconst startRecording = async (\n mediaStreamRef: MutableRefObject<MediaStream | null>,\n mediaRecorderRef: MutableRefObject<MediaRecorder | null>,\n audioContextRef: MutableRefObject<AudioContext | null>,\n recordedChunks: Blob[],\n onStop: () => void,\n) => {\n if (!mediaStreamRef.current || !audioContextRef.current) {\n mediaStreamRef.current = await navigator.mediaDevices.getUserMedia({ audio: true });\n audioContextRef.current = new window.AudioContext();\n await audioContextRef.current.resume();\n }\n\n mediaRecorderRef.current = new MediaRecorder(mediaStreamRef.current!);\n mediaRecorderRef.current.start(1000);\n mediaRecorderRef.current.ondataavailable = (event) => {\n recordedChunks.push(event.data);\n };\n mediaRecorderRef.current.onstop = onStop;\n};\n\nconst stopRecording = (mediaRecorderRef: MutableRefObject<MediaRecorder | null>) => {\n if (mediaRecorderRef.current && mediaRecorderRef.current.state !== \"inactive\") {\n mediaRecorderRef.current.stop();\n }\n};\n\nconst transcribeAudio = async (recordedChunks: Blob[], transcribeAudioUrl: string) => {\n const completeBlob = new Blob(recordedChunks, { type: \"audio/mp4\" });\n const formData = new FormData();\n formData.append(\"file\", completeBlob, \"recording.mp4\");\n\n const response = await fetch(transcribeAudioUrl, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n throw new Error(`Error: ${response.statusText}`);\n }\n\n const transcription = await response.json();\n return transcription.text;\n};\n\nconst playAudioResponse = (text: string, textToSpeechUrl: string, audioContext: AudioContext) => {\n const encodedText = encodeURIComponent(text);\n const url = `${textToSpeechUrl}?text=${encodedText}`;\n\n fetch(url)\n .then((response) => response.arrayBuffer())\n .then((arrayBuffer) => audioContext.decodeAudioData(arrayBuffer))\n .then((audioBuffer) => {\n const source = audioContext.createBufferSource();\n source.buffer = audioBuffer;\n source.connect(audioContext.destination);\n source.start(0);\n })\n .catch((error) => {\n console.error(\"Error with decoding audio data\", error);\n });\n};\n\nexport type PushToTalkState = \"idle\" | \"recording\" | \"transcribing\";\n\nexport type SendFunction = (text: string) => Promise<Message>;\n\nexport const usePushToTalk = ({\n sendFunction,\n inProgress,\n}: {\n sendFunction: SendFunction;\n inProgress: boolean;\n}) => {\n const [pushToTalkState, setPushToTalkState] = useState<PushToTalkState>(\"idle\");\n const mediaStreamRef = useRef<MediaStream | null>(null);\n const audioContextRef = useRef<AudioContext | null>(null);\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const recordedChunks = useRef<Blob[]>([]);\n const generalContext = useCopilotContext();\n const messagesContext = useCopilotMessagesContext();\n const context = { ...generalContext, ...messagesContext };\n const [startReadingFromMessageId, setStartReadingFromMessageId] = useState<string | null>(null);\n\n useEffect(() => {\n if (pushToTalkState === \"recording\") {\n startRecording(\n mediaStreamRef,\n mediaRecorderRef,\n audioContextRef,\n recordedChunks.current,\n () => {\n setPushToTalkState(\"transcribing\");\n },\n );\n } else {\n stopRecording(mediaRecorderRef);\n if (pushToTalkState === \"transcribing\") {\n transcribeAudio(recordedChunks.current, context.copilotApiConfig.transcribeAudioUrl!).then(\n async (transcription) => {\n recordedChunks.current = [];\n setPushToTalkState(\"idle\");\n const message = await sendFunction(transcription);\n setStartReadingFromMessageId(message.id);\n },\n );\n }\n }\n\n return () => {\n stopRecording(mediaRecorderRef);\n };\n }, [pushToTalkState]);\n\n useEffect(() => {\n if (inProgress === false && startReadingFromMessageId) {\n const lastMessageIndex = context.messages.findIndex(\n (message) => message.id === startReadingFromMessageId,\n );\n\n const messagesAfterLast = context.messages\n .slice(lastMessageIndex + 1)\n .filter(\n (message) => message.isTextMessage() && message.role === \"assistant\",\n ) as TextMessage[];\n\n const text = messagesAfterLast.map((message) => message.content).join(\"\\n\");\n playAudioResponse(text, context.copilotApiConfig.textToSpeechUrl!, audioContextRef.current!);\n\n setStartReadingFromMessageId(null);\n }\n }, [startReadingFromMessageId, inProgress]);\n\n return { pushToTalkState, setPushToTalkState };\n};\n"],"mappings":"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","names":["import_react","React","import_react","import_jsx_runtime","import_react","import_react_core","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/chat/Input.tsx","../../../src/components/chat/ChatContext.tsx","../../../src/components/chat/Textarea.tsx","../../../src/hooks/use-push-to-talk.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport { InputProps } from \"./props\";\nimport { useChatContext } from \"./ChatContext\";\nimport AutoResizingTextarea from \"./Textarea\";\nimport { usePushToTalk } from \"../../hooks/use-push-to-talk\";\nimport { useCopilotContext } from \"@copilotkit/react-core\";\n\nexport const Input = ({ inProgress, onSend, isVisible = false }: InputProps) => {\n const context = useChatContext();\n const copilotContext = useCopilotContext();\n\n const pushToTalkConfigured =\n copilotContext.copilotApiConfig.textToSpeechUrl !== undefined &&\n copilotContext.copilotApiConfig.transcribeAudioUrl !== undefined;\n\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n const handleDivClick = (event: React.MouseEvent<HTMLDivElement>) => {\n // Check if the clicked element is not the textarea itself\n if (event.target !== event.currentTarget) return;\n\n textareaRef.current?.focus();\n };\n\n const [text, setText] = useState(\"\");\n const send = () => {\n if (inProgress) return;\n onSend(text);\n setText(\"\");\n\n textareaRef.current?.focus();\n };\n\n useEffect(() => {\n if (isVisible) {\n textareaRef.current?.focus();\n }\n }, [isVisible]);\n\n const { pushToTalkState, setPushToTalkState } = usePushToTalk({\n sendFunction: onSend,\n inProgress,\n });\n\n const sendIcon =\n inProgress || pushToTalkState === \"transcribing\"\n ? context.icons.activityIcon\n : context.icons.sendIcon;\n const showPushToTalk =\n pushToTalkConfigured &&\n (pushToTalkState === \"idle\" || pushToTalkState === \"recording\") &&\n !inProgress;\n\n const canSend = () => {\n return !inProgress && text.trim().length > 0 && pushToTalkState === \"idle\";\n };\n\n const sendDisabled = !canSend();\n\n return (\n <div className=\"copilotKitInput\" onClick={handleDivClick}>\n <AutoResizingTextarea\n ref={textareaRef}\n placeholder={context.labels.placeholder}\n autoFocus={true}\n maxRows={5}\n value={text}\n onChange={(event) => setText(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n if (canSend()) {\n send();\n }\n }\n }}\n />\n <div className=\"copilotKitInputControls\">\n {showPushToTalk && (\n <button\n onClick={() =>\n setPushToTalkState(pushToTalkState === \"idle\" ? \"recording\" : \"transcribing\")\n }\n className={pushToTalkState === \"recording\" ? \"copilotKitPushToTalkRecording\" : \"\"}\n >\n {context.icons.pushToTalkIcon}\n </button>\n )}\n <button\n disabled={sendDisabled}\n onClick={send}\n data-copilotkit-in-progress={!!inProgress}\n data-testid={inProgress ? \"copilot-chat-request-in-progress\" : undefined}\n >\n {sendIcon}\n </button>\n </div>\n </div>\n );\n};\n","import React, { useMemo, useState } from \"react\";\nimport * as DefaultIcons from \"./Icons\";\n\n/**\n * Icons for CopilotChat component.\n */\nexport interface CopilotChatIcons {\n /**\n * The icon to use for the open chat button.\n * @default <OpenIcon />\n */\n openIcon?: React.ReactNode;\n\n /**\n * The icon to use for the close chat button.\n * @default <CloseIcon />\n */\n closeIcon?: React.ReactNode;\n\n /**\n * The icon to use for the close chat button in the header.\n * @default <HeaderCloseIcon />\n */\n headerCloseIcon?: React.ReactNode;\n\n /**\n * The icon to use for the send button.\n * @default <SendIcon />\n */\n sendIcon?: React.ReactNode;\n\n /**\n * The icon to use for the activity indicator.\n * @default <ActivityIcon />\n */\n activityIcon?: React.ReactNode;\n\n /**\n * The icon to use for the spinner.\n * @default <SpinnerIcon />\n */\n spinnerIcon?: React.ReactNode;\n\n /**\n * The icon to use for the stop button.\n * @default <StopIcon />\n */\n stopIcon?: React.ReactNode;\n\n /**\n * The icon to use for the regenerate button.\n * @default <RegenerateIcon />\n */\n regenerateIcon?: React.ReactNode;\n\n /**\n * The icons to use for push to talk.\n * @default <PushToTalkIcon />\n */\n\n pushToTalkIcon?: React.ReactNode;\n}\n\n/**\n * Labels for CopilotChat component.\n */\nexport interface CopilotChatLabels {\n /**\n * The initial message(s) to display in the chat window.\n */\n initial?: string | string[];\n\n /**\n * The title to display in the header.\n * @default \"CopilotKit\"\n */\n title?: string;\n\n /**\n * The placeholder to display in the input.\n * @default \"Type a message...\"\n */\n placeholder?: string;\n\n /**\n * The message to display when an error occurs.\n * @default \"❌ An error occurred. Please try again.\"\n */\n error?: string;\n\n /**\n * The label to display on the stop button.\n * @default \"Stop generating\"\n */\n stopGenerating?: string;\n\n /**\n * The label to display on the regenerate button.\n * @default \"Regenerate response\"\n */\n regenerateResponse?: string;\n}\n\ninterface ChatContext {\n labels: Required<CopilotChatLabels>;\n icons: Required<CopilotChatIcons>;\n open: boolean;\n setOpen: (open: boolean) => void;\n}\n\nexport const ChatContext = React.createContext<ChatContext | undefined>(undefined);\n\nexport function useChatContext(): ChatContext {\n const context = React.useContext(ChatContext);\n if (context === undefined) {\n throw new Error(\n \"Context not found. Did you forget to wrap your app in a <ChatContextProvider> component?\",\n );\n }\n return context;\n}\n\ninterface ChatContextProps {\n // temperature?: number;\n // instructions?: string;\n // maxFeedback?: number;\n labels?: CopilotChatLabels;\n icons?: CopilotChatIcons;\n children?: React.ReactNode;\n open: boolean;\n setOpen: (open: boolean) => void;\n}\n\nexport const ChatContextProvider = ({\n // temperature,\n // instructions,\n // maxFeedback,\n labels,\n icons,\n children,\n open,\n setOpen,\n}: ChatContextProps) => {\n const memoizedLabels = useMemo(\n () => ({\n ...{\n initial: \"\",\n title: \"CopilotKit\",\n placeholder: \"Type a message...\",\n error: \"❌ An error occurred. Please try again.\",\n stopGenerating: \"Stop generating\",\n regenerateResponse: \"Regenerate response\",\n },\n ...labels,\n }),\n [labels],\n );\n\n const memoizedIcons = useMemo(\n () => ({\n ...{\n openIcon: DefaultIcons.OpenIcon,\n closeIcon: DefaultIcons.CloseIcon,\n headerCloseIcon: DefaultIcons.HeaderCloseIcon,\n sendIcon: DefaultIcons.SendIcon,\n activityIcon: DefaultIcons.ActivityIcon,\n spinnerIcon: DefaultIcons.SpinnerIcon,\n stopIcon: DefaultIcons.StopIcon,\n regenerateIcon: DefaultIcons.RegenerateIcon,\n pushToTalkIcon: DefaultIcons.PushToTalkIcon,\n },\n ...icons,\n }),\n [icons],\n );\n\n const context = useMemo(\n () => ({\n labels: memoizedLabels,\n icons: memoizedIcons,\n open,\n setOpen,\n }),\n [memoizedLabels, memoizedIcons, open, setOpen],\n );\n\n return <ChatContext.Provider value={context}>{children}</ChatContext.Provider>;\n};\n","import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle } from \"react\";\n\ninterface AutoResizingTextareaProps {\n maxRows?: number;\n placeholder?: string;\n value: string;\n onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;\n onKeyDown?: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;\n autoFocus?: boolean;\n}\n\nconst AutoResizingTextarea = forwardRef<HTMLTextAreaElement, AutoResizingTextareaProps>(\n ({ maxRows = 1, placeholder, value, onChange, onKeyDown, autoFocus }, ref) => {\n const internalTextareaRef = useRef<HTMLTextAreaElement>(null);\n const [maxHeight, setMaxHeight] = useState<number>(0);\n\n useImperativeHandle(ref, () => internalTextareaRef.current as HTMLTextAreaElement);\n\n useEffect(() => {\n const calculateMaxHeight = () => {\n const textarea = internalTextareaRef.current;\n if (textarea) {\n textarea.style.height = \"auto\";\n const singleRowHeight = textarea.scrollHeight;\n setMaxHeight(singleRowHeight * maxRows);\n if (autoFocus) {\n textarea.focus();\n }\n }\n };\n\n calculateMaxHeight();\n }, [maxRows]);\n\n useEffect(() => {\n const textarea = internalTextareaRef.current;\n if (textarea) {\n textarea.style.height = \"auto\";\n textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;\n }\n }, [value, maxHeight]);\n\n return (\n <textarea\n ref={internalTextareaRef}\n value={value}\n onChange={onChange}\n onKeyDown={onKeyDown}\n placeholder={placeholder}\n style={{\n overflow: \"auto\",\n resize: \"none\",\n maxHeight: `${maxHeight}px`,\n }}\n rows={1}\n />\n );\n },\n);\n\nexport default AutoResizingTextarea;\n","import { useCopilotContext, useCopilotMessagesContext } from \"@copilotkit/react-core\";\nimport { Message, TextMessage } from \"@copilotkit/runtime-client-gql\";\nimport { MutableRefObject, useEffect, useRef, useState } from \"react\";\n\nexport const checkMicrophonePermission = async () => {\n try {\n const permissionStatus = await navigator.permissions.query({\n name: \"microphone\" as PermissionName,\n });\n if (permissionStatus.state === \"granted\") {\n return true;\n } else {\n return false;\n }\n } catch (err) {\n console.error(\"Error checking microphone permission\", err);\n }\n};\n\nexport const requestMicAndPlaybackPermission = async () => {\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n const audioContext = new window.AudioContext();\n await audioContext.resume();\n return { stream, audioContext };\n } catch (err) {\n console.error(\"Error requesting microphone and playback permissions\", err);\n return null;\n }\n};\n\nconst startRecording = async (\n mediaStreamRef: MutableRefObject<MediaStream | null>,\n mediaRecorderRef: MutableRefObject<MediaRecorder | null>,\n audioContextRef: MutableRefObject<AudioContext | null>,\n recordedChunks: Blob[],\n onStop: () => void,\n) => {\n if (!mediaStreamRef.current || !audioContextRef.current) {\n mediaStreamRef.current = await navigator.mediaDevices.getUserMedia({ audio: true });\n audioContextRef.current = new window.AudioContext();\n await audioContextRef.current.resume();\n }\n\n mediaRecorderRef.current = new MediaRecorder(mediaStreamRef.current!);\n mediaRecorderRef.current.start(1000);\n mediaRecorderRef.current.ondataavailable = (event) => {\n recordedChunks.push(event.data);\n };\n mediaRecorderRef.current.onstop = onStop;\n};\n\nconst stopRecording = (mediaRecorderRef: MutableRefObject<MediaRecorder | null>) => {\n if (mediaRecorderRef.current && mediaRecorderRef.current.state !== \"inactive\") {\n mediaRecorderRef.current.stop();\n }\n};\n\nconst transcribeAudio = async (recordedChunks: Blob[], transcribeAudioUrl: string) => {\n const completeBlob = new Blob(recordedChunks, { type: \"audio/mp4\" });\n const formData = new FormData();\n formData.append(\"file\", completeBlob, \"recording.mp4\");\n\n const response = await fetch(transcribeAudioUrl, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n throw new Error(`Error: ${response.statusText}`);\n }\n\n const transcription = await response.json();\n return transcription.text;\n};\n\nconst playAudioResponse = (text: string, textToSpeechUrl: string, audioContext: AudioContext) => {\n const encodedText = encodeURIComponent(text);\n const url = `${textToSpeechUrl}?text=${encodedText}`;\n\n fetch(url)\n .then((response) => response.arrayBuffer())\n .then((arrayBuffer) => audioContext.decodeAudioData(arrayBuffer))\n .then((audioBuffer) => {\n const source = audioContext.createBufferSource();\n source.buffer = audioBuffer;\n source.connect(audioContext.destination);\n source.start(0);\n })\n .catch((error) => {\n console.error(\"Error with decoding audio data\", error);\n });\n};\n\nexport type PushToTalkState = \"idle\" | \"recording\" | \"transcribing\";\n\nexport type SendFunction = (text: string) => Promise<Message>;\n\nexport const usePushToTalk = ({\n sendFunction,\n inProgress,\n}: {\n sendFunction: SendFunction;\n inProgress: boolean;\n}) => {\n const [pushToTalkState, setPushToTalkState] = useState<PushToTalkState>(\"idle\");\n const mediaStreamRef = useRef<MediaStream | null>(null);\n const audioContextRef = useRef<AudioContext | null>(null);\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const recordedChunks = useRef<Blob[]>([]);\n const generalContext = useCopilotContext();\n const messagesContext = useCopilotMessagesContext();\n const context = { ...generalContext, ...messagesContext };\n const [startReadingFromMessageId, setStartReadingFromMessageId] = useState<string | null>(null);\n\n useEffect(() => {\n if (pushToTalkState === \"recording\") {\n startRecording(\n mediaStreamRef,\n mediaRecorderRef,\n audioContextRef,\n recordedChunks.current,\n () => {\n setPushToTalkState(\"transcribing\");\n },\n );\n } else {\n stopRecording(mediaRecorderRef);\n if (pushToTalkState === \"transcribing\") {\n transcribeAudio(recordedChunks.current, context.copilotApiConfig.transcribeAudioUrl!).then(\n async (transcription) => {\n recordedChunks.current = [];\n setPushToTalkState(\"idle\");\n const message = await sendFunction(transcription);\n setStartReadingFromMessageId(message.id);\n },\n );\n }\n }\n\n return () => {\n stopRecording(mediaRecorderRef);\n };\n }, [pushToTalkState]);\n\n useEffect(() => {\n if (inProgress === false && startReadingFromMessageId) {\n const lastMessageIndex = context.messages.findIndex(\n (message) => message.id === startReadingFromMessageId,\n );\n\n const messagesAfterLast = context.messages\n .slice(lastMessageIndex + 1)\n .filter(\n (message) => message.isTextMessage() && message.role === \"assistant\",\n ) as TextMessage[];\n\n const text = messagesAfterLast.map((message) => message.content).join(\"\\n\");\n playAudioResponse(text, context.copilotApiConfig.textToSpeechUrl!, audioContextRef.current!);\n\n setStartReadingFromMessageId(null);\n }\n }, [startReadingFromMessageId, inProgress]);\n\n return { pushToTalkState, setPushToTalkState };\n};\n"],"mappings":"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","names":["import_react","React","import_react","import_jsx_runtime","import_react","import_react_core","import_jsx_runtime"]}
|
|
@@ -875,7 +875,10 @@ var Input = ({ inProgress, onSend, isVisible = false }) => {
|
|
|
875
875
|
});
|
|
876
876
|
const sendIcon = inProgress || pushToTalkState === "transcribing" ? context.icons.activityIcon : context.icons.sendIcon;
|
|
877
877
|
const showPushToTalk = pushToTalkConfigured && (pushToTalkState === "idle" || pushToTalkState === "recording") && !inProgress;
|
|
878
|
-
const
|
|
878
|
+
const canSend = () => {
|
|
879
|
+
return !inProgress && text.trim().length > 0 && pushToTalkState === "idle";
|
|
880
|
+
};
|
|
881
|
+
const sendDisabled = !canSend();
|
|
879
882
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "copilotKitInput", onClick: handleDivClick, children: [
|
|
880
883
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
881
884
|
Textarea_default,
|
|
@@ -889,7 +892,9 @@ var Input = ({ inProgress, onSend, isVisible = false }) => {
|
|
|
889
892
|
onKeyDown: (event) => {
|
|
890
893
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
891
894
|
event.preventDefault();
|
|
892
|
-
|
|
895
|
+
if (canSend()) {
|
|
896
|
+
send();
|
|
897
|
+
}
|
|
893
898
|
}
|
|
894
899
|
}
|
|
895
900
|
}
|
|
@@ -1932,15 +1937,79 @@ var CloseIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
|
1932
1937
|
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" })
|
|
1933
1938
|
}
|
|
1934
1939
|
);
|
|
1940
|
+
var LoadingSpinnerIcon = ({ color = "rgb(107 114 128)" }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
1941
|
+
"svg",
|
|
1942
|
+
{
|
|
1943
|
+
style: {
|
|
1944
|
+
animation: "copilotKitSpinAnimation 1s linear infinite",
|
|
1945
|
+
color
|
|
1946
|
+
},
|
|
1947
|
+
width: "24",
|
|
1948
|
+
height: "24",
|
|
1949
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1950
|
+
fill: "none",
|
|
1951
|
+
viewBox: "0 0 24 24",
|
|
1952
|
+
children: [
|
|
1953
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1954
|
+
"circle",
|
|
1955
|
+
{
|
|
1956
|
+
style: { opacity: 0.25 },
|
|
1957
|
+
cx: "12",
|
|
1958
|
+
cy: "12",
|
|
1959
|
+
r: "10",
|
|
1960
|
+
stroke: "currentColor",
|
|
1961
|
+
strokeWidth: "4"
|
|
1962
|
+
}
|
|
1963
|
+
),
|
|
1964
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1965
|
+
"path",
|
|
1966
|
+
{
|
|
1967
|
+
style: { opacity: 0.75 },
|
|
1968
|
+
fill: "currentColor",
|
|
1969
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
1970
|
+
}
|
|
1971
|
+
)
|
|
1972
|
+
]
|
|
1973
|
+
}
|
|
1974
|
+
);
|
|
1935
1975
|
|
|
1936
1976
|
// src/components/help-modal/modal.tsx
|
|
1937
1977
|
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1938
1978
|
function CopilotKitHelpModal() {
|
|
1939
1979
|
const [showHelpModal, setShowHelpModal] = (0, import_react9.useState)(false);
|
|
1940
1980
|
const [issueDescription, setIssueDescription] = (0, import_react9.useState)("");
|
|
1941
|
-
const
|
|
1942
|
-
|
|
1981
|
+
const [email, setEmail] = (0, import_react9.useState)("");
|
|
1982
|
+
const [emailError, setEmailError] = (0, import_react9.useState)("");
|
|
1983
|
+
const [submitting, setSubmitting] = (0, import_react9.useState)(false);
|
|
1984
|
+
const validateEmail = (email2) => {
|
|
1985
|
+
const re = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
1986
|
+
return re.test(email2);
|
|
1943
1987
|
};
|
|
1988
|
+
const handleSubmit = (e) => __async(this, null, function* () {
|
|
1989
|
+
e.preventDefault();
|
|
1990
|
+
if ((email == null ? void 0 : email.length) > 0 && !validateEmail(email)) {
|
|
1991
|
+
setEmailError("Please enter a valid email address");
|
|
1992
|
+
return;
|
|
1993
|
+
}
|
|
1994
|
+
setSubmitting(true);
|
|
1995
|
+
yield fetch("https://api.segment.io/v1/track", {
|
|
1996
|
+
method: "POST",
|
|
1997
|
+
headers: {
|
|
1998
|
+
"Content-Type": "application/json"
|
|
1999
|
+
},
|
|
2000
|
+
body: JSON.stringify({
|
|
2001
|
+
event: "oss.dev-console.help",
|
|
2002
|
+
anonymousId: window.crypto.randomUUID(),
|
|
2003
|
+
properties: { email, text: issueDescription },
|
|
2004
|
+
writeKey: "q0gQqvGYyw9pNyhIocNzefSYKGO1aiwW"
|
|
2005
|
+
})
|
|
2006
|
+
});
|
|
2007
|
+
setEmailError("");
|
|
2008
|
+
setEmail("");
|
|
2009
|
+
setIssueDescription("");
|
|
2010
|
+
setSubmitting(false);
|
|
2011
|
+
setShowHelpModal(false);
|
|
2012
|
+
});
|
|
1944
2013
|
const HelpButton = () => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1945
2014
|
"button",
|
|
1946
2015
|
{
|
|
@@ -1950,6 +2019,10 @@ function CopilotKitHelpModal() {
|
|
|
1950
2019
|
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(LifeBuoyIcon, {})
|
|
1951
2020
|
}
|
|
1952
2021
|
);
|
|
2022
|
+
const submitButtonDisabled = (0, import_react9.useMemo)(
|
|
2023
|
+
() => submitting || !!emailError || issueDescription == null || (issueDescription == null ? void 0 : issueDescription.length) == 0,
|
|
2024
|
+
[submitting, emailError, issueDescription]
|
|
2025
|
+
);
|
|
1953
2026
|
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
1954
2027
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(HelpButton, {}),
|
|
1955
2028
|
showHelpModal && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
@@ -1988,6 +2061,52 @@ function CopilotKitHelpModal() {
|
|
|
1988
2061
|
children: "Apply for Priority Direct Slack Support"
|
|
1989
2062
|
}
|
|
1990
2063
|
) })
|
|
2064
|
+
] }),
|
|
2065
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("form", { onSubmit: handleSubmit, className: "flex flex-col space-y-2", children: [
|
|
2066
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
2067
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { htmlFor: "feedback", className: "block text-sm font-medium text-gray-700 mb-1", children: "Let us know what your issue is:" }),
|
|
2068
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2069
|
+
"textarea",
|
|
2070
|
+
{
|
|
2071
|
+
id: "feedback",
|
|
2072
|
+
rows: 4,
|
|
2073
|
+
className: "w-full px-3 py-2 text-gray-700 border rounded-lg focus:outline-none focus:border-blue-500",
|
|
2074
|
+
placeholder: "A Loom link / screen recording is always great!",
|
|
2075
|
+
onChange: (e) => setIssueDescription(e.target.value),
|
|
2076
|
+
value: issueDescription,
|
|
2077
|
+
required: true
|
|
2078
|
+
}
|
|
2079
|
+
)
|
|
2080
|
+
] }),
|
|
2081
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
2082
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { htmlFor: "email", className: "block text-sm font-medium text-gray-700 mb-1", children: "Email (optional):" }),
|
|
2083
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2084
|
+
"input",
|
|
2085
|
+
{
|
|
2086
|
+
type: "email",
|
|
2087
|
+
id: "email",
|
|
2088
|
+
className: `w-full px-3 py-2 text-gray-700 border rounded-lg focus:outline-none focus:border-blue-500 ${emailError ? "border-red-500" : ""}`,
|
|
2089
|
+
placeholder: "Enter your email for follow-up",
|
|
2090
|
+
onChange: (e) => {
|
|
2091
|
+
setEmail(e.target.value);
|
|
2092
|
+
setEmailError("");
|
|
2093
|
+
},
|
|
2094
|
+
value: email
|
|
2095
|
+
}
|
|
2096
|
+
),
|
|
2097
|
+
emailError && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-red-500 text-sm mt-1", children: emailError })
|
|
2098
|
+
] }),
|
|
2099
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "bg-gray-50 px-4 py-4 sm:px-6 sm:flex sm:flex-row-reverse rounded-b-lg", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2100
|
+
"button",
|
|
2101
|
+
{
|
|
2102
|
+
type: "submit",
|
|
2103
|
+
onClick: handleSubmit,
|
|
2104
|
+
disabled: submitButtonDisabled,
|
|
2105
|
+
style: submitButtonDisabled ? { backgroundColor: "rgb(216, 216, 216)", color: "rgb(129, 129, 129)" } : void 0,
|
|
2106
|
+
className: "w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-500 text-base font-medium text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm disabled:shadow-none",
|
|
2107
|
+
children: submitting ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(LoadingSpinnerIcon, { color: "white" }) : "Submit"
|
|
2108
|
+
}
|
|
2109
|
+
) })
|
|
1991
2110
|
] })
|
|
1992
2111
|
] })
|
|
1993
2112
|
}
|