@rt-tools/ui-kit-v2 0.38.0 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/fesm2022/rt-tools-ui-kit-v2-aside.mjs +43 -5
  2. package/fesm2022/rt-tools-ui-kit-v2-aside.mjs.map +1 -1
  3. package/fesm2022/rt-tools-ui-kit-v2-core.mjs +1 -0
  4. package/fesm2022/rt-tools-ui-kit-v2-core.mjs.map +1 -1
  5. package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs +5 -2
  6. package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs.map +1 -1
  7. package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs +2 -2
  8. package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs.map +1 -1
  9. package/fesm2022/rt-tools-ui-kit-v2-popover.mjs +22 -6
  10. package/fesm2022/rt-tools-ui-kit-v2-popover.mjs.map +1 -1
  11. package/fesm2022/rt-tools-ui-kit-v2-profile-menu.mjs +9 -5
  12. package/fesm2022/rt-tools-ui-kit-v2-profile-menu.mjs.map +1 -1
  13. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +2 -1
  14. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
  15. package/fesm2022/rt-tools-ui-kit-v2-table.mjs +3 -1
  16. package/fesm2022/rt-tools-ui-kit-v2-table.mjs.map +1 -1
  17. package/fesm2022/rt-tools-ui-kit-v2-toolbar.mjs +342 -17
  18. package/fesm2022/rt-tools-ui-kit-v2-toolbar.mjs.map +1 -1
  19. package/package.json +1 -1
  20. package/src/lib/components/aside/CONTEXT.md +4 -1
  21. package/src/lib/components/aside/header/rt-aside-header.component.scss +4 -1
  22. package/src/lib/components/popover/CONTEXT.md +3 -0
  23. package/src/lib/components/profile-menu/CONTEXT.md +4 -0
  24. package/src/lib/components/profile-menu/rt-profile-menu.component.scss +11 -0
  25. package/src/lib/components/tabs/CONTEXT.md +1 -0
  26. package/src/lib/components/toolbar/CONTEXT.md +21 -4
  27. package/src/lib/components/toolbar/filters-aside/rt-toolbar-filters-aside.component.scss +22 -0
  28. package/src/lib/components/toolbar/rt-toolbar.component.scss +12 -0
  29. package/types/rt-tools-ui-kit-v2-aside.d.ts +21 -2
  30. package/types/rt-tools-ui-kit-v2-core.d.ts +1 -0
  31. package/types/rt-tools-ui-kit-v2-popover.d.ts +3 -1
  32. package/types/rt-tools-ui-kit-v2-profile-menu.d.ts +6 -1
  33. package/types/rt-tools-ui-kit-v2-toolbar.d.ts +79 -2
@@ -1,7 +1,158 @@
1
- import { NgTemplateOutlet } from "@angular/common";
1
+ import { InteractivityChecker } from "@angular/cdk/a11y";
2
+ import { DOCUMENT, NgTemplateOutlet } from "@angular/common";
2
3
  import * as i0 from "@angular/core";
3
- import { ChangeDetectionStrategy, Component, Directive, TemplateRef, ViewEncapsulation, booleanAttribute, contentChild, input } from "@angular/core";
4
+ import { ChangeDetectionStrategy, Component, Directive, ElementRef, Injector, TemplateRef, ViewEncapsulation, afterNextRender, booleanAttribute, computed, contentChild, effect, inject, input, output, untracked } from "@angular/core";
5
+ import { firstValueFrom } from "rxjs";
4
6
  import { BlockDirective, ElemDirective, ModDirective } from "@rt-tools/core";
