@gravity-ui/aikit 2.21.4-beta.de9a973e6444f67d992e855b9b83d5a97fec4fd7.0 → 2.22.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 (31) hide show
  1. package/build/cjs/components/atoms/SubmitButton/SubmitButton.d.ts +5 -1
  2. package/build/cjs/components/atoms/SubmitButton/SubmitButton.js +7 -4
  3. package/build/cjs/components/atoms/SubmitButton/SubmitButton.js.map +1 -1
  4. package/build/cjs/components/organisms/PromptInput/PromptInput.js +1 -2
  5. package/build/cjs/components/organisms/PromptInput/PromptInput.js.map +1 -1
  6. package/build/cjs/components/organisms/PromptInput/PromptInputFull.js +3 -3
  7. package/build/cjs/components/organisms/PromptInput/PromptInputFull.js.map +1 -1
  8. package/build/cjs/components/organisms/PromptInput/PromptInputSimple.js +3 -3
  9. package/build/cjs/components/organisms/PromptInput/PromptInputSimple.js.map +1 -1
  10. package/build/cjs/components/organisms/PromptInput/types.d.ts +3 -1
  11. package/build/cjs/components/organisms/PromptInput/types.js.map +1 -1
  12. package/build/cjs/hooks/useFileUploadStore.js +30 -28
  13. package/build/cjs/hooks/useFileUploadStore.js.map +1 -1
  14. package/build/cjs/package.json +1 -1
  15. package/build/docs/components/atoms/SubmitButton.md +1 -0
  16. package/build/docs/components/organisms/PromptInput.md +17 -16
  17. package/build/esm/components/atoms/SubmitButton/SubmitButton.d.ts +5 -1
  18. package/build/esm/components/atoms/SubmitButton/SubmitButton.js +7 -4
  19. package/build/esm/components/atoms/SubmitButton/SubmitButton.js.map +1 -1
  20. package/build/esm/components/organisms/PromptInput/PromptInput.js +1 -2
  21. package/build/esm/components/organisms/PromptInput/PromptInput.js.map +1 -1
  22. package/build/esm/components/organisms/PromptInput/PromptInputFull.js +3 -3
  23. package/build/esm/components/organisms/PromptInput/PromptInputFull.js.map +1 -1
  24. package/build/esm/components/organisms/PromptInput/PromptInputSimple.js +3 -3
  25. package/build/esm/components/organisms/PromptInput/PromptInputSimple.js.map +1 -1
  26. package/build/esm/components/organisms/PromptInput/types.d.ts +3 -1
  27. package/build/esm/components/organisms/PromptInput/types.js.map +1 -1
  28. package/build/esm/hooks/useFileUploadStore.js +30 -28
  29. package/build/esm/hooks/useFileUploadStore.js.map +1 -1
  30. package/build/esm/package.json +1 -1
  31. package/package.json +1 -1
