@rt-tools/ui-kit-v2 0.36.0 → 0.37.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 (32) hide show
  1. package/fesm2022/rt-tools-ui-kit-v2-ai-prompt-input.mjs +2 -2
  2. package/fesm2022/rt-tools-ui-kit-v2-ai-prompt-input.mjs.map +1 -1
  3. package/fesm2022/rt-tools-ui-kit-v2-detail-list.mjs +2 -2
  4. package/fesm2022/rt-tools-ui-kit-v2-detail-list.mjs.map +1 -1
  5. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +147 -21
  6. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
  7. package/fesm2022/rt-tools-ui-kit-v2-tabs.mjs +23 -2
  8. package/fesm2022/rt-tools-ui-kit-v2-tabs.mjs.map +1 -1
  9. package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs +31 -6
  10. package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs.map +1 -1
  11. package/fesm2022/rt-tools-ui-kit-v2-toggle-button-group.mjs +2 -2
  12. package/fesm2022/rt-tools-ui-kit-v2-toggle-button-group.mjs.map +1 -1
  13. package/fesm2022/rt-tools-ui-kit-v2-workspace-details.mjs +29 -4
  14. package/fesm2022/rt-tools-ui-kit-v2-workspace-details.mjs.map +1 -1
  15. package/fesm2022/rt-tools-ui-kit-v2-workspace.mjs +23 -2
  16. package/fesm2022/rt-tools-ui-kit-v2-workspace.mjs.map +1 -1
  17. package/package.json +1 -1
  18. package/src/lib/components/ai-prompt-input/rt-ai-prompt-input.component.scss +2 -1
  19. package/src/lib/components/detail-list/rt-detail-row.component.scss +2 -0
  20. package/src/lib/components/tabs/rt-tabs.component.scss +19 -2
  21. package/src/lib/components/thread-list/rt-thread-list-messenger.scss +45 -0
  22. package/src/lib/components/toggle-button-group/rt-toggle-button-group.component.scss +9 -0
  23. package/src/lib/components/workspace/rt-workspace.component.scss +40 -0
  24. package/src/lib/components/workspace-details/rt-workspace-details.component.scss +26 -1
  25. package/src/rich-editor/lib/components/chat/rt-chat-messenger.scss +146 -0
  26. package/src/rich-editor/lib/components/message-composer/rt-message-composer.component.scss +7 -2
  27. package/types/rt-tools-ui-kit-v2-ai-prompt-input.d.ts +14 -1
  28. package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +40 -21
  29. package/types/rt-tools-ui-kit-v2-tabs.d.ts +7 -0
  30. package/types/rt-tools-ui-kit-v2-thread-list.d.ts +7 -0
  31. package/types/rt-tools-ui-kit-v2-workspace-details.d.ts +14 -0
  32. package/types/rt-tools-ui-kit-v2-workspace.d.ts +7 -0
@@ -270,7 +270,7 @@ var RtAiPromptInputComponent = class RtAiPromptInputComponent {
270
270
  isSignal: true
271
271
  }],
272
272
  ngImport: i0,
