@rt-tools/ui-kit-v2 0.34.4 → 0.35.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 (38) hide show
  1. package/fesm2022/rt-tools-ui-kit-v2-ai-prompt-input.mjs +574 -0
  2. package/fesm2022/rt-tools-ui-kit-v2-ai-prompt-input.mjs.map +1 -0
  3. package/fesm2022/rt-tools-ui-kit-v2-aside.mjs +76 -10
  4. package/fesm2022/rt-tools-ui-kit-v2-aside.mjs.map +1 -1
  5. package/fesm2022/rt-tools-ui-kit-v2-button.mjs +18 -9
  6. package/fesm2022/rt-tools-ui-kit-v2-button.mjs.map +1 -1
  7. package/fesm2022/rt-tools-ui-kit-v2-confirm-popover.mjs +2 -2
  8. package/fesm2022/rt-tools-ui-kit-v2-confirm-popover.mjs.map +1 -1
  9. package/fesm2022/rt-tools-ui-kit-v2-core.mjs +66 -4
  10. package/fesm2022/rt-tools-ui-kit-v2-core.mjs.map +1 -1
  11. package/fesm2022/rt-tools-ui-kit-v2-markdown-text.mjs +2 -2
  12. package/fesm2022/rt-tools-ui-kit-v2-markdown-text.mjs.map +1 -1
  13. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +128 -20
  14. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
  15. package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs +2 -2
  16. package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs.map +1 -1
  17. package/fesm2022/rt-tools-ui-kit-v2-usage-ring.mjs +163 -0
  18. package/fesm2022/rt-tools-ui-kit-v2-usage-ring.mjs.map +1 -0
  19. package/fesm2022/rt-tools-ui-kit-v2.mjs +2 -0
  20. package/package.json +9 -1
  21. package/src/lib/components/ai-prompt-input/CONTEXT.md +60 -0
  22. package/src/lib/components/ai-prompt-input/rt-ai-prompt-input.component.scss +113 -0
  23. package/src/lib/components/aside/footer/rt-aside-footer.component.scss +3 -1
  24. package/src/lib/components/aside/unsaved-dialog/rt-aside-unsaved-dialog.component.scss +10 -3
  25. package/src/lib/components/markdown-text/rt-markdown-text.component.scss +3 -0
  26. package/src/lib/components/thread-list/rt-thread-list.component.scss +19 -11
  27. package/src/lib/components/usage-ring/CONTEXT.md +33 -0
  28. package/src/lib/components/usage-ring/rt-usage-ring.component.scss +64 -0
  29. package/src/rich-editor/lib/components/ai-chat/CONTEXT.md +1 -1
  30. package/src/rich-editor/lib/components/ai-chat/answer/rt-ai-chat-answer.component.scss +1 -0
  31. package/src/rich-editor/lib/components/ai-chat/rt-ai-chat.component.scss +6 -0
  32. package/types/rt-tools-ui-kit-v2-ai-prompt-input.d.ts +193 -0
  33. package/types/rt-tools-ui-kit-v2-aside.d.ts +17 -7
  34. package/types/rt-tools-ui-kit-v2-button.d.ts +6 -1
  35. package/types/rt-tools-ui-kit-v2-core.d.ts +22 -0
  36. package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +49 -3
  37. package/types/rt-tools-ui-kit-v2-usage-ring.d.ts +47 -0
  38. package/types/rt-tools-ui-kit-v2.d.ts +2 -0
@@ -44,7 +44,7 @@ var RtMarkdownTextComponent = class RtMarkdownTextComponent {
44
44
  }],
45
45
  ngImport: i0,
46
46
  template: "<ng-container rtBlock=\"rt-markdown-text\">\n @for (item of blocks(); track $index) {\n <ng-container *ngTemplateOutlet=\"blockTpl; context: { $implicit: item }\" />\n }\n\n <ng-template #blockTpl let-item>\n @switch (item.kind) {\n @case (blockKind.Heading) {\n <div\n rtElem=\"heading\"\n qa-dataid=\"markdown-heading\"\n role=\"heading\"\n [attr.aria-level]=\"item.level\"\n [rtMod]=\"{ level: item.levelName }\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: item.content }\" />\n </div>\n }\n @case (blockKind.List) {\n @if (item.ordered) {\n <ol rtElem=\"list\" qa-dataid=\"markdown-list\" [rtMod]=\"{ ordered: true }\">\n <ng-container *ngTemplateOutlet=\"itemsTpl; context: { $implicit: item.items }\" />\n </ol>\n } @else {\n <ul rtElem=\"list\" qa-dataid=\"markdown-list\">\n <ng-container *ngTemplateOutlet=\"itemsTpl; context: { $implicit: item.items }\" />\n </ul>\n }\n }\n @case (blockKind.Quote) {\n <blockquote rtElem=\"quote\" qa-dataid=\"markdown-quote\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: item.content }\" />\n </blockquote>\n }\n @case (blockKind.Code) {\n <pre rtElem=\"code\" qa-dataid=\"markdown-code\"><code>{{ item.code }}</code></pre>\n }\n @case (blockKind.Table) {\n <ng-container *ngTemplateOutlet=\"tableTpl; context: { $implicit: item }\" />\n }\n @default {\n <p rtElem=\"paragraph\" qa-dataid=\"markdown-paragraph\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: item.content }\" />\n </p>\n }\n }\n </ng-template>\n\n <ng-template #itemsTpl let-items>\n @for (point of items; track $index) {\n <li rtElem=\"item\" qa-dataid=\"markdown-item\" [rtMod]=\"{ level: point.levelName }\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: point.content }\" />\n </li>\n }\n </ng-template>\n\n <ng-template #tableTpl let-item>\n <div rtElem=\"table-scroll\" qa-dataid=\"markdown-table-scroll\">\n <table rtElem=\"table\" qa-dataid=\"markdown-table\">\n <thead>\n <tr>\n @for (cell of item.head; track $index) {\n <th rtElem=\"head-cell\" qa-dataid=\"markdown-head-cell\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: cell }\" />\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of item.rows; track $index) {\n <tr>\n @for (cell of row; track $index) {\n <td rtElem=\"cell\" qa-dataid=\"markdown-cell\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: cell }\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n </ng-template>\n\n <!--\n Ветки шаблона кусков пишутся без переносов, а форматтер отключён для них нарочно: перенос\n строки в разметке становится пробелом, и размеченный кусок отъезжает от соседнего знака —\n «жирно , а рядом».\n -->\n <!-- prettier-ignore -->\n <ng-template #inlineTpl let-nodes>@for (node of nodes; track $index) {@switch (node.kind) {@case (inlineKind.Strong) {<strong rtElem=\"strong\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></strong>}@case (inlineKind.Emphasis) {<em rtElem=\"emphasis\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></em>}@case (inlineKind.Strike) {<s rtElem=\"strike\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></s>}@case (inlineKind.Code) {<code rtElem=\"code-inline\" qa-dataid=\"markdown-code-inline\">{{ node.text }}</code>}@case (inlineKind.Link) {<a rtElem=\"link\" qa-dataid=\"markdown-link\" rel=\"noopener noreferrer\" target=\"_blank\" [href]=\"node.href\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></a>}@case (inlineKind.Break) {<br />}@default {{{ node.text }}}}}</ng-template>\n</ng-container>\n",