@@ -18,6 +18,10 @@ export interface SubmitButtonProps {
18
18
  * Button size. Defaults to `m`, or `xl` in mobile mode
19
19
  */
20
20
  size?: ButtonButtonProps['size'];
21
+ /**
22
+ * Force the button into a disabled state
23
+ */
24
+ disabled?: ButtonButtonProps['disabled'];
21
25
  /**
22
26
  * Custom tooltip for enabled state
23
27
  */
@@ -46,4 +50,4 @@ export interface SubmitButtonProps {
46
50
  *
47
51
  * @returns Submit button component
48
52
  */
49
- export declare function SubmitButton({ onClick, state, className, size: sizeProp, tooltipSend, tooltipCancel, cancelableText, qa, }: SubmitButtonProps): import("react/jsx-runtime").JSX.Element;
53
+ export declare function SubmitButton({ onClick, state, className, size: sizeProp, disabled, tooltipSend, tooltipCancel, cancelableText, qa, }: SubmitButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -22,20 +22,23 @@ const b = (0, cn_1.block)('submit-button');
22
22
  *
23
23
  * @returns Submit button component
24
24
  */
25
- function SubmitButton({ onClick, state, className, size: sizeProp, tooltipSend, tooltipCancel, cancelableText, qa, }) {
25
+ function SubmitButton({ onClick, state, className, size: sizeProp, disabled = false, tooltipSend, tooltipCancel, cancelableText, qa, }) {
26
26
  const size = (0, useMobileControlSize_1.useMobileControlSize)(sizeProp, 'm', 'xl');
27
27
  const iconSize = (0, useMobileControlSize_1.getControlIconSize)(size);
28
28
  const isCancelable = state === 'cancelable';
29
29
  const isLoading = state === 'loading';
30
- const isDisabled = state === 'disabled';
30
+ const isDisabled = disabled || state === 'disabled';
31
31
  const handleClick = (0, react_1.useCallback)(async () => {
32
- if (['enabled', 'cancelable'].includes(state)) {
32
+ if (!disabled && ['enabled', 'cancelable'].includes(state)) {
33
33
  return onClick();
34
34
  }
35
35
  return Promise.resolve();
36
- }, [state, onClick]);
36
+ }, [disabled, state, onClick]);
37
37
  // Get tooltip based on state
38
38
  const getTooltipTitle = () => {
39
+ if (disabled) {
40
+ return undefined;
41
+ }
39
42
  switch (state) {
40
43
  case 'enabled':
41
44
  return tooltipSend || (0, i18n_1.i18n)('tooltip-send');
@@ -1 +1 @@
1
- {"version":3,"file":"SubmitButton.js","sourceRoot":"../../../../../src","sources":["components/atoms/SubmitButton/SubmitButton.tsx"],"names":[],"mappings":";;AA+DA,oCAyEC;;AAxID,iCAAkC;AAElC,6CAAsD;AACtD,6CAAgE;AAEhE,iFAA6F;AAC7F,6CAAwC;AACxC,2DAA6C;AAE7C,0CAA4B;AAE5B,8BAA6B;AAE7B,MAAM,CAAC,GAAG,IAAA,UAAK,EAAC,eAAe,CAAC,CAAC;AAuCjC;;;;;;;;;;GAUG;AACH,SAAgB,YAAY,CAAC,EACzB,OAAO,EACP,KAAK,EACL,SAAS,EACT,IAAI,EAAE,QAAQ,EACd,WAAW,EACX,aAAa,EACb,cAAc,EACd,EAAE,GACc;IAChB,MAAM,IAAI,GAAG,IAAA,2CAAoB,EAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,IAAA,yCAAkB,EAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,YAAY,GAAG,KAAK,KAAK,YAAY,CAAC;IAC5C,MAAM,SAAS,GAAG,KAAK,KAAK,SAAS,CAAC;IACtC,MAAM,UAAU,GAAG,KAAK,KAAK,UAAU,CAAC;IACxC,MAAM,WAAW,GAAG,IAAA,mBAAW,EAAC,KAAK,IAAI,EAAE;QACvC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,OAAO,OAAO,EAAE,CAAC;QACrB,CAAC;QAED,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;IAErB,6BAA6B;IAC7B,MAAM,eAAe,GAAG,GAAuB,EAAE;QAC7C,QAAQ,KAAK,EAAE,CAAC;YACZ,KAAK,SAAS;gBACV,OAAO,WAAW,IAAI,IAAA,WAAI,EAAC,cAAc,CAAC,CAAC;YAC/C,KAAK,YAAY;gBACb,OAAO,aAAa,IAAI,IAAA,WAAI,EAAC,gBAAgB,CAAC,CAAC;YACnD,KAAK,UAAU,CAAC;YAChB,KAAK,SAAS;gBACV,OAAO,SAAS,CAAC;YACrB;gBACI,OAAO,SAAS,CAAC;QACzB,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,GAAG,EAAE;QACvB,IAAI,SAAS,EAAE,CAAC;YACZ,OAAO,CACH,gCAAK,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,YACvB,uBAAC,YAAI,IAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,EAAE,IAAI,EAAC,IAAI,GAAG,GACzC,CACT,CAAC;QACN,CAAC;QAED,IAAI,YAAY,EAAE,CAAC;YACf,OAAO,cAAc,CAAC,CAAC,CAAC,CACpB,CAAC,uBAAC,YAAI,IAAY,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,kBAAU,IAAvC,MAAM,CAAqC,EAAE,cAAc,CAAC,CAC1E,CAAC,CAAC,CAAC,CACA,uBAAC,YAAI,IAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,kBAAU,GAAI,CAC7C,CAAC;QACN,CAAC;QAED,OAAO,uBAAC,YAAI,IAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAO,GAAI,CAAC;IACnD,CAAC,CAAC;IAEF,OAAO,CACH,uBAAC,2BAAY,IACT,IAAI,EAAC,QAAQ,EACb,IAAI,EAAE,IAAI,EACV,KAAK,EAAC,OAAO,EACb,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,CAAC,CAAC,EAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAC,EAAE,SAAS,CAAC,EAC7E,EAAE,EAAE,EAAE,EACN,YAAY,EAAE,eAAe,EAAE,gBACnB,KAAK,YAEhB,aAAa,EAAE,GACL,CAClB,CAAC;AACN,CAAC","sourcesContent":["import {useCallback} from 'react';\n\nimport {ArrowUp, CircleStop} from '@gravity-ui/icons';\nimport {ButtonButtonProps, Icon, Spin} from '@gravity-ui/uikit';\n\nimport {getControlIconSize, useMobileControlSize} from '../../../hooks/useMobileControlSize';\nimport {block} from '../../../utils/cn';\nimport {ActionButton} from '../ActionButton';\n\nimport {i18n} from './i18n';\n\nimport './SubmitButton.scss';\n\nconst b = block('submit-button');\n\nexport type SubmitButtonState = 'enabled' | 'disabled' | 'loading' | 'cancelable';\n\nexport interface SubmitButtonProps {\n /**\n * Click handler\n */\n onClick: () => Promise<void>;\n /**\n * Button state\n */\n state: SubmitButtonState;\n /**\n * Additional CSS class\n */\n className?: string;\n /**\n * Button size. Defaults to `m`, or `xl` in mobile mode\n */\n size?: ButtonButtonProps['size'];\n /**\n * Custom tooltip for enabled state\n */\n tooltipSend?: string;\n /**\n * Custom tooltip for cancelable state\n */\n tooltipCancel?: string;\n /**\n * Custom cancelable text (if provided, will be shown in cancelable state)\n */\n cancelableText?: string;\n /**\n * QA/test identifier\n */\n qa?: string;\n}\n\n/**\n * Submit button component with state management through props\n *\n * States:\n * - disabled: disabled button state\n * - enabled: enabled button state\n * - loading: loading state\n * - cancelable: cancellation state (during loading)\n *\n * @returns Submit button component\n */\nexport function SubmitButton({\n onClick,\n state,\n className,\n size: sizeProp,\n tooltipSend,\n tooltipCancel,\n cancelableText,\n qa,\n}: SubmitButtonProps) {\n const size = useMobileControlSize(sizeProp, 'm', 'xl');\n const iconSize = getControlIconSize(size);\n const isCancelable = state === 'cancelable';\n const isLoading = state === 'loading';\n const isDisabled = state === 'disabled';\n const handleClick = useCallback(async () => {\n if (['enabled', 'cancelable'].includes(state)) {\n return onClick();\n }\n\n return Promise.resolve();\n }, [state, onClick]);\n\n // Get tooltip based on state\n const getTooltipTitle = (): string | undefined => {\n switch (state) {\n case 'enabled':\n return tooltipSend || i18n('tooltip-send');\n case 'cancelable':\n return tooltipCancel || i18n('tooltip-cancel');\n case 'disabled':\n case 'loading':\n return undefined;\n default:\n return undefined;\n }\n };\n\n const renderContent = () => {\n if (isLoading) {\n return (\n <div className={b('loader')}>\n <Spin className={b('spinner')} size=\"xs\" />\n </div>\n );\n }\n\n if (isCancelable) {\n return cancelableText ? (\n [<Icon key=\"icon\" size={iconSize} data={CircleStop} />, cancelableText]\n ) : (\n <Icon size={iconSize} data={CircleStop} />\n );\n }\n\n return <Icon size={iconSize} data={ArrowUp} />;\n };\n\n return (\n <ActionButton\n view=\"action\"\n size={size}\n color=\"brand\"\n disabled={isDisabled}\n onClick={handleClick}\n className={b({size, loading: isLoading, cancelable: isCancelable}, className)}\n qa={qa}\n tooltipTitle={getTooltipTitle()}\n data-state={state}\n >\n {renderContent()}\n </ActionButton>\n );\n}\n"]}
1
+ {"version":3,"file":"SubmitButton.js","sourceRoot":"../../../../../src","sources":["components/atoms/SubmitButton/SubmitButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import {useCallback} from 'react';\n\nimport {ArrowUp, CircleStop} from '@gravity-ui/icons';\nimport {ButtonButtonProps, Icon, Spin} from '@gravity-ui/uikit';\n\nimport {getControlIconSize, useMobileControlSize} from '../../../hooks/useMobileControlSize';\nimport {block} from '../../../utils/cn';\nimport {ActionButton} from '../ActionButton';\n\nimport {i18n} from './i18n';\n\nimport './SubmitButton.scss';\n\nconst b = block('submit-button');\n\nexport type SubmitButtonState = 'enabled' | 'disabled' | 'loading' | 'cancelable';\n\nexport interface SubmitButtonProps {\n /**\n * Click handler\n */\n onClick: () => Promise<void>;\n /**\n * Button state\n */\n state: SubmitButtonState;\n /**\n * Additional CSS class\n */\n className?: string;\n /**\n * Button size. Defaults to `m`, or `xl` in mobile mode\n */\n size?: ButtonButtonProps['size'];\n /**\n * Force the button into a disabled state\n */\n disabled?: ButtonButtonProps['disabled'];\n /**\n * Custom tooltip for enabled state\n */\n tooltipSend?: string;\n /**\n * Custom tooltip for cancelable state\n */\n tooltipCancel?: string;\n /**\n * Custom cancelable text (if provided, will be shown in cancelable state)\n */\n cancelableText?: string;\n /**\n * QA/test identifier\n */\n qa?: string;\n}\n\n/**\n * Submit button component with state management through props\n *\n * States:\n * - disabled: disabled button state\n * - enabled: enabled button state\n * - loading: loading state\n * - cancelable: cancellation state (during loading)\n *\n * @returns Submit button component\n */\nexport function SubmitButton({\n onClick,\n state,\n className,\n size: sizeProp,\n disabled = false,\n tooltipSend,\n tooltipCancel,\n cancelableText,\n qa,\n}: SubmitButtonProps) {\n const size = useMobileControlSize(sizeProp, 'm', 'xl');\n const iconSize = getControlIconSize(size);\n const isCancelable = state === 'cancelable';\n const isLoading = state === 'loading';\n const isDisabled = disabled || state === 'disabled';\n const handleClick = useCallback(async () => {\n if (!disabled && ['enabled', 'cancelable'].includes(state)) {\n return onClick();\n }\n\n return Promise.resolve();\n }, [disabled, state, onClick]);\n\n // Get tooltip based on state\n const getTooltipTitle = (): string | undefined => {\n if (disabled) {\n return undefined;\n }\n\n switch (state) {\n case 'enabled':\n return tooltipSend || i18n('tooltip-send');\n case 'cancelable':\n return tooltipCancel || i18n('tooltip-cancel');\n case 'disabled':\n case 'loading':\n return undefined;\n default:\n return undefined;\n }\n };\n\n const renderContent = () => {\n if (isLoading) {\n return (\n <div className={b('loader')}>\n <Spin className={b('spinner')} size=\"xs\" />\n </div>\n );\n }\n\n if (isCancelable) {\n return cancelableText ? (\n [<Icon key=\"icon\" size={iconSize} data={CircleStop} />, cancelableText]\n ) : (\n <Icon size={iconSize} data={CircleStop} />\n );\n }\n\n return <Icon size={iconSize} data={ArrowUp} />;\n };\n\n return (\n <ActionButton\n view=\"action\"\n size={size}\n color=\"brand\"\n disabled={isDisabled}\n onClick={handleClick}\n className={b({size, loading: isLoading, cancelable: isCancelable}, className)}\n qa={qa}\n tooltipTitle={getTooltipTitle()}\n data-state={state}\n >\n {renderContent()}\n </ActionButton>\n );\n}\n"]}
@@ -16,13 +16,12 @@ require("./PromptInput.css");
16
16
  * @returns React component
17
17
  */
18
18
  function PromptInput(props) {
19
- var _a;
20
19
  const { view = 'simple', onSend, onCancel, initialValue, disabled = false, status = 'ready', maxLength, onValueChange, headerProps, bodyProps, footerProps, suggestionsProps, topPanel, bottomPanel, className, qa, } = props;
21
20
  const hookState = (0, usePromptInput_1.usePromptInput)({
22
21
  onSend,
23
22
  onCancel,
24
23
  initialValue,
25
- disabled: disabled || ((_a = footerProps === null || footerProps === void 0 ? void 0 : footerProps.submitButtonProps) === null || _a === void 0 ? void 0 : _a.disabled),
24
+ disabled,
26
25
  status,
27
26
  maxLength,
28
27
  onValueChange,
@@ -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,EAAE,QAAQ,KAAI,MAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,iBAAiB,0CAAE,QAAQ,CAAA;QAC9D,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: disabled || footerProps?.submitButtonProps?.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":";;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"]}
@@ -17,11 +17,11 @@ function PromptInputFull(props) {
17
17
  var _a, _b, _c, _d, _e;
18
18
  const { 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, inputRef, qa: bodyQa, } = bodyProps;
20
+ const { placeholder = 'Plan, code, build and test anything', size: bodySize, minRows = 1, maxRows = 15, autoFocus = false, disabledInput = false, inputRef, 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
- const { value, submitButtonState, handleChange, handleKeyDown, handleSubmit } = hookState;
22
+ const { value, submitButtonState, isInputDisabled, handleChange, handleKeyDown, handleSubmit } = hookState;
23
23
  const shouldShowHeader = topContent || contextItems.length > 0 || showContextIndicator;
24
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, 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 })] }));
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 })] }));
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 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, handleChange, handleKeyDown, handleSubmit} = 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 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 {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"]}
@@ -16,10 +16,10 @@ const b = (0, cn_1.block)('prompt-input');
16
16
  function PromptInputSimple(props) {
17
17
  var _a, _b, _c, _d, _e;
18
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, inputRef, qa: bodyQa, } = bodyProps;
19
+ const { placeholder = 'Plan, code, build and test anything', size: bodySize, minRows = 1, maxRows = 15, autoFocus = false, disabledInput = false, inputRef, 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
- const { value, submitButtonState, handleChange, handleKeyDown, handleSubmit } = hookState;
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, 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.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 })] }) }));
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,8CA4EC;;AA5GD,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,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,YAAY,EAAE,aAAa,EAAE,YAAY,EAAC,GAAG,SAAS,CAAC;IACxF,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,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 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, handleChange, handleKeyDown, handleSubmit} = 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 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":";;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"]}
@@ -58,6 +58,8 @@ export type PromptInputBodyConfig = {
58
58
  maxRows?: number;
59
59
  /** Auto focus textarea on mount */
60
60
  autoFocus?: boolean;
61
+ /** Disabled state for textarea */
62
+ disabledInput?: boolean;
61
63
  /**
62
64
  * Auto focus textarea when a new chat is opened via the plus icon.
63
65
  * Only applies inside ChatContainer. Defaults to false.
@@ -82,7 +84,7 @@ export type PromptInputFooterConfig = {
82
84
  /** Size of footer action buttons */
83
85
  buttonSize?: ButtonButtonProps['size'];
84
86
  /** Props for the submit button. State, click handling, and size are managed by PromptInput. */
85
- submitButtonProps?: Omit<SubmitButtonProps, 'state' | 'onClick' | 'size'> & Pick<ButtonButtonProps, 'disabled'>;
87
+ submitButtonProps?: Omit<SubmitButtonProps, 'state' | 'onClick' | 'size'>;
86
88
  /** Custom content for footer area (SubmitButton will still be shown) */
87
89
  bottomContent?: ReactNode;
88
90
  /** Show settings icon in footer */
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/types.ts"],"names":[],"mappings":"","sourcesContent":["import {ReactNode, type Ref} from 'react';\n\nimport type {ButtonButtonProps, TextAreaProps} from '@gravity-ui/uikit';\n\nimport type {SuggestionClickHandler, SuggestionsItem} from '../../../types/common';\nimport type {SubmitButtonProps} from '../../atoms/SubmitButton';\nimport {PromptInputHeaderProps} from '../../molecules/PromptInputHeader';\nimport type {SuggestionsProps} from '../../molecules/Suggestions';\n\n/**\n * Props for a panel (top or bottom)\n */\nexport type PromptInputPanelConfig = {\n /** Is panel open */\n isOpen: boolean;\n /** Panel content */\n children?: ReactNode;\n};\n\n/**\n * Props for the header section of PromptInput.\n * Custom content (`topContent`) and default header props are mutually exclusive:\n * `topContent` replaces the default header entirely.\n */\nexport type PromptInputHeaderConfig = {\n /** QA/test identifier for header wrapper */\n qa?: string;\n} & (\n | {\n /** Custom content for header area (replaces the default header) */\n topContent?: ReactNode;\n /** Not allowed together with custom content */\n contextItems?: never;\n /** Not allowed together with custom content */\n showContextIndicator?: never;\n /** Not allowed together with custom content */\n contextIndicatorProps?: never;\n }\n | {\n /** Not allowed together with default header props */\n topContent?: never;\n /** Array of context items to display on the left */\n contextItems?: PromptInputHeaderProps['contextItems'];\n /** Show context indicator in header */\n showContextIndicator?: boolean;\n /** Props for context indicator */\n contextIndicatorProps?: PromptInputHeaderProps['contextIndicatorProps'];\n }\n);\n\n/**\n * Props for the body/textarea section of PromptInput\n */\nexport type PromptInputBodyConfig = {\n /** QA/test identifier for body wrapper */\n qa?: string;\n /** Ref to the textarea input */\n inputRef?: Ref<HTMLTextAreaElement>;\n /** Placeholder text for textarea */\n placeholder?: string;\n /** Size of the textarea. Defaults to `l`, or `xl` in mobile mode */\n size?: TextAreaProps['size'];\n /** Minimum number of textarea rows */\n minRows?: number;\n /** Maximum number of textarea rows */\n maxRows?: number;\n /** Auto focus textarea on mount */\n autoFocus?: boolean;\n /**\n * Auto focus textarea when a new chat is opened via the plus icon.\n * Only applies inside ChatContainer. Defaults to false.\n */\n autoFocusOnNewChat?: boolean;\n /**\n * Auto focus textarea when a chat is selected from history.\n * Only applies inside ChatContainer. Defaults to false.\n */\n autoFocusOnChatSelect?: boolean;\n};\n\n/**\n * Props for the footer section of PromptInput\n */\nexport type PromptInputFooterConfig = {\n /** QA/test identifier for footer wrapper */\n qa?: string;\n /** Additional CSS class for the footer wrapper */\n className?: string;\n /** Additional CSS class for the custom content wrapper */\n contentClassName?: string;\n /** Size of footer action buttons */\n buttonSize?: ButtonButtonProps['size'];\n /** Props for the submit button. State, click handling, and size are managed by PromptInput. */\n submitButtonProps?: Omit<SubmitButtonProps, 'state' | 'onClick' | 'size'> &\n Pick<ButtonButtonProps, 'disabled'>;\n /** Custom content for footer area (SubmitButton will still be shown) */\n bottomContent?: ReactNode;\n /** Show settings icon in footer */\n showSettings?: boolean;\n /** Settings icon click handler */\n onSettingsClick?: () => void;\n /** Show attachment icon in footer */\n showAttachment?: boolean;\n /** Attachment icon click handler */\n onAttachmentClick?: () => void;\n /**\n * Replaces the built-in attachment icon button with a custom node (e.g. AttachmentPicker).\n * When set, `showAttachment` and `onAttachmentClick` are ignored.\n */\n attachmentContent?: ReactNode;\n /** Show microphone icon in footer */\n showMicrophone?: boolean;\n /** Microphone icon click handler */\n onMicrophoneClick?: () => void;\n /** Custom tooltip for submit button in enabled state */\n submitButtonTooltipSend?: string;\n /** Custom tooltip for submit button in cancelable state */\n submitButtonTooltipCancel?: string;\n /** Custom cancelable text (if provided, will be shown in cancelable state) */\n submitButtonCancelableText?: string;\n /** QA/test identifier for submit button */\n submitButtonQa?: string;\n};\n\n/**\n * Props for the suggestions section of PromptInput\n */\nexport type PromptInputSuggestionsConfig = {\n /** Submit suggestions array */\n suggestions?: SuggestionsItem[];\n /** Show submit suggestions */\n showSuggestions?: boolean;\n /** Title for the suggestions section - can be string or custom React element */\n suggestTitle?: string | ReactNode;\n /** Layout orientation for suggestions: 'grid' for horizontal, 'list' for vertical */\n suggestionsLayout?: SuggestionsProps['layout'];\n /** Text alignment inside suggestion buttons */\n suggestionsTextAlign?: SuggestionsProps['textAlign'];\n /** Callback when suggestion is clicked */\n onSuggestionClick?: SuggestionClickHandler;\n};\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/types.ts"],"names":[],"mappings":"","sourcesContent":["import {ReactNode, type Ref} from 'react';\n\nimport type {ButtonButtonProps, TextAreaProps} from '@gravity-ui/uikit';\n\nimport type {SuggestionClickHandler, SuggestionsItem} from '../../../types/common';\nimport type {SubmitButtonProps} from '../../atoms/SubmitButton';\nimport {PromptInputHeaderProps} from '../../molecules/PromptInputHeader';\nimport type {SuggestionsProps} from '../../molecules/Suggestions';\n\n/**\n * Props for a panel (top or bottom)\n */\nexport type PromptInputPanelConfig = {\n /** Is panel open */\n isOpen: boolean;\n /** Panel content */\n children?: ReactNode;\n};\n\n/**\n * Props for the header section of PromptInput.\n * Custom content (`topContent`) and default header props are mutually exclusive:\n * `topContent` replaces the default header entirely.\n */\nexport type PromptInputHeaderConfig = {\n /** QA/test identifier for header wrapper */\n qa?: string;\n} & (\n | {\n /** Custom content for header area (replaces the default header) */\n topContent?: ReactNode;\n /** Not allowed together with custom content */\n contextItems?: never;\n /** Not allowed together with custom content */\n showContextIndicator?: never;\n /** Not allowed together with custom content */\n contextIndicatorProps?: never;\n }\n | {\n /** Not allowed together with default header props */\n topContent?: never;\n /** Array of context items to display on the left */\n contextItems?: PromptInputHeaderProps['contextItems'];\n /** Show context indicator in header */\n showContextIndicator?: boolean;\n /** Props for context indicator */\n contextIndicatorProps?: PromptInputHeaderProps['contextIndicatorProps'];\n }\n);\n\n/**\n * Props for the body/textarea section of PromptInput\n */\nexport type PromptInputBodyConfig = {\n /** QA/test identifier for body wrapper */\n qa?: string;\n /** Ref to the textarea input */\n inputRef?: Ref<HTMLTextAreaElement>;\n /** Placeholder text for textarea */\n placeholder?: string;\n /** Size of the textarea. Defaults to `l`, or `xl` in mobile mode */\n size?: TextAreaProps['size'];\n /** Minimum number of textarea rows */\n minRows?: number;\n /** Maximum number of textarea rows */\n maxRows?: number;\n /** Auto focus textarea on mount */\n autoFocus?: boolean;\n /** Disabled state for textarea */\n disabledInput?: boolean;\n /**\n * Auto focus textarea when a new chat is opened via the plus icon.\n * Only applies inside ChatContainer. Defaults to false.\n */\n autoFocusOnNewChat?: boolean;\n /**\n * Auto focus textarea when a chat is selected from history.\n * Only applies inside ChatContainer. Defaults to false.\n */\n autoFocusOnChatSelect?: boolean;\n};\n\n/**\n * Props for the footer section of PromptInput\n */\nexport type PromptInputFooterConfig = {\n /** QA/test identifier for footer wrapper */\n qa?: string;\n /** Additional CSS class for the footer wrapper */\n className?: string;\n /** Additional CSS class for the custom content wrapper */\n contentClassName?: string;\n /** Size of footer action buttons */\n buttonSize?: ButtonButtonProps['size'];\n /** Props for the submit button. State, click handling, and size are managed by PromptInput. */\n submitButtonProps?: Omit<SubmitButtonProps, 'state' | 'onClick' | 'size'>;\n /** Custom content for footer area (SubmitButton will still be shown) */\n bottomContent?: ReactNode;\n /** Show settings icon in footer */\n showSettings?: boolean;\n /** Settings icon click handler */\n onSettingsClick?: () => void;\n /** Show attachment icon in footer */\n showAttachment?: boolean;\n /** Attachment icon click handler */\n onAttachmentClick?: () => void;\n /**\n * Replaces the built-in attachment icon button with a custom node (e.g. AttachmentPicker).\n * When set, `showAttachment` and `onAttachmentClick` are ignored.\n */\n attachmentContent?: ReactNode;\n /** Show microphone icon in footer */\n showMicrophone?: boolean;\n /** Microphone icon click handler */\n onMicrophoneClick?: () => void;\n /** Custom tooltip for submit button in enabled state */\n submitButtonTooltipSend?: string;\n /** Custom tooltip for submit button in cancelable state */\n submitButtonTooltipCancel?: string;\n /** Custom cancelable text (if provided, will be shown in cancelable state) */\n submitButtonCancelableText?: string;\n /** QA/test identifier for submit button */\n submitButtonQa?: string;\n};\n\n/**\n * Props for the suggestions section of PromptInput\n */\nexport type PromptInputSuggestionsConfig = {\n /** Submit suggestions array */\n suggestions?: SuggestionsItem[];\n /** Show submit suggestions */\n showSuggestions?: boolean;\n /** Title for the suggestions section - can be string or custom React element */\n suggestTitle?: string | ReactNode;\n /** Layout orientation for suggestions: 'grid' for horizontal, 'list' for vertical */\n suggestionsLayout?: SuggestionsProps['layout'];\n /** Text alignment inside suggestion buttons */\n suggestionsTextAlign?: SuggestionsProps['textAlign'];\n /** Callback when suggestion is clicked */\n onSuggestionClick?: SuggestionClickHandler;\n};\n"]}
@@ -2,6 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useFileUploadStore = useFileUploadStore;
4
4
  const react_1 = require("react");
5
+ function createFileId({ sequence }) {
6
+ return `file-${sequence}`;
7
+ }
5
8
  /**
6
9
  * State machine for managing the file upload lifecycle.
7
10
  * The consumer provides an `upload` function — this hook never calls any API directly.
@@ -9,52 +12,51 @@ const react_1 = require("react");
9
12
  function useFileUploadStore(options) {
10
13
  const optionsRef = (0, react_1.useRef)(options);
11
14
  optionsRef.current = options;
15
+ // `entries` is stored in state so that changes trigger a re-render.
16
+ // `entriesRef` stores the latest value synchronously so that multiple calls before the next
17
+ // render correctly account for already added files and respect `maxFiles`.
12
18
  const [entries, setEntries] = (0, react_1.useState)([]);
13
- const idCounterRef = (0, react_1.useRef)(0);
14
- const nextId = (0, react_1.useCallback)(() => {
15
- idCounterRef.current += 1;
16
- return `file-${idCounterRef.current}`;
19
+ const entriesRef = (0, react_1.useRef)([]);
20
+ const applyEntriesUpdate = (0, react_1.useCallback)((updater) => {
21
+ const nextEntries = updater(entriesRef.current);
22
+ entriesRef.current = nextEntries;
23
+ setEntries(nextEntries);
17
24
  }, []);
25
+ const idCounterRef = (0, react_1.useRef)(0);
18
26
  const addFiles = (0, react_1.useCallback)((files) => {
19
27
  const { upload: up, withoutApply: wa, onUpload: ou, maxFiles: mf } = optionsRef.current;
20
- const pending = [];
21
- const filesToUpload = [];
22
- setEntries((prev) => {
23
- const remaining = mf === undefined ? files.length : Math.max(0, mf - prev.length);
24
- const sliced = files.slice(0, remaining);
25
- for (const file of sliced) {
26
- const id = nextId();
27
- pending.push({ id, file });
28
- }
29
- return [
30
- ...prev,
31
- ...pending.map(({ id, file }) => ({ status: 'pending', id, file })),
32
- ];
28
+ const remaining = mf === undefined ? files.length : Math.max(0, mf - entriesRef.current.length);
29
+ const filesToUpload = files.slice(0, remaining).map((file) => {
30
+ idCounterRef.current += 1;
31
+ return { id: createFileId({ sequence: idCounterRef.current }), file };
33
32
  });
34
- if (pending.length === 0)
33
+ if (filesToUpload.length === 0)
35
34
  return;
35
+ applyEntriesUpdate((current) => [
36
+ ...current,
37
+ ...filesToUpload.map(({ id, file }) => ({ status: 'pending', id, file })),
38
+ ]);
36
39
  if (wa) {
37
- ou === null || ou === void 0 ? void 0 : ou(pending.map((e) => e.file));
40
+ ou === null || ou === void 0 ? void 0 : ou(filesToUpload.map((entry) => entry.file));
38
41
  return;
39
42
  }
40
- filesToUpload.push(...pending);
41
43
  for (const { id, file } of filesToUpload) {
42
- setEntries((prev) => prev.map((e) => (e.id === id ? { status: 'uploading', id, file } : e)));
44
+ applyEntriesUpdate((current) => current.map((e) => e.id === id ? { status: 'uploading', id, file } : e));
43
45
  up(file)
44
46
  .then((meta) => {
45
- setEntries((prev) => prev.map((e) => e.id === id ? { status: 'done', id, file, meta } : e));
47
+ applyEntriesUpdate((current) => current.map((e) => e.id === id ? { status: 'done', id, file, meta } : e));
46
48
  })
47
49
  .catch((error) => {
48
- setEntries((prev) => prev.map((e) => e.id === id ? { status: 'error', id, file, error } : e));
50
+ applyEntriesUpdate((current) => current.map((e) => e.id === id ? { status: 'error', id, file, error } : e));
49
51
  });
50
52
  }
51
- }, [nextId]);
53
+ }, [applyEntriesUpdate]);
52
54
  const removeFile = (0, react_1.useCallback)((id) => {
53
- setEntries((prev) => prev.filter((e) => e.id !== id));
54
- }, []);
55
+ applyEntriesUpdate((current) => current.filter((entry) => entry.id !== id));
56
+ }, [applyEntriesUpdate]);
55
57
  const reset = (0, react_1.useCallback)(() => {
56
- setEntries([]);
57
- }, []);
58
+ applyEntriesUpdate(() => []);
59
+ }, [applyEntriesUpdate]);
58
60
  const isLoading = entries.some((e) => e.status === 'uploading');
59
61
  const uploadedMetas = entries
60
62
  .filter((e) => e.status === 'done')
@@ -1 +1 @@
1
- {"version":3,"file":"useFileUploadStore.js","sourceRoot":"../../../src","sources":["hooks/useFileUploadStore.ts"],"names":[],"mappings":";;AAuCA,gDAmFC;AA1HD,iCAAoD;AAmCpD;;;GAGG;AACH,SAAgB,kBAAkB,CAC9B,OAAwC;IAExC,MAAM,UAAU,GAAG,IAAA,cAAM,EAAC,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC;IAE7B,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,IAAA,gBAAQ,EAA0B,EAAE,CAAC,CAAC;IACpE,MAAM,YAAY,GAAG,IAAA,cAAM,EAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAA,mBAAW,EAAC,GAAW,EAAE;QACpC,YAAY,CAAC,OAAO,IAAI,CAAC,CAAC;QAC1B,OAAO,QAAQ,YAAY,CAAC,OAAO,EAAE,CAAC;IAC1C,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,QAAQ,GAAG,IAAA,mBAAW,EACxB,CAAC,KAAa,EAAE,EAAE;QACd,MAAM,EAAC,MAAM,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAC,GAAG,UAAU,CAAC,OAAO,CAAC;QAEtF,MAAM,OAAO,GAA+B,EAAE,CAAC;QAC/C,MAAM,aAAa,GAA+B,EAAE,CAAC;QAErD,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE;YAChB,MAAM,SAAS,GAAG,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;YAClF,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;YAEzC,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;gBACxB,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;gBACpB,OAAO,CAAC,IAAI,CAAC,EAAC,EAAE,EAAE,IAAI,EAAC,CAAC,CAAC;YAC7B,CAAC;YAED,OAAO;gBACH,GAAG,IAAI;gBACP,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,EAAC,EAAE,EAAE,IAAI,EAAC,EAAE,EAAE,CAAC,CAAC,EAAC,MAAM,EAAE,SAAkB,EAAE,EAAE,EAAE,IAAI,EAAC,CAAC,CAAC;aAC3E,CAAC;QACN,CAAC,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEjC,IAAI,EAAE,EAAE,CAAC;YACL,EAAE,aAAF,EAAE,uBAAF,EAAE,CAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACjC,OAAO;QACX,CAAC;QAED,aAAa,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;QAE/B,KAAK,MAAM,EAAC,EAAE,EAAE,IAAI,EAAC,IAAI,aAAa,EAAE,CAAC;YACrC,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAChB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,MAAM,EAAE,WAAoB,EAAE,EAAE,EAAE,IAAI,EAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAChF,CAAC;YAEF,EAAE,CAAC,IAAI,CAAC;iBACH,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;gBACX,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAChB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACX,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,MAAM,EAAE,MAAe,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC,CAAC,CAAC,CAC9D,CACJ,CAAC;YACN,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gBACb,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAChB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACX,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,MAAM,EAAE,OAAgB,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAC,CAAC,CAAC,CAAC,CAAC,CAChE,CACJ,CAAC;YACN,CAAC,CAAC,CAAC;QACX,CAAC;IACL,CAAC,EACD,CAAC,MAAM,CAAC,CACX,CAAC;IAEF,MAAM,UAAU,GAAG,IAAA,mBAAW,EAAC,CAAC,EAAU,EAAE,EAAE;QAC1C,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAC1D,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,KAAK,GAAG,IAAA,mBAAW,EAAC,GAAG,EAAE;QAC3B,UAAU,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC;IAChE,MAAM,aAAa,GAAG,OAAO;SACxB,MAAM,CAAC,CAAC,CAAC,EAAyD,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC;SACzF,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAExB,OAAO,EAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAC,CAAC;AAC5E,CAAC","sourcesContent":["import {useCallback, useRef, useState} from 'react';\n\nexport type FileUploadEntry<Meta = {id: string; name: string}> =\n | {status: 'pending'; id: string; file: File}\n | {status: 'uploading'; id: string; file: File}\n | {status: 'done'; id: string; file: File; meta: Meta}\n | {status: 'error'; id: string; file: File; error: unknown};\n\nexport type UseFileUploadStoreOptions<Meta = {id: string; name: string}> = {\n /**\n * Called for each file to perform the actual upload.\n * Should return a promise resolving to file metadata.\n * Not called when `withoutApply` is true.\n */\n upload: (file: File) => Promise<Meta>;\n /** Maximum number of files allowed */\n maxFiles?: number;\n /**\n * When true, files are queued without starting the upload.\n * `onUpload` is called instead so the consumer can drive the upload externally.\n */\n withoutApply?: boolean;\n /** Called with newly added files when `withoutApply` is true */\n onUpload?: (files: File[]) => void;\n};\n\nexport type UseFileUploadStoreReturn<Meta = {id: string; name: string}> = {\n entries: FileUploadEntry<Meta>[];\n isLoading: boolean;\n addFiles: (files: File[]) => void;\n removeFile: (id: string) => void;\n reset: () => void;\n uploadedMetas: Meta[];\n};\n\n/**\n * State machine for managing the file upload lifecycle.\n * The consumer provides an `upload` function — this hook never calls any API directly.\n */\nexport function useFileUploadStore<Meta = {id: string; name: string}>(\n options: UseFileUploadStoreOptions<Meta>,\n): UseFileUploadStoreReturn<Meta> {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const [entries, setEntries] = useState<FileUploadEntry<Meta>[]>([]);\n const idCounterRef = useRef(0);\n const nextId = useCallback((): string => {\n idCounterRef.current += 1;\n return `file-${idCounterRef.current}`;\n }, []);\n\n const addFiles = useCallback(\n (files: File[]) => {\n const {upload: up, withoutApply: wa, onUpload: ou, maxFiles: mf} = optionsRef.current;\n\n const pending: {id: string; file: File}[] = [];\n const filesToUpload: {id: string; file: File}[] = [];\n\n setEntries((prev) => {\n const remaining = mf === undefined ? files.length : Math.max(0, mf - prev.length);\n const sliced = files.slice(0, remaining);\n\n for (const file of sliced) {\n const id = nextId();\n pending.push({id, file});\n }\n\n return [\n ...prev,\n ...pending.map(({id, file}) => ({status: 'pending' as const, id, file})),\n ];\n });\n\n if (pending.length === 0) return;\n\n if (wa) {\n ou?.(pending.map((e) => e.file));\n return;\n }\n\n filesToUpload.push(...pending);\n\n for (const {id, file} of filesToUpload) {\n setEntries((prev) =>\n prev.map((e) => (e.id === id ? {status: 'uploading' as const, id, file} : e)),\n );\n\n up(file)\n .then((meta) => {\n setEntries((prev) =>\n prev.map((e) =>\n e.id === id ? {status: 'done' as const, id, file, meta} : e,\n ),\n );\n })\n .catch((error) => {\n setEntries((prev) =>\n prev.map((e) =>\n e.id === id ? {status: 'error' as const, id, file, error} : e,\n ),\n );\n });\n }\n },\n [nextId],\n );\n\n const removeFile = useCallback((id: string) => {\n setEntries((prev) => prev.filter((e) => e.id !== id));\n }, []);\n\n const reset = useCallback(() => {\n setEntries([]);\n }, []);\n\n const isLoading = entries.some((e) => e.status === 'uploading');\n const uploadedMetas = entries\n .filter((e): e is Extract<FileUploadEntry<Meta>, {status: 'done'}> => e.status === 'done')\n .map((e) => e.meta);\n\n return {entries, isLoading, addFiles, removeFile, reset, uploadedMetas};\n}\n"]}
1
+ {"version":3,"file":"useFileUploadStore.js","sourceRoot":"../../../src","sources":["hooks/useFileUploadStore.ts"],"names":[],"mappings":"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","sourcesContent":["import {useCallback, useRef, useState} from 'react';\n\nexport type FileUploadEntry<Meta = {id: string; name: string}> =\n | {status: 'pending'; id: string; file: File}\n | {status: 'uploading'; id: string; file: File}\n | {status: 'done'; id: string; file: File; meta: Meta}\n | {status: 'error'; id: string; file: File; error: unknown};\n\nexport type UseFileUploadStoreOptions<Meta = {id: string; name: string}> = {\n /**\n * Called for each file to perform the actual upload.\n * Should return a promise resolving to file metadata.\n * Not called when `withoutApply` is true.\n */\n upload: (file: File) => Promise<Meta>;\n /** Maximum number of files allowed */\n maxFiles?: number;\n /**\n * When true, files are queued without starting the upload.\n * `onUpload` is called instead so the consumer can drive the upload externally.\n */\n withoutApply?: boolean;\n /** Called with newly added files when `withoutApply` is true */\n onUpload?: (files: File[]) => void;\n};\n\nexport type UseFileUploadStoreReturn<Meta = {id: string; name: string}> = {\n entries: FileUploadEntry<Meta>[];\n isLoading: boolean;\n addFiles: (files: File[]) => void;\n removeFile: (id: string) => void;\n reset: () => void;\n uploadedMetas: Meta[];\n};\n\nfunction createFileId({sequence}: {sequence: number}): string {\n return `file-${sequence}`;\n}\n\n/**\n * State machine for managing the file upload lifecycle.\n * The consumer provides an `upload` function — this hook never calls any API directly.\n */\nexport function useFileUploadStore<Meta = {id: string; name: string}>(\n options: UseFileUploadStoreOptions<Meta>,\n): UseFileUploadStoreReturn<Meta> {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n // `entries` is stored in state so that changes trigger a re-render.\n // `entriesRef` stores the latest value synchronously so that multiple calls before the next\n // render correctly account for already added files and respect `maxFiles`.\n const [entries, setEntries] = useState<FileUploadEntry<Meta>[]>([]);\n const entriesRef = useRef<FileUploadEntry<Meta>[]>([]);\n const applyEntriesUpdate = useCallback(\n (updater: (current: FileUploadEntry<Meta>[]) => FileUploadEntry<Meta>[]) => {\n const nextEntries = updater(entriesRef.current);\n entriesRef.current = nextEntries;\n setEntries(nextEntries);\n },\n [],\n );\n const idCounterRef = useRef(0);\n\n const addFiles = useCallback(\n (files: File[]) => {\n const {upload: up, withoutApply: wa, onUpload: ou, maxFiles: mf} = optionsRef.current;\n const remaining =\n mf === undefined ? files.length : Math.max(0, mf - entriesRef.current.length);\n const filesToUpload = files.slice(0, remaining).map((file) => {\n idCounterRef.current += 1;\n\n return {id: createFileId({sequence: idCounterRef.current}), file};\n });\n\n if (filesToUpload.length === 0) return;\n\n applyEntriesUpdate((current) => [\n ...current,\n ...filesToUpload.map(({id, file}) => ({status: 'pending' as const, id, file})),\n ]);\n\n if (wa) {\n ou?.(filesToUpload.map((entry) => entry.file));\n return;\n }\n\n for (const {id, file} of filesToUpload) {\n applyEntriesUpdate((current) =>\n current.map((e) =>\n e.id === id ? {status: 'uploading' as const, id, file} : e,\n ),\n );\n\n up(file)\n .then((meta) => {\n applyEntriesUpdate((current) =>\n current.map((e) =>\n e.id === id ? {status: 'done' as const, id, file, meta} : e,\n ),\n );\n })\n .catch((error) => {\n applyEntriesUpdate((current) =>\n current.map((e) =>\n e.id === id ? {status: 'error' as const, id, file, error} : e,\n ),\n );\n });\n }\n },\n [applyEntriesUpdate],\n );\n\n const removeFile = useCallback(\n (id: string) => {\n applyEntriesUpdate((current) => current.filter((entry) => entry.id !== id));\n },\n [applyEntriesUpdate],\n );\n\n const reset = useCallback(() => {\n applyEntriesUpdate(() => []);\n }, [applyEntriesUpdate]);\n\n const isLoading = entries.some((e) => e.status === 'uploading');\n const uploadedMetas = entries\n .filter((e): e is Extract<FileUploadEntry<Meta>, {status: 'done'}> => e.status === 'done')\n .map((e) => e.meta);\n\n return {entries, isLoading, addFiles, removeFile, reset, uploadedMetas};\n}\n"]}
@@ -1 +1 @@
1
- {"version":"2.21.4-beta.de9a973e6444f67d992e855b9b83d5a97fec4fd7.0","type":"commonjs","sideEffects":["*.css","*.scss"]}
1
+ {"version":"2.22.0","type":"commonjs","sideEffects":["*.css","*.scss"]}
@@ -41,6 +41,7 @@ const [state, setState] = useState<'enabled' | 'disabled' | 'loading' | 'cancela
41
41
  | `state` | `'enabled' \| 'disabled' \| 'loading' \| 'cancelable'` | Yes | - | Button state |
