@hh.ru/magritte-ui-chat-input 1.2.2 → 1.2.4

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 (66) hide show
  1. package/index.css +117 -117
  2. package/index.d.ts +10 -10
  3. package/index.js +1 -1
  4. package/index.mock.d.ts +9 -9
  5. package/index.mock.js +37 -36
  6. package/index.mock.js.map +1 -1
  7. package/internal/ChatInputContext.d.ts +1 -1
  8. package/internal/ChatInputContext.js.map +1 -1
  9. package/internal/ChatInputSlotButton.js +13 -13
  10. package/internal/ChatInputSlotButton.js.map +1 -1
  11. package/internal/FocusTarget.js +3 -10
  12. package/internal/FocusTarget.js.map +1 -1
  13. package/internal/ModeTransition.js +41 -11
  14. package/internal/ModeTransition.js.map +1 -1
  15. package/internal/TextInput.d.ts +1 -1
  16. package/internal/TextInput.js +146 -126
  17. package/internal/TextInput.js.map +1 -1
  18. package/internal/VoiceRecord.d.ts +1 -1
  19. package/internal/VoiceRecord.js +66 -24
  20. package/internal/VoiceRecord.js.map +1 -1
  21. package/internal/VoiceRecordIndicator.js +22 -9
  22. package/internal/VoiceRecordIndicator.js.map +1 -1
  23. package/internal/flattenFragments.js +9 -13
  24. package/internal/flattenFragments.js.map +1 -1
  25. package/internal/focusGroup.js +18 -28
  26. package/internal/focusGroup.js.map +1 -1
  27. package/internal/useHasSound.js +49 -64
  28. package/internal/useHasSound.js.map +1 -1
  29. package/internal/useObjectUrl.js +15 -21
  30. package/internal/useObjectUrl.js.map +1 -1
  31. package/internal/useRovingFocusGroup.js +102 -137
  32. package/internal/useRovingFocusGroup.js.map +1 -1
  33. package/internal/useSendOnEnter.js +44 -46
  34. package/internal/useSendOnEnter.js.map +1 -1
  35. package/internal/useVoiceRecordSession.d.ts +1 -1
  36. package/internal/useVoiceRecordSession.js +185 -219
  37. package/internal/useVoiceRecordSession.js.map +1 -1
  38. package/internal/voiceSlotRegistry.d.ts +1 -1
  39. package/internal/voiceSlotRegistry.js +3 -3
  40. package/internal/voiceSlotRegistry.js.map +1 -1
  41. package/package.json +17 -16
  42. package/public/ChatInput.d.ts +6 -6
  43. package/public/ChatInput.js +129 -73
  44. package/public/ChatInput.js.map +1 -1
  45. package/public/ChatInputChips.js +4 -4
  46. package/public/ChatInputChips.js.map +1 -1
  47. package/public/ChatInputFile.d.ts +1 -1
  48. package/public/ChatInputFile.js +107 -47
  49. package/public/ChatInputFile.js.map +1 -1
  50. package/public/ChatInputFiles.js +10 -3
  51. package/public/ChatInputFiles.js.map +1 -1
  52. package/public/ChatInputPreview.js +14 -9
  53. package/public/ChatInputPreview.js.map +1 -1
  54. package/public/ChatInputSendButton.d.ts +1 -1
  55. package/public/ChatInputSendButton.js +34 -23
  56. package/public/ChatInputSendButton.js.map +1 -1
  57. package/public/ChatInputVoiceButton.d.ts +1 -1
  58. package/public/ChatInputVoiceButton.js +87 -91
  59. package/public/ChatInputVoiceButton.js.map +1 -1
  60. package/public/getChatInputFileType.d.ts +1 -1
  61. package/public/getChatInputFileType.js +7 -10
  62. package/public/getChatInputFileType.js.map +1 -1
  63. package/styles-DofLkp5v.js +5 -0
  64. package/styles-DofLkp5v.js.map +1 -0
  65. package/styles-CHMi0EYL.js +0 -5
  66. package/styles-CHMi0EYL.js.map +0 -1
@@ -5,70 +5,130 @@ import classNames from 'classnames';
5
5
  import { useTranslation } from '@hh.ru/magritte-common-use-translation';
6
6
  import { Cell, CellText } from '@hh.ru/magritte-ui-cell';
7
7
  import { useObjectUrl } from '../internal/useObjectUrl.js';
8
- import { CheckCircleOutlinedSize16, ExclamationTriangleOutlinedSize16, ImageOutlinedSize24, CrossOutlinedSize16, VideocameraOutlinedSize24, DocumentOutlinedSize24 } from '@hh.ru/magritte-ui-icon/icon';
8
+ import { CrossOutlinedSize16, CheckCircleOutlinedSize16, ExclamationTriangleOutlinedSize16, ImageOutlinedSize24, VideocameraOutlinedSize24, DocumentOutlinedSize24 } from '@hh.ru/magritte-ui-icon/icon';
9
9
  import { LinkDefaultPropsContext } from '@hh.ru/magritte-ui-link';
10
10
  import { Loader } from '@hh.ru/magritte-ui-loader';
11
11
  import { TextDefaultPropsContext } from '@hh.ru/magritte-ui-typography';
12
- import { s as styles } from '../styles-CHMi0EYL.js';
12
+ import { s as styles } from '../styles-DofLkp5v.js';
13
13
 
14
14
  const splitFileName = (name) => {
15
- const dotIndex = name.lastIndexOf('.');
16
- // точка в начале (.gitignore) или в конце (file.) — расширения нет, имя целиком
17
- if (dotIndex <= 0 || dotIndex === name.length - 1) {
18
- return { base: name, extension: '' };
19
- }
20
- return { base: name.slice(0, dotIndex), extension: name.slice(dotIndex) };
15
+ const dotIndex = name.lastIndexOf(".");
16
+ if (dotIndex <= 0 || dotIndex === name.length - 1) {
17
+ return { base: name, extension: "" };
18
+ }
19
+ return { base: name.slice(0, dotIndex), extension: name.slice(dotIndex) };
21
20
  };
22
21
  const FileName = ({ name }) => {
23
- if (typeof name !== 'string') {
24
- return jsx(Fragment, { children: name });
25
- }
26
- const { base, extension } = splitFileName(name);
27
- // основа сжимается с многоточием, расширение не сжимается; типографику даёт CellText.
28
- // имя без расширения обрезается так же, целиком
29
- return (jsxs("span", { className: styles.fileName, children: [jsx("span", { className: styles.fileNameBase, children: base }), extension && jsx("span", { className: styles.fileNameExtension, children: extension })] }));
22
+ if (typeof name !== "string") {
23
+ return /* @__PURE__ */ jsx(Fragment, { children: name });
24
+ }
25
+ const { base, extension } = splitFileName(name);
26
+ return /* @__PURE__ */ jsxs("span", { className: styles.fileName, children: [
27
+ /* @__PURE__ */ jsx("span", { className: styles.fileNameBase, children: base }),
28
+ extension && /* @__PURE__ */ jsx("span", { className: styles.fileNameExtension, children: extension })
29
+ ] });
30
30
  };
31
31
  const STATUS_ICON = {
32
- loading: jsx(Loader, { size: 16 }),
33
- loaded: jsx(CheckCircleOutlinedSize16, { initialColor: "positive" }),
34
- invalid: jsx(ExclamationTriangleOutlinedSize16, { initialColor: "negative" }),
32
+ loading: /* @__PURE__ */ jsx(Loader, { size: 16 }),
33
+ loaded: /* @__PURE__ */ jsx(CheckCircleOutlinedSize16, { initialColor: "positive" }),
34
+ invalid: /* @__PURE__ */ jsx(ExclamationTriangleOutlinedSize16, { initialColor: "negative" })
35
35
  };
