@rt-tools/ui-kit-v2 0.29.0 → 0.30.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-popover.mjs +4 -0
- package/fesm2022/rt-tools-ui-kit-v2-popover.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-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-table.mjs +4 -1
- package/fesm2022/rt-tools-ui-kit-v2-table.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/package.json +1 -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/popover/CONTEXT.md +2 -1
- 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-side-menu.d.ts +5 -20
- package/types/rt-tools-ui-kit-v2-table.d.ts +4 -0
- 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/src/styles/_place.scss +0 -7
|
@@ -2,14 +2,13 @@ import { NgTemplateOutlet } from "@angular/common";
|
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
3
|
import { ChangeDetectionStrategy, Component, ViewEncapsulation, booleanAttribute, computed, forwardRef, inject, input, output, signal, viewChild } from "@angular/core";
|
|
4
4
|
import { BlockDirective, ElemDirective, ModDirective } from "@rt-tools/core";
|
|
5
|
-
import { RT_KIT_LABELS } from "@rt-tools/ui-kit-v2/core";
|
|
5
|
+
import { RT_KIT_LABELS, RtOptionList } from "@rt-tools/ui-kit-v2/core";
|
|
6
6
|
import { RtFormControlBase } from "@rt-tools/ui-kit-v2/form-control";
|
|
7
7
|
import { RtIconComponent } from "@rt-tools/ui-kit-v2/icon";
|
|
8
8
|
import { RtIconButtonComponent } from "@rt-tools/ui-kit-v2/icon-button";
|
|
9
9
|
import { RtPopoverDirective } from "@rt-tools/ui-kit-v2/popover";
|
|
10
10
|
import * as i1 from "@rt-tools/ui-kit-v2/radius";
|
|
11
11
|
import { RtRadiusDirective } from "@rt-tools/ui-kit-v2/radius";
|
|
12
|
-
import { rtScrollActiveOptionIntoView } from "@rt-tools/ui-kit-v2/select";
|
|
13
12
|
const BEM_BLOCK = "rt-autocomplete";
|
|
14
13
|
let panelIdSeed = 0;
|
|
15
14
|
function nextPanelId() {
|
|
@@ -18,15 +17,23 @@ function nextPanelId() {
|
|
|
18
17
|
}
|
|
19
18
|
var RtAutocompleteComponent = class RtAutocompleteComponent extends RtFormControlBase {
|
|
20
19
|
constructor() {
|
|
21
|
-
super();
|
|
20
|
+
super(...arguments);
|
|
22
21
|
this.t = inject(RT_KIT_LABELS);
|
|
23
22
|
this.panelId = `rt-autocomplete-panel-${nextPanelId()}`;
|
|
24
23
|
this.popover = viewChild.required(RtPopoverDirective, ...ngDevMode ? [{ debugName: "popover" }] : /* istanbul ignore next */ []);
|
|
25
24
|
this.fieldEl = viewChild("fieldEl", ...ngDevMode ? [{ debugName: "fieldEl" }] : /* istanbul ignore next */ []);
|
|
26
25
|
this.inputText = signal("", ...ngDevMode ? [{ debugName: "inputText" }] : /* istanbul ignore next */ []);
|
|
27
|
-
this.activeIndex = signal(-1, ...ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []);
|
|
28
26
|
this.isOpen = computed(() => this.popover().isOpen(), ...ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []);
|
|
29
|
-
this.
|
|
27
|
+
this.optionList = new RtOptionList({
|
|
28
|
+
panelId: () => this.panelId,
|
|
29
|
+
isOpen: () => this.isOpen(),
|
|
30
|
+
count: () => this.suggestions().length,
|
|
31
|
+
chooseKeys: /* @__PURE__ */ new Set(["Enter"]),
|
|
32
|
+
sideKeys: false,
|
|
33
|
+
edgeKeys: false
|
|
34
|
+
});
|
|
35
|
+
this.activeIndex = this.optionList.activeIndex;
|
|
36
|
+
this.activeOptionId = this.optionList.activeOptionId;
|
|
30
37
|
this.hasValue = computed(() => this.inputText() !== "", ...ngDevMode ? [{ debugName: "hasValue" }] : /* istanbul ignore next */ []);
|
|
31
38
|
this.displayText = computed(() => this.displayWith()(this.value()), ...ngDevMode ? [{ debugName: "displayText" }] : /* istanbul ignore next */ []);
|
|
32
39
|
this.suggestions = input([], ...ngDevMode ? [{ debugName: "suggestions" }] : /* istanbul ignore next */ []);
|
|
@@ -41,7 +48,6 @@ var RtAutocompleteComponent = class RtAutocompleteComponent extends RtFormContro
|
|
|
41
48
|
this.itemTemplate = input(null, ...ngDevMode ? [{ debugName: "itemTemplate" }] : /* istanbul ignore next */ []);
|
|
42
49
|
this.complete = output();
|
|
43
50
|
this.itemSelect = output();
|
|
44
|
-
rtScrollActiveOptionIntoView(this.activeOptionId);
|
|
45
51
|
}
|
|
46
52
|
writeValue(value) {
|
|
47
53
|
super.writeValue(value);
|
|
@@ -98,32 +104,21 @@ var RtAutocompleteComponent = class RtAutocompleteComponent extends RtFormContro
|
|
|
98
104
|
if (this.isDisabled()) return;
|
|
99
105
|
const key = event.key;
|
|
100
106
|
if (!this.isOpen()) return;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
const action = this.optionList.actionOf(key);
|
|
108
|
+
if (action === "none" || action === "side") return;
|
|
109
|
+
event.preventDefault();
|
|
110
|
+
switch (action) {
|
|
111
|
+
case "next":
|
|
112
|
+
this.optionList.move(1);
|
|
105
113
|
break;
|
|
106
|
-
case "
|
|
107
|
-
|
|
108
|
-
this.#moveActive(-1);
|
|
114
|
+
case "previous":
|
|
115
|
+
this.optionList.move(-1);
|
|
109
116
|
break;
|
|
110
|
-
case "
|
|
111
|
-
event.preventDefault();
|
|
117
|
+
case "choose":
|
|
112
118
|
this.#selectActive();
|
|
113
119
|
break;
|
|
114
|
-
case "
|
|
115
|
-
event.preventDefault();
|
|
116
|
-
this.popover().close();
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
#moveActive(delta) {
|
|
120
|
-
const items = this.suggestions();
|
|
121
|
-
if (items.length === 0) {
|
|
122
|
-
this.activeIndex.set(-1);
|
|
123
|
-
return;
|
|
120
|
+
case "close": this.popover().close();
|
|
124
121
|
}
|
|
125
|
-
const next = (this.activeIndex() + delta + items.length) % items.length;
|
|
126
|
-
this.activeIndex.set(next);
|
|
127
122
|
}
|
|
128
123
|
#selectActive() {
|
|
129
124
|
const items = this.suggestions();
|
|
@@ -136,7 +131,7 @@ var RtAutocompleteComponent = class RtAutocompleteComponent extends RtFormContro
|
|
|
136
131
|
version: "22.2.2",
|
|
137
132
|
ngImport: i0,
|
|
138
133
|
type: RtAutocompleteComponent,
|
|
139
|
-
deps:
|
|
134
|
+
deps: null,
|
|
140
135
|
target: i0.ɵɵFactoryTarget.Component
|
|
141
136
|
});
|
|
142
137
|
}
|
|
@@ -375,7 +370,6 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
375
370
|
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-autocomplete{--rt-autocomplete-radius: var(--rt-input-radius);position:relative;display:block;width:100%}.rt-autocomplete__field{display:inline-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-autocomplete-radius);background-color:var(--rt-input-color-bg);color:var(--rt-input-color-text);cursor:text;font-size:var(--rt-input-font-size);gap:var(--rt-space-sm);line-height:var(--rt-input-line-height);transition:var(--rt-input-transition)}.rt-autocomplete__field:focus-within{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-autocomplete--borderless .rt-autocomplete__field{border-color:transparent}.rt-autocomplete--open .rt-autocomplete__field{border-color:var(--rt-input-color-border-focus)}.rt-autocomplete--invalid .rt-autocomplete__field{border-color:var(--rt-input-color-border-error)}.rt-autocomplete--invalid .rt-autocomplete__field:focus-within{box-shadow:var(--rt-input-focus-shadow-error)}.rt-autocomplete--disabled .rt-autocomplete__field{cursor:not-allowed;opacity:var(--rt-input-disabled-opacity)}.rt-autocomplete--size--sm .rt-autocomplete__field{min-height:var(--rt-input-height-sm)}.rt-autocomplete--size--lg .rt-autocomplete__field{min-height:var(--rt-input-height-lg)}.rt-autocomplete--readonly .rt-autocomplete__field{display:none}.rt-autocomplete__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-autocomplete__readonly--empty{color:var(--rt-field-value-empty-color)}.rt-autocomplete__input{min-width:0;flex:1 1 auto;padding:0;border:none;background:transparent;color:inherit;font:inherit;outline:none}.rt-autocomplete__input::placeholder{color:var(--rt-input-color-text-placeholder);opacity:1}.rt-autocomplete__input:disabled{cursor:not-allowed}.rt-autocomplete__icon-left,.rt-autocomplete__clear{flex-shrink:0}.rt-autocomplete__panel{--rt-autocomplete-panel-shadow: var(--rt-shadow-md);width:100%;max-height:var(--rt-input-panel-max-height);box-sizing:border-box;padding:var(--rt-space-2xs) 0;border:var(--rt-input-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-input-radius);margin:0;background-color:var(--rt-color-bg-surface);box-shadow:var(--rt-autocomplete-panel-shadow);list-style:none;overflow-y:auto}.rt-autocomplete__option{padding:var(--rt-space-sm) var(--rt-space-md);color:var(--rt-color-text-primary);cursor:pointer;font-size:var(--rt-input-font-size)}.rt-autocomplete__option:hover,.rt-autocomplete__option--active{background-color:var(--rt-color-bg-hover)}.rt-autocomplete__empty{padding:var(--rt-space-sm) var(--rt-space-md);color:var(--rt-input-color-text-placeholder);font-style:italic}.rt-autocomplete[data-rt-radius=none]{--rt-autocomplete-radius: var(--rt-radius-none)}.rt-autocomplete[data-rt-radius=xs]{--rt-autocomplete-radius: var(--rt-radius-xs)}.rt-autocomplete[data-rt-radius=sm]{--rt-autocomplete-radius: var(--rt-radius-sm)}.rt-autocomplete[data-rt-radius=ms]{--rt-autocomplete-radius: var(--rt-radius-ms)}.rt-autocomplete[data-rt-radius=md]{--rt-autocomplete-radius: var(--rt-radius-md)}.rt-autocomplete[data-rt-radius=lg]{--rt-autocomplete-radius: var(--rt-radius-lg)}.rt-autocomplete[data-rt-radius=xl]{--rt-autocomplete-radius: var(--rt-radius-xl)}.rt-autocomplete[data-rt-radius=\"2xl\"]{--rt-autocomplete-radius: var(--rt-radius-2xl)}.rt-autocomplete[data-rt-radius=full]{--rt-autocomplete-radius: var(--rt-radius-full)}}\n"]
|
|
376
371
|
}]
|
|
377
372
|
}],
|
|
378
|
-
ctorParameters: () => [],
|
|
379
373
|
propDecorators: {
|
|
380
374
|
popover: [{
|
|
381
375
|
type: i0.ViewChild,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rt-tools-ui-kit-v2-autocomplete.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/autocomplete/rt-autocomplete.component.ts","../../../projects/ui-kit-v2/src/lib/components/autocomplete/rt-autocomplete.component.html"],"sourcesContent":["import { BooleanInput } from '@angular/cdk/coercion';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n computed,\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 TemplateRef,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RT_KIT_LABELS, TRtKitLabelMap } from '@rt-tools/ui-kit-v2/core';\nimport { RtFormControlBase } from '@rt-tools/ui-kit-v2/form-control';\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 { RtPopoverDirective } from '@rt-tools/ui-kit-v2/popover';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { rtScrollActiveOptionIntoView } from '@rt-tools/ui-kit-v2/select';\nimport { IRtAutocomplete } from './rt-autocomplete.model';\n\nconst BEM_BLOCK: string = 'rt-autocomplete';\n\nlet panelIdSeed: number = 0;\n\nfunction nextPanelId(): number {\n panelIdSeed += 1;\n return panelIdSeed;\n}\n\n/**\n * Typeahead/autocomplete с server-side filter через `(complete)` event.\n *\n * Panel рендерится через CDK Overlay (`[rtPopover]` trigger=\"manual\" на input'е)\n * — открывается по набору текста (не click/hover), не обрезается overflow.\n * Подписчик получает `(complete)` с текущей строкой и сам грузит подсказки.\n *\n * CVA через общий `RtFormControlBase`. Generic `TItem` — тип подсказки и\n * selected value. Крестик (`clearable`) виден при непустом тексте — очищает и\n * текст, и выбранный объект. Keyboard-nav (activedescendant): ArrowUp/Down —\n * highlight, Enter — выбрать активную, Escape — закрыть. Home/End — deferred.\n */\n@Component({\n selector: 'rt-autocomplete',\n templateUrl: './rt-autocomplete.component.html',\n styleUrl: './rt-autocomplete.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n NgTemplateOutlet,\n\n // standalone components / directives\n RtIconButtonComponent,\n RtIconComponent,\n RtPopoverDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n providers: [\n // Алиас базового токена — для contentChild(RtFormControlBase) в rt-field.\n { provide: RtFormControlBase, useExisting: forwardRef(() => RtAutocompleteComponent) },\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n '[class.rt-autocomplete--open]': 'isOpen()',\n '[class.rt-autocomplete--disabled]': 'isDisabled()',\n '[class.rt-autocomplete--readonly]': 'isReadonly()',\n '[class.rt-autocomplete--invalid]': 'isInvalid()',\n '[class.rt-autocomplete--borderless]': '!bordered()',\n '[class.rt-autocomplete--size--sm]': \"size() === 'sm'\",\n '[class.rt-autocomplete--size--lg]': \"size() === 'lg'\",\n },\n})\nexport class RtAutocompleteComponent<TItem> extends RtFormControlBase<TItem | null> {\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly panelId: string = `rt-autocomplete-panel-${nextPanelId()}`;\n\n protected readonly popover: Signal<RtPopoverDirective> = viewChild.required(RtPopoverDirective);\n\n protected readonly fieldEl: Signal<ElementRef<HTMLInputElement> | undefined> = viewChild<ElementRef<HTMLInputElement>>('fieldEl');\n\n protected readonly inputText: WritableSignal<string> = signal<string>('');\n protected readonly activeIndex: WritableSignal<number> = signal<number>(-1);\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 protected readonly hasValue: Signal<boolean> = computed((): boolean => this.inputText() !== '');\n\n public readonly displayText: Signal<string> = computed((): string => this.displayWith()(this.value()));\n\n public readonly suggestions: InputSignal<ReadonlyArray<TItem>> = input<ReadonlyArray<TItem>>([]);\n\n public readonly displayWith: InputSignal<(item: TItem | null) => string> = input<(item: TItem | null) => string>(\n (item: TItem | null): string => String(item ?? '')\n );\n\n public readonly placeholder: InputSignal<string> = input<string>('');\n public readonly minLength: InputSignal<number> = input<number>(1);\n\n /** Префикс-иконка слева в поле (например, `map` для поиска). */\n public readonly iconLeft: InputSignal<IRtIcon.Name | null> = input<IRtIcon.Name | null>(null);\n\n public readonly openOnFocus: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly itemTemplate: InputSignal<TemplateRef<{ $implicit: TItem }> | null> = input<TemplateRef<{ $implicit: TItem }> | null>(\n null\n );\n\n public readonly complete: OutputEmitterRef<IRtAutocomplete.CompleteEvent> = output<IRtAutocomplete.CompleteEvent>();\n\n public readonly itemSelect: OutputEmitterRef<TItem> = output<TItem>();\n\n constructor() {\n super();\n // Подсветка, сдвинутая клавишами, не уходит за край панели с пределом высоты.\n rtScrollActiveOptionIntoView(this.activeOptionId);\n }\n\n public override writeValue(value: TItem | null): void {\n super.writeValue(value);\n this.inputText.set(this.displayWith()(this.value()));\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(): TItem | null {\n return null;\n }\n\n protected focusAfterClear(): void {\n this.fieldEl()?.nativeElement.focus();\n }\n\n protected override clearValue(): void {\n super.clearValue();\n this.inputText.set('');\n }\n\n protected onInput(event: Event): void {\n const target: HTMLInputElement = event.target as HTMLInputElement;\n const query: string = target.value;\n this.inputText.set(query);\n this.activeIndex.set(-1);\n if (query.length >= this.minLength()) {\n this.complete.emit({ query, originalEvent: event });\n this.popover().open();\n } else {\n this.popover().close();\n }\n }\n\n protected onFocus(): void {\n if (!this.openOnFocus()) {\n return;\n }\n this.complete.emit({ query: this.inputText(), originalEvent: new Event('focus') });\n this.popover().open();\n }\n\n protected onBlur(): void {\n this.markTouched();\n }\n\n protected onClosed(): void {\n this.activeIndex.set(-1);\n }\n\n protected onSelect(item: TItem): void {\n this.value.set(item);\n this.inputText.set(this.displayWith()(item));\n this.emitChange(item);\n this.itemSelect.emit(item);\n this.popover().close();\n }\n\n protected onInputKeydown(event: KeyboardEvent): void {\n if (this.isDisabled()) {\n return;\n }\n const key: string = event.key;\n if (!this.isOpen()) {\n return;\n }\n switch (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 event.preventDefault();\n this.#selectActive();\n break;\n case 'Escape':\n event.preventDefault();\n this.popover().close();\n break;\n default:\n break;\n }\n }\n\n #moveActive(delta: number): void {\n const items: ReadonlyArray<TItem> = this.suggestions();\n if (items.length === 0) {\n this.activeIndex.set(-1);\n return;\n }\n const index: number = this.activeIndex();\n const next: number = (index + delta + items.length) % items.length;\n this.activeIndex.set(next);\n }\n\n #selectActive(): void {\n const items: ReadonlyArray<TItem> = this.suggestions();\n const index: number = this.activeIndex();\n if (index >= 0 && index < items.length) {\n this.onSelect(items[index]);\n }\n }\n}\n","<ng-container rtBlock=\"rt-autocomplete\">\n @if (isReadonly()) {\n <span rtElem=\"readonly\" qa-dataid=\"autocomplete-readonly\" [rtMod]=\"{ empty: !displayText() }\">{{ displayText() || '—' }}</span>\n }\n <div rtElem=\"field\" rtPopoverTrigger=\"manual\" rtPopoverWidth=\"trigger\" [rtPopover]=\"panelTpl\" (rtPopoverClosed)=\"onClosed()\">\n @if (iconLeft(); as left) {\n <rt-icon rtElem=\"icon-left\" size=\"sm\" color=\"muted\" [name]=\"left\" />\n }\n <input\n #fieldEl\n rtElem=\"input\"\n qa-dataid=\"autocomplete-input\"\n type=\"text\"\n autocomplete=\"off\"\n role=\"combobox\"\n [attr.id]=\"effectiveControlId()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-invalid]=\"isInvalid() || null\"\n [attr.aria-autocomplete]=\"'list'\"\n [attr.aria-controls]=\"panelId\"\n [attr.aria-activedescendant]=\"activeOptionId()\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputText()\"\n [disabled]=\"isDisabled()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onInputKeydown($event)\" />\n @if (showClearButton()) {\n <rt-icon-button\n rtElem=\"clear\"\n qa-dataid=\"autocomplete-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 </div>\n\n <ng-template #panelTpl>\n <!--\n Опции выбираются мышью через (click); keyboard-nav — на input'е\n (activedescendant), опции не focusable индивидуально.\n -->\n <!-- eslint-disable @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <ul rtElem=\"panel\" qa-dataid=\"autocomplete-panel\" role=\"listbox\" [id]=\"panelId\">\n @for (item of suggestions(); track $index; let i = $index) {\n <li\n rtElem=\"option\"\n qa-dataid=\"autocomplete-option\"\n role=\"option\"\n [id]=\"panelId + '-opt-' + i\"\n [rtMod]=\"{ active: i === activeIndex() }\"\n [attr.aria-selected]=\"item === value()\"\n (click)=\"onSelect(item)\">\n @if (itemTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: item }\" />\n } @else {\n {{ displayWith()(item) }}\n }\n </li>\n } @empty {\n <li rtElem=\"empty\" qa-dataid=\"autocomplete-empty\">{{ t().uiNothingFound }}</li>\n }\n </ul>\n </ng-template>\n</ng-container>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rt-tools-ui-kit-v2-autocomplete.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/autocomplete/rt-autocomplete.component.ts","../../../projects/ui-kit-v2/src/lib/components/autocomplete/rt-autocomplete.component.html"],"sourcesContent":["import { BooleanInput } from '@angular/cdk/coercion';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n computed,\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 TemplateRef,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RT_KIT_LABELS, TRtKitLabelMap } from '@rt-tools/ui-kit-v2/core';\nimport { RtFormControlBase } from '@rt-tools/ui-kit-v2/form-control';\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 { RtPopoverDirective } 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 { IRtAutocomplete } from './rt-autocomplete.model';\n\nconst BEM_BLOCK: string = 'rt-autocomplete';\n\nlet panelIdSeed: number = 0;\n\nfunction nextPanelId(): number {\n panelIdSeed += 1;\n return panelIdSeed;\n}\n\n/**\n * Typeahead/autocomplete с server-side filter через `(complete)` event.\n *\n * Panel рендерится через CDK Overlay (`[rtPopover]` trigger=\"manual\" на input'е)\n * — открывается по набору текста (не click/hover), не обрезается overflow.\n * Подписчик получает `(complete)` с текущей строкой и сам грузит подсказки.\n *\n * CVA через общий `RtFormControlBase`. Generic `TItem` — тип подсказки и\n * selected value. Крестик (`clearable`) виден при непустом тексте — очищает и\n * текст, и выбранный объект. Keyboard-nav (activedescendant): ArrowUp/Down —\n * highlight, Enter — выбрать активную, Escape — закрыть. Home/End — deferred.\n */\n@Component({\n selector: 'rt-autocomplete',\n templateUrl: './rt-autocomplete.component.html',\n styleUrl: './rt-autocomplete.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n NgTemplateOutlet,\n\n // standalone components / directives\n RtIconButtonComponent,\n RtIconComponent,\n RtPopoverDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n providers: [\n // Алиас базового токена — для contentChild(RtFormControlBase) в rt-field.\n { provide: RtFormControlBase, useExisting: forwardRef(() => RtAutocompleteComponent) },\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n '[class.rt-autocomplete--open]': 'isOpen()',\n '[class.rt-autocomplete--disabled]': 'isDisabled()',\n '[class.rt-autocomplete--readonly]': 'isReadonly()',\n '[class.rt-autocomplete--invalid]': 'isInvalid()',\n '[class.rt-autocomplete--borderless]': '!bordered()',\n '[class.rt-autocomplete--size--sm]': \"size() === 'sm'\",\n '[class.rt-autocomplete--size--lg]': \"size() === 'lg'\",\n },\n})\nexport class RtAutocompleteComponent<TItem> extends RtFormControlBase<TItem | null> {\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly panelId: string = `rt-autocomplete-panel-${nextPanelId()}`;\n\n protected readonly popover: Signal<RtPopoverDirective> = viewChild.required(RtPopoverDirective);\n\n protected readonly fieldEl: Signal<ElementRef<HTMLInputElement> | undefined> = viewChild<ElementRef<HTMLInputElement>>('fieldEl');\n\n protected readonly inputText: WritableSignal<string> = signal<string>('');\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.suggestions().length,\n chooseKeys: new Set<string>(['Enter']),\n sideKeys: false,\n edgeKeys: false,\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 protected readonly hasValue: Signal<boolean> = computed((): boolean => this.inputText() !== '');\n\n public readonly displayText: Signal<string> = computed((): string => this.displayWith()(this.value()));\n\n public readonly suggestions: InputSignal<ReadonlyArray<TItem>> = input<ReadonlyArray<TItem>>([]);\n\n public readonly displayWith: InputSignal<(item: TItem | null) => string> = input<(item: TItem | null) => string>(\n (item: TItem | null): string => String(item ?? '')\n );\n\n public readonly placeholder: InputSignal<string> = input<string>('');\n public readonly minLength: InputSignal<number> = input<number>(1);\n\n /** Префикс-иконка слева в поле (например, `map` для поиска). */\n public readonly iconLeft: InputSignal<IRtIcon.Name | null> = input<IRtIcon.Name | null>(null);\n\n public readonly openOnFocus: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly itemTemplate: InputSignal<TemplateRef<{ $implicit: TItem }> | null> = input<TemplateRef<{ $implicit: TItem }> | null>(\n null\n );\n\n public readonly complete: OutputEmitterRef<IRtAutocomplete.CompleteEvent> = output<IRtAutocomplete.CompleteEvent>();\n\n public readonly itemSelect: OutputEmitterRef<TItem> = output<TItem>();\n\n public override writeValue(value: TItem | null): void {\n super.writeValue(value);\n this.inputText.set(this.displayWith()(this.value()));\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(): TItem | null {\n return null;\n }\n\n protected focusAfterClear(): void {\n this.fieldEl()?.nativeElement.focus();\n }\n\n protected override clearValue(): void {\n super.clearValue();\n this.inputText.set('');\n }\n\n protected onInput(event: Event): void {\n const target: HTMLInputElement = event.target as HTMLInputElement;\n const query: string = target.value;\n this.inputText.set(query);\n this.activeIndex.set(-1);\n if (query.length >= this.minLength()) {\n this.complete.emit({ query, originalEvent: event });\n this.popover().open();\n } else {\n this.popover().close();\n }\n }\n\n protected onFocus(): void {\n if (!this.openOnFocus()) {\n return;\n }\n this.complete.emit({ query: this.inputText(), originalEvent: new Event('focus') });\n this.popover().open();\n }\n\n protected onBlur(): void {\n this.markTouched();\n }\n\n protected onClosed(): void {\n this.activeIndex.set(-1);\n }\n\n protected onSelect(item: TItem): void {\n this.value.set(item);\n this.inputText.set(this.displayWith()(item));\n this.emitChange(item);\n this.itemSelect.emit(item);\n this.popover().close();\n }\n\n protected onInputKeydown(event: KeyboardEvent): void {\n if (this.isDisabled()) {\n return;\n }\n const key: string = event.key;\n if (!this.isOpen()) {\n return;\n }\n const action: TRtOptionListAction = this.optionList.actionOf(key);\n if (action === 'none' || action === 'side') {\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 'choose':\n this.#selectActive();\n break;\n case 'close':\n this.popover().close();\n break;\n }\n }\n\n #selectActive(): void {\n const items: ReadonlyArray<TItem> = this.suggestions();\n const index: number = this.activeIndex();\n if (index >= 0 && index < items.length) {\n this.onSelect(items[index]);\n }\n }\n}\n","<ng-container rtBlock=\"rt-autocomplete\">\n @if (isReadonly()) {\n <span rtElem=\"readonly\" qa-dataid=\"autocomplete-readonly\" [rtMod]=\"{ empty: !displayText() }\">{{ displayText() || '—' }}</span>\n }\n <div rtElem=\"field\" rtPopoverTrigger=\"manual\" rtPopoverWidth=\"trigger\" [rtPopover]=\"panelTpl\" (rtPopoverClosed)=\"onClosed()\">\n @if (iconLeft(); as left) {\n <rt-icon rtElem=\"icon-left\" size=\"sm\" color=\"muted\" [name]=\"left\" />\n }\n <input\n #fieldEl\n rtElem=\"input\"\n qa-dataid=\"autocomplete-input\"\n type=\"text\"\n autocomplete=\"off\"\n role=\"combobox\"\n [attr.id]=\"effectiveControlId()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-invalid]=\"isInvalid() || null\"\n [attr.aria-autocomplete]=\"'list'\"\n [attr.aria-controls]=\"panelId\"\n [attr.aria-activedescendant]=\"activeOptionId()\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputText()\"\n [disabled]=\"isDisabled()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onInputKeydown($event)\" />\n @if (showClearButton()) {\n <rt-icon-button\n rtElem=\"clear\"\n qa-dataid=\"autocomplete-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 </div>\n\n <ng-template #panelTpl>\n <!--\n Опции выбираются мышью через (click); keyboard-nav — на input'е\n (activedescendant), опции не focusable индивидуально.\n -->\n <!-- eslint-disable @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <ul rtElem=\"panel\" qa-dataid=\"autocomplete-panel\" role=\"listbox\" [id]=\"panelId\">\n @for (item of suggestions(); track $index; let i = $index) {\n <li\n rtElem=\"option\"\n qa-dataid=\"autocomplete-option\"\n role=\"option\"\n [id]=\"panelId + '-opt-' + i\"\n [rtMod]=\"{ active: i === activeIndex() }\"\n [attr.aria-selected]=\"item === value()\"\n (click)=\"onSelect(item)\">\n @if (itemTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: item }\" />\n } @else {\n {{ displayWith()(item) }}\n }\n </li>\n } @empty {\n <li rtElem=\"empty\" qa-dataid=\"autocomplete-empty\">{{ t().uiNothingFound }}</li>\n }\n </ul>\n </ng-template>\n</ng-container>\n"],"mappings":"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"}
|
|
@@ -214,7 +214,7 @@ var RtCalendarComponent = class RtCalendarComponent {
|
|
|
214
214
|
}],
|
|
215
215
|
ngImport: i0,
|
|
216
216
|
template: "<ng-container rtBlock=\"rt-calendar\">\n <div rtElem=\"header\">\n <rt-icon-button\n rtElem=\"nav\"\n qa-dataid=\"calendar-prev-month\"\n icon=\"chevron-left\"\n variant=\"secondary\"\n radius=\"full\"\n [ariaLabel]=\"prevAriaLabel()\"\n [disabled]=\"!canPrev()\"\n (clicked)=\"prevMonth.emit()\" />\n @if (headerTitle() && months()[0]; as first) {\n <ng-container *ngTemplateOutlet=\"titleTpl; context: { $implicit: first }\" />\n }\n <ng-content select=\"[calendarHint]\" />\n <rt-icon-button\n rtElem=\"nav\"\n qa-dataid=\"calendar-next-month\"\n icon=\"chevron-right\"\n variant=\"secondary\"\n radius=\"full\"\n [ariaLabel]=\"nextAriaLabel()\"\n [disabled]=\"!canNext()\"\n (clicked)=\"nextMonth.emit()\" />\n </div>\n\n <div rtElem=\"months\" qa-dataid=\"calendar-months\" (mouseleave)=\"dayHover.emit(null)\">\n @for (month of months(); track month.key) {\n <div rtElem=\"month\" qa-dataid=\"calendar-month\">\n @if (!headerTitle()) {\n <ng-container *ngTemplateOutlet=\"titleTpl; context: { $implicit: month }\" />\n }\n <div rtElem=\"grid\" qa-dataid=\"calendar-grid\">\n @for (weekday of weekdayLabels(); track $index) {\n <span rtElem=\"weekday\" qa-dataid=\"calendar-weekday\">{{ weekday }}</span>\n }\n @for (blank of month.leadingBlanks; track blank) {\n <!-- Пустая ячейка сетки до первого дня месяца: занимает место и ничего не красит. -->\n <span qa-dataid=\"calendar-blank\" aria-hidden=\"true\"></span>\n }\n @for (day of month.days; track day.key) {\n <button\n #dayButton\n rtElem=\"day\"\n qa-dataid=\"calendar-day\"\n type=\"button\"\n [attr.data-iso]=\"day.key\"\n [attr.data-state]=\"day.state\"\n [attr.data-today]=\"day.today ? '' : null\"\n [attr.aria-current]=\"day.today ? 'date' : null\"\n [attr.aria-pressed]=\"day.state === chosenState ? true : null\"\n [attr.tabindex]=\"rovingKey() === null ? null : day.key === rovingKey() ? 0 : -1\"\n [disabled]=\"day.disabled\"\n (keydown)=\"onDayKey($event, day)\"\n (mouseenter)=\"onDayHover(day)\"\n (focus)=\"onDayHover(day)\"\n (click)=\"onDayClick(day)\">\n <span rtElem=\"day-num\" qa-dataid=\"calendar-day-num\">{{ day.dayOfMonth }}</span>\n @if (sublabelsLoading()) {\n <rt-skeleton\n rtElem=\"day-sublabel\"\n qa-dataid=\"calendar-day-price-skeleton\"\n width=\"80%\"\n radius=\"sm\"\n [height]=\"sublabelSkeletonHeight\" />\n } @else if (day.sublabel) {\n <span rtElem=\"day-sublabel\" qa-dataid=\"calendar-day-price\">{{ day.sublabel }}</span>\n }\n </button>\n }\n </div>\n </div>\n }\n </div>\n\n <ng-content />\n\n <ng-template #titleTpl let-month>\n @if (titleAction()) {\n <button rtElem=\"month-title\" qa-dataid=\"calendar-month-title\" type=\"button\" (click)=\"titleClick.emit(month)\">\n {{ month.label }}\n </button>\n } @else {\n <p rtElem=\"month-title\" qa-dataid=\"calendar-month-title\">{{ month.label }}</p>\n }\n </ng-template>\n</ng-container>\n",
|
|
217
|
-
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-calendar{--rt-calendar-day-radius: var(--rt-radius-md);--rt-calendar-day-size: auto;--rt-calendar-day-justify: flex-start;--rt-calendar-month-count: 2;--rt-calendar-column-gap: var(--rt-space-0-5);--rt-calendar-range-inner-radius: var(--rt-calendar-day-radius);--rt-calendar-today-ring: inset 0 0 0 var(--rt-border-width-thin) var(--rt-color-action-primary);display:block}.rt-calendar__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--rt-space-4);gap:var(--rt-space-4)}.rt-calendar__nav{flex:0 0 auto}.rt-calendar__header .rt-calendar__month-title{width:auto;padding:var(--rt-space-1) var(--rt-space-2);margin:0}.rt-calendar__months{display:grid;gap:var(--rt-space-6);grid-template-columns:repeat(var(--rt-calendar-month-count),1fr)}.rt-calendar__month-title{display:block;width:100%;padding:0;border:none;margin:0 0 var(--rt-space-2);background:none;color:var(--rt-color-text-primary);font:inherit;font-weight:var(--rt-font-weight-semibold);text-align:center}.rt-calendar__month-title:first-letter{text-transform:uppercase}.rt-calendar__month-title:is(button){border-radius:var(--rt-calendar-day-radius);cursor:pointer}.rt-calendar__month-title:is(button):hover{color:var(--rt-color-text-link)}.rt-calendar__month-title:is(button):focus-visible{outline:var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);outline-offset:var(--rt-focus-ring-offset)}.rt-calendar__grid{display:grid;gap:var(--rt-space-0-5) var(--rt-calendar-column-gap);grid-template-columns:repeat(7,1fr)}.rt-calendar__weekday{padding:var(--rt-space-1) 0;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);text-align:center}.rt-calendar__day{display:flex;flex-direction:column;align-items:center;justify-content:var(--rt-calendar-day-justify);padding:var(--rt-space-2) var(--rt-space-0-5);border:none;border-radius:var(--rt-calendar-day-radius);background:none;color:var(--rt-color-text-primary);cursor:pointer;font:inherit;gap:var(--rt-space-0-5);min-block-size:var(--rt-calendar-day-size)}.rt-calendar__day:hover:not(:disabled,[data-state=start],[data-state=end],[data-state=in-range],[data-state=chosen]){background:var(--rt-color-bg-subtle)}.rt-calendar__day:disabled{color:var(--rt-color-text-muted);cursor:not-allowed;opacity:.45}.rt-calendar__day[data-state=past],.rt-calendar__day[data-state=blocked]{color:var(--rt-color-text-muted);opacity:.45}.rt-calendar__day[data-state=busy]{color:var(--rt-color-text-muted);opacity:.45;text-decoration:line-through}.rt-calendar__day[data-today]{box-shadow:var(--rt-calendar-today-ring)}.rt-calendar__day:focus-visible{outline:var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);outline-offset:var(--rt-focus-ring-offset)}.rt-calendar__day[data-state=start],.rt-calendar__day[data-state=end],.rt-calendar__day[data-state=chosen]{background:var(--rt-color-action-primary);color:var(--rt-color-action-on-primary)}.rt-calendar__day[data-state=start]{border-end-end-radius:var(--rt-calendar-range-inner-radius);border-start-end-radius:var(--rt-calendar-range-inner-radius)}.rt-calendar__day[data-state=end]{border-end-start-radius:var(--rt-calendar-range-inner-radius);border-start-start-radius:var(--rt-calendar-range-inner-radius)}.rt-calendar__day[data-state=in-range]{border-radius:var(--rt-calendar-range-inner-radius);background:var(--rt-color-action-primary-soft);color:var(--rt-color-text-link);font-weight:var(--rt-font-weight-semibold)}.rt-calendar__day-num{font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-medium)}.rt-calendar__day-sublabel{font-size:var(--rt-text-2xs);opacity:.75}@container rt-place (width <= 640px){.rt-calendar__months{grid-template-columns:1fr}.rt-calendar__month:last-child{display:none}}@container rt-place (width <= 374px){.rt-calendar__day{padding-inline:0}.rt-calendar__day-sublabel{font-size:var(--rt-text-3xs)}}.rt-calendar[data-rt-radius=none]{--rt-calendar-day-radius: var(--rt-radius-none)}.rt-calendar[data-rt-radius=xs]{--rt-calendar-day-radius: var(--rt-radius-xs)}.rt-calendar[data-rt-radius=sm]{--rt-calendar-day-radius: var(--rt-radius-sm)}.rt-calendar[data-rt-radius=ms]{--rt-calendar-day-radius: var(--rt-radius-ms)}.rt-calendar[data-rt-radius=md]{--rt-calendar-day-radius: var(--rt-radius-md)}.rt-calendar[data-rt-radius=lg]{--rt-calendar-day-radius: var(--rt-radius-lg)}.rt-calendar[data-rt-radius=xl]{--rt-calendar-day-radius: var(--rt-radius-xl)}.rt-calendar[data-rt-radius=\"2xl\"]{--rt-calendar-day-radius: var(--rt-radius-2xl)}.rt-calendar[data-rt-radius=full]{--rt-calendar-day-radius: var(--rt-radius-full)}}\n"],
|
|
217
|
+
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-calendar{--rt-calendar-day-radius: var(--rt-radius-md);--rt-calendar-day-size: auto;--rt-calendar-day-justify: flex-start;--rt-calendar-month-count: 2;--rt-calendar-column-gap: var(--rt-space-0-5);--rt-calendar-range-inner-radius: var(--rt-calendar-day-radius);--rt-calendar-today-ring: inset 0 0 0 var(--rt-border-width-thin) var(--rt-color-action-primary);display:block}.rt-calendar__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--rt-space-4);gap:var(--rt-space-4)}.rt-calendar__nav{flex:0 0 auto}.rt-calendar__header .rt-calendar__month-title{width:auto;padding:var(--rt-space-1) var(--rt-space-2);margin:0}.rt-calendar__months{display:grid;gap:var(--rt-space-6);grid-template-columns:repeat(var(--rt-calendar-month-count),1fr)}.rt-calendar__month-title{display:block;width:100%;padding:0;border:none;margin:0 0 var(--rt-space-2);background:none;color:var(--rt-color-text-primary);font:inherit;font-weight:var(--rt-font-weight-semibold);text-align:center}.rt-calendar__month-title:first-letter{text-transform:uppercase}.rt-calendar__month-title:is(button){border-radius:var(--rt-calendar-day-radius);cursor:pointer}.rt-calendar__month-title:is(button):hover{color:var(--rt-color-text-link)}.rt-calendar__month-title:is(button):focus-visible{outline:var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);outline-offset:var(--rt-focus-ring-offset)}.rt-calendar__grid{display:grid;gap:var(--rt-space-0-5) var(--rt-calendar-column-gap);grid-template-columns:repeat(7,1fr)}.rt-calendar__weekday{padding:var(--rt-space-1) 0;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);text-align:center}.rt-calendar__day{display:flex;flex-direction:column;align-items:center;justify-content:var(--rt-calendar-day-justify);padding:var(--rt-space-2) var(--rt-space-0-5);border:none;border-radius:var(--rt-calendar-day-radius);background:none;color:var(--rt-color-text-primary);cursor:pointer;font:inherit;gap:var(--rt-space-0-5);min-block-size:var(--rt-calendar-day-size)}.rt-calendar__day:hover:not(:disabled,[data-state=start],[data-state=end],[data-state=in-range],[data-state=chosen]){background:var(--rt-color-bg-subtle)}.rt-calendar__day:disabled{color:var(--rt-color-text-muted);cursor:not-allowed;opacity:.45}.rt-calendar__day[data-state=past],.rt-calendar__day[data-state=blocked]{color:var(--rt-color-text-muted);opacity:.45}.rt-calendar__day[data-state=busy]{color:var(--rt-color-text-muted);opacity:.45;text-decoration:line-through}.rt-calendar__day[data-today]{box-shadow:var(--rt-calendar-today-ring)}.rt-calendar__day:focus-visible{outline:var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);outline-offset:var(--rt-focus-ring-offset)}.rt-calendar__day[data-state=start],.rt-calendar__day[data-state=end],.rt-calendar__day[data-state=chosen]{background:var(--rt-color-action-primary);color:var(--rt-color-action-on-primary)}.rt-calendar__day[data-state=start]{border-end-end-radius:var(--rt-calendar-range-inner-radius);border-start-end-radius:var(--rt-calendar-range-inner-radius)}.rt-calendar__day[data-state=end]{border-end-start-radius:var(--rt-calendar-range-inner-radius);border-start-start-radius:var(--rt-calendar-range-inner-radius)}.rt-calendar__day[data-state=in-range]{border-radius:var(--rt-calendar-range-inner-radius);background:var(--rt-color-action-primary-soft);color:var(--rt-color-text-link);font-weight:var(--rt-font-weight-semibold)}.rt-calendar__day-num{font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-medium)}.rt-calendar__day-sublabel{font-size:var(--rt-text-2xs);opacity:.75}@container rt-place (width <= 640px){.rt-calendar__months{grid-template-columns:1fr}.rt-calendar__month:last-child{display:none}}@media(width<=640px){:where(html:not(:has(.rt-container))) .rt-calendar__months{grid-template-columns:1fr}:where(html:not(:has(.rt-container))) .rt-calendar__month:last-child{display:none}}@container rt-place (width <= 374px){.rt-calendar__day{padding-inline:0}.rt-calendar__day-sublabel{font-size:var(--rt-text-3xs)}}@media(width<=374px){:where(html:not(:has(.rt-container))) .rt-calendar__day{padding-inline:0}:where(html:not(:has(.rt-container))) .rt-calendar__day-sublabel{font-size:var(--rt-text-3xs)}}.rt-calendar[data-rt-radius=none]{--rt-calendar-day-radius: var(--rt-radius-none)}.rt-calendar[data-rt-radius=xs]{--rt-calendar-day-radius: var(--rt-radius-xs)}.rt-calendar[data-rt-radius=sm]{--rt-calendar-day-radius: var(--rt-radius-sm)}.rt-calendar[data-rt-radius=ms]{--rt-calendar-day-radius: var(--rt-radius-ms)}.rt-calendar[data-rt-radius=md]{--rt-calendar-day-radius: var(--rt-radius-md)}.rt-calendar[data-rt-radius=lg]{--rt-calendar-day-radius: var(--rt-radius-lg)}.rt-calendar[data-rt-radius=xl]{--rt-calendar-day-radius: var(--rt-radius-xl)}.rt-calendar[data-rt-radius=\"2xl\"]{--rt-calendar-day-radius: var(--rt-radius-2xl)}.rt-calendar[data-rt-radius=full]{--rt-calendar-day-radius: var(--rt-radius-full)}}\n"],
|
|
218
218
|
dependencies: [
|
|
219
219
|
{
|
|
220
220
|
kind: "directive",
|
|
@@ -305,7 +305,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
305
305
|
}],
|
|
306
306
|
host: { class: BEM_BLOCK },
|
|
307
307
|
template: "<ng-container rtBlock=\"rt-calendar\">\n <div rtElem=\"header\">\n <rt-icon-button\n rtElem=\"nav\"\n qa-dataid=\"calendar-prev-month\"\n icon=\"chevron-left\"\n variant=\"secondary\"\n radius=\"full\"\n [ariaLabel]=\"prevAriaLabel()\"\n [disabled]=\"!canPrev()\"\n (clicked)=\"prevMonth.emit()\" />\n @if (headerTitle() && months()[0]; as first) {\n <ng-container *ngTemplateOutlet=\"titleTpl; context: { $implicit: first }\" />\n }\n <ng-content select=\"[calendarHint]\" />\n <rt-icon-button\n rtElem=\"nav\"\n qa-dataid=\"calendar-next-month\"\n icon=\"chevron-right\"\n variant=\"secondary\"\n radius=\"full\"\n [ariaLabel]=\"nextAriaLabel()\"\n [disabled]=\"!canNext()\"\n (clicked)=\"nextMonth.emit()\" />\n </div>\n\n <div rtElem=\"months\" qa-dataid=\"calendar-months\" (mouseleave)=\"dayHover.emit(null)\">\n @for (month of months(); track month.key) {\n <div rtElem=\"month\" qa-dataid=\"calendar-month\">\n @if (!headerTitle()) {\n <ng-container *ngTemplateOutlet=\"titleTpl; context: { $implicit: month }\" />\n }\n <div rtElem=\"grid\" qa-dataid=\"calendar-grid\">\n @for (weekday of weekdayLabels(); track $index) {\n <span rtElem=\"weekday\" qa-dataid=\"calendar-weekday\">{{ weekday }}</span>\n }\n @for (blank of month.leadingBlanks; track blank) {\n <!-- Пустая ячейка сетки до первого дня месяца: занимает место и ничего не красит. -->\n <span qa-dataid=\"calendar-blank\" aria-hidden=\"true\"></span>\n }\n @for (day of month.days; track day.key) {\n <button\n #dayButton\n rtElem=\"day\"\n qa-dataid=\"calendar-day\"\n type=\"button\"\n [attr.data-iso]=\"day.key\"\n [attr.data-state]=\"day.state\"\n [attr.data-today]=\"day.today ? '' : null\"\n [attr.aria-current]=\"day.today ? 'date' : null\"\n [attr.aria-pressed]=\"day.state === chosenState ? true : null\"\n [attr.tabindex]=\"rovingKey() === null ? null : day.key === rovingKey() ? 0 : -1\"\n [disabled]=\"day.disabled\"\n (keydown)=\"onDayKey($event, day)\"\n (mouseenter)=\"onDayHover(day)\"\n (focus)=\"onDayHover(day)\"\n (click)=\"onDayClick(day)\">\n <span rtElem=\"day-num\" qa-dataid=\"calendar-day-num\">{{ day.dayOfMonth }}</span>\n @if (sublabelsLoading()) {\n <rt-skeleton\n rtElem=\"day-sublabel\"\n qa-dataid=\"calendar-day-price-skeleton\"\n width=\"80%\"\n radius=\"sm\"\n [height]=\"sublabelSkeletonHeight\" />\n } @else if (day.sublabel) {\n <span rtElem=\"day-sublabel\" qa-dataid=\"calendar-day-price\">{{ day.sublabel }}</span>\n }\n </button>\n }\n </div>\n </div>\n }\n </div>\n\n <ng-content />\n\n <ng-template #titleTpl let-month>\n @if (titleAction()) {\n <button rtElem=\"month-title\" qa-dataid=\"calendar-month-title\" type=\"button\" (click)=\"titleClick.emit(month)\">\n {{ month.label }}\n </button>\n } @else {\n <p rtElem=\"month-title\" qa-dataid=\"calendar-month-title\">{{ month.label }}</p>\n }\n </ng-template>\n</ng-container>\n",
|
|
308
|
-
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-calendar{--rt-calendar-day-radius: var(--rt-radius-md);--rt-calendar-day-size: auto;--rt-calendar-day-justify: flex-start;--rt-calendar-month-count: 2;--rt-calendar-column-gap: var(--rt-space-0-5);--rt-calendar-range-inner-radius: var(--rt-calendar-day-radius);--rt-calendar-today-ring: inset 0 0 0 var(--rt-border-width-thin) var(--rt-color-action-primary);display:block}.rt-calendar__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--rt-space-4);gap:var(--rt-space-4)}.rt-calendar__nav{flex:0 0 auto}.rt-calendar__header .rt-calendar__month-title{width:auto;padding:var(--rt-space-1) var(--rt-space-2);margin:0}.rt-calendar__months{display:grid;gap:var(--rt-space-6);grid-template-columns:repeat(var(--rt-calendar-month-count),1fr)}.rt-calendar__month-title{display:block;width:100%;padding:0;border:none;margin:0 0 var(--rt-space-2);background:none;color:var(--rt-color-text-primary);font:inherit;font-weight:var(--rt-font-weight-semibold);text-align:center}.rt-calendar__month-title:first-letter{text-transform:uppercase}.rt-calendar__month-title:is(button){border-radius:var(--rt-calendar-day-radius);cursor:pointer}.rt-calendar__month-title:is(button):hover{color:var(--rt-color-text-link)}.rt-calendar__month-title:is(button):focus-visible{outline:var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);outline-offset:var(--rt-focus-ring-offset)}.rt-calendar__grid{display:grid;gap:var(--rt-space-0-5) var(--rt-calendar-column-gap);grid-template-columns:repeat(7,1fr)}.rt-calendar__weekday{padding:var(--rt-space-1) 0;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);text-align:center}.rt-calendar__day{display:flex;flex-direction:column;align-items:center;justify-content:var(--rt-calendar-day-justify);padding:var(--rt-space-2) var(--rt-space-0-5);border:none;border-radius:var(--rt-calendar-day-radius);background:none;color:var(--rt-color-text-primary);cursor:pointer;font:inherit;gap:var(--rt-space-0-5);min-block-size:var(--rt-calendar-day-size)}.rt-calendar__day:hover:not(:disabled,[data-state=start],[data-state=end],[data-state=in-range],[data-state=chosen]){background:var(--rt-color-bg-subtle)}.rt-calendar__day:disabled{color:var(--rt-color-text-muted);cursor:not-allowed;opacity:.45}.rt-calendar__day[data-state=past],.rt-calendar__day[data-state=blocked]{color:var(--rt-color-text-muted);opacity:.45}.rt-calendar__day[data-state=busy]{color:var(--rt-color-text-muted);opacity:.45;text-decoration:line-through}.rt-calendar__day[data-today]{box-shadow:var(--rt-calendar-today-ring)}.rt-calendar__day:focus-visible{outline:var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);outline-offset:var(--rt-focus-ring-offset)}.rt-calendar__day[data-state=start],.rt-calendar__day[data-state=end],.rt-calendar__day[data-state=chosen]{background:var(--rt-color-action-primary);color:var(--rt-color-action-on-primary)}.rt-calendar__day[data-state=start]{border-end-end-radius:var(--rt-calendar-range-inner-radius);border-start-end-radius:var(--rt-calendar-range-inner-radius)}.rt-calendar__day[data-state=end]{border-end-start-radius:var(--rt-calendar-range-inner-radius);border-start-start-radius:var(--rt-calendar-range-inner-radius)}.rt-calendar__day[data-state=in-range]{border-radius:var(--rt-calendar-range-inner-radius);background:var(--rt-color-action-primary-soft);color:var(--rt-color-text-link);font-weight:var(--rt-font-weight-semibold)}.rt-calendar__day-num{font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-medium)}.rt-calendar__day-sublabel{font-size:var(--rt-text-2xs);opacity:.75}@container rt-place (width <= 640px){.rt-calendar__months{grid-template-columns:1fr}.rt-calendar__month:last-child{display:none}}@container rt-place (width <= 374px){.rt-calendar__day{padding-inline:0}.rt-calendar__day-sublabel{font-size:var(--rt-text-3xs)}}.rt-calendar[data-rt-radius=none]{--rt-calendar-day-radius: var(--rt-radius-none)}.rt-calendar[data-rt-radius=xs]{--rt-calendar-day-radius: var(--rt-radius-xs)}.rt-calendar[data-rt-radius=sm]{--rt-calendar-day-radius: var(--rt-radius-sm)}.rt-calendar[data-rt-radius=ms]{--rt-calendar-day-radius: var(--rt-radius-ms)}.rt-calendar[data-rt-radius=md]{--rt-calendar-day-radius: var(--rt-radius-md)}.rt-calendar[data-rt-radius=lg]{--rt-calendar-day-radius: var(--rt-radius-lg)}.rt-calendar[data-rt-radius=xl]{--rt-calendar-day-radius: var(--rt-radius-xl)}.rt-calendar[data-rt-radius=\"2xl\"]{--rt-calendar-day-radius: var(--rt-radius-2xl)}.rt-calendar[data-rt-radius=full]{--rt-calendar-day-radius: var(--rt-radius-full)}}\n"]
|
|
308
|
+
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-calendar{--rt-calendar-day-radius: var(--rt-radius-md);--rt-calendar-day-size: auto;--rt-calendar-day-justify: flex-start;--rt-calendar-month-count: 2;--rt-calendar-column-gap: var(--rt-space-0-5);--rt-calendar-range-inner-radius: var(--rt-calendar-day-radius);--rt-calendar-today-ring: inset 0 0 0 var(--rt-border-width-thin) var(--rt-color-action-primary);display:block}.rt-calendar__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--rt-space-4);gap:var(--rt-space-4)}.rt-calendar__nav{flex:0 0 auto}.rt-calendar__header .rt-calendar__month-title{width:auto;padding:var(--rt-space-1) var(--rt-space-2);margin:0}.rt-calendar__months{display:grid;gap:var(--rt-space-6);grid-template-columns:repeat(var(--rt-calendar-month-count),1fr)}.rt-calendar__month-title{display:block;width:100%;padding:0;border:none;margin:0 0 var(--rt-space-2);background:none;color:var(--rt-color-text-primary);font:inherit;font-weight:var(--rt-font-weight-semibold);text-align:center}.rt-calendar__month-title:first-letter{text-transform:uppercase}.rt-calendar__month-title:is(button){border-radius:var(--rt-calendar-day-radius);cursor:pointer}.rt-calendar__month-title:is(button):hover{color:var(--rt-color-text-link)}.rt-calendar__month-title:is(button):focus-visible{outline:var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);outline-offset:var(--rt-focus-ring-offset)}.rt-calendar__grid{display:grid;gap:var(--rt-space-0-5) var(--rt-calendar-column-gap);grid-template-columns:repeat(7,1fr)}.rt-calendar__weekday{padding:var(--rt-space-1) 0;color:var(--rt-color-text-muted);font-size:var(--rt-text-xs);text-align:center}.rt-calendar__day{display:flex;flex-direction:column;align-items:center;justify-content:var(--rt-calendar-day-justify);padding:var(--rt-space-2) var(--rt-space-0-5);border:none;border-radius:var(--rt-calendar-day-radius);background:none;color:var(--rt-color-text-primary);cursor:pointer;font:inherit;gap:var(--rt-space-0-5);min-block-size:var(--rt-calendar-day-size)}.rt-calendar__day:hover:not(:disabled,[data-state=start],[data-state=end],[data-state=in-range],[data-state=chosen]){background:var(--rt-color-bg-subtle)}.rt-calendar__day:disabled{color:var(--rt-color-text-muted);cursor:not-allowed;opacity:.45}.rt-calendar__day[data-state=past],.rt-calendar__day[data-state=blocked]{color:var(--rt-color-text-muted);opacity:.45}.rt-calendar__day[data-state=busy]{color:var(--rt-color-text-muted);opacity:.45;text-decoration:line-through}.rt-calendar__day[data-today]{box-shadow:var(--rt-calendar-today-ring)}.rt-calendar__day:focus-visible{outline:var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);outline-offset:var(--rt-focus-ring-offset)}.rt-calendar__day[data-state=start],.rt-calendar__day[data-state=end],.rt-calendar__day[data-state=chosen]{background:var(--rt-color-action-primary);color:var(--rt-color-action-on-primary)}.rt-calendar__day[data-state=start]{border-end-end-radius:var(--rt-calendar-range-inner-radius);border-start-end-radius:var(--rt-calendar-range-inner-radius)}.rt-calendar__day[data-state=end]{border-end-start-radius:var(--rt-calendar-range-inner-radius);border-start-start-radius:var(--rt-calendar-range-inner-radius)}.rt-calendar__day[data-state=in-range]{border-radius:var(--rt-calendar-range-inner-radius);background:var(--rt-color-action-primary-soft);color:var(--rt-color-text-link);font-weight:var(--rt-font-weight-semibold)}.rt-calendar__day-num{font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-medium)}.rt-calendar__day-sublabel{font-size:var(--rt-text-2xs);opacity:.75}@container rt-place (width <= 640px){.rt-calendar__months{grid-template-columns:1fr}.rt-calendar__month:last-child{display:none}}@media(width<=640px){:where(html:not(:has(.rt-container))) .rt-calendar__months{grid-template-columns:1fr}:where(html:not(:has(.rt-container))) .rt-calendar__month:last-child{display:none}}@container rt-place (width <= 374px){.rt-calendar__day{padding-inline:0}.rt-calendar__day-sublabel{font-size:var(--rt-text-3xs)}}@media(width<=374px){:where(html:not(:has(.rt-container))) .rt-calendar__day{padding-inline:0}:where(html:not(:has(.rt-container))) .rt-calendar__day-sublabel{font-size:var(--rt-text-3xs)}}.rt-calendar[data-rt-radius=none]{--rt-calendar-day-radius: var(--rt-radius-none)}.rt-calendar[data-rt-radius=xs]{--rt-calendar-day-radius: var(--rt-radius-xs)}.rt-calendar[data-rt-radius=sm]{--rt-calendar-day-radius: var(--rt-radius-sm)}.rt-calendar[data-rt-radius=ms]{--rt-calendar-day-radius: var(--rt-radius-ms)}.rt-calendar[data-rt-radius=md]{--rt-calendar-day-radius: var(--rt-radius-md)}.rt-calendar[data-rt-radius=lg]{--rt-calendar-day-radius: var(--rt-radius-lg)}.rt-calendar[data-rt-radius=xl]{--rt-calendar-day-radius: var(--rt-radius-xl)}.rt-calendar[data-rt-radius=\"2xl\"]{--rt-calendar-day-radius: var(--rt-radius-2xl)}.rt-calendar[data-rt-radius=full]{--rt-calendar-day-radius: var(--rt-radius-full)}}\n"]
|
|
309
309
|
}]
|
|
310
310
|
}],
|
|
311
311
|
ctorParameters: () => [],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rt-tools-ui-kit-v2-calendar.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/calendar/rt-calendar.model.ts","../../../projects/ui-kit-v2/src/lib/components/calendar/rt-calendar.component.ts","../../../projects/ui-kit-v2/src/lib/components/calendar/rt-calendar.component.html"],"sourcesContent":["/**\n * Контракты `rt-calendar` — презентационный месячный грид с range-выбором.\n *\n * Компонент домен-агностичен: состояния/цены/доступность дней вычисляет\n * consumer и передаёт готовые view-модели месяцев. Клики по дням и навигация\n * по месяцам эмитятся наружу; никакой доменной логики внутри нет.\n */\n\n/** Состояние ячейки дня — модификатор `data-state` на кнопке дня. */\nexport enum ERtCalendarDayState {\n Free = 'free',\n Busy = 'busy',\n Past = 'past',\n Blocked = 'blocked',\n Start = 'start',\n End = 'end',\n InRange = 'in-range',\n /** Выбранный день одиночного выбора — залит. */\n Chosen = 'chosen',\n}\n\nexport namespace IRtCalendar {\n /** View-модель дня. `key` — стабильный ключ (ISO-дата). */\n export interface Day {\n key: string;\n dayOfMonth: number;\n /** Подпись под числом (цена за ночь и т.п.); пустая строка не рендерится. */\n sublabel: string;\n state: ERtCalendarDayState;\n disabled: boolean;\n /** Сегодняшний день — обведён рамкой поверх любого состояния. */\n today?: boolean;\n }\n\n /** Клавиша сетки, нажатая на дне. */\n export interface GridKey {\n key: string;\n day: Day;\n }\n\n /** View-модель месяца: подпись, пустые ячейки до первого дня, дни. */\n export interface Month {\n key: string;\n label: string;\n leadingBlanks: readonly number[];\n days: readonly Day[];\n }\n}\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n afterRenderEffect,\n booleanAttribute,\n computed,\n signal,\n viewChildren,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n input,\n InputSignal,\n InputSignalWithTransform,\n output,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\n// rt-tools\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RtSkeletonComponent } from '@rt-tools/ui-kit-v2/skeleton';\nimport { ERtCalendarDayState, IRtCalendar } from './rt-calendar.model';\n\nconst BEM_BLOCK: string = 'rt-calendar';\n\n/** Клавиши, что календарь в режиме сетки отдаёт наружу вместо прокрутки страницы. */\nconst GRID_KEYS: ReadonlySet<string> = new Set(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'PageUp', 'PageDown', 'Home', 'End']);\n\n@Component({\n selector: 'rt-calendar',\n templateUrl: './rt-calendar.component.html',\n styleUrl: './rt-calendar.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // angular\n NgTemplateOutlet,\n\n // rt-tools\n BlockDirective,\n ElemDirective,\n\n // components\n RtIconButtonComponent,\n RtSkeletonComponent,\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtCalendarComponent {\n /** Фокус двигала клавиша: только тогда календарь переводит фокус на `activeKey`. */\n readonly #keyed: WritableSignal<boolean> = signal(false);\n\n protected readonly sublabelSkeletonHeight: string = '12px';\n protected readonly chosenState: ERtCalendarDayState = ERtCalendarDayState.Chosen;\n\n protected readonly dayButtons: Signal<readonly ElementRef<HTMLButtonElement>[]> =\n viewChildren<ElementRef<HTMLButtonElement>>('dayButton');\n\n /**\n * День, что стоит в порядке обхода Tab в режиме сетки: `activeKey`, иначе выбранный, иначе\n * сегодняшний, иначе первый доступный. Вне режима сетки — `null`, и каждый день обходится Tab.\n */\n protected readonly rovingKey: Signal<string | null> = computed((): string | null => {\n if (!this.grid()) {\n return null;\n }\n const days: IRtCalendar.Day[] = this.months().flatMap((month: IRtCalendar.Month): IRtCalendar.Day[] => [...month.days]);\n const active: string | null = this.activeKey();\n const pick: IRtCalendar.Day | undefined =\n days.find((day: IRtCalendar.Day): boolean => day.key === active) ??\n days.find((day: IRtCalendar.Day): boolean => day.state === ERtCalendarDayState.Chosen) ??\n days.find((day: IRtCalendar.Day): boolean => day.today === true) ??\n days.find((day: IRtCalendar.Day): boolean => !day.disabled);\n return pick?.key ?? null;\n });\n\n public readonly months: InputSignal<readonly IRtCalendar.Month[]> = input.required<readonly IRtCalendar.Month[]>();\n public readonly weekdayLabels: InputSignal<readonly string[]> = input.required<readonly string[]>();\n public readonly canPrev: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n public readonly canNext: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** Локализованные aria-подписи кнопок навигации — задаёт consumer. */\n public readonly prevAriaLabel: InputSignal<string> = input<string>('');\n public readonly nextAriaLabel: InputSignal<string> = input<string>('');\n public readonly sublabelsLoading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /**\n * Режим сетки: один день в обходе Tab, клавиши стрелок, PageUp/PageDown, Home и End уходят\n * наружу событием `gridKey`, а фокус встаёт на `activeKey`. Выключен — поведение прежнее.\n */\n public readonly grid: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** День с фокусом в режиме сетки, ключ `YYYY-MM-DD`; его ставит consumer по `gridKey`. */\n public readonly activeKey: InputSignal<string | null> = input<string | null>(null);\n /** Заголовок месяца — кнопка, что шлёт `titleClick`: так consumer открывает выбор месяца. */\n public readonly titleAction: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** Заголовок первого месяца стоит в шапке между стрелками, а не над сеткой. */\n public readonly headerTitle: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly prevMonth: OutputEmitterRef<void> = output<void>();\n public readonly nextMonth: OutputEmitterRef<void> = output<void>();\n public readonly dayClick: OutputEmitterRef<IRtCalendar.Day> = output<IRtCalendar.Day>();\n /** Клавиша сетки на дне: куда перевести фокус, решает consumer. */\n public readonly gridKey: OutputEmitterRef<IRtCalendar.GridKey> = output<IRtCalendar.GridKey>();\n public readonly titleClick: OutputEmitterRef<IRtCalendar.Month> = output<IRtCalendar.Month>();\n /** День под указателем или с фокусом; `null` — указатель ушёл с месяцев. По нему рисуется будущий диапазон. */\n public readonly dayHover: OutputEmitterRef<IRtCalendar.Day | null> = output<IRtCalendar.Day | null>();\n\n constructor() {\n afterRenderEffect((): void => {\n const key: string | null = this.rovingKey();\n if (!this.#keyed() || key === null) {\n return;\n }\n this.dayButtons()\n .find((button: ElementRef<HTMLButtonElement>): boolean => button.nativeElement.dataset['iso'] === key)\n ?.nativeElement.focus();\n });\n }\n\n protected onDayKey(event: KeyboardEvent, day: IRtCalendar.Day): void {\n if (!this.grid() || !GRID_KEYS.has(event.key)) {\n return;\n }\n event.preventDefault();\n this.#keyed.set(true);\n this.gridKey.emit({ key: event.key, day });\n }\n\n protected onDayHover(day: IRtCalendar.Day): void {\n if (!day.disabled) {\n this.dayHover.emit(day);\n }\n }\n\n protected onDayClick(day: IRtCalendar.Day): void {\n if (!day.disabled) {\n this.dayClick.emit(day);\n }\n }\n}\n","<ng-container rtBlock=\"rt-calendar\">\n <div rtElem=\"header\">\n <rt-icon-button\n rtElem=\"nav\"\n qa-dataid=\"calendar-prev-month\"\n icon=\"chevron-left\"\n variant=\"secondary\"\n radius=\"full\"\n [ariaLabel]=\"prevAriaLabel()\"\n [disabled]=\"!canPrev()\"\n (clicked)=\"prevMonth.emit()\" />\n @if (headerTitle() && months()[0]; as first) {\n <ng-container *ngTemplateOutlet=\"titleTpl; context: { $implicit: first }\" />\n }\n <ng-content select=\"[calendarHint]\" />\n <rt-icon-button\n rtElem=\"nav\"\n qa-dataid=\"calendar-next-month\"\n icon=\"chevron-right\"\n variant=\"secondary\"\n radius=\"full\"\n [ariaLabel]=\"nextAriaLabel()\"\n [disabled]=\"!canNext()\"\n (clicked)=\"nextMonth.emit()\" />\n </div>\n\n <div rtElem=\"months\" qa-dataid=\"calendar-months\" (mouseleave)=\"dayHover.emit(null)\">\n @for (month of months(); track month.key) {\n <div rtElem=\"month\" qa-dataid=\"calendar-month\">\n @if (!headerTitle()) {\n <ng-container *ngTemplateOutlet=\"titleTpl; context: { $implicit: month }\" />\n }\n <div rtElem=\"grid\" qa-dataid=\"calendar-grid\">\n @for (weekday of weekdayLabels(); track $index) {\n <span rtElem=\"weekday\" qa-dataid=\"calendar-weekday\">{{ weekday }}</span>\n }\n @for (blank of month.leadingBlanks; track blank) {\n <!-- Пустая ячейка сетки до первого дня месяца: занимает место и ничего не красит. -->\n <span qa-dataid=\"calendar-blank\" aria-hidden=\"true\"></span>\n }\n @for (day of month.days; track day.key) {\n <button\n #dayButton\n rtElem=\"day\"\n qa-dataid=\"calendar-day\"\n type=\"button\"\n [attr.data-iso]=\"day.key\"\n [attr.data-state]=\"day.state\"\n [attr.data-today]=\"day.today ? '' : null\"\n [attr.aria-current]=\"day.today ? 'date' : null\"\n [attr.aria-pressed]=\"day.state === chosenState ? true : null\"\n [attr.tabindex]=\"rovingKey() === null ? null : day.key === rovingKey() ? 0 : -1\"\n [disabled]=\"day.disabled\"\n (keydown)=\"onDayKey($event, day)\"\n (mouseenter)=\"onDayHover(day)\"\n (focus)=\"onDayHover(day)\"\n (click)=\"onDayClick(day)\">\n <span rtElem=\"day-num\" qa-dataid=\"calendar-day-num\">{{ day.dayOfMonth }}</span>\n @if (sublabelsLoading()) {\n <rt-skeleton\n rtElem=\"day-sublabel\"\n qa-dataid=\"calendar-day-price-skeleton\"\n width=\"80%\"\n radius=\"sm\"\n [height]=\"sublabelSkeletonHeight\" />\n } @else if (day.sublabel) {\n <span rtElem=\"day-sublabel\" qa-dataid=\"calendar-day-price\">{{ day.sublabel }}</span>\n }\n </button>\n }\n </div>\n </div>\n }\n </div>\n\n <ng-content />\n\n <ng-template #titleTpl let-month>\n @if (titleAction()) {\n <button rtElem=\"month-title\" qa-dataid=\"calendar-month-title\" type=\"button\" (click)=\"titleClick.emit(month)\">\n {{ month.label }}\n </button>\n } @else {\n <p rtElem=\"month-title\" qa-dataid=\"calendar-month-title\">{{ month.label }}</p>\n }\n </ng-template>\n</ng-container>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rt-tools-ui-kit-v2-calendar.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/calendar/rt-calendar.model.ts","../../../projects/ui-kit-v2/src/lib/components/calendar/rt-calendar.component.ts","../../../projects/ui-kit-v2/src/lib/components/calendar/rt-calendar.component.html"],"sourcesContent":["/**\n * Контракты `rt-calendar` — презентационный месячный грид с range-выбором.\n *\n * Компонент домен-агностичен: состояния/цены/доступность дней вычисляет\n * consumer и передаёт готовые view-модели месяцев. Клики по дням и навигация\n * по месяцам эмитятся наружу; никакой доменной логики внутри нет.\n */\n\n/** Состояние ячейки дня — модификатор `data-state` на кнопке дня. */\nexport enum ERtCalendarDayState {\n Free = 'free',\n Busy = 'busy',\n Past = 'past',\n Blocked = 'blocked',\n Start = 'start',\n End = 'end',\n InRange = 'in-range',\n /** Выбранный день одиночного выбора — залит. */\n Chosen = 'chosen',\n}\n\nexport namespace IRtCalendar {\n /** View-модель дня. `key` — стабильный ключ (ISO-дата). */\n export interface Day {\n key: string;\n dayOfMonth: number;\n /** Подпись под числом (цена за ночь и т.п.); пустая строка не рендерится. */\n sublabel: string;\n state: ERtCalendarDayState;\n disabled: boolean;\n /** Сегодняшний день — обведён рамкой поверх любого состояния. */\n today?: boolean;\n }\n\n /** Клавиша сетки, нажатая на дне. */\n export interface GridKey {\n key: string;\n day: Day;\n }\n\n /** View-модель месяца: подпись, пустые ячейки до первого дня, дни. */\n export interface Month {\n key: string;\n label: string;\n leadingBlanks: readonly number[];\n days: readonly Day[];\n }\n}\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n afterRenderEffect,\n booleanAttribute,\n computed,\n signal,\n viewChildren,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n input,\n InputSignal,\n InputSignalWithTransform,\n output,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\n// rt-tools\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RtSkeletonComponent } from '@rt-tools/ui-kit-v2/skeleton';\nimport { ERtCalendarDayState, IRtCalendar } from './rt-calendar.model';\n\nconst BEM_BLOCK: string = 'rt-calendar';\n\n/** Клавиши, что календарь в режиме сетки отдаёт наружу вместо прокрутки страницы. */\nconst GRID_KEYS: ReadonlySet<string> = new Set(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'PageUp', 'PageDown', 'Home', 'End']);\n\n@Component({\n selector: 'rt-calendar',\n templateUrl: './rt-calendar.component.html',\n styleUrl: './rt-calendar.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // angular\n NgTemplateOutlet,\n\n // rt-tools\n BlockDirective,\n ElemDirective,\n\n // components\n RtIconButtonComponent,\n RtSkeletonComponent,\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtCalendarComponent {\n /** Фокус двигала клавиша: только тогда календарь переводит фокус на `activeKey`. */\n readonly #keyed: WritableSignal<boolean> = signal(false);\n\n protected readonly sublabelSkeletonHeight: string = '12px';\n protected readonly chosenState: ERtCalendarDayState = ERtCalendarDayState.Chosen;\n\n protected readonly dayButtons: Signal<readonly ElementRef<HTMLButtonElement>[]> =\n viewChildren<ElementRef<HTMLButtonElement>>('dayButton');\n\n /**\n * День, что стоит в порядке обхода Tab в режиме сетки: `activeKey`, иначе выбранный, иначе\n * сегодняшний, иначе первый доступный. Вне режима сетки — `null`, и каждый день обходится Tab.\n */\n protected readonly rovingKey: Signal<string | null> = computed((): string | null => {\n if (!this.grid()) {\n return null;\n }\n const days: IRtCalendar.Day[] = this.months().flatMap((month: IRtCalendar.Month): IRtCalendar.Day[] => [...month.days]);\n const active: string | null = this.activeKey();\n const pick: IRtCalendar.Day | undefined =\n days.find((day: IRtCalendar.Day): boolean => day.key === active) ??\n days.find((day: IRtCalendar.Day): boolean => day.state === ERtCalendarDayState.Chosen) ??\n days.find((day: IRtCalendar.Day): boolean => day.today === true) ??\n days.find((day: IRtCalendar.Day): boolean => !day.disabled);\n return pick?.key ?? null;\n });\n\n public readonly months: InputSignal<readonly IRtCalendar.Month[]> = input.required<readonly IRtCalendar.Month[]>();\n public readonly weekdayLabels: InputSignal<readonly string[]> = input.required<readonly string[]>();\n public readonly canPrev: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n public readonly canNext: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** Локализованные aria-подписи кнопок навигации — задаёт consumer. */\n public readonly prevAriaLabel: InputSignal<string> = input<string>('');\n public readonly nextAriaLabel: InputSignal<string> = input<string>('');\n public readonly sublabelsLoading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /**\n * Режим сетки: один день в обходе Tab, клавиши стрелок, PageUp/PageDown, Home и End уходят\n * наружу событием `gridKey`, а фокус встаёт на `activeKey`. Выключен — поведение прежнее.\n */\n public readonly grid: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** День с фокусом в режиме сетки, ключ `YYYY-MM-DD`; его ставит consumer по `gridKey`. */\n public readonly activeKey: InputSignal<string | null> = input<string | null>(null);\n /** Заголовок месяца — кнопка, что шлёт `titleClick`: так consumer открывает выбор месяца. */\n public readonly titleAction: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** Заголовок первого месяца стоит в шапке между стрелками, а не над сеткой. */\n public readonly headerTitle: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly prevMonth: OutputEmitterRef<void> = output<void>();\n public readonly nextMonth: OutputEmitterRef<void> = output<void>();\n public readonly dayClick: OutputEmitterRef<IRtCalendar.Day> = output<IRtCalendar.Day>();\n /** Клавиша сетки на дне: куда перевести фокус, решает consumer. */\n public readonly gridKey: OutputEmitterRef<IRtCalendar.GridKey> = output<IRtCalendar.GridKey>();\n public readonly titleClick: OutputEmitterRef<IRtCalendar.Month> = output<IRtCalendar.Month>();\n /** День под указателем или с фокусом; `null` — указатель ушёл с месяцев. По нему рисуется будущий диапазон. */\n public readonly dayHover: OutputEmitterRef<IRtCalendar.Day | null> = output<IRtCalendar.Day | null>();\n\n constructor() {\n afterRenderEffect((): void => {\n const key: string | null = this.rovingKey();\n if (!this.#keyed() || key === null) {\n return;\n }\n this.dayButtons()\n .find((button: ElementRef<HTMLButtonElement>): boolean => button.nativeElement.dataset['iso'] === key)\n ?.nativeElement.focus();\n });\n }\n\n protected onDayKey(event: KeyboardEvent, day: IRtCalendar.Day): void {\n if (!this.grid() || !GRID_KEYS.has(event.key)) {\n return;\n }\n event.preventDefault();\n this.#keyed.set(true);\n this.gridKey.emit({ key: event.key, day });\n }\n\n protected onDayHover(day: IRtCalendar.Day): void {\n if (!day.disabled) {\n this.dayHover.emit(day);\n }\n }\n\n protected onDayClick(day: IRtCalendar.Day): void {\n if (!day.disabled) {\n this.dayClick.emit(day);\n }\n }\n}\n","<ng-container rtBlock=\"rt-calendar\">\n <div rtElem=\"header\">\n <rt-icon-button\n rtElem=\"nav\"\n qa-dataid=\"calendar-prev-month\"\n icon=\"chevron-left\"\n variant=\"secondary\"\n radius=\"full\"\n [ariaLabel]=\"prevAriaLabel()\"\n [disabled]=\"!canPrev()\"\n (clicked)=\"prevMonth.emit()\" />\n @if (headerTitle() && months()[0]; as first) {\n <ng-container *ngTemplateOutlet=\"titleTpl; context: { $implicit: first }\" />\n }\n <ng-content select=\"[calendarHint]\" />\n <rt-icon-button\n rtElem=\"nav\"\n qa-dataid=\"calendar-next-month\"\n icon=\"chevron-right\"\n variant=\"secondary\"\n radius=\"full\"\n [ariaLabel]=\"nextAriaLabel()\"\n [disabled]=\"!canNext()\"\n (clicked)=\"nextMonth.emit()\" />\n </div>\n\n <div rtElem=\"months\" qa-dataid=\"calendar-months\" (mouseleave)=\"dayHover.emit(null)\">\n @for (month of months(); track month.key) {\n <div rtElem=\"month\" qa-dataid=\"calendar-month\">\n @if (!headerTitle()) {\n <ng-container *ngTemplateOutlet=\"titleTpl; context: { $implicit: month }\" />\n }\n <div rtElem=\"grid\" qa-dataid=\"calendar-grid\">\n @for (weekday of weekdayLabels(); track $index) {\n <span rtElem=\"weekday\" qa-dataid=\"calendar-weekday\">{{ weekday }}</span>\n }\n @for (blank of month.leadingBlanks; track blank) {\n <!-- Пустая ячейка сетки до первого дня месяца: занимает место и ничего не красит. -->\n <span qa-dataid=\"calendar-blank\" aria-hidden=\"true\"></span>\n }\n @for (day of month.days; track day.key) {\n <button\n #dayButton\n rtElem=\"day\"\n qa-dataid=\"calendar-day\"\n type=\"button\"\n [attr.data-iso]=\"day.key\"\n [attr.data-state]=\"day.state\"\n [attr.data-today]=\"day.today ? '' : null\"\n [attr.aria-current]=\"day.today ? 'date' : null\"\n [attr.aria-pressed]=\"day.state === chosenState ? true : null\"\n [attr.tabindex]=\"rovingKey() === null ? null : day.key === rovingKey() ? 0 : -1\"\n [disabled]=\"day.disabled\"\n (keydown)=\"onDayKey($event, day)\"\n (mouseenter)=\"onDayHover(day)\"\n (focus)=\"onDayHover(day)\"\n (click)=\"onDayClick(day)\">\n <span rtElem=\"day-num\" qa-dataid=\"calendar-day-num\">{{ day.dayOfMonth }}</span>\n @if (sublabelsLoading()) {\n <rt-skeleton\n rtElem=\"day-sublabel\"\n qa-dataid=\"calendar-day-price-skeleton\"\n width=\"80%\"\n radius=\"sm\"\n [height]=\"sublabelSkeletonHeight\" />\n } @else if (day.sublabel) {\n <span rtElem=\"day-sublabel\" qa-dataid=\"calendar-day-price\">{{ day.sublabel }}</span>\n }\n </button>\n }\n </div>\n </div>\n }\n </div>\n\n <ng-content />\n\n <ng-template #titleTpl let-month>\n @if (titleAction()) {\n <button rtElem=\"month-title\" qa-dataid=\"calendar-month-title\" type=\"button\" (click)=\"titleClick.emit(month)\">\n {{ month.label }}\n </button>\n } @else {\n <p rtElem=\"month-title\" qa-dataid=\"calendar-month-title\">{{ month.label }}</p>\n }\n </ng-template>\n</ng-container>\n"],"mappings":"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"}
|