@rt-tools/ui-kit-v2 0.33.0 → 0.34.1
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/README.md +4 -3
- package/fesm2022/rt-tools-ui-kit-v2-ai-run-status.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-ai-run-status.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs +92 -5
- package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-badge.mjs +191 -0
- package/fesm2022/rt-tools-ui-kit-v2-badge.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-breadcrumbs.mjs +3 -2
- package/fesm2022/rt-tools-ui-kit-v2-breadcrumbs.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-button.mjs +6 -1
- package/fesm2022/rt-tools-ui-kit-v2-button.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-checkbox.mjs +35 -4
- package/fesm2022/rt-tools-ui-kit-v2-checkbox.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-color-palette.mjs +13 -4
- package/fesm2022/rt-tools-ui-kit-v2-color-palette.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-container.mjs +245 -60
- package/fesm2022/rt-tools-ui-kit-v2-container.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-copy-value.mjs +30 -5
- package/fesm2022/rt-tools-ui-kit-v2-copy-value.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-core.mjs +113 -2
- package/fesm2022/rt-tools-ui-kit-v2-core.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs +14 -3
- package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-data-table.mjs +17 -3
- package/fesm2022/rt-tools-ui-kit-v2-data-table.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-date-picker.mjs +6 -3
- package/fesm2022/rt-tools-ui-kit-v2-date-picker.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-date-range.mjs +2 -2
- package/fesm2022/rt-tools-ui-kit-v2-date-range.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-divider.mjs +112 -0
- package/fesm2022/rt-tools-ui-kit-v2-divider.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-draggable-tree.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-draggable-tree.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-drawer.mjs +854 -0
- package/fesm2022/rt-tools-ui-kit-v2-drawer.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-list.mjs +16 -5
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-list.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs +580 -65
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-expansion-panel.mjs +203 -15
- package/fesm2022/rt-tools-ui-kit-v2-expansion-panel.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-field.mjs +40 -8
- package/fesm2022/rt-tools-ui-kit-v2-field.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-file-card.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-file-card.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-filter-control.mjs +7 -3
- package/fesm2022/rt-tools-ui-kit-v2-filter-control.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-form-control.mjs +53 -2
- package/fesm2022/rt-tools-ui-kit-v2-form-control.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree-selector.mjs +14 -4
- package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree-selector.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree.mjs +6 -3
- package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-icon-button.mjs +16 -5
- package/fesm2022/rt-tools-ui-kit-v2-icon-button.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-image-upload.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-image-upload.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-inline-edit.mjs +14 -4
- package/fesm2022/rt-tools-ui-kit-v2-inline-edit.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-input-number.mjs +3 -2
- package/fesm2022/rt-tools-ui-kit-v2-input-number.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-input.mjs +207 -7
- package/fesm2022/rt-tools-ui-kit-v2-input.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-menu.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-menu.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs +3 -2
- package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs +2 -0
- package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-pagination.mjs +3 -2
- package/fesm2022/rt-tools-ui-kit-v2-pagination.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-profile-menu.mjs +3 -2
- package/fesm2022/rt-tools-ui-kit-v2-profile-menu.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-progress-bar.mjs +171 -0
- package/fesm2022/rt-tools-ui-kit-v2-progress-bar.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-radio-button.mjs +176 -6
- package/fesm2022/rt-tools-ui-kit-v2-radio-button.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +2 -1
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-scroll-area.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-scroll-area.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-select.mjs +142 -23
- package/fesm2022/rt-tools-ui-kit-v2-select.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs +22 -9
- package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-speed-menu.mjs +3 -2
- package/fesm2022/rt-tools-ui-kit-v2-speed-menu.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-stepper.mjs +105 -8
- package/fesm2022/rt-tools-ui-kit-v2-stepper.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-table.mjs +13 -2
- package/fesm2022/rt-tools-ui-kit-v2-table.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-tabs.mjs +654 -43
- package/fesm2022/rt-tools-ui-kit-v2-tabs.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-tag.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-tag.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-textarea.mjs +45 -7
- package/fesm2022/rt-tools-ui-kit-v2-textarea.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-theme-toggle.mjs +2 -2
- package/fesm2022/rt-tools-ui-kit-v2-theme-toggle.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs +11 -2
- package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-toast.mjs +152 -11
- package/fesm2022/rt-tools-ui-kit-v2-toast.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-toggle-button-group.mjs +199 -17
- package/fesm2022/rt-tools-ui-kit-v2-toggle-button-group.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-tooltip.mjs +35 -5
- package/fesm2022/rt-tools-ui-kit-v2-tooltip.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-tree-selector.mjs +14 -4
- package/fesm2022/rt-tools-ui-kit-v2-tree-selector.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-tree.mjs +6 -3
- package/fesm2022/rt-tools-ui-kit-v2-tree.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-workspace-details.mjs +21 -6
- package/fesm2022/rt-tools-ui-kit-v2-workspace-details.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2.mjs +4 -0
- package/package.json +17 -1
- package/src/assets/icons/volume-off.svg +2 -1
- package/src/lib/components/autocomplete/CONTEXT.md +25 -14
- package/src/lib/components/autocomplete/rt-autocomplete.component.scss +19 -0
- package/src/lib/components/badge/CONTEXT.md +33 -0
- package/src/lib/components/badge/rt-badge.directive.scss +104 -0
- package/src/lib/components/breadcrumbs/rt-breadcrumbs.component.scss +2 -2
- package/src/lib/components/button/CONTEXT.md +5 -0
- package/src/lib/components/button/rt-button.directive.scss +3 -1
- package/src/lib/components/checkbox/CONTEXT.md +15 -8
- package/src/lib/components/color-palette/rt-color-palette.component.scss +2 -2
- package/src/lib/components/container/CONTEXT.md +23 -6
- package/src/lib/components/container/rt-container.component.scss +90 -1
- package/src/lib/components/copy-value/CONTEXT.md +6 -5
- package/src/lib/components/copy-value/rt-copy-value.component.scss +16 -0
- package/src/lib/components/date-picker/rt-date-picker.component.scss +7 -0
- package/src/lib/components/date-range/rt-date-range.component.scss +7 -0
- package/src/lib/components/divider/CONTEXT.md +21 -0
- package/src/lib/components/divider/rt-divider.component.scss +34 -0
- package/src/lib/components/drawer/CONTEXT.md +73 -0
- package/src/lib/components/drawer/rt-drawer-container.component.scss +19 -0
- package/src/lib/components/drawer/rt-drawer.component.scss +168 -0
- package/src/lib/components/drawer/rt-resize-handle.component.scss +42 -0
- package/src/lib/components/dynamic-selector/CONTEXT.md +5 -0
- package/src/lib/components/expansion-panel/CONTEXT.md +32 -8
- package/src/lib/components/expansion-panel/rt-expansion-panel.component.scss +67 -2
- package/src/lib/components/field/CONTEXT.md +43 -0
- package/src/lib/components/field/rt-field-label-inside.scss +179 -0
- package/src/lib/components/field/rt-field.component.scss +51 -2
- package/src/lib/components/icon-button/CONTEXT.md +17 -15
- package/src/lib/components/icon-button/rt-icon-button.component.scss +3 -1
- package/src/lib/components/inline-edit/rt-inline-edit.component.scss +4 -4
- package/src/lib/components/input/CONTEXT.md +45 -11
- package/src/lib/components/input/rt-input-floating-label.scss +192 -0
- package/src/lib/components/input/rt-input-icons.scss +105 -0
- package/src/lib/components/input/rt-input.component.scss +91 -13
- package/src/lib/components/input-number/CONTEXT.md +7 -0
- package/src/lib/components/input-number/rt-input-number.component.scss +58 -1
- package/src/lib/components/menu/CONTEXT.md +1 -0
- package/src/lib/components/multiselect/CONTEXT.md +2 -1
- package/src/lib/components/multiselect/rt-multiselect.component.scss +7 -0
- package/src/lib/components/pagination/CONTEXT.md +3 -0
- package/src/lib/components/pagination/rt-pagination.component.scss +7 -0
- package/src/lib/components/progress-bar/CONTEXT.md +22 -0
- package/src/lib/components/progress-bar/rt-progress-bar.component.scss +77 -0
- package/src/lib/components/radio-button/CONTEXT.md +9 -0
- package/src/lib/components/radio-button/rt-radio-group.component.scss +13 -0
- package/src/lib/components/select/CONTEXT.md +28 -0
- package/src/lib/components/select/rt-select-clear.scss +88 -0
- package/src/lib/components/select/rt-select-floating-label.scss +155 -0
- package/src/lib/components/select/rt-select-material.scss +54 -0
- package/src/lib/components/select/rt-select.component.scss +54 -16
- package/src/lib/components/side-menu/CONTEXT.md +5 -0
- package/src/lib/components/speed-menu/rt-speed-menu.component.scss +5 -5
- package/src/lib/components/stepper/CONTEXT.md +13 -5
- package/src/lib/components/stepper/rt-stepper.component.scss +93 -0
- package/src/lib/components/tabs/CONTEXT.md +61 -9
- package/src/lib/components/tabs/rt-tabs.component.scss +201 -5
- package/src/lib/components/textarea/CONTEXT.md +12 -1
- package/src/lib/components/textarea/rt-textarea.component.scss +116 -1
- package/src/lib/components/toast/CONTEXT.md +23 -0
- package/src/lib/components/toast/rt-toast.component.scss +37 -0
- package/src/lib/components/toggle-button-group/CONTEXT.md +24 -4
- package/src/lib/components/toggle-button-group/rt-toggle-button-group-chips.scss +151 -0
- package/src/lib/components/toggle-button-group/rt-toggle-button-group.component.scss +35 -0
- package/src/lib/components/tooltip/CONTEXT.md +7 -1
- package/src/lib/components/tree/rt-tree.component.scss +2 -2
- package/src/styles/_color-scheme.scss +1 -1
- package/src/styles/_density.scss +48 -0
- package/src/styles/_index.scss +8 -0
- package/src/styles/_preset-material.scss +160 -70
- package/src/styles/_primitives.scss +1 -0
- package/src/styles/_semantic-navigation.scss +117 -0
- package/src/styles/_semantic.scss +29 -98
- package/src/styles/_theme-dark.scss +8 -0
- package/styles/tokens.css +2066 -1134
- package/types/rt-tools-ui-kit-v2-autocomplete.d.ts +34 -0
- package/types/rt-tools-ui-kit-v2-badge.d.ts +71 -0
- package/types/rt-tools-ui-kit-v2-checkbox.d.ts +17 -3
- package/types/rt-tools-ui-kit-v2-container.d.ts +65 -9
- package/types/rt-tools-ui-kit-v2-copy-value.d.ts +11 -1
- package/types/rt-tools-ui-kit-v2-core.d.ts +109 -4
- package/types/rt-tools-ui-kit-v2-divider.d.ts +29 -0
- package/types/rt-tools-ui-kit-v2-drawer.d.ts +257 -0
- package/types/rt-tools-ui-kit-v2-dynamic-selector.d.ts +240 -25
- package/types/rt-tools-ui-kit-v2-expansion-panel.d.ts +87 -3
- package/types/rt-tools-ui-kit-v2-field.d.ts +18 -1
- package/types/rt-tools-ui-kit-v2-form-control.d.ts +42 -4
- package/types/rt-tools-ui-kit-v2-icon-button.d.ts +2 -1
- package/types/rt-tools-ui-kit-v2-input-number.d.ts +1 -0
- package/types/rt-tools-ui-kit-v2-input.d.ts +98 -4
- package/types/rt-tools-ui-kit-v2-progress-bar.d.ts +53 -0
- package/types/rt-tools-ui-kit-v2-radio-button.d.ts +80 -1
- package/types/rt-tools-ui-kit-v2-select.d.ts +65 -1
- package/types/rt-tools-ui-kit-v2-side-menu.d.ts +3 -0
- package/types/rt-tools-ui-kit-v2-stepper.d.ts +57 -4
- package/types/rt-tools-ui-kit-v2-tabs.d.ts +337 -8
- package/types/rt-tools-ui-kit-v2-textarea.d.ts +16 -0
- package/types/rt-tools-ui-kit-v2-toast.d.ts +38 -2
- package/types/rt-tools-ui-kit-v2-toggle-button-group.d.ts +83 -3
- package/types/rt-tools-ui-kit-v2-tooltip.d.ts +17 -2
- package/types/rt-tools-ui-kit-v2.d.ts +4 -0
- package/src/lib/components/dynamic-selector/stories/component/test-dynamic-selector-popup-frame.component.scss +0 -6
|
@@ -1,26 +1,32 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
|
-
import { ChangeDetectionStrategy, Component, DestroyRef, Injector, ViewEncapsulation, booleanAttribute, computed, forwardRef, inject, input, output, signal } from "@angular/core";
|
|
2
|
+
import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, InjectionToken, Injector, ViewEncapsulation, afterRenderEffect, booleanAttribute, computed, forwardRef, inject, input, output, signal } from "@angular/core";
|
|
3
3
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
|
4
4
|
import { NG_VALUE_ACCESSOR, NgControl } from "@angular/forms";
|
|
5
5
|
import { EMPTY, Subject, distinctUntilChanged, switchMap } from "rxjs";
|
|
6
6
|
import { BlockDirective, ElemDirective, ModDirective } from "@rt-tools/core";
|
|
7
7
|
import * as i1 from "@rt-tools/ui-kit-v2/radius";
|
|
8
8
|
import { RtRadiusDirective } from "@rt-tools/ui-kit-v2/radius";
|
|
9
|
-
const
|
|
9
|
+
const RT_RADIO_GROUP = new InjectionToken("RT_RADIO_GROUP");
|
|
10
|
+
const BEM_BLOCK$1 = "rt-radio-button";
|
|
10
11
|
function checkedAttribute(value) {
|
|
11
12
|
return value === null || value === void 0 ? null : booleanAttribute(value);
|
|
12
13
|
}
|
|
13
14
|
var RtRadioButtonComponent = class RtRadioButtonComponent {
|
|
14
15
|
#injector;
|
|
15
16
|
#destroyRef;
|
|
17
|
+
#host;
|
|
18
|
+
#group;
|
|
16
19
|
#onChange;
|
|
17
20
|
#onTouched;
|
|
18
21
|
#controlSource;
|
|
19
22
|
#model;
|
|
20
23
|
#disabledByForm;
|
|
24
|
+
#tabStop;
|
|
21
25
|
constructor() {
|
|
22
26
|
this.#injector = inject(Injector);
|
|
23
27
|
this.#destroyRef = inject(DestroyRef);
|
|
28
|
+
this.#host = inject(ElementRef);
|
|
29
|
+
this.#group = inject(RT_RADIO_GROUP, { optional: true });
|
|
24
30
|
this.#onChange = () => void 0;
|
|
25
31
|
this.#onTouched = () => void 0;
|
|
26
32
|
this.#controlSource = new Subject();
|
|
@@ -28,6 +34,9 @@ var RtRadioButtonComponent = class RtRadioButtonComponent {
|
|
|
28
34
|
this.#disabledByForm = signal(false, ...ngDevMode ? [{ debugName: "#disabledByForm" }] : /* istanbul ignore next */ []);
|
|
29
35
|
this.isChecked = computed(() => this.checked() ?? this.value() === this.#model(), ...ngDevMode ? [{ debugName: "isChecked" }] : /* istanbul ignore next */ []);
|
|
30
36
|
this.isDisabled = computed(() => this.disabled() || this.#disabledByForm(), ...ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []);
|
|
37
|
+
this.#tabStop = signal(false, ...ngDevMode ? [{ debugName: "#tabStop" }] : /* istanbul ignore next */ []);
|
|
38
|
+
this.tabIndex = computed(() => this.#group === null || this.#tabStop() ? 0 : -1, ...ngDevMode ? [{ debugName: "tabIndex" }] : /* istanbul ignore next */ []);
|
|
39
|
+
this.element = this.#host.nativeElement;
|
|
31
40
|
this.value = input.required(...ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []);
|
|
32
41
|
this.checked = input(null, {
|
|
33
42
|
...ngDevMode ? { debugName: "checked" } : /* istanbul ignore next */ {},
|
|
@@ -44,8 +53,12 @@ var RtRadioButtonComponent = class RtRadioButtonComponent {
|
|
|
44
53
|
this.label = input("", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
|
|
45
54
|
this.description = input("", ...ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []);
|
|
46
55
|
this.ariaLabel = input(null, ...ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
|
|
56
|
+
this.selected = computed(() => this.isChecked(), ...ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []);
|
|
57
|
+
this.off = computed(() => this.isDisabled(), ...ngDevMode ? [{ debugName: "off" }] : /* istanbul ignore next */ []);
|
|
47
58
|
this.clickAction = output();
|
|
48
59
|
this.checkedChange = output();
|
|
60
|
+
this.#group?.register(this);
|
|
61
|
+
this.#destroyRef.onDestroy(() => this.#group?.unregister(this));
|
|
49
62
|
this.#controlSource.pipe(distinctUntilChanged(), switchMap((control) => control?.valueChanges ?? EMPTY), takeUntilDestroyed(this.#destroyRef)).subscribe((value) => this.#model.set(value));
|
|
50
63
|
}
|
|
51
64
|
writeValue(value) {
|
|
@@ -64,6 +77,16 @@ var RtRadioButtonComponent = class RtRadioButtonComponent {
|
|
|
64
77
|
setDisabledState(disabled) {
|
|
65
78
|
this.#disabledByForm.set(disabled);
|
|
66
79
|
}
|
|
80
|
+
setTabStop(on) {
|
|
81
|
+
this.#tabStop.set(on);
|
|
82
|
+
}
|
|
83
|
+
contains(target) {
|
|
84
|
+
return target instanceof Node && this.#host.nativeElement.contains(target);
|
|
85
|
+
}
|
|
86
|
+
selectFromKeyboard() {
|
|
87
|
+
this.#host.nativeElement.querySelector("[role=\"radio\"]")?.focus();
|
|
88
|
+
this.#select();
|
|
89
|
+
}
|
|
67
90
|
onClick(event) {
|
|
68
91
|
this.#select();
|
|
69
92
|
this.clickAction.emit(event);
|
|
@@ -167,7 +190,7 @@ var RtRadioButtonComponent = class RtRadioButtonComponent {
|
|
|
167
190
|
inputs: ["radius", "radius"]
|
|
168
191
|
}],
|
|
169
192
|
ngImport: i0,
|
|
170
|
-
template: "<div\n rtBlock=\"rt-radio-button\"\n qa-dataid=\"radio-button-control\"\n role=\"radio\"\n tabindex=\"
|
|
193
|
+
template: "<div\n rtBlock=\"rt-radio-button\"\n qa-dataid=\"radio-button-control\"\n role=\"radio\"\n [attr.tabindex]=\"tabIndex()\"\n [rtMod]=\"{ checked: isChecked(), disabled: isDisabled(), card: card() }\"\n [attr.aria-checked]=\"isChecked()\"\n [attr.aria-disabled]=\"isDisabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n (click)=\"onClick($event)\"\n (keydown)=\"onKeydown($event)\">\n <span rtElem=\"indicator\">\n @if (isChecked()) {\n <span rtElem=\"dot\"></span>\n }\n </span>\n\n @if (label() || description()) {\n <span rtElem=\"content\">\n @if (label()) {\n <span rtElem=\"label\" qa-dataid=\"radio-button-label\">{{ label() }}</span>\n }\n @if (description()) {\n <span rtElem=\"description\" qa-dataid=\"radio-button-description\">{{ description() }}</span>\n }\n </span>\n }\n</div>\n",
|
|
171
194
|
styles: ["@charset \"UTF-8\";@layer rt-kit.components{rt-radio-button{display:inline-block}rt-radio-button[data-rt-radius=none]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-none)}rt-radio-button[data-rt-radius=xs]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-xs)}rt-radio-button[data-rt-radius=sm]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-sm)}rt-radio-button[data-rt-radius=ms]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-ms)}rt-radio-button[data-rt-radius=md]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-md)}rt-radio-button[data-rt-radius=lg]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-lg)}rt-radio-button[data-rt-radius=xl]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-xl)}rt-radio-button[data-rt-radius=\"2xl\"]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-2xl)}rt-radio-button[data-rt-radius=full]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-full)}rt-radio-button .rt-radio-button{--rt-radio-button-size: var(--rt-size-4);--rt-radio-button-dot-size: var(--rt-size-2);--rt-radio-button-rim-width: var(--rt-border-width-medium);--rt-radio-button-round: var(--rt-radius-full);--rt-radio-button-focus-radius: var(--rt-radius-sm);--rt-radio-button-focus-shadow: var(--rt-shadow-focus-ring);--rt-radio-button-card-radius: var(--rt-radius-md);--rt-radio-button-card-border-width: var(--rt-border-width-thin);--rt-radio-button-transition-duration: var(--rt-duration-fast);display:flex;align-items:center;cursor:pointer;gap:var(--rt-space-sm);text-align:start}rt-radio-button .rt-radio-button:focus-visible{border-radius:var(--rt-radio-button-focus-radius);box-shadow:var(--rt-radio-button-focus-shadow);outline:2px solid transparent;outline-offset:2px}rt-radio-button .rt-radio-button__indicator{display:inline-flex;width:var(--rt-radio-button-size);height:var(--rt-radio-button-size);flex-shrink:0;align-items:center;justify-content:center;border:var(--rt-radio-button-rim-width) solid var(--rt-color-border-strong);border-radius:var(--rt-radio-button-round);transition:border-color var(--rt-radio-button-transition-duration) ease}rt-radio-button .rt-radio-button__dot{width:var(--rt-radio-button-dot-size);height:var(--rt-radio-button-dot-size);border-radius:var(--rt-radio-button-round);background:var(--rt-color-action-primary)}rt-radio-button .rt-radio-button__content{display:flex;min-width:0;flex:1;flex-direction:column;gap:var(--rt-space-xs)}rt-radio-button .rt-radio-button__label{color:var(--rt-color-text-primary);font-size:var(--rt-text-sm);-webkit-user-select:none;user-select:none}rt-radio-button .rt-radio-button__description{color:var(--rt-color-text-muted);font-size:var(--rt-text-xs)}rt-radio-button .rt-radio-button--checked .rt-radio-button__indicator{border-color:var(--rt-color-action-primary)}rt-radio-button .rt-radio-button--card{flex-direction:row-reverse;align-items:flex-start;justify-content:space-between;padding:var(--rt-space-sm) var(--rt-space-md);border:var(--rt-radio-button-card-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-radio-button-card-radius);transition:border-color var(--rt-radio-button-transition-duration) ease}rt-radio-button .rt-radio-button--card .rt-radio-button__label{font-weight:var(--rt-font-weight-medium)}rt-radio-button .rt-radio-button--card.rt-radio-button--checked{border-color:var(--rt-color-action-primary)}rt-radio-button .rt-radio-button--disabled{cursor:not-allowed;opacity:var(--rt-opacity-disabled);pointer-events:none}}\n"],
|
|
172
195
|
dependencies: [
|
|
173
196
|
{
|
|
@@ -218,8 +241,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
218
241
|
directive: RtRadiusDirective,
|
|
219
242
|
inputs: ["radius"]
|
|
220
243
|
}],
|
|
221
|
-
host: { class: BEM_BLOCK },
|
|
222
|
-
template: "<div\n rtBlock=\"rt-radio-button\"\n qa-dataid=\"radio-button-control\"\n role=\"radio\"\n tabindex=\"
|
|
244
|
+
host: { class: BEM_BLOCK$1 },
|
|
245
|
+
template: "<div\n rtBlock=\"rt-radio-button\"\n qa-dataid=\"radio-button-control\"\n role=\"radio\"\n [attr.tabindex]=\"tabIndex()\"\n [rtMod]=\"{ checked: isChecked(), disabled: isDisabled(), card: card() }\"\n [attr.aria-checked]=\"isChecked()\"\n [attr.aria-disabled]=\"isDisabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n (click)=\"onClick($event)\"\n (keydown)=\"onKeydown($event)\">\n <span rtElem=\"indicator\">\n @if (isChecked()) {\n <span rtElem=\"dot\"></span>\n }\n </span>\n\n @if (label() || description()) {\n <span rtElem=\"content\">\n @if (label()) {\n <span rtElem=\"label\" qa-dataid=\"radio-button-label\">{{ label() }}</span>\n }\n @if (description()) {\n <span rtElem=\"description\" qa-dataid=\"radio-button-description\">{{ description() }}</span>\n }\n </span>\n }\n</div>\n",
|
|
223
246
|
styles: ["@charset \"UTF-8\";@layer rt-kit.components{rt-radio-button{display:inline-block}rt-radio-button[data-rt-radius=none]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-none)}rt-radio-button[data-rt-radius=xs]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-xs)}rt-radio-button[data-rt-radius=sm]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-sm)}rt-radio-button[data-rt-radius=ms]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-ms)}rt-radio-button[data-rt-radius=md]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-md)}rt-radio-button[data-rt-radius=lg]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-lg)}rt-radio-button[data-rt-radius=xl]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-xl)}rt-radio-button[data-rt-radius=\"2xl\"]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-2xl)}rt-radio-button[data-rt-radius=full]>.rt-radio-button{--rt-radio-button-card-radius: var(--rt-radius-full)}rt-radio-button .rt-radio-button{--rt-radio-button-size: var(--rt-size-4);--rt-radio-button-dot-size: var(--rt-size-2);--rt-radio-button-rim-width: var(--rt-border-width-medium);--rt-radio-button-round: var(--rt-radius-full);--rt-radio-button-focus-radius: var(--rt-radius-sm);--rt-radio-button-focus-shadow: var(--rt-shadow-focus-ring);--rt-radio-button-card-radius: var(--rt-radius-md);--rt-radio-button-card-border-width: var(--rt-border-width-thin);--rt-radio-button-transition-duration: var(--rt-duration-fast);display:flex;align-items:center;cursor:pointer;gap:var(--rt-space-sm);text-align:start}rt-radio-button .rt-radio-button:focus-visible{border-radius:var(--rt-radio-button-focus-radius);box-shadow:var(--rt-radio-button-focus-shadow);outline:2px solid transparent;outline-offset:2px}rt-radio-button .rt-radio-button__indicator{display:inline-flex;width:var(--rt-radio-button-size);height:var(--rt-radio-button-size);flex-shrink:0;align-items:center;justify-content:center;border:var(--rt-radio-button-rim-width) solid var(--rt-color-border-strong);border-radius:var(--rt-radio-button-round);transition:border-color var(--rt-radio-button-transition-duration) ease}rt-radio-button .rt-radio-button__dot{width:var(--rt-radio-button-dot-size);height:var(--rt-radio-button-dot-size);border-radius:var(--rt-radio-button-round);background:var(--rt-color-action-primary)}rt-radio-button .rt-radio-button__content{display:flex;min-width:0;flex:1;flex-direction:column;gap:var(--rt-space-xs)}rt-radio-button .rt-radio-button__label{color:var(--rt-color-text-primary);font-size:var(--rt-text-sm);-webkit-user-select:none;user-select:none}rt-radio-button .rt-radio-button__description{color:var(--rt-color-text-muted);font-size:var(--rt-text-xs)}rt-radio-button .rt-radio-button--checked .rt-radio-button__indicator{border-color:var(--rt-color-action-primary)}rt-radio-button .rt-radio-button--card{flex-direction:row-reverse;align-items:flex-start;justify-content:space-between;padding:var(--rt-space-sm) var(--rt-space-md);border:var(--rt-radio-button-card-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-radio-button-card-radius);transition:border-color var(--rt-radio-button-transition-duration) ease}rt-radio-button .rt-radio-button--card .rt-radio-button__label{font-weight:var(--rt-font-weight-medium)}rt-radio-button .rt-radio-button--card.rt-radio-button--checked{border-color:var(--rt-color-action-primary)}rt-radio-button .rt-radio-button--disabled{cursor:not-allowed;opacity:var(--rt-opacity-disabled);pointer-events:none}}\n"]
|
|
224
247
|
}]
|
|
225
248
|
}],
|
|
@@ -291,6 +314,153 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
291
314
|
}]
|
|
292
315
|
}
|
|
293
316
|
});
|
|
294
|
-
|
|
317
|
+
const BEM_BLOCK = "rt-radio-group";
|
|
318
|
+
const NEXT_KEYS = /* @__PURE__ */ new Set(["ArrowDown", "ArrowRight"]);
|
|
319
|
+
const PREV_KEYS = /* @__PURE__ */ new Set(["ArrowUp", "ArrowLeft"]);
|
|
320
|
+
var RtRadioGroupComponent = class RtRadioGroupComponent {
|
|
321
|
+
#host;
|
|
322
|
+
#members;
|
|
323
|
+
constructor() {
|
|
324
|
+
this.#host = inject(ElementRef);
|
|
325
|
+
this.#members = signal([], ...ngDevMode ? [{ debugName: "#members" }] : /* istanbul ignore next */ []);
|
|
326
|
+
this.radios = computed(() => {
|
|
327
|
+
const order = Array.from(this.#host.nativeElement.querySelectorAll("rt-radio-button"));
|
|
328
|
+
return [...this.#members()].sort((a, b) => order.indexOf(a.element) - order.indexOf(b.element));
|
|
329
|
+
}, ...ngDevMode ? [{ debugName: "radios" }] : /* istanbul ignore next */ []);
|
|
330
|
+
this.tabStop = computed(() => {
|
|
331
|
+
const radios = this.radios();
|
|
332
|
+
return radios.find((radio) => radio.selected() && !radio.off()) ?? radios.find((radio) => !radio.off()) ?? null;
|
|
333
|
+
}, ...ngDevMode ? [{ debugName: "tabStop" }] : /* istanbul ignore next */ []);
|
|
334
|
+
this.ariaLabel = input(null, ...ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
|
|
335
|
+
this.orientation = input("vertical", ...ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []);
|
|
336
|
+
afterRenderEffect({ write: () => {
|
|
337
|
+
const stop = this.tabStop();
|
|
338
|
+
for (const radio of this.radios()) radio.setTabStop(Object.is(radio, stop));
|
|
339
|
+
} });
|
|
340
|
+
}
|
|
341
|
+
register(radio) {
|
|
342
|
+
this.#members.update((members) => [...members, radio]);
|
|
343
|
+
}
|
|
344
|
+
unregister(radio) {
|
|
345
|
+
this.#members.update((members) => members.filter((member) => member !== radio));
|
|
346
|
+
}
|
|
347
|
+
onKeydown(event) {
|
|
348
|
+
if (!NEXT_KEYS.has(event.key) && !PREV_KEYS.has(event.key)) return;
|
|
349
|
+
const step = NEXT_KEYS.has(event.key) ? 1 : -1;
|
|
350
|
+
const radios = this.radios();
|
|
351
|
+
const from = radios.findIndex((radio) => radio.contains(event.target));
|
|
352
|
+
if (from < 0) return;
|
|
353
|
+
event.preventDefault();
|
|
354
|
+
for (let shift = 1; shift < radios.length; shift += 1) {
|
|
355
|
+
const next = radios[(from + step * shift + radios.length * shift) % radios.length];
|
|
356
|
+
if (!next.off()) {
|
|
357
|
+
next.selectFromKeyboard();
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
static {
|
|
363
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
364
|
+
minVersion: "12.0.0",
|
|
365
|
+
version: "22.2.2",
|
|
366
|
+
ngImport: i0,
|
|
367
|
+
type: RtRadioGroupComponent,
|
|
368
|
+
deps: [],
|
|
369
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
static {
|
|
373
|
+
this.ɵcmp = i0.ɵɵngDeclareComponent({
|
|
374
|
+
minVersion: "17.1.0",
|
|
375
|
+
version: "22.2.2",
|
|
376
|
+
type: RtRadioGroupComponent,
|
|
377
|
+
isStandalone: true,
|
|
378
|
+
selector: "rt-radio-group",
|
|
379
|
+
inputs: {
|
|
380
|
+
ariaLabel: {
|
|
381
|
+
classPropertyName: "ariaLabel",
|
|
382
|
+
publicName: "ariaLabel",
|
|
383
|
+
isSignal: true,
|
|
384
|
+
isRequired: false,
|
|
385
|
+
transformFunction: null
|
|
386
|
+
},
|
|
387
|
+
orientation: {
|
|
388
|
+
classPropertyName: "orientation",
|
|
389
|
+
publicName: "orientation",
|
|
390
|
+
isSignal: true,
|
|
391
|
+
isRequired: false,
|
|
392
|
+
transformFunction: null
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
host: {
|
|
396
|
+
attributes: { "role": "radiogroup" },
|
|
397
|
+
listeners: { "keydown": "onKeydown($event)" },
|
|
398
|
+
properties: {
|
|
399
|
+
"class.rt-radio-group--horizontal": "orientation() === 'horizontal'",
|
|
400
|
+
"attr.aria-label": "ariaLabel()",
|
|
401
|
+
"attr.aria-orientation": "orientation()"
|
|
402
|
+
},
|
|
403
|
+
classAttribute: "rt-radio-group"
|
|
404
|
+
},
|
|
405
|
+
providers: [{
|
|
406
|
+
provide: RT_RADIO_GROUP,
|
|
407
|
+
useExisting: RtRadioGroupComponent
|
|
408
|
+
}],
|
|
409
|
+
ngImport: i0,
|
|
410
|
+
template: "<ng-content />\n",
|
|
411
|
+
styles: ["@layer rt-kit.components{.rt-radio-group{--rt-radio-group-gap: var(--rt-space-2);display:flex;flex-direction:column;gap:var(--rt-radio-group-gap)}.rt-radio-group--horizontal{flex-flow:row wrap}}\n"],
|
|
412
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush,
|
|
413
|
+
encapsulation: i0.ViewEncapsulation.None
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
418
|
+
minVersion: "12.0.0",
|
|
419
|
+
version: "22.2.2",
|
|
420
|
+
ngImport: i0,
|
|
421
|
+
type: RtRadioGroupComponent,
|
|
422
|
+
decorators: [{
|
|
423
|
+
type: Component,
|
|
424
|
+
args: [{
|
|
425
|
+
selector: "rt-radio-group",
|
|
426
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
427
|
+
encapsulation: ViewEncapsulation.None,
|
|
428
|
+
providers: [{
|
|
429
|
+
provide: RT_RADIO_GROUP,
|
|
430
|
+
useExisting: RtRadioGroupComponent
|
|
431
|
+
}],
|
|
432
|
+
host: {
|
|
433
|
+
class: BEM_BLOCK,
|
|
434
|
+
role: "radiogroup",
|
|
435
|
+
"[class.rt-radio-group--horizontal]": "orientation() === 'horizontal'",
|
|
436
|
+
"[attr.aria-label]": "ariaLabel()",
|
|
437
|
+
"[attr.aria-orientation]": "orientation()",
|
|
438
|
+
"(keydown)": "onKeydown($event)"
|
|
439
|
+
},
|
|
440
|
+
template: "<ng-content />\n",
|
|
441
|
+
styles: ["@layer rt-kit.components{.rt-radio-group{--rt-radio-group-gap: var(--rt-space-2);display:flex;flex-direction:column;gap:var(--rt-radio-group-gap)}.rt-radio-group--horizontal{flex-flow:row wrap}}\n"]
|
|
442
|
+
}]
|
|
443
|
+
}],
|
|
444
|
+
ctorParameters: () => [],
|
|
445
|
+
propDecorators: {
|
|
446
|
+
ariaLabel: [{
|
|
447
|
+
type: i0.Input,
|
|
448
|
+
args: [{
|
|
449
|
+
isSignal: true,
|
|
450
|
+
alias: "ariaLabel",
|
|
451
|
+
required: false
|
|
452
|
+
}]
|
|
453
|
+
}],
|
|
454
|
+
orientation: [{
|
|
455
|
+
type: i0.Input,
|
|
456
|
+
args: [{
|
|
457
|
+
isSignal: true,
|
|
458
|
+
alias: "orientation",
|
|
459
|
+
required: false
|
|
460
|
+
}]
|
|
461
|
+
}]
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
export { RT_RADIO_GROUP, RtRadioButtonComponent, RtRadioGroupComponent };
|
|
295
465
|
|
|
296
466
|
//# sourceMappingURL=rt-tools-ui-kit-v2-radio-button.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rt-tools-ui-kit-v2-radio-button.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/radio-button/rt-radio-button.component.ts","../../../projects/ui-kit-v2/src/lib/components/radio-button/rt-radio-button.component.html"],"sourcesContent":["import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n forwardRef,\n inject,\n Injector,\n input,\n InputSignal,\n InputSignalWithTransform,\n output,\n OutputEmitterRef,\n Signal,\n signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { AbstractControl, ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms';\nimport { distinctUntilChanged, EMPTY, Observable, Subject, switchMap } from 'rxjs';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\n\nconst BEM_BLOCK: string = 'rt-radio-button';\n\n/** Вход выбранности: не заданный вход — `null`, и тогда выбранность решает форма. */\nfunction checkedAttribute(value: BooleanInput | null | undefined): boolean | null {\n return value === null || value === undefined ? null : booleanAttribute(value);\n}\n\n/**\n * Радиокнопка: `role=\"radio\"` с `aria-checked` и `aria-disabled`, выбор нажатием, пробелом и Enter.\n *\n * Выбор приходит двумя путями. Форма пишет модель через `ControlValueAccessor`, и радиокнопка\n * выбрана, когда её значение — сама модель, а не равное ей. Без формы выбранность ставится входом\n * `checked`, а выбор сообщается выходом `checkedChange`: так строку отмечает таблица. Заданный вход\n * решает раньше модели формы.\n *\n * Нажатие на выбранную выбор не снимает — радиокнопку покидают только выбором другой. Каждое\n * нажатие сообщается наружу `clickAction` и дальше обёртки не идёт: строка таблицы под кружком не\n * открывается. Выбор клавишей наружу нажатием не сообщается.\n *\n * Отключение складывается из входа `disabled` и слова формы: форма зовёт `setDisabledState`\n * раньше первого обновления вида, и один общий signal затёр бы её слово.\n *\n * Каждая радиокнопка — свой `ControlValueAccessor`, и значение, отданное одной, форма соседям на\n * том же контроле не пишет: поэтому модель берётся и у самого контрола.\n */\n@Component({\n selector: 'rt-radio-button',\n templateUrl: './rt-radio-button.component.html',\n styleUrl: './rt-radio-button.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone directives\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef((): typeof RtRadioButtonComponent => RtRadioButtonComponent),\n multi: true,\n },\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtRadioButtonComponent implements ControlValueAccessor {\n readonly #injector: Injector = inject(Injector);\n readonly #destroyRef: DestroyRef = inject(DestroyRef);\n\n #onChange: (value: unknown) => void = (): void => undefined;\n #onTouched: () => void = (): void => undefined;\n\n /**\n * Контрол, к которому радиокнопка привязана сейчас. Директива формы меняет его, не пересоздавая\n * себя: `[formControl]` получил другой контрол, `[formGroup]` — другую группу. Слушать надо\n * только нынешний — прежний, оставшись под подпиской, зажёг бы точку из мёртвой формы, и\n * нажатие по ней уже не дошло бы до живой.\n */\n readonly #controlSource: Subject<AbstractControl | null> = new Subject<AbstractControl | null>();\n\n /** Модель, записанная формой. */\n readonly #model: WritableSignal<unknown> = signal<unknown>(null);\n\n /** Отключение, назначенное формой через `setDisabledState`. */\n readonly #disabledByForm: WritableSignal<boolean> = signal<boolean>(false);\n\n protected readonly isChecked: Signal<boolean> = computed((): boolean => this.checked() ?? this.value() === this.#model());\n protected readonly isDisabled: Signal<boolean> = computed((): boolean => this.disabled() || this.#disabledByForm());\n\n /** Значение радиокнопки: выбрана та, чьё значение — модель формы. */\n public readonly value: InputSignal<unknown> = input.required<unknown>();\n\n /** Выбранность без формы; не заданный вход оставляет решение форме. */\n public readonly checked: InputSignalWithTransform<boolean | null, BooleanInput | null | undefined> = input<\n boolean | null,\n BooleanInput | null | undefined\n >(null, { transform: checkedAttribute });\n\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Вид «карточка»: рамка, содержимое слева, кружок справа. */\n public readonly card: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly label: InputSignal<string> = input<string>('');\n public readonly description: InputSignal<string> = input<string>('');\n\n /** Имя для вспомогательных средств, когда видимой подписи нет — кружок в строке таблицы. */\n public readonly ariaLabel: InputSignal<string | null> = input<string | null>(null);\n\n /** Каждое нажатие указателем, сменило оно выбор или нет. */\n public readonly clickAction: OutputEmitterRef<MouseEvent> = output<MouseEvent>();\n\n /** Радиокнопка стала выбранной. */\n public readonly checkedChange: OutputEmitterRef<boolean> = output<boolean>();\n\n constructor() {\n // Значение, отданное соседкой, форма этой радиокнопке не пишет — модель берётся у самого\n // контрола, иначе точка осталась бы у двух сразу. Подписка идёт за сменой контрола и\n // бросает прежний.\n this.#controlSource\n .pipe(\n distinctUntilChanged(),\n switchMap((control: AbstractControl | null): Observable<unknown> => control?.valueChanges ?? EMPTY),\n takeUntilDestroyed(this.#destroyRef)\n )\n .subscribe((value: unknown): void => this.#model.set(value));\n }\n\n public writeValue(value: unknown): void {\n this.#model.set(value);\n }\n\n /**\n * Директива формы зовёт это при каждой привязке к контролу — и первой, и после смены контрола,\n * — уже поставив новый контрол себе. Здесь радиокнопка и узнаёт, кого слушать. Спросить\n * директиву в конструкторе нельзя: она берёт радиокнопку своим accessor, и это круговая\n * зависимость.\n */\n public registerOnChange(fn: (value: unknown) => void): void {\n this.#onChange = fn;\n this.#controlSource.next(this.#injector.get(NgControl, null, { self: true, optional: true })?.control ?? null);\n }\n\n public registerOnTouched(fn: () => void): void {\n this.#onTouched = fn;\n }\n\n public setDisabledState(disabled: boolean): void {\n this.#disabledByForm.set(disabled);\n }\n\n protected onClick(event: MouseEvent): void {\n this.#select();\n this.clickAction.emit(event);\n event.stopPropagation();\n event.preventDefault();\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (event.key !== ' ' && event.key !== 'Enter') {\n return;\n }\n event.preventDefault();\n this.#select();\n }\n\n #select(): void {\n if (this.isDisabled()) {\n return;\n }\n if (!this.isChecked()) {\n this.#model.set(this.value());\n this.#onChange(this.value());\n this.checkedChange.emit(true);\n }\n this.#onTouched();\n }\n}\n","<div\n rtBlock=\"rt-radio-button\"\n qa-dataid=\"radio-button-control\"\n role=\"radio\"\n tabindex=\"0\"\n [rtMod]=\"{ checked: isChecked(), disabled: isDisabled(), card: card() }\"\n [attr.aria-checked]=\"isChecked()\"\n [attr.aria-disabled]=\"isDisabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n (click)=\"onClick($event)\"\n (keydown)=\"onKeydown($event)\">\n <span rtElem=\"indicator\">\n @if (isChecked()) {\n <span rtElem=\"dot\"></span>\n }\n </span>\n\n @if (label() || description()) {\n <span rtElem=\"content\">\n @if (label()) {\n <span rtElem=\"label\" qa-dataid=\"radio-button-label\">{{ label() }}</span>\n }\n @if (description()) {\n <span rtElem=\"description\" qa-dataid=\"radio-button-description\">{{ description() }}</span>\n }\n </span>\n }\n</div>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rt-tools-ui-kit-v2-radio-button.mjs","names":["BEM_BLOCK"],"sources":["../../../projects/ui-kit-v2/src/lib/components/radio-button/rt-radio-group.token.ts","../../../projects/ui-kit-v2/src/lib/components/radio-button/rt-radio-button.component.ts","../../../projects/ui-kit-v2/src/lib/components/radio-button/rt-radio-button.component.html","../../../projects/ui-kit-v2/src/lib/components/radio-button/rt-radio-group.component.ts","../../../projects/ui-kit-v2/src/lib/components/radio-button/rt-radio-group.component.html"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\n/**\n * Что группа знает о радиокнопке. Отдельным описанием, а не классом радиокнопки: радиокнопка\n * импортирует токен, и прямой импорт в обе стороны замкнул бы файлы в круг.\n */\nexport interface IRtRadioGroupMember {\n /** Узел радиокнопки: по нему группа ставит радиокнопки в порядок страницы. */\n readonly element: HTMLElement;\n readonly selected: () => boolean;\n readonly off: () => boolean;\n readonly setTabStop: (on: boolean) => void;\n readonly contains: (target: EventTarget | null) => boolean;\n readonly selectFromKeyboard: () => void;\n}\n\n/**\n * Что радиокнопка сообщает группе, в которой стоит. Радиокнопка встаёт в группу сама, через\n * внедрение: так в группу попадает и радиокнопка из шаблона обёртки потребителя, до которой запрос\n * по содержимому не дотянулся бы.\n */\nexport interface IRtRadioGroupHost {\n /** Ориентация группы. */\n readonly orientation: () => string;\n readonly register: (radio: IRtRadioGroupMember) => void;\n readonly unregister: (radio: IRtRadioGroupMember) => void;\n}\n\nexport const RT_RADIO_GROUP: InjectionToken<IRtRadioGroupHost> = new InjectionToken<IRtRadioGroupHost>('RT_RADIO_GROUP');\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n ElementRef,\n forwardRef,\n inject,\n Injector,\n input,\n InputSignal,\n InputSignalWithTransform,\n output,\n OutputEmitterRef,\n Signal,\n signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { AbstractControl, ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms';\nimport { distinctUntilChanged, EMPTY, Observable, Subject, switchMap } from 'rxjs';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\n\nimport { IRtRadioGroupHost, RT_RADIO_GROUP } from './rt-radio-group.token';\n\nconst BEM_BLOCK: string = 'rt-radio-button';\n\n/** Вход выбранности: не заданный вход — `null`, и тогда выбранность решает форма. */\nfunction checkedAttribute(value: BooleanInput | null | undefined): boolean | null {\n return value === null || value === undefined ? null : booleanAttribute(value);\n}\n\n/**\n * Радиокнопка: `role=\"radio\"` с `aria-checked` и `aria-disabled`, выбор нажатием, пробелом и Enter.\n *\n * Выбор приходит двумя путями. Форма пишет модель через `ControlValueAccessor`, и радиокнопка\n * выбрана, когда её значение — сама модель, а не равное ей. Без формы выбранность ставится входом\n * `checked`, а выбор сообщается выходом `checkedChange`: так строку отмечает таблица. Заданный вход\n * решает раньше модели формы.\n *\n * Нажатие на выбранную выбор не снимает — радиокнопку покидают только выбором другой. Каждое\n * нажатие сообщается наружу `clickAction` и дальше обёртки не идёт: строка таблицы под кружком не\n * открывается. Выбор клавишей наружу нажатием не сообщается.\n *\n * Отключение складывается из входа `disabled` и слова формы: форма зовёт `setDisabledState`\n * раньше первого обновления вида, и один общий signal затёр бы её слово.\n *\n * Внутри `rt-radio-group` в порядке обхода по Tab стоит одна радиокнопка группы, а соседей выбирают\n * стрелки; вне группы каждая радиокнопка стоит в порядке обхода сама, как прежде.\n *\n * Каждая радиокнопка — свой `ControlValueAccessor`, и значение, отданное одной, форма соседям на\n * том же контроле не пишет: поэтому модель берётся и у самого контрола.\n */\n@Component({\n selector: 'rt-radio-button',\n templateUrl: './rt-radio-button.component.html',\n styleUrl: './rt-radio-button.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone directives\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef((): typeof RtRadioButtonComponent => RtRadioButtonComponent),\n multi: true,\n },\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtRadioButtonComponent implements ControlValueAccessor {\n readonly #injector: Injector = inject(Injector);\n readonly #destroyRef: DestroyRef = inject(DestroyRef);\n readonly #host: ElementRef<HTMLElement> = inject<ElementRef<HTMLElement>>(ElementRef);\n readonly #group: IRtRadioGroupHost | null = inject(RT_RADIO_GROUP, { optional: true });\n\n #onChange: (value: unknown) => void = (): void => undefined;\n #onTouched: () => void = (): void => undefined;\n\n /**\n * Контрол, к которому радиокнопка привязана сейчас. Директива формы меняет его, не пересоздавая\n * себя: `[formControl]` получил другой контрол, `[formGroup]` — другую группу. Слушать надо\n * только нынешний — прежний, оставшись под подпиской, зажёг бы точку из мёртвой формы, и\n * нажатие по ней уже не дошло бы до живой.\n */\n readonly #controlSource: Subject<AbstractControl | null> = new Subject<AbstractControl | null>();\n\n /** Модель, записанная формой. */\n readonly #model: WritableSignal<unknown> = signal<unknown>(null);\n\n /** Отключение, назначенное формой через `setDisabledState`. */\n readonly #disabledByForm: WritableSignal<boolean> = signal<boolean>(false);\n\n protected readonly isChecked: Signal<boolean> = computed((): boolean => this.checked() ?? this.value() === this.#model());\n protected readonly isDisabled: Signal<boolean> = computed((): boolean => this.disabled() || this.#disabledByForm());\n\n /** Шаг Tab, отданный группой; до первого слова группы радиокнопка в группе вне обхода. */\n readonly #tabStop: WritableSignal<boolean> = signal<boolean>(false);\n\n /** Место в порядке обхода: в группе — только у той, на которую указала группа. */\n protected readonly tabIndex: Signal<number> = computed((): number => (this.#group === null || this.#tabStop() ? 0 : -1));\n\n /** Узел радиокнопки: по нему группа ставит радиокнопки в порядок страницы. */\n public readonly element: HTMLElement = this.#host.nativeElement;\n\n /** Значение радиокнопки: выбрана та, чьё значение — модель формы. */\n public readonly value: InputSignal<unknown> = input.required<unknown>();\n\n /** Выбранность без формы; не заданный вход оставляет решение форме. */\n public readonly checked: InputSignalWithTransform<boolean | null, BooleanInput | null | undefined> = input<\n boolean | null,\n BooleanInput | null | undefined\n >(null, { transform: checkedAttribute });\n\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Вид «карточка»: рамка, содержимое слева, кружок справа. */\n public readonly card: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly label: InputSignal<string> = input<string>('');\n public readonly description: InputSignal<string> = input<string>('');\n\n /** Имя для вспомогательных средств, когда видимой подписи нет — кружок в строке таблицы. */\n public readonly ariaLabel: InputSignal<string | null> = input<string | null>(null);\n\n /** Выбрана ли радиокнопка — для группы, которая ведёт по ним стрелками. */\n public readonly selected: Signal<boolean> = computed((): boolean => this.isChecked());\n\n /** Отключена ли радиокнопка — группа её пропускает. */\n public readonly off: Signal<boolean> = computed((): boolean => this.isDisabled());\n\n /** Каждое нажатие указателем, сменило оно выбор или нет. */\n public readonly clickAction: OutputEmitterRef<MouseEvent> = output<MouseEvent>();\n\n /** Радиокнопка стала выбранной. */\n public readonly checkedChange: OutputEmitterRef<boolean> = output<boolean>();\n\n constructor() {\n // Радиокнопка встаёт в группу сама: так группа знает и радиокнопку из шаблона обёртки.\n this.#group?.register(this);\n this.#destroyRef.onDestroy((): void => this.#group?.unregister(this));\n\n // Значение, отданное соседкой, форма этой радиокнопке не пишет — модель берётся у самого\n // контрола, иначе точка осталась бы у двух сразу. Подписка идёт за сменой контрола и\n // бросает прежний.\n this.#controlSource\n .pipe(\n distinctUntilChanged(),\n switchMap((control: AbstractControl | null): Observable<unknown> => control?.valueChanges ?? EMPTY),\n takeUntilDestroyed(this.#destroyRef)\n )\n .subscribe((value: unknown): void => this.#model.set(value));\n }\n\n public writeValue(value: unknown): void {\n this.#model.set(value);\n }\n\n /**\n * Директива формы зовёт это при каждой привязке к контролу — и первой, и после смены контрола,\n * — уже поставив новый контрол себе. Здесь радиокнопка и узнаёт, кого слушать. Спросить\n * директиву в конструкторе нельзя: она берёт радиокнопку своим accessor, и это круговая\n * зависимость.\n */\n public registerOnChange(fn: (value: unknown) => void): void {\n this.#onChange = fn;\n this.#controlSource.next(this.#injector.get(NgControl, null, { self: true, optional: true })?.control ?? null);\n }\n\n public registerOnTouched(fn: () => void): void {\n this.#onTouched = fn;\n }\n\n public setDisabledState(disabled: boolean): void {\n this.#disabledByForm.set(disabled);\n }\n\n /** Группа отдаёт или забирает шаг Tab. */\n public setTabStop(on: boolean): void {\n this.#tabStop.set(on);\n }\n\n /** Лежит ли узел внутри радиокнопки — группа так находит, с какой ушла стрелка. */\n public contains(target: EventTarget | null): boolean {\n return target instanceof Node && this.#host.nativeElement.contains(target);\n }\n\n /** Выбор стрелкой из группы: фокус и выбор переходят сюда вместе. */\n public selectFromKeyboard(): void {\n this.#host.nativeElement.querySelector<HTMLElement>('[role=\"radio\"]')?.focus();\n this.#select();\n }\n\n protected onClick(event: MouseEvent): void {\n this.#select();\n this.clickAction.emit(event);\n event.stopPropagation();\n event.preventDefault();\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (event.key !== ' ' && event.key !== 'Enter') {\n return;\n }\n event.preventDefault();\n this.#select();\n }\n\n #select(): void {\n if (this.isDisabled()) {\n return;\n }\n if (!this.isChecked()) {\n this.#model.set(this.value());\n this.#onChange(this.value());\n this.checkedChange.emit(true);\n }\n this.#onTouched();\n }\n}\n","<div\n rtBlock=\"rt-radio-button\"\n qa-dataid=\"radio-button-control\"\n role=\"radio\"\n [attr.tabindex]=\"tabIndex()\"\n [rtMod]=\"{ checked: isChecked(), disabled: isDisabled(), card: card() }\"\n [attr.aria-checked]=\"isChecked()\"\n [attr.aria-disabled]=\"isDisabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n (click)=\"onClick($event)\"\n (keydown)=\"onKeydown($event)\">\n <span rtElem=\"indicator\">\n @if (isChecked()) {\n <span rtElem=\"dot\"></span>\n }\n </span>\n\n @if (label() || description()) {\n <span rtElem=\"content\">\n @if (label()) {\n <span rtElem=\"label\" qa-dataid=\"radio-button-label\">{{ label() }}</span>\n }\n @if (description()) {\n <span rtElem=\"description\" qa-dataid=\"radio-button-description\">{{ description() }}</span>\n }\n </span>\n }\n</div>\n","import {\n afterRenderEffect,\n computed,\n inject,\n input,\n ElementRef,\n signal,\n ChangeDetectionStrategy,\n Component,\n InputSignal,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport { IRtRadioGroupHost, IRtRadioGroupMember, RT_RADIO_GROUP } from './rt-radio-group.token';\n\nconst BEM_BLOCK: string = 'rt-radio-group';\n\n/** Клавиши, переводящие выбор на соседа: вперёд и назад. */\nconst NEXT_KEYS: ReadonlySet<string> = new Set<string>(['ArrowDown', 'ArrowRight']);\nconst PREV_KEYS: ReadonlySet<string> = new Set<string>(['ArrowUp', 'ArrowLeft']);\n\n/** Раскладка группы: столбцом или строкой с переносом. */\nexport type TRtRadioGroupOrientation = 'vertical' | 'horizontal';\n\n/**\n * Группа радиокнопок: `role=\"radiogroup\"`, имя группы и ход стрелками.\n *\n * Стрелки переводят фокус и выбор на соседнюю включённую радиокнопку, по кругу; в порядке обхода по\n * Tab стоит одна радиокнопка группы — выбранная, а пока выбора нет, первая включённая. Выбор и форма\n * остаются у самих радиокнопок: группа значения не держит, и радиокнопки вне группы работают как\n * прежде.\n */\n@Component({\n selector: 'rt-radio-group',\n templateUrl: './rt-radio-group.component.html',\n styleUrl: './rt-radio-group.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n providers: [{ provide: RT_RADIO_GROUP, useExisting: RtRadioGroupComponent }],\n host: {\n class: BEM_BLOCK,\n role: 'radiogroup',\n '[class.rt-radio-group--horizontal]': \"orientation() === 'horizontal'\",\n '[attr.aria-label]': 'ariaLabel()',\n '[attr.aria-orientation]': 'orientation()',\n '(keydown)': 'onKeydown($event)',\n },\n})\nexport class RtRadioGroupComponent implements IRtRadioGroupHost {\n readonly #host: ElementRef<HTMLElement> = inject<ElementRef<HTMLElement>>(ElementRef);\n\n /**\n * Радиокнопки группы. Их список ведут сами радиокнопки, а не запрос по содержимому: запрос не\n * видит радиокнопку из шаблона обёртки потребителя, и такая радиокнопка осталась бы вне обхода.\n */\n readonly #members: WritableSignal<readonly IRtRadioGroupMember[]> = signal<readonly IRtRadioGroupMember[]>([]);\n\n /** Радиокнопки в порядке страницы: регистрация идёт в порядке создания, а не расположения. */\n protected readonly radios: Signal<readonly IRtRadioGroupMember[]> = computed((): readonly IRtRadioGroupMember[] => {\n const order: readonly Element[] = Array.from(this.#host.nativeElement.querySelectorAll('rt-radio-button'));\n return [...this.#members()].sort(\n (a: IRtRadioGroupMember, b: IRtRadioGroupMember): number => order.indexOf(a.element) - order.indexOf(b.element)\n );\n });\n\n /** Радиокнопка, стоящая в порядке обхода: выбранная, иначе первая включённая. */\n protected readonly tabStop: Signal<IRtRadioGroupMember | null> = computed((): IRtRadioGroupMember | null => {\n const radios: readonly IRtRadioGroupMember[] = this.radios();\n return (\n radios.find((radio: IRtRadioGroupMember): boolean => radio.selected() && !radio.off()) ??\n radios.find((radio: IRtRadioGroupMember): boolean => !radio.off()) ??\n null\n );\n });\n\n /** Имя группы для вспомогательных средств — вопрос, на который отвечают радиокнопки. */\n public readonly ariaLabel: InputSignal<string | null> = input<string | null>(null);\n\n public readonly orientation: InputSignal<TRtRadioGroupOrientation> = input<TRtRadioGroupOrientation>('vertical');\n\n constructor() {\n // Шаг Tab раздаётся после отрисовки: радиокнопки, выведенные `@for`, получают значение по\n // одной, и чтение выбора соседки до того, как ей поставили значение, роняет вид (NG0950).\n afterRenderEffect({\n write: (): void => {\n const stop: IRtRadioGroupMember | null = this.tabStop();\n for (const radio of this.radios()) {\n radio.setTabStop(Object.is(radio, stop));\n }\n },\n });\n }\n\n public register(radio: IRtRadioGroupMember): void {\n this.#members.update((members: readonly IRtRadioGroupMember[]): readonly IRtRadioGroupMember[] => [...members, radio]);\n }\n\n public unregister(radio: IRtRadioGroupMember): void {\n this.#members.update((members: readonly IRtRadioGroupMember[]): readonly IRtRadioGroupMember[] =>\n members.filter((member: IRtRadioGroupMember): boolean => member !== radio)\n );\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (!NEXT_KEYS.has(event.key) && !PREV_KEYS.has(event.key)) {\n return;\n }\n const step: number = NEXT_KEYS.has(event.key) ? 1 : -1;\n const radios: readonly IRtRadioGroupMember[] = this.radios();\n const from: number = radios.findIndex((radio: IRtRadioGroupMember): boolean => radio.contains(event.target));\n if (from < 0) {\n return;\n }\n event.preventDefault();\n for (let shift: number = 1; shift < radios.length; shift += 1) {\n const next: IRtRadioGroupMember = radios[(from + step * shift + radios.length * shift) % radios.length];\n if (!next.off()) {\n next.selectFromKeyboard();\n return;\n }\n }\n }\n}\n","<ng-content />\n"],"mappings":"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"}
|