36
- const LINK_DEFAULT_PROPS = { typography: 'label-3-regular', inline: true };
37
- // строку оформляет CellText, а Text, переданный пользователем в name/description, получает те же дефолты.
38
- // ellipsis — для Text: блочный элемент не обрезается text-overflow родителя
39
- const NAME_TEXT_PROPS = { typography: 'label-3-regular', style: 'primary', ellipsis: true };
40
- const DESCRIPTION_TEXT_PROPS = { typography: 'label-3-regular', style: 'secondary', ellipsis: true };
41
- /** Приложенный к сообщению файл */
42
- const ChatInputFile = forwardRef(({ 'data-qa': dataQa = 'chat-input-file', description, name, onRemove, preview, previewAlt, removeButtonProps, state = 'loaded', type = 'doc', ...props }, ref) => {
43
- const removeLabel = useTranslation('ChatInput', 'removeFile');
44
- const isImage = type === 'image';
45
- // object URL создаём только для плитки картинки — карточкам он не нужен
46
- const previewSrc = useObjectUrl(isImage ? preview : undefined);
47
- // битая картинка — показываем заглушку; сбрасывается сменой src или уходом из loaded,
48
- // чтобы тот же url (например, ещё не готовое серверное превью) загрузился повторно
36
+ const LINK_DEFAULT_PROPS = { typography: "label-3-regular", inline: true };
37
+ const NAME_TEXT_PROPS = { typography: "label-3-regular", style: "primary", ellipsis: true };
38
+ const DESCRIPTION_TEXT_PROPS = { typography: "label-3-regular", style: "secondary", ellipsis: true };
39
+ const ChatInputFile = forwardRef(
40
+ ({
41
+ "data-qa": dataQa = "chat-input-file",
42
+ description,
43
+ name,
44
+ onRemove,
45
+ preview,
46
+ previewAlt,
47
+ removeButtonProps,
48
+ state = "loaded",
49
+ type = "doc",
50
+ ...props
51
+ }, ref) => {
52
+ const removeLabel = useTranslation("ChatInput", "removeFile");
53
+ const isImage = type === "image";
54
+ const previewSrc = useObjectUrl(isImage ? preview : void 0);
49
55
  const [failedSrc, setFailedSrc] = useState();
50
- if (state !== 'loaded' && failedSrc !== undefined) {
51
- setFailedSrc(undefined);
56
+ if (state !== "loaded" && failedSrc !== void 0) {
57
+ setFailedSrc(void 0);
52
58
  }
53
59
  let content;
54
60
  if (isImage) {
55
- const showPreview = state === 'loaded' && !!previewSrc && previewSrc !== failedSrc;
56
- let placeholder = null;
57
- if (state === 'loading') {
58
- placeholder = jsx(Loader, { size: 24 });
61
+ const showPreview = state === "loaded" && !!previewSrc && previewSrc !== failedSrc;
62
+ let placeholder = null;
63
+ if (state === "loading") {
64
+ placeholder = /* @__PURE__ */ jsx(Loader, { size: 24 });
65
+ } else if (!showPreview) {
66
+ placeholder = /* @__PURE__ */ jsx(ImageOutlinedSize24, { initialColor: "tertiary" });
67
+ }
68
+ content = /* @__PURE__ */ jsx("div", { className: classNames(styles.fileTile, { [styles.fileTilePlaceholder]: !showPreview }), children: showPreview ? /* @__PURE__ */ jsx(
69
+ "img",
70
+ {
71
+ className: styles.fileTileImage,
72
+ src: previewSrc,
73
+ alt: previewAlt ?? (typeof name === "string" ? name : ""),
74
+ onError: () => setFailedSrc(previewSrc)
59
75
  }
60
- else if (!showPreview) {
61
- placeholder = jsx(ImageOutlinedSize24, { initialColor: "tertiary" });
76
+ ) : placeholder });
77
+ } else {
78
+ const Icon = type === "video" ? VideocameraOutlinedSize24 : DocumentOutlinedSize24;
79
+ content = /* @__PURE__ */ jsx("div", { className: classNames(styles.fileCard, { [styles.fileCardRemovable]: !!onRemove }), children: /* @__PURE__ */ jsxs(
80
+ Cell,
81
+ {
82
+ align: "center",
83
+ horPadding: false,
84
+ vertPadding: false,
85
+ left: /* @__PURE__ */ jsx(Icon, { initialColor: "secondary", backgroundStyle: "secondary", padding: 12, borderRadius: 8 }),
86
+ children: [
87
+ !!name && /* @__PURE__ */ jsx(
88
+ CellText,
89
+ {
90
+ type: "title",
91
+ typography: "label-3-regular",
92
+ style: "primary",
93
+ maxLines: 1,
94
+ "data-qa": "chat-input-file-name",
95
+ children: /* @__PURE__ */ jsx(TextDefaultPropsContext, { props: NAME_TEXT_PROPS, children: /* @__PURE__ */ jsx(FileName, { name }) })
96
+ }
97
+ ),
98
+ !!description && /* @__PURE__ */ jsx(
99
+ CellText,
100
+ {
101
+ type: "subtitle",
102
+ style: "secondary",
103
+ maxLines: 1,
104
+ left: STATUS_ICON[state],
105
+ "data-qa": "chat-input-file-description",
106
+ children: /* @__PURE__ */ jsx(TextDefaultPropsContext, { props: DESCRIPTION_TEXT_PROPS, children: /* @__PURE__ */ jsx(LinkDefaultPropsContext, { props: LINK_DEFAULT_PROPS, children: description }) })
107
+ }
108
+ )
109
+ ]
62
110
  }
63
- content = (jsx("div", { className: classNames(styles.fileTile, { [styles.fileTilePlaceholder]: !showPreview }), children: showPreview ? (jsx("img", { className: styles.fileTileImage, src: previewSrc, alt: previewAlt ?? (typeof name === 'string' ? name : ''), onError: () => setFailedSrc(previewSrc) })) : (placeholder) }));
111
+ ) });
64
112
  }
65
- else {
66
- const Icon = type === 'video' ? VideocameraOutlinedSize24 : DocumentOutlinedSize24;
67
- content = (jsx("div", { className: classNames(styles.fileCard, { [styles.fileCardRemovable]: !!onRemove }), children: jsxs(Cell, { align: "center", horPadding: false, vertPadding: false, left: jsx(Icon, { initialColor: "secondary", backgroundStyle: "secondary", padding: 12, borderRadius: 8 }), children: [!!name && (jsx(CellText, { type: "title", typography: "label-3-regular", style: "primary", maxLines: 1, "data-qa": "chat-input-file-name", children: jsx(TextDefaultPropsContext, { props: NAME_TEXT_PROPS, children: jsx(FileName, { name: name }) }) })), !!description && (jsx(CellText, { type: "subtitle", style: "secondary", maxLines: 1, left: STATUS_ICON[state], "data-qa": "chat-input-file-description", children: jsx(TextDefaultPropsContext, { props: DESCRIPTION_TEXT_PROPS, children: jsx(LinkDefaultPropsContext, { props: LINK_DEFAULT_PROPS, children: description }) }) }))] }) }));
68
- }
69
- return (jsxs("div", { ...props, className: styles.file, "data-qa": dataQa, ref: ref, children: [content, onRemove && (jsx("span", { className: styles.fileRemove, children: jsx(CrossOutlinedSize16, { "data-qa": "chat-input-file-remove", ...removeButtonProps, "aria-label": removeButtonProps?.['aria-label'] ?? removeLabel, initialColor: "primary", backgroundStyle: "secondary", borderRadius: 8, padding: 2, onClick: onRemove }) }))] }));
70
- });
71
- ChatInputFile.displayName = 'ChatInputFile';
113
+ return /* @__PURE__ */ jsxs("div", { ...props, className: styles.file, "data-qa": dataQa, ref, children: [
114
+ content,
115
+ onRemove && /* @__PURE__ */ jsx("span", { className: styles.fileRemove, children: /* @__PURE__ */ jsx(
116
+ CrossOutlinedSize16,
117
+ {
118
+ "data-qa": "chat-input-file-remove",
119
+ ...removeButtonProps,
120
+ "aria-label": removeButtonProps?.["aria-label"] ?? removeLabel,
121
+ initialColor: "primary",
122
+ backgroundStyle: "secondary",
123
+ borderRadius: 8,
124
+ padding: 2,
125
+ onClick: onRemove
126
+ }
127
+ ) })
128
+ ] });
129
+ }
130
+ );
131
+ ChatInputFile.displayName = "ChatInputFile";
72
132
 
73
133
  export { ChatInputFile };
74
134
  //# sourceMappingURL=ChatInputFile.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInputFile.js","sources":["src/public/ChatInputFile.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes, type MouseEventHandler, type ReactNode, useState } from 'react';\nimport classNames from 'classnames';\n\nimport { useTranslation } from '@hh.ru/magritte-common-use-translation';\nimport { Cell, CellText } from '@hh.ru/magritte-ui-cell';\nimport { useObjectUrl } from '@hh.ru/magritte-ui-chat-input/internal/useObjectUrl';\nimport { type ChatInputButtonAria } from '@hh.ru/magritte-ui-chat-input/types';\nimport {\n CheckCircleOutlinedSize16,\n CrossOutlinedSize16,\n DocumentOutlinedSize24,\n ExclamationTriangleOutlinedSize16,\n ImageOutlinedSize24,\n VideocameraOutlinedSize24,\n} from '@hh.ru/magritte-ui-icon/icon';\nimport { LinkDefaultPropsContext } from '@hh.ru/magritte-ui-link';\nimport { Loader } from '@hh.ru/magritte-ui-loader';\nimport { TextDefaultPropsContext } from '@hh.ru/magritte-ui-typography';\n\nimport styles from '../styles.less';\n\nexport type ChatInputFileState = 'loading' | 'loaded' | 'invalid';\n\nexport type ChatInputFileType = 'doc' | 'video' | 'image';\n\nexport interface ChatInputFileProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'className'> {\n /** Имя файла. Если передана строка, при нехватке места обрезается основа имени, а расширение\n * остаётся видимым целиком */\n name?: ReactNode;\n /**\n * Строка под именем (например, для размера файла или текста ошибки).\n * Для `type=\"image\"` не отображается\n */\n description?: ReactNode;\n /**\n * Состояние файла\n * @default loaded\n */\n state?: ChatInputFileState;\n /**\n * Тип файла: `doc` и `video` — карточка с иконкой и именем, `image` — квадратное превью\n * @default doc\n */\n type?: ChatInputFileType;\n /**\n * Превью, показывается для `type=\"image\"` в состоянии `loaded`: url картинки или сам файл (`File`/`Blob`).\n * Для файла компонент локально создаёт object URL и сам его отзывает — загружать файл на сервер\n * ради превью не нужно\n */\n preview?: string | Blob;\n /** Alt превью. По умолчанию — имя файла, если оно строка */\n previewAlt?: string;\n /** Обработчик удаления файла. Без него кнопка удаления файла не показывается */\n onRemove?: MouseEventHandler<HTMLButtonElement>;\n /** aria/data-qa пропсы кнопки удаления файла. Своя `aria-label` перекрывает дефолтную */\n removeButtonProps?: ChatInputButtonAria;\n /**\n * Значение data-qa\n * @default chat-input-file\n */\n 'data-qa'?: string;\n}\n\nconst splitFileName = (name: string): { base: string; extension: string } => {\n const dotIndex = name.lastIndexOf('.');\n // точка в начале (.gitignore) или в конце (file.) — расширения нет, имя целиком\n if (dotIndex <= 0 || dotIndex === name.length - 1) {\n return { base: name, extension: '' };\n }\n return { base: name.slice(0, dotIndex), extension: name.slice(dotIndex) };\n};\n\nconst FileName = ({ name }: { name: ReactNode }) => {\n if (typeof name !== 'string') {\n return <>{name}</>;\n }\n const { base, extension } = splitFileName(name);\n // основа сжимается с многоточием, расширение не сжимается; типографику даёт CellText.\n // имя без расширения обрезается так же, целиком\n return (\n <span className={styles.fileName}>\n <span className={styles.fileNameBase}>{base}</span>\n {extension && <span className={styles.fileNameExtension}>{extension}</span>}\n </span>\n );\n};\n\nconst STATUS_ICON: Record<ChatInputFileState, ReactNode> = {\n loading: <Loader size={16} />,\n loaded: <CheckCircleOutlinedSize16 initialColor=\"positive\" />,\n invalid: <ExclamationTriangleOutlinedSize16 initialColor=\"negative\" />,\n};\n\nconst LINK_DEFAULT_PROPS = { typography: 'label-3-regular', inline: true } as const;\n\n// строку оформляет CellText, а Text, переданный пользователем в name/description, получает те же дефолты.\n// ellipsis — для Text: блочный элемент не обрезается text-overflow родителя\nconst NAME_TEXT_PROPS = { typography: 'label-3-regular', style: 'primary', ellipsis: true } as const;\nconst DESCRIPTION_TEXT_PROPS = { typography: 'label-3-regular', style: 'secondary', ellipsis: true } as const;\n\n/** Приложенный к сообщению файл */\nexport const ChatInputFile = forwardRef<HTMLDivElement, ChatInputFileProps>(\n (\n {\n 'data-qa': dataQa = 'chat-input-file',\n description,\n name,\n onRemove,\n preview,\n previewAlt,\n removeButtonProps,\n state = 'loaded',\n type = 'doc',\n ...props\n },\n ref\n ) => {\n const removeLabel = useTranslation('ChatInput', 'removeFile');\n const isImage = type === 'image';\n // object URL создаём только для плитки картинки — карточкам он не нужен\n const previewSrc = useObjectUrl(isImage ? preview : undefined);\n // битая картинка — показываем заглушку; сбрасывается сменой src или уходом из loaded,\n // чтобы тот же url (например, ещё не готовое серверное превью) загрузился повторно\n const [failedSrc, setFailedSrc] = useState<string>();\n if (state !== 'loaded' && failedSrc !== undefined) {\n setFailedSrc(undefined);\n }\n\n let content: ReactNode;\n if (isImage) {\n const showPreview = state === 'loaded' && !!previewSrc && previewSrc !== failedSrc;\n let placeholder: ReactNode = null;\n if (state === 'loading') {\n placeholder = <Loader size={24} />;\n } else if (!showPreview) {\n placeholder = <ImageOutlinedSize24 initialColor=\"tertiary\" />;\n }\n content = (\n <div className={classNames(styles.fileTile, { [styles.fileTilePlaceholder]: !showPreview })}>\n {showPreview ? (\n <img\n className={styles.fileTileImage}\n src={previewSrc}\n alt={previewAlt ?? (typeof name === 'string' ? name : '')}\n onError={() => setFailedSrc(previewSrc)}\n />\n ) : (\n placeholder\n )}\n </div>\n );\n } else {\n const Icon = type === 'video' ? VideocameraOutlinedSize24 : DocumentOutlinedSize24;\n content = (\n <div className={classNames(styles.fileCard, { [styles.fileCardRemovable]: !!onRemove })}>\n <Cell\n align=\"center\"\n horPadding={false}\n vertPadding={false}\n left={\n <Icon initialColor=\"secondary\" backgroundStyle=\"secondary\" padding={12} borderRadius={8} />\n }\n >\n {!!name && (\n <CellText\n type=\"title\"\n typography=\"label-3-regular\"\n style=\"primary\"\n maxLines={1}\n data-qa=\"chat-input-file-name\"\n >\n <TextDefaultPropsContext props={NAME_TEXT_PROPS}>\n <FileName name={name} />\n </TextDefaultPropsContext>\n </CellText>\n )}\n {!!description && (\n <CellText\n type=\"subtitle\"\n style=\"secondary\"\n maxLines={1}\n left={STATUS_ICON[state]}\n data-qa=\"chat-input-file-description\"\n >\n <TextDefaultPropsContext props={DESCRIPTION_TEXT_PROPS}>\n <LinkDefaultPropsContext props={LINK_DEFAULT_PROPS}>\n {description}\n </LinkDefaultPropsContext>\n </TextDefaultPropsContext>\n </CellText>\n )}\n </Cell>\n </div>\n );\n }\n\n return (\n <div {...props} className={styles.file} data-qa={dataQa} ref={ref}>\n {content}\n {onRemove && (\n <span className={styles.fileRemove}>\n <CrossOutlinedSize16\n data-qa=\"chat-input-file-remove\"\n {...removeButtonProps}\n aria-label={removeButtonProps?.['aria-label'] ?? removeLabel}\n initialColor=\"primary\"\n backgroundStyle=\"secondary\"\n borderRadius={8}\n padding={2}\n onClick={onRemove}\n />\n </span>\n )}\n </div>\n );\n }\n);\n\nChatInputFile.displayName = 'ChatInputFile';\n"],"names":["_jsx","_Fragment","_jsxs"],"mappings":"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"}
1
+ {"version":3,"file":"ChatInputFile.js","sources":["src/public/ChatInputFile.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes, type MouseEventHandler, type ReactNode, useState } from 'react';\nimport classNames from 'classnames';\n\nimport { useTranslation } from '@hh.ru/magritte-common-use-translation';\nimport { Cell, CellText } from '@hh.ru/magritte-ui-cell';\nimport { useObjectUrl } from '@hh.ru/magritte-ui-chat-input/internal/useObjectUrl';\nimport { type ChatInputButtonAria } from '@hh.ru/magritte-ui-chat-input/types';\nimport {\n CheckCircleOutlinedSize16,\n CrossOutlinedSize16,\n DocumentOutlinedSize24,\n ExclamationTriangleOutlinedSize16,\n ImageOutlinedSize24,\n VideocameraOutlinedSize24,\n} from '@hh.ru/magritte-ui-icon/icon';\nimport { LinkDefaultPropsContext } from '@hh.ru/magritte-ui-link';\nimport { Loader } from '@hh.ru/magritte-ui-loader';\nimport { TextDefaultPropsContext } from '@hh.ru/magritte-ui-typography';\n\nimport styles from '../styles.less';\n\nexport type ChatInputFileState = 'loading' | 'loaded' | 'invalid';\n\nexport type ChatInputFileType = 'doc' | 'video' | 'image';\n\nexport interface ChatInputFileProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'className'> {\n /** Имя файла. Если передана строка, при нехватке места обрезается основа имени, а расширение\n * остаётся видимым целиком */\n name?: ReactNode;\n /**\n * Строка под именем (например, для размера файла или текста ошибки).\n * Для `type=\"image\"` не отображается\n */\n description?: ReactNode;\n /**\n * Состояние файла\n * @default loaded\n */\n state?: ChatInputFileState;\n /**\n * Тип файла: `doc` и `video` — карточка с иконкой и именем, `image` — квадратное превью\n * @default doc\n */\n type?: ChatInputFileType;\n /**\n * Превью, показывается для `type=\"image\"` в состоянии `loaded`: url картинки или сам файл (`File`/`Blob`).\n * Для файла компонент локально создаёт object URL и сам его отзывает — загружать файл на сервер\n * ради превью не нужно\n */\n preview?: string | Blob;\n /** Alt превью. По умолчанию — имя файла, если оно строка */\n previewAlt?: string;\n /** Обработчик удаления файла. Без него кнопка удаления файла не показывается */\n onRemove?: MouseEventHandler<HTMLButtonElement>;\n /** aria/data-qa пропсы кнопки удаления файла. Своя `aria-label` перекрывает дефолтную */\n removeButtonProps?: ChatInputButtonAria;\n /**\n * Значение data-qa\n * @default chat-input-file\n */\n 'data-qa'?: string;\n}\n\nconst splitFileName = (name: string): { base: string; extension: string } => {\n const dotIndex = name.lastIndexOf('.');\n // точка в начале (.gitignore) или в конце (file.) — расширения нет, имя целиком\n if (dotIndex <= 0 || dotIndex === name.length - 1) {\n return { base: name, extension: '' };\n }\n return { base: name.slice(0, dotIndex), extension: name.slice(dotIndex) };\n};\n\nconst FileName = ({ name }: { name: ReactNode }) => {\n if (typeof name !== 'string') {\n return <>{name}</>;\n }\n const { base, extension } = splitFileName(name);\n // основа сжимается с многоточием, расширение не сжимается; типографику даёт CellText.\n // имя без расширения обрезается так же, целиком\n return (\n <span className={styles.fileName}>\n <span className={styles.fileNameBase}>{base}</span>\n {extension && <span className={styles.fileNameExtension}>{extension}</span>}\n </span>\n );\n};\n\nconst STATUS_ICON: Record<ChatInputFileState, ReactNode> = {\n loading: <Loader size={16} />,\n loaded: <CheckCircleOutlinedSize16 initialColor=\"positive\" />,\n invalid: <ExclamationTriangleOutlinedSize16 initialColor=\"negative\" />,\n};\n\nconst LINK_DEFAULT_PROPS = { typography: 'label-3-regular', inline: true } as const;\n\n// строку оформляет CellText, а Text, переданный пользователем в name/description, получает те же дефолты.\n// ellipsis — для Text: блочный элемент не обрезается text-overflow родителя\nconst NAME_TEXT_PROPS = { typography: 'label-3-regular', style: 'primary', ellipsis: true } as const;\nconst DESCRIPTION_TEXT_PROPS = { typography: 'label-3-regular', style: 'secondary', ellipsis: true } as const;\n\n/** Приложенный к сообщению файл */\nexport const ChatInputFile = forwardRef<HTMLDivElement, ChatInputFileProps>(\n (\n {\n 'data-qa': dataQa = 'chat-input-file',\n description,\n name,\n onRemove,\n preview,\n previewAlt,\n removeButtonProps,\n state = 'loaded',\n type = 'doc',\n ...props\n },\n ref\n ) => {\n const removeLabel = useTranslation('ChatInput', 'removeFile');\n const isImage = type === 'image';\n // object URL создаём только для плитки картинки — карточкам он не нужен\n const previewSrc = useObjectUrl(isImage ? preview : undefined);\n // битая картинка — показываем заглушку; сбрасывается сменой src или уходом из loaded,\n // чтобы тот же url (например, ещё не готовое серверное превью) загрузился повторно\n const [failedSrc, setFailedSrc] = useState<string>();\n if (state !== 'loaded' && failedSrc !== undefined) {\n setFailedSrc(undefined);\n }\n\n let content: ReactNode;\n if (isImage) {\n const showPreview = state === 'loaded' && !!previewSrc && previewSrc !== failedSrc;\n let placeholder: ReactNode = null;\n if (state === 'loading') {\n placeholder = <Loader size={24} />;\n } else if (!showPreview) {\n placeholder = <ImageOutlinedSize24 initialColor=\"tertiary\" />;\n }\n content = (\n <div className={classNames(styles.fileTile, { [styles.fileTilePlaceholder]: !showPreview })}>\n {showPreview ? (\n <img\n className={styles.fileTileImage}\n src={previewSrc}\n alt={previewAlt ?? (typeof name === 'string' ? name : '')}\n onError={() => setFailedSrc(previewSrc)}\n />\n ) : (\n placeholder\n )}\n </div>\n );\n } else {\n const Icon = type === 'video' ? VideocameraOutlinedSize24 : DocumentOutlinedSize24;\n content = (\n <div className={classNames(styles.fileCard, { [styles.fileCardRemovable]: !!onRemove })}>\n <Cell\n align=\"center\"\n horPadding={false}\n vertPadding={false}\n left={\n <Icon initialColor=\"secondary\" backgroundStyle=\"secondary\" padding={12} borderRadius={8} />\n }\n >\n {!!name && (\n <CellText\n type=\"title\"\n typography=\"label-3-regular\"\n style=\"primary\"\n maxLines={1}\n data-qa=\"chat-input-file-name\"\n >\n <TextDefaultPropsContext props={NAME_TEXT_PROPS}>\n <FileName name={name} />\n </TextDefaultPropsContext>\n </CellText>\n )}\n {!!description && (\n <CellText\n type=\"subtitle\"\n style=\"secondary\"\n maxLines={1}\n left={STATUS_ICON[state]}\n data-qa=\"chat-input-file-description\"\n >\n <TextDefaultPropsContext props={DESCRIPTION_TEXT_PROPS}>\n <LinkDefaultPropsContext props={LINK_DEFAULT_PROPS}>\n {description}\n </LinkDefaultPropsContext>\n </TextDefaultPropsContext>\n </CellText>\n )}\n </Cell>\n </div>\n );\n }\n\n return (\n <div {...props} className={styles.file} data-qa={dataQa} ref={ref}>\n {content}\n {onRemove && (\n <span className={styles.fileRemove}>\n <CrossOutlinedSize16\n data-qa=\"chat-input-file-remove\"\n {...removeButtonProps}\n aria-label={removeButtonProps?.['aria-label'] ?? removeLabel}\n initialColor=\"primary\"\n backgroundStyle=\"secondary\"\n borderRadius={8}\n padding={2}\n onClick={onRemove}\n />\n </span>\n )}\n </div>\n );\n }\n);\n\nChatInputFile.displayName = 'ChatInputFile';\n"],"names":[],"mappings":"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"}
@@ -3,10 +3,17 @@ import { jsx } from 'react/jsx-runtime';
3
3
  import { isValidElement } from 'react';
4
4
  import { flattenFragments } from '../internal/flattenFragments.js';
5
5
  import { ScrollableContainer } from '@hh.ru/magritte-ui-scrollable-container';
6
- import { s as styles } from '../styles-CHMi0EYL.js';
6
+ import { s as styles } from '../styles-DofLkp5v.js';
7
7
 
8
- const ChatInputFiles = ({ children }) => (jsx("div", { className: styles.filesContainer, "data-qa": "chat-input-files", children: jsx(ScrollableContainer, { correction: 11, children: jsx(ScrollableContainer.DefaultLayout, { size: "small", noFadeOnDesktop: true, buttonsOffset: 8, buttonsOnHover: true, children: jsx(ScrollableContainer.Gallery, { children: jsx("div", { className: styles.files, children: flattenFragments(children).map((child, index) => (jsx(ScrollableContainer.Item, { scrollToItemOnFocus: true, children: child }, (isValidElement(child) && child.key) || index))) }) }) }) }) }));
9
- ChatInputFiles.displayName = 'ChatInputFiles';
8
+ const ChatInputFiles = ({ children }) => /* @__PURE__ */ jsx("div", { className: styles.filesContainer, "data-qa": "chat-input-files", children: /* @__PURE__ */ jsx(ScrollableContainer, { correction: 11, children: /* @__PURE__ */ jsx(ScrollableContainer.DefaultLayout, { size: "small", noFadeOnDesktop: true, buttonsOffset: 8, buttonsOnHover: true, children: /* @__PURE__ */ jsx(ScrollableContainer.Gallery, { children: /* @__PURE__ */ jsx("div", { className: styles.files, children: flattenFragments(children).map((child, index) => /* @__PURE__ */ jsx(
9
+ ScrollableContainer.Item,
10
+ {
11
+ scrollToItemOnFocus: true,
12
+ children: child
13
+ },
14
+ isValidElement(child) && child.key || index
15
+ )) }) }) }) }) });
16
+ ChatInputFiles.displayName = "ChatInputFiles";
10
17
 
11
18
  export { ChatInputFiles };
12
19
  //# sourceMappingURL=ChatInputFiles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInputFiles.js","sources":["src/public/ChatInputFiles.tsx"],"sourcesContent":["import { isValidElement, type FC, type ReactNode } from 'react';\n\nimport { flattenFragments } from '@hh.ru/magritte-ui-chat-input/internal/flattenFragments';\nimport { ScrollableContainer } from '@hh.ru/magritte-ui-scrollable-container';\n\nimport styles from '../styles.less';\n\nexport interface ChatInputFilesProps {\n /** Файлы (`ChatInput.File`), размещаются в один ряд с возможностью горизонтального скролла */\n children: ReactNode;\n}\n\nexport const ChatInputFiles: FC<ChatInputFilesProps> = ({ children }) => (\n <div className={styles.filesContainer} data-qa=\"chat-input-files\">\n {/* область прокрутки выходит за паддинг ChatInput (12px) до его обводки (1px), чтобы файлы\n обрезались краем компонента, но не перекрывали обводку; в крайних положениях контент отступает\n от краёв на те же 12px */}\n <ScrollableContainer correction={11}>\n {/* в макете у ряда файлов нет краевых фейдов: на десктопе оставляем только кнопки листания,\n на мобильных фейды и так выключены по умолчанию. Кнопки — на 8px внутрь от края ряда\n (20px от края ChatInput) и появляются только при наведении на ряд */}\n <ScrollableContainer.DefaultLayout size=\"small\" noFadeOnDesktop buttonsOffset={8} buttonsOnHover>\n <ScrollableContainer.Gallery>\n <div className={styles.files}>\n {/* ключи детей переносим на обёртку, чтобы удаление файла из середины\n не сдвигало стейт соседей; при фокусе внутри файла (крестик, с клавиатуры)\n подскролливаем к нему */}\n {flattenFragments(children).map((child, index) => (\n <ScrollableContainer.Item\n key={(isValidElement(child) && child.key) || index}\n scrollToItemOnFocus\n >\n {child}\n </ScrollableContainer.Item>\n ))}\n </div>\n </ScrollableContainer.Gallery>\n </ScrollableContainer.DefaultLayout>\n </ScrollableContainer>\n </div>\n);\n\nChatInputFiles.displayName = 'ChatInputFiles';\n"],"names":["_jsx"],"mappings":";;;;;;MAYa,cAAc,GAA4B,CAAC,EAAE,QAAQ,EAAE,MAChEA,GAAK,CAAA,KAAA,EAAA,EAAA,SAAS,EAAE,MAAM,CAAC,cAAc,EAAU,SAAA,EAAA,kBAAkB,EAI7D,QAAA,EAAAA,GAAA,CAAC,mBAAmB,EAAA,EAAC,UAAU,EAAE,EAAE,YAI/BA,GAAC,CAAA,mBAAmB,CAAC,aAAa,EAAA,EAAC,IAAI,EAAC,OAAO,EAAC,eAAe,EAAC,IAAA,EAAA,aAAa,EAAE,CAAC,EAAE,cAAc,kBAC5FA,GAAC,CAAA,mBAAmB,CAAC,OAAO,EACxB,EAAA,QAAA,EAAAA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,KAAK,EAAA,QAAA,EAIvB,gBAAgB,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,MACzCA,GAAA,CAAC,mBAAmB,CAAC,IAAI,EAAA,EAErB,mBAAmB,EAElB,IAAA,EAAA,QAAA,EAAA,KAAK,IAHD,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,CAI3B,CAC9B,CAAC,EAAA,CACA,GACoB,EACE,CAAA,EAAA,CAClB,EACpB,CAAA,EACR;AAEF,cAAc,CAAC,WAAW,GAAG,gBAAgB;;;;"}
1
+ {"version":3,"file":"ChatInputFiles.js","sources":["src/public/ChatInputFiles.tsx"],"sourcesContent":["import { isValidElement, type FC, type ReactNode } from 'react';\n\nimport { flattenFragments } from '@hh.ru/magritte-ui-chat-input/internal/flattenFragments';\nimport { ScrollableContainer } from '@hh.ru/magritte-ui-scrollable-container';\n\nimport styles from '../styles.less';\n\nexport interface ChatInputFilesProps {\n /** Файлы (`ChatInput.File`), размещаются в один ряд с возможностью горизонтального скролла */\n children: ReactNode;\n}\n\nexport const ChatInputFiles: FC<ChatInputFilesProps> = ({ children }) => (\n <div className={styles.filesContainer} data-qa=\"chat-input-files\">\n {/* область прокрутки выходит за паддинг ChatInput (12px) до его обводки (1px), чтобы файлы\n обрезались краем компонента, но не перекрывали обводку; в крайних положениях контент отступает\n от краёв на те же 12px */}\n <ScrollableContainer correction={11}>\n {/* в макете у ряда файлов нет краевых фейдов: на десктопе оставляем только кнопки листания,\n на мобильных фейды и так выключены по умолчанию. Кнопки — на 8px внутрь от края ряда\n (20px от края ChatInput) и появляются только при наведении на ряд */}\n <ScrollableContainer.DefaultLayout size=\"small\" noFadeOnDesktop buttonsOffset={8} buttonsOnHover>\n <ScrollableContainer.Gallery>\n <div className={styles.files}>\n {/* ключи детей переносим на обёртку, чтобы удаление файла из середины\n не сдвигало стейт соседей; при фокусе внутри файла (крестик, с клавиатуры)\n подскролливаем к нему */}\n {flattenFragments(children).map((child, index) => (\n <ScrollableContainer.Item\n key={(isValidElement(child) && child.key) || index}\n scrollToItemOnFocus\n >\n {child}\n </ScrollableContainer.Item>\n ))}\n </div>\n </ScrollableContainer.Gallery>\n </ScrollableContainer.DefaultLayout>\n </ScrollableContainer>\n </div>\n);\n\nChatInputFiles.displayName = 'ChatInputFiles';\n"],"names":[],"mappings":";;;;;;AAYO,MAAM,iBAA0C,CAAC,EAAE,UACtD,qBAAA,GAAA,CAAC,SAAI,SAAW,EAAA,MAAA,CAAO,gBAAgB,SAAQ,EAAA,kBAAA,EAI3C,8BAAC,mBAAoB,EAAA,EAAA,UAAA,EAAY,IAI7B,QAAC,kBAAA,GAAA,CAAA,mBAAA,CAAoB,eAApB,EAAkC,IAAA,EAAK,SAAQ,eAAe,EAAA,IAAA,EAAC,eAAe,CAAG,EAAA,cAAA,EAAc,MAC5F,QAAC,kBAAA,GAAA,CAAA,mBAAA,CAAoB,SAApB,EACG,QAAA,kBAAA,GAAA,CAAC,SAAI,SAAW,EAAA,MAAA,CAAO,OAIlB,QAAiB,EAAA,gBAAA,CAAA,QAAQ,EAAE,GAAI,CAAA,CAAC,OAAO,KACpC,qBAAA,GAAA;AAAA,EAAC,mBAAoB,CAAA,IAAA;AAAA,EAApB;AAAA,IAEG,mBAAmB,EAAA,IAAA;AAAA,IAElB,QAAA,EAAA,KAAA;AAAA,GAAA;AAAA,EAHK,cAAe,CAAA,KAAK,CAAK,IAAA,KAAA,CAAM,GAAQ,IAAA,KAAA;AAIjD,CACH,CACL,EAAA,CAAA,EACJ,CACJ,EAAA,CAAA,EACJ,CACJ,EAAA,EAAA;AAGJ,cAAA,CAAe,WAAc,GAAA,gBAAA;;;;"}
@@ -2,18 +2,23 @@ import './../index.css';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
3
  import { IconDefaultPropsContext } from '@hh.ru/magritte-ui-icon';
4
4
  import { TextDefaultPropsContext } from '@hh.ru/magritte-ui-typography';
5
- import { s as styles } from '../styles-CHMi0EYL.js';
5
+ import { s as styles } from '../styles-DofLkp5v.js';
6
6
 
7
7
  const DEFAULT_ICON_PROPS = {
8
- initialColor: 'secondary',
9
- padding: 8,
8
+ initialColor: "secondary",
9
+ padding: 8
10
10
  };
11
- // строку оформляют стили слота, а Text, переданный пользователем в title/subtitle, получает те же дефолты.
12
- // ellipsis — для Text: блочный элемент не обрезается text-overflow родителя
13
- const TITLE_TEXT_PROPS = { typography: 'subtitle-3-semibold', style: 'primary' };
14
- const SUBTITLE_TEXT_PROPS = { typography: 'label-3-regular', style: 'secondary', ellipsis: true };
15
- const ChatInputPreview = ({ title, subtitle, leftActions, rightActions }) => (jsx(IconDefaultPropsContext, { props: DEFAULT_ICON_PROPS, children: jsxs("div", { className: styles.previewBlock, children: [!!leftActions && jsx("div", { className: styles.previewSide, children: leftActions }), jsxs("div", { className: styles.previewContent, children: [!!title && (jsx(TextDefaultPropsContext, { props: TITLE_TEXT_PROPS, children: jsx("div", { className: styles.previewTitle, children: title }) })), !!subtitle && (jsx(TextDefaultPropsContext, { props: SUBTITLE_TEXT_PROPS, children: jsx("div", { className: styles.previewSubtitle, children: subtitle }) }))] }), !!rightActions && jsx("div", { className: styles.previewSide, children: rightActions })] }) }));
16
- ChatInputPreview.displayName = 'ChatInputPreview';
11
+ const TITLE_TEXT_PROPS = { typography: "subtitle-3-semibold", style: "primary" };
12
+ const SUBTITLE_TEXT_PROPS = { typography: "label-3-regular", style: "secondary", ellipsis: true };
13
+ const ChatInputPreview = ({ title, subtitle, leftActions, rightActions }) => /* @__PURE__ */ jsx(IconDefaultPropsContext, { props: DEFAULT_ICON_PROPS, children: /* @__PURE__ */ jsxs("div", { className: styles.previewBlock, children: [
14
+ !!leftActions && /* @__PURE__ */ jsx("div", { className: styles.previewSide, children: leftActions }),
15
+ /* @__PURE__ */ jsxs("div", { className: styles.previewContent, children: [
16
+ !!title && /* @__PURE__ */ jsx(TextDefaultPropsContext, { props: TITLE_TEXT_PROPS, children: /* @__PURE__ */ jsx("div", { className: styles.previewTitle, children: title }) }),
17
+ !!subtitle && /* @__PURE__ */ jsx(TextDefaultPropsContext, { props: SUBTITLE_TEXT_PROPS, children: /* @__PURE__ */ jsx("div", { className: styles.previewSubtitle, children: subtitle }) })
18
+ ] }),
19
+ !!rightActions && /* @__PURE__ */ jsx("div", { className: styles.previewSide, children: rightActions })
20
+ ] }) });
21
+ ChatInputPreview.displayName = "ChatInputPreview";
17
22
 
18
23
  export { ChatInputPreview };
19
24
  //# sourceMappingURL=ChatInputPreview.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInputPreview.js","sources":["src/public/ChatInputPreview.tsx"],"sourcesContent":["import { type FC, type ReactNode } from 'react';\n\nimport { IconDefaultPropsContext } from '@hh.ru/magritte-ui-icon';\nimport { TextDefaultPropsContext } from '@hh.ru/magritte-ui-typography';\n\nimport styles from '../styles.less';\n\nexport interface ChatInputPreviewProps {\n /** Заголовок в центральной секции, типографика subtitle-3-semibold */\n title?: ReactNode;\n /** Подзаголовок под title, типографика label-3-regular; обрезается многоточием */\n subtitle?: ReactNode;\n /** Слот левой секции, обычно иконка */\n leftActions?: ReactNode;\n /** Слот правой секции, обычно иконка */\n rightActions?: ReactNode;\n}\n\nconst DEFAULT_ICON_PROPS = {\n initialColor: 'secondary',\n padding: 8,\n} as const;\n\n// строку оформляют стили слота, а Text, переданный пользователем в title/subtitle, получает те же дефолты.\n// ellipsis — для Text: блочный элемент не обрезается text-overflow родителя\nconst TITLE_TEXT_PROPS = { typography: 'subtitle-3-semibold', style: 'primary' } as const;\nconst SUBTITLE_TEXT_PROPS = { typography: 'label-3-regular', style: 'secondary', ellipsis: true } as const;\n\nexport const ChatInputPreview: FC<ChatInputPreviewProps> = ({ title, subtitle, leftActions, rightActions }) => (\n <IconDefaultPropsContext props={DEFAULT_ICON_PROPS}>\n <div className={styles.previewBlock}>\n {!!leftActions && <div className={styles.previewSide}>{leftActions}</div>}\n <div className={styles.previewContent}>\n {!!title && (\n <TextDefaultPropsContext props={TITLE_TEXT_PROPS}>\n <div className={styles.previewTitle}>{title}</div>\n </TextDefaultPropsContext>\n )}\n {!!subtitle && (\n <TextDefaultPropsContext props={SUBTITLE_TEXT_PROPS}>\n <div className={styles.previewSubtitle}>{subtitle}</div>\n </TextDefaultPropsContext>\n )}\n </div>\n {!!rightActions && <div className={styles.previewSide}>{rightActions}</div>}\n </div>\n </IconDefaultPropsContext>\n);\n\nChatInputPreview.displayName = 'ChatInputPreview';\n"],"names":["_jsx","_jsxs"],"mappings":";;;;;AAkBA,MAAM,kBAAkB,GAAG;AACvB,IAAA,YAAY,EAAE,WAAW;AACzB,IAAA,OAAO,EAAE,CAAC;CACJ,CAAC;AAEX;AACA;AACA,MAAM,gBAAgB,GAAG,EAAE,UAAU,EAAE,qBAAqB,EAAE,KAAK,EAAE,SAAS,EAAW,CAAC;AAC1F,MAAM,mBAAmB,GAAG,EAAE,UAAU,EAAE,iBAAiB,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAW,CAAC;AAE9F,MAAA,gBAAgB,GAA8B,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,MACtGA,GAAC,CAAA,uBAAuB,EAAC,EAAA,KAAK,EAAE,kBAAkB,EAC9C,QAAA,EAAAC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,YAAY,EAC9B,QAAA,EAAA,CAAA,CAAC,CAAC,WAAW,IAAID,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,WAAW,EAAA,QAAA,EAAG,WAAW,EAAA,CAAO,EACzEC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,cAAc,EAAA,QAAA,EAAA,CAChC,CAAC,CAAC,KAAK,KACJD,GAAA,CAAC,uBAAuB,EAAC,EAAA,KAAK,EAAE,gBAAgB,EAC5C,QAAA,EAAAA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,YAAY,EAAA,QAAA,EAAG,KAAK,EAAA,CAAO,GAC5B,CAC7B,EACA,CAAC,CAAC,QAAQ,KACPA,GAAA,CAAC,uBAAuB,EAAA,EAAC,KAAK,EAAE,mBAAmB,EAAA,QAAA,EAC/CA,aAAK,SAAS,EAAE,MAAM,CAAC,eAAe,EAAA,QAAA,EAAG,QAAQ,EAAA,CAAO,EAClC,CAAA,CAC7B,CACC,EAAA,CAAA,EACL,CAAC,CAAC,YAAY,IAAIA,GAAK,CAAA,KAAA,EAAA,EAAA,SAAS,EAAE,MAAM,CAAC,WAAW,EAAG,QAAA,EAAA,YAAY,EAAO,CAAA,CAAA,EAAA,CACzE,EACgB,CAAA,EAC5B;AAEF,gBAAgB,CAAC,WAAW,GAAG,kBAAkB;;;;"}
1
+ {"version":3,"file":"ChatInputPreview.js","sources":["src/public/ChatInputPreview.tsx"],"sourcesContent":["import { type FC, type ReactNode } from 'react';\n\nimport { IconDefaultPropsContext } from '@hh.ru/magritte-ui-icon';\nimport { TextDefaultPropsContext } from '@hh.ru/magritte-ui-typography';\n\nimport styles from '../styles.less';\n\nexport interface ChatInputPreviewProps {\n /** Заголовок в центральной секции, типографика subtitle-3-semibold */\n title?: ReactNode;\n /** Подзаголовок под title, типографика label-3-regular; обрезается многоточием */\n subtitle?: ReactNode;\n /** Слот левой секции, обычно иконка */\n leftActions?: ReactNode;\n /** Слот правой секции, обычно иконка */\n rightActions?: ReactNode;\n}\n\nconst DEFAULT_ICON_PROPS = {\n initialColor: 'secondary',\n padding: 8,\n} as const;\n\n// строку оформляют стили слота, а Text, переданный пользователем в title/subtitle, получает те же дефолты.\n// ellipsis — для Text: блочный элемент не обрезается text-overflow родителя\nconst TITLE_TEXT_PROPS = { typography: 'subtitle-3-semibold', style: 'primary' } as const;\nconst SUBTITLE_TEXT_PROPS = { typography: 'label-3-regular', style: 'secondary', ellipsis: true } as const;\n\nexport const ChatInputPreview: FC<ChatInputPreviewProps> = ({ title, subtitle, leftActions, rightActions }) => (\n <IconDefaultPropsContext props={DEFAULT_ICON_PROPS}>\n <div className={styles.previewBlock}>\n {!!leftActions && <div className={styles.previewSide}>{leftActions}</div>}\n <div className={styles.previewContent}>\n {!!title && (\n <TextDefaultPropsContext props={TITLE_TEXT_PROPS}>\n <div className={styles.previewTitle}>{title}</div>\n </TextDefaultPropsContext>\n )}\n {!!subtitle && (\n <TextDefaultPropsContext props={SUBTITLE_TEXT_PROPS}>\n <div className={styles.previewSubtitle}>{subtitle}</div>\n </TextDefaultPropsContext>\n )}\n </div>\n {!!rightActions && <div className={styles.previewSide}>{rightActions}</div>}\n </div>\n </IconDefaultPropsContext>\n);\n\nChatInputPreview.displayName = 'ChatInputPreview';\n"],"names":[],"mappings":";;;;;AAkBA,MAAM,kBAAqB,GAAA;AAAA,EACvB,YAAc,EAAA,WAAA;AAAA,EACd,OAAS,EAAA,CAAA;AACb,CAAA,CAAA;AAIA,MAAM,gBAAmB,GAAA,EAAE,UAAY,EAAA,qBAAA,EAAuB,OAAO,SAAU,EAAA,CAAA;AAC/E,MAAM,sBAAsB,EAAE,UAAA,EAAY,mBAAmB,KAAO,EAAA,WAAA,EAAa,UAAU,IAAK,EAAA,CAAA;AAEzF,MAAM,mBAA8C,CAAC,EAAE,KAAO,EAAA,QAAA,EAAU,aAAa,YAAa,EAAA,qBACpG,GAAA,CAAA,uBAAA,EAAA,EAAwB,OAAO,kBAC5B,EAAA,QAAA,kBAAA,IAAA,CAAC,KAAI,EAAA,EAAA,SAAA,EAAW,OAAO,YAClB,EAAA,QAAA,EAAA;AAAA,EAAA,CAAC,CAAC,WAAe,oBAAA,GAAA,CAAC,SAAI,SAAW,EAAA,MAAA,CAAO,aAAc,QAAY,EAAA,WAAA,EAAA,CAAA;AAAA,kBAClE,IAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,cAClB,EAAA,QAAA,EAAA;AAAA,IAAA,CAAC,CAAC,KAAA,oBACE,GAAA,CAAA,uBAAA,EAAA,EAAwB,KAAO,EAAA,gBAAA,EAC5B,QAAC,kBAAA,GAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,YAAe,EAAA,QAAA,EAAA,KAAA,EAAM,CAChD,EAAA,CAAA;AAAA,IAEH,CAAC,CAAC,QACC,oBAAA,GAAA,CAAC,uBAAwB,EAAA,EAAA,KAAA,EAAO,mBAC5B,EAAA,QAAA,kBAAA,GAAA,CAAC,KAAI,EAAA,EAAA,SAAA,EAAW,MAAO,CAAA,eAAA,EAAkB,oBAAS,CACtD,EAAA,CAAA;AAAA,GAER,EAAA,CAAA;AAAA,EACC,CAAC,CAAC,YAAgB,oBAAA,GAAA,CAAC,SAAI,SAAW,EAAA,MAAA,CAAO,aAAc,QAAa,EAAA,YAAA,EAAA,CAAA;AAAA,CAAA,EACzE,CACJ,EAAA,EAAA;AAGJ,gBAAA,CAAiB,WAAc,GAAA,kBAAA;;;;"}
@@ -1,5 +1,5 @@
1
1
  import { type FC, type MouseEventHandler, type ReactNode } from 'react';
2
- import { type ChatInputButtonAria } from '@hh.ru/magritte-ui-chat-input/types';
2
+ import { type ChatInputButtonAria } from '../types';
3
3
  export interface ChatInputSendButtonProps extends ChatInputButtonAria {
4
4
  /** Доп. обработчик клика — вызывается вместе с `onSend`, а не вместо него */
5
5
  onClick?: MouseEventHandler<HTMLButtonElement>;
@@ -10,30 +10,41 @@ import 'react';
10
10
  import '@hh.ru/magritte-common-use-disabled';
11
11
  import '@hh.ru/magritte-ui-icon';
12
12
 
13
- /**
14
- * Кнопка отправки для слота ChatInput. Обёртка над иконкой с фиксированным оформлением;
15
- * по клику дёргает `onSend` из контекста ChatInput вместе с собственным `onClick`.
16
- */
17
- const ChatInputSendButton = ({ onClick, children, disabled = false, 'aria-label': ariaLabel, ...ariaProps }) => {
18
- const { onSend } = useChatInputContext();
19
- const sendLabel = useTranslation('ChatInput', 'send');
20
- const handleClick = (event) => {
21
- onClick?.(event);
22
- onSend?.();
23
- };
24
- const iconProps = {
25
- // дефолтный data-qa до спреда — пользовательский data-qa из ariaProps его перекрывает
26
- 'data-qa': 'send',
27
- ...ariaProps,
28
- 'aria-label': ariaLabel ?? sendLabel,
29
- initialColor: 'inverse',
30
- backgroundStyle: 'inverse',
31
- disabled,
32
- onClick: handleClick,
33
- };
34
- return (jsx(FocusTarget, { priority: FOCUS_PRIORITY.send, children: jsx(ChatInputSlotButton, { icon: jsx(ArrowUpOutlinedSize24, { ...iconProps }), iconProps: iconProps, disabled: disabled, onClick: handleClick, children: children }) }));
13
+ const ChatInputSendButton = ({
14
+ onClick,
15
+ children,
16
+ disabled = false,
17
+ "aria-label": ariaLabel,
18
+ ...ariaProps
19
+ }) => {
20
+ const { onSend } = useChatInputContext();
21
+ const sendLabel = useTranslation("ChatInput", "send");
22
+ const handleClick = (event) => {
23
+ onClick?.(event);
24
+ onSend?.();
25
+ };
26
+ const iconProps = {
27
+ // дефолтный data-qa до спреда — пользовательский data-qa из ariaProps его перекрывает
28
+ "data-qa": "send",
29
+ ...ariaProps,
30
+ "aria-label": ariaLabel ?? sendLabel,
31
+ initialColor: "inverse",
32
+ backgroundStyle: "inverse",
33
+ disabled,
34
+ onClick: handleClick
35
+ };
36
+ return /* @__PURE__ */ jsx(FocusTarget, { priority: FOCUS_PRIORITY.send, children: /* @__PURE__ */ jsx(
37
+ ChatInputSlotButton,
38
+ {
39
+ icon: /* @__PURE__ */ jsx(ArrowUpOutlinedSize24, { ...iconProps }),
40
+ iconProps,
41
+ disabled,
42
+ onClick: handleClick,
43
+ children
44
+ }
45
+ ) });
35
46
  };
36
- ChatInputSendButton.displayName = 'ChatInputSendButton';
47
+ ChatInputSendButton.displayName = "ChatInputSendButton";
37
48
 
38
49
  export { ChatInputSendButton };
39
50
  //# sourceMappingURL=ChatInputSendButton.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInputSendButton.js","sources":["src/public/ChatInputSendButton.tsx"],"sourcesContent":["import { type FC, type MouseEvent, type MouseEventHandler, type ReactNode } from 'react';\n\nimport { useTranslation } from '@hh.ru/magritte-common-use-translation';\nimport { useChatInputContext } from '@hh.ru/magritte-ui-chat-input/internal/ChatInputContext';\nimport { ChatInputSlotButton } from '@hh.ru/magritte-ui-chat-input/internal/ChatInputSlotButton';\nimport { FocusTarget } from '@hh.ru/magritte-ui-chat-input/internal/FocusTarget';\nimport { FOCUS_PRIORITY } from '@hh.ru/magritte-ui-chat-input/internal/focusGroup';\nimport { type ChatInputButtonAria } from '@hh.ru/magritte-ui-chat-input/types';\nimport { ArrowUpOutlinedSize24 } from '@hh.ru/magritte-ui-icon/icon';\n\nexport interface ChatInputSendButtonProps extends ChatInputButtonAria {\n /** Доп. обработчик клика — вызывается вместе с `onSend`, а не вместо него */\n onClick?: MouseEventHandler<HTMLButtonElement>;\n /**\n * Блокирует кнопку отправки независимо от общего `disabled` компонента `ChatInput`\n * @default false\n */\n disabled?: boolean;\n /** Кастомный контент вместо иконки отправки. Иконку в children оформляем как встроенную\n * (через IconDefaultPropsContext); клик по любому content ловится в любом случае */\n children?: ReactNode;\n}\n\n/**\n * Кнопка отправки для слота ChatInput. Обёртка над иконкой с фиксированным оформлением;\n * по клику дёргает `onSend` из контекста ChatInput вместе с собственным `onClick`.\n */\nexport const ChatInputSendButton: FC<ChatInputSendButtonProps> = ({\n onClick,\n children,\n disabled = false,\n 'aria-label': ariaLabel,\n ...ariaProps\n}) => {\n const { onSend } = useChatInputContext();\n const sendLabel = useTranslation('ChatInput', 'send');\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n onSend?.();\n };\n\n const iconProps = {\n // дефолтный data-qa до спреда — пользовательский data-qa из ariaProps его перекрывает\n 'data-qa': 'send',\n ...ariaProps,\n 'aria-label': ariaLabel ?? sendLabel,\n initialColor: 'inverse',\n backgroundStyle: 'inverse',\n disabled,\n onClick: handleClick,\n } as const;\n\n return (\n <FocusTarget priority={FOCUS_PRIORITY.send}>\n <ChatInputSlotButton\n icon={<ArrowUpOutlinedSize24 {...iconProps} />}\n iconProps={iconProps}\n disabled={disabled}\n onClick={handleClick}\n >\n {children}\n </ChatInputSlotButton>\n </FocusTarget>\n );\n};\n\nChatInputSendButton.displayName = 'ChatInputSendButton';\n"],"names":["_jsx"],"mappings":";;;;;;;;;;;AAuBA;;;AAGG;MACU,mBAAmB,GAAiC,CAAC,EAC9D,OAAO,EACP,QAAQ,EACR,QAAQ,GAAG,KAAK,EAChB,YAAY,EAAE,SAAS,EACvB,GAAG,SAAS,EACf,KAAI;AACD,IAAA,MAAM,EAAE,MAAM,EAAE,GAAG,mBAAmB,EAAE,CAAC;IACzC,MAAM,SAAS,GAAG,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AAEtD,IAAA,MAAM,WAAW,GAAG,CAAC,KAAoC,KAAI;AACzD,QAAA,OAAO,GAAG,KAAK,CAAC,CAAC;QACjB,MAAM,IAAI,CAAC;AACf,KAAC,CAAC;AAEF,IAAA,MAAM,SAAS,GAAG;;AAEd,QAAA,SAAS,EAAE,MAAM;AACjB,QAAA,GAAG,SAAS;QACZ,YAAY,EAAE,SAAS,IAAI,SAAS;AACpC,QAAA,YAAY,EAAE,SAAS;AACvB,QAAA,eAAe,EAAE,SAAS;QAC1B,QAAQ;AACR,QAAA,OAAO,EAAE,WAAW;KACd,CAAC;AAEX,IAAA,QACIA,GAAC,CAAA,WAAW,EAAC,EAAA,QAAQ,EAAE,cAAc,CAAC,IAAI,EAAA,QAAA,EACtCA,IAAC,mBAAmB,EAAA,EAChB,IAAI,EAAEA,IAAC,qBAAqB,EAAA,EAAA,GAAK,SAAS,EAAA,CAAI,EAC9C,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,WAAW,EAAA,QAAA,EAEnB,QAAQ,EACS,CAAA,EAAA,CACZ,EAChB;AACN,EAAE;AAEF,mBAAmB,CAAC,WAAW,GAAG,qBAAqB;;;;"}
1
+ {"version":3,"file":"ChatInputSendButton.js","sources":["src/public/ChatInputSendButton.tsx"],"sourcesContent":["import { type FC, type MouseEvent, type MouseEventHandler, type ReactNode } from 'react';\n\nimport { useTranslation } from '@hh.ru/magritte-common-use-translation';\nimport { useChatInputContext } from '@hh.ru/magritte-ui-chat-input/internal/ChatInputContext';\nimport { ChatInputSlotButton } from '@hh.ru/magritte-ui-chat-input/internal/ChatInputSlotButton';\nimport { FocusTarget } from '@hh.ru/magritte-ui-chat-input/internal/FocusTarget';\nimport { FOCUS_PRIORITY } from '@hh.ru/magritte-ui-chat-input/internal/focusGroup';\nimport { type ChatInputButtonAria } from '@hh.ru/magritte-ui-chat-input/types';\nimport { ArrowUpOutlinedSize24 } from '@hh.ru/magritte-ui-icon/icon';\n\nexport interface ChatInputSendButtonProps extends ChatInputButtonAria {\n /** Доп. обработчик клика — вызывается вместе с `onSend`, а не вместо него */\n onClick?: MouseEventHandler<HTMLButtonElement>;\n /**\n * Блокирует кнопку отправки независимо от общего `disabled` компонента `ChatInput`\n * @default false\n */\n disabled?: boolean;\n /** Кастомный контент вместо иконки отправки. Иконку в children оформляем как встроенную\n * (через IconDefaultPropsContext); клик по любому content ловится в любом случае */\n children?: ReactNode;\n}\n\n/**\n * Кнопка отправки для слота ChatInput. Обёртка над иконкой с фиксированным оформлением;\n * по клику дёргает `onSend` из контекста ChatInput вместе с собственным `onClick`.\n */\nexport const ChatInputSendButton: FC<ChatInputSendButtonProps> = ({\n onClick,\n children,\n disabled = false,\n 'aria-label': ariaLabel,\n ...ariaProps\n}) => {\n const { onSend } = useChatInputContext();\n const sendLabel = useTranslation('ChatInput', 'send');\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n onSend?.();\n };\n\n const iconProps = {\n // дефолтный data-qa до спреда — пользовательский data-qa из ariaProps его перекрывает\n 'data-qa': 'send',\n ...ariaProps,\n 'aria-label': ariaLabel ?? sendLabel,\n initialColor: 'inverse',\n backgroundStyle: 'inverse',\n disabled,\n onClick: handleClick,\n } as const;\n\n return (\n <FocusTarget priority={FOCUS_PRIORITY.send}>\n <ChatInputSlotButton\n icon={<ArrowUpOutlinedSize24 {...iconProps} />}\n iconProps={iconProps}\n disabled={disabled}\n onClick={handleClick}\n >\n {children}\n </ChatInputSlotButton>\n </FocusTarget>\n );\n};\n\nChatInputSendButton.displayName = 'ChatInputSendButton';\n"],"names":[],"mappings":";;;;;;;;;;;AA2BO,MAAM,sBAAoD,CAAC;AAAA,EAC9D,OAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAW,GAAA,KAAA;AAAA,EACX,YAAc,EAAA,SAAA;AAAA,EACd,GAAG,SAAA;AACP,CAAM,KAAA;AACF,EAAM,MAAA,EAAE,MAAO,EAAA,GAAI,mBAAoB,EAAA,CAAA;AACvC,EAAM,MAAA,SAAA,GAAY,cAAe,CAAA,WAAA,EAAa,MAAM,CAAA,CAAA;AAEpD,EAAM,MAAA,WAAA,GAAc,CAAC,KAAyC,KAAA;AAC1D,IAAA,OAAA,GAAU,KAAK,CAAA,CAAA;AACf,IAAS,MAAA,IAAA,CAAA;AAAA,GACb,CAAA;AAEA,EAAA,MAAM,SAAY,GAAA;AAAA;AAAA,IAEd,SAAW,EAAA,MAAA;AAAA,IACX,GAAG,SAAA;AAAA,IACH,cAAc,SAAa,IAAA,SAAA;AAAA,IAC3B,YAAc,EAAA,SAAA;AAAA,IACd,eAAiB,EAAA,SAAA;AAAA,IACjB,QAAA;AAAA,IACA,OAAS,EAAA,WAAA;AAAA,GACb,CAAA;AAEA,EAAA,uBACK,GAAA,CAAA,WAAA,EAAA,EAAY,QAAU,EAAA,cAAA,CAAe,IAClC,EAAA,QAAA,kBAAA,GAAA;AAAA,IAAC,mBAAA;AAAA,IAAA;AAAA,MACG,IAAM,kBAAA,GAAA,CAAC,qBAAuB,EAAA,EAAA,GAAG,SAAW,EAAA,CAAA;AAAA,MAC5C,SAAA;AAAA,MACA,QAAA;AAAA,MACA,OAAS,EAAA,WAAA;AAAA,MAER,QAAA;AAAA,KAAA;AAAA,GAET,EAAA,CAAA,CAAA;AAER,EAAA;AAEA,mBAAA,CAAoB,WAAc,GAAA,qBAAA;;;;"}
@@ -1,5 +1,5 @@
1
1
  import { type FC, type MouseEventHandler, type ReactNode } from 'react';
2
- import { type ChatInputButtonAria, type ChatInputVoiceRecordConfig } from '@hh.ru/magritte-ui-chat-input/types';
2
+ import { type ChatInputButtonAria, type ChatInputVoiceRecordConfig } from '../types';
3
3
  export interface ChatInputVoiceButtonProps extends ChatInputButtonAria, ChatInputVoiceRecordConfig {
4
4
  /** Доп. обработчик клика — вызывается вместе со стартом записи, а не вместо него */
5
5
  onClick?: MouseEventHandler<HTMLButtonElement>;