42
42
  | `className` | `string` | No | - | Additional CSS class |
43
43
  | `size` | `ButtonButtonProps['size']` | No | `'m'` desktop, `'xl'` mobile | Button size; icon size follows (`16`/`20`) |
44
+ | `disabled` | `boolean` | No | `false` | Force the button into a disabled state |
44
45
  | `qa` | `string` | No | - | QA/test identifier |
45
46
 
46
47
  ## States
@@ -157,27 +157,28 @@ import {PromptInput} from '@gravity-ui/aikit';
157
157
  | `minRows` | `number` | - | `1` | Minimum number of textarea rows |
158
158
  | `maxRows` | `number` | - | `15` | Maximum number of textarea rows |
159
159
  | `autoFocus` | `boolean` | - | `false` | Auto focus textarea on mount |
160
+ | `disabledInput` | `boolean` | - | `false` | Disabled state for textarea |
160
161
  | `autoFocusOnNewChat` | `boolean` | - | `false` | Auto focus textarea when a new chat is open |
161
162
  | `autoFocusOnChatSelect` | `boolean` | - | `false` | Auto focus textarea when a chat is selected |
162
163
 
163
164
  ### PromptInputFooterConfig
164
165
 
165
- | Prop | Type | Required | Default | Description |
166
- | --------------------------- | ----------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------- | ----------------------------------------------------- |
167
- | `bottomContent` | `ReactNode` | - | - | Custom content for footer area |
168
- | `className` | `string` | - | - | Additional CSS class for the footer wrapper |
169
- | `contentClassName` | `string` | - | - | Additional CSS class for the custom content wrapper |
170
- | `buttonSize` | `ButtonButtonProps['size']` | - | `'m'` in full view, `'l'` in simple view, `'xl'` in mobile mode | Size of footer action buttons |
171
- | `submitButtonProps` | `Omit<SubmitButtonProps, 'state' \| 'onClick' \| 'size'> & Pick<ButtonButtonProps, 'disabled'>` | - | - | Submit button customization, including disabled state |
172
- | `showSettings` | `boolean` | - | `false` | Show settings icon |
173
- | `onSettingsClick` | `() => void` | - | - | Settings icon click handler |
174
- | `showAttachment` | `boolean` | - | `false` | Show attachment icon |
175
- | `onAttachmentClick` | `() => void` | - | - | Attachment icon click handler |
176
- | `showMicrophone` | `boolean` | - | `false` | Show microphone icon |
177
- | `onMicrophoneClick` | `() => void` | - | - | Microphone icon click handler |
178
- | `submitButtonTooltipSend` | `string` | - | - | Custom tooltip for submit button in enabled state |
179
- | `submitButtonTooltipCancel` | `string` | - | - | Custom tooltip for submit button in cancelable state |
180
- | `submitButtonQa` | `string` | - | `'submit-button-full'` or `'submit-button-simple'` | QA/test identifier for submit button |
166
+ | Prop | Type | Required | Default | Description |
167
+ | --------------------------- | --------------------------------------------------------- | -------- | --------------------------------------------------------------- | ----------------------------------------------------- |
168
+ | `bottomContent` | `ReactNode` | - | - | Custom content for footer area |
169
+ | `className` | `string` | - | - | Additional CSS class for the footer wrapper |
170
+ | `contentClassName` | `string` | - | - | Additional CSS class for the custom content wrapper |
171
+ | `buttonSize` | `ButtonButtonProps['size']` | - | `'m'` in full view, `'l'` in simple view, `'xl'` in mobile mode | Size of footer action buttons |
172
+ | `submitButtonProps` | `Omit<SubmitButtonProps, 'state' \| 'onClick' \| 'size'>` | - | - | Submit button customization, including disabled state |
173
+ | `showSettings` | `boolean` | - | `false` | Show settings icon |
174
+ | `onSettingsClick` | `() => void` | - | - | Settings icon click handler |
175
+ | `showAttachment` | `boolean` | - | `false` | Show attachment icon |
176
+ | `onAttachmentClick` | `() => void` | - | - | Attachment icon click handler |
177
+ | `showMicrophone` | `boolean` | - | `false` | Show microphone icon |
178
+ | `onMicrophoneClick` | `() => void` | - | - | Microphone icon click handler |
179
+ | `submitButtonTooltipSend` | `string` | - | - | Custom tooltip for submit button in enabled state |
180
+ | `submitButtonTooltipCancel` | `string` | - | - | Custom tooltip for submit button in cancelable state |
181
+ | `submitButtonQa` | `string` | - | `'submit-button-full'` or `'submit-button-simple'` | QA/test identifier for submit button |
181
182
 