47
- styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-markdown-text{--rt-markdown-text-radius: var(--rt-radius-sm);--rt-markdown-text-border-width: var(--rt-border-width-thin);display:flex;min-width:0;max-width:100%;flex-direction:column;color:var(--rt-color-text-primary);font-family:var(--rt-font-family-sans);font-size:var(--rt-text-xs);font-weight:var(--rt-font-weight-regular);gap:var(--rt-space-sm);letter-spacing:var(--rt-letter-spacing-wide);line-height:var(--rt-leading-snug)}.rt-markdown-text__heading{margin:0;color:var(--rt-color-text-primary);font-weight:var(--rt-font-weight-semibold)}.rt-markdown-text__heading--level--1{font-size:var(--rt-text-lg)}.rt-markdown-text__heading--level--2{font-size:var(--rt-text-md)}.rt-markdown-text__heading--level--3,.rt-markdown-text__heading--level--4,.rt-markdown-text__heading--level--5,.rt-markdown-text__heading--level--6{font-size:var(--rt-text-sm)}.rt-markdown-text__paragraph{margin:0}.rt-markdown-text__list{padding-left:var(--rt-space-md);margin:0;list-style:disc}.rt-markdown-text__list--ordered{list-style:decimal}.rt-markdown-text__item--level--1{margin-left:var(--rt-space-md)}.rt-markdown-text__item--level--2{margin-left:var(--rt-space-lg)}.rt-markdown-text__quote{padding-left:var(--rt-space-sm);border-left:var(--rt-markdown-text-border-width) solid var(--rt-color-border-default);margin:0;color:var(--rt-color-text-muted)}.rt-markdown-text__code{max-width:100%;padding:var(--rt-space-sm);border-radius:var(--rt-markdown-text-radius);margin:0;background:var(--rt-color-bg-subtle);color:var(--rt-color-text-primary);font-family:var(--rt-font-family-mono);font-size:var(--rt-text-2xs);line-height:var(--rt-leading-snug);overflow-x:auto}.rt-markdown-text__code-inline{padding:0 var(--rt-space-2xs);border-radius:var(--rt-markdown-text-radius);background:var(--rt-color-bg-subtle);font-family:var(--rt-font-family-mono);font-size:var(--rt-text-2xs)}.rt-markdown-text__table-scroll{max-width:100%;overflow-x:auto}.rt-markdown-text__table{width:100%;border-collapse:collapse}.rt-markdown-text__head-cell,.rt-markdown-text__cell{padding:var(--rt-space-2xs) var(--rt-space-sm);border:var(--rt-markdown-text-border-width) solid var(--rt-color-border-default);text-align:left}.rt-markdown-text__head-cell{color:var(--rt-color-text-muted);font-weight:var(--rt-font-weight-semibold)}.rt-markdown-text__strong{font-weight:var(--rt-font-weight-semibold)}.rt-markdown-text__emphasis{font-style:italic}.rt-markdown-text__strike{text-decoration:line-through}.rt-markdown-text__link{color:var(--rt-color-text-link);text-decoration:underline}.rt-markdown-text[data-rt-radius=none]{--rt-markdown-text-radius: var(--rt-radius-none)}.rt-markdown-text[data-rt-radius=xs]{--rt-markdown-text-radius: var(--rt-radius-xs)}.rt-markdown-text[data-rt-radius=sm]{--rt-markdown-text-radius: var(--rt-radius-sm)}.rt-markdown-text[data-rt-radius=ms]{--rt-markdown-text-radius: var(--rt-radius-ms)}.rt-markdown-text[data-rt-radius=md]{--rt-markdown-text-radius: var(--rt-radius-md)}.rt-markdown-text[data-rt-radius=lg]{--rt-markdown-text-radius: var(--rt-radius-lg)}.rt-markdown-text[data-rt-radius=xl]{--rt-markdown-text-radius: var(--rt-radius-xl)}.rt-markdown-text[data-rt-radius=\"2xl\"]{--rt-markdown-text-radius: var(--rt-radius-2xl)}.rt-markdown-text[data-rt-radius=full]{--rt-markdown-text-radius: var(--rt-radius-full)}}\n"],
47
+ styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-markdown-text{--rt-markdown-text-radius: var(--rt-radius-sm);--rt-markdown-text-border-width: var(--rt-border-width-thin);display:flex;min-width:0;max-width:100%;flex-direction:column;color:var(--rt-color-text-primary);font-family:var(--rt-font-family-sans);font-size:var(--rt-text-xs);font-weight:var(--rt-font-weight-regular);gap:var(--rt-space-sm);letter-spacing:var(--rt-letter-spacing-wide);line-height:var(--rt-leading-snug);overflow-wrap:anywhere}.rt-markdown-text__heading{margin:0;color:var(--rt-color-text-primary);font-weight:var(--rt-font-weight-semibold)}.rt-markdown-text__heading--level--1{font-size:var(--rt-text-lg)}.rt-markdown-text__heading--level--2{font-size:var(--rt-text-md)}.rt-markdown-text__heading--level--3,.rt-markdown-text__heading--level--4,.rt-markdown-text__heading--level--5,.rt-markdown-text__heading--level--6{font-size:var(--rt-text-sm)}.rt-markdown-text__paragraph{margin:0}.rt-markdown-text__list{padding-left:var(--rt-space-md);margin:0;list-style:disc}.rt-markdown-text__list--ordered{list-style:decimal}.rt-markdown-text__item--level--1{margin-left:var(--rt-space-md)}.rt-markdown-text__item--level--2{margin-left:var(--rt-space-lg)}.rt-markdown-text__quote{padding-left:var(--rt-space-sm);border-left:var(--rt-markdown-text-border-width) solid var(--rt-color-border-default);margin:0;color:var(--rt-color-text-muted)}.rt-markdown-text__code{max-width:100%;padding:var(--rt-space-sm);border-radius:var(--rt-markdown-text-radius);margin:0;background:var(--rt-color-bg-subtle);color:var(--rt-color-text-primary);font-family:var(--rt-font-family-mono);font-size:var(--rt-text-2xs);line-height:var(--rt-leading-snug);overflow-x:auto}.rt-markdown-text__code-inline{padding:0 var(--rt-space-2xs);border-radius:var(--rt-markdown-text-radius);background:var(--rt-color-bg-subtle);font-family:var(--rt-font-family-mono);font-size:var(--rt-text-2xs)}.rt-markdown-text__table-scroll{max-width:100%;overflow-x:auto}.rt-markdown-text__table{width:100%;border-collapse:collapse}.rt-markdown-text__head-cell,.rt-markdown-text__cell{padding:var(--rt-space-2xs) var(--rt-space-sm);border:var(--rt-markdown-text-border-width) solid var(--rt-color-border-default);text-align:left}.rt-markdown-text__head-cell{color:var(--rt-color-text-muted);font-weight:var(--rt-font-weight-semibold)}.rt-markdown-text__strong{font-weight:var(--rt-font-weight-semibold)}.rt-markdown-text__emphasis{font-style:italic}.rt-markdown-text__strike{text-decoration:line-through}.rt-markdown-text__link{color:var(--rt-color-text-link);text-decoration:underline}.rt-markdown-text[data-rt-radius=none]{--rt-markdown-text-radius: var(--rt-radius-none)}.rt-markdown-text[data-rt-radius=xs]{--rt-markdown-text-radius: var(--rt-radius-xs)}.rt-markdown-text[data-rt-radius=sm]{--rt-markdown-text-radius: var(--rt-radius-sm)}.rt-markdown-text[data-rt-radius=ms]{--rt-markdown-text-radius: var(--rt-radius-ms)}.rt-markdown-text[data-rt-radius=md]{--rt-markdown-text-radius: var(--rt-radius-md)}.rt-markdown-text[data-rt-radius=lg]{--rt-markdown-text-radius: var(--rt-radius-lg)}.rt-markdown-text[data-rt-radius=xl]{--rt-markdown-text-radius: var(--rt-radius-xl)}.rt-markdown-text[data-rt-radius=\"2xl\"]{--rt-markdown-text-radius: var(--rt-radius-2xl)}.rt-markdown-text[data-rt-radius=full]{--rt-markdown-text-radius: var(--rt-radius-full)}}\n"],
48
48
  dependencies: [
49
49
  {
50
50
  kind: "directive",
@@ -102,7 +102,7 @@ i0.ɵɵngDeclareClassMetadata({
102
102
  }],
103
103
  host: { class: BEM_BLOCK },
104
104
  template: "<ng-container rtBlock=\"rt-markdown-text\">\n @for (item of blocks(); track $index) {\n <ng-container *ngTemplateOutlet=\"blockTpl; context: { $implicit: item }\" />\n }\n\n <ng-template #blockTpl let-item>\n @switch (item.kind) {\n @case (blockKind.Heading) {\n <div\n rtElem=\"heading\"\n qa-dataid=\"markdown-heading\"\n role=\"heading\"\n [attr.aria-level]=\"item.level\"\n [rtMod]=\"{ level: item.levelName }\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: item.content }\" />\n </div>\n }\n @case (blockKind.List) {\n @if (item.ordered) {\n <ol rtElem=\"list\" qa-dataid=\"markdown-list\" [rtMod]=\"{ ordered: true }\">\n <ng-container *ngTemplateOutlet=\"itemsTpl; context: { $implicit: item.items }\" />\n </ol>\n } @else {\n <ul rtElem=\"list\" qa-dataid=\"markdown-list\">\n <ng-container *ngTemplateOutlet=\"itemsTpl; context: { $implicit: item.items }\" />\n </ul>\n }\n }\n @case (blockKind.Quote) {\n <blockquote rtElem=\"quote\" qa-dataid=\"markdown-quote\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: item.content }\" />\n </blockquote>\n }\n @case (blockKind.Code) {\n <pre rtElem=\"code\" qa-dataid=\"markdown-code\"><code>{{ item.code }}</code></pre>\n }\n @case (blockKind.Table) {\n <ng-container *ngTemplateOutlet=\"tableTpl; context: { $implicit: item }\" />\n }\n @default {\n <p rtElem=\"paragraph\" qa-dataid=\"markdown-paragraph\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: item.content }\" />\n </p>\n }\n }\n </ng-template>\n\n <ng-template #itemsTpl let-items>\n @for (point of items; track $index) {\n <li rtElem=\"item\" qa-dataid=\"markdown-item\" [rtMod]=\"{ level: point.levelName }\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: point.content }\" />\n </li>\n }\n </ng-template>\n\n <ng-template #tableTpl let-item>\n <div rtElem=\"table-scroll\" qa-dataid=\"markdown-table-scroll\">\n <table rtElem=\"table\" qa-dataid=\"markdown-table\">\n <thead>\n <tr>\n @for (cell of item.head; track $index) {\n <th rtElem=\"head-cell\" qa-dataid=\"markdown-head-cell\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: cell }\" />\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of item.rows; track $index) {\n <tr>\n @for (cell of row; track $index) {\n <td rtElem=\"cell\" qa-dataid=\"markdown-cell\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: cell }\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n </ng-template>\n\n <!--\n Ветки шаблона кусков пишутся без переносов, а форматтер отключён для них нарочно: перенос\n строки в разметке становится пробелом, и размеченный кусок отъезжает от соседнего знака —\n «жирно , а рядом».\n -->\n <!-- prettier-ignore -->\n <ng-template #inlineTpl let-nodes>@for (node of nodes; track $index) {@switch (node.kind) {@case (inlineKind.Strong) {<strong rtElem=\"strong\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></strong>}@case (inlineKind.Emphasis) {<em rtElem=\"emphasis\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></em>}@case (inlineKind.Strike) {<s rtElem=\"strike\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></s>}@case (inlineKind.Code) {<code rtElem=\"code-inline\" qa-dataid=\"markdown-code-inline\">{{ node.text }}</code>}@case (inlineKind.Link) {<a rtElem=\"link\" qa-dataid=\"markdown-link\" rel=\"noopener noreferrer\" target=\"_blank\" [href]=\"node.href\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></a>}@case (inlineKind.Break) {<br />}@default {{{ node.text }}}}}</ng-template>\n</ng-container>\n",
105
- styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-markdown-text{--rt-markdown-text-radius: var(--rt-radius-sm);--rt-markdown-text-border-width: var(--rt-border-width-thin);display:flex;min-width:0;max-width:100%;flex-direction:column;color:var(--rt-color-text-primary);font-family:var(--rt-font-family-sans);font-size:var(--rt-text-xs);font-weight:var(--rt-font-weight-regular);gap:var(--rt-space-sm);letter-spacing:var(--rt-letter-spacing-wide);line-height:var(--rt-leading-snug)}.rt-markdown-text__heading{margin:0;color:var(--rt-color-text-primary);font-weight:var(--rt-font-weight-semibold)}.rt-markdown-text__heading--level--1{font-size:var(--rt-text-lg)}.rt-markdown-text__heading--level--2{font-size:var(--rt-text-md)}.rt-markdown-text__heading--level--3,.rt-markdown-text__heading--level--4,.rt-markdown-text__heading--level--5,.rt-markdown-text__heading--level--6{font-size:var(--rt-text-sm)}.rt-markdown-text__paragraph{margin:0}.rt-markdown-text__list{padding-left:var(--rt-space-md);margin:0;list-style:disc}.rt-markdown-text__list--ordered{list-style:decimal}.rt-markdown-text__item--level--1{margin-left:var(--rt-space-md)}.rt-markdown-text__item--level--2{margin-left:var(--rt-space-lg)}.rt-markdown-text__quote{padding-left:var(--rt-space-sm);border-left:var(--rt-markdown-text-border-width) solid var(--rt-color-border-default);margin:0;color:var(--rt-color-text-muted)}.rt-markdown-text__code{max-width:100%;padding:var(--rt-space-sm);border-radius:var(--rt-markdown-text-radius);margin:0;background:var(--rt-color-bg-subtle);color:var(--rt-color-text-primary);font-family:var(--rt-font-family-mono);font-size:var(--rt-text-2xs);line-height:var(--rt-leading-snug);overflow-x:auto}.rt-markdown-text__code-inline{padding:0 var(--rt-space-2xs);border-radius:var(--rt-markdown-text-radius);background:var(--rt-color-bg-subtle);font-family:var(--rt-font-family-mono);font-size:var(--rt-text-2xs)}.rt-markdown-text__table-scroll{max-width:100%;overflow-x:auto}.rt-markdown-text__table{width:100%;border-collapse:collapse}.rt-markdown-text__head-cell,.rt-markdown-text__cell{padding:var(--rt-space-2xs) var(--rt-space-sm);border:var(--rt-markdown-text-border-width) solid var(--rt-color-border-default);text-align:left}.rt-markdown-text__head-cell{color:var(--rt-color-text-muted);font-weight:var(--rt-font-weight-semibold)}.rt-markdown-text__strong{font-weight:var(--rt-font-weight-semibold)}.rt-markdown-text__emphasis{font-style:italic}.rt-markdown-text__strike{text-decoration:line-through}.rt-markdown-text__link{color:var(--rt-color-text-link);text-decoration:underline}.rt-markdown-text[data-rt-radius=none]{--rt-markdown-text-radius: var(--rt-radius-none)}.rt-markdown-text[data-rt-radius=xs]{--rt-markdown-text-radius: var(--rt-radius-xs)}.rt-markdown-text[data-rt-radius=sm]{--rt-markdown-text-radius: var(--rt-radius-sm)}.rt-markdown-text[data-rt-radius=ms]{--rt-markdown-text-radius: var(--rt-radius-ms)}.rt-markdown-text[data-rt-radius=md]{--rt-markdown-text-radius: var(--rt-radius-md)}.rt-markdown-text[data-rt-radius=lg]{--rt-markdown-text-radius: var(--rt-radius-lg)}.rt-markdown-text[data-rt-radius=xl]{--rt-markdown-text-radius: var(--rt-radius-xl)}.rt-markdown-text[data-rt-radius=\"2xl\"]{--rt-markdown-text-radius: var(--rt-radius-2xl)}.rt-markdown-text[data-rt-radius=full]{--rt-markdown-text-radius: var(--rt-radius-full)}}\n"]
105
+ styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-markdown-text{--rt-markdown-text-radius: var(--rt-radius-sm);--rt-markdown-text-border-width: var(--rt-border-width-thin);display:flex;min-width:0;max-width:100%;flex-direction:column;color:var(--rt-color-text-primary);font-family:var(--rt-font-family-sans);font-size:var(--rt-text-xs);font-weight:var(--rt-font-weight-regular);gap:var(--rt-space-sm);letter-spacing:var(--rt-letter-spacing-wide);line-height:var(--rt-leading-snug);overflow-wrap:anywhere}.rt-markdown-text__heading{margin:0;color:var(--rt-color-text-primary);font-weight:var(--rt-font-weight-semibold)}.rt-markdown-text__heading--level--1{font-size:var(--rt-text-lg)}.rt-markdown-text__heading--level--2{font-size:var(--rt-text-md)}.rt-markdown-text__heading--level--3,.rt-markdown-text__heading--level--4,.rt-markdown-text__heading--level--5,.rt-markdown-text__heading--level--6{font-size:var(--rt-text-sm)}.rt-markdown-text__paragraph{margin:0}.rt-markdown-text__list{padding-left:var(--rt-space-md);margin:0;list-style:disc}.rt-markdown-text__list--ordered{list-style:decimal}.rt-markdown-text__item--level--1{margin-left:var(--rt-space-md)}.rt-markdown-text__item--level--2{margin-left:var(--rt-space-lg)}.rt-markdown-text__quote{padding-left:var(--rt-space-sm);border-left:var(--rt-markdown-text-border-width) solid var(--rt-color-border-default);margin:0;color:var(--rt-color-text-muted)}.rt-markdown-text__code{max-width:100%;padding:var(--rt-space-sm);border-radius:var(--rt-markdown-text-radius);margin:0;background:var(--rt-color-bg-subtle);color:var(--rt-color-text-primary);font-family:var(--rt-font-family-mono);font-size:var(--rt-text-2xs);line-height:var(--rt-leading-snug);overflow-x:auto}.rt-markdown-text__code-inline{padding:0 var(--rt-space-2xs);border-radius:var(--rt-markdown-text-radius);background:var(--rt-color-bg-subtle);font-family:var(--rt-font-family-mono);font-size:var(--rt-text-2xs)}.rt-markdown-text__table-scroll{max-width:100%;overflow-x:auto}.rt-markdown-text__table{width:100%;border-collapse:collapse}.rt-markdown-text__head-cell,.rt-markdown-text__cell{padding:var(--rt-space-2xs) var(--rt-space-sm);border:var(--rt-markdown-text-border-width) solid var(--rt-color-border-default);text-align:left}.rt-markdown-text__head-cell{color:var(--rt-color-text-muted);font-weight:var(--rt-font-weight-semibold)}.rt-markdown-text__strong{font-weight:var(--rt-font-weight-semibold)}.rt-markdown-text__emphasis{font-style:italic}.rt-markdown-text__strike{text-decoration:line-through}.rt-markdown-text__link{color:var(--rt-color-text-link);text-decoration:underline}.rt-markdown-text[data-rt-radius=none]{--rt-markdown-text-radius: var(--rt-radius-none)}.rt-markdown-text[data-rt-radius=xs]{--rt-markdown-text-radius: var(--rt-radius-xs)}.rt-markdown-text[data-rt-radius=sm]{--rt-markdown-text-radius: var(--rt-radius-sm)}.rt-markdown-text[data-rt-radius=ms]{--rt-markdown-text-radius: var(--rt-radius-ms)}.rt-markdown-text[data-rt-radius=md]{--rt-markdown-text-radius: var(--rt-radius-md)}.rt-markdown-text[data-rt-radius=lg]{--rt-markdown-text-radius: var(--rt-radius-lg)}.rt-markdown-text[data-rt-radius=xl]{--rt-markdown-text-radius: var(--rt-radius-xl)}.rt-markdown-text[data-rt-radius=\"2xl\"]{--rt-markdown-text-radius: var(--rt-radius-2xl)}.rt-markdown-text[data-rt-radius=full]{--rt-markdown-text-radius: var(--rt-radius-full)}}\n"]
106
106
  }]
107
107
  }],
