@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.
Files changed (118) hide show
  1. package/build/cjs/components/molecules/PromptInputBody/PromptInputBody.d.ts +1 -0
  2. package/build/cjs/components/molecules/PromptInputBody/PromptInputBody.js +2 -8
  3. package/build/cjs/components/molecules/PromptInputBody/PromptInputBody.js.map +1 -1
  4. package/build/cjs/components/organisms/PromptInput/PromptInput.css +37 -0
  5. package/build/cjs/components/organisms/PromptInput/PromptInput.d.ts +13 -2
  6. package/build/cjs/components/organisms/PromptInput/PromptInput.js +64 -3
  7. package/build/cjs/components/organisms/PromptInput/PromptInput.js.map +1 -1
  8. package/build/cjs/components/organisms/PromptInput/PromptInputCommands.d.ts +9 -0
  9. package/build/cjs/components/organisms/PromptInput/PromptInputCommands.js +39 -0
  10. package/build/cjs/components/organisms/PromptInput/PromptInputCommands.js.map +1 -0
  11. package/build/cjs/components/organisms/PromptInput/PromptInputFull.d.ts +2 -0
  12. package/build/cjs/components/organisms/PromptInput/PromptInputFull.js +4 -4
  13. package/build/cjs/components/organisms/PromptInput/PromptInputFull.js.map +1 -1
  14. package/build/cjs/components/organisms/PromptInput/PromptInputSimple.d.ts +2 -0
  15. package/build/cjs/components/organisms/PromptInput/PromptInputSimple.js +3 -3
  16. package/build/cjs/components/organisms/PromptInput/PromptInputSimple.js.map +1 -1
  17. package/build/cjs/components/organisms/PromptInput/commandUtils.d.ts +13 -0
  18. package/build/cjs/components/organisms/PromptInput/commandUtils.js +27 -0
  19. package/build/cjs/components/organisms/PromptInput/commandUtils.js.map +1 -0
  20. package/build/cjs/components/organisms/PromptInput/i18n/en.json +8 -0
  21. package/build/cjs/components/organisms/PromptInput/i18n/index.d.ts +13 -0
  22. package/build/cjs/components/organisms/PromptInput/i18n/index.js +10 -0
  23. package/build/cjs/components/organisms/PromptInput/i18n/index.js.map +1 -0
  24. package/build/cjs/components/organisms/PromptInput/i18n/ru.json +8 -0
  25. package/build/cjs/components/organisms/PromptInput/index.d.ts +2 -1
  26. package/build/cjs/components/organisms/PromptInput/index.js.map +1 -1
  27. package/build/cjs/components/organisms/PromptInput/types.d.ts +1 -0
  28. package/build/cjs/components/organisms/PromptInput/types.js.map +1 -1
  29. package/build/cjs/components/organisms/PromptInput/usePromptCommands.d.ts +41 -0
  30. package/build/cjs/components/organisms/PromptInput/usePromptCommands.js +222 -0
  31. package/build/cjs/components/organisms/PromptInput/usePromptCommands.js.map +1 -0
  32. package/build/cjs/components/organisms/PromptInput/usePromptInput.d.ts +10 -1
  33. package/build/cjs/components/organisms/PromptInput/usePromptInput.js +100 -11
  34. package/build/cjs/components/organisms/PromptInput/usePromptInput.js.map +1 -1
  35. package/build/cjs/components/pages/AIStudioChat/AIStudioChat.js +139 -52
  36. package/build/cjs/components/pages/AIStudioChat/AIStudioChat.js.map +1 -1
  37. package/build/cjs/components/pages/AIStudioChat/request.d.ts +4 -0
  38. package/build/cjs/components/pages/AIStudioChat/request.js +11 -0
  39. package/build/cjs/components/pages/AIStudioChat/request.js.map +1 -0
  40. package/build/cjs/components/pages/AIStudioChat/types.d.ts +5 -5
  41. package/build/cjs/components/pages/AIStudioChat/types.js.map +1 -1
  42. package/build/cjs/components/pages/ChatContainer/ChatContainer.js +10 -4
  43. package/build/cjs/components/pages/ChatContainer/ChatContainer.js.map +1 -1
  44. package/build/cjs/components/pages/ChatContainer/types.d.ts +1 -1
  45. package/build/cjs/components/pages/ChatContainer/types.js.map +1 -1
  46. package/build/cjs/components/pages/ChatContainer/useChatContainer.d.ts +1 -0
  47. package/build/cjs/components/pages/ChatContainer/useChatContainer.js +5 -1
  48. package/build/cjs/components/pages/ChatContainer/useChatContainer.js.map +1 -1
  49. package/build/cjs/package.json +1 -1
  50. package/build/cjs/types/index.d.ts +1 -0
  51. package/build/cjs/types/index.js +1 -0
  52. package/build/cjs/types/index.js.map +1 -1
  53. package/build/cjs/types/messages.d.ts +3 -0
  54. package/build/cjs/types/messages.js.map +1 -1
  55. package/build/cjs/types/promptCommands.d.ts +44 -0
  56. package/build/cjs/types/promptCommands.js +3 -0
  57. package/build/cjs/types/promptCommands.js.map +1 -0
  58. package/build/docs/components/molecules/PromptInputBody.md +16 -15
  59. package/build/docs/components/organisms/PromptInput.md +151 -0
  60. package/build/docs/components/pages/AIStudioChat.md +38 -0
  61. package/build/esm/components/molecules/PromptInputBody/PromptInputBody.d.ts +1 -0
  62. package/build/esm/components/molecules/PromptInputBody/PromptInputBody.js +2 -8
  63. package/build/esm/components/molecules/PromptInputBody/PromptInputBody.js.map +1 -1
  64. package/build/esm/components/organisms/PromptInput/PromptInput.css +37 -0
  65. package/build/esm/components/organisms/PromptInput/PromptInput.d.ts +13 -2
  66. package/build/esm/components/organisms/PromptInput/PromptInput.js +65 -4
  67. package/build/esm/components/organisms/PromptInput/PromptInput.js.map +1 -1
  68. package/build/esm/components/organisms/PromptInput/PromptInputCommands.d.ts +9 -0
  69. package/build/esm/components/organisms/PromptInput/PromptInputCommands.js +36 -0
  70. package/build/esm/components/organisms/PromptInput/PromptInputCommands.js.map +1 -0
  71. package/build/esm/components/organisms/PromptInput/PromptInputFull.d.ts +2 -0
  72. package/build/esm/components/organisms/PromptInput/PromptInputFull.js +4 -4
  73. package/build/esm/components/organisms/PromptInput/PromptInputFull.js.map +1 -1
  74. package/build/esm/components/organisms/PromptInput/PromptInputSimple.d.ts +2 -0
  75. package/build/esm/components/organisms/PromptInput/PromptInputSimple.js +3 -3
  76. package/build/esm/components/organisms/PromptInput/PromptInputSimple.js.map +1 -1
  77. package/build/esm/components/organisms/PromptInput/commandUtils.d.ts +13 -0
  78. package/build/esm/components/organisms/PromptInput/commandUtils.js +23 -0
  79. package/build/esm/components/organisms/PromptInput/commandUtils.js.map +1 -0
  80. package/build/esm/components/organisms/PromptInput/i18n/en.json +8 -0
  81. package/build/esm/components/organisms/PromptInput/i18n/index.d.ts +13 -0
  82. package/build/esm/components/organisms/PromptInput/i18n/index.js +6 -0
  83. package/build/esm/components/organisms/PromptInput/i18n/index.js.map +1 -0
  84. package/build/esm/components/organisms/PromptInput/i18n/ru.json +8 -0
  85. package/build/esm/components/organisms/PromptInput/index.d.ts +2 -1
  86. package/build/esm/components/organisms/PromptInput/index.js.map +1 -1
  87. package/build/esm/components/organisms/PromptInput/types.d.ts +1 -0
  88. package/build/esm/components/organisms/PromptInput/types.js.map +1 -1
  89. package/build/esm/components/organisms/PromptInput/usePromptCommands.d.ts +41 -0
  90. package/build/esm/components/organisms/PromptInput/usePromptCommands.js +219 -0
  91. package/build/esm/components/organisms/PromptInput/usePromptCommands.js.map +1 -0
  92. package/build/esm/components/organisms/PromptInput/usePromptInput.d.ts +10 -1
  93. package/build/esm/components/organisms/PromptInput/usePromptInput.js +101 -12
  94. package/build/esm/components/organisms/PromptInput/usePromptInput.js.map +1 -1
  95. package/build/esm/components/pages/AIStudioChat/AIStudioChat.js +139 -52
  96. package/build/esm/components/pages/AIStudioChat/AIStudioChat.js.map +1 -1
  97. package/build/esm/components/pages/AIStudioChat/request.d.ts +4 -0
  98. package/build/esm/components/pages/AIStudioChat/request.js +8 -0
  99. package/build/esm/components/pages/AIStudioChat/request.js.map +1 -0
  100. package/build/esm/components/pages/AIStudioChat/types.d.ts +5 -5
  101. package/build/esm/components/pages/AIStudioChat/types.js.map +1 -1
  102. package/build/esm/components/pages/ChatContainer/ChatContainer.js +12 -6
  103. package/build/esm/components/pages/ChatContainer/ChatContainer.js.map +1 -1
  104. package/build/esm/components/pages/ChatContainer/types.d.ts +1 -1
  105. package/build/esm/components/pages/ChatContainer/types.js.map +1 -1
  106. package/build/esm/components/pages/ChatContainer/useChatContainer.d.ts +1 -0
  107. package/build/esm/components/pages/ChatContainer/useChatContainer.js +5 -1
  108. package/build/esm/components/pages/ChatContainer/useChatContainer.js.map +1 -1
  109. package/build/esm/package.json +1 -1
  110. package/build/esm/types/index.d.ts +1 -0
  111. package/build/esm/types/index.js +1 -0
  112. package/build/esm/types/index.js.map +1 -1
  113. package/build/esm/types/messages.d.ts +3 -0
  114. package/build/esm/types/messages.js.map +1 -1
  115. package/build/esm/types/promptCommands.d.ts +44 -0
  116. package/build/esm/types/promptCommands.js +2 -0
  117. package/build/esm/types/promptCommands.js.map +1 -0
  118. 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":"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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 /** 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 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 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"]}
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 { ChatStatus, TSubmitData } from "../../../types/index.js";
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
- const { view = 'simple', onSend, onCancel, initialValue, disabled = false, status = 'ready', maxLength, onValueChange, headerProps, bodyProps, footerProps, suggestionsProps, topPanel, bottomPanel, className, qa, } = props;
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
- onSend,
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: hookState, headerProps: headerProps, bodyProps: bodyProps, footerProps: footerProps, className: className, qa: qa })) : ((0, jsx_runtime_1.jsx)(PromptInputSimple_1.PromptInputSimple, { hookState: hookState, bodyProps: bodyProps, footerProps: footerProps, className: className, qa: qa })) }) }));
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":"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","sourcesContent":["import {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 /** 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 {hookState, headerProps = {}, bodyProps = {}, footerProps = {}, className, qa} = 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 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 {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 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
+ {"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.jsx)("div", { className: b({ view: 'simple' }, className), "data-qa": qa, children: (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, 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 })] }) }));
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":";;AAgCA,8CA+EC;;AA/GD,iFAAyE;AACzE,6CAAwC;AACxC,8EAAgE;AAChE,kFAAoE;AAKpE,MAAM,CAAC,GAAG,IAAA,UAAK,EAAC,cAAc,CAAC,CAAC;AAkBhC;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,KAA6B;;IAC3D,MAAM,EAAC,SAAS,EAAE,SAAS,GAAG,EAAE,EAAE,WAAW,GAAG,EAAE,EAAE,SAAS,EAAE,EAAE,EAAC,GAAG,KAAK,CAAC;IAE3E,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,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,gCAAK,SAAS,EAAE,CAAC,CAAC,EAAC,IAAI,EAAE,QAAQ,EAAC,EAAE,SAAS,CAAC,aAAW,EAAE,YACvD,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,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,GACJ,CACT,CAAC;AACN,CAAC","sourcesContent":["import {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 /** 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 {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 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 <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 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"]}
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"]}
@@ -0,0 +1,8 @@
1
+ {
2
+ "loading": "Loading…",
3
+ "empty": "No matches",
4
+ "error": "Could not select or load items. Try again.",
5
+ "retry": "Retry",
6
+ "search": "Search",
7
+ "send-error": "Could not send the message. Your draft has been kept."
8
+ }