7
+ import { BreakpointsService, rtKitLabel } from "@rt-tools/ui-kit-v2/core";
8
+ import { RT_ASIDE_DATA, RtAsideComponent, RtAsideFooterComponent, RtAsideHeaderComponent, RtAsideRef, RtAsideService } from "@rt-tools/ui-kit-v2/aside";
9
+ import { RtIconButtonComponent } from "@rt-tools/ui-kit-v2/icon-button";
10
+ import { RtButtonDirective } from "@rt-tools/ui-kit-v2/button";
11
+ const BEM_BLOCK$1 = "rt-toolbar-filters-aside";
12
+ var RtToolbarFiltersAsideComponent = class RtToolbarFiltersAsideComponent {
13
+ constructor() {
14
+ this.#asideRef = inject(RtAsideRef);
15
+ this.data = inject(RT_ASIDE_DATA);
16
+ this.title = rtKitLabel("uiFilters");
17
+ this.resetLabel = rtKitLabel("uiReset");
18
+ this.applyLabel = rtKitLabel("uiApply");
19
+ }
20
+ #asideRef;
21
+ onReset() {
22
+ this.data.reset();
23
+ }
24
+ onApply() {
25
+ this.data.apply();
26
+ this.#asideRef.close();
27
+ }
28
+ static {
29
+ this.ɵfac = i0.ɵɵngDeclareFactory({
30
+ minVersion: "12.0.0",
31
+ version: "22.2.2",
32
+ ngImport: i0,
33
+ type: RtToolbarFiltersAsideComponent,
34
+ deps: [],
35
+ target: i0.ɵɵFactoryTarget.Component
36
+ });
37
+ }
38
+ static {
39
+ this.ɵcmp = i0.ɵɵngDeclareComponent({
40
+ minVersion: "14.0.0",
41
+ version: "22.2.2",
42
+ type: RtToolbarFiltersAsideComponent,
43
+ isStandalone: true,
44
+ selector: "rt-toolbar-filters-aside",
45
+ host: { classAttribute: "rt-toolbar-filters-aside" },
46
+ ngImport: i0,
47
+ template: "<rt-aside size=\"sm\" trapFocus modal [ariaLabel]=\"title()\">\n <rt-aside-header [title]=\"title()\" />\n\n <ng-container rtBlock=\"rt-toolbar-filters-aside\">\n <!-- Начальный фокус — на блоке полей, а не на стрелке: рамка фокуса не встаёт на кнопку, которую не нажимали -->\n <div rtElem=\"fields\" qa-dataid=\"toolbar-filters-fields\" tabindex=\"-1\" cdkFocusInitial>\n <ng-container [ngTemplateOutlet]=\"data.template\" [ngTemplateOutletContext]=\"{ $implicit: 'panel' }\" />\n </div>\n </ng-container>\n\n <rt-aside-footer [phoneCloseLabel]=\"false\">\n <button rtButton asideDismiss qa-dataid=\"toolbar-filters-reset\" type=\"button\" [label]=\"resetLabel()\" (click)=\"onReset()\">\n <!-- empty: label is drawn by the directive -->\n </button>\n <button rtButton asidePrimary qa-dataid=\"toolbar-filters-apply\" type=\"button\" [label]=\"applyLabel()\" (click)=\"onApply()\">\n <!-- empty: label is drawn by the directive -->\n </button>\n </rt-aside-footer>\n</rt-aside>\n",
48
+ styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-toolbar-filters-aside{--rt-toolbar-filters-aside-gap: var(--rt-space-md)}.rt-toolbar-filters-aside__fields{display:flex;flex-direction:column;gap:var(--rt-toolbar-filters-aside-gap)}.rt-toolbar-filters-aside__fields:focus{outline:none}.rt-toolbar-filters-aside__fields>*{width:100%}}\n"],
49
+ dependencies: [
50
+ {
51
+ kind: "directive",
52
+ type: NgTemplateOutlet,
53
+ selector: "[ngTemplateOutlet]",
54
+ inputs: [
55
+ "ngTemplateOutletContext",
56
+ "ngTemplateOutlet",
57
+ "ngTemplateOutletInjector"
58
+ ]
59
+ },
60
+ {
61
+ kind: "component",
62
+ type: RtAsideComponent,
63
+ selector: "rt-aside",
64
+ inputs: [
65
+ "size",
66
+ "contentLayout",
67
+ "width",
68
+ "ariaLabel",
69
+ "requestError",
70
+ "trapFocus",
71
+ "modal",
72
+ "pending"
73
+ ]
74
+ },
75
+ {
76
+ kind: "component",
77
+ type: RtAsideFooterComponent,
78
+ selector: "rt-aside-footer",
79
+ inputs: ["phoneCloseLabel"]
80
+ },
81
+ {
82
+ kind: "component",
83
+ type: RtAsideHeaderComponent,
84
+ selector: "rt-aside-header",
85
+ inputs: [
86
+ "title",
87
+ "overline",
88
+ "subtitle",
89
+ "badges",
90
+ "closable",
91
+ "loading"
92
+ ],
93
+ outputs: ["dismiss"]
94
+ },
95
+ {
96
+ kind: "directive",
97
+ type: BlockDirective,
98
+ selector: "[rtBlock]",
99
+ inputs: ["rtMod"]
100
+ },
101
+ {
102
+ kind: "directive",
103
+ type: ElemDirective,
104
+ selector: "[rtElem]",
105
+ inputs: ["rtMod"]
106
+ },
107
+ {
108
+ kind: "directive",
109
+ type: RtButtonDirective,
110
+ selector: "button[rtButton], a[rtButton]",
111
+ inputs: [
112
+ "label",
113
+ "icon",
114
+ "iconPos",
115
+ "theme",
116
+ "appearance",
117
+ "size",
118
+ "loading",
119
+ "loadingIcon",
120
+ "loadingLabel",
121
+ "pressed"
122
+ ]
123
+ }
124
+ ],
125
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
126
+ encapsulation: i0.ViewEncapsulation.None
127
+ });
128
+ }
129
+ };
130
+ i0.ɵɵngDeclareClassMetadata({
131
+ minVersion: "12.0.0",
132
+ version: "22.2.2",
133
+ ngImport: i0,
134
+ type: RtToolbarFiltersAsideComponent,
135
+ decorators: [{
136
+ type: Component,
137
+ args: [{
138
+ selector: "rt-toolbar-filters-aside",
139
+ changeDetection: ChangeDetectionStrategy.OnPush,
140
+ encapsulation: ViewEncapsulation.None,
141
+ imports: [
142
+ NgTemplateOutlet,
143
+ RtAsideComponent,
144
+ RtAsideFooterComponent,
145
+ RtAsideHeaderComponent,
146
+ BlockDirective,
147
+ ElemDirective,
148
+ RtButtonDirective
149
+ ],
150
+ host: { class: BEM_BLOCK$1 },
151
+ template: "<rt-aside size=\"sm\" trapFocus modal [ariaLabel]=\"title()\">\n <rt-aside-header [title]=\"title()\" />\n\n <ng-container rtBlock=\"rt-toolbar-filters-aside\">\n <!-- Начальный фокус — на блоке полей, а не на стрелке: рамка фокуса не встаёт на кнопку, которую не нажимали -->\n <div rtElem=\"fields\" qa-dataid=\"toolbar-filters-fields\" tabindex=\"-1\" cdkFocusInitial>\n <ng-container [ngTemplateOutlet]=\"data.template\" [ngTemplateOutletContext]=\"{ $implicit: 'panel' }\" />\n </div>\n </ng-container>\n\n <rt-aside-footer [phoneCloseLabel]=\"false\">\n <button rtButton asideDismiss qa-dataid=\"toolbar-filters-reset\" type=\"button\" [label]=\"resetLabel()\" (click)=\"onReset()\">\n <!-- empty: label is drawn by the directive -->\n </button>\n <button rtButton asidePrimary qa-dataid=\"toolbar-filters-apply\" type=\"button\" [label]=\"applyLabel()\" (click)=\"onApply()\">\n <!-- empty: label is drawn by the directive -->\n </button>\n </rt-aside-footer>\n</rt-aside>\n",
152
+ styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-toolbar-filters-aside{--rt-toolbar-filters-aside-gap: var(--rt-space-md)}.rt-toolbar-filters-aside__fields{display:flex;flex-direction:column;gap:var(--rt-toolbar-filters-aside-gap)}.rt-toolbar-filters-aside__fields:focus{outline:none}.rt-toolbar-filters-aside__fields>*{width:100%}}\n"]
153
+ }]
154
+ }]
155
+ });
5
156
  var RtToolbarLeftDirective = class RtToolbarLeftDirective {
6
157
  static {
7
158
  this.ɵfac = i0.ɵɵngDeclareFactory({
@@ -98,9 +249,68 @@ i0.ɵɵngDeclareClassMetadata({
98
249
  args: [{ selector: "[rtToolbarRight]" }]
99
250
  }]
100
251
  });
252
+ var RtToolbarFiltersDirective = class RtToolbarFiltersDirective {
253
+ static ngTemplateContextGuard(_directive, context) {
254
+ return true;
255
+ }
256
+ static {
257
+ this.ɵfac = i0.ɵɵngDeclareFactory({
258
+ minVersion: "12.0.0",
259
+ version: "22.2.2",
260
+ ngImport: i0,
261
+ type: RtToolbarFiltersDirective,
262
+ deps: [],
263
+ target: i0.ɵɵFactoryTarget.Directive
264
+ });
265
+ }
266
+ static {
267
+ this.ɵdir = i0.ɵɵngDeclareDirective({
268
+ minVersion: "14.0.0",
269
+ version: "22.2.2",
270
+ type: RtToolbarFiltersDirective,
271
+ isStandalone: true,
272
+ selector: "[rtToolbarFilters]",
273
+ ngImport: i0
274
+ });
275
+ }
276
+ };
277
+ i0.ɵɵngDeclareClassMetadata({
278
+ minVersion: "12.0.0",
279
+ version: "22.2.2",
280
+ ngImport: i0,
281
+ type: RtToolbarFiltersDirective,
282
+ decorators: [{
283
+ type: Directive,
284
+ args: [{ selector: "[rtToolbarFilters]" }]
285
+ }]
286
+ });
101
287
  const BEM_BLOCK = "rt-toolbar";
102
288
  var RtToolbarComponent = class RtToolbarComponent {
289
+ #narrow;
290
+ #asideService;
291
+ #injector;
292
+ #host;
293
+ #document;
294
+ #interactivity;
295
+ #filtersActiveLabel;
296
+ #filtersRef;
103
297
  constructor() {
298
+ this.#narrow = inject(BreakpointsService).narrow;
299
+ this.#asideService = inject(RtAsideService);
300
+ this.#injector = inject(Injector);
301
+ this.#host = inject(ElementRef).nativeElement;
302
+ this.#document = inject(DOCUMENT);
303
+ this.#interactivity = inject(InteractivityChecker);
304
+ this.#filtersActiveLabel = rtKitLabel("uiFiltersActive");
305
+ this.#filtersRef = null;
306
+ this.filtersLabel = rtKitLabel("uiFilters");
307
+ this.filtersAriaLabel = computed(() => this.filtersActive() ? this.#filtersActiveLabel() : this.filtersLabel(), ...ngDevMode ? [{ debugName: "filtersAriaLabel" }] : /* istanbul ignore next */ []);
308
+ this.filtersTpl = contentChild(RtToolbarFiltersDirective, {
309
+ ...ngDevMode ? { debugName: "filtersTpl" } : /* istanbul ignore next */ {},
310
+ read: TemplateRef
311
+ });
312
+ this.collapsed = computed(() => this.filtersTpl() !== void 0 && this.#narrow(), ...ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []);
313
+ this.filtersInBar = computed(() => this.filtersTpl() !== void 0 && !this.#narrow(), ...ngDevMode ? [{ debugName: "filtersInBar" }] : /* istanbul ignore next */ []);
104
314
  this.leftTpl = contentChild(RtToolbarLeftDirective, {
105
315
  ...ngDevMode ? { debugName: "leftTpl" } : /* istanbul ignore next */ {},
106
316
  read: TemplateRef
@@ -117,6 +327,44 @@ var RtToolbarComponent = class RtToolbarComponent {
117
327
  ...ngDevMode ? { debugName: "dense" } : /* istanbul ignore next */ {},
118
328
  transform: booleanAttribute
119
329
  });
330
+ this.filtersActive = input(false, {
331
+ ...ngDevMode ? { debugName: "filtersActive" } : /* istanbul ignore next */ {},
332
+ transform: booleanAttribute
333
+ });
334
+ this.filtersApply = output();
335
+ this.filtersReset = output();
336
+ effect(() => {
337
+ if (this.filtersInBar()) untracked(() => this.#closeFilters());
338
+ });
339
+ }
340
+ openFilters() {
341
+ const template = this.filtersTpl();
342
+ if (template === void 0 || this.#filtersRef !== null) return;
343
+ const ref = this.#asideService.open(RtToolbarFiltersAsideComponent, {
344
+ injector: this.#injector,
345
+ data: {
346
+ template,
347
+ reset: () => this.filtersReset.emit(),
348
+ apply: () => this.filtersApply.emit()
349
+ },
350
+ position: "right",
351
+ backdropClass: "rt-aside-backdrop"
352
+ });
353
+ this.#filtersRef = ref;
354
+ firstValueFrom(ref.afterClosed(), { defaultValue: null }).then(() => {
355
+ if (this.#filtersRef === ref) this.#filtersRef = null;
356
+ });
357
+ }
358
+ #closeFilters() {
359
+ if (this.#filtersRef === null) return;
360
+ const focusInPanel = this.#document.activeElement?.closest("rt-toolbar-filters-aside") != null;
361
+ this.#filtersRef.close();
362
+ this.#filtersRef = null;
363
+ if (focusInPanel) afterNextRender({ write: () => this.#focusBar() }, { injector: this.#injector });
364
+ }
365
+ #focusBar() {
366
+ const place = this.#host.querySelector("[data-slot=\"left\"]") ?? this.#host;
367
+ Array.from(place.querySelectorAll("*")).find((node) => this.#interactivity.isFocusable(node) && this.#interactivity.isTabbable(node))?.focus();
120
368
  }
121
369
  static {
122
370
  this.ɵfac = i0.ɵɵngDeclareFactory({
@@ -135,18 +383,42 @@ var RtToolbarComponent = class RtToolbarComponent {
135
383
  type: RtToolbarComponent,
136
384
  isStandalone: true,
137
385
  selector: "rt-toolbar",
138
- inputs: { dense: {
139
- classPropertyName: "dense",
140
- publicName: "dense",
141
- isSignal: true,
142
- isRequired: false,
143
- transformFunction: null
144
- } },
386
+ inputs: {
387
+ dense: {
388
+ classPropertyName: "dense",
389
+ publicName: "dense",
390
+ isSignal: true,
391
+ isRequired: false,
392
+ transformFunction: null
393
+ },
394
+ filtersActive: {
395
+ classPropertyName: "filtersActive",
396
+ publicName: "filtersActive",
397
+ isSignal: true,
398
+ isRequired: false,
399
+ transformFunction: null
400
+ }
401
+ },
402
+ outputs: {
403
+ filtersApply: "filtersApply",
404
+ filtersReset: "filtersReset"
405
+ },
145
406
  host: {
146
- properties: { "class.rt-toolbar--dense": "dense()" },
407
+ properties: {
408
+ "class.rt-toolbar--dense": "dense()",
409
+ "class.rt-toolbar--filters-collapsed": "collapsed()"
410
+ },
147
411
  classAttribute: "rt-toolbar"
148
412
  },
149
413
  queries: [
414
+ {
415
+ propertyName: "filtersTpl",
416
+ first: true,
417
+ predicate: RtToolbarFiltersDirective,
418
+ descendants: true,
419
+ read: TemplateRef,
420
+ isSignal: true
421
+ },
150
422
  {
151
423
  propertyName: "leftTpl",
152
424
  first: true,
@@ -173,8 +445,8 @@ var RtToolbarComponent = class RtToolbarComponent {
173
445
  }
174
446
  ],
175
447
  ngImport: i0,
176
- template: "@if (leftTpl() || centerTpl() || rightTpl()) {\n <ng-container rtBlock=\"rt-toolbar\">\n <div rtElem=\"bars\">\n @if (leftTpl()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"left\" [rtMod]=\"{ left: true }\">\n <ng-container [ngTemplateOutlet]=\"leftTpl() ?? null\" />\n </div>\n }\n\n @if (centerTpl()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"center\" [rtMod]=\"{ center: true }\">\n <ng-container [ngTemplateOutlet]=\"centerTpl() ?? null\" />\n </div>\n }\n\n @if (rightTpl()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"right\" [rtMod]=\"{ right: true }\">\n <ng-container [ngTemplateOutlet]=\"rightTpl() ?? null\" />\n </div>\n }\n </div>\n </ng-container>\n}\n",
177
- styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-toolbar{--rt-toolbar-padding-top: var(--rt-space-2);--rt-toolbar-padding-bottom: var(--rt-space-2);--rt-toolbar-padding-inline: 0;--rt-toolbar-height: auto;--rt-toolbar-border-bottom: none;--rt-toolbar-gap: var(--rt-space-2);--rt-toolbar-center-justify: flex-end;--rt-toolbar-center-overflow: visible;--rt-toolbar-field-width: var(--rt-size-100);display:block}.rt-toolbar__bars{display:flex;width:100%;min-height:var(--rt-toolbar-height);box-sizing:border-box;flex-direction:row;align-items:center;justify-content:space-between;padding:var(--rt-toolbar-padding-top) var(--rt-toolbar-padding-inline) var(--rt-toolbar-padding-bottom);border-bottom:var(--rt-toolbar-border-bottom);gap:var(--rt-toolbar-gap)}.rt-toolbar__bar{display:flex;align-items:center}.rt-toolbar__bar--left{min-width:0;flex:0 0 auto;gap:var(--rt-space-2)}.rt-toolbar__bar--left>rt-input{width:var(--rt-toolbar-field-width);max-width:100%}.rt-toolbar__bar--center{overflow:var(--rt-toolbar-center-overflow);flex:1 1 auto;justify-content:var(--rt-toolbar-center-justify);gap:var(--rt-space-2)}.rt-toolbar__bar--center rt-input,.rt-toolbar__bar--center rt-select{width:100%}.rt-toolbar__bar--right{flex:0 1 auto;margin-left:auto;gap:var(--rt-space-sm)}.rt-toolbar--dense .rt-toolbar__bar--left{min-width:0;flex:0 1 auto}@container rt-place (width <= 768px){.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bars{flex-direction:column;align-items:stretch;gap:var(--rt-space-sm)}.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar{flex-wrap:wrap}.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--center{justify-content:stretch}.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--right{justify-content:flex-end;margin-left:0}}@media(width<=768px){:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bars{flex-direction:column;align-items:stretch;gap:var(--rt-space-sm)}:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar{flex-wrap:wrap}:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--center{justify-content:stretch}:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--right{justify-content:flex-end;margin-left:0}}}\n"],
448
+ template: "@if (leftTpl() || centerTpl() || rightTpl() || filtersTpl()) {\n <ng-container rtBlock=\"rt-toolbar\">\n <div rtElem=\"bars\">\n @if (leftTpl() || filtersInBar()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"left\" [rtMod]=\"{ left: true }\">\n <ng-container [ngTemplateOutlet]=\"leftTpl() ?? null\" />\n\n <!-- На широком месте отборы стоят в полосе сами, после содержимого левой секции -->\n @if (filtersInBar()) {\n <ng-container [ngTemplateOutlet]=\"filtersTpl() ?? null\" [ngTemplateOutletContext]=\"{ $implicit: 'bar' }\" />\n }\n </div>\n }\n\n @if (centerTpl()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"center\" [rtMod]=\"{ center: true }\">\n <ng-container [ngTemplateOutlet]=\"centerTpl() ?? null\" />\n </div>\n }\n\n @if (rightTpl() || collapsed()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"right\" [rtMod]=\"{ right: true }\">\n <!-- На узком месте отборы уходят за кнопку: она первая в ряду кнопок полосы -->\n @if (collapsed()) {\n <rt-icon-button\n rtElem=\"filters-trigger\"\n qa-dataid=\"toolbar-filters-trigger\"\n icon=\"filter\"\n variant=\"primary\"\n [ariaLabel]=\"filtersAriaLabel()\"\n [tooltip]=\"filtersLabel()\"\n [indicator]=\"filtersActive()\"\n (clicked)=\"openFilters()\" />\n }\n\n <ng-container [ngTemplateOutlet]=\"rightTpl() ?? null\" />\n </div>\n }\n </div>\n </ng-container>\n}\n",
449
+ styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-toolbar{--rt-toolbar-padding-top: var(--rt-space-2);--rt-toolbar-padding-bottom: var(--rt-space-2);--rt-toolbar-padding-inline: 0;--rt-toolbar-height: auto;--rt-toolbar-border-bottom: none;--rt-toolbar-gap: var(--rt-space-2);--rt-toolbar-center-justify: flex-end;--rt-toolbar-center-overflow: visible;--rt-toolbar-field-width: var(--rt-size-100);display:block}.rt-toolbar__bars{display:flex;width:100%;min-height:var(--rt-toolbar-height);box-sizing:border-box;flex-direction:row;align-items:center;justify-content:space-between;padding:var(--rt-toolbar-padding-top) var(--rt-toolbar-padding-inline) var(--rt-toolbar-padding-bottom);border-bottom:var(--rt-toolbar-border-bottom);gap:var(--rt-toolbar-gap)}.rt-toolbar__bar{display:flex;align-items:center}.rt-toolbar__bar--left{min-width:0;flex:0 0 auto;gap:var(--rt-space-2)}.rt-toolbar__bar--left>rt-input{width:var(--rt-toolbar-field-width);max-width:100%}.rt-toolbar__bar--center{overflow:var(--rt-toolbar-center-overflow);flex:1 1 auto;justify-content:var(--rt-toolbar-center-justify);gap:var(--rt-space-2)}.rt-toolbar__bar--center rt-input,.rt-toolbar__bar--center rt-select{width:100%}.rt-toolbar__bar--right{flex:0 1 auto;margin-left:auto;gap:var(--rt-space-sm)}.rt-toolbar__filters-trigger{flex-shrink:0}.rt-toolbar--dense .rt-toolbar__bar--left{min-width:0;flex:0 1 auto}@container rt-place (width <= 768px){.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bars{flex-direction:column;align-items:stretch;gap:var(--rt-space-sm)}.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar{flex-wrap:wrap}.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--center{justify-content:stretch}.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--right{justify-content:flex-end;margin-left:0}.rt-toolbar--filters-collapsed:not(.rt-toolbar--dense) .rt-toolbar__bar--right{justify-content:flex-start}}@media(width<=768px){:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bars{flex-direction:column;align-items:stretch;gap:var(--rt-space-sm)}:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar{flex-wrap:wrap}:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--center{justify-content:stretch}:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--right{justify-content:flex-end;margin-left:0}:where(html:not(:has(.rt-container))) .rt-toolbar--filters-collapsed:not(.rt-toolbar--dense) .rt-toolbar__bar--right{justify-content:flex-start}}}\n"],
178
450
  dependencies: [
179
451
  {
180
452
  kind: "directive",
@@ -202,6 +474,33 @@ var RtToolbarComponent = class RtToolbarComponent {
202
474
  kind: "directive",
203
475
  type: ModDirective,
204
476
  selector: "[rtMod]"
477
+ },
478
+ {
479
+ kind: "component",
480
+ type: RtIconButtonComponent,
481
+ selector: "rt-icon-button",
482
+ inputs: [
483
+ "icon",
484
+ "glyph",
485
+ "ariaLabel",
486
+ "variant",
487
+ "iconColor",
488
+ "iconFill",
489
+ "size",
490
+ "iconSize",
491
+ "type",
492
+ "tooltip",
493
+ "tooltipHideOnClick",
494
+ "tabIndex",
495
+ "loading",
496
+ "disabled",
497
+ "active",
498
+ "expanded",
499
+ "ariaHaspopup",
500
+ "link",
501
+ "indicator"
502
+ ],
503
+ outputs: ["clicked"]
205
504
  }
206
505
  ],
207
506
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
@@ -224,17 +523,27 @@ i0.ɵɵngDeclareClassMetadata({
224
523
  NgTemplateOutlet,
225
524
  BlockDirective,
226
525
  ElemDirective,
227
- ModDirective
526
+ ModDirective,
527
+ RtIconButtonComponent
228
528
  ],
229
529
  host: {
230
530
  class: BEM_BLOCK,
231
- "[class.rt-toolbar--dense]": "dense()"
531
+ "[class.rt-toolbar--dense]": "dense()",
532
+ "[class.rt-toolbar--filters-collapsed]": "collapsed()"
232
533
  },
233
- template: "@if (leftTpl() || centerTpl() || rightTpl()) {\n <ng-container rtBlock=\"rt-toolbar\">\n <div rtElem=\"bars\">\n @if (leftTpl()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"left\" [rtMod]=\"{ left: true }\">\n <ng-container [ngTemplateOutlet]=\"leftTpl() ?? null\" />\n </div>\n }\n\n @if (centerTpl()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"center\" [rtMod]=\"{ center: true }\">\n <ng-container [ngTemplateOutlet]=\"centerTpl() ?? null\" />\n </div>\n }\n\n @if (rightTpl()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"right\" [rtMod]=\"{ right: true }\">\n <ng-container [ngTemplateOutlet]=\"rightTpl() ?? null\" />\n </div>\n }\n </div>\n </ng-container>\n}\n",
234
- styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-toolbar{--rt-toolbar-padding-top: var(--rt-space-2);--rt-toolbar-padding-bottom: var(--rt-space-2);--rt-toolbar-padding-inline: 0;--rt-toolbar-height: auto;--rt-toolbar-border-bottom: none;--rt-toolbar-gap: var(--rt-space-2);--rt-toolbar-center-justify: flex-end;--rt-toolbar-center-overflow: visible;--rt-toolbar-field-width: var(--rt-size-100);display:block}.rt-toolbar__bars{display:flex;width:100%;min-height:var(--rt-toolbar-height);box-sizing:border-box;flex-direction:row;align-items:center;justify-content:space-between;padding:var(--rt-toolbar-padding-top) var(--rt-toolbar-padding-inline) var(--rt-toolbar-padding-bottom);border-bottom:var(--rt-toolbar-border-bottom);gap:var(--rt-toolbar-gap)}.rt-toolbar__bar{display:flex;align-items:center}.rt-toolbar__bar--left{min-width:0;flex:0 0 auto;gap:var(--rt-space-2)}.rt-toolbar__bar--left>rt-input{width:var(--rt-toolbar-field-width);max-width:100%}.rt-toolbar__bar--center{overflow:var(--rt-toolbar-center-overflow);flex:1 1 auto;justify-content:var(--rt-toolbar-center-justify);gap:var(--rt-space-2)}.rt-toolbar__bar--center rt-input,.rt-toolbar__bar--center rt-select{width:100%}.rt-toolbar__bar--right{flex:0 1 auto;margin-left:auto;gap:var(--rt-space-sm)}.rt-toolbar--dense .rt-toolbar__bar--left{min-width:0;flex:0 1 auto}@container rt-place (width <= 768px){.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bars{flex-direction:column;align-items:stretch;gap:var(--rt-space-sm)}.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar{flex-wrap:wrap}.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--center{justify-content:stretch}.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--right{justify-content:flex-end;margin-left:0}}@media(width<=768px){:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bars{flex-direction:column;align-items:stretch;gap:var(--rt-space-sm)}:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar{flex-wrap:wrap}:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--center{justify-content:stretch}:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--right{justify-content:flex-end;margin-left:0}}}\n"]
534
+ template: "@if (leftTpl() || centerTpl() || rightTpl() || filtersTpl()) {\n <ng-container rtBlock=\"rt-toolbar\">\n <div rtElem=\"bars\">\n @if (leftTpl() || filtersInBar()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"left\" [rtMod]=\"{ left: true }\">\n <ng-container [ngTemplateOutlet]=\"leftTpl() ?? null\" />\n\n <!-- На широком месте отборы стоят в полосе сами, после содержимого левой секции -->\n @if (filtersInBar()) {\n <ng-container [ngTemplateOutlet]=\"filtersTpl() ?? null\" [ngTemplateOutletContext]=\"{ $implicit: 'bar' }\" />\n }\n </div>\n }\n\n @if (centerTpl()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"center\" [rtMod]=\"{ center: true }\">\n <ng-container [ngTemplateOutlet]=\"centerTpl() ?? null\" />\n </div>\n }\n\n @if (rightTpl() || collapsed()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"right\" [rtMod]=\"{ right: true }\">\n <!-- На узком месте отборы уходят за кнопку: она первая в ряду кнопок полосы -->\n @if (collapsed()) {\n <rt-icon-button\n rtElem=\"filters-trigger\"\n qa-dataid=\"toolbar-filters-trigger\"\n icon=\"filter\"\n variant=\"primary\"\n [ariaLabel]=\"filtersAriaLabel()\"\n [tooltip]=\"filtersLabel()\"\n [indicator]=\"filtersActive()\"\n (clicked)=\"openFilters()\" />\n }\n\n <ng-container [ngTemplateOutlet]=\"rightTpl() ?? null\" />\n </div>\n }\n </div>\n </ng-container>\n}\n",
535
+ styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-toolbar{--rt-toolbar-padding-top: var(--rt-space-2);--rt-toolbar-padding-bottom: var(--rt-space-2);--rt-toolbar-padding-inline: 0;--rt-toolbar-height: auto;--rt-toolbar-border-bottom: none;--rt-toolbar-gap: var(--rt-space-2);--rt-toolbar-center-justify: flex-end;--rt-toolbar-center-overflow: visible;--rt-toolbar-field-width: var(--rt-size-100);display:block}.rt-toolbar__bars{display:flex;width:100%;min-height:var(--rt-toolbar-height);box-sizing:border-box;flex-direction:row;align-items:center;justify-content:space-between;padding:var(--rt-toolbar-padding-top) var(--rt-toolbar-padding-inline) var(--rt-toolbar-padding-bottom);border-bottom:var(--rt-toolbar-border-bottom);gap:var(--rt-toolbar-gap)}.rt-toolbar__bar{display:flex;align-items:center}.rt-toolbar__bar--left{min-width:0;flex:0 0 auto;gap:var(--rt-space-2)}.rt-toolbar__bar--left>rt-input{width:var(--rt-toolbar-field-width);max-width:100%}.rt-toolbar__bar--center{overflow:var(--rt-toolbar-center-overflow);flex:1 1 auto;justify-content:var(--rt-toolbar-center-justify);gap:var(--rt-space-2)}.rt-toolbar__bar--center rt-input,.rt-toolbar__bar--center rt-select{width:100%}.rt-toolbar__bar--right{flex:0 1 auto;margin-left:auto;gap:var(--rt-space-sm)}.rt-toolbar__filters-trigger{flex-shrink:0}.rt-toolbar--dense .rt-toolbar__bar--left{min-width:0;flex:0 1 auto}@container rt-place (width <= 768px){.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bars{flex-direction:column;align-items:stretch;gap:var(--rt-space-sm)}.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar{flex-wrap:wrap}.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--center{justify-content:stretch}.rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--right{justify-content:flex-end;margin-left:0}.rt-toolbar--filters-collapsed:not(.rt-toolbar--dense) .rt-toolbar__bar--right{justify-content:flex-start}}@media(width<=768px){:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bars{flex-direction:column;align-items:stretch;gap:var(--rt-space-sm)}:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar{flex-wrap:wrap}:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--center{justify-content:stretch}:where(html:not(:has(.rt-container))) .rt-toolbar:not(.rt-toolbar--dense) .rt-toolbar__bar--right{justify-content:flex-end;margin-left:0}:where(html:not(:has(.rt-container))) .rt-toolbar--filters-collapsed:not(.rt-toolbar--dense) .rt-toolbar__bar--right{justify-content:flex-start}}}\n"]
235
536
  }]
236
537
  }],
538
+ ctorParameters: () => [],
237
539
  propDecorators: {
540
+ filtersTpl: [{
541
+ type: i0.ContentChild,
542
+ args: [i0.forwardRef(() => RtToolbarFiltersDirective), {
543
+ read: TemplateRef,
544
+ isSignal: true
545
+ }]
546
+ }],
238
547
  leftTpl: [{
239
548
  type: i0.ContentChild,
240
549
  args: [i0.forwardRef(() => RtToolbarLeftDirective), {
@@ -263,9 +572,25 @@ i0.ɵɵngDeclareClassMetadata({
263
572
  alias: "dense",
264
573
  required: false
265
574
  }]
575
+ }],
576
+ filtersActive: [{
577
+ type: i0.Input,
578
+ args: [{
579
+ isSignal: true,
580
+ alias: "filtersActive",
581
+ required: false
582
+ }]
583
+ }],
584
+ filtersApply: [{
585
+ type: i0.Output,
586
+ args: ["filtersApply"]
587
+ }],
588
+ filtersReset: [{
589
+ type: i0.Output,
590
+ args: ["filtersReset"]
266
591
  }]
267
592
  }
268
593
  });
269
- export { RtToolbarCenterDirective, RtToolbarComponent, RtToolbarLeftDirective, RtToolbarRightDirective };
594
+ export { RtToolbarCenterDirective, RtToolbarComponent, RtToolbarFiltersAsideComponent, RtToolbarFiltersDirective, RtToolbarLeftDirective, RtToolbarRightDirective };
270
595
 
271
596
  //# sourceMappingURL=rt-tools-ui-kit-v2-toolbar.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-toolbar.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/toolbar/rt-toolbar.component.ts","../../../projects/ui-kit-v2/src/lib/components/toolbar/rt-toolbar.component.html"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n contentChild,\n Directive,\n input,\n InputSignalWithTransform,\n Signal,\n TemplateRef,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\n/**\n * Маркер-директива для контента в левой секции тулбара.\n *\n * @example\n * ```html\n * <rt-toolbar>\n * <ng-template rtToolbarLeft>\n * <button rtButton label=\"Создать\" />\n * </ng-template>\n * </rt-toolbar>\n * ```\n */\n@Directive({\n selector: '[rtToolbarLeft]',\n})\nexport class RtToolbarLeftDirective {}\n\n/**\n * Маркер-директива для контента в центральной секции тулбара.\n *\n * @example\n * ```html\n * <rt-toolbar>\n * <ng-template rtToolbarCenter>\n * <span>Заголовок страницы</span>\n * </ng-template>\n * </rt-toolbar>\n * ```\n */\n@Directive({\n selector: '[rtToolbarCenter]',\n})\nexport class RtToolbarCenterDirective {}\n\n/**\n * Маркер-директива для контента в правой секции тулбара.\n *\n * @example\n * ```html\n * <rt-toolbar>\n * <ng-template rtToolbarRight>\n * <input type=\"search\" placeholder=\"Поиск\" />\n * </ng-template>\n * </rt-toolbar>\n * ```\n */\n@Directive({\n selector: '[rtToolbarRight]',\n})\nexport class RtToolbarRightDirective {}\n\n/**\n * Универсальный тулбар с тремя секциями: left, center, right.\n * Секции задаются `<ng-template>` с директивами-маркерами и подставляются через `ngTemplateOutlet`.\n * Каждый модуль/фича подключает `rt-toolbar` в своём layout и наполняет нужные секции.\n *\n * @example\n * ```html\n * <rt-toolbar>\n * <ng-template rtToolbarLeft>\n * <button rtButton label=\"Создать\" />\n * <button rtButton label=\"Удалить\" appearance=\"text\" />\n * </ng-template>\n *\n * <ng-template rtToolbarCenter>\n * <span>Заявки</span>\n * </ng-template>\n *\n * <ng-template rtToolbarRight>\n * <input type=\"search\" [formControl]=\"searchCtrl\" />\n * </ng-template>\n * </rt-toolbar>\n * ```\n */\nconst BEM_BLOCK: string = 'rt-toolbar';\n\n@Component({\n selector: 'rt-toolbar',\n templateUrl: './rt-toolbar.component.html',\n styleUrls: ['./rt-toolbar.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n NgTemplateOutlet,\n\n // standalone components / directives\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n host: {\n class: BEM_BLOCK,\n '[class.rt-toolbar--dense]': 'dense()',\n },\n})\nexport class RtToolbarComponent {\n protected readonly leftTpl: Signal<TemplateRef<unknown> | undefined> = contentChild(RtToolbarLeftDirective, { read: TemplateRef });\n\n protected readonly centerTpl: Signal<TemplateRef<unknown> | undefined> = contentChild(RtToolbarCenterDirective, { read: TemplateRef });\n\n protected readonly rightTpl: Signal<TemplateRef<unknown> | undefined> = contentChild(RtToolbarRightDirective, { read: TemplateRef });\n\n /**\n * Компактная шапка (заголовок + иконки-действия): зоны остаются в одну строку\n * даже на мобилке. Без этого трёхзонный list-тулбар стекается в колонку на\n * ≤768px, что для узкой шапки (напр. rt-chat) неверно.\n */\n public readonly dense: InputSignalWithTransform<boolean, boolean | string> = input<boolean, boolean | string>(false, {\n transform: booleanAttribute,\n });\n}\n","@if (leftTpl() || centerTpl() || rightTpl()) {\n <ng-container rtBlock=\"rt-toolbar\">\n <div rtElem=\"bars\">\n @if (leftTpl()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"left\" [rtMod]=\"{ left: true }\">\n <ng-container [ngTemplateOutlet]=\"leftTpl() ?? null\" />\n </div>\n }\n\n @if (centerTpl()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"center\" [rtMod]=\"{ center: true }\">\n <ng-container [ngTemplateOutlet]=\"centerTpl() ?? null\" />\n </div>\n }\n\n @if (rightTpl()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"right\" [rtMod]=\"{ right: true }\">\n <ng-container [ngTemplateOutlet]=\"rightTpl() ?? null\" />\n </div>\n }\n </div>\n </ng-container>\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-toolbar.mjs","names":["BEM_BLOCK"],"sources":["../../../projects/ui-kit-v2/src/lib/components/toolbar/filters-aside/rt-toolbar-filters-aside.component.ts","../../../projects/ui-kit-v2/src/lib/components/toolbar/filters-aside/rt-toolbar-filters-aside.component.html","../../../projects/ui-kit-v2/src/lib/components/toolbar/rt-toolbar.component.ts","../../../projects/ui-kit-v2/src/lib/components/toolbar/rt-toolbar.component.html"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, inject, Signal, ViewEncapsulation } from '@angular/core';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RT_ASIDE_DATA, RtAsideComponent, RtAsideFooterComponent, RtAsideHeaderComponent, RtAsideRef } from '@rt-tools/ui-kit-v2/aside';\nimport { RtButtonDirective } from '@rt-tools/ui-kit-v2/button';\nimport { IRtToolbar } from '../rt-toolbar.model';\n\nconst BEM_BLOCK: string = 'rt-toolbar-filters-aside';\n\n/**\n * Панель отборов полосы `rt-toolbar` на узком экране.\n *\n * Её поднимает кнопка фильтров полосы службой боковых панелей кита. В теле — слот\n * `rtToolbarFilters` с контекстом `panel`; шапка — заголовок «Фильтры» и стрелка возврата, без\n * надзаголовка и действий; подвал — «Сбросить» и «Применить» по краям. «Сбросить» сообщает о себе\n * и оставляет панель открытой, «Применить» сообщает и закрывает, стрелка закрывает молча.\n */\n@Component({\n selector: 'rt-toolbar-filters-aside',\n templateUrl: './rt-toolbar-filters-aside.component.html',\n styleUrl: './rt-toolbar-filters-aside.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n NgTemplateOutlet,\n\n // components\n RtAsideComponent,\n RtAsideFooterComponent,\n RtAsideHeaderComponent,\n\n // directives\n BlockDirective,\n ElemDirective,\n RtButtonDirective,\n ],\n host: { class: BEM_BLOCK },\n})\nexport class RtToolbarFiltersAsideComponent {\n readonly #asideRef: RtAsideRef = inject(RtAsideRef);\n\n protected readonly data: IRtToolbar.IFiltersPanelData = inject(RT_ASIDE_DATA) as IRtToolbar.IFiltersPanelData;\n\n protected readonly title: Signal<string> = rtKitLabel('uiFilters');\n protected readonly resetLabel: Signal<string> = rtKitLabel('uiReset');\n protected readonly applyLabel: Signal<string> = rtKitLabel('uiApply');\n\n protected onReset(): void {\n this.data.reset();\n }\n\n protected onApply(): void {\n this.data.apply();\n this.#asideRef.close();\n }\n}\n","<rt-aside size=\"sm\" trapFocus modal [ariaLabel]=\"title()\">\n <rt-aside-header [title]=\"title()\" />\n\n <ng-container rtBlock=\"rt-toolbar-filters-aside\">\n <!-- Начальный фокус — на блоке полей, а не на стрелке: рамка фокуса не встаёт на кнопку, которую не нажимали -->\n <div rtElem=\"fields\" qa-dataid=\"toolbar-filters-fields\" tabindex=\"-1\" cdkFocusInitial>\n <ng-container [ngTemplateOutlet]=\"data.template\" [ngTemplateOutletContext]=\"{ $implicit: 'panel' }\" />\n </div>\n </ng-container>\n\n <rt-aside-footer [phoneCloseLabel]=\"false\">\n <button rtButton asideDismiss qa-dataid=\"toolbar-filters-reset\" type=\"button\" [label]=\"resetLabel()\" (click)=\"onReset()\">\n <!-- empty: label is drawn by the directive -->\n </button>\n <button rtButton asidePrimary qa-dataid=\"toolbar-filters-apply\" type=\"button\" [label]=\"applyLabel()\" (click)=\"onApply()\">\n <!-- empty: label is drawn by the directive -->\n </button>\n </rt-aside-footer>\n</rt-aside>\n","import { InteractivityChecker } from '@angular/cdk/a11y';\nimport { DOCUMENT, NgTemplateOutlet } from '@angular/common';\nimport {\n afterNextRender,\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n Directive,\n effect,\n ElementRef,\n inject,\n Injector,\n input,\n InputSignalWithTransform,\n output,\n OutputEmitterRef,\n Signal,\n TemplateRef,\n untracked,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport { firstValueFrom } from 'rxjs';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { BreakpointsService, rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RtAsideRef, RtAsideService } from '@rt-tools/ui-kit-v2/aside';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtToolbarFiltersAsideComponent } from './filters-aside/rt-toolbar-filters-aside.component';\nimport { IRtToolbar } from './rt-toolbar.model';\n\n/**\n * Маркер-директива для контента в левой секции тулбара.\n *\n * @example\n * ```html\n * <rt-toolbar>\n * <ng-template rtToolbarLeft>\n * <button rtButton label=\"Создать\" />\n * </ng-template>\n * </rt-toolbar>\n * ```\n */\n@Directive({\n selector: '[rtToolbarLeft]',\n})\nexport class RtToolbarLeftDirective {}\n\n/**\n * Маркер-директива для контента в центральной секции тулбара.\n *\n * @example\n * ```html\n * <rt-toolbar>\n * <ng-template rtToolbarCenter>\n * <span>Заголовок страницы</span>\n * </ng-template>\n * </rt-toolbar>\n * ```\n */\n@Directive({\n selector: '[rtToolbarCenter]',\n})\nexport class RtToolbarCenterDirective {}\n\n/**\n * Маркер-директива для контента в правой секции тулбара.\n *\n * @example\n * ```html\n * <rt-toolbar>\n * <ng-template rtToolbarRight>\n * <input type=\"search\" placeholder=\"Поиск\" />\n * </ng-template>\n * </rt-toolbar>\n * ```\n */\n@Directive({\n selector: '[rtToolbarRight]',\n})\nexport class RtToolbarRightDirective {}\n\n/**\n * Маркер-директива для отборов списка. На широком экране они стоят в левой секции после её\n * содержимого, на узком — за кнопкой фильтров, которая открывает панель отборов. Контекст шаблона\n * — место, где он нарисован: `bar` или `panel`.\n *\n * @example\n * ```html\n * <rt-toolbar [filtersActive]=\"hasFilter()\" (filtersReset)=\"reset()\">\n * <ng-template rtToolbarFilters let-place>\n * <rt-select [label]=\"place === 'panel' ? 'Статус' : null\" … />\n * </ng-template>\n * </rt-toolbar>\n * ```\n */\n@Directive({\n selector: '[rtToolbarFilters]',\n})\nexport class RtToolbarFiltersDirective {\n public static ngTemplateContextGuard(\n _directive: RtToolbarFiltersDirective,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- второй довод стража контекста шаблона стоит только в типе-предикате; убрать его нечем, подпись задаёт каркас\n context: unknown\n ): context is IRtToolbar.IFiltersContext {\n return true;\n }\n}\n\n/**\n * Универсальный тулбар с тремя секциями: left, center, right.\n * Секции задаются `<ng-template>` с директивами-маркерами и подставляются через `ngTemplateOutlet`.\n * Каждый модуль/фича подключает `rt-toolbar` в своём layout и наполняет нужные секции.\n *\n * @example\n * ```html\n * <rt-toolbar>\n * <ng-template rtToolbarLeft>\n * <button rtButton label=\"Создать\" />\n * <button rtButton label=\"Удалить\" appearance=\"text\" />\n * </ng-template>\n *\n * <ng-template rtToolbarCenter>\n * <span>Заявки</span>\n * </ng-template>\n *\n * <ng-template rtToolbarRight>\n * <input type=\"search\" [formControl]=\"searchCtrl\" />\n * </ng-template>\n * </rt-toolbar>\n * ```\n */\nconst BEM_BLOCK: string = 'rt-toolbar';\n\n@Component({\n selector: 'rt-toolbar',\n templateUrl: './rt-toolbar.component.html',\n styleUrls: ['./rt-toolbar.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n NgTemplateOutlet,\n\n // standalone components / directives\n BlockDirective,\n ElemDirective,\n ModDirective,\n RtIconButtonComponent,\n ],\n host: {\n class: BEM_BLOCK,\n '[class.rt-toolbar--dense]': 'dense()',\n '[class.rt-toolbar--filters-collapsed]': 'collapsed()',\n },\n})\nexport class RtToolbarComponent {\n readonly #narrow: Signal<boolean> = inject(BreakpointsService).narrow;\n readonly #asideService: RtAsideService = inject(RtAsideService);\n readonly #injector: Injector = inject(Injector);\n readonly #host: HTMLElement = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n readonly #document: Document = inject(DOCUMENT);\n readonly #interactivity: InteractivityChecker = inject(InteractivityChecker);\n readonly #filtersActiveLabel: Signal<string> = rtKitLabel('uiFiltersActive');\n\n /** Открытая панель отборов: на широком месте её закрывают, чтобы поля не жили в двух местах. */\n #filtersRef: RtAsideRef | null = null;\n\n protected readonly filtersLabel: Signal<string> = rtKitLabel('uiFilters');\n\n /** Имя кнопки для скринридера: точку в углу он не видит, и включённый отбор назван словами. */\n protected readonly filtersAriaLabel: Signal<string> = computed((): string =>\n this.filtersActive() ? this.#filtersActiveLabel() : this.filtersLabel()\n );\n\n protected readonly filtersTpl: Signal<TemplateRef<IRtToolbar.IFiltersContext> | undefined> = contentChild(RtToolbarFiltersDirective, {\n read: TemplateRef,\n });\n\n /** Отборы ушли за кнопку: они объявлены, а место узкое. */\n protected readonly collapsed: Signal<boolean> = computed((): boolean => this.filtersTpl() !== undefined && this.#narrow());\n\n /** Отборы стоят в левой секции: они объявлены, а место широкое. */\n protected readonly filtersInBar: Signal<boolean> = computed((): boolean => this.filtersTpl() !== undefined && !this.#narrow());\n\n protected readonly leftTpl: Signal<TemplateRef<unknown> | undefined> = contentChild(RtToolbarLeftDirective, { read: TemplateRef });\n\n protected readonly centerTpl: Signal<TemplateRef<unknown> | undefined> = contentChild(RtToolbarCenterDirective, { read: TemplateRef });\n\n protected readonly rightTpl: Signal<TemplateRef<unknown> | undefined> = contentChild(RtToolbarRightDirective, { read: TemplateRef });\n\n /**\n * Компактная шапка (заголовок + иконки-действия): зоны остаются в одну строку\n * даже на мобилке. Без этого трёхзонный list-тулбар стекается в колонку на\n * ≤768px, что для узкой шапки (напр. rt-chat) неверно.\n */\n public readonly dense: InputSignalWithTransform<boolean, boolean | string> = input<boolean, boolean | string>(false, {\n transform: booleanAttribute,\n });\n\n /** Включён хотя бы один отбор: кнопка фильтров узкого экрана несёт точку в углу значка. */\n public readonly filtersActive: InputSignalWithTransform<boolean, boolean | string> = input<boolean, boolean | string>(false, {\n transform: booleanAttribute,\n });\n\n /** Нажата «Применить» панели отборов; панель после этого закрыта. */\n public readonly filtersApply: OutputEmitterRef<void> = output<void>();\n\n /** Нажата «Сбросить» панели отборов; панель остаётся открытой. */\n public readonly filtersReset: OutputEmitterRef<void> = output<void>();\n\n constructor() {\n // Место расширилось при открытой панели: отборы вернулись в полосу, и второй экземпляр\n // полей в панели закрывается, иначе одни и те же отборы показаны дважды\n effect((): void => {\n if (this.filtersInBar()) {\n untracked((): void => this.#closeFilters());\n }\n });\n }\n\n protected openFilters(): void {\n const template: TemplateRef<IRtToolbar.IFiltersContext> | undefined = this.filtersTpl();\n // Подложка ловит нажатия только со следующего кадра: второе нажатие до него открыло бы\n // вторую панель поверх первой\n if (template === undefined || this.#filtersRef !== null) {\n return;\n }\n\n // Инжектор полосы — хозяин панели: уничтожение полосы закрывает и панель\n const ref: RtAsideRef = this.#asideService.open<RtToolbarFiltersAsideComponent, IRtToolbar.IFiltersPanelData>(\n RtToolbarFiltersAsideComponent,\n {\n injector: this.#injector,\n data: {\n template,\n reset: (): void => this.filtersReset.emit(),\n apply: (): void => this.filtersApply.emit(),\n },\n position: 'right',\n backdropClass: 'rt-aside-backdrop',\n }\n );\n this.#filtersRef = ref;\n // Панель закрывается и сама — «Применить», стрелкой, подложкой: ссылка гаснет вместе с ней\n void firstValueFrom(ref.afterClosed(), { defaultValue: null }).then((): void => {\n if (this.#filtersRef === ref) {\n this.#filtersRef = null;\n }\n });\n }\n\n #closeFilters(): void {\n if (this.#filtersRef === null) {\n return;\n }\n // Кнопка, с которой панель открыли, на широком месте уже снята, и вернуть фокус панели\n // некуда: он уходит в левую секцию полосы, куда вернулись поля отборов\n const focusInPanel: boolean = this.#document.activeElement?.closest('rt-toolbar-filters-aside') != null;\n this.#filtersRef.close();\n this.#filtersRef = null;\n if (focusInPanel) {\n afterNextRender({ write: (): void => this.#focusBar() }, { injector: this.#injector });\n }\n }\n\n #focusBar(): void {\n const place: HTMLElement = this.#host.querySelector<HTMLElement>('[data-slot=\"left\"]') ?? this.#host;\n const target: HTMLElement | undefined = Array.from(place.querySelectorAll<HTMLElement>('*')).find(\n (node: HTMLElement): boolean => this.#interactivity.isFocusable(node) && this.#interactivity.isTabbable(node)\n );\n target?.focus();\n }\n}\n","@if (leftTpl() || centerTpl() || rightTpl() || filtersTpl()) {\n <ng-container rtBlock=\"rt-toolbar\">\n <div rtElem=\"bars\">\n @if (leftTpl() || filtersInBar()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"left\" [rtMod]=\"{ left: true }\">\n <ng-container [ngTemplateOutlet]=\"leftTpl() ?? null\" />\n\n <!-- На широком месте отборы стоят в полосе сами, после содержимого левой секции -->\n @if (filtersInBar()) {\n <ng-container [ngTemplateOutlet]=\"filtersTpl() ?? null\" [ngTemplateOutletContext]=\"{ $implicit: 'bar' }\" />\n }\n </div>\n }\n\n @if (centerTpl()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"center\" [rtMod]=\"{ center: true }\">\n <ng-container [ngTemplateOutlet]=\"centerTpl() ?? null\" />\n </div>\n }\n\n @if (rightTpl() || collapsed()) {\n <div rtElem=\"bar\" qa-dataid=\"toolbar-bar\" data-slot=\"right\" [rtMod]=\"{ right: true }\">\n <!-- На узком месте отборы уходят за кнопку: она первая в ряду кнопок полосы -->\n @if (collapsed()) {\n <rt-icon-button\n rtElem=\"filters-trigger\"\n qa-dataid=\"toolbar-filters-trigger\"\n icon=\"filter\"\n variant=\"primary\"\n [ariaLabel]=\"filtersAriaLabel()\"\n [tooltip]=\"filtersLabel()\"\n [indicator]=\"filtersActive()\"\n (clicked)=\"openFilters()\" />\n }\n\n <ng-container [ngTemplateOutlet]=\"rightTpl() ?? null\" />\n </div>\n }\n </div>\n </ng-container>\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rt-tools/ui-kit-v2",
3
- "version": "0.38.0",
3
+ "version": "0.39.0",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Yauheni Krumin",
6
6
  "type": "module",
@@ -26,6 +26,7 @@ ref.afterClosed().subscribe((result?: ITour): void => …);
26
26
  | `ariaLabel` | `string \| null` | `null` |
27
27
  | `requestError` | `unknown` | `null` |
28
28
  | `trapFocus` | `boolean` | `false` |
29
+ | `modal` | `boolean` | `false` |
29
30
  | `pending` | `boolean` | `false` |
30
31
 
31
32
  | настройка `open()` | умолчание |
@@ -44,7 +45,9 @@ ref.afterClosed().subscribe((result?: ITour): void => …);
44
45
  минуту открытия. Открытая не по нажатию — через `panelClass` приложения.
45
46
 
46
47
  **Асайд объявлен `role="complementary"`, а не диалогом.** Он не модален: страница за ним
47
- остаётся видна, и это осознанный выбор — карточку смотрят, не теряя список.
48
+ остаётся видна, и это осознанный выбор — карточку смотрят, не теряя список. Панель, которая
49
+ блокирует страницу подложкой и держит фокус, включает вход `modal`: рамка становится
50
+ `role="dialog"` с `aria-modal="true"`.
48
51
 
49
52
  **Закрытие двухтактное.** `close(result)` отдаёт результат **сразу**, а панель убирает через
50
53
  200 мс — чтобы доиграла анимация ухода. В тестах это значит: подписчик получил значение, а
@@ -41,12 +41,15 @@
41
41
  }
42
42
 
43
43
  /* Колонка overline + title. flex/min-width живут здесь, чтобы ellipsis
44
- у title работал и в двухстрочном варианте. */
44
+ у title работал и в двухстрочном варианте. Колонка не ниже кнопки «назад» и держит
45
+ содержимое посередине: заголовок без надзаголовка стоит на линии стрелки. */
45
46
  &__heading {
46
47
  display: flex;
47
48
  min-width: 0;
49
+ min-height: var(--rt-aside-header-back-size, var(--rt-control-height-sm));
48
50
  flex: 1 1 auto;
49
51
  flex-direction: column;
52
+ justify-content: center;
50
53
  gap: var(--rt-space-0-5);
51
54
  }
52
55
 
@@ -42,6 +42,9 @@
42
42
  - `manual` — для контролов со своим жестом (поле с подсказками открывает панель по набору текста).
43
43
  - `hover` держит панель открытой при переходе курсора на неё: закрытие отложено на 100 мс, и
44
44
  наведение на панель отсрочку гасит.
45
+ - `hover` судит наведение только мышиное: касание и перо браузер дублирует событиями мыши, и они
46
+ панель не открывают и не закрывают. Касанию открывает панель нажатие на host, второе нажатие её
47
+ не закрывает — закрывают нажатие снаружи и подложка.
45
48
  - `fitViewport` **выключен по умолчанию**: панель стоит там, куда её ставит привязка к триггеру,
46
49
  даже если часть ушла за экран. Включать для широких и высоких панелей, иначе их содержимое
47
50
  остаётся недостижимым. Порог 120 точек решает только, сдвинуть панель или ужать: короткая
@@ -23,6 +23,10 @@
23
23
  **Панель рисует само меню.** У поповера кита оформления нет, и голые пункты меню в попапе шапки
24
24
  легли бы прямо поверх страницы. Стили без инкапсуляции: попап живёт в перекрытии у конца `<body>`.
25
25
 
26
+ **В панели поповера меню не выше свободного места и прокручивается.** На низком экране — телефон
27
+ боком, невысокое окно — нижние пункты уходили за край. Шапка открывает меню с подгонкой под окно, а
28
+ меню в панели ужимается до её высоты; вне панели оно рисуется во весь рост.
29
+
26
30
  **Тему переключает `ThemeService`**, как у `rt-theme-toggle`: значок показывает тему, к которой
27
31
  переведёт нажатие.
28
32
 
@@ -16,6 +16,17 @@
16
16
  box-shadow: var(--rt-profile-menu-shadow);
17
17
  gap: var(--rt-space-2);
18
18
 
19
+ /* В панели поповера меню ужимается до свободного места под именем, а пункты прокручиваются
20
+ внутри него: на низком экране — телефон боком, невысокое окно — нижние пункты уходили за
21
+ край экрана, и до «Выйти» было не дотянуться. Вне панели меню рисуется как раньше.
22
+ По горизонтали прокрутки нет: строки выступают в поле отступа, и прокручиваемый блок
23
+ прибавлял к ним правый отступ — меню ездило вбок на 8 точек. */
24
+ .rt-popover-panel > & {
25
+ overflow: hidden auto;
26
+ min-height: 0;
27
+ max-height: 100%;
28
+ }
29
+
19
30
  &__user {
20
31
  display: flex;
21
32
  flex-direction: column;
@@ -25,6 +25,7 @@
25
25
  | `scrollStep` | `'fixed' \| 'page' \| 'third'` | `'fixed'` |
26
26
  | `animationDuration` | `string \| number \| null` | `null` |
27
27
  | `preserveContent` | `boolean` | `false` |
28
+ | `dense` | `boolean` | `false` |
28
29
 
29
30
  Выходы: `activeIdChange: IRtTabs.Id`, `tabClose: IRtTabs.Id` — просьба закрыть вкладку с `closable`.
30
31