182
183
  ### PromptInputSuggestionsConfig
183
184
 
@@ -18,6 +18,10 @@ export interface SubmitButtonProps {
18
18
  * Button size. Defaults to `m`, or `xl` in mobile mode
19
19
  */
20
20
  size?: ButtonButtonProps['size'];
21
+ /**
22
+ * Force the button into a disabled state
23
+ */
24
+ disabled?: ButtonButtonProps['disabled'];
21
25
  /**
22
26
  * Custom tooltip for enabled state
23
27
  */
@@ -46,4 +50,4 @@ export interface SubmitButtonProps {
46
50
  *
47
51
  * @returns Submit button component
48
52
  */
49
- export declare function SubmitButton({ onClick, state, className, size: sizeProp, tooltipSend, tooltipCancel, cancelableText, qa, }: SubmitButtonProps): import("react/jsx-runtime").JSX.Element;
53
+ export declare function SubmitButton({ onClick, state, className, size: sizeProp, disabled, tooltipSend, tooltipCancel, cancelableText, qa, }: SubmitButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -19,20 +19,23 @@ const b = block('submit-button');
19
19
  *
20
20
  * @returns Submit button component
21
21
  */
22
- export function SubmitButton({ onClick, state, className, size: sizeProp, tooltipSend, tooltipCancel, cancelableText, qa, }) {
22
+ export function SubmitButton({ onClick, state, className, size: sizeProp, disabled = false, tooltipSend, tooltipCancel, cancelableText, qa, }) {
23
23
  const size = useMobileControlSize(sizeProp, 'm', 'xl');
24
24
  const iconSize = getControlIconSize(size);
25
25
  const isCancelable = state === 'cancelable';
26
26
  const isLoading = state === 'loading';
27
- const isDisabled = state === 'disabled';
27
+ const isDisabled = disabled || state === 'disabled';
28
28
  const handleClick = useCallback(async () => {
29
- if (['enabled', 'cancelable'].includes(state)) {
29
+ if (!disabled && ['enabled', 'cancelable'].includes(state)) {
30
30
  return onClick();
31
31
  }
32
32
  return Promise.resolve();
33
- }, [state, onClick]);
33
+ }, [disabled, state, onClick]);
34
34
  // Get tooltip based on state
35
35
  const getTooltipTitle = () => {
36
+ if (disabled) {
37
+ return undefined;
38
+ }
36
39
  switch (state) {
37
40
  case 'enabled':
38
41
  return tooltipSend || i18n('tooltip-send');
@@ -1 +1 @@
1
- {"version":3,"file":"SubmitButton.js","sourceRoot":"../../../../../src","sources":["components/atoms/SubmitButton/SubmitButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import {useCallback} from 'react';\n\nimport {ArrowUp, CircleStop} from '@gravity-ui/icons';\nimport {ButtonButtonProps, Icon, Spin} from '@gravity-ui/uikit';\n\nimport {getControlIconSize, useMobileControlSize} from '../../../hooks/useMobileControlSize';\nimport {block} from '../../../utils/cn';\nimport {ActionButton} from '../ActionButton';\n\nimport {i18n} from './i18n';\n\nimport './SubmitButton.scss';\n\nconst b = block('submit-button');\n\nexport type SubmitButtonState = 'enabled' | 'disabled' | 'loading' | 'cancelable';\n\nexport interface SubmitButtonProps {\n /**\n * Click handler\n */\n onClick: () => Promise<void>;\n /**\n * Button state\n */\n state: SubmitButtonState;\n /**\n * Additional CSS class\n */\n className?: string;\n /**\n * Button size. Defaults to `m`, or `xl` in mobile mode\n */\n size?: ButtonButtonProps['size'];\n /**\n * Custom tooltip for enabled state\n */\n tooltipSend?: string;\n /**\n * Custom tooltip for cancelable state\n */\n tooltipCancel?: string;\n /**\n * Custom cancelable text (if provided, will be shown in cancelable state)\n */\n cancelableText?: string;\n /**\n * QA/test identifier\n */\n qa?: string;\n}\n\n/**\n * Submit button component with state management through props\n *\n * States:\n * - disabled: disabled button state\n * - enabled: enabled button state\n * - loading: loading state\n * - cancelable: cancellation state (during loading)\n *\n * @returns Submit button component\n */\nexport function SubmitButton({\n onClick,\n state,\n className,\n size: sizeProp,\n tooltipSend,\n tooltipCancel,\n cancelableText,\n qa,\n}: SubmitButtonProps) {\n const size = useMobileControlSize(sizeProp, 'm', 'xl');\n const iconSize = getControlIconSize(size);\n const isCancelable = state === 'cancelable';\n const isLoading = state === 'loading';\n const isDisabled = state === 'disabled';\n const handleClick = useCallback(async () => {\n if (['enabled', 'cancelable'].includes(state)) {\n return onClick();\n }\n\n return Promise.resolve();\n }, [state, onClick]);\n\n // Get tooltip based on state\n const getTooltipTitle = (): string | undefined => {\n switch (state) {\n case 'enabled':\n return tooltipSend || i18n('tooltip-send');\n case 'cancelable':\n return tooltipCancel || i18n('tooltip-cancel');\n case 'disabled':\n case 'loading':\n return undefined;\n default:\n return undefined;\n }\n };\n\n const renderContent = () => {\n if (isLoading) {\n return (\n <div className={b('loader')}>\n <Spin className={b('spinner')} size=\"xs\" />\n </div>\n );\n }\n\n if (isCancelable) {\n return cancelableText ? (\n [<Icon key=\"icon\" size={iconSize} data={CircleStop} />, cancelableText]\n ) : (\n <Icon size={iconSize} data={CircleStop} />\n );\n }\n\n return <Icon size={iconSize} data={ArrowUp} />;\n };\n\n return (\n <ActionButton\n view=\"action\"\n size={size}\n color=\"brand\"\n disabled={isDisabled}\n onClick={handleClick}\n className={b({size, loading: isLoading, cancelable: isCancelable}, className)}\n qa={qa}\n tooltipTitle={getTooltipTitle()}\n data-state={state}\n >\n {renderContent()}\n </ActionButton>\n );\n}\n"]}
1
+ {"version":3,"file":"SubmitButton.js","sourceRoot":"../../../../../src","sources":["components/atoms/SubmitButton/SubmitButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import {useCallback} from 'react';\n\nimport {ArrowUp, CircleStop} from '@gravity-ui/icons';\nimport {ButtonButtonProps, Icon, Spin} from '@gravity-ui/uikit';\n\nimport {getControlIconSize, useMobileControlSize} from '../../../hooks/useMobileControlSize';\nimport {block} from '../../../utils/cn';\nimport {ActionButton} from '../ActionButton';\n\nimport {i18n} from './i18n';\n\nimport './SubmitButton.scss';\n\nconst b = block('submit-button');\n\nexport type SubmitButtonState = 'enabled' | 'disabled' | 'loading' | 'cancelable';\n\nexport interface SubmitButtonProps {\n /**\n * Click handler\n */\n onClick: () => Promise<void>;\n /**\n * Button state\n */\n state: SubmitButtonState;\n /**\n * Additional CSS class\n */\n className?: string;\n /**\n * Button size. Defaults to `m`, or `xl` in mobile mode\n */\n size?: ButtonButtonProps['size'];\n /**\n * Force the button into a disabled state\n */\n disabled?: ButtonButtonProps['disabled'];\n /**\n * Custom tooltip for enabled state\n */\n tooltipSend?: string;\n /**\n * Custom tooltip for cancelable state\n */\n tooltipCancel?: string;\n /**\n * Custom cancelable text (if provided, will be shown in cancelable state)\n */\n cancelableText?: string;\n /**\n * QA/test identifier\n */\n qa?: string;\n}\n\n/**\n * Submit button component with state management through props\n *\n * States:\n * - disabled: disabled button state\n * - enabled: enabled button state\n * - loading: loading state\n * - cancelable: cancellation state (during loading)\n *\n * @returns Submit button component\n */\nexport function SubmitButton({\n onClick,\n state,\n className,\n size: sizeProp,\n disabled = false,\n tooltipSend,\n tooltipCancel,\n cancelableText,\n qa,\n}: SubmitButtonProps) {\n const size = useMobileControlSize(sizeProp, 'm', 'xl');\n const iconSize = getControlIconSize(size);\n const isCancelable = state === 'cancelable';\n const isLoading = state === 'loading';\n const isDisabled = disabled || state === 'disabled';\n const handleClick = useCallback(async () => {\n if (!disabled && ['enabled', 'cancelable'].includes(state)) {\n return onClick();\n }\n\n return Promise.resolve();\n }, [disabled, state, onClick]);\n\n // Get tooltip based on state\n const getTooltipTitle = (): string | undefined => {\n if (disabled) {\n return undefined;\n }\n\n switch (state) {\n case 'enabled':\n return tooltipSend || i18n('tooltip-send');\n case 'cancelable':\n return tooltipCancel || i18n('tooltip-cancel');\n case 'disabled':\n case 'loading':\n return undefined;\n default:\n return undefined;\n }\n };\n\n const renderContent = () => {\n if (isLoading) {\n return (\n <div className={b('loader')}>\n <Spin className={b('spinner')} size=\"xs\" />\n </div>\n );\n }\n\n if (isCancelable) {\n return cancelableText ? (\n [<Icon key=\"icon\" size={iconSize} data={CircleStop} />, cancelableText]\n ) : (\n <Icon size={iconSize} data={CircleStop} />\n );\n }\n\n return <Icon size={iconSize} data={ArrowUp} />;\n };\n\n return (\n <ActionButton\n view=\"action\"\n size={size}\n color=\"brand\"\n disabled={isDisabled}\n onClick={handleClick}\n className={b({size, loading: isLoading, cancelable: isCancelable}, className)}\n qa={qa}\n tooltipTitle={getTooltipTitle()}\n data-state={state}\n >\n {renderContent()}\n </ActionButton>\n );\n}\n"]}
@@ -13,13 +13,12 @@ import "./PromptInput.css";
13
13
  * @returns React component
14
14
  */
15
15
  export function PromptInput(props) {
16
- var _a;
17
16
  const { view = 'simple', onSend, onCancel, initialValue, disabled = false, status = 'ready', maxLength, onValueChange, headerProps, bodyProps, footerProps, suggestionsProps, topPanel, bottomPanel, className, qa, } = props;
18
17
  const hookState = usePromptInput({
19
18
  onSend,
20
19
  onCancel,
21
20
  initialValue,
22
- disabled: disabled || ((_a = footerProps === null || footerProps === void 0 ? void 0 : footerProps.submitButtonProps) === null || _a === void 0 ? void 0 : _a.disabled),
21
+ disabled,
23
22
  status,
24
23
  maxLength,
25
24
  onValueChange,
@@ -1 +1 @@
1
- {"version":3,"file":"PromptInput.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/PromptInput.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAC,eAAe,EAAC,6BAA0B;AAClD,OAAO,EAAC,iBAAiB,EAAC,+BAA4B;AACtD,OAAO,EAAC,qBAAqB,EAAC,mCAAgC;AAC9D,OAAO,EAAC,0BAA0B,EAAC,wCAAqC;AAQxE,OAAO,EAAC,cAAc,EAAC,4BAAyB;AAEhD,2BAA4B;AAwC5B;;;;;;GAMG;AACH,MAAM,UAAU,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,cAAc,CAAC;QAC7B,MAAM;QACN,QAAQ;QACR,YAAY;QACZ,QAAQ,EAAE,QAAQ,KAAI,MAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,iBAAiB,0CAAE,QAAQ,CAAA;QAC9D,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,KAAC,0BAA0B,IAAC,gBAAgB,EAAE,uBAAuB,YACjE,KAAC,qBAAqB,IAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,YAC9D,UAAU,CAAC,CAAC,CAAC,CACV,KAAC,eAAe,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,KAAC,iBAAiB,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: disabled || footerProps?.submitButtonProps?.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":";AAEA,OAAO,EAAC,eAAe,EAAC,6BAA0B;AAClD,OAAO,EAAC,iBAAiB,EAAC,+BAA4B;AACtD,OAAO,EAAC,qBAAqB,EAAC,mCAAgC;AAC9D,OAAO,EAAC,0BAA0B,EAAC,wCAAqC;AAQxE,OAAO,EAAC,cAAc,EAAC,4BAAyB;AAEhD,2BAA4B;AAwC5B;;;;;;GAMG;AACH,MAAM,UAAU,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,cAAc,CAAC;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,KAAC,0BAA0B,IAAC,gBAAgB,EAAE,uBAAuB,YACjE,KAAC,qBAAqB,IAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,YAC9D,UAAU,CAAC,CAAC,CAAC,CACV,KAAC,eAAe,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,KAAC,iBAAiB,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"]}
@@ -14,11 +14,11 @@ export function PromptInputFull(props) {
14
14
  var _a, _b, _c, _d, _e;
15
15
  const { hookState, headerProps = {}, bodyProps = {}, footerProps = {}, className, qa } = props;
16
16
  const { topContent, contextItems = [], showContextIndicator = false, contextIndicatorProps, qa: headerQa, } = headerProps;
17
- const { placeholder = 'Plan, code, build and test anything', size: bodySize, minRows = 1, maxRows = 15, autoFocus = false, inputRef, qa: bodyQa, } = bodyProps;
17
+ const { placeholder = 'Plan, code, build and test anything', size: bodySize, minRows = 1, maxRows = 15, autoFocus = false, disabledInput = false, inputRef, qa: bodyQa, } = bodyProps;
18
18
  const { bottomContent, className: footerClassName, contentClassName, buttonSize, submitButtonProps, showSettings = false, onSettingsClick, attachmentContent, showAttachment, onAttachmentClick, showMicrophone = false, onMicrophoneClick, submitButtonTooltipSend, submitButtonTooltipCancel, submitButtonCancelableText, submitButtonQa, qa: footerQa, } = footerProps;
19
- const { value, submitButtonState, handleChange, handleKeyDown, handleSubmit } = hookState;
19
+ const { value, submitButtonState, isInputDisabled, handleChange, handleKeyDown, handleSubmit } = hookState;
20
20
  const shouldShowHeader = topContent || contextItems.length > 0 || showContextIndicator;
21
21
  return (_jsxs("div", { className: b({ view: 'full' }, className), "data-qa": qa, children: [shouldShowHeader &&
22
- (topContent ? (_jsx(PromptInputHeader, { qa: headerQa, children: topContent })) : (_jsx(PromptInputHeader, { contextItems: contextItems, showContextIndicator: showContextIndicator, contextIndicatorProps: contextIndicatorProps, qa: headerQa }))), _jsx(PromptInputBody, { value: value, placeholder: placeholder, size: bodySize, minRows: minRows, maxRows: maxRows, autoFocus: autoFocus, ref: inputRef, onChange: handleChange, onKeyDown: handleKeyDown, inputClassName: b('textarea'), qa: bodyQa }), _jsx(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 })] }));
22
+ (topContent ? (_jsx(PromptInputHeader, { qa: headerQa, children: topContent })) : (_jsx(PromptInputHeader, { contextItems: contextItems, showContextIndicator: showContextIndicator, contextIndicatorProps: contextIndicatorProps, qa: headerQa }))), _jsx(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 }), _jsx(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 })] }));
23
23
  }
24
24
  //# 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 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, handleChange, handleKeyDown, handleSubmit} = 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 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 {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"]}
@@ -13,10 +13,10 @@ const b = block('prompt-input');
13
13
  export function PromptInputSimple(props) {
14
14
  var _a, _b, _c, _d, _e;
15
15
  const { hookState, bodyProps = {}, footerProps = {}, className, qa } = props;
16
- const { placeholder = 'Plan, code, build and test anything', size: bodySize, minRows = 1, maxRows = 15, autoFocus = false, inputRef, qa: bodyQa, } = bodyProps;
16
+ const { placeholder = 'Plan, code, build and test anything', size: bodySize, minRows = 1, maxRows = 15, autoFocus = false, disabledInput = false, inputRef, qa: bodyQa, } = bodyProps;
17
17
  const { bottomContent, className: footerClassName, contentClassName, buttonSize, submitButtonProps, showAttachment = false, onAttachmentClick, attachmentContent, showMicrophone = false, onMicrophoneClick, submitButtonTooltipSend, submitButtonTooltipCancel, submitButtonCancelableText, submitButtonQa, qa: footerQa, } = footerProps;
18
- const { value, submitButtonState, handleChange, handleKeyDown, handleSubmit } = hookState;
18
+ const { value, submitButtonState, isInputDisabled, handleChange, handleKeyDown, handleSubmit } = hookState;
19
19
  const resolvedButtonSize = useMobileControlSize(buttonSize, 'l', 'xl');
20
- return (_jsx("div", { className: b({ view: 'simple' }, className), "data-qa": qa, children: _jsxs("div", { className: b('content'), children: [_jsx(PromptInputBody, { value: value, placeholder: placeholder, size: bodySize, minRows: minRows, maxRows: maxRows, autoFocus: autoFocus, ref: inputRef, onChange: handleChange, onKeyDown: handleKeyDown, qa: bodyQa }), _jsx(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 })] }) }));
20
+ return (_jsx("div", { className: b({ view: 'simple' }, className), "data-qa": qa, children: _jsxs("div", { className: b('content'), children: [_jsx(PromptInputBody, { value: value, placeholder: placeholder, size: bodySize, minRows: minRows, maxRows: maxRows, autoFocus: autoFocus, disabledInput: isInputDisabled || disabledInput, ref: inputRef, onChange: handleChange, onKeyDown: handleKeyDown, qa: bodyQa }), _jsx(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 })] }) }));
21
21
  }
