@gravity-ui/aikit 2.24.1-beta.883c85d04b93d8521b2733baa3e86da20249b4e7.0 → 2.25.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/build/cjs/components/molecules/PromptInputBody/PromptInputBody.d.ts +1 -0
- package/build/cjs/components/molecules/PromptInputBody/PromptInputBody.js +2 -8
- package/build/cjs/components/molecules/PromptInputBody/PromptInputBody.js.map +1 -1
- package/build/cjs/components/organisms/PromptInput/PromptInput.css +37 -0
- package/build/cjs/components/organisms/PromptInput/PromptInput.d.ts +13 -2
- package/build/cjs/components/organisms/PromptInput/PromptInput.js +64 -3
- package/build/cjs/components/organisms/PromptInput/PromptInput.js.map +1 -1
- package/build/cjs/components/organisms/PromptInput/PromptInputCommands.d.ts +9 -0
- package/build/cjs/components/organisms/PromptInput/PromptInputCommands.js +39 -0
- package/build/cjs/components/organisms/PromptInput/PromptInputCommands.js.map +1 -0
- package/build/cjs/components/organisms/PromptInput/PromptInputFull.d.ts +2 -0
- package/build/cjs/components/organisms/PromptInput/PromptInputFull.js +4 -4
- package/build/cjs/components/organisms/PromptInput/PromptInputFull.js.map +1 -1
- package/build/cjs/components/organisms/PromptInput/PromptInputSimple.d.ts +2 -0
- package/build/cjs/components/organisms/PromptInput/PromptInputSimple.js +3 -3
- package/build/cjs/components/organisms/PromptInput/PromptInputSimple.js.map +1 -1
- package/build/cjs/components/organisms/PromptInput/commandUtils.d.ts +13 -0
- package/build/cjs/components/organisms/PromptInput/commandUtils.js +27 -0
- package/build/cjs/components/organisms/PromptInput/commandUtils.js.map +1 -0
- package/build/cjs/components/organisms/PromptInput/i18n/en.json +8 -0
- package/build/cjs/components/organisms/PromptInput/i18n/index.d.ts +13 -0
- package/build/cjs/components/organisms/PromptInput/i18n/index.js +10 -0
- package/build/cjs/components/organisms/PromptInput/i18n/index.js.map +1 -0
- package/build/cjs/components/organisms/PromptInput/i18n/ru.json +8 -0
- package/build/cjs/components/organisms/PromptInput/index.d.ts +2 -1
- package/build/cjs/components/organisms/PromptInput/index.js.map +1 -1
- package/build/cjs/components/organisms/PromptInput/types.d.ts +1 -0
- package/build/cjs/components/organisms/PromptInput/types.js.map +1 -1
- package/build/cjs/components/organisms/PromptInput/usePromptCommands.d.ts +41 -0
- package/build/cjs/components/organisms/PromptInput/usePromptCommands.js +222 -0
- package/build/cjs/components/organisms/PromptInput/usePromptCommands.js.map +1 -0
- package/build/cjs/components/organisms/PromptInput/usePromptInput.d.ts +10 -1
- package/build/cjs/components/organisms/PromptInput/usePromptInput.js +100 -11
- package/build/cjs/components/organisms/PromptInput/usePromptInput.js.map +1 -1
- package/build/cjs/components/pages/AIStudioChat/AIStudioChat.js +139 -52
- package/build/cjs/components/pages/AIStudioChat/AIStudioChat.js.map +1 -1
- package/build/cjs/components/pages/AIStudioChat/request.d.ts +4 -0
- package/build/cjs/components/pages/AIStudioChat/request.js +11 -0
- package/build/cjs/components/pages/AIStudioChat/request.js.map +1 -0
- package/build/cjs/components/pages/AIStudioChat/types.d.ts +5 -5
- package/build/cjs/components/pages/AIStudioChat/types.js.map +1 -1
- package/build/cjs/components/pages/ChatContainer/ChatContainer.js +10 -4
- package/build/cjs/components/pages/ChatContainer/ChatContainer.js.map +1 -1
- package/build/cjs/components/pages/ChatContainer/types.d.ts +1 -1
- package/build/cjs/components/pages/ChatContainer/types.js.map +1 -1
- package/build/cjs/components/pages/ChatContainer/useChatContainer.d.ts +1 -0
- package/build/cjs/components/pages/ChatContainer/useChatContainer.js +5 -1
- package/build/cjs/components/pages/ChatContainer/useChatContainer.js.map +1 -1
- package/build/cjs/package.json +1 -1
- package/build/cjs/types/index.d.ts +1 -0
- package/build/cjs/types/index.js +1 -0
- package/build/cjs/types/index.js.map +1 -1
- package/build/cjs/types/messages.d.ts +3 -0
- package/build/cjs/types/messages.js.map +1 -1
- package/build/cjs/types/promptCommands.d.ts +44 -0
- package/build/cjs/types/promptCommands.js +3 -0
- package/build/cjs/types/promptCommands.js.map +1 -0
- package/build/docs/components/molecules/PromptInputBody.md +16 -15
- package/build/docs/components/organisms/PromptInput.md +151 -0
- package/build/docs/components/pages/AIStudioChat.md +38 -0
- package/build/esm/components/molecules/PromptInputBody/PromptInputBody.d.ts +1 -0
- package/build/esm/components/molecules/PromptInputBody/PromptInputBody.js +2 -8
- package/build/esm/components/molecules/PromptInputBody/PromptInputBody.js.map +1 -1
- package/build/esm/components/organisms/PromptInput/PromptInput.css +37 -0
- package/build/esm/components/organisms/PromptInput/PromptInput.d.ts +13 -2
- package/build/esm/components/organisms/PromptInput/PromptInput.js +65 -4
- package/build/esm/components/organisms/PromptInput/PromptInput.js.map +1 -1
- package/build/esm/components/organisms/PromptInput/PromptInputCommands.d.ts +9 -0
- package/build/esm/components/organisms/PromptInput/PromptInputCommands.js +36 -0
- package/build/esm/components/organisms/PromptInput/PromptInputCommands.js.map +1 -0
- package/build/esm/components/organisms/PromptInput/PromptInputFull.d.ts +2 -0
- package/build/esm/components/organisms/PromptInput/PromptInputFull.js +4 -4
- package/build/esm/components/organisms/PromptInput/PromptInputFull.js.map +1 -1
- package/build/esm/components/organisms/PromptInput/PromptInputSimple.d.ts +2 -0
- package/build/esm/components/organisms/PromptInput/PromptInputSimple.js +3 -3
- package/build/esm/components/organisms/PromptInput/PromptInputSimple.js.map +1 -1
- package/build/esm/components/organisms/PromptInput/commandUtils.d.ts +13 -0
- package/build/esm/components/organisms/PromptInput/commandUtils.js +23 -0
- package/build/esm/components/organisms/PromptInput/commandUtils.js.map +1 -0
- package/build/esm/components/organisms/PromptInput/i18n/en.json +8 -0
- package/build/esm/components/organisms/PromptInput/i18n/index.d.ts +13 -0
- package/build/esm/components/organisms/PromptInput/i18n/index.js +6 -0
- package/build/esm/components/organisms/PromptInput/i18n/index.js.map +1 -0
- package/build/esm/components/organisms/PromptInput/i18n/ru.json +8 -0
- package/build/esm/components/organisms/PromptInput/index.d.ts +2 -1
- package/build/esm/components/organisms/PromptInput/index.js.map +1 -1
- package/build/esm/components/organisms/PromptInput/types.d.ts +1 -0
- package/build/esm/components/organisms/PromptInput/types.js.map +1 -1
- package/build/esm/components/organisms/PromptInput/usePromptCommands.d.ts +41 -0
- package/build/esm/components/organisms/PromptInput/usePromptCommands.js +219 -0
- package/build/esm/components/organisms/PromptInput/usePromptCommands.js.map +1 -0
- package/build/esm/components/organisms/PromptInput/usePromptInput.d.ts +10 -1
- package/build/esm/components/organisms/PromptInput/usePromptInput.js +101 -12
- package/build/esm/components/organisms/PromptInput/usePromptInput.js.map +1 -1
- package/build/esm/components/pages/AIStudioChat/AIStudioChat.js +139 -52
- package/build/esm/components/pages/AIStudioChat/AIStudioChat.js.map +1 -1
- package/build/esm/components/pages/AIStudioChat/request.d.ts +4 -0
- package/build/esm/components/pages/AIStudioChat/request.js +8 -0
- package/build/esm/components/pages/AIStudioChat/request.js.map +1 -0
- package/build/esm/components/pages/AIStudioChat/types.d.ts +5 -5
- package/build/esm/components/pages/AIStudioChat/types.js.map +1 -1
- package/build/esm/components/pages/ChatContainer/ChatContainer.js +12 -6
- package/build/esm/components/pages/ChatContainer/ChatContainer.js.map +1 -1
- package/build/esm/components/pages/ChatContainer/types.d.ts +1 -1
- package/build/esm/components/pages/ChatContainer/types.js.map +1 -1
- package/build/esm/components/pages/ChatContainer/useChatContainer.d.ts +1 -0
- package/build/esm/components/pages/ChatContainer/useChatContainer.js +5 -1
- package/build/esm/components/pages/ChatContainer/useChatContainer.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/types/index.d.ts +1 -0
- package/build/esm/types/index.js +1 -0
- package/build/esm/types/index.js.map +1 -1
- package/build/esm/types/messages.d.ts +3 -0
- package/build/esm/types/messages.js.map +1 -1
- package/build/esm/types/promptCommands.d.ts +44 -0
- package/build/esm/types/promptCommands.js +2 -0
- package/build/esm/types/promptCommands.js.map +1 -0
- package/package.json +1 -1
|
@@ -21,6 +21,7 @@ export type PromptInputBodyProps = {
|
|
|
21
21
|
autoFocus?: boolean;
|
|
22
22
|
/** Disabled state for input */
|
|
23
23
|
disabledInput?: boolean;
|
|
24
|
+
controlProps?: TextAreaProps['controlProps'];
|
|
24
25
|
/** Change handler */
|
|
25
26
|
onChange?: (value: string) => void;
|
|
26
27
|
/** Key down handler */
|
|
@@ -26,7 +26,7 @@ const scheduleCaretAtEndIfCollapsed = (textarea) => {
|
|
|
26
26
|
* @returns React component
|
|
27
27
|
*/
|
|
28
28
|
exports.PromptInputBody = (0, react_1.forwardRef)((props, ref) => {
|
|
29
|
-
const { value, placeholder, maxLength, size, minRows = 1, maxRows = 15, autoFocus = false, disabledInput = false, onChange, onKeyDown, children, className, inputClassName, qa, } = props;
|
|
29
|
+
const { controlProps, value, placeholder, maxLength, size, minRows = 1, maxRows = 15, autoFocus = false, disabledInput = false, onChange, onKeyDown, children, className, inputClassName, qa, } = props;
|
|
30
30
|
const resolvedSize = (0, useMobileControlSize_1.useMobileControlSize)(size, 'l', 'xl');
|
|
31
31
|
const hasHandledInitialFocusRef = (0, react_1.useRef)(false);
|
|
32
32
|
const pendingInitialPointerIdRef = (0, react_1.useRef)(null);
|
|
@@ -67,13 +67,7 @@ exports.PromptInputBody = (0, react_1.forwardRef)((props, ref) => {
|
|
|
67
67
|
return ((0, jsx_runtime_1.jsx)("div", { className: b(null, className), "data-qa": qa, children: children }));
|
|
68
68
|
}
|
|
69
69
|
// Render default textarea
|
|
70
|
-
return ((0, jsx_runtime_1.jsx)("div", { className: b(null, className), "data-qa": qa, children: (0, jsx_runtime_1.jsx)(uikit_1.TextArea, { controlRef: ref, size: resolvedSize, value: value, placeholder: placeholder, minRows: minRows, maxRows: maxRows, autoFocus: autoFocus, disabled: disabledInput, onUpdate: onChange, onFocus: handleFocus, onKeyDown: onKeyDown, view: "clear", className: b('textarea'), controlProps: {
|
|
71
|
-
className: b('textarea-control', inputClassName),
|
|
72
|
-
maxLength,
|
|
73
|
-
onPointerDown: handlePointerDown,
|
|
74
|
-
onPointerUp: handlePointerUp,
|
|
75
|
-
onPointerCancel: handlePointerCancel,
|
|
76
|
-
} }) }));
|
|
70
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: b(null, className), "data-qa": qa, children: (0, jsx_runtime_1.jsx)(uikit_1.TextArea, { controlRef: ref, size: resolvedSize, value: value, placeholder: placeholder, minRows: minRows, maxRows: maxRows, autoFocus: autoFocus, disabled: disabledInput, onUpdate: onChange, onFocus: handleFocus, onKeyDown: onKeyDown, view: "clear", className: b('textarea'), controlProps: Object.assign(Object.assign({}, controlProps), { className: b('textarea-control', inputClassName), maxLength, onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerCancel: handlePointerCancel }) }) }));
|
|
77
71
|
});
|
|
78
72
|
exports.PromptInputBody.displayName = 'PromptInputBody';
|
|
79
73
|
//# sourceMappingURL=PromptInputBody.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromptInputBody.js","sourceRoot":"../../../../../src","sources":["components/molecules/PromptInputBody/PromptInputBody.tsx"],"names":[],"mappings":";;;;AAAA,iCAAoD;AAGpD,6CAA2C;AAE3C,iFAAyE;AACzE,6CAAwC;AAExC,iCAAgC;AAEhC,MAAM,CAAC,GAAG,IAAA,UAAK,EAAC,mBAAmB,CAAC,CAAC;AAErC,MAAM,6BAA6B,GAAG,CAAC,QAA6B,EAAE,EAAE;IACpE,qBAAqB,CAAC,GAAG,EAAE;QACvB,IACI,QAAQ,CAAC,WAAW;YACpB,QAAQ,CAAC,aAAa,CAAC,aAAa,KAAK,QAAQ;YACjD,QAAQ,CAAC,cAAc,KAAK,QAAQ,CAAC,YAAY,EACnD,CAAC;YACC,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;YAC5C,QAAQ,CAAC,iBAAiB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;QAC7D,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"PromptInputBody.js","sourceRoot":"../../../../../src","sources":["components/molecules/PromptInputBody/PromptInputBody.tsx"],"names":[],"mappings":"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","sourcesContent":["import {ReactNode, forwardRef, useRef} from 'react';\n\nimport type {TextAreaProps} from '@gravity-ui/uikit';\nimport {TextArea} from '@gravity-ui/uikit';\n\nimport {useMobileControlSize} from '../../../hooks/useMobileControlSize';\nimport {block} from '../../../utils/cn';\n\nimport './PromptInputBody.scss';\n\nconst b = block('prompt-input-body');\n\nconst scheduleCaretAtEndIfCollapsed = (textarea: HTMLTextAreaElement) => {\n requestAnimationFrame(() => {\n if (\n textarea.isConnected &&\n textarea.ownerDocument.activeElement === textarea &&\n textarea.selectionStart === textarea.selectionEnd\n ) {\n const caretPosition = textarea.value.length;\n textarea.setSelectionRange(caretPosition, caretPosition);\n }\n });\n};\n\n/**\n * Props for the PromptInputBody component\n */\nexport type PromptInputBodyProps = {\n /** Value of the textarea */\n value?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Maximum length of input */\n maxLength?: number;\n /** Size of the textarea. Defaults to `l`, or `xl` in mobile mode */\n size?: TextAreaProps['size'];\n /** Minimum number of rows */\n minRows?: number;\n /** Maximum number of rows */\n maxRows?: number;\n /** Auto focus on mount */\n autoFocus?: boolean;\n /** Disabled state for input */\n disabledInput?: boolean;\n controlProps?: TextAreaProps['controlProps'];\n /** Change handler */\n onChange?: (value: string) => void;\n /** Key down handler */\n onKeyDown?: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;\n /** Custom content to replace the default textarea */\n children?: ReactNode;\n /** Additional CSS class */\n className?: string;\n /** Additional CSS class for input element */\n inputClassName?: string;\n /** QA/test identifier */\n qa?: string;\n};\n\n/**\n * PromptInputBody component displays the main input area\n * with textarea or custom content\n *\n * @param props - Component props\n * @returns React component\n */\nexport const PromptInputBody = forwardRef<HTMLTextAreaElement, PromptInputBodyProps>(\n (props, ref) => {\n const {\n controlProps,\n value,\n placeholder,\n maxLength,\n size,\n minRows = 1,\n maxRows = 15,\n autoFocus = false,\n disabledInput = false,\n onChange,\n onKeyDown,\n children,\n className,\n inputClassName,\n qa,\n } = props;\n\n const resolvedSize = useMobileControlSize(size, 'l', 'xl');\n const hasHandledInitialFocusRef = useRef(false);\n const pendingInitialPointerIdRef = useRef<number | null>(null);\n\n const handlePointerDown = (event: React.PointerEvent<HTMLTextAreaElement>) => {\n pendingInitialPointerIdRef.current =\n !hasHandledInitialFocusRef.current && event.isPrimary && event.button === 0\n ? event.pointerId\n : null;\n };\n\n const handlePointerUp = (event: React.PointerEvent<HTMLTextAreaElement>) => {\n if (pendingInitialPointerIdRef.current !== event.pointerId) {\n return;\n }\n\n pendingInitialPointerIdRef.current = null;\n scheduleCaretAtEndIfCollapsed(event.currentTarget);\n };\n\n const handlePointerCancel = (event: React.PointerEvent<HTMLTextAreaElement>) => {\n if (pendingInitialPointerIdRef.current === event.pointerId) {\n pendingInitialPointerIdRef.current = null;\n }\n };\n\n const handleFocus = (event: React.FocusEvent<HTMLTextAreaElement>) => {\n if (hasHandledInitialFocusRef.current) {\n return;\n }\n\n hasHandledInitialFocusRef.current = true;\n\n const textarea = event.currentTarget;\n if (!textarea.value) {\n pendingInitialPointerIdRef.current = null;\n return;\n }\n\n if (pendingInitialPointerIdRef.current === null) {\n scheduleCaretAtEndIfCollapsed(textarea);\n }\n };\n\n // If custom content is provided, render it\n if (children) {\n return (\n <div className={b(null, className)} data-qa={qa}>\n {children}\n </div>\n );\n }\n\n // Render default textarea\n return (\n <div className={b(null, className)} data-qa={qa}>\n <TextArea\n controlRef={ref}\n size={resolvedSize}\n value={value}\n placeholder={placeholder}\n minRows={minRows}\n maxRows={maxRows}\n autoFocus={autoFocus}\n disabled={disabledInput}\n onUpdate={onChange}\n onFocus={handleFocus}\n onKeyDown={onKeyDown}\n view=\"clear\"\n className={b('textarea')}\n controlProps={{\n ...controlProps,\n className: b('textarea-control', inputClassName),\n maxLength,\n onPointerDown: handlePointerDown,\n onPointerUp: handlePointerUp,\n onPointerCancel: handlePointerCancel,\n }}\n />\n </div>\n );\n },\n);\n\nPromptInputBody.displayName = 'PromptInputBody';\n"]}
|
|
@@ -47,4 +47,41 @@
|
|
|
47
47
|
}
|
|
48
48
|
.g-aikit-prompt-input__suggestions {
|
|
49
49
|
padding-bottom: var(--g-spacing-2);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.g-aikit-prompt-input__command-buttons {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-wrap: wrap;
|
|
55
|
+
gap: var(--g-spacing-1);
|
|
56
|
+
}
|
|
57
|
+
.g-aikit-prompt-input__commands {
|
|
58
|
+
width: min(400px, 100vw - 32px);
|
|
59
|
+
padding: var(--g-spacing-3);
|
|
60
|
+
box-sizing: border-box;
|
|
61
|
+
}
|
|
62
|
+
.g-aikit-prompt-input__commands-title {
|
|
63
|
+
font-weight: 600;
|
|
64
|
+
margin-bottom: var(--g-spacing-2);
|
|
65
|
+
}
|
|
66
|
+
.g-aikit-prompt-input__command-list {
|
|
67
|
+
max-height: 240px;
|
|
68
|
+
overflow-y: auto;
|
|
69
|
+
}
|
|
70
|
+
.g-aikit-prompt-input__command {
|
|
71
|
+
display: flex;
|
|
72
|
+
gap: var(--g-spacing-2);
|
|
73
|
+
padding: var(--g-spacing-2);
|
|
74
|
+
border-radius: var(--g-border-radius-m);
|
|
75
|
+
cursor: pointer;
|
|
76
|
+
}
|
|
77
|
+
.g-aikit-prompt-input__command_active, .g-aikit-prompt-input__command:hover {
|
|
78
|
+
background: var(--g-color-base-simple-hover);
|
|
79
|
+
}
|
|
80
|
+
.g-aikit-prompt-input__command_disabled {
|
|
81
|
+
opacity: 0.5;
|
|
82
|
+
cursor: default;
|
|
83
|
+
}
|
|
84
|
+
.g-aikit-prompt-input__command-description {
|
|
85
|
+
color: var(--g-color-text-secondary);
|
|
86
|
+
font-size: var(--g-text-body-1-font-size);
|
|
50
87
|
}
|
|
@@ -1,14 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type Ref } from 'react';
|
|
2
|
+
import { ChatStatus, type PromptCommandsConfig, TSubmitData } from "../../../types/index.js";
|
|
2
3
|
import { PromptInputBodyConfig, PromptInputFooterConfig, PromptInputHeaderConfig, PromptInputPanelConfig, PromptInputSuggestionsConfig } from "./types.js";
|
|
3
4
|
import "./PromptInput.css";
|
|
4
5
|
/**
|
|
5
6
|
* Props for the PromptInput component
|
|
6
7
|
*/
|
|
8
|
+
export type PromptInputHandle = {
|
|
9
|
+
submit: (data?: TSubmitData) => Promise<void>;
|
|
10
|
+
clearFailedDraft: () => boolean;
|
|
11
|
+
};
|
|
7
12
|
export type PromptInputProps = {
|
|
13
|
+
/** Programmatic submission uses the same draft lifecycle as the send button. */
|
|
14
|
+
apiRef?: Ref<PromptInputHandle>;
|
|
15
|
+
/** Application-defined commands and context sources. */
|
|
16
|
+
commands?: PromptCommandsConfig;
|
|
17
|
+
/** Resets uncontrolled command selections and search without changing focus. */
|
|
18
|
+
commandsResetKey?: string | number;
|
|
8
19
|
/** View variant: 'full' with all features, 'simple' with minimal UI */
|
|
9
20
|
view?: 'full' | 'simple';
|
|
10
21
|
/** Callback when message is sent */
|
|
11
|
-
onSend: (data: TSubmitData) => Promise<void>;
|
|
22
|
+
onSend: (data: TSubmitData) => Promise<void | false>;
|
|
12
23
|
/** Callback when sending is cancelled */
|
|
13
24
|
onCancel?: () => Promise<void>;
|
|
14
25
|
/** Initial value */
|
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PromptInput = PromptInput;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const uikit_1 = require("@gravity-ui/uikit");
|
|
7
|
+
const PromptInputCommands_1 = require("./PromptInputCommands.js");
|
|
5
8
|
const PromptInputFull_1 = require("./PromptInputFull.js");
|
|
6
9
|
const PromptInputSimple_1 = require("./PromptInputSimple.js");
|
|
7
10
|
const PromptInputWithPanels_1 = require("./PromptInputWithPanels.js");
|
|
8
11
|
const PromptInputWithSuggestions_1 = require("./PromptInputWithSuggestions.js");
|
|
12
|
+
const i18n_1 = require("./i18n/index.js");
|
|
13
|
+
const usePromptCommands_1 = require("./usePromptCommands.js");
|
|
9
14
|
const usePromptInput_1 = require("./usePromptInput.js");
|
|
10
15
|
require("./PromptInput.css");
|
|
11
16
|
/**
|
|
@@ -16,9 +21,23 @@ require("./PromptInput.css");
|
|
|
16
21
|
* @returns React component
|
|
17
22
|
*/
|
|
18
23
|
function PromptInput(props) {
|
|
19
|
-
|
|
24
|
+
var _a;
|
|
25
|
+
const { apiRef, commands: commandsConfig, commandsResetKey, view = 'simple', onSend, onCancel, initialValue, disabled = false, status = 'ready', maxLength, onValueChange, headerProps, bodyProps, footerProps, suggestionsProps, topPanel, bottomPanel, className, qa, } = props;
|
|
26
|
+
const inputRef = (0, react_1.useRef)(null);
|
|
27
|
+
const mergedInputRef = (0, uikit_1.useForkRef)(inputRef, bodyProps === null || bodyProps === void 0 ? void 0 : bodyProps.inputRef);
|
|
28
|
+
const commandsRef = (0, react_1.useRef)(null);
|
|
29
|
+
const submittedSelections = (0, react_1.useRef)([]);
|
|
20
30
|
const hookState = (0, usePromptInput_1.usePromptInput)({
|
|
21
|
-
|
|
31
|
+
resetKey: commandsResetKey,
|
|
32
|
+
captureSubmission: () => {
|
|
33
|
+
var _a, _b;
|
|
34
|
+
const snapshot = (_a = commandsRef.current) === null || _a === void 0 ? void 0 : _a.captureSubmission();
|
|
35
|
+
submittedSelections.current = (_b = snapshot === null || snapshot === void 0 ? void 0 : snapshot.selections) !== null && _b !== void 0 ? _b : [];
|
|
36
|
+
return snapshot !== null && snapshot !== void 0 ? snapshot : { restore: () => { }, clear: () => { }, hasChanged: () => false };
|
|
37
|
+
},
|
|
38
|
+
onSend: (data) => onSend(Object.assign(Object.assign({}, data), (submittedSelections.current.length && {
|
|
39
|
+
selections: [...submittedSelections.current],
|
|
40
|
+
}))),
|
|
22
41
|
onCancel,
|
|
23
42
|
initialValue,
|
|
24
43
|
disabled,
|
|
@@ -26,6 +45,48 @@ function PromptInput(props) {
|
|
|
26
45
|
maxLength,
|
|
27
46
|
onValueChange,
|
|
28
47
|
});
|
|
48
|
+
(0, react_1.useImperativeHandle)(apiRef, () => ({
|
|
49
|
+
submit: hookState.submit,
|
|
50
|
+
clearFailedDraft: hookState.clearFailedDraft,
|
|
51
|
+
}));
|
|
52
|
+
const commandsDisabled = disabled || hookState.isInputDisabled || Boolean(bodyProps === null || bodyProps === void 0 ? void 0 : bodyProps.disabledInput);
|
|
53
|
+
const commands = (0, usePromptCommands_1.usePromptCommands)({
|
|
54
|
+
config: commandsConfig,
|
|
55
|
+
resetKey: commandsResetKey,
|
|
56
|
+
value: hookState.value,
|
|
57
|
+
onChange: hookState.handleChange,
|
|
58
|
+
inputRef,
|
|
59
|
+
disabled: commandsDisabled,
|
|
60
|
+
maxLength,
|
|
61
|
+
});
|
|
62
|
+
commandsRef.current = commands;
|
|
63
|
+
const inputBodyProps = Object.assign(Object.assign({}, bodyProps), { inputRef: mergedInputRef, controlProps: Object.assign(Object.assign({}, bodyProps === null || bodyProps === void 0 ? void 0 : bodyProps.controlProps), (commandsConfig && {
|
|
64
|
+
role: 'combobox',
|
|
65
|
+
'aria-expanded': commands.open && ((_a = commands.session) === null || _a === void 0 ? void 0 : _a.origin) === 'input',
|
|
66
|
+
'aria-controls': commands.open ? commands.listId : undefined,
|
|
67
|
+
'aria-autocomplete': 'list',
|
|
68
|
+
'aria-activedescendant': commands.open && commands.items[commands.activeIndex]
|
|
69
|
+
? `${commands.listId}-${commands.activeIndex}`
|
|
70
|
+
: undefined,
|
|
71
|
+
onSelect: (event) => {
|
|
72
|
+
var _a, _b;
|
|
73
|
+
(_b = (_a = bodyProps === null || bodyProps === void 0 ? void 0 : bodyProps.controlProps) === null || _a === void 0 ? void 0 : _a.onSelect) === null || _b === void 0 ? void 0 : _b.call(_a, event);
|
|
74
|
+
const input = event.currentTarget;
|
|
75
|
+
commands.detect(input.value, input.selectionStart, input.selectionEnd);
|
|
76
|
+
},
|
|
77
|
+
})) });
|
|
78
|
+
const commandHookState = Object.assign(Object.assign({}, hookState), { isInputDisabled: commandsDisabled, handleChange: (value) => {
|
|
79
|
+
if (maxLength !== undefined && value.length > maxLength)
|
|
80
|
+
return;
|
|
81
|
+
hookState.handleChange(value);
|
|
82
|
+
const input = inputRef.current;
|
|
83
|
+
if (input)
|
|
84
|
+
commands.detect(value, input.selectionStart, input.selectionEnd, true);
|
|
85
|
+
}, handleKeyDown: (event) => {
|
|
86
|
+
if (!commands.handleKeyDown(event))
|
|
87
|
+
hookState.handleKeyDown(event);
|
|
88
|
+
} });
|
|
89
|
+
const commandsContent = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [commandsConfig && ((0, jsx_runtime_1.jsx)(PromptInputCommands_1.PromptInputCommands, { commands: commands, config: commandsConfig, inputRef: inputRef, disabled: commandsDisabled })), hookState.sendError && (0, jsx_runtime_1.jsx)("div", { role: "alert", children: (0, i18n_1.i18n)('send-error') })] }));
|
|
29
90
|
// Handle suggestion click with custom handler or default to input change
|
|
30
91
|
const handleSuggestionClick = (content, id, data) => {
|
|
31
92
|
if (suggestionsProps === null || suggestionsProps === void 0 ? void 0 : suggestionsProps.onSuggestionClick) {
|
|
@@ -39,6 +100,6 @@ function PromptInput(props) {
|
|
|
39
100
|
// Prepare suggestions props with wrapped handler
|
|
40
101
|
const wrappedSuggestionsProps = suggestionsProps
|
|
41
102
|
? Object.assign(Object.assign({}, suggestionsProps), { onSuggestionClick: handleSuggestionClick }) : undefined;
|
|
42
|
-
return ((0, jsx_runtime_1.jsx)(PromptInputWithSuggestions_1.PromptInputWithSuggestions, { suggestionsProps: wrappedSuggestionsProps, children: (0, jsx_runtime_1.jsx)(PromptInputWithPanels_1.PromptInputWithPanels, { topPanel: topPanel, bottomPanel: bottomPanel, children: isFullView ? ((0, jsx_runtime_1.jsx)(PromptInputFull_1.PromptInputFull, { hookState:
|
|
103
|
+
return ((0, jsx_runtime_1.jsx)(PromptInputWithSuggestions_1.PromptInputWithSuggestions, { suggestionsProps: wrappedSuggestionsProps, children: (0, jsx_runtime_1.jsx)(PromptInputWithPanels_1.PromptInputWithPanels, { topPanel: topPanel, bottomPanel: bottomPanel, children: isFullView ? ((0, jsx_runtime_1.jsx)(PromptInputFull_1.PromptInputFull, { hookState: commandHookState, commandsContent: commandsContent, headerProps: headerProps, bodyProps: inputBodyProps, footerProps: footerProps, className: className, qa: qa })) : ((0, jsx_runtime_1.jsx)(PromptInputSimple_1.PromptInputSimple, { hookState: commandHookState, commandsContent: commandsContent, bodyProps: inputBodyProps, footerProps: footerProps, className: className, qa: qa })) }) }));
|
|
43
104
|
}
|
|
44
105
|
//# sourceMappingURL=PromptInput.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromptInput.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/PromptInput.tsx"],"names":[],"mappings":";;AA8DA,kCA6EC;;AAzID,0DAAkD;AAClD,8DAAsD;AACtD,sEAA8D;AAC9D,gFAAwE;AAQxE,wDAAgD;AAEhD,6BAA4B;AAwC5B;;;;;;GAMG;AACH,SAAgB,WAAW,CAAC,KAAuB;IAC/C,MAAM,EACF,IAAI,GAAG,QAAQ,EACf,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,QAAQ,GAAG,KAAK,EAChB,MAAM,GAAG,OAAO,EAChB,SAAS,EACT,aAAa,EACb,WAAW,EACX,SAAS,EACT,WAAW,EACX,gBAAgB,EAChB,QAAQ,EACR,WAAW,EACX,SAAS,EACT,EAAE,GACL,GAAG,KAAK,CAAC;IAEV,MAAM,SAAS,GAAG,IAAA,+BAAc,EAAC;QAC7B,MAAM;QACN,QAAQ;QACR,YAAY;QACZ,QAAQ;QACR,MAAM;QACN,SAAS;QACT,aAAa;KAChB,CAAC,CAAC;IAEH,yEAAyE;IACzE,MAAM,qBAAqB,GAAG,CAC1B,OAAe,EACf,EAAW,EACX,IAA8B,EAChC,EAAE;QACA,IAAI,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,iBAAiB,EAAE,CAAC;YACtC,gBAAgB,CAAC,iBAAiB,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QAC1D,CAAC;aAAM,CAAC;YACJ,SAAS,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,IAAI,KAAK,MAAM,CAAC;IAEnC,iDAAiD;IACjD,MAAM,uBAAuB,GAAG,gBAAgB;QAC5C,CAAC,iCACQ,gBAAgB,KACnB,iBAAiB,EAAE,qBAAqB,IAE9C,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO,CACH,uBAAC,uDAA0B,IAAC,gBAAgB,EAAE,uBAAuB,YACjE,uBAAC,6CAAqB,IAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,YAC9D,UAAU,CAAC,CAAC,CAAC,CACV,uBAAC,iCAAe,IACZ,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,SAAS,EACpB,EAAE,EAAE,EAAE,GACR,CACL,CAAC,CAAC,CAAC,CACA,uBAAC,qCAAiB,IACd,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,SAAS,EACpB,EAAE,EAAE,EAAE,GACR,CACL,GACmB,GACC,CAChC,CAAC;AACN,CAAC","sourcesContent":["import {ChatStatus, TSubmitData} from '../../../types';\n\nimport {PromptInputFull} from './PromptInputFull';\nimport {PromptInputSimple} from './PromptInputSimple';\nimport {PromptInputWithPanels} from './PromptInputWithPanels';\nimport {PromptInputWithSuggestions} from './PromptInputWithSuggestions';\nimport {\n PromptInputBodyConfig,\n PromptInputFooterConfig,\n PromptInputHeaderConfig,\n PromptInputPanelConfig,\n PromptInputSuggestionsConfig,\n} from './types';\nimport {usePromptInput} from './usePromptInput';\n\nimport './PromptInput.scss';\n\n/**\n * Props for the PromptInput component\n */\nexport type PromptInputProps = {\n /** View variant: 'full' with all features, 'simple' with minimal UI */\n view?: 'full' | 'simple';\n /** Callback when message is sent */\n onSend: (data: TSubmitData) => Promise<void>;\n /** Callback when sending is cancelled */\n onCancel?: () => Promise<void>;\n /** Initial value */\n initialValue?: string;\n /** Disabled state */\n disabled?: boolean;\n /** Chat status to determine input behavior */\n status?: ChatStatus;\n /** Maximum length of input */\n maxLength?: number;\n /** Called whenever PromptInput changes its internal value. */\n onValueChange?: (value: string) => void;\n /** Header-related props */\n headerProps?: PromptInputHeaderConfig;\n /** Body/textarea-related props */\n bodyProps?: PromptInputBodyConfig;\n /** Footer-related props */\n footerProps?: PromptInputFooterConfig;\n /** Suggestions-related props */\n suggestionsProps?: PromptInputSuggestionsConfig;\n /** Top panel configuration */\n topPanel?: PromptInputPanelConfig;\n /** Bottom panel configuration */\n bottomPanel?: PromptInputPanelConfig;\n /** Additional CSS class */\n className?: string;\n /** QA/test identifier */\n qa?: string;\n};\n\n/**\n * PromptInput component - a flexible input component for chat interfaces\n * with support for simple and full views, attachments, suggestions, and expandable panels\n *\n * @param props - Component props\n * @returns React component\n */\nexport function PromptInput(props: PromptInputProps) {\n const {\n view = 'simple',\n onSend,\n onCancel,\n initialValue,\n disabled = false,\n status = 'ready',\n maxLength,\n onValueChange,\n headerProps,\n bodyProps,\n footerProps,\n suggestionsProps,\n topPanel,\n bottomPanel,\n className,\n qa,\n } = props;\n\n const hookState = usePromptInput({\n onSend,\n onCancel,\n initialValue,\n disabled,\n status,\n maxLength,\n onValueChange,\n });\n\n // Handle suggestion click with custom handler or default to input change\n const handleSuggestionClick = (\n content: string,\n id?: string,\n data?: Record<string, unknown>,\n ) => {\n if (suggestionsProps?.onSuggestionClick) {\n suggestionsProps.onSuggestionClick(content, id, data);\n } else {\n hookState.handleChange(content);\n }\n };\n\n const isFullView = view === 'full';\n\n // Prepare suggestions props with wrapped handler\n const wrappedSuggestionsProps = suggestionsProps\n ? {\n ...suggestionsProps,\n onSuggestionClick: handleSuggestionClick,\n }\n : undefined;\n\n return (\n <PromptInputWithSuggestions suggestionsProps={wrappedSuggestionsProps}>\n <PromptInputWithPanels topPanel={topPanel} bottomPanel={bottomPanel}>\n {isFullView ? (\n <PromptInputFull\n hookState={hookState}\n headerProps={headerProps}\n bodyProps={bodyProps}\n footerProps={footerProps}\n className={className}\n qa={qa}\n />\n ) : (\n <PromptInputSimple\n hookState={hookState}\n bodyProps={bodyProps}\n footerProps={footerProps}\n className={className}\n qa={qa}\n />\n )}\n </PromptInputWithPanels>\n </PromptInputWithSuggestions>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"PromptInput.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/PromptInput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {type Ref, useImperativeHandle, useRef} from 'react';\n\nimport {useForkRef} from '@gravity-ui/uikit';\n\nimport {ChatStatus, type PromptCommandsConfig, TSubmitData} from '../../../types';\n\nimport {PromptInputCommands} from './PromptInputCommands';\nimport {PromptInputFull} from './PromptInputFull';\nimport {PromptInputSimple} from './PromptInputSimple';\nimport {PromptInputWithPanels} from './PromptInputWithPanels';\nimport {PromptInputWithSuggestions} from './PromptInputWithSuggestions';\nimport {i18n} from './i18n';\nimport {\n PromptInputBodyConfig,\n PromptInputFooterConfig,\n PromptInputHeaderConfig,\n PromptInputPanelConfig,\n PromptInputSuggestionsConfig,\n} from './types';\nimport {usePromptCommands} from './usePromptCommands';\nimport {usePromptInput} from './usePromptInput';\n\nimport './PromptInput.scss';\n\n/**\n * Props for the PromptInput component\n */\nexport type PromptInputHandle = {\n submit: (data?: TSubmitData) => Promise<void>;\n clearFailedDraft: () => boolean;\n};\n\nexport type PromptInputProps = {\n /** Programmatic submission uses the same draft lifecycle as the send button. */\n apiRef?: Ref<PromptInputHandle>;\n /** Application-defined commands and context sources. */\n commands?: PromptCommandsConfig;\n /** Resets uncontrolled command selections and search without changing focus. */\n commandsResetKey?: string | number;\n /** View variant: 'full' with all features, 'simple' with minimal UI */\n view?: 'full' | 'simple';\n /** Callback when message is sent */\n onSend: (data: TSubmitData) => Promise<void | false>;\n /** Callback when sending is cancelled */\n onCancel?: () => Promise<void>;\n /** Initial value */\n initialValue?: string;\n /** Disabled state */\n disabled?: boolean;\n /** Chat status to determine input behavior */\n status?: ChatStatus;\n /** Maximum length of input */\n maxLength?: number;\n /** Called whenever PromptInput changes its internal value. */\n onValueChange?: (value: string) => void;\n /** Header-related props */\n headerProps?: PromptInputHeaderConfig;\n /** Body/textarea-related props */\n bodyProps?: PromptInputBodyConfig;\n /** Footer-related props */\n footerProps?: PromptInputFooterConfig;\n /** Suggestions-related props */\n suggestionsProps?: PromptInputSuggestionsConfig;\n /** Top panel configuration */\n topPanel?: PromptInputPanelConfig;\n /** Bottom panel configuration */\n bottomPanel?: PromptInputPanelConfig;\n /** Additional CSS class */\n className?: string;\n /** QA/test identifier */\n qa?: string;\n};\n\n/**\n * PromptInput component - a flexible input component for chat interfaces\n * with support for simple and full views, attachments, suggestions, and expandable panels\n *\n * @param props - Component props\n * @returns React component\n */\nexport function PromptInput(props: PromptInputProps) {\n const {\n apiRef,\n commands: commandsConfig,\n commandsResetKey,\n view = 'simple',\n onSend,\n onCancel,\n initialValue,\n disabled = false,\n status = 'ready',\n maxLength,\n onValueChange,\n headerProps,\n bodyProps,\n footerProps,\n suggestionsProps,\n topPanel,\n bottomPanel,\n className,\n qa,\n } = props;\n\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const mergedInputRef = useForkRef(inputRef, bodyProps?.inputRef);\n const commandsRef = useRef<ReturnType<typeof usePromptCommands> | null>(null);\n const submittedSelections = useRef<ReturnType<typeof usePromptCommands>['selections']>([]);\n const hookState = usePromptInput({\n resetKey: commandsResetKey,\n captureSubmission: () => {\n const snapshot = commandsRef.current?.captureSubmission();\n submittedSelections.current = snapshot?.selections ?? [];\n return snapshot ?? {restore: () => {}, clear: () => {}, hasChanged: () => false};\n },\n onSend: (data) =>\n onSend({\n ...data,\n ...(submittedSelections.current.length && {\n selections: [...submittedSelections.current],\n }),\n }),\n onCancel,\n initialValue,\n disabled,\n status,\n maxLength,\n onValueChange,\n });\n\n useImperativeHandle(apiRef, () => ({\n submit: hookState.submit,\n clearFailedDraft: hookState.clearFailedDraft,\n }));\n\n const commandsDisabled =\n disabled || hookState.isInputDisabled || Boolean(bodyProps?.disabledInput);\n const commands = usePromptCommands({\n config: commandsConfig,\n resetKey: commandsResetKey,\n value: hookState.value,\n onChange: hookState.handleChange,\n inputRef,\n disabled: commandsDisabled,\n maxLength,\n });\n commandsRef.current = commands;\n const inputBodyProps = {\n ...bodyProps,\n inputRef: mergedInputRef,\n controlProps: {\n ...bodyProps?.controlProps,\n ...(commandsConfig && {\n role: 'combobox',\n 'aria-expanded': commands.open && commands.session?.origin === 'input',\n 'aria-controls': commands.open ? commands.listId : undefined,\n 'aria-autocomplete': 'list' as const,\n 'aria-activedescendant':\n commands.open && commands.items[commands.activeIndex]\n ? `${commands.listId}-${commands.activeIndex}`\n : undefined,\n onSelect: (event: React.SyntheticEvent<HTMLTextAreaElement>) => {\n bodyProps?.controlProps?.onSelect?.(event);\n const input = event.currentTarget;\n commands.detect(input.value, input.selectionStart, input.selectionEnd);\n },\n }),\n },\n };\n const commandHookState = {\n ...hookState,\n isInputDisabled: commandsDisabled,\n handleChange: (value: string) => {\n if (maxLength !== undefined && value.length > maxLength) return;\n hookState.handleChange(value);\n const input = inputRef.current;\n if (input) commands.detect(value, input.selectionStart, input.selectionEnd, true);\n },\n handleKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (!commands.handleKeyDown(event)) hookState.handleKeyDown(event);\n },\n };\n const commandsContent = (\n <>\n {commandsConfig && (\n <PromptInputCommands\n commands={commands}\n config={commandsConfig}\n inputRef={inputRef}\n disabled={commandsDisabled}\n />\n )}\n {hookState.sendError && <div role=\"alert\">{i18n('send-error')}</div>}\n </>\n );\n\n // Handle suggestion click with custom handler or default to input change\n const handleSuggestionClick = (\n content: string,\n id?: string,\n data?: Record<string, unknown>,\n ) => {\n if (suggestionsProps?.onSuggestionClick) {\n suggestionsProps.onSuggestionClick(content, id, data);\n } else {\n hookState.handleChange(content);\n }\n };\n\n const isFullView = view === 'full';\n\n // Prepare suggestions props with wrapped handler\n const wrappedSuggestionsProps = suggestionsProps\n ? {\n ...suggestionsProps,\n onSuggestionClick: handleSuggestionClick,\n }\n : undefined;\n\n return (\n <PromptInputWithSuggestions suggestionsProps={wrappedSuggestionsProps}>\n <PromptInputWithPanels topPanel={topPanel} bottomPanel={bottomPanel}>\n {isFullView ? (\n <PromptInputFull\n hookState={commandHookState}\n commandsContent={commandsContent}\n headerProps={headerProps}\n bodyProps={inputBodyProps}\n footerProps={footerProps}\n className={className}\n qa={qa}\n />\n ) : (\n <PromptInputSimple\n hookState={commandHookState}\n commandsContent={commandsContent}\n bodyProps={inputBodyProps}\n footerProps={footerProps}\n className={className}\n qa={qa}\n />\n )}\n </PromptInputWithPanels>\n </PromptInputWithSuggestions>\n );\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { PromptCommandsConfig } from "../../../types/index.js";
|
|
3
|
+
import type { usePromptCommands } from "./usePromptCommands.js";
|
|
4
|
+
export declare function PromptInputCommands({ commands, config, inputRef, disabled, }: {
|
|
5
|
+
commands: ReturnType<typeof usePromptCommands>;
|
|
6
|
+
config: PromptCommandsConfig;
|
|
7
|
+
inputRef: RefObject<HTMLTextAreaElement>;
|
|
8
|
+
disabled: boolean;
|
|
9
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PromptInputCommands = PromptInputCommands;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const uikit_1 = require("@gravity-ui/uikit");
|
|
7
|
+
const cn_1 = require("../../../utils/cn.js");
|
|
8
|
+
const PromptInputHeader_1 = require("../../molecules/PromptInputHeader/index.js");
|
|
9
|
+
const i18n_1 = require("./i18n/index.js");
|
|
10
|
+
const b = (0, cn_1.block)('prompt-input');
|
|
11
|
+
function PromptInputCommands({ commands, config, inputRef, disabled, }) {
|
|
12
|
+
var _a, _b, _c, _d;
|
|
13
|
+
const listRef = (0, react_1.useRef)(null);
|
|
14
|
+
(0, react_1.useEffect)(() => {
|
|
15
|
+
var _a, _b;
|
|
16
|
+
(_b = (_a = listRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('[aria-selected="true"]')) === null || _b === void 0 ? void 0 : _b.scrollIntoView({ block: 'nearest' });
|
|
17
|
+
}, [commands.activeIndex]);
|
|
18
|
+
const optionId = (index) => `${commands.listId}-${index}`;
|
|
19
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [commands.selections.length > 0 && ((0, jsx_runtime_1.jsx)(PromptInputHeader_1.PromptInputHeader, { contextItems: commands.selections.map((item) => ({
|
|
20
|
+
id: JSON.stringify([item.sourceId, item.id]),
|
|
21
|
+
content: item.title,
|
|
22
|
+
onRemove: disabled ? undefined : () => commands.remove(item),
|
|
23
|
+
})) })), config.sources.some((source) => source.buttonLabel) && ((0, jsx_runtime_1.jsx)("div", { className: b('command-buttons'), children: config.sources
|
|
24
|
+
.filter((source) => source.buttonLabel)
|
|
25
|
+
.map((source) => ((0, jsx_runtime_1.jsx)(uikit_1.Button, { size: "s", view: "flat", disabled: disabled, onClick: () => commands.openSource(source.id), children: source.buttonLabel }, source.id))) })), (0, jsx_runtime_1.jsx)(uikit_1.Popup, { open: commands.open, anchorRef: inputRef, placement: ['top-start', 'bottom-start'], onClose: commands.close, children: (0, jsx_runtime_1.jsxs)("div", { className: b('commands'), children: [(0, jsx_runtime_1.jsx)("div", { className: b('commands-title'), children: (_a = commands.source) === null || _a === void 0 ? void 0 : _a.title }), ((_b = commands.session) === null || _b === void 0 ? void 0 : _b.origin) === 'button' && ((0, jsx_runtime_1.jsx)(uikit_1.TextInput, { autoFocus: true, value: commands.session.query, onUpdate: commands.search, placeholder: (0, i18n_1.i18n)('search'), onKeyDown: commands.handleKeyDown, controlProps: {
|
|
26
|
+
role: 'combobox',
|
|
27
|
+
'aria-label': (_c = commands.source) === null || _c === void 0 ? void 0 : _c.title,
|
|
28
|
+
'aria-expanded': true,
|
|
29
|
+
'aria-controls': commands.listId,
|
|
30
|
+
'aria-autocomplete': 'list',
|
|
31
|
+
'aria-activedescendant': commands.items[commands.activeIndex]
|
|
32
|
+
? optionId(commands.activeIndex)
|
|
33
|
+
: undefined,
|
|
34
|
+
} })), commands.loading && (0, jsx_runtime_1.jsx)("div", { role: "status", children: (0, i18n_1.i18n)('loading') }), commands.error && ((0, jsx_runtime_1.jsxs)("div", { role: "alert", children: [(0, i18n_1.i18n)('error'), ' ', (0, jsx_runtime_1.jsx)(uikit_1.Button, { size: "s", onClick: commands.retry, children: (0, i18n_1.i18n)('retry') })] })), !commands.loading && !commands.error && commands.items.length === 0 && ((0, jsx_runtime_1.jsx)("div", { role: "status", children: (0, i18n_1.i18n)('empty') })), (0, jsx_runtime_1.jsx)("div", { ref: listRef, id: commands.listId, role: "listbox", "aria-label": (_d = commands.source) === null || _d === void 0 ? void 0 : _d.title, className: b('command-list'), children: commands.items.map((item, index) => ((0, jsx_runtime_1.jsxs)("div", { id: optionId(index), role: "option", "aria-selected": index === commands.activeIndex, "aria-disabled": item.disabled, className: b('command', {
|
|
35
|
+
active: index === commands.activeIndex,
|
|
36
|
+
disabled: item.disabled,
|
|
37
|
+
}), onMouseDown: (event) => event.preventDefault(), onClick: () => commands.select(item), children: [item.icon && (0, jsx_runtime_1.jsx)("span", { children: item.icon }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { children: item.title }), item.description && ((0, jsx_runtime_1.jsx)("div", { className: b('command-description'), children: item.description }))] })] }, item.id))) })] }) })] }));
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=PromptInputCommands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptInputCommands.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/PromptInputCommands.tsx"],"names":[],"mappings":"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","sourcesContent":["import {useEffect, useRef} from 'react';\nimport type {RefObject} from 'react';\n\nimport {Button, Popup, TextInput} from '@gravity-ui/uikit';\n\nimport type {PromptCommandsConfig} from '../../../types';\nimport {block} from '../../../utils/cn';\nimport {PromptInputHeader} from '../../molecules/PromptInputHeader';\n\nimport {i18n} from './i18n';\nimport type {usePromptCommands} from './usePromptCommands';\n\nconst b = block('prompt-input');\n\nexport function PromptInputCommands({\n commands,\n config,\n inputRef,\n disabled,\n}: {\n commands: ReturnType<typeof usePromptCommands>;\n config: PromptCommandsConfig;\n inputRef: RefObject<HTMLTextAreaElement>;\n disabled: boolean;\n}) {\n const listRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n listRef.current\n ?.querySelector('[aria-selected=\"true\"]')\n ?.scrollIntoView({block: 'nearest'});\n }, [commands.activeIndex]);\n const optionId = (index: number) => `${commands.listId}-${index}`;\n return (\n <>\n {commands.selections.length > 0 && (\n <PromptInputHeader\n contextItems={commands.selections.map((item) => ({\n id: JSON.stringify([item.sourceId, item.id]),\n content: item.title,\n onRemove: disabled ? undefined : () => commands.remove(item),\n }))}\n />\n )}\n {config.sources.some((source) => source.buttonLabel) && (\n <div className={b('command-buttons')}>\n {config.sources\n .filter((source) => source.buttonLabel)\n .map((source) => (\n <Button\n key={source.id}\n size=\"s\"\n view=\"flat\"\n disabled={disabled}\n onClick={() => commands.openSource(source.id)}\n >\n {source.buttonLabel}\n </Button>\n ))}\n </div>\n )}\n <Popup\n open={commands.open}\n anchorRef={inputRef}\n placement={['top-start', 'bottom-start']}\n onClose={commands.close}\n >\n <div className={b('commands')}>\n <div className={b('commands-title')}>{commands.source?.title}</div>\n {commands.session?.origin === 'button' && (\n <TextInput\n autoFocus\n value={commands.session.query}\n onUpdate={commands.search}\n placeholder={i18n('search')}\n onKeyDown={commands.handleKeyDown}\n controlProps={{\n role: 'combobox',\n 'aria-label': commands.source?.title,\n 'aria-expanded': true,\n 'aria-controls': commands.listId,\n 'aria-autocomplete': 'list',\n 'aria-activedescendant': commands.items[commands.activeIndex]\n ? optionId(commands.activeIndex)\n : undefined,\n }}\n />\n )}\n {commands.loading && <div role=\"status\">{i18n('loading')}</div>}\n {commands.error && (\n <div role=\"alert\">\n {i18n('error')}{' '}\n <Button size=\"s\" onClick={commands.retry}>\n {i18n('retry')}\n </Button>\n </div>\n )}\n {!commands.loading && !commands.error && commands.items.length === 0 && (\n <div role=\"status\">{i18n('empty')}</div>\n )}\n <div\n ref={listRef}\n id={commands.listId}\n role=\"listbox\"\n aria-label={commands.source?.title}\n className={b('command-list')}\n >\n {commands.items.map((item, index) => (\n <div\n key={item.id}\n id={optionId(index)}\n role=\"option\"\n aria-selected={index === commands.activeIndex}\n aria-disabled={item.disabled}\n className={b('command', {\n active: index === commands.activeIndex,\n disabled: item.disabled,\n })}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => commands.select(item)}\n >\n {item.icon && <span>{item.icon}</span>}\n <div>\n <div>{item.title}</div>\n {item.description && (\n <div className={b('command-description')}>\n {item.description}\n </div>\n )}\n </div>\n </div>\n ))}\n </div>\n </div>\n </Popup>\n </>\n );\n}\n"]}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
1
2
|
import { PromptInputBodyConfig, PromptInputFooterConfig, PromptInputHeaderConfig } from "./types.js";
|
|
2
3
|
import { UsePromptInputReturn } from "./usePromptInput.js";
|
|
3
4
|
/**
|
|
4
5
|
* Props for the PromptInputFull component
|
|
5
6
|
*/
|
|
6
7
|
export type PromptInputFullProps = {
|
|
8
|
+
commandsContent?: ReactNode;
|
|
7
9
|
/** Hook return value with state and handlers */
|
|
8
10
|
hookState: UsePromptInputReturn;
|
|
9
11
|
/** Header-related props */
|
|
@@ -15,13 +15,13 @@ const b = (0, cn_1.block)('prompt-input');
|
|
|
15
15
|
*/
|
|
16
16
|
function PromptInputFull(props) {
|
|
17
17
|
var _a, _b, _c, _d, _e;
|
|
18
|
-
const { hookState, headerProps = {}, bodyProps = {}, footerProps = {}, className, qa } = props;
|
|
18
|
+
const { commandsContent, hookState, headerProps = {}, bodyProps = {}, footerProps = {}, className, qa, } = props;
|
|
19
19
|
const { topContent, contextItems = [], showContextIndicator = false, contextIndicatorProps, qa: headerQa, } = headerProps;
|
|
20
|
-
const { placeholder = 'Plan, code, build and test anything', size: bodySize, minRows = 1, maxRows = 15, autoFocus = false, disabledInput = false, inputRef, qa: bodyQa, } = bodyProps;
|
|
20
|
+
const { placeholder = 'Plan, code, build and test anything', size: bodySize, minRows = 1, maxRows = 15, autoFocus = false, disabledInput = false, inputRef, controlProps, qa: bodyQa, } = bodyProps;
|
|
21
21
|
const { bottomContent, className: footerClassName, contentClassName, buttonSize, submitButtonProps, showSettings = false, onSettingsClick, attachmentContent, showAttachment, onAttachmentClick, showMicrophone = false, onMicrophoneClick, submitButtonTooltipSend, submitButtonTooltipCancel, submitButtonCancelableText, submitButtonQa, qa: footerQa, } = footerProps;
|
|
22
22
|
const { value, submitButtonState, isInputDisabled, handleChange, handleKeyDown, handleSubmit } = hookState;
|
|
23
23
|
const shouldShowHeader = topContent || contextItems.length > 0 || showContextIndicator;
|
|
24
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: b({ view: 'full' }, className), "data-qa": qa, children: [shouldShowHeader &&
|
|
25
|
-
(topContent ? ((0, jsx_runtime_1.jsx)(PromptInputHeader_1.PromptInputHeader, { qa: headerQa, children: topContent })) : ((0, jsx_runtime_1.jsx)(PromptInputHeader_1.PromptInputHeader, { contextItems: contextItems, showContextIndicator: showContextIndicator, contextIndicatorProps: contextIndicatorProps, qa: headerQa }))), (0, jsx_runtime_1.jsx)(PromptInputBody_1.PromptInputBody, { value: value, placeholder: placeholder, size: bodySize, minRows: minRows, maxRows: maxRows, autoFocus: autoFocus, disabledInput: isInputDisabled || disabledInput, ref: inputRef, onChange: handleChange, onKeyDown: handleKeyDown, inputClassName: b('textarea'), qa: bodyQa }), (0, jsx_runtime_1.jsx)(PromptInputFooter_1.PromptInputFooter, { qa: footerQa, className: footerClassName, contentClassName: contentClassName, buttonSize: buttonSize, submitButton: Object.assign(Object.assign({}, submitButtonProps), { onClick: handleSubmit, state: submitButtonState, tooltipSend: (_a = submitButtonProps === null || submitButtonProps === void 0 ? void 0 : submitButtonProps.tooltipSend) !== null && _a !== void 0 ? _a : submitButtonTooltipSend, tooltipCancel: (_b = submitButtonProps === null || submitButtonProps === void 0 ? void 0 : submitButtonProps.tooltipCancel) !== null && _b !== void 0 ? _b : submitButtonTooltipCancel, cancelableText: (_c = submitButtonProps === null || submitButtonProps === void 0 ? void 0 : submitButtonProps.cancelableText) !== null && _c !== void 0 ? _c : submitButtonCancelableText, qa: (_e = (_d = submitButtonProps === null || submitButtonProps === void 0 ? void 0 : submitButtonProps.qa) !== null && _d !== void 0 ? _d : submitButtonQa) !== null && _e !== void 0 ? _e : 'submit-button-full' }), showSettings: showSettings, onSettingsClick: onSettingsClick, showAttachment: showAttachment, onAttachmentClick: onAttachmentClick, attachmentContent: attachmentContent, showMicrophone: showMicrophone, onMicrophoneClick: onMicrophoneClick, children: bottomContent })] }));
|
|
24
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: b({ view: 'full' }, className), "data-qa": qa, children: [commandsContent, shouldShowHeader &&
|
|
25
|
+
(topContent ? ((0, jsx_runtime_1.jsx)(PromptInputHeader_1.PromptInputHeader, { qa: headerQa, children: topContent })) : ((0, jsx_runtime_1.jsx)(PromptInputHeader_1.PromptInputHeader, { contextItems: contextItems, showContextIndicator: showContextIndicator, contextIndicatorProps: contextIndicatorProps, qa: headerQa }))), (0, jsx_runtime_1.jsx)(PromptInputBody_1.PromptInputBody, { value: value, placeholder: placeholder, size: bodySize, minRows: minRows, maxRows: maxRows, autoFocus: autoFocus, disabledInput: isInputDisabled || disabledInput, ref: inputRef, controlProps: controlProps, onChange: handleChange, onKeyDown: handleKeyDown, inputClassName: b('textarea'), qa: bodyQa }), (0, jsx_runtime_1.jsx)(PromptInputFooter_1.PromptInputFooter, { qa: footerQa, className: footerClassName, contentClassName: contentClassName, buttonSize: buttonSize, submitButton: Object.assign(Object.assign({}, submitButtonProps), { onClick: handleSubmit, state: submitButtonState, tooltipSend: (_a = submitButtonProps === null || submitButtonProps === void 0 ? void 0 : submitButtonProps.tooltipSend) !== null && _a !== void 0 ? _a : submitButtonTooltipSend, tooltipCancel: (_b = submitButtonProps === null || submitButtonProps === void 0 ? void 0 : submitButtonProps.tooltipCancel) !== null && _b !== void 0 ? _b : submitButtonTooltipCancel, cancelableText: (_c = submitButtonProps === null || submitButtonProps === void 0 ? void 0 : submitButtonProps.cancelableText) !== null && _c !== void 0 ? _c : submitButtonCancelableText, qa: (_e = (_d = submitButtonProps === null || submitButtonProps === void 0 ? void 0 : submitButtonProps.qa) !== null && _d !== void 0 ? _d : submitButtonQa) !== null && _e !== void 0 ? _e : 'submit-button-full' }), showSettings: showSettings, onSettingsClick: onSettingsClick, showAttachment: showAttachment, onAttachmentClick: onAttachmentClick, attachmentContent: attachmentContent, showMicrophone: showMicrophone, onMicrophoneClick: onMicrophoneClick, children: bottomContent })] }));
|
|
26
26
|
}
|
|
27
27
|
//# sourceMappingURL=PromptInputFull.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromptInputFull.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/PromptInputFull.tsx"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"PromptInputFull.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/PromptInputFull.tsx"],"names":[],"mappings":"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","sourcesContent":["import type {ReactNode} from 'react';\n\nimport {block} from '../../../utils/cn';\nimport {PromptInputBody} from '../../molecules/PromptInputBody';\nimport {PromptInputFooter} from '../../molecules/PromptInputFooter';\nimport {PromptInputHeader} from '../../molecules/PromptInputHeader';\n\nimport {PromptInputBodyConfig, PromptInputFooterConfig, PromptInputHeaderConfig} from './types';\nimport {UsePromptInputReturn} from './usePromptInput';\n\nconst b = block('prompt-input');\n\n/**\n * Props for the PromptInputFull component\n */\nexport type PromptInputFullProps = {\n commandsContent?: ReactNode;\n /** Hook return value with state and handlers */\n hookState: UsePromptInputReturn;\n /** Header-related props */\n headerProps?: PromptInputHeaderConfig;\n /** Body/textarea-related props */\n bodyProps?: PromptInputBodyConfig;\n /** Footer-related props */\n footerProps?: PromptInputFooterConfig;\n /** Additional CSS class */\n className?: string;\n /** QA/test identifier */\n qa?: string;\n};\n\n/**\n * PromptInputFull component - full view with header, body, and footer\n *\n * @param props - Component props\n * @returns React component\n */\nexport function PromptInputFull(props: PromptInputFullProps) {\n const {\n commandsContent,\n hookState,\n headerProps = {},\n bodyProps = {},\n footerProps = {},\n className,\n qa,\n } = props;\n\n const {\n topContent,\n contextItems = [],\n showContextIndicator = false,\n contextIndicatorProps,\n qa: headerQa,\n } = headerProps;\n\n const {\n placeholder = 'Plan, code, build and test anything',\n size: bodySize,\n minRows = 1,\n maxRows = 15,\n autoFocus = false,\n disabledInput = false,\n inputRef,\n controlProps,\n qa: bodyQa,\n } = bodyProps;\n\n const {\n bottomContent,\n className: footerClassName,\n contentClassName,\n buttonSize,\n submitButtonProps,\n showSettings = false,\n onSettingsClick,\n attachmentContent,\n showAttachment,\n onAttachmentClick,\n showMicrophone = false,\n onMicrophoneClick,\n submitButtonTooltipSend,\n submitButtonTooltipCancel,\n submitButtonCancelableText,\n submitButtonQa,\n qa: footerQa,\n } = footerProps;\n\n const {value, submitButtonState, isInputDisabled, handleChange, handleKeyDown, handleSubmit} =\n hookState;\n\n const shouldShowHeader = topContent || contextItems.length > 0 || showContextIndicator;\n\n return (\n <div className={b({view: 'full'}, className)} data-qa={qa}>\n {commandsContent}\n {shouldShowHeader &&\n (topContent ? (\n <PromptInputHeader qa={headerQa}>{topContent}</PromptInputHeader>\n ) : (\n <PromptInputHeader\n contextItems={contextItems}\n showContextIndicator={showContextIndicator}\n contextIndicatorProps={contextIndicatorProps}\n qa={headerQa}\n />\n ))}\n\n <PromptInputBody\n value={value}\n placeholder={placeholder}\n size={bodySize}\n minRows={minRows}\n maxRows={maxRows}\n autoFocus={autoFocus}\n disabledInput={isInputDisabled || disabledInput}\n ref={inputRef}\n controlProps={controlProps}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n inputClassName={b('textarea')}\n qa={bodyQa}\n />\n\n <PromptInputFooter\n qa={footerQa}\n className={footerClassName}\n contentClassName={contentClassName}\n buttonSize={buttonSize}\n submitButton={{\n ...submitButtonProps,\n onClick: handleSubmit,\n state: submitButtonState,\n tooltipSend: submitButtonProps?.tooltipSend ?? submitButtonTooltipSend,\n tooltipCancel: submitButtonProps?.tooltipCancel ?? submitButtonTooltipCancel,\n cancelableText: submitButtonProps?.cancelableText ?? submitButtonCancelableText,\n qa: submitButtonProps?.qa ?? submitButtonQa ?? 'submit-button-full',\n }}\n showSettings={showSettings}\n onSettingsClick={onSettingsClick}\n showAttachment={showAttachment}\n onAttachmentClick={onAttachmentClick}\n attachmentContent={attachmentContent}\n showMicrophone={showMicrophone}\n onMicrophoneClick={onMicrophoneClick}\n >\n {bottomContent}\n </PromptInputFooter>\n </div>\n );\n}\n"]}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
1
2
|
import { PromptInputBodyConfig, PromptInputFooterConfig } from "./types.js";
|
|
2
3
|
import { UsePromptInputReturn } from "./usePromptInput.js";
|
|
3
4
|
/**
|
|
4
5
|
* Props for the PromptInputSimple component
|
|
5
6
|
*/
|
|
6
7
|
export type PromptInputSimpleProps = {
|
|
8
|
+
commandsContent?: ReactNode;
|
|
7
9
|
/** Hook return value with state and handlers */
|
|
8
10
|
hookState: UsePromptInputReturn;
|
|
9
11
|
/** Body/textarea-related props */
|
|
@@ -15,11 +15,11 @@ const b = (0, cn_1.block)('prompt-input');
|
|
|
15
15
|
*/
|
|
16
16
|
function PromptInputSimple(props) {
|
|
17
17
|
var _a, _b, _c, _d, _e;
|
|
18
|
-
const { hookState, bodyProps = {}, footerProps = {}, className, qa } = props;
|
|
19
|
-
const { placeholder = 'Plan, code, build and test anything', size: bodySize, minRows = 1, maxRows = 15, autoFocus = false, disabledInput = false, inputRef, qa: bodyQa, } = bodyProps;
|
|
18
|
+
const { commandsContent, hookState, bodyProps = {}, footerProps = {}, className, qa } = props;
|
|
19
|
+
const { placeholder = 'Plan, code, build and test anything', size: bodySize, minRows = 1, maxRows = 15, autoFocus = false, disabledInput = false, inputRef, controlProps, qa: bodyQa, } = bodyProps;
|
|
20
20
|
const { bottomContent, className: footerClassName, contentClassName, buttonSize, submitButtonProps, showAttachment = false, onAttachmentClick, attachmentContent, showMicrophone = false, onMicrophoneClick, submitButtonTooltipSend, submitButtonTooltipCancel, submitButtonCancelableText, submitButtonQa, qa: footerQa, } = footerProps;
|
|
21
21
|
const { value, submitButtonState, isInputDisabled, handleChange, handleKeyDown, handleSubmit } = hookState;
|
|
22
22
|
const resolvedButtonSize = (0, useMobileControlSize_1.useMobileControlSize)(buttonSize, 'l', 'xl');
|
|
23
|
-
return ((0, jsx_runtime_1.
|
|
23
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: b({ view: 'simple' }, className), "data-qa": qa, children: [commandsContent, (0, jsx_runtime_1.jsxs)("div", { className: b('content'), children: [(0, jsx_runtime_1.jsx)(PromptInputBody_1.PromptInputBody, { value: value, placeholder: placeholder, size: bodySize, minRows: minRows, maxRows: maxRows, autoFocus: autoFocus, disabledInput: isInputDisabled || disabledInput, ref: inputRef, controlProps: controlProps, onChange: handleChange, onKeyDown: handleKeyDown, qa: bodyQa }), (0, jsx_runtime_1.jsx)(PromptInputFooter_1.PromptInputFooter, { qa: footerQa, className: footerClassName, contentClassName: contentClassName, submitButton: Object.assign(Object.assign({}, submitButtonProps), { onClick: handleSubmit, state: submitButtonState, tooltipSend: (_a = submitButtonProps === null || submitButtonProps === void 0 ? void 0 : submitButtonProps.tooltipSend) !== null && _a !== void 0 ? _a : submitButtonTooltipSend, tooltipCancel: (_b = submitButtonProps === null || submitButtonProps === void 0 ? void 0 : submitButtonProps.tooltipCancel) !== null && _b !== void 0 ? _b : submitButtonTooltipCancel, cancelableText: (_c = submitButtonProps === null || submitButtonProps === void 0 ? void 0 : submitButtonProps.cancelableText) !== null && _c !== void 0 ? _c : submitButtonCancelableText, qa: (_e = (_d = submitButtonProps === null || submitButtonProps === void 0 ? void 0 : submitButtonProps.qa) !== null && _d !== void 0 ? _d : submitButtonQa) !== null && _e !== void 0 ? _e : 'submit-button-simple' }), showAttachment: showAttachment, onAttachmentClick: onAttachmentClick, attachmentContent: attachmentContent, showMicrophone: showMicrophone, onMicrophoneClick: onMicrophoneClick, buttonSize: resolvedButtonSize, children: bottomContent })] })] }));
|
|
24
24
|
}
|
|
25
25
|
//# sourceMappingURL=PromptInputSimple.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromptInputSimple.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/PromptInputSimple.tsx"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"PromptInputSimple.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/PromptInputSimple.tsx"],"names":[],"mappings":";;AAmCA,8CAkFC;;AAnHD,iFAAyE;AACzE,6CAAwC;AACxC,8EAAgE;AAChE,kFAAoE;AAKpE,MAAM,CAAC,GAAG,IAAA,UAAK,EAAC,cAAc,CAAC,CAAC;AAmBhC;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,KAA6B;;IAC3D,MAAM,EAAC,eAAe,EAAE,SAAS,EAAE,SAAS,GAAG,EAAE,EAAE,WAAW,GAAG,EAAE,EAAE,SAAS,EAAE,EAAE,EAAC,GAAG,KAAK,CAAC;IAE5F,MAAM,EACF,WAAW,GAAG,qCAAqC,EACnD,IAAI,EAAE,QAAQ,EACd,OAAO,GAAG,CAAC,EACX,OAAO,GAAG,EAAE,EACZ,SAAS,GAAG,KAAK,EACjB,aAAa,GAAG,KAAK,EACrB,QAAQ,EACR,YAAY,EACZ,EAAE,EAAE,MAAM,GACb,GAAG,SAAS,CAAC;IAEd,MAAM,EACF,aAAa,EACb,SAAS,EAAE,eAAe,EAC1B,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,cAAc,GAAG,KAAK,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,GAAG,KAAK,EACtB,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,0BAA0B,EAC1B,cAAc,EACd,EAAE,EAAE,QAAQ,GACf,GAAG,WAAW,CAAC;IAEhB,MAAM,EAAC,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAC,GACxF,SAAS,CAAC;IACd,MAAM,kBAAkB,GAAG,IAAA,2CAAoB,EAAC,UAAU,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAEvE,OAAO,CACH,iCAAK,SAAS,EAAE,CAAC,CAAC,EAAC,IAAI,EAAE,QAAQ,EAAC,EAAE,SAAS,CAAC,aAAW,EAAE,aACtD,eAAe,EAChB,iCAAK,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,aACxB,uBAAC,iCAAe,IACZ,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,QAAQ,EACd,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,aAAa,EAAE,eAAe,IAAI,aAAa,EAC/C,GAAG,EAAE,QAAQ,EACb,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,aAAa,EACxB,EAAE,EAAE,MAAM,GACZ,EACF,uBAAC,qCAAiB,IACd,EAAE,EAAE,QAAQ,EACZ,SAAS,EAAE,eAAe,EAC1B,gBAAgB,EAAE,gBAAgB,EAClC,YAAY,kCACL,iBAAiB,KACpB,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,iBAAiB,EACxB,WAAW,EAAE,MAAA,iBAAiB,aAAjB,iBAAiB,uBAAjB,iBAAiB,CAAE,WAAW,mCAAI,uBAAuB,EACtE,aAAa,EACT,MAAA,iBAAiB,aAAjB,iBAAiB,uBAAjB,iBAAiB,CAAE,aAAa,mCAAI,yBAAyB,EACjE,cAAc,EACV,MAAA,iBAAiB,aAAjB,iBAAiB,uBAAjB,iBAAiB,CAAE,cAAc,mCAAI,0BAA0B,EACnE,EAAE,EAAE,MAAA,MAAA,iBAAiB,aAAjB,iBAAiB,uBAAjB,iBAAiB,CAAE,EAAE,mCAAI,cAAc,mCAAI,sBAAsB,KAEzE,cAAc,EAAE,cAAc,EAC9B,iBAAiB,EAAE,iBAAiB,EACpC,iBAAiB,EAAE,iBAAiB,EACpC,cAAc,EAAE,cAAc,EAC9B,iBAAiB,EAAE,iBAAiB,EACpC,UAAU,EAAE,kBAAkB,YAE7B,aAAa,GACE,IAClB,IACJ,CACT,CAAC;AACN,CAAC","sourcesContent":["import type {ReactNode} from 'react';\n\nimport {useMobileControlSize} from '../../../hooks/useMobileControlSize';\nimport {block} from '../../../utils/cn';\nimport {PromptInputBody} from '../../molecules/PromptInputBody';\nimport {PromptInputFooter} from '../../molecules/PromptInputFooter';\n\nimport {PromptInputBodyConfig, PromptInputFooterConfig} from './types';\nimport {UsePromptInputReturn} from './usePromptInput';\n\nconst b = block('prompt-input');\n\n/**\n * Props for the PromptInputSimple component\n */\nexport type PromptInputSimpleProps = {\n commandsContent?: ReactNode;\n /** Hook return value with state and handlers */\n hookState: UsePromptInputReturn;\n /** Body/textarea-related props */\n bodyProps?: PromptInputBodyConfig;\n /** Footer-related props */\n footerProps?: PromptInputFooterConfig;\n /** Additional CSS class */\n className?: string;\n /** QA/test identifier */\n qa?: string;\n};\n\n/**\n * PromptInputSimple component - simple view with just body and footer\n *\n * @param props - Component props\n * @returns React component\n */\nexport function PromptInputSimple(props: PromptInputSimpleProps) {\n const {commandsContent, hookState, bodyProps = {}, footerProps = {}, className, qa} = props;\n\n const {\n placeholder = 'Plan, code, build and test anything',\n size: bodySize,\n minRows = 1,\n maxRows = 15,\n autoFocus = false,\n disabledInput = false,\n inputRef,\n controlProps,\n qa: bodyQa,\n } = bodyProps;\n\n const {\n bottomContent,\n className: footerClassName,\n contentClassName,\n buttonSize,\n submitButtonProps,\n showAttachment = false,\n onAttachmentClick,\n attachmentContent,\n showMicrophone = false,\n onMicrophoneClick,\n submitButtonTooltipSend,\n submitButtonTooltipCancel,\n submitButtonCancelableText,\n submitButtonQa,\n qa: footerQa,\n } = footerProps;\n\n const {value, submitButtonState, isInputDisabled, handleChange, handleKeyDown, handleSubmit} =\n hookState;\n const resolvedButtonSize = useMobileControlSize(buttonSize, 'l', 'xl');\n\n return (\n <div className={b({view: 'simple'}, className)} data-qa={qa}>\n {commandsContent}\n <div className={b('content')}>\n <PromptInputBody\n value={value}\n placeholder={placeholder}\n size={bodySize}\n minRows={minRows}\n maxRows={maxRows}\n autoFocus={autoFocus}\n disabledInput={isInputDisabled || disabledInput}\n ref={inputRef}\n controlProps={controlProps}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n qa={bodyQa}\n />\n <PromptInputFooter\n qa={footerQa}\n className={footerClassName}\n contentClassName={contentClassName}\n submitButton={{\n ...submitButtonProps,\n onClick: handleSubmit,\n state: submitButtonState,\n tooltipSend: submitButtonProps?.tooltipSend ?? submitButtonTooltipSend,\n tooltipCancel:\n submitButtonProps?.tooltipCancel ?? submitButtonTooltipCancel,\n cancelableText:\n submitButtonProps?.cancelableText ?? submitButtonCancelableText,\n qa: submitButtonProps?.qa ?? submitButtonQa ?? 'submit-button-simple',\n }}\n showAttachment={showAttachment}\n onAttachmentClick={onAttachmentClick}\n attachmentContent={attachmentContent}\n showMicrophone={showMicrophone}\n onMicrophoneClick={onMicrophoneClick}\n buttonSize={resolvedButtonSize}\n >\n {bottomContent}\n </PromptInputFooter>\n </div>\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PromptCommandSource } from "../../../types/index.js";
|
|
2
|
+
export type CommandMatch = {
|
|
3
|
+
sourceId: string;
|
|
4
|
+
query: string;
|
|
5
|
+
start: number;
|
|
6
|
+
end: number;
|
|
7
|
+
};
|
|
8
|
+
/** Match only a whitespace-delimited token at a collapsed caret. */
|
|
9
|
+
export declare function findCommandMatch(value: string, start: number, end: number, sources: readonly PromptCommandSource[]): CommandMatch | undefined;
|
|
10
|
+
export declare function replaceCommand(value: string, match: Pick<CommandMatch, 'start' | 'end'>, text?: string): {
|
|
11
|
+
value: string;
|
|
12
|
+
caret: number;
|
|
13
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findCommandMatch = findCommandMatch;
|
|
4
|
+
exports.replaceCommand = replaceCommand;
|
|
5
|
+
/** Match only a whitespace-delimited token at a collapsed caret. */
|
|
6
|
+
function findCommandMatch(value, start, end, sources) {
|
|
7
|
+
var _a, _b;
|
|
8
|
+
if (start !== end)
|
|
9
|
+
return undefined;
|
|
10
|
+
const match = /(?:^|\s)([/@])([^\s/@]*)$/.exec(value.slice(0, start));
|
|
11
|
+
if (!match)
|
|
12
|
+
return undefined;
|
|
13
|
+
const source = sources.find((item) => item.trigger === match[1]);
|
|
14
|
+
if (!source)
|
|
15
|
+
return undefined;
|
|
16
|
+
const tokenStart = start - match[2].length - 1;
|
|
17
|
+
const suffix = (_b = (_a = /^[^\s/@]*/.exec(value.slice(start))) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : '';
|
|
18
|
+
return { sourceId: source.id, query: match[2], start: tokenStart, end: start + suffix.length };
|
|
19
|
+
}
|
|
20
|
+
function replaceCommand(value, match, text = '') {
|
|
21
|
+
const insertion = text && !/\s$/.test(text) ? `${text} ` : text;
|
|
22
|
+
return {
|
|
23
|
+
value: value.slice(0, match.start) + insertion + value.slice(match.end),
|
|
24
|
+
caret: match.start + insertion.length,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=commandUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commandUtils.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/commandUtils.ts"],"names":[],"mappings":";;AAKA,4CAcC;AAED,wCAUC;AA3BD,oEAAoE;AACpE,SAAgB,gBAAgB,CAC5B,KAAa,EACb,KAAa,EACb,GAAW,EACX,OAAuC;;IAEvC,IAAI,KAAK,KAAK,GAAG;QAAE,OAAO,SAAS,CAAC;IACpC,MAAM,KAAK,GAAG,2BAA2B,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACtE,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,MAAA,MAAA,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,0CAAG,CAAC,CAAC,mCAAI,EAAE,CAAC;IAC/D,OAAO,EAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAC,CAAC;AACjG,CAAC;AAED,SAAgB,cAAc,CAC1B,KAAa,EACb,KAA0C,EAC1C,IAAI,GAAG,EAAE;IAET,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAChE,OAAO;QACH,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;QACvE,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC,MAAM;KACxC,CAAC;AACN,CAAC","sourcesContent":["import type {PromptCommandSource} from '../../../types';\n\nexport type CommandMatch = {sourceId: string; query: string; start: number; end: number};\n\n/** Match only a whitespace-delimited token at a collapsed caret. */\nexport function findCommandMatch(\n value: string,\n start: number,\n end: number,\n sources: readonly PromptCommandSource[],\n): CommandMatch | undefined {\n if (start !== end) return undefined;\n const match = /(?:^|\\s)([/@])([^\\s/@]*)$/.exec(value.slice(0, start));\n if (!match) return undefined;\n const source = sources.find((item) => item.trigger === match[1]);\n if (!source) return undefined;\n const tokenStart = start - match[2].length - 1;\n const suffix = /^[^\\s/@]*/.exec(value.slice(start))?.[0] ?? '';\n return {sourceId: source.id, query: match[2], start: tokenStart, end: start + suffix.length};\n}\n\nexport function replaceCommand(\n value: string,\n match: Pick<CommandMatch, 'start' | 'end'>,\n text = '',\n) {\n const insertion = text && !/\\s$/.test(text) ? `${text} ` : text;\n return {\n value: value.slice(0, match.start) + insertion + value.slice(match.end),\n caret: match.start + insertion.length,\n };\n}\n"]}
|