273
- template: "<ng-container rtBlock=\"rt-ai-prompt-input\">\n @if (hintAbove()) {\n <p rtElem=\"hint\" qa-dataid=\"ai-prompt-input-hint\" [rtMod]=\"{ above: true }\">{{ hintText() }}</p>\n }\n\n <div rtElem=\"box\" qa-dataid=\"ai-prompt-input-box\" [rtMod]=\"boxMods()\">\n @if (attachments() && files().length) {\n <div rtElem=\"files\" qa-dataid=\"ai-prompt-input-files\">\n @for (file of files(); track $index) {\n <rt-file-card\n showRemove\n qa-dataid=\"ai-prompt-input-file\"\n size=\"sm\"\n [name]=\"file.name\"\n [sizeBytes]=\"file.size\"\n [disabled]=\"locked()\"\n (removed)=\"removeFile($index)\" />\n }\n </div>\n }\n\n <textarea\n #textEl\n rtElem=\"input\"\n qa-dataid=\"ai-prompt-input-field\"\n cdkTextareaAutosize\n [attr.aria-label]=\"t().chatComposerAria\"\n [placeholder]=\"placeholderText()\"\n [value]=\"text()\"\n [disabled]=\"locked()\"\n [cdkAutosizeMinRows]=\"minRows()\"\n [cdkAutosizeMaxRows]=\"maxRows()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"></textarea>\n\n <div rtElem=\"actions\">\n @if (attachments()) {\n <input\n #fileEl\n qa-dataid=\"ai-prompt-input-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=\"ai-prompt-input-attach\"\n icon=\"ico-plus\"\n iconColor=\"muted\"\n size=\"sm\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatAttachAria\"\n [tooltip]=\"t().chatAttachTooltip\"\n [disabled]=\"locked()\"\n (clicked)=\"openPicker()\" />\n }\n\n <div rtElem=\"controls\">\n @if (model()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-model\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [label]=\"model()\"\n [attr.aria-label]=\"t().aiPromptModelAria + ': ' + model()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('model')\"></button>\n }\n\n @if (effort()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-effort\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [rtMod]=\"{ muted: true }\"\n [label]=\"effort()\"\n [attr.aria-label]=\"t().aiPromptEffortAria + ': ' + effort()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('effort')\"></button>\n }\n\n @if (mode()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-mode\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [rtMod]=\"{ muted: true }\"\n [label]=\"mode()\"\n [attr.aria-label]=\"t().aiPromptModeAria + ': ' + mode()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('mode')\"></button>\n }\n\n @if (hasUsage()) {\n <rt-usage-ring qa-dataid=\"ai-prompt-input-usage\" [value]=\"usage() ?? 0\" [warnAt]=\"usageWarnAt()\" [hint]=\"usageHint()\" />\n }\n\n @if (isStoppable()) {\n <rt-icon-button\n qa-dataid=\"ai-prompt-input-stop\"\n icon=\"stop\"\n size=\"sm\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatStopAria\"\n [tooltip]=\"t().chatStopLabel\"\n (clicked)=\"stop()\" />\n } @else {\n <rt-icon-button\n qa-dataid=\"ai-prompt-input-send\"\n icon=\"arrow-up\"\n size=\"sm\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatSendAria\"\n [tooltip]=\"t().chatSendLabel\"\n [loading]=\"sending()\"\n [disabled]=\"!canSend()\"\n (clicked)=\"submit()\" />\n }\n </div>\n </div>\n </div>\n\n @if (hintBelow()) {\n <p rtElem=\"hint\" qa-dataid=\"ai-prompt-input-hint\">{{ hintText() }}</p>\n }\n</ng-container>\n",
273
+ template: "<ng-container rtBlock=\"rt-ai-prompt-input\">\n @if (hintAbove()) {\n <p rtElem=\"hint\" qa-dataid=\"ai-prompt-input-hint\" [rtMod]=\"{ above: true }\">{{ hintText() }}</p>\n }\n\n <div rtElem=\"box\" qa-dataid=\"ai-prompt-input-box\" [rtMod]=\"boxMods()\">\n @if (attachments() && files().length) {\n <div rtElem=\"files\" qa-dataid=\"ai-prompt-input-files\">\n @for (file of files(); track $index) {\n <rt-file-card\n showRemove\n qa-dataid=\"ai-prompt-input-file\"\n size=\"sm\"\n [name]=\"file.name\"\n [sizeBytes]=\"file.size\"\n [disabled]=\"locked()\"\n (removed)=\"removeFile($index)\" />\n }\n </div>\n }\n\n <textarea\n #textEl\n rtElem=\"input\"\n qa-dataid=\"ai-prompt-input-field\"\n cdkTextareaAutosize\n [attr.aria-label]=\"t().chatComposerAria\"\n [placeholder]=\"placeholderText()\"\n [value]=\"text()\"\n [disabled]=\"locked()\"\n [cdkAutosizeMinRows]=\"minRows()\"\n [cdkAutosizeMaxRows]=\"maxRows()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"></textarea>\n\n <div rtElem=\"actions\">\n @if (attachments()) {\n <input\n #fileEl\n qa-dataid=\"ai-prompt-input-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=\"ai-prompt-input-attach\"\n icon=\"ico-plus\"\n iconColor=\"muted\"\n size=\"sm\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatAttachAria\"\n [tooltip]=\"t().chatAttachTooltip\"\n [disabled]=\"locked()\"\n (clicked)=\"openPicker()\" />\n }\n\n <ng-content select=\"[rtPromptInputStart]\" />\n\n <div rtElem=\"controls\">\n <ng-content select=\"[rtPromptInputEnd]\" />\n\n @if (model()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-model\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [label]=\"model()\"\n [attr.aria-label]=\"t().aiPromptModelAria + ': ' + model()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('model')\"></button>\n }\n\n @if (effort()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-effort\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [rtMod]=\"{ muted: true }\"\n [label]=\"effort()\"\n [attr.aria-label]=\"t().aiPromptEffortAria + ': ' + effort()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('effort')\"></button>\n }\n\n @if (mode()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-mode\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [rtMod]=\"{ muted: true }\"\n [label]=\"mode()\"\n [attr.aria-label]=\"t().aiPromptModeAria + ': ' + mode()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('mode')\"></button>\n }\n\n @if (hasUsage()) {\n <rt-usage-ring qa-dataid=\"ai-prompt-input-usage\" [value]=\"usage() ?? 0\" [warnAt]=\"usageWarnAt()\" [hint]=\"usageHint()\" />\n }\n\n @if (isStoppable()) {\n <rt-icon-button\n qa-dataid=\"ai-prompt-input-stop\"\n icon=\"stop\"\n size=\"sm\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatStopAria\"\n [tooltip]=\"t().chatStopLabel\"\n (clicked)=\"stop()\" />\n } @else {\n <rt-icon-button\n qa-dataid=\"ai-prompt-input-send\"\n icon=\"arrow-up\"\n size=\"sm\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatSendAria\"\n [tooltip]=\"t().chatSendLabel\"\n [loading]=\"sending()\"\n [disabled]=\"!canSend()\"\n (clicked)=\"submit()\" />\n }\n </div>\n </div>\n </div>\n\n @if (hintBelow()) {\n <p rtElem=\"hint\" qa-dataid=\"ai-prompt-input-hint\">{{ hintText() }}</p>\n }\n</ng-container>\n",
274
274
  styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-ai-prompt-input{--rt-ai-prompt-input-radius: var(--rt-radius-xl);--rt-ai-prompt-input-border-width: var(--rt-border-width-thin);--rt-ai-prompt-input-shadow: var(--rt-shadow-sm);display:flex;flex-direction:column;gap:calc(var(--rt-space-1) * 1.5);inline-size:100%}.rt-ai-prompt-input__box{display:flex;flex-direction:column;border:var(--rt-ai-prompt-input-border-width) solid var(--rt-input-color-border);border-radius:var(--rt-ai-prompt-input-radius);background:var(--rt-color-bg-surface);box-shadow:var(--rt-ai-prompt-input-shadow);padding-block-start:var(--rt-space-1)}.rt-ai-prompt-input__box:focus-within{border-color:var(--rt-input-color-border-focus);box-shadow:var(--rt-input-focus-shadow)}.rt-ai-prompt-input__box--disabled{background:var(--rt-input-color-bg-disabled)}.rt-ai-prompt-input__files{display:flex;flex-direction:column;padding:var(--rt-space-2) var(--rt-space-2) 0;gap:var(--rt-space-1)}.rt-ai-prompt-input__input{box-sizing:content-box;padding:calc(var(--rt-space-1) * 3) calc(var(--rt-space-1) * 3) var(--rt-space-2) var(--rt-space-4);border:0;margin:0;background:transparent;color:var(--rt-input-color-text);font:inherit;font-size:var(--rt-text-base);inline-size:auto;line-height:var(--rt-leading-normal);min-inline-size:0;outline:0;resize:none;scrollbar-color:var(--rt-color-border-default) transparent;scrollbar-gutter:stable;scrollbar-width:thin}.rt-ai-prompt-input__input::placeholder{color:var(--rt-input-color-text-placeholder)}.rt-ai-prompt-input__input:disabled{cursor:not-allowed}.rt-ai-prompt-input__input:disabled::placeholder{color:var(--rt-color-text-disabled)}.rt-ai-prompt-input__actions{display:flex;align-items:center;padding:0 var(--rt-space-2) var(--rt-space-2);gap:var(--rt-space-1)}.rt-ai-prompt-input__controls{display:flex;align-items:center;gap:var(--rt-space-1);margin-inline-start:auto;min-inline-size:0}.rt-ai-prompt-input__control{padding-inline:calc(var(--rt-space-1) * 1.5)}.rt-ai-prompt-input__control.rt-button{--rt-btn-color: var(--rt-color-text-primary)}.rt-ai-prompt-input__control--muted.rt-button{--rt-btn-color: var(--rt-color-text-muted)}.rt-ai-prompt-input__hint{margin:0;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug);text-align:center}}\n"],