108
108
  propDecorators: { text: [{
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-markdown-text.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/markdown-text/rt-markdown-text.component.ts","../../../projects/ui-kit-v2/src/lib/components/markdown-text/rt-markdown-text.component.html"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport { computed, input, ChangeDetectionStrategy, Component, InputSignal, Signal, ViewEncapsulation } from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { parseMarkdown } from '@rt-tools/ui-kit-v2/core';\nimport { ERtMarkdownBlock, ERtMarkdownInline, IRtMarkdownBlockNode } from '@rt-tools/ui-kit-v2/core';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\n\nconst BEM_BLOCK: string = 'rt-markdown-text';\n\n/**\n * Текст, написанный разметкой, показанный узлами.\n *\n * Перечень разметки зашит в разборщике и входом не задаётся: вход у компонента один — сам\n * текст. Настраивать нечего, значит нечем и ослабить.\n *\n * Присланная строка в страницу не отдаётся ни разу: компонент рисует дерево узлов, которое\n * вернул разбор, и другого пути у текста внутрь страницы нет. Поэтому сырой HTML, картинки и\n * адреса чужих схем показываются видимым текстом — узла для них разборщик не строит.\n *\n * Таблица рисуется своей разметкой, а не таблицей кита: та объявляет колонки заранее\n * директивами, а число столбцов здесь приходит из текста и заранее не известно никому.\n */\n@Component({\n selector: 'rt-markdown-text',\n templateUrl: './rt-markdown-text.component.html',\n styleUrl: './rt-markdown-text.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n BlockDirective,\n ElemDirective,\n ModDirective,\n NgTemplateOutlet,\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtMarkdownTextComponent {\n /** Роды блоков в шаблоне: сравнение идёт со значением перечисления, а не со строкой. */\n protected readonly blockKind: typeof ERtMarkdownBlock = ERtMarkdownBlock;\n\n /** Роды кусков строки в шаблоне. */\n protected readonly inlineKind: typeof ERtMarkdownInline = ERtMarkdownInline;\n\n protected readonly blocks: Signal<readonly IRtMarkdownBlockNode[]> = computed((): readonly IRtMarkdownBlockNode[] =>\n parseMarkdown(this.text())\n );\n\n public readonly text: InputSignal<string | null> = input.required<string | null>();\n}\n","<ng-container rtBlock=\"rt-markdown-text\">\n @for (item of blocks(); track $index) {\n <ng-container *ngTemplateOutlet=\"blockTpl; context: { $implicit: item }\" />\n }\n\n <ng-template #blockTpl let-item>\n @switch (item.kind) {\n @case (blockKind.Heading) {\n <div\n rtElem=\"heading\"\n qa-dataid=\"markdown-heading\"\n role=\"heading\"\n [attr.aria-level]=\"item.level\"\n [rtMod]=\"{ level: item.levelName }\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: item.content }\" />\n </div>\n }\n @case (blockKind.List) {\n @if (item.ordered) {\n <ol rtElem=\"list\" qa-dataid=\"markdown-list\" [rtMod]=\"{ ordered: true }\">\n <ng-container *ngTemplateOutlet=\"itemsTpl; context: { $implicit: item.items }\" />\n </ol>\n } @else {\n <ul rtElem=\"list\" qa-dataid=\"markdown-list\">\n <ng-container *ngTemplateOutlet=\"itemsTpl; context: { $implicit: item.items }\" />\n </ul>\n }\n }\n @case (blockKind.Quote) {\n <blockquote rtElem=\"quote\" qa-dataid=\"markdown-quote\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: item.content }\" />\n </blockquote>\n }\n @case (blockKind.Code) {\n <pre rtElem=\"code\" qa-dataid=\"markdown-code\"><code>{{ item.code }}</code></pre>\n }\n @case (blockKind.Table) {\n <ng-container *ngTemplateOutlet=\"tableTpl; context: { $implicit: item }\" />\n }\n @default {\n <p rtElem=\"paragraph\" qa-dataid=\"markdown-paragraph\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: item.content }\" />\n </p>\n }\n }\n </ng-template>\n\n <ng-template #itemsTpl let-items>\n @for (point of items; track $index) {\n <li rtElem=\"item\" qa-dataid=\"markdown-item\" [rtMod]=\"{ level: point.levelName }\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: point.content }\" />\n </li>\n }\n </ng-template>\n\n <ng-template #tableTpl let-item>\n <div rtElem=\"table-scroll\" qa-dataid=\"markdown-table-scroll\">\n <table rtElem=\"table\" qa-dataid=\"markdown-table\">\n <thead>\n <tr>\n @for (cell of item.head; track $index) {\n <th rtElem=\"head-cell\" qa-dataid=\"markdown-head-cell\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: cell }\" />\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of item.rows; track $index) {\n <tr>\n @for (cell of row; track $index) {\n <td rtElem=\"cell\" qa-dataid=\"markdown-cell\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: cell }\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n </ng-template>\n\n <!--\n Ветки шаблона кусков пишутся без переносов, а форматтер отключён для них нарочно: перенос\n строки в разметке становится пробелом, и размеченный кусок отъезжает от соседнего знака —\n «жирно , а рядом».\n -->\n <!-- prettier-ignore -->\n <ng-template #inlineTpl let-nodes>@for (node of nodes; track $index) {@switch (node.kind) {@case (inlineKind.Strong) {<strong rtElem=\"strong\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></strong>}@case (inlineKind.Emphasis) {<em rtElem=\"emphasis\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></em>}@case (inlineKind.Strike) {<s rtElem=\"strike\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></s>}@case (inlineKind.Code) {<code rtElem=\"code-inline\" qa-dataid=\"markdown-code-inline\">{{ node.text }}</code>}@case (inlineKind.Link) {<a rtElem=\"link\" qa-dataid=\"markdown-link\" rel=\"noopener noreferrer\" target=\"_blank\" [href]=\"node.href\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></a>}@case (inlineKind.Break) {<br />}@default {{{ node.text }}}}}</ng-template>\n</ng-container>\n"],"mappings":";;;;;;;AASA,MAAM,YAAoB;AAiC1B,IAAa,0BAAb,MAAa,wBAAuB;CAlBpC,cAAA;EAoBuB,KAAA,YAAqC;EAGrC,KAAA,aAAuC;EAEvC,KAAA,SAAkD,eACjE,cAAc,KAAK,KAAI,CAAE,GAC5B,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;EAEe,KAAA,OAAmC,MAAM,SAAyB,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CACrF;CAZY;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAuB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAAvB;EAAA,KAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAAuB,cAAA;GAAA,UAAA;GAAA,QAAA,EAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA,EAAA;GAAA,MAAA,EAAA,gBAAA,mBAAA;GAAA,gBAAA,CAAA;IAAA,WAAA,GAAA;IAAA,QAAA,CAAA,UAAA,QAAA;GAAA,CAAA;GAAA,UAAA;GAAA,UC1CpC;GA0FA,QAAA,CAAA,gyGAAA;GAAA,cAAA;IAAA;KAAA,MAAA;KAAA,MD1DQ;KAAc,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACd;KAAa,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACb;KAAY,UAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACZ;KAAgB,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;KAAA;IAAA;GAAA;GAAA,iBAAA,GAAA,wBAAA;GAAA,eAAA,GAAA,kBAAA;EAAA,CAAA;CAAA;;AAOX,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAuB,YAAA,CAAA;EAlBnC,MAAA;EACa,MAAA,CAAA;GAAA,UAAA;GAAkB,iBAGX,wBAAwB;GAAM,eAChC,kBAAkB;GAAI,SAC5B;IAEL;IACA;IACA;IACA;GACH;GAAA,gBACe,CAAC;IAAE,WAAW;IAAmB,QAAQ,CAAC,QAAQ;GAAC,CAAE;GAAC,MAChE,EACF,OAAO,UACV;GAAA,UAAA;GAAA,QAAA,CAAA,gyGAAA;EAAA,CAAA"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-markdown-text.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/markdown-text/rt-markdown-text.component.ts","../../../projects/ui-kit-v2/src/lib/components/markdown-text/rt-markdown-text.component.html"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport { computed, input, ChangeDetectionStrategy, Component, InputSignal, Signal, ViewEncapsulation } from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { parseMarkdown } from '@rt-tools/ui-kit-v2/core';\nimport { ERtMarkdownBlock, ERtMarkdownInline, IRtMarkdownBlockNode } from '@rt-tools/ui-kit-v2/core';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\n\nconst BEM_BLOCK: string = 'rt-markdown-text';\n\n/**\n * Текст, написанный разметкой, показанный узлами.\n *\n * Перечень разметки зашит в разборщике и входом не задаётся: вход у компонента один — сам\n * текст. Настраивать нечего, значит нечем и ослабить.\n *\n * Присланная строка в страницу не отдаётся ни разу: компонент рисует дерево узлов, которое\n * вернул разбор, и другого пути у текста внутрь страницы нет. Поэтому сырой HTML, картинки и\n * адреса чужих схем показываются видимым текстом — узла для них разборщик не строит.\n *\n * Таблица рисуется своей разметкой, а не таблицей кита: та объявляет колонки заранее\n * директивами, а число столбцов здесь приходит из текста и заранее не известно никому.\n */\n@Component({\n selector: 'rt-markdown-text',\n templateUrl: './rt-markdown-text.component.html',\n styleUrl: './rt-markdown-text.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n BlockDirective,\n ElemDirective,\n ModDirective,\n NgTemplateOutlet,\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtMarkdownTextComponent {\n /** Роды блоков в шаблоне: сравнение идёт со значением перечисления, а не со строкой. */\n protected readonly blockKind: typeof ERtMarkdownBlock = ERtMarkdownBlock;\n\n /** Роды кусков строки в шаблоне. */\n protected readonly inlineKind: typeof ERtMarkdownInline = ERtMarkdownInline;\n\n protected readonly blocks: Signal<readonly IRtMarkdownBlockNode[]> = computed((): readonly IRtMarkdownBlockNode[] =>\n parseMarkdown(this.text())\n );\n\n public readonly text: InputSignal<string | null> = input.required<string | null>();\n}\n","<ng-container rtBlock=\"rt-markdown-text\">\n @for (item of blocks(); track $index) {\n <ng-container *ngTemplateOutlet=\"blockTpl; context: { $implicit: item }\" />\n }\n\n <ng-template #blockTpl let-item>\n @switch (item.kind) {\n @case (blockKind.Heading) {\n <div\n rtElem=\"heading\"\n qa-dataid=\"markdown-heading\"\n role=\"heading\"\n [attr.aria-level]=\"item.level\"\n [rtMod]=\"{ level: item.levelName }\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: item.content }\" />\n </div>\n }\n @case (blockKind.List) {\n @if (item.ordered) {\n <ol rtElem=\"list\" qa-dataid=\"markdown-list\" [rtMod]=\"{ ordered: true }\">\n <ng-container *ngTemplateOutlet=\"itemsTpl; context: { $implicit: item.items }\" />\n </ol>\n } @else {\n <ul rtElem=\"list\" qa-dataid=\"markdown-list\">\n <ng-container *ngTemplateOutlet=\"itemsTpl; context: { $implicit: item.items }\" />\n </ul>\n }\n }\n @case (blockKind.Quote) {\n <blockquote rtElem=\"quote\" qa-dataid=\"markdown-quote\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: item.content }\" />\n </blockquote>\n }\n @case (blockKind.Code) {\n <pre rtElem=\"code\" qa-dataid=\"markdown-code\"><code>{{ item.code }}</code></pre>\n }\n @case (blockKind.Table) {\n <ng-container *ngTemplateOutlet=\"tableTpl; context: { $implicit: item }\" />\n }\n @default {\n <p rtElem=\"paragraph\" qa-dataid=\"markdown-paragraph\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: item.content }\" />\n </p>\n }\n }\n </ng-template>\n\n <ng-template #itemsTpl let-items>\n @for (point of items; track $index) {\n <li rtElem=\"item\" qa-dataid=\"markdown-item\" [rtMod]=\"{ level: point.levelName }\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: point.content }\" />\n </li>\n }\n </ng-template>\n\n <ng-template #tableTpl let-item>\n <div rtElem=\"table-scroll\" qa-dataid=\"markdown-table-scroll\">\n <table rtElem=\"table\" qa-dataid=\"markdown-table\">\n <thead>\n <tr>\n @for (cell of item.head; track $index) {\n <th rtElem=\"head-cell\" qa-dataid=\"markdown-head-cell\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: cell }\" />\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of item.rows; track $index) {\n <tr>\n @for (cell of row; track $index) {\n <td rtElem=\"cell\" qa-dataid=\"markdown-cell\">\n <ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: cell }\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n </ng-template>\n\n <!--\n Ветки шаблона кусков пишутся без переносов, а форматтер отключён для них нарочно: перенос\n строки в разметке становится пробелом, и размеченный кусок отъезжает от соседнего знака —\n «жирно , а рядом».\n -->\n <!-- prettier-ignore -->\n <ng-template #inlineTpl let-nodes>@for (node of nodes; track $index) {@switch (node.kind) {@case (inlineKind.Strong) {<strong rtElem=\"strong\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></strong>}@case (inlineKind.Emphasis) {<em rtElem=\"emphasis\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></em>}@case (inlineKind.Strike) {<s rtElem=\"strike\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></s>}@case (inlineKind.Code) {<code rtElem=\"code-inline\" qa-dataid=\"markdown-code-inline\">{{ node.text }}</code>}@case (inlineKind.Link) {<a rtElem=\"link\" qa-dataid=\"markdown-link\" rel=\"noopener noreferrer\" target=\"_blank\" [href]=\"node.href\"><ng-container *ngTemplateOutlet=\"inlineTpl; context: { $implicit: node.children }\" /></a>}@case (inlineKind.Break) {<br />}@default {{{ node.text }}}}}</ng-template>\n</ng-container>\n"],"mappings":";;;;;;;AASA,MAAM,YAAoB;AAiC1B,IAAa,0BAAb,MAAa,wBAAuB;CAlBpC,cAAA;EAoBuB,KAAA,YAAqC;EAGrC,KAAA,aAAuC;EAEvC,KAAA,SAAkD,eACjE,cAAc,KAAK,KAAI,CAAE,GAC5B,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;EAEe,KAAA,OAAmC,MAAM,SAAyB,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CACrF;CAZY;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAuB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAAvB;EAAA,KAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAAuB,cAAA;GAAA,UAAA;GAAA,QAAA,EAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA,EAAA;GAAA,MAAA,EAAA,gBAAA,mBAAA;GAAA,gBAAA,CAAA;IAAA,WAAA,GAAA;IAAA,QAAA,CAAA,UAAA,QAAA;GAAA,CAAA;GAAA,UAAA;GAAA,UC1CpC;GA0FA,QAAA,CAAA,uzGAAA;GAAA,cAAA;IAAA;KAAA,MAAA;KAAA,MD1DQ;KAAc,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACd;KAAa,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACb;KAAY,UAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACZ;KAAgB,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;KAAA;IAAA;GAAA;GAAA,iBAAA,GAAA,wBAAA;GAAA,eAAA,GAAA,kBAAA;EAAA,CAAA;CAAA;;AAOX,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAuB,YAAA,CAAA;EAlBnC,MAAA;EACa,MAAA,CAAA;GAAA,UAAA;GAAkB,iBAGX,wBAAwB;GAAM,eAChC,kBAAkB;GAAI,SAC5B;IAEL;IACA;IACA;IACA;GACH;GAAA,gBACe,CAAC;IAAE,WAAW;IAAmB,QAAQ,CAAC,QAAQ;GAAC,CAAE;GAAC,MAChE,EACF,OAAO,UACV;GAAA,UAAA;GAAA,QAAA,CAAA,uzGAAA;EAAA,CAAA"}
@@ -1,7 +1,7 @@
1
1
  import * as i0 from "@angular/core";
2
2
  import { ChangeDetectionStrategy, Component, DestroyRef, Directive, ElementRef, Injector, Pipe, TemplateRef, ViewEncapsulation, afterNextRender, afterRenderEffect, booleanAttribute, computed, contentChild, effect, forwardRef, inject, input, model, numberAttribute, output, signal, viewChild } from "@angular/core";
3
3
  import { BlockDirective, ElemDirective, ModDirective } from "@rt-tools/core";
4
- import { RT_KIT_LABELS, RT_KIT_LOCALE, RtAiRunStatusComponent, RtButtonDirective, RtConfirmDirective, RtCopyValueComponent, RtDeltaViewComponent, RtEmptyStateComponent, RtFileCardComponent, RtFileDropComponent, RtFormControlBase, RtIconButtonComponent, RtIconComponent, RtMarkdownTextComponent, RtMenuComponent, RtMenuItemComponent, RtMessageComponent, RtNoteComponent, RtPromptSuggestionComponent, RtServiceLogoComponent, RtSkeletonWrapperComponent, RtSpinnerComponent, RtThreadListComponent, RtThreadListRowActionsDirective, RtThreadListRowDirective, RtToolbarComponent, RtToolbarLeftDirective, RtToolbarRightDirective, coerceQuillDeltaOutput, fileNameFromUrl, markdownToPlainText, rtKitLabel, rtMatchParts } from "@rt-tools/ui-kit-v2";
4
+ import { RT_KIT_LABELS, RT_KIT_LOCALE, RtAiPromptInputComponent, RtAiRunStatusComponent, RtButtonDirective, RtConfirmDirective, RtCopyValueComponent, RtDeltaViewComponent, RtEmptyStateComponent, RtFileCardComponent, RtFileDropComponent, RtFormControlBase, RtIconButtonComponent, RtIconComponent, RtMarkdownTextComponent, RtMenuComponent, RtMenuItemComponent, RtMessageComponent, RtNoteComponent, RtPromptSuggestionComponent, RtServiceLogoComponent, RtSkeletonWrapperComponent, RtSpinnerComponent, RtThreadListComponent, RtThreadListRowActionsDirective, RtThreadListRowDirective, RtToolbarComponent, RtToolbarLeftDirective, RtToolbarRightDirective, coerceQuillDeltaOutput, fileNameFromUrl, markdownToPlainText, rtKitLabel, rtMatchParts } from "@rt-tools/ui-kit-v2";
5
5
  import { CdkTextareaAutosize } from "@angular/cdk/text-field";
6
6
  import { takeUntilDestroyed, toSignal } from "@angular/core/rxjs-interop";
7
7
  import * as i1 from "@angular/forms";
@@ -2239,7 +2239,7 @@ var RtAiChatAnswerComponent = class RtAiChatAnswerComponent {
2239
2239
  },
2240
2240
  ngImport: i0,