22
22
  //# sourceMappingURL=PromptInputSimple.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PromptInputSimple.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/PromptInputSimple.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,oBAAoB,EAAC,+CAA4C;AACzE,OAAO,EAAC,KAAK,EAAC,6BAA0B;AACxC,OAAO,EAAC,eAAe,EAAC,iDAAwC;AAChE,OAAO,EAAC,iBAAiB,EAAC,mDAA0C;AAKpE,MAAM,CAAC,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC;AAkBhC;;;;;GAKG;AACH,MAAM,UAAU,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,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,YAAY,EAAE,aAAa,EAAE,YAAY,EAAC,GAAG,SAAS,CAAC;IACxF,MAAM,kBAAkB,GAAG,oBAAoB,CAAC,UAAU,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAEvE,OAAO,CACH,cAAK,SAAS,EAAE,CAAC,CAAC,EAAC,IAAI,EAAE,QAAQ,EAAC,EAAE,SAAS,CAAC,aAAW,EAAE,YACvD,eAAK,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,aACxB,KAAC,eAAe,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,GAAG,EAAE,QAAQ,EACb,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,aAAa,EACxB,EAAE,EAAE,MAAM,GACZ,EACF,KAAC,iBAAiB,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 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, handleChange, handleKeyDown, handleSubmit} = 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 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":";AAAA,OAAO,EAAC,oBAAoB,EAAC,+CAA4C;AACzE,OAAO,EAAC,KAAK,EAAC,6BAA0B;AACxC,OAAO,EAAC,eAAe,EAAC,iDAAwC;AAChE,OAAO,EAAC,iBAAiB,EAAC,mDAA0C;AAKpE,MAAM,CAAC,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC;AAkBhC;;;;;GAKG;AACH,MAAM,UAAU,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,oBAAoB,CAAC,UAAU,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAEvE,OAAO,CACH,cAAK,SAAS,EAAE,CAAC,CAAC,EAAC,IAAI,EAAE,QAAQ,EAAC,EAAE,SAAS,CAAC,aAAW,EAAE,YACvD,eAAK,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,aACxB,KAAC,eAAe,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,KAAC,iBAAiB,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"]}