275
275
  dependencies: [
276
276
  {
@@ -403,7 +403,7 @@ i0.ɵɵngDeclareClassMetadata({
403
403
  RtUsageRingComponent
404
404
  ],
405
405
  host: { class: BEM_BLOCK },
406
- template: "<ng-container rtBlock=\"rt-ai-prompt-input\">\n @if (hintAbove()) {\n <p rtElem=\"hint\" qa-dataid=\"ai-prompt-input-hint\" [rtMod]=\"{ above: true }\">{{ hintText() }}</p>\n }\n\n <div rtElem=\"box\" qa-dataid=\"ai-prompt-input-box\" [rtMod]=\"boxMods()\">\n @if (attachments() && files().length) {\n <div rtElem=\"files\" qa-dataid=\"ai-prompt-input-files\">\n @for (file of files(); track $index) {\n <rt-file-card\n showRemove\n qa-dataid=\"ai-prompt-input-file\"\n size=\"sm\"\n [name]=\"file.name\"\n [sizeBytes]=\"file.size\"\n [disabled]=\"locked()\"\n (removed)=\"removeFile($index)\" />\n }\n </div>\n }\n\n <textarea\n #textEl\n rtElem=\"input\"\n qa-dataid=\"ai-prompt-input-field\"\n cdkTextareaAutosize\n [attr.aria-label]=\"t().chatComposerAria\"\n [placeholder]=\"placeholderText()\"\n [value]=\"text()\"\n [disabled]=\"locked()\"\n [cdkAutosizeMinRows]=\"minRows()\"\n [cdkAutosizeMaxRows]=\"maxRows()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"></textarea>\n\n <div rtElem=\"actions\">\n @if (attachments()) {\n <input\n #fileEl\n qa-dataid=\"ai-prompt-input-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=\"ai-prompt-input-attach\"\n icon=\"ico-plus\"\n iconColor=\"muted\"\n size=\"sm\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatAttachAria\"\n [tooltip]=\"t().chatAttachTooltip\"\n [disabled]=\"locked()\"\n (clicked)=\"openPicker()\" />\n }\n\n <div rtElem=\"controls\">\n @if (model()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-model\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [label]=\"model()\"\n [attr.aria-label]=\"t().aiPromptModelAria + ': ' + model()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('model')\"></button>\n }\n\n @if (effort()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-effort\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [rtMod]=\"{ muted: true }\"\n [label]=\"effort()\"\n [attr.aria-label]=\"t().aiPromptEffortAria + ': ' + effort()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('effort')\"></button>\n }\n\n @if (mode()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-mode\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [rtMod]=\"{ muted: true }\"\n [label]=\"mode()\"\n [attr.aria-label]=\"t().aiPromptModeAria + ': ' + mode()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('mode')\"></button>\n }\n\n @if (hasUsage()) {\n <rt-usage-ring qa-dataid=\"ai-prompt-input-usage\" [value]=\"usage() ?? 0\" [warnAt]=\"usageWarnAt()\" [hint]=\"usageHint()\" />\n }\n\n @if (isStoppable()) {\n <rt-icon-button\n qa-dataid=\"ai-prompt-input-stop\"\n icon=\"stop\"\n size=\"sm\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatStopAria\"\n [tooltip]=\"t().chatStopLabel\"\n (clicked)=\"stop()\" />\n } @else {\n <rt-icon-button\n qa-dataid=\"ai-prompt-input-send\"\n icon=\"arrow-up\"\n size=\"sm\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatSendAria\"\n [tooltip]=\"t().chatSendLabel\"\n [loading]=\"sending()\"\n [disabled]=\"!canSend()\"\n (clicked)=\"submit()\" />\n }\n </div>\n </div>\n </div>\n\n @if (hintBelow()) {\n <p rtElem=\"hint\" qa-dataid=\"ai-prompt-input-hint\">{{ hintText() }}</p>\n }\n</ng-container>\n",
406
+ template: "<ng-container rtBlock=\"rt-ai-prompt-input\">\n @if (hintAbove()) {\n <p rtElem=\"hint\" qa-dataid=\"ai-prompt-input-hint\" [rtMod]=\"{ above: true }\">{{ hintText() }}</p>\n }\n\n <div rtElem=\"box\" qa-dataid=\"ai-prompt-input-box\" [rtMod]=\"boxMods()\">\n @if (attachments() && files().length) {\n <div rtElem=\"files\" qa-dataid=\"ai-prompt-input-files\">\n @for (file of files(); track $index) {\n <rt-file-card\n showRemove\n qa-dataid=\"ai-prompt-input-file\"\n size=\"sm\"\n [name]=\"file.name\"\n [sizeBytes]=\"file.size\"\n [disabled]=\"locked()\"\n (removed)=\"removeFile($index)\" />\n }\n </div>\n }\n\n <textarea\n #textEl\n rtElem=\"input\"\n qa-dataid=\"ai-prompt-input-field\"\n cdkTextareaAutosize\n [attr.aria-label]=\"t().chatComposerAria\"\n [placeholder]=\"placeholderText()\"\n [value]=\"text()\"\n [disabled]=\"locked()\"\n [cdkAutosizeMinRows]=\"minRows()\"\n [cdkAutosizeMaxRows]=\"maxRows()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"></textarea>\n\n <div rtElem=\"actions\">\n @if (attachments()) {\n <input\n #fileEl\n qa-dataid=\"ai-prompt-input-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=\"ai-prompt-input-attach\"\n icon=\"ico-plus\"\n iconColor=\"muted\"\n size=\"sm\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatAttachAria\"\n [tooltip]=\"t().chatAttachTooltip\"\n [disabled]=\"locked()\"\n (clicked)=\"openPicker()\" />\n }\n\n <ng-content select=\"[rtPromptInputStart]\" />\n\n <div rtElem=\"controls\">\n <ng-content select=\"[rtPromptInputEnd]\" />\n\n @if (model()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-model\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [label]=\"model()\"\n [attr.aria-label]=\"t().aiPromptModelAria + ': ' + model()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('model')\"></button>\n }\n\n @if (effort()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-effort\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [rtMod]=\"{ muted: true }\"\n [label]=\"effort()\"\n [attr.aria-label]=\"t().aiPromptEffortAria + ': ' + effort()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('effort')\"></button>\n }\n\n @if (mode()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-mode\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [rtMod]=\"{ muted: true }\"\n [label]=\"mode()\"\n [attr.aria-label]=\"t().aiPromptModeAria + ': ' + mode()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('mode')\"></button>\n }\n\n @if (hasUsage()) {\n <rt-usage-ring qa-dataid=\"ai-prompt-input-usage\" [value]=\"usage() ?? 0\" [warnAt]=\"usageWarnAt()\" [hint]=\"usageHint()\" />\n }\n\n @if (isStoppable()) {\n <rt-icon-button\n qa-dataid=\"ai-prompt-input-stop\"\n icon=\"stop\"\n size=\"sm\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatStopAria\"\n [tooltip]=\"t().chatStopLabel\"\n (clicked)=\"stop()\" />\n } @else {\n <rt-icon-button\n qa-dataid=\"ai-prompt-input-send\"\n icon=\"arrow-up\"\n size=\"sm\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatSendAria\"\n [tooltip]=\"t().chatSendLabel\"\n [loading]=\"sending()\"\n [disabled]=\"!canSend()\"\n (clicked)=\"submit()\" />\n }\n </div>\n </div>\n </div>\n\n @if (hintBelow()) {\n <p rtElem=\"hint\" qa-dataid=\"ai-prompt-input-hint\">{{ hintText() }}</p>\n }\n</ng-container>\n",
407
407
  styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-ai-prompt-input{--rt-ai-prompt-input-radius: var(--rt-radius-xl);--rt-ai-prompt-input-border-width: var(--rt-border-width-thin);--rt-ai-prompt-input-shadow: var(--rt-shadow-sm);display:flex;flex-direction:column;gap:calc(var(--rt-space-1) * 1.5);inline-size:100%}.rt-ai-prompt-input__box{display:flex;flex-direction:column;border:var(--rt-ai-prompt-input-border-width) solid var(--rt-input-color-border);border-radius:var(--rt-ai-prompt-input-radius);background:var(--rt-color-bg-surface);box-shadow:var(--rt-ai-prompt-input-shadow);padding-block-start:var(--rt-space-1)}.rt-ai-prompt-input__box:focus-within{border-color:var(--rt-input-color-border-focus);box-shadow:var(--rt-input-focus-shadow)}.rt-ai-prompt-input__box--disabled{background:var(--rt-input-color-bg-disabled)}.rt-ai-prompt-input__files{display:flex;flex-direction:column;padding:var(--rt-space-2) var(--rt-space-2) 0;gap:var(--rt-space-1)}.rt-ai-prompt-input__input{box-sizing:content-box;padding:calc(var(--rt-space-1) * 3) calc(var(--rt-space-1) * 3) var(--rt-space-2) var(--rt-space-4);border:0;margin:0;background:transparent;color:var(--rt-input-color-text);font:inherit;font-size:var(--rt-text-base);inline-size:auto;line-height:var(--rt-leading-normal);min-inline-size:0;outline:0;resize:none;scrollbar-color:var(--rt-color-border-default) transparent;scrollbar-gutter:stable;scrollbar-width:thin}.rt-ai-prompt-input__input::placeholder{color:var(--rt-input-color-text-placeholder)}.rt-ai-prompt-input__input:disabled{cursor:not-allowed}.rt-ai-prompt-input__input:disabled::placeholder{color:var(--rt-color-text-disabled)}.rt-ai-prompt-input__actions{display:flex;align-items:center;padding:0 var(--rt-space-2) var(--rt-space-2);gap:var(--rt-space-1)}.rt-ai-prompt-input__controls{display:flex;align-items:center;gap:var(--rt-space-1);margin-inline-start:auto;min-inline-size:0}.rt-ai-prompt-input__control{padding-inline:calc(var(--rt-space-1) * 1.5)}.rt-ai-prompt-input__control.rt-button{--rt-btn-color: var(--rt-color-text-primary)}.rt-ai-prompt-input__control--muted.rt-button{--rt-btn-color: var(--rt-color-text-muted)}.rt-ai-prompt-input__hint{margin:0;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug);text-align:center}}\n"]
408
408
  }]