2241
2241
  template: "<ng-container rtBlock=\"rt-ai-chat-answer\">\n @if (message().run; as run) {\n <rt-ai-run-status\n qa-dataid=\"ai-chat-run\"\n [state]=\"run.state\"\n [label]=\"run.label\"\n [meta]=\"run.meta ?? ''\"\n [steps]=\"run.steps ?? []\"\n [(expanded)]=\"expanded\" />\n }\n @if (message().text) {\n <rt-markdown-text rtElem=\"text\" qa-dataid=\"ai-chat-answer-text\" [text]=\"message().text\" />\n }\n @if (extra(); as extraTemplate) {\n <ng-container [ngTemplateOutlet]=\"extraTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message() }\" />\n }\n @if (isWritten()) {\n <div rtElem=\"feedback\" qa-dataid=\"ai-chat-feedback\">\n @if (copyable()) {\n <rt-ai-chat-copy [text]=\"plainText()\" />\n }\n <rt-icon-button\n qa-dataid=\"ai-chat-like\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"thumb-up\"\n [active]=\"message().feedback === 'liked'\"\n [ariaLabel]=\"t().aiLike\"\n [tooltip]=\"t().aiLike\"\n (clicked)=\"feedbackChange.emit('liked')\" />\n <rt-icon-button\n qa-dataid=\"ai-chat-dislike\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"thumb-down\"\n [active]=\"message().feedback === 'disliked'\"\n [ariaLabel]=\"t().aiDislike\"\n [tooltip]=\"t().aiDislike\"\n (clicked)=\"feedbackChange.emit('disliked')\" />\n </div>\n }\n</ng-container>\n",
2242
- styles: ["@layer rt-kit.components{.rt-ai-chat-answer{display:flex;flex-direction:column;gap:var(--rt-space-sm)}.rt-ai-chat-answer__feedback{display:flex;gap:var(--rt-space-xs)}}\n"],
2242
+ styles: ["@layer rt-kit.components{.rt-ai-chat-answer{display:flex;min-width:0;flex-direction:column;gap:var(--rt-space-sm)}.rt-ai-chat-answer__feedback{display:flex;gap:var(--rt-space-xs)}}\n"],
2243
2243
  dependencies: [
2244
2244
  {
2245
2245
  kind: "directive",
@@ -2347,7 +2347,7 @@ i0.ɵɵngDeclareClassMetadata({
2347
2347
  "[attr.data-id]": "message().id"
2348
2348
  },
2349
2349
  template: "<ng-container rtBlock=\"rt-ai-chat-answer\">\n @if (message().run; as run) {\n <rt-ai-run-status\n qa-dataid=\"ai-chat-run\"\n [state]=\"run.state\"\n [label]=\"run.label\"\n [meta]=\"run.meta ?? ''\"\n [steps]=\"run.steps ?? []\"\n [(expanded)]=\"expanded\" />\n }\n @if (message().text) {\n <rt-markdown-text rtElem=\"text\" qa-dataid=\"ai-chat-answer-text\" [text]=\"message().text\" />\n }\n @if (extra(); as extraTemplate) {\n <ng-container [ngTemplateOutlet]=\"extraTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message() }\" />\n }\n @if (isWritten()) {\n <div rtElem=\"feedback\" qa-dataid=\"ai-chat-feedback\">\n @if (copyable()) {\n <rt-ai-chat-copy [text]=\"plainText()\" />\n }\n <rt-icon-button\n qa-dataid=\"ai-chat-like\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"thumb-up\"\n [active]=\"message().feedback === 'liked'\"\n [ariaLabel]=\"t().aiLike\"\n [tooltip]=\"t().aiLike\"\n (clicked)=\"feedbackChange.emit('liked')\" />\n <rt-icon-button\n qa-dataid=\"ai-chat-dislike\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"thumb-down\"\n [active]=\"message().feedback === 'disliked'\"\n [ariaLabel]=\"t().aiDislike\"\n [tooltip]=\"t().aiDislike\"\n (clicked)=\"feedbackChange.emit('disliked')\" />\n </div>\n }\n</ng-container>\n",
2350
- styles: ["@layer rt-kit.components{.rt-ai-chat-answer{display:flex;flex-direction:column;gap:var(--rt-space-sm)}.rt-ai-chat-answer__feedback{display:flex;gap:var(--rt-space-xs)}}\n"]
2350
+ styles: ["@layer rt-kit.components{.rt-ai-chat-answer{display:flex;min-width:0;flex-direction:column;gap:var(--rt-space-sm)}.rt-ai-chat-answer__feedback{display:flex;gap:var(--rt-space-xs)}}\n"]
2351
2351
  }]
2352
2352
  }],
