@rt-tools/ui-kit-v2 0.31.0 → 0.33.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.
- package/fesm2022/rt-tools-ui-kit-v2-core.mjs +2 -0
- package/fesm2022/rt-tools-ui-kit-v2-core.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +38 -13
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-service-logo.mjs +5 -2
- package/fesm2022/rt-tools-ui-kit-v2-service-logo.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs +12 -4
- package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs.map +1 -1
- package/package.json +1 -1
- package/src/lib/components/service-logo/CONTEXT.md +2 -2
- package/src/lib/components/service-logo/rt-service-logo.component.scss +8 -1
- package/src/lib/components/thread-list/CONTEXT.md +7 -1
- package/src/lib/components/thread-list/rt-thread-list.component.scss +15 -0
- package/src/rich-editor/lib/components/chat/CONTEXT.md +9 -2
- package/src/rich-editor/lib/components/chat/rt-chat.component.scss +14 -0
- package/src/styles/_primitives.scss +1 -0
- package/styles/tokens.css +1 -0
- package/types/rt-tools-ui-kit-v2-core.d.ts +2 -1
- package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +16 -3
- package/types/rt-tools-ui-kit-v2-service-logo.d.ts +2 -2
- package/types/rt-tools-ui-kit-v2-thread-list.d.ts +4 -0
|
@@ -4,6 +4,7 @@ import { BlockDirective, ElemDirective } from "@rt-tools/core";
|
|
|
4
4
|
import { RtIconComponent } from "@rt-tools/ui-kit-v2/icon";
|
|
5
5
|
const BEM_BLOCK = "rt-service-logo";
|
|
6
6
|
const ICON_SIZES = Object.freeze({
|
|
7
|
+
xs: "sm",
|
|
7
8
|
sm: "md",
|
|
8
9
|
md: "xl",
|
|
9
10
|
lg: "3xl"
|
|
@@ -62,6 +63,7 @@ var RtServiceLogoComponent = class RtServiceLogoComponent {
|
|
|
62
63
|
host: {
|
|
63
64
|
attributes: { "role": "list" },
|
|
64
65
|
properties: {
|
|
66
|
+
"class.rt-service-logo--size-xs": "size() === 'xs'",
|
|
65
67
|
"class.rt-service-logo--size-sm": "size() === 'sm'",
|
|
66
68
|
"class.rt-service-logo--size-lg": "size() === 'lg'"
|
|
67
69
|
},
|
|
@@ -69,7 +71,7 @@ var RtServiceLogoComponent = class RtServiceLogoComponent {
|
|
|
69
71
|
},
|
|
70
72
|
ngImport: i0,
|
|
71
73
|
template: "<ng-container rtBlock=\"rt-service-logo\">\n @for (mark of marks(); track $index) {\n <span rtElem=\"plate\" role=\"listitem\" qa-dataid=\"service-logo-plate\" [attr.data-label]=\"mark.label\">\n @if (mark.src !== null) {\n <img rtElem=\"image\" qa-dataid=\"service-logo-image\" [src]=\"mark.src\" [alt]=\"mark.label\" />\n } @else {\n <span rtElem=\"icon\" role=\"img\" qa-dataid=\"service-logo-icon\" [attr.aria-label]=\"mark.label\">\n <rt-icon [name]=\"mark.icon\" [size]=\"iconSize()\" />\n </span>\n }\n </span>\n }\n</ng-container>\n",
|
|
72
|
-
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-service-logo{--rt-service-logo-size: var(--rt-size-16);--rt-service-logo-mark-height: var(--rt-size-8);--rt-service-logo-step: var(--rt-size-10);--rt-service-logo-shadow: var(--rt-shadow-service-logo-md);--rt-service-logo-radius: var(--rt-radius-full);--rt-service-logo-bg: var(--rt-color-service-logo-bg);--rt-service-logo-color: var(--rt-color-service-logo-mark);display:inline-flex;align-items:center;vertical-align:middle}.rt-service-logo--size-sm{--rt-service-logo-size: var(--rt-size-10);--rt-service-logo-mark-height: var(--rt-size-5);--rt-service-logo-step: var(--rt-size-6);--rt-service-logo-shadow: var(--rt-shadow-service-logo-sm)}.rt-service-logo--size-lg{--rt-service-logo-size: var(--rt-size-24);--rt-service-logo-mark-height: var(--rt-size-12);--rt-service-logo-step: calc(var(--rt-size-12) + var(--rt-size-3));--rt-service-logo-shadow: var(--rt-shadow-service-logo-lg)}.rt-service-logo__plate{position:relative;display:inline-flex;width:var(--rt-service-logo-size);height:var(--rt-service-logo-size);flex:none;align-items:center;justify-content:center;border-radius:var(--rt-service-logo-radius);background:var(--rt-service-logo-bg);box-shadow:var(--rt-service-logo-shadow);color:var(--rt-service-logo-color)}.rt-service-logo__plate+.rt-service-logo__plate{margin-inline-start:calc(var(--rt-service-logo-step) - var(--rt-service-logo-size))}.rt-service-logo__image{display:block;width:calc(var(--rt-service-logo-mark-height) * 1.375);height:var(--rt-service-logo-mark-height);object-fit:contain}.rt-service-logo__icon{display:inline-flex}}\n"],
|
|
74
|
+
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-service-logo{--rt-service-logo-size: var(--rt-size-16);--rt-service-logo-mark-height: var(--rt-size-8);--rt-service-logo-step: var(--rt-size-10);--rt-service-logo-shadow: var(--rt-shadow-service-logo-md);--rt-service-logo-radius: var(--rt-radius-full);--rt-service-logo-bg: var(--rt-color-service-logo-bg);--rt-service-logo-color: var(--rt-color-service-logo-mark);display:inline-flex;align-items:center;vertical-align:middle}.rt-service-logo--size-xs{--rt-service-logo-size: var(--rt-size-8);--rt-service-logo-mark-height: var(--rt-size-4);--rt-service-logo-step: var(--rt-size-5);--rt-service-logo-shadow: var(--rt-shadow-service-logo-xs)}.rt-service-logo--size-sm{--rt-service-logo-size: var(--rt-size-10);--rt-service-logo-mark-height: var(--rt-size-5);--rt-service-logo-step: var(--rt-size-6);--rt-service-logo-shadow: var(--rt-shadow-service-logo-sm)}.rt-service-logo--size-lg{--rt-service-logo-size: var(--rt-size-24);--rt-service-logo-mark-height: var(--rt-size-12);--rt-service-logo-step: calc(var(--rt-size-12) + var(--rt-size-3));--rt-service-logo-shadow: var(--rt-shadow-service-logo-lg)}.rt-service-logo__plate{position:relative;display:inline-flex;width:var(--rt-service-logo-size);height:var(--rt-service-logo-size);flex:none;align-items:center;justify-content:center;border-radius:var(--rt-service-logo-radius);background:var(--rt-service-logo-bg);box-shadow:var(--rt-service-logo-shadow);color:var(--rt-service-logo-color)}.rt-service-logo__plate+.rt-service-logo__plate{margin-inline-start:calc(var(--rt-service-logo-step) - var(--rt-service-logo-size))}.rt-service-logo__image{display:block;width:calc(var(--rt-service-logo-mark-height) * 1.375);height:var(--rt-service-logo-mark-height);object-fit:contain}.rt-service-logo__icon{display:inline-flex}}\n"],
|
|
73
75
|
dependencies: [
|
|
74
76
|
{
|
|
75
77
|
kind: "directive",
|
|
@@ -123,11 +125,12 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
123
125
|
host: {
|
|
124
126
|
class: BEM_BLOCK,
|
|
125
127
|
role: "list",
|
|
128
|
+
"[class.rt-service-logo--size-xs]": "size() === 'xs'",
|
|
126
129
|
"[class.rt-service-logo--size-sm]": "size() === 'sm'",
|
|
127
130
|
"[class.rt-service-logo--size-lg]": "size() === 'lg'"
|
|
128
131
|
},
|
|
129
132
|
template: "<ng-container rtBlock=\"rt-service-logo\">\n @for (mark of marks(); track $index) {\n <span rtElem=\"plate\" role=\"listitem\" qa-dataid=\"service-logo-plate\" [attr.data-label]=\"mark.label\">\n @if (mark.src !== null) {\n <img rtElem=\"image\" qa-dataid=\"service-logo-image\" [src]=\"mark.src\" [alt]=\"mark.label\" />\n } @else {\n <span rtElem=\"icon\" role=\"img\" qa-dataid=\"service-logo-icon\" [attr.aria-label]=\"mark.label\">\n <rt-icon [name]=\"mark.icon\" [size]=\"iconSize()\" />\n </span>\n }\n </span>\n }\n</ng-container>\n",
|
|
130
|
-
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-service-logo{--rt-service-logo-size: var(--rt-size-16);--rt-service-logo-mark-height: var(--rt-size-8);--rt-service-logo-step: var(--rt-size-10);--rt-service-logo-shadow: var(--rt-shadow-service-logo-md);--rt-service-logo-radius: var(--rt-radius-full);--rt-service-logo-bg: var(--rt-color-service-logo-bg);--rt-service-logo-color: var(--rt-color-service-logo-mark);display:inline-flex;align-items:center;vertical-align:middle}.rt-service-logo--size-sm{--rt-service-logo-size: var(--rt-size-10);--rt-service-logo-mark-height: var(--rt-size-5);--rt-service-logo-step: var(--rt-size-6);--rt-service-logo-shadow: var(--rt-shadow-service-logo-sm)}.rt-service-logo--size-lg{--rt-service-logo-size: var(--rt-size-24);--rt-service-logo-mark-height: var(--rt-size-12);--rt-service-logo-step: calc(var(--rt-size-12) + var(--rt-size-3));--rt-service-logo-shadow: var(--rt-shadow-service-logo-lg)}.rt-service-logo__plate{position:relative;display:inline-flex;width:var(--rt-service-logo-size);height:var(--rt-service-logo-size);flex:none;align-items:center;justify-content:center;border-radius:var(--rt-service-logo-radius);background:var(--rt-service-logo-bg);box-shadow:var(--rt-service-logo-shadow);color:var(--rt-service-logo-color)}.rt-service-logo__plate+.rt-service-logo__plate{margin-inline-start:calc(var(--rt-service-logo-step) - var(--rt-service-logo-size))}.rt-service-logo__image{display:block;width:calc(var(--rt-service-logo-mark-height) * 1.375);height:var(--rt-service-logo-mark-height);object-fit:contain}.rt-service-logo__icon{display:inline-flex}}\n"]
|
|
133
|
+
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-service-logo{--rt-service-logo-size: var(--rt-size-16);--rt-service-logo-mark-height: var(--rt-size-8);--rt-service-logo-step: var(--rt-size-10);--rt-service-logo-shadow: var(--rt-shadow-service-logo-md);--rt-service-logo-radius: var(--rt-radius-full);--rt-service-logo-bg: var(--rt-color-service-logo-bg);--rt-service-logo-color: var(--rt-color-service-logo-mark);display:inline-flex;align-items:center;vertical-align:middle}.rt-service-logo--size-xs{--rt-service-logo-size: var(--rt-size-8);--rt-service-logo-mark-height: var(--rt-size-4);--rt-service-logo-step: var(--rt-size-5);--rt-service-logo-shadow: var(--rt-shadow-service-logo-xs)}.rt-service-logo--size-sm{--rt-service-logo-size: var(--rt-size-10);--rt-service-logo-mark-height: var(--rt-size-5);--rt-service-logo-step: var(--rt-size-6);--rt-service-logo-shadow: var(--rt-shadow-service-logo-sm)}.rt-service-logo--size-lg{--rt-service-logo-size: var(--rt-size-24);--rt-service-logo-mark-height: var(--rt-size-12);--rt-service-logo-step: calc(var(--rt-size-12) + var(--rt-size-3));--rt-service-logo-shadow: var(--rt-shadow-service-logo-lg)}.rt-service-logo__plate{position:relative;display:inline-flex;width:var(--rt-service-logo-size);height:var(--rt-service-logo-size);flex:none;align-items:center;justify-content:center;border-radius:var(--rt-service-logo-radius);background:var(--rt-service-logo-bg);box-shadow:var(--rt-service-logo-shadow);color:var(--rt-service-logo-color)}.rt-service-logo__plate+.rt-service-logo__plate{margin-inline-start:calc(var(--rt-service-logo-step) - var(--rt-service-logo-size))}.rt-service-logo__image{display:block;width:calc(var(--rt-service-logo-mark-height) * 1.375);height:var(--rt-service-logo-mark-height);object-fit:contain}.rt-service-logo__icon{display:inline-flex}}\n"]
|
|
131
134
|
}]
|
|
132
135
|
}],
|
|
133
136
|
propDecorators: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rt-tools-ui-kit-v2-service-logo.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/service-logo/rt-service-logo.component.ts","../../../projects/ui-kit-v2/src/lib/components/service-logo/rt-service-logo.component.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input, InputSignal, Signal, ViewEncapsulation } from '@angular/core';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\n\nimport { IRtServiceLogo } from './rt-service-logo.model';\n\nconst BEM_BLOCK: string = 'rt-service-logo';\n\n/** Высота знака — ступенью значка кита: 20 / 32 / 48, те же числа, что у знака-картинки. */\nconst ICON_SIZES: Readonly<Record<IRtServiceLogo.Size, IRtIcon.Size>> = Object.freeze({\n sm: 'md',\n md: 'xl',\n lg: '3xl',\n});\n\n/** Знак, готовый к отрисовке: картинка или значок, у каждого своё имя для диктора. */\ninterface IRtServiceLogoMark {\n readonly label: string;\n readonly src: string | null;\n readonly icon: IRtIcon.Name | null;\n}\n\nfunction toMark(item: IRtServiceLogo.Item): IRtServiceLogoMark {\n return 'src' in item ? { label: item.label, src: item.src, icon: null } : { label: item.label, src: null, icon: item.icon };\n}\n\n/**\n * Знак внешней службы в светлом круге с мягкой тенью. Несколько знаков ложатся внахлёст шагом\n * атома, и каждый следующий лежит поверх предыдущего. Знаки чужих компаний приложение передаёт\n * адресом картинки; знак без компании — значок кита в том же круге.\n */\n@Component({\n selector: 'rt-service-logo',\n templateUrl: './rt-service-logo.component.html',\n styleUrl: './rt-service-logo.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n BlockDirective,\n ElemDirective,\n RtIconComponent,\n ],\n host: {\n class: BEM_BLOCK,\n role: 'list',\n '[class.rt-service-logo--size-sm]': \"size() === 'sm'\",\n '[class.rt-service-logo--size-lg]': \"size() === 'lg'\",\n },\n})\nexport class RtServiceLogoComponent {\n protected readonly marks: Signal<readonly IRtServiceLogoMark[]> = computed((): readonly IRtServiceLogoMark[] =>\n this.logos().map(toMark)\n );\n\n protected readonly iconSize: Signal<IRtIcon.Size> = computed((): IRtIcon.Size => ICON_SIZES[this.size()]);\n\n /** Знаки ряда в порядке отрисовки: следующий ложится поверх предыдущего. */\n public readonly logos: InputSignal<readonly IRtServiceLogo.Item[]> = input.required<readonly IRtServiceLogo.Item[]>();\n\n /** Размер круга и знака. */\n public readonly size: InputSignal<IRtServiceLogo.Size> = input<IRtServiceLogo.Size>('md');\n}\n","<ng-container rtBlock=\"rt-service-logo\">\n @for (mark of marks(); track $index) {\n <span rtElem=\"plate\" role=\"listitem\" qa-dataid=\"service-logo-plate\" [attr.data-label]=\"mark.label\">\n @if (mark.src !== null) {\n <img rtElem=\"image\" qa-dataid=\"service-logo-image\" [src]=\"mark.src\" [alt]=\"mark.label\" />\n } @else {\n <span rtElem=\"icon\" role=\"img\" qa-dataid=\"service-logo-icon\" [attr.aria-label]=\"mark.label\">\n <rt-icon [name]=\"mark.icon\" [size]=\"iconSize()\" />\n </span>\n }\n </span>\n }\n</ng-container>\n"],"mappings":";;;;AASA,MAAM,YAAoB;AAG1B,MAAM,aAAkE,OAAO,OAAO;CAClF,IAAI;CACJ,IAAI;CACJ,IAAI;AACP,CAAA;AASD,SAAS,OAAO,MAAyB;CACrC,OAAO,SAAS,OAAO;EAAE,OAAO,KAAK;EAAO,KAAK,KAAK;EAAK,MAAM;CAAI,IAAK;EAAE,OAAO,KAAK;EAAO,KAAK;EAAM,MAAM,KAAK;CAAI;AAC7H;
|
|
1
|
+
{"version":3,"file":"rt-tools-ui-kit-v2-service-logo.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/service-logo/rt-service-logo.component.ts","../../../projects/ui-kit-v2/src/lib/components/service-logo/rt-service-logo.component.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input, InputSignal, Signal, ViewEncapsulation } from '@angular/core';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\n\nimport { IRtServiceLogo } from './rt-service-logo.model';\n\nconst BEM_BLOCK: string = 'rt-service-logo';\n\n/** Высота знака — ступенью значка кита: 16 / 20 / 32 / 48, те же числа, что у знака-картинки. */\nconst ICON_SIZES: Readonly<Record<IRtServiceLogo.Size, IRtIcon.Size>> = Object.freeze({\n xs: 'sm',\n sm: 'md',\n md: 'xl',\n lg: '3xl',\n});\n\n/** Знак, готовый к отрисовке: картинка или значок, у каждого своё имя для диктора. */\ninterface IRtServiceLogoMark {\n readonly label: string;\n readonly src: string | null;\n readonly icon: IRtIcon.Name | null;\n}\n\nfunction toMark(item: IRtServiceLogo.Item): IRtServiceLogoMark {\n return 'src' in item ? { label: item.label, src: item.src, icon: null } : { label: item.label, src: null, icon: item.icon };\n}\n\n/**\n * Знак внешней службы в светлом круге с мягкой тенью. Несколько знаков ложатся внахлёст шагом\n * атома, и каждый следующий лежит поверх предыдущего. Знаки чужих компаний приложение передаёт\n * адресом картинки; знак без компании — значок кита в том же круге.\n */\n@Component({\n selector: 'rt-service-logo',\n templateUrl: './rt-service-logo.component.html',\n styleUrl: './rt-service-logo.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n BlockDirective,\n ElemDirective,\n RtIconComponent,\n ],\n host: {\n class: BEM_BLOCK,\n role: 'list',\n '[class.rt-service-logo--size-xs]': \"size() === 'xs'\",\n '[class.rt-service-logo--size-sm]': \"size() === 'sm'\",\n '[class.rt-service-logo--size-lg]': \"size() === 'lg'\",\n },\n})\nexport class RtServiceLogoComponent {\n protected readonly marks: Signal<readonly IRtServiceLogoMark[]> = computed((): readonly IRtServiceLogoMark[] =>\n this.logos().map(toMark)\n );\n\n protected readonly iconSize: Signal<IRtIcon.Size> = computed((): IRtIcon.Size => ICON_SIZES[this.size()]);\n\n /** Знаки ряда в порядке отрисовки: следующий ложится поверх предыдущего. */\n public readonly logos: InputSignal<readonly IRtServiceLogo.Item[]> = input.required<readonly IRtServiceLogo.Item[]>();\n\n /** Размер круга и знака. */\n public readonly size: InputSignal<IRtServiceLogo.Size> = input<IRtServiceLogo.Size>('md');\n}\n","<ng-container rtBlock=\"rt-service-logo\">\n @for (mark of marks(); track $index) {\n <span rtElem=\"plate\" role=\"listitem\" qa-dataid=\"service-logo-plate\" [attr.data-label]=\"mark.label\">\n @if (mark.src !== null) {\n <img rtElem=\"image\" qa-dataid=\"service-logo-image\" [src]=\"mark.src\" [alt]=\"mark.label\" />\n } @else {\n <span rtElem=\"icon\" role=\"img\" qa-dataid=\"service-logo-icon\" [attr.aria-label]=\"mark.label\">\n <rt-icon [name]=\"mark.icon\" [size]=\"iconSize()\" />\n </span>\n }\n </span>\n }\n</ng-container>\n"],"mappings":";;;;AASA,MAAM,YAAoB;AAG1B,MAAM,aAAkE,OAAO,OAAO;CAClF,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACP,CAAA;AASD,SAAS,OAAO,MAAyB;CACrC,OAAO,SAAS,OAAO;EAAE,OAAO,KAAK;EAAO,KAAK,KAAK;EAAK,MAAM;CAAI,IAAK;EAAE,OAAO,KAAK;EAAO,KAAK;EAAM,MAAM,KAAK;CAAI;AAC7H;AA2BA,IAAa,yBAAb,MAAa,uBAAsB;CApBnC,cAAA;EAqBuB,KAAA,QAA+C,eAC9D,KAAK,MAAK,CAAE,CAAC,IAAI,MAAM,GAC1B,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;EAEkB,KAAA,WAAiC,eAA6B,WAAW,KAAK,KAAI,IAAI,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;EAGzF,KAAA,QAAqD,MAAM,SAA0C,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;EAGrG,KAAA,OAAyC,MAA2B,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAC5F;CAZY;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAsB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAAtB;EAAA,KAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAAsB,cAAA;GAAA,UAAA;GAAA,QAAA;IAAA,OAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,MAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;GAAA;GAAA,MAAA;IAAA,YAAA,EAAA,QAAA,OAAA;IAAA,YAAA;KAAA,kCAAA;KAAA,kCAAA;KAAA,kCAAA;IAAA;IAAA,gBAAA;GAAA;GAAA,UAAA;GAAA,UCvDnC;GAaA,QAAA,CAAA,8xDAAA;GAAA,cAAA;IAAA;KAAA,MAAA;KAAA,MD8BQ;KAAc,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACd;KAAa,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACb;KAAe,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;KAAA;IAAA;GAAA;GAAA,iBAAA,GAAA,wBAAA;GAAA,eAAA,GAAA,kBAAA;EAAA,CAAA;CAAA;;AAUV,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAsB,YAAA,CAAA;EApBlC,MAAA;EACa,MAAA,CAAA;GAAA,UAAA;GAAiB,iBAGV,wBAAwB;GAAM,eAChC,kBAAkB;GAAI,SAC5B;IAEL;IACA;IACA;GACH;GAAA,MACK;IACF,OAAO;IACP,MAAM;IACN,oCAAoC;IACpC,oCAAoC;IACpC,oCAAoC;GACvC;GAAA,UAAA;GAAA,QAAA,CAAA,8xDAAA;EAAA,CAAA"}
|
|
@@ -14,6 +14,7 @@ import { RtInputComponent } from "@rt-tools/ui-kit-v2/input";
|
|
|
14
14
|
import { RtPopoverDirective } from "@rt-tools/ui-kit-v2/popover";
|
|
15
15
|
import * as i1 from "@rt-tools/ui-kit-v2/radius";
|
|
16
16
|
import { RtRadiusDirective } from "@rt-tools/ui-kit-v2/radius";
|
|
17
|
+
import { RtServiceLogoComponent } from "@rt-tools/ui-kit-v2/service-logo";
|
|
17
18
|
import { RtSkeletonComponent } from "@rt-tools/ui-kit-v2/skeleton";
|
|
18
19
|
var RtThreadListRowDirective = class RtThreadListRowDirective {
|
|
19
20
|
constructor() {
|
|
@@ -391,8 +392,8 @@ var RtThreadListComponent = class RtThreadListComponent {
|
|
|
391
392
|
inputs: ["radius", "radius"]
|
|
392
393
|
}],
|
|
393
394
|
ngImport: i0,
|
|
394
|
-
template: "<ng-container rtBlock=\"rt-thread-list\">\n <header rtElem=\"head\">\n @if (searchTemplate()) {\n <div rtElem=\"search\" qa-dataid=\"thread-list-search\">\n <ng-container [ngTemplateOutlet]=\"searchTemplate()?.templateRef ?? null\" />\n </div>\n } @else {\n <rt-input\n rtElem=\"search\"\n qa-dataid=\"thread-list-search\"\n iconLeft=\"search\"\n [placeholder]=\"searchPlaceholderText()\"\n [formControl]=\"searchControl\" />\n }\n @if (filtersTemplate()) {\n <rt-icon-button\n rtElem=\"filter-trigger\"\n qa-dataid=\"thread-list-filter\"\n icon=\"filter\"\n variant=\"secondary\"\n rtPopoverAlign=\"end\"\n [ariaLabel]=\"t().uiFilters\"\n [indicator]=\"filtersActive()\"\n [rtPopover]=\"filtersPanel\" />\n }\n </header>\n\n <ng-template #rowButton let-row>\n <button\n rtElem=\"row\"\n qa-dataid=\"thread-list-row\"\n type=\"button\"\n [attr.data-id]=\"row.id\"\n [attr.data-unread]=\"row.hasUnread\"\n [attr.aria-current]=\"row.id === activeId() ? 'true' : null\"\n [rtMod]=\"{\n active: row.id === activeId(),\n unread: row.hasUnread,\n overdue: !!row.overdue,\n }\"\n (click)=\"onSelect(row.id, $event)\">\n <ng-container [ngTemplateOutlet]=\"rowTemplate()?.templateRef ?? null\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n
|
|
395
|
-
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-thread-list{--rt-thread-list-border-width: var(--rt-border-width-thin);--rt-thread-list-card-radius: var(--rt-radius-lg);--rt-thread-list-tag-radius: var(--rt-radius-sm);--rt-thread-list-dot-radius: var(--rt-radius-full);--rt-thread-list-avatar-radius: var(--rt-radius-full);--rt-thread-list-line-radius: var(--rt-radius-full);display:flex;flex:1 1 auto;flex-direction:column;min-block-size:0}.rt-thread-list__head{display:flex;flex:0 0 auto;align-items:center;block-size:56px;border-block-end:var(--rt-thread-list-border-width) solid var(--rt-color-border-strong);gap:var(--rt-space-2);padding-inline:var(--rt-space-4)}.rt-thread-list__search{flex:1 1 auto;min-inline-size:0}.rt-thread-list__filter-trigger{flex:0 0 auto}.rt-thread-list__filters-panel{display:flex;flex-direction:column;padding:var(--rt-space-4);gap:var(--rt-space-2);min-inline-size:220px}.rt-thread-list__rows{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:0;overflow-y:auto}.rt-thread-list__row{display:flex;align-items:center;justify-content:space-between;padding:var(--rt-space-2) var(--rt-space-4);border:none;background:none;border-inline-start:3px solid transparent;cursor:pointer;font-family:inherit;font-size:var(--rt-text-sm);gap:var(--rt-space-4);inline-size:100%;text-align:start}.rt-thread-list__row:hover{background:var(--rt-color-bg-subtle)}.rt-thread-list__row--active,.rt-thread-list__row--active:hover{background:var(--rt-color-state-info-bg);border-inline-start-color:var(--rt-color-action-primary)}.rt-thread-list__row--unread{position:relative;background:var(--rt-color-bg-subtle);border-inline-start-color:var(--rt-color-action-primary)}.rt-thread-list__row--unread .rt-thread-list__row-title{font-weight:var(--rt-font-weight-semibold)}.rt-thread-list__row--unread:before{position:absolute;border-radius:var(--rt-thread-list-dot-radius);background:var(--rt-color-action-primary);block-size:var(--rt-space-2);content:\"\";inline-size:var(--rt-space-2);inset-block-start:50%;inset-inline-start:var(--rt-space-2);transform:translateY(-50%)}.rt-thread-list__row--active,.rt-thread-list__row--active:hover{background:var(--rt-color-state-info-bg)}.rt-thread-list__row--overdue .rt-thread-list__row-time{color:var(--rt-color-state-error-text)}.rt-thread-list__row-wrap{position:relative}.rt-thread-list__row-wrap:hover .rt-thread-list__row-actions,.rt-thread-list__row-wrap:focus-within .rt-thread-list__row-actions,.rt-thread-list__row-wrap:has(.rt-menu--open) .rt-thread-list__row-actions{opacity:1;pointer-events:auto}.rt-thread-list__row-actions{position:absolute;display:flex;align-items:center;background:var(--rt-color-bg-subtle);gap:var(--rt-space-1);inset-block:0;inset-inline-end:0;opacity:0;padding-inline:var(--rt-space-2) var(--rt-space-4);pointer-events:none}.rt-thread-list__row--active+.rt-thread-list__row-actions{background:var(--rt-color-state-info-bg)}.rt-thread-list__row-body{display:flex;flex-direction:column;gap:var(--rt-space-0-5);min-inline-size:0}.rt-thread-list__row-title{overflow:hidden;color:var(--rt-color-text-primary);text-overflow:ellipsis;white-space:nowrap}.rt-thread-list__row-id{color:var(--rt-color-text-muted);font-size:var(--rt-text-sm)}.rt-thread-list__row:hover .rt-copy-cell__button,.rt-thread-list__row:focus-within .rt-copy-cell__button{opacity:1}.rt-thread-list__row-subtitle{overflow:hidden;color:var(--rt-color-text-muted);text-overflow:ellipsis;white-space:nowrap}.rt-thread-list__row-meta{display:flex;flex:0 0 auto;align-items:center;gap:var(--rt-space-2)}.rt-thread-list__row-time{color:var(--rt-color-text-muted);white-space:nowrap}.rt-thread-list__row-tag{padding:var(--rt-space-0-5) var(--rt-space-2);border-radius:var(--rt-thread-list-tag-radius);background:var(--rt-color-state-warning-bg);color:var(--rt-color-state-warning-text);font-size:var(--rt-text-xs);white-space:nowrap}.rt-thread-list__row-dot{display:inline-block;border-radius:var(--rt-thread-list-dot-radius);background:var(--rt-color-text-link);block-size:6px;inline-size:6px}.rt-thread-list__row-skeleton{display:flex;flex-direction:column;padding:var(--rt-space-2) var(--rt-space-4);gap:var(--rt-space-2)}.rt-thread-list__row-loader{display:flex;justify-content:center;padding:var(--rt-space-2) var(--rt-space-4)}.rt-thread-list__load-anchor{block-size:1px}.rt-thread-list__empty{padding:var(--rt-space-6) var(--rt-space-4)}.rt-thread-list__empty-preview{display:flex;flex-direction:column;gap:var(--rt-space-1)}.rt-thread-list__empty-card{display:flex;align-items:center;padding:var(--rt-space-2);border:var(--rt-thread-list-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-thread-list-card-radius);background:var(--rt-color-bg-surface-subtle);gap:var(--rt-space-2)}.rt-thread-list__empty-card--offset{transform:translate(20px)}.rt-thread-list__empty-avatar{display:grid;flex:0 0 auto;border-radius:var(--rt-thread-list-avatar-radius);background:var(--rt-color-text-muted);block-size:24px;color:var(--rt-color-bg-surface);inline-size:24px;place-items:center}.rt-thread-list__empty-lines{display:flex;flex-direction:column;gap:var(--rt-space-2)}.rt-thread-list__empty-line{border-radius:var(--rt-thread-list-line-radius);background:var(--rt-color-border-strong);block-size:6px;inline-size:112px}.rt-thread-list__empty-line--short{inline-size:48px}.rt-thread-list[data-rt-radius=none]{--rt-thread-list-card-radius: var(--rt-radius-none)}.rt-thread-list[data-rt-radius=xs]{--rt-thread-list-card-radius: var(--rt-radius-xs)}.rt-thread-list[data-rt-radius=sm]{--rt-thread-list-card-radius: var(--rt-radius-sm)}.rt-thread-list[data-rt-radius=ms]{--rt-thread-list-card-radius: var(--rt-radius-ms)}.rt-thread-list[data-rt-radius=md]{--rt-thread-list-card-radius: var(--rt-radius-md)}.rt-thread-list[data-rt-radius=lg]{--rt-thread-list-card-radius: var(--rt-radius-lg)}.rt-thread-list[data-rt-radius=xl]{--rt-thread-list-card-radius: var(--rt-radius-xl)}.rt-thread-list[data-rt-radius=\"2xl\"]{--rt-thread-list-card-radius: var(--rt-radius-2xl)}.rt-thread-list[data-rt-radius=full]{--rt-thread-list-card-radius: var(--rt-radius-full)}}\n"],
|
|
395
|
+
template: "<ng-container rtBlock=\"rt-thread-list\">\n <header rtElem=\"head\">\n @if (searchTemplate()) {\n <div rtElem=\"search\" qa-dataid=\"thread-list-search\">\n <ng-container [ngTemplateOutlet]=\"searchTemplate()?.templateRef ?? null\" />\n </div>\n } @else {\n <rt-input\n rtElem=\"search\"\n qa-dataid=\"thread-list-search\"\n iconLeft=\"search\"\n [placeholder]=\"searchPlaceholderText()\"\n [formControl]=\"searchControl\" />\n }\n @if (filtersTemplate()) {\n <rt-icon-button\n rtElem=\"filter-trigger\"\n qa-dataid=\"thread-list-filter\"\n icon=\"filter\"\n variant=\"secondary\"\n rtPopoverAlign=\"end\"\n [ariaLabel]=\"t().uiFilters\"\n [indicator]=\"filtersActive()\"\n [rtPopover]=\"filtersPanel\" />\n }\n </header>\n\n <ng-template #rowButton let-row>\n <button\n rtElem=\"row\"\n qa-dataid=\"thread-list-row\"\n type=\"button\"\n [attr.data-id]=\"row.id\"\n [attr.data-unread]=\"row.hasUnread\"\n [attr.aria-current]=\"row.id === activeId() ? 'true' : null\"\n [rtMod]=\"{\n active: row.id === activeId(),\n unread: row.hasUnread,\n overdue: !!row.overdue,\n }\"\n (click)=\"onSelect(row.id, $event)\">\n @if (row.sign; as sign) {\n <rt-service-logo rtElem=\"row-sign\" qa-dataid=\"thread-list-row-sign\" size=\"xs\" [logos]=\"[sign]\" />\n <span rtElem=\"row-content\">\n <ng-container [ngTemplateOutlet]=\"rowContent\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </span>\n } @else {\n <ng-container [ngTemplateOutlet]=\"rowContent\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n </button>\n </ng-template>\n\n <ng-template #rowContent let-row>\n <ng-container [ngTemplateOutlet]=\"rowTemplate()?.templateRef ?? null\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </ng-template>\n\n <ng-template #filtersPanel>\n <div rtElem=\"filters-panel\" qa-dataid=\"thread-list-filters-panel\">\n <ng-container [ngTemplateOutlet]=\"filtersTemplate()?.templateRef ?? null\" />\n </div>\n </ng-template>\n\n <div rtElem=\"rows\" qa-dataid=\"thread-list-rows\">\n @if (loading() && !rows().length) {\n @for (i of skeletonRows; track i) {\n <div rtElem=\"row-skeleton\" qa-dataid=\"thread-list-row-skeleton\" aria-hidden=\"true\">\n <rt-skeleton width=\"60%\" height=\"14px\" />\n <rt-skeleton width=\"90%\" height=\"12px\" />\n </div>\n }\n } @else if (!rows().length) {\n <rt-empty-state rtElem=\"empty\" qa-dataid=\"thread-list-empty\" [description]=\"t().uiThreadListEmptyHint\" [title]=\"emptyTitle()\">\n <div rtEmptyIllustration rtElem=\"empty-preview\">\n @for (row of emptyPreviewRows(); track row.id) {\n <div rtElem=\"empty-card\" [rtMod]=\"{ offset: row.offset }\">\n <span rtElem=\"empty-avatar\">\n <rt-icon size=\"sm\" [name]=\"row.icon\" />\n </span>\n <span rtElem=\"empty-lines\">\n <span rtElem=\"empty-line\" [rtMod]=\"{ short: true }\"></span>\n <span rtElem=\"empty-line\"></span>\n </span>\n </div>\n }\n </div>\n </rt-empty-state>\n } @else {\n @for (row of rows(); track row.id) {\n @if (rowActionsTemplate(); as actions) {\n <div rtElem=\"row-wrap\" qa-dataid=\"thread-list-row-wrap\">\n <ng-container [ngTemplateOutlet]=\"rowButton\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n <div rtElem=\"row-actions\" qa-dataid=\"thread-list-row-actions\">\n <ng-container [ngTemplateOutlet]=\"actions.templateRef\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </div>\n </div>\n } @else {\n <ng-container [ngTemplateOutlet]=\"rowButton\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n }\n @if (fetching()) {\n <div rtElem=\"row-loader\" qa-dataid=\"thread-list-row-loader\">\n <rt-skeleton width=\"90%\" height=\"12px\" />\n </div>\n }\n @if (hasMore()) {\n <div\n rtElem=\"load-anchor\"\n qa-dataid=\"thread-list-load-more\"\n aria-hidden=\"true\"\n rtInfiniteScroll\n [disabled]=\"fetching()\"\n (loadMore)=\"onLoadMore()\"></div>\n }\n }\n </div>\n</ng-container>\n",
|
|
396
|
+
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-thread-list{--rt-thread-list-border-width: var(--rt-border-width-thin);--rt-thread-list-card-radius: var(--rt-radius-lg);--rt-thread-list-tag-radius: var(--rt-radius-sm);--rt-thread-list-dot-radius: var(--rt-radius-full);--rt-thread-list-avatar-radius: var(--rt-radius-full);--rt-thread-list-line-radius: var(--rt-radius-full);display:flex;flex:1 1 auto;flex-direction:column;min-block-size:0}.rt-thread-list__head{display:flex;flex:0 0 auto;align-items:center;block-size:56px;border-block-end:var(--rt-thread-list-border-width) solid var(--rt-color-border-strong);gap:var(--rt-space-2);padding-inline:var(--rt-space-4)}.rt-thread-list__search{flex:1 1 auto;min-inline-size:0}.rt-thread-list__filter-trigger{flex:0 0 auto}.rt-thread-list__filters-panel{display:flex;flex-direction:column;padding:var(--rt-space-4);gap:var(--rt-space-2);min-inline-size:220px}.rt-thread-list__rows{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:0;overflow-y:auto}.rt-thread-list__row{display:flex;align-items:center;justify-content:space-between;padding:var(--rt-space-2) var(--rt-space-4);border:none;background:none;border-inline-start:3px solid transparent;cursor:pointer;font-family:inherit;font-size:var(--rt-text-sm);gap:var(--rt-space-4);inline-size:100%;text-align:start}.rt-thread-list__row:hover{background:var(--rt-color-bg-subtle)}.rt-thread-list__row--active,.rt-thread-list__row--active:hover{background:var(--rt-color-state-info-bg);border-inline-start-color:var(--rt-color-action-primary)}.rt-thread-list__row--unread{position:relative;background:var(--rt-color-bg-subtle);border-inline-start-color:var(--rt-color-action-primary)}.rt-thread-list__row--unread .rt-thread-list__row-title{font-weight:var(--rt-font-weight-semibold)}.rt-thread-list__row--unread:before{position:absolute;border-radius:var(--rt-thread-list-dot-radius);background:var(--rt-color-action-primary);block-size:var(--rt-space-2);content:\"\";inline-size:var(--rt-space-2);inset-block-start:50%;inset-inline-start:var(--rt-space-2);transform:translateY(-50%)}.rt-thread-list__row--active,.rt-thread-list__row--active:hover{background:var(--rt-color-state-info-bg)}.rt-thread-list__row--overdue .rt-thread-list__row-time{color:var(--rt-color-state-error-text)}.rt-thread-list__row-wrap{position:relative}.rt-thread-list__row-wrap:hover .rt-thread-list__row-actions,.rt-thread-list__row-wrap:focus-within .rt-thread-list__row-actions,.rt-thread-list__row-wrap:has(.rt-menu--open) .rt-thread-list__row-actions{opacity:1;pointer-events:auto}.rt-thread-list__row-actions{position:absolute;display:flex;align-items:center;background:var(--rt-color-bg-subtle);gap:var(--rt-space-1);inset-block:0;inset-inline-end:0;opacity:0;padding-inline:var(--rt-space-2) var(--rt-space-4);pointer-events:none}.rt-thread-list__row--active+.rt-thread-list__row-actions{background:var(--rt-color-state-info-bg)}.rt-thread-list__row-sign{flex:none}.rt-thread-list__row-content{display:flex;flex:1 1 auto;align-items:center;justify-content:space-between;gap:var(--rt-space-4);min-inline-size:0}.rt-thread-list__row-body{display:flex;flex-direction:column;gap:var(--rt-space-0-5);min-inline-size:0}.rt-thread-list__row-title{overflow:hidden;color:var(--rt-color-text-primary);text-overflow:ellipsis;white-space:nowrap}.rt-thread-list__row-id{color:var(--rt-color-text-muted);font-size:var(--rt-text-sm)}.rt-thread-list__row:hover .rt-copy-cell__button,.rt-thread-list__row:focus-within .rt-copy-cell__button{opacity:1}.rt-thread-list__row-subtitle{overflow:hidden;color:var(--rt-color-text-muted);text-overflow:ellipsis;white-space:nowrap}.rt-thread-list__row-meta{display:flex;flex:0 0 auto;align-items:center;gap:var(--rt-space-2)}.rt-thread-list__row-time{color:var(--rt-color-text-muted);white-space:nowrap}.rt-thread-list__row-tag{padding:var(--rt-space-0-5) var(--rt-space-2);border-radius:var(--rt-thread-list-tag-radius);background:var(--rt-color-state-warning-bg);color:var(--rt-color-state-warning-text);font-size:var(--rt-text-xs);white-space:nowrap}.rt-thread-list__row-dot{display:inline-block;border-radius:var(--rt-thread-list-dot-radius);background:var(--rt-color-text-link);block-size:6px;inline-size:6px}.rt-thread-list__row-skeleton{display:flex;flex-direction:column;padding:var(--rt-space-2) var(--rt-space-4);gap:var(--rt-space-2)}.rt-thread-list__row-loader{display:flex;justify-content:center;padding:var(--rt-space-2) var(--rt-space-4)}.rt-thread-list__load-anchor{block-size:1px}.rt-thread-list__empty{padding:var(--rt-space-6) var(--rt-space-4)}.rt-thread-list__empty-preview{display:flex;flex-direction:column;gap:var(--rt-space-1)}.rt-thread-list__empty-card{display:flex;align-items:center;padding:var(--rt-space-2);border:var(--rt-thread-list-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-thread-list-card-radius);background:var(--rt-color-bg-surface-subtle);gap:var(--rt-space-2)}.rt-thread-list__empty-card--offset{transform:translate(20px)}.rt-thread-list__empty-avatar{display:grid;flex:0 0 auto;border-radius:var(--rt-thread-list-avatar-radius);background:var(--rt-color-text-muted);block-size:24px;color:var(--rt-color-bg-surface);inline-size:24px;place-items:center}.rt-thread-list__empty-lines{display:flex;flex-direction:column;gap:var(--rt-space-2)}.rt-thread-list__empty-line{border-radius:var(--rt-thread-list-line-radius);background:var(--rt-color-border-strong);block-size:6px;inline-size:112px}.rt-thread-list__empty-line--short{inline-size:48px}.rt-thread-list[data-rt-radius=none]{--rt-thread-list-card-radius: var(--rt-radius-none)}.rt-thread-list[data-rt-radius=xs]{--rt-thread-list-card-radius: var(--rt-radius-xs)}.rt-thread-list[data-rt-radius=sm]{--rt-thread-list-card-radius: var(--rt-radius-sm)}.rt-thread-list[data-rt-radius=ms]{--rt-thread-list-card-radius: var(--rt-radius-ms)}.rt-thread-list[data-rt-radius=md]{--rt-thread-list-card-radius: var(--rt-radius-md)}.rt-thread-list[data-rt-radius=lg]{--rt-thread-list-card-radius: var(--rt-radius-lg)}.rt-thread-list[data-rt-radius=xl]{--rt-thread-list-card-radius: var(--rt-radius-xl)}.rt-thread-list[data-rt-radius=\"2xl\"]{--rt-thread-list-card-radius: var(--rt-radius-2xl)}.rt-thread-list[data-rt-radius=full]{--rt-thread-list-card-radius: var(--rt-radius-full)}}\n"],
|
|
396
397
|
dependencies: [
|
|
397
398
|
{
|
|
398
399
|
kind: "directive",
|
|
@@ -511,6 +512,12 @@ var RtThreadListComponent = class RtThreadListComponent {
|
|
|
511
512
|
outputs: ["rtPopoverOpened", "rtPopoverClosed"],
|
|
512
513
|
exportAs: ["rtPopover"]
|
|
513
514
|
},
|
|
515
|
+
{
|
|
516
|
+
kind: "component",
|
|
517
|
+
type: RtServiceLogoComponent,
|
|
518
|
+
selector: "rt-service-logo",
|
|
519
|
+
inputs: ["logos", "size"]
|
|
520
|
+
},
|
|
514
521
|
{
|
|
515
522
|
kind: "component",
|
|
516
523
|
type: RtSkeletonComponent,
|
|
@@ -572,6 +579,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
572
579
|
RtIconButtonComponent,
|
|
573
580
|
RtInputComponent,
|
|
574
581
|
RtPopoverDirective,
|
|
582
|
+
RtServiceLogoComponent,
|
|
575
583
|
RtSkeletonComponent,
|
|
576
584
|
BlockDirective,
|
|
577
585
|
ElemDirective,
|
|
@@ -583,8 +591,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
583
591
|
inputs: ["radius"]
|
|
584
592
|
}],
|
|
585
593
|
host: { class: BEM_BLOCK },
|
|
586
|
-
template: "<ng-container rtBlock=\"rt-thread-list\">\n <header rtElem=\"head\">\n @if (searchTemplate()) {\n <div rtElem=\"search\" qa-dataid=\"thread-list-search\">\n <ng-container [ngTemplateOutlet]=\"searchTemplate()?.templateRef ?? null\" />\n </div>\n } @else {\n <rt-input\n rtElem=\"search\"\n qa-dataid=\"thread-list-search\"\n iconLeft=\"search\"\n [placeholder]=\"searchPlaceholderText()\"\n [formControl]=\"searchControl\" />\n }\n @if (filtersTemplate()) {\n <rt-icon-button\n rtElem=\"filter-trigger\"\n qa-dataid=\"thread-list-filter\"\n icon=\"filter\"\n variant=\"secondary\"\n rtPopoverAlign=\"end\"\n [ariaLabel]=\"t().uiFilters\"\n [indicator]=\"filtersActive()\"\n [rtPopover]=\"filtersPanel\" />\n }\n </header>\n\n <ng-template #rowButton let-row>\n <button\n rtElem=\"row\"\n qa-dataid=\"thread-list-row\"\n type=\"button\"\n [attr.data-id]=\"row.id\"\n [attr.data-unread]=\"row.hasUnread\"\n [attr.aria-current]=\"row.id === activeId() ? 'true' : null\"\n [rtMod]=\"{\n active: row.id === activeId(),\n unread: row.hasUnread,\n overdue: !!row.overdue,\n }\"\n (click)=\"onSelect(row.id, $event)\">\n <ng-container [ngTemplateOutlet]=\"rowTemplate()?.templateRef ?? null\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n
|
|
587
|
-
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-thread-list{--rt-thread-list-border-width: var(--rt-border-width-thin);--rt-thread-list-card-radius: var(--rt-radius-lg);--rt-thread-list-tag-radius: var(--rt-radius-sm);--rt-thread-list-dot-radius: var(--rt-radius-full);--rt-thread-list-avatar-radius: var(--rt-radius-full);--rt-thread-list-line-radius: var(--rt-radius-full);display:flex;flex:1 1 auto;flex-direction:column;min-block-size:0}.rt-thread-list__head{display:flex;flex:0 0 auto;align-items:center;block-size:56px;border-block-end:var(--rt-thread-list-border-width) solid var(--rt-color-border-strong);gap:var(--rt-space-2);padding-inline:var(--rt-space-4)}.rt-thread-list__search{flex:1 1 auto;min-inline-size:0}.rt-thread-list__filter-trigger{flex:0 0 auto}.rt-thread-list__filters-panel{display:flex;flex-direction:column;padding:var(--rt-space-4);gap:var(--rt-space-2);min-inline-size:220px}.rt-thread-list__rows{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:0;overflow-y:auto}.rt-thread-list__row{display:flex;align-items:center;justify-content:space-between;padding:var(--rt-space-2) var(--rt-space-4);border:none;background:none;border-inline-start:3px solid transparent;cursor:pointer;font-family:inherit;font-size:var(--rt-text-sm);gap:var(--rt-space-4);inline-size:100%;text-align:start}.rt-thread-list__row:hover{background:var(--rt-color-bg-subtle)}.rt-thread-list__row--active,.rt-thread-list__row--active:hover{background:var(--rt-color-state-info-bg);border-inline-start-color:var(--rt-color-action-primary)}.rt-thread-list__row--unread{position:relative;background:var(--rt-color-bg-subtle);border-inline-start-color:var(--rt-color-action-primary)}.rt-thread-list__row--unread .rt-thread-list__row-title{font-weight:var(--rt-font-weight-semibold)}.rt-thread-list__row--unread:before{position:absolute;border-radius:var(--rt-thread-list-dot-radius);background:var(--rt-color-action-primary);block-size:var(--rt-space-2);content:\"\";inline-size:var(--rt-space-2);inset-block-start:50%;inset-inline-start:var(--rt-space-2);transform:translateY(-50%)}.rt-thread-list__row--active,.rt-thread-list__row--active:hover{background:var(--rt-color-state-info-bg)}.rt-thread-list__row--overdue .rt-thread-list__row-time{color:var(--rt-color-state-error-text)}.rt-thread-list__row-wrap{position:relative}.rt-thread-list__row-wrap:hover .rt-thread-list__row-actions,.rt-thread-list__row-wrap:focus-within .rt-thread-list__row-actions,.rt-thread-list__row-wrap:has(.rt-menu--open) .rt-thread-list__row-actions{opacity:1;pointer-events:auto}.rt-thread-list__row-actions{position:absolute;display:flex;align-items:center;background:var(--rt-color-bg-subtle);gap:var(--rt-space-1);inset-block:0;inset-inline-end:0;opacity:0;padding-inline:var(--rt-space-2) var(--rt-space-4);pointer-events:none}.rt-thread-list__row--active+.rt-thread-list__row-actions{background:var(--rt-color-state-info-bg)}.rt-thread-list__row-body{display:flex;flex-direction:column;gap:var(--rt-space-0-5);min-inline-size:0}.rt-thread-list__row-title{overflow:hidden;color:var(--rt-color-text-primary);text-overflow:ellipsis;white-space:nowrap}.rt-thread-list__row-id{color:var(--rt-color-text-muted);font-size:var(--rt-text-sm)}.rt-thread-list__row:hover .rt-copy-cell__button,.rt-thread-list__row:focus-within .rt-copy-cell__button{opacity:1}.rt-thread-list__row-subtitle{overflow:hidden;color:var(--rt-color-text-muted);text-overflow:ellipsis;white-space:nowrap}.rt-thread-list__row-meta{display:flex;flex:0 0 auto;align-items:center;gap:var(--rt-space-2)}.rt-thread-list__row-time{color:var(--rt-color-text-muted);white-space:nowrap}.rt-thread-list__row-tag{padding:var(--rt-space-0-5) var(--rt-space-2);border-radius:var(--rt-thread-list-tag-radius);background:var(--rt-color-state-warning-bg);color:var(--rt-color-state-warning-text);font-size:var(--rt-text-xs);white-space:nowrap}.rt-thread-list__row-dot{display:inline-block;border-radius:var(--rt-thread-list-dot-radius);background:var(--rt-color-text-link);block-size:6px;inline-size:6px}.rt-thread-list__row-skeleton{display:flex;flex-direction:column;padding:var(--rt-space-2) var(--rt-space-4);gap:var(--rt-space-2)}.rt-thread-list__row-loader{display:flex;justify-content:center;padding:var(--rt-space-2) var(--rt-space-4)}.rt-thread-list__load-anchor{block-size:1px}.rt-thread-list__empty{padding:var(--rt-space-6) var(--rt-space-4)}.rt-thread-list__empty-preview{display:flex;flex-direction:column;gap:var(--rt-space-1)}.rt-thread-list__empty-card{display:flex;align-items:center;padding:var(--rt-space-2);border:var(--rt-thread-list-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-thread-list-card-radius);background:var(--rt-color-bg-surface-subtle);gap:var(--rt-space-2)}.rt-thread-list__empty-card--offset{transform:translate(20px)}.rt-thread-list__empty-avatar{display:grid;flex:0 0 auto;border-radius:var(--rt-thread-list-avatar-radius);background:var(--rt-color-text-muted);block-size:24px;color:var(--rt-color-bg-surface);inline-size:24px;place-items:center}.rt-thread-list__empty-lines{display:flex;flex-direction:column;gap:var(--rt-space-2)}.rt-thread-list__empty-line{border-radius:var(--rt-thread-list-line-radius);background:var(--rt-color-border-strong);block-size:6px;inline-size:112px}.rt-thread-list__empty-line--short{inline-size:48px}.rt-thread-list[data-rt-radius=none]{--rt-thread-list-card-radius: var(--rt-radius-none)}.rt-thread-list[data-rt-radius=xs]{--rt-thread-list-card-radius: var(--rt-radius-xs)}.rt-thread-list[data-rt-radius=sm]{--rt-thread-list-card-radius: var(--rt-radius-sm)}.rt-thread-list[data-rt-radius=ms]{--rt-thread-list-card-radius: var(--rt-radius-ms)}.rt-thread-list[data-rt-radius=md]{--rt-thread-list-card-radius: var(--rt-radius-md)}.rt-thread-list[data-rt-radius=lg]{--rt-thread-list-card-radius: var(--rt-radius-lg)}.rt-thread-list[data-rt-radius=xl]{--rt-thread-list-card-radius: var(--rt-radius-xl)}.rt-thread-list[data-rt-radius=\"2xl\"]{--rt-thread-list-card-radius: var(--rt-radius-2xl)}.rt-thread-list[data-rt-radius=full]{--rt-thread-list-card-radius: var(--rt-radius-full)}}\n"]
|
|
594
|
+
template: "<ng-container rtBlock=\"rt-thread-list\">\n <header rtElem=\"head\">\n @if (searchTemplate()) {\n <div rtElem=\"search\" qa-dataid=\"thread-list-search\">\n <ng-container [ngTemplateOutlet]=\"searchTemplate()?.templateRef ?? null\" />\n </div>\n } @else {\n <rt-input\n rtElem=\"search\"\n qa-dataid=\"thread-list-search\"\n iconLeft=\"search\"\n [placeholder]=\"searchPlaceholderText()\"\n [formControl]=\"searchControl\" />\n }\n @if (filtersTemplate()) {\n <rt-icon-button\n rtElem=\"filter-trigger\"\n qa-dataid=\"thread-list-filter\"\n icon=\"filter\"\n variant=\"secondary\"\n rtPopoverAlign=\"end\"\n [ariaLabel]=\"t().uiFilters\"\n [indicator]=\"filtersActive()\"\n [rtPopover]=\"filtersPanel\" />\n }\n </header>\n\n <ng-template #rowButton let-row>\n <button\n rtElem=\"row\"\n qa-dataid=\"thread-list-row\"\n type=\"button\"\n [attr.data-id]=\"row.id\"\n [attr.data-unread]=\"row.hasUnread\"\n [attr.aria-current]=\"row.id === activeId() ? 'true' : null\"\n [rtMod]=\"{\n active: row.id === activeId(),\n unread: row.hasUnread,\n overdue: !!row.overdue,\n }\"\n (click)=\"onSelect(row.id, $event)\">\n @if (row.sign; as sign) {\n <rt-service-logo rtElem=\"row-sign\" qa-dataid=\"thread-list-row-sign\" size=\"xs\" [logos]=\"[sign]\" />\n <span rtElem=\"row-content\">\n <ng-container [ngTemplateOutlet]=\"rowContent\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </span>\n } @else {\n <ng-container [ngTemplateOutlet]=\"rowContent\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n </button>\n </ng-template>\n\n <ng-template #rowContent let-row>\n <ng-container [ngTemplateOutlet]=\"rowTemplate()?.templateRef ?? null\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </ng-template>\n\n <ng-template #filtersPanel>\n <div rtElem=\"filters-panel\" qa-dataid=\"thread-list-filters-panel\">\n <ng-container [ngTemplateOutlet]=\"filtersTemplate()?.templateRef ?? null\" />\n </div>\n </ng-template>\n\n <div rtElem=\"rows\" qa-dataid=\"thread-list-rows\">\n @if (loading() && !rows().length) {\n @for (i of skeletonRows; track i) {\n <div rtElem=\"row-skeleton\" qa-dataid=\"thread-list-row-skeleton\" aria-hidden=\"true\">\n <rt-skeleton width=\"60%\" height=\"14px\" />\n <rt-skeleton width=\"90%\" height=\"12px\" />\n </div>\n }\n } @else if (!rows().length) {\n <rt-empty-state rtElem=\"empty\" qa-dataid=\"thread-list-empty\" [description]=\"t().uiThreadListEmptyHint\" [title]=\"emptyTitle()\">\n <div rtEmptyIllustration rtElem=\"empty-preview\">\n @for (row of emptyPreviewRows(); track row.id) {\n <div rtElem=\"empty-card\" [rtMod]=\"{ offset: row.offset }\">\n <span rtElem=\"empty-avatar\">\n <rt-icon size=\"sm\" [name]=\"row.icon\" />\n </span>\n <span rtElem=\"empty-lines\">\n <span rtElem=\"empty-line\" [rtMod]=\"{ short: true }\"></span>\n <span rtElem=\"empty-line\"></span>\n </span>\n </div>\n }\n </div>\n </rt-empty-state>\n } @else {\n @for (row of rows(); track row.id) {\n @if (rowActionsTemplate(); as actions) {\n <div rtElem=\"row-wrap\" qa-dataid=\"thread-list-row-wrap\">\n <ng-container [ngTemplateOutlet]=\"rowButton\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n <div rtElem=\"row-actions\" qa-dataid=\"thread-list-row-actions\">\n <ng-container [ngTemplateOutlet]=\"actions.templateRef\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </div>\n </div>\n } @else {\n <ng-container [ngTemplateOutlet]=\"rowButton\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n }\n @if (fetching()) {\n <div rtElem=\"row-loader\" qa-dataid=\"thread-list-row-loader\">\n <rt-skeleton width=\"90%\" height=\"12px\" />\n </div>\n }\n @if (hasMore()) {\n <div\n rtElem=\"load-anchor\"\n qa-dataid=\"thread-list-load-more\"\n aria-hidden=\"true\"\n rtInfiniteScroll\n [disabled]=\"fetching()\"\n (loadMore)=\"onLoadMore()\"></div>\n }\n }\n </div>\n</ng-container>\n",
|
|
595
|
+
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-thread-list{--rt-thread-list-border-width: var(--rt-border-width-thin);--rt-thread-list-card-radius: var(--rt-radius-lg);--rt-thread-list-tag-radius: var(--rt-radius-sm);--rt-thread-list-dot-radius: var(--rt-radius-full);--rt-thread-list-avatar-radius: var(--rt-radius-full);--rt-thread-list-line-radius: var(--rt-radius-full);display:flex;flex:1 1 auto;flex-direction:column;min-block-size:0}.rt-thread-list__head{display:flex;flex:0 0 auto;align-items:center;block-size:56px;border-block-end:var(--rt-thread-list-border-width) solid var(--rt-color-border-strong);gap:var(--rt-space-2);padding-inline:var(--rt-space-4)}.rt-thread-list__search{flex:1 1 auto;min-inline-size:0}.rt-thread-list__filter-trigger{flex:0 0 auto}.rt-thread-list__filters-panel{display:flex;flex-direction:column;padding:var(--rt-space-4);gap:var(--rt-space-2);min-inline-size:220px}.rt-thread-list__rows{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:0;overflow-y:auto}.rt-thread-list__row{display:flex;align-items:center;justify-content:space-between;padding:var(--rt-space-2) var(--rt-space-4);border:none;background:none;border-inline-start:3px solid transparent;cursor:pointer;font-family:inherit;font-size:var(--rt-text-sm);gap:var(--rt-space-4);inline-size:100%;text-align:start}.rt-thread-list__row:hover{background:var(--rt-color-bg-subtle)}.rt-thread-list__row--active,.rt-thread-list__row--active:hover{background:var(--rt-color-state-info-bg);border-inline-start-color:var(--rt-color-action-primary)}.rt-thread-list__row--unread{position:relative;background:var(--rt-color-bg-subtle);border-inline-start-color:var(--rt-color-action-primary)}.rt-thread-list__row--unread .rt-thread-list__row-title{font-weight:var(--rt-font-weight-semibold)}.rt-thread-list__row--unread:before{position:absolute;border-radius:var(--rt-thread-list-dot-radius);background:var(--rt-color-action-primary);block-size:var(--rt-space-2);content:\"\";inline-size:var(--rt-space-2);inset-block-start:50%;inset-inline-start:var(--rt-space-2);transform:translateY(-50%)}.rt-thread-list__row--active,.rt-thread-list__row--active:hover{background:var(--rt-color-state-info-bg)}.rt-thread-list__row--overdue .rt-thread-list__row-time{color:var(--rt-color-state-error-text)}.rt-thread-list__row-wrap{position:relative}.rt-thread-list__row-wrap:hover .rt-thread-list__row-actions,.rt-thread-list__row-wrap:focus-within .rt-thread-list__row-actions,.rt-thread-list__row-wrap:has(.rt-menu--open) .rt-thread-list__row-actions{opacity:1;pointer-events:auto}.rt-thread-list__row-actions{position:absolute;display:flex;align-items:center;background:var(--rt-color-bg-subtle);gap:var(--rt-space-1);inset-block:0;inset-inline-end:0;opacity:0;padding-inline:var(--rt-space-2) var(--rt-space-4);pointer-events:none}.rt-thread-list__row--active+.rt-thread-list__row-actions{background:var(--rt-color-state-info-bg)}.rt-thread-list__row-sign{flex:none}.rt-thread-list__row-content{display:flex;flex:1 1 auto;align-items:center;justify-content:space-between;gap:var(--rt-space-4);min-inline-size:0}.rt-thread-list__row-body{display:flex;flex-direction:column;gap:var(--rt-space-0-5);min-inline-size:0}.rt-thread-list__row-title{overflow:hidden;color:var(--rt-color-text-primary);text-overflow:ellipsis;white-space:nowrap}.rt-thread-list__row-id{color:var(--rt-color-text-muted);font-size:var(--rt-text-sm)}.rt-thread-list__row:hover .rt-copy-cell__button,.rt-thread-list__row:focus-within .rt-copy-cell__button{opacity:1}.rt-thread-list__row-subtitle{overflow:hidden;color:var(--rt-color-text-muted);text-overflow:ellipsis;white-space:nowrap}.rt-thread-list__row-meta{display:flex;flex:0 0 auto;align-items:center;gap:var(--rt-space-2)}.rt-thread-list__row-time{color:var(--rt-color-text-muted);white-space:nowrap}.rt-thread-list__row-tag{padding:var(--rt-space-0-5) var(--rt-space-2);border-radius:var(--rt-thread-list-tag-radius);background:var(--rt-color-state-warning-bg);color:var(--rt-color-state-warning-text);font-size:var(--rt-text-xs);white-space:nowrap}.rt-thread-list__row-dot{display:inline-block;border-radius:var(--rt-thread-list-dot-radius);background:var(--rt-color-text-link);block-size:6px;inline-size:6px}.rt-thread-list__row-skeleton{display:flex;flex-direction:column;padding:var(--rt-space-2) var(--rt-space-4);gap:var(--rt-space-2)}.rt-thread-list__row-loader{display:flex;justify-content:center;padding:var(--rt-space-2) var(--rt-space-4)}.rt-thread-list__load-anchor{block-size:1px}.rt-thread-list__empty{padding:var(--rt-space-6) var(--rt-space-4)}.rt-thread-list__empty-preview{display:flex;flex-direction:column;gap:var(--rt-space-1)}.rt-thread-list__empty-card{display:flex;align-items:center;padding:var(--rt-space-2);border:var(--rt-thread-list-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-thread-list-card-radius);background:var(--rt-color-bg-surface-subtle);gap:var(--rt-space-2)}.rt-thread-list__empty-card--offset{transform:translate(20px)}.rt-thread-list__empty-avatar{display:grid;flex:0 0 auto;border-radius:var(--rt-thread-list-avatar-radius);background:var(--rt-color-text-muted);block-size:24px;color:var(--rt-color-bg-surface);inline-size:24px;place-items:center}.rt-thread-list__empty-lines{display:flex;flex-direction:column;gap:var(--rt-space-2)}.rt-thread-list__empty-line{border-radius:var(--rt-thread-list-line-radius);background:var(--rt-color-border-strong);block-size:6px;inline-size:112px}.rt-thread-list__empty-line--short{inline-size:48px}.rt-thread-list[data-rt-radius=none]{--rt-thread-list-card-radius: var(--rt-radius-none)}.rt-thread-list[data-rt-radius=xs]{--rt-thread-list-card-radius: var(--rt-radius-xs)}.rt-thread-list[data-rt-radius=sm]{--rt-thread-list-card-radius: var(--rt-radius-sm)}.rt-thread-list[data-rt-radius=ms]{--rt-thread-list-card-radius: var(--rt-radius-ms)}.rt-thread-list[data-rt-radius=md]{--rt-thread-list-card-radius: var(--rt-radius-md)}.rt-thread-list[data-rt-radius=lg]{--rt-thread-list-card-radius: var(--rt-radius-lg)}.rt-thread-list[data-rt-radius=xl]{--rt-thread-list-card-radius: var(--rt-radius-xl)}.rt-thread-list[data-rt-radius=\"2xl\"]{--rt-thread-list-card-radius: var(--rt-radius-2xl)}.rt-thread-list[data-rt-radius=full]{--rt-thread-list-card-radius: var(--rt-radius-full)}}\n"]
|
|
588
596
|
}]
|
|
589
597
|
}],
|
|
590
598
|
propDecorators: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rt-tools-ui-kit-v2-thread-list.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/thread-list/rt-thread-list.directives.ts","../../../projects/ui-kit-v2/src/lib/components/thread-list/rt-thread-list.component.ts","../../../projects/ui-kit-v2/src/lib/components/thread-list/rt-thread-list.component.html"],"sourcesContent":["import { Directive, inject, input, InputSignal, TemplateRef } from '@angular/core';\n\nimport { IRtThreadList } from './rt-thread-list.model';\n\n/**\n * Помечает `<ng-template>` содержимого строки списка. Входом `[rtThreadListRow]`\n * потребитель передаёт свой массив строк — из него выводится тип `TRow`, поэтому\n * `let-row` в темплейте типизируется строго (context-guard ниже это подтверждает).\n */\n@Directive({\n selector: 'ng-template[rtThreadListRow]',\n})\nexport class RtThreadListRowDirective<TRow extends IRtThreadList.Row> {\n public readonly templateRef: TemplateRef<IRtThreadList.RowContext<TRow>> =\n inject<TemplateRef<IRtThreadList.RowContext<TRow>>>(TemplateRef);\n\n public readonly rows: InputSignal<readonly TRow[]> = input<readonly TRow[]>([], {\n alias: 'rtThreadListRow',\n });\n\n public static ngTemplateContextGuard<TRow extends IRtThreadList.Row>(\n _directive: RtThreadListRowDirective<TRow>,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- второй довод стража контекста шаблона стоит только в типе-предикате; убрать его нечем, подпись задаёт каркас\n context: unknown\n ): context is IRtThreadList.RowContext<TRow> {\n return true;\n }\n}\n\n/**\n * Помечает `<ng-template>` действий строки (удалить, закрепить). Действия рисуются рядом с\n * кнопкой строки, а не внутри неё: вложенная кнопка в `<button>` недопустима и крадёт клик\n * выбора строки. Видны при наведении и фокусе внутри строки.\n */\n@Directive({\n selector: 'ng-template[rtThreadListRowActions]',\n})\nexport class RtThreadListRowActionsDirective<TRow extends IRtThreadList.Row> {\n public readonly templateRef: TemplateRef<IRtThreadList.RowContext<TRow>> =\n inject<TemplateRef<IRtThreadList.RowContext<TRow>>>(TemplateRef);\n\n public readonly rows: InputSignal<readonly TRow[]> = input<readonly TRow[]>([], {\n alias: 'rtThreadListRowActions',\n });\n\n public static ngTemplateContextGuard<TRow extends IRtThreadList.Row>(\n _directive: RtThreadListRowActionsDirective<TRow>,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- второй довод стража контекста шаблона стоит только в типе-предикате; убрать его нечем, подпись задаёт каркас\n context: unknown\n ): context is IRtThreadList.RowContext<TRow> {\n return true;\n }\n}\n\n/**\n * Помечает `<ng-template>` с фильтрами — его содержимое рендерится в поповере,\n * который открывает иконка-фильтр в шапке списка.\n */\n@Directive({\n selector: 'ng-template[rtThreadListFilters]',\n})\nexport class RtThreadListFiltersDirective {\n public readonly templateRef: TemplateRef<unknown> = inject<TemplateRef<unknown>>(TemplateRef);\n}\n\n/**\n * Помечает `<ng-template>` с кастомным контролом поиска. Когда потребитель его\n * проецирует, шапка списка рендерит его содержимое вместо встроенного `rt-input`\n * — так воркспейс подставляет свой автокомплит по каталогу вместо текстового\n * поиска, не ломая generic-природу списка.\n */\n@Directive({\n selector: 'ng-template[rtThreadListSearch]',\n})\nexport class RtThreadListSearchDirective {\n public readonly templateRef: TemplateRef<unknown> = inject<TemplateRef<unknown>>(TemplateRef);\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n computed,\n contentChild,\n inject,\n input,\n output,\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n InputSignal,\n InputSignalWithTransform,\n OnInit,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { FormControl, ReactiveFormsModule } from '@angular/forms';\n\nimport { distinctUntilChanged, map } from 'rxjs';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RT_KIT_LABELS, TRtKitLabelMap, rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { searchDebounce } from '@rt-tools/ui-kit-v2/core';\n\nimport { RtInfiniteScrollDirective } from '@rt-tools/ui-kit-v2/core';\nimport { RtEmptyStateComponent } from '@rt-tools/ui-kit-v2/empty-state';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport { RtInputComponent } from '@rt-tools/ui-kit-v2/input';\nimport { RtPopoverDirective } from '@rt-tools/ui-kit-v2/popover';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RtSkeletonComponent } from '@rt-tools/ui-kit-v2/skeleton';\nimport {\n RtThreadListFiltersDirective,\n RtThreadListRowActionsDirective,\n RtThreadListRowDirective,\n RtThreadListSearchDirective,\n} from './rt-thread-list.directives';\nimport { IRtThreadList } from './rt-thread-list.model';\n\nconst BEM_BLOCK: string = 'rt-thread-list';\n\n/** Кол-во скелетон-строк на первичной загрузке (пока `rows` пусты). */\nconst SKELETON_ROWS_COUNT: number = 6;\n\n/** Значки строк-превью пустого списка по умолчанию: люди переписки. */\nconst PREVIEW_ICONS: readonly IRtIcon.Name[] = ['user', 'users', 'user'];\n\n/**\n * Презентационный список тредов для воркспейсов:\n * поиск с дебаунсом, фильтр-поповер и бесконечная прокрутка. Данные и оркестрация\n * — на вызывающем; список стора/api не видит.\n *\n * Строку рисует потребитель через `<ng-template rtThreadListRow let-row>` (body +\n * meta); оболочка владеет кнопкой строки (active/unread/overdue), поиском, кнопкой\n * фильтров (точка-индикатор при `filtersActive`) и скроллом. Фильтры потребитель\n * кладёт в `<ng-template rtThreadListFilters>` — они рендерятся в поповере.\n */\n@Component({\n selector: 'rt-thread-list',\n templateUrl: './rt-thread-list.component.html',\n styleUrls: ['./rt-thread-list.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n NgTemplateOutlet,\n ReactiveFormsModule,\n\n // standalone components / directives\n RtEmptyStateComponent,\n RtIconComponent,\n RtIconButtonComponent,\n RtInputComponent,\n RtPopoverDirective,\n RtSkeletonComponent,\n BlockDirective,\n ElemDirective,\n RtInfiniteScrollDirective,\n ModDirective,\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtThreadListComponent<TRow extends IRtThreadList.Row> implements OnInit {\n readonly #destroyRef: DestroyRef = inject(DestroyRef);\n\n readonly #t_uiSearch: Signal<string> = rtKitLabel('uiSearch');\n readonly #t_uiNothingFound: Signal<string> = rtKitLabel('uiNothingFound');\n\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly searchPlaceholderText: Signal<string> = computed((): string => this.searchPlaceholder() || this.#t_uiSearch());\n protected readonly emptyTitle: Signal<string> = computed((): string => this.emptyText() || this.#t_uiNothingFound());\n\n protected readonly skeletonRows: number[] = Array.from({ length: SKELETON_ROWS_COUNT }, (_: unknown, i: number): number => i);\n\n /** Декоративные строки-превью пустого состояния: значок строки из `emptyPreviewIcons`, каждая вторая сдвинута. */\n protected readonly emptyPreviewRows: Signal<readonly IRtThreadList.PreviewRow[]> = computed((): readonly IRtThreadList.PreviewRow[] =>\n this.emptyPreviewIcons().map((icon: IRtIcon.Name, index: number): IRtThreadList.PreviewRow => ({\n icon,\n id: index,\n offset: index % 2 === 1,\n }))\n );\n\n protected readonly searchControl: FormControl<string> = new FormControl<string>('', {\n nonNullable: true,\n });\n\n protected readonly rowTemplate: Signal<RtThreadListRowDirective<TRow> | undefined> = contentChild(RtThreadListRowDirective<TRow>);\n\n protected readonly rowActionsTemplate: Signal<RtThreadListRowActionsDirective<TRow> | undefined> = contentChild(\n RtThreadListRowActionsDirective<TRow>\n );\n\n protected readonly filtersTemplate: Signal<RtThreadListFiltersDirective | undefined> = contentChild(RtThreadListFiltersDirective);\n\n protected readonly searchTemplate: Signal<RtThreadListSearchDirective | undefined> = contentChild(RtThreadListSearchDirective);\n\n public readonly rows: InputSignal<readonly TRow[]> = input<readonly TRow[]>([]);\n\n public readonly activeId: InputSignal<IRtThreadList.TRowId | null> = input<IRtThreadList.TRowId | null>(null);\n\n /** Пусто — берётся переведённая подпись по умолчанию */\n public readonly searchPlaceholder: InputSignal<string> = input<string>('');\n\n public readonly emptyText: InputSignal<string> = input<string>('');\n\n /** Значки декоративных строк-превью пустого состояния, по строке на значок */\n public readonly emptyPreviewIcons: InputSignal<readonly IRtIcon.Name[]> = input<readonly IRtIcon.Name[]>(PREVIEW_ICONS);\n\n public readonly loading: InputSignalWithTransform<boolean, boolean | string> = input<boolean, boolean | string>(false, {\n transform: booleanAttribute,\n });\n\n public readonly fetching: InputSignalWithTransform<boolean, boolean | string> = input<boolean, boolean | string>(false, {\n transform: booleanAttribute,\n });\n\n public readonly hasMore: InputSignalWithTransform<boolean, boolean | string> = input<boolean, boolean | string>(false, {\n transform: booleanAttribute,\n });\n\n public readonly filtersActive: InputSignalWithTransform<boolean, boolean | string> = input<boolean, boolean | string>(false, {\n transform: booleanAttribute,\n });\n\n // Имя `select` зарезервировано под нативное DOM-событие\n // (@angular-eslint/no-output-native), поэтому output переименован.\n public readonly selectRow: OutputEmitterRef<IRtThreadList.TRowId> = output<IRtThreadList.TRowId>();\n\n // Ctrl/⌘+клик по строке: потребитель открывает строку в новой вкладке.\n // Обычный клик остаётся на `selectRow`.\n public readonly openInNewTab: OutputEmitterRef<IRtThreadList.TRowId> = output<IRtThreadList.TRowId>();\n\n public readonly searchChange: OutputEmitterRef<string> = output<string>();\n\n public readonly loadMore: OutputEmitterRef<void> = output<void>();\n\n public ngOnInit(): void {\n // Дебаунс непустого ввода; очистка крестиком применяется сразу (searchDebounce).\n this.searchControl.valueChanges\n .pipe(\n map((value: string): string => value.trim()),\n searchDebounce(),\n distinctUntilChanged(),\n takeUntilDestroyed(this.#destroyRef)\n )\n .subscribe((value: string): void => this.searchChange.emit(value));\n }\n\n protected onSelect(id: IRtThreadList.TRowId, event: MouseEvent): void {\n // Ctrl (Win/Linux) или ⌘ (macOS) — «открыть в новой вкладке», как у\n // нативных ссылок. Иначе — обычный выбор строки в текущей вкладке.\n if (event.ctrlKey || event.metaKey) {\n this.openInNewTab.emit(id);\n return;\n }\n this.selectRow.emit(id);\n }\n\n protected onLoadMore(): void {\n this.loadMore.emit();\n }\n}\n","<ng-container rtBlock=\"rt-thread-list\">\n <header rtElem=\"head\">\n @if (searchTemplate()) {\n <div rtElem=\"search\" qa-dataid=\"thread-list-search\">\n <ng-container [ngTemplateOutlet]=\"searchTemplate()?.templateRef ?? null\" />\n </div>\n } @else {\n <rt-input\n rtElem=\"search\"\n qa-dataid=\"thread-list-search\"\n iconLeft=\"search\"\n [placeholder]=\"searchPlaceholderText()\"\n [formControl]=\"searchControl\" />\n }\n @if (filtersTemplate()) {\n <rt-icon-button\n rtElem=\"filter-trigger\"\n qa-dataid=\"thread-list-filter\"\n icon=\"filter\"\n variant=\"secondary\"\n rtPopoverAlign=\"end\"\n [ariaLabel]=\"t().uiFilters\"\n [indicator]=\"filtersActive()\"\n [rtPopover]=\"filtersPanel\" />\n }\n </header>\n\n <ng-template #rowButton let-row>\n <button\n rtElem=\"row\"\n qa-dataid=\"thread-list-row\"\n type=\"button\"\n [attr.data-id]=\"row.id\"\n [attr.data-unread]=\"row.hasUnread\"\n [attr.aria-current]=\"row.id === activeId() ? 'true' : null\"\n [rtMod]=\"{\n active: row.id === activeId(),\n unread: row.hasUnread,\n overdue: !!row.overdue,\n }\"\n (click)=\"onSelect(row.id, $event)\">\n <ng-container [ngTemplateOutlet]=\"rowTemplate()?.templateRef ?? null\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </button>\n </ng-template>\n\n <ng-template #filtersPanel>\n <div rtElem=\"filters-panel\" qa-dataid=\"thread-list-filters-panel\">\n <ng-container [ngTemplateOutlet]=\"filtersTemplate()?.templateRef ?? null\" />\n </div>\n </ng-template>\n\n <div rtElem=\"rows\" qa-dataid=\"thread-list-rows\">\n @if (loading() && !rows().length) {\n @for (i of skeletonRows; track i) {\n <div rtElem=\"row-skeleton\" qa-dataid=\"thread-list-row-skeleton\" aria-hidden=\"true\">\n <rt-skeleton width=\"60%\" height=\"14px\" />\n <rt-skeleton width=\"90%\" height=\"12px\" />\n </div>\n }\n } @else if (!rows().length) {\n <rt-empty-state rtElem=\"empty\" qa-dataid=\"thread-list-empty\" [description]=\"t().uiThreadListEmptyHint\" [title]=\"emptyTitle()\">\n <div rtEmptyIllustration rtElem=\"empty-preview\">\n @for (row of emptyPreviewRows(); track row.id) {\n <div rtElem=\"empty-card\" [rtMod]=\"{ offset: row.offset }\">\n <span rtElem=\"empty-avatar\">\n <rt-icon size=\"sm\" [name]=\"row.icon\" />\n </span>\n <span rtElem=\"empty-lines\">\n <span rtElem=\"empty-line\" [rtMod]=\"{ short: true }\"></span>\n <span rtElem=\"empty-line\"></span>\n </span>\n </div>\n }\n </div>\n </rt-empty-state>\n } @else {\n @for (row of rows(); track row.id) {\n @if (rowActionsTemplate(); as actions) {\n <div rtElem=\"row-wrap\" qa-dataid=\"thread-list-row-wrap\">\n <ng-container [ngTemplateOutlet]=\"rowButton\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n <div rtElem=\"row-actions\" qa-dataid=\"thread-list-row-actions\">\n <ng-container [ngTemplateOutlet]=\"actions.templateRef\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </div>\n </div>\n } @else {\n <ng-container [ngTemplateOutlet]=\"rowButton\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n }\n @if (fetching()) {\n <div rtElem=\"row-loader\" qa-dataid=\"thread-list-row-loader\">\n <rt-skeleton width=\"90%\" height=\"12px\" />\n </div>\n }\n @if (hasMore()) {\n <div\n rtElem=\"load-anchor\"\n qa-dataid=\"thread-list-load-more\"\n aria-hidden=\"true\"\n rtInfiniteScroll\n [disabled]=\"fetching()\"\n (loadMore)=\"onLoadMore()\"></div>\n }\n }\n </div>\n</ng-container>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rt-tools-ui-kit-v2-thread-list.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/thread-list/rt-thread-list.directives.ts","../../../projects/ui-kit-v2/src/lib/components/thread-list/rt-thread-list.component.ts","../../../projects/ui-kit-v2/src/lib/components/thread-list/rt-thread-list.component.html"],"sourcesContent":["import { Directive, inject, input, InputSignal, TemplateRef } from '@angular/core';\n\nimport { IRtThreadList } from './rt-thread-list.model';\n\n/**\n * Помечает `<ng-template>` содержимого строки списка. Входом `[rtThreadListRow]`\n * потребитель передаёт свой массив строк — из него выводится тип `TRow`, поэтому\n * `let-row` в темплейте типизируется строго (context-guard ниже это подтверждает).\n */\n@Directive({\n selector: 'ng-template[rtThreadListRow]',\n})\nexport class RtThreadListRowDirective<TRow extends IRtThreadList.Row> {\n public readonly templateRef: TemplateRef<IRtThreadList.RowContext<TRow>> =\n inject<TemplateRef<IRtThreadList.RowContext<TRow>>>(TemplateRef);\n\n public readonly rows: InputSignal<readonly TRow[]> = input<readonly TRow[]>([], {\n alias: 'rtThreadListRow',\n });\n\n public static ngTemplateContextGuard<TRow extends IRtThreadList.Row>(\n _directive: RtThreadListRowDirective<TRow>,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- второй довод стража контекста шаблона стоит только в типе-предикате; убрать его нечем, подпись задаёт каркас\n context: unknown\n ): context is IRtThreadList.RowContext<TRow> {\n return true;\n }\n}\n\n/**\n * Помечает `<ng-template>` действий строки (удалить, закрепить). Действия рисуются рядом с\n * кнопкой строки, а не внутри неё: вложенная кнопка в `<button>` недопустима и крадёт клик\n * выбора строки. Видны при наведении и фокусе внутри строки.\n */\n@Directive({\n selector: 'ng-template[rtThreadListRowActions]',\n})\nexport class RtThreadListRowActionsDirective<TRow extends IRtThreadList.Row> {\n public readonly templateRef: TemplateRef<IRtThreadList.RowContext<TRow>> =\n inject<TemplateRef<IRtThreadList.RowContext<TRow>>>(TemplateRef);\n\n public readonly rows: InputSignal<readonly TRow[]> = input<readonly TRow[]>([], {\n alias: 'rtThreadListRowActions',\n });\n\n public static ngTemplateContextGuard<TRow extends IRtThreadList.Row>(\n _directive: RtThreadListRowActionsDirective<TRow>,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- второй довод стража контекста шаблона стоит только в типе-предикате; убрать его нечем, подпись задаёт каркас\n context: unknown\n ): context is IRtThreadList.RowContext<TRow> {\n return true;\n }\n}\n\n/**\n * Помечает `<ng-template>` с фильтрами — его содержимое рендерится в поповере,\n * который открывает иконка-фильтр в шапке списка.\n */\n@Directive({\n selector: 'ng-template[rtThreadListFilters]',\n})\nexport class RtThreadListFiltersDirective {\n public readonly templateRef: TemplateRef<unknown> = inject<TemplateRef<unknown>>(TemplateRef);\n}\n\n/**\n * Помечает `<ng-template>` с кастомным контролом поиска. Когда потребитель его\n * проецирует, шапка списка рендерит его содержимое вместо встроенного `rt-input`\n * — так воркспейс подставляет свой автокомплит по каталогу вместо текстового\n * поиска, не ломая generic-природу списка.\n */\n@Directive({\n selector: 'ng-template[rtThreadListSearch]',\n})\nexport class RtThreadListSearchDirective {\n public readonly templateRef: TemplateRef<unknown> = inject<TemplateRef<unknown>>(TemplateRef);\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n computed,\n contentChild,\n inject,\n input,\n output,\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n InputSignal,\n InputSignalWithTransform,\n OnInit,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { FormControl, ReactiveFormsModule } from '@angular/forms';\n\nimport { distinctUntilChanged, map } from 'rxjs';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RT_KIT_LABELS, TRtKitLabelMap, rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { searchDebounce } from '@rt-tools/ui-kit-v2/core';\n\nimport { RtInfiniteScrollDirective } from '@rt-tools/ui-kit-v2/core';\nimport { RtEmptyStateComponent } from '@rt-tools/ui-kit-v2/empty-state';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport { RtInputComponent } from '@rt-tools/ui-kit-v2/input';\nimport { RtPopoverDirective } from '@rt-tools/ui-kit-v2/popover';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RtServiceLogoComponent } from '@rt-tools/ui-kit-v2/service-logo';\nimport { RtSkeletonComponent } from '@rt-tools/ui-kit-v2/skeleton';\nimport {\n RtThreadListFiltersDirective,\n RtThreadListRowActionsDirective,\n RtThreadListRowDirective,\n RtThreadListSearchDirective,\n} from './rt-thread-list.directives';\nimport { IRtThreadList } from './rt-thread-list.model';\n\nconst BEM_BLOCK: string = 'rt-thread-list';\n\n/** Кол-во скелетон-строк на первичной загрузке (пока `rows` пусты). */\nconst SKELETON_ROWS_COUNT: number = 6;\n\n/** Значки строк-превью пустого списка по умолчанию: люди переписки. */\nconst PREVIEW_ICONS: readonly IRtIcon.Name[] = ['user', 'users', 'user'];\n\n/**\n * Презентационный список тредов для воркспейсов:\n * поиск с дебаунсом, фильтр-поповер и бесконечная прокрутка. Данные и оркестрация\n * — на вызывающем; список стора/api не видит.\n *\n * Строку рисует потребитель через `<ng-template rtThreadListRow let-row>` (body +\n * meta); оболочка владеет кнопкой строки (active/unread/overdue), поиском, кнопкой\n * фильтров (точка-индикатор при `filtersActive`) и скроллом. Фильтры потребитель\n * кладёт в `<ng-template rtThreadListFilters>` — они рендерятся в поповере.\n */\n@Component({\n selector: 'rt-thread-list',\n templateUrl: './rt-thread-list.component.html',\n styleUrls: ['./rt-thread-list.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n NgTemplateOutlet,\n ReactiveFormsModule,\n\n // standalone components / directives\n RtEmptyStateComponent,\n RtIconComponent,\n RtIconButtonComponent,\n RtInputComponent,\n RtPopoverDirective,\n RtServiceLogoComponent,\n RtSkeletonComponent,\n BlockDirective,\n ElemDirective,\n RtInfiniteScrollDirective,\n ModDirective,\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtThreadListComponent<TRow extends IRtThreadList.Row> implements OnInit {\n readonly #destroyRef: DestroyRef = inject(DestroyRef);\n\n readonly #t_uiSearch: Signal<string> = rtKitLabel('uiSearch');\n readonly #t_uiNothingFound: Signal<string> = rtKitLabel('uiNothingFound');\n\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly searchPlaceholderText: Signal<string> = computed((): string => this.searchPlaceholder() || this.#t_uiSearch());\n protected readonly emptyTitle: Signal<string> = computed((): string => this.emptyText() || this.#t_uiNothingFound());\n\n protected readonly skeletonRows: number[] = Array.from({ length: SKELETON_ROWS_COUNT }, (_: unknown, i: number): number => i);\n\n /** Декоративные строки-превью пустого состояния: значок строки из `emptyPreviewIcons`, каждая вторая сдвинута. */\n protected readonly emptyPreviewRows: Signal<readonly IRtThreadList.PreviewRow[]> = computed((): readonly IRtThreadList.PreviewRow[] =>\n this.emptyPreviewIcons().map((icon: IRtIcon.Name, index: number): IRtThreadList.PreviewRow => ({\n icon,\n id: index,\n offset: index % 2 === 1,\n }))\n );\n\n protected readonly searchControl: FormControl<string> = new FormControl<string>('', {\n nonNullable: true,\n });\n\n protected readonly rowTemplate: Signal<RtThreadListRowDirective<TRow> | undefined> = contentChild(RtThreadListRowDirective<TRow>);\n\n protected readonly rowActionsTemplate: Signal<RtThreadListRowActionsDirective<TRow> | undefined> = contentChild(\n RtThreadListRowActionsDirective<TRow>\n );\n\n protected readonly filtersTemplate: Signal<RtThreadListFiltersDirective | undefined> = contentChild(RtThreadListFiltersDirective);\n\n protected readonly searchTemplate: Signal<RtThreadListSearchDirective | undefined> = contentChild(RtThreadListSearchDirective);\n\n public readonly rows: InputSignal<readonly TRow[]> = input<readonly TRow[]>([]);\n\n public readonly activeId: InputSignal<IRtThreadList.TRowId | null> = input<IRtThreadList.TRowId | null>(null);\n\n /** Пусто — берётся переведённая подпись по умолчанию */\n public readonly searchPlaceholder: InputSignal<string> = input<string>('');\n\n public readonly emptyText: InputSignal<string> = input<string>('');\n\n /** Значки декоративных строк-превью пустого состояния, по строке на значок */\n public readonly emptyPreviewIcons: InputSignal<readonly IRtIcon.Name[]> = input<readonly IRtIcon.Name[]>(PREVIEW_ICONS);\n\n public readonly loading: InputSignalWithTransform<boolean, boolean | string> = input<boolean, boolean | string>(false, {\n transform: booleanAttribute,\n });\n\n public readonly fetching: InputSignalWithTransform<boolean, boolean | string> = input<boolean, boolean | string>(false, {\n transform: booleanAttribute,\n });\n\n public readonly hasMore: InputSignalWithTransform<boolean, boolean | string> = input<boolean, boolean | string>(false, {\n transform: booleanAttribute,\n });\n\n public readonly filtersActive: InputSignalWithTransform<boolean, boolean | string> = input<boolean, boolean | string>(false, {\n transform: booleanAttribute,\n });\n\n // Имя `select` зарезервировано под нативное DOM-событие\n // (@angular-eslint/no-output-native), поэтому output переименован.\n public readonly selectRow: OutputEmitterRef<IRtThreadList.TRowId> = output<IRtThreadList.TRowId>();\n\n // Ctrl/⌘+клик по строке: потребитель открывает строку в новой вкладке.\n // Обычный клик остаётся на `selectRow`.\n public readonly openInNewTab: OutputEmitterRef<IRtThreadList.TRowId> = output<IRtThreadList.TRowId>();\n\n public readonly searchChange: OutputEmitterRef<string> = output<string>();\n\n public readonly loadMore: OutputEmitterRef<void> = output<void>();\n\n public ngOnInit(): void {\n // Дебаунс непустого ввода; очистка крестиком применяется сразу (searchDebounce).\n this.searchControl.valueChanges\n .pipe(\n map((value: string): string => value.trim()),\n searchDebounce(),\n distinctUntilChanged(),\n takeUntilDestroyed(this.#destroyRef)\n )\n .subscribe((value: string): void => this.searchChange.emit(value));\n }\n\n protected onSelect(id: IRtThreadList.TRowId, event: MouseEvent): void {\n // Ctrl (Win/Linux) или ⌘ (macOS) — «открыть в новой вкладке», как у\n // нативных ссылок. Иначе — обычный выбор строки в текущей вкладке.\n if (event.ctrlKey || event.metaKey) {\n this.openInNewTab.emit(id);\n return;\n }\n this.selectRow.emit(id);\n }\n\n protected onLoadMore(): void {\n this.loadMore.emit();\n }\n}\n","<ng-container rtBlock=\"rt-thread-list\">\n <header rtElem=\"head\">\n @if (searchTemplate()) {\n <div rtElem=\"search\" qa-dataid=\"thread-list-search\">\n <ng-container [ngTemplateOutlet]=\"searchTemplate()?.templateRef ?? null\" />\n </div>\n } @else {\n <rt-input\n rtElem=\"search\"\n qa-dataid=\"thread-list-search\"\n iconLeft=\"search\"\n [placeholder]=\"searchPlaceholderText()\"\n [formControl]=\"searchControl\" />\n }\n @if (filtersTemplate()) {\n <rt-icon-button\n rtElem=\"filter-trigger\"\n qa-dataid=\"thread-list-filter\"\n icon=\"filter\"\n variant=\"secondary\"\n rtPopoverAlign=\"end\"\n [ariaLabel]=\"t().uiFilters\"\n [indicator]=\"filtersActive()\"\n [rtPopover]=\"filtersPanel\" />\n }\n </header>\n\n <ng-template #rowButton let-row>\n <button\n rtElem=\"row\"\n qa-dataid=\"thread-list-row\"\n type=\"button\"\n [attr.data-id]=\"row.id\"\n [attr.data-unread]=\"row.hasUnread\"\n [attr.aria-current]=\"row.id === activeId() ? 'true' : null\"\n [rtMod]=\"{\n active: row.id === activeId(),\n unread: row.hasUnread,\n overdue: !!row.overdue,\n }\"\n (click)=\"onSelect(row.id, $event)\">\n @if (row.sign; as sign) {\n <rt-service-logo rtElem=\"row-sign\" qa-dataid=\"thread-list-row-sign\" size=\"xs\" [logos]=\"[sign]\" />\n <span rtElem=\"row-content\">\n <ng-container [ngTemplateOutlet]=\"rowContent\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </span>\n } @else {\n <ng-container [ngTemplateOutlet]=\"rowContent\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n </button>\n </ng-template>\n\n <ng-template #rowContent let-row>\n <ng-container [ngTemplateOutlet]=\"rowTemplate()?.templateRef ?? null\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </ng-template>\n\n <ng-template #filtersPanel>\n <div rtElem=\"filters-panel\" qa-dataid=\"thread-list-filters-panel\">\n <ng-container [ngTemplateOutlet]=\"filtersTemplate()?.templateRef ?? null\" />\n </div>\n </ng-template>\n\n <div rtElem=\"rows\" qa-dataid=\"thread-list-rows\">\n @if (loading() && !rows().length) {\n @for (i of skeletonRows; track i) {\n <div rtElem=\"row-skeleton\" qa-dataid=\"thread-list-row-skeleton\" aria-hidden=\"true\">\n <rt-skeleton width=\"60%\" height=\"14px\" />\n <rt-skeleton width=\"90%\" height=\"12px\" />\n </div>\n }\n } @else if (!rows().length) {\n <rt-empty-state rtElem=\"empty\" qa-dataid=\"thread-list-empty\" [description]=\"t().uiThreadListEmptyHint\" [title]=\"emptyTitle()\">\n <div rtEmptyIllustration rtElem=\"empty-preview\">\n @for (row of emptyPreviewRows(); track row.id) {\n <div rtElem=\"empty-card\" [rtMod]=\"{ offset: row.offset }\">\n <span rtElem=\"empty-avatar\">\n <rt-icon size=\"sm\" [name]=\"row.icon\" />\n </span>\n <span rtElem=\"empty-lines\">\n <span rtElem=\"empty-line\" [rtMod]=\"{ short: true }\"></span>\n <span rtElem=\"empty-line\"></span>\n </span>\n </div>\n }\n </div>\n </rt-empty-state>\n } @else {\n @for (row of rows(); track row.id) {\n @if (rowActionsTemplate(); as actions) {\n <div rtElem=\"row-wrap\" qa-dataid=\"thread-list-row-wrap\">\n <ng-container [ngTemplateOutlet]=\"rowButton\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n <div rtElem=\"row-actions\" qa-dataid=\"thread-list-row-actions\">\n <ng-container [ngTemplateOutlet]=\"actions.templateRef\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </div>\n </div>\n } @else {\n <ng-container [ngTemplateOutlet]=\"rowButton\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n }\n @if (fetching()) {\n <div rtElem=\"row-loader\" qa-dataid=\"thread-list-row-loader\">\n <rt-skeleton width=\"90%\" height=\"12px\" />\n </div>\n }\n @if (hasMore()) {\n <div\n rtElem=\"load-anchor\"\n qa-dataid=\"thread-list-load-more\"\n aria-hidden=\"true\"\n rtInfiniteScroll\n [disabled]=\"fetching()\"\n (loadMore)=\"onLoadMore()\"></div>\n }\n }\n </div>\n</ng-container>\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
| вход | тип | умолчание |
|
|
8
8
|
| ------- | -------------------------------- | ---------- |
|
|
9
9
|
| `logos` | `readonly IRtServiceLogo.Item[]` | обязателен |
|
|
10
|
-
| `size` | `'sm' \| 'md' \| 'lg'`
|
|
10
|
+
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg'` | `'md'` |
|
|
11
11
|
|
|
12
12
|
Выходов нет.
|
|
13
13
|
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
**Следующий круг лежит поверх предыдущего порядком разметки.** Круги позиционированы без
|
|
24
24
|
`z-index`, нахлёст — отрицательный отступ, равный разнице круга и шага.
|
|
25
25
|
|
|
26
|
-
**Знак значком — `rt-icon` ступенью, равной высоте знака:** `sm` → `md` (20), `md` → `xl` (32),
|
|
26
|
+
**Знак значком — `rt-icon` ступенью, равной высоте знака:** `xs` → `sm` (16), `sm` → `md` (20), `md` → `xl` (32),
|
|
27
27
|
`lg` → `3xl` (48). `rt-icon` сам скрыт от диктора, поэтому имя несёт обёртка с `role="img"`.
|
|
28
28
|
|
|
29
29
|
## Края
|
|
@@ -16,6 +16,13 @@
|
|
|
16
16
|
align-items: center;
|
|
17
17
|
vertical-align: middle;
|
|
18
18
|
|
|
19
|
+
&--size-xs {
|
|
20
|
+
--rt-service-logo-size: var(--rt-size-8);
|
|
21
|
+
--rt-service-logo-mark-height: var(--rt-size-4);
|
|
22
|
+
--rt-service-logo-step: var(--rt-size-5);
|
|
23
|
+
--rt-service-logo-shadow: var(--rt-shadow-service-logo-xs);
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
&--size-sm {
|
|
20
27
|
--rt-service-logo-size: var(--rt-size-10);
|
|
21
28
|
--rt-service-logo-mark-height: var(--rt-size-5);
|
|
@@ -52,7 +59,7 @@
|
|
|
52
59
|
}
|
|
53
60
|
}
|
|
54
61
|
|
|
55
|
-
/* Рамка знака шире высоты в 1.375 раза (27.5×20, 44×32, 66×48): картинка вписывается в неё
|
|
62
|
+
/* Рамка знака шире высоты в 1.375 раза (22×16, 27.5×20, 44×32, 66×48): картинка вписывается в неё
|
|
56
63
|
целиком, без растяжения и обрезки. */
|
|
57
64
|
&__image {
|
|
58
65
|
display: block;
|
|
@@ -21,7 +21,13 @@
|
|
|
21
21
|
Входы: `rows`, `activeId`, `searchPlaceholder`, `emptyText`, `loading`, `fetching`, `hasMore`,
|
|
22
22
|
`filtersActive`, `emptyPreviewIcons`. Выходы: `selectRow`, `openInNewTab`, `searchChange`, `loadMore`.
|
|
23
23
|
|
|
24
|
-
Строка обязана иметь `id`, `hasUnread` и (необязательно) `overdue` — это всё, что список о
|
|
24
|
+
Строка обязана иметь `id`, `hasUnread` и (необязательно) `overdue` и `sign` — это всё, что список о
|
|
25
|
+
ней знает.
|
|
26
|
+
|
|
27
|
+
Знак канала — поле `sign` строки (`IRtServiceLogo.Item`: картинка по адресу или значок кита).
|
|
28
|
+
Оболочка рисует его первым в кнопке строки: [`rt-service-logo`](../service-logo/CONTEXT.md) размера
|
|
29
|
+
`xs`, круг 32. Содержимое шаблона при знаке стоит в обёртке `__row-content`: кнопка разводит детей
|
|
30
|
+
по краям, и третий ребёнок встал бы посередине. Строка без знака рисуется без обёртки, как раньше.
|
|
25
31
|
Номер строки — число или строка: у записей домена ключ не всегда числовой. Тем же типом приходит
|
|
26
32
|
`activeId` и уходят `selectRow` и `openInNewTab`.
|
|
27
33
|
|
|
@@ -158,6 +158,21 @@
|
|
|
158
158
|
background: var(--rt-color-state-info-bg);
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
// Знак канала стоит слева от содержимого строки. Содержимое при знаке собрано в свою обёртку:
|
|
162
|
+
// кнопка разводит детей по краям, и третий ребёнок встал бы посередине строки.
|
|
163
|
+
&__row-sign {
|
|
164
|
+
flex: none;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
&__row-content {
|
|
168
|
+
display: flex;
|
|
169
|
+
flex: 1 1 auto;
|
|
170
|
+
align-items: center;
|
|
171
|
+
justify-content: space-between;
|
|
172
|
+
gap: var(--rt-space-4);
|
|
173
|
+
min-inline-size: 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
161
176
|
&__row-body {
|
|
162
177
|
display: flex;
|
|
163
178
|
flex-direction: column;
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
Основные входы: `messages`, `hasThread`, `canReply`, `replyBlockReason`, `loading`, `fetching`,
|
|
19
|
-
`sending`, `attachments`, `accept`, `formatting`, `title`, `
|
|
20
|
-
`typingText`. Выходы: `send`, `refresh`, `typing` и события по сообщениям (повтор, удаление).
|
|
19
|
+
`sending`, `attachments`, `accept`, `formatting`, `title`, `sign`, `showRefresh`, `showExpand`,
|
|
20
|
+
`fill`, `typingText`. Выходы: `send`, `refresh`, `typing` и события по сообщениям (повтор, удаление).
|
|
21
21
|
|
|
22
22
|
## Главное, что нужно знать
|
|
23
23
|
|
|
@@ -32,6 +32,10 @@ rtChatMessageActions let-message>` рисуется в меню «…» у ре
|
|
|
32
32
|
**Шапка появляется только вместе с кнопками**: `showHeader = showRefresh || showExpand`.
|
|
33
33
|
Один `title` шапку не создаёт.
|
|
34
34
|
|
|
35
|
+
**Знак канала — вход `sign`, круг [`rt-service-logo`](../../../../lib/components/service-logo/CONTEXT.md)
|
|
36
|
+
размера `xs` перед заголовком.** Стоит в левой полосе тулбара, отступ до заголовка — её же, 8. Шапку
|
|
37
|
+
сам не создаёт, как и `title`.
|
|
38
|
+
|
|
35
39
|
**Поле ответа гейтится `canReply`.** Когда отвечать нельзя, вместо него рисуется причина
|
|
36
40
|
из `replyBlockReason`.
|
|
37
41
|
|
|
@@ -48,4 +52,7 @@ rtChatMessageActions let-message>` рисуется в меню «…» у ре
|
|
|
48
52
|
- Режим `formatting` подменяет простое поле [`rt-rich-editor`](../rich-editor/CONTEXT.md);
|
|
49
53
|
тот грузит Quill динамическим импортом.
|
|
50
54
|
- Неотправленное сообщение (`status: 'failed'`) получает кнопку повтора.
|
|
55
|
+
- Недоставленное (`status: 'undelivered'`): ответ записан, служба собеседника его не приняла. Значок
|
|
56
|
+
предупреждения и подпись `rtKit.chatStatusUndelivered`, кнопки повтора нет — повтор записал бы ответ
|
|
57
|
+
второй раз.
|
|
51
58
|
- Файлы можно бросать прямо в ленту — чат обёрнут в [`rt-file-drop`](../../../../lib/components/file-drop/CONTEXT.md).
|
|
@@ -72,6 +72,11 @@
|
|
|
72
72
|
max-height: none;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
// Знак канала стоит перед заголовком и не сжимается, когда длинный заголовок переносится.
|
|
76
|
+
&__sign {
|
|
77
|
+
flex: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
75
80
|
&__title {
|
|
76
81
|
margin: 0;
|
|
77
82
|
color: var(--rt-color-text-primary);
|
|
@@ -289,12 +294,21 @@
|
|
|
289
294
|
&--status--failed {
|
|
290
295
|
color: var(--rt-color-state-danger);
|
|
291
296
|
}
|
|
297
|
+
|
|
298
|
+
&--status--undelivered {
|
|
299
|
+
color: var(--rt-color-state-warning-text);
|
|
300
|
+
}
|
|
292
301
|
}
|
|
293
302
|
|
|
294
303
|
&__status-icon {
|
|
295
304
|
font-size: var(--rt-text-sm);
|
|
296
305
|
}
|
|
297
306
|
|
|
307
|
+
&__status-caption {
|
|
308
|
+
font-size: var(--rt-text-xs);
|
|
309
|
+
line-height: var(--rt-leading-none);
|
|
310
|
+
}
|
|
311
|
+
|
|
298
312
|
// Скелетон-пузырь повторяет геометрию `&__message`, чтобы подмена на реальное
|
|
299
313
|
// сообщение не сдвигала тред.
|
|
300
314
|
&__message-skeleton {
|
|
@@ -210,6 +210,7 @@
|
|
|
210
210
|
|
|
211
211
|
/* Тень круга логотипа службы — ореол без сдвига цвета почти чёрного на 15%;
|
|
212
212
|
размытие растёт с размером круга, по ступени на размер атома. */
|
|
213
|
+
--rt-shadow-service-logo-xs: 0 0 16px rgb(24 24 24 / 15%);
|
|
213
214
|
--rt-shadow-service-logo-sm: 0 0 24px rgb(24 24 24 / 15%);
|
|
214
215
|
--rt-shadow-service-logo-md: 0 0 40px rgb(24 24 24 / 15%);
|
|
215
216
|
--rt-shadow-service-logo-lg: 0 0 56px rgb(24 24 24 / 15%);
|
package/styles/tokens.css
CHANGED
|
@@ -273,6 +273,7 @@
|
|
|
273
273
|
--rt-shadow-dialog: 0 0 40px rgb(0 0 0 / 25%);
|
|
274
274
|
/* Тень круга логотипа службы — ореол без сдвига цвета почти чёрного на 15%;
|
|
275
275
|
размытие растёт с размером круга, по ступени на размер атома. */
|
|
276
|
+
--rt-shadow-service-logo-xs: 0 0 16px rgb(24 24 24 / 15%);
|
|
276
277
|
--rt-shadow-service-logo-sm: 0 0 24px rgb(24 24 24 / 15%);
|
|
277
278
|
--rt-shadow-service-logo-md: 0 0 40px rgb(24 24 24 / 15%);
|
|
278
279
|
--rt-shadow-service-logo-lg: 0 0 56px rgb(24 24 24 / 15%);
|