@rt-tools/ui-kit-v2 0.42.0 → 0.43.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 (43) hide show
  1. package/fesm2022/rt-tools-ui-kit-v2-core.mjs +22 -0
  2. package/fesm2022/rt-tools-ui-kit-v2-core.mjs.map +1 -1
  3. package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs +1778 -18
  4. package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs.map +1 -1
  5. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +19 -5
  6. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
  7. package/fesm2022/rt-tools-ui-kit-v2-stepper.mjs +34 -11
  8. package/fesm2022/rt-tools-ui-kit-v2-stepper.mjs.map +1 -1
  9. package/fesm2022/rt-tools-ui-kit-v2-tabs.mjs +725 -47
  10. package/fesm2022/rt-tools-ui-kit-v2-tabs.mjs.map +1 -1
  11. package/fesm2022/rt-tools-ui-kit-v2-workspace-details.mjs +6 -0
  12. package/fesm2022/rt-tools-ui-kit-v2-workspace-details.mjs.map +1 -1
  13. package/fesm2022/rt-tools-ui-kit-v2-workspace.mjs +217 -6
  14. package/fesm2022/rt-tools-ui-kit-v2-workspace.mjs.map +1 -1
  15. package/package.json +1 -1
  16. package/src/lib/components/page-header/CONTEXT.md +35 -1
  17. package/src/lib/components/page-header/bar/rt-page-bar.component.scss +161 -0
  18. package/src/lib/components/page-header/rail/rt-page-actions.component.scss +115 -0
  19. package/src/lib/components/page-header/rail/rt-page-phone-menu.component.scss +129 -0
  20. package/src/lib/components/page-header/rail/rt-page-rail.component.scss +281 -0
  21. package/src/lib/components/page-header/rail/rt-page-user.component.scss +76 -0
  22. package/src/lib/components/page-header/rt-page-header.component.scss +5 -0
  23. package/src/lib/components/page-header/stories/component/test-page-header-vertical.component.scss +72 -0
  24. package/src/lib/components/page-header/stories/component/test-page-table.component.scss +81 -0
  25. package/src/lib/components/page-header/user/rt-page-header-user.component.scss +6 -0
  26. package/src/lib/components/stepper/CONTEXT.md +34 -2
  27. package/src/lib/components/stepper/rt-stepper.component.scss +62 -43
  28. package/src/lib/components/tabs/CONTEXT.md +30 -1
  29. package/src/lib/components/tabs/rt-tabs-arrows.scss +140 -0
  30. package/src/lib/components/tabs/rt-tabs-more-menu.scss +126 -0
  31. package/src/lib/components/tabs/rt-tabs-more.component.scss +29 -0
  32. package/src/lib/components/tabs/rt-tabs.component.scss +18 -61
  33. package/src/lib/components/workspace/CONTEXT.md +11 -1
  34. package/src/lib/components/workspace/rt-workspace.component.scss +51 -3
  35. package/src/rich-editor/lib/components/chat/CONTEXT.md +11 -1
  36. package/src/rich-editor/lib/components/chat/rt-chat-messenger.scss +9 -3
  37. package/src/rich-editor/lib/components/chat/rt-chat-translation.scss +92 -0
  38. package/types/rt-tools-ui-kit-v2-core.d.ts +9 -1
  39. package/types/rt-tools-ui-kit-v2-page-header.d.ts +202 -2
  40. package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +23 -0
  41. package/types/rt-tools-ui-kit-v2-stepper.d.ts +20 -6
  42. package/types/rt-tools-ui-kit-v2-tabs.d.ts +120 -1
  43. package/types/rt-tools-ui-kit-v2-workspace.d.ts +33 -1
@@ -1,12 +1,15 @@
1
1
  import { DOCUMENT, NgTemplateOutlet } from "@angular/common";
2
2
  import * as i0 from "@angular/core";
3
- import { ChangeDetectionStrategy, Component, DestroyRef, Directive, ElementRef, Injector, TemplateRef, ViewEncapsulation, afterNextRender, afterRenderEffect, booleanAttribute, computed, contentChildren, inject, input, linkedSignal, output, signal, untracked, viewChild } from "@angular/core";
3
+ import { ChangeDetectionStrategy, Component, DestroyRef, Directive, ElementRef, Injector, TemplateRef, ViewEncapsulation, afterNextRender, afterRenderEffect, booleanAttribute, computed, contentChildren, effect, inject, input, linkedSignal, numberAttribute, output, signal, untracked, viewChild } from "@angular/core";
4
4
  import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
5
5
  import { debounceTime, fromEvent } from "rxjs";
6
6
  import { BlockDirective, ElemDirective, ModDirective } from "@rt-tools/core";
7
7
  import { RtIconComponent } from "@rt-tools/ui-kit-v2/icon";
8
8
  import { RtTooltipDirective } from "@rt-tools/ui-kit-v2/tooltip";
9
- import { rtKitLabel } from "@rt-tools/ui-kit-v2/core";
9
+ import { RT_KIT_LABELS, rtKitLabel } from "@rt-tools/ui-kit-v2/core";
10
+ import { CdkConnectedOverlay } from "@angular/cdk/overlay";
11
+ import { FocusKeyManager } from "@angular/cdk/a11y";
12
+ import { RtPopoverDirective } from "@rt-tools/ui-kit-v2/popover";
10
13
  var RtTabDirective = class RtTabDirective {
11
14
  constructor() {
12
15
  this.#t_uiTabInvalid = rtKitLabel("uiTabInvalid");
@@ -47,6 +50,11 @@ var RtTabDirective = class RtTabDirective {
47
50
  ...ngDevMode ? { debugName: "closable" } : /* istanbul ignore next */ {},
48
51
  transform: booleanAttribute
49
52
  });
53
+ this.pinned = input(false, {
54
+ ...ngDevMode ? { debugName: "pinned" } : /* istanbul ignore next */ {},
55
+ transform: booleanAttribute
56
+ });
57
+ this.contextMenu = input(null, ...ngDevMode ? [{ debugName: "contextMenu" }] : /* istanbul ignore next */ []);
50
58
  this.closeTooltip = input("", ...ngDevMode ? [{ debugName: "closeTooltip" }] : /* istanbul ignore next */ []);
51
59
  this.closeTooltipPlacement = input(null, ...ngDevMode ? [{ debugName: "closeTooltipPlacement" }] : /* istanbul ignore next */ []);
52
60
  this.closeHovered = signal(false, ...ngDevMode ? [{ debugName: "closeHovered" }] : /* istanbul ignore next */ []);
@@ -57,7 +65,8 @@ var RtTabDirective = class RtTabDirective {
57
65
  }, ...ngDevMode ? [{ debugName: "buttonTooltip" }] : /* istanbul ignore next */ []);
58
66
  this.ariaLabel = computed(() => this.label() || this.titleTemplate() ? null : this.tooltip() || null, ...ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
59
67
  this.closeLabel = computed(() => this.closeTooltip() || this.#t_uiClose(), ...ngDevMode ? [{ debugName: "closeLabel" }] : /* istanbul ignore next */ []);
60
- this.hasIcon = computed(() => Boolean(this.icon() || this.glyph()), ...ngDevMode ? [{ debugName: "hasIcon" }] : /* istanbul ignore next */ []);
68
+ this.shownIcon = computed(() => this.icon() ?? (this.pinned() && !this.glyph() ? "pin" : null), ...ngDevMode ? [{ debugName: "shownIcon" }] : /* istanbul ignore next */ []);
69
+ this.hasIcon = computed(() => Boolean(this.shownIcon() || this.glyph()), ...ngDevMode ? [{ debugName: "hasIcon" }] : /* istanbul ignore next */ []);
61
70
  this.badgeOverlay = computed(() => this.badgePosition() === "overlay" && this.badge() !== null && this.hasIcon(), ...ngDevMode ? [{ debugName: "badgeOverlay" }] : /* istanbul ignore next */ []);
62
71
  this.showClose = computed(() => this.closable() && !this.disabled(), ...ngDevMode ? [{ debugName: "showClose" }] : /* istanbul ignore next */ []);
63
72
  }
@@ -200,6 +209,20 @@ var RtTabDirective = class RtTabDirective {
200
209
  isRequired: false,
201
210
  transformFunction: null
202
211
  },
212
+ pinned: {
213
+ classPropertyName: "pinned",
214
+ publicName: "pinned",
215
+ isSignal: true,
216
+ isRequired: false,
217
+ transformFunction: null
218
+ },
219
+ contextMenu: {
220
+ classPropertyName: "contextMenu",
221
+ publicName: "contextMenu",
222
+ isSignal: true,
223
+ isRequired: false,
224
+ transformFunction: null
225
+ },
203
226
  closeTooltip: {
204
227
  classPropertyName: "closeTooltip",
205
228
  publicName: "closeTooltip",
@@ -365,6 +388,22 @@ i0.ɵɵngDeclareClassMetadata({
365
388
  required: false
366
389
  }]
367
390
  }],