2353
2353
  propDecorators: {
@@ -2448,7 +2448,7 @@ var RtAiChatComponent = class RtAiChatComponent {
2448
2448
  this.#forceScroll = false;
2449
2449
  this.#injector = inject(Injector);
2450
2450
  this.#clipboard = inject(Clipboard);
2451
- this.composer = viewChild(RtMessageComposerComponent, ...ngDevMode ? [{ debugName: "composer" }] : /* istanbul ignore next */ []);
2451
+ this.composer = viewChild(RtAiPromptInputComponent, ...ngDevMode ? [{ debugName: "composer" }] : /* istanbul ignore next */ []);
2452
2452
  this.backButton = viewChild("back", {
2453
2453
  ...ngDevMode ? { debugName: "backButton" } : /* istanbul ignore next */ {},
2454
2454
  read: ElementRef
@@ -2461,6 +2461,7 @@ var RtAiChatComponent = class RtAiChatComponent {
2461
2461
  this.emptyTitleText = computed(() => this.emptyTitle() || this.t().aiEmptyTitle, ...ngDevMode ? [{ debugName: "emptyTitleText" }] : /* istanbul ignore next */ []);
2462
2462
  this.emptyDescriptionText = computed(() => this.emptyDescription() || this.t().aiEmptyText, ...ngDevMode ? [{ debugName: "emptyDescriptionText" }] : /* istanbul ignore next */ []);
2463
2463
  this.disclaimerText = computed(() => this.disclaimer() ?? this.t().aiDisclaimer, ...ngDevMode ? [{ debugName: "disclaimerText" }] : /* istanbul ignore next */ []);
2464
+ this.disclaimerAbove = computed(() => this.disclaimerPosition() === "above", ...ngDevMode ? [{ debugName: "disclaimerAbove" }] : /* istanbul ignore next */ []);
2464
2465
  this.headerIconSign = computed(() => this.headerIconPreset() === "material" ? "material" : null, ...ngDevMode ? [{ debugName: "headerIconSign" }] : /* istanbul ignore next */ []);
2465
2466
  this.hasThreads = computed(() => this.threads() !== null, ...ngDevMode ? [{ debugName: "hasThreads" }] : /* istanbul ignore next */ []);
2466
2467
  this.isThreadColumn = computed(() => this.fullScreen() && this.hasThreads(), ...ngDevMode ? [{ debugName: "isThreadColumn" }] : /* istanbul ignore next */ []);
@@ -2487,6 +2488,12 @@ var RtAiChatComponent = class RtAiChatComponent {
2487
2488
  this.emptyDescription = input("", ...ngDevMode ? [{ debugName: "emptyDescription" }] : /* istanbul ignore next */ []);
2488
2489
  this.placeholder = input("", ...ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []);
2489
2490
  this.disclaimer = input(null, ...ngDevMode ? [{ debugName: "disclaimer" }] : /* istanbul ignore next */ []);
2491
+ this.disclaimerPosition = input("below", ...ngDevMode ? [{ debugName: "disclaimerPosition" }] : /* istanbul ignore next */ []);
2492
+ this.model = input("", ...ngDevMode ? [{ debugName: "model" }] : /* istanbul ignore next */ []);
2493
+ this.effort = input("", ...ngDevMode ? [{ debugName: "effort" }] : /* istanbul ignore next */ []);
2494
+ this.mode = input("", ...ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []);
2495
+ this.usage = input(null, ...ngDevMode ? [{ debugName: "usage" }] : /* istanbul ignore next */ []);
2496
+ this.usageHint = input("", ...ngDevMode ? [{ debugName: "usageHint" }] : /* istanbul ignore next */ []);
2490
2497
  this.sending = input(false, {
2491
2498
  ...ngDevMode ? { debugName: "sending" } : /* istanbul ignore next */ {},
2492
2499
  transform: booleanAttribute
@@ -2541,6 +2548,7 @@ var RtAiChatComponent = class RtAiChatComponent {
2541
2548
  this.searchThreads = output();
2542
2549
  this.loadMoreThreads = output();
2543
2550
  this.feedbackChange = output();
2551
+ this.controlPicked = output();
2544
2552
  afterRenderEffect(() => {
2545
2553
  this.messages();
2546
2554
  this.error();
@@ -2698,6 +2706,48 @@ var RtAiChatComponent = class RtAiChatComponent {
2698
2706
  isRequired: false,
2699
2707
  transformFunction: null
2700
2708
  },
2709
+ disclaimerPosition: {
2710
+ classPropertyName: "disclaimerPosition",
2711
+ publicName: "disclaimerPosition",
2712
+ isSignal: true,
2713
+ isRequired: false,
2714
+ transformFunction: null
2715
+ },
2716
+ model: {
2717
+ classPropertyName: "model",
2718
+ publicName: "model",
2719
+ isSignal: true,
2720
+ isRequired: false,
2721
+ transformFunction: null
2722
+ },
2723
+ effort: {
2724
+ classPropertyName: "effort",
2725
+ publicName: "effort",
2726
+ isSignal: true,
2727
+ isRequired: false,
2728
+ transformFunction: null
2729
+ },
2730
+ mode: {
2731
+ classPropertyName: "mode",
2732
+ publicName: "mode",
2733
+ isSignal: true,
2734
+ isRequired: false,
2735
+ transformFunction: null
2736
+ },
2737
+ usage: {
2738
+ classPropertyName: "usage",
2739
+ publicName: "usage",
2740
+ isSignal: true,
2741
+ isRequired: false,
2742
+ transformFunction: null
2743
+ },
2744
+ usageHint: {
2745
+ classPropertyName: "usageHint",
2746
+ publicName: "usageHint",
2747
+ isSignal: true,
2748
+ isRequired: false,
2749
+ transformFunction: null
2750
+ },
2701
2751
  sending: {
2702
2752
  classPropertyName: "sending",
2703
2753
  publicName: "sending",
@@ -2831,7 +2881,8 @@ var RtAiChatComponent = class RtAiChatComponent {
2831
2881
  deleteThread: "deleteThread",
2832
2882
  searchThreads: "searchThreads",
2833
2883
  loadMoreThreads: "loadMoreThreads",
2834
- feedbackChange: "feedbackChange"
2884
+ feedbackChange: "feedbackChange",
2885
+ controlPicked: "controlPicked"
2835
2886
  },
2836
2887
  host: { classAttribute: "rt-ai-chat" },
2837
2888
  queries: [{
@@ -2845,7 +2896,7 @@ var RtAiChatComponent = class RtAiChatComponent {
2845
2896
  {
2846
2897
  propertyName: "composer",
2847
2898
  first: true,
2848
- predicate: RtMessageComposerComponent,
2899
+ predicate: RtAiPromptInputComponent,
2849
2900
  descendants: true,
2850
2901
  isSignal: true
2851
2902
  },
@@ -2866,8 +2917,8 @@ var RtAiChatComponent = class RtAiChatComponent {
2866
2917
  }
2867
2918
  ],
2868
2919
  ngImport: i0,
2869
- template: "<ng-container rtBlock=\"rt-ai-chat\">\n @if (isThreadColumn()) {\n <aside rtElem=\"thread-column\" qa-dataid=\"ai-chat-thread-column\" [attr.aria-label]=\"t().aiThreads\">\n <div rtElem=\"column-head\">\n <span rtElem=\"column-title\">{{ t().aiThreads }}</span>\n <ng-container [ngTemplateOutlet]=\"newThreadButton\" />\n </div>\n <ng-container [ngTemplateOutlet]=\"threadList\" />\n </aside>\n }\n\n <section rtElem=\"conversation\" qa-dataid=\"ai-chat\" [attr.aria-label]=\"titleText()\">\n <header rtElem=\"header\" [attr.data-rt-icon-preset]=\"headerIconSign()\">\n @if (isThreadPage()) {\n <rt-icon-button\n #back\n qa-dataid=\"ai-chat-back\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"arrow-left\"\n [ariaLabel]=\"t().aiBackToChat\"\n [tooltip]=\"t().aiBackToChat\"\n (clicked)=\"onToggleThreads()\" />\n }\n\n <div rtElem=\"heading\">\n <span rtElem=\"title\" qa-dataid=\"ai-chat-title\">\n @if (!isThreadPage()) {\n <rt-icon name=\"sparkle\" size=\"sm\" color=\"primary\" aria-hidden=\"true\" />\n }\n {{ isThreadPage() ? t().aiThreads : titleText() }}\n </span>\n @if (!isThreadPage() && subtitle()) {\n <span rtElem=\"subtitle\" qa-dataid=\"ai-chat-subtitle\">{{ subtitle() }}</span>\n }\n </div>\n\n <div rtElem=\"actions\">\n @if (fullScreenable()) {\n <rt-icon-button\n qa-dataid=\"ai-chat-full-screen\"\n size=\"sm\"\n iconSize=\"sm\"\n [icon]=\"fullScreen() ? 'window-minimize' : 'fullscreen'\"\n [active]=\"fullScreen()\"\n [ariaLabel]=\"fullScreen() ? t().aiExitFullScreen : t().aiFullScreen\"\n [tooltip]=\"fullScreen() ? t().aiExitFullScreen : t().aiFullScreen\"\n (clicked)=\"onToggleFullScreen()\" />\n }\n @if (hasThreads() && !isThreadPage() && !isThreadColumn()) {\n <rt-icon-button\n qa-dataid=\"ai-chat-threads\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"history\"\n [ariaLabel]=\"t().aiThreads\"\n [tooltip]=\"t().aiThreads\"\n (clicked)=\"onToggleThreads()\" />\n }\n @if (!isThreadColumn()) {\n <ng-container [ngTemplateOutlet]=\"newThreadButton\" />\n }\n @if (closable()) {\n <rt-icon-button\n qa-dataid=\"ai-chat-close\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"close\"\n [ariaLabel]=\"t().aiClose\"\n [tooltip]=\"t().aiClose\"\n (clicked)=\"closed.emit()\" />\n }\n </div>\n </header>\n\n @if (isThreadPage()) {\n <ng-container [ngTemplateOutlet]=\"threadList\" />\n } @else {\n <div #feed rtElem=\"feed\" qa-dataid=\"ai-chat-feed\" aria-live=\"polite\" (scroll)=\"onFeedScroll()\">\n @if (loading() && !messages().length) {\n <rt-spinner rtElem=\"spinner\" appearance=\"arc\" [diameter]=\"32\" />\n } @else if (isEmpty()) {\n <div rtElem=\"empty\" qa-dataid=\"ai-chat-empty\">\n <rt-empty-state icon=\"comments\" [title]=\"emptyTitleText()\" [description]=\"emptyDescriptionText()\" />\n @if (suggestions().length) {\n <div rtElem=\"suggestions\">\n @for (suggestion of suggestions(); track suggestion) {\n <rt-prompt-suggestion\n qa-dataid=\"ai-chat-suggestion\"\n [label]=\"suggestion\"\n [disabled]=\"sending()\"\n (picked)=\"onSuggestion($event)\" />\n }\n </div>\n }\n </div>\n }\n\n @for (message of messages(); track message.id) {\n @if (message.role === 'user') {\n <div rtElem=\"question\" qa-dataid=\"ai-chat-question\">\n <div rtElem=\"bubble\">\n <span rtElem=\"author\">{{ t().aiYou }}</span>\n <p rtElem=\"bubble-text\">{{ message.text }}</p>\n @if (message.time) {\n <span rtElem=\"time\">{{ message.time }}</span>\n }\n </div>\n @if (copyable() && message.text) {\n <div rtElem=\"question-actions\" qa-dataid=\"ai-chat-question-actions\">\n <rt-ai-chat-copy [text]=\"message.text\" />\n </div>\n }\n </div>\n } @else {\n <rt-ai-chat-answer\n qa-dataid=\"ai-chat-answer\"\n [message]=\"message\"\n [copyable]=\"copyable()\"\n [extra]=\"extraTemplate()?.templateRef ?? null\"\n [expanded]=\"openRuns().has(message.id)\"\n (expandedChange)=\"onToggleRun(message.id, $event)\"\n (feedbackChange)=\"onFeedback(message, $event)\" />\n }\n }\n\n @if (error(); as runError) {\n <div rtElem=\"error\" qa-dataid=\"ai-chat-error\" role=\"alert\">\n <rt-message severity=\"danger\">{{ runError.message }}</rt-message>\n @if (runError.referenceId) {\n <rt-copy-value [label]=\"t().aiReference\" [value]=\"runError.referenceId\" [copyLabel]=\"t().aiCopyReference\" />\n }\n @if (runError.retryable) {\n <button\n rtButton\n type=\"button\"\n qa-dataid=\"ai-chat-retry\"\n appearance=\"text\"\n icon=\"sync\"\n size=\"sm\"\n [label]=\"t().aiRetry\"\n [attr.aria-label]=\"t().aiRetry\"\n [disabled]=\"sending()\"\n (click)=\"retry.emit()\"></button>\n }\n </div>\n }\n </div>\n\n <rt-message-composer\n rtElem=\"composer\"\n qa-dataid=\"ai-chat-composer\"\n stoppable\n [placeholder]=\"placeholder()\"\n [sending]=\"sending()\"\n [(text)]=\"draft\"\n (submitted)=\"onSubmitted($event)\"\n (stopped)=\"onStop()\" />\n\n @if (disclaimerText()) {\n <p rtElem=\"disclaimer\" qa-dataid=\"ai-chat-disclaimer\">{{ disclaimerText() }}</p>\n }\n }\n </section>\n</ng-container>\n\n<ng-template #newThreadButton>\n <rt-icon-button\n qa-dataid=\"ai-chat-new-thread\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"ico-plus\"\n [disabled]=\"sending()\"\n [ariaLabel]=\"t().aiNewThread\"\n [tooltip]=\"t().aiNewThread\"\n (clicked)=\"onNewThread()\" />\n</ng-template>\n\n<ng-template #threadList>\n <ng-container rtBlock=\"rt-ai-chat\">\n <rt-thread-list\n rtElem=\"threads\"\n qa-dataid=\"ai-chat-thread-list\"\n [rows]=\"threadRows()\"\n [activeId]=\"activeThreadId()\"\n [searchPlaceholder]=\"t().aiSearchThreads\"\n [emptyText]=\"threadsEmptyText()\"\n [emptyPreviewIcons]=\"emptyPreviewIcons()\"\n [loading]=\"threadsLoading()\"\n [fetching]=\"threadsFetching()\"\n [hasMore]=\"threadsHasMore()\"\n (selectRow)=\"onSelectThread($event)\"\n (searchChange)=\"onSearchThreads($event)\"\n (loadMore)=\"loadMoreThreads.emit()\">\n <ng-template let-row [rtThreadListRow]=\"threadRows()\">\n <span rtElem=\"thread-title\" qa-dataid=\"ai-chat-thread-title\" [attr.title]=\"row.title\">\n @for (part of row.titleParts; track $index) {\n <span rtElem=\"thread-part\" [rtMod]=\"{ match: part.matched }\">{{ part.text }}</span>\n }\n </span>\n <span rtElem=\"thread-meta\">\n @if (row.unreadCount) {\n <span rtElem=\"thread-unread\" qa-dataid=\"ai-chat-thread-unread\">{{ row.unreadCount }}</span>\n }\n @if (row.time) {\n <span rtElem=\"thread-time\">{{ row.time }}</span>\n }\n </span>\n </ng-template>\n <ng-template let-row [rtThreadListRowActions]=\"threadRows()\">\n @if (threadMenu()) {\n <rt-menu qa-dataid=\"ai-chat-thread-menu\" icon=\"ellipsis-v\" triggerSize=\"xs\" size=\"sm\" [ariaLabel]=\"t().uiMoreActions\">\n <rt-menu-item\n qa-dataid=\"ai-chat-thread-copy-id\"\n icon=\"copy\"\n [label]=\"t().aiCopyThreadId\"\n (selected)=\"onCopyThreadId(row.id)\" />\n <rt-menu-item\n qa-dataid=\"ai-chat-thread-delete\"\n icon=\"trash\"\n danger\n [label]=\"t().uiRemove\"\n [disabled]=\"sending() && row.id === activeThreadId()\"\n (selected)=\"deleteThread.emit(row.id)\" />\n </rt-menu>\n } @else {\n <rt-icon-button\n qa-dataid=\"ai-chat-delete-thread\"\n size=\"xs\"\n iconSize=\"sm\"\n icon=\"trash\"\n [disabled]=\"sending() && row.id === activeThreadId()\"\n [ariaLabel]=\"t().aiDeleteThread\"\n [tooltip]=\"t().aiDeleteThread\"\n (clicked)=\"deleteThread.emit(row.id)\" />\n }\n </ng-template>\n </rt-thread-list>\n </ng-container>\n</ng-template>\n",
2870
- styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-ai-chat{--rt-ai-chat-bubble-radius: var(--rt-radius-xl);--rt-ai-chat-column-border-width: var(--rt-border-width-thin);--rt-ai-chat-column-width: 280px;--rt-ai-chat-content-max-width: 100%;--rt-ai-chat-match-bg: var(--rt-yellow-400);--rt-ai-chat-match-color: var(--rt-neutral-950);--rt-ai-chat-match-radius: var(--rt-radius-xs);--rt-ai-chat-unread-radius: var(--rt-radius-full);display:flex;overflow:hidden;background:var(--rt-color-bg-surface);block-size:100%;color:var(--rt-color-text-primary);min-block-size:0}.rt-ai-chat__thread-column{display:flex;flex:none;flex-direction:column;border-inline-end:var(--rt-ai-chat-column-border-width) solid var(--rt-color-border-default);inline-size:var(--rt-ai-chat-column-width)}.rt-ai-chat__column-head{display:flex;align-items:center;justify-content:space-between;padding:var(--rt-space-sm) var(--rt-space-md);gap:var(--rt-space-xs)}.rt-ai-chat__column-title{font-size:var(--rt-text-md);font-weight:var(--rt-font-weight-semibold)}.rt-ai-chat__conversation{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:0;min-inline-size:0}.rt-ai-chat__header{display:flex;flex:none;align-items:center;padding:var(--rt-space-sm) var(--rt-space-md);gap:var(--rt-space-xs)}.rt-ai-chat__heading{display:flex;flex:1 1 auto;flex-direction:column;min-inline-size:0}.rt-ai-chat__title{display:inline-flex;align-items:center;font-size:var(--rt-text-md);font-weight:var(--rt-font-weight-semibold);gap:var(--rt-space-xs);line-height:var(--rt-leading-snug)}.rt-ai-chat__subtitle{overflow:hidden;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug);text-overflow:ellipsis;white-space:nowrap}.rt-ai-chat__actions{display:flex;flex:none;align-items:center;gap:var(--rt-space-xs)}.rt-ai-chat__feed{display:flex;flex:1 1 auto;flex-direction:column;font-size:var(--rt-text-sm);gap:var(--rt-space-md);min-block-size:0;overflow-y:auto;padding-block:var(--rt-space-md);padding-inline:max(var(--rt-space-md),(100% - var(--rt-ai-chat-content-max-width)) / 2)}.rt-ai-chat__spinner{align-self:center;margin:auto}.rt-ai-chat__empty{display:flex;flex-direction:column;justify-content:center;gap:var(--rt-space-lg);margin-block:auto}.rt-ai-chat__suggestions{display:flex;flex-direction:column;gap:var(--rt-space-sm)}.rt-ai-chat__question{display:flex;flex-direction:column;align-items:flex-end;gap:var(--rt-space-2xs)}.rt-ai-chat__question-actions{display:flex;gap:var(--rt-space-xs)}.rt-ai-chat__bubble{display:flex;flex-direction:column;padding:var(--rt-space-sm) var(--rt-space-md);border-radius:var(--rt-ai-chat-bubble-radius);background:var(--rt-color-bg-subtle);gap:var(--rt-space-2xs);max-inline-size:80%}.rt-ai-chat__author,.rt-ai-chat__time{color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug)}.rt-ai-chat__author{font-weight:var(--rt-font-weight-semibold)}.rt-ai-chat__bubble-text{margin:0;line-height:var(--rt-leading-normal);overflow-wrap:anywhere;white-space:pre-wrap}.rt-ai-chat__error{display:flex;flex-direction:column;align-items:flex-start;gap:var(--rt-space-sm)}.rt-ai-chat__error rt-message{align-self:stretch}.rt-ai-chat__composer{box-sizing:border-box;flex:none;padding-block:var(--rt-space-sm) 0;padding-inline:max(var(--rt-space-md),(100% - var(--rt-ai-chat-content-max-width)) / 2)}.rt-ai-chat__disclaimer{flex:none;margin:0;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug);padding-block:var(--rt-space-xs) var(--rt-space-sm);padding-inline:max(var(--rt-space-md),(100% - var(--rt-ai-chat-content-max-width)) / 2);text-align:center}.rt-ai-chat__threads{flex:1 1 auto;min-block-size:0}.rt-ai-chat__thread-title{overflow:hidden;min-inline-size:0;text-overflow:ellipsis;white-space:nowrap}.rt-ai-chat__thread-part--match{border-radius:var(--rt-ai-chat-match-radius);background:var(--rt-ai-chat-match-bg);color:var(--rt-ai-chat-match-color)}.rt-ai-chat__thread-meta{display:flex;flex:none;align-items:center;gap:var(--rt-space-xs)}.rt-ai-chat__thread-unread{border-radius:var(--rt-ai-chat-unread-radius);background:var(--rt-color-action-primary);color:var(--rt-color-text-inverse);font-size:var(--rt-text-xs);font-weight:var(--rt-font-weight-semibold);line-height:18px;padding-inline:6px}.rt-ai-chat__thread-time{color:var(--rt-color-text-muted);font-size:var(--rt-text-xs)}}\n"],
2920
+ template: "<ng-container rtBlock=\"rt-ai-chat\">\n @if (isThreadColumn()) {\n <aside rtElem=\"thread-column\" qa-dataid=\"ai-chat-thread-column\" [attr.aria-label]=\"t().aiThreads\">\n <div rtElem=\"column-head\">\n <span rtElem=\"column-title\">{{ t().aiThreads }}</span>\n <ng-container [ngTemplateOutlet]=\"newThreadButton\" />\n </div>\n <ng-container [ngTemplateOutlet]=\"threadList\" />\n </aside>\n }\n\n <section rtElem=\"conversation\" qa-dataid=\"ai-chat\" [attr.aria-label]=\"titleText()\">\n <header rtElem=\"header\" [attr.data-rt-icon-preset]=\"headerIconSign()\">\n @if (isThreadPage()) {\n <rt-icon-button\n #back\n qa-dataid=\"ai-chat-back\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"arrow-left\"\n [ariaLabel]=\"t().aiBackToChat\"\n [tooltip]=\"t().aiBackToChat\"\n (clicked)=\"onToggleThreads()\" />\n }\n\n <div rtElem=\"heading\">\n <span rtElem=\"title\" qa-dataid=\"ai-chat-title\">\n @if (!isThreadPage()) {\n <rt-icon name=\"sparkle\" size=\"sm\" color=\"primary\" aria-hidden=\"true\" />\n }\n {{ isThreadPage() ? t().aiThreads : titleText() }}\n </span>\n @if (!isThreadPage() && subtitle()) {\n <span rtElem=\"subtitle\" qa-dataid=\"ai-chat-subtitle\">{{ subtitle() }}</span>\n }\n </div>\n\n <div rtElem=\"actions\">\n @if (fullScreenable()) {\n <rt-icon-button\n qa-dataid=\"ai-chat-full-screen\"\n size=\"sm\"\n iconSize=\"sm\"\n [icon]=\"fullScreen() ? 'window-minimize' : 'fullscreen'\"\n [active]=\"fullScreen()\"\n [ariaLabel]=\"fullScreen() ? t().aiExitFullScreen : t().aiFullScreen\"\n [tooltip]=\"fullScreen() ? t().aiExitFullScreen : t().aiFullScreen\"\n (clicked)=\"onToggleFullScreen()\" />\n }\n @if (hasThreads() && !isThreadPage() && !isThreadColumn()) {\n <rt-icon-button\n qa-dataid=\"ai-chat-threads\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"history\"\n [ariaLabel]=\"t().aiThreads\"\n [tooltip]=\"t().aiThreads\"\n (clicked)=\"onToggleThreads()\" />\n }\n @if (!isThreadColumn()) {\n <ng-container [ngTemplateOutlet]=\"newThreadButton\" />\n }\n @if (closable()) {\n <rt-icon-button\n qa-dataid=\"ai-chat-close\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"close\"\n [ariaLabel]=\"t().aiClose\"\n [tooltip]=\"t().aiClose\"\n (clicked)=\"closed.emit()\" />\n }\n </div>\n </header>\n\n @if (isThreadPage()) {\n <ng-container [ngTemplateOutlet]=\"threadList\" />\n } @else {\n <div #feed rtElem=\"feed\" qa-dataid=\"ai-chat-feed\" aria-live=\"polite\" (scroll)=\"onFeedScroll()\">\n @if (loading() && !messages().length) {\n <rt-spinner rtElem=\"spinner\" appearance=\"arc\" [diameter]=\"32\" />\n } @else if (isEmpty()) {\n <div rtElem=\"empty\" qa-dataid=\"ai-chat-empty\">\n <rt-empty-state icon=\"comments\" [title]=\"emptyTitleText()\" [description]=\"emptyDescriptionText()\" />\n @if (suggestions().length) {\n <div rtElem=\"suggestions\">\n @for (suggestion of suggestions(); track suggestion) {\n <rt-prompt-suggestion\n qa-dataid=\"ai-chat-suggestion\"\n [label]=\"suggestion\"\n [disabled]=\"sending()\"\n (picked)=\"onSuggestion($event)\" />\n }\n </div>\n }\n </div>\n }\n\n @for (message of messages(); track message.id) {\n @if (message.role === 'user') {\n <div rtElem=\"question\" qa-dataid=\"ai-chat-question\">\n <div rtElem=\"bubble\">\n <span rtElem=\"author\">{{ t().aiYou }}</span>\n <p rtElem=\"bubble-text\">{{ message.text }}</p>\n @if (message.time) {\n <span rtElem=\"time\">{{ message.time }}</span>\n }\n </div>\n @if (copyable() && message.text) {\n <div rtElem=\"question-actions\" qa-dataid=\"ai-chat-question-actions\">\n <rt-ai-chat-copy [text]=\"message.text\" />\n </div>\n }\n </div>\n } @else {\n <rt-ai-chat-answer\n qa-dataid=\"ai-chat-answer\"\n [message]=\"message\"\n [copyable]=\"copyable()\"\n [extra]=\"extraTemplate()?.templateRef ?? null\"\n [expanded]=\"openRuns().has(message.id)\"\n (expandedChange)=\"onToggleRun(message.id, $event)\"\n (feedbackChange)=\"onFeedback(message, $event)\" />\n }\n }\n\n @if (error(); as runError) {\n <div rtElem=\"error\" qa-dataid=\"ai-chat-error\" role=\"alert\">\n <rt-message severity=\"danger\">{{ runError.message }}</rt-message>\n @if (runError.referenceId) {\n <rt-copy-value [label]=\"t().aiReference\" [value]=\"runError.referenceId\" [copyLabel]=\"t().aiCopyReference\" />\n }\n @if (runError.retryable) {\n <button\n rtButton\n type=\"button\"\n qa-dataid=\"ai-chat-retry\"\n appearance=\"text\"\n icon=\"sync\"\n size=\"sm\"\n [label]=\"t().aiRetry\"\n [attr.aria-label]=\"t().aiRetry\"\n [disabled]=\"sending()\"\n (click)=\"retry.emit()\"></button>\n }\n </div>\n }\n </div>\n\n @if (disclaimerText() && disclaimerAbove()) {\n <p rtElem=\"disclaimer\" qa-dataid=\"ai-chat-disclaimer\" [rtMod]=\"{ above: true }\">{{ disclaimerText() }}</p>\n }\n\n <rt-ai-prompt-input\n rtElem=\"composer\"\n qa-dataid=\"ai-chat-composer\"\n stoppable\n hint=\"\"\n [placeholder]=\"placeholder()\"\n [model]=\"model()\"\n [effort]=\"effort()\"\n [mode]=\"mode()\"\n [usage]=\"usage()\"\n [usageHint]=\"usageHint()\"\n [sending]=\"sending()\"\n [(text)]=\"draft\"\n (submitted)=\"onSubmitted($event)\"\n (stopped)=\"onStop()\"\n (controlPicked)=\"controlPicked.emit($event)\" />\n\n @if (disclaimerText() && !disclaimerAbove()) {\n <p rtElem=\"disclaimer\" qa-dataid=\"ai-chat-disclaimer\">{{ disclaimerText() }}</p>\n }\n }\n </section>\n</ng-container>\n\n<ng-template #newThreadButton>\n <rt-icon-button\n qa-dataid=\"ai-chat-new-thread\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"ico-plus\"\n [disabled]=\"sending()\"\n [ariaLabel]=\"t().aiNewThread\"\n [tooltip]=\"t().aiNewThread\"\n (clicked)=\"onNewThread()\" />\n</ng-template>\n\n<ng-template #threadList>\n <ng-container rtBlock=\"rt-ai-chat\">\n <rt-thread-list\n rtElem=\"threads\"\n qa-dataid=\"ai-chat-thread-list\"\n [rows]=\"threadRows()\"\n [activeId]=\"activeThreadId()\"\n [searchPlaceholder]=\"t().aiSearchThreads\"\n [emptyText]=\"threadsEmptyText()\"\n [emptyPreviewIcons]=\"emptyPreviewIcons()\"\n [loading]=\"threadsLoading()\"\n [fetching]=\"threadsFetching()\"\n [hasMore]=\"threadsHasMore()\"\n (selectRow)=\"onSelectThread($event)\"\n (searchChange)=\"onSearchThreads($event)\"\n (loadMore)=\"loadMoreThreads.emit()\">\n <ng-template let-row [rtThreadListRow]=\"threadRows()\">\n <span rtElem=\"thread-title\" qa-dataid=\"ai-chat-thread-title\" [attr.title]=\"row.title\">\n @for (part of row.titleParts; track $index) {\n <span rtElem=\"thread-part\" [rtMod]=\"{ match: part.matched }\">{{ part.text }}</span>\n }\n </span>\n <span rtElem=\"thread-meta\">\n @if (row.unreadCount) {\n <span rtElem=\"thread-unread\" qa-dataid=\"ai-chat-thread-unread\">{{ row.unreadCount }}</span>\n }\n @if (row.time) {\n <span rtElem=\"thread-time\">{{ row.time }}</span>\n }\n </span>\n </ng-template>\n <ng-template let-row [rtThreadListRowActions]=\"threadRows()\">\n @if (threadMenu()) {\n <rt-menu qa-dataid=\"ai-chat-thread-menu\" icon=\"ellipsis-v\" triggerSize=\"xs\" size=\"sm\" [ariaLabel]=\"t().uiMoreActions\">\n <rt-menu-item\n qa-dataid=\"ai-chat-thread-copy-id\"\n icon=\"copy\"\n [label]=\"t().aiCopyThreadId\"\n (selected)=\"onCopyThreadId(row.id)\" />\n <rt-menu-item\n qa-dataid=\"ai-chat-thread-delete\"\n icon=\"trash\"\n danger\n [label]=\"t().uiRemove\"\n [disabled]=\"sending() && row.id === activeThreadId()\"\n (selected)=\"deleteThread.emit(row.id)\" />\n </rt-menu>\n } @else {\n <rt-icon-button\n qa-dataid=\"ai-chat-delete-thread\"\n size=\"xs\"\n iconSize=\"sm\"\n icon=\"trash\"\n [disabled]=\"sending() && row.id === activeThreadId()\"\n [ariaLabel]=\"t().aiDeleteThread\"\n [tooltip]=\"t().aiDeleteThread\"\n (clicked)=\"deleteThread.emit(row.id)\" />\n }\n </ng-template>\n </rt-thread-list>\n </ng-container>\n</ng-template>\n",
2921
+ styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-ai-chat{--rt-ai-chat-bubble-radius: var(--rt-radius-xl);--rt-ai-chat-column-border-width: var(--rt-border-width-thin);--rt-ai-chat-column-width: 280px;--rt-ai-chat-content-max-width: 100%;--rt-ai-chat-match-bg: var(--rt-yellow-400);--rt-ai-chat-match-color: var(--rt-neutral-950);--rt-ai-chat-match-radius: var(--rt-radius-xs);--rt-ai-chat-unread-radius: var(--rt-radius-full);display:flex;overflow:hidden;background:var(--rt-color-bg-surface);block-size:100%;color:var(--rt-color-text-primary);min-block-size:0}.rt-ai-chat__thread-column{display:flex;flex:none;flex-direction:column;border-inline-end:var(--rt-ai-chat-column-border-width) solid var(--rt-color-border-default);inline-size:var(--rt-ai-chat-column-width)}.rt-ai-chat__column-head{display:flex;align-items:center;justify-content:space-between;padding:var(--rt-space-sm) var(--rt-space-md);gap:var(--rt-space-xs)}.rt-ai-chat__column-title{font-size:var(--rt-text-md);font-weight:var(--rt-font-weight-semibold)}.rt-ai-chat__conversation{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:0;min-inline-size:0}.rt-ai-chat__header{display:flex;flex:none;align-items:center;padding:var(--rt-space-sm) var(--rt-space-md);gap:var(--rt-space-xs)}.rt-ai-chat__heading{display:flex;flex:1 1 auto;flex-direction:column;min-inline-size:0}.rt-ai-chat__title{display:inline-flex;align-items:center;font-size:var(--rt-text-md);font-weight:var(--rt-font-weight-semibold);gap:var(--rt-space-xs);line-height:var(--rt-leading-snug)}.rt-ai-chat__subtitle{overflow:hidden;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug);text-overflow:ellipsis;white-space:nowrap}.rt-ai-chat__actions{display:flex;flex:none;align-items:center;gap:var(--rt-space-xs)}.rt-ai-chat__feed{display:flex;flex:1 1 auto;flex-direction:column;font-size:var(--rt-text-sm);gap:var(--rt-space-md);min-block-size:0;overflow-y:auto;overscroll-behavior:contain;padding-block:var(--rt-space-md);padding-inline:max(var(--rt-space-md),(100% - var(--rt-ai-chat-content-max-width)) / 2)}.rt-ai-chat__spinner{align-self:center;margin:auto}.rt-ai-chat__empty{display:flex;flex-direction:column;justify-content:center;gap:var(--rt-space-lg);margin-block:auto}.rt-ai-chat__suggestions{display:flex;flex-direction:column;gap:var(--rt-space-sm)}.rt-ai-chat__question{display:flex;flex-direction:column;align-items:flex-end;gap:var(--rt-space-2xs)}.rt-ai-chat__question-actions{display:flex;gap:var(--rt-space-xs)}.rt-ai-chat__bubble{display:flex;flex-direction:column;padding:var(--rt-space-sm) var(--rt-space-md);border-radius:var(--rt-ai-chat-bubble-radius);background:var(--rt-color-bg-subtle);gap:var(--rt-space-2xs);max-inline-size:80%}.rt-ai-chat__author,.rt-ai-chat__time{color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug)}.rt-ai-chat__author{font-weight:var(--rt-font-weight-semibold)}.rt-ai-chat__bubble-text{margin:0;line-height:var(--rt-leading-normal);overflow-wrap:anywhere;white-space:pre-wrap}.rt-ai-chat__error{display:flex;flex-direction:column;align-items:flex-start;gap:var(--rt-space-sm)}.rt-ai-chat__error rt-message{align-self:stretch}.rt-ai-chat__composer{box-sizing:border-box;flex:none;padding-block:var(--rt-space-sm) 0;padding-inline:max(var(--rt-space-md),(100% - var(--rt-ai-chat-content-max-width)) / 2)}.rt-ai-chat__disclaimer{flex:none;margin:0;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug);padding-block:var(--rt-space-xs) var(--rt-space-sm);padding-inline:max(var(--rt-space-md),(100% - var(--rt-ai-chat-content-max-width)) / 2);text-align:center}.rt-ai-chat__disclaimer--above{padding-block:var(--rt-space-sm) 0}.rt-ai-chat__threads{flex:1 1 auto;min-block-size:0}.rt-ai-chat__thread-title{overflow:hidden;min-inline-size:0;text-overflow:ellipsis;white-space:nowrap}.rt-ai-chat__thread-part--match{border-radius:var(--rt-ai-chat-match-radius);background:var(--rt-ai-chat-match-bg);color:var(--rt-ai-chat-match-color)}.rt-ai-chat__thread-meta{display:flex;flex:none;align-items:center;gap:var(--rt-space-xs)}.rt-ai-chat__thread-unread{border-radius:var(--rt-ai-chat-unread-radius);background:var(--rt-color-action-primary);color:var(--rt-color-text-inverse);font-size:var(--rt-text-xs);font-weight:var(--rt-font-weight-semibold);line-height:18px;padding-inline:6px}.rt-ai-chat__thread-time{color:var(--rt-color-text-muted);font-size:var(--rt-text-xs)}}\n"],
2871
2922
  dependencies: [
2872
2923
  {
2873
2924
  kind: "directive",
@@ -3048,27 +3099,32 @@ var RtAiChatComponent = class RtAiChatComponent {
3048
3099
  },
3049
3100
  {
3050
3101
  kind: "component",
3051
- type: RtMessageComposerComponent,
3052
- selector: "rt-message-composer",
3102
+ type: RtAiPromptInputComponent,
3103
+ selector: "rt-ai-prompt-input",
3053
3104
  inputs: [
3054
3105
  "placeholder",
3055
- "accept",
3056
3106
  "hint",
3107
+ "hintPosition",
3057
3108
  "attachments",
3109
+ "accept",
3110
+ "model",
3111
+ "effort",
3112
+ "mode",
3113
+ "usage",
3114
+ "usageHint",
3115
+ "usageWarnAt",
3058
3116
  "sending",
3059
3117
  "stoppable",
3060
3118
  "disabled",
3061
- "formatting",
3062
- "toolbar",
3063
3119
  "minRows",
3064
3120
  "maxRows",
3065
- "droppedFiles",
3066
3121
  "text"
3067
3122
  ],
3068
3123
  outputs: [
3069
- "submitted",
3070
3124
  "textChange",
3071
- "stopped"
3125
+ "submitted",
3126
+ "stopped",
3127
+ "controlPicked"
3072
3128
  ]
3073
3129
  },
3074
3130
  {
@@ -3157,7 +3213,7 @@ i0.ɵɵngDeclareClassMetadata({
3157
3213
  RtMenuComponent,
3158
3214
  RtMenuItemComponent,
3159
3215
  RtMessageComponent,
3160
- RtMessageComposerComponent,
3216
+ RtAiPromptInputComponent,
3161
3217
  RtPromptSuggestionComponent,
3162
3218
  RtSpinnerComponent,
3163
3219
  RtThreadListComponent,
@@ -3165,15 +3221,15 @@ i0.ɵɵngDeclareClassMetadata({
3165
3221
  RtThreadListRowDirective
3166
3222
  ],
3167
3223
  host: { class: BEM_BLOCK },
3168
- template: "<ng-container rtBlock=\"rt-ai-chat\">\n @if (isThreadColumn()) {\n <aside rtElem=\"thread-column\" qa-dataid=\"ai-chat-thread-column\" [attr.aria-label]=\"t().aiThreads\">\n <div rtElem=\"column-head\">\n <span rtElem=\"column-title\">{{ t().aiThreads }}</span>\n <ng-container [ngTemplateOutlet]=\"newThreadButton\" />\n </div>\n <ng-container [ngTemplateOutlet]=\"threadList\" />\n </aside>\n }\n\n <section rtElem=\"conversation\" qa-dataid=\"ai-chat\" [attr.aria-label]=\"titleText()\">\n <header rtElem=\"header\" [attr.data-rt-icon-preset]=\"headerIconSign()\">\n @if (isThreadPage()) {\n <rt-icon-button\n #back\n qa-dataid=\"ai-chat-back\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"arrow-left\"\n [ariaLabel]=\"t().aiBackToChat\"\n [tooltip]=\"t().aiBackToChat\"\n (clicked)=\"onToggleThreads()\" />\n }\n\n <div rtElem=\"heading\">\n <span rtElem=\"title\" qa-dataid=\"ai-chat-title\">\n @if (!isThreadPage()) {\n <rt-icon name=\"sparkle\" size=\"sm\" color=\"primary\" aria-hidden=\"true\" />\n }\n {{ isThreadPage() ? t().aiThreads : titleText() }}\n </span>\n @if (!isThreadPage() && subtitle()) {\n <span rtElem=\"subtitle\" qa-dataid=\"ai-chat-subtitle\">{{ subtitle() }}</span>\n }\n </div>\n\n <div rtElem=\"actions\">\n @if (fullScreenable()) {\n <rt-icon-button\n qa-dataid=\"ai-chat-full-screen\"\n size=\"sm\"\n iconSize=\"sm\"\n [icon]=\"fullScreen() ? 'window-minimize' : 'fullscreen'\"\n [active]=\"fullScreen()\"\n [ariaLabel]=\"fullScreen() ? t().aiExitFullScreen : t().aiFullScreen\"\n [tooltip]=\"fullScreen() ? t().aiExitFullScreen : t().aiFullScreen\"\n (clicked)=\"onToggleFullScreen()\" />\n }\n @if (hasThreads() && !isThreadPage() && !isThreadColumn()) {\n <rt-icon-button\n qa-dataid=\"ai-chat-threads\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"history\"\n [ariaLabel]=\"t().aiThreads\"\n [tooltip]=\"t().aiThreads\"\n (clicked)=\"onToggleThreads()\" />\n }\n @if (!isThreadColumn()) {\n <ng-container [ngTemplateOutlet]=\"newThreadButton\" />\n }\n @if (closable()) {\n <rt-icon-button\n qa-dataid=\"ai-chat-close\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"close\"\n [ariaLabel]=\"t().aiClose\"\n [tooltip]=\"t().aiClose\"\n (clicked)=\"closed.emit()\" />\n }\n </div>\n </header>\n\n @if (isThreadPage()) {\n <ng-container [ngTemplateOutlet]=\"threadList\" />\n } @else {\n <div #feed rtElem=\"feed\" qa-dataid=\"ai-chat-feed\" aria-live=\"polite\" (scroll)=\"onFeedScroll()\">\n @if (loading() && !messages().length) {\n <rt-spinner rtElem=\"spinner\" appearance=\"arc\" [diameter]=\"32\" />\n } @else if (isEmpty()) {\n <div rtElem=\"empty\" qa-dataid=\"ai-chat-empty\">\n <rt-empty-state icon=\"comments\" [title]=\"emptyTitleText()\" [description]=\"emptyDescriptionText()\" />\n @if (suggestions().length) {\n <div rtElem=\"suggestions\">\n @for (suggestion of suggestions(); track suggestion) {\n <rt-prompt-suggestion\n qa-dataid=\"ai-chat-suggestion\"\n [label]=\"suggestion\"\n [disabled]=\"sending()\"\n (picked)=\"onSuggestion($event)\" />\n }\n </div>\n }\n </div>\n }\n\n @for (message of messages(); track message.id) {\n @if (message.role === 'user') {\n <div rtElem=\"question\" qa-dataid=\"ai-chat-question\">\n <div rtElem=\"bubble\">\n <span rtElem=\"author\">{{ t().aiYou }}</span>\n <p rtElem=\"bubble-text\">{{ message.text }}</p>\n @if (message.time) {\n <span rtElem=\"time\">{{ message.time }}</span>\n }\n </div>\n @if (copyable() && message.text) {\n <div rtElem=\"question-actions\" qa-dataid=\"ai-chat-question-actions\">\n <rt-ai-chat-copy [text]=\"message.text\" />\n </div>\n }\n </div>\n } @else {\n <rt-ai-chat-answer\n qa-dataid=\"ai-chat-answer\"\n [message]=\"message\"\n [copyable]=\"copyable()\"\n [extra]=\"extraTemplate()?.templateRef ?? null\"\n [expanded]=\"openRuns().has(message.id)\"\n (expandedChange)=\"onToggleRun(message.id, $event)\"\n (feedbackChange)=\"onFeedback(message, $event)\" />\n }\n }\n\n @if (error(); as runError) {\n <div rtElem=\"error\" qa-dataid=\"ai-chat-error\" role=\"alert\">\n <rt-message severity=\"danger\">{{ runError.message }}</rt-message>\n @if (runError.referenceId) {\n <rt-copy-value [label]=\"t().aiReference\" [value]=\"runError.referenceId\" [copyLabel]=\"t().aiCopyReference\" />\n }\n @if (runError.retryable) {\n <button\n rtButton\n type=\"button\"\n qa-dataid=\"ai-chat-retry\"\n appearance=\"text\"\n icon=\"sync\"\n size=\"sm\"\n [label]=\"t().aiRetry\"\n [attr.aria-label]=\"t().aiRetry\"\n [disabled]=\"sending()\"\n (click)=\"retry.emit()\"></button>\n }\n </div>\n }\n </div>\n\n <rt-message-composer\n rtElem=\"composer\"\n qa-dataid=\"ai-chat-composer\"\n stoppable\n [placeholder]=\"placeholder()\"\n [sending]=\"sending()\"\n [(text)]=\"draft\"\n (submitted)=\"onSubmitted($event)\"\n (stopped)=\"onStop()\" />\n\n @if (disclaimerText()) {\n <p rtElem=\"disclaimer\" qa-dataid=\"ai-chat-disclaimer\">{{ disclaimerText() }}</p>\n }\n }\n </section>\n</ng-container>\n\n<ng-template #newThreadButton>\n <rt-icon-button\n qa-dataid=\"ai-chat-new-thread\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"ico-plus\"\n [disabled]=\"sending()\"\n [ariaLabel]=\"t().aiNewThread\"\n [tooltip]=\"t().aiNewThread\"\n (clicked)=\"onNewThread()\" />\n</ng-template>\n\n<ng-template #threadList>\n <ng-container rtBlock=\"rt-ai-chat\">\n <rt-thread-list\n rtElem=\"threads\"\n qa-dataid=\"ai-chat-thread-list\"\n [rows]=\"threadRows()\"\n [activeId]=\"activeThreadId()\"\n [searchPlaceholder]=\"t().aiSearchThreads\"\n [emptyText]=\"threadsEmptyText()\"\n [emptyPreviewIcons]=\"emptyPreviewIcons()\"\n [loading]=\"threadsLoading()\"\n [fetching]=\"threadsFetching()\"\n [hasMore]=\"threadsHasMore()\"\n (selectRow)=\"onSelectThread($event)\"\n (searchChange)=\"onSearchThreads($event)\"\n (loadMore)=\"loadMoreThreads.emit()\">\n <ng-template let-row [rtThreadListRow]=\"threadRows()\">\n <span rtElem=\"thread-title\" qa-dataid=\"ai-chat-thread-title\" [attr.title]=\"row.title\">\n @for (part of row.titleParts; track $index) {\n <span rtElem=\"thread-part\" [rtMod]=\"{ match: part.matched }\">{{ part.text }}</span>\n }\n </span>\n <span rtElem=\"thread-meta\">\n @if (row.unreadCount) {\n <span rtElem=\"thread-unread\" qa-dataid=\"ai-chat-thread-unread\">{{ row.unreadCount }}</span>\n }\n @if (row.time) {\n <span rtElem=\"thread-time\">{{ row.time }}</span>\n }\n </span>\n </ng-template>\n <ng-template let-row [rtThreadListRowActions]=\"threadRows()\">\n @if (threadMenu()) {\n <rt-menu qa-dataid=\"ai-chat-thread-menu\" icon=\"ellipsis-v\" triggerSize=\"xs\" size=\"sm\" [ariaLabel]=\"t().uiMoreActions\">\n <rt-menu-item\n qa-dataid=\"ai-chat-thread-copy-id\"\n icon=\"copy\"\n [label]=\"t().aiCopyThreadId\"\n (selected)=\"onCopyThreadId(row.id)\" />\n <rt-menu-item\n qa-dataid=\"ai-chat-thread-delete\"\n icon=\"trash\"\n danger\n [label]=\"t().uiRemove\"\n [disabled]=\"sending() && row.id === activeThreadId()\"\n (selected)=\"deleteThread.emit(row.id)\" />\n </rt-menu>\n } @else {\n <rt-icon-button\n qa-dataid=\"ai-chat-delete-thread\"\n size=\"xs\"\n iconSize=\"sm\"\n icon=\"trash\"\n [disabled]=\"sending() && row.id === activeThreadId()\"\n [ariaLabel]=\"t().aiDeleteThread\"\n [tooltip]=\"t().aiDeleteThread\"\n (clicked)=\"deleteThread.emit(row.id)\" />\n }\n </ng-template>\n </rt-thread-list>\n </ng-container>\n</ng-template>\n",
3169
- styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-ai-chat{--rt-ai-chat-bubble-radius: var(--rt-radius-xl);--rt-ai-chat-column-border-width: var(--rt-border-width-thin);--rt-ai-chat-column-width: 280px;--rt-ai-chat-content-max-width: 100%;--rt-ai-chat-match-bg: var(--rt-yellow-400);--rt-ai-chat-match-color: var(--rt-neutral-950);--rt-ai-chat-match-radius: var(--rt-radius-xs);--rt-ai-chat-unread-radius: var(--rt-radius-full);display:flex;overflow:hidden;background:var(--rt-color-bg-surface);block-size:100%;color:var(--rt-color-text-primary);min-block-size:0}.rt-ai-chat__thread-column{display:flex;flex:none;flex-direction:column;border-inline-end:var(--rt-ai-chat-column-border-width) solid var(--rt-color-border-default);inline-size:var(--rt-ai-chat-column-width)}.rt-ai-chat__column-head{display:flex;align-items:center;justify-content:space-between;padding:var(--rt-space-sm) var(--rt-space-md);gap:var(--rt-space-xs)}.rt-ai-chat__column-title{font-size:var(--rt-text-md);font-weight:var(--rt-font-weight-semibold)}.rt-ai-chat__conversation{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:0;min-inline-size:0}.rt-ai-chat__header{display:flex;flex:none;align-items:center;padding:var(--rt-space-sm) var(--rt-space-md);gap:var(--rt-space-xs)}.rt-ai-chat__heading{display:flex;flex:1 1 auto;flex-direction:column;min-inline-size:0}.rt-ai-chat__title{display:inline-flex;align-items:center;font-size:var(--rt-text-md);font-weight:var(--rt-font-weight-semibold);gap:var(--rt-space-xs);line-height:var(--rt-leading-snug)}.rt-ai-chat__subtitle{overflow:hidden;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug);text-overflow:ellipsis;white-space:nowrap}.rt-ai-chat__actions{display:flex;flex:none;align-items:center;gap:var(--rt-space-xs)}.rt-ai-chat__feed{display:flex;flex:1 1 auto;flex-direction:column;font-size:var(--rt-text-sm);gap:var(--rt-space-md);min-block-size:0;overflow-y:auto;padding-block:var(--rt-space-md);padding-inline:max(var(--rt-space-md),(100% - var(--rt-ai-chat-content-max-width)) / 2)}.rt-ai-chat__spinner{align-self:center;margin:auto}.rt-ai-chat__empty{display:flex;flex-direction:column;justify-content:center;gap:var(--rt-space-lg);margin-block:auto}.rt-ai-chat__suggestions{display:flex;flex-direction:column;gap:var(--rt-space-sm)}.rt-ai-chat__question{display:flex;flex-direction:column;align-items:flex-end;gap:var(--rt-space-2xs)}.rt-ai-chat__question-actions{display:flex;gap:var(--rt-space-xs)}.rt-ai-chat__bubble{display:flex;flex-direction:column;padding:var(--rt-space-sm) var(--rt-space-md);border-radius:var(--rt-ai-chat-bubble-radius);background:var(--rt-color-bg-subtle);gap:var(--rt-space-2xs);max-inline-size:80%}.rt-ai-chat__author,.rt-ai-chat__time{color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug)}.rt-ai-chat__author{font-weight:var(--rt-font-weight-semibold)}.rt-ai-chat__bubble-text{margin:0;line-height:var(--rt-leading-normal);overflow-wrap:anywhere;white-space:pre-wrap}.rt-ai-chat__error{display:flex;flex-direction:column;align-items:flex-start;gap:var(--rt-space-sm)}.rt-ai-chat__error rt-message{align-self:stretch}.rt-ai-chat__composer{box-sizing:border-box;flex:none;padding-block:var(--rt-space-sm) 0;padding-inline:max(var(--rt-space-md),(100% - var(--rt-ai-chat-content-max-width)) / 2)}.rt-ai-chat__disclaimer{flex:none;margin:0;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug);padding-block:var(--rt-space-xs) var(--rt-space-sm);padding-inline:max(var(--rt-space-md),(100% - var(--rt-ai-chat-content-max-width)) / 2);text-align:center}.rt-ai-chat__threads{flex:1 1 auto;min-block-size:0}.rt-ai-chat__thread-title{overflow:hidden;min-inline-size:0;text-overflow:ellipsis;white-space:nowrap}.rt-ai-chat__thread-part--match{border-radius:var(--rt-ai-chat-match-radius);background:var(--rt-ai-chat-match-bg);color:var(--rt-ai-chat-match-color)}.rt-ai-chat__thread-meta{display:flex;flex:none;align-items:center;gap:var(--rt-space-xs)}.rt-ai-chat__thread-unread{border-radius:var(--rt-ai-chat-unread-radius);background:var(--rt-color-action-primary);color:var(--rt-color-text-inverse);font-size:var(--rt-text-xs);font-weight:var(--rt-font-weight-semibold);line-height:18px;padding-inline:6px}.rt-ai-chat__thread-time{color:var(--rt-color-text-muted);font-size:var(--rt-text-xs)}}\n"]
3224
+ template: "<ng-container rtBlock=\"rt-ai-chat\">\n @if (isThreadColumn()) {\n <aside rtElem=\"thread-column\" qa-dataid=\"ai-chat-thread-column\" [attr.aria-label]=\"t().aiThreads\">\n <div rtElem=\"column-head\">\n <span rtElem=\"column-title\">{{ t().aiThreads }}</span>\n <ng-container [ngTemplateOutlet]=\"newThreadButton\" />\n </div>\n <ng-container [ngTemplateOutlet]=\"threadList\" />\n </aside>\n }\n\n <section rtElem=\"conversation\" qa-dataid=\"ai-chat\" [attr.aria-label]=\"titleText()\">\n <header rtElem=\"header\" [attr.data-rt-icon-preset]=\"headerIconSign()\">\n @if (isThreadPage()) {\n <rt-icon-button\n #back\n qa-dataid=\"ai-chat-back\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"arrow-left\"\n [ariaLabel]=\"t().aiBackToChat\"\n [tooltip]=\"t().aiBackToChat\"\n (clicked)=\"onToggleThreads()\" />\n }\n\n <div rtElem=\"heading\">\n <span rtElem=\"title\" qa-dataid=\"ai-chat-title\">\n @if (!isThreadPage()) {\n <rt-icon name=\"sparkle\" size=\"sm\" color=\"primary\" aria-hidden=\"true\" />\n }\n {{ isThreadPage() ? t().aiThreads : titleText() }}\n </span>\n @if (!isThreadPage() && subtitle()) {\n <span rtElem=\"subtitle\" qa-dataid=\"ai-chat-subtitle\">{{ subtitle() }}</span>\n }\n </div>\n\n <div rtElem=\"actions\">\n @if (fullScreenable()) {\n <rt-icon-button\n qa-dataid=\"ai-chat-full-screen\"\n size=\"sm\"\n iconSize=\"sm\"\n [icon]=\"fullScreen() ? 'window-minimize' : 'fullscreen'\"\n [active]=\"fullScreen()\"\n [ariaLabel]=\"fullScreen() ? t().aiExitFullScreen : t().aiFullScreen\"\n [tooltip]=\"fullScreen() ? t().aiExitFullScreen : t().aiFullScreen\"\n (clicked)=\"onToggleFullScreen()\" />\n }\n @if (hasThreads() && !isThreadPage() && !isThreadColumn()) {\n <rt-icon-button\n qa-dataid=\"ai-chat-threads\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"history\"\n [ariaLabel]=\"t().aiThreads\"\n [tooltip]=\"t().aiThreads\"\n (clicked)=\"onToggleThreads()\" />\n }\n @if (!isThreadColumn()) {\n <ng-container [ngTemplateOutlet]=\"newThreadButton\" />\n }\n @if (closable()) {\n <rt-icon-button\n qa-dataid=\"ai-chat-close\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"close\"\n [ariaLabel]=\"t().aiClose\"\n [tooltip]=\"t().aiClose\"\n (clicked)=\"closed.emit()\" />\n }\n </div>\n </header>\n\n @if (isThreadPage()) {\n <ng-container [ngTemplateOutlet]=\"threadList\" />\n } @else {\n <div #feed rtElem=\"feed\" qa-dataid=\"ai-chat-feed\" aria-live=\"polite\" (scroll)=\"onFeedScroll()\">\n @if (loading() && !messages().length) {\n <rt-spinner rtElem=\"spinner\" appearance=\"arc\" [diameter]=\"32\" />\n } @else if (isEmpty()) {\n <div rtElem=\"empty\" qa-dataid=\"ai-chat-empty\">\n <rt-empty-state icon=\"comments\" [title]=\"emptyTitleText()\" [description]=\"emptyDescriptionText()\" />\n @if (suggestions().length) {\n <div rtElem=\"suggestions\">\n @for (suggestion of suggestions(); track suggestion) {\n <rt-prompt-suggestion\n qa-dataid=\"ai-chat-suggestion\"\n [label]=\"suggestion\"\n [disabled]=\"sending()\"\n (picked)=\"onSuggestion($event)\" />\n }\n </div>\n }\n </div>\n }\n\n @for (message of messages(); track message.id) {\n @if (message.role === 'user') {\n <div rtElem=\"question\" qa-dataid=\"ai-chat-question\">\n <div rtElem=\"bubble\">\n <span rtElem=\"author\">{{ t().aiYou }}</span>\n <p rtElem=\"bubble-text\">{{ message.text }}</p>\n @if (message.time) {\n <span rtElem=\"time\">{{ message.time }}</span>\n }\n </div>\n @if (copyable() && message.text) {\n <div rtElem=\"question-actions\" qa-dataid=\"ai-chat-question-actions\">\n <rt-ai-chat-copy [text]=\"message.text\" />\n </div>\n }\n </div>\n } @else {\n <rt-ai-chat-answer\n qa-dataid=\"ai-chat-answer\"\n [message]=\"message\"\n [copyable]=\"copyable()\"\n [extra]=\"extraTemplate()?.templateRef ?? null\"\n [expanded]=\"openRuns().has(message.id)\"\n (expandedChange)=\"onToggleRun(message.id, $event)\"\n (feedbackChange)=\"onFeedback(message, $event)\" />\n }\n }\n\n @if (error(); as runError) {\n <div rtElem=\"error\" qa-dataid=\"ai-chat-error\" role=\"alert\">\n <rt-message severity=\"danger\">{{ runError.message }}</rt-message>\n @if (runError.referenceId) {\n <rt-copy-value [label]=\"t().aiReference\" [value]=\"runError.referenceId\" [copyLabel]=\"t().aiCopyReference\" />\n }\n @if (runError.retryable) {\n <button\n rtButton\n type=\"button\"\n qa-dataid=\"ai-chat-retry\"\n appearance=\"text\"\n icon=\"sync\"\n size=\"sm\"\n [label]=\"t().aiRetry\"\n [attr.aria-label]=\"t().aiRetry\"\n [disabled]=\"sending()\"\n (click)=\"retry.emit()\"></button>\n }\n </div>\n }\n </div>\n\n @if (disclaimerText() && disclaimerAbove()) {\n <p rtElem=\"disclaimer\" qa-dataid=\"ai-chat-disclaimer\" [rtMod]=\"{ above: true }\">{{ disclaimerText() }}</p>\n }\n\n <rt-ai-prompt-input\n rtElem=\"composer\"\n qa-dataid=\"ai-chat-composer\"\n stoppable\n hint=\"\"\n [placeholder]=\"placeholder()\"\n [model]=\"model()\"\n [effort]=\"effort()\"\n [mode]=\"mode()\"\n [usage]=\"usage()\"\n [usageHint]=\"usageHint()\"\n [sending]=\"sending()\"\n [(text)]=\"draft\"\n (submitted)=\"onSubmitted($event)\"\n (stopped)=\"onStop()\"\n (controlPicked)=\"controlPicked.emit($event)\" />\n\n @if (disclaimerText() && !disclaimerAbove()) {\n <p rtElem=\"disclaimer\" qa-dataid=\"ai-chat-disclaimer\">{{ disclaimerText() }}</p>\n }\n }\n </section>\n</ng-container>\n\n<ng-template #newThreadButton>\n <rt-icon-button\n qa-dataid=\"ai-chat-new-thread\"\n size=\"sm\"\n iconSize=\"sm\"\n icon=\"ico-plus\"\n [disabled]=\"sending()\"\n [ariaLabel]=\"t().aiNewThread\"\n [tooltip]=\"t().aiNewThread\"\n (clicked)=\"onNewThread()\" />\n</ng-template>\n\n<ng-template #threadList>\n <ng-container rtBlock=\"rt-ai-chat\">\n <rt-thread-list\n rtElem=\"threads\"\n qa-dataid=\"ai-chat-thread-list\"\n [rows]=\"threadRows()\"\n [activeId]=\"activeThreadId()\"\n [searchPlaceholder]=\"t().aiSearchThreads\"\n [emptyText]=\"threadsEmptyText()\"\n [emptyPreviewIcons]=\"emptyPreviewIcons()\"\n [loading]=\"threadsLoading()\"\n [fetching]=\"threadsFetching()\"\n [hasMore]=\"threadsHasMore()\"\n (selectRow)=\"onSelectThread($event)\"\n (searchChange)=\"onSearchThreads($event)\"\n (loadMore)=\"loadMoreThreads.emit()\">\n <ng-template let-row [rtThreadListRow]=\"threadRows()\">\n <span rtElem=\"thread-title\" qa-dataid=\"ai-chat-thread-title\" [attr.title]=\"row.title\">\n @for (part of row.titleParts; track $index) {\n <span rtElem=\"thread-part\" [rtMod]=\"{ match: part.matched }\">{{ part.text }}</span>\n }\n </span>\n <span rtElem=\"thread-meta\">\n @if (row.unreadCount) {\n <span rtElem=\"thread-unread\" qa-dataid=\"ai-chat-thread-unread\">{{ row.unreadCount }}</span>\n }\n @if (row.time) {\n <span rtElem=\"thread-time\">{{ row.time }}</span>\n }\n </span>\n </ng-template>\n <ng-template let-row [rtThreadListRowActions]=\"threadRows()\">\n @if (threadMenu()) {\n <rt-menu qa-dataid=\"ai-chat-thread-menu\" icon=\"ellipsis-v\" triggerSize=\"xs\" size=\"sm\" [ariaLabel]=\"t().uiMoreActions\">\n <rt-menu-item\n qa-dataid=\"ai-chat-thread-copy-id\"\n icon=\"copy\"\n [label]=\"t().aiCopyThreadId\"\n (selected)=\"onCopyThreadId(row.id)\" />\n <rt-menu-item\n qa-dataid=\"ai-chat-thread-delete\"\n icon=\"trash\"\n danger\n [label]=\"t().uiRemove\"\n [disabled]=\"sending() && row.id === activeThreadId()\"\n (selected)=\"deleteThread.emit(row.id)\" />\n </rt-menu>\n } @else {\n <rt-icon-button\n qa-dataid=\"ai-chat-delete-thread\"\n size=\"xs\"\n iconSize=\"sm\"\n icon=\"trash\"\n [disabled]=\"sending() && row.id === activeThreadId()\"\n [ariaLabel]=\"t().aiDeleteThread\"\n [tooltip]=\"t().aiDeleteThread\"\n (clicked)=\"deleteThread.emit(row.id)\" />\n }\n </ng-template>\n </rt-thread-list>\n </ng-container>\n</ng-template>\n",
3225
+ styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-ai-chat{--rt-ai-chat-bubble-radius: var(--rt-radius-xl);--rt-ai-chat-column-border-width: var(--rt-border-width-thin);--rt-ai-chat-column-width: 280px;--rt-ai-chat-content-max-width: 100%;--rt-ai-chat-match-bg: var(--rt-yellow-400);--rt-ai-chat-match-color: var(--rt-neutral-950);--rt-ai-chat-match-radius: var(--rt-radius-xs);--rt-ai-chat-unread-radius: var(--rt-radius-full);display:flex;overflow:hidden;background:var(--rt-color-bg-surface);block-size:100%;color:var(--rt-color-text-primary);min-block-size:0}.rt-ai-chat__thread-column{display:flex;flex:none;flex-direction:column;border-inline-end:var(--rt-ai-chat-column-border-width) solid var(--rt-color-border-default);inline-size:var(--rt-ai-chat-column-width)}.rt-ai-chat__column-head{display:flex;align-items:center;justify-content:space-between;padding:var(--rt-space-sm) var(--rt-space-md);gap:var(--rt-space-xs)}.rt-ai-chat__column-title{font-size:var(--rt-text-md);font-weight:var(--rt-font-weight-semibold)}.rt-ai-chat__conversation{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:0;min-inline-size:0}.rt-ai-chat__header{display:flex;flex:none;align-items:center;padding:var(--rt-space-sm) var(--rt-space-md);gap:var(--rt-space-xs)}.rt-ai-chat__heading{display:flex;flex:1 1 auto;flex-direction:column;min-inline-size:0}.rt-ai-chat__title{display:inline-flex;align-items:center;font-size:var(--rt-text-md);font-weight:var(--rt-font-weight-semibold);gap:var(--rt-space-xs);line-height:var(--rt-leading-snug)}.rt-ai-chat__subtitle{overflow:hidden;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug);text-overflow:ellipsis;white-space:nowrap}.rt-ai-chat__actions{display:flex;flex:none;align-items:center;gap:var(--rt-space-xs)}.rt-ai-chat__feed{display:flex;flex:1 1 auto;flex-direction:column;font-size:var(--rt-text-sm);gap:var(--rt-space-md);min-block-size:0;overflow-y:auto;overscroll-behavior:contain;padding-block:var(--rt-space-md);padding-inline:max(var(--rt-space-md),(100% - var(--rt-ai-chat-content-max-width)) / 2)}.rt-ai-chat__spinner{align-self:center;margin:auto}.rt-ai-chat__empty{display:flex;flex-direction:column;justify-content:center;gap:var(--rt-space-lg);margin-block:auto}.rt-ai-chat__suggestions{display:flex;flex-direction:column;gap:var(--rt-space-sm)}.rt-ai-chat__question{display:flex;flex-direction:column;align-items:flex-end;gap:var(--rt-space-2xs)}.rt-ai-chat__question-actions{display:flex;gap:var(--rt-space-xs)}.rt-ai-chat__bubble{display:flex;flex-direction:column;padding:var(--rt-space-sm) var(--rt-space-md);border-radius:var(--rt-ai-chat-bubble-radius);background:var(--rt-color-bg-subtle);gap:var(--rt-space-2xs);max-inline-size:80%}.rt-ai-chat__author,.rt-ai-chat__time{color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug)}.rt-ai-chat__author{font-weight:var(--rt-font-weight-semibold)}.rt-ai-chat__bubble-text{margin:0;line-height:var(--rt-leading-normal);overflow-wrap:anywhere;white-space:pre-wrap}.rt-ai-chat__error{display:flex;flex-direction:column;align-items:flex-start;gap:var(--rt-space-sm)}.rt-ai-chat__error rt-message{align-self:stretch}.rt-ai-chat__composer{box-sizing:border-box;flex:none;padding-block:var(--rt-space-sm) 0;padding-inline:max(var(--rt-space-md),(100% - var(--rt-ai-chat-content-max-width)) / 2)}.rt-ai-chat__disclaimer{flex:none;margin:0;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);line-height:var(--rt-leading-snug);padding-block:var(--rt-space-xs) var(--rt-space-sm);padding-inline:max(var(--rt-space-md),(100% - var(--rt-ai-chat-content-max-width)) / 2);text-align:center}.rt-ai-chat__disclaimer--above{padding-block:var(--rt-space-sm) 0}.rt-ai-chat__threads{flex:1 1 auto;min-block-size:0}.rt-ai-chat__thread-title{overflow:hidden;min-inline-size:0;text-overflow:ellipsis;white-space:nowrap}.rt-ai-chat__thread-part--match{border-radius:var(--rt-ai-chat-match-radius);background:var(--rt-ai-chat-match-bg);color:var(--rt-ai-chat-match-color)}.rt-ai-chat__thread-meta{display:flex;flex:none;align-items:center;gap:var(--rt-space-xs)}.rt-ai-chat__thread-unread{border-radius:var(--rt-ai-chat-unread-radius);background:var(--rt-color-action-primary);color:var(--rt-color-text-inverse);font-size:var(--rt-text-xs);font-weight:var(--rt-font-weight-semibold);line-height:18px;padding-inline:6px}.rt-ai-chat__thread-time{color:var(--rt-color-text-muted);font-size:var(--rt-text-xs)}}\n"]
3170
3226
  }]
3171
3227
  }],