409
409
  }],
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-ai-prompt-input.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/ai-prompt-input/rt-ai-prompt-input.component.ts","../../../projects/ui-kit-v2/src/lib/components/ai-prompt-input/rt-ai-prompt-input.component.html"],"sourcesContent":["import { BooleanInput, NumberInput } from '@angular/cdk/coercion';\nimport { CdkTextareaAutosize } from '@angular/cdk/text-field';\nimport {\n booleanAttribute,\n computed,\n inject,\n input,\n model,\n numberAttribute,\n output,\n signal,\n viewChild,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n InputSignal,\n InputSignalWithTransform,\n ModelSignal,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RtButtonDirective } from '@rt-tools/ui-kit-v2/button';\nimport { RT_KIT_LABELS, TRtKitLabelMap, rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RtFileCardComponent } from '@rt-tools/ui-kit-v2/file-card';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtUsageRingComponent } from '@rt-tools/ui-kit-v2/usage-ring';\n\nimport { IRtAiPromptInput } from './rt-ai-prompt-input.model';\n\nconst BEM_BLOCK: string = 'rt-ai-prompt-input';\n\n/** Можно ли отправить: есть непустой текст или файл, поле свободно. */\nexport function rtPromptCanSend(text: string, files: number, busy: boolean): boolean {\n return !busy && (text.trim().length > 0 || files > 0);\n}\n\n/**\n * Поле ввода ИИ-чата: одна рамка, текст сверху, ряд действий внутри рамки снизу.\n *\n * Слева в ряду «+» для файлов, справа модель, усилие, режим, кольцо расхода и отправка. Каждый\n * элемент ряда включается своим входом: без значения его нет. Что открывает нажатие на модель,\n * усилие и режим, решает приложение: поле сообщает, какую кнопку нажали.\n *\n * Подсказка стоит отдельной строкой под полем или над ним, в ряд действий она не входит.\n *\n * Отправка — `Enter` без Shift или кнопка со стрелкой; `Shift+Enter` переносит строку. Со\n * `stoppable` во время `sending` стрелку сменяет «Стоп», а поле остаётся открытым.\n */\n@Component({\n selector: 'rt-ai-prompt-input',\n templateUrl: './rt-ai-prompt-input.component.html',\n styleUrl: './rt-ai-prompt-input.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // cdk\n CdkTextareaAutosize,\n\n // standalone components / directives\n BlockDirective,\n ElemDirective,\n ModDirective,\n RtButtonDirective,\n RtFileCardComponent,\n RtIconButtonComponent,\n RtUsageRingComponent,\n ],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtAiPromptInputComponent {\n readonly #t_placeholder: Signal<string> = rtKitLabel('chatPlaceholder');\n\n readonly #t_disclaimer: Signal<string> = rtKitLabel('aiDisclaimer');\n\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\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 files: WritableSignal<File[]> = signal<File[]>([]);\n\n protected readonly placeholderText: Signal<string> = computed((): string => this.placeholder() || this.#t_placeholder());\n\n /** Текст подсказки: `null` — английское умолчание кита, пустая строка — подсказки нет. */\n protected readonly hintText: Signal<string> = computed((): string => this.hint() ?? this.#t_disclaimer());\n\n protected readonly hintAbove: Signal<boolean> = computed((): boolean => this.hintText() !== '' && this.hintPosition() === 'above');\n\n protected readonly hintBelow: Signal<boolean> = computed((): boolean => this.hintText() !== '' && this.hintPosition() === 'below');\n\n /** Поле закрыто для набора: выключено или идёт ответ, который нельзя остановить. */\n protected readonly locked: Signal<boolean> = computed((): boolean => this.disabled() || (this.sending() && !this.stoppable()));\n\n protected readonly canSend: Signal<boolean> = computed((): boolean =>\n rtPromptCanSend(this.text(), this.attachments() ? this.files().length : 0, this.sending() || this.disabled())\n );\n\n /** Идёт ответ, который можно остановить: вместо стрелки стоит «Стоп». */\n protected readonly isStoppable: Signal<boolean> = computed((): boolean => this.stoppable() && this.sending() && !this.disabled());\n\n protected readonly hasUsage: Signal<boolean> = computed((): boolean => this.usage() !== null);\n\n protected readonly boxMods: Signal<Record<string, boolean>> = computed((): Record<string, boolean> => ({\n disabled: this.disabled(),\n }));\n\n /** Текст-подсказка поля. Пусто — переведённое умолчание кита. */\n public readonly placeholder: InputSignal<string> = input<string>('');\n\n /** Подсказка отдельной строкой. `null` — английское умолчание кита, пустая строка убирает её. */\n public readonly hint: InputSignal<string | null> = input<string | null>(null);\n\n /** Где стоит подсказка: под полем, а где места под ним нет — над полем. */\n public readonly hintPosition: InputSignal<IRtAiPromptInput.HintPosition> = input<IRtAiPromptInput.HintPosition>('below');\n\n /** Кнопка «+» и карточки приложенных файлов. */\n public readonly attachments: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Фильтр типов файлов (`.pdf,.png`). */\n public readonly accept: InputSignal<string> = input<string>('');\n\n /** Подпись модели. Пусто — кнопки модели нет. */\n public readonly model: InputSignal<string> = input<string>('');\n\n /** Подпись усилия. Пусто — кнопки усилия нет. */\n public readonly effort: InputSignal<string> = input<string>('');\n\n /** Подпись режима. Пусто — кнопки режима нет. */\n public readonly mode: InputSignal<string> = input<string>('');\n\n /** Потраченная доля лимита в процентах. `null` — кольца нет. */\n public readonly usage: InputSignal<number | null> = input<number | null>(null);\n\n /** Подсказка кольца по наведению: доля и дата сброса словами приложения. */\n public readonly usageHint: InputSignal<string> = input<string>('');\n\n /** С этой доли кольцо оранжевое. */\n public readonly usageWarnAt: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(80, {\n transform: numberAttribute,\n });\n\n /** Отправка идёт: кнопка крутит индикатор, без `stoppable` поле закрыто. */\n public readonly sending: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Ответ можно остановить: во время `sending` стрелку сменяет «Стоп», поле открыто. */\n public readonly stoppable: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Наименьшая высота поля в строках. */\n public readonly minRows: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(1, { transform: numberAttribute });\n\n /** Наибольшая высота поля в строках, дальше текст прокручивается. */\n public readonly maxRows: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(8, { transform: numberAttribute });\n\n /** Черновик: задаётся снаружи, правки уходят наружу, после отправки пуст. */\n public readonly text: ModelSignal<string> = model<string>('');\n\n /** Отправка вопроса. */\n public readonly submitted: OutputEmitterRef<IRtAiPromptInput.SubmitPayload> = output<IRtAiPromptInput.SubmitPayload>();\n\n /** Нажата «Стоп» во время ответа. */\n public readonly stopped: OutputEmitterRef<void> = output<void>();\n\n /** Нажата кнопка модели, усилия или режима. */\n public readonly controlPicked: OutputEmitterRef<IRtAiPromptInput.Control> = output<IRtAiPromptInput.Control>();\n\n /** Ставит фокус в поле. */\n public focus(): void {\n this.textInput()?.nativeElement.focus();\n }\n\n protected onInput(event: Event): void {\n this.text.set((event.target as HTMLTextAreaElement).value);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n // Enter без Shift отправляет; подтверждение набора IME не перехватывается.\n if (event.key === 'Enter' && !event.shiftKey && !event.isComposing) {\n event.preventDefault();\n this.submit();\n }\n }\n\n protected pick(control: IRtAiPromptInput.Control): void {\n this.controlPicked.emit(control);\n }\n\n protected stop(): void {\n if (this.isStoppable()) {\n this.stopped.emit();\n }\n }\n\n protected openPicker(): void {\n if (!this.locked()) {\n this.fileInput()?.nativeElement.click();\n }\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 > 0) {\n this.files.update((current: File[]): File[] => [...current, ...picked]);\n }\n // Сброс значения: повторный выбор того же файла снова даёт событие.\n el.value = '';\n }\n\n protected removeFile(index: number): void {\n this.files.update((current: File[]): File[] => current.filter((_: File, i: number): boolean => i !== index));\n }\n\n protected submit(): void {\n if (!this.canSend()) {\n return;\n }\n this.submitted.emit({ text: this.text().trim(), files: this.attachments() ? this.files() : [] });\n this.text.set('');\n this.files.set([]);\n }\n}\n","<ng-container rtBlock=\"rt-ai-prompt-input\">\n @if (hintAbove()) {\n <p rtElem=\"hint\" qa-dataid=\"ai-prompt-input-hint\" [rtMod]=\"{ above: true }\">{{ hintText() }}</p>\n }\n\n <div rtElem=\"box\" qa-dataid=\"ai-prompt-input-box\" [rtMod]=\"boxMods()\">\n @if (attachments() && files().length) {\n <div rtElem=\"files\" qa-dataid=\"ai-prompt-input-files\">\n @for (file of files(); track $index) {\n <rt-file-card\n showRemove\n qa-dataid=\"ai-prompt-input-file\"\n size=\"sm\"\n [name]=\"file.name\"\n [sizeBytes]=\"file.size\"\n [disabled]=\"locked()\"\n (removed)=\"removeFile($index)\" />\n }\n </div>\n }\n\n <textarea\n #textEl\n rtElem=\"input\"\n qa-dataid=\"ai-prompt-input-field\"\n cdkTextareaAutosize\n [attr.aria-label]=\"t().chatComposerAria\"\n [placeholder]=\"placeholderText()\"\n [value]=\"text()\"\n [disabled]=\"locked()\"\n [cdkAutosizeMinRows]=\"minRows()\"\n [cdkAutosizeMaxRows]=\"maxRows()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"></textarea>\n\n <div rtElem=\"actions\">\n @if (attachments()) {\n <input\n #fileEl\n qa-dataid=\"ai-prompt-input-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=\"ai-prompt-input-attach\"\n icon=\"ico-plus\"\n iconColor=\"muted\"\n size=\"sm\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatAttachAria\"\n [tooltip]=\"t().chatAttachTooltip\"\n [disabled]=\"locked()\"\n (clicked)=\"openPicker()\" />\n }\n\n <div rtElem=\"controls\">\n @if (model()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-model\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [label]=\"model()\"\n [attr.aria-label]=\"t().aiPromptModelAria + ': ' + model()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('model')\"></button>\n }\n\n @if (effort()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-effort\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [rtMod]=\"{ muted: true }\"\n [label]=\"effort()\"\n [attr.aria-label]=\"t().aiPromptEffortAria + ': ' + effort()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('effort')\"></button>\n }\n\n @if (mode()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-mode\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [rtMod]=\"{ muted: true }\"\n [label]=\"mode()\"\n [attr.aria-label]=\"t().aiPromptModeAria + ': ' + mode()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('mode')\"></button>\n }\n\n @if (hasUsage()) {\n <rt-usage-ring qa-dataid=\"ai-prompt-input-usage\" [value]=\"usage() ?? 0\" [warnAt]=\"usageWarnAt()\" [hint]=\"usageHint()\" />\n }\n\n @if (isStoppable()) {\n <rt-icon-button\n qa-dataid=\"ai-prompt-input-stop\"\n icon=\"stop\"\n size=\"sm\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatStopAria\"\n [tooltip]=\"t().chatStopLabel\"\n (clicked)=\"stop()\" />\n } @else {\n <rt-icon-button\n qa-dataid=\"ai-prompt-input-send\"\n icon=\"arrow-up\"\n size=\"sm\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatSendAria\"\n [tooltip]=\"t().chatSendLabel\"\n [loading]=\"sending()\"\n [disabled]=\"!canSend()\"\n (clicked)=\"submit()\" />\n }\n </div>\n </div>\n </div>\n\n @if (hintBelow()) {\n <p rtElem=\"hint\" qa-dataid=\"ai-prompt-input-hint\">{{ hintText() }}</p>\n }\n</ng-container>\n"],"mappings":"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"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-ai-prompt-input.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/ai-prompt-input/rt-ai-prompt-input.component.ts","../../../projects/ui-kit-v2/src/lib/components/ai-prompt-input/rt-ai-prompt-input.component.html"],"sourcesContent":["import { BooleanInput, NumberInput } from '@angular/cdk/coercion';\nimport { CdkTextareaAutosize } from '@angular/cdk/text-field';\nimport {\n booleanAttribute,\n computed,\n inject,\n input,\n model,\n numberAttribute,\n output,\n signal,\n viewChild,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n InputSignal,\n InputSignalWithTransform,\n ModelSignal,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RtButtonDirective } from '@rt-tools/ui-kit-v2/button';\nimport { RT_KIT_LABELS, TRtKitLabelMap, rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RtFileCardComponent } from '@rt-tools/ui-kit-v2/file-card';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtUsageRingComponent } from '@rt-tools/ui-kit-v2/usage-ring';\n\nimport { IRtAiPromptInput } from './rt-ai-prompt-input.model';\n\nconst BEM_BLOCK: string = 'rt-ai-prompt-input';\n\n/** Можно ли отправить: есть непустой текст или файл, поле свободно. */\nexport function rtPromptCanSend(text: string, files: number, busy: boolean): boolean {\n return !busy && (text.trim().length > 0 || files > 0);\n}\n\n/**\n * Поле ввода ИИ-чата: одна рамка, текст сверху, ряд действий внутри рамки снизу.\n *\n * Слева в ряду «+» для файлов, справа модель, усилие, режим, кольцо расхода и отправка. Каждый\n * элемент ряда включается своим входом: без значения его нет. Что открывает нажатие на модель,\n * усилие и режим, решает приложение: поле сообщает, какую кнопку нажали.\n *\n * Свои элементы ряда приложение кладёт проекцией: с меткой `rtPromptInputStart` они встают слева\n * после «+», с меткой `rtPromptInputEnd` справа перед моделью и отправкой. Подходит любой\n * элемент высотой с кнопку sm: кнопка-иконка, кнопка с текстом, выпадающий список.\n *\n * @example\n * ```html\n * <rt-ai-prompt-input attachments>\n * <rt-icon-button rtPromptInputStart icon=\"bolt\" variant=\"ghost\" size=\"sm\" ariaLabel=\"Быстрые ответы\" />\n * <button rtButton rtPromptInputStart appearance=\"text\" size=\"sm\" label=\"Отправить позже\"></button>\n * <rt-icon-button rtPromptInputEnd icon=\"mic\" variant=\"ghost\" size=\"sm\" ariaLabel=\"Голос\" />\n * </rt-ai-prompt-input>\n * ```\n *\n * Подсказка стоит отдельной строкой под полем или над ним, в ряд действий она не входит.\n *\n * Отправка — `Enter` без Shift или кнопка со стрелкой; `Shift+Enter` переносит строку. Со\n * `stoppable` во время `sending` стрелку сменяет «Стоп», а поле остаётся открытым.\n */\n@Component({\n selector: 'rt-ai-prompt-input',\n templateUrl: './rt-ai-prompt-input.component.html',\n styleUrl: './rt-ai-prompt-input.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // cdk\n CdkTextareaAutosize,\n\n // standalone components / directives\n BlockDirective,\n ElemDirective,\n ModDirective,\n RtButtonDirective,\n RtFileCardComponent,\n RtIconButtonComponent,\n RtUsageRingComponent,\n ],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtAiPromptInputComponent {\n readonly #t_placeholder: Signal<string> = rtKitLabel('chatPlaceholder');\n\n readonly #t_disclaimer: Signal<string> = rtKitLabel('aiDisclaimer');\n\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\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 files: WritableSignal<File[]> = signal<File[]>([]);\n\n protected readonly placeholderText: Signal<string> = computed((): string => this.placeholder() || this.#t_placeholder());\n\n /** Текст подсказки: `null` — английское умолчание кита, пустая строка — подсказки нет. */\n protected readonly hintText: Signal<string> = computed((): string => this.hint() ?? this.#t_disclaimer());\n\n protected readonly hintAbove: Signal<boolean> = computed((): boolean => this.hintText() !== '' && this.hintPosition() === 'above');\n\n protected readonly hintBelow: Signal<boolean> = computed((): boolean => this.hintText() !== '' && this.hintPosition() === 'below');\n\n /** Поле закрыто для набора: выключено или идёт ответ, который нельзя остановить. */\n protected readonly locked: Signal<boolean> = computed((): boolean => this.disabled() || (this.sending() && !this.stoppable()));\n\n protected readonly canSend: Signal<boolean> = computed((): boolean =>\n rtPromptCanSend(this.text(), this.attachments() ? this.files().length : 0, this.sending() || this.disabled())\n );\n\n /** Идёт ответ, который можно остановить: вместо стрелки стоит «Стоп». */\n protected readonly isStoppable: Signal<boolean> = computed((): boolean => this.stoppable() && this.sending() && !this.disabled());\n\n protected readonly hasUsage: Signal<boolean> = computed((): boolean => this.usage() !== null);\n\n protected readonly boxMods: Signal<Record<string, boolean>> = computed((): Record<string, boolean> => ({\n disabled: this.disabled(),\n }));\n\n /** Текст-подсказка поля. Пусто — переведённое умолчание кита. */\n public readonly placeholder: InputSignal<string> = input<string>('');\n\n /** Подсказка отдельной строкой. `null` — английское умолчание кита, пустая строка убирает её. */\n public readonly hint: InputSignal<string | null> = input<string | null>(null);\n\n /** Где стоит подсказка: под полем, а где места под ним нет — над полем. */\n public readonly hintPosition: InputSignal<IRtAiPromptInput.HintPosition> = input<IRtAiPromptInput.HintPosition>('below');\n\n /** Кнопка «+» и карточки приложенных файлов. */\n public readonly attachments: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Фильтр типов файлов (`.pdf,.png`). */\n public readonly accept: InputSignal<string> = input<string>('');\n\n /** Подпись модели. Пусто — кнопки модели нет. */\n public readonly model: InputSignal<string> = input<string>('');\n\n /** Подпись усилия. Пусто — кнопки усилия нет. */\n public readonly effort: InputSignal<string> = input<string>('');\n\n /** Подпись режима. Пусто — кнопки режима нет. */\n public readonly mode: InputSignal<string> = input<string>('');\n\n /** Потраченная доля лимита в процентах. `null` — кольца нет. */\n public readonly usage: InputSignal<number | null> = input<number | null>(null);\n\n /** Подсказка кольца по наведению: доля и дата сброса словами приложения. */\n public readonly usageHint: InputSignal<string> = input<string>('');\n\n /** С этой доли кольцо оранжевое. */\n public readonly usageWarnAt: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(80, {\n transform: numberAttribute,\n });\n\n /** Отправка идёт: кнопка крутит индикатор, без `stoppable` поле закрыто. */\n public readonly sending: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Ответ можно остановить: во время `sending` стрелку сменяет «Стоп», поле открыто. */\n public readonly stoppable: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Наименьшая высота поля в строках. */\n public readonly minRows: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(1, { transform: numberAttribute });\n\n /** Наибольшая высота поля в строках, дальше текст прокручивается. */\n public readonly maxRows: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(8, { transform: numberAttribute });\n\n /** Черновик: задаётся снаружи, правки уходят наружу, после отправки пуст. */\n public readonly text: ModelSignal<string> = model<string>('');\n\n /** Отправка вопроса. */\n public readonly submitted: OutputEmitterRef<IRtAiPromptInput.SubmitPayload> = output<IRtAiPromptInput.SubmitPayload>();\n\n /** Нажата «Стоп» во время ответа. */\n public readonly stopped: OutputEmitterRef<void> = output<void>();\n\n /** Нажата кнопка модели, усилия или режима. */\n public readonly controlPicked: OutputEmitterRef<IRtAiPromptInput.Control> = output<IRtAiPromptInput.Control>();\n\n /** Ставит фокус в поле. */\n public focus(): void {\n this.textInput()?.nativeElement.focus();\n }\n\n protected onInput(event: Event): void {\n this.text.set((event.target as HTMLTextAreaElement).value);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n // Enter без Shift отправляет; подтверждение набора IME не перехватывается.\n if (event.key === 'Enter' && !event.shiftKey && !event.isComposing) {\n event.preventDefault();\n this.submit();\n }\n }\n\n protected pick(control: IRtAiPromptInput.Control): void {\n this.controlPicked.emit(control);\n }\n\n protected stop(): void {\n if (this.isStoppable()) {\n this.stopped.emit();\n }\n }\n\n protected openPicker(): void {\n if (!this.locked()) {\n this.fileInput()?.nativeElement.click();\n }\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 > 0) {\n this.files.update((current: File[]): File[] => [...current, ...picked]);\n }\n // Сброс значения: повторный выбор того же файла снова даёт событие.\n el.value = '';\n }\n\n protected removeFile(index: number): void {\n this.files.update((current: File[]): File[] => current.filter((_: File, i: number): boolean => i !== index));\n }\n\n protected submit(): void {\n if (!this.canSend()) {\n return;\n }\n this.submitted.emit({ text: this.text().trim(), files: this.attachments() ? this.files() : [] });\n this.text.set('');\n this.files.set([]);\n }\n}\n","<ng-container rtBlock=\"rt-ai-prompt-input\">\n @if (hintAbove()) {\n <p rtElem=\"hint\" qa-dataid=\"ai-prompt-input-hint\" [rtMod]=\"{ above: true }\">{{ hintText() }}</p>\n }\n\n <div rtElem=\"box\" qa-dataid=\"ai-prompt-input-box\" [rtMod]=\"boxMods()\">\n @if (attachments() && files().length) {\n <div rtElem=\"files\" qa-dataid=\"ai-prompt-input-files\">\n @for (file of files(); track $index) {\n <rt-file-card\n showRemove\n qa-dataid=\"ai-prompt-input-file\"\n size=\"sm\"\n [name]=\"file.name\"\n [sizeBytes]=\"file.size\"\n [disabled]=\"locked()\"\n (removed)=\"removeFile($index)\" />\n }\n </div>\n }\n\n <textarea\n #textEl\n rtElem=\"input\"\n qa-dataid=\"ai-prompt-input-field\"\n cdkTextareaAutosize\n [attr.aria-label]=\"t().chatComposerAria\"\n [placeholder]=\"placeholderText()\"\n [value]=\"text()\"\n [disabled]=\"locked()\"\n [cdkAutosizeMinRows]=\"minRows()\"\n [cdkAutosizeMaxRows]=\"maxRows()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"></textarea>\n\n <div rtElem=\"actions\">\n @if (attachments()) {\n <input\n #fileEl\n qa-dataid=\"ai-prompt-input-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=\"ai-prompt-input-attach\"\n icon=\"ico-plus\"\n iconColor=\"muted\"\n size=\"sm\"\n variant=\"ghost\"\n [ariaLabel]=\"t().chatAttachAria\"\n [tooltip]=\"t().chatAttachTooltip\"\n [disabled]=\"locked()\"\n (clicked)=\"openPicker()\" />\n }\n\n <ng-content select=\"[rtPromptInputStart]\" />\n\n <div rtElem=\"controls\">\n <ng-content select=\"[rtPromptInputEnd]\" />\n\n @if (model()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-model\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [label]=\"model()\"\n [attr.aria-label]=\"t().aiPromptModelAria + ': ' + model()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('model')\"></button>\n }\n\n @if (effort()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-effort\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [rtMod]=\"{ muted: true }\"\n [label]=\"effort()\"\n [attr.aria-label]=\"t().aiPromptEffortAria + ': ' + effort()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('effort')\"></button>\n }\n\n @if (mode()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"ai-prompt-input-mode\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n size=\"sm\"\n [rtMod]=\"{ muted: true }\"\n [label]=\"mode()\"\n [attr.aria-label]=\"t().aiPromptModeAria + ': ' + mode()\"\n [disabled]=\"disabled()\"\n (click)=\"pick('mode')\"></button>\n }\n\n @if (hasUsage()) {\n <rt-usage-ring qa-dataid=\"ai-prompt-input-usage\" [value]=\"usage() ?? 0\" [warnAt]=\"usageWarnAt()\" [hint]=\"usageHint()\" />\n }\n\n @if (isStoppable()) {\n <rt-icon-button\n qa-dataid=\"ai-prompt-input-stop\"\n icon=\"stop\"\n size=\"sm\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatStopAria\"\n [tooltip]=\"t().chatStopLabel\"\n (clicked)=\"stop()\" />\n } @else {\n <rt-icon-button\n qa-dataid=\"ai-prompt-input-send\"\n icon=\"arrow-up\"\n size=\"sm\"\n variant=\"primary\"\n [ariaLabel]=\"t().chatSendAria\"\n [tooltip]=\"t().chatSendLabel\"\n [loading]=\"sending()\"\n [disabled]=\"!canSend()\"\n (clicked)=\"submit()\" />\n }\n </div>\n </div>\n </div>\n\n @if (hintBelow()) {\n <p rtElem=\"hint\" qa-dataid=\"ai-prompt-input-hint\">{{ hintText() }}</p>\n }\n</ng-container>\n"],"mappings":"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"}
@@ -99,7 +99,7 @@ var RtDetailRowComponent = class RtDetailRowComponent {
99
99
  host: { classAttribute: "rt-detail-row" },
100
100
  ngImport: i0,
101
101
  template: "<ng-container rtBlock=\"rt-detail-row\">\n <span rtElem=\"label\" qa-dataid=\"detail-row-label\">{{ label() }}</span>\n <div rtElem=\"value\" qa-dataid=\"detail-row-value\">\n <rt-skeleton-wrapper width=\"180px\" height=\"16px\" [isLoading]=\"loading()\">\n <ng-content />\n </rt-skeleton-wrapper>\n </div>\n</ng-container>\n",
102
- styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-detail-row{display:flex;flex-direction:column;gap:var(--rt-field-gap)}.rt-detail-row__label{color:var(--rt-field-label-color);font-size:var(--rt-field-label-font-size);font-weight:var(--rt-field-label-font-weight)}.rt-detail-row__value{color:var(--rt-field-value-color);font-size:var(--rt-field-value-font-size)}}\n"],
102
+ styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-detail-row{display:flex;flex-direction:column;gap:var(--rt-field-gap)}.rt-detail-row__label{color:var(--rt-field-label-color);font-size:var(--rt-field-label-font-size);font-weight:var(--rt-field-label-font-weight);line-height:round(1em * var(--rt-leading-snug),1px)}.rt-detail-row__value{color:var(--rt-field-value-color);font-size:var(--rt-field-value-font-size);line-height:var(--rt-leading-normal)}}\n"],
103
103
  dependencies: [
104
104
  {
105
105
  kind: "component",
@@ -151,7 +151,7 @@ i0.ɵɵngDeclareClassMetadata({
151
151
  ],
152
152
  host: { class: BEM_BLOCK },
153
153
  template: "<ng-container rtBlock=\"rt-detail-row\">\n <span rtElem=\"label\" qa-dataid=\"detail-row-label\">{{ label() }}</span>\n <div rtElem=\"value\" qa-dataid=\"detail-row-value\">\n <rt-skeleton-wrapper width=\"180px\" height=\"16px\" [isLoading]=\"loading()\">\n <ng-content />\n </rt-skeleton-wrapper>\n </div>\n</ng-container>\n",
154
- styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-detail-row{display:flex;flex-direction:column;gap:var(--rt-field-gap)}.rt-detail-row__label{color:var(--rt-field-label-color);font-size:var(--rt-field-label-font-size);font-weight:var(--rt-field-label-font-weight)}.rt-detail-row__value{color:var(--rt-field-value-color);font-size:var(--rt-field-value-font-size)}}\n"]
154
+ styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-detail-row{display:flex;flex-direction:column;gap:var(--rt-field-gap)}.rt-detail-row__label{color:var(--rt-field-label-color);font-size:var(--rt-field-label-font-size);font-weight:var(--rt-field-label-font-weight);line-height:round(1em * var(--rt-leading-snug),1px)}.rt-detail-row__value{color:var(--rt-field-value-color);font-size:var(--rt-field-value-font-size);line-height:var(--rt-leading-normal)}}\n"]
155
155
  }]