391
+ pinned: [{
392
+ type: i0.Input,
393
+ args: [{
394
+ isSignal: true,
395
+ alias: "pinned",
396
+ required: false
397
+ }]
398
+ }],
399
+ contextMenu: [{
400
+ type: i0.Input,
401
+ args: [{
402
+ isSignal: true,
403
+ alias: "contextMenu",
404
+ required: false
405
+ }]
406
+ }],
368
407
  closeTooltip: [{
369
408
  type: i0.Input,
370
409
  args: [{
@@ -597,6 +636,12 @@ function rtTabsEasing(value) {
597
636
  return bezierAt((low + high) / 2, y1, y2);
598
637
  };
599
638
  }
639
+ function rtTabsRestShown(list) {
640
+ return {
641
+ before: list.scrollLeft > 0,
642
+ after: list.scrollWidth - list.scrollLeft - list.clientWidth > 1
643
+ };
644
+ }
600
645
  function rtTabsPageTarget(list, from, back, step) {
601
646
  const max = Math.max(0, list.scrollWidth - list.clientWidth);
602
647
  const shift = step === "fixed" ? FIXED_STEP : list.clientWidth * STEP_SHARE[step];
@@ -625,6 +670,16 @@ var RtTabsScroller = class {
625
670
  from() {
626
671
  return this.#target ?? this.#list()?.nativeElement.scrollLeft ?? 0;
627
672
  }
673
+ place(target, instant) {
674
+ const list = this.#list()?.nativeElement;
675
+ if (target === null || !list) return;
676
+ if (instant) {
677
+ this.stop();
678
+ list.scrollLeft = target;
679
+ return;
680
+ }
681
+ this.to(target);
682
+ }
628
683
  to(left) {
629
684
  const list = this.#list()?.nativeElement;
630
685
  const win = this.#win;
@@ -754,6 +809,23 @@ var RtTabsFollow = class {
754
809
  this.#list = null;
755
810
  }
756
811
  };
812
+ function rtTabsKeyTarget(key, direction, index, count) {
813
+ const isVertical = direction === "vertical";
814
+ return (/* @__PURE__ */ new Map([
815
+ [isVertical ? "ArrowDown" : "ArrowRight", (index + 1) % count],
816
+ [isVertical ? "ArrowUp" : "ArrowLeft", (index - 1 + count) % count],
817
+ ["Home", 0],
818
+ ["End", count - 1]
819
+ ])).get(key);
820
+ }
821
+ function rtTabsKeyTargetId(enabled, currentId, key, direction) {
822
+ if (!enabled.length) return;
823
+ const index = rtTabsKeyTarget(key, direction, enabled.indexOf(currentId), enabled.length);
824
+ return index === void 0 ? void 0 : enabled[index];
825
+ }
826
+ function rtTabsSelectedId(enabled, candidate) {
827
+ return candidate !== null && enabled.includes(candidate) ? candidate : enabled[0] ?? null;
828
+ }
757
829
  var RtTabsControlDirective = class RtTabsControlDirective {
758
830
  constructor() {
759
831
  this.templateRef = inject(TemplateRef);
@@ -809,6 +881,539 @@ i0.ɵɵngDeclareClassMetadata({
809
881
  }]
810
882
  }] }
811
883
  });
884
+ var RtTabsMenuKeysDirective = class RtTabsMenuKeysDirective {
885
+ #host = inject(ElementRef).nativeElement;
886
+ #doc = inject(DOCUMENT);
887
+ #returnTo = this.#doc.activeElement;
888
+ #keys = null;
889
+ constructor() {
890
+ afterNextRender(() => {
891
+ const items = this.#items().map((node) => ({
892
+ disabled: node.getAttribute("aria-disabled") === "true" || node.hasAttribute("disabled"),
893
+ focus: () => node.focus()
894
+ }));
895
+ this.#keys = new FocusKeyManager(items).withWrap().withHomeAndEnd();
896
+ this.#keys.setFirstItemActive();
897
+ });
898
+ inject(DestroyRef).onDestroy(() => {
899
+ this.#keys?.destroy();
900
+ const active = this.#doc.activeElement;
901
+ if ((active === null || active === this.#doc.body || this.#host.contains(active)) && this.#returnTo instanceof HTMLElement && this.#returnTo.isConnected) this.#returnTo.focus();
902
+ });
903
+ }
904
+ onKeydown(event) {
905
+ if (event.key !== "Tab" && event.key !== "Escape") this.#keys?.onKeydown(event);
906
+ }
907
+ #items() {
908
+ const items = Array.from(this.#host.querySelectorAll("[role=\"menuitem\"]"));
909
+ return items.length > 0 ? items : Array.from(this.#host.querySelectorAll("button"));
910
+ }
911
+ static {
912
+ this.ɵfac = i0.ɵɵngDeclareFactory({
913
+ minVersion: "12.0.0",
914
+ version: "22.2.2",
915
+ ngImport: i0,
916
+ type: RtTabsMenuKeysDirective,
917
+ deps: [],
918
+ target: i0.ɵɵFactoryTarget.Directive
919
+ });
920
+ }
921
+ static {
922
+ this.ɵdir = i0.ɵɵngDeclareDirective({
923
+ minVersion: "14.0.0",
924
+ version: "22.2.2",
925
+ type: RtTabsMenuKeysDirective,
926
+ isStandalone: true,
927
+ selector: "[rtTabsMenuKeys]",
928
+ host: { listeners: { "keydown": "onKeydown($event)" } },
929
+ ngImport: i0
930
+ });
931
+ }
932
+ };
933
+ i0.ɵɵngDeclareClassMetadata({
934
+ minVersion: "12.0.0",
935
+ version: "22.2.2",
936
+ ngImport: i0,
937
+ type: RtTabsMenuKeysDirective,
938
+ decorators: [{
939
+ type: Directive,
940
+ args: [{
941
+ selector: "[rtTabsMenuKeys]",
942
+ host: { "(keydown)": "onKeydown($event)" }
943
+ }]
944
+ }],
945
+ ctorParameters: () => []
946
+ });
947
+ const BEM_BLOCK$2 = "rt-tabs-context-menu";
948
+ var RtTabsContextMenuComponent = class RtTabsContextMenuComponent {
949
+ constructor() {
950
+ this.state = signal(null, ...ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []);
951
+ }
952
+ open(event, tab) {
953
+ const template = tab.contextMenu();
954
+ if (template === null) return;
955
+ event.preventDefault();
956
+ this.state.set({
957
+ template,
958
+ point: RtTabsContextMenuComponent.pointOf(event),
959
+ context: { $implicit: tab.id() }
960
+ });
961
+ }
962
+ static pointOf(event) {
963
+ if (event.clientX === 0 && event.clientY === 0 && event.target instanceof Element) {
964
+ const box = event.target.getBoundingClientRect();
965
+ return {
966
+ x: box.left,
967
+ y: box.bottom
968
+ };
969
+ }
970
+ return {
971
+ x: event.clientX,
972
+ y: event.clientY
973
+ };
974
+ }
975
+ close() {
976
+ this.state.set(null);
977
+ }
978
+ onKeydown(event) {
979
+ if (event.key === "Escape") this.close();
980
+ }
981
+ static {
982
+ this.ɵfac = i0.ɵɵngDeclareFactory({
983
+ minVersion: "12.0.0",
984
+ version: "22.2.2",
985
+ ngImport: i0,
986
+ type: RtTabsContextMenuComponent,
987
+ deps: [],
988
+ target: i0.ɵɵFactoryTarget.Component
989
+ });
990
+ }
991
+ static {
992
+ this.ɵcmp = i0.ɵɵngDeclareComponent({
993
+ minVersion: "17.0.0",
994
+ version: "22.2.2",
995
+ type: RtTabsContextMenuComponent,
996
+ isStandalone: true,
997
+ selector: "rt-tabs-context-menu",
998
+ host: { classAttribute: "rt-tabs-context-menu" },
999
+ ngImport: i0,
1000
+ template: "@if (state(); as menu) {\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOpen]=\"true\"\n [cdkConnectedOverlayOrigin]=\"menu.point\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\"\n (overlayKeydown)=\"onKeydown($event)\">\n <div\n rtBlock=\"rt-tabs-more-menu\"\n rtTabsMenuKeys\n role=\"menu\"\n tabindex=\"-1\"\n qa-dataid=\"tabs-context-menu\"\n (click)=\"close()\"\n (keydown.enter)=\"close()\">\n <ng-container [ngTemplateOutlet]=\"menu.template\" [ngTemplateOutletContext]=\"menu.context\" />\n </div>\n </ng-template>\n}\n",
1001
+ dependencies: [
1002
+ {
1003
+ kind: "directive",
1004
+ type: CdkConnectedOverlay,
1005
+ selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]",
1006
+ inputs: [
1007
+ "cdkConnectedOverlayOrigin",
1008
+ "cdkConnectedOverlayPositions",
1009
+ "cdkConnectedOverlayPositionStrategy",
1010
+ "cdkConnectedOverlayOffsetX",
1011
+ "cdkConnectedOverlayOffsetY",
1012
+ "cdkConnectedOverlayWidth",
1013
+ "cdkConnectedOverlayHeight",
1014
+ "cdkConnectedOverlayMinWidth",
1015
+ "cdkConnectedOverlayMinHeight",
1016
+ "cdkConnectedOverlayBackdropClass",
1017
+ "cdkConnectedOverlayPanelClass",
1018
+ "cdkConnectedOverlayViewportMargin",
1019
+ "cdkConnectedOverlayScrollStrategy",
1020
+ "cdkConnectedOverlayOpen",
1021
+ "cdkConnectedOverlayDisableClose",
1022
+ "cdkConnectedOverlayTransformOriginOn",
1023
+ "cdkConnectedOverlayHasBackdrop",
1024
+ "cdkConnectedOverlayLockPosition",
1025
+ "cdkConnectedOverlayFlexibleDimensions",
1026
+ "cdkConnectedOverlayGrowAfterOpen",
1027
+ "cdkConnectedOverlayPush",
1028
+ "cdkConnectedOverlayDisposeOnNavigation",
1029
+ "cdkConnectedOverlayUsePopover",
1030
+ "cdkConnectedOverlayMatchWidth",
1031
+ "cdkConnectedOverlay"
1032
+ ],
1033
+ outputs: [
1034
+ "backdropClick",
1035
+ "positionChange",
1036
+ "attach",
1037
+ "detach",
1038
+ "overlayKeydown",
1039
+ "overlayOutsideClick"
1040
+ ],
1041
+ exportAs: ["cdkConnectedOverlay"]
1042
+ },
1043
+ {
1044
+ kind: "directive",
1045
+ type: NgTemplateOutlet,
1046
+ selector: "[ngTemplateOutlet]",
1047
+ inputs: [
1048
+ "ngTemplateOutletContext",
1049
+ "ngTemplateOutlet",
1050
+ "ngTemplateOutletInjector"
1051
+ ]
1052
+ },
1053
+ {
1054
+ kind: "directive",
1055
+ type: RtTabsMenuKeysDirective,
1056
+ selector: "[rtTabsMenuKeys]"
1057
+ },
1058
+ {
1059
+ kind: "directive",
1060
+ type: BlockDirective,
1061
+ selector: "[rtBlock]",
1062
+ inputs: ["rtMod"]
1063
+ }
1064
+ ],
1065
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
1066
+ encapsulation: i0.ViewEncapsulation.None
1067
+ });
1068
+ }
1069
+ };
1070
+ i0.ɵɵngDeclareClassMetadata({
1071
+ minVersion: "12.0.0",
1072
+ version: "22.2.2",
1073
+ ngImport: i0,
1074
+ type: RtTabsContextMenuComponent,
1075
+ decorators: [{
1076
+ type: Component,
1077
+ args: [{
1078
+ selector: "rt-tabs-context-menu",
1079
+ changeDetection: ChangeDetectionStrategy.OnPush,
1080
+ encapsulation: ViewEncapsulation.None,
1081
+ imports: [
1082
+ CdkConnectedOverlay,
1083
+ NgTemplateOutlet,
1084
+ RtTabsMenuKeysDirective,
1085
+ BlockDirective
1086
+ ],
1087
+ host: { class: BEM_BLOCK$2 },
1088
+ template: "@if (state(); as menu) {\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOpen]=\"true\"\n [cdkConnectedOverlayOrigin]=\"menu.point\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\"\n (overlayKeydown)=\"onKeydown($event)\">\n <div\n rtBlock=\"rt-tabs-more-menu\"\n rtTabsMenuKeys\n role=\"menu\"\n tabindex=\"-1\"\n qa-dataid=\"tabs-context-menu\"\n (click)=\"close()\"\n (keydown.enter)=\"close()\">\n <ng-container [ngTemplateOutlet]=\"menu.template\" [ngTemplateOutletContext]=\"menu.context\" />\n </div>\n </ng-template>\n}\n"
1089
+ }]
1090
+ }]
1091
+ });
1092
+ const BEM_BLOCK$1 = "rt-tabs-more";
1093
+ var RtTabsMoreComponent = class RtTabsMoreComponent {
1094
+ constructor() {
1095
+ this.t = inject(RT_KIT_LABELS);
1096
+ this.popover = viewChild(RtPopoverDirective, ...ngDevMode ? [{ debugName: "popover" }] : /* istanbul ignore next */ []);
1097
+ this.hasError = computed(() => this.tabs().some((tab) => tab.invalid()), ...ngDevMode ? [{ debugName: "hasError" }] : /* istanbul ignore next */ []);
1098
+ this.tabs = input([], ...ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []);
1099
+ this.pick = output();
1100
+ this.closeTab = output();
1101
+ effect(() => {
1102
+ const popover = this.popover();
1103
+ if (this.tabs().length === 0 && popover?.isOpen()) popover.close();
1104
+ });
1105
+ }
1106
+ onPick(tab, popover) {
1107
+ if (tab.disabled()) return;
1108
+ this.pick.emit(tab.id());
1109
+ popover.close();
1110
+ }
1111
+ static {
1112
+ this.ɵfac = i0.ɵɵngDeclareFactory({
1113
+ minVersion: "12.0.0",
1114
+ version: "22.2.2",
1115
+ ngImport: i0,
1116
+ type: RtTabsMoreComponent,
1117
+ deps: [],
1118
+ target: i0.ɵɵFactoryTarget.Component
1119
+ });
1120
+ }
1121
+ static {
1122
+ this.ɵcmp = i0.ɵɵngDeclareComponent({
1123
+ minVersion: "17.0.0",
1124
+ version: "22.2.2",
1125
+ type: RtTabsMoreComponent,
1126
+ isStandalone: true,
1127
+ selector: "rt-tabs-more",
1128
+ inputs: { tabs: {
1129
+ classPropertyName: "tabs",
1130
+ publicName: "tabs",
1131
+ isSignal: true,
1132
+ isRequired: false,
1133
+ transformFunction: null
1134
+ } },
1135
+ outputs: {
1136
+ pick: "pick",
1137
+ closeTab: "closeTab"
1138
+ },
1139
+ host: {
1140
+ attributes: { "role": "presentation" },
1141
+ properties: { "class.rt-tabs-more--idle": "!tabs().length" },
1142
+ classAttribute: "rt-tabs-more"
1143
+ },
1144
+ viewQueries: [{
1145
+ propertyName: "popover",
1146
+ first: true,
1147
+ predicate: RtPopoverDirective,
1148
+ descendants: true,
1149
+ isSignal: true
1150
+ }],
1151
+ ngImport: i0,
1152
+ template: "<!-- Пункт выглядит как вкладка и берёт её блок: второй набор тех же правил разошёлся бы с первым. -->\n<div rtBlock=\"rt-tab-item\" role=\"presentation\">\n <button\n rtElem=\"trigger\"\n qa-dataid=\"tabs-more\"\n type=\"button\"\n role=\"tab\"\n aria-haspopup=\"menu\"\n aria-selected=\"false\"\n #morePopover=\"rtPopover\"\n rtPopoverAlign=\"end\"\n rtPopoverFitViewport\n rtPopoverOffsetY=\"6\"\n [attr.aria-expanded]=\"morePopover.isOpen()\"\n [attr.tabindex]=\"tabs().length ? 0 : -1\"\n [rtMod]=\"{ open: morePopover.isOpen() }\"\n [rtPopover]=\"moreTpl\">\n <span rtElem=\"title\">{{ t().uiNavMore }}</span>\n @if (hasError()) {\n <span rtElem=\"more-dot\" role=\"img\" qa-dataid=\"tabs-more-dot\" [attr.aria-label]=\"t().uiTabInvalid\"></span>\n }\n <rt-icon color=\"current\" size=\"xs\" [name]=\"morePopover.isOpen() ? 'chevron-up' : 'chevron-down'\" />\n </button>\n</div>\n\n<ng-template #moreTpl>\n <div rtBlock=\"rt-tabs-more-menu\" rtTabsMenuKeys role=\"menu\" qa-dataid=\"tabs-more-menu\">\n @for (tab of tabs(); track tab.id()) {\n <div rtElem=\"row\" role=\"none\" [rtMod]=\"{ disabled: tab.disabled(), invalid: tab.invalid() }\">\n <button\n rtElem=\"pick\"\n qa-dataid=\"tabs-more-item\"\n type=\"button\"\n role=\"menuitem\"\n [attr.aria-disabled]=\"tab.disabled() || null\"\n [attr.data-id]=\"tab.id()\"\n [rtTooltip]=\"tab.buttonTooltip()\"\n (click)=\"onPick(tab, morePopover)\">\n @if (tab.hasIcon()) {\n <rt-icon\n rtElem=\"icon\"\n size=\"sm\"\n [name]=\"tab.icon()\"\n [glyph]=\"tab.glyph()\"\n [color]=\"tab.iconColor()\"\n [fill]=\"tab.iconFill()\" />\n }\n <span rtElem=\"label\">\n @if (tab.titleTemplate(); as titleTpl) {\n <ng-container [ngTemplateOutlet]=\"titleTpl\" />\n } @else {\n {{ tab.label() }}\n }\n </span>\n @if (tab.badge() !== null) {\n <span rtElem=\"badge\">{{ tab.badge() }}</span>\n }\n </button>\n @if (tab.showClose()) {\n <button\n rtElem=\"close\"\n qa-dataid=\"tabs-more-close\"\n type=\"button\"\n [attr.aria-label]=\"tab.closeLabel()\"\n [attr.data-id]=\"tab.id()\"\n (click)=\"closeTab.emit(tab)\">\n <rt-icon name=\"close\" color=\"current\" size=\"xs\" />\n </button>\n }\n </div>\n }\n </div>\n</ng-template>\n",
1153
+ styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-tabs-more{--rt-tabs-more-dot-radius: var(--rt-radius-full);display:inline-flex;order:9999}.rt-tabs-more--idle{position:absolute;top:0;left:0;pointer-events:none;visibility:hidden}.rt-tabs-more .rt-tab-item__trigger--open{background-color:var(--rt-color-bg-hover);color:var(--rt-color-text-primary)}.rt-tabs-more .rt-tab-item__more-dot{width:var(--rt-size-2);height:var(--rt-size-2);border-radius:var(--rt-tabs-more-dot-radius);background-color:var(--rt-color-state-danger)}}\n"],
1154
+ dependencies: [
1155
+ {
1156
+ kind: "directive",
1157
+ type: NgTemplateOutlet,
1158
+ selector: "[ngTemplateOutlet]",
1159
+ inputs: [
1160
+ "ngTemplateOutletContext",
1161
+ "ngTemplateOutlet",
1162
+ "ngTemplateOutletInjector"
1163
+ ]
1164
+ },
1165
+ {
1166
+ kind: "component",
1167
+ type: RtIconComponent,
1168
+ selector: "rt-icon",
1169
+ inputs: [
1170
+ "name",
1171
+ "glyph",
1172
+ "glyphStrategy",
1173
+ "size",
1174
+ "color",
1175
+ "fill",
1176
+ "spin",
1177
+ "rotate"
1178
+ ]
1179
+ },
1180
+ {
1181
+ kind: "directive",
1182
+ type: RtPopoverDirective,
1183
+ selector: "[rtPopover]",
1184
+ inputs: [
1185
+ "rtPopover",
1186
+ "rtPopoverTrigger",
1187
+ "rtPopoverWidth",
1188
+ "rtPopoverAlign",
1189
+ "rtPopoverFitViewport",
1190
+ "rtPopoverContext",
1191
+ "rtPopoverPanelClass",
1192
+ "rtPopoverBackdropClass",
1193
+ "rtPopoverDisabled",
1194
+ "rtPopoverOffsetY",
1195
+ "rtPopoverOffsetX",
1196
+ "rtPopoverPositions"
1197
+ ],
1198
+ outputs: ["rtPopoverOpened", "rtPopoverClosed"],
1199
+ exportAs: ["rtPopover"]
1200
+ },
1201
+ {
1202
+ kind: "directive",
1203
+ type: RtTooltipDirective,
1204
+ selector: "[rtTooltip]",
1205
+ inputs: [
1206
+ "rtTooltip",
1207
+ "rtTooltipPlacement",
1208
+ "rtTooltipShowDelay",
1209
+ "rtTooltipWhenTruncated",
1210
+ "rtTooltipHideOnClick",
1211
+ "rtTooltipShowOnTap"
1212
+ ],
1213
+ exportAs: ["rtTooltip"]
1214
+ },
1215
+ {
1216
+ kind: "directive",
1217
+ type: RtTabsMenuKeysDirective,
1218
+ selector: "[rtTabsMenuKeys]"
1219
+ },
1220
+ {
1221
+ kind: "directive",
1222
+ type: BlockDirective,
1223
+ selector: "[rtBlock]",
1224
+ inputs: ["rtMod"]
1225
+ },
1226
+ {
1227
+ kind: "directive",
1228
+ type: ElemDirective,
1229
+ selector: "[rtElem]",
1230
+ inputs: ["rtMod"]
1231
+ },
1232
+ {
1233
+ kind: "directive",
1234
+ type: ModDirective,
1235
+ selector: "[rtMod]"
1236
+ }
1237
+ ],
1238
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
1239
+ encapsulation: i0.ViewEncapsulation.None
1240
+ });
1241
+ }
1242
+ };
1243
+ i0.ɵɵngDeclareClassMetadata({
1244
+ minVersion: "12.0.0",
1245
+ version: "22.2.2",
1246
+ ngImport: i0,
1247
+ type: RtTabsMoreComponent,
1248
+ decorators: [{
1249
+ type: Component,
1250
+ args: [{
1251
+ selector: "rt-tabs-more",
1252
+ changeDetection: ChangeDetectionStrategy.OnPush,
1253
+ encapsulation: ViewEncapsulation.None,
1254
+ imports: [
1255
+ NgTemplateOutlet,
1256
+ RtIconComponent,
1257
+ RtPopoverDirective,
1258
+ RtTooltipDirective,
1259
+ RtTabsMenuKeysDirective,
1260
+ BlockDirective,
1261
+ ElemDirective,
1262
+ ModDirective
1263
+ ],
1264
+ host: {
1265
+ class: BEM_BLOCK$1,
1266
+ role: "presentation",
1267
+ "[class.rt-tabs-more--idle]": "!tabs().length"
1268
+ },
1269
+ template: "<!-- Пункт выглядит как вкладка и берёт её блок: второй набор тех же правил разошёлся бы с первым. -->\n<div rtBlock=\"rt-tab-item\" role=\"presentation\">\n <button\n rtElem=\"trigger\"\n qa-dataid=\"tabs-more\"\n type=\"button\"\n role=\"tab\"\n aria-haspopup=\"menu\"\n aria-selected=\"false\"\n #morePopover=\"rtPopover\"\n rtPopoverAlign=\"end\"\n rtPopoverFitViewport\n rtPopoverOffsetY=\"6\"\n [attr.aria-expanded]=\"morePopover.isOpen()\"\n [attr.tabindex]=\"tabs().length ? 0 : -1\"\n [rtMod]=\"{ open: morePopover.isOpen() }\"\n [rtPopover]=\"moreTpl\">\n <span rtElem=\"title\">{{ t().uiNavMore }}</span>\n @if (hasError()) {\n <span rtElem=\"more-dot\" role=\"img\" qa-dataid=\"tabs-more-dot\" [attr.aria-label]=\"t().uiTabInvalid\"></span>\n }\n <rt-icon color=\"current\" size=\"xs\" [name]=\"morePopover.isOpen() ? 'chevron-up' : 'chevron-down'\" />\n </button>\n</div>\n\n<ng-template #moreTpl>\n <div rtBlock=\"rt-tabs-more-menu\" rtTabsMenuKeys role=\"menu\" qa-dataid=\"tabs-more-menu\">\n @for (tab of tabs(); track tab.id()) {\n <div rtElem=\"row\" role=\"none\" [rtMod]=\"{ disabled: tab.disabled(), invalid: tab.invalid() }\">\n <button\n rtElem=\"pick\"\n qa-dataid=\"tabs-more-item\"\n type=\"button\"\n role=\"menuitem\"\n [attr.aria-disabled]=\"tab.disabled() || null\"\n [attr.data-id]=\"tab.id()\"\n [rtTooltip]=\"tab.buttonTooltip()\"\n (click)=\"onPick(tab, morePopover)\">\n @if (tab.hasIcon()) {\n <rt-icon\n rtElem=\"icon\"\n size=\"sm\"\n [name]=\"tab.icon()\"\n [glyph]=\"tab.glyph()\"\n [color]=\"tab.iconColor()\"\n [fill]=\"tab.iconFill()\" />\n }\n <span rtElem=\"label\">\n @if (tab.titleTemplate(); as titleTpl) {\n <ng-container [ngTemplateOutlet]=\"titleTpl\" />\n } @else {\n {{ tab.label() }}\n }\n </span>\n @if (tab.badge() !== null) {\n <span rtElem=\"badge\">{{ tab.badge() }}</span>\n }\n </button>\n @if (tab.showClose()) {\n <button\n rtElem=\"close\"\n qa-dataid=\"tabs-more-close\"\n type=\"button\"\n [attr.aria-label]=\"tab.closeLabel()\"\n [attr.data-id]=\"tab.id()\"\n (click)=\"closeTab.emit(tab)\">\n <rt-icon name=\"close\" color=\"current\" size=\"xs\" />\n </button>\n }\n </div>\n }\n </div>\n</ng-template>\n",
1270
+ styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-tabs-more{--rt-tabs-more-dot-radius: var(--rt-radius-full);display:inline-flex;order:9999}.rt-tabs-more--idle{position:absolute;top:0;left:0;pointer-events:none;visibility:hidden}.rt-tabs-more .rt-tab-item__trigger--open{background-color:var(--rt-color-bg-hover);color:var(--rt-color-text-primary)}.rt-tabs-more .rt-tab-item__more-dot{width:var(--rt-size-2);height:var(--rt-size-2);border-radius:var(--rt-tabs-more-dot-radius);background-color:var(--rt-color-state-danger)}}\n"]
1271
+ }]
1272
+ }],
1273
+ ctorParameters: () => [],
1274
+ propDecorators: {
1275
+ popover: [{
1276
+ type: i0.ViewChild,
1277
+ args: [i0.forwardRef(() => RtPopoverDirective), { isSignal: true }]
1278
+ }],
1279
+ tabs: [{
1280
+ type: i0.Input,
1281
+ args: [{
1282
+ isSignal: true,
1283
+ alias: "tabs",
1284
+ required: false
1285
+ }]
1286
+ }],
1287
+ pick: [{
1288
+ type: i0.Output,
1289
+ args: ["pick"]
1290
+ }],
1291
+ closeTab: [{
1292
+ type: i0.Output,
1293
+ args: ["closeTab"]
1294
+ }]
1295
+ }
1296
+ });
1297
+ const FIT_TOLERANCE = .5;
1298
+ function widthOf(tabs) {
1299
+ return tabs.reduce((sum, tab) => sum + tab.width, 0);
1300
+ }
1301
+ function idOf(tab) {
1302
+ return tab.id;
1303
+ }
1304
+ function leadingFit(free, budget, limit) {
1305
+ const prefix = [];
1306
+ let used = 0;
1307
+ for (const tab of free) {
1308
+ if (prefix.length >= limit || used + tab.width > budget) break;
1309
+ prefix.push(tab);
1310
+ used += tab.width;
1311
+ }
1312
+ return prefix;
1313
+ }
1314
+ function makeRoom(prefix, selected, budget, limit) {
1315
+ while (prefix.length > 0 && (widthOf(prefix) + selected.width > budget || prefix.length >= limit)) prefix.pop();
1316
+ prefix.push(selected);
1317
+ }
1318
+ function rtTabsFitRow(input) {
1319
+ const { slots, selectedId, moreWidth, available, limit = Infinity } = input;
1320
+ const pinned = slots.filter((tab) => tab.pinned);
1321
+ const free = slots.filter((tab) => !tab.pinned);
1322
+ const freeLimit = Math.max(0, limit - pinned.length);
1323
+ if (widthOf(slots) <= available + FIT_TOLERANCE && free.length <= freeLimit) return {
1324
+ row: [...pinned, ...free].map(idOf),
1325
+ more: []
1326
+ };
1327
+ const selected = free.find((tab) => tab.id === selectedId);
1328
+ const budget = available - moreWidth - widthOf(pinned) + FIT_TOLERANCE;
1329
+ const prefix = leadingFit(free, budget, freeLimit);
1330
+ if (selected !== void 0 && !prefix.includes(selected)) makeRoom(prefix, selected, budget, freeLimit);
1331
+ const inRow = new Set(prefix);
1332
+ return {
1333
+ row: [...pinned, ...prefix].map(idOf),
1334
+ more: free.filter((tab) => !inRow.has(tab)).map(idOf)
1335
+ };
1336
+ }
1337
+ const EMPTY_LAYOUT = {
1338
+ row: [],
1339
+ more: []
1340
+ };
1341
+ const RT_TABS_MEASURE_CLASS = "rt-tabs__tab-list--measure";
1342
+ function sameLayout(a, b) {
1343
+ return a.row.join() === b.row.join() && a.more.join() === b.more.join();
1344
+ }
1345
+ var RtTabsMoreRow = class {
1346
+ #win;
1347
+ #list;
1348
+ #deps;
1349
+ #layout;
1350
+ #watch;
1351
+ constructor(win, list, deps) {
1352
+ this.#layout = signal(EMPTY_LAYOUT, {
1353
+ ...ngDevMode ? { debugName: "#layout" } : /* istanbul ignore next */ {},
1354
+ equal: sameLayout
1355
+ });
1356
+ this.#watch = null;
1357
+ this.ids = computed(() => new Set(this.#layout().more), ...ngDevMode ? [{ debugName: "ids" }] : /* istanbul ignore next */ []);
1358
+ this.order = computed(() => new Map(this.#layout().row.map((id, index) => [id, index])), ...ngDevMode ? [{ debugName: "order" }] : /* istanbul ignore next */ []);
1359
+ this.moreTabs = computed(() => this.#deps.visible().filter((tab) => this.ids().has(tab.id())), ...ngDevMode ? [{ debugName: "moreTabs" }] : /* istanbul ignore next */ []);
1360
+ this.rowTabs = computed(() => {
1361
+ const order = this.order();
1362
+ return this.#deps.visible().filter((tab) => !this.ids().has(tab.id())).sort((a, b) => (order.get(a.id()) ?? 0) - (order.get(b.id()) ?? 0));
1363
+ }, ...ngDevMode ? [{ debugName: "rowTabs" }] : /* istanbul ignore next */ []);
1364
+ this.#win = win;
1365
+ this.#list = list;
1366
+ this.#deps = deps;
1367
+ afterRenderEffect(() => {
1368
+ deps.visible();
1369
+ deps.enabled();
1370
+ this.#watchSizes();
1371
+ });
1372
+ afterRenderEffect(() => {
1373
+ deps.visible();
1374
+ deps.selectedId();
1375
+ deps.enabled();
1376
+ deps.limit();
1377
+ this.#measure();
1378
+ });
1379
+ inject(DestroyRef).onDestroy(() => this.#watch?.disconnect());
1380
+ }
1381
+ #watchSizes() {
1382
+ const list = this.#list()?.nativeElement;
1383
+ this.#watch?.disconnect();
1384
+ this.#watch = null;
1385
+ if (!this.#deps.enabled() || !list || !this.#win || !("ResizeObserver" in this.#win)) return;
1386
+ const watch = new ResizeObserver(() => this.#measure());
1387
+ watch.observe(list);
1388
+ Array.from(list.children).forEach((node) => watch.observe(node));
1389
+ this.#watch = watch;
1390
+ }
1391
+ #measure() {
1392
+ const list = this.#list()?.nativeElement;
1393
+ if (!this.#deps.enabled() || !list || !this.#win) {
1394
+ this.#layout.set(EMPTY_LAYOUT);
1395
+ return;
1396
+ }
1397
+ const style = this.#win.getComputedStyle(list);
1398
+ const padding = (parseFloat(style.paddingInlineStart) || 0) + (parseFloat(style.paddingInlineEnd) || 0);
1399
+ const available = list.getBoundingClientRect().width - padding;
1400
+ if (available <= 0) return;
1401
+ list.classList.add(RT_TABS_MEASURE_CLASS);
1402
+ const slots = this.#deps.visible().map((tab) => ({
1403
+ id: tab.id(),
1404
+ pinned: tab.pinned(),
1405
+ width: list.querySelector(`[data-tabitem="${tab.id()}"]`)?.getBoundingClientRect().width ?? 0
1406
+ }));
1407
+ list.classList.remove(RT_TABS_MEASURE_CLASS);
1408
+ this.#layout.set(rtTabsFitRow({
1409
+ slots,
1410
+ available,
1411
+ selectedId: this.#deps.selectedId(),
1412
+ limit: this.#deps.limit(),
1413
+ moreWidth: list.querySelector(".rt-tabs-more")?.getBoundingClientRect().width ?? 0
1414
+ }));
1415
+ }
1416
+ };
812
1417
  const REST_DEBOUNCE_MS = 50;
