@rt-tools/ui-kit-v2 0.13.1 → 0.14.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 (69) hide show
  1. package/README.md +25 -5
  2. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +45 -9
  3. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
  4. package/fesm2022/rt-tools-ui-kit-v2.mjs +2265 -664
  5. package/fesm2022/rt-tools-ui-kit-v2.mjs.map +1 -1
  6. package/package.json +1 -1
  7. package/rt-tools-ui-kit-v2-0.14.0.tgz +0 -0
  8. package/src/lib/components/CONTEXT.md +1 -1
  9. package/src/lib/components/action-bar/rt-action-bar.component.scss +5 -0
  10. package/src/lib/components/autocomplete/rt-autocomplete.component.scss +8 -1
  11. package/src/lib/components/bottom-sheet/rt-bottom-sheet.component.scss +5 -0
  12. package/src/lib/components/button/CONTEXT.md +1 -1
  13. package/src/lib/components/button/rt-button.directive.scss +5 -7
  14. package/src/lib/components/calendar/CONTEXT.md +16 -2
  15. package/src/lib/components/calendar/rt-calendar.component.scss +81 -4
  16. package/src/lib/components/card/rt-card.component.scss +5 -0
  17. package/src/lib/components/checkbox/rt-checkbox.component.scss +5 -0
  18. package/src/lib/components/data-list/settings/rt-data-list-settings-aside.component.scss +1 -1
  19. package/src/lib/components/data-list/toolbar/rt-data-list-toolbar.component.scss +1 -1
  20. package/src/lib/components/data-table/cell/rt-data-table-cell.component.scss +1 -1
  21. package/src/lib/components/data-table/filter-cell/rt-data-table-filter-cell.component.scss +1 -1
  22. package/src/lib/components/data-table/rt-data-table.component.scss +1 -1
  23. package/src/lib/components/date-picker/CONTEXT.md +33 -14
  24. package/src/lib/components/date-picker/panel/rt-date-panel.component.scss +155 -0
  25. package/src/lib/components/date-picker/rt-date-picker.component.scss +18 -2
  26. package/src/lib/components/date-range/CONTEXT.md +53 -0
  27. package/src/lib/components/date-range/panel/rt-date-range-panel.component.scss +103 -0
  28. package/src/lib/components/date-range/rt-date-range.component.scss +120 -0
  29. package/src/lib/components/dialog/rt-dialog.component.scss +5 -0
  30. package/src/lib/components/empty-state/rt-empty-state.component.scss +5 -0
  31. package/src/lib/components/file-card/rt-file-card.component.scss +5 -0
  32. package/src/lib/components/file-drop/rt-file-drop.component.scss +5 -0
  33. package/src/lib/components/header/rt-header.component.scss +5 -0
  34. package/src/lib/components/icon-button/CONTEXT.md +1 -1
  35. package/src/lib/components/icon-button/rt-icon-button.component.scss +9 -29
  36. package/src/lib/components/input/rt-input.component.scss +7 -1
  37. package/src/lib/components/input-number/rt-input-number.component.scss +7 -1
  38. package/src/lib/components/markdown-text/rt-markdown-text.component.scss +5 -0
  39. package/src/lib/components/menu/rt-menu-item.component.scss +5 -0
  40. package/src/lib/components/message/rt-message.component.scss +5 -0
  41. package/src/lib/components/money-list/rt-money-list.component.scss +5 -0
  42. package/src/lib/components/multiselect/CONTEXT.md +12 -5
  43. package/src/lib/components/multiselect/rt-multiselect.component.scss +32 -1
  44. package/src/lib/components/note/rt-note.component.scss +5 -0
  45. package/src/lib/components/notifications-bell/rt-notifications-bell.component.scss +5 -0
  46. package/src/lib/components/pagination/rt-pagination.component.scss +6 -1
  47. package/src/lib/components/radio-button/rt-radio-button.component.scss +5 -0
  48. package/src/lib/components/section-nav/rt-section-nav.component.scss +5 -0
  49. package/src/lib/components/select/CONTEXT.md +10 -7
  50. package/src/lib/components/select/rt-select.component.scss +36 -1
  51. package/src/lib/components/skeleton/CONTEXT.md +14 -16
  52. package/src/lib/components/skeleton/rt-skeleton.component.scss +7 -1
  53. package/src/lib/components/skeleton-wrapper/CONTEXT.md +6 -6
  54. package/src/lib/components/split-button/rt-split-button.component.scss +6 -0
  55. package/src/lib/components/stepper/rt-stepper.component.scss +5 -0
  56. package/src/lib/components/table/rt-table.component.scss +12 -0
  57. package/src/lib/components/tag/CONTEXT.md +14 -15
  58. package/src/lib/components/tag/rt-tag.component.scss +6 -30
  59. package/src/lib/components/textarea/rt-textarea.component.scss +8 -1
  60. package/src/lib/components/thread-list/rt-thread-list.component.scss +5 -0
  61. package/src/lib/components/toggle-button-group/rt-toggle-button-group.component.scss +7 -6
  62. package/src/lib/components/toggle-switch/rt-toggle-switch.component.scss +5 -0
  63. package/src/rich-editor/lib/components/message-composer/CONTEXT.md +11 -1
  64. package/src/rich-editor/lib/components/message-composer/rt-message-composer.component.scss +78 -34
  65. package/src/styles/_mixins.scss +39 -0
  66. package/styles/tokens.css +30 -5
  67. package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +11 -5
  68. package/types/rt-tools-ui-kit-v2.d.ts +394 -109
  69. package/rt-tools-ui-kit-v2-0.13.1.tgz +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-rich-editor.mjs","sources":["../../../projects/ui-kit-v2/src/rich-editor/lib/components/rich-editor/rt-rich-editor.component.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/rich-editor/rt-rich-editor.component.html","../../../projects/ui-kit-v2/src/rich-editor/lib/components/message-composer/rt-message-composer.component.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/message-composer/rt-message-composer.component.html","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat-message-actions.directive.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat-message-actions.logic.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat-message-actions.pipe.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat.model.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/pipes/rt-chat-status-label.pipe.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat-files.logic.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat-thread.logic.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat.component.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat.component.html","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/to-rt-message.ts","../../../projects/ui-kit-v2/src/rich-editor/public-api.ts","../../../projects/ui-kit-v2/src/rich-editor/rt-tools-ui-kit-v2-rich-editor.ts"],"sourcesContent":["import {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n computed,\n ElementRef,\n forwardRef,\n input,\n InputSignal,\n OnDestroy,\n output,\n OutputEmitterRef,\n Signal,\n signal,\n viewChild,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport type Quill from 'quill';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { coerceQuillDeltaOutput, IQuillDelta, IQuillDeltaOp, RtFormControlBase } from '@rt-tools/ui-kit-v2';\n\nconst BEM_BLOCK: string = 'rt-rich-editor';\n\n/**\n * Режим тулбара: `full` — весь whitelist, `minimal` — жирный + два списка\n * (G113: чаты оператора/админа/саппорта).\n */\nexport type TRtRichEditorToolbar = 'full' | 'minimal';\n\n/** Модули тулбара — строго whitelist (без link/image/color/script). */\nconst TOOLBAR: Record<TRtRichEditorToolbar, readonly unknown[]> = {\n full: [\n ['bold', 'italic', 'underline', 'strike'],\n [{ header: 1 }, { header: 2 }, { header: 3 }],\n [{ list: 'ordered' }, { list: 'bullet' }],\n ['blockquote', 'code-block'],\n ],\n minimal: [['bold'], [{ list: 'ordered' }, { list: 'bullet' }]],\n};\n\n/** Форматы, которые Quill вообще примет (вставленное из буфера лишнее вырезается). */\nconst FORMATS: Record<TRtRichEditorToolbar, readonly string[]> = {\n full: ['bold', 'italic', 'underline', 'strike', 'header', 'list', 'blockquote', 'code-block'],\n minimal: ['bold', 'list'],\n};\n\ntype TQuillContentsArg = Parameters<Quill['setContents']>[0];\n\n/**\n * Rich-редактор чата на Quill. Наследует CVA-ядро input-семейства\n * (`RtFormControlBase`) — плагается в reactive-форму. Quill грузится **лениво**\n * (`import(\"quill\")` в `ngAfterViewInit`), тип импортируется `import type` и в\n * бандл не попадает. Значение CVA — `IQuillDelta` (или `null`, когда пусто).\n */\n@Component({\n selector: 'rt-rich-editor',\n templateUrl: './rt-rich-editor.component.html',\n styleUrl: './rt-rich-editor.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n BlockDirective,\n ElemDirective,\n ],\n providers: [\n // Алиас базового токена — чтобы rt-field мог найти контрол через\n // contentChild(RtFormControlBase) (query по абстрактному классу).\n { provide: RtFormControlBase, useExisting: forwardRef(() => RtRichEditorComponent) },\n ],\n host: {\n class: BEM_BLOCK,\n // Пока начинка редактора не смонтирована, хост несёт признак недостроенности: снаружи\n // недостроенный редактор ничем не отличается от достроенного пустого, и съёмка витрины\n // ловила именно этот промежуток — кадр выходил втрое ниже эталона.\n '[attr.data-rt-pending]': 'mounted() ? null : \"\"',\n },\n})\nexport class RtRichEditorComponent extends RtFormControlBase<IQuillDelta | null> implements AfterViewInit, OnDestroy {\n // `viewChild` не работает на ES-private (`#`) поле — держим `protected`.\n protected readonly editorHost: Signal<ElementRef<HTMLElement>> = viewChild.required<ElementRef<HTMLElement>>('editor');\n\n #quill: Quill | null = null;\n\n /** Значение, пришедшее через writeValue до готовности Quill. */\n #pending: IQuillDelta | null = null;\n\n /**\n * Смонтирована ли начинка редактора. Пока нет, хост несёт признак недостроенности: съёмке\n * витрины и любой другой проверке снаружи иначе нечем отличить недостроенный редактор от\n * достроенного пустого — оба выглядят пустым местом.\n */\n protected readonly mounted: WritableSignal<boolean> = signal<boolean>(false);\n\n protected readonly hasValue: Signal<boolean> = computed((): boolean => this.value() !== null);\n\n public readonly placeholder: InputSignal<string> = input<string>('');\n\n /** Набор кнопок форматирования; сужает и принимаемые форматы (вставка из буфера). */\n public readonly toolbar: InputSignal<TRtRichEditorToolbar> = input<TRtRichEditorToolbar>('full');\n\n /** Enter без Shift в редакторе — сигнал отправки (Shift+Enter остаётся переносом). */\n public readonly enterPressed: OutputEmitterRef<void> = output<void>();\n\n public readonly displayText: Signal<string> = computed((): string => {\n const delta: IQuillDelta | null = this.value();\n if (delta === null) {\n return '';\n }\n return delta.ops.map((op: IQuillDeltaOp): string => op.insert).join('');\n });\n\n public async ngAfterViewInit(): Promise<void> {\n const QuillCtor: typeof Quill = (await import('quill')).default;\n const quill: Quill = new QuillCtor(this.editorHost().nativeElement, {\n theme: 'snow',\n placeholder: this.placeholder(),\n formats: [...FORMATS[this.toolbar()]],\n modules: {\n toolbar: [...TOOLBAR[this.toolbar()]],\n keyboard: {\n bindings: {\n // Enter без Shift — отправка (перенос гасим возвратом false);\n // Shift+Enter не совпадает с биндингом и уходит в дефолт (перенос).\n enterSubmit: {\n key: 'Enter',\n shiftKey: false,\n handler: (): boolean => {\n this.enterPressed.emit();\n return false;\n },\n },\n },\n },\n },\n });\n this.#quill = quill;\n if (this.#pending !== null) {\n quill.setContents(this.#pending as unknown as TQuillContentsArg);\n this.#pending = null;\n }\n if (this.isDisabled()) {\n quill.disable();\n }\n quill.on('text-change', (): void => this.#onEditorChange());\n this.mounted.set(true);\n }\n\n public ngOnDestroy(): void {\n this.#quill = null;\n this.mounted.set(false);\n }\n\n public override writeValue(value: IQuillDelta | null): void {\n super.writeValue(value);\n if (this.#quill === null) {\n this.#pending = value;\n return;\n }\n this.#quill.setContents((value ?? { ops: [] }) as unknown as TQuillContentsArg);\n }\n\n public override setDisabledState(isDisabled: boolean): void {\n super.setDisabledState(isDisabled);\n if (this.#quill === null) {\n return;\n }\n if (isDisabled) {\n this.#quill.disable();\n return;\n }\n this.#quill.enable();\n }\n\n protected getEmptyValue(): IQuillDelta | null {\n return null;\n }\n\n protected focusAfterClear(): void {\n this.#quill?.focus();\n }\n\n /** Text-change: пустой слепок → null-канал; иначе delta. */\n #onEditorChange(): void {\n if (this.#quill === null) {\n return;\n }\n const blank: boolean = this.#quill.getText().trim().length === 0;\n const next: IQuillDelta | null = blank\n ? null\n : coerceQuillDeltaOutput({\n ops: this.#quill.getContents().ops as unknown as IQuillDeltaOp[],\n });\n this.value.set(next);\n this.emitChange(next);\n this.markTouched();\n }\n}\n","<ng-container rtBlock=\"rt-rich-editor\">\n <div #editor rtElem=\"surface\" qa-dataid=\"rich-editor-surface\"></div>\n</ng-container>\n","import { BooleanInput, NumberInput } from '@angular/cdk/coercion';\nimport { CdkTextareaAutosize } from '@angular/cdk/text-field';\nimport {\n booleanAttribute,\n computed,\n effect,\n inject,\n input,\n numberAttribute,\n output,\n viewChild,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n InputSignal,\n InputSignalWithTransform,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n} from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { IQuillDelta, RT_KIT_LABELS, RtFileCardComponent, RtIconButtonComponent, rtKitLabel, TRtKitLabelMap } from '@rt-tools/ui-kit-v2';\n\nimport { RtRichEditorComponent, TRtRichEditorToolbar } from '../rich-editor/rt-rich-editor.component';\nimport { IRtMessageComposer } from './rt-message-composer.model';\n\nconst BEM_BLOCK: string = 'rt-message-composer';\n\ninterface IComposerFormShape {\n message: FormControl<string>;\n files: FormControl<File[]>;\n delta: FormControl<IQuillDelta | null>;\n}\n\n/**\n * Композер сообщения: авто-растущая textarea сверху, под разделительной линией —\n * ряд контролов (слева — прикрепить файл, справа — отправить). Презентационный,\n * без data-access: наружу торчит только `submitted` с текстом и файлами.\n *\n * Отправка — `Enter` (без Shift) или клик по иконке; `Shift+Enter` — перенос\n * строки. Кнопка отправки активна, пока есть непустой текст или вложения.\n */\n@Component({\n selector: 'rt-message-composer',\n templateUrl: './rt-message-composer.component.html',\n styleUrl: './rt-message-composer.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // angular\n ReactiveFormsModule,\n\n // cdk\n CdkTextareaAutosize,\n\n // standalone components / directives\n RtFileCardComponent,\n RtIconButtonComponent,\n RtRichEditorComponent,\n BlockDirective,\n ElemDirective,\n ],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtMessageComposerComponent {\n readonly #formValue: Signal<Partial<{ message: string; files: File[]; delta: IQuillDelta | null }>>;\n\n readonly #t_chatPlaceholder: Signal<string> = rtKitLabel('chatPlaceholder');\n\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly placeholderText: Signal<string> = computed((): string => this.placeholder() || this.#t_chatPlaceholder());\n\n protected readonly fileInput: Signal<ElementRef<HTMLInputElement> | undefined> = viewChild<ElementRef<HTMLInputElement>>('fileEl');\n\n protected readonly form: FormGroup<IComposerFormShape> = new FormGroup<IComposerFormShape>({\n message: new FormControl<string>('', { nonNullable: true }),\n files: new FormControl<File[]>([], { nonNullable: true }),\n delta: new FormControl<IQuillDelta | null>(null),\n });\n\n protected readonly files: Signal<readonly File[]> = computed((): readonly File[] => this.#formValue().files ?? []);\n\n /** Отправка доступна: есть контент (текст/delta/файлы), композер не занят. */\n protected readonly canSend: Signal<boolean> = computed((): boolean => {\n if (this.sending() || this.disabled()) {\n return false;\n }\n const value: Partial<{ message: string; files: File[]; delta: IQuillDelta | null }> = this.#formValue();\n const hasFiles: boolean = this.attachments() && (value.files?.length ?? 0) > 0;\n if (this.formatting()) {\n return (value.delta ?? null) !== null || hasFiles;\n }\n const hasText: boolean = (value.message ?? '').trim().length > 0;\n return hasText || hasFiles;\n });\n\n /** Текст-подсказка textarea. Пусто — берётся переведённое умолчание. */\n public readonly placeholder: InputSignal<string> = input<string>('');\n\n /** Фильтр типов для file-input (`.pdf,.doc,...`). */\n public readonly accept: InputSignal<string> = input<string>('');\n\n /** Показывать кнопку вложения и список файлов. */\n public readonly attachments: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Отправка в процессе — блокирует submit и показывает её недоступность. */\n public readonly sending: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Полная блокировка композера. */\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Rich-режим: вместо textarea — Quill-редактор, отправка уходит delta-каналом. */\n public readonly formatting: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Набор кнопок rich-редактора (проброс в `rt-rich-editor`). */\n public readonly toolbar: InputSignal<TRtRichEditorToolbar> = input<TRtRichEditorToolbar>('full');\n\n /** Минимальная высота textarea в строках. */\n public readonly minRows: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(1, { transform: numberAttribute });\n\n /** Максимальная высота textarea в строках (дальше — скролл). */\n public readonly maxRows: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(6, { transform: numberAttribute });\n\n /**\n * Файлы, выброшенные drag-n-drop'ом в обёртку чата: пробрасываются сюда как\n * вложения. Каждый физический drop даёт новый массив, поэтому effect\n * перезапускается на каждое перетаскивание; файлы добавляются к уже выбранным.\n */\n public readonly droppedFiles: InputSignal<File[] | null> = input<File[] | null>(null);\n\n /** Отправка сообщения: текст + файлы (последние — только при `attachments`). */\n public readonly submitted: OutputEmitterRef<IRtMessageComposer.SubmitPayload> = output<IRtMessageComposer.SubmitPayload>();\n\n constructor() {\n this.#formValue = toSignal(this.form.valueChanges, {\n initialValue: this.form.value,\n });\n\n effect((): void => {\n const blocked: boolean = this.disabled() || this.sending();\n if (blocked && this.form.enabled) {\n this.form.disable({ emitEvent: false });\n }\n if (!blocked && this.form.disabled) {\n this.form.enable({ emitEvent: false });\n }\n });\n\n effect((): void => {\n const dropped: File[] | null = this.droppedFiles();\n if (dropped !== null && dropped.length > 0 && this.attachments()) {\n this.form.controls.files.setValue([...this.form.controls.files.value, ...dropped]);\n }\n });\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n // Enter без модификаторов — отправка; Shift+Enter оставляем переносом строки.\n // isComposing — не перехватываем подтверждение IME-композиции.\n if (event.key === 'Enter' && !event.shiftKey && !event.isComposing) {\n event.preventDefault();\n this.submit();\n }\n }\n\n protected openPicker(): void {\n if (this.disabled() || this.sending()) {\n return;\n }\n this.fileInput()?.nativeElement.click();\n }\n\n protected onFilesPicked(event: Event): void {\n const el: HTMLInputElement = event.target as HTMLInputElement;\n const picked: File[] = el.files ? Array.from(el.files) : [];\n if (picked.length) {\n this.form.controls.files.setValue([...this.form.controls.files.value, ...picked]);\n }\n // Сброс value — чтобы повторный выбор того же файла снова дал change-событие.\n el.value = '';\n }\n\n protected removeFile(index: number): void {\n const next: File[] = this.form.controls.files.value.filter((_: File, i: number): boolean => i !== index);\n this.form.controls.files.setValue(next);\n }\n\n protected submit(): void {\n if (!this.canSend()) {\n return;\n }\n const files: File[] = this.attachments() ? this.form.controls.files.value : [];\n if (this.formatting()) {\n const delta: IQuillDelta | null = this.form.controls.delta.value;\n this.submitted.emit({\n text: '',\n delta: delta === null ? null : JSON.stringify(delta),\n files,\n });\n } else {\n const text: string = this.form.controls.message.value.trim();\n this.submitted.emit({ text, files });\n }\n this.form.reset({ message: '', files: [], delta: null });\n }\n}\n","<ng-container rtBlock=\"rt-message-composer\" [formGroup]=\"form\">\n @if (formatting()) {\n <rt-rich-editor\n qa-dataid=\"message-composer-rich\"\n formControlName=\"delta\"\n [placeholder]=\"placeholderText()\"\n [toolbar]=\"toolbar()\"\n (enterPressed)=\"submit()\" />\n } @else {\n <textarea\n rtElem=\"input\"\n qa-dataid=\"message-composer-input\"\n cdkTextareaAutosize\n formControlName=\"message\"\n [attr.aria-label]=\"t().chatComposerAria\"\n [placeholder]=\"placeholderText()\"\n [cdkAutosizeMinRows]=\"minRows()\"\n [cdkAutosizeMaxRows]=\"maxRows()\"\n (keydown)=\"onKeydown($event)\"></textarea>\n }\n\n @if (attachments() && files().length) {\n <div rtElem=\"files\" qa-dataid=\"message-composer-files\">\n @for (file of files(); track $index) {\n <rt-file-card\n showRemove\n qa-dataid=\"message-composer-file\"\n size=\"sm\"\n [name]=\"file.name\"\n [sizeBytes]=\"file.size\"\n [disabled]=\"disabled() || sending()\"\n (removed)=\"removeFile($index)\" />\n }\n </div>\n }\n\n <div rtElem=\"divider\"></div>\n\n <div rtElem=\"controls\">\n @if (attachments()) {\n <input\n #fileEl\n qa-dataid=\"message-composer-file-input\"\n type=\"file\"\n hidden\n multiple\n [attr.accept]=\"accept() || null\"\n (change)=\"onFilesPicked($event)\" />\n <rt-icon-button\n qa-dataid=\"message-composer-attach\"\n icon=\"paperclip\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatAttachAria\"\n [tooltip]=\"t().chatAttachTooltip\"\n [disabled]=\"disabled() || sending()\"\n (clicked)=\"openPicker()\" />\n }\n\n <rt-icon-button\n rtElem=\"send\"\n qa-dataid=\"message-composer-send\"\n icon=\"send\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatSendAria\"\n [tooltip]=\"t().chatSendLabel\"\n [disabled]=\"!canSend()\"\n (clicked)=\"submit()\" />\n </div>\n</ng-container>\n","import { Directive, inject, TemplateRef } from '@angular/core';\n\nimport { IRtChat } from './rt-chat.model';\n\n/**\n * Контекст шаблона `[rtChatMessageActions]`: `$implicit` — реплика треда.\n */\nexport interface IRtChatMessageActionsContext {\n $implicit: IRtChat.Message;\n}\n\n/**\n * Захватывает `<ng-template rtChatMessageActions let-message>` — содержимое «…»-меню\n * действий у реплики. `rt-chat` рисует этот шаблон рядом с точечными действиями реплики,\n * прокидывая её через `$implicit`.\n *\n * Точечные действия остаются на месте: удаление, повтор отправки и скачивание общи для\n * любой переписки. Шаблон нужен тем действиям, которых кит не знает и знать не должен, —\n * без него потребителю оставалось ждать правки кита либо ставить кнопку над диалогом, то\n * есть не там, где читают реплику.\n *\n * Дженерика у контекста нет: тип реплики у переписки один, и type-carrier, который у\n * строки таблицы несёт тип строки, здесь не нужен.\n *\n * @example\n * ```html\n * <rt-chat [messages]=\"messages()\" [messageHasActions]=\"canAct\">\n * <ng-template rtChatMessageActions let-message>\n * <rt-menu-item icon=\"link\" label=\"Скопировать ссылку\" (selected)=\"copy(message)\" />\n * </ng-template>\n * </rt-chat>\n * ```\n */\n@Directive({\n selector: 'ng-template[rtChatMessageActions]',\n})\nexport class RtChatMessageActionsDirective {\n public readonly template: TemplateRef<IRtChatMessageActionsContext> = inject<TemplateRef<IRtChatMessageActionsContext>>(TemplateRef);\n\n /** Type-guard: сужает контекст шаблона до реплики при проверке шаблонов. */\n public static ngTemplateContextGuard(\n _directive: RtChatMessageActionsDirective,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- второй довод стража контекста шаблона стоит только в типе-предикате; убрать его нечем, подпись задаёт каркас\n context: unknown\n ): context is IRtChatMessageActionsContext {\n return true;\n }\n}\n","import { IRtChat } from './rt-chat.model';\n\n/**\n * Есть ли у реплики хотя бы одно доступное действие потребителя.\n *\n * Признак приходит предикатом от экрана, а не подсчётом отрисованных пунктов меню:\n * содержимое спроецированного шаблона известно только после отрисовки, и кнопка\n * успевала бы мигнуть на первом кадре.\n *\n * Предикат не задан — у реплики есть действия: экран, который ничего не гейтит,\n * показывает кнопку меню. Так же это устроено у строки таблицы, и расхождение между\n * двумя точками проекции одного кита читалось бы дефектом.\n */\nexport function messageHasAvailableActions(message: IRtChat.Message, hasActions: IRtChat.MessageActionsPredicate | null): boolean {\n return hasActions === null ? true : hasActions(message);\n}\n","import { Pipe, PipeTransform } from '@angular/core';\n\nimport { messageHasAvailableActions } from './rt-chat-message-actions.logic';\nimport { IRtChat } from './rt-chat.model';\n\n/**\n * Есть ли у реплики доступные действия — гейт кнопки «…» у неё.\n *\n * Pure-pipe: пересчитывается только при смене реплики или предиката, а не на каждом\n * цикле проверки. Значение приходит из контекста шаблона (реплика треда), поэтому\n * `computed()` здесь неприменим.\n */\n@Pipe({ name: 'rtChatMessageHasActions' })\nexport class RtChatMessageHasActionsPipe implements PipeTransform {\n public transform(message: IRtChat.Message, hasActions: IRtChat.MessageActionsPredicate | null): boolean {\n return messageHasAvailableActions(message, hasActions);\n }\n}\n","import { IQuillDelta } from '@rt-tools/ui-kit-v2';\n\n/**\n * Модель общего чат-компонента `rt-chat`: один корневой неймспейс\n * с префиксом `I`. Доменные стора маппят свою модель сообщения в `Message`, а сам\n * `rt-chat` ничего не знает о доменных сущностях — только рисует тред и композер.\n */\n/**\n * Судьба своего сообщения в ленте: пока летит на сервер — часы, после записи —\n * двойной чек, после того как собеседник открыл переписку — тот же чек синим,\n * при обрыве — «!» с повтором. Входящие сообщения статуса не имеют.\n */\nexport enum ERtChatMessageStatus {\n Sending = 'sending',\n Sent = 'sent',\n Read = 'read',\n Failed = 'failed',\n}\n\nexport namespace IRtChat {\n /** Алиас enum'а для доменных мапперов, работающих через неймспейс. */\n export type MessageStatus = ERtChatMessageStatus;\n\n /**\n * Есть ли у реплики доступные действия потребителя — гейт кнопки «…» у неё.\n *\n * Признак приходит предикатом, а не полем модели: действие, которого кит не знает,\n * его моделью и не описывается.\n */\n export type MessageActionsPredicate = (message: Message) => boolean;\n\n /** Вложение сообщения — домен маппит свой ресурс, скачивание по `public_id`. */\n export interface Attachment {\n id: number;\n /** Обезличенное имя для карточки файла. */\n name: string;\n /** Непрозрачный идентификатор файла — консюмер качает blob по нему. */\n publicId: string;\n }\n\n /**\n * Одно сообщение треда в уже подготовленной для отображения форме: автор —\n * готовый лейбл (домен решает, как его собрать), `own`/`system` — флаги\n * выравнивания и стиля, дата — ISO-строка (форматируется `DatePipe` внутри).\n */\n export interface Message {\n /** Идентификатор сообщения — ключ `@for track`. */\n id: number | string;\n /** Клиентский временный id оптимистичного сообщения (до ответа сервера). */\n tempId?: string;\n /**\n * Статус своего сообщения. Отсутствует у входящих: чужому сообщению\n * нечего сообщать о доставке.\n */\n status?: MessageStatus;\n /** Готовый лейбл автора (доменный authorLabel). */\n author: string;\n /** Сообщение текущего пользователя — выравнивается вправо, акцентный фон. */\n own: boolean;\n /** Признак системного сообщения (рендерится обычным входящим пузырём). */\n system?: boolean;\n text: string;\n /**\n * Rich-тело (Quill delta) — при наличии рендерится вместо plain `text`\n * через `rt-delta-view`. `null`/отсутствует ⇒ показываем `text`.\n */\n delta?: IQuillDelta | null;\n /** ISO-дата создания. */\n createdAt: string;\n /** URL вложения (если есть) — наличие включает карточку файла. */\n fileUrl?: string | null;\n /** Имя вложения для отображения в карточке. */\n fileName?: string | null;\n /**\n * Вложения сообщения (несколько файлов). Непустой массив имеет приоритет\n * над legacy-парой `fileUrl`/`fileName` (та равна первому вложению).\n */\n attachments?: readonly Attachment[];\n /** Внешняя ссылка-призыв (привязка Telegram) — наличие включает кнопку-ссылку. */\n deepLink?: string | null;\n /** Подпись кнопки-ссылки `deepLink` (домен решает текст по состоянию). */\n deepLinkLabel?: string | null;\n /** Сообщение помечено удалённым — рендерится плейсхолдером вместо содержимого. */\n deleted?: boolean;\n /** Показать действие «удалить» на этом сообщении (домен решает по правам/направлению). */\n canDelete?: boolean;\n /**\n * Текст подтверждения перед удалением. Задан — клик по корзине открывает\n * confirm-попап с этим текстом, удаление уходит только после подтверждения.\n * Пусто/undefined — удаление сразу по клику (домен без confirm-семантики).\n */\n deleteConfirm?: string;\n }\n\n /** Payload отправки: текст + файлы (пусто/undefined, если вложения выключены). */\n export interface SendPayload {\n text: string;\n files?: File[];\n /**\n * Rich-тело строкой JSON (`JSON.stringify(getContents())`) — взаимоисключимо\n * с непустым `text`. При наличии домен шлёт delta-канал (`message:\"\"`).\n */\n delta?: string | null;\n }\n}\n","import { Pipe, PipeTransform } from '@angular/core';\n\nimport { ERtChatMessageStatus } from '../components/chat/rt-chat.model';\n\n/**\n * Ключи подписей статусов для скринридера: сам индикатор — иконка, и без текста\n * различие «доставлено/прочитано» слышно не будет.\n *\n * Пайп отдаёт ключ, а переводит его `transloco` следующим звеном цепочки.\n * Готовый текст здесь застыл бы на языке, активном в момент загрузки модуля.\n */\nconst STATUS_KEYS: Readonly<Record<ERtChatMessageStatus, string>> = {\n [ERtChatMessageStatus.Sending]: 'rtKit.chatStatusSending',\n [ERtChatMessageStatus.Sent]: 'rtKit.chatStatusSent',\n [ERtChatMessageStatus.Read]: 'rtKit.chatStatusRead',\n [ERtChatMessageStatus.Failed]: 'rtKit.chatStatusFailed',\n};\n\n/** Ключ текстовой расшифровки иконки статуса сообщения. */\n@Pipe({ name: 'rtChatStatusLabel' })\nexport class RtChatStatusLabelPipe implements PipeTransform {\n public transform(status: ERtChatMessageStatus): string {\n return STATUS_KEYS[status];\n }\n}\n","/** Выбранные файлы вместе с только что добавленными. Список всегда новый: его читает сигнал. */\nexport function withAppendedFiles(current: ReadonlyArray<File>, added: ReadonlyArray<File>): File[] {\n return [...current, ...added];\n}\n\n/** Выбранные файлы без того, что стоит на этом месте. */\nexport function withoutFileAt(current: ReadonlyArray<File>, index: number): File[] {\n return current.filter((_: File, position: number): boolean => position !== index);\n}\n\n/** Файлы, названные полем выбора. Поле без выбора отдаёт пустой список, а не отсутствие. */\nexport function pickedFiles(files: FileList | null): File[] {\n return Array.from(files ?? []);\n}\n","/** Замеры прокрутки треда: столько, сколько нужно решению о прилипании к низу. */\nexport interface IRtChatThreadMetrics {\n scrollTop: number;\n scrollHeight: number;\n clientHeight: number;\n}\n\n/** Зазор от низа треда, в пределах которого читатель считается стоящим у нижнего края. */\nexport const RT_CHAT_NEAR_BOTTOM_THRESHOLD_PX: number = 64;\n\n/**\n * Задержки повторных подтягиваний ленты к низу после первой прокрутки. Присланное\n * содержимое дорисовывается несколькими проходами уже после того, как лента встала по\n * промежуточной высоте, и набор тиков покрывает окно, за которое высота устаканивается.\n */\nexport const RT_CHAT_PIN_RETRY_DELAYS_MS: ReadonlyArray<number> = [50, 150, 300, 500, 800];\n\n/** Стоит ли читатель у нижнего края треда. */\nexport function isNearBottom(metrics: IRtChatThreadMetrics): boolean {\n return metrics.scrollHeight - metrics.clientHeight - metrics.scrollTop <= RT_CHAT_NEAR_BOTTOM_THRESHOLD_PX;\n}\n\n/**\n * Прилипает ли лента к низу после этой прокрутки.\n *\n * Прилипание снимается только тогда, когда читатель уехал вверх сам. Прокрутка, сделанная\n * самим компонентом, и рост содержимого приходят с тем же или большим положением — на них\n * прилипание лишь подтверждается: иначе позднее событие от собственной прокрутки читалось бы\n * отрывом от низа, и лента переставала бы догонять последнее сообщение.\n */\nexport function nextAtBottom(previous: boolean, lastScrollTop: number, metrics: IRtChatThreadMetrics): boolean {\n const nearBottom: boolean = isNearBottom(metrics);\n\n return metrics.scrollTop < lastScrollTop - 1 ? nearBottom : previous || nearBottom;\n}\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { CdkTextareaAutosize } from '@angular/cdk/text-field';\nimport { DatePipe } from '@angular/common';\nimport {\n afterRenderEffect,\n booleanAttribute,\n computed,\n contentChild,\n effect,\n inject,\n input,\n output,\n signal,\n viewChild,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n InputSignal,\n InputSignalWithTransform,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';\n\nimport { NgTemplateOutlet } from '@angular/common';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport {\n RtButtonDirective,\n RtConfirmDirective,\n RtDeltaViewComponent,\n RtFileCardComponent,\n RtFileDropComponent,\n RtIconButtonComponent,\n RtIconComponent,\n RtMenuComponent,\n RtNoteComponent,\n RtSkeletonWrapperComponent,\n RtSpinnerComponent,\n RtToolbarComponent,\n RtToolbarLeftDirective,\n RtToolbarRightDirective,\n} from '@rt-tools/ui-kit-v2';\nimport { RT_KIT_LABELS, RT_KIT_LOCALE, rtKitLabel, TRtKitLabelKey, TRtKitLabelMap } from '@rt-tools/ui-kit-v2';\nimport { RtChatMessageActionsDirective } from './rt-chat-message-actions.directive';\nimport { RtChatMessageHasActionsPipe } from './rt-chat-message-actions.pipe';\nimport { RtChatStatusLabelPipe } from '../../pipes/rt-chat-status-label.pipe';\nimport { RtMessageComposerComponent } from '../message-composer/rt-message-composer.component';\nimport { IRtMessageComposer } from '../message-composer/rt-message-composer.model';\nimport { TRtRichEditorToolbar } from '../rich-editor/rt-rich-editor.component';\nimport { pickedFiles, withAppendedFiles, withoutFileAt } from './rt-chat-files.logic';\nimport { nextAtBottom, RT_CHAT_PIN_RETRY_DELAYS_MS } from './rt-chat-thread.logic';\nimport { ERtChatMessageStatus, IRtChat } from './rt-chat.model';\n\nconst BEM_BLOCK: string = 'rt-chat';\n\n/** Ключ заглушки имени вложения, когда домен не отдал `fileName` (только URL). */\nconst ATTACHMENT_FALLBACK_KEY: TRtKitLabelKey = 'chatAttachmentFallback';\n\n/**\n * Общий презентационный чат: тред сообщений + композер. Никакого data-access/api — история\n * приходит готовым массивом `IRtChat.Message[]`, отправка/обновление/скачивание уходят наружу\n * через outputs, а стор и blob-загрузка остаются в feature-компоненте каждого домена.\n *\n * Композер держит свой `FormGroup` — наружу торчит только `send`. Полноэкранный\n * режим (expand) — overlay внутри самого компонента (`--expanded`), потребителю\n * лишь опционально сообщается через `expandedChange`.\n *\n * Шапка (тулбар «Чат» + refresh/expand) рендерится только когда включена хотя бы\n * одна из иконок (`showRefresh`/`showExpand`): в диалогах своя header-обёртка,\n * туда тулбар не нужен.\n */\n@Component({\n selector: 'rt-chat',\n templateUrl: './rt-chat.component.html',\n styleUrls: ['./rt-chat.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n CdkTextareaAutosize,\n DatePipe,\n NgTemplateOutlet,\n ReactiveFormsModule,\n\n // standalone components / directives\n RtButtonDirective,\n RtChatStatusLabelPipe,\n RtConfirmDirective,\n RtDeltaViewComponent,\n RtFileCardComponent,\n RtFileDropComponent,\n RtIconButtonComponent,\n RtIconComponent,\n RtChatMessageHasActionsPipe,\n RtMenuComponent,\n RtMessageComposerComponent,\n RtNoteComponent,\n RtSkeletonWrapperComponent,\n RtSpinnerComponent,\n RtToolbarComponent,\n RtToolbarLeftDirective,\n RtToolbarRightDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n host: {\n class: BEM_BLOCK,\n '[class.rt-chat--expanded]': 'expanded()',\n '[class.rt-chat--fill]': 'fill()',\n },\n})\nexport class RtChatComponent {\n /**\n * Дата сообщения форматируется по активной локали приложения, а не по\n * `LOCALE_ID`: тот вычисляется на подъёме приложения и там, где язык\n * переключают на ходу, оставил бы часы в прежнем формате до перезагрузки.\n *\n * Данные локали для `DatePipe` регистрирует приложение: без них пайп падает\n * `Missing locale data`, и кит за это не отвечает.\n */\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly locale: Signal<string> = inject(RT_KIT_LOCALE);\n\n /**\n * Пользователь у нижнего края треда. Плоское поле (не сигнал), чтобы\n * afterRenderEffect не перезапускался на каждый scroll — обновляется в\n * обработчике scroll и читается при автоскролле.\n */\n #atBottom: boolean = true;\n\n /** Прошлый scrollTop треда — для различения прокрутки вверх и роста контента. */\n #lastScrollTop: number = 0;\n\n /** One-shot: своё отправленное сообщение всегда прокручивает тред вниз. */\n #forceScroll: boolean = false;\n\n /** Текущее значение композера — источник реактивности для `canSend`. */\n readonly #formValue: Signal<Partial<{ message: string; files: File[] }>>;\n\n /**\n * Скролл-контейнер треда — для автопрокрутки к последнему сообщению.\n * `viewChild` не работает на ES-private (`#`) поле, поэтому `protected`.\n */\n protected readonly thread: Signal<ElementRef<HTMLElement> | undefined> = viewChild<ElementRef<HTMLElement>>('thread');\n\n /** Скрытый нативный input — открывается кнопкой-скрепкой внутри поля ввода. */\n protected readonly composerFileEl: Signal<ElementRef<HTMLInputElement> | undefined> =\n viewChild<ElementRef<HTMLInputElement>>('composerFileEl');\n\n protected readonly attachmentFallbackName: Signal<string> = rtKitLabel(ATTACHMENT_FALLBACK_KEY);\n\n /** Подписи с учётом того, что передал хозяин компонента: своё важнее умолчания */\n protected readonly titleText: Signal<string> = computed((): string => this.title() || this.#defaultTitle());\n protected readonly placeholderText: Signal<string> = computed((): string => this.placeholder() || this.#defaultPlaceholder());\n protected readonly emptyHintText: Signal<string> = computed((): string => this.emptyHint() || this.#defaultEmptyHint());\n\n readonly #defaultTitle: Signal<string> = rtKitLabel('chatTitle');\n readonly #defaultPlaceholder: Signal<string> = rtKitLabel('chatPlaceholder');\n readonly #defaultEmptyHint: Signal<string> = rtKitLabel('chatEmptyHint');\n\n protected readonly MessageStatus: typeof ERtChatMessageStatus = ERtChatMessageStatus;\n\n /** Плейсхолдеры скелетонов треда при первичной загрузке. */\n protected readonly skeletonRows: readonly number[] = [1, 2, 3];\n\n /** Полноэкранный режим (overlay поверх страницы). */\n protected readonly expanded: WritableSignal<boolean> = signal<boolean>(false);\n\n protected readonly replyForm: FormGroup<{\n message: FormControl<string>;\n files: FormControl<File[]>;\n }> = new FormGroup({\n message: new FormControl<string>('', { nonNullable: true }),\n files: new FormControl<File[]>([], { nonNullable: true }),\n });\n\n /** Композер заблокирован при загрузке/рефреше треда или отправке in-flight. */\n protected readonly composerDisabled: Signal<boolean> = computed((): boolean => this.loading() || this.fetching() || this.sending());\n\n /**\n * Можно ли отправить: композер активен и есть содержимое — непустой текст или\n * (при включённых вложениях) хотя бы один файл. Сообщение само по себе не\n * бывает «невалидным» — пустоту гасим дизейблом кнопки, а не подсветкой поля.\n */\n protected readonly canSend: Signal<boolean> = computed((): boolean => {\n if (this.composerDisabled()) {\n return false;\n }\n const value: Partial<{ message: string; files: File[] }> = this.#formValue();\n const hasText: boolean = (value.message ?? '').trim().length > 0;\n const hasFiles: boolean = this.attachments() && (value.files?.length ?? 0) > 0;\n return hasText || hasFiles;\n });\n\n /** Показывать ли шапку: только когда включена хотя бы одна иконка. */\n protected readonly showHeader: Signal<boolean> = computed((): boolean => this.showRefresh() || this.showExpand());\n\n /** Подпись кнопки fullscreen: тернарник в шаблоне переводом не покрыть. */\n protected readonly expandLabel: Signal<string> = rtKitLabel(\n computed((): TRtKitLabelKey => (this.expanded() ? 'chatCollapse' : 'chatExpand'))\n );\n\n /** Выбранные, но ещё не отправленные файлы — карточки над полем ввода. */\n protected readonly selectedFiles: Signal<File[]> = computed((): File[] => this.#formValue().files ?? []);\n\n /**\n * Drop-зона активна только когда вложения включены, ответ доступен и композер\n * не занят (загрузка/рефреш/отправка). Иначе обёртка `rt-file-drop` просто\n * пропускает контент без оверлея.\n */\n protected readonly dropDisabled: Signal<boolean> = computed(\n (): boolean => !this.attachments() || !this.canReply() || this.composerDisabled()\n );\n\n /**\n * Файл из drag-n-drop для rich-композера: каждый drop кладёт новый `File`,\n * пробрасывается в `rt-message-composer` через input. Классический композер\n * принимает drop напрямую в свой `replyForm`.\n */\n protected readonly droppedFiles: WritableSignal<File[] | null> = signal<File[] | null>(null);\n\n /**\n * Шаблон действий у реплики: `<ng-template rtChatMessageActions let-message>`.\n *\n * Не объявлен — разметка реплики прежняя, и лишней кнопки у неё не появляется.\n */\n protected readonly messageActions: Signal<RtChatMessageActionsDirective | undefined> = contentChild(RtChatMessageActionsDirective);\n\n /** История сообщений (consumer уже смаппил из доменной модели). */\n public readonly messages: InputSignal<readonly IRtChat.Message[]> = input<readonly IRtChat.Message[]>([]);\n\n /** Первичная загрузка — скелетоны вместо треда. */\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Рефреш при наличии данных — тред остаётся, композер дизейблится. */\n public readonly fetching: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Доступна ли отправка (иначе вместо композера — note с причиной). */\n public readonly canReply: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Причина блокировки ответа — note под тредом. */\n public readonly replyBlockReason: InputSignal<string | null> = input<string | null>(null);\n\n /** Отправка in-flight — спиннер/дизейбл на кнопке. */\n public readonly sending: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /**\n * Подписи по умолчанию приходят пустыми и переводятся ниже: значение\n * `input()` вычисляется при создании компонента, и готовый перевод застыл бы\n * на языке, активном в этот момент.\n */\n public readonly placeholder: InputSignal<string> = input<string>('');\n\n public readonly title: InputSignal<string> = input<string>('');\n\n /** Текст, когда треда ещё нет (заявка не создана). */\n public readonly emptyHint: InputSignal<string> = input<string>('');\n\n /** Есть ли тред (иначе показываем `emptyHint`). */\n public readonly hasThread: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Включить загрузку файлов в композере. */\n public readonly attachments: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** `accept` для file-input (`.pdf,.doc,...`). */\n public readonly accept: InputSignal<string> = input<string>('');\n\n /**\n * Компактный композер (`rt-message-composer`): авто-растущая textarea над\n * разделителем + ряд иконок (прикрепить слева, отправить справа) вместо\n * классического вертикального стека. По умолчанию выключен.\n */\n public readonly richComposer: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /**\n * Rich-текст в композере (Quill delta). Требует `richComposer` — форматирование\n * живёт только в компактном композере. Отправка уходит delta-каналом.\n */\n public readonly formatting: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Набор кнопок rich-редактора (проброс до `rt-rich-editor` через композер). */\n public readonly formattingToolbar: InputSignal<TRtRichEditorToolbar> = input<TRtRichEditorToolbar>('full');\n\n /**\n * Растягивать чат на всю высоту контейнера: тред занимает свободное место,\n * композер прижат к низу. По умолчанию выключен (тред с фикс. max-height).\n * Требует, чтобы родитель давал высоту (flex-цепочка).\n */\n public readonly fill: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Показать иконку refresh в шапке. */\n public readonly showRefresh: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Показать иконку expand (fullscreen) в шапке. */\n public readonly showExpand: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Отправка сообщения (+файлы) — consumer вызывает свой store/api. */\n public readonly send: OutputEmitterRef<IRtChat.SendPayload> = output<IRtChat.SendPayload>();\n\n /** Клик refresh — consumer перетягивает тред. */\n public readonly refresh: OutputEmitterRef<void> = output<void>();\n\n /** Клик по вложению — consumer качает blob своим api. Шаблон зовёт выход прямо: релей-метод,\n * который только повторял `emit`, ничего не добавлял, а файл при этом рос. */\n public readonly downloadFile: OutputEmitterRef<IRtChat.Message> = output<IRtChat.Message>();\n\n /** Клик по карточке вложения из `attachments[]` — консюмер качает по `publicId`. */\n public readonly downloadAttachment: OutputEmitterRef<IRtChat.Attachment> = output<IRtChat.Attachment>();\n\n /** Смена fullscreen-состояния. */\n public readonly expandedChange: OutputEmitterRef<boolean> = output<boolean>();\n\n public readonly deleteMessage: OutputEmitterRef<IRtChat.Message> = output<IRtChat.Message>();\n\n /** Повторная отправка своего сообщения со статусом `failed`. */\n public readonly retryMessage: OutputEmitterRef<IRtChat.Message> = output<IRtChat.Message>();\n\n /**\n * Есть ли у реплики действия потребителя — гейт кнопки «…» у неё.\n *\n * Не задан — точка действий показывается у каждой реплики: экран, который ничего не\n * гейтит, показывает её так же, как это делает строка таблицы.\n */\n public readonly messageHasActions: InputSignal<IRtChat.MessageActionsPredicate | null> = input<IRtChat.MessageActionsPredicate | null>(\n null\n );\n\n constructor() {\n this.#formValue = toSignal(this.replyForm.valueChanges, {\n initialValue: this.replyForm.value,\n });\n\n // Поведение мессенджера: после каждого рендера, зависящего от треда\n // (новые сообщения, окончание загрузки, fullscreen), прокручиваем к\n // последнему сообщению — но только если это своё сообщение (forceScroll)\n // или пользователь уже у нижнего края. Если он ушёл вверх читать историю,\n // входящее сообщение его не дёргает. afterRenderEffect гарантирует, что DOM\n // уже обновлён и scrollHeight посчитан по реальной высоте.\n afterRenderEffect((): void => {\n this.messages();\n this.loading();\n this.fetching();\n this.expanded();\n const el: HTMLElement | undefined = this.thread()?.nativeElement;\n if (el === undefined) {\n return;\n }\n if (this.#forceScroll || this.#atBottom) {\n el.scrollTop = el.scrollHeight;\n this.#atBottom = true;\n this.#pinToBottomDeferred();\n }\n this.#forceScroll = false;\n });\n\n // `formControlName`-инпуты игнорируют атрибут `disabled` — состояние ввода\n // держим через сам контрол: блок при рефреше треда или отправке in-flight.\n effect((): void => {\n const blocked: boolean = this.composerDisabled();\n if (blocked && this.replyForm.enabled) {\n this.replyForm.disable({ emitEvent: false });\n return;\n }\n if (!blocked && this.replyForm.disabled) {\n this.replyForm.enable({ emitEvent: false });\n }\n });\n }\n\n protected onSubmit(): void {\n // Кнопка уже дизейблится по `canSend` — guard лишь страхует от submit в\n // обход кнопки (программный/Enter), молча и без подсветки поля.\n if (!this.canSend()) {\n return;\n }\n const text: string = this.replyForm.controls.message.value.trim();\n const files: File[] = this.replyForm.controls.files.value;\n // Своё сообщение всегда прокручивает тред вниз — независимо от позиции.\n this.#forceScroll = true;\n this.send.emit({ text, files: this.attachments() ? files : undefined });\n this.replyForm.reset({ message: '', files: [] });\n }\n\n protected onComposerKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter' && !event.shiftKey && !event.isComposing) {\n event.preventDefault();\n this.onSubmit();\n }\n }\n\n /** Релей submit'а от `rt-message-composer` (rich-режим) наружу как `send`. */\n protected onComposerSubmit(payload: IRtMessageComposer.SubmitPayload): void {\n // Своё сообщение всегда прокручивает тред вниз — независимо от позиции.\n this.#forceScroll = true;\n this.send.emit({\n text: payload.text,\n files: this.attachments() ? payload.files : undefined,\n delta: payload.delta,\n });\n }\n\n /**\n * Файлы выброшены в обёртку чата: в rich-режиме отдаём массив композеру через\n * input, в классическом — добавляем к уже выбранным в собственном `replyForm`.\n */\n protected onFilesDropped(files: File[]): void {\n if (files.length === 0) {\n return;\n }\n if (this.richComposer()) {\n // Новый массив на каждый drop — effect композера видит каждое перетаскивание.\n this.droppedFiles.set([...files]);\n return;\n }\n this.replyForm.controls.files.setValue(withAppendedFiles(this.replyForm.controls.files.value, files));\n }\n\n protected openFilePicker(): void {\n this.composerFileEl()?.nativeElement.click();\n }\n\n protected onFilesPicked(event: Event): void {\n const inputEl: HTMLInputElement = event.target as HTMLInputElement;\n const picked: File[] = pickedFiles(inputEl.files);\n if (picked.length > 0) {\n this.replyForm.controls.files.setValue(withAppendedFiles(this.replyForm.controls.files.value, picked));\n }\n // Сброс значения: без него повторный выбор того же файла не даёт `change`.\n inputEl.value = '';\n }\n\n protected removeFile(index: number): void {\n this.replyForm.controls.files.setValue(withoutFileAt(this.replyForm.controls.files.value, index));\n }\n\n /** Признак «читатель у нижнего края» обновляется по прокрутке: на нём стоит автопрокрутка. */\n protected onThreadScroll(): void {\n const el: HTMLElement | undefined = this.thread()?.nativeElement;\n if (el === undefined) {\n return;\n }\n\n this.#atBottom = nextAtBottom(this.#atBottom, this.#lastScrollTop, el);\n this.#lastScrollTop = el.scrollTop;\n }\n\n /**\n * Серия отложенных подтягиваний ленты к низу: присланное содержимое дорисовывается несколькими\n * проходами, и одной прокрутки мало. Каждый тик берёт тред заново — он бывает пересоздан — и\n * дотягивает ленту, пока читатель стоит у нижнего края.\n */\n #pinToBottomDeferred(): void {\n for (const delay of RT_CHAT_PIN_RETRY_DELAYS_MS) {\n setTimeout((): void => {\n const el: HTMLElement | undefined = this.thread()?.nativeElement;\n if (el !== undefined && this.#atBottom) {\n el.scrollTop = el.scrollHeight;\n }\n }, delay);\n }\n }\n\n protected toggleExpand(): void {\n const next: boolean = !this.expanded();\n this.expanded.set(next);\n this.expandedChange.emit(next);\n }\n}\n","<ng-container rtBlock=\"rt-chat\">\n <rt-file-drop\n [overlayLabel]=\"t().chatDropOverlay\"\n [accept]=\"accept()\"\n [disabled]=\"dropDisabled()\"\n (filesDropped)=\"onFilesDropped($event)\">\n @if (showHeader()) {\n <rt-toolbar rtElem=\"header\" dense>\n <ng-template rtToolbarLeft>\n <h3 rtElem=\"title\" qa-dataid=\"chat-title\">{{ title() }}</h3>\n </ng-template>\n <ng-template rtToolbarRight>\n @if (showRefresh()) {\n <rt-icon-button\n qa-dataid=\"chat-refresh\"\n icon=\"sync\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatRefreshAria\"\n [tooltip]=\"t().chatRefreshTooltip\"\n [loading]=\"fetching()\"\n [disabled]=\"!hasThread()\"\n (clicked)=\"refresh.emit()\" />\n }\n @if (showExpand()) {\n <rt-icon-button\n qa-dataid=\"chat-expand\"\n variant=\"ghost\"\n [icon]=\"expanded() ? 'window-minimize' : 'window-maximize'\"\n [ariaLabel]=\"expandLabel()\"\n [tooltip]=\"expandLabel()\"\n (clicked)=\"toggleExpand()\" />\n }\n <ng-content select=\"[rtChatHeaderActions]\" />\n </ng-template>\n </rt-toolbar>\n }\n\n @if (!hasThread()) {\n <rt-note qa-dataid=\"chat-empty-hint\">{{ emptyHint() }}</rt-note>\n } @else {\n <div rtElem=\"thread-viewport\" qa-dataid=\"chat-thread-viewport\">\n @if (loading()) {\n <!-- Скелетон повторяет структуру сообщения (автор → текст → дата),\n чередуя выравнивание, чтобы тред не «прыгал» при подмене на реальные. -->\n <div rtElem=\"thread\" qa-dataid=\"chat-thread-skeleton\">\n @for (row of skeletonRows; track row; let even = $even) {\n <div rtElem=\"message-skeleton\" qa-dataid=\"chat-message-skeleton\" [rtMod]=\"{ own: even }\">\n <rt-skeleton-wrapper rtElem=\"skeleton-line\" width=\"72px\" height=\"10px\" [isLoading]=\"true\" />\n <rt-skeleton-wrapper rtElem=\"skeleton-line\" width=\"100%\" height=\"13px\" [isLoading]=\"true\" />\n <rt-skeleton-wrapper rtElem=\"skeleton-line\" width=\"55%\" height=\"13px\" [isLoading]=\"true\" />\n <rt-skeleton-wrapper rtElem=\"skeleton-line\" width=\"56px\" height=\"10px\" [isLoading]=\"true\" />\n </div>\n }\n </div>\n } @else {\n <div\n #thread\n rtElem=\"thread\"\n qa-dataid=\"chat-thread\"\n [rtMod]=\"{ frozen: fetching() }\"\n [attr.aria-busy]=\"fetching() ? 'true' : null\"\n (scroll)=\"onThreadScroll()\">\n @for (m of messages(); track m.id) {\n <div\n rtElem=\"message-row\"\n qa-dataid=\"chat-message\"\n [attr.data-own]=\"m.own\"\n [attr.data-status]=\"m.status || null\"\n [attr.data-deleted]=\"m.deleted || null\"\n [rtMod]=\"{ own: m.own }\">\n @if (m.canDelete && !m.deleted) {\n @if (m.deleteConfirm) {\n <rt-icon-button\n rtElem=\"message-delete\"\n qa-dataid=\"chat-message-delete\"\n icon=\"trash\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatDeleteAria\"\n [tooltip]=\"t().chatDeleteTooltip\"\n [rtConfirm]=\"m.deleteConfirm\"\n (confirmed)=\"deleteMessage.emit(m)\" />\n } @else {\n <rt-icon-button\n rtElem=\"message-delete\"\n qa-dataid=\"chat-message-delete\"\n icon=\"trash\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatDeleteAria\"\n [tooltip]=\"t().chatDeleteTooltip\"\n (clicked)=\"deleteMessage.emit(m)\" />\n }\n }\n @if (messageActions()?.template; as actionsTpl) {\n @if (m | rtChatMessageHasActions: messageHasActions()) {\n <div rtElem=\"message-actions\" qa-dataid=\"chat-message-actions\">\n <rt-menu>\n <ng-container\n [ngTemplateOutlet]=\"actionsTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: m }\" />\n </rt-menu>\n </div>\n }\n }\n <div rtElem=\"message\" [rtMod]=\"{ own: m.own, deleted: m.deleted }\">\n <p rtElem=\"message-author\" qa-dataid=\"chat-message-author\">{{ m.author }}</p>\n @if (m.deleted) {\n <p rtElem=\"message-text\" qa-dataid=\"chat-message-deleted\" rtMod=\"deleted\">\n {{ t().chatMessageDeleted }}\n </p>\n } @else {\n @if (m.delta) {\n <rt-delta-view rtElem=\"message-text\" qa-dataid=\"chat-message-text\" [delta]=\"m.delta\" />\n } @else {\n <p rtElem=\"message-text\" qa-dataid=\"chat-message-text\">{{ m.text }}</p>\n }\n @if (m.attachments?.length) {\n @for (att of m.attachments; track att.id) {\n <span rtElem=\"message-attachment\" qa-dataid=\"chat-message-attachment\">\n <rt-file-card\n showDownload\n size=\"sm\"\n [name]=\"att.name || attachmentFallbackName()\"\n (download)=\"downloadAttachment.emit(att)\" />\n </span>\n }\n } @else if (m.fileUrl) {\n <span rtElem=\"message-attachment\" qa-dataid=\"chat-message-attachment\">\n <rt-file-card\n showDownload\n size=\"sm\"\n [name]=\"m.fileName || attachmentFallbackName()\"\n (download)=\"downloadFile.emit(m)\" />\n </span>\n }\n @if (m.deepLink) {\n <span rtElem=\"message-deeplink\">\n <a\n rtButton\n qa-dataid=\"chat-message-deeplink\"\n appearance=\"outlined\"\n icon=\"send\"\n rel=\"noopener\"\n target=\"_blank\"\n [href]=\"m.deepLink\"\n [label]=\"m.deepLinkLabel || t().uiSubscribeNotifications\"\n [attr.aria-label]=\"m.deepLinkLabel || t().uiSubscribeNotifications\"></a>\n </span>\n }\n }\n <span rtElem=\"message-footer\">\n <span rtElem=\"message-date\" qa-dataid=\"chat-message-date\">\n {{ m.createdAt | date: 'short' : undefined : locale() }}\n </span>\n @if (m.status) {\n <span\n rtElem=\"message-status\"\n qa-dataid=\"chat-message-status\"\n [attr.data-status]=\"m.status\"\n [rtMod]=\"{ status: m.status }\"\n [attr.aria-label]=\"m.status | rtChatStatusLabel\">\n @if (m.status === MessageStatus.Failed) {\n <rt-icon rtElem=\"status-icon\" name=\"exclamation-circle\" size=\"sm\" />\n <rt-icon-button\n qa-dataid=\"chat-message-retry\"\n icon=\"sync\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatRetryAria\"\n [tooltip]=\"t().chatRetryTooltip\"\n (clicked)=\"retryMessage.emit(m)\" />\n } @else {\n <!-- Часы, пока сообщение в пути; дальше двойной чек, цвет которого\n (серый/синий) различает доставлено и прочитано. -->\n <rt-icon\n rtElem=\"status-icon\"\n size=\"sm\"\n [name]=\"m.status === MessageStatus.Sending ? 'clock' : 'check-double'\" />\n }\n </span>\n }\n </span>\n </div>\n </div>\n } @empty {\n <rt-note qa-dataid=\"chat-empty-thread\">{{ t().chatEmptyThread }}</rt-note>\n }\n </div>\n }\n @if (!loading() && fetching()) {\n <div rtElem=\"thread-overlay\" qa-dataid=\"chat-thread-overlay\" role=\"status\" [attr.aria-label]=\"t().chatRefreshAria\">\n <rt-spinner diameter=\"32\" />\n </div>\n }\n </div>\n\n @if (canReply()) {\n @if (richComposer()) {\n <rt-message-composer\n rtElem=\"composer-rich\"\n qa-dataid=\"chat-composer-rich\"\n [placeholder]=\"placeholder()\"\n [accept]=\"accept()\"\n [attachments]=\"attachments()\"\n [formatting]=\"formatting()\"\n [toolbar]=\"formattingToolbar()\"\n [sending]=\"sending()\"\n [disabled]=\"loading() || fetching()\"\n [droppedFiles]=\"droppedFiles()\"\n (submitted)=\"onComposerSubmit($event)\" />\n } @else {\n <form rtElem=\"composer\" qa-dataid=\"chat-composer\" [formGroup]=\"replyForm\" (ngSubmit)=\"onSubmit()\">\n @if (attachments() && selectedFiles().length > 0) {\n <div rtElem=\"composer-files\" qa-dataid=\"chat-composer-files\">\n @for (file of selectedFiles(); track $index) {\n <rt-file-card\n showRemove\n qa-dataid=\"chat-composer-file\"\n size=\"sm\"\n [name]=\"file.name\"\n [sizeBytes]=\"file.size\"\n [disabled]=\"composerDisabled()\"\n (removed)=\"removeFile($index)\" />\n }\n </div>\n }\n <div rtElem=\"composer-field\" [rtMod]=\"{ attach: attachments() }\">\n @if (attachments()) {\n <input\n #composerFileEl\n qa-dataid=\"chat-composer-file-input\"\n type=\"file\"\n hidden\n multiple\n [attr.accept]=\"accept() || null\"\n (change)=\"onFilesPicked($event)\" />\n <rt-icon-button\n qa-dataid=\"chat-composer-attach\"\n icon=\"paperclip\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatAttachAria\"\n [tooltip]=\"t().chatAttachTooltip\"\n [disabled]=\"composerDisabled()\"\n (clicked)=\"openFilePicker()\" />\n }\n <textarea\n rtElem=\"composer-input\"\n qa-dataid=\"chat-composer-input\"\n cdkTextareaAutosize\n formControlName=\"message\"\n cdkAutosizeMinRows=\"1\"\n cdkAutosizeMaxRows=\"4\"\n [attr.aria-label]=\"t().chatComposerAria\"\n [placeholder]=\"placeholder()\"\n (keydown)=\"onComposerKeydown($event)\"></textarea>\n </div>\n <button\n rtButton\n rtElem=\"composer-send\"\n qa-dataid=\"chat-composer-send\"\n type=\"submit\"\n theme=\"primary\"\n appearance=\"filled\"\n [label]=\"t().chatSendLabel\"\n [attr.aria-label]=\"t().chatSendAria\"\n [loading]=\"sending()\"\n [disabled]=\"!canSend()\"></button>\n </form>\n }\n } @else if (replyBlockReason()) {\n <rt-note rtElem=\"reply-block\" qa-dataid=\"chat-reply-block\">{{ replyBlockReason() }}</rt-note>\n }\n\n <!-- Слот доменных действий потребителя под композером: в fullscreen\n попадает внутрь overlay, поэтому кнопки остаются видны. -->\n <div rtElem=\"footer-slot\" qa-dataid=\"chat-footer\" [rtMod]=\"{ blocked: fetching() }\" [attr.inert]=\"fetching() ? '' : null\">\n <ng-content select=\"[rtChatFooter]\" />\n </div>\n }\n </rt-file-drop>\n</ng-container>\n","import { fileNameFromUrl, IQuillDelta } from '@rt-tools/ui-kit-v2';\n\nimport { ERtChatMessageStatus, IRtChat } from './rt-chat.model';\n\n/**\n * Статус уже сохранённого своего сообщения: сервер знает только, дошло ли оно до\n * собеседника. Часы и ошибка — состояния клиентской очереди, сюда не попадают.\n */\nexport function deliveryStatus(read: boolean): ERtChatMessageStatus {\n return read ? ERtChatMessageStatus.Read : ERtChatMessageStatus.Sent;\n}\n\n/**\n * Сообщение, ещё не подтверждённое сервером. Серверного id и ссылок на вложения\n * у него нет: есть клиентский ключ, текст и выбранные файлы.\n *\n * Rich-тело приходит уже разобранным — доменная форма его хранения тут ни при\n * чём, а хранят его стороны по-разному: одна шлёт обычный текст, другая —\n * строку композера, которая в том же виде уходит на сервер.\n */\nexport interface IRtPendingMessage {\n tempId: string;\n text: string;\n delta?: IQuillDelta | null;\n createdAt: string;\n status: IRtChat.MessageStatus;\n files: readonly File[];\n}\n\n/**\n * Неподтверждённое сообщение → строка ленты. Показывается сразу после отправки:\n * ждать ответа сервера, глядя в пустоту, незачем ни одной из сторон.\n *\n * Скрыть такое сообщение нельзя: на сервере его ещё нет, и удалять нечего.\n */\nexport function pendingToRtMessage(pending: IRtPendingMessage, authorLabel: string): IRtChat.Message {\n return {\n id: pending.tempId,\n tempId: pending.tempId,\n author: authorLabel,\n own: true,\n text: pending.text,\n delta: pending.delta ?? null,\n createdAt: pending.createdAt,\n status: pending.status,\n canDelete: false,\n attachments: pending.files.map((file: File, index: number): IRtChat.Attachment => ({\n id: index,\n name: file.name,\n // Файл ещё не на сервере — скачивать нечего, карточка только именует.\n publicId: '',\n })),\n };\n}\n\n/**\n * Структурный контракт доменного сообщения, достаточный для маппинга в\n * `IRtChat.Message`. Доменные модели удовлетворяют ему по форме;\n * роль-специфика (автор/own/system) задаётся опциями.\n */\nexport interface IRtMappableMessage {\n id: string | number;\n tempId?: string;\n status?: IRtChat.MessageStatus;\n message: string;\n messageDelta: IQuillDelta | null;\n createdAt: string;\n fileUrl: string | null;\n attachments: readonly { id: number; name: string; publicId: string }[];\n}\n\n/**\n * Опции маппинга: роль-специфичные куски, которые не вывести из общего контракта.\n *\n * - `roleLabel` — подпись автора (обычно ярлык роли).\n * - `isOwn` — своё ли это сообщение (правый пузырь).\n * - `isSystem` — системное ли (нейтральный стиль); по умолчанию нет.\n * - `fileName` — имя файла вложения; по умолчанию выводится из `fileUrl`.\n * - `optimistic` — включить `tempId`/`status` (оптимистичная отправка); по умолчанию да.\n * Для read-only тредов (агент) — `false`: тогда `id` берётся из серверного `id`.\n */\nexport interface IToRtMessageOptions<TMessage extends IRtMappableMessage> {\n roleLabel: (message: TMessage) => string;\n isOwn: (message: TMessage) => boolean;\n isSystem?: (message: TMessage) => boolean;\n fileName?: (message: TMessage) => string | null;\n optimistic?: boolean;\n}\n\n/**\n * Собрать `IRtChat.Message` из доменного сообщения. Общие поля (текст, delta,\n * дата, вложения, файл) берутся из контракта; автор/own/system/имя файла —\n * из опций. Ключ `id` — `tempId ?? id` в оптимистичном режиме (пока сервер не\n * подтвердил), иначе серверный `id`.\n */\nexport function toRtMessage<TMessage extends IRtMappableMessage>(\n message: TMessage,\n options: IToRtMessageOptions<TMessage>\n): IRtChat.Message {\n const optimistic: boolean = options.optimistic ?? true;\n const fileNameFromUrlOrNull: string | null = message.fileUrl ? fileNameFromUrl(message.fileUrl) : null;\n return {\n id: optimistic ? (message.tempId ?? message.id) : message.id,\n tempId: optimistic ? message.tempId : undefined,\n status: optimistic ? message.status : undefined,\n author: options.roleLabel(message),\n own: options.isOwn(message),\n system: options.isSystem?.(message) ?? false,\n text: message.message,\n delta: message.messageDelta,\n createdAt: message.createdAt,\n fileUrl: message.fileUrl,\n fileName: options.fileName ? options.fileName(message) : fileNameFromUrlOrNull,\n attachments: message.attachments.map((attachment: { id: number; name: string; publicId: string }): IRtChat.Attachment => ({\n id: attachment.id,\n name: attachment.name,\n publicId: attachment.publicId,\n })),\n };\n}\n","/*\n * Вход @rt-tools/ui-kit-v2/rich-editor — компоненты, которые работают на библиотеке quill: редактор\n * текста, поле ввода сообщения и чат. Они стоят отдельным входом, чтобы приложение без них\n * собиралось без quill: из основного входа сборщик разрешал бы import('quill') всегда.\n */\n\nexport * from './lib/components/rich-editor';\nexport * from './lib/components/message-composer';\nexport * from './lib/components/chat';\nexport * from './lib/pipes';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["BEM_BLOCK"],"mappings":"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"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-rich-editor.mjs","sources":["../../../projects/ui-kit-v2/src/rich-editor/lib/components/rich-editor/rt-rich-editor.component.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/rich-editor/rt-rich-editor.component.html","../../../projects/ui-kit-v2/src/rich-editor/lib/components/message-composer/rt-message-composer.component.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/message-composer/rt-message-composer.component.html","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat-message-actions.directive.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat-message-actions.logic.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat-message-actions.pipe.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat.model.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/pipes/rt-chat-status-label.pipe.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat-files.logic.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat-thread.logic.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat.component.ts","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/rt-chat.component.html","../../../projects/ui-kit-v2/src/rich-editor/lib/components/chat/to-rt-message.ts","../../../projects/ui-kit-v2/src/rich-editor/public-api.ts","../../../projects/ui-kit-v2/src/rich-editor/rt-tools-ui-kit-v2-rich-editor.ts"],"sourcesContent":["import {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n computed,\n ElementRef,\n forwardRef,\n input,\n InputSignal,\n OnDestroy,\n output,\n OutputEmitterRef,\n Signal,\n signal,\n viewChild,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport type Quill from 'quill';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { coerceQuillDeltaOutput, IQuillDelta, IQuillDeltaOp, RtFormControlBase } from '@rt-tools/ui-kit-v2';\n\nconst BEM_BLOCK: string = 'rt-rich-editor';\n\n/**\n * Режим тулбара: `full` — весь whitelist, `minimal` — жирный + два списка\n * (G113: чаты оператора/админа/саппорта).\n */\nexport type TRtRichEditorToolbar = 'full' | 'minimal';\n\n/** Модули тулбара — строго whitelist (без link/image/color/script). */\nconst TOOLBAR: Record<TRtRichEditorToolbar, readonly unknown[]> = {\n full: [\n ['bold', 'italic', 'underline', 'strike'],\n [{ header: 1 }, { header: 2 }, { header: 3 }],\n [{ list: 'ordered' }, { list: 'bullet' }],\n ['blockquote', 'code-block'],\n ],\n minimal: [['bold'], [{ list: 'ordered' }, { list: 'bullet' }]],\n};\n\n/** Форматы, которые Quill вообще примет (вставленное из буфера лишнее вырезается). */\nconst FORMATS: Record<TRtRichEditorToolbar, readonly string[]> = {\n full: ['bold', 'italic', 'underline', 'strike', 'header', 'list', 'blockquote', 'code-block'],\n minimal: ['bold', 'list'],\n};\n\ntype TQuillContentsArg = Parameters<Quill['setContents']>[0];\n\n/**\n * Rich-редактор чата на Quill. Наследует CVA-ядро input-семейства\n * (`RtFormControlBase`) — плагается в reactive-форму. Quill грузится **лениво**\n * (`import(\"quill\")` в `ngAfterViewInit`), тип импортируется `import type` и в\n * бандл не попадает. Значение CVA — `IQuillDelta` (или `null`, когда пусто).\n */\n@Component({\n selector: 'rt-rich-editor',\n templateUrl: './rt-rich-editor.component.html',\n styleUrl: './rt-rich-editor.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n BlockDirective,\n ElemDirective,\n ],\n providers: [\n // Алиас базового токена — чтобы rt-field мог найти контрол через\n // contentChild(RtFormControlBase) (query по абстрактному классу).\n { provide: RtFormControlBase, useExisting: forwardRef(() => RtRichEditorComponent) },\n ],\n host: {\n class: BEM_BLOCK,\n // Пока начинка редактора не смонтирована, хост несёт признак недостроенности: снаружи\n // недостроенный редактор ничем не отличается от достроенного пустого, и съёмка витрины\n // ловила именно этот промежуток — кадр выходил втрое ниже эталона.\n '[attr.data-rt-pending]': 'mounted() ? null : \"\"',\n },\n})\nexport class RtRichEditorComponent extends RtFormControlBase<IQuillDelta | null> implements AfterViewInit, OnDestroy {\n // `viewChild` не работает на ES-private (`#`) поле — держим `protected`.\n protected readonly editorHost: Signal<ElementRef<HTMLElement>> = viewChild.required<ElementRef<HTMLElement>>('editor');\n\n #quill: Quill | null = null;\n\n /** Значение, пришедшее через writeValue до готовности Quill. */\n #pending: IQuillDelta | null = null;\n\n /**\n * Смонтирована ли начинка редактора. Пока нет, хост несёт признак недостроенности: съёмке\n * витрины и любой другой проверке снаружи иначе нечем отличить недостроенный редактор от\n * достроенного пустого — оба выглядят пустым местом.\n */\n protected readonly mounted: WritableSignal<boolean> = signal<boolean>(false);\n\n protected readonly hasValue: Signal<boolean> = computed((): boolean => this.value() !== null);\n\n public readonly placeholder: InputSignal<string> = input<string>('');\n\n /** Набор кнопок форматирования; сужает и принимаемые форматы (вставка из буфера). */\n public readonly toolbar: InputSignal<TRtRichEditorToolbar> = input<TRtRichEditorToolbar>('full');\n\n /** Enter без Shift в редакторе — сигнал отправки (Shift+Enter остаётся переносом). */\n public readonly enterPressed: OutputEmitterRef<void> = output<void>();\n\n public readonly displayText: Signal<string> = computed((): string => {\n const delta: IQuillDelta | null = this.value();\n if (delta === null) {\n return '';\n }\n return delta.ops.map((op: IQuillDeltaOp): string => op.insert).join('');\n });\n\n public async ngAfterViewInit(): Promise<void> {\n const QuillCtor: typeof Quill = (await import('quill')).default;\n const quill: Quill = new QuillCtor(this.editorHost().nativeElement, {\n theme: 'snow',\n placeholder: this.placeholder(),\n formats: [...FORMATS[this.toolbar()]],\n modules: {\n toolbar: [...TOOLBAR[this.toolbar()]],\n keyboard: {\n bindings: {\n // Enter без Shift — отправка (перенос гасим возвратом false);\n // Shift+Enter не совпадает с биндингом и уходит в дефолт (перенос).\n enterSubmit: {\n key: 'Enter',\n shiftKey: false,\n handler: (): boolean => {\n this.enterPressed.emit();\n return false;\n },\n },\n },\n },\n },\n });\n this.#quill = quill;\n if (this.#pending !== null) {\n quill.setContents(this.#pending as unknown as TQuillContentsArg);\n this.#pending = null;\n }\n if (this.isDisabled()) {\n quill.disable();\n }\n quill.on('text-change', (): void => this.#onEditorChange());\n this.mounted.set(true);\n }\n\n public ngOnDestroy(): void {\n this.#quill = null;\n this.mounted.set(false);\n }\n\n public override writeValue(value: IQuillDelta | null): void {\n super.writeValue(value);\n if (this.#quill === null) {\n this.#pending = value;\n return;\n }\n this.#quill.setContents((value ?? { ops: [] }) as unknown as TQuillContentsArg);\n }\n\n public override setDisabledState(isDisabled: boolean): void {\n super.setDisabledState(isDisabled);\n if (this.#quill === null) {\n return;\n }\n if (isDisabled) {\n this.#quill.disable();\n return;\n }\n this.#quill.enable();\n }\n\n protected getEmptyValue(): IQuillDelta | null {\n return null;\n }\n\n protected focusAfterClear(): void {\n this.#quill?.focus();\n }\n\n /** Text-change: пустой слепок → null-канал; иначе delta. */\n #onEditorChange(): void {\n if (this.#quill === null) {\n return;\n }\n const blank: boolean = this.#quill.getText().trim().length === 0;\n const next: IQuillDelta | null = blank\n ? null\n : coerceQuillDeltaOutput({\n ops: this.#quill.getContents().ops as unknown as IQuillDeltaOp[],\n });\n this.value.set(next);\n this.emitChange(next);\n this.markTouched();\n }\n}\n","<ng-container rtBlock=\"rt-rich-editor\">\n <div #editor rtElem=\"surface\" qa-dataid=\"rich-editor-surface\"></div>\n</ng-container>\n","import { BooleanInput, NumberInput } from '@angular/cdk/coercion';\nimport { CdkTextareaAutosize } from '@angular/cdk/text-field';\nimport {\n booleanAttribute,\n computed,\n effect,\n inject,\n input,\n numberAttribute,\n output,\n signal,\n viewChild,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n InputSignal,\n InputSignalWithTransform,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { IQuillDelta, RT_KIT_LABELS, RtFileCardComponent, RtIconButtonComponent, rtKitLabel, TRtKitLabelMap } from '@rt-tools/ui-kit-v2';\n\nimport { RtRichEditorComponent, TRtRichEditorToolbar } from '../rich-editor/rt-rich-editor.component';\nimport { IRtMessageComposer } from './rt-message-composer.model';\n\nconst BEM_BLOCK: string = 'rt-message-composer';\n\n/** Текст в поле выше полутора строк — он перенёсся, и капсула берёт скругление высокой. */\nfunction rtComposerWraps(node: HTMLTextAreaElement): boolean {\n const style: CSSStyleDeclaration = getComputedStyle(node);\n const line: number = parseFloat(style.lineHeight) || parseFloat(style.fontSize) * 1.5;\n const text: number = node.clientHeight - parseFloat(style.paddingTop) - parseFloat(style.paddingBottom);\n return text > line * 1.5;\n}\n\ninterface IComposerFormShape {\n message: FormControl<string>;\n files: FormControl<File[]>;\n delta: FormControl<IQuillDelta | null>;\n}\n\n/**\n * Композер сообщения — капсула: слева круглая кнопка вложения, по центру авто-растущая\n * textarea, справа круглая кнопка отправки; вложения стоят внутри капсулы над строкой.\n * Презентационный, без data-access: наружу торчит только `submitted` с текстом и файлами.\n *\n * Отправка — `Enter` (без Shift) или клик по иконке; `Shift+Enter` — перенос\n * строки. Кнопка отправки активна, пока есть непустой текст или вложения.\n */\n@Component({\n selector: 'rt-message-composer',\n templateUrl: './rt-message-composer.component.html',\n styleUrl: './rt-message-composer.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // angular\n ReactiveFormsModule,\n\n // cdk\n CdkTextareaAutosize,\n\n // standalone components / directives\n RtFileCardComponent,\n RtIconButtonComponent,\n RtRichEditorComponent,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtMessageComposerComponent {\n readonly #formValue: Signal<Partial<{ message: string; files: File[]; delta: IQuillDelta | null }>>;\n\n readonly #t_chatPlaceholder: Signal<string> = rtKitLabel('chatPlaceholder');\n\n /** Текст перенёсся на вторую строку — меряется по высоте textarea после отрисовки. */\n readonly #multiRow: WritableSignal<boolean> = signal(false);\n\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly placeholderText: Signal<string> = computed((): string => this.placeholder() || this.#t_chatPlaceholder());\n\n protected readonly fileInput: Signal<ElementRef<HTMLInputElement> | undefined> = viewChild<ElementRef<HTMLInputElement>>('fileEl');\n\n protected readonly textInput: Signal<ElementRef<HTMLTextAreaElement> | undefined> =\n viewChild<ElementRef<HTMLTextAreaElement>>('textEl');\n\n protected readonly form: FormGroup<IComposerFormShape> = new FormGroup<IComposerFormShape>({\n message: new FormControl<string>('', { nonNullable: true }),\n files: new FormControl<File[]>([], { nonNullable: true }),\n delta: new FormControl<IQuillDelta | null>(null),\n });\n\n protected readonly files: Signal<readonly File[]> = computed((): readonly File[] => this.#formValue().files ?? []);\n\n /** Отправка доступна: есть контент (текст/delta/файлы), композер не занят. */\n protected readonly canSend: Signal<boolean> = computed((): boolean => {\n if (this.sending() || this.disabled()) {\n return false;\n }\n const value: Partial<{ message: string; files: File[]; delta: IQuillDelta | null }> = this.#formValue();\n const hasFiles: boolean = this.attachments() && (value.files?.length ?? 0) > 0;\n if (this.formatting()) {\n return (value.delta ?? null) !== null || hasFiles;\n }\n const hasText: boolean = (value.message ?? '').trim().length > 0;\n return hasText || hasFiles;\n });\n\n /** Капсула выше одной строки: перенос текста, вложения или режим форматирования. */\n protected readonly tall: Signal<boolean> = computed(\n (): boolean => this.#multiRow() || this.formatting() || (this.attachments() && this.files().length > 0)\n );\n\n protected readonly capsuleMods: Signal<Record<string, boolean>> = computed((): Record<string, boolean> => ({\n tall: this.tall(),\n disabled: this.disabled(),\n }));\n\n /** Текст-подсказка textarea. Пусто — берётся переведённое умолчание. */\n public readonly placeholder: InputSignal<string> = input<string>('');\n\n /** Фильтр типов для file-input (`.pdf,.doc,...`). */\n public readonly accept: InputSignal<string> = input<string>('');\n\n /** Строка под капсулой про Enter и Shift + Enter. */\n public readonly hint: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Показывать кнопку вложения и список файлов. */\n public readonly attachments: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Отправка в процессе — блокирует submit, кнопка отправки крутит индикатор. */\n public readonly sending: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Полная блокировка композера. */\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Rich-режим: вместо textarea — Quill-редактор, отправка уходит delta-каналом. */\n public readonly formatting: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Набор кнопок rich-редактора (проброс в `rt-rich-editor`). */\n public readonly toolbar: InputSignal<TRtRichEditorToolbar> = input<TRtRichEditorToolbar>('full');\n\n /** Минимальная высота textarea в строках. */\n public readonly minRows: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(1, { transform: numberAttribute });\n\n /** Максимальная высота textarea в строках (дальше — скролл). */\n public readonly maxRows: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(6, { transform: numberAttribute });\n\n /**\n * Файлы, выброшенные drag-n-drop'ом в обёртку чата: пробрасываются сюда как\n * вложения. Каждый физический drop даёт новый массив, поэтому effect\n * перезапускается на каждое перетаскивание; файлы добавляются к уже выбранным.\n */\n public readonly droppedFiles: InputSignal<File[] | null> = input<File[] | null>(null);\n\n /** Отправка сообщения: текст + файлы (последние — только при `attachments`). */\n public readonly submitted: OutputEmitterRef<IRtMessageComposer.SubmitPayload> = output<IRtMessageComposer.SubmitPayload>();\n\n constructor() {\n this.#formValue = toSignal(this.form.valueChanges, {\n initialValue: this.form.value,\n });\n\n effect((): void => {\n const blocked: boolean = this.disabled() || this.sending();\n if (blocked && this.form.enabled) {\n this.form.disable({ emitEvent: false });\n }\n if (!blocked && this.form.disabled) {\n this.form.enable({ emitEvent: false });\n }\n });\n\n // Поле пересоздаётся при смене режима форматирования: наблюдатель идёт за текущим узлом.\n effect((onCleanup: (fn: () => void) => void): void => {\n const node: HTMLTextAreaElement | undefined = this.textInput()?.nativeElement;\n if (!node || typeof ResizeObserver === 'undefined') {\n this.#multiRow.set(false);\n return;\n }\n const observer: ResizeObserver = new ResizeObserver((): void => this.#multiRow.set(rtComposerWraps(node)));\n observer.observe(node);\n onCleanup((): void => observer.disconnect());\n });\n\n effect((): void => {\n const dropped: File[] | null = this.droppedFiles();\n if (dropped !== null && dropped.length > 0 && this.attachments()) {\n this.form.controls.files.setValue([...this.form.controls.files.value, ...dropped]);\n }\n });\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n // Enter без модификаторов — отправка; Shift+Enter оставляем переносом строки.\n // isComposing — не перехватываем подтверждение IME-композиции.\n if (event.key === 'Enter' && !event.shiftKey && !event.isComposing) {\n event.preventDefault();\n this.submit();\n }\n }\n\n protected openPicker(): void {\n if (this.disabled() || this.sending()) {\n return;\n }\n this.fileInput()?.nativeElement.click();\n }\n\n protected onFilesPicked(event: Event): void {\n const el: HTMLInputElement = event.target as HTMLInputElement;\n const picked: File[] = el.files ? Array.from(el.files) : [];\n if (picked.length) {\n this.form.controls.files.setValue([...this.form.controls.files.value, ...picked]);\n }\n // Сброс value — чтобы повторный выбор того же файла снова дал change-событие.\n el.value = '';\n }\n\n protected removeFile(index: number): void {\n const next: File[] = this.form.controls.files.value.filter((_: File, i: number): boolean => i !== index);\n this.form.controls.files.setValue(next);\n }\n\n protected submit(): void {\n if (!this.canSend()) {\n return;\n }\n const files: File[] = this.attachments() ? this.form.controls.files.value : [];\n if (this.formatting()) {\n const delta: IQuillDelta | null = this.form.controls.delta.value;\n this.submitted.emit({\n text: '',\n delta: delta === null ? null : JSON.stringify(delta),\n files,\n });\n } else {\n const text: string = this.form.controls.message.value.trim();\n this.submitted.emit({ text, files });\n }\n this.form.reset({ message: '', files: [], delta: null });\n }\n}\n","<ng-container rtBlock=\"rt-message-composer\" [formGroup]=\"form\">\n <div rtElem=\"capsule\" qa-dataid=\"message-composer-capsule\" [rtMod]=\"capsuleMods()\">\n @if (attachments() && files().length) {\n <div rtElem=\"files\" qa-dataid=\"message-composer-files\">\n @for (file of files(); track $index) {\n <rt-file-card\n showRemove\n qa-dataid=\"message-composer-file\"\n size=\"sm\"\n [name]=\"file.name\"\n [sizeBytes]=\"file.size\"\n [disabled]=\"disabled() || sending()\"\n (removed)=\"removeFile($index)\" />\n }\n </div>\n }\n\n @if (formatting()) {\n <rt-rich-editor\n rtElem=\"rich\"\n qa-dataid=\"message-composer-rich\"\n formControlName=\"delta\"\n [placeholder]=\"placeholderText()\"\n [toolbar]=\"toolbar()\"\n (enterPressed)=\"submit()\" />\n }\n\n <div rtElem=\"row\">\n @if (attachments()) {\n <input\n #fileEl\n qa-dataid=\"message-composer-file-input\"\n type=\"file\"\n hidden\n multiple\n [attr.accept]=\"accept() || null\"\n (change)=\"onFilesPicked($event)\" />\n <rt-icon-button\n qa-dataid=\"message-composer-attach\"\n icon=\"paperclip\"\n iconColor=\"muted\"\n radius=\"full\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatAttachAria\"\n [tooltip]=\"t().chatAttachTooltip\"\n [disabled]=\"disabled() || sending()\"\n (clicked)=\"openPicker()\" />\n }\n\n @if (!formatting()) {\n <textarea\n #textEl\n rtElem=\"input\"\n qa-dataid=\"message-composer-input\"\n cdkTextareaAutosize\n formControlName=\"message\"\n [attr.aria-label]=\"t().chatComposerAria\"\n [placeholder]=\"placeholderText()\"\n [cdkAutosizeMinRows]=\"minRows()\"\n [cdkAutosizeMaxRows]=\"maxRows()\"\n (keydown)=\"onKeydown($event)\"></textarea>\n }\n\n <rt-icon-button\n rtElem=\"send\"\n qa-dataid=\"message-composer-send\"\n icon=\"arrow-up\"\n radius=\"full\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatSendAria\"\n [tooltip]=\"t().chatSendLabel\"\n [loading]=\"sending()\"\n [disabled]=\"!canSend()\"\n (clicked)=\"submit()\" />\n </div>\n </div>\n\n @if (hint()) {\n <p rtElem=\"hint\" qa-dataid=\"message-composer-hint\">{{ t().chatComposerHint }}</p>\n }\n</ng-container>\n","import { Directive, inject, TemplateRef } from '@angular/core';\n\nimport { IRtChat } from './rt-chat.model';\n\n/**\n * Контекст шаблона `[rtChatMessageActions]`: `$implicit` — реплика треда.\n */\nexport interface IRtChatMessageActionsContext {\n $implicit: IRtChat.Message;\n}\n\n/**\n * Захватывает `<ng-template rtChatMessageActions let-message>` — содержимое «…»-меню\n * действий у реплики. `rt-chat` рисует этот шаблон рядом с точечными действиями реплики,\n * прокидывая её через `$implicit`.\n *\n * Точечные действия остаются на месте: удаление, повтор отправки и скачивание общи для\n * любой переписки. Шаблон нужен тем действиям, которых кит не знает и знать не должен, —\n * без него потребителю оставалось ждать правки кита либо ставить кнопку над диалогом, то\n * есть не там, где читают реплику.\n *\n * Дженерика у контекста нет: тип реплики у переписки один, и type-carrier, который у\n * строки таблицы несёт тип строки, здесь не нужен.\n *\n * @example\n * ```html\n * <rt-chat [messages]=\"messages()\" [messageHasActions]=\"canAct\">\n * <ng-template rtChatMessageActions let-message>\n * <rt-menu-item icon=\"link\" label=\"Скопировать ссылку\" (selected)=\"copy(message)\" />\n * </ng-template>\n * </rt-chat>\n * ```\n */\n@Directive({\n selector: 'ng-template[rtChatMessageActions]',\n})\nexport class RtChatMessageActionsDirective {\n public readonly template: TemplateRef<IRtChatMessageActionsContext> = inject<TemplateRef<IRtChatMessageActionsContext>>(TemplateRef);\n\n /** Type-guard: сужает контекст шаблона до реплики при проверке шаблонов. */\n public static ngTemplateContextGuard(\n _directive: RtChatMessageActionsDirective,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- второй довод стража контекста шаблона стоит только в типе-предикате; убрать его нечем, подпись задаёт каркас\n context: unknown\n ): context is IRtChatMessageActionsContext {\n return true;\n }\n}\n","import { IRtChat } from './rt-chat.model';\n\n/**\n * Есть ли у реплики хотя бы одно доступное действие потребителя.\n *\n * Признак приходит предикатом от экрана, а не подсчётом отрисованных пунктов меню:\n * содержимое спроецированного шаблона известно только после отрисовки, и кнопка\n * успевала бы мигнуть на первом кадре.\n *\n * Предикат не задан — у реплики есть действия: экран, который ничего не гейтит,\n * показывает кнопку меню. Так же это устроено у строки таблицы, и расхождение между\n * двумя точками проекции одного кита читалось бы дефектом.\n */\nexport function messageHasAvailableActions(message: IRtChat.Message, hasActions: IRtChat.MessageActionsPredicate | null): boolean {\n return hasActions === null ? true : hasActions(message);\n}\n","import { Pipe, PipeTransform } from '@angular/core';\n\nimport { messageHasAvailableActions } from './rt-chat-message-actions.logic';\nimport { IRtChat } from './rt-chat.model';\n\n/**\n * Есть ли у реплики доступные действия — гейт кнопки «…» у неё.\n *\n * Pure-pipe: пересчитывается только при смене реплики или предиката, а не на каждом\n * цикле проверки. Значение приходит из контекста шаблона (реплика треда), поэтому\n * `computed()` здесь неприменим.\n */\n@Pipe({ name: 'rtChatMessageHasActions' })\nexport class RtChatMessageHasActionsPipe implements PipeTransform {\n public transform(message: IRtChat.Message, hasActions: IRtChat.MessageActionsPredicate | null): boolean {\n return messageHasAvailableActions(message, hasActions);\n }\n}\n","import { IQuillDelta } from '@rt-tools/ui-kit-v2';\n\n/**\n * Модель общего чат-компонента `rt-chat`: один корневой неймспейс\n * с префиксом `I`. Доменные стора маппят свою модель сообщения в `Message`, а сам\n * `rt-chat` ничего не знает о доменных сущностях — только рисует тред и композер.\n */\n/**\n * Судьба своего сообщения в ленте: пока летит на сервер — часы, после записи —\n * двойной чек, после того как собеседник открыл переписку — тот же чек синим,\n * при обрыве — «!» с повтором. Входящие сообщения статуса не имеют.\n */\nexport enum ERtChatMessageStatus {\n Sending = 'sending',\n Sent = 'sent',\n Read = 'read',\n Failed = 'failed',\n}\n\nexport namespace IRtChat {\n /** Алиас enum'а для доменных мапперов, работающих через неймспейс. */\n export type MessageStatus = ERtChatMessageStatus;\n\n /**\n * Есть ли у реплики доступные действия потребителя — гейт кнопки «…» у неё.\n *\n * Признак приходит предикатом, а не полем модели: действие, которого кит не знает,\n * его моделью и не описывается.\n */\n export type MessageActionsPredicate = (message: Message) => boolean;\n\n /** Вложение сообщения — домен маппит свой ресурс, скачивание по `public_id`. */\n export interface Attachment {\n id: number;\n /** Обезличенное имя для карточки файла. */\n name: string;\n /** Непрозрачный идентификатор файла — консюмер качает blob по нему. */\n publicId: string;\n }\n\n /**\n * Одно сообщение треда в уже подготовленной для отображения форме: автор —\n * готовый лейбл (домен решает, как его собрать), `own`/`system` — флаги\n * выравнивания и стиля, дата — ISO-строка (форматируется `DatePipe` внутри).\n */\n export interface Message {\n /** Идентификатор сообщения — ключ `@for track`. */\n id: number | string;\n /** Клиентский временный id оптимистичного сообщения (до ответа сервера). */\n tempId?: string;\n /**\n * Статус своего сообщения. Отсутствует у входящих: чужому сообщению\n * нечего сообщать о доставке.\n */\n status?: MessageStatus;\n /** Готовый лейбл автора (доменный authorLabel). */\n author: string;\n /** Сообщение текущего пользователя — выравнивается вправо, акцентный фон. */\n own: boolean;\n /** Признак системного сообщения (рендерится обычным входящим пузырём). */\n system?: boolean;\n text: string;\n /**\n * Rich-тело (Quill delta) — при наличии рендерится вместо plain `text`\n * через `rt-delta-view`. `null`/отсутствует ⇒ показываем `text`.\n */\n delta?: IQuillDelta | null;\n /** ISO-дата создания. */\n createdAt: string;\n /** URL вложения (если есть) — наличие включает карточку файла. */\n fileUrl?: string | null;\n /** Имя вложения для отображения в карточке. */\n fileName?: string | null;\n /**\n * Вложения сообщения (несколько файлов). Непустой массив имеет приоритет\n * над legacy-парой `fileUrl`/`fileName` (та равна первому вложению).\n */\n attachments?: readonly Attachment[];\n /** Внешняя ссылка-призыв (привязка Telegram) — наличие включает кнопку-ссылку. */\n deepLink?: string | null;\n /** Подпись кнопки-ссылки `deepLink` (домен решает текст по состоянию). */\n deepLinkLabel?: string | null;\n /** Сообщение помечено удалённым — рендерится плейсхолдером вместо содержимого. */\n deleted?: boolean;\n /** Показать действие «удалить» на этом сообщении (домен решает по правам/направлению). */\n canDelete?: boolean;\n /**\n * Текст подтверждения перед удалением. Задан — клик по корзине открывает\n * confirm-попап с этим текстом, удаление уходит только после подтверждения.\n * Пусто/undefined — удаление сразу по клику (домен без confirm-семантики).\n */\n deleteConfirm?: string;\n }\n\n /** Payload отправки: текст + файлы (пусто/undefined, если вложения выключены). */\n export interface SendPayload {\n text: string;\n files?: File[];\n /**\n * Rich-тело строкой JSON (`JSON.stringify(getContents())`) — взаимоисключимо\n * с непустым `text`. При наличии домен шлёт delta-канал (`message:\"\"`).\n */\n delta?: string | null;\n }\n}\n","import { Pipe, PipeTransform } from '@angular/core';\n\nimport { ERtChatMessageStatus } from '../components/chat/rt-chat.model';\n\n/**\n * Ключи подписей статусов для скринридера: сам индикатор — иконка, и без текста\n * различие «доставлено/прочитано» слышно не будет.\n *\n * Пайп отдаёт ключ, а переводит его `transloco` следующим звеном цепочки.\n * Готовый текст здесь застыл бы на языке, активном в момент загрузки модуля.\n */\nconst STATUS_KEYS: Readonly<Record<ERtChatMessageStatus, string>> = {\n [ERtChatMessageStatus.Sending]: 'rtKit.chatStatusSending',\n [ERtChatMessageStatus.Sent]: 'rtKit.chatStatusSent',\n [ERtChatMessageStatus.Read]: 'rtKit.chatStatusRead',\n [ERtChatMessageStatus.Failed]: 'rtKit.chatStatusFailed',\n};\n\n/** Ключ текстовой расшифровки иконки статуса сообщения. */\n@Pipe({ name: 'rtChatStatusLabel' })\nexport class RtChatStatusLabelPipe implements PipeTransform {\n public transform(status: ERtChatMessageStatus): string {\n return STATUS_KEYS[status];\n }\n}\n","/** Выбранные файлы вместе с только что добавленными. Список всегда новый: его читает сигнал. */\nexport function withAppendedFiles(current: ReadonlyArray<File>, added: ReadonlyArray<File>): File[] {\n return [...current, ...added];\n}\n\n/** Выбранные файлы без того, что стоит на этом месте. */\nexport function withoutFileAt(current: ReadonlyArray<File>, index: number): File[] {\n return current.filter((_: File, position: number): boolean => position !== index);\n}\n\n/** Файлы, названные полем выбора. Поле без выбора отдаёт пустой список, а не отсутствие. */\nexport function pickedFiles(files: FileList | null): File[] {\n return Array.from(files ?? []);\n}\n","/** Замеры прокрутки треда: столько, сколько нужно решению о прилипании к низу. */\nexport interface IRtChatThreadMetrics {\n scrollTop: number;\n scrollHeight: number;\n clientHeight: number;\n}\n\n/** Зазор от низа треда, в пределах которого читатель считается стоящим у нижнего края. */\nexport const RT_CHAT_NEAR_BOTTOM_THRESHOLD_PX: number = 64;\n\n/**\n * Задержки повторных подтягиваний ленты к низу после первой прокрутки. Присланное\n * содержимое дорисовывается несколькими проходами уже после того, как лента встала по\n * промежуточной высоте, и набор тиков покрывает окно, за которое высота устаканивается.\n */\nexport const RT_CHAT_PIN_RETRY_DELAYS_MS: ReadonlyArray<number> = [50, 150, 300, 500, 800];\n\n/** Стоит ли читатель у нижнего края треда. */\nexport function isNearBottom(metrics: IRtChatThreadMetrics): boolean {\n return metrics.scrollHeight - metrics.clientHeight - metrics.scrollTop <= RT_CHAT_NEAR_BOTTOM_THRESHOLD_PX;\n}\n\n/**\n * Прилипает ли лента к низу после этой прокрутки.\n *\n * Прилипание снимается только тогда, когда читатель уехал вверх сам. Прокрутка, сделанная\n * самим компонентом, и рост содержимого приходят с тем же или большим положением — на них\n * прилипание лишь подтверждается: иначе позднее событие от собственной прокрутки читалось бы\n * отрывом от низа, и лента переставала бы догонять последнее сообщение.\n */\nexport function nextAtBottom(previous: boolean, lastScrollTop: number, metrics: IRtChatThreadMetrics): boolean {\n const nearBottom: boolean = isNearBottom(metrics);\n\n return metrics.scrollTop < lastScrollTop - 1 ? nearBottom : previous || nearBottom;\n}\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { CdkTextareaAutosize } from '@angular/cdk/text-field';\nimport { DatePipe } from '@angular/common';\nimport {\n afterRenderEffect,\n booleanAttribute,\n computed,\n contentChild,\n effect,\n inject,\n input,\n output,\n signal,\n viewChild,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n InputSignal,\n InputSignalWithTransform,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';\n\nimport { NgTemplateOutlet } from '@angular/common';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport {\n RtButtonDirective,\n RtConfirmDirective,\n RtDeltaViewComponent,\n RtFileCardComponent,\n RtFileDropComponent,\n RtIconButtonComponent,\n RtIconComponent,\n RtMenuComponent,\n RtNoteComponent,\n RtSkeletonWrapperComponent,\n RtSpinnerComponent,\n RtToolbarComponent,\n RtToolbarLeftDirective,\n RtToolbarRightDirective,\n} from '@rt-tools/ui-kit-v2';\nimport { RT_KIT_LABELS, RT_KIT_LOCALE, rtKitLabel, TRtKitLabelKey, TRtKitLabelMap } from '@rt-tools/ui-kit-v2';\nimport { RtChatMessageActionsDirective } from './rt-chat-message-actions.directive';\nimport { RtChatMessageHasActionsPipe } from './rt-chat-message-actions.pipe';\nimport { RtChatStatusLabelPipe } from '../../pipes/rt-chat-status-label.pipe';\nimport { RtMessageComposerComponent } from '../message-composer/rt-message-composer.component';\nimport { IRtMessageComposer } from '../message-composer/rt-message-composer.model';\nimport { TRtRichEditorToolbar } from '../rich-editor/rt-rich-editor.component';\nimport { pickedFiles, withAppendedFiles, withoutFileAt } from './rt-chat-files.logic';\nimport { nextAtBottom, RT_CHAT_PIN_RETRY_DELAYS_MS } from './rt-chat-thread.logic';\nimport { ERtChatMessageStatus, IRtChat } from './rt-chat.model';\n\nconst BEM_BLOCK: string = 'rt-chat';\n\n/** Ключ заглушки имени вложения, когда домен не отдал `fileName` (только URL). */\nconst ATTACHMENT_FALLBACK_KEY: TRtKitLabelKey = 'chatAttachmentFallback';\n\n/**\n * Общий презентационный чат: тред сообщений + композер. Никакого data-access/api — история\n * приходит готовым массивом `IRtChat.Message[]`, отправка/обновление/скачивание уходят наружу\n * через outputs, а стор и blob-загрузка остаются в feature-компоненте каждого домена.\n *\n * Композер держит свой `FormGroup` — наружу торчит только `send`. Полноэкранный\n * режим (expand) — overlay внутри самого компонента (`--expanded`), потребителю\n * лишь опционально сообщается через `expandedChange`.\n *\n * Шапка (тулбар «Чат» + refresh/expand) рендерится только когда включена хотя бы\n * одна из иконок (`showRefresh`/`showExpand`): в диалогах своя header-обёртка,\n * туда тулбар не нужен.\n */\n@Component({\n selector: 'rt-chat',\n templateUrl: './rt-chat.component.html',\n styleUrls: ['./rt-chat.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n CdkTextareaAutosize,\n DatePipe,\n NgTemplateOutlet,\n ReactiveFormsModule,\n\n // standalone components / directives\n RtButtonDirective,\n RtChatStatusLabelPipe,\n RtConfirmDirective,\n RtDeltaViewComponent,\n RtFileCardComponent,\n RtFileDropComponent,\n RtIconButtonComponent,\n RtIconComponent,\n RtChatMessageHasActionsPipe,\n RtMenuComponent,\n RtMessageComposerComponent,\n RtNoteComponent,\n RtSkeletonWrapperComponent,\n RtSpinnerComponent,\n RtToolbarComponent,\n RtToolbarLeftDirective,\n RtToolbarRightDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n host: {\n class: BEM_BLOCK,\n '[class.rt-chat--expanded]': 'expanded()',\n '[class.rt-chat--fill]': 'fill()',\n },\n})\nexport class RtChatComponent {\n /**\n * Дата сообщения форматируется по активной локали приложения, а не по\n * `LOCALE_ID`: тот вычисляется на подъёме приложения и там, где язык\n * переключают на ходу, оставил бы часы в прежнем формате до перезагрузки.\n *\n * Данные локали для `DatePipe` регистрирует приложение: без них пайп падает\n * `Missing locale data`, и кит за это не отвечает.\n */\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly locale: Signal<string> = inject(RT_KIT_LOCALE);\n\n /**\n * Пользователь у нижнего края треда. Плоское поле (не сигнал), чтобы\n * afterRenderEffect не перезапускался на каждый scroll — обновляется в\n * обработчике scroll и читается при автоскролле.\n */\n #atBottom: boolean = true;\n\n /** Прошлый scrollTop треда — для различения прокрутки вверх и роста контента. */\n #lastScrollTop: number = 0;\n\n /** One-shot: своё отправленное сообщение всегда прокручивает тред вниз. */\n #forceScroll: boolean = false;\n\n /** Текущее значение композера — источник реактивности для `canSend`. */\n readonly #formValue: Signal<Partial<{ message: string; files: File[] }>>;\n\n /**\n * Скролл-контейнер треда — для автопрокрутки к последнему сообщению.\n * `viewChild` не работает на ES-private (`#`) поле, поэтому `protected`.\n */\n protected readonly thread: Signal<ElementRef<HTMLElement> | undefined> = viewChild<ElementRef<HTMLElement>>('thread');\n\n /** Скрытый нативный input — открывается кнопкой-скрепкой внутри поля ввода. */\n protected readonly composerFileEl: Signal<ElementRef<HTMLInputElement> | undefined> =\n viewChild<ElementRef<HTMLInputElement>>('composerFileEl');\n\n protected readonly attachmentFallbackName: Signal<string> = rtKitLabel(ATTACHMENT_FALLBACK_KEY);\n\n /** Подписи с учётом того, что передал хозяин компонента: своё важнее умолчания */\n protected readonly titleText: Signal<string> = computed((): string => this.title() || this.#defaultTitle());\n protected readonly placeholderText: Signal<string> = computed((): string => this.placeholder() || this.#defaultPlaceholder());\n protected readonly emptyHintText: Signal<string> = computed((): string => this.emptyHint() || this.#defaultEmptyHint());\n\n readonly #defaultTitle: Signal<string> = rtKitLabel('chatTitle');\n readonly #defaultPlaceholder: Signal<string> = rtKitLabel('chatPlaceholder');\n readonly #defaultEmptyHint: Signal<string> = rtKitLabel('chatEmptyHint');\n\n protected readonly MessageStatus: typeof ERtChatMessageStatus = ERtChatMessageStatus;\n\n /** Плейсхолдеры скелетонов треда при первичной загрузке. */\n protected readonly skeletonRows: readonly number[] = [1, 2, 3];\n\n /** Полноэкранный режим (overlay поверх страницы). */\n protected readonly expanded: WritableSignal<boolean> = signal<boolean>(false);\n\n protected readonly replyForm: FormGroup<{\n message: FormControl<string>;\n files: FormControl<File[]>;\n }> = new FormGroup({\n message: new FormControl<string>('', { nonNullable: true }),\n files: new FormControl<File[]>([], { nonNullable: true }),\n });\n\n /** Композер заблокирован при загрузке/рефреше треда или отправке in-flight. */\n protected readonly composerDisabled: Signal<boolean> = computed((): boolean => this.loading() || this.fetching() || this.sending());\n\n /**\n * Можно ли отправить: композер активен и есть содержимое — непустой текст или\n * (при включённых вложениях) хотя бы один файл. Сообщение само по себе не\n * бывает «невалидным» — пустоту гасим дизейблом кнопки, а не подсветкой поля.\n */\n protected readonly canSend: Signal<boolean> = computed((): boolean => {\n if (this.composerDisabled()) {\n return false;\n }\n const value: Partial<{ message: string; files: File[] }> = this.#formValue();\n const hasText: boolean = (value.message ?? '').trim().length > 0;\n const hasFiles: boolean = this.attachments() && (value.files?.length ?? 0) > 0;\n return hasText || hasFiles;\n });\n\n /** Показывать ли шапку: только когда включена хотя бы одна иконка. */\n protected readonly showHeader: Signal<boolean> = computed((): boolean => this.showRefresh() || this.showExpand());\n\n /** Подпись кнопки fullscreen: тернарник в шаблоне переводом не покрыть. */\n protected readonly expandLabel: Signal<string> = rtKitLabel(\n computed((): TRtKitLabelKey => (this.expanded() ? 'chatCollapse' : 'chatExpand'))\n );\n\n /** Выбранные, но ещё не отправленные файлы — карточки над полем ввода. */\n protected readonly selectedFiles: Signal<File[]> = computed((): File[] => this.#formValue().files ?? []);\n\n /**\n * Drop-зона активна только когда вложения включены, ответ доступен и композер\n * не занят (загрузка/рефреш/отправка). Иначе обёртка `rt-file-drop` просто\n * пропускает контент без оверлея.\n */\n protected readonly dropDisabled: Signal<boolean> = computed(\n (): boolean => !this.attachments() || !this.canReply() || this.composerDisabled()\n );\n\n /**\n * Файл из drag-n-drop для rich-композера: каждый drop кладёт новый `File`,\n * пробрасывается в `rt-message-composer` через input. Классический композер\n * принимает drop напрямую в свой `replyForm`.\n */\n protected readonly droppedFiles: WritableSignal<File[] | null> = signal<File[] | null>(null);\n\n /**\n * Шаблон действий у реплики: `<ng-template rtChatMessageActions let-message>`.\n *\n * Не объявлен — разметка реплики прежняя, и лишней кнопки у неё не появляется.\n */\n protected readonly messageActions: Signal<RtChatMessageActionsDirective | undefined> = contentChild(RtChatMessageActionsDirective);\n\n /** История сообщений (consumer уже смаппил из доменной модели). */\n public readonly messages: InputSignal<readonly IRtChat.Message[]> = input<readonly IRtChat.Message[]>([]);\n\n /** Первичная загрузка — скелетоны вместо треда. */\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Рефреш при наличии данных — тред остаётся, композер дизейблится. */\n public readonly fetching: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Доступна ли отправка (иначе вместо композера — note с причиной). */\n public readonly canReply: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Причина блокировки ответа — note под тредом. */\n public readonly replyBlockReason: InputSignal<string | null> = input<string | null>(null);\n\n /** Отправка in-flight — спиннер/дизейбл на кнопке. */\n public readonly sending: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /**\n * Подписи по умолчанию приходят пустыми и переводятся ниже: значение\n * `input()` вычисляется при создании компонента, и готовый перевод застыл бы\n * на языке, активном в этот момент.\n */\n public readonly placeholder: InputSignal<string> = input<string>('');\n\n public readonly title: InputSignal<string> = input<string>('');\n\n /** Текст, когда треда ещё нет (заявка не создана). */\n public readonly emptyHint: InputSignal<string> = input<string>('');\n\n /** Есть ли тред (иначе показываем `emptyHint`). */\n public readonly hasThread: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Включить загрузку файлов в композере. */\n public readonly attachments: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** `accept` для file-input (`.pdf,.doc,...`). */\n public readonly accept: InputSignal<string> = input<string>('');\n\n /**\n * Компактный композер (`rt-message-composer`): авто-растущая textarea над\n * разделителем + ряд иконок (прикрепить слева, отправить справа) вместо\n * классического вертикального стека. По умолчанию выключен.\n */\n public readonly richComposer: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /**\n * Rich-текст в композере (Quill delta). Требует `richComposer` — форматирование\n * живёт только в компактном композере. Отправка уходит delta-каналом.\n */\n public readonly formatting: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Набор кнопок rich-редактора (проброс до `rt-rich-editor` через композер). */\n public readonly formattingToolbar: InputSignal<TRtRichEditorToolbar> = input<TRtRichEditorToolbar>('full');\n\n /**\n * Растягивать чат на всю высоту контейнера: тред занимает свободное место,\n * композер прижат к низу. По умолчанию выключен (тред с фикс. max-height).\n * Требует, чтобы родитель давал высоту (flex-цепочка).\n */\n public readonly fill: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Показать иконку refresh в шапке. */\n public readonly showRefresh: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Показать иконку expand (fullscreen) в шапке. */\n public readonly showExpand: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Отправка сообщения (+файлы) — consumer вызывает свой store/api. */\n public readonly send: OutputEmitterRef<IRtChat.SendPayload> = output<IRtChat.SendPayload>();\n\n /** Клик refresh — consumer перетягивает тред. */\n public readonly refresh: OutputEmitterRef<void> = output<void>();\n\n /** Клик по вложению — consumer качает blob своим api. Шаблон зовёт выход прямо: релей-метод,\n * который только повторял `emit`, ничего не добавлял, а файл при этом рос. */\n public readonly downloadFile: OutputEmitterRef<IRtChat.Message> = output<IRtChat.Message>();\n\n /** Клик по карточке вложения из `attachments[]` — консюмер качает по `publicId`. */\n public readonly downloadAttachment: OutputEmitterRef<IRtChat.Attachment> = output<IRtChat.Attachment>();\n\n /** Смена fullscreen-состояния. */\n public readonly expandedChange: OutputEmitterRef<boolean> = output<boolean>();\n\n public readonly deleteMessage: OutputEmitterRef<IRtChat.Message> = output<IRtChat.Message>();\n\n /** Повторная отправка своего сообщения со статусом `failed`. */\n public readonly retryMessage: OutputEmitterRef<IRtChat.Message> = output<IRtChat.Message>();\n\n /**\n * Есть ли у реплики действия потребителя — гейт кнопки «…» у неё.\n *\n * Не задан — точка действий показывается у каждой реплики: экран, который ничего не\n * гейтит, показывает её так же, как это делает строка таблицы.\n */\n public readonly messageHasActions: InputSignal<IRtChat.MessageActionsPredicate | null> = input<IRtChat.MessageActionsPredicate | null>(\n null\n );\n\n constructor() {\n this.#formValue = toSignal(this.replyForm.valueChanges, {\n initialValue: this.replyForm.value,\n });\n\n // Поведение мессенджера: после каждого рендера, зависящего от треда\n // (новые сообщения, окончание загрузки, fullscreen), прокручиваем к\n // последнему сообщению — но только если это своё сообщение (forceScroll)\n // или пользователь уже у нижнего края. Если он ушёл вверх читать историю,\n // входящее сообщение его не дёргает. afterRenderEffect гарантирует, что DOM\n // уже обновлён и scrollHeight посчитан по реальной высоте.\n afterRenderEffect((): void => {\n this.messages();\n this.loading();\n this.fetching();\n this.expanded();\n const el: HTMLElement | undefined = this.thread()?.nativeElement;\n if (el === undefined) {\n return;\n }\n if (this.#forceScroll || this.#atBottom) {\n el.scrollTop = el.scrollHeight;\n this.#atBottom = true;\n this.#pinToBottomDeferred();\n }\n this.#forceScroll = false;\n });\n\n // `formControlName`-инпуты игнорируют атрибут `disabled` — состояние ввода\n // держим через сам контрол: блок при рефреше треда или отправке in-flight.\n effect((): void => {\n const blocked: boolean = this.composerDisabled();\n if (blocked && this.replyForm.enabled) {\n this.replyForm.disable({ emitEvent: false });\n return;\n }\n if (!blocked && this.replyForm.disabled) {\n this.replyForm.enable({ emitEvent: false });\n }\n });\n }\n\n protected onSubmit(): void {\n // Кнопка уже дизейблится по `canSend` — guard лишь страхует от submit в\n // обход кнопки (программный/Enter), молча и без подсветки поля.\n if (!this.canSend()) {\n return;\n }\n const text: string = this.replyForm.controls.message.value.trim();\n const files: File[] = this.replyForm.controls.files.value;\n // Своё сообщение всегда прокручивает тред вниз — независимо от позиции.\n this.#forceScroll = true;\n this.send.emit({ text, files: this.attachments() ? files : undefined });\n this.replyForm.reset({ message: '', files: [] });\n }\n\n protected onComposerKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter' && !event.shiftKey && !event.isComposing) {\n event.preventDefault();\n this.onSubmit();\n }\n }\n\n /** Релей submit'а от `rt-message-composer` (rich-режим) наружу как `send`. */\n protected onComposerSubmit(payload: IRtMessageComposer.SubmitPayload): void {\n // Своё сообщение всегда прокручивает тред вниз — независимо от позиции.\n this.#forceScroll = true;\n this.send.emit({\n text: payload.text,\n files: this.attachments() ? payload.files : undefined,\n delta: payload.delta,\n });\n }\n\n /**\n * Файлы выброшены в обёртку чата: в rich-режиме отдаём массив композеру через\n * input, в классическом — добавляем к уже выбранным в собственном `replyForm`.\n */\n protected onFilesDropped(files: File[]): void {\n if (files.length === 0) {\n return;\n }\n if (this.richComposer()) {\n // Новый массив на каждый drop — effect композера видит каждое перетаскивание.\n this.droppedFiles.set([...files]);\n return;\n }\n this.replyForm.controls.files.setValue(withAppendedFiles(this.replyForm.controls.files.value, files));\n }\n\n protected openFilePicker(): void {\n this.composerFileEl()?.nativeElement.click();\n }\n\n protected onFilesPicked(event: Event): void {\n const inputEl: HTMLInputElement = event.target as HTMLInputElement;\n const picked: File[] = pickedFiles(inputEl.files);\n if (picked.length > 0) {\n this.replyForm.controls.files.setValue(withAppendedFiles(this.replyForm.controls.files.value, picked));\n }\n // Сброс значения: без него повторный выбор того же файла не даёт `change`.\n inputEl.value = '';\n }\n\n protected removeFile(index: number): void {\n this.replyForm.controls.files.setValue(withoutFileAt(this.replyForm.controls.files.value, index));\n }\n\n /** Признак «читатель у нижнего края» обновляется по прокрутке: на нём стоит автопрокрутка. */\n protected onThreadScroll(): void {\n const el: HTMLElement | undefined = this.thread()?.nativeElement;\n if (el === undefined) {\n return;\n }\n\n this.#atBottom = nextAtBottom(this.#atBottom, this.#lastScrollTop, el);\n this.#lastScrollTop = el.scrollTop;\n }\n\n /**\n * Серия отложенных подтягиваний ленты к низу: присланное содержимое дорисовывается несколькими\n * проходами, и одной прокрутки мало. Каждый тик берёт тред заново — он бывает пересоздан — и\n * дотягивает ленту, пока читатель стоит у нижнего края.\n */\n #pinToBottomDeferred(): void {\n for (const delay of RT_CHAT_PIN_RETRY_DELAYS_MS) {\n setTimeout((): void => {\n const el: HTMLElement | undefined = this.thread()?.nativeElement;\n if (el !== undefined && this.#atBottom) {\n el.scrollTop = el.scrollHeight;\n }\n }, delay);\n }\n }\n\n protected toggleExpand(): void {\n const next: boolean = !this.expanded();\n this.expanded.set(next);\n this.expandedChange.emit(next);\n }\n}\n","<ng-container rtBlock=\"rt-chat\">\n <rt-file-drop\n [overlayLabel]=\"t().chatDropOverlay\"\n [accept]=\"accept()\"\n [disabled]=\"dropDisabled()\"\n (filesDropped)=\"onFilesDropped($event)\">\n @if (showHeader()) {\n <rt-toolbar rtElem=\"header\" dense>\n <ng-template rtToolbarLeft>\n <h3 rtElem=\"title\" qa-dataid=\"chat-title\">{{ title() }}</h3>\n </ng-template>\n <ng-template rtToolbarRight>\n @if (showRefresh()) {\n <rt-icon-button\n qa-dataid=\"chat-refresh\"\n icon=\"sync\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatRefreshAria\"\n [tooltip]=\"t().chatRefreshTooltip\"\n [loading]=\"fetching()\"\n [disabled]=\"!hasThread()\"\n (clicked)=\"refresh.emit()\" />\n }\n @if (showExpand()) {\n <rt-icon-button\n qa-dataid=\"chat-expand\"\n variant=\"ghost\"\n [icon]=\"expanded() ? 'window-minimize' : 'window-maximize'\"\n [ariaLabel]=\"expandLabel()\"\n [tooltip]=\"expandLabel()\"\n (clicked)=\"toggleExpand()\" />\n }\n <ng-content select=\"[rtChatHeaderActions]\" />\n </ng-template>\n </rt-toolbar>\n }\n\n @if (!hasThread()) {\n <rt-note qa-dataid=\"chat-empty-hint\">{{ emptyHint() }}</rt-note>\n } @else {\n <div rtElem=\"thread-viewport\" qa-dataid=\"chat-thread-viewport\">\n @if (loading()) {\n <!-- Скелетон повторяет структуру сообщения (автор → текст → дата),\n чередуя выравнивание, чтобы тред не «прыгал» при подмене на реальные. -->\n <div rtElem=\"thread\" qa-dataid=\"chat-thread-skeleton\">\n @for (row of skeletonRows; track row; let even = $even) {\n <div rtElem=\"message-skeleton\" qa-dataid=\"chat-message-skeleton\" [rtMod]=\"{ own: even }\">\n <rt-skeleton-wrapper rtElem=\"skeleton-line\" width=\"72px\" height=\"10px\" [isLoading]=\"true\" />\n <rt-skeleton-wrapper rtElem=\"skeleton-line\" width=\"100%\" height=\"13px\" [isLoading]=\"true\" />\n <rt-skeleton-wrapper rtElem=\"skeleton-line\" width=\"55%\" height=\"13px\" [isLoading]=\"true\" />\n <rt-skeleton-wrapper rtElem=\"skeleton-line\" width=\"56px\" height=\"10px\" [isLoading]=\"true\" />\n </div>\n }\n </div>\n } @else {\n <div\n #thread\n rtElem=\"thread\"\n qa-dataid=\"chat-thread\"\n [rtMod]=\"{ frozen: fetching() }\"\n [attr.aria-busy]=\"fetching() ? 'true' : null\"\n (scroll)=\"onThreadScroll()\">\n @for (m of messages(); track m.id) {\n <div\n rtElem=\"message-row\"\n qa-dataid=\"chat-message\"\n [attr.data-own]=\"m.own\"\n [attr.data-status]=\"m.status || null\"\n [attr.data-deleted]=\"m.deleted || null\"\n [rtMod]=\"{ own: m.own }\">\n @if (m.canDelete && !m.deleted) {\n @if (m.deleteConfirm) {\n <rt-icon-button\n rtElem=\"message-delete\"\n qa-dataid=\"chat-message-delete\"\n icon=\"trash\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatDeleteAria\"\n [tooltip]=\"t().chatDeleteTooltip\"\n [rtConfirm]=\"m.deleteConfirm\"\n (confirmed)=\"deleteMessage.emit(m)\" />\n } @else {\n <rt-icon-button\n rtElem=\"message-delete\"\n qa-dataid=\"chat-message-delete\"\n icon=\"trash\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatDeleteAria\"\n [tooltip]=\"t().chatDeleteTooltip\"\n (clicked)=\"deleteMessage.emit(m)\" />\n }\n }\n @if (messageActions()?.template; as actionsTpl) {\n @if (m | rtChatMessageHasActions: messageHasActions()) {\n <div rtElem=\"message-actions\" qa-dataid=\"chat-message-actions\">\n <rt-menu>\n <ng-container\n [ngTemplateOutlet]=\"actionsTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: m }\" />\n </rt-menu>\n </div>\n }\n }\n <div rtElem=\"message\" [rtMod]=\"{ own: m.own, deleted: m.deleted }\">\n <p rtElem=\"message-author\" qa-dataid=\"chat-message-author\">{{ m.author }}</p>\n @if (m.deleted) {\n <p rtElem=\"message-text\" qa-dataid=\"chat-message-deleted\" rtMod=\"deleted\">\n {{ t().chatMessageDeleted }}\n </p>\n } @else {\n @if (m.delta) {\n <rt-delta-view rtElem=\"message-text\" qa-dataid=\"chat-message-text\" [delta]=\"m.delta\" />\n } @else {\n <p rtElem=\"message-text\" qa-dataid=\"chat-message-text\">{{ m.text }}</p>\n }\n @if (m.attachments?.length) {\n @for (att of m.attachments; track att.id) {\n <span rtElem=\"message-attachment\" qa-dataid=\"chat-message-attachment\">\n <rt-file-card\n showDownload\n size=\"sm\"\n [name]=\"att.name || attachmentFallbackName()\"\n (download)=\"downloadAttachment.emit(att)\" />\n </span>\n }\n } @else if (m.fileUrl) {\n <span rtElem=\"message-attachment\" qa-dataid=\"chat-message-attachment\">\n <rt-file-card\n showDownload\n size=\"sm\"\n [name]=\"m.fileName || attachmentFallbackName()\"\n (download)=\"downloadFile.emit(m)\" />\n </span>\n }\n @if (m.deepLink) {\n <span rtElem=\"message-deeplink\">\n <a\n rtButton\n qa-dataid=\"chat-message-deeplink\"\n appearance=\"outlined\"\n icon=\"send\"\n rel=\"noopener\"\n target=\"_blank\"\n [href]=\"m.deepLink\"\n [label]=\"m.deepLinkLabel || t().uiSubscribeNotifications\"\n [attr.aria-label]=\"m.deepLinkLabel || t().uiSubscribeNotifications\"></a>\n </span>\n }\n }\n <span rtElem=\"message-footer\">\n <span rtElem=\"message-date\" qa-dataid=\"chat-message-date\">\n {{ m.createdAt | date: 'short' : undefined : locale() }}\n </span>\n @if (m.status) {\n <span\n rtElem=\"message-status\"\n qa-dataid=\"chat-message-status\"\n [attr.data-status]=\"m.status\"\n [rtMod]=\"{ status: m.status }\"\n [attr.aria-label]=\"m.status | rtChatStatusLabel\">\n @if (m.status === MessageStatus.Failed) {\n <rt-icon rtElem=\"status-icon\" name=\"exclamation-circle\" size=\"sm\" />\n <rt-icon-button\n qa-dataid=\"chat-message-retry\"\n icon=\"sync\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatRetryAria\"\n [tooltip]=\"t().chatRetryTooltip\"\n (clicked)=\"retryMessage.emit(m)\" />\n } @else {\n <!-- Часы, пока сообщение в пути; дальше двойной чек, цвет которого\n (серый/синий) различает доставлено и прочитано. -->\n <rt-icon\n rtElem=\"status-icon\"\n size=\"sm\"\n [name]=\"m.status === MessageStatus.Sending ? 'clock' : 'check-double'\" />\n }\n </span>\n }\n </span>\n </div>\n </div>\n } @empty {\n <rt-note qa-dataid=\"chat-empty-thread\">{{ t().chatEmptyThread }}</rt-note>\n }\n </div>\n }\n @if (!loading() && fetching()) {\n <div rtElem=\"thread-overlay\" qa-dataid=\"chat-thread-overlay\" role=\"status\" [attr.aria-label]=\"t().chatRefreshAria\">\n <rt-spinner diameter=\"32\" />\n </div>\n }\n </div>\n\n @if (canReply()) {\n @if (richComposer()) {\n <rt-message-composer\n rtElem=\"composer-rich\"\n qa-dataid=\"chat-composer-rich\"\n [placeholder]=\"placeholder()\"\n [accept]=\"accept()\"\n [attachments]=\"attachments()\"\n [formatting]=\"formatting()\"\n [toolbar]=\"formattingToolbar()\"\n [sending]=\"sending()\"\n [disabled]=\"loading() || fetching()\"\n [droppedFiles]=\"droppedFiles()\"\n (submitted)=\"onComposerSubmit($event)\" />\n } @else {\n <form rtElem=\"composer\" qa-dataid=\"chat-composer\" [formGroup]=\"replyForm\" (ngSubmit)=\"onSubmit()\">\n @if (attachments() && selectedFiles().length > 0) {\n <div rtElem=\"composer-files\" qa-dataid=\"chat-composer-files\">\n @for (file of selectedFiles(); track $index) {\n <rt-file-card\n showRemove\n qa-dataid=\"chat-composer-file\"\n size=\"sm\"\n [name]=\"file.name\"\n [sizeBytes]=\"file.size\"\n [disabled]=\"composerDisabled()\"\n (removed)=\"removeFile($index)\" />\n }\n </div>\n }\n <div rtElem=\"composer-field\" [rtMod]=\"{ attach: attachments() }\">\n @if (attachments()) {\n <input\n #composerFileEl\n qa-dataid=\"chat-composer-file-input\"\n type=\"file\"\n hidden\n multiple\n [attr.accept]=\"accept() || null\"\n (change)=\"onFilesPicked($event)\" />\n <rt-icon-button\n qa-dataid=\"chat-composer-attach\"\n icon=\"paperclip\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatAttachAria\"\n [tooltip]=\"t().chatAttachTooltip\"\n [disabled]=\"composerDisabled()\"\n (clicked)=\"openFilePicker()\" />\n }\n <textarea\n rtElem=\"composer-input\"\n qa-dataid=\"chat-composer-input\"\n cdkTextareaAutosize\n formControlName=\"message\"\n cdkAutosizeMinRows=\"1\"\n cdkAutosizeMaxRows=\"4\"\n [attr.aria-label]=\"t().chatComposerAria\"\n [placeholder]=\"placeholder()\"\n (keydown)=\"onComposerKeydown($event)\"></textarea>\n </div>\n <button\n rtButton\n rtElem=\"composer-send\"\n qa-dataid=\"chat-composer-send\"\n type=\"submit\"\n theme=\"primary\"\n appearance=\"filled\"\n [label]=\"t().chatSendLabel\"\n [attr.aria-label]=\"t().chatSendAria\"\n [loading]=\"sending()\"\n [disabled]=\"!canSend()\"></button>\n </form>\n }\n } @else if (replyBlockReason()) {\n <rt-note rtElem=\"reply-block\" qa-dataid=\"chat-reply-block\">{{ replyBlockReason() }}</rt-note>\n }\n\n <!-- Слот доменных действий потребителя под композером: в fullscreen\n попадает внутрь overlay, поэтому кнопки остаются видны. -->\n <div rtElem=\"footer-slot\" qa-dataid=\"chat-footer\" [rtMod]=\"{ blocked: fetching() }\" [attr.inert]=\"fetching() ? '' : null\">\n <ng-content select=\"[rtChatFooter]\" />\n </div>\n }\n </rt-file-drop>\n</ng-container>\n","import { fileNameFromUrl, IQuillDelta } from '@rt-tools/ui-kit-v2';\n\nimport { ERtChatMessageStatus, IRtChat } from './rt-chat.model';\n\n/**\n * Статус уже сохранённого своего сообщения: сервер знает только, дошло ли оно до\n * собеседника. Часы и ошибка — состояния клиентской очереди, сюда не попадают.\n */\nexport function deliveryStatus(read: boolean): ERtChatMessageStatus {\n return read ? ERtChatMessageStatus.Read : ERtChatMessageStatus.Sent;\n}\n\n/**\n * Сообщение, ещё не подтверждённое сервером. Серверного id и ссылок на вложения\n * у него нет: есть клиентский ключ, текст и выбранные файлы.\n *\n * Rich-тело приходит уже разобранным — доменная форма его хранения тут ни при\n * чём, а хранят его стороны по-разному: одна шлёт обычный текст, другая —\n * строку композера, которая в том же виде уходит на сервер.\n */\nexport interface IRtPendingMessage {\n tempId: string;\n text: string;\n delta?: IQuillDelta | null;\n createdAt: string;\n status: IRtChat.MessageStatus;\n files: readonly File[];\n}\n\n/**\n * Неподтверждённое сообщение → строка ленты. Показывается сразу после отправки:\n * ждать ответа сервера, глядя в пустоту, незачем ни одной из сторон.\n *\n * Скрыть такое сообщение нельзя: на сервере его ещё нет, и удалять нечего.\n */\nexport function pendingToRtMessage(pending: IRtPendingMessage, authorLabel: string): IRtChat.Message {\n return {\n id: pending.tempId,\n tempId: pending.tempId,\n author: authorLabel,\n own: true,\n text: pending.text,\n delta: pending.delta ?? null,\n createdAt: pending.createdAt,\n status: pending.status,\n canDelete: false,\n attachments: pending.files.map((file: File, index: number): IRtChat.Attachment => ({\n id: index,\n name: file.name,\n // Файл ещё не на сервере — скачивать нечего, карточка только именует.\n publicId: '',\n })),\n };\n}\n\n/**\n * Структурный контракт доменного сообщения, достаточный для маппинга в\n * `IRtChat.Message`. Доменные модели удовлетворяют ему по форме;\n * роль-специфика (автор/own/system) задаётся опциями.\n */\nexport interface IRtMappableMessage {\n id: string | number;\n tempId?: string;\n status?: IRtChat.MessageStatus;\n message: string;\n messageDelta: IQuillDelta | null;\n createdAt: string;\n fileUrl: string | null;\n attachments: readonly { id: number; name: string; publicId: string }[];\n}\n\n/**\n * Опции маппинга: роль-специфичные куски, которые не вывести из общего контракта.\n *\n * - `roleLabel` — подпись автора (обычно ярлык роли).\n * - `isOwn` — своё ли это сообщение (правый пузырь).\n * - `isSystem` — системное ли (нейтральный стиль); по умолчанию нет.\n * - `fileName` — имя файла вложения; по умолчанию выводится из `fileUrl`.\n * - `optimistic` — включить `tempId`/`status` (оптимистичная отправка); по умолчанию да.\n * Для read-only тредов (агент) — `false`: тогда `id` берётся из серверного `id`.\n */\nexport interface IToRtMessageOptions<TMessage extends IRtMappableMessage> {\n roleLabel: (message: TMessage) => string;\n isOwn: (message: TMessage) => boolean;\n isSystem?: (message: TMessage) => boolean;\n fileName?: (message: TMessage) => string | null;\n optimistic?: boolean;\n}\n\n/**\n * Собрать `IRtChat.Message` из доменного сообщения. Общие поля (текст, delta,\n * дата, вложения, файл) берутся из контракта; автор/own/system/имя файла —\n * из опций. Ключ `id` — `tempId ?? id` в оптимистичном режиме (пока сервер не\n * подтвердил), иначе серверный `id`.\n */\nexport function toRtMessage<TMessage extends IRtMappableMessage>(\n message: TMessage,\n options: IToRtMessageOptions<TMessage>\n): IRtChat.Message {\n const optimistic: boolean = options.optimistic ?? true;\n const fileNameFromUrlOrNull: string | null = message.fileUrl ? fileNameFromUrl(message.fileUrl) : null;\n return {\n id: optimistic ? (message.tempId ?? message.id) : message.id,\n tempId: optimistic ? message.tempId : undefined,\n status: optimistic ? message.status : undefined,\n author: options.roleLabel(message),\n own: options.isOwn(message),\n system: options.isSystem?.(message) ?? false,\n text: message.message,\n delta: message.messageDelta,\n createdAt: message.createdAt,\n fileUrl: message.fileUrl,\n fileName: options.fileName ? options.fileName(message) : fileNameFromUrlOrNull,\n attachments: message.attachments.map((attachment: { id: number; name: string; publicId: string }): IRtChat.Attachment => ({\n id: attachment.id,\n name: attachment.name,\n publicId: attachment.publicId,\n })),\n };\n}\n","/*\n * Вход @rt-tools/ui-kit-v2/rich-editor — компоненты, которые работают на библиотеке quill: редактор\n * текста, поле ввода сообщения и чат. Они стоят отдельным входом, чтобы приложение без них\n * собиралось без quill: из основного входа сборщик разрешал бы import('quill') всегда.\n */\n\nexport * from './lib/components/rich-editor';\nexport * from './lib/components/message-composer';\nexport * from './lib/components/chat';\nexport * from './lib/pipes';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["BEM_BLOCK"],"mappings":"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"}