156
156
  }],
157
157
  propDecorators: {
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-detail-list.mjs","names":["BEM_BLOCK"],"sources":["../../../projects/ui-kit-v2/src/lib/components/detail-list/rt-detail-list.component.ts","../../../projects/ui-kit-v2/src/lib/components/detail-list/rt-detail-list.component.html","../../../projects/ui-kit-v2/src/lib/components/detail-list/rt-detail-row.component.ts","../../../projects/ui-kit-v2/src/lib/components/detail-list/rt-detail-row.component.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\nimport { BlockDirective } from '@rt-tools/core';\n\nconst BEM_BLOCK: string = 'rt-detail-list';\n\n/**\n * Контейнер для стопки `rt-detail-row` — задаёт единый вертикальный gap между\n * строками «лейбл + значение». Используется в read-only details-панелях асайдов\n * (детали заявки, профиля) вместо самопальных `div`-обёрток.\n *\n * Контент — только `rt-detail-row` через проекцию.\n */\n@Component({\n selector: 'rt-detail-list',\n templateUrl: './rt-detail-list.component.html',\n styleUrl: './rt-detail-list.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n BlockDirective,\n ],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtDetailListComponent {}\n","<ng-container rtBlock=\"rt-detail-list\">\n <ng-content />\n</ng-container>\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n input,\n InputSignal,\n InputSignalWithTransform,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { RtSkeletonWrapperComponent } from '@rt-tools/ui-kit-v2/skeleton-wrapper';\n\nconst BEM_BLOCK: string = 'rt-detail-row';\n\n/**\n * Одна read-only строка «лейбл + значение» в stacked-раскладке: приглушённый\n * лейбл сверху, значение снизу. Единый паттерн info-строки для всех асайдов\n * (раньше — пять разных реализаций).\n *\n * Значение проецируется через `<ng-content>` — допустим текст, дата через pipe\n * или `rt-tag`. При `[loading]=\"true\"` значение замещается скелетоном (потребитель\n * не оборачивает `rt-skeleton-wrapper` вручную).\n */\n@Component({\n selector: 'rt-detail-row',\n templateUrl: './rt-detail-row.component.html',\n styleUrl: './rt-detail-row.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n RtSkeletonWrapperComponent,\n BlockDirective,\n ElemDirective,\n ],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtDetailRowComponent {\n public readonly label: InputSignal<string> = input<string>('');\n\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n}\n","<ng-container rtBlock=\"rt-detail-row\">\n <span rtElem=\"label\" qa-dataid=\"detail-row-label\">{{ label() }}</span>\n <div rtElem=\"value\" qa-dataid=\"detail-row-value\">\n <rt-skeleton-wrapper width=\"180px\" height=\"16px\" [isLoading]=\"loading()\">\n <ng-content />\n </rt-skeleton-wrapper>\n </div>\n</ng-container>\n"],"mappings":";;;;AAIA,MAAMA,cAAoB;AAuB1B,IAAa,wBAAb,MAAa,sBAAqB;CAArB;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAqB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAArB;EAAA,KAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAAqB,cAAA;GAAA,UAAA;GAAA,MAAA,EAAA,gBAAA,iBAAA;GAAA,UAAA;GAAA,UC3BlC;GAGA,QAAA,CAAA,2HAAA;GAAA,cAAA,CAAA;IAAA,MAAA;IAAA,MDkBQ;IAAc,UAAA;IAAA,QAAA,CAAA,OAAA;GAAA,CAAA;GAAA,iBAAA,GAAA,wBAAA;GAAA,eAAA,GAAA,kBAAA;EAAA,CAAA;CAAA;;AAMT,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAqB,YAAA,CAAA;EAdjC,MAAA;EACa,MAAA,CAAA;GAAA,UAAA;GAAgB,iBAGT,wBAAwB;GAAM,eAChC,kBAAkB;GAAI,SAC5B,CAEL,cACH;GAAA,MACK,EACF,OAAOA,YACV;GAAA,UAAA;GAAA,QAAA,CAAA,2HAAA;EAAA,CAAA;;;AEVL,MAAM,YAAoB;AA2B1B,IAAa,uBAAb,MAAa,qBAAoB;CAhBjC,cAAA;EAiBoB,KAAA,QAA6B,MAAc,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;EAE9C,KAAA,UAA2D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,UAAA,+BAAA,CAAA;GACzG,WAAW;EAAgB,CAAA;CAElC;CANY;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAoB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAApB;EAAA,KAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAAoB,cAAA;GAAA,UAAA;GAAA,QAAA;IAAA,OAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,SAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;GAAA;GAAA,MAAA,EAAA,gBAAA,gBAAA;GAAA,UAAA;GAAA,UC1CjC;GAQA,QAAA,CAAA,6WAAA;GAAA,cAAA;IAAA;KAAA,MAAA;KAAA,MD0BQ;KAA0B,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;KAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MAC1B;KAAc,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACd;KAAa,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;GAAA;GAAA,iBAAA,GAAA,wBAAA;GAAA,eAAA,GAAA,kBAAA;EAAA,CAAA;CAAA;;AAMR,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAoB,YAAA,CAAA;EAhBhC,MAAA;EACa,MAAA,CAAA;GAAA,UAAA;GAAe,iBAGR,wBAAwB;GAAM,eAChC,kBAAkB;GAAI,SAC5B;IAEL;IACA;IACA;GACH;GAAA,MACK,EACF,OAAO,UACV;GAAA,UAAA;GAAA,QAAA,CAAA,6WAAA;EAAA,CAAA"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-detail-list.mjs","names":["BEM_BLOCK"],"sources":["../../../projects/ui-kit-v2/src/lib/components/detail-list/rt-detail-list.component.ts","../../../projects/ui-kit-v2/src/lib/components/detail-list/rt-detail-list.component.html","../../../projects/ui-kit-v2/src/lib/components/detail-list/rt-detail-row.component.ts","../../../projects/ui-kit-v2/src/lib/components/detail-list/rt-detail-row.component.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\nimport { BlockDirective } from '@rt-tools/core';\n\nconst BEM_BLOCK: string = 'rt-detail-list';\n\n/**\n * Контейнер для стопки `rt-detail-row` — задаёт единый вертикальный gap между\n * строками «лейбл + значение». Используется в read-only details-панелях асайдов\n * (детали заявки, профиля) вместо самопальных `div`-обёрток.\n *\n * Контент — только `rt-detail-row` через проекцию.\n */\n@Component({\n selector: 'rt-detail-list',\n templateUrl: './rt-detail-list.component.html',\n styleUrl: './rt-detail-list.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n BlockDirective,\n ],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtDetailListComponent {}\n","<ng-container rtBlock=\"rt-detail-list\">\n <ng-content />\n</ng-container>\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n input,\n InputSignal,\n InputSignalWithTransform,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { RtSkeletonWrapperComponent } from '@rt-tools/ui-kit-v2/skeleton-wrapper';\n\nconst BEM_BLOCK: string = 'rt-detail-row';\n\n/**\n * Одна read-only строка «лейбл + значение» в stacked-раскладке: приглушённый\n * лейбл сверху, значение снизу. Единый паттерн info-строки для всех асайдов\n * (раньше — пять разных реализаций).\n *\n * Значение проецируется через `<ng-content>` — допустим текст, дата через pipe\n * или `rt-tag`. При `[loading]=\"true\"` значение замещается скелетоном (потребитель\n * не оборачивает `rt-skeleton-wrapper` вручную).\n */\n@Component({\n selector: 'rt-detail-row',\n templateUrl: './rt-detail-row.component.html',\n styleUrl: './rt-detail-row.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n RtSkeletonWrapperComponent,\n BlockDirective,\n ElemDirective,\n ],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtDetailRowComponent {\n public readonly label: InputSignal<string> = input<string>('');\n\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n}\n","<ng-container rtBlock=\"rt-detail-row\">\n <span rtElem=\"label\" qa-dataid=\"detail-row-label\">{{ label() }}</span>\n <div rtElem=\"value\" qa-dataid=\"detail-row-value\">\n <rt-skeleton-wrapper width=\"180px\" height=\"16px\" [isLoading]=\"loading()\">\n <ng-content />\n </rt-skeleton-wrapper>\n </div>\n</ng-container>\n"],"mappings":";;;;AAIA,MAAMA,cAAoB;AAuB1B,IAAa,wBAAb,MAAa,sBAAqB;CAArB;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAqB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAArB;EAAA,KAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAAqB,cAAA;GAAA,UAAA;GAAA,MAAA,EAAA,gBAAA,iBAAA;GAAA,UAAA;GAAA,UC3BlC;GAGA,QAAA,CAAA,2HAAA;GAAA,cAAA,CAAA;IAAA,MAAA;IAAA,MDkBQ;IAAc,UAAA;IAAA,QAAA,CAAA,OAAA;GAAA,CAAA;GAAA,iBAAA,GAAA,wBAAA;GAAA,eAAA,GAAA,kBAAA;EAAA,CAAA;CAAA;;AAMT,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAqB,YAAA,CAAA;EAdjC,MAAA;EACa,MAAA,CAAA;GAAA,UAAA;GAAgB,iBAGT,wBAAwB;GAAM,eAChC,kBAAkB;GAAI,SAC5B,CAEL,cACH;GAAA,MACK,EACF,OAAOA,YACV;GAAA,UAAA;GAAA,QAAA,CAAA,2HAAA;EAAA,CAAA;;;AEVL,MAAM,YAAoB;AA2B1B,IAAa,uBAAb,MAAa,qBAAoB;CAhBjC,cAAA;EAiBoB,KAAA,QAA6B,MAAc,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;EAE9C,KAAA,UAA2D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,UAAA,+BAAA,CAAA;GACzG,WAAW;EAAgB,CAAA;CAElC;CANY;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAoB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAApB;EAAA,KAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAAoB,cAAA;GAAA,UAAA;GAAA,QAAA;IAAA,OAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,SAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;GAAA;GAAA,MAAA,EAAA,gBAAA,gBAAA;GAAA,UAAA;GAAA,UC1CjC;GAQA,QAAA,CAAA,scAAA;GAAA,cAAA;IAAA;KAAA,MAAA;KAAA,MD0BQ;KAA0B,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;KAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MAC1B;KAAc,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACd;KAAa,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;GAAA;GAAA,iBAAA,GAAA,wBAAA;GAAA,eAAA,GAAA,kBAAA;EAAA,CAAA;CAAA;;AAMR,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAoB,YAAA,CAAA;EAhBhC,MAAA;EACa,MAAA,CAAA;GAAA,UAAA;GAAe,iBAGR,wBAAwB;GAAM,eAChC,kBAAkB;GAAI,SAC5B;IAEL;IACA;IACA;GACH;GAAA,MACK,EACF,OAAO,UACV;GAAA,UAAA;GAAA,QAAA,CAAA,scAAA;EAAA,CAAA"}