3172
3228
  ctorParameters: () => [],
3173
3229
  propDecorators: {
3174
3230
  composer: [{
3175
3231
  type: i0.ViewChild,
3176
- args: [i0.forwardRef(() => RtMessageComposerComponent), { isSignal: true }]
3232
+ args: [i0.forwardRef(() => RtAiPromptInputComponent), { isSignal: true }]
3177
3233
  }],
3178
3234
  backButton: [{
3179
3235
  type: i0.ViewChild,
@@ -3254,6 +3310,54 @@ i0.ɵɵngDeclareClassMetadata({
3254
3310
  required: false
3255
3311
  }]
3256
3312
  }],
3313
+ disclaimerPosition: [{
3314
+ type: i0.Input,
3315
+ args: [{
3316
+ isSignal: true,
3317
+ alias: "disclaimerPosition",
3318
+ required: false
3319
+ }]
3320
+ }],
3321
+ model: [{
3322
+ type: i0.Input,
3323
+ args: [{
3324
+ isSignal: true,
3325
+ alias: "model",
3326
+ required: false
3327
+ }]
3328
+ }],
3329
+ effort: [{
3330
+ type: i0.Input,
3331
+ args: [{
3332
+ isSignal: true,
3333
+ alias: "effort",
3334
+ required: false
3335
+ }]
3336
+ }],
3337
+ mode: [{
3338
+ type: i0.Input,
3339
+ args: [{
3340
+ isSignal: true,
3341
+ alias: "mode",
3342
+ required: false
3343
+ }]
3344
+ }],
3345
+ usage: [{
3346
+ type: i0.Input,
3347
+ args: [{
3348
+ isSignal: true,
3349
+ alias: "usage",
3350
+ required: false
3351
+ }]
3352
+ }],
3353
+ usageHint: [{
3354
+ type: i0.Input,
3355
+ args: [{
3356
+ isSignal: true,
3357
+ alias: "usageHint",
3358
+ required: false
3359
+ }]
3360
+ }],
3257
3361
  sending: [{
3258
3362
  type: i0.Input,
3259
3363
  args: [{
@@ -3438,6 +3542,10 @@ i0.ɵɵngDeclareClassMetadata({
3438
3542
  feedbackChange: [{
3439
3543
  type: i0.Output,
3440
3544
  args: ["feedbackChange"]
3545
+ }],
3546
+ controlPicked: [{
3547
+ type: i0.Output,
3548
+ args: ["controlPicked"]
3441
3549
  }]
3442
3550
  }
3443
3551
  });