@@ -58,6 +58,8 @@ export type PromptInputBodyConfig = {
58
58
  maxRows?: number;
59
59
  /** Auto focus textarea on mount */
60
60
  autoFocus?: boolean;
61
+ /** Disabled state for textarea */
62
+ disabledInput?: boolean;
61
63
  /**
62
64
  * Auto focus textarea when a new chat is opened via the plus icon.
63
65
  * Only applies inside ChatContainer. Defaults to false.
@@ -82,7 +84,7 @@ export type PromptInputFooterConfig = {
82
84
  /** Size of footer action buttons */
83
85
  buttonSize?: ButtonButtonProps['size'];
84
86
  /** Props for the submit button. State, click handling, and size are managed by PromptInput. */
85
- submitButtonProps?: Omit<SubmitButtonProps, 'state' | 'onClick' | 'size'> & Pick<ButtonButtonProps, 'disabled'>;
87
+ submitButtonProps?: Omit<SubmitButtonProps, 'state' | 'onClick' | 'size'>;
86
88
  /** Custom content for footer area (SubmitButton will still be shown) */
87
89
  bottomContent?: ReactNode;
88
90
  /** Show settings icon in footer */
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/types.ts"],"names":[],"mappings":"","sourcesContent":["import {ReactNode, type Ref} from 'react';\n\nimport type {ButtonButtonProps, TextAreaProps} from '@gravity-ui/uikit';\n\nimport type {SuggestionClickHandler, SuggestionsItem} from '../../../types/common';\nimport type {SubmitButtonProps} from '../../atoms/SubmitButton';\nimport {PromptInputHeaderProps} from '../../molecules/PromptInputHeader';\nimport type {SuggestionsProps} from '../../molecules/Suggestions';\n\n/**\n * Props for a panel (top or bottom)\n */\nexport type PromptInputPanelConfig = {\n /** Is panel open */\n isOpen: boolean;\n /** Panel content */\n children?: ReactNode;\n};\n\n/**\n * Props for the header section of PromptInput.\n * Custom content (`topContent`) and default header props are mutually exclusive:\n * `topContent` replaces the default header entirely.\n */\nexport type PromptInputHeaderConfig = {\n /** QA/test identifier for header wrapper */\n qa?: string;\n} & (\n | {\n /** Custom content for header area (replaces the default header) */\n topContent?: ReactNode;\n /** Not allowed together with custom content */\n contextItems?: never;\n /** Not allowed together with custom content */\n showContextIndicator?: never;\n /** Not allowed together with custom content */\n contextIndicatorProps?: never;\n }\n | {\n /** Not allowed together with default header props */\n topContent?: never;\n /** Array of context items to display on the left */\n contextItems?: PromptInputHeaderProps['contextItems'];\n /** Show context indicator in header */\n showContextIndicator?: boolean;\n /** Props for context indicator */\n contextIndicatorProps?: PromptInputHeaderProps['contextIndicatorProps'];\n }\n);\n\n/**\n * Props for the body/textarea section of PromptInput\n */\nexport type PromptInputBodyConfig = {\n /** QA/test identifier for body wrapper */\n qa?: string;\n /** Ref to the textarea input */\n inputRef?: Ref<HTMLTextAreaElement>;\n /** Placeholder text for textarea */\n placeholder?: string;\n /** Size of the textarea. Defaults to `l`, or `xl` in mobile mode */\n size?: TextAreaProps['size'];\n /** Minimum number of textarea rows */\n minRows?: number;\n /** Maximum number of textarea rows */\n maxRows?: number;\n /** Auto focus textarea on mount */\n autoFocus?: boolean;\n /**\n * Auto focus textarea when a new chat is opened via the plus icon.\n * Only applies inside ChatContainer. Defaults to false.\n */\n autoFocusOnNewChat?: boolean;\n /**\n * Auto focus textarea when a chat is selected from history.\n * Only applies inside ChatContainer. Defaults to false.\n */\n autoFocusOnChatSelect?: boolean;\n};\n\n/**\n * Props for the footer section of PromptInput\n */\nexport type PromptInputFooterConfig = {\n /** QA/test identifier for footer wrapper */\n qa?: string;\n /** Additional CSS class for the footer wrapper */\n className?: string;\n /** Additional CSS class for the custom content wrapper */\n contentClassName?: string;\n /** Size of footer action buttons */\n buttonSize?: ButtonButtonProps['size'];\n /** Props for the submit button. State, click handling, and size are managed by PromptInput. */\n submitButtonProps?: Omit<SubmitButtonProps, 'state' | 'onClick' | 'size'> &\n Pick<ButtonButtonProps, 'disabled'>;\n /** Custom content for footer area (SubmitButton will still be shown) */\n bottomContent?: ReactNode;\n /** Show settings icon in footer */\n showSettings?: boolean;\n /** Settings icon click handler */\n onSettingsClick?: () => void;\n /** Show attachment icon in footer */\n showAttachment?: boolean;\n /** Attachment icon click handler */\n onAttachmentClick?: () => void;\n /**\n * Replaces the built-in attachment icon button with a custom node (e.g. AttachmentPicker).\n * When set, `showAttachment` and `onAttachmentClick` are ignored.\n */\n attachmentContent?: ReactNode;\n /** Show microphone icon in footer */\n showMicrophone?: boolean;\n /** Microphone icon click handler */\n onMicrophoneClick?: () => void;\n /** Custom tooltip for submit button in enabled state */\n submitButtonTooltipSend?: string;\n /** Custom tooltip for submit button in cancelable state */\n submitButtonTooltipCancel?: string;\n /** Custom cancelable text (if provided, will be shown in cancelable state) */\n submitButtonCancelableText?: string;\n /** QA/test identifier for submit button */\n submitButtonQa?: string;\n};\n\n/**\n * Props for the suggestions section of PromptInput\n */\nexport type PromptInputSuggestionsConfig = {\n /** Submit suggestions array */\n suggestions?: SuggestionsItem[];\n /** Show submit suggestions */\n showSuggestions?: boolean;\n /** Title for the suggestions section - can be string or custom React element */\n suggestTitle?: string | ReactNode;\n /** Layout orientation for suggestions: 'grid' for horizontal, 'list' for vertical */\n suggestionsLayout?: SuggestionsProps['layout'];\n /** Text alignment inside suggestion buttons */\n suggestionsTextAlign?: SuggestionsProps['textAlign'];\n /** Callback when suggestion is clicked */\n onSuggestionClick?: SuggestionClickHandler;\n};\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"../../../../../src","sources":["components/organisms/PromptInput/types.ts"],"names":[],"mappings":"","sourcesContent":["import {ReactNode, type Ref} from 'react';\n\nimport type {ButtonButtonProps, TextAreaProps} from '@gravity-ui/uikit';\n\nimport type {SuggestionClickHandler, SuggestionsItem} from '../../../types/common';\nimport type {SubmitButtonProps} from '../../atoms/SubmitButton';\nimport {PromptInputHeaderProps} from '../../molecules/PromptInputHeader';\nimport type {SuggestionsProps} from '../../molecules/Suggestions';\n\n/**\n * Props for a panel (top or bottom)\n */\nexport type PromptInputPanelConfig = {\n /** Is panel open */\n isOpen: boolean;\n /** Panel content */\n children?: ReactNode;\n};\n\n/**\n * Props for the header section of PromptInput.\n * Custom content (`topContent`) and default header props are mutually exclusive:\n * `topContent` replaces the default header entirely.\n */\nexport type PromptInputHeaderConfig = {\n /** QA/test identifier for header wrapper */\n qa?: string;\n} & (\n | {\n /** Custom content for header area (replaces the default header) */\n topContent?: ReactNode;\n /** Not allowed together with custom content */\n contextItems?: never;\n /** Not allowed together with custom content */\n showContextIndicator?: never;\n /** Not allowed together with custom content */\n contextIndicatorProps?: never;\n }\n | {\n /** Not allowed together with default header props */\n topContent?: never;\n /** Array of context items to display on the left */\n contextItems?: PromptInputHeaderProps['contextItems'];\n /** Show context indicator in header */\n showContextIndicator?: boolean;\n /** Props for context indicator */\n contextIndicatorProps?: PromptInputHeaderProps['contextIndicatorProps'];\n }\n);\n\n/**\n * Props for the body/textarea section of PromptInput\n */\nexport type PromptInputBodyConfig = {\n /** QA/test identifier for body wrapper */\n qa?: string;\n /** Ref to the textarea input */\n inputRef?: Ref<HTMLTextAreaElement>;\n /** Placeholder text for textarea */\n placeholder?: string;\n /** Size of the textarea. Defaults to `l`, or `xl` in mobile mode */\n size?: TextAreaProps['size'];\n /** Minimum number of textarea rows */\n minRows?: number;\n /** Maximum number of textarea rows */\n maxRows?: number;\n /** Auto focus textarea on mount */\n autoFocus?: boolean;\n /** Disabled state for textarea */\n disabledInput?: boolean;\n /**\n * Auto focus textarea when a new chat is opened via the plus icon.\n * Only applies inside ChatContainer. Defaults to false.\n */\n autoFocusOnNewChat?: boolean;\n /**\n * Auto focus textarea when a chat is selected from history.\n * Only applies inside ChatContainer. Defaults to false.\n */\n autoFocusOnChatSelect?: boolean;\n};\n\n/**\n * Props for the footer section of PromptInput\n */\nexport type PromptInputFooterConfig = {\n /** QA/test identifier for footer wrapper */\n qa?: string;\n /** Additional CSS class for the footer wrapper */\n className?: string;\n /** Additional CSS class for the custom content wrapper */\n contentClassName?: string;\n /** Size of footer action buttons */\n buttonSize?: ButtonButtonProps['size'];\n /** Props for the submit button. State, click handling, and size are managed by PromptInput. */\n submitButtonProps?: Omit<SubmitButtonProps, 'state' | 'onClick' | 'size'>;\n /** Custom content for footer area (SubmitButton will still be shown) */\n bottomContent?: ReactNode;\n /** Show settings icon in footer */\n showSettings?: boolean;\n /** Settings icon click handler */\n onSettingsClick?: () => void;\n /** Show attachment icon in footer */\n showAttachment?: boolean;\n /** Attachment icon click handler */\n onAttachmentClick?: () => void;\n /**\n * Replaces the built-in attachment icon button with a custom node (e.g. AttachmentPicker).\n * When set, `showAttachment` and `onAttachmentClick` are ignored.\n */\n attachmentContent?: ReactNode;\n /** Show microphone icon in footer */\n showMicrophone?: boolean;\n /** Microphone icon click handler */\n onMicrophoneClick?: () => void;\n /** Custom tooltip for submit button in enabled state */\n submitButtonTooltipSend?: string;\n /** Custom tooltip for submit button in cancelable state */\n submitButtonTooltipCancel?: string;\n /** Custom cancelable text (if provided, will be shown in cancelable state) */\n submitButtonCancelableText?: string;\n /** QA/test identifier for submit button */\n submitButtonQa?: string;\n};\n\n/**\n * Props for the suggestions section of PromptInput\n */\nexport type PromptInputSuggestionsConfig = {\n /** Submit suggestions array */\n suggestions?: SuggestionsItem[];\n /** Show submit suggestions */\n showSuggestions?: boolean;\n /** Title for the suggestions section - can be string or custom React element */\n suggestTitle?: string | ReactNode;\n /** Layout orientation for suggestions: 'grid' for horizontal, 'list' for vertical */\n suggestionsLayout?: SuggestionsProps['layout'];\n /** Text alignment inside suggestion buttons */\n suggestionsTextAlign?: SuggestionsProps['textAlign'];\n /** Callback when suggestion is clicked */\n onSuggestionClick?: SuggestionClickHandler;\n};\n"]}
@@ -1,4 +1,7 @@
1
1
  import { useCallback, useRef, useState } from 'react';
