@rt-tools/ui-kit-v2 0.29.1 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs +23 -29
- package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-calendar.mjs +2 -2
- package/fesm2022/rt-tools-ui-kit-v2-calendar.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-core.mjs +223 -3
- package/fesm2022/rt-tools-ui-kit-v2-core.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs +2 -2
- package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-draggable-tree.mjs +1 -2
- package/fesm2022/rt-tools-ui-kit-v2-draggable-tree.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-list.mjs +2 -2
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-list.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs +277 -904
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-filter-control.mjs +2 -2
- package/fesm2022/rt-tools-ui-kit-v2-filter-control.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree.mjs +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs +35 -48
- package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs +2 -2
- package/fesm2022/rt-tools-ui-kit-v2-pdf-viewer.mjs +2 -2
- package/fesm2022/rt-tools-ui-kit-v2-pdf-viewer.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +4 -4
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-select.mjs +37 -181
- package/fesm2022/rt-tools-ui-kit-v2-select.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-service-block.mjs +131 -0
- package/fesm2022/rt-tools-ui-kit-v2-service-block.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs +5 -36
- package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-tag.mjs +2 -3
- package/fesm2022/rt-tools-ui-kit-v2-tag.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-toolbar.mjs +2 -2
- package/fesm2022/rt-tools-ui-kit-v2-toolbar.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-tree-selector.mjs +8 -13
- package/fesm2022/rt-tools-ui-kit-v2-tree-selector.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-tree.mjs +12 -7
- package/fesm2022/rt-tools-ui-kit-v2-tree.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-workspace.mjs +2 -2
- package/fesm2022/rt-tools-ui-kit-v2-workspace.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2.mjs +1 -0
- package/package.json +5 -1
- package/src/lib/components/dynamic-selector/stories/component/test-dynamic-selector-popup-frame.component.scss +6 -0
- package/src/lib/components/page-header/rt-page-header.component.scss +4 -2
- package/src/lib/components/service-block/CONTEXT.md +37 -0
- package/src/lib/components/service-block/rt-service-block.component.scss +61 -0
- package/src/lib/components/tree/CONTEXT.md +1 -1
- package/src/rich-editor/lib/components/ai-chat/CONTEXT.md +1 -1
- package/src/styles/_breakpoints.scss +37 -4
- package/src/styles/_index.scss +0 -4
- package/styles/tokens.css +0 -8
- package/types/rt-tools-ui-kit-v2-autocomplete.d.ts +4 -3
- package/types/rt-tools-ui-kit-v2-core.d.ts +155 -1
- package/types/rt-tools-ui-kit-v2-dynamic-selector.d.ts +51 -269
- package/types/rt-tools-ui-kit-v2-multiselect.d.ts +4 -3
- package/types/rt-tools-ui-kit-v2-select.d.ts +12 -74
- package/types/rt-tools-ui-kit-v2-service-block.d.ts +34 -0
- package/types/rt-tools-ui-kit-v2-side-menu.d.ts +5 -20
- package/types/rt-tools-ui-kit-v2-tag.d.ts +2 -3
- package/types/rt-tools-ui-kit-v2-tree-selector.d.ts +0 -2
- package/types/rt-tools-ui-kit-v2-tree.d.ts +7 -9
- package/types/rt-tools-ui-kit-v2.d.ts +1 -0
- package/src/styles/_place.scss +0 -7
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NgTemplateOutlet } from "@angular/common";
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
|
-
import { ChangeDetectionStrategy, Component, Directive, TemplateRef, ViewEncapsulation,
|
|
3
|
+
import { ChangeDetectionStrategy, Component, Directive, TemplateRef, ViewEncapsulation, booleanAttribute, computed, contentChild, forwardRef, inject, input, output, signal, viewChild } from "@angular/core";
|
|
4
4
|
import * as i2 from "@angular/forms";
|
|
5
5
|
import { FormsModule } from "@angular/forms";
|
|
6
6
|
import { BlockDirective, ElemDirective, ModDirective } from "@rt-tools/core";
|
|
7
|
-
import { RT_KIT_LABELS, rtKitLabel } from "@rt-tools/ui-kit-v2/core";
|
|
7
|
+
import { RT_KIT_LABELS, RtOptionList, rtKitLabel, rtTreeFind, rtTreeIsTree, rtTreeOpenFor, rtTreeRows, rtTreeSideKey, rtTreeToggle } from "@rt-tools/ui-kit-v2/core";
|
|
8
8
|
import { RtFormControlBase } from "@rt-tools/ui-kit-v2/form-control";
|
|
9
9
|
import { RtIconComponent } from "@rt-tools/ui-kit-v2/icon";
|
|
10
10
|
import { RtIconButtonComponent } from "@rt-tools/ui-kit-v2/icon-button";
|
|
@@ -12,137 +12,6 @@ import { RtInputComponent } from "@rt-tools/ui-kit-v2/input";
|
|
|
12
12
|
import { RtPopoverDirective } from "@rt-tools/ui-kit-v2/popover";
|
|
13
13
|
import * as i1 from "@rt-tools/ui-kit-v2/radius";
|
|
14
14
|
import { RtRadiusDirective } from "@rt-tools/ui-kit-v2/radius";
|
|
15
|
-
function rtScrollActiveOptionIntoView(activeOptionId) {
|
|
16
|
-
const document = inject(DOCUMENT);
|
|
17
|
-
afterRenderEffect(() => {
|
|
18
|
-
const id = activeOptionId();
|
|
19
|
-
const option = id ? document.getElementById(id) : null;
|
|
20
|
-
if (typeof option?.scrollIntoView === "function") option.scrollIntoView({ block: "nearest" });
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
function childrenOf(option) {
|
|
24
|
-
return option.children ?? [];
|
|
25
|
-
}
|
|
26
|
-
function isBranch(option) {
|
|
27
|
-
return childrenOf(option).length > 0;
|
|
28
|
-
}
|
|
29
|
-
function rtTreeIsTree(options) {
|
|
30
|
-
return options.some((option) => isBranch(option));
|
|
31
|
-
}
|
|
32
|
-
function rtTreeFind(options, value) {
|
|
33
|
-
for (const option of options) {
|
|
34
|
-
if (option.value === value) return option;
|
|
35
|
-
const found = rtTreeFind(childrenOf(option), value);
|
|
36
|
-
if (found) return found;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
function rtTreeLeaves(option) {
|
|
40
|
-
if (option.disabled) return [];
|
|
41
|
-
if (!isBranch(option)) return [option.value];
|
|
42
|
-
return childrenOf(option).flatMap((child) => rtTreeLeaves(child));
|
|
43
|
-
}
|
|
44
|
-
function rtTreeBranchState(option, chosen) {
|
|
45
|
-
const leaves = rtTreeLeaves(option);
|
|
46
|
-
const count = leaves.filter((leaf) => chosen.includes(leaf)).length;
|
|
47
|
-
if (count === 0) return "none";
|
|
48
|
-
return count === leaves.length ? "all" : "some";
|
|
49
|
-
}
|
|
50
|
-
function holdsChosen(option, chosen) {
|
|
51
|
-
return childrenOf(option).some((child) => chosen.includes(child.value) || holdsChosen(child, chosen));
|
|
52
|
-
}
|
|
53
|
-
function collectOpen(list, chosen, open) {
|
|
54
|
-
for (const option of list) if (holdsChosen(option, chosen)) {
|
|
55
|
-
open.add(option.value);
|
|
56
|
-
collectOpen(childrenOf(option), chosen, open);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
function rtTreeOpenFor(options, chosen) {
|
|
60
|
-
const open = /* @__PURE__ */ new Set();
|
|
61
|
-
collectOpen(options, chosen, open);
|
|
62
|
-
return open;
|
|
63
|
-
}
|
|
64
|
-
function matches(option, term) {
|
|
65
|
-
return option.label.toLowerCase().includes(term);
|
|
66
|
-
}
|
|
67
|
-
function descendantMatches(option, term) {
|
|
68
|
-
return childrenOf(option).some((child) => matches(child, term) || descendantMatches(child, term));
|
|
69
|
-
}
|
|
70
|
-
function placeOption(walk, option, place) {
|
|
71
|
-
const self = !place.filtered || matches(option, walk.term);
|
|
72
|
-
const below = place.filtered && descendantMatches(option, walk.term);
|
|
73
|
-
if (!self && !below) return null;
|
|
74
|
-
const branch = isBranch(option);
|
|
75
|
-
const openBySet = self && walk.open.has(option.value);
|
|
76
|
-
const open = branch && (openBySet || below);
|
|
77
|
-
walk.rows.push({
|
|
78
|
-
option,
|
|
79
|
-
branch,
|
|
80
|
-
open,
|
|
81
|
-
level: place.level,
|
|
82
|
-
parent: place.parent
|
|
83
|
-
});
|
|
84
|
-
return open ? {
|
|
85
|
-
level: place.level + 1,
|
|
86
|
-
parent: option.value,
|
|
87
|
-
filtered: place.filtered && !openBySet
|
|
88
|
-
} : null;
|
|
89
|
-
}
|
|
90
|
-
function walkRows(walk, list, place) {
|
|
91
|
-
for (const option of list) {
|
|
92
|
-
const childPlace = placeOption(walk, option, place);
|
|
93
|
-
if (childPlace) walkRows(walk, childrenOf(option), childPlace);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
function rtTreeRows(options, open, rawTerm = "") {
|
|
97
|
-
const term = rawTerm.toLowerCase().trim();
|
|
98
|
-
const walk = {
|
|
99
|
-
open,
|
|
100
|
-
term,
|
|
101
|
-
rows: []
|
|
102
|
-
};
|
|
103
|
-
walkRows(walk, options, {
|
|
104
|
-
level: 0,
|
|
105
|
-
parent: null,
|
|
106
|
-
filtered: term.length > 0
|
|
107
|
-
});
|
|
108
|
-
return walk.rows;
|
|
109
|
-
}
|
|
110
|
-
function sideRight(rows, row, index) {
|
|
111
|
-
if (row.branch && !row.open) return {
|
|
112
|
-
toggle: row.option.value,
|
|
113
|
-
index
|
|
114
|
-
};
|
|
115
|
-
return {
|
|
116
|
-
toggle: null,
|
|
117
|
-
index: row.branch && rows[index + 1]?.parent === row.option.value ? index + 1 : index
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
function sideLeft(rows, row, index) {
|
|
121
|
-
if (row.branch && row.open) return {
|
|
122
|
-
toggle: row.option.value,
|
|
123
|
-
index
|
|
124
|
-
};
|
|
125
|
-
const parentIndex = rows.findIndex((candidate) => candidate.option.value === row.parent);
|
|
126
|
-
return {
|
|
127
|
-
toggle: null,
|
|
128
|
-
index: parentIndex >= 0 ? parentIndex : index
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
function rtTreeSideKey(rows, index, key) {
|
|
132
|
-
const row = rows[index];
|
|
133
|
-
if (row && key === "ArrowRight") return sideRight(rows, row, index);
|
|
134
|
-
if (row && key === "ArrowLeft") return sideLeft(rows, row, index);
|
|
135
|
-
return {
|
|
136
|
-
toggle: null,
|
|
137
|
-
index
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
function rtTreeToggle(open, value) {
|
|
141
|
-
const next = new Set(open);
|
|
142
|
-
if (next.has(value)) next.delete(value);
|
|
143
|
-
else next.add(value);
|
|
144
|
-
return next;
|
|
145
|
-
}
|
|
146
15
|
var RtSelectTriggerDirective = class RtSelectTriggerDirective {
|
|
147
16
|
constructor() {
|
|
148
17
|
this.templateRef = inject(TemplateRef);
|
|
@@ -179,21 +48,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
179
48
|
}]
|
|
180
49
|
});
|
|
181
50
|
const BEM_BLOCK = "rt-select";
|
|
182
|
-
const OPEN_KEYS = /* @__PURE__ */ new Set([
|
|
183
|
-
"ArrowDown",
|
|
184
|
-
"ArrowUp",
|
|
185
|
-
"Enter",
|
|
186
|
-
" "
|
|
187
|
-
]);
|
|
188
51
|
let panelIdSeed = 0;
|
|
189
52
|
function nextPanelId() {
|
|
190
53
|
panelIdSeed += 1;
|
|
191
54
|
return panelIdSeed;
|
|
192
55
|
}
|
|
193
56
|
var RtSelectComponent = class RtSelectComponent extends RtFormControlBase {
|
|
194
|
-
#t_uiSearch;
|
|
195
57
|
constructor() {
|
|
196
|
-
super();
|
|
58
|
+
super(...arguments);
|
|
197
59
|
this.#t_uiSearch = rtKitLabel("uiSearch");
|
|
198
60
|
this.t = inject(RT_KIT_LABELS);
|
|
199
61
|
this.panelId = `rt-select-panel-${nextPanelId()}`;
|
|
@@ -201,10 +63,19 @@ var RtSelectComponent = class RtSelectComponent extends RtFormControlBase {
|
|
|
201
63
|
this.popover = viewChild.required(RtPopoverDirective, ...ngDevMode ? [{ debugName: "popover" }] : /* istanbul ignore next */ []);
|
|
202
64
|
this.triggerEl = viewChild("triggerEl", ...ngDevMode ? [{ debugName: "triggerEl" }] : /* istanbul ignore next */ []);
|
|
203
65
|
this.filterTerm = signal("", ...ngDevMode ? [{ debugName: "filterTerm" }] : /* istanbul ignore next */ []);
|
|
204
|
-
this.activeIndex = signal(-1, ...ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []);
|
|
205
66
|
this.openBranches = signal(/* @__PURE__ */ new Set(), ...ngDevMode ? [{ debugName: "openBranches" }] : /* istanbul ignore next */ []);
|
|
206
67
|
this.isOpen = computed(() => this.popover().isOpen(), ...ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []);
|
|
207
|
-
this.
|
|
68
|
+
this.optionList = new RtOptionList({
|
|
69
|
+
panelId: () => this.panelId,
|
|
70
|
+
isOpen: () => this.isOpen(),
|
|
71
|
+
count: () => this.rows().length,
|
|
72
|
+
isDisabled: (index) => Boolean(this.rows()[index]?.option.disabled),
|
|
73
|
+
chooseKeys: /* @__PURE__ */ new Set(["Enter", " "]),
|
|
74
|
+
sideKeys: true,
|
|
75
|
+
edgeKeys: true
|
|
76
|
+
});
|
|
77
|
+
this.activeIndex = this.optionList.activeIndex;
|
|
78
|
+
this.activeOptionId = this.optionList.activeOptionId;
|
|
208
79
|
this.triggerTpl = contentChild(RtSelectTriggerDirective, ...ngDevMode ? [{ debugName: "triggerTpl" }] : /* istanbul ignore next */ []);
|
|
209
80
|
this.hasValue = computed(() => this.value() !== null, ...ngDevMode ? [{ debugName: "hasValue" }] : /* istanbul ignore next */ []);
|
|
210
81
|
this.selectedLabel = computed(() => {
|
|
@@ -233,8 +104,8 @@ var RtSelectComponent = class RtSelectComponent extends RtFormControlBase {
|
|
|
233
104
|
this.panelWidth = input("trigger-min", ...ngDevMode ? [{ debugName: "panelWidth" }] : /* istanbul ignore next */ []);
|
|
234
105
|
this.panelMaxHeight = input(null, ...ngDevMode ? [{ debugName: "panelMaxHeight" }] : /* istanbul ignore next */ []);
|
|
235
106
|
this.selectionChange = output();
|
|
236
|
-
rtScrollActiveOptionIntoView(this.activeOptionId);
|
|
237
107
|
}
|
|
108
|
+
#t_uiSearch;
|
|
238
109
|
setDisabledState(disabled) {
|
|
239
110
|
super.setDisabledState(disabled);
|
|
240
111
|
if (disabled) this.popover().close();
|
|
@@ -281,38 +152,39 @@ var RtSelectComponent = class RtSelectComponent extends RtFormControlBase {
|
|
|
281
152
|
onTriggerKeydown(event) {
|
|
282
153
|
if (this.isDisabled()) return;
|
|
283
154
|
if (!this.isOpen()) {
|
|
284
|
-
if (
|
|
155
|
+
if (this.optionList.opensBy(event.key)) {
|
|
285
156
|
event.preventDefault();
|
|
286
157
|
this.popover().open();
|
|
287
|
-
if (this.activeIndex() < 0) this
|
|
158
|
+
if (this.activeIndex() < 0) this.optionList.move(1);
|
|
288
159
|
}
|
|
289
160
|
return;
|
|
290
161
|
}
|
|
291
162
|
this.#handleOpenKeydown(event);
|
|
292
163
|
}
|
|
293
164
|
#handleOpenKeydown(event) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
165
|
+
const action = this.optionList.actionOf(event.key);
|
|
166
|
+
if (action === "none") return;
|
|
167
|
+
event.preventDefault();
|
|
168
|
+
switch (action) {
|
|
169
|
+
case "next":
|
|
170
|
+
this.optionList.move(1);
|
|
298
171
|
break;
|
|
299
|
-
case "
|
|
300
|
-
|
|
301
|
-
this.#moveActive(-1);
|
|
172
|
+
case "previous":
|
|
173
|
+
this.optionList.move(-1);
|
|
302
174
|
break;
|
|
303
|
-
case "
|
|
304
|
-
|
|
305
|
-
|
|
175
|
+
case "first":
|
|
176
|
+
this.optionList.first();
|
|
177
|
+
break;
|
|
178
|
+
case "last":
|
|
179
|
+
this.optionList.last();
|
|
180
|
+
break;
|
|
181
|
+
case "choose":
|
|
306
182
|
this.#selectActive();
|
|
307
183
|
break;
|
|
308
|
-
case "
|
|
309
|
-
event.preventDefault();
|
|
184
|
+
case "close":
|
|
310
185
|
this.popover().close();
|
|
311
186
|
break;
|
|
312
|
-
case "
|
|
313
|
-
case "ArrowLeft":
|
|
314
|
-
event.preventDefault();
|
|
315
|
-
this.#sideKey(event.key);
|
|
187
|
+
case "side": this.#sideKey(event.key);
|
|
316
188
|
}
|
|
317
189
|
}
|
|
318
190
|
#sideKey(key) {
|
|
@@ -321,21 +193,6 @@ var RtSelectComponent = class RtSelectComponent extends RtFormControlBase {
|
|
|
321
193
|
if (toggle !== null) this.openBranches.update((open) => rtTreeToggle(open, toggle));
|
|
322
194
|
this.activeIndex.set(answer.index);
|
|
323
195
|
}
|
|
324
|
-
#moveActive(delta) {
|
|
325
|
-
const opts = this.rows().map((row) => row.option);
|
|
326
|
-
if (opts.length === 0) {
|
|
327
|
-
this.activeIndex.set(-1);
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
let index = this.activeIndex();
|
|
331
|
-
for (let step = 0; step < opts.length; step += 1) {
|
|
332
|
-
index = (index + delta + opts.length) % opts.length;
|
|
333
|
-
if (!opts[index].disabled) {
|
|
334
|
-
this.activeIndex.set(index);
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
196
|
#selectActive() {
|
|
340
197
|
const opts = this.rows().map((row) => row.option);
|
|
341
198
|
const index = this.activeIndex();
|
|
@@ -347,7 +204,7 @@ var RtSelectComponent = class RtSelectComponent extends RtFormControlBase {
|
|
|
347
204
|
version: "22.2.2",
|
|
348
205
|
ngImport: i0,
|
|
349
206
|
type: RtSelectComponent,
|
|
350
|
-
deps:
|
|
207
|
+
deps: null,
|
|
351
208
|
target: i0.ɵɵFactoryTarget.Component
|
|
352
209
|
});
|
|
353
210
|
}
|
|
@@ -639,7 +496,6 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
639
496
|
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-select{--rt-select-radius: var(--rt-input-radius);--rt-select-fill-radius: var(--rt-radius-sm);--rt-select-caret-transition-duration: var(--rt-duration-fast);--rt-select-own-outline-width: var(--rt-border-width-medium);position:relative;display:block;width:100%}.rt-select--borderless .rt-select__trigger{border-color:transparent}.rt-select--appearance--fill .rt-select__trigger{border-color:transparent;border-radius:var(--rt-select-fill-radius) var(--rt-select-fill-radius) 0 0;border-bottom-color:var(--rt-color-field-fill-underline);background-color:var(--rt-color-bg-surface-subtle-2)}.rt-select__trigger{display:flex;width:100%;min-height:var(--rt-input-height);box-sizing:border-box;align-items:center;padding:var(--rt-input-padding-y) var(--rt-input-padding-x);border:var(--rt-input-border-width) solid var(--rt-input-color-border);border-radius:var(--rt-select-radius);background-color:var(--rt-input-color-bg);color:var(--rt-input-color-text);cursor:pointer;font-family:inherit;font-size:var(--rt-input-font-size);gap:var(--rt-space-sm);line-height:var(--rt-input-line-height);text-align:start;transition:var(--rt-input-transition)}.rt-select__trigger:focus{border-color:var(--rt-input-color-border-focus);box-shadow:var(--rt-input-focus-shadow);outline:2px solid transparent;outline-offset:var(--rt-input-focus-outline-offset)}.rt-select__trigger:disabled{cursor:not-allowed}.rt-select__trigger--own{width:auto;min-height:0;padding:0;border-color:transparent;background-color:transparent;line-height:var(--rt-leading-none)}.rt-select__trigger--own:focus{border-color:transparent;box-shadow:none}.rt-select__trigger--own:focus-visible{outline:var(--rt-select-own-outline-width) solid var(--rt-input-color-border-focus);outline-offset:var(--rt-input-focus-outline-offset)}.rt-select--open .rt-select__trigger{border-color:var(--rt-input-color-border-focus)}.rt-select--open .rt-select__trigger--own{border-color:transparent}.rt-select--invalid .rt-select__trigger{border-color:var(--rt-input-color-border-error)}.rt-select--invalid .rt-select__trigger:focus{box-shadow:var(--rt-input-focus-shadow-error)}.rt-select--invalid .rt-select__trigger--own{border-color:transparent}.rt-select--invalid .rt-select__trigger--own:focus{box-shadow:none}.rt-select--disabled{opacity:var(--rt-input-disabled-opacity)}.rt-select--readonly .rt-select__trigger{display:none}.rt-select__readonly{display:inline-flex;min-height:var(--rt-input-height);align-items:center;color:var(--rt-field-value-color);font-size:var(--rt-field-value-font-size)}.rt-select__readonly--empty{color:var(--rt-field-value-empty-color)}.rt-select--size--sm .rt-select__trigger{min-height:var(--rt-input-height-sm)}.rt-select--size--lg .rt-select__trigger{min-height:var(--rt-input-height-lg)}.rt-select__label{overflow:hidden;min-width:0;flex:1 1 auto;text-overflow:ellipsis;white-space:nowrap}.rt-select__label--placeholder{color:var(--rt-input-color-text-placeholder)}.rt-select__icon-left,.rt-select__clear{flex-shrink:0}.rt-select__chevron{flex-shrink:0;transition:transform var(--rt-select-caret-transition-duration) ease}.rt-select--open .rt-select__chevron{transform:rotate(180deg)}:is(.rt-preset-material,[data-preset=material]) .rt-select__chevron{max-width:10px;max-height:5px;background-color:currentcolor;clip-path:polygon(0 0,100% 0,50% 100%);transform:none}:is(.rt-preset-material,[data-preset=material]) .rt-select__chevron svg{display:none}.rt-select__panel{--rt-select-panel-shadow: var(--rt-overlay-select-shadow);--rt-select-panel-radius: var(--rt-overlay-select-radius);--rt-select-option-font-size: var(--rt-overlay-select-option-font-size);--rt-select-selected-bg: var(--rt-overlay-select-selected-bg);--rt-select-selected-weight: var(--rt-overlay-select-selected-weight);--rt-select-check-display: var(--rt-overlay-select-check-display);--rt-select-option-min-height: var(--rt-overlay-select-option-min-height);--rt-select-panel-border-width: var(--rt-overlay-select-panel-border-width);--rt-select-tree-indent: var(--rt-space-lg);--rt-select-panel-max-height: var(--rt-input-panel-max-height);width:100%;max-height:var(--rt-select-panel-max-height);box-sizing:border-box;border:var(--rt-select-panel-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-select-panel-radius);background-color:var(--rt-color-bg-surface);box-shadow:var(--rt-select-panel-shadow);overflow-y:auto}.rt-select__filter{padding:var(--rt-space-sm);border-block-end:var(--rt-input-border-width) solid var(--rt-color-border-subtle)}.rt-select__list{padding:var(--rt-space-2xs) 0;margin:0;list-style:none}.rt-select__option{--rt-select-tree-level: 0;display:flex;min-height:var(--rt-select-option-min-height);box-sizing:border-box;align-items:center;justify-content:space-between;padding:var(--rt-space-sm) var(--rt-space-md);color:var(--rt-color-text-primary);cursor:pointer;font-size:var(--rt-select-option-font-size);gap:var(--rt-space-sm);padding-inline-start:calc(var(--rt-space-md) + var(--rt-select-tree-indent) * var(--rt-select-tree-level))}.rt-select__option:hover,.rt-select__option--active{background-color:var(--rt-color-bg-hover)}.rt-select__option--selected{background-color:var(--rt-select-selected-bg);font-weight:var(--rt-select-selected-weight)}.rt-select__option--disabled{cursor:not-allowed;opacity:var(--rt-input-disabled-opacity)}.rt-select__option--disabled:hover{background-color:transparent}.rt-select__option-label{min-width:0;flex:1 1 auto}.rt-select__toggle,.rt-select__toggle-space{display:inline-flex;flex-shrink:0;block-size:var(--rt-input-icon-size);inline-size:var(--rt-input-icon-size)}.rt-select__toggle{align-items:center;justify-content:center;padding:0;border:0;background:transparent;cursor:pointer}.rt-select__check{display:var(--rt-select-check-display);flex-shrink:0}.rt-select__empty{padding:var(--rt-space-sm) var(--rt-space-md);color:var(--rt-input-color-text-placeholder);font-style:italic}.rt-select[data-rt-radius=none]{--rt-select-radius: var(--rt-radius-none)}.rt-select[data-rt-radius=xs]{--rt-select-radius: var(--rt-radius-xs)}.rt-select[data-rt-radius=sm]{--rt-select-radius: var(--rt-radius-sm)}.rt-select[data-rt-radius=ms]{--rt-select-radius: var(--rt-radius-ms)}.rt-select[data-rt-radius=md]{--rt-select-radius: var(--rt-radius-md)}.rt-select[data-rt-radius=lg]{--rt-select-radius: var(--rt-radius-lg)}.rt-select[data-rt-radius=xl]{--rt-select-radius: var(--rt-radius-xl)}.rt-select[data-rt-radius=\"2xl\"]{--rt-select-radius: var(--rt-radius-2xl)}.rt-select[data-rt-radius=full]{--rt-select-radius: var(--rt-radius-full)}}\n"]
|
|
640
497
|
}]
|
|
641
498
|
}],
|
|
642
|
-
ctorParameters: () => [],
|
|
643
499
|
propDecorators: {
|
|
644
500
|
popover: [{
|
|
645
501
|
type: i0.ViewChild,
|
|
@@ -723,6 +579,6 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
723
579
|
}]
|
|
724
580
|
}
|
|
725
581
|
});
|
|
726
|
-
export { RtSelectComponent, RtSelectTriggerDirective
|
|
582
|
+
export { RtSelectComponent, RtSelectTriggerDirective };
|
|
727
583
|
|
|
728
584
|
//# sourceMappingURL=rt-tools-ui-kit-v2-select.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rt-tools-ui-kit-v2-select.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/select/rt-select-active-option.ts","../../../projects/ui-kit-v2/src/lib/components/select/rt-select-tree.ts","../../../projects/ui-kit-v2/src/lib/components/select/rt-select-trigger.directive.ts","../../../projects/ui-kit-v2/src/lib/components/select/rt-select.component.ts","../../../projects/ui-kit-v2/src/lib/components/select/rt-select.component.html"],"sourcesContent":["import { DOCUMENT } from '@angular/common';\nimport { afterRenderEffect, inject } from '@angular/core';\n\n/**\n * Держит подсвеченную клавишами опцию в видимой части панели.\n *\n * Панель списка ограничена по высоте, и длинный список прокручивается внутри неё. Клавиши двигают\n * подсветку, но фокус остаётся на поле: браузер сам панель не прокручивает, и подсветка уходила\n * за нижний край — человек выбирал Enter'ом то, чего не видел. После каждой отрисовки, в которой\n * сменилась подсвеченная опция, она прокручивается ровно настолько, чтобы встать в панель.\n *\n * Панель рисуется в наложении, вне поддерева семьи, поэтому опция ищется в документе по своему\n * идентификатору — тому же, что стоит в `aria-activedescendant`. На сервере отрисовки нет, и\n * эффект не выполняется; среда без `scrollIntoView` пропускается.\n *\n * Зовётся в контексте внедрения — полем или конструктором семьи.\n *\n * @param activeOptionId идентификатор подсвеченной опции; `null` — подсветки нет или панель закрыта\n */\nexport function rtScrollActiveOptionIntoView(activeOptionId: () => string | null): void {\n const document: Document = inject(DOCUMENT);\n\n afterRenderEffect((): void => {\n const id: string | null = activeOptionId();\n const option: HTMLElement | null = id ? document.getElementById(id) : null;\n\n if (typeof option?.scrollIntoView === 'function') {\n option.scrollIntoView({ block: 'nearest' });\n }\n });\n}\n","import { IRtSelect } from './rt-select.model';\n\n/**\n * Дерево опций выбора из списка — общее для `rt-select` и `rt-multiselect`.\n *\n * Обе семьи раскладывают, ищут и считают дерево одинаково, поэтому это чистые функции в одном\n * месте: две копии разошлись бы на первой правке. Состояние — какие ветки раскрыты — живёт в семье,\n * здесь только расчёт по нему.\n */\n\ntype TOption<TValue> = IRtSelect.Option<TValue>;\ntype TRow<TValue> = IRtSelect.Row<TValue>;\n\nfunction childrenOf<TValue>(option: TOption<TValue>): ReadonlyArray<TOption<TValue>> {\n return option.children ?? [];\n}\n\nfunction isBranch<TValue>(option: TOption<TValue>): boolean {\n return childrenOf(option).length > 0;\n}\n\n/** Список — дерево, если хоть у одной опции есть дети. Плоский список рисуется как прежде. */\nexport function rtTreeIsTree<TValue>(options: ReadonlyArray<TOption<TValue>>): boolean {\n return options.some((option: TOption<TValue>): boolean => isBranch(option));\n}\n\n/** Опция по значению на любой глубине. */\nexport function rtTreeFind<TValue>(options: ReadonlyArray<TOption<TValue>>, value: TValue): TOption<TValue> | undefined {\n for (const option of options) {\n if (option.value === value) {\n return option;\n }\n const found: TOption<TValue> | undefined = rtTreeFind(childrenOf(option), value);\n if (found) {\n return found;\n }\n }\n return undefined;\n}\n\n/**\n * Включённые листья под опцией; у самого листа — он сам. Отключённая ветка не отдаёт никого: её\n * листья выбрать нельзя, как и её саму.\n */\nexport function rtTreeLeaves<TValue>(option: TOption<TValue>): ReadonlyArray<TValue> {\n if (option.disabled) {\n return [];\n }\n if (!isBranch(option)) {\n return [option.value];\n }\n return childrenOf(option).flatMap((child: TOption<TValue>): ReadonlyArray<TValue> => rtTreeLeaves(child));\n}\n\n/** Сколько включённых листьев ветки выбрано. Флажок ветки выводится из этого, а не хранится. */\nexport function rtTreeBranchState<TValue>(option: TOption<TValue>, chosen: ReadonlyArray<TValue>): IRtSelect.TBranchState {\n const leaves: ReadonlyArray<TValue> = rtTreeLeaves(option);\n const count: number = leaves.filter((leaf: TValue): boolean => chosen.includes(leaf)).length;\n if (count === 0) {\n return 'none';\n }\n return count === leaves.length ? 'all' : 'some';\n}\n\nfunction holdsChosen<TValue>(option: TOption<TValue>, chosen: ReadonlyArray<TValue>): boolean {\n return childrenOf(option).some((child: TOption<TValue>): boolean => chosen.includes(child.value) || holdsChosen(child, chosen));\n}\n\nfunction collectOpen<TValue>(list: ReadonlyArray<TOption<TValue>>, chosen: ReadonlyArray<TValue>, open: Set<TValue>): void {\n for (const option of list) {\n if (holdsChosen(option, chosen)) {\n open.add(option.value);\n collectOpen(childrenOf(option), chosen, open);\n }\n }\n}\n\n/** Ветки, под которыми лежит выбранное значение: они раскрыты, когда список открывается. */\nexport function rtTreeOpenFor<TValue>(options: ReadonlyArray<TOption<TValue>>, chosen: ReadonlyArray<TValue>): ReadonlySet<TValue> {\n const open: Set<TValue> = new Set<TValue>();\n collectOpen(options, chosen, open);\n return open;\n}\n\nfunction matches<TValue>(option: TOption<TValue>, term: string): boolean {\n return option.label.toLowerCase().includes(term);\n}\n\nfunction descendantMatches<TValue>(option: TOption<TValue>, term: string): boolean {\n return childrenOf(option).some((child: TOption<TValue>): boolean => matches(child, term) || descendantMatches(child, term));\n}\n\ninterface ITreeWalk<TValue> {\n readonly open: ReadonlySet<TValue>;\n readonly term: string;\n readonly rows: TRow<TValue>[];\n}\n\ninterface IRowPlace<TValue> {\n readonly level: number;\n readonly parent: TValue | null;\n readonly filtered: boolean;\n}\n\n/**\n * Раскладка одной опции: кладёт её строку и отвечает, где раскладывать её детей, или `null`, если\n * их не видно. `filtered` — действует ли поисковое слово на уровень: под веткой, совпавшей самой и\n * раскрытой, дети идут все, как без поиска.\n */\nfunction placeOption<TValue>(walk: ITreeWalk<TValue>, option: TOption<TValue>, place: IRowPlace<TValue>): IRowPlace<TValue> | null {\n const self: boolean = !place.filtered || matches(option, walk.term);\n const below: boolean = place.filtered && descendantMatches(option, walk.term);\n if (!self && !below) {\n return null;\n }\n const branch: boolean = isBranch(option);\n const openBySet: boolean = self && walk.open.has(option.value);\n const open: boolean = branch && (openBySet || below);\n walk.rows.push({ option, branch, open, level: place.level, parent: place.parent });\n return open ? { level: place.level + 1, parent: option.value, filtered: place.filtered && !openBySet } : null;\n}\n\nfunction walkRows<TValue>(walk: ITreeWalk<TValue>, list: ReadonlyArray<TOption<TValue>>, place: IRowPlace<TValue>): void {\n for (const option of list) {\n const childPlace: IRowPlace<TValue> | null = placeOption(walk, option, place);\n if (childPlace) {\n walkRows(walk, childrenOf(option), childPlace);\n }\n }\n}\n\n/**\n * Видимые строки по уровням. Без поискового слова раскрыты ветки из `open`. Со словом строка\n * остаётся, если совпала она сама или кто-то под ней, и путь к совпадению показан раскрытым.\n * Ветка, совпавшая сама, держит детей такими, какими они были.\n */\nexport function rtTreeRows<TValue>(\n options: ReadonlyArray<TOption<TValue>>,\n open: ReadonlySet<TValue>,\n rawTerm: string = ''\n): ReadonlyArray<TRow<TValue>> {\n const term: string = rawTerm.toLowerCase().trim();\n const walk: ITreeWalk<TValue> = { open, term, rows: [] };\n walkRows(walk, options, { level: 0, parent: null, filtered: term.length > 0 });\n return walk.rows;\n}\n\nfunction sideRight<TValue>(rows: ReadonlyArray<TRow<TValue>>, row: TRow<TValue>, index: number): IRtSelect.SideKeyAnswer<TValue> {\n if (row.branch && !row.open) {\n return { toggle: row.option.value, index };\n }\n const firstChild: boolean = row.branch && rows[index + 1]?.parent === row.option.value;\n return { toggle: null, index: firstChild ? index + 1 : index };\n}\n\nfunction sideLeft<TValue>(rows: ReadonlyArray<TRow<TValue>>, row: TRow<TValue>, index: number): IRtSelect.SideKeyAnswer<TValue> {\n if (row.branch && row.open) {\n return { toggle: row.option.value, index };\n }\n const parentIndex: number = rows.findIndex((candidate: TRow<TValue>): boolean => candidate.option.value === row.parent);\n return { toggle: null, index: parentIndex >= 0 ? parentIndex : index };\n}\n\n/**\n * Ответ на боковую стрелку. Вправо: свёрнутая ветка раскрывается, раскрытая уводит подсветку на\n * первого ребёнка. Влево: раскрытая ветка сворачивается, иначе подсветка уходит на родителя.\n */\nexport function rtTreeSideKey<TValue>(rows: ReadonlyArray<TRow<TValue>>, index: number, key: string): IRtSelect.SideKeyAnswer<TValue> {\n const row: TRow<TValue> | undefined = rows[index];\n if (row && key === 'ArrowRight') {\n return sideRight(rows, row, index);\n }\n if (row && key === 'ArrowLeft') {\n return sideLeft(rows, row, index);\n }\n return { toggle: null, index };\n}\n\n/** Набор раскрытых веток с переключённой одной. */\nexport function rtTreeToggle<TValue>(open: ReadonlySet<TValue>, value: TValue): ReadonlySet<TValue> {\n const next: Set<TValue> = new Set<TValue>(open);\n if (next.has(value)) {\n next.delete(value);\n } else {\n next.add(value);\n }\n return next;\n}\n","import { Directive, inject, TemplateRef } from '@angular/core';\n\nimport { IRtSelect } from './rt-select.model';\n\n/**\n * Маркер своей разметки указателя — того, что человек нажимает, чтобы открыть список.\n *\n * Поведение указателя остаётся киту: открытие панели, её ширина, приметы доступности,\n * отключённость, клавиши и закрытие висят на кнопке. Потребитель даёт только то, что рисуется\n * внутри неё, и получает три значения обстановки: открыт ли список, что выбрано, отключён ли выбор.\n *\n * Один маркер на обе семьи выбора: они отличаются только разметкой внутри кнопки, и два маркера\n * разошлись бы на первой же правке.\n *\n * @example\n * ```html\n * <rt-select [options]=\"options\">\n * <ng-template rtSelectTrigger let-state>\n * <rt-tag [value]=\"state.label\" [icon]=\"state.isOpen ? 'chevron-up' : 'chevron-down'\" />\n * </ng-template>\n * </rt-select>\n * ```\n */\n@Directive({\n selector: '[rtSelectTrigger]',\n})\nexport class RtSelectTriggerDirective<TValue = unknown> {\n public readonly templateRef: TemplateRef<IRtSelect.TriggerContext<TValue>> =\n inject<TemplateRef<IRtSelect.TriggerContext<TValue>>>(TemplateRef);\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n computed,\n contentChild,\n forwardRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n InputSignal,\n InputSignalWithTransform,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RT_KIT_LABELS, TRtKitLabelMap, rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RtFormControlBase } from '@rt-tools/ui-kit-v2/form-control';\nimport { IRtInput } from '@rt-tools/ui-kit-v2/core';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtInputComponent } from '@rt-tools/ui-kit-v2/input';\nimport { RtPopoverDirective } from '@rt-tools/ui-kit-v2/popover';\nimport { IRtPopover } from '@rt-tools/ui-kit-v2/popover';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { rtScrollActiveOptionIntoView } from './rt-select-active-option';\nimport { rtTreeFind, rtTreeIsTree, rtTreeOpenFor, rtTreeRows, rtTreeSideKey, rtTreeToggle } from './rt-select-tree';\nimport { RtSelectTriggerDirective } from './rt-select-trigger.directive';\nimport { IRtSelect } from './rt-select.model';\n\nconst BEM_BLOCK: string = 'rt-select';\n\n/** Клавиши, открывающие закрытый dropdown с фокуса на trigger'е. */\nconst OPEN_KEYS: ReadonlySet<string> = new Set<string>(['ArrowDown', 'ArrowUp', 'Enter', ' ']);\n\ntype TBooleanInput = boolean | string;\n\nlet panelIdSeed: number = 0;\n\nfunction nextPanelId(): number {\n panelIdSeed += 1;\n return panelIdSeed;\n}\n\n/**\n * Single-select dropdown с опциональным filter input.\n *\n * Panel рендерится через CDK Overlay (директива `[rtPopover]` на trigger'е) —\n * не обрезается `overflow: hidden` предками (таблицы, aside, карточки) и\n * авто-flip'ается у края viewport. CVA через общий `RtFormControlBase`. Крестик\n * (`clearable`) слева от шеврона — виден при наличии значения, очищает выбор.\n *\n * Keyboard-nav (activedescendant): фокус на trigger'е, ArrowUp/Down двигают\n * виртуальный highlight (`aria-activedescendant`), Enter выбирает, Escape\n * закрывает. Home/End/typeahead — deferred.\n */\n@Component({\n selector: 'rt-select',\n templateUrl: './rt-select.component.html',\n styleUrl: './rt-select.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n FormsModule,\n NgTemplateOutlet,\n\n // standalone components / directives\n RtIconButtonComponent,\n RtIconComponent,\n RtInputComponent,\n RtPopoverDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n providers: [\n // Алиас базового токена — для contentChild(RtFormControlBase) в rt-field.\n { provide: RtFormControlBase, useExisting: forwardRef(() => RtSelectComponent) },\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n '[class.rt-select--open]': 'isOpen()',\n '[class.rt-select--disabled]': 'isDisabled()',\n '[class.rt-select--readonly]': 'isReadonly()',\n '[class.rt-select--invalid]': 'isInvalid()',\n '[class.rt-select--borderless]': '!bordered()',\n '[class.rt-select--appearance--fill]': \"appearance() === 'fill'\",\n '[class.rt-select--size--sm]': \"size() === 'sm'\",\n '[class.rt-select--size--lg]': \"size() === 'lg'\",\n '[class.rt-select--with-icon-left]': '!!iconLeft()',\n },\n})\nexport class RtSelectComponent<TValue> extends RtFormControlBase<TValue | null> {\n readonly #t_uiSearch: Signal<string> = rtKitLabel('uiSearch');\n\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly panelId: string = `rt-select-panel-${nextPanelId()}`;\n\n protected readonly filterPlaceholderText: Signal<string> = computed((): string => this.filterPlaceholder() || this.#t_uiSearch());\n\n protected readonly popover: Signal<RtPopoverDirective> = viewChild.required(RtPopoverDirective);\n\n protected readonly triggerEl: Signal<ElementRef<HTMLButtonElement> | undefined> = viewChild<ElementRef<HTMLButtonElement>>('triggerEl');\n\n protected readonly filterTerm: WritableSignal<string> = signal<string>('');\n protected readonly activeIndex: WritableSignal<number> = signal<number>(-1);\n /** Раскрытые ветки дерева. Живут, пока открыта панель: при открытии раскрыты ветки над выбранным. */\n protected readonly openBranches: WritableSignal<ReadonlySet<TValue>> = signal<ReadonlySet<TValue>>(new Set<TValue>());\n\n protected readonly isOpen: Signal<boolean> = computed((): boolean => this.popover().isOpen());\n\n /** Идентификатор подсвеченной опции — тот же, что уходит в `aria-activedescendant`. */\n protected readonly activeOptionId: Signal<string | null> = computed((): string | null =>\n this.isOpen() && this.activeIndex() >= 0 ? `${this.panelId}-opt-${this.activeIndex()}` : null\n );\n\n /**\n * Своя разметка указателя, если потребитель её объявил. Не объявил — кит рисует свою, и ни один\n * нынешний потребитель не двигается.\n */\n protected readonly triggerTpl: Signal<RtSelectTriggerDirective<TValue> | undefined> = contentChild(RtSelectTriggerDirective);\n\n protected readonly hasValue: Signal<boolean> = computed((): boolean => this.value() !== null);\n\n protected readonly selectedLabel: Signal<string> = computed((): string => {\n const v: TValue | null = this.value();\n if (v === null) {\n return '';\n }\n return rtTreeFind(this.options(), v)?.label ?? '';\n });\n\n /** Дерево ли список: тогда у строк есть место под стрелку и отступ по уровню. */\n protected readonly isTree: Signal<boolean> = computed((): boolean => rtTreeIsTree(this.options()));\n\n /** Видимые строки: плоский список — как прежде, дерево — по раскрытым веткам и поисковому слову. */\n protected readonly rows: Signal<ReadonlyArray<IRtSelect.Row<TValue>>> = computed((): ReadonlyArray<IRtSelect.Row<TValue>> =>\n rtTreeRows(this.options(), this.openBranches(), this.filterTerm())\n );\n\n /** Три значения, которые кит отдаёт своей разметке указателя, и не больше. */\n protected readonly triggerState: Signal<IRtSelect.TriggerState<TValue>> = computed((): IRtSelect.TriggerState<TValue> => ({\n isOpen: this.isOpen(),\n value: this.value(),\n label: this.selectedLabel(),\n isDisabled: this.isDisabled(),\n }));\n\n /** Вид рамки: `outline` — рамка со всех сторон, `fill` — залитое поле с чертой снизу. */\n public readonly appearance: InputSignal<IRtInput.Appearance> = input<IRtInput.Appearance>('outline');\n\n public readonly displayText: Signal<string> = computed((): string => this.selectedLabel());\n\n public readonly options: InputSignal<ReadonlyArray<IRtSelect.Option<TValue>>> = input<ReadonlyArray<IRtSelect.Option<TValue>>>([]);\n\n public readonly placeholder: InputSignal<string> = input<string>('');\n\n public readonly iconLeft: InputSignal<IRtIcon.Name | null> = input<IRtIcon.Name | null>(null);\n\n public readonly filter: InputSignalWithTransform<boolean, TBooleanInput> = input<boolean, TBooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Пусто — берётся переведённая подпись по умолчанию */\n public readonly filterPlaceholder: InputSignal<string> = input<string>('');\n\n /**\n * Чем мерится панель. По умолчанию она не уже кнопки и дальше растёт по содержимому:\n * со своим указателем кнопка бывает узкой, и панель по её ширине давила бы содержимое.\n * `trigger` возвращает прежнее — ровно по кнопке, `auto` пускает панель по содержимому\n * целиком. Предел высоты назначается входом `panelMaxHeight`.\n */\n public readonly panelWidth: InputSignal<IRtPopover.Width> = input<IRtPopover.Width>('trigger-min');\n\n /**\n * Предел высоты панели — длина как в стилях, например `20rem`. Пусто — предел кита\n * `--rt-input-panel-max-height`, и длинный список прокручивается внутри панели: без предела\n * он уходил за нижний край экрана, и пункты за краем были недостижимы. `none` снимает предел —\n * для короткого списка, который должен открываться целиком, без прокрутки. Значение ставится\n * на саму панель: она рисуется в наложении, вне поддерева блока.\n */\n public readonly panelMaxHeight: InputSignal<string | null> = input<string | null>(null);\n\n public readonly selectionChange: OutputEmitterRef<TValue | null> = output<TValue | null>();\n\n constructor() {\n super();\n // Подсветка, сдвинутая клавишами, не уходит за край панели с пределом высоты.\n rtScrollActiveOptionIntoView(this.activeOptionId);\n }\n\n public override setDisabledState(disabled: boolean): void {\n super.setDisabledState(disabled);\n if (disabled) {\n this.popover().close();\n }\n }\n\n protected getEmptyValue(): TValue | null {\n return null;\n }\n\n protected focusAfterClear(): void {\n this.triggerEl()?.nativeElement.focus();\n }\n\n protected override clear(event?: Event): void {\n if (this.isDisabled()) {\n return;\n }\n super.clear(event);\n this.selectionChange.emit(null);\n }\n\n /**\n * Открытый список встаёт подсветкой на выбранный пункт.\n *\n * Иначе стрелка вниз начинала с первого пункта, и человек с выбранным «20» из «10, 20, 40»\n * получал «10» вместо «40».\n */\n protected onOpened(): void {\n const v: TValue | null = this.value();\n this.openBranches.set(rtTreeOpenFor(this.options(), v === null ? [] : [v]));\n if (v !== null) {\n const chosen: number = this.rows().findIndex((row: IRtSelect.Row<TValue>): boolean => row.option.value === v);\n if (chosen >= 0) {\n this.activeIndex.set(chosen);\n }\n }\n }\n\n protected toggleBranch(event: Event, value: TValue): void {\n event.stopPropagation();\n this.openBranches.update((open: ReadonlySet<TValue>): ReadonlySet<TValue> => rtTreeToggle(open, value));\n }\n\n protected onClosed(): void {\n // Закрытие (outside-click / Escape / выбор) = пользователь увёл фокус.\n this.filterTerm.set('');\n this.activeIndex.set(-1);\n this.markTouched();\n }\n\n protected select(opt: IRtSelect.Option<TValue>): void {\n if (opt.disabled) {\n return;\n }\n this.value.set(opt.value);\n this.emitChange(opt.value);\n this.selectionChange.emit(opt.value);\n this.popover().close();\n }\n\n protected setFilter(term: string): void {\n this.filterTerm.set(term);\n this.activeIndex.set(-1);\n }\n\n protected onTriggerKeydown(event: KeyboardEvent): void {\n if (this.isDisabled()) {\n return;\n }\n if (!this.isOpen()) {\n if (OPEN_KEYS.has(event.key)) {\n event.preventDefault();\n this.popover().open();\n if (this.activeIndex() < 0) {\n this.#moveActive(1);\n }\n }\n return;\n }\n this.#handleOpenKeydown(event);\n }\n\n #handleOpenKeydown(event: KeyboardEvent): void {\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.#moveActive(1);\n break;\n case 'ArrowUp':\n event.preventDefault();\n this.#moveActive(-1);\n break;\n case 'Enter':\n case ' ':\n event.preventDefault();\n this.#selectActive();\n break;\n case 'Escape':\n event.preventDefault();\n this.popover().close();\n break;\n case 'ArrowRight':\n case 'ArrowLeft':\n event.preventDefault();\n this.#sideKey(event.key);\n break;\n default:\n break;\n }\n }\n\n #sideKey(key: string): void {\n const answer: IRtSelect.SideKeyAnswer<TValue> = rtTreeSideKey(this.rows(), this.activeIndex(), key);\n const toggle: TValue | null = answer.toggle;\n if (toggle !== null) {\n this.openBranches.update((open: ReadonlySet<TValue>): ReadonlySet<TValue> => rtTreeToggle(open, toggle));\n }\n this.activeIndex.set(answer.index);\n }\n\n #moveActive(delta: number): void {\n const opts: ReadonlyArray<IRtSelect.Option<TValue>> = this.rows().map(\n (row: IRtSelect.Row<TValue>): IRtSelect.Option<TValue> => row.option\n );\n if (opts.length === 0) {\n this.activeIndex.set(-1);\n return;\n }\n let index: number = this.activeIndex();\n for (let step: number = 0; step < opts.length; step += 1) {\n index = (index + delta + opts.length) % opts.length;\n if (!opts[index].disabled) {\n this.activeIndex.set(index);\n return;\n }\n }\n }\n\n #selectActive(): void {\n const opts: ReadonlyArray<IRtSelect.Option<TValue>> = this.rows().map(\n (row: IRtSelect.Row<TValue>): IRtSelect.Option<TValue> => row.option\n );\n const index: number = this.activeIndex();\n if (index >= 0 && index < opts.length) {\n this.select(opts[index]);\n }\n }\n}\n","<ng-container rtBlock=\"rt-select\">\n @if (isReadonly()) {\n <span rtElem=\"readonly\" [rtMod]=\"{ empty: !displayText() }\">{{ displayText() || '—' }}</span>\n }\n <button\n #triggerEl\n rtElem=\"trigger\"\n qa-dataid=\"select-trigger\"\n type=\"button\"\n [rtPopoverWidth]=\"panelWidth()\"\n [rtMod]=\"{ own: !!triggerTpl() }\"\n [rtPopover]=\"panelTpl\"\n [rtPopoverDisabled]=\"isDisabled()\"\n [attr.id]=\"effectiveControlId()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-invalid]=\"isInvalid() || null\"\n [attr.aria-controls]=\"panelId\"\n [attr.aria-activedescendant]=\"activeOptionId()\"\n [disabled]=\"isDisabled()\"\n (keydown)=\"onTriggerKeydown($event)\"\n (rtPopoverOpened)=\"onOpened()\"\n (rtPopoverClosed)=\"onClosed()\">\n <!--\n Разметка указателя: своя, если потребитель её объявил, иначе зашитая китом. Она встаёт\n внутрь кнопки, а не вместо неё: поведение — открытие панели, приметы доступности,\n отключённость, клавиши и закрытие — остаётся на кнопке кита.\n -->\n @if (triggerTpl(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.templateRef\" [ngTemplateOutletContext]=\"{ $implicit: triggerState() }\" />\n } @else {\n @if (iconLeft(); as left) {\n <rt-icon rtElem=\"icon-left\" size=\"sm\" color=\"muted\" [name]=\"left\" />\n }\n <span rtElem=\"label\" [rtMod]=\"{ placeholder: !selectedLabel() }\">\n {{ selectedLabel() || placeholder() }}\n </span>\n @if (showClearButton()) {\n <rt-icon-button\n rtElem=\"clear\"\n icon=\"ico-close\"\n size=\"sm\"\n variant=\"ghost\"\n iconColor=\"muted\"\n [ariaLabel]=\"t().uiClear\"\n [tabIndex]=\"-1\"\n (clicked)=\"clear($event)\" />\n }\n <rt-icon rtElem=\"chevron\" name=\"chevron-down\" size=\"sm\" color=\"muted\" />\n }\n </button>\n\n <ng-template #panelTpl>\n <div rtElem=\"panel\" role=\"listbox\" [style.--rt-select-panel-max-height]=\"panelMaxHeight()\" [attr.aria-label]=\"ariaLabel()\">\n @if (filter()) {\n <div rtElem=\"filter\">\n <rt-input\n iconLeft=\"ico-search\"\n [placeholder]=\"filterPlaceholderText()\"\n [ngModel]=\"filterTerm()\"\n (ngModelChange)=\"setFilter($event)\" />\n </div>\n }\n <!--\n Опции listbox'а выбираются мышью через (click); keyboard-nav —\n на trigger'е (activedescendant: ArrowUp/Down/Enter), опции не\n focusable индивидуально, поэтому a11y-правила здесь не применимы.\n -->\n <!-- eslint-disable @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <ul rtElem=\"list\">\n @for (row of rows(); track row.option.value; let i = $index) {\n <li\n rtElem=\"option\"\n qa-dataid=\"select-option\"\n role=\"option\"\n [id]=\"panelId + '-opt-' + i\"\n [attr.data-value]=\"row.option.value\"\n [attr.aria-level]=\"isTree() ? row.level + 1 : null\"\n [style.--rt-select-tree-level]=\"row.level\"\n [rtMod]=\"{\n selected: row.option.value === value(),\n active: i === activeIndex(),\n disabled: !!row.option.disabled,\n }\"\n [attr.aria-selected]=\"row.option.value === value()\"\n [attr.aria-disabled]=\"!!row.option.disabled\"\n (click)=\"select(row.option)\">\n @if (isTree()) {\n @if (row.branch) {\n <button\n rtElem=\"toggle\"\n qa-dataid=\"select-option-toggle\"\n type=\"button\"\n tabindex=\"-1\"\n [attr.aria-label]=\"row.open ? t().uiCollapse : t().uiExpand\"\n [attr.aria-expanded]=\"row.open\"\n (click)=\"toggleBranch($event, row.option.value)\">\n <rt-icon size=\"sm\" color=\"muted\" [name]=\"row.open ? 'chevron-down' : 'chevron-right'\" />\n </button>\n } @else {\n <span rtElem=\"toggle-space\"></span>\n }\n }\n <span rtElem=\"option-label\">{{ row.option.label }}</span>\n @if (row.option.value === value()) {\n <rt-icon rtElem=\"check\" name=\"check\" size=\"sm\" aria-hidden=\"true\" />\n }\n </li>\n } @empty {\n <li rtElem=\"empty\">{{ t().uiNoOptions }}</li>\n }\n </ul>\n </div>\n </ng-template>\n</ng-container>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rt-tools-ui-kit-v2-select.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/select/rt-select-trigger.directive.ts","../../../projects/ui-kit-v2/src/lib/components/select/rt-select.component.ts","../../../projects/ui-kit-v2/src/lib/components/select/rt-select.component.html"],"sourcesContent":["import { Directive, inject, TemplateRef } from '@angular/core';\n\nimport { IRtSelect } from './rt-select.model';\n\n/**\n * Маркер своей разметки указателя — того, что человек нажимает, чтобы открыть список.\n *\n * Поведение указателя остаётся киту: открытие панели, её ширина, приметы доступности,\n * отключённость, клавиши и закрытие висят на кнопке. Потребитель даёт только то, что рисуется\n * внутри неё, и получает три значения обстановки: открыт ли список, что выбрано, отключён ли выбор.\n *\n * Один маркер на обе семьи выбора: они отличаются только разметкой внутри кнопки, и два маркера\n * разошлись бы на первой же правке.\n *\n * @example\n * ```html\n * <rt-select [options]=\"options\">\n * <ng-template rtSelectTrigger let-state>\n * <rt-tag [value]=\"state.label\" [icon]=\"state.isOpen ? 'chevron-up' : 'chevron-down'\" />\n * </ng-template>\n * </rt-select>\n * ```\n */\n@Directive({\n selector: '[rtSelectTrigger]',\n})\nexport class RtSelectTriggerDirective<TValue = unknown> {\n public readonly templateRef: TemplateRef<IRtSelect.TriggerContext<TValue>> =\n inject<TemplateRef<IRtSelect.TriggerContext<TValue>>>(TemplateRef);\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n computed,\n contentChild,\n forwardRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n InputSignal,\n InputSignalWithTransform,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RT_KIT_LABELS, TRtKitLabelMap, rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RtFormControlBase } from '@rt-tools/ui-kit-v2/form-control';\nimport { IRtInput } from '@rt-tools/ui-kit-v2/core';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtInputComponent } from '@rt-tools/ui-kit-v2/input';\nimport { RtPopoverDirective } from '@rt-tools/ui-kit-v2/popover';\nimport { IRtPopover } from '@rt-tools/ui-kit-v2/popover';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RtOptionList, TRtOptionListAction } from '@rt-tools/ui-kit-v2/core';\nimport { rtTreeFind, rtTreeIsTree, rtTreeOpenFor, rtTreeRows, rtTreeSideKey, rtTreeToggle } from '@rt-tools/ui-kit-v2/core';\nimport { RtSelectTriggerDirective } from './rt-select-trigger.directive';\nimport { IRtSelect } from './rt-select.model';\n\nconst BEM_BLOCK: string = 'rt-select';\n\n/** Клавиши, открывающие закрытый dropdown с фокуса на trigger'е. */\n\ntype TBooleanInput = boolean | string;\n\nlet panelIdSeed: number = 0;\n\nfunction nextPanelId(): number {\n panelIdSeed += 1;\n return panelIdSeed;\n}\n\n/**\n * Single-select dropdown с опциональным filter input.\n *\n * Panel рендерится через CDK Overlay (директива `[rtPopover]` на trigger'е) —\n * не обрезается `overflow: hidden` предками (таблицы, aside, карточки) и\n * авто-flip'ается у края viewport. CVA через общий `RtFormControlBase`. Крестик\n * (`clearable`) слева от шеврона — виден при наличии значения, очищает выбор.\n *\n * Keyboard-nav (activedescendant): фокус на trigger'е, ArrowUp/Down двигают\n * виртуальный highlight (`aria-activedescendant`), Enter выбирает, Escape\n * закрывает. Home/End/typeahead — deferred.\n */\n@Component({\n selector: 'rt-select',\n templateUrl: './rt-select.component.html',\n styleUrl: './rt-select.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n FormsModule,\n NgTemplateOutlet,\n\n // standalone components / directives\n RtIconButtonComponent,\n RtIconComponent,\n RtInputComponent,\n RtPopoverDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n providers: [\n // Алиас базового токена — для contentChild(RtFormControlBase) в rt-field.\n { provide: RtFormControlBase, useExisting: forwardRef(() => RtSelectComponent) },\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n '[class.rt-select--open]': 'isOpen()',\n '[class.rt-select--disabled]': 'isDisabled()',\n '[class.rt-select--readonly]': 'isReadonly()',\n '[class.rt-select--invalid]': 'isInvalid()',\n '[class.rt-select--borderless]': '!bordered()',\n '[class.rt-select--appearance--fill]': \"appearance() === 'fill'\",\n '[class.rt-select--size--sm]': \"size() === 'sm'\",\n '[class.rt-select--size--lg]': \"size() === 'lg'\",\n '[class.rt-select--with-icon-left]': '!!iconLeft()',\n },\n})\nexport class RtSelectComponent<TValue> extends RtFormControlBase<TValue | null> {\n readonly #t_uiSearch: Signal<string> = rtKitLabel('uiSearch');\n\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly panelId: string = `rt-select-panel-${nextPanelId()}`;\n\n protected readonly filterPlaceholderText: Signal<string> = computed((): string => this.filterPlaceholder() || this.#t_uiSearch());\n\n protected readonly popover: Signal<RtPopoverDirective> = viewChild.required(RtPopoverDirective);\n\n protected readonly triggerEl: Signal<ElementRef<HTMLButtonElement> | undefined> = viewChild<ElementRef<HTMLButtonElement>>('triggerEl');\n\n protected readonly filterTerm: WritableSignal<string> = signal<string>('');\n /** Раскрытые ветки дерева. Живут, пока открыта панель: при открытии раскрыты ветки над выбранным. */\n protected readonly openBranches: WritableSignal<ReadonlySet<TValue>> = signal<ReadonlySet<TValue>>(new Set<TValue>());\n\n protected readonly isOpen: Signal<boolean> = computed((): boolean => this.popover().isOpen());\n\n /** Клавиатура списка: подсветка, клавиши открытия, id для `aria-activedescendant`, прокрутка к опции. */\n protected readonly optionList: RtOptionList = new RtOptionList({\n panelId: (): string => this.panelId,\n isOpen: (): boolean => this.isOpen(),\n count: (): number => this.rows().length,\n isDisabled: (index: number): boolean => Boolean(this.rows()[index]?.option.disabled),\n chooseKeys: new Set<string>(['Enter', ' ']),\n sideKeys: true,\n edgeKeys: true,\n });\n\n protected readonly activeIndex: WritableSignal<number> = this.optionList.activeIndex;\n\n /** Идентификатор подсвеченной опции — тот же, что уходит в `aria-activedescendant`. */\n protected readonly activeOptionId: Signal<string | null> = this.optionList.activeOptionId;\n\n /**\n * Своя разметка указателя, если потребитель её объявил. Не объявил — кит рисует свою, и ни один\n * нынешний потребитель не двигается.\n */\n protected readonly triggerTpl: Signal<RtSelectTriggerDirective<TValue> | undefined> = contentChild(RtSelectTriggerDirective);\n\n protected readonly hasValue: Signal<boolean> = computed((): boolean => this.value() !== null);\n\n protected readonly selectedLabel: Signal<string> = computed((): string => {\n const v: TValue | null = this.value();\n if (v === null) {\n return '';\n }\n return rtTreeFind(this.options(), v)?.label ?? '';\n });\n\n /** Дерево ли список: тогда у строк есть место под стрелку и отступ по уровню. */\n protected readonly isTree: Signal<boolean> = computed((): boolean => rtTreeIsTree(this.options()));\n\n /** Видимые строки: плоский список — как прежде, дерево — по раскрытым веткам и поисковому слову. */\n protected readonly rows: Signal<ReadonlyArray<IRtSelect.Row<TValue>>> = computed((): ReadonlyArray<IRtSelect.Row<TValue>> =>\n rtTreeRows(this.options(), this.openBranches(), this.filterTerm())\n );\n\n /** Три значения, которые кит отдаёт своей разметке указателя, и не больше. */\n protected readonly triggerState: Signal<IRtSelect.TriggerState<TValue>> = computed((): IRtSelect.TriggerState<TValue> => ({\n isOpen: this.isOpen(),\n value: this.value(),\n label: this.selectedLabel(),\n isDisabled: this.isDisabled(),\n }));\n\n /** Вид рамки: `outline` — рамка со всех сторон, `fill` — залитое поле с чертой снизу. */\n public readonly appearance: InputSignal<IRtInput.Appearance> = input<IRtInput.Appearance>('outline');\n\n public readonly displayText: Signal<string> = computed((): string => this.selectedLabel());\n\n public readonly options: InputSignal<ReadonlyArray<IRtSelect.Option<TValue>>> = input<ReadonlyArray<IRtSelect.Option<TValue>>>([]);\n\n public readonly placeholder: InputSignal<string> = input<string>('');\n\n public readonly iconLeft: InputSignal<IRtIcon.Name | null> = input<IRtIcon.Name | null>(null);\n\n public readonly filter: InputSignalWithTransform<boolean, TBooleanInput> = input<boolean, TBooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Пусто — берётся переведённая подпись по умолчанию */\n public readonly filterPlaceholder: InputSignal<string> = input<string>('');\n\n /**\n * Чем мерится панель. По умолчанию она не уже кнопки и дальше растёт по содержимому:\n * со своим указателем кнопка бывает узкой, и панель по её ширине давила бы содержимое.\n * `trigger` возвращает прежнее — ровно по кнопке, `auto` пускает панель по содержимому\n * целиком. Предел высоты назначается входом `panelMaxHeight`.\n */\n public readonly panelWidth: InputSignal<IRtPopover.Width> = input<IRtPopover.Width>('trigger-min');\n\n /**\n * Предел высоты панели — длина как в стилях, например `20rem`. Пусто — предел кита\n * `--rt-input-panel-max-height`, и длинный список прокручивается внутри панели: без предела\n * он уходил за нижний край экрана, и пункты за краем были недостижимы. `none` снимает предел —\n * для короткого списка, который должен открываться целиком, без прокрутки. Значение ставится\n * на саму панель: она рисуется в наложении, вне поддерева блока.\n */\n public readonly panelMaxHeight: InputSignal<string | null> = input<string | null>(null);\n\n public readonly selectionChange: OutputEmitterRef<TValue | null> = output<TValue | null>();\n\n public override setDisabledState(disabled: boolean): void {\n super.setDisabledState(disabled);\n if (disabled) {\n this.popover().close();\n }\n }\n\n protected getEmptyValue(): TValue | null {\n return null;\n }\n\n protected focusAfterClear(): void {\n this.triggerEl()?.nativeElement.focus();\n }\n\n protected override clear(event?: Event): void {\n if (this.isDisabled()) {\n return;\n }\n super.clear(event);\n this.selectionChange.emit(null);\n }\n\n /**\n * Открытый список встаёт подсветкой на выбранный пункт.\n *\n * Иначе стрелка вниз начинала с первого пункта, и человек с выбранным «20» из «10, 20, 40»\n * получал «10» вместо «40».\n */\n protected onOpened(): void {\n const v: TValue | null = this.value();\n this.openBranches.set(rtTreeOpenFor(this.options(), v === null ? [] : [v]));\n if (v !== null) {\n const chosen: number = this.rows().findIndex((row: IRtSelect.Row<TValue>): boolean => row.option.value === v);\n if (chosen >= 0) {\n this.activeIndex.set(chosen);\n }\n }\n }\n\n protected toggleBranch(event: Event, value: TValue): void {\n event.stopPropagation();\n this.openBranches.update((open: ReadonlySet<TValue>): ReadonlySet<TValue> => rtTreeToggle(open, value));\n }\n\n protected onClosed(): void {\n // Закрытие (outside-click / Escape / выбор) = пользователь увёл фокус.\n this.filterTerm.set('');\n this.activeIndex.set(-1);\n this.markTouched();\n }\n\n protected select(opt: IRtSelect.Option<TValue>): void {\n if (opt.disabled) {\n return;\n }\n this.value.set(opt.value);\n this.emitChange(opt.value);\n this.selectionChange.emit(opt.value);\n this.popover().close();\n }\n\n protected setFilter(term: string): void {\n this.filterTerm.set(term);\n this.activeIndex.set(-1);\n }\n\n protected onTriggerKeydown(event: KeyboardEvent): void {\n if (this.isDisabled()) {\n return;\n }\n if (!this.isOpen()) {\n if (this.optionList.opensBy(event.key)) {\n event.preventDefault();\n this.popover().open();\n if (this.activeIndex() < 0) {\n this.optionList.move(1);\n }\n }\n return;\n }\n this.#handleOpenKeydown(event);\n }\n\n #handleOpenKeydown(event: KeyboardEvent): void {\n const action: TRtOptionListAction = this.optionList.actionOf(event.key);\n if (action === 'none') {\n return;\n }\n event.preventDefault();\n switch (action) {\n case 'next':\n this.optionList.move(1);\n break;\n case 'previous':\n this.optionList.move(-1);\n break;\n case 'first':\n this.optionList.first();\n break;\n case 'last':\n this.optionList.last();\n break;\n case 'choose':\n this.#selectActive();\n break;\n case 'close':\n this.popover().close();\n break;\n case 'side':\n this.#sideKey(event.key);\n break;\n }\n }\n\n #sideKey(key: string): void {\n const answer: IRtSelect.SideKeyAnswer<TValue> = rtTreeSideKey(this.rows(), this.activeIndex(), key);\n const toggle: TValue | null = answer.toggle;\n if (toggle !== null) {\n this.openBranches.update((open: ReadonlySet<TValue>): ReadonlySet<TValue> => rtTreeToggle(open, toggle));\n }\n this.activeIndex.set(answer.index);\n }\n\n #selectActive(): void {\n const opts: ReadonlyArray<IRtSelect.Option<TValue>> = this.rows().map(\n (row: IRtSelect.Row<TValue>): IRtSelect.Option<TValue> => row.option\n );\n const index: number = this.activeIndex();\n if (index >= 0 && index < opts.length) {\n this.select(opts[index]);\n }\n }\n}\n","<ng-container rtBlock=\"rt-select\">\n @if (isReadonly()) {\n <span rtElem=\"readonly\" [rtMod]=\"{ empty: !displayText() }\">{{ displayText() || '—' }}</span>\n }\n <button\n #triggerEl\n rtElem=\"trigger\"\n qa-dataid=\"select-trigger\"\n type=\"button\"\n [rtPopoverWidth]=\"panelWidth()\"\n [rtMod]=\"{ own: !!triggerTpl() }\"\n [rtPopover]=\"panelTpl\"\n [rtPopoverDisabled]=\"isDisabled()\"\n [attr.id]=\"effectiveControlId()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-invalid]=\"isInvalid() || null\"\n [attr.aria-controls]=\"panelId\"\n [attr.aria-activedescendant]=\"activeOptionId()\"\n [disabled]=\"isDisabled()\"\n (keydown)=\"onTriggerKeydown($event)\"\n (rtPopoverOpened)=\"onOpened()\"\n (rtPopoverClosed)=\"onClosed()\">\n <!--\n Разметка указателя: своя, если потребитель её объявил, иначе зашитая китом. Она встаёт\n внутрь кнопки, а не вместо неё: поведение — открытие панели, приметы доступности,\n отключённость, клавиши и закрытие — остаётся на кнопке кита.\n -->\n @if (triggerTpl(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.templateRef\" [ngTemplateOutletContext]=\"{ $implicit: triggerState() }\" />\n } @else {\n @if (iconLeft(); as left) {\n <rt-icon rtElem=\"icon-left\" size=\"sm\" color=\"muted\" [name]=\"left\" />\n }\n <span rtElem=\"label\" [rtMod]=\"{ placeholder: !selectedLabel() }\">\n {{ selectedLabel() || placeholder() }}\n </span>\n @if (showClearButton()) {\n <rt-icon-button\n rtElem=\"clear\"\n icon=\"ico-close\"\n size=\"sm\"\n variant=\"ghost\"\n iconColor=\"muted\"\n [ariaLabel]=\"t().uiClear\"\n [tabIndex]=\"-1\"\n (clicked)=\"clear($event)\" />\n }\n <rt-icon rtElem=\"chevron\" name=\"chevron-down\" size=\"sm\" color=\"muted\" />\n }\n </button>\n\n <ng-template #panelTpl>\n <div rtElem=\"panel\" role=\"listbox\" [style.--rt-select-panel-max-height]=\"panelMaxHeight()\" [attr.aria-label]=\"ariaLabel()\">\n @if (filter()) {\n <div rtElem=\"filter\">\n <rt-input\n iconLeft=\"ico-search\"\n [placeholder]=\"filterPlaceholderText()\"\n [ngModel]=\"filterTerm()\"\n (ngModelChange)=\"setFilter($event)\" />\n </div>\n }\n <!--\n Опции listbox'а выбираются мышью через (click); keyboard-nav —\n на trigger'е (activedescendant: ArrowUp/Down/Enter), опции не\n focusable индивидуально, поэтому a11y-правила здесь не применимы.\n -->\n <!-- eslint-disable @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <ul rtElem=\"list\">\n @for (row of rows(); track row.option.value; let i = $index) {\n <li\n rtElem=\"option\"\n qa-dataid=\"select-option\"\n role=\"option\"\n [id]=\"panelId + '-opt-' + i\"\n [attr.data-value]=\"row.option.value\"\n [attr.aria-level]=\"isTree() ? row.level + 1 : null\"\n [style.--rt-select-tree-level]=\"row.level\"\n [rtMod]=\"{\n selected: row.option.value === value(),\n active: i === activeIndex(),\n disabled: !!row.option.disabled,\n }\"\n [attr.aria-selected]=\"row.option.value === value()\"\n [attr.aria-disabled]=\"!!row.option.disabled\"\n (click)=\"select(row.option)\">\n @if (isTree()) {\n @if (row.branch) {\n <button\n rtElem=\"toggle\"\n qa-dataid=\"select-option-toggle\"\n type=\"button\"\n tabindex=\"-1\"\n [attr.aria-label]=\"row.open ? t().uiCollapse : t().uiExpand\"\n [attr.aria-expanded]=\"row.open\"\n (click)=\"toggleBranch($event, row.option.value)\">\n <rt-icon size=\"sm\" color=\"muted\" [name]=\"row.open ? 'chevron-down' : 'chevron-right'\" />\n </button>\n } @else {\n <span rtElem=\"toggle-space\"></span>\n }\n }\n <span rtElem=\"option-label\">{{ row.option.label }}</span>\n @if (row.option.value === value()) {\n <rt-icon rtElem=\"check\" name=\"check\" size=\"sm\" aria-hidden=\"true\" />\n }\n </li>\n } @empty {\n <li rtElem=\"empty\">{{ t().uiNoOptions }}</li>\n }\n </ul>\n </div>\n </ng-template>\n</ng-container>\n"],"mappings":"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"}
|