@rt-tools/ui-kit-v2 0.29.1 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs +23 -29
  2. package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs.map +1 -1
  3. package/fesm2022/rt-tools-ui-kit-v2-calendar.mjs +2 -2
  4. package/fesm2022/rt-tools-ui-kit-v2-calendar.mjs.map +1 -1
  5. package/fesm2022/rt-tools-ui-kit-v2-core.mjs +223 -3
  6. package/fesm2022/rt-tools-ui-kit-v2-core.mjs.map +1 -1
  7. package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs +2 -2
  8. package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs.map +1 -1
  9. package/fesm2022/rt-tools-ui-kit-v2-draggable-tree.mjs +1 -2
  10. package/fesm2022/rt-tools-ui-kit-v2-draggable-tree.mjs.map +1 -1
  11. package/fesm2022/rt-tools-ui-kit-v2-dynamic-list.mjs +2 -2
  12. package/fesm2022/rt-tools-ui-kit-v2-dynamic-list.mjs.map +1 -1
  13. package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs +277 -904
  14. package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs.map +1 -1
  15. package/fesm2022/rt-tools-ui-kit-v2-filter-control.mjs +2 -2
  16. package/fesm2022/rt-tools-ui-kit-v2-filter-control.mjs.map +1 -1
  17. package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree.mjs +1 -1
  18. package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree.mjs.map +1 -1
  19. package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs +35 -48
  20. package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs.map +1 -1
  21. package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs +2 -2
  22. package/fesm2022/rt-tools-ui-kit-v2-pdf-viewer.mjs +2 -2
  23. package/fesm2022/rt-tools-ui-kit-v2-pdf-viewer.mjs.map +1 -1
  24. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +4 -4
  25. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
  26. package/fesm2022/rt-tools-ui-kit-v2-select.mjs +37 -181
  27. package/fesm2022/rt-tools-ui-kit-v2-select.mjs.map +1 -1
  28. package/fesm2022/rt-tools-ui-kit-v2-service-block.mjs +131 -0
  29. package/fesm2022/rt-tools-ui-kit-v2-service-block.mjs.map +1 -0
  30. package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs +5 -36
  31. package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs.map +1 -1
  32. package/fesm2022/rt-tools-ui-kit-v2-tag.mjs +2 -3
  33. package/fesm2022/rt-tools-ui-kit-v2-tag.mjs.map +1 -1
  34. package/fesm2022/rt-tools-ui-kit-v2-toolbar.mjs +2 -2
  35. package/fesm2022/rt-tools-ui-kit-v2-toolbar.mjs.map +1 -1
  36. package/fesm2022/rt-tools-ui-kit-v2-tree-selector.mjs +8 -13
  37. package/fesm2022/rt-tools-ui-kit-v2-tree-selector.mjs.map +1 -1
  38. package/fesm2022/rt-tools-ui-kit-v2-tree.mjs +12 -7
  39. package/fesm2022/rt-tools-ui-kit-v2-tree.mjs.map +1 -1
  40. package/fesm2022/rt-tools-ui-kit-v2-workspace.mjs +2 -2
  41. package/fesm2022/rt-tools-ui-kit-v2-workspace.mjs.map +1 -1
  42. package/fesm2022/rt-tools-ui-kit-v2.mjs +1 -0
  43. package/package.json +5 -1
  44. package/src/lib/components/dynamic-selector/stories/component/test-dynamic-selector-popup-frame.component.scss +6 -0
  45. package/src/lib/components/page-header/rt-page-header.component.scss +4 -2
  46. package/src/lib/components/service-block/CONTEXT.md +37 -0
  47. package/src/lib/components/service-block/rt-service-block.component.scss +61 -0
  48. package/src/lib/components/tree/CONTEXT.md +1 -1
  49. package/src/rich-editor/lib/components/ai-chat/CONTEXT.md +1 -1
  50. package/src/styles/_breakpoints.scss +37 -4
  51. package/src/styles/_index.scss +0 -4
  52. package/styles/tokens.css +0 -8
  53. package/types/rt-tools-ui-kit-v2-autocomplete.d.ts +4 -3
  54. package/types/rt-tools-ui-kit-v2-core.d.ts +155 -1
  55. package/types/rt-tools-ui-kit-v2-dynamic-selector.d.ts +51 -269
  56. package/types/rt-tools-ui-kit-v2-multiselect.d.ts +4 -3
  57. package/types/rt-tools-ui-kit-v2-select.d.ts +12 -74
  58. package/types/rt-tools-ui-kit-v2-service-block.d.ts +34 -0
  59. package/types/rt-tools-ui-kit-v2-side-menu.d.ts +5 -20
  60. package/types/rt-tools-ui-kit-v2-tag.d.ts +2 -3
  61. package/types/rt-tools-ui-kit-v2-tree-selector.d.ts +0 -2
  62. package/types/rt-tools-ui-kit-v2-tree.d.ts +7 -9
  63. package/types/rt-tools-ui-kit-v2.d.ts +1 -0
  64. 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.activeOptionId = computed(() => this.isOpen() && this.activeIndex() >= 0 ? `${this.panelId}-opt-${this.activeIndex()}` : null, ...ngDevMode ? [{ debugName: "activeOptionId" }] : /* istanbul ignore next */ []);
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
- switch (key) {
102
- case "ArrowDown":
103
- event.preventDefault();
104
- this.#moveActive(1);
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 "ArrowUp":
107
- event.preventDefault();
108
- this.#moveActive(-1);
114
+ case "previous":
115
+ this.optionList.move(-1);
109
116
  break;
110
- case "Enter":
111
- event.preventDefault();
117
+ case "choose":
112
118
  this.#selectActive();
113
119
  break;
114
- case "Escape":
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":";;;;;;;;AASA,IAAY;CAAZ,SAAY,qBAAmB;CAC3B,oBAAA,UAAA;CACA,oBAAA,UAAA;CACA,oBAAA,UAAA;CACA,oBAAA,aAAA;CACA,oBAAA,WAAA;CACA,oBAAA,SAAA;CACA,oBAAA,aAAA;CAEA,oBAAA,YAAA;AACJ,EAAA,CAVY,wBAAA,sBAAmB,CAAA,EAAA;ACoB/B,MAAM,YAAoB;AAG1B,MAAM,4BAAiC,IAAI,IAAI;CAAC;CAAa;CAAc;CAAW;CAAa;CAAU;CAAY;CAAQ;AAAK,CAAC;AAyBvI,IAAa,sBAAb,MAAa,oBAAmB;CAEnB;CAoET,cAAA;EApES,KAAA,SAAkC,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;EAErC,KAAA,yBAAiC;EACjC,KAAA,cAAmC,oBAAoB;EAEvD,KAAA,aACf,aAA4C,aAAY,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;EAMzC,KAAA,YAAmC,eAA6B;GAC/E,IAAI,CAAC,KAAK,KAAI,GACV,OAAO;GAEX,MAAM,OAA0B,KAAK,OAAM,CAAE,CAAC,SAAS,UAAgD,CAAC,GAAG,MAAM,IAAI,CAAC;GACtH,MAAM,SAAwB,KAAK,UAAS;GAM5C,QAJI,KAAK,MAAM,QAAkC,IAAI,QAAQ,MAAM,KAC/D,KAAK,MAAM,QAAkC,IAAI,UAAU,oBAAoB,MAAM,KACrF,KAAK,MAAM,QAAkC,IAAI,UAAU,IAAI,KAC/D,KAAK,MAAM,QAAkC,CAAC,IAAI,QAAQ,EACvD,EAAM,OAAO;EACxB,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;EAEc,KAAA,SAAoD,MAAM,SAAwC,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;EAClG,KAAA,gBAAgD,MAAM,SAA6B,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;EACnF,KAAA,UAA2D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,UAAA,+BAAA,CAAA;GACzG,WAAW;EAAgB,CAAA;EAEf,KAAA,UAA2D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,UAAA,+BAAA,CAAA;GACzG,WAAW;EAAgB,CAAA;EAGf,KAAA,gBAAqC,MAAc,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;EACtD,KAAA,gBAAqC,MAAc,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;EACtD,KAAA,mBAAoE,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,mBAAA,+BAAA,CAAA;GAClH,WAAW;EAAgB,CAAA;EAOf,KAAA,OAAwD,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,OAAA,+BAAA,CAAA;GACtG,WAAW;EAAgB,CAAA;EAGf,KAAA,YAAwC,MAAqB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;EAElE,KAAA,cAA+D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,cAAA,+BAAA,CAAA;GAC7G,WAAW;EAAgB,CAAA;EAGf,KAAA,cAA+D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,cAAA,+BAAA,CAAA;GAC7G,WAAW;EAAgB,CAAA;EAGf,KAAA,YAAoC,OAAM;EAC1C,KAAA,YAAoC,OAAM;EAC1C,KAAA,WAA8C,OAAM;EAEpD,KAAA,UAAiD,OAAM;EACvD,KAAA,aAAkD,OAAM;EAExD,KAAA,WAAqD,OAAM;EAGvE,wBAA6B;GACzB,MAAM,MAAqB,KAAK,UAAS;GACzC,IAAI,CAAC,KAAK,OAAM,KAAM,QAAQ,MAC1B;GAEJ,KAAK,WAAU,CAAE,CACZ,MAAM,WAAmD,OAAO,cAAc,QAAQ,WAAW,GAAG,CAAC,EACpG,cAAc,MAAK;EAC7B,CAAC;CACL;CAEU,SAAS,OAAsB,KAAoB;EACzD,IAAI,CAAC,KAAK,KAAI,KAAM,CAAC,UAAU,IAAI,MAAM,GAAG,GACxC;EAEJ,MAAM,eAAc;EACpB,KAAK,OAAO,IAAI,IAAI;EACpB,KAAK,QAAQ,KAAK;GAAE,KAAK,MAAM;GAAK;EAAG,CAAE;CAC7C;CAEU,WAAW,KAAoB;EACrC,IAAI,CAAC,IAAI,UACL,KAAK,SAAS,KAAK,GAAG;CAE9B;CAEU,WAAW,KAAoB;EACrC,IAAI,CAAC,IAAI,UACL,KAAK,SAAS,KAAK,GAAG;CAE9B;CArGS;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAmB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAAnB;EAAA,KAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAAmB,cAAA;GAAA,UAAA;GAAA,QAAA;IAAA,QAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,eAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,SAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,SAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,eAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,eAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,kBAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,MAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,WAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,aAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,aAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;GAAA;GAAA,SAAA;IAAA,WAAA;IAAA,WAAA;IAAA,UAAA;IAAA,SAAA;IAAA,YAAA;IAAA,UAAA;GAAA;GAAA,MAAA,EAAA,gBAAA,cAAA;GAAA,aAAA,CAAA;IAAA,cAAA;IAAA,WAAA,CAAA,WAAA;IAAA,aAAA;IAAA,UAAA;GAAA,CAAA;GAAA,gBAAA,CAAA;IAAA,WAAA,GAAA;IAAA,QAAA,CAAA,UAAA,QAAA;GAAA,CAAA;GAAA,UAAA;GAAA,UCzDhC;GAuFA,QAAA,CAAA,+/IAAA;GAAA,cAAA;IAAA;KAAA,MAAA;KAAA,MD7CQ;KAAgB,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;KAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MAGhB;KAAc,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACd;KAAa,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MAGb;KAAqB,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;KAAA;KAAA,SAAA,CAAA,SAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACrB;KAAmB,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;MAAA;MAAA;KAAA;IAAA;GAAA;GAAA,iBAAA,GAAA,wBAAA;GAAA,eAAA,GAAA,kBAAA;EAAA,CAAA;CAAA;;AAOd,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAmB,YAAA,CAAA;EAvB/B,MAAA;EACa,MAAA,CAAA;GAAA,UAAA;GAAa,iBAGN,wBAAwB;GAAM,eAChC,kBAAkB;GAAI,SAC5B;IAEL;IAGA;IACA;IAGA;IACA;GACH;GAAA,gBACe,CAAC;IAAE,WAAW;IAAmB,QAAQ,CAAC,QAAQ;GAAC,CAAE;GAAC,MAChE,EACF,OAAO,UACV;GAAA,UAAA;GAAA,QAAA,CAAA,+/IAAA;EAAA,CAAA;CAU+C,CAAA;CAAA,sBAAA,CAAA;CAAA,gBAAA;EAAA,YAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,aAAW,EAAA,UAAA,KAAA,CAAA;EAAA,CAAA;EAAA,QAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,eAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,eAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,eAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,kBAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,MAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,WAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,aAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,aAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,WAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,WAAA;EAAA,CAAA;EAAA,WAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,WAAA;EAAA,CAAA;EAAA,UAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,UAAA;EAAA,CAAA;EAAA,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,SAAA;EAAA,CAAA;EAAA,YAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,YAAA;EAAA,CAAA;EAAA,UAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,UAAA;EAAA,CAAA;CAAA;AAAA,CAAA"}
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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"}