2
+ function createFileId({ sequence }) {
3
+ return `file-${sequence}`;
4
+ }
2
5
  /**
3
6
  * State machine for managing the file upload lifecycle.
4
7
  * The consumer provides an `upload` function — this hook never calls any API directly.
@@ -6,52 +9,51 @@ import { useCallback, useRef, useState } from 'react';
6
9
  export function useFileUploadStore(options) {
7
10
  const optionsRef = useRef(options);
8
11
  optionsRef.current = options;
12
+ // `entries` is stored in state so that changes trigger a re-render.
13
+ // `entriesRef` stores the latest value synchronously so that multiple calls before the next
14
+ // render correctly account for already added files and respect `maxFiles`.
9
15
  const [entries, setEntries] = useState([]);
10
- const idCounterRef = useRef(0);
11
- const nextId = useCallback(() => {
12
- idCounterRef.current += 1;
13
- return `file-${idCounterRef.current}`;
16
+ const entriesRef = useRef([]);
17
+ const applyEntriesUpdate = useCallback((updater) => {
18
+ const nextEntries = updater(entriesRef.current);
19
+ entriesRef.current = nextEntries;
20
+ setEntries(nextEntries);
14
21
  }, []);
22
+ const idCounterRef = useRef(0);
15
23
  const addFiles = useCallback((files) => {
16
24
  const { upload: up, withoutApply: wa, onUpload: ou, maxFiles: mf } = optionsRef.current;
17
- const pending = [];
18
- const filesToUpload = [];
19
- setEntries((prev) => {
20
- const remaining = mf === undefined ? files.length : Math.max(0, mf - prev.length);
21
- const sliced = files.slice(0, remaining);
22
- for (const file of sliced) {
23
- const id = nextId();
24
- pending.push({ id, file });
25
- }
26
- return [
27
- ...prev,
28
- ...pending.map(({ id, file }) => ({ status: 'pending', id, file })),
29
- ];
25
+ const remaining = mf === undefined ? files.length : Math.max(0, mf - entriesRef.current.length);
26
+ const filesToUpload = files.slice(0, remaining).map((file) => {
27
+ idCounterRef.current += 1;
28
+ return { id: createFileId({ sequence: idCounterRef.current }), file };
30
29
  });
31
- if (pending.length === 0)
30
+ if (filesToUpload.length === 0)
32
31
  return;
32
+ applyEntriesUpdate((current) => [
33
+ ...current,
34
+ ...filesToUpload.map(({ id, file }) => ({ status: 'pending', id, file })),
35
+ ]);
33
36
  if (wa) {
34
- ou === null || ou === void 0 ? void 0 : ou(pending.map((e) => e.file));
37
+ ou === null || ou === void 0 ? void 0 : ou(filesToUpload.map((entry) => entry.file));
35
38
  return;
36
39
  }
37
- filesToUpload.push(...pending);
38
40
  for (const { id, file } of filesToUpload) {
39
- setEntries((prev) => prev.map((e) => (e.id === id ? { status: 'uploading', id, file } : e)));
41
+ applyEntriesUpdate((current) => current.map((e) => e.id === id ? { status: 'uploading', id, file } : e));
40
42
  up(file)
41
43
  .then((meta) => {
42
- setEntries((prev) => prev.map((e) => e.id === id ? { status: 'done', id, file, meta } : e));
44
+ applyEntriesUpdate((current) => current.map((e) => e.id === id ? { status: 'done', id, file, meta } : e));
43
45
  })
44
46
  .catch((error) => {
45
- setEntries((prev) => prev.map((e) => e.id === id ? { status: 'error', id, file, error } : e));
47
+ applyEntriesUpdate((current) => current.map((e) => e.id === id ? { status: 'error', id, file, error } : e));
46
48
  });
47
49
  }
48
- }, [nextId]);
50
+ }, [applyEntriesUpdate]);
49
51
  const removeFile = useCallback((id) => {
50
- setEntries((prev) => prev.filter((e) => e.id !== id));
51
- }, []);
52
+ applyEntriesUpdate((current) => current.filter((entry) => entry.id !== id));
53
+ }, [applyEntriesUpdate]);
52
54
  const reset = useCallback(() => {
53
- setEntries([]);
54
- }, []);
55
+ applyEntriesUpdate(() => []);
56
+ }, [applyEntriesUpdate]);
55
57
  const isLoading = entries.some((e) => e.status === 'uploading');
56
58
  const uploadedMetas = entries
57
59
  .filter((e) => e.status === 'done')
@@ -1 +1 @@
1
- {"version":3,"file":"useFileUploadStore.js","sourceRoot":"../../../src","sources":["hooks/useFileUploadStore.ts"],"names":[],"mappings":"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","sourcesContent":["import {useCallback, useRef, useState} from 'react';\n\nexport type FileUploadEntry<Meta = {id: string; name: string}> =\n | {status: 'pending'; id: string; file: File}\n | {status: 'uploading'; id: string; file: File}\n | {status: 'done'; id: string; file: File; meta: Meta}\n | {status: 'error'; id: string; file: File; error: unknown};\n\nexport type UseFileUploadStoreOptions<Meta = {id: string; name: string}> = {\n /**\n * Called for each file to perform the actual upload.\n * Should return a promise resolving to file metadata.\n * Not called when `withoutApply` is true.\n */\n upload: (file: File) => Promise<Meta>;\n /** Maximum number of files allowed */\n maxFiles?: number;\n /**\n * When true, files are queued without starting the upload.\n * `onUpload` is called instead so the consumer can drive the upload externally.\n */\n withoutApply?: boolean;\n /** Called with newly added files when `withoutApply` is true */\n onUpload?: (files: File[]) => void;\n};\n\nexport type UseFileUploadStoreReturn<Meta = {id: string; name: string}> = {\n entries: FileUploadEntry<Meta>[];\n isLoading: boolean;\n addFiles: (files: File[]) => void;\n removeFile: (id: string) => void;\n reset: () => void;\n uploadedMetas: Meta[];\n};\n\n/**\n * State machine for managing the file upload lifecycle.\n * The consumer provides an `upload` function — this hook never calls any API directly.\n */\nexport function useFileUploadStore<Meta = {id: string; name: string}>(\n options: UseFileUploadStoreOptions<Meta>,\n): UseFileUploadStoreReturn<Meta> {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const [entries, setEntries] = useState<FileUploadEntry<Meta>[]>([]);\n const idCounterRef = useRef(0);\n const nextId = useCallback((): string => {\n idCounterRef.current += 1;\n return `file-${idCounterRef.current}`;\n }, []);\n\n const addFiles = useCallback(\n (files: File[]) => {\n const {upload: up, withoutApply: wa, onUpload: ou, maxFiles: mf} = optionsRef.current;\n\n const pending: {id: string; file: File}[] = [];\n const filesToUpload: {id: string; file: File}[] = [];\n\n setEntries((prev) => {\n const remaining = mf === undefined ? files.length : Math.max(0, mf - prev.length);\n const sliced = files.slice(0, remaining);\n\n for (const file of sliced) {\n const id = nextId();\n pending.push({id, file});\n }\n\n return [\n ...prev,\n ...pending.map(({id, file}) => ({status: 'pending' as const, id, file})),\n ];\n });\n\n if (pending.length === 0) return;\n\n if (wa) {\n ou?.(pending.map((e) => e.file));\n return;\n }\n\n filesToUpload.push(...pending);\n\n for (const {id, file} of filesToUpload) {\n setEntries((prev) =>\n prev.map((e) => (e.id === id ? {status: 'uploading' as const, id, file} : e)),\n );\n\n up(file)\n .then((meta) => {\n setEntries((prev) =>\n prev.map((e) =>\n e.id === id ? {status: 'done' as const, id, file, meta} : e,\n ),\n );\n })\n .catch((error) => {\n setEntries((prev) =>\n prev.map((e) =>\n e.id === id ? {status: 'error' as const, id, file, error} : e,\n ),\n );\n });\n }\n },\n [nextId],\n );\n\n const removeFile = useCallback((id: string) => {\n setEntries((prev) => prev.filter((e) => e.id !== id));\n }, []);\n\n const reset = useCallback(() => {\n setEntries([]);\n }, []);\n\n const isLoading = entries.some((e) => e.status === 'uploading');\n const uploadedMetas = entries\n .filter((e): e is Extract<FileUploadEntry<Meta>, {status: 'done'}> => e.status === 'done')\n .map((e) => e.meta);\n\n return {entries, isLoading, addFiles, removeFile, reset, uploadedMetas};\n}\n"]}
1
+ {"version":3,"file":"useFileUploadStore.js","sourceRoot":"../../../src","sources":["hooks/useFileUploadStore.ts"],"names":[],"mappings":"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","sourcesContent":["import {useCallback, useRef, useState} from 'react';\n\nexport type FileUploadEntry<Meta = {id: string; name: string}> =\n | {status: 'pending'; id: string; file: File}\n | {status: 'uploading'; id: string; file: File}\n | {status: 'done'; id: string; file: File; meta: Meta}\n | {status: 'error'; id: string; file: File; error: unknown};\n\nexport type UseFileUploadStoreOptions<Meta = {id: string; name: string}> = {\n /**\n * Called for each file to perform the actual upload.\n * Should return a promise resolving to file metadata.\n * Not called when `withoutApply` is true.\n */\n upload: (file: File) => Promise<Meta>;\n /** Maximum number of files allowed */\n maxFiles?: number;\n /**\n * When true, files are queued without starting the upload.\n * `onUpload` is called instead so the consumer can drive the upload externally.\n */\n withoutApply?: boolean;\n /** Called with newly added files when `withoutApply` is true */\n onUpload?: (files: File[]) => void;\n};\n\nexport type UseFileUploadStoreReturn<Meta = {id: string; name: string}> = {\n entries: FileUploadEntry<Meta>[];\n isLoading: boolean;\n addFiles: (files: File[]) => void;\n removeFile: (id: string) => void;\n reset: () => void;\n uploadedMetas: Meta[];\n};\n\nfunction createFileId({sequence}: {sequence: number}): string {\n return `file-${sequence}`;\n}\n\n/**\n * State machine for managing the file upload lifecycle.\n * The consumer provides an `upload` function — this hook never calls any API directly.\n */\nexport function useFileUploadStore<Meta = {id: string; name: string}>(\n options: UseFileUploadStoreOptions<Meta>,\n): UseFileUploadStoreReturn<Meta> {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n // `entries` is stored in state so that changes trigger a re-render.\n // `entriesRef` stores the latest value synchronously so that multiple calls before the next\n // render correctly account for already added files and respect `maxFiles`.\n const [entries, setEntries] = useState<FileUploadEntry<Meta>[]>([]);\n const entriesRef = useRef<FileUploadEntry<Meta>[]>([]);\n const applyEntriesUpdate = useCallback(\n (updater: (current: FileUploadEntry<Meta>[]) => FileUploadEntry<Meta>[]) => {\n const nextEntries = updater(entriesRef.current);\n entriesRef.current = nextEntries;\n setEntries(nextEntries);\n },\n [],\n );\n const idCounterRef = useRef(0);\n\n const addFiles = useCallback(\n (files: File[]) => {\n const {upload: up, withoutApply: wa, onUpload: ou, maxFiles: mf} = optionsRef.current;\n const remaining =\n mf === undefined ? files.length : Math.max(0, mf - entriesRef.current.length);\n const filesToUpload = files.slice(0, remaining).map((file) => {\n idCounterRef.current += 1;\n\n return {id: createFileId({sequence: idCounterRef.current}), file};\n });\n\n if (filesToUpload.length === 0) return;\n\n applyEntriesUpdate((current) => [\n ...current,\n ...filesToUpload.map(({id, file}) => ({status: 'pending' as const, id, file})),\n ]);\n\n if (wa) {\n ou?.(filesToUpload.map((entry) => entry.file));\n return;\n }\n\n for (const {id, file} of filesToUpload) {\n applyEntriesUpdate((current) =>\n current.map((e) =>\n e.id === id ? {status: 'uploading' as const, id, file} : e,\n ),\n );\n\n up(file)\n .then((meta) => {\n applyEntriesUpdate((current) =>\n current.map((e) =>\n e.id === id ? {status: 'done' as const, id, file, meta} : e,\n ),\n );\n })\n .catch((error) => {\n applyEntriesUpdate((current) =>\n current.map((e) =>\n e.id === id ? {status: 'error' as const, id, file, error} : e,\n ),\n );\n });\n }\n },\n [applyEntriesUpdate],\n );\n\n const removeFile = useCallback(\n (id: string) => {\n applyEntriesUpdate((current) => current.filter((entry) => entry.id !== id));\n },\n [applyEntriesUpdate],\n );\n\n const reset = useCallback(() => {\n applyEntriesUpdate(() => []);\n }, [applyEntriesUpdate]);\n\n const isLoading = entries.some((e) => e.status === 'uploading');\n const uploadedMetas = entries\n .filter((e): e is Extract<FileUploadEntry<Meta>, {status: 'done'}> => e.status === 'done')\n .map((e) => e.meta);\n\n return {entries, isLoading, addFiles, removeFile, reset, uploadedMetas};\n}\n"]}
@@ -1 +1 @@
1
- {"version":"2.21.4-beta.de9a973e6444f67d992e855b9b83d5a97fec4fd7.0","type":"module","sideEffects":["*.css","*.scss"]}
1
+ {"version":"2.22.0","type":"module","sideEffects":["*.css","*.scss"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/aikit",
3
- "version": "2.21.4-beta.de9a973e6444f67d992e855b9b83d5a97fec4fd7.0",
3
+ "version": "2.22.0",
4
4
  "description": "Gravity UI base kit for building ai assistant chats",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",