813
1418
  const BEM_BLOCK = "rt-tabs";
814
1419
  var RtTabsComponent = class RtTabsComponent {
@@ -829,20 +1434,12 @@ var RtTabsComponent = class RtTabsComponent {
829
1434
  this.visibleTabs = computed(() => this.tabs().filter((tab) => !tab.hidden()), ...ngDevMode ? [{ debugName: "visibleTabs" }] : /* istanbul ignore next */ []);
830
1435
  this.leftControls = computed(() => this.controls().filter((c) => c.side() === "left"), ...ngDevMode ? [{ debugName: "leftControls" }] : /* istanbul ignore next */ []);
831
1436
  this.rightControls = computed(() => this.controls().filter((c) => c.side() === "right"), ...ngDevMode ? [{ debugName: "rightControls" }] : /* istanbul ignore next */ []);
832
- this.selectedId = computed(() => {
833
- const enabled = this.visibleTabs().filter((tab) => !tab.disabled());
834
- const candidate = this.activeId() ?? this.#internalId();
835
- const candidateValid = candidate !== null && enabled.some((tab) => tab.id() === candidate);
836
- let result;
837
- if (candidateValid) result = candidate;
838
- else if (enabled.length) result = enabled[0].id();
839
- else result = null;
840
- return result;
841
- }, ...ngDevMode ? [{ debugName: "selectedId" }] : /* istanbul ignore next */ []);
1437
+ this.selectedId = computed(() => rtTabsSelectedId(this.visibleTabs().filter((tab) => !tab.disabled()).map((tab) => tab.id()), this.activeId() ?? this.#internalId()), ...ngDevMode ? [{ debugName: "selectedId" }] : /* istanbul ignore next */ []);
1438
+ this.moreMode = computed(() => this.overflow() === "more" && this.direction() === "horizontal", ...ngDevMode ? [{ debugName: "moreMode" }] : /* istanbul ignore next */ []);
842
1439
  this.activeTab = computed(() => this.visibleTabs().find((tab) => tab.id() === this.selectedId()) ?? null, ...ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []);
843
1440
  this.focusId = computed(() => {
844
1441
  const focused = this.#focusedId();
845
- return focused !== null && this.visibleTabs().some((tab) => tab.id() === focused && !tab.disabled()) ? focused : this.selectedId();
1442
+ return focused !== null && this.more.rowTabs().some((tab) => tab.id() === focused && !tab.disabled()) ? focused : this.selectedId();
846
1443
  }, ...ngDevMode ? [{ debugName: "focusId" }] : /* istanbul ignore next */ []);
847
1444
  this.restBeforeVisible = signal(false, ...ngDevMode ? [{ debugName: "restBeforeVisible" }] : /* istanbul ignore next */ []);
848
1445
  this.restAfterVisible = signal(false, ...ngDevMode ? [{ debugName: "restAfterVisible" }] : /* istanbul ignore next */ []);
@@ -857,8 +1454,14 @@ var RtTabsComponent = class RtTabsComponent {
857
1454
  duration: () => this.animationDuration(),
858
1455
  preserve: () => this.preserveContent()
859
1456
  });
860
- this.ink = new RtTabsInk(this.#win, this.tabListRef, {
1457
+ this.more = new RtTabsMoreRow(this.#win, this.tabListRef, {
1458
+ enabled: this.moreMode,
861
1459
  visible: this.visibleTabs,
1460
+ selectedId: this.selectedId,
1461
+ limit: computed(() => this.moreLimit())
1462
+ });
1463
+ this.ink = new RtTabsInk(this.#win, this.tabListRef, {
1464
+ visible: this.more.rowTabs,
862
1465
  active: this.activeTab
863
1466
  });
864
1467
  this.activeId = input(null, ...ngDevMode ? [{ debugName: "activeId" }] : /* istanbul ignore next */ []);
@@ -871,6 +1474,7 @@ var RtTabsComponent = class RtTabsComponent {
871
1474
  ...ngDevMode ? { debugName: "dense" } : /* istanbul ignore next */ {},
872
1475
  transform: booleanAttribute
873
1476
  });
1477
+ this.closeOn = input("all", ...ngDevMode ? [{ debugName: "closeOn" }] : /* istanbul ignore next */ []);
874
1478
  this.contentScrollable = input(true, {
875
1479
  ...ngDevMode ? { debugName: "contentScrollable" } : /* istanbul ignore next */ {},
876
1480
  transform: booleanAttribute
@@ -884,7 +1488,13 @@ var RtTabsComponent = class RtTabsComponent {
884
1488
  transform: booleanAttribute
885
1489
  });
886
1490
  this.activation = input("auto", ...ngDevMode ? [{ debugName: "activation" }] : /* istanbul ignore next */ []);
1491
+ this.overflow = input("scroll", ...ngDevMode ? [{ debugName: "overflow" }] : /* istanbul ignore next */ []);
1492
+ this.moreLimit = input(10, {
1493
+ ...ngDevMode ? { debugName: "moreLimit" } : /* istanbul ignore next */ {},
1494
+ transform: (value) => numberAttribute(value, 10)
1495
+ });
887
1496
  this.scrollArrows = input("overlay", ...ngDevMode ? [{ debugName: "scrollArrows" }] : /* istanbul ignore next */ []);
1497
+ this.arrowLook = input("block", ...ngDevMode ? [{ debugName: "arrowLook" }] : /* istanbul ignore next */ []);
888
1498
  this.scrollStep = input("fixed", ...ngDevMode ? [{ debugName: "scrollStep" }] : /* istanbul ignore next */ []);
889
1499
  this.animationDuration = input(null, ...ngDevMode ? [{ debugName: "animationDuration" }] : /* istanbul ignore next */ []);
890
1500
  this.contentTabIndex = input(0, ...ngDevMode ? [{ debugName: "contentTabIndex" }] : /* istanbul ignore next */ []);
@@ -923,26 +1533,17 @@ var RtTabsComponent = class RtTabsComponent {
923
1533
  event.stopPropagation();
924
1534
  this.#close(tab, event.currentTarget instanceof HTMLElement && event.currentTarget.matches(":focus"));
925
1535
  }
1536
+ onMoreClose(tab) {
1537
+ this.#close(tab, false);
1538
+ }
926
1539
  onTabKeydown(event, tab) {
927
1540
  if (event.key === "Delete") {
928
1541
  this.#closeByKey(event, tab);
929
1542
  return;
930
1543
  }
931
- const enabled = this.visibleTabs().filter((item) => !item.disabled());
932
- if (!enabled.length) return;
933
- const isVertical = this.direction() === "vertical";
934
- const nextKey = isVertical ? "ArrowDown" : "ArrowRight";
935
- const prevKey = isVertical ? "ArrowUp" : "ArrowLeft";
936
- const currentIndex = enabled.findIndex((item) => item.id() === tab.id());
937
- const targetIndex = (/* @__PURE__ */ new Map([
938
- [nextKey, (currentIndex + 1) % enabled.length],
939
- [prevKey, (currentIndex - 1 + enabled.length) % enabled.length],
940
- ["Home", 0],
941
- ["End", enabled.length - 1]
942
- ])).get(event.key);
943
- if (targetIndex === void 0) return;
1544
+ const targetId = rtTabsKeyTargetId(this.more.rowTabs().filter((item) => !item.disabled()).map((item) => item.id()), tab.id(), event.key, this.direction());
1545
+ if (targetId === void 0) return;
944
1546
  event.preventDefault();
945
- const targetId = enabled[targetIndex].id();
946
1547
  if (this.activation() === "manual") {
947
1548
  this.#focusedId.set(targetId);
948
1549
  this.#scrollTabIntoView(targetId);
@@ -965,7 +1566,7 @@ var RtTabsComponent = class RtTabsComponent {
965
1566
  this.#updateRestVisibility();
966
1567
  }
967
1568
  #closeByKey(event, tab) {
968
- if (!tab.showClose()) return;
1569
+ if (!tab.showClose() || this.closeOn() === "selected" && tab.id() !== this.selectedId()) return;
969
1570
  event.preventDefault();
970
1571
  this.#close(tab, true);
971
1572
  }
@@ -985,14 +1586,12 @@ var RtTabsComponent = class RtTabsComponent {
985
1586
  }
986
1587
  #updateRestVisibility() {
987
1588
  const list = this.tabListRef()?.nativeElement;
988
- if (!list || this.direction() !== "horizontal") {
989
- this.restBeforeVisible.set(false);
990
- this.restAfterVisible.set(false);
991
- return;
992
- }
993
- const scrolledRight = list.scrollWidth - list.scrollLeft - list.clientWidth;
994
- this.restBeforeVisible.set(list.scrollLeft > 0);
995
- this.restAfterVisible.set(scrolledRight > 1);
1589
+ const shown = list && this.direction() === "horizontal" && !this.moreMode() ? rtTabsRestShown(list) : {
1590
+ before: false,
1591
+ after: false
1592
+ };
1593
+ this.restBeforeVisible.set(shown.before);
1594
+ this.restAfterVisible.set(shown.after);
996
1595
  }
997
1596
  #scrollToSelected(again = false) {
998
1597
  const id = this.selectedId();
@@ -1004,15 +1603,12 @@ var RtTabsComponent = class RtTabsComponent {
1004
1603
  #scrollTabIntoView(id) {
1005
1604
  const list = this.tabListRef()?.nativeElement;
1006
1605
  const tab = list?.querySelector(`[data-tabitem="${id}"]`);
1007
- if (!list || !tab) return;
1606
+ if (!list || !tab || this.moreMode()) return;
1008
1607
  const first = this.#scrolledId === null;
1009
1608
  const rest = list.parentElement?.querySelector(".rt-tabs__rest");
1010
1609
  const target = rtTabsIntoViewTarget(list, tab, this.scrollArrows() === "overlay" ? rest?.offsetWidth ?? 0 : 0);
1011
1610
  this.#scrolledId = id;
1012
- if (target !== null && first) {
1013
- this.#scroller.stop();
1014
- list.scrollLeft = target;
1015
- } else if (target !== null) this.#scroller.to(target);
1611
+ this.#scroller.place(target, first);
1016
1612
  this.#updateRestVisibility();
1017
1613
  }
1018
1614
  #focusTab(id) {
@@ -1064,6 +1660,13 @@ var RtTabsComponent = class RtTabsComponent {
1064
1660
  isRequired: false,
1065
1661
  transformFunction: null
1066
1662
  },
1663
+ closeOn: {
1664
+ classPropertyName: "closeOn",
1665
+ publicName: "closeOn",
1666
+ isSignal: true,
1667
+ isRequired: false,
1668
+ transformFunction: null
1669
+ },
1067
1670
  contentScrollable: {
1068
1671
  classPropertyName: "contentScrollable",
1069
1672
  publicName: "contentScrollable",
@@ -1092,6 +1695,20 @@ var RtTabsComponent = class RtTabsComponent {
1092
1695
  isRequired: false,
1093
1696
  transformFunction: null
1094
1697
  },
1698
+ overflow: {
1699
+ classPropertyName: "overflow",
1700
+ publicName: "overflow",
1701
+ isSignal: true,
1702
+ isRequired: false,
1703
+ transformFunction: null
1704
+ },
1705
+ moreLimit: {
1706
+ classPropertyName: "moreLimit",
1707
+ publicName: "moreLimit",
1708
+ isSignal: true,
1709
+ isRequired: false,
1710
+ transformFunction: null
1711
+ },
1095
1712
  scrollArrows: {
1096
1713
  classPropertyName: "scrollArrows",
1097
1714
  publicName: "scrollArrows",
@@ -1099,6 +1716,13 @@ var RtTabsComponent = class RtTabsComponent {
1099
1716
  isRequired: false,
1100
1717
  transformFunction: null
1101
1718
  },
1719
+ arrowLook: {
1720
+ classPropertyName: "arrowLook",
1721
+ publicName: "arrowLook",
1722
+ isSignal: true,
1723
+ isRequired: false,
1724
+ transformFunction: null
1725
+ },
1102
1726
  scrollStep: {
1103
1727
  classPropertyName: "scrollStep",
1104
1728
  publicName: "scrollStep",
@@ -1152,8 +1776,12 @@ var RtTabsComponent = class RtTabsComponent {
1152
1776
  isSignal: true
1153
1777
  }],
1154
1778
  ngImport: i0,
1155
- template: "<ng-container rtBlock=\"rt-tabs\">\n <div rtElem=\"header\">\n @if (leftControls().length) {\n <div rtElem=\"controls\" [rtMod]=\"{ before: true }\">\n @for (control of leftControls(); track $index) {\n <ng-container [ngTemplateOutlet]=\"control.templateRef\" />\n }\n </div>\n }\n\n <div rtElem=\"tab-list-wrapper\" [rtMod]=\"{ inline: scrollArrows() === 'inline', overflowing: overflowing() }\">\n <div\n rtElem=\"rest\"\n qa-dataid=\"tabs-scroll-prev\"\n [rtMod]=\"{ before: true, visible: restBeforeVisible(), inactive: !restBeforeVisible() }\"\n (mousedown)=\"onRestPointerDown('before', $event)\"\n (mouseup)=\"onRestPointerUp()\"\n (mouseleave)=\"onRestPointerLeave()\">\n <rt-icon name=\"chevron-left\" color=\"current\" size=\"sm\" />\n </div>\n\n <div\n #tabList\n rtElem=\"tab-list\"\n qa-dataid=\"tabs-tab-list\"\n role=\"tablist\"\n [rtMod]=\"{ stretch: stretch(), direction: direction(), ink: ink.box() !== null }\"\n [attr.aria-orientation]=\"direction()\"\n (scroll)=\"onTabListScroll()\">\n @for (tab of visibleTabs(); track tab.id()) {\n @let focusable = tab.id() === focusId();\n <!-- Вкладка — обёртка из двух кнопок: самой вкладки и крестика рядом с ней, не внутри,\n потому что кнопка в кнопке недопустима. Нажатие в любом месте обёртки выбирает\n вкладку; крестик своё нажатие дальше не пускает. -->\n <div\n rtBlock=\"rt-tab-item\"\n role=\"presentation\"\n [rtMod]=\"{\n selected: tab.id() === selectedId(),\n disabled: tab.disabled(),\n invalid: tab.invalid(),\n stretch: stretch(),\n }\"\n [attr.data-tabitem]=\"tab.id()\"\n (click)=\"selectTab(tab.id())\">\n <button\n rtElem=\"trigger\"\n qa-dataid=\"tabs-tab\"\n type=\"button\"\n role=\"tab\"\n [rtMod]=\"{ closable: tab.showClose() }\"\n [id]=\"'rt-tab-' + tab.id()\"\n [attr.aria-disabled]=\"tab.disabled() || null\"\n [attr.aria-label]=\"tab.ariaLabel()\"\n [attr.aria-keyshortcuts]=\"tab.showClose() ? 'Delete' : null\"\n [attr.data-tabid]=\"tab.id()\"\n [attr.aria-selected]=\"tab.id() === selectedId()\"\n [attr.aria-controls]=\"headerOnly() ? null : 'rt-tabpanel-' + tab.id()\"\n [attr.tabindex]=\"focusable ? 0 : -1\"\n [rtTooltip]=\"tab.buttonTooltip()\"\n (keydown)=\"onTabKeydown($event, tab)\">\n @if (tab.hasIcon()) {\n <span rtElem=\"icon-box\">\n <rt-icon\n rtElem=\"icon\"\n size=\"sm\"\n [name]=\"tab.icon()\"\n [glyph]=\"tab.glyph()\"\n [color]=\"tab.iconColor()\"\n [fill]=\"tab.iconFill()\" />\n @if (tab.badgeOverlay()) {\n <!-- prettier-ignore -->\n <span rtElem=\"badge\" [rtMod]=\"{ overlay: true }\" [rtTooltip]=\"tab.badgeTitle()\" [attr.aria-label]=\"tab.badgeAriaLabel() || null\">{{ tab.badge() }}</span>\n }\n </span>\n }\n\n @if (tab.titleTemplate(); as titleTpl) {\n <ng-container [ngTemplateOutlet]=\"titleTpl\" />\n } @else if (tab.label()) {\n <!-- Пустая подпись не рисуется: её зазор сдвигал значок вкладки без подписи с середины. -->\n <span rtElem=\"title\">{{ tab.label() }}</span>\n }\n\n @if (tab.badge() !== null && !tab.badgeOverlay()) {\n <!-- В одну строку: перенос внутри добавил бы пробел в текст кнопки. -->\n <!-- prettier-ignore -->\n <span rtElem=\"badge\" [rtTooltip]=\"tab.badgeTitle()\" [attr.aria-label]=\"tab.badgeAriaLabel() || null\">{{ tab.badge() }}</span>\n }\n </button>\n\n @if (tab.showClose()) {\n <!-- В таб-порядке только у вкладки в фокусе: Tab с неё идёт на её крестик, дальше — из полосы. -->\n <button\n rtElem=\"close\"\n qa-dataid=\"tabs-tab-close\"\n type=\"button\"\n [attr.aria-label]=\"tab.closeLabel()\"\n [attr.tabindex]=\"focusable ? 0 : -1\"\n [rtTooltip]=\"tab.closeTooltip()\"\n [rtTooltipPlacement]=\"tab.closeTooltipPlacement()\"\n (mouseenter)=\"tab.closeHovered.set(true)\"\n (mouseleave)=\"tab.closeHovered.set(false)\"\n (click)=\"onCloseClick($event, tab)\">\n <rt-icon name=\"close\" color=\"current\" size=\"xs\" />\n </button>\n }\n </div>\n }\n\n <!-- Полоса выбранной вкладки — одна на всю полосу: так она переезжает между вкладками. -->\n <span\n rtElem=\"ink\"\n aria-hidden=\"true\"\n [rtMod]=\"{ placed: ink.box() !== null, animated: ink.animated(), invalid: ink.invalid() }\"\n [style.width.px]=\"ink.box()?.width\"\n [style.translate]=\"ink.translate()\"></span>\n </div>\n\n <div\n rtElem=\"rest\"\n qa-dataid=\"tabs-scroll-next\"\n [rtMod]=\"{ after: true, visible: restAfterVisible(), inactive: !restAfterVisible() }\"\n (mousedown)=\"onRestPointerDown('after', $event)\"\n (mouseup)=\"onRestPointerUp()\"\n (mouseleave)=\"onRestPointerLeave()\">\n <rt-icon name=\"chevron-right\" color=\"current\" size=\"sm\" />\n </div>\n </div>\n\n @if (rightControls().length) {\n <div rtElem=\"controls\" [rtMod]=\"{ after: true }\">\n @for (control of rightControls(); track $index) {\n <ng-container [ngTemplateOutlet]=\"control.templateRef\" />\n }\n </div>\n }\n </div>\n\n <!-- Уходящая панель стоит поверх: место ей задаёт замер, сделанный до смены. Сохранённые\n тела посещённых вкладок скрыты и вне таб-порядка. -->\n @for (panel of panels.list(); track panel.tab.id()) {\n @let current = panel.leaving === null && !panel.idle;\n <div\n rtElem=\"content\"\n role=\"tabpanel\"\n [attr.qa-dataid]=\"current ? 'tabs-panel' : panel.idle ? 'tabs-panel-idle' : 'tabs-panel-leaving'\"\n [attr.tabindex]=\"current ? contentTabIndex() : -1\"\n [attr.aria-hidden]=\"current ? null : 'true'\"\n [attr.inert]=\"current ? null : ''\"\n [hidden]=\"panel.idle\"\n [rtMod]=\"{\n scrollable: contentScrollable(),\n idle: panel.idle,\n leaving: panel.leaving !== null,\n entering: current && panels.shift() !== null,\n shift: panels.shift(),\n }\"\n [style.top.px]=\"panel.leaving?.top\"\n [style.left.px]=\"panel.leaving?.left\"\n [id]=\"'rt-tabpanel-' + panel.tab.id()\"\n [attr.aria-labelledby]=\"'rt-tab-' + panel.tab.id()\"\n (animationend)=\"panels.animationEnd($event)\"\n (animationcancel)=\"panels.animationEnd($event)\">\n <ng-container [ngTemplateOutlet]=\"panel.tab.templateRef\" />\n </div>\n }\n</ng-container>\n",
1156
- styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-tabs{--rt-tabs-border-width: var(--rt-border-width-thin);--rt-tabs-transition-duration: var(--rt-duration-fast);--rt-tabs-list-align: stretch;--rt-tabs-list-border-color: var(--rt-color-border-default);--rt-tabs-list-min-height: auto;--rt-tabs-list-padding-inline: 0;--rt-tabs-content-padding-top: var(--rt-space-md);display:flex;-webkit-tap-highlight-color:transparent}.rt-tabs--direction--horizontal{flex-direction:column}.rt-tabs--direction--vertical{flex-direction:row}.rt-tabs--animating{position:relative;overflow-x:clip}.rt-tabs__header{display:flex;align-items:center}.rt-tabs__tab-list-wrapper{position:relative;display:flex;overflow:hidden;flex:1 1 auto;align-items:center}.rt-tabs__tab-list{position:relative;display:flex;box-sizing:border-box;align-items:var(--rt-tabs-list-align);border-bottom:var(--rt-tabs-border-width) solid var(--rt-tabs-list-border-color);margin:0;min-block-size:var(--rt-tabs-list-min-height);-ms-overflow-style:none;overflow-x:auto;padding-inline:var(--rt-tabs-list-padding-inline);scrollbar-width:none;white-space:nowrap}.rt-tabs__tab-list::-webkit-scrollbar{display:none}.rt-tabs__tab-list--direction--horizontal{width:100%;flex-direction:row}.rt-tabs__tab-list--direction--vertical{flex-direction:column;border-right:var(--rt-tabs-border-width) solid var(--rt-color-border-default);border-bottom:0}.rt-tabs__tab-list--stretch{justify-content:space-between}.rt-tabs__tab-list--ink .rt-tab-item--selected:not(.rt-tab-item--invalid):after{background-color:transparent}.rt-tabs__ink{position:absolute;top:0;left:0;display:none;height:2px;margin-top:var(--rt-tabs-border-width);background-color:var(--rt-color-action-primary);pointer-events:none;transform:translateY(-100%)}.rt-tabs__ink--placed{display:block}.rt-tabs__ink--animated{transition:translate var(--rt-tabs-indicator-duration) var(--rt-tabs-indicator-easing),width var(--rt-tabs-indicator-duration) var(--rt-tabs-indicator-easing)}.rt-tabs__ink--invalid{background-color:var(--rt-color-state-danger)}.rt-tabs__rest{position:absolute;z-index:1;top:0;bottom:0;display:flex;width:var(--rt-control-height-lg);align-items:center;justify-content:center;background-color:var(--rt-color-bg-surface);color:var(--rt-color-text-muted);cursor:pointer;transition:color var(--rt-tabs-transition-duration) linear;visibility:hidden}.rt-tabs__rest:hover{color:var(--rt-color-text-primary)}.rt-tabs__rest--before{left:0;border-right:var(--rt-tabs-border-width) solid var(--rt-color-border-default)}.rt-tabs__rest--after{right:0;border-left:var(--rt-tabs-border-width) solid var(--rt-color-border-default)}.rt-tabs__rest--visible{visibility:visible}.rt-tabs__tab-list-wrapper--inline{align-items:stretch}.rt-tabs__tab-list-wrapper--inline .rt-tabs__rest{position:static;display:none;flex-shrink:0;border:0;border-bottom:var(--rt-tabs-border-width) solid var(--rt-color-border-default);background-color:transparent}.rt-tabs__tab-list-wrapper--inline.rt-tabs__tab-list-wrapper--overflowing .rt-tabs__rest{display:flex;visibility:visible}.rt-tabs__tab-list-wrapper--inline .rt-tabs__rest--inactive{color:var(--rt-color-text-disabled);cursor:default;pointer-events:none}.rt-tabs__controls{display:flex;flex-shrink:0;align-items:center}.rt-tabs__controls--before{padding-right:var(--rt-space-md)}.rt-tabs__controls--after{padding-left:var(--rt-space-md)}.rt-tabs__content{display:flex;min-height:0;flex:1 1 auto;flex-direction:column;padding-top:var(--rt-tabs-content-padding-top);gap:var(--rt-space-md);line-height:var(--rt-leading-relaxed)}.rt-tabs__content--scrollable{overflow:auto}.rt-tabs__content--idle{display:none}.rt-tabs__content--leaving{position:absolute;right:0;bottom:0;animation:rt-tabs-panel-leave var(--rt-tabs-panel-duration) var(--rt-tabs-panel-easing) forwards;pointer-events:none}.rt-tabs__content--entering{animation:rt-tabs-panel-enter var(--rt-tabs-panel-duration) var(--rt-tabs-panel-easing)}.rt-tabs__content--shift--forward{--rt-tabs-panel-leave-to: -100%;--rt-tabs-panel-enter-from: 100%}.rt-tabs__content--shift--backward{--rt-tabs-panel-leave-to: 100%;--rt-tabs-panel-enter-from: -100%}@keyframes rt-tabs-panel-leave{to{translate:var(--rt-tabs-panel-leave-to) 0}}@keyframes rt-tabs-panel-enter{0%{translate:var(--rt-tabs-panel-enter-from) 0}}@media(prefers-reduced-motion:reduce){.rt-tabs__ink--animated{transition:none}.rt-tabs__content--leaving,.rt-tabs__content--entering{animation:none}}.rt-tab-item{--rt-tab-item-border-width: var(--rt-border-width-thin);--rt-tab-item-badge-radius: var(--rt-radius-full);--rt-tab-item-transition-duration: var(--rt-duration-fast);--rt-tab-item-close-size: var(--rt-size-5);--rt-tab-item-close-radius: var(--rt-radius-full);--rt-tab-item-close-bg: transparent;--rt-tab-item-close-bg-hover: var(--rt-color-bg-hover);--rt-tab-item-close-color: var(--rt-color-text-muted);--rt-tab-item-close-color-hover: var(--rt-color-text-primary);--rt-tab-item-close-icon-size: var(--rt-icon-step-xs);--rt-tab-item-close-margin-inline-start: 0;--rt-tab-item-close-margin-inline-end: calc(-1 * var(--rt-space-2));position:relative;display:inline-flex;align-items:center;justify-content:center;margin:0;background-color:transparent;color:var(--rt-color-text-muted);cursor:pointer;font-family:inherit;font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-semibold);gap:var(--rt-space-sm);line-height:var(--rt-leading-none);transition:color var(--rt-tab-item-transition-duration) linear,background-color var(--rt-tab-item-transition-duration) linear;white-space:nowrap}.rt-tab-item:after{position:absolute;bottom:0;height:2px;background-color:transparent;content:\"\";inset-inline:0;pointer-events:none;translate:0 var(--rt-tab-item-border-width)}.rt-tab-item:hover:not(.rt-tab-item--disabled,.rt-tab-item--selected){background-color:var(--rt-color-bg-hover);color:var(--rt-color-text-primary)}.rt-tab-item:has(>.rt-tab-item__trigger:focus-visible){outline:2px solid var(--rt-color-action-primary);outline-offset:-3px}.rt-tab-item__trigger{display:inline-flex;min-width:0;align-items:center;justify-content:center;padding:var(--rt-space-2) var(--rt-space-4);border:0;margin:0;background:none;color:inherit;cursor:inherit;font:inherit;gap:inherit;line-height:inherit;outline:none}.rt-tab-item__trigger--closable{padding-inline-end:0}.rt-tabs--dense .rt-tab-item__trigger{padding-inline:var(--rt-space-2)}.rt-tab-item__title{overflow:hidden;max-width:200px;text-overflow:ellipsis}.rt-tab-item__icon{flex-shrink:0}.rt-tab-item__icon-box{position:relative;display:inline-flex;flex-shrink:0}.rt-tab-item__badge{display:inline-flex;min-width:18px;height:18px;align-items:center;justify-content:center;padding:0 var(--rt-space-2);border-radius:var(--rt-tab-item-badge-radius);background-color:var(--rt-color-bg-surface-subtle);color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);font-weight:var(--rt-font-weight-medium);line-height:var(--rt-leading-none)}.rt-tab-item__badge--overlay{position:absolute;top:calc(-1 * var(--rt-space-2));right:calc(-1 * (var(--rt-space-1) + var(--rt-space-0-5)));min-width:var(--rt-size-4);height:var(--rt-size-4);box-sizing:border-box;padding:0 var(--rt-space-1);background-color:var(--rt-color-action-primary);color:var(--rt-color-action-on-primary);font-size:var(--rt-text-2xs)}.rt-tab-item__close{--rt-icon-step-xs: var(--rt-tab-item-close-icon-size);display:inline-flex;width:var(--rt-tab-item-close-size);height:var(--rt-tab-item-close-size);flex-shrink:0;align-items:center;justify-content:center;padding:0;border:0;border-radius:var(--rt-tab-item-close-radius);background-color:var(--rt-tab-item-close-bg);color:var(--rt-tab-item-close-color);cursor:pointer;font:inherit;margin-block:calc(-1 * var(--rt-space-1));margin-inline:var(--rt-tab-item-close-margin-inline-start) calc(var(--rt-space-4) + var(--rt-tab-item-close-margin-inline-end));transition:color var(--rt-tab-item-transition-duration) linear,background-color var(--rt-tab-item-transition-duration) linear}.rt-tab-item__close:hover{background-color:var(--rt-tab-item-close-bg-hover);color:var(--rt-tab-item-close-color-hover)}.rt-tab-item__close:focus-visible{outline:2px solid var(--rt-color-action-primary);outline-offset:0}.rt-tab-item--selected{color:var(--rt-color-action-primary);cursor:default}.rt-tab-item--selected .rt-tab-item__trigger{padding-block-end:calc(var(--rt-space-2) + 2px)}.rt-tab-item--selected:after{background-color:var(--rt-color-action-primary)}.rt-tab-item--selected .rt-tab-item__badge:not(.rt-tab-item__badge--overlay){background-color:var(--rt-color-action-primary-soft);color:var(--rt-color-action-primary)}.rt-tab-item--invalid{color:var(--rt-color-state-danger)}.rt-tab-item--invalid:after{background-color:var(--rt-color-state-danger)}.rt-tab-item--disabled{color:var(--rt-color-text-disabled);cursor:not-allowed}.rt-tab-item--stretch{max-width:100%;flex:1 1 auto}}\n"],
1779
+ template: "<ng-container rtBlock=\"rt-tabs\">\n <div rtElem=\"header\">\n @if (leftControls().length) {\n <div rtElem=\"controls\" [rtMod]=\"{ before: true }\">\n @for (control of leftControls(); track $index) {\n <ng-container [ngTemplateOutlet]=\"control.templateRef\" />\n }\n </div>\n }\n\n <div\n rtElem=\"tab-list-wrapper\"\n [rtMod]=\"{ inline: scrollArrows() === 'inline', overflowing: overflowing(), compact: arrowLook() === 'compact' }\">\n @if (!moreMode()) {\n <div\n rtElem=\"rest\"\n qa-dataid=\"tabs-scroll-prev\"\n [rtMod]=\"{ before: true, visible: restBeforeVisible(), inactive: !restBeforeVisible() }\"\n (mousedown)=\"onRestPointerDown('before', $event)\"\n (mouseup)=\"onRestPointerUp()\"\n (mouseleave)=\"onRestPointerLeave()\">\n <span rtElem=\"arrow\"><rt-icon name=\"chevron-left\" color=\"current\" size=\"sm\" /></span>\n </div>\n }\n\n <div\n #tabList\n rtElem=\"tab-list\"\n qa-dataid=\"tabs-tab-list\"\n role=\"tablist\"\n [rtMod]=\"{ stretch: stretch(), direction: direction(), ink: ink.box() !== null, more: moreMode() }\"\n [attr.aria-orientation]=\"direction()\"\n (scroll)=\"onTabListScroll()\">\n @for (tab of visibleTabs(); track tab.id()) {\n @let focusable = tab.id() === focusId();\n @let closeShown = tab.showClose() && (closeOn() === 'all' || tab.id() === selectedId());\n <!-- Вкладка — обёртка из двух кнопок: самой вкладки и крестика рядом с ней, не внутри,\n потому что кнопка в кнопке недопустима. Нажатие в любом месте обёртки выбирает\n вкладку; крестик своё нажатие дальше не пускает. -->\n <div\n rtBlock=\"rt-tab-item\"\n role=\"presentation\"\n [rtMod]=\"{\n selected: tab.id() === selectedId(),\n disabled: tab.disabled(),\n invalid: tab.invalid(),\n stretch: stretch(),\n inMore: more.ids().has(tab.id()),\n }\"\n [style.order]=\"more.order().get(tab.id())\"\n [attr.inert]=\"more.ids().has(tab.id()) || null\"\n [attr.data-tabitem]=\"tab.id()\"\n (click)=\"selectTab(tab.id())\"\n (contextmenu)=\"contextMenu.open($event, tab)\">\n <button\n rtElem=\"trigger\"\n qa-dataid=\"tabs-tab\"\n type=\"button\"\n role=\"tab\"\n [rtMod]=\"{ closable: closeShown }\"\n [id]=\"'rt-tab-' + tab.id()\"\n [attr.aria-disabled]=\"tab.disabled() || null\"\n [attr.aria-label]=\"tab.ariaLabel()\"\n [attr.aria-keyshortcuts]=\"closeShown ? 'Delete' : null\"\n [attr.data-tabid]=\"tab.id()\"\n [attr.aria-selected]=\"tab.id() === selectedId()\"\n [attr.aria-controls]=\"headerOnly() ? null : 'rt-tabpanel-' + tab.id()\"\n [attr.tabindex]=\"focusable ? 0 : -1\"\n [rtTooltip]=\"tab.buttonTooltip()\"\n (keydown)=\"onTabKeydown($event, tab)\">\n @if (tab.hasIcon()) {\n <span rtElem=\"icon-box\">\n <rt-icon\n rtElem=\"icon\"\n size=\"sm\"\n [name]=\"tab.shownIcon()\"\n [glyph]=\"tab.glyph()\"\n [color]=\"tab.iconColor()\"\n [fill]=\"tab.iconFill()\" />\n @if (tab.badgeOverlay()) {\n <!-- prettier-ignore -->\n <span rtElem=\"badge\" [rtMod]=\"{ overlay: true }\" [rtTooltip]=\"tab.badgeTitle()\" [attr.aria-label]=\"tab.badgeAriaLabel() || null\">{{ tab.badge() }}</span>\n }\n </span>\n }\n\n @if (tab.titleTemplate(); as titleTpl) {\n <ng-container [ngTemplateOutlet]=\"titleTpl\" />\n } @else if (tab.label()) {\n <!-- Пустая подпись не рисуется: её зазор сдвигал значок вкладки без подписи с середины. -->\n <span rtElem=\"title\">{{ tab.label() }}</span>\n }\n\n @if (tab.badge() !== null && !tab.badgeOverlay()) {\n <!-- В одну строку: перенос внутри добавил бы пробел в текст кнопки. -->\n <!-- prettier-ignore -->\n <span rtElem=\"badge\" [rtTooltip]=\"tab.badgeTitle()\" [attr.aria-label]=\"tab.badgeAriaLabel() || null\">{{ tab.badge() }}</span>\n }\n </button>\n\n @if (closeShown) {\n <!-- В таб-порядке только у вкладки в фокусе: Tab с неё идёт на её крестик, дальше — из полосы. -->\n <button\n rtElem=\"close\"\n qa-dataid=\"tabs-tab-close\"\n type=\"button\"\n [attr.aria-label]=\"tab.closeLabel()\"\n [attr.tabindex]=\"focusable ? 0 : -1\"\n [rtTooltip]=\"tab.closeTooltip()\"\n [rtTooltipPlacement]=\"tab.closeTooltipPlacement()\"\n (mouseenter)=\"tab.closeHovered.set(true)\"\n (mouseleave)=\"tab.closeHovered.set(false)\"\n (click)=\"onCloseClick($event, tab)\">\n <rt-icon name=\"close\" color=\"current\" size=\"xs\" />\n </button>\n }\n </div>\n }\n\n @if (moreMode()) {\n <rt-tabs-more [tabs]=\"more.moreTabs()\" (pick)=\"selectTab($event)\" (closeTab)=\"onMoreClose($event)\" />\n }\n\n <!-- Полоса выбранной вкладки — одна на всю полосу: так она переезжает между вкладками. -->\n <span\n rtElem=\"ink\"\n aria-hidden=\"true\"\n [rtMod]=\"{ placed: ink.box() !== null, animated: ink.animated(), invalid: ink.invalid() }\"\n [style.width.px]=\"ink.box()?.width\"\n [style.translate]=\"ink.translate()\"></span>\n </div>\n\n @if (!moreMode()) {\n <div\n rtElem=\"rest\"\n qa-dataid=\"tabs-scroll-next\"\n [rtMod]=\"{ after: true, visible: restAfterVisible(), inactive: !restAfterVisible() }\"\n (mousedown)=\"onRestPointerDown('after', $event)\"\n (mouseup)=\"onRestPointerUp()\"\n (mouseleave)=\"onRestPointerLeave()\">\n <span rtElem=\"arrow\"><rt-icon name=\"chevron-right\" color=\"current\" size=\"sm\" /></span>\n </div>\n }\n </div>\n\n @if (rightControls().length) {\n <div rtElem=\"controls\" [rtMod]=\"{ after: true }\">\n @for (control of rightControls(); track $index) {\n <ng-container [ngTemplateOutlet]=\"control.templateRef\" />\n }\n </div>\n }\n </div>\n\n <rt-tabs-context-menu #contextMenu />\n\n <!-- Уходящая панель стоит поверх: место ей задаёт замер, сделанный до смены. Сохранённые\n тела посещённых вкладок скрыты и вне таб-порядка. -->\n @for (panel of panels.list(); track panel.tab.id()) {\n @let current = panel.leaving === null && !panel.idle;\n <div\n rtElem=\"content\"\n role=\"tabpanel\"\n [attr.qa-dataid]=\"current ? 'tabs-panel' : panel.idle ? 'tabs-panel-idle' : 'tabs-panel-leaving'\"\n [attr.tabindex]=\"current ? contentTabIndex() : -1\"\n [attr.aria-hidden]=\"current ? null : 'true'\"\n [attr.inert]=\"current ? null : ''\"\n [hidden]=\"panel.idle\"\n [rtMod]=\"{\n scrollable: contentScrollable(),\n idle: panel.idle,\n leaving: panel.leaving !== null,\n entering: current && panels.shift() !== null,\n shift: panels.shift(),\n }\"\n [style.top.px]=\"panel.leaving?.top\"\n [style.left.px]=\"panel.leaving?.left\"\n [id]=\"'rt-tabpanel-' + panel.tab.id()\"\n [attr.aria-labelledby]=\"'rt-tab-' + panel.tab.id()\"\n (animationend)=\"panels.animationEnd($event)\"\n (animationcancel)=\"panels.animationEnd($event)\">\n <ng-container [ngTemplateOutlet]=\"panel.tab.templateRef\" />\n </div>\n }\n</ng-container>\n",
1780
+ styles: [
1781
+ "@charset \"UTF-8\";@layer rt-kit.components{.rt-tabs{--rt-tabs-border-width: var(--rt-border-width-thin);--rt-tabs-transition-duration: var(--rt-duration-fast);--rt-tabs-list-align: stretch;--rt-tabs-list-border-color: var(--rt-color-border-default);--rt-tabs-list-min-height: auto;--rt-tabs-list-padding-inline: 0;--rt-tabs-content-padding-top: var(--rt-space-md);display:flex;-webkit-tap-highlight-color:transparent}.rt-tabs--direction--horizontal{flex-direction:column}.rt-tabs--direction--vertical{flex-direction:row}.rt-tabs--animating{position:relative;overflow-x:clip}.rt-tabs__header{display:flex;align-items:center}.rt-tabs__tab-list-wrapper{position:relative;display:flex;overflow:hidden;flex:1 1 auto;align-items:center}.rt-tabs__tab-list{position:relative;display:flex;box-sizing:border-box;align-items:var(--rt-tabs-list-align);border-bottom:var(--rt-tabs-border-width) solid var(--rt-tabs-list-border-color);margin:0;min-block-size:var(--rt-tabs-list-min-height);-ms-overflow-style:none;overflow-x:auto;padding-inline:var(--rt-tabs-list-padding-inline);scrollbar-width:none;white-space:nowrap}.rt-tabs__tab-list::-webkit-scrollbar{display:none}.rt-tabs__tab-list--direction--horizontal{width:100%;flex-direction:row}.rt-tabs__tab-list--direction--vertical{flex-direction:column;border-right:var(--rt-tabs-border-width) solid var(--rt-color-border-default);border-bottom:0}.rt-tabs__tab-list--stretch{justify-content:space-between}.rt-tabs__tab-list--more{overflow-x:clip}.rt-tabs__tab-list--ink .rt-tab-item--selected:not(.rt-tab-item--invalid):after{background-color:transparent}.rt-tabs__ink{position:absolute;top:0;left:0;display:none;height:2px;margin-top:var(--rt-tabs-border-width);background-color:var(--rt-color-action-primary);pointer-events:none;transform:translateY(-100%)}.rt-tabs__ink--placed{display:block}.rt-tabs__ink--animated{transition:translate var(--rt-tabs-indicator-duration) var(--rt-tabs-indicator-easing),width var(--rt-tabs-indicator-duration) var(--rt-tabs-indicator-easing)}.rt-tabs__ink--invalid{background-color:var(--rt-color-state-danger)}.rt-tabs__controls{display:flex;flex-shrink:0;align-items:center}.rt-tabs__controls--before{padding-right:var(--rt-space-md)}.rt-tabs__controls--after{padding-left:var(--rt-space-md)}.rt-tabs__content{display:flex;min-height:0;flex:1 1 auto;flex-direction:column;padding-top:var(--rt-tabs-content-padding-top);gap:var(--rt-space-md);line-height:var(--rt-leading-relaxed)}.rt-tabs__content--scrollable{overflow:auto}.rt-tabs__content--idle{display:none}.rt-tabs__content--leaving{position:absolute;right:0;bottom:0;animation:rt-tabs-panel-leave var(--rt-tabs-panel-duration) var(--rt-tabs-panel-easing) forwards;pointer-events:none}.rt-tabs__content--entering{animation:rt-tabs-panel-enter var(--rt-tabs-panel-duration) var(--rt-tabs-panel-easing)}.rt-tabs__content--shift--forward{--rt-tabs-panel-leave-to: -100%;--rt-tabs-panel-enter-from: 100%}.rt-tabs__content--shift--backward{--rt-tabs-panel-leave-to: 100%;--rt-tabs-panel-enter-from: -100%}@keyframes rt-tabs-panel-leave{to{translate:var(--rt-tabs-panel-leave-to) 0}}@keyframes rt-tabs-panel-enter{0%{translate:var(--rt-tabs-panel-enter-from) 0}}@media(prefers-reduced-motion:reduce){.rt-tabs__ink--animated{transition:none}.rt-tabs__content--leaving,.rt-tabs__content--entering{animation:none}}.rt-tab-item{--rt-tab-item-border-width: var(--rt-border-width-thin);--rt-tab-item-badge-radius: var(--rt-radius-full);--rt-tab-item-transition-duration: var(--rt-duration-fast);--rt-tab-item-close-size: var(--rt-size-5);--rt-tab-item-close-radius: var(--rt-radius-full);--rt-tab-item-close-bg: transparent;--rt-tab-item-close-bg-hover: var(--rt-color-bg-hover);--rt-tab-item-close-color: var(--rt-color-text-muted);--rt-tab-item-close-color-hover: var(--rt-color-text-primary);--rt-tab-item-close-icon-size: var(--rt-icon-step-xs);--rt-tab-item-close-margin-inline-start: 0;--rt-tab-item-close-margin-inline-end: calc(-1 * var(--rt-space-2));position:relative;display:inline-flex;align-items:center;justify-content:center;margin:0;background-color:transparent;color:var(--rt-color-text-muted);cursor:pointer;font-family:inherit;font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-semibold);gap:var(--rt-space-sm);line-height:var(--rt-leading-none);transition:color var(--rt-tab-item-transition-duration) linear,background-color var(--rt-tab-item-transition-duration) linear;white-space:nowrap}.rt-tab-item:after{position:absolute;bottom:0;height:2px;background-color:transparent;content:\"\";inset-inline:0;pointer-events:none;translate:0 var(--rt-tab-item-border-width)}.rt-tab-item--in-more{position:absolute;top:0;left:0;visibility:hidden}.rt-tab-item:hover:not(.rt-tab-item--disabled,.rt-tab-item--selected){background-color:var(--rt-color-bg-hover);color:var(--rt-color-text-primary)}.rt-tab-item:has(>.rt-tab-item__trigger:focus-visible){outline:2px solid var(--rt-color-action-primary);outline-offset:-3px}.rt-tab-item__trigger{display:inline-flex;min-width:0;align-items:center;justify-content:center;padding:var(--rt-space-2) var(--rt-space-4);border:0;margin:0;background:none;color:inherit;cursor:inherit;font:inherit;gap:inherit;line-height:inherit;outline:none}.rt-tab-item__trigger--closable{padding-inline-end:0}.rt-tabs--dense .rt-tab-item__trigger{padding-inline:var(--rt-space-2)}.rt-tab-item__title{overflow:hidden;max-width:200px;text-overflow:ellipsis}.rt-tab-item__icon{flex-shrink:0}.rt-tab-item__icon-box{position:relative;display:inline-flex;flex-shrink:0}.rt-tab-item__badge{display:inline-flex;min-width:18px;height:18px;align-items:center;justify-content:center;padding:0 var(--rt-space-2);border-radius:var(--rt-tab-item-badge-radius);background-color:var(--rt-color-bg-surface-subtle);color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);font-weight:var(--rt-font-weight-medium);line-height:var(--rt-leading-none)}.rt-tab-item__badge--overlay{position:absolute;top:calc(-1 * var(--rt-space-2));right:calc(-1 * (var(--rt-space-1) + var(--rt-space-0-5)));min-width:var(--rt-size-4);height:var(--rt-size-4);box-sizing:border-box;padding:0 var(--rt-space-1);background-color:var(--rt-color-action-primary);color:var(--rt-color-action-on-primary);font-size:var(--rt-text-2xs)}.rt-tab-item__close{--rt-icon-step-xs: var(--rt-tab-item-close-icon-size);display:inline-flex;width:var(--rt-tab-item-close-size);height:var(--rt-tab-item-close-size);flex-shrink:0;align-items:center;justify-content:center;padding:0;border:0;border-radius:var(--rt-tab-item-close-radius);background-color:var(--rt-tab-item-close-bg);color:var(--rt-tab-item-close-color);cursor:pointer;font:inherit;margin-block:calc(-1 * var(--rt-space-1));margin-inline:var(--rt-tab-item-close-margin-inline-start) calc(var(--rt-space-4) + var(--rt-tab-item-close-margin-inline-end));transition:color var(--rt-tab-item-transition-duration) linear,background-color var(--rt-tab-item-transition-duration) linear}.rt-tab-item__close:hover{background-color:var(--rt-tab-item-close-bg-hover);color:var(--rt-tab-item-close-color-hover)}.rt-tab-item__close:focus-visible{outline:2px solid var(--rt-color-action-primary);outline-offset:0}.rt-tab-item--selected{color:var(--rt-color-action-primary);cursor:default}.rt-tab-item--selected .rt-tab-item__trigger{padding-block-end:calc(var(--rt-space-2) + 2px)}.rt-tab-item--selected:after{background-color:var(--rt-color-action-primary)}.rt-tab-item--selected .rt-tab-item__badge:not(.rt-tab-item__badge--overlay){background-color:var(--rt-color-action-primary-soft);color:var(--rt-color-action-primary)}.rt-tab-item--invalid{color:var(--rt-color-state-danger)}.rt-tab-item--invalid:after{background-color:var(--rt-color-state-danger)}.rt-tab-item--disabled{color:var(--rt-color-text-disabled);cursor:not-allowed}.rt-tab-item--stretch{max-width:100%;flex:1 1 auto}.rt-tabs__tab-list--measure>.rt-tab-item--stretch{flex-grow:0}}\n",
1782
+ "@charset \"UTF-8\";@layer rt-kit.components{.rt-tabs{--rt-tabs-arrow-size: var(--rt-size-6);--rt-tabs-arrow-inset: var(--rt-space-1);--rt-tabs-arrow-radius: var(--rt-radius-sm);--rt-tabs-arrow-shadow: var(--rt-shadow-sm);--rt-tabs-arrow-bg: var(--rt-color-bg-surface);--rt-tabs-arrow-bg-hover: var(--rt-color-bg-hover);--rt-tabs-arrow-color: var(--rt-color-text-muted);--rt-tabs-arrow-color-hover: var(--rt-color-text-primary);--rt-tabs-arrow-fade: var(--rt-color-bg-surface)}.rt-tabs__rest{position:absolute;z-index:1;top:0;bottom:0;display:flex;width:var(--rt-control-height-lg);align-items:center;justify-content:center;background-color:var(--rt-color-bg-surface);color:var(--rt-color-text-muted);cursor:pointer;transition:color var(--rt-tabs-transition-duration) linear;visibility:hidden}.rt-tabs__rest:hover{color:var(--rt-color-text-primary)}.rt-tabs__rest--before{left:0;border-right:var(--rt-tabs-border-width) solid var(--rt-color-border-default)}.rt-tabs__rest--after{right:0;border-left:var(--rt-tabs-border-width) solid var(--rt-color-border-default)}.rt-tabs__rest--visible{visibility:visible}.rt-tabs__arrow{display:contents}.rt-tabs__tab-list-wrapper--inline{align-items:stretch}.rt-tabs__tab-list-wrapper--inline .rt-tabs__rest{position:static;display:none;flex-shrink:0;border:0;border-bottom:var(--rt-tabs-border-width) solid var(--rt-color-border-default);background-color:transparent}.rt-tabs__tab-list-wrapper--inline.rt-tabs__tab-list-wrapper--overflowing .rt-tabs__rest{display:flex;visibility:visible}.rt-tabs__tab-list-wrapper--inline .rt-tabs__rest--inactive{color:var(--rt-color-text-disabled);cursor:default;pointer-events:none}.rt-tabs__tab-list-wrapper--compact .rt-tabs__rest{width:auto;border:0;padding-inline:var(--rt-tabs-arrow-inset)}.rt-tabs__tab-list-wrapper--compact .rt-tabs__rest--before{background:linear-gradient(to right,var(--rt-tabs-arrow-fade) 70%,transparent)}.rt-tabs__tab-list-wrapper--compact .rt-tabs__rest--after{background:linear-gradient(to left,var(--rt-tabs-arrow-fade) 70%,transparent)}.rt-tabs__tab-list-wrapper--compact .rt-tabs__arrow{display:flex;width:var(--rt-tabs-arrow-size);height:var(--rt-tabs-arrow-size);flex:none;align-items:center;justify-content:center;border-radius:var(--rt-tabs-arrow-radius);background-color:var(--rt-tabs-arrow-bg);box-shadow:var(--rt-tabs-arrow-shadow);color:var(--rt-tabs-arrow-color);transition:color var(--rt-tabs-transition-duration) linear,background-color var(--rt-tabs-transition-duration) linear}.rt-tabs__tab-list-wrapper--compact .rt-tabs__rest:hover .rt-tabs__arrow{background-color:var(--rt-tabs-arrow-bg-hover);color:var(--rt-tabs-arrow-color-hover)}.rt-tabs__tab-list-wrapper--compact.rt-tabs__tab-list-wrapper--inline .rt-tabs__rest{border-bottom:var(--rt-tabs-border-width) solid var(--rt-tabs-list-border-color);background:none}.rt-tabs__tab-list-wrapper--compact.rt-tabs__tab-list-wrapper--inline .rt-tabs__arrow{box-shadow:none}.rt-tabs__tab-list-wrapper--compact.rt-tabs__tab-list-wrapper--inline .rt-tabs__rest--inactive .rt-tabs__arrow{color:var(--rt-color-text-disabled)}}\n",
1783
+ "@charset \"UTF-8\";@layer rt-kit.components{.rt-tabs-more-menu{--rt-tabs-more-menu-radius: var(--rt-overlay-menu-radius);--rt-tabs-more-menu-border-width: var(--rt-border-width-thin);--rt-tabs-more-menu-shadow: var(--rt-overlay-menu-shadow);--rt-tabs-more-menu-row-radius: var(--rt-radius-sm);--rt-tabs-more-menu-close-radius: var(--rt-radius-full);--rt-tabs-more-menu-max-height: 282px;display:flex;overflow:hidden auto;width:var(--rt-size-60);max-height:var(--rt-tabs-more-menu-max-height);box-sizing:border-box;flex-direction:column;padding:var(--rt-overlay-menu-padding-y) var(--rt-space-xs);border:var(--rt-tabs-more-menu-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-tabs-more-menu-radius);background:var(--rt-overlay-menu-bg);box-shadow:var(--rt-tabs-more-menu-shadow)}.rt-tabs-more-menu__row{display:flex;min-height:var(--rt-overlay-menu-item-min-height);flex:none;align-items:center;border-radius:var(--rt-tabs-more-menu-row-radius);padding-inline-end:var(--rt-space-2)}.rt-tabs-more-menu__row:hover:not(.rt-tabs-more-menu__row--disabled){background:var(--rt-color-bg-hover)}.rt-tabs-more-menu__row--disabled{opacity:var(--rt-opacity-disabled)}.rt-tabs-more-menu__row--invalid{color:var(--rt-color-state-danger)}.rt-tabs-more-menu__pick{display:flex;min-width:0;flex:1 1 auto;align-items:center;padding:var(--rt-overlay-menu-item-padding-y) var(--rt-overlay-menu-item-padding-x);border:0;background:none;color:var(--rt-color-text-primary);cursor:pointer;font-family:inherit;font-size:var(--rt-text-sm);font-weight:var(--rt-overlay-menu-item-weight);gap:var(--rt-space-sm);outline:none;text-align:start}.rt-tabs-more-menu__pick:focus-visible{background:var(--rt-color-bg-hover)}.rt-tabs-more-menu__pick[aria-disabled=true]{cursor:default}.rt-tabs-more-menu__row--invalid .rt-tabs-more-menu__pick{color:inherit}.rt-tabs-more-menu__icon{flex:none}.rt-tabs-more-menu__label{overflow:hidden;min-width:0;flex:1 1 auto;text-overflow:ellipsis;white-space:nowrap}.rt-tabs-more-menu__badge{flex:none;color:var(--rt-color-text-muted)}.rt-tabs-more-menu__close{display:inline-flex;width:var(--rt-size-5);height:var(--rt-size-5);flex:none;align-items:center;justify-content:center;padding:0;border:0;border-radius:var(--rt-tabs-more-menu-close-radius);background:transparent;color:var(--rt-color-text-muted);cursor:pointer;opacity:0}.rt-tabs-more-menu__row:hover .rt-tabs-more-menu__close,.rt-tabs-more-menu__row:focus-within .rt-tabs-more-menu__close{opacity:1}@media(hover:none){.rt-tabs-more-menu__close{opacity:1}}.rt-tabs-more-menu__close:hover{background:var(--rt-color-bg-hover);color:var(--rt-color-text-primary)}}\n"
1784
+ ],
1157
1785
  dependencies: [
1158
1786
  {
1159
1787
  kind: "directive",
@@ -1180,6 +1808,18 @@ var RtTabsComponent = class RtTabsComponent {
1180
1808
  "rotate"
1181
1809
  ]
1182
1810
  },
1811
+ {
1812
+ kind: "component",
1813
+ type: RtTabsContextMenuComponent,
1814
+ selector: "rt-tabs-context-menu"
1815
+ },
1816
+ {
1817
+ kind: "component",
1818
+ type: RtTabsMoreComponent,
1819
+ selector: "rt-tabs-more",
1820
+ inputs: ["tabs"],
1821
+ outputs: ["pick", "closeTab"]
1822
+ },
1183
1823
  {
1184
1824
  kind: "directive",
1185
1825
  type: RtTooltipDirective,
@@ -1231,6 +1871,8 @@ i0.ɵɵngDeclareClassMetadata({
1231
1871
  imports: [
1232
1872
  NgTemplateOutlet,
1233
1873
  RtIconComponent,
1874
+ RtTabsContextMenuComponent,
1875
+ RtTabsMoreComponent,
1234
1876
  RtTooltipDirective,
1235
1877
  BlockDirective,
1236
1878
  ElemDirective,
@@ -1244,8 +1886,12 @@ i0.ɵɵngDeclareClassMetadata({
1244
1886
  "[class.rt-tabs--dense]": "dense()",
1245
1887
  "[style]": "panels.durations()"
1246
1888
  },
1247
- template: "<ng-container rtBlock=\"rt-tabs\">\n <div rtElem=\"header\">\n @if (leftControls().length) {\n <div rtElem=\"controls\" [rtMod]=\"{ before: true }\">\n @for (control of leftControls(); track $index) {\n <ng-container [ngTemplateOutlet]=\"control.templateRef\" />\n }\n </div>\n }\n\n <div rtElem=\"tab-list-wrapper\" [rtMod]=\"{ inline: scrollArrows() === 'inline', overflowing: overflowing() }\">\n <div\n rtElem=\"rest\"\n qa-dataid=\"tabs-scroll-prev\"\n [rtMod]=\"{ before: true, visible: restBeforeVisible(), inactive: !restBeforeVisible() }\"\n (mousedown)=\"onRestPointerDown('before', $event)\"\n (mouseup)=\"onRestPointerUp()\"\n (mouseleave)=\"onRestPointerLeave()\">\n <rt-icon name=\"chevron-left\" color=\"current\" size=\"sm\" />\n </div>\n\n <div\n #tabList\n rtElem=\"tab-list\"\n qa-dataid=\"tabs-tab-list\"\n role=\"tablist\"\n [rtMod]=\"{ stretch: stretch(), direction: direction(), ink: ink.box() !== null }\"\n [attr.aria-orientation]=\"direction()\"\n (scroll)=\"onTabListScroll()\">\n @for (tab of visibleTabs(); track tab.id()) {\n @let focusable = tab.id() === focusId();\n <!-- Вкладка — обёртка из двух кнопок: самой вкладки и крестика рядом с ней, не внутри,\n потому что кнопка в кнопке недопустима. Нажатие в любом месте обёртки выбирает\n вкладку; крестик своё нажатие дальше не пускает. -->\n <div\n rtBlock=\"rt-tab-item\"\n role=\"presentation\"\n [rtMod]=\"{\n selected: tab.id() === selectedId(),\n disabled: tab.disabled(),\n invalid: tab.invalid(),\n stretch: stretch(),\n }\"\n [attr.data-tabitem]=\"tab.id()\"\n (click)=\"selectTab(tab.id())\">\n <button\n rtElem=\"trigger\"\n qa-dataid=\"tabs-tab\"\n type=\"button\"\n role=\"tab\"\n [rtMod]=\"{ closable: tab.showClose() }\"\n [id]=\"'rt-tab-' + tab.id()\"\n [attr.aria-disabled]=\"tab.disabled() || null\"\n [attr.aria-label]=\"tab.ariaLabel()\"\n [attr.aria-keyshortcuts]=\"tab.showClose() ? 'Delete' : null\"\n [attr.data-tabid]=\"tab.id()\"\n [attr.aria-selected]=\"tab.id() === selectedId()\"\n [attr.aria-controls]=\"headerOnly() ? null : 'rt-tabpanel-' + tab.id()\"\n [attr.tabindex]=\"focusable ? 0 : -1\"\n [rtTooltip]=\"tab.buttonTooltip()\"\n (keydown)=\"onTabKeydown($event, tab)\">\n @if (tab.hasIcon()) {\n <span rtElem=\"icon-box\">\n <rt-icon\n rtElem=\"icon\"\n size=\"sm\"\n [name]=\"tab.icon()\"\n [glyph]=\"tab.glyph()\"\n [color]=\"tab.iconColor()\"\n [fill]=\"tab.iconFill()\" />\n @if (tab.badgeOverlay()) {\n <!-- prettier-ignore -->\n <span rtElem=\"badge\" [rtMod]=\"{ overlay: true }\" [rtTooltip]=\"tab.badgeTitle()\" [attr.aria-label]=\"tab.badgeAriaLabel() || null\">{{ tab.badge() }}</span>\n }\n </span>\n }\n\n @if (tab.titleTemplate(); as titleTpl) {\n <ng-container [ngTemplateOutlet]=\"titleTpl\" />\n } @else if (tab.label()) {\n <!-- Пустая подпись не рисуется: её зазор сдвигал значок вкладки без подписи с середины. -->\n <span rtElem=\"title\">{{ tab.label() }}</span>\n }\n\n @if (tab.badge() !== null && !tab.badgeOverlay()) {\n <!-- В одну строку: перенос внутри добавил бы пробел в текст кнопки. -->\n <!-- prettier-ignore -->\n <span rtElem=\"badge\" [rtTooltip]=\"tab.badgeTitle()\" [attr.aria-label]=\"tab.badgeAriaLabel() || null\">{{ tab.badge() }}</span>\n }\n </button>\n\n @if (tab.showClose()) {\n <!-- В таб-порядке только у вкладки в фокусе: Tab с неё идёт на её крестик, дальше — из полосы. -->\n <button\n rtElem=\"close\"\n qa-dataid=\"tabs-tab-close\"\n type=\"button\"\n [attr.aria-label]=\"tab.closeLabel()\"\n [attr.tabindex]=\"focusable ? 0 : -1\"\n [rtTooltip]=\"tab.closeTooltip()\"\n [rtTooltipPlacement]=\"tab.closeTooltipPlacement()\"\n (mouseenter)=\"tab.closeHovered.set(true)\"\n (mouseleave)=\"tab.closeHovered.set(false)\"\n (click)=\"onCloseClick($event, tab)\">\n <rt-icon name=\"close\" color=\"current\" size=\"xs\" />\n </button>\n }\n </div>\n }\n\n <!-- Полоса выбранной вкладки — одна на всю полосу: так она переезжает между вкладками. -->\n <span\n rtElem=\"ink\"\n aria-hidden=\"true\"\n [rtMod]=\"{ placed: ink.box() !== null, animated: ink.animated(), invalid: ink.invalid() }\"\n [style.width.px]=\"ink.box()?.width\"\n [style.translate]=\"ink.translate()\"></span>\n </div>\n\n <div\n rtElem=\"rest\"\n qa-dataid=\"tabs-scroll-next\"\n [rtMod]=\"{ after: true, visible: restAfterVisible(), inactive: !restAfterVisible() }\"\n (mousedown)=\"onRestPointerDown('after', $event)\"\n (mouseup)=\"onRestPointerUp()\"\n (mouseleave)=\"onRestPointerLeave()\">\n <rt-icon name=\"chevron-right\" color=\"current\" size=\"sm\" />\n </div>\n </div>\n\n @if (rightControls().length) {\n <div rtElem=\"controls\" [rtMod]=\"{ after: true }\">\n @for (control of rightControls(); track $index) {\n <ng-container [ngTemplateOutlet]=\"control.templateRef\" />\n }\n </div>\n }\n </div>\n\n <!-- Уходящая панель стоит поверх: место ей задаёт замер, сделанный до смены. Сохранённые\n тела посещённых вкладок скрыты и вне таб-порядка. -->\n @for (panel of panels.list(); track panel.tab.id()) {\n @let current = panel.leaving === null && !panel.idle;\n <div\n rtElem=\"content\"\n role=\"tabpanel\"\n [attr.qa-dataid]=\"current ? 'tabs-panel' : panel.idle ? 'tabs-panel-idle' : 'tabs-panel-leaving'\"\n [attr.tabindex]=\"current ? contentTabIndex() : -1\"\n [attr.aria-hidden]=\"current ? null : 'true'\"\n [attr.inert]=\"current ? null : ''\"\n [hidden]=\"panel.idle\"\n [rtMod]=\"{\n scrollable: contentScrollable(),\n idle: panel.idle,\n leaving: panel.leaving !== null,\n entering: current && panels.shift() !== null,\n shift: panels.shift(),\n }\"\n [style.top.px]=\"panel.leaving?.top\"\n [style.left.px]=\"panel.leaving?.left\"\n [id]=\"'rt-tabpanel-' + panel.tab.id()\"\n [attr.aria-labelledby]=\"'rt-tab-' + panel.tab.id()\"\n (animationend)=\"panels.animationEnd($event)\"\n (animationcancel)=\"panels.animationEnd($event)\">\n <ng-container [ngTemplateOutlet]=\"panel.tab.templateRef\" />\n </div>\n }\n</ng-container>\n",
1248
- styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-tabs{--rt-tabs-border-width: var(--rt-border-width-thin);--rt-tabs-transition-duration: var(--rt-duration-fast);--rt-tabs-list-align: stretch;--rt-tabs-list-border-color: var(--rt-color-border-default);--rt-tabs-list-min-height: auto;--rt-tabs-list-padding-inline: 0;--rt-tabs-content-padding-top: var(--rt-space-md);display:flex;-webkit-tap-highlight-color:transparent}.rt-tabs--direction--horizontal{flex-direction:column}.rt-tabs--direction--vertical{flex-direction:row}.rt-tabs--animating{position:relative;overflow-x:clip}.rt-tabs__header{display:flex;align-items:center}.rt-tabs__tab-list-wrapper{position:relative;display:flex;overflow:hidden;flex:1 1 auto;align-items:center}.rt-tabs__tab-list{position:relative;display:flex;box-sizing:border-box;align-items:var(--rt-tabs-list-align);border-bottom:var(--rt-tabs-border-width) solid var(--rt-tabs-list-border-color);margin:0;min-block-size:var(--rt-tabs-list-min-height);-ms-overflow-style:none;overflow-x:auto;padding-inline:var(--rt-tabs-list-padding-inline);scrollbar-width:none;white-space:nowrap}.rt-tabs__tab-list::-webkit-scrollbar{display:none}.rt-tabs__tab-list--direction--horizontal{width:100%;flex-direction:row}.rt-tabs__tab-list--direction--vertical{flex-direction:column;border-right:var(--rt-tabs-border-width) solid var(--rt-color-border-default);border-bottom:0}.rt-tabs__tab-list--stretch{justify-content:space-between}.rt-tabs__tab-list--ink .rt-tab-item--selected:not(.rt-tab-item--invalid):after{background-color:transparent}.rt-tabs__ink{position:absolute;top:0;left:0;display:none;height:2px;margin-top:var(--rt-tabs-border-width);background-color:var(--rt-color-action-primary);pointer-events:none;transform:translateY(-100%)}.rt-tabs__ink--placed{display:block}.rt-tabs__ink--animated{transition:translate var(--rt-tabs-indicator-duration) var(--rt-tabs-indicator-easing),width var(--rt-tabs-indicator-duration) var(--rt-tabs-indicator-easing)}.rt-tabs__ink--invalid{background-color:var(--rt-color-state-danger)}.rt-tabs__rest{position:absolute;z-index:1;top:0;bottom:0;display:flex;width:var(--rt-control-height-lg);align-items:center;justify-content:center;background-color:var(--rt-color-bg-surface);color:var(--rt-color-text-muted);cursor:pointer;transition:color var(--rt-tabs-transition-duration) linear;visibility:hidden}.rt-tabs__rest:hover{color:var(--rt-color-text-primary)}.rt-tabs__rest--before{left:0;border-right:var(--rt-tabs-border-width) solid var(--rt-color-border-default)}.rt-tabs__rest--after{right:0;border-left:var(--rt-tabs-border-width) solid var(--rt-color-border-default)}.rt-tabs__rest--visible{visibility:visible}.rt-tabs__tab-list-wrapper--inline{align-items:stretch}.rt-tabs__tab-list-wrapper--inline .rt-tabs__rest{position:static;display:none;flex-shrink:0;border:0;border-bottom:var(--rt-tabs-border-width) solid var(--rt-color-border-default);background-color:transparent}.rt-tabs__tab-list-wrapper--inline.rt-tabs__tab-list-wrapper--overflowing .rt-tabs__rest{display:flex;visibility:visible}.rt-tabs__tab-list-wrapper--inline .rt-tabs__rest--inactive{color:var(--rt-color-text-disabled);cursor:default;pointer-events:none}.rt-tabs__controls{display:flex;flex-shrink:0;align-items:center}.rt-tabs__controls--before{padding-right:var(--rt-space-md)}.rt-tabs__controls--after{padding-left:var(--rt-space-md)}.rt-tabs__content{display:flex;min-height:0;flex:1 1 auto;flex-direction:column;padding-top:var(--rt-tabs-content-padding-top);gap:var(--rt-space-md);line-height:var(--rt-leading-relaxed)}.rt-tabs__content--scrollable{overflow:auto}.rt-tabs__content--idle{display:none}.rt-tabs__content--leaving{position:absolute;right:0;bottom:0;animation:rt-tabs-panel-leave var(--rt-tabs-panel-duration) var(--rt-tabs-panel-easing) forwards;pointer-events:none}.rt-tabs__content--entering{animation:rt-tabs-panel-enter var(--rt-tabs-panel-duration) var(--rt-tabs-panel-easing)}.rt-tabs__content--shift--forward{--rt-tabs-panel-leave-to: -100%;--rt-tabs-panel-enter-from: 100%}.rt-tabs__content--shift--backward{--rt-tabs-panel-leave-to: 100%;--rt-tabs-panel-enter-from: -100%}@keyframes rt-tabs-panel-leave{to{translate:var(--rt-tabs-panel-leave-to) 0}}@keyframes rt-tabs-panel-enter{0%{translate:var(--rt-tabs-panel-enter-from) 0}}@media(prefers-reduced-motion:reduce){.rt-tabs__ink--animated{transition:none}.rt-tabs__content--leaving,.rt-tabs__content--entering{animation:none}}.rt-tab-item{--rt-tab-item-border-width: var(--rt-border-width-thin);--rt-tab-item-badge-radius: var(--rt-radius-full);--rt-tab-item-transition-duration: var(--rt-duration-fast);--rt-tab-item-close-size: var(--rt-size-5);--rt-tab-item-close-radius: var(--rt-radius-full);--rt-tab-item-close-bg: transparent;--rt-tab-item-close-bg-hover: var(--rt-color-bg-hover);--rt-tab-item-close-color: var(--rt-color-text-muted);--rt-tab-item-close-color-hover: var(--rt-color-text-primary);--rt-tab-item-close-icon-size: var(--rt-icon-step-xs);--rt-tab-item-close-margin-inline-start: 0;--rt-tab-item-close-margin-inline-end: calc(-1 * var(--rt-space-2));position:relative;display:inline-flex;align-items:center;justify-content:center;margin:0;background-color:transparent;color:var(--rt-color-text-muted);cursor:pointer;font-family:inherit;font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-semibold);gap:var(--rt-space-sm);line-height:var(--rt-leading-none);transition:color var(--rt-tab-item-transition-duration) linear,background-color var(--rt-tab-item-transition-duration) linear;white-space:nowrap}.rt-tab-item:after{position:absolute;bottom:0;height:2px;background-color:transparent;content:\"\";inset-inline:0;pointer-events:none;translate:0 var(--rt-tab-item-border-width)}.rt-tab-item:hover:not(.rt-tab-item--disabled,.rt-tab-item--selected){background-color:var(--rt-color-bg-hover);color:var(--rt-color-text-primary)}.rt-tab-item:has(>.rt-tab-item__trigger:focus-visible){outline:2px solid var(--rt-color-action-primary);outline-offset:-3px}.rt-tab-item__trigger{display:inline-flex;min-width:0;align-items:center;justify-content:center;padding:var(--rt-space-2) var(--rt-space-4);border:0;margin:0;background:none;color:inherit;cursor:inherit;font:inherit;gap:inherit;line-height:inherit;outline:none}.rt-tab-item__trigger--closable{padding-inline-end:0}.rt-tabs--dense .rt-tab-item__trigger{padding-inline:var(--rt-space-2)}.rt-tab-item__title{overflow:hidden;max-width:200px;text-overflow:ellipsis}.rt-tab-item__icon{flex-shrink:0}.rt-tab-item__icon-box{position:relative;display:inline-flex;flex-shrink:0}.rt-tab-item__badge{display:inline-flex;min-width:18px;height:18px;align-items:center;justify-content:center;padding:0 var(--rt-space-2);border-radius:var(--rt-tab-item-badge-radius);background-color:var(--rt-color-bg-surface-subtle);color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);font-weight:var(--rt-font-weight-medium);line-height:var(--rt-leading-none)}.rt-tab-item__badge--overlay{position:absolute;top:calc(-1 * var(--rt-space-2));right:calc(-1 * (var(--rt-space-1) + var(--rt-space-0-5)));min-width:var(--rt-size-4);height:var(--rt-size-4);box-sizing:border-box;padding:0 var(--rt-space-1);background-color:var(--rt-color-action-primary);color:var(--rt-color-action-on-primary);font-size:var(--rt-text-2xs)}.rt-tab-item__close{--rt-icon-step-xs: var(--rt-tab-item-close-icon-size);display:inline-flex;width:var(--rt-tab-item-close-size);height:var(--rt-tab-item-close-size);flex-shrink:0;align-items:center;justify-content:center;padding:0;border:0;border-radius:var(--rt-tab-item-close-radius);background-color:var(--rt-tab-item-close-bg);color:var(--rt-tab-item-close-color);cursor:pointer;font:inherit;margin-block:calc(-1 * var(--rt-space-1));margin-inline:var(--rt-tab-item-close-margin-inline-start) calc(var(--rt-space-4) + var(--rt-tab-item-close-margin-inline-end));transition:color var(--rt-tab-item-transition-duration) linear,background-color var(--rt-tab-item-transition-duration) linear}.rt-tab-item__close:hover{background-color:var(--rt-tab-item-close-bg-hover);color:var(--rt-tab-item-close-color-hover)}.rt-tab-item__close:focus-visible{outline:2px solid var(--rt-color-action-primary);outline-offset:0}.rt-tab-item--selected{color:var(--rt-color-action-primary);cursor:default}.rt-tab-item--selected .rt-tab-item__trigger{padding-block-end:calc(var(--rt-space-2) + 2px)}.rt-tab-item--selected:after{background-color:var(--rt-color-action-primary)}.rt-tab-item--selected .rt-tab-item__badge:not(.rt-tab-item__badge--overlay){background-color:var(--rt-color-action-primary-soft);color:var(--rt-color-action-primary)}.rt-tab-item--invalid{color:var(--rt-color-state-danger)}.rt-tab-item--invalid:after{background-color:var(--rt-color-state-danger)}.rt-tab-item--disabled{color:var(--rt-color-text-disabled);cursor:not-allowed}.rt-tab-item--stretch{max-width:100%;flex:1 1 auto}}\n"]
1889
+ template: "<ng-container rtBlock=\"rt-tabs\">\n <div rtElem=\"header\">\n @if (leftControls().length) {\n <div rtElem=\"controls\" [rtMod]=\"{ before: true }\">\n @for (control of leftControls(); track $index) {\n <ng-container [ngTemplateOutlet]=\"control.templateRef\" />\n }\n </div>\n }\n\n <div\n rtElem=\"tab-list-wrapper\"\n [rtMod]=\"{ inline: scrollArrows() === 'inline', overflowing: overflowing(), compact: arrowLook() === 'compact' }\">\n @if (!moreMode()) {\n <div\n rtElem=\"rest\"\n qa-dataid=\"tabs-scroll-prev\"\n [rtMod]=\"{ before: true, visible: restBeforeVisible(), inactive: !restBeforeVisible() }\"\n (mousedown)=\"onRestPointerDown('before', $event)\"\n (mouseup)=\"onRestPointerUp()\"\n (mouseleave)=\"onRestPointerLeave()\">\n <span rtElem=\"arrow\"><rt-icon name=\"chevron-left\" color=\"current\" size=\"sm\" /></span>\n </div>\n }\n\n <div\n #tabList\n rtElem=\"tab-list\"\n qa-dataid=\"tabs-tab-list\"\n role=\"tablist\"\n [rtMod]=\"{ stretch: stretch(), direction: direction(), ink: ink.box() !== null, more: moreMode() }\"\n [attr.aria-orientation]=\"direction()\"\n (scroll)=\"onTabListScroll()\">\n @for (tab of visibleTabs(); track tab.id()) {\n @let focusable = tab.id() === focusId();\n @let closeShown = tab.showClose() && (closeOn() === 'all' || tab.id() === selectedId());\n <!-- Вкладка — обёртка из двух кнопок: самой вкладки и крестика рядом с ней, не внутри,\n потому что кнопка в кнопке недопустима. Нажатие в любом месте обёртки выбирает\n вкладку; крестик своё нажатие дальше не пускает. -->\n <div\n rtBlock=\"rt-tab-item\"\n role=\"presentation\"\n [rtMod]=\"{\n selected: tab.id() === selectedId(),\n disabled: tab.disabled(),\n invalid: tab.invalid(),\n stretch: stretch(),\n inMore: more.ids().has(tab.id()),\n }\"\n [style.order]=\"more.order().get(tab.id())\"\n [attr.inert]=\"more.ids().has(tab.id()) || null\"\n [attr.data-tabitem]=\"tab.id()\"\n (click)=\"selectTab(tab.id())\"\n (contextmenu)=\"contextMenu.open($event, tab)\">\n <button\n rtElem=\"trigger\"\n qa-dataid=\"tabs-tab\"\n type=\"button\"\n role=\"tab\"\n [rtMod]=\"{ closable: closeShown }\"\n [id]=\"'rt-tab-' + tab.id()\"\n [attr.aria-disabled]=\"tab.disabled() || null\"\n [attr.aria-label]=\"tab.ariaLabel()\"\n [attr.aria-keyshortcuts]=\"closeShown ? 'Delete' : null\"\n [attr.data-tabid]=\"tab.id()\"\n [attr.aria-selected]=\"tab.id() === selectedId()\"\n [attr.aria-controls]=\"headerOnly() ? null : 'rt-tabpanel-' + tab.id()\"\n [attr.tabindex]=\"focusable ? 0 : -1\"\n [rtTooltip]=\"tab.buttonTooltip()\"\n (keydown)=\"onTabKeydown($event, tab)\">\n @if (tab.hasIcon()) {\n <span rtElem=\"icon-box\">\n <rt-icon\n rtElem=\"icon\"\n size=\"sm\"\n [name]=\"tab.shownIcon()\"\n [glyph]=\"tab.glyph()\"\n [color]=\"tab.iconColor()\"\n [fill]=\"tab.iconFill()\" />\n @if (tab.badgeOverlay()) {\n <!-- prettier-ignore -->\n <span rtElem=\"badge\" [rtMod]=\"{ overlay: true }\" [rtTooltip]=\"tab.badgeTitle()\" [attr.aria-label]=\"tab.badgeAriaLabel() || null\">{{ tab.badge() }}</span>\n }\n </span>\n }\n\n @if (tab.titleTemplate(); as titleTpl) {\n <ng-container [ngTemplateOutlet]=\"titleTpl\" />\n } @else if (tab.label()) {\n <!-- Пустая подпись не рисуется: её зазор сдвигал значок вкладки без подписи с середины. -->\n <span rtElem=\"title\">{{ tab.label() }}</span>\n }\n\n @if (tab.badge() !== null && !tab.badgeOverlay()) {\n <!-- В одну строку: перенос внутри добавил бы пробел в текст кнопки. -->\n <!-- prettier-ignore -->\n <span rtElem=\"badge\" [rtTooltip]=\"tab.badgeTitle()\" [attr.aria-label]=\"tab.badgeAriaLabel() || null\">{{ tab.badge() }}</span>\n }\n </button>\n\n @if (closeShown) {\n <!-- В таб-порядке только у вкладки в фокусе: Tab с неё идёт на её крестик, дальше — из полосы. -->\n <button\n rtElem=\"close\"\n qa-dataid=\"tabs-tab-close\"\n type=\"button\"\n [attr.aria-label]=\"tab.closeLabel()\"\n [attr.tabindex]=\"focusable ? 0 : -1\"\n [rtTooltip]=\"tab.closeTooltip()\"\n [rtTooltipPlacement]=\"tab.closeTooltipPlacement()\"\n (mouseenter)=\"tab.closeHovered.set(true)\"\n (mouseleave)=\"tab.closeHovered.set(false)\"\n (click)=\"onCloseClick($event, tab)\">\n <rt-icon name=\"close\" color=\"current\" size=\"xs\" />\n </button>\n }\n </div>\n }\n\n @if (moreMode()) {\n <rt-tabs-more [tabs]=\"more.moreTabs()\" (pick)=\"selectTab($event)\" (closeTab)=\"onMoreClose($event)\" />\n }\n\n <!-- Полоса выбранной вкладки — одна на всю полосу: так она переезжает между вкладками. -->\n <span\n rtElem=\"ink\"\n aria-hidden=\"true\"\n [rtMod]=\"{ placed: ink.box() !== null, animated: ink.animated(), invalid: ink.invalid() }\"\n [style.width.px]=\"ink.box()?.width\"\n [style.translate]=\"ink.translate()\"></span>\n </div>\n\n @if (!moreMode()) {\n <div\n rtElem=\"rest\"\n qa-dataid=\"tabs-scroll-next\"\n [rtMod]=\"{ after: true, visible: restAfterVisible(), inactive: !restAfterVisible() }\"\n (mousedown)=\"onRestPointerDown('after', $event)\"\n (mouseup)=\"onRestPointerUp()\"\n (mouseleave)=\"onRestPointerLeave()\">\n <span rtElem=\"arrow\"><rt-icon name=\"chevron-right\" color=\"current\" size=\"sm\" /></span>\n </div>\n }\n </div>\n\n @if (rightControls().length) {\n <div rtElem=\"controls\" [rtMod]=\"{ after: true }\">\n @for (control of rightControls(); track $index) {\n <ng-container [ngTemplateOutlet]=\"control.templateRef\" />\n }\n </div>\n }\n </div>\n\n <rt-tabs-context-menu #contextMenu />\n\n <!-- Уходящая панель стоит поверх: место ей задаёт замер, сделанный до смены. Сохранённые\n тела посещённых вкладок скрыты и вне таб-порядка. -->\n @for (panel of panels.list(); track panel.tab.id()) {\n @let current = panel.leaving === null && !panel.idle;\n <div\n rtElem=\"content\"\n role=\"tabpanel\"\n [attr.qa-dataid]=\"current ? 'tabs-panel' : panel.idle ? 'tabs-panel-idle' : 'tabs-panel-leaving'\"\n [attr.tabindex]=\"current ? contentTabIndex() : -1\"\n [attr.aria-hidden]=\"current ? null : 'true'\"\n [attr.inert]=\"current ? null : ''\"\n [hidden]=\"panel.idle\"\n [rtMod]=\"{\n scrollable: contentScrollable(),\n idle: panel.idle,\n leaving: panel.leaving !== null,\n entering: current && panels.shift() !== null,\n shift: panels.shift(),\n }\"\n [style.top.px]=\"panel.leaving?.top\"\n [style.left.px]=\"panel.leaving?.left\"\n [id]=\"'rt-tabpanel-' + panel.tab.id()\"\n [attr.aria-labelledby]=\"'rt-tab-' + panel.tab.id()\"\n (animationend)=\"panels.animationEnd($event)\"\n (animationcancel)=\"panels.animationEnd($event)\">\n <ng-container [ngTemplateOutlet]=\"panel.tab.templateRef\" />\n </div>\n }\n</ng-container>\n",
1890
+ styles: [
1891
+ "@charset \"UTF-8\";@layer rt-kit.components{.rt-tabs{--rt-tabs-border-width: var(--rt-border-width-thin);--rt-tabs-transition-duration: var(--rt-duration-fast);--rt-tabs-list-align: stretch;--rt-tabs-list-border-color: var(--rt-color-border-default);--rt-tabs-list-min-height: auto;--rt-tabs-list-padding-inline: 0;--rt-tabs-content-padding-top: var(--rt-space-md);display:flex;-webkit-tap-highlight-color:transparent}.rt-tabs--direction--horizontal{flex-direction:column}.rt-tabs--direction--vertical{flex-direction:row}.rt-tabs--animating{position:relative;overflow-x:clip}.rt-tabs__header{display:flex;align-items:center}.rt-tabs__tab-list-wrapper{position:relative;display:flex;overflow:hidden;flex:1 1 auto;align-items:center}.rt-tabs__tab-list{position:relative;display:flex;box-sizing:border-box;align-items:var(--rt-tabs-list-align);border-bottom:var(--rt-tabs-border-width) solid var(--rt-tabs-list-border-color);margin:0;min-block-size:var(--rt-tabs-list-min-height);-ms-overflow-style:none;overflow-x:auto;padding-inline:var(--rt-tabs-list-padding-inline);scrollbar-width:none;white-space:nowrap}.rt-tabs__tab-list::-webkit-scrollbar{display:none}.rt-tabs__tab-list--direction--horizontal{width:100%;flex-direction:row}.rt-tabs__tab-list--direction--vertical{flex-direction:column;border-right:var(--rt-tabs-border-width) solid var(--rt-color-border-default);border-bottom:0}.rt-tabs__tab-list--stretch{justify-content:space-between}.rt-tabs__tab-list--more{overflow-x:clip}.rt-tabs__tab-list--ink .rt-tab-item--selected:not(.rt-tab-item--invalid):after{background-color:transparent}.rt-tabs__ink{position:absolute;top:0;left:0;display:none;height:2px;margin-top:var(--rt-tabs-border-width);background-color:var(--rt-color-action-primary);pointer-events:none;transform:translateY(-100%)}.rt-tabs__ink--placed{display:block}.rt-tabs__ink--animated{transition:translate var(--rt-tabs-indicator-duration) var(--rt-tabs-indicator-easing),width var(--rt-tabs-indicator-duration) var(--rt-tabs-indicator-easing)}.rt-tabs__ink--invalid{background-color:var(--rt-color-state-danger)}.rt-tabs__controls{display:flex;flex-shrink:0;align-items:center}.rt-tabs__controls--before{padding-right:var(--rt-space-md)}.rt-tabs__controls--after{padding-left:var(--rt-space-md)}.rt-tabs__content{display:flex;min-height:0;flex:1 1 auto;flex-direction:column;padding-top:var(--rt-tabs-content-padding-top);gap:var(--rt-space-md);line-height:var(--rt-leading-relaxed)}.rt-tabs__content--scrollable{overflow:auto}.rt-tabs__content--idle{display:none}.rt-tabs__content--leaving{position:absolute;right:0;bottom:0;animation:rt-tabs-panel-leave var(--rt-tabs-panel-duration) var(--rt-tabs-panel-easing) forwards;pointer-events:none}.rt-tabs__content--entering{animation:rt-tabs-panel-enter var(--rt-tabs-panel-duration) var(--rt-tabs-panel-easing)}.rt-tabs__content--shift--forward{--rt-tabs-panel-leave-to: -100%;--rt-tabs-panel-enter-from: 100%}.rt-tabs__content--shift--backward{--rt-tabs-panel-leave-to: 100%;--rt-tabs-panel-enter-from: -100%}@keyframes rt-tabs-panel-leave{to{translate:var(--rt-tabs-panel-leave-to) 0}}@keyframes rt-tabs-panel-enter{0%{translate:var(--rt-tabs-panel-enter-from) 0}}@media(prefers-reduced-motion:reduce){.rt-tabs__ink--animated{transition:none}.rt-tabs__content--leaving,.rt-tabs__content--entering{animation:none}}.rt-tab-item{--rt-tab-item-border-width: var(--rt-border-width-thin);--rt-tab-item-badge-radius: var(--rt-radius-full);--rt-tab-item-transition-duration: var(--rt-duration-fast);--rt-tab-item-close-size: var(--rt-size-5);--rt-tab-item-close-radius: var(--rt-radius-full);--rt-tab-item-close-bg: transparent;--rt-tab-item-close-bg-hover: var(--rt-color-bg-hover);--rt-tab-item-close-color: var(--rt-color-text-muted);--rt-tab-item-close-color-hover: var(--rt-color-text-primary);--rt-tab-item-close-icon-size: var(--rt-icon-step-xs);--rt-tab-item-close-margin-inline-start: 0;--rt-tab-item-close-margin-inline-end: calc(-1 * var(--rt-space-2));position:relative;display:inline-flex;align-items:center;justify-content:center;margin:0;background-color:transparent;color:var(--rt-color-text-muted);cursor:pointer;font-family:inherit;font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-semibold);gap:var(--rt-space-sm);line-height:var(--rt-leading-none);transition:color var(--rt-tab-item-transition-duration) linear,background-color var(--rt-tab-item-transition-duration) linear;white-space:nowrap}.rt-tab-item:after{position:absolute;bottom:0;height:2px;background-color:transparent;content:\"\";inset-inline:0;pointer-events:none;translate:0 var(--rt-tab-item-border-width)}.rt-tab-item--in-more{position:absolute;top:0;left:0;visibility:hidden}.rt-tab-item:hover:not(.rt-tab-item--disabled,.rt-tab-item--selected){background-color:var(--rt-color-bg-hover);color:var(--rt-color-text-primary)}.rt-tab-item:has(>.rt-tab-item__trigger:focus-visible){outline:2px solid var(--rt-color-action-primary);outline-offset:-3px}.rt-tab-item__trigger{display:inline-flex;min-width:0;align-items:center;justify-content:center;padding:var(--rt-space-2) var(--rt-space-4);border:0;margin:0;background:none;color:inherit;cursor:inherit;font:inherit;gap:inherit;line-height:inherit;outline:none}.rt-tab-item__trigger--closable{padding-inline-end:0}.rt-tabs--dense .rt-tab-item__trigger{padding-inline:var(--rt-space-2)}.rt-tab-item__title{overflow:hidden;max-width:200px;text-overflow:ellipsis}.rt-tab-item__icon{flex-shrink:0}.rt-tab-item__icon-box{position:relative;display:inline-flex;flex-shrink:0}.rt-tab-item__badge{display:inline-flex;min-width:18px;height:18px;align-items:center;justify-content:center;padding:0 var(--rt-space-2);border-radius:var(--rt-tab-item-badge-radius);background-color:var(--rt-color-bg-surface-subtle);color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);font-weight:var(--rt-font-weight-medium);line-height:var(--rt-leading-none)}.rt-tab-item__badge--overlay{position:absolute;top:calc(-1 * var(--rt-space-2));right:calc(-1 * (var(--rt-space-1) + var(--rt-space-0-5)));min-width:var(--rt-size-4);height:var(--rt-size-4);box-sizing:border-box;padding:0 var(--rt-space-1);background-color:var(--rt-color-action-primary);color:var(--rt-color-action-on-primary);font-size:var(--rt-text-2xs)}.rt-tab-item__close{--rt-icon-step-xs: var(--rt-tab-item-close-icon-size);display:inline-flex;width:var(--rt-tab-item-close-size);height:var(--rt-tab-item-close-size);flex-shrink:0;align-items:center;justify-content:center;padding:0;border:0;border-radius:var(--rt-tab-item-close-radius);background-color:var(--rt-tab-item-close-bg);color:var(--rt-tab-item-close-color);cursor:pointer;font:inherit;margin-block:calc(-1 * var(--rt-space-1));margin-inline:var(--rt-tab-item-close-margin-inline-start) calc(var(--rt-space-4) + var(--rt-tab-item-close-margin-inline-end));transition:color var(--rt-tab-item-transition-duration) linear,background-color var(--rt-tab-item-transition-duration) linear}.rt-tab-item__close:hover{background-color:var(--rt-tab-item-close-bg-hover);color:var(--rt-tab-item-close-color-hover)}.rt-tab-item__close:focus-visible{outline:2px solid var(--rt-color-action-primary);outline-offset:0}.rt-tab-item--selected{color:var(--rt-color-action-primary);cursor:default}.rt-tab-item--selected .rt-tab-item__trigger{padding-block-end:calc(var(--rt-space-2) + 2px)}.rt-tab-item--selected:after{background-color:var(--rt-color-action-primary)}.rt-tab-item--selected .rt-tab-item__badge:not(.rt-tab-item__badge--overlay){background-color:var(--rt-color-action-primary-soft);color:var(--rt-color-action-primary)}.rt-tab-item--invalid{color:var(--rt-color-state-danger)}.rt-tab-item--invalid:after{background-color:var(--rt-color-state-danger)}.rt-tab-item--disabled{color:var(--rt-color-text-disabled);cursor:not-allowed}.rt-tab-item--stretch{max-width:100%;flex:1 1 auto}.rt-tabs__tab-list--measure>.rt-tab-item--stretch{flex-grow:0}}\n",
1892
+ "@charset \"UTF-8\";@layer rt-kit.components{.rt-tabs{--rt-tabs-arrow-size: var(--rt-size-6);--rt-tabs-arrow-inset: var(--rt-space-1);--rt-tabs-arrow-radius: var(--rt-radius-sm);--rt-tabs-arrow-shadow: var(--rt-shadow-sm);--rt-tabs-arrow-bg: var(--rt-color-bg-surface);--rt-tabs-arrow-bg-hover: var(--rt-color-bg-hover);--rt-tabs-arrow-color: var(--rt-color-text-muted);--rt-tabs-arrow-color-hover: var(--rt-color-text-primary);--rt-tabs-arrow-fade: var(--rt-color-bg-surface)}.rt-tabs__rest{position:absolute;z-index:1;top:0;bottom:0;display:flex;width:var(--rt-control-height-lg);align-items:center;justify-content:center;background-color:var(--rt-color-bg-surface);color:var(--rt-color-text-muted);cursor:pointer;transition:color var(--rt-tabs-transition-duration) linear;visibility:hidden}.rt-tabs__rest:hover{color:var(--rt-color-text-primary)}.rt-tabs__rest--before{left:0;border-right:var(--rt-tabs-border-width) solid var(--rt-color-border-default)}.rt-tabs__rest--after{right:0;border-left:var(--rt-tabs-border-width) solid var(--rt-color-border-default)}.rt-tabs__rest--visible{visibility:visible}.rt-tabs__arrow{display:contents}.rt-tabs__tab-list-wrapper--inline{align-items:stretch}.rt-tabs__tab-list-wrapper--inline .rt-tabs__rest{position:static;display:none;flex-shrink:0;border:0;border-bottom:var(--rt-tabs-border-width) solid var(--rt-color-border-default);background-color:transparent}.rt-tabs__tab-list-wrapper--inline.rt-tabs__tab-list-wrapper--overflowing .rt-tabs__rest{display:flex;visibility:visible}.rt-tabs__tab-list-wrapper--inline .rt-tabs__rest--inactive{color:var(--rt-color-text-disabled);cursor:default;pointer-events:none}.rt-tabs__tab-list-wrapper--compact .rt-tabs__rest{width:auto;border:0;padding-inline:var(--rt-tabs-arrow-inset)}.rt-tabs__tab-list-wrapper--compact .rt-tabs__rest--before{background:linear-gradient(to right,var(--rt-tabs-arrow-fade) 70%,transparent)}.rt-tabs__tab-list-wrapper--compact .rt-tabs__rest--after{background:linear-gradient(to left,var(--rt-tabs-arrow-fade) 70%,transparent)}.rt-tabs__tab-list-wrapper--compact .rt-tabs__arrow{display:flex;width:var(--rt-tabs-arrow-size);height:var(--rt-tabs-arrow-size);flex:none;align-items:center;justify-content:center;border-radius:var(--rt-tabs-arrow-radius);background-color:var(--rt-tabs-arrow-bg);box-shadow:var(--rt-tabs-arrow-shadow);color:var(--rt-tabs-arrow-color);transition:color var(--rt-tabs-transition-duration) linear,background-color var(--rt-tabs-transition-duration) linear}.rt-tabs__tab-list-wrapper--compact .rt-tabs__rest:hover .rt-tabs__arrow{background-color:var(--rt-tabs-arrow-bg-hover);color:var(--rt-tabs-arrow-color-hover)}.rt-tabs__tab-list-wrapper--compact.rt-tabs__tab-list-wrapper--inline .rt-tabs__rest{border-bottom:var(--rt-tabs-border-width) solid var(--rt-tabs-list-border-color);background:none}.rt-tabs__tab-list-wrapper--compact.rt-tabs__tab-list-wrapper--inline .rt-tabs__arrow{box-shadow:none}.rt-tabs__tab-list-wrapper--compact.rt-tabs__tab-list-wrapper--inline .rt-tabs__rest--inactive .rt-tabs__arrow{color:var(--rt-color-text-disabled)}}\n",
1893
+ "@charset \"UTF-8\";@layer rt-kit.components{.rt-tabs-more-menu{--rt-tabs-more-menu-radius: var(--rt-overlay-menu-radius);--rt-tabs-more-menu-border-width: var(--rt-border-width-thin);--rt-tabs-more-menu-shadow: var(--rt-overlay-menu-shadow);--rt-tabs-more-menu-row-radius: var(--rt-radius-sm);--rt-tabs-more-menu-close-radius: var(--rt-radius-full);--rt-tabs-more-menu-max-height: 282px;display:flex;overflow:hidden auto;width:var(--rt-size-60);max-height:var(--rt-tabs-more-menu-max-height);box-sizing:border-box;flex-direction:column;padding:var(--rt-overlay-menu-padding-y) var(--rt-space-xs);border:var(--rt-tabs-more-menu-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-tabs-more-menu-radius);background:var(--rt-overlay-menu-bg);box-shadow:var(--rt-tabs-more-menu-shadow)}.rt-tabs-more-menu__row{display:flex;min-height:var(--rt-overlay-menu-item-min-height);flex:none;align-items:center;border-radius:var(--rt-tabs-more-menu-row-radius);padding-inline-end:var(--rt-space-2)}.rt-tabs-more-menu__row:hover:not(.rt-tabs-more-menu__row--disabled){background:var(--rt-color-bg-hover)}.rt-tabs-more-menu__row--disabled{opacity:var(--rt-opacity-disabled)}.rt-tabs-more-menu__row--invalid{color:var(--rt-color-state-danger)}.rt-tabs-more-menu__pick{display:flex;min-width:0;flex:1 1 auto;align-items:center;padding:var(--rt-overlay-menu-item-padding-y) var(--rt-overlay-menu-item-padding-x);border:0;background:none;color:var(--rt-color-text-primary);cursor:pointer;font-family:inherit;font-size:var(--rt-text-sm);font-weight:var(--rt-overlay-menu-item-weight);gap:var(--rt-space-sm);outline:none;text-align:start}.rt-tabs-more-menu__pick:focus-visible{background:var(--rt-color-bg-hover)}.rt-tabs-more-menu__pick[aria-disabled=true]{cursor:default}.rt-tabs-more-menu__row--invalid .rt-tabs-more-menu__pick{color:inherit}.rt-tabs-more-menu__icon{flex:none}.rt-tabs-more-menu__label{overflow:hidden;min-width:0;flex:1 1 auto;text-overflow:ellipsis;white-space:nowrap}.rt-tabs-more-menu__badge{flex:none;color:var(--rt-color-text-muted)}.rt-tabs-more-menu__close{display:inline-flex;width:var(--rt-size-5);height:var(--rt-size-5);flex:none;align-items:center;justify-content:center;padding:0;border:0;border-radius:var(--rt-tabs-more-menu-close-radius);background:transparent;color:var(--rt-color-text-muted);cursor:pointer;opacity:0}.rt-tabs-more-menu__row:hover .rt-tabs-more-menu__close,.rt-tabs-more-menu__row:focus-within .rt-tabs-more-menu__close{opacity:1}@media(hover:none){.rt-tabs-more-menu__close{opacity:1}}.rt-tabs-more-menu__close:hover{background:var(--rt-color-bg-hover);color:var(--rt-color-text-primary)}}\n"
1894
+ ]
1249
1895
  }]
1250
1896
  }],
1251
1897
  ctorParameters: () => [],
@@ -1294,6 +1940,14 @@ i0.ɵɵngDeclareClassMetadata({
1294
1940
  required: false
1295
1941
  }]
1296
1942
  }],
1943
+ closeOn: [{
1944
+ type: i0.Input,
1945
+ args: [{
1946
+ isSignal: true,
1947
+ alias: "closeOn",
1948
+ required: false
1949
+ }]
1950
+ }],
1297
1951
  contentScrollable: [{
1298
1952
  type: i0.Input,
1299
1953
  args: [{
@@ -1326,6 +1980,22 @@ i0.ɵɵngDeclareClassMetadata({
1326
1980
  required: false
1327
1981
  }]
1328
1982
  }],
1983
+ overflow: [{
1984
+ type: i0.Input,
1985
+ args: [{
1986
+ isSignal: true,
1987
+ alias: "overflow",
1988
+ required: false
1989
+ }]
1990
+ }],
1991
+ moreLimit: [{
1992
+ type: i0.Input,
1993
+ args: [{
1994
+ isSignal: true,
1995
+ alias: "moreLimit",
1996
+ required: false
1997
+ }]
1998
+ }],
1329
1999
  scrollArrows: [{
1330
2000
  type: i0.Input,
1331
2001
  args: [{
@@ -1334,6 +2004,14 @@ i0.ɵɵngDeclareClassMetadata({
1334
2004
  required: false
1335
2005
  }]
1336
2006
  }],
2007
+ arrowLook: [{
2008
+ type: i0.Input,
2009
+ args: [{
2010
+ isSignal: true,
2011
+ alias: "arrowLook",
2012
+ required: false
2013
+ }]
2014
+ }],
1337
2015
  scrollStep: [{
1338
2016
  type: i0.Input,
1339
2017
  args: [{