@gravionlabs/helix-ui 22.2.7 → 22.2.9

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.
@@ -2,7 +2,7 @@ import * as i1 from "@angular/cdk/accordion";
2
2
  import { CdkAccordion, CdkAccordionItem } from "@angular/cdk/accordion";
3
3
  import { DOCUMENT, NgComponentOutlet, NgStyle, NgTemplateOutlet, isPlatformBrowser } from "@angular/common";
4
4
  import * as i0 from "@angular/core";
5
- import { ChangeDetectionStrategy, Component, DestroyRef, Directive, ElementRef, Injectable, InjectionToken, Injector, PLATFORM_ID, TemplateRef, afterEveryRender, afterNextRender, booleanAttribute, computed, contentChild, contentChildren, effect, forwardRef, inject, input, isDevMode, makeEnvironmentProviders, model, numberAttribute, output, provideEnvironmentInitializer, signal, untracked, viewChild } from "@angular/core";
5
+ import { ChangeDetectionStrategy, Component, DestroyRef, Directive, ElementRef, Injectable, InjectionToken, Injector, PLATFORM_ID, TemplateRef, afterEveryRender, afterNextRender, booleanAttribute, computed, contentChild, contentChildren, effect, forwardRef, inject, input, isDevMode, makeEnvironmentProviders, model, numberAttribute, output, provideEnvironmentInitializer, signal, untracked, viewChild, viewChildren } from "@angular/core";
6
6
  import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
7
7
  import { CdkConnectedOverlay, CdkOverlayOrigin, Overlay } from "@angular/cdk/overlay";
8
8
  import { NG_VALUE_ACCESSOR, NgControl } from "@angular/forms";
@@ -4441,9 +4441,14 @@ i0.ɵɵngDeclareClassMetadata({
4441
4441
  }]
4442
4442
  }
4443
4443
  });
4444
+ const HX_SELECT_OVERLAY_CLASS = "hx-select-overlay";
4445
+ function isInSelectOverlay(target) {
4446
+ return target instanceof Element && target.closest(`.hx-select-overlay`) !== null;
4447
+ }
4444
4448
  var HxSelect = class HxSelect {
4445
4449
  #host = inject(ElementRef);
4446
4450
  #injector = inject(Injector);
4451
+ overlayClass = HX_SELECT_OVERLAY_CLASS;
4447
4452
  options = input([], ...ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []);
4448
4453
  optionLabel = input("label", ...ngDevMode ? [{ debugName: "optionLabel" }] : /* istanbul ignore next */ []);
4449
4454
  optionValue = input("value", ...ngDevMode ? [{ debugName: "optionValue" }] : /* istanbul ignore next */ []);
@@ -4470,6 +4475,7 @@ var HxSelect = class HxSelect {
4470
4475
  inputId = input(...ngDevMode ? [void 0, { debugName: "inputId" }] : /* istanbul ignore next */ []);
4471
4476
  ariaLabel = input(...ngDevMode ? [void 0, { debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
4472
4477
  ariaLabelledby = input(...ngDevMode ? [void 0, { debugName: "ariaLabelledby" }] : /* istanbul ignore next */ []);
4478
+ ariaDescribedby = input(...ngDevMode ? [void 0, { debugName: "ariaDescribedby" }] : /* istanbul ignore next */ []);
4473
4479
  compareWith = input(compareValues$1, ...ngDevMode ? [{ debugName: "compareWith" }] : /* istanbul ignore next */ []);
4474
4480
  value = model(null, ...ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []);
4475
4481
  disabled = input(false, {
@@ -4750,6 +4756,13 @@ var HxSelect = class HxSelect {
4750
4756
  isRequired: false,
4751
4757
  transformFunction: null
4752
4758
  },
4759
+ ariaDescribedby: {
4760
+ classPropertyName: "ariaDescribedby",
4761
+ publicName: "ariaDescribedby",
4762
+ isSignal: true,
4763
+ isRequired: false,
4764
+ transformFunction: null
4765
+ },
4753
4766
  compareWith: {
4754
4767
  classPropertyName: "compareWith",
4755
4768
  publicName: "compareWith",
@@ -4827,7 +4840,7 @@ var HxSelect = class HxSelect {
4827
4840
  }
4828
4841
  ],
4829
4842
  ngImport: i0,
4830
- template: "<button\n #trigger\n type=\"button\"\n class=\"hx-select-trigger\"\n role=\"combobox\"\n cdkOverlayOrigin\n #origin=\"cdkOverlayOrigin\"\n aria-haspopup=\"listbox\"\n [attr.id]=\"inputId() ?? null\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? panelId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (click)=\"toggle()\"\n (keydown)=\"onTriggerKeydown($event)\"\n>\n <span class=\"hx-select-label\" [class.hx-select-placeholder]=\"!selected()\">{{\n selected()?.label ?? placeholder()\n }}</span>\n <span class=\"hx-select-chevron\" aria-hidden=\"true\"></span>\n</button>\n@if (canClear()) {\n <button type=\"button\" class=\"hx-select-clear\" aria-label=\"Clear selection\" (click)=\"clear($event)\">\n <span class=\"hx-select-clear-icon\" aria-hidden=\"true\"></span>\n </button>\n}\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayPanelClass=\"hx-select-overlay\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayMinWidth]=\"panelWidth()\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"close()\"\n>\n <div class=\"hx-select-panel\">\n @if (filter()) {\n <div class=\"hx-select-header\">\n <input\n #filterField\n type=\"text\"\n class=\"hx-select-filter\"\n autocomplete=\"off\"\n [attr.aria-label]=\"filterPlaceholder()\"\n [attr.aria-controls]=\"panelId\"\n [placeholder]=\"filterPlaceholder()\"\n [value]=\"query()\"\n (input)=\"query.set($any($event.target).value)\"\n (keydown)=\"onFilterKeydown($event)\"\n />\n </div>\n }\n <div\n cdkListbox\n class=\"hx-select-list\"\n [id]=\"panelId\"\n [cdkListboxValue]=\"selectedValues()\"\n [cdkListboxUseActiveDescendant]=\"true\"\n [cdkListboxCompareWith]=\"compareWith()\"\n [attr.aria-label]=\"ariaLabel() ?? placeholder() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (cdkListboxValueChange)=\"onSelect($event)\"\n >\n @for (item of visibleItems(); track item) {\n <div\n class=\"hx-select-option\"\n [cdkOption]=\"item.value\"\n [cdkOptionDisabled]=\"item.disabled\"\n [cdkOptionTypeaheadLabel]=\"item.label\"\n >\n <span class=\"hx-select-check\" aria-hidden=\"true\"></span>\n <span>{{ item.label }}</span>\n </div>\n } @empty {\n <div class=\"hx-select-empty\">{{ query().trim() ? emptyFilterMessage() : emptyMessage() }}</div>\n }\n </div>\n @if (filter()) {\n <span class=\"hx-select-sr-only\" aria-live=\"polite\">{{ resultsLabel() }}</span>\n }\n </div>\n</ng-template>\n",
4843
+ template: "<button\n #trigger\n type=\"button\"\n class=\"hx-select-trigger\"\n role=\"combobox\"\n cdkOverlayOrigin\n #origin=\"cdkOverlayOrigin\"\n aria-haspopup=\"listbox\"\n [attr.id]=\"inputId() ?? null\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? panelId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-describedby]=\"ariaDescribedby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (click)=\"toggle()\"\n (keydown)=\"onTriggerKeydown($event)\"\n>\n <span class=\"hx-select-label\" [class.hx-select-placeholder]=\"!selected()\">{{\n selected()?.label ?? placeholder()\n }}</span>\n <span class=\"hx-select-chevron\" aria-hidden=\"true\"></span>\n</button>\n@if (canClear()) {\n <button type=\"button\" class=\"hx-select-clear\" aria-label=\"Clear selection\" (click)=\"clear($event)\">\n <span class=\"hx-select-clear-icon\" aria-hidden=\"true\"></span>\n </button>\n}\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayPanelClass]=\"overlayClass\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayMinWidth]=\"panelWidth()\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"close()\"\n>\n <div class=\"hx-select-panel\">\n @if (filter()) {\n <div class=\"hx-select-header\">\n <input\n #filterField\n type=\"text\"\n class=\"hx-select-filter\"\n autocomplete=\"off\"\n [attr.aria-label]=\"filterPlaceholder()\"\n [attr.aria-controls]=\"panelId\"\n [placeholder]=\"filterPlaceholder()\"\n [value]=\"query()\"\n (input)=\"query.set($any($event.target).value)\"\n (keydown)=\"onFilterKeydown($event)\"\n />\n </div>\n }\n <div\n cdkListbox\n class=\"hx-select-list\"\n [id]=\"panelId\"\n [cdkListboxValue]=\"selectedValues()\"\n [cdkListboxUseActiveDescendant]=\"true\"\n [cdkListboxCompareWith]=\"compareWith()\"\n [attr.aria-label]=\"ariaLabel() ?? placeholder() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (cdkListboxValueChange)=\"onSelect($event)\"\n >\n @for (item of visibleItems(); track item) {\n <div\n class=\"hx-select-option\"\n [cdkOption]=\"item.value\"\n [cdkOptionDisabled]=\"item.disabled\"\n [cdkOptionTypeaheadLabel]=\"item.label\"\n >\n <span class=\"hx-select-check\" aria-hidden=\"true\"></span>\n <span>{{ item.label }}</span>\n </div>\n } @empty {\n <div class=\"hx-select-empty\">{{ query().trim() ? emptyFilterMessage() : emptyMessage() }}</div>\n }\n </div>\n @if (filter()) {\n <span class=\"hx-select-sr-only\" aria-live=\"polite\">{{ resultsLabel() }}</span>\n }\n </div>\n</ng-template>\n",
4831
4844
  dependencies: [
4832
4845
  {
4833
4846
  kind: "directive",
@@ -4946,7 +4959,7 @@ i0.ɵɵngDeclareClassMetadata({
4946
4959
  "[class.hx-filled]": "!!selected()",
4947
4960
  "(focusout)": "onFocusOut($event)"
4948
4961
  },
4949
- template: "<button\n #trigger\n type=\"button\"\n class=\"hx-select-trigger\"\n role=\"combobox\"\n cdkOverlayOrigin\n #origin=\"cdkOverlayOrigin\"\n aria-haspopup=\"listbox\"\n [attr.id]=\"inputId() ?? null\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? panelId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (click)=\"toggle()\"\n (keydown)=\"onTriggerKeydown($event)\"\n>\n <span class=\"hx-select-label\" [class.hx-select-placeholder]=\"!selected()\">{{\n selected()?.label ?? placeholder()\n }}</span>\n <span class=\"hx-select-chevron\" aria-hidden=\"true\"></span>\n</button>\n@if (canClear()) {\n <button type=\"button\" class=\"hx-select-clear\" aria-label=\"Clear selection\" (click)=\"clear($event)\">\n <span class=\"hx-select-clear-icon\" aria-hidden=\"true\"></span>\n </button>\n}\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayPanelClass=\"hx-select-overlay\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayMinWidth]=\"panelWidth()\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"close()\"\n>\n <div class=\"hx-select-panel\">\n @if (filter()) {\n <div class=\"hx-select-header\">\n <input\n #filterField\n type=\"text\"\n class=\"hx-select-filter\"\n autocomplete=\"off\"\n [attr.aria-label]=\"filterPlaceholder()\"\n [attr.aria-controls]=\"panelId\"\n [placeholder]=\"filterPlaceholder()\"\n [value]=\"query()\"\n (input)=\"query.set($any($event.target).value)\"\n (keydown)=\"onFilterKeydown($event)\"\n />\n </div>\n }\n <div\n cdkListbox\n class=\"hx-select-list\"\n [id]=\"panelId\"\n [cdkListboxValue]=\"selectedValues()\"\n [cdkListboxUseActiveDescendant]=\"true\"\n [cdkListboxCompareWith]=\"compareWith()\"\n [attr.aria-label]=\"ariaLabel() ?? placeholder() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (cdkListboxValueChange)=\"onSelect($event)\"\n >\n @for (item of visibleItems(); track item) {\n <div\n class=\"hx-select-option\"\n [cdkOption]=\"item.value\"\n [cdkOptionDisabled]=\"item.disabled\"\n [cdkOptionTypeaheadLabel]=\"item.label\"\n >\n <span class=\"hx-select-check\" aria-hidden=\"true\"></span>\n <span>{{ item.label }}</span>\n </div>\n } @empty {\n <div class=\"hx-select-empty\">{{ query().trim() ? emptyFilterMessage() : emptyMessage() }}</div>\n }\n </div>\n @if (filter()) {\n <span class=\"hx-select-sr-only\" aria-live=\"polite\">{{ resultsLabel() }}</span>\n }\n </div>\n</ng-template>\n"
4962
+ template: "<button\n #trigger\n type=\"button\"\n class=\"hx-select-trigger\"\n role=\"combobox\"\n cdkOverlayOrigin\n #origin=\"cdkOverlayOrigin\"\n aria-haspopup=\"listbox\"\n [attr.id]=\"inputId() ?? null\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? panelId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-describedby]=\"ariaDescribedby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (click)=\"toggle()\"\n (keydown)=\"onTriggerKeydown($event)\"\n>\n <span class=\"hx-select-label\" [class.hx-select-placeholder]=\"!selected()\">{{\n selected()?.label ?? placeholder()\n }}</span>\n <span class=\"hx-select-chevron\" aria-hidden=\"true\"></span>\n</button>\n@if (canClear()) {\n <button type=\"button\" class=\"hx-select-clear\" aria-label=\"Clear selection\" (click)=\"clear($event)\">\n <span class=\"hx-select-clear-icon\" aria-hidden=\"true\"></span>\n </button>\n}\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayPanelClass]=\"overlayClass\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayMinWidth]=\"panelWidth()\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"close()\"\n>\n <div class=\"hx-select-panel\">\n @if (filter()) {\n <div class=\"hx-select-header\">\n <input\n #filterField\n type=\"text\"\n class=\"hx-select-filter\"\n autocomplete=\"off\"\n [attr.aria-label]=\"filterPlaceholder()\"\n [attr.aria-controls]=\"panelId\"\n [placeholder]=\"filterPlaceholder()\"\n [value]=\"query()\"\n (input)=\"query.set($any($event.target).value)\"\n (keydown)=\"onFilterKeydown($event)\"\n />\n </div>\n }\n <div\n cdkListbox\n class=\"hx-select-list\"\n [id]=\"panelId\"\n [cdkListboxValue]=\"selectedValues()\"\n [cdkListboxUseActiveDescendant]=\"true\"\n [cdkListboxCompareWith]=\"compareWith()\"\n [attr.aria-label]=\"ariaLabel() ?? placeholder() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (cdkListboxValueChange)=\"onSelect($event)\"\n >\n @for (item of visibleItems(); track item) {\n <div\n class=\"hx-select-option\"\n [cdkOption]=\"item.value\"\n [cdkOptionDisabled]=\"item.disabled\"\n [cdkOptionTypeaheadLabel]=\"item.label\"\n >\n <span class=\"hx-select-check\" aria-hidden=\"true\"></span>\n <span>{{ item.label }}</span>\n </div>\n } @empty {\n <div class=\"hx-select-empty\">{{ query().trim() ? emptyFilterMessage() : emptyMessage() }}</div>\n }\n </div>\n @if (filter()) {\n <span class=\"hx-select-sr-only\" aria-live=\"polite\">{{ resultsLabel() }}</span>\n }\n </div>\n</ng-template>\n"
4950
4963
  }]
4951
4964
  }],
4952
4965
  propDecorators: {
@@ -5086,6 +5099,14 @@ i0.ɵɵngDeclareClassMetadata({
5086
5099
  required: false
5087
5100
  }]
5088
5101
  }],
5102
+ ariaDescribedby: [{
5103
+ type: i0.Input,
5104
+ args: [{
5105
+ isSignal: true,
5106
+ alias: "ariaDescribedby",
5107
+ required: false
5108
+ }]
5109
+ }],
5089
5110
  compareWith: [{
5090
5111
  type: i0.Input,
5091
5112
  args: [{
@@ -5393,6 +5414,7 @@ var HxPaginator = class HxPaginator {
5393
5414
  "inputId",
5394
5415
  "ariaLabel",
5395
5416
  "ariaLabelledby",
5417
+ "ariaDescribedby",
5396
5418
  "compareWith",
5397
5419
  "value",
5398
5420
  "disabled",
@@ -6199,6 +6221,11 @@ var HxDataTable = class HxDataTable {
6199
6221
  filterDisplay = input(...ngDevMode ? [void 0, { debugName: "filterDisplay" }] : /* istanbul ignore next */ []);
6200
6222
  filters = model({}, ...ngDevMode ? [{ debugName: "filters" }] : /* istanbul ignore next */ []);
6201
6223
  filterLabel = input("Filter {header}", ...ngDevMode ? [{ debugName: "filterLabel" }] : /* istanbul ignore next */ []);
6224
+ clearLabel = input("Clear", ...ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []);
6225
+ filterPopover = viewChild(HxPopover, ...ngDevMode ? [{ debugName: "filterPopover" }] : /* istanbul ignore next */ []);
6226
+ filterInput = viewChild("filterInput", ...ngDevMode ? [{ debugName: "filterInput" }] : /* istanbul ignore next */ []);
6227
+ activeFilterColumn = signal(null, ...ngDevMode ? [{ debugName: "activeFilterColumn" }] : /* istanbul ignore next */ []);
6228
+ injector = inject(Injector);
6202
6229
  expandedRowKeys = model({}, ...ngDevMode ? [{ debugName: "expandedRowKeys" }] : /* istanbul ignore next */ []);
6203
6230
  expandLabel = input("Expand row", ...ngDevMode ? [{ debugName: "expandLabel" }] : /* istanbul ignore next */ []);
6204
6231
  collapseLabel = input("Collapse row", ...ngDevMode ? [{ debugName: "collapseLabel" }] : /* istanbul ignore next */ []);
@@ -6322,6 +6349,26 @@ var HxDataTable = class HxDataTable {
6322
6349
  this.first.set(0);
6323
6350
  if (this.lazy()) this.emitLazy();
6324
6351
  }
6352
+ openFilter(event, column) {
6353
+ const popover = this.filterPopover();
6354
+ if (!popover) return;
6355
+ if (popover.open() && this.activeFilterColumn()?.field === column.field) {
6356
+ popover.hide();
6357
+ return;
6358
+ }
6359
+ const switching = popover.open();
6360
+ popover.hide(false);
6361
+ this.activeFilterColumn.set(column);
6362
+ popover.show(event, event.currentTarget);
6363
+ if (switching) afterNextRender(() => this.filterInput()?.nativeElement.focus(), { injector: this.injector });
6364
+ }
6365
+ filterLabelFor(column) {
6366
+ return this.filterLabel().replace("{header}", column.header);
6367
+ }
6368
+ clearFilter(column) {
6369
+ this.setFilter(column, "");
6370
+ this.filterPopover()?.hide();
6371
+ }
6325
6372
  setFilter(column, text) {
6326
6373
  const next = { ...this.filters() };
6327
6374
  if (text) next[column.field] = text;
@@ -6695,6 +6742,13 @@ var HxDataTable = class HxDataTable {
6695
6742
  isRequired: false,
6696
6743
  transformFunction: null
6697
6744
  },
6745
+ clearLabel: {
6746
+ classPropertyName: "clearLabel",
6747
+ publicName: "clearLabel",
6748
+ isSignal: true,
6749
+ isRequired: false,
6750
+ transformFunction: null
6751
+ },
6698
6752
  expandedRowKeys: {
6699
6753
  classPropertyName: "expandedRowKeys",
6700
6754
  publicName: "expandedRowKeys",
@@ -6783,8 +6837,21 @@ var HxDataTable = class HxDataTable {
6783
6837
  isSignal: true
6784
6838
  }
6785
6839
  ],
6840
+ viewQueries: [{
6841
+ propertyName: "filterPopover",
6842
+ first: true,
6843
+ predicate: HxPopover,
6844
+ descendants: true,
6845
+ isSignal: true
6846
+ }, {
6847
+ propertyName: "filterInput",
6848
+ first: true,
6849
+ predicate: ["filterInput"],
6850
+ descendants: true,
6851
+ isSignal: true
6852
+ }],
6786
6853
  ngImport: i0,
6787
- template: "<div class=\"hx-data-table-frame\" [attr.aria-busy]=\"loading() ? 'true' : null\">\n <div\n class=\"hx-table-scroll hx-data-table-scroll\"\n [class.hx-data-table-scrolls]=\"scrolls()\"\n [style.max-height]=\"scrollHeight() ?? null\"\n [attr.role]=\"scrolls() ? 'region' : null\"\n [attr.aria-label]=\"scrolls() ? (ariaLabel() ?? caption() ?? null) : null\"\n [attr.tabindex]=\"scrolls() ? 0 : null\"\n >\n <table\n class=\"hx-table\"\n [class.hx-table-sm]=\"size() === 'small'\"\n [class.hx-table-lg]=\"size() === 'large'\"\n [class.hx-table-striped]=\"stripedRows()\"\n [class.hx-table-gridlines]=\"showGridlines()\"\n [class.hx-table-hoverable]=\"hoverRows()\"\n [class.hx-table-sticky]=\"!!scrollHeight()\"\n >\n @if (hasCaption()) {\n <caption [class.hx-data-table-caption-hidden]=\"captionHidden()\">\n @if (captionTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" />\n } @else {\n {{ caption() ?? ariaLabel() }}\n }\n </caption>\n }\n <thead>\n <tr>\n @if (expanderColumn()) {\n <th scope=\"col\" class=\"hx-data-table-expander-cell\"><span class=\"hx-data-table-caption-hidden\">Row details</span></th>\n }\n @if (checkboxColumn()) {\n <th scope=\"col\" class=\"hx-data-table-select-cell\">\n <input type=\"checkbox\" hx-checkbox [attr.aria-label]=\"selectAllLabel()\" [checked]=\"allSelected()\" [indeterminate]=\"someSelected()\" (change)=\"toggleSelectAll($any($event.target).checked)\" />\n </th>\n }\n @if (headerTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: columns() }\" />\n } @else {\n @for (column of columns(); track column.field) {\n <th\n scope=\"col\"\n [class]=\"'hx-data-table-align-' + (column.align ?? 'left')\"\n [class.hx-data-table-sorted]=\"orderOf(column) !== 0\"\n [style.width]=\"column.width ?? null\"\n [attr.aria-sort]=\"ariaSort(column)\"\n [attr.title]=\"column.title ?? null\"\n >\n @if (columnHeaders().get(column.field); as extra) {\n <div class=\"hx-data-table-header-content\">\n <ng-container [ngTemplateOutlet]=\"label\" [ngTemplateOutletContext]=\"{ $implicit: column }\" />\n <ng-container [ngTemplateOutlet]=\"extra\" [ngTemplateOutletContext]=\"{ $implicit: column }\" />\n </div>\n } @else {\n <ng-container [ngTemplateOutlet]=\"label\" [ngTemplateOutletContext]=\"{ $implicit: column }\" />\n }\n </th>\n }\n }\n </tr>\n @if (filterRow()) {\n <tr class=\"hx-data-table-filter-row\">\n @if (expanderColumn()) { <th></th> }\n @if (checkboxColumn()) { <th></th> }\n @for (column of columns(); track column.field) {\n <th>\n @if (column.filter) {\n <input type=\"text\" hx-input size=\"small\" fluid [attr.aria-label]=\"filterLabel().replace('{header}', column.header)\" [value]=\"filters()[column.field] ?? ''\" (input)=\"setFilter(column, $any($event.target).value)\" />\n }\n </th>\n }\n </tr>\n }\n </thead>\n <tbody>\n @for (row of visibleRows(); track trackRow(row, $index); let i = $index) {\n <tr\n [class]=\"rowClassOf(row)\"\n [class.hx-data-table-selectable]=\"selectable()\"\n [attr.aria-selected]=\"selectionMode() ? (isSelected(row) ? 'true' : 'false') : null\"\n [attr.tabindex]=\"selectable() ? 0 : null\"\n (click)=\"selectRow(row, $event)\"\n (keydown.enter)=\"onRowKey(row, $event)\"\n (keydown.space)=\"onRowKey(row, $event)\"\n >\n @if (expanderColumn()) {\n <td class=\"hx-data-table-expander-cell\">\n <button type=\"button\" class=\"hx-data-table-expander\" [class.hx-data-table-expander-open]=\"isExpanded(row, i)\" [attr.aria-expanded]=\"isExpanded(row, i)\" [attr.aria-label]=\"isExpanded(row, i) ? collapseLabel() : expandLabel()\" (click)=\"toggleExpansion(row, i)\"></button>\n </td>\n }\n @if (checkboxColumn()) {\n <td class=\"hx-data-table-select-cell\">\n <input type=\"checkbox\" hx-checkbox [attr.aria-label]=\"selectRowLabel().replace('{row}', '' + (first() + i + 1))\" [checked]=\"isSelected(row)\" (change)=\"toggleRowCheckbox(row, $any($event.target).checked)\" />\n </td>\n }\n @if (bodyTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: row, index: i, columns: columns() }\" />\n } @else {\n @for (column of columns(); track column.field) {\n <td [class]=\"'hx-data-table-align-' + (column.align ?? 'left')\">\n @if (cells().get(column.field); as cell) {\n <ng-container [ngTemplateOutlet]=\"cell\" [ngTemplateOutletContext]=\"{ $implicit: row, value: valueOf(row, column), index: i }\" />\n } @else {\n {{ valueOf(row, column) ?? emptyValue() }}\n }\n </td>\n }\n }\n </tr>\n @if (expansionTemplate(); as tpl) {\n @if (isExpanded(row, i)) {\n <tr class=\"hx-data-table-expansion\">\n <td [attr.colspan]=\"colspan()\">\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: row, index: i, columns: columns() }\" />\n </td>\n </tr>\n }\n }\n } @empty {\n <tr class=\"hx-data-table-empty\">\n <td [attr.colspan]=\"colspan()\">\n @if (emptyTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" />\n } @else {\n {{ emptyMessage() }}\n }\n </td>\n </tr>\n }\n </tbody>\n @if (footerTemplate(); as tpl) {\n <tfoot>\n <tr>\n @if (expanderColumn()) { <td></td> }\n @if (checkboxColumn()) { <td></td> }\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: columns() }\" />\n </tr>\n </tfoot>\n }\n </table>\n </div>\n <span class=\"hx-data-table-caption-hidden\" aria-live=\"polite\">{{ announcement() }}</span>\n @if (loading()) {\n <div class=\"hx-data-table-loading\" role=\"status\">\n <hx-progress-spinner ariaLabel=\"Loading\" />\n </div>\n }\n @if (paginator()) {\n <hx-paginator\n class=\"hx-data-table-paginator\"\n [rows]=\"rows()\"\n [first]=\"first()\"\n [totalRecords]=\"total()\"\n [rowsPerPageOptions]=\"rowsPerPageOptions()\"\n [showAll]=\"showAll()\"\n (showAllChange)=\"showAll.set($event)\"\n [allLabel]=\"allLabel()\"\n [showCurrentPageReport]=\"showCurrentPageReport()\"\n (pageChange)=\"onPage($event)\"\n />\n }\n</div>\n\n<ng-template #label let-column>\n @if (column.sortable) {\n <button type=\"button\" class=\"hx-data-table-sort\" (click)=\"sort(column)\">\n <span>{{ column.header }}</span>\n <span class=\"hx-data-table-sort-icon\" [class.hx-data-table-sort-asc]=\"orderOf(column) === 1\" [class.hx-data-table-sort-desc]=\"orderOf(column) === -1\" aria-hidden=\"true\"></span>\n @if (sortRank(column); as rank) {\n <span class=\"hx-data-table-sort-rank\" aria-hidden=\"true\">{{ rank }}</span>\n }\n </button>\n } @else {\n {{ column.header }}\n }\n</ng-template>\n",
6854
+ template: "<div class=\"hx-data-table-frame\" [attr.aria-busy]=\"loading() ? 'true' : null\">\n <div\n class=\"hx-table-scroll hx-data-table-scroll\"\n [class.hx-data-table-scrolls]=\"scrolls()\"\n [style.max-height]=\"scrollHeight() ?? null\"\n [attr.role]=\"scrolls() ? 'region' : null\"\n [attr.aria-label]=\"scrolls() ? (ariaLabel() ?? caption() ?? null) : null\"\n [attr.tabindex]=\"scrolls() ? 0 : null\"\n >\n <table\n class=\"hx-table\"\n [class.hx-table-sm]=\"size() === 'small'\"\n [class.hx-table-lg]=\"size() === 'large'\"\n [class.hx-table-striped]=\"stripedRows()\"\n [class.hx-table-gridlines]=\"showGridlines()\"\n [class.hx-table-hoverable]=\"hoverRows()\"\n [class.hx-table-sticky]=\"!!scrollHeight()\"\n >\n @if (hasCaption()) {\n <caption [class.hx-data-table-caption-hidden]=\"captionHidden()\">\n @if (captionTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" />\n } @else {\n {{ caption() ?? ariaLabel() }}\n }\n </caption>\n }\n <thead>\n <tr>\n @if (expanderColumn()) {\n <th scope=\"col\" class=\"hx-data-table-expander-cell\"><span class=\"hx-data-table-caption-hidden\">Row details</span></th>\n }\n @if (checkboxColumn()) {\n <th scope=\"col\" class=\"hx-data-table-select-cell\">\n <input type=\"checkbox\" hx-checkbox [attr.aria-label]=\"selectAllLabel()\" [checked]=\"allSelected()\" [indeterminate]=\"someSelected()\" (change)=\"toggleSelectAll($any($event.target).checked)\" />\n </th>\n }\n @if (headerTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: columns() }\" />\n } @else {\n @for (column of columns(); track column.field) {\n <th\n scope=\"col\"\n [class]=\"'hx-data-table-align-' + (column.align ?? 'left')\"\n [class.hx-data-table-sorted]=\"orderOf(column) !== 0\"\n [style.width]=\"column.width ?? null\"\n [attr.aria-sort]=\"ariaSort(column)\"\n [attr.title]=\"column.title ?? null\"\n >\n @let extra = columnHeaders().get(column.field);\n @let menu = filterDisplay() === 'menu' && column.filter;\n @if (extra || menu) {\n <div class=\"hx-data-table-header-content\">\n <ng-container [ngTemplateOutlet]=\"label\" [ngTemplateOutletContext]=\"{ $implicit: column }\" />\n @if (extra) {\n <ng-container [ngTemplateOutlet]=\"extra\" [ngTemplateOutletContext]=\"{ $implicit: column }\" />\n }\n @if (menu) {\n <button\n type=\"button\"\n class=\"hx-data-table-filter-button\"\n [class.hx-data-table-filter-active]=\"!!filters()[column.field]\"\n aria-haspopup=\"dialog\"\n [attr.aria-expanded]=\"activeFilterColumn()?.field === column.field\"\n [attr.aria-label]=\"filterLabelFor(column)\"\n (click)=\"openFilter($event, column)\"\n >\n <span class=\"hx-data-table-filter-icon\" aria-hidden=\"true\"></span>\n </button>\n }\n </div>\n } @else {\n <ng-container [ngTemplateOutlet]=\"label\" [ngTemplateOutletContext]=\"{ $implicit: column }\" />\n }\n </th>\n }\n }\n </tr>\n @if (filterRow()) {\n <tr class=\"hx-data-table-filter-row\">\n @if (expanderColumn()) { <th></th> }\n @if (checkboxColumn()) { <th></th> }\n @for (column of columns(); track column.field) {\n <th>\n @if (column.filter) {\n <input type=\"text\" hx-input size=\"small\" fluid [attr.aria-label]=\"filterLabelFor(column)\" [value]=\"filters()[column.field] ?? ''\" (input)=\"setFilter(column, $any($event.target).value)\" />\n }\n </th>\n }\n </tr>\n }\n </thead>\n <tbody>\n @for (row of visibleRows(); track trackRow(row, $index); let i = $index) {\n <tr\n [class]=\"rowClassOf(row)\"\n [class.hx-data-table-selectable]=\"selectable()\"\n [attr.aria-selected]=\"selectionMode() ? (isSelected(row) ? 'true' : 'false') : null\"\n [attr.tabindex]=\"selectable() ? 0 : null\"\n (click)=\"selectRow(row, $event)\"\n (keydown.enter)=\"onRowKey(row, $event)\"\n (keydown.space)=\"onRowKey(row, $event)\"\n >\n @if (expanderColumn()) {\n <td class=\"hx-data-table-expander-cell\">\n <button type=\"button\" class=\"hx-data-table-expander\" [class.hx-data-table-expander-open]=\"isExpanded(row, i)\" [attr.aria-expanded]=\"isExpanded(row, i)\" [attr.aria-label]=\"isExpanded(row, i) ? collapseLabel() : expandLabel()\" (click)=\"toggleExpansion(row, i)\"></button>\n </td>\n }\n @if (checkboxColumn()) {\n <td class=\"hx-data-table-select-cell\">\n <input type=\"checkbox\" hx-checkbox [attr.aria-label]=\"selectRowLabel().replace('{row}', '' + (first() + i + 1))\" [checked]=\"isSelected(row)\" (change)=\"toggleRowCheckbox(row, $any($event.target).checked)\" />\n </td>\n }\n @if (bodyTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: row, index: i, columns: columns() }\" />\n } @else {\n @for (column of columns(); track column.field) {\n <td [class]=\"'hx-data-table-align-' + (column.align ?? 'left')\">\n @if (cells().get(column.field); as cell) {\n <ng-container [ngTemplateOutlet]=\"cell\" [ngTemplateOutletContext]=\"{ $implicit: row, value: valueOf(row, column), index: i }\" />\n } @else {\n {{ valueOf(row, column) ?? emptyValue() }}\n }\n </td>\n }\n }\n </tr>\n @if (expansionTemplate(); as tpl) {\n @if (isExpanded(row, i)) {\n <tr class=\"hx-data-table-expansion\">\n <td [attr.colspan]=\"colspan()\">\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: row, index: i, columns: columns() }\" />\n </td>\n </tr>\n }\n }\n } @empty {\n <tr class=\"hx-data-table-empty\">\n <td [attr.colspan]=\"colspan()\">\n @if (emptyTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" />\n } @else {\n {{ emptyMessage() }}\n }\n </td>\n </tr>\n }\n </tbody>\n @if (footerTemplate(); as tpl) {\n <tfoot>\n <tr>\n @if (expanderColumn()) { <td></td> }\n @if (checkboxColumn()) { <td></td> }\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: columns() }\" />\n </tr>\n </tfoot>\n }\n </table>\n </div>\n <span class=\"hx-data-table-caption-hidden\" aria-live=\"polite\">{{ announcement() }}</span>\n @if (loading()) {\n <div class=\"hx-data-table-loading\" role=\"status\">\n <hx-progress-spinner ariaLabel=\"Loading\" />\n </div>\n }\n @if (paginator()) {\n <hx-paginator\n class=\"hx-data-table-paginator\"\n [rows]=\"rows()\"\n [first]=\"first()\"\n [totalRecords]=\"total()\"\n [rowsPerPageOptions]=\"rowsPerPageOptions()\"\n [showAll]=\"showAll()\"\n (showAllChange)=\"showAll.set($event)\"\n [allLabel]=\"allLabel()\"\n [showCurrentPageReport]=\"showCurrentPageReport()\"\n (pageChange)=\"onPage($event)\"\n />\n }\n</div>\n\n@if (filterDisplay() === 'menu') {\n @let active = activeFilterColumn();\n <hx-popover panelClass=\"hx-data-table-filter-popover\" [ariaLabel]=\"active ? filterLabelFor(active) : undefined\" (hidden)=\"activeFilterColumn.set(null)\">\n @if (active) {\n <div class=\"hx-data-table-filter-menu\">\n <input #filterInput type=\"text\" hx-input size=\"small\" fluid [attr.aria-label]=\"filterLabelFor(active)\" [value]=\"filters()[active.field] ?? ''\" (input)=\"setFilter(active, $any($event.target).value)\" (keydown.enter)=\"filterPopover()?.hide()\" />\n <button hx-button type=\"button\" size=\"small\" variant=\"text\" class=\"hx-data-table-filter-clear\" (click)=\"clearFilter(active)\">{{ clearLabel() }}</button>\n </div>\n }\n </hx-popover>\n}\n\n<ng-template #label let-column>\n @if (column.sortable) {\n <button type=\"button\" class=\"hx-data-table-sort\" (click)=\"sort(column)\">\n <span>{{ column.header }}</span>\n <span class=\"hx-data-table-sort-icon\" [class.hx-data-table-sort-asc]=\"orderOf(column) === 1\" [class.hx-data-table-sort-desc]=\"orderOf(column) === -1\" aria-hidden=\"true\"></span>\n @if (sortRank(column); as rank) {\n <span class=\"hx-data-table-sort-rank\" aria-hidden=\"true\">{{ rank }}</span>\n }\n </button>\n } @else {\n {{ column.header }}\n }\n</ng-template>\n",
6788
6855
  dependencies: [
6789
6856
  {
6790
6857
  kind: "directive",
@@ -6854,6 +6921,37 @@ var HxDataTable = class HxDataTable {
6854
6921
  "autoResize"
6855
6922
  ],
6856
6923
  exportAs: ["hx-input"]
6924
+ },
6925
+ {
6926
+ kind: "directive",
6927
+ type: HxButton,
6928
+ selector: "button[hx-button], a[hx-button]",
6929
+ inputs: [
6930
+ "variant",
6931
+ "severity",
6932
+ "size",
6933
+ "rounded",
6934
+ "raised",
6935
+ "fluid",
6936
+ "iconOnly",
6937
+ "loading"
6938
+ ],
6939
+ exportAs: ["hx-button"]
6940
+ },
6941
+ {
6942
+ kind: "component",
6943
+ type: HxPopover,
6944
+ selector: "hx-popover",
6945
+ inputs: [
6946
+ "ariaLabel",
6947
+ "ariaLabelledBy",
6948
+ "ariaDescribedBy",
6949
+ "role",
6950
+ "panelClass",
6951
+ "dismissable",
6952
+ "closeOnEscape"
6953
+ ],
6954
+ outputs: ["shown", "hidden"]
6857
6955
  }
6858
6956
  ],
6859
6957
  changeDetection: i0.ChangeDetectionStrategy.OnPush
@@ -6873,11 +6971,13 @@ i0.ɵɵngDeclareClassMetadata({
6873
6971
  HxProgressSpinner,
6874
6972
  HxPaginator,
6875
6973
  HxCheckbox,
6876
- HxInput
6974
+ HxInput,
6975
+ HxButton,
6976
+ HxPopover
6877
6977
  ],
6878
6978
  changeDetection: ChangeDetectionStrategy.OnPush,
6879
6979
  host: { class: "hx-data-table" },
6880
- template: "<div class=\"hx-data-table-frame\" [attr.aria-busy]=\"loading() ? 'true' : null\">\n <div\n class=\"hx-table-scroll hx-data-table-scroll\"\n [class.hx-data-table-scrolls]=\"scrolls()\"\n [style.max-height]=\"scrollHeight() ?? null\"\n [attr.role]=\"scrolls() ? 'region' : null\"\n [attr.aria-label]=\"scrolls() ? (ariaLabel() ?? caption() ?? null) : null\"\n [attr.tabindex]=\"scrolls() ? 0 : null\"\n >\n <table\n class=\"hx-table\"\n [class.hx-table-sm]=\"size() === 'small'\"\n [class.hx-table-lg]=\"size() === 'large'\"\n [class.hx-table-striped]=\"stripedRows()\"\n [class.hx-table-gridlines]=\"showGridlines()\"\n [class.hx-table-hoverable]=\"hoverRows()\"\n [class.hx-table-sticky]=\"!!scrollHeight()\"\n >\n @if (hasCaption()) {\n <caption [class.hx-data-table-caption-hidden]=\"captionHidden()\">\n @if (captionTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" />\n } @else {\n {{ caption() ?? ariaLabel() }}\n }\n </caption>\n }\n <thead>\n <tr>\n @if (expanderColumn()) {\n <th scope=\"col\" class=\"hx-data-table-expander-cell\"><span class=\"hx-data-table-caption-hidden\">Row details</span></th>\n }\n @if (checkboxColumn()) {\n <th scope=\"col\" class=\"hx-data-table-select-cell\">\n <input type=\"checkbox\" hx-checkbox [attr.aria-label]=\"selectAllLabel()\" [checked]=\"allSelected()\" [indeterminate]=\"someSelected()\" (change)=\"toggleSelectAll($any($event.target).checked)\" />\n </th>\n }\n @if (headerTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: columns() }\" />\n } @else {\n @for (column of columns(); track column.field) {\n <th\n scope=\"col\"\n [class]=\"'hx-data-table-align-' + (column.align ?? 'left')\"\n [class.hx-data-table-sorted]=\"orderOf(column) !== 0\"\n [style.width]=\"column.width ?? null\"\n [attr.aria-sort]=\"ariaSort(column)\"\n [attr.title]=\"column.title ?? null\"\n >\n @if (columnHeaders().get(column.field); as extra) {\n <div class=\"hx-data-table-header-content\">\n <ng-container [ngTemplateOutlet]=\"label\" [ngTemplateOutletContext]=\"{ $implicit: column }\" />\n <ng-container [ngTemplateOutlet]=\"extra\" [ngTemplateOutletContext]=\"{ $implicit: column }\" />\n </div>\n } @else {\n <ng-container [ngTemplateOutlet]=\"label\" [ngTemplateOutletContext]=\"{ $implicit: column }\" />\n }\n </th>\n }\n }\n </tr>\n @if (filterRow()) {\n <tr class=\"hx-data-table-filter-row\">\n @if (expanderColumn()) { <th></th> }\n @if (checkboxColumn()) { <th></th> }\n @for (column of columns(); track column.field) {\n <th>\n @if (column.filter) {\n <input type=\"text\" hx-input size=\"small\" fluid [attr.aria-label]=\"filterLabel().replace('{header}', column.header)\" [value]=\"filters()[column.field] ?? ''\" (input)=\"setFilter(column, $any($event.target).value)\" />\n }\n </th>\n }\n </tr>\n }\n </thead>\n <tbody>\n @for (row of visibleRows(); track trackRow(row, $index); let i = $index) {\n <tr\n [class]=\"rowClassOf(row)\"\n [class.hx-data-table-selectable]=\"selectable()\"\n [attr.aria-selected]=\"selectionMode() ? (isSelected(row) ? 'true' : 'false') : null\"\n [attr.tabindex]=\"selectable() ? 0 : null\"\n (click)=\"selectRow(row, $event)\"\n (keydown.enter)=\"onRowKey(row, $event)\"\n (keydown.space)=\"onRowKey(row, $event)\"\n >\n @if (expanderColumn()) {\n <td class=\"hx-data-table-expander-cell\">\n <button type=\"button\" class=\"hx-data-table-expander\" [class.hx-data-table-expander-open]=\"isExpanded(row, i)\" [attr.aria-expanded]=\"isExpanded(row, i)\" [attr.aria-label]=\"isExpanded(row, i) ? collapseLabel() : expandLabel()\" (click)=\"toggleExpansion(row, i)\"></button>\n </td>\n }\n @if (checkboxColumn()) {\n <td class=\"hx-data-table-select-cell\">\n <input type=\"checkbox\" hx-checkbox [attr.aria-label]=\"selectRowLabel().replace('{row}', '' + (first() + i + 1))\" [checked]=\"isSelected(row)\" (change)=\"toggleRowCheckbox(row, $any($event.target).checked)\" />\n </td>\n }\n @if (bodyTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: row, index: i, columns: columns() }\" />\n } @else {\n @for (column of columns(); track column.field) {\n <td [class]=\"'hx-data-table-align-' + (column.align ?? 'left')\">\n @if (cells().get(column.field); as cell) {\n <ng-container [ngTemplateOutlet]=\"cell\" [ngTemplateOutletContext]=\"{ $implicit: row, value: valueOf(row, column), index: i }\" />\n } @else {\n {{ valueOf(row, column) ?? emptyValue() }}\n }\n </td>\n }\n }\n </tr>\n @if (expansionTemplate(); as tpl) {\n @if (isExpanded(row, i)) {\n <tr class=\"hx-data-table-expansion\">\n <td [attr.colspan]=\"colspan()\">\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: row, index: i, columns: columns() }\" />\n </td>\n </tr>\n }\n }\n } @empty {\n <tr class=\"hx-data-table-empty\">\n <td [attr.colspan]=\"colspan()\">\n @if (emptyTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" />\n } @else {\n {{ emptyMessage() }}\n }\n </td>\n </tr>\n }\n </tbody>\n @if (footerTemplate(); as tpl) {\n <tfoot>\n <tr>\n @if (expanderColumn()) { <td></td> }\n @if (checkboxColumn()) { <td></td> }\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: columns() }\" />\n </tr>\n </tfoot>\n }\n </table>\n </div>\n <span class=\"hx-data-table-caption-hidden\" aria-live=\"polite\">{{ announcement() }}</span>\n @if (loading()) {\n <div class=\"hx-data-table-loading\" role=\"status\">\n <hx-progress-spinner ariaLabel=\"Loading\" />\n </div>\n }\n @if (paginator()) {\n <hx-paginator\n class=\"hx-data-table-paginator\"\n [rows]=\"rows()\"\n [first]=\"first()\"\n [totalRecords]=\"total()\"\n [rowsPerPageOptions]=\"rowsPerPageOptions()\"\n [showAll]=\"showAll()\"\n (showAllChange)=\"showAll.set($event)\"\n [allLabel]=\"allLabel()\"\n [showCurrentPageReport]=\"showCurrentPageReport()\"\n (pageChange)=\"onPage($event)\"\n />\n }\n</div>\n\n<ng-template #label let-column>\n @if (column.sortable) {\n <button type=\"button\" class=\"hx-data-table-sort\" (click)=\"sort(column)\">\n <span>{{ column.header }}</span>\n <span class=\"hx-data-table-sort-icon\" [class.hx-data-table-sort-asc]=\"orderOf(column) === 1\" [class.hx-data-table-sort-desc]=\"orderOf(column) === -1\" aria-hidden=\"true\"></span>\n @if (sortRank(column); as rank) {\n <span class=\"hx-data-table-sort-rank\" aria-hidden=\"true\">{{ rank }}</span>\n }\n </button>\n } @else {\n {{ column.header }}\n }\n</ng-template>\n"
6980
+ template: "<div class=\"hx-data-table-frame\" [attr.aria-busy]=\"loading() ? 'true' : null\">\n <div\n class=\"hx-table-scroll hx-data-table-scroll\"\n [class.hx-data-table-scrolls]=\"scrolls()\"\n [style.max-height]=\"scrollHeight() ?? null\"\n [attr.role]=\"scrolls() ? 'region' : null\"\n [attr.aria-label]=\"scrolls() ? (ariaLabel() ?? caption() ?? null) : null\"\n [attr.tabindex]=\"scrolls() ? 0 : null\"\n >\n <table\n class=\"hx-table\"\n [class.hx-table-sm]=\"size() === 'small'\"\n [class.hx-table-lg]=\"size() === 'large'\"\n [class.hx-table-striped]=\"stripedRows()\"\n [class.hx-table-gridlines]=\"showGridlines()\"\n [class.hx-table-hoverable]=\"hoverRows()\"\n [class.hx-table-sticky]=\"!!scrollHeight()\"\n >\n @if (hasCaption()) {\n <caption [class.hx-data-table-caption-hidden]=\"captionHidden()\">\n @if (captionTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" />\n } @else {\n {{ caption() ?? ariaLabel() }}\n }\n </caption>\n }\n <thead>\n <tr>\n @if (expanderColumn()) {\n <th scope=\"col\" class=\"hx-data-table-expander-cell\"><span class=\"hx-data-table-caption-hidden\">Row details</span></th>\n }\n @if (checkboxColumn()) {\n <th scope=\"col\" class=\"hx-data-table-select-cell\">\n <input type=\"checkbox\" hx-checkbox [attr.aria-label]=\"selectAllLabel()\" [checked]=\"allSelected()\" [indeterminate]=\"someSelected()\" (change)=\"toggleSelectAll($any($event.target).checked)\" />\n </th>\n }\n @if (headerTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: columns() }\" />\n } @else {\n @for (column of columns(); track column.field) {\n <th\n scope=\"col\"\n [class]=\"'hx-data-table-align-' + (column.align ?? 'left')\"\n [class.hx-data-table-sorted]=\"orderOf(column) !== 0\"\n [style.width]=\"column.width ?? null\"\n [attr.aria-sort]=\"ariaSort(column)\"\n [attr.title]=\"column.title ?? null\"\n >\n @let extra = columnHeaders().get(column.field);\n @let menu = filterDisplay() === 'menu' && column.filter;\n @if (extra || menu) {\n <div class=\"hx-data-table-header-content\">\n <ng-container [ngTemplateOutlet]=\"label\" [ngTemplateOutletContext]=\"{ $implicit: column }\" />\n @if (extra) {\n <ng-container [ngTemplateOutlet]=\"extra\" [ngTemplateOutletContext]=\"{ $implicit: column }\" />\n }\n @if (menu) {\n <button\n type=\"button\"\n class=\"hx-data-table-filter-button\"\n [class.hx-data-table-filter-active]=\"!!filters()[column.field]\"\n aria-haspopup=\"dialog\"\n [attr.aria-expanded]=\"activeFilterColumn()?.field === column.field\"\n [attr.aria-label]=\"filterLabelFor(column)\"\n (click)=\"openFilter($event, column)\"\n >\n <span class=\"hx-data-table-filter-icon\" aria-hidden=\"true\"></span>\n </button>\n }\n </div>\n } @else {\n <ng-container [ngTemplateOutlet]=\"label\" [ngTemplateOutletContext]=\"{ $implicit: column }\" />\n }\n </th>\n }\n }\n </tr>\n @if (filterRow()) {\n <tr class=\"hx-data-table-filter-row\">\n @if (expanderColumn()) { <th></th> }\n @if (checkboxColumn()) { <th></th> }\n @for (column of columns(); track column.field) {\n <th>\n @if (column.filter) {\n <input type=\"text\" hx-input size=\"small\" fluid [attr.aria-label]=\"filterLabelFor(column)\" [value]=\"filters()[column.field] ?? ''\" (input)=\"setFilter(column, $any($event.target).value)\" />\n }\n </th>\n }\n </tr>\n }\n </thead>\n <tbody>\n @for (row of visibleRows(); track trackRow(row, $index); let i = $index) {\n <tr\n [class]=\"rowClassOf(row)\"\n [class.hx-data-table-selectable]=\"selectable()\"\n [attr.aria-selected]=\"selectionMode() ? (isSelected(row) ? 'true' : 'false') : null\"\n [attr.tabindex]=\"selectable() ? 0 : null\"\n (click)=\"selectRow(row, $event)\"\n (keydown.enter)=\"onRowKey(row, $event)\"\n (keydown.space)=\"onRowKey(row, $event)\"\n >\n @if (expanderColumn()) {\n <td class=\"hx-data-table-expander-cell\">\n <button type=\"button\" class=\"hx-data-table-expander\" [class.hx-data-table-expander-open]=\"isExpanded(row, i)\" [attr.aria-expanded]=\"isExpanded(row, i)\" [attr.aria-label]=\"isExpanded(row, i) ? collapseLabel() : expandLabel()\" (click)=\"toggleExpansion(row, i)\"></button>\n </td>\n }\n @if (checkboxColumn()) {\n <td class=\"hx-data-table-select-cell\">\n <input type=\"checkbox\" hx-checkbox [attr.aria-label]=\"selectRowLabel().replace('{row}', '' + (first() + i + 1))\" [checked]=\"isSelected(row)\" (change)=\"toggleRowCheckbox(row, $any($event.target).checked)\" />\n </td>\n }\n @if (bodyTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: row, index: i, columns: columns() }\" />\n } @else {\n @for (column of columns(); track column.field) {\n <td [class]=\"'hx-data-table-align-' + (column.align ?? 'left')\">\n @if (cells().get(column.field); as cell) {\n <ng-container [ngTemplateOutlet]=\"cell\" [ngTemplateOutletContext]=\"{ $implicit: row, value: valueOf(row, column), index: i }\" />\n } @else {\n {{ valueOf(row, column) ?? emptyValue() }}\n }\n </td>\n }\n }\n </tr>\n @if (expansionTemplate(); as tpl) {\n @if (isExpanded(row, i)) {\n <tr class=\"hx-data-table-expansion\">\n <td [attr.colspan]=\"colspan()\">\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: row, index: i, columns: columns() }\" />\n </td>\n </tr>\n }\n }\n } @empty {\n <tr class=\"hx-data-table-empty\">\n <td [attr.colspan]=\"colspan()\">\n @if (emptyTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.template\" />\n } @else {\n {{ emptyMessage() }}\n }\n </td>\n </tr>\n }\n </tbody>\n @if (footerTemplate(); as tpl) {\n <tfoot>\n <tr>\n @if (expanderColumn()) { <td></td> }\n @if (checkboxColumn()) { <td></td> }\n <ng-container [ngTemplateOutlet]=\"tpl.template\" [ngTemplateOutletContext]=\"{ $implicit: columns() }\" />\n </tr>\n </tfoot>\n }\n </table>\n </div>\n <span class=\"hx-data-table-caption-hidden\" aria-live=\"polite\">{{ announcement() }}</span>\n @if (loading()) {\n <div class=\"hx-data-table-loading\" role=\"status\">\n <hx-progress-spinner ariaLabel=\"Loading\" />\n </div>\n }\n @if (paginator()) {\n <hx-paginator\n class=\"hx-data-table-paginator\"\n [rows]=\"rows()\"\n [first]=\"first()\"\n [totalRecords]=\"total()\"\n [rowsPerPageOptions]=\"rowsPerPageOptions()\"\n [showAll]=\"showAll()\"\n (showAllChange)=\"showAll.set($event)\"\n [allLabel]=\"allLabel()\"\n [showCurrentPageReport]=\"showCurrentPageReport()\"\n (pageChange)=\"onPage($event)\"\n />\n }\n</div>\n\n@if (filterDisplay() === 'menu') {\n @let active = activeFilterColumn();\n <hx-popover panelClass=\"hx-data-table-filter-popover\" [ariaLabel]=\"active ? filterLabelFor(active) : undefined\" (hidden)=\"activeFilterColumn.set(null)\">\n @if (active) {\n <div class=\"hx-data-table-filter-menu\">\n <input #filterInput type=\"text\" hx-input size=\"small\" fluid [attr.aria-label]=\"filterLabelFor(active)\" [value]=\"filters()[active.field] ?? ''\" (input)=\"setFilter(active, $any($event.target).value)\" (keydown.enter)=\"filterPopover()?.hide()\" />\n <button hx-button type=\"button\" size=\"small\" variant=\"text\" class=\"hx-data-table-filter-clear\" (click)=\"clearFilter(active)\">{{ clearLabel() }}</button>\n </div>\n }\n </hx-popover>\n}\n\n<ng-template #label let-column>\n @if (column.sortable) {\n <button type=\"button\" class=\"hx-data-table-sort\" (click)=\"sort(column)\">\n <span>{{ column.header }}</span>\n <span class=\"hx-data-table-sort-icon\" [class.hx-data-table-sort-asc]=\"orderOf(column) === 1\" [class.hx-data-table-sort-desc]=\"orderOf(column) === -1\" aria-hidden=\"true\"></span>\n @if (sortRank(column); as rank) {\n <span class=\"hx-data-table-sort-rank\" aria-hidden=\"true\">{{ rank }}</span>\n }\n </button>\n } @else {\n {{ column.header }}\n }\n</ng-template>\n"
6881
6981
  }]
6882
6982
  }],
6883
6983
  propDecorators: {
@@ -7218,6 +7318,22 @@ i0.ɵɵngDeclareClassMetadata({
7218
7318
  required: false
7219
7319
  }]
7220
7320
  }],
7321
+ clearLabel: [{
7322
+ type: i0.Input,
7323
+ args: [{
7324
+ isSignal: true,
7325
+ alias: "clearLabel",
7326
+ required: false
7327
+ }]
7328
+ }],
7329
+ filterPopover: [{
7330
+ type: i0.ViewChild,
7331
+ args: [i0.forwardRef(() => HxPopover), { isSignal: true }]
7332
+ }],
7333
+ filterInput: [{
7334
+ type: i0.ViewChild,
7335
+ args: ["filterInput", { isSignal: true }]
7336
+ }],
7221
7337
  expandedRowKeys: [{
7222
7338
  type: i0.Input,
7223
7339
  args: [{
@@ -7319,6 +7435,90 @@ function monthCells(year, month, firstDayOfWeek) {
7319
7435
  for (let i = 0; i < cells.length; i += 7) rows.push(cells.slice(i, i + 7));
7320
7436
  return rows;
7321
7437
  }
7438
+ function hxResolvePreset(preset, context, fit) {
7439
+ const from = fit(preset.from(context), "from");
7440
+ const to = fit(preset.to(context), "to");
7441
+ if (from === void 0 || to === void 0) return void 0;
7442
+ return from && to && to < from ? {
7443
+ from: to,
7444
+ to: from
7445
+ } : {
7446
+ from,
7447
+ to
7448
+ };
7449
+ }
7450
+ const ENGLISH = {
7451
+ last15Minutes: "Last 15 minutes",
7452
+ last1Hour: "Last 1 hour",
7453
+ last6Hours: "Last 6 hours",
7454
+ last24Hours: "Last 24 hours",
7455
+ last7Days: "Last 7 days",
7456
+ last30Days: "Last 30 days",
7457
+ today: "Today",
7458
+ yesterday: "Yesterday",
7459
+ thisWeek: "This week",
7460
+ thisMonth: "This month"
7461
+ };
7462
+ const minutesAgo = (minutes) => () => /* @__PURE__ */ new Date(Date.now() - minutes * 6e4);
7463
+ const now = () => /* @__PURE__ */ new Date();
7464
+ const endOfDay = (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999);
7465
+ const startOfWeek = (date, firstDayOfWeek = 0) => addDays(startOfDay(date), -((date.getDay() - firstDayOfWeek + 7) % 7));
7466
+ const RANGES = {
7467
+ last15Minutes: {
7468
+ from: minutesAgo(15),
7469
+ to: now
7470
+ },
7471
+ last1Hour: {
7472
+ from: minutesAgo(60),
7473
+ to: now
7474
+ },
7475
+ last6Hours: {
7476
+ from: minutesAgo(360),
7477
+ to: now
7478
+ },
7479
+ last24Hours: {
7480
+ from: minutesAgo(1440),
7481
+ to: now
7482
+ },
7483
+ last7Days: {
7484
+ from: () => addDays(startOfDay(/* @__PURE__ */ new Date()), -6),
7485
+ to: now
7486
+ },
7487
+ last30Days: {
7488
+ from: () => addDays(startOfDay(/* @__PURE__ */ new Date()), -29),
7489
+ to: now
7490
+ },
7491
+ today: {
7492
+ from: () => startOfDay(/* @__PURE__ */ new Date()),
7493
+ to: now
7494
+ },
7495
+ yesterday: {
7496
+ from: () => addDays(startOfDay(/* @__PURE__ */ new Date()), -1),
7497
+ to: () => endOfDay(addDays(/* @__PURE__ */ new Date(), -1))
7498
+ },
7499
+ thisWeek: {
7500
+ from: (c) => startOfWeek(/* @__PURE__ */ new Date(), c?.firstDayOfWeek),
7501
+ to: (c) => endOfDay(addDays(startOfWeek(/* @__PURE__ */ new Date(), c?.firstDayOfWeek), 6))
7502
+ },
7503
+ thisMonth: {
7504
+ from: () => new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), 1),
7505
+ to: () => endOfDay(new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth() + 1, 0))
7506
+ }
7507
+ };
7508
+ const DAY_IDS = [
7509
+ "today",
7510
+ "last7Days",
7511
+ "thisMonth"
7512
+ ];
7513
+ const build = (ids, labels) => ids.map((id) => ({
7514
+ label: labels[id] ?? ENGLISH[id],
7515
+ ...RANGES[id]
7516
+ }));
7517
+ function hxDateRangePresets(labels = {}) {
7518
+ return build(Object.keys(RANGES), labels);
7519
+ }
7520
+ const HX_DATE_RANGE_PRESETS = hxDateRangePresets();
7521
+ const HX_DATE_RANGE_DAY_PRESETS = build(DAY_IDS, {});
7322
7522
  function dateKey(date) {
7323
7523
  return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
7324
7524
  }
@@ -7724,326 +7924,2076 @@ function parseDateTimeText(text, options) {
7724
7924
  const day = options.timeOnly && rest === "" ? startOfDay(options.fallbackDay) : parseDateText(rest, options.locale);
7725
7925
  return day && withTime(day, hours, minutes, seconds);
7726
7926
  }
7727
- const startOfDayOrNull$1 = (date) => isValidDate(date) ? startOfDay(date) : null;
7728
- var HxDatePicker = class HxDatePicker {
7729
- #host = inject(ElementRef);
7730
- #injector = inject(Injector);
7731
- placeholder = input("", ...ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []);
7732
- showIcon = input(false, {
7733
- ...ngDevMode ? { debugName: "showIcon" } : /* istanbul ignore next */ {},
7734
- transform: booleanAttribute
7735
- });
7736
- showButtonBar = input(false, {
7737
- ...ngDevMode ? { debugName: "showButtonBar" } : /* istanbul ignore next */ {},
7738
- transform: booleanAttribute
7739
- });
7740
- dateFormat = input(...ngDevMode ? [void 0, { debugName: "dateFormat" }] : /* istanbul ignore next */ []);
7741
- todayLabel = input("Today", ...ngDevMode ? [{ debugName: "todayLabel" }] : /* istanbul ignore next */ []);
7742
- clearLabel = input("Clear", ...ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []);
7743
- chooseLabel = input("Choose date", ...ngDevMode ? [{ debugName: "chooseLabel" }] : /* istanbul ignore next */ []);
7744
- inputId = input(...ngDevMode ? [void 0, { debugName: "inputId" }] : /* istanbul ignore next */ []);
7745
- inline = input(false, {
7746
- ...ngDevMode ? { debugName: "inline" } : /* istanbul ignore next */ {},
7747
- transform: booleanAttribute
7748
- });
7749
- selectionMode = input("single", ...ngDevMode ? [{ debugName: "selectionMode" }] : /* istanbul ignore next */ []);
7750
- minDate = input(null, ...ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []);
7751
- maxDate = input(null, ...ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []);
7752
- disabledDates = input([], ...ngDevMode ? [{ debugName: "disabledDates" }] : /* istanbul ignore next */ []);
7753
- firstDayOfWeek = input(0, {
7754
- ...ngDevMode ? { debugName: "firstDayOfWeek" } : /* istanbul ignore next */ {},
7755
- transform: numberAttribute
7756
- });
7757
- locale = input(...ngDevMode ? [void 0, { debugName: "locale" }] : /* istanbul ignore next */ []);
7758
- ariaLabel = input(...ngDevMode ? [void 0, { debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
7759
- ariaLabelledby = input(...ngDevMode ? [void 0, { debugName: "ariaLabelledby" }] : /* istanbul ignore next */ []);
7760
- value = model(null, ...ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []);
7927
+ var HxRangePresets = class HxRangePresets {
7928
+ presets = input.required(...ngDevMode ? [{ debugName: "presets" }] : /* istanbul ignore next */ []);
7929
+ display = input("buttons", ...ngDevMode ? [{ debugName: "display" }] : /* istanbul ignore next */ []);
7930
+ label = input("Presets", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
7761
7931
  disabled = input(false, {
7762
7932
  ...ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {},
7763
7933
  transform: booleanAttribute
7764
7934
  });
7765
- invalid = input(false, {
7766
- ...ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {},
7767
- transform: booleanAttribute
7768
- });
7769
- touch = output();
7770
- open = signal(false, ...ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []);
7771
- titleId = nextId("hx-date-picker-title");
7772
- popupId = nextId("hx-date-picker-popup");
7773
- positions = [{
7774
- originX: "start",
7775
- originY: "bottom",
7776
- overlayX: "start",
7777
- overlayY: "top",
7778
- offsetY: 2
7779
- }, {
7780
- originX: "start",
7781
- originY: "top",
7782
- overlayX: "start",
7783
- overlayY: "bottom",
7784
- offsetY: -2
7785
- }];
7786
- field = viewChild("field", ...ngDevMode ? [{ debugName: "field" }] : /* istanbul ignore next */ []);
7787
- calendar = viewChild(HxCalendar, ...ngDevMode ? [{ debugName: "calendar" }] : /* istanbul ignore next */ []);
7788
- #typed = signal(null, ...ngDevMode ? [{ debugName: "#typed" }] : /* istanbul ignore next */ []);
7789
- view = signal("day", ...ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []);
7790
- #cvaDisabled = signal(false, ...ngDevMode ? [{ debugName: "#cvaDisabled" }] : /* istanbul ignore next */ []);
7791
- isDisabled = computed(() => this.disabled() || this.#cvaDisabled(), ...ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []);
7792
- focusedDate = signal(startOfDay(/* @__PURE__ */ new Date()), ...ngDevMode ? [{ debugName: "focusedDate" }] : /* istanbul ignore next */ []);
7793
- today = startOfDay(/* @__PURE__ */ new Date());
7794
- selectedDates = computed(() => {
7795
- const value = this.value();
7796
- if (Array.isArray(value)) return value.filter(isValidDate);
7797
- return isValidDate(value) ? [value] : [];
7798
- }, ...ngDevMode ? [{ debugName: "selectedDates" }] : /* istanbul ignore next */ []);
7799
- #format = computed(() => new Intl.DateTimeFormat(this.locale(), this.dateFormat() ?? {
7800
- day: "2-digit",
7801
- month: "2-digit",
7802
- year: "numeric"
7803
- }), ...ngDevMode ? [{ debugName: "#format" }] : /* istanbul ignore next */ []);
7804
- text = computed(() => {
7805
- const typed = this.#typed();
7806
- if (typed !== null) return typed;
7807
- const dates = this.selectedDates();
7808
- const fmt = this.#format();
7809
- if (this.selectionMode() === "range") return dates.map((d) => fmt.format(d)).join(" – ");
7810
- return dates.map((d) => fmt.format(d)).join(", ");
7811
- }, ...ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []);
7812
- constructor() {
7813
- effect(() => {
7814
- const first = this.selectedDates()[0] ?? clampTime(this.today, startOfDayOrNull$1(this.minDate()), this.maxDate());
7815
- const shown = untracked(() => this.focusedDate());
7816
- if (first && (first.getFullYear() !== shown.getFullYear() || first.getMonth() !== shown.getMonth())) this.focusedDate.set(startOfDay(first));
7817
- });
7818
- }
7819
- #onChange = () => {};
7820
- #onTouched = () => {};
7821
- writeValue(value) {
7822
- this.#typed.set(null);
7823
- this.value.set(value ?? null);
7824
- }
7825
- registerOnChange(fn) {
7826
- this.#onChange = fn;
7827
- }
7828
- registerOnTouched(fn) {
7829
- this.#onTouched = fn;
7830
- }
7831
- setDisabledState(disabled) {
7832
- this.#cvaDisabled.set(disabled);
7833
- }
7834
- focus() {
7835
- const field = this.field();
7836
- if (field) field.nativeElement.focus();
7837
- else this.#focusDay();
7838
- }
7839
- isDateDisabled(date) {
7840
- return isDateDisabled(date, {
7841
- min: this.minDate(),
7842
- max: this.maxDate(),
7843
- disabledDates: this.disabledDates()
7844
- });
7845
- }
7846
- isSelected(date) {
7847
- return this.selectedDates().some((d) => isSameDay(d, date));
7848
- }
7849
- pick(date) {
7850
- if (this.isDisabled() || this.isDateDisabled(date)) return;
7851
- const day = startOfDay(date);
7852
- this.focusedDate.set(day);
7853
- const selected = this.selectedDates();
7854
- let next;
7855
- const mode = this.selectionMode();
7856
- switch (mode) {
7857
- case "multiple":
7858
- next = this.isSelected(day) ? selected.filter((d) => !isSameDay(d, day)) : [...selected, day];
7859
- break;
7860
- case "range":
7861
- if (selected.length !== 1) next = [day];
7862
- else next = compareDays(day, selected[0]) < 0 ? [day, selected[0]] : [selected[0], day];
7863
- break;
7864
- default: next = day;
7865
- }
7866
- this.#typed.set(null);
7867
- this.#commit(next);
7868
- if (!this.inline()) {
7869
- if (mode === "single" || mode === "range" && Array.isArray(next) && next.length === 2) this.close(true);
7870
- }
7871
- }
7872
- #commit(next) {
7873
- this.value.set(next);
7874
- this.#onChange(next);
7875
- }
7876
- #focusDay() {
7877
- afterNextRender(() => {
7878
- this.calendar()?.focusDay();
7879
- }, { injector: this.#injector });
7880
- }
7881
- show() {
7882
- if (this.isDisabled() || this.inline() || this.open()) return;
7883
- this.open.set(true);
7884
- }
7885
- toggle() {
7886
- if (this.open()) this.close(true);
7887
- else this.show();
7888
- }
7889
- close(refocus = false) {
7890
- if (!this.open()) return;
7891
- this.open.set(false);
7892
- if (refocus) this.field()?.nativeElement.focus();
7893
- }
7894
- onAttach() {
7895
- const first = this.selectedDates()[0];
7896
- this.view.set("day");
7897
- this.focusedDate.set(startOfDay(first ?? clampTime(this.today, startOfDayOrNull$1(this.minDate()), this.maxDate())));
7898
- this.#focusDay();
7899
- }
7900
- onOverlayKeydown(event) {
7901
- if (event.key === "Escape") {
7902
- event.preventDefault();
7903
- this.close(true);
7935
+ selected = input(null, ...ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []);
7936
+ describedBy = input(null, ...ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []);
7937
+ chosen = output();
7938
+ select = viewChild(HxSelect, ...ngDevMode ? [{ debugName: "select" }] : /* istanbul ignore next */ []);
7939
+ presetValue = (preset) => preset;
7940
+ #restoring = false;
7941
+ chooseInSelect(preset) {
7942
+ if (!preset || this.#restoring) return;
7943
+ this.chosen.emit(preset);
7944
+ this.#restoring = true;
7945
+ try {
7946
+ this.select()?.value.set(this.selected());
7947
+ } finally {
7948
+ this.#restoring = false;
7904
7949
  }
7905
7950
  }
7906
- onOutsideClick(event) {
7907
- if (!this.#host.nativeElement.contains(event.target)) this.close();
7908
- }
7909
- onFieldKeydown(event) {
7910
- if (event.key === "ArrowDown" || event.altKey && event.key === "ArrowUp") {
7911
- event.preventDefault();
7912
- this.show();
7913
- } else if (event.key === "Enter") this.commitTyping();
7914
- }
7915
- onTyping(event) {
7916
- this.#typed.set(event.target.value);
7917
- }
7918
- commitTyping() {
7919
- const typed = this.#typed();
7920
- if (typed === null) return;
7921
- this.#typed.set(null);
7922
- this.#parseAndCommit(typed);
7923
- const field = this.field();
7924
- if (field) field.nativeElement.value = this.text();
7925
- }
7926
- #parseAndCommit(typed) {
7927
- const text = typed.trim();
7928
- if (text === "") {
7929
- this.#commit(this.selectionMode() === "single" ? null : []);
7930
- return;
7931
- }
7932
- const dates = (this.selectionMode() === "single" ? [text] : text.split(/\s*(?:,|–)\s*/)).map((part) => this.#parse(part));
7933
- if (dates.some((d) => d === null || this.isDateDisabled(d))) return;
7934
- const valid = dates;
7935
- if (this.selectionMode() === "range" && valid.length > 2) return;
7936
- this.#commit(this.selectionMode() === "single" ? valid[0] : valid);
7937
- if (valid[0]) this.focusedDate.set(startOfDay(valid[0]));
7938
- }
7939
- #parse(text) {
7940
- return parseDateText(text, this.locale());
7941
- }
7942
- selectToday() {
7943
- this.pick(this.today);
7944
- }
7945
- clear() {
7946
- this.#typed.set(null);
7947
- this.#commit(this.selectionMode() === "single" ? null : []);
7948
- this.close(true);
7949
- }
7950
- onHostFocusOut(event) {
7951
- if (this.inline()) return;
7952
- const next = event.relatedTarget;
7953
- if (next?.closest(".hx-date-picker-popup") || this.#host.nativeElement.contains(next)) return;
7954
- if (this.open()) return;
7955
- this.close();
7956
- this.commitTyping();
7957
- this.#onTouched();
7958
- this.touch.emit();
7959
- }
7960
- onFocusOut(event) {
7961
- if (!this.inline()) return;
7962
- if (this.#host.nativeElement.contains(event.relatedTarget)) return;
7963
- this.#onTouched();
7964
- this.touch.emit();
7965
- }
7966
7951
  static ɵfac = i0.ɵɵngDeclareFactory({
7967
7952
  minVersion: "12.0.0",
7968
7953
  version: "22.2.1",
7969
7954
  ngImport: i0,
7970
- type: HxDatePicker,
7955
+ type: HxRangePresets,
7971
7956
  deps: [],
7972
7957
  target: i0.ɵɵFactoryTarget.Component
7973
7958
  });
7974
7959
  static ɵcmp = i0.ɵɵngDeclareComponent({
7975
7960
  minVersion: "17.0.0",
7976
7961
  version: "22.2.1",
7977
- type: HxDatePicker,
7962
+ type: HxRangePresets,
7978
7963
  isStandalone: true,
7979
- selector: "hx-date-picker",
7964
+ selector: "hx-range-presets",
7980
7965
  inputs: {
7981
- placeholder: {
7982
- classPropertyName: "placeholder",
7983
- publicName: "placeholder",
7966
+ presets: {
7967
+ classPropertyName: "presets",
7968
+ publicName: "presets",
7984
7969
  isSignal: true,
7985
- isRequired: false,
7970
+ isRequired: true,
7986
7971
  transformFunction: null
7987
7972
  },
7988
- showIcon: {
7989
- classPropertyName: "showIcon",
7990
- publicName: "showIcon",
7973
+ display: {
7974
+ classPropertyName: "display",
7975
+ publicName: "display",
7991
7976
  isSignal: true,
7992
7977
  isRequired: false,
7993
7978
  transformFunction: null
7994
7979
  },
7995
- showButtonBar: {
7996
- classPropertyName: "showButtonBar",
7997
- publicName: "showButtonBar",
7980
+ label: {
7981
+ classPropertyName: "label",
7982
+ publicName: "label",
7998
7983
  isSignal: true,
7999
7984
  isRequired: false,
8000
7985
  transformFunction: null
8001
7986
  },
8002
- dateFormat: {
8003
- classPropertyName: "dateFormat",
8004
- publicName: "dateFormat",
7987
+ disabled: {
7988
+ classPropertyName: "disabled",
7989
+ publicName: "disabled",
8005
7990
  isSignal: true,
8006
7991
  isRequired: false,
8007
7992
  transformFunction: null
8008
7993
  },
8009
- todayLabel: {
8010
- classPropertyName: "todayLabel",
8011
- publicName: "todayLabel",
7994
+ selected: {
7995
+ classPropertyName: "selected",
7996
+ publicName: "selected",
8012
7997
  isSignal: true,
8013
7998
  isRequired: false,
8014
7999
  transformFunction: null
8015
8000
  },
8016
- clearLabel: {
8017
- classPropertyName: "clearLabel",
8018
- publicName: "clearLabel",
8001
+ describedBy: {
8002
+ classPropertyName: "describedBy",
8003
+ publicName: "describedBy",
8019
8004
  isSignal: true,
8020
8005
  isRequired: false,
8021
8006
  transformFunction: null
8007
+ }
8008
+ },
8009
+ outputs: { chosen: "chosen" },
8010
+ host: {
8011
+ properties: {
8012
+ "class.hx-range-presets-select": "display() === 'select'",
8013
+ "attr.role": "display() === 'select' ? null : 'group'",
8014
+ "attr.aria-label": "display() === 'select' ? null : label()"
8022
8015
  },
8023
- chooseLabel: {
8024
- classPropertyName: "chooseLabel",
8025
- publicName: "chooseLabel",
8016
+ classAttribute: "hx-range-presets"
8017
+ },
8018
+ viewQueries: [{
8019
+ propertyName: "select",
8020
+ first: true,
8021
+ predicate: HxSelect,
8022
+ descendants: true,
8023
+ isSignal: true
8024
+ }],
8025
+ ngImport: i0,
8026
+ template: `
8027
+ @if (display() === 'select') {
8028
+ <hx-select
8029
+ class="hx-range-preset-select"
8030
+ fluid
8031
+ [options]="presets()"
8032
+ optionLabel="label"
8033
+ [optionValue]="presetValue"
8034
+ [placeholder]="label()"
8035
+ [ariaLabel]="label()"
8036
+ [ariaDescribedby]="describedBy()"
8037
+ [disabled]="disabled()"
8038
+ [value]="selected()"
8039
+ (valueChange)="chooseInSelect($event)"
8040
+ />
8041
+ } @else {
8042
+ @for (preset of presets(); track $index) {
8043
+ <button
8044
+ type="button"
8045
+ class="hx-date-picker-button hx-range-preset"
8046
+ [disabled]="disabled()"
8047
+ [attr.aria-describedby]="describedBy()"
8048
+ (click)="chosen.emit(preset)"
8049
+ >
8050
+ {{ preset.label }}
8051
+ </button>
8052
+ }
8053
+ }
8054
+ `,
8055
+ isInline: true,
8056
+ dependencies: [{
8057
+ kind: "component",
8058
+ type: HxSelect,
8059
+ selector: "hx-select",
8060
+ inputs: [
8061
+ "options",
8062
+ "optionLabel",
8063
+ "optionValue",
8064
+ "optionDisabled",
8065
+ "placeholder",
8066
+ "emptyMessage",
8067
+ "filter",
8068
+ "filterPlaceholder",
8069
+ "filterBy",
8070
+ "emptyFilterMessage",
8071
+ "size",
8072
+ "variant",
8073
+ "fluid",
8074
+ "showClear",
8075
+ "inputId",
8076
+ "ariaLabel",
8077
+ "ariaLabelledby",
8078
+ "ariaDescribedby",
8079
+ "compareWith",
8080
+ "value",
8081
+ "disabled",
8082
+ "invalid"
8083
+ ],
8084
+ outputs: ["valueChange", "touch"]
8085
+ }],
8086
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
8087
+ });
8088
+ };
8089
+ i0.ɵɵngDeclareClassMetadata({
8090
+ minVersion: "12.0.0",
8091
+ version: "22.2.1",
8092
+ ngImport: i0,
8093
+ type: HxRangePresets,
8094
+ decorators: [{
8095
+ type: Component,
8096
+ args: [{
8097
+ selector: "hx-range-presets",
8098
+ imports: [HxSelect],
8099
+ template: `
8100
+ @if (display() === 'select') {
8101
+ <hx-select
8102
+ class="hx-range-preset-select"
8103
+ fluid
8104
+ [options]="presets()"
8105
+ optionLabel="label"
8106
+ [optionValue]="presetValue"
8107
+ [placeholder]="label()"
8108
+ [ariaLabel]="label()"
8109
+ [ariaDescribedby]="describedBy()"
8110
+ [disabled]="disabled()"
8111
+ [value]="selected()"
8112
+ (valueChange)="chooseInSelect($event)"
8113
+ />
8114
+ } @else {
8115
+ @for (preset of presets(); track $index) {
8116
+ <button
8117
+ type="button"
8118
+ class="hx-date-picker-button hx-range-preset"
8119
+ [disabled]="disabled()"
8120
+ [attr.aria-describedby]="describedBy()"
8121
+ (click)="chosen.emit(preset)"
8122
+ >
8123
+ {{ preset.label }}
8124
+ </button>
8125
+ }
8126
+ }
8127
+ `,
8128
+ changeDetection: ChangeDetectionStrategy.OnPush,
8129
+ host: {
8130
+ class: "hx-range-presets",
8131
+ "[class.hx-range-presets-select]": "display() === 'select'",
8132
+ "[attr.role]": "display() === 'select' ? null : 'group'",
8133
+ "[attr.aria-label]": "display() === 'select' ? null : label()"
8134
+ }
8135
+ }]
8136
+ }],
8137
+ propDecorators: {
8138
+ presets: [{
8139
+ type: i0.Input,
8140
+ args: [{
8026
8141
  isSignal: true,
8027
- isRequired: false,
8028
- transformFunction: null
8029
- },
8030
- inputId: {
8031
- classPropertyName: "inputId",
8032
- publicName: "inputId",
8142
+ alias: "presets",
8143
+ required: true
8144
+ }]
8145
+ }],
8146
+ display: [{
8147
+ type: i0.Input,
8148
+ args: [{
8149
+ isSignal: true,
8150
+ alias: "display",
8151
+ required: false
8152
+ }]
8153
+ }],
8154
+ label: [{
8155
+ type: i0.Input,
8156
+ args: [{
8157
+ isSignal: true,
8158
+ alias: "label",
8159
+ required: false
8160
+ }]
8161
+ }],
8162
+ disabled: [{
8163
+ type: i0.Input,
8164
+ args: [{
8165
+ isSignal: true,
8166
+ alias: "disabled",
8167
+ required: false
8168
+ }]
8169
+ }],
8170
+ selected: [{
8171
+ type: i0.Input,
8172
+ args: [{
8173
+ isSignal: true,
8174
+ alias: "selected",
8175
+ required: false
8176
+ }]
8177
+ }],
8178
+ describedBy: [{
8179
+ type: i0.Input,
8180
+ args: [{
8181
+ isSignal: true,
8182
+ alias: "describedBy",
8183
+ required: false
8184
+ }]
8185
+ }],
8186
+ chosen: [{
8187
+ type: i0.Output,
8188
+ args: ["chosen"]
8189
+ }],
8190
+ select: [{
8191
+ type: i0.ViewChild,
8192
+ args: [i0.forwardRef(() => HxSelect), { isSignal: true }]
8193
+ }]
8194
+ }
8195
+ });
8196
+ const startOfDayOrNull$1 = (date) => isValidDate(date) ? startOfDay(date) : null;
8197
+ var HxDatePicker = class HxDatePicker {
8198
+ #host = inject(ElementRef);
8199
+ #injector = inject(Injector);
8200
+ placeholder = input("", ...ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []);
8201
+ showIcon = input(false, {
8202
+ ...ngDevMode ? { debugName: "showIcon" } : /* istanbul ignore next */ {},
8203
+ transform: booleanAttribute
8204
+ });
8205
+ showButtonBar = input(false, {
8206
+ ...ngDevMode ? { debugName: "showButtonBar" } : /* istanbul ignore next */ {},
8207
+ transform: booleanAttribute
8208
+ });
8209
+ dateFormat = input(...ngDevMode ? [void 0, { debugName: "dateFormat" }] : /* istanbul ignore next */ []);
8210
+ todayLabel = input("Today", ...ngDevMode ? [{ debugName: "todayLabel" }] : /* istanbul ignore next */ []);
8211
+ clearLabel = input("Clear", ...ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []);
8212
+ chooseLabel = input("Choose date", ...ngDevMode ? [{ debugName: "chooseLabel" }] : /* istanbul ignore next */ []);
8213
+ inputId = input(...ngDevMode ? [void 0, { debugName: "inputId" }] : /* istanbul ignore next */ []);
8214
+ inline = input(false, {
8215
+ ...ngDevMode ? { debugName: "inline" } : /* istanbul ignore next */ {},
8216
+ transform: booleanAttribute
8217
+ });
8218
+ selectionMode = input("single", ...ngDevMode ? [{ debugName: "selectionMode" }] : /* istanbul ignore next */ []);
8219
+ minDate = input(null, ...ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []);
8220
+ maxDate = input(null, ...ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []);
8221
+ disabledDates = input([], ...ngDevMode ? [{ debugName: "disabledDates" }] : /* istanbul ignore next */ []);
8222
+ firstDayOfWeek = input(0, {
8223
+ ...ngDevMode ? { debugName: "firstDayOfWeek" } : /* istanbul ignore next */ {},
8224
+ transform: numberAttribute
8225
+ });
8226
+ locale = input(...ngDevMode ? [void 0, { debugName: "locale" }] : /* istanbul ignore next */ []);
8227
+ ariaLabel = input(...ngDevMode ? [void 0, { debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
8228
+ ariaLabelledby = input(...ngDevMode ? [void 0, { debugName: "ariaLabelledby" }] : /* istanbul ignore next */ []);
8229
+ presets = input([], ...ngDevMode ? [{ debugName: "presets" }] : /* istanbul ignore next */ []);
8230
+ presetDisplay = input("buttons", ...ngDevMode ? [{ debugName: "presetDisplay" }] : /* istanbul ignore next */ []);
8231
+ presetsLabel = input("Presets", ...ngDevMode ? [{ debugName: "presetsLabel" }] : /* istanbul ignore next */ []);
8232
+ presetRefusedLabel = input("This range cannot be chosen.", ...ngDevMode ? [{ debugName: "presetRefusedLabel" }] : /* istanbul ignore next */ []);
8233
+ value = model(null, ...ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []);
8234
+ disabled = input(false, {
8235
+ ...ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {},
8236
+ transform: booleanAttribute
8237
+ });
8238
+ invalid = input(false, {
8239
+ ...ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {},
8240
+ transform: booleanAttribute
8241
+ });
8242
+ touch = output();
8243
+ open = signal(false, ...ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []);
8244
+ titleId = nextId("hx-date-picker-title");
8245
+ popupId = nextId("hx-date-picker-popup");
8246
+ positions = [{
8247
+ originX: "start",
8248
+ originY: "bottom",
8249
+ overlayX: "start",
8250
+ overlayY: "top",
8251
+ offsetY: 2
8252
+ }, {
8253
+ originX: "start",
8254
+ originY: "top",
8255
+ overlayX: "start",
8256
+ overlayY: "bottom",
8257
+ offsetY: -2
8258
+ }];
8259
+ field = viewChild("field", ...ngDevMode ? [{ debugName: "field" }] : /* istanbul ignore next */ []);
8260
+ calendar = viewChild(HxCalendar, ...ngDevMode ? [{ debugName: "calendar" }] : /* istanbul ignore next */ []);
8261
+ shownPresets = computed(() => this.selectionMode() === "range" ? this.presets() : [], ...ngDevMode ? [{ debugName: "shownPresets" }] : /* istanbul ignore next */ []);
8262
+ #chosen = signal(null, ...ngDevMode ? [{ debugName: "#chosen" }] : /* istanbul ignore next */ []);
8263
+ selectedPreset = computed(() => {
8264
+ const chosen = this.#chosen();
8265
+ if (!chosen) return null;
8266
+ const days = this.selectedDates();
8267
+ if (!(days.length === 2 && isSameDay(days[0], chosen.from) && isSameDay(days[1], chosen.to))) return null;
8268
+ const list = this.shownPresets();
8269
+ return list.find((p) => p === chosen.preset) ?? list.find((p) => p.label === chosen.preset.label) ?? null;
8270
+ }, ...ngDevMode ? [{ debugName: "selectedPreset" }] : /* istanbul ignore next */ []);
8271
+ presetError = signal(false, ...ngDevMode ? [{ debugName: "presetError" }] : /* istanbul ignore next */ []);
8272
+ presetErrorId = nextId("hx-date-picker-preset-error");
8273
+ #typed = signal(null, ...ngDevMode ? [{ debugName: "#typed" }] : /* istanbul ignore next */ []);
8274
+ view = signal("day", ...ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []);
8275
+ #cvaDisabled = signal(false, ...ngDevMode ? [{ debugName: "#cvaDisabled" }] : /* istanbul ignore next */ []);
8276
+ isDisabled = computed(() => this.disabled() || this.#cvaDisabled(), ...ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []);
8277
+ focusedDate = signal(startOfDay(/* @__PURE__ */ new Date()), ...ngDevMode ? [{ debugName: "focusedDate" }] : /* istanbul ignore next */ []);
8278
+ today = startOfDay(/* @__PURE__ */ new Date());
8279
+ selectedDates = computed(() => {
8280
+ const value = this.value();
8281
+ if (Array.isArray(value)) return value.filter(isValidDate);
8282
+ return isValidDate(value) ? [value] : [];
8283
+ }, ...ngDevMode ? [{ debugName: "selectedDates" }] : /* istanbul ignore next */ []);
8284
+ #format = computed(() => new Intl.DateTimeFormat(this.locale(), this.dateFormat() ?? {
8285
+ day: "2-digit",
8286
+ month: "2-digit",
8287
+ year: "numeric"
8288
+ }), ...ngDevMode ? [{ debugName: "#format" }] : /* istanbul ignore next */ []);
8289
+ text = computed(() => {
8290
+ const typed = this.#typed();
8291
+ if (typed !== null) return typed;
8292
+ const dates = this.selectedDates();
8293
+ const fmt = this.#format();
8294
+ if (this.selectionMode() === "range") return dates.map((d) => fmt.format(d)).join(" – ");
8295
+ return dates.map((d) => fmt.format(d)).join(", ");
8296
+ }, ...ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []);
8297
+ constructor() {
8298
+ effect(() => {
8299
+ const first = this.selectedDates()[0] ?? clampTime(this.today, startOfDayOrNull$1(this.minDate()), this.maxDate());
8300
+ const shown = untracked(() => this.focusedDate());
8301
+ if (first && (first.getFullYear() !== shown.getFullYear() || first.getMonth() !== shown.getMonth())) this.focusedDate.set(startOfDay(first));
8302
+ });
8303
+ }
8304
+ #onChange = () => {};
8305
+ #onTouched = () => {};
8306
+ writeValue(value) {
8307
+ this.#typed.set(null);
8308
+ this.presetError.set(false);
8309
+ this.value.set(value ?? null);
8310
+ }
8311
+ registerOnChange(fn) {
8312
+ this.#onChange = fn;
8313
+ }
8314
+ registerOnTouched(fn) {
8315
+ this.#onTouched = fn;
8316
+ }
8317
+ setDisabledState(disabled) {
8318
+ this.#cvaDisabled.set(disabled);
8319
+ }
8320
+ focus() {
8321
+ const field = this.field();
8322
+ if (field) field.nativeElement.focus();
8323
+ else this.#focusDay();
8324
+ }
8325
+ isDateDisabled(date) {
8326
+ return isDateDisabled(date, {
8327
+ min: this.minDate(),
8328
+ max: this.maxDate(),
8329
+ disabledDates: this.disabledDates()
8330
+ });
8331
+ }
8332
+ isSelected(date) {
8333
+ return this.selectedDates().some((d) => isSameDay(d, date));
8334
+ }
8335
+ pick(date) {
8336
+ if (this.isDisabled() || this.isDateDisabled(date)) return;
8337
+ const day = startOfDay(date);
8338
+ this.focusedDate.set(day);
8339
+ const selected = this.selectedDates();
8340
+ let next;
8341
+ const mode = this.selectionMode();
8342
+ switch (mode) {
8343
+ case "multiple":
8344
+ next = this.isSelected(day) ? selected.filter((d) => !isSameDay(d, day)) : [...selected, day];
8345
+ break;
8346
+ case "range":
8347
+ if (selected.length !== 1) next = [day];
8348
+ else next = compareDays(day, selected[0]) < 0 ? [day, selected[0]] : [selected[0], day];
8349
+ break;
8350
+ default: next = day;
8351
+ }
8352
+ this.#typed.set(null);
8353
+ this.#commit(next);
8354
+ if (!this.inline()) {
8355
+ if (mode === "single" || mode === "range" && Array.isArray(next) && next.length === 2) this.close(true);
8356
+ }
8357
+ }
8358
+ applyPreset(preset) {
8359
+ if (this.isDisabled()) return;
8360
+ const range = hxResolvePreset(preset, { firstDayOfWeek: this.firstDayOfWeek() }, (date) => this.#presetDay(date));
8361
+ const [min, max] = [this.minDate(), this.maxDate()];
8362
+ const outside = !range?.from || !range.to || isValidDate(min) && compareDays(range.to, min) < 0 || isValidDate(max) && compareDays(range.from, max) > 0;
8363
+ const from = range?.from && this.#inLimits(range.from);
8364
+ const to = range?.to && this.#inLimits(range.to);
8365
+ if (outside || !from || !to || this.isDateDisabled(from) || this.isDateDisabled(to)) {
8366
+ this.presetError.set(true);
8367
+ return;
8368
+ }
8369
+ const next = [from, to];
8370
+ this.#typed.set(null);
8371
+ this.focusedDate.set(from);
8372
+ this.#commit(next);
8373
+ this.#chosen.set({
8374
+ preset,
8375
+ from,
8376
+ to
8377
+ });
8378
+ if (this.inline() || !this.open()) return;
8379
+ this.close();
8380
+ afterNextRender(() => this.field()?.nativeElement.focus(), { injector: this.#injector });
8381
+ }
8382
+ #presetDay(date) {
8383
+ if (!isValidDate(date)) return null;
8384
+ const day = startOfDay(date);
8385
+ return this.disabledDates().some((d) => isSameDay(d, day)) ? void 0 : day;
8386
+ }
8387
+ #inLimits(day) {
8388
+ const max = this.maxDate();
8389
+ return clampTime(day, startOfDayOrNull$1(this.minDate()), isValidDate(max) ? startOfDay(max) : null);
8390
+ }
8391
+ #commit(next) {
8392
+ this.presetError.set(false);
8393
+ this.value.set(next);
8394
+ this.#onChange(next);
8395
+ }
8396
+ #focusDay() {
8397
+ afterNextRender(() => {
8398
+ this.calendar()?.focusDay();
8399
+ }, { injector: this.#injector });
8400
+ }
8401
+ show() {
8402
+ if (this.isDisabled() || this.inline() || this.open()) return;
8403
+ this.presetError.set(false);
8404
+ this.open.set(true);
8405
+ }
8406
+ toggle() {
8407
+ if (this.open()) this.close(true);
8408
+ else this.show();
8409
+ }
8410
+ close(refocus = false) {
8411
+ if (!this.open()) return;
8412
+ this.open.set(false);
8413
+ if (refocus) this.field()?.nativeElement.focus();
8414
+ }
8415
+ onAttach() {
8416
+ const first = this.selectedDates()[0];
8417
+ this.view.set("day");
8418
+ this.focusedDate.set(startOfDay(first ?? clampTime(this.today, startOfDayOrNull$1(this.minDate()), this.maxDate())));
8419
+ this.#focusDay();
8420
+ }
8421
+ onOverlayKeydown(event) {
8422
+ if (event.key === "Escape") {
8423
+ event.preventDefault();
8424
+ this.close(true);
8425
+ }
8426
+ }
8427
+ onOutsideClick(event) {
8428
+ if (isInSelectOverlay(event.target)) return;
8429
+ if (!this.#host.nativeElement.contains(event.target)) this.close();
8430
+ }
8431
+ onFieldKeydown(event) {
8432
+ if (event.key === "ArrowDown" || event.altKey && event.key === "ArrowUp") {
8433
+ event.preventDefault();
8434
+ this.show();
8435
+ } else if (event.key === "Enter") this.commitTyping();
8436
+ }
8437
+ onTyping(event) {
8438
+ this.#typed.set(event.target.value);
8439
+ }
8440
+ commitTyping() {
8441
+ const typed = this.#typed();
8442
+ if (typed === null) return;
8443
+ this.#typed.set(null);
8444
+ this.#parseAndCommit(typed);
8445
+ const field = this.field();
8446
+ if (field) field.nativeElement.value = this.text();
8447
+ }
8448
+ #parseAndCommit(typed) {
8449
+ const text = typed.trim();
8450
+ if (text === "") {
8451
+ this.#commit(this.selectionMode() === "single" ? null : []);
8452
+ return;
8453
+ }
8454
+ const dates = (this.selectionMode() === "single" ? [text] : text.split(/\s*(?:,|–)\s*/)).map((part) => this.#parse(part));
8455
+ if (dates.some((d) => d === null || this.isDateDisabled(d))) return;
8456
+ const valid = dates;
8457
+ if (this.selectionMode() === "range" && valid.length > 2) return;
8458
+ this.#commit(this.selectionMode() === "single" ? valid[0] : valid);
8459
+ if (valid[0]) this.focusedDate.set(startOfDay(valid[0]));
8460
+ }
8461
+ #parse(text) {
8462
+ return parseDateText(text, this.locale());
8463
+ }
8464
+ selectToday() {
8465
+ this.pick(this.today);
8466
+ }
8467
+ clear() {
8468
+ this.#typed.set(null);
8469
+ this.#commit(this.selectionMode() === "single" ? null : []);
8470
+ this.close(true);
8471
+ }
8472
+ onHostFocusOut(event) {
8473
+ if (this.inline()) return;
8474
+ const next = event.relatedTarget;
8475
+ if (next?.closest(".hx-date-picker-popup") || this.#host.nativeElement.contains(next)) return;
8476
+ if (this.open()) return;
8477
+ this.close();
8478
+ this.commitTyping();
8479
+ this.#onTouched();
8480
+ this.touch.emit();
8481
+ }
8482
+ onFocusOut(event) {
8483
+ if (!this.inline()) return;
8484
+ const host = this.#host.nativeElement;
8485
+ const next = event.relatedTarget;
8486
+ if (host.contains(next) || isInSelectOverlay(next)) return;
8487
+ this.#onTouched();
8488
+ this.touch.emit();
8489
+ }
8490
+ static ɵfac = i0.ɵɵngDeclareFactory({
8491
+ minVersion: "12.0.0",
8492
+ version: "22.2.1",
8493
+ ngImport: i0,
8494
+ type: HxDatePicker,
8495
+ deps: [],
8496
+ target: i0.ɵɵFactoryTarget.Component
8497
+ });
8498
+ static ɵcmp = i0.ɵɵngDeclareComponent({
8499
+ minVersion: "17.0.0",
8500
+ version: "22.2.1",
8501
+ type: HxDatePicker,
8502
+ isStandalone: true,
8503
+ selector: "hx-date-picker",
8504
+ inputs: {
8505
+ placeholder: {
8506
+ classPropertyName: "placeholder",
8507
+ publicName: "placeholder",
8508
+ isSignal: true,
8509
+ isRequired: false,
8510
+ transformFunction: null
8511
+ },
8512
+ showIcon: {
8513
+ classPropertyName: "showIcon",
8514
+ publicName: "showIcon",
8515
+ isSignal: true,
8516
+ isRequired: false,
8517
+ transformFunction: null
8518
+ },
8519
+ showButtonBar: {
8520
+ classPropertyName: "showButtonBar",
8521
+ publicName: "showButtonBar",
8522
+ isSignal: true,
8523
+ isRequired: false,
8524
+ transformFunction: null
8525
+ },
8526
+ dateFormat: {
8527
+ classPropertyName: "dateFormat",
8528
+ publicName: "dateFormat",
8529
+ isSignal: true,
8530
+ isRequired: false,
8531
+ transformFunction: null
8532
+ },
8533
+ todayLabel: {
8534
+ classPropertyName: "todayLabel",
8535
+ publicName: "todayLabel",
8536
+ isSignal: true,
8537
+ isRequired: false,
8538
+ transformFunction: null
8539
+ },
8540
+ clearLabel: {
8541
+ classPropertyName: "clearLabel",
8542
+ publicName: "clearLabel",
8543
+ isSignal: true,
8544
+ isRequired: false,
8545
+ transformFunction: null
8546
+ },
8547
+ chooseLabel: {
8548
+ classPropertyName: "chooseLabel",
8549
+ publicName: "chooseLabel",
8550
+ isSignal: true,
8551
+ isRequired: false,
8552
+ transformFunction: null
8553
+ },
8554
+ inputId: {
8555
+ classPropertyName: "inputId",
8556
+ publicName: "inputId",
8557
+ isSignal: true,
8558
+ isRequired: false,
8559
+ transformFunction: null
8560
+ },
8561
+ inline: {
8562
+ classPropertyName: "inline",
8563
+ publicName: "inline",
8564
+ isSignal: true,
8565
+ isRequired: false,
8566
+ transformFunction: null
8567
+ },
8568
+ selectionMode: {
8569
+ classPropertyName: "selectionMode",
8570
+ publicName: "selectionMode",
8571
+ isSignal: true,
8572
+ isRequired: false,
8573
+ transformFunction: null
8574
+ },
8575
+ minDate: {
8576
+ classPropertyName: "minDate",
8577
+ publicName: "minDate",
8578
+ isSignal: true,
8579
+ isRequired: false,
8580
+ transformFunction: null
8581
+ },
8582
+ maxDate: {
8583
+ classPropertyName: "maxDate",
8584
+ publicName: "maxDate",
8585
+ isSignal: true,
8586
+ isRequired: false,
8587
+ transformFunction: null
8588
+ },
8589
+ disabledDates: {
8590
+ classPropertyName: "disabledDates",
8591
+ publicName: "disabledDates",
8592
+ isSignal: true,
8593
+ isRequired: false,
8594
+ transformFunction: null
8595
+ },
8596
+ firstDayOfWeek: {
8597
+ classPropertyName: "firstDayOfWeek",
8598
+ publicName: "firstDayOfWeek",
8599
+ isSignal: true,
8600
+ isRequired: false,
8601
+ transformFunction: null
8602
+ },
8603
+ locale: {
8604
+ classPropertyName: "locale",
8605
+ publicName: "locale",
8606
+ isSignal: true,
8607
+ isRequired: false,
8608
+ transformFunction: null
8609
+ },
8610
+ ariaLabel: {
8611
+ classPropertyName: "ariaLabel",
8612
+ publicName: "ariaLabel",
8613
+ isSignal: true,
8614
+ isRequired: false,
8615
+ transformFunction: null
8616
+ },
8617
+ ariaLabelledby: {
8618
+ classPropertyName: "ariaLabelledby",
8619
+ publicName: "ariaLabelledby",
8620
+ isSignal: true,
8621
+ isRequired: false,
8622
+ transformFunction: null
8623
+ },
8624
+ presets: {
8625
+ classPropertyName: "presets",
8626
+ publicName: "presets",
8627
+ isSignal: true,
8628
+ isRequired: false,
8629
+ transformFunction: null
8630
+ },
8631
+ presetDisplay: {
8632
+ classPropertyName: "presetDisplay",
8633
+ publicName: "presetDisplay",
8634
+ isSignal: true,
8635
+ isRequired: false,
8636
+ transformFunction: null
8637
+ },
8638
+ presetsLabel: {
8639
+ classPropertyName: "presetsLabel",
8640
+ publicName: "presetsLabel",
8641
+ isSignal: true,
8642
+ isRequired: false,
8643
+ transformFunction: null
8644
+ },
8645
+ presetRefusedLabel: {
8646
+ classPropertyName: "presetRefusedLabel",
8647
+ publicName: "presetRefusedLabel",
8648
+ isSignal: true,
8649
+ isRequired: false,
8650
+ transformFunction: null
8651
+ },
8652
+ value: {
8653
+ classPropertyName: "value",
8654
+ publicName: "value",
8655
+ isSignal: true,
8656
+ isRequired: false,
8657
+ transformFunction: null
8658
+ },
8659
+ disabled: {
8660
+ classPropertyName: "disabled",
8661
+ publicName: "disabled",
8662
+ isSignal: true,
8663
+ isRequired: false,
8664
+ transformFunction: null
8665
+ },
8666
+ invalid: {
8667
+ classPropertyName: "invalid",
8668
+ publicName: "invalid",
8669
+ isSignal: true,
8670
+ isRequired: false,
8671
+ transformFunction: null
8672
+ }
8673
+ },
8674
+ outputs: {
8675
+ value: "valueChange",
8676
+ touch: "touch"
8677
+ },
8678
+ host: {
8679
+ listeners: { "focusout": "onHostFocusOut($event)" },
8680
+ properties: {
8681
+ "class.hx-date-picker-inline": "inline()",
8682
+ "class.hx-date-picker-disabled": "isDisabled()",
8683
+ "class.hx-date-picker-invalid": "invalid()",
8684
+ "class.hx-date-picker-open": "open()",
8685
+ "class.hx-date-picker-has-icon": "showIcon() && !inline()",
8686
+ "class.hx-filled": "!inline() && text() !== \"\""
8687
+ },
8688
+ classAttribute: "hx-date-picker"
8689
+ },
8690
+ providers: [{
8691
+ provide: NG_VALUE_ACCESSOR,
8692
+ useExisting: forwardRef(() => HxDatePicker),
8693
+ multi: true
8694
+ }],
8695
+ viewQueries: [{
8696
+ propertyName: "field",
8697
+ first: true,
8698
+ predicate: ["field"],
8699
+ descendants: true,
8700
+ isSignal: true
8701
+ }, {
8702
+ propertyName: "calendar",
8703
+ first: true,
8704
+ predicate: HxCalendar,
8705
+ descendants: true,
8706
+ isSignal: true
8707
+ }],
8708
+ ngImport: i0,
8709
+ template: "@if (inline()) {\n <ng-container [ngTemplateOutlet]=\"calendar\" />\n} @else {\n <div class=\"hx-date-picker-field\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n <input\n #field\n type=\"text\"\n class=\"hx-date-picker-input\"\n autocomplete=\"off\"\n aria-haspopup=\"dialog\"\n [attr.id]=\"inputId() ?? null\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"text()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? popupId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (input)=\"onTyping($event)\"\n (change)=\"commitTyping()\"\n (click)=\"show()\"\n (keydown)=\"onFieldKeydown($event)\"\n />\n @if (showIcon()) {\n <button\n type=\"button\"\n class=\"hx-date-picker-trigger\"\n aria-haspopup=\"dialog\"\n [attr.aria-label]=\"chooseLabel()\"\n [attr.aria-expanded]=\"open()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n >\n <span class=\"hx-date-picker-trigger-icon\" aria-hidden=\"true\"></span>\n </button>\n }\n </div>\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayPanelClass=\"hx-date-picker-overlay\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"open.set(false)\"\n >\n <div\n class=\"hx-date-picker-popup\"\n role=\"dialog\"\n aria-modal=\"false\"\n [id]=\"popupId\"\n [attr.aria-label]=\"ariaLabel() ?? 'Choose date'\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n >\n <ng-container [ngTemplateOutlet]=\"calendar\" />\n @if (showButtonBar()) {\n <div class=\"hx-date-picker-buttonbar\">\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"selectToday()\">{{ todayLabel() }}</button>\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"clear()\">{{ clearLabel() }}</button>\n </div>\n }\n </div>\n </ng-template>\n}\n\n<ng-template #calendar>\n<div\n class=\"hx-date-picker-panel\"\n role=\"group\"\n [attr.aria-label]=\"ariaLabel() ?? 'Calendar'\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (focusout)=\"onFocusOut($event)\"\n>\n @if (shownPresets().length > 0) {\n <hx-range-presets\n [presets]=\"shownPresets()\"\n [display]=\"presetDisplay()\"\n [label]=\"presetsLabel()\"\n [disabled]=\"isDisabled()\"\n [selected]=\"selectedPreset()\"\n [describedBy]=\"presetError() ? presetErrorId : null\"\n (chosen)=\"applyPreset($event)\"\n />\n @if (presetError()) {\n <p class=\"hx-date-picker-error\" role=\"alert\" [id]=\"presetErrorId\">{{ presetRefusedLabel() }}</p>\n }\n }\n <hx-calendar\n [(focusedDate)]=\"focusedDate\"\n [(view)]=\"view\"\n [selectedDates]=\"selectedDates()\"\n [selectionMode]=\"selectionMode()\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [disabledDates]=\"disabledDates()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n [titleId]=\"titleId\"\n [today]=\"today\"\n (picked)=\"pick($event)\"\n />\n</div>\n</ng-template>\n",
8710
+ dependencies: [
8711
+ {
8712
+ kind: "directive",
8713
+ type: CdkConnectedOverlay,
8714
+ selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]",
8715
+ inputs: [
8716
+ "cdkConnectedOverlayOrigin",
8717
+ "cdkConnectedOverlayPositions",
8718
+ "cdkConnectedOverlayPositionStrategy",
8719
+ "cdkConnectedOverlayOffsetX",
8720
+ "cdkConnectedOverlayOffsetY",
8721
+ "cdkConnectedOverlayWidth",
8722
+ "cdkConnectedOverlayHeight",
8723
+ "cdkConnectedOverlayMinWidth",
8724
+ "cdkConnectedOverlayMinHeight",
8725
+ "cdkConnectedOverlayBackdropClass",
8726
+ "cdkConnectedOverlayPanelClass",
8727
+ "cdkConnectedOverlayViewportMargin",
8728
+ "cdkConnectedOverlayScrollStrategy",
8729
+ "cdkConnectedOverlayOpen",
8730
+ "cdkConnectedOverlayDisableClose",
8731
+ "cdkConnectedOverlayTransformOriginOn",
8732
+ "cdkConnectedOverlayHasBackdrop",
8733
+ "cdkConnectedOverlayLockPosition",
8734
+ "cdkConnectedOverlayFlexibleDimensions",
8735
+ "cdkConnectedOverlayGrowAfterOpen",
8736
+ "cdkConnectedOverlayPush",
8737
+ "cdkConnectedOverlayDisposeOnNavigation",
8738
+ "cdkConnectedOverlayUsePopover",
8739
+ "cdkConnectedOverlayMatchWidth",
8740
+ "cdkConnectedOverlay"
8741
+ ],
8742
+ outputs: [
8743
+ "backdropClick",
8744
+ "positionChange",
8745
+ "attach",
8746
+ "detach",
8747
+ "overlayKeydown",
8748
+ "overlayOutsideClick"
8749
+ ],
8750
+ exportAs: ["cdkConnectedOverlay"]
8751
+ },
8752
+ {
8753
+ kind: "directive",
8754
+ type: CdkOverlayOrigin,
8755
+ selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]",
8756
+ exportAs: ["cdkOverlayOrigin"]
8757
+ },
8758
+ {
8759
+ kind: "directive",
8760
+ type: NgTemplateOutlet,
8761
+ selector: "[ngTemplateOutlet]",
8762
+ inputs: [
8763
+ "ngTemplateOutletContext",
8764
+ "ngTemplateOutlet",
8765
+ "ngTemplateOutletInjector"
8766
+ ]
8767
+ },
8768
+ {
8769
+ kind: "component",
8770
+ type: HxCalendar,
8771
+ selector: "hx-calendar",
8772
+ inputs: [
8773
+ "focusedDate",
8774
+ "view",
8775
+ "selectedDates",
8776
+ "selectionMode",
8777
+ "minDate",
8778
+ "maxDate",
8779
+ "disabledDates",
8780
+ "firstDayOfWeek",
8781
+ "locale",
8782
+ "disabled",
8783
+ "titleId",
8784
+ "today"
8785
+ ],
8786
+ outputs: [
8787
+ "focusedDateChange",
8788
+ "viewChange",
8789
+ "picked"
8790
+ ]
8791
+ },
8792
+ {
8793
+ kind: "component",
8794
+ type: HxRangePresets,
8795
+ selector: "hx-range-presets",
8796
+ inputs: [
8797
+ "presets",
8798
+ "display",
8799
+ "label",
8800
+ "disabled",
8801
+ "selected",
8802
+ "describedBy"
8803
+ ],
8804
+ outputs: ["chosen"]
8805
+ }
8806
+ ],
8807
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
8808
+ });
8809
+ };
8810
+ i0.ɵɵngDeclareClassMetadata({
8811
+ minVersion: "12.0.0",
8812
+ version: "22.2.1",
8813
+ ngImport: i0,
8814
+ type: HxDatePicker,
8815
+ decorators: [{
8816
+ type: Component,
8817
+ args: [{
8818
+ selector: "hx-date-picker",
8819
+ imports: [
8820
+ CdkConnectedOverlay,
8821
+ CdkOverlayOrigin,
8822
+ NgTemplateOutlet,
8823
+ HxCalendar,
8824
+ HxRangePresets
8825
+ ],
8826
+ changeDetection: ChangeDetectionStrategy.OnPush,
8827
+ providers: [{
8828
+ provide: NG_VALUE_ACCESSOR,
8829
+ useExisting: forwardRef(() => HxDatePicker),
8830
+ multi: true
8831
+ }],
8832
+ host: {
8833
+ class: "hx-date-picker",
8834
+ "[class.hx-date-picker-inline]": "inline()",
8835
+ "[class.hx-date-picker-disabled]": "isDisabled()",
8836
+ "[class.hx-date-picker-invalid]": "invalid()",
8837
+ "[class.hx-date-picker-open]": "open()",
8838
+ "[class.hx-date-picker-has-icon]": "showIcon() && !inline()",
8839
+ "[class.hx-filled]": "!inline() && text() !== \"\"",
8840
+ "(focusout)": "onHostFocusOut($event)"
8841
+ },
8842
+ template: "@if (inline()) {\n <ng-container [ngTemplateOutlet]=\"calendar\" />\n} @else {\n <div class=\"hx-date-picker-field\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n <input\n #field\n type=\"text\"\n class=\"hx-date-picker-input\"\n autocomplete=\"off\"\n aria-haspopup=\"dialog\"\n [attr.id]=\"inputId() ?? null\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"text()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? popupId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (input)=\"onTyping($event)\"\n (change)=\"commitTyping()\"\n (click)=\"show()\"\n (keydown)=\"onFieldKeydown($event)\"\n />\n @if (showIcon()) {\n <button\n type=\"button\"\n class=\"hx-date-picker-trigger\"\n aria-haspopup=\"dialog\"\n [attr.aria-label]=\"chooseLabel()\"\n [attr.aria-expanded]=\"open()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n >\n <span class=\"hx-date-picker-trigger-icon\" aria-hidden=\"true\"></span>\n </button>\n }\n </div>\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayPanelClass=\"hx-date-picker-overlay\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"open.set(false)\"\n >\n <div\n class=\"hx-date-picker-popup\"\n role=\"dialog\"\n aria-modal=\"false\"\n [id]=\"popupId\"\n [attr.aria-label]=\"ariaLabel() ?? 'Choose date'\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n >\n <ng-container [ngTemplateOutlet]=\"calendar\" />\n @if (showButtonBar()) {\n <div class=\"hx-date-picker-buttonbar\">\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"selectToday()\">{{ todayLabel() }}</button>\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"clear()\">{{ clearLabel() }}</button>\n </div>\n }\n </div>\n </ng-template>\n}\n\n<ng-template #calendar>\n<div\n class=\"hx-date-picker-panel\"\n role=\"group\"\n [attr.aria-label]=\"ariaLabel() ?? 'Calendar'\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (focusout)=\"onFocusOut($event)\"\n>\n @if (shownPresets().length > 0) {\n <hx-range-presets\n [presets]=\"shownPresets()\"\n [display]=\"presetDisplay()\"\n [label]=\"presetsLabel()\"\n [disabled]=\"isDisabled()\"\n [selected]=\"selectedPreset()\"\n [describedBy]=\"presetError() ? presetErrorId : null\"\n (chosen)=\"applyPreset($event)\"\n />\n @if (presetError()) {\n <p class=\"hx-date-picker-error\" role=\"alert\" [id]=\"presetErrorId\">{{ presetRefusedLabel() }}</p>\n }\n }\n <hx-calendar\n [(focusedDate)]=\"focusedDate\"\n [(view)]=\"view\"\n [selectedDates]=\"selectedDates()\"\n [selectionMode]=\"selectionMode()\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [disabledDates]=\"disabledDates()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n [titleId]=\"titleId\"\n [today]=\"today\"\n (picked)=\"pick($event)\"\n />\n</div>\n</ng-template>\n"
8843
+ }]
8844
+ }],
8845
+ ctorParameters: () => [],
8846
+ propDecorators: {
8847
+ placeholder: [{
8848
+ type: i0.Input,
8849
+ args: [{
8850
+ isSignal: true,
8851
+ alias: "placeholder",
8852
+ required: false
8853
+ }]
8854
+ }],
8855
+ showIcon: [{
8856
+ type: i0.Input,
8857
+ args: [{
8858
+ isSignal: true,
8859
+ alias: "showIcon",
8860
+ required: false
8861
+ }]
8862
+ }],
8863
+ showButtonBar: [{
8864
+ type: i0.Input,
8865
+ args: [{
8866
+ isSignal: true,
8867
+ alias: "showButtonBar",
8868
+ required: false
8869
+ }]
8870
+ }],
8871
+ dateFormat: [{
8872
+ type: i0.Input,
8873
+ args: [{
8874
+ isSignal: true,
8875
+ alias: "dateFormat",
8876
+ required: false
8877
+ }]
8878
+ }],
8879
+ todayLabel: [{
8880
+ type: i0.Input,
8881
+ args: [{
8882
+ isSignal: true,
8883
+ alias: "todayLabel",
8884
+ required: false
8885
+ }]
8886
+ }],
8887
+ clearLabel: [{
8888
+ type: i0.Input,
8889
+ args: [{
8890
+ isSignal: true,
8891
+ alias: "clearLabel",
8892
+ required: false
8893
+ }]
8894
+ }],
8895
+ chooseLabel: [{
8896
+ type: i0.Input,
8897
+ args: [{
8898
+ isSignal: true,
8899
+ alias: "chooseLabel",
8900
+ required: false
8901
+ }]
8902
+ }],
8903
+ inputId: [{
8904
+ type: i0.Input,
8905
+ args: [{
8906
+ isSignal: true,
8907
+ alias: "inputId",
8908
+ required: false
8909
+ }]
8910
+ }],
8911
+ inline: [{
8912
+ type: i0.Input,
8913
+ args: [{
8914
+ isSignal: true,
8915
+ alias: "inline",
8916
+ required: false
8917
+ }]
8918
+ }],
8919
+ selectionMode: [{
8920
+ type: i0.Input,
8921
+ args: [{
8922
+ isSignal: true,
8923
+ alias: "selectionMode",
8924
+ required: false
8925
+ }]
8926
+ }],
8927
+ minDate: [{
8928
+ type: i0.Input,
8929
+ args: [{
8930
+ isSignal: true,
8931
+ alias: "minDate",
8932
+ required: false
8933
+ }]
8934
+ }],
8935
+ maxDate: [{
8936
+ type: i0.Input,
8937
+ args: [{
8938
+ isSignal: true,
8939
+ alias: "maxDate",
8940
+ required: false
8941
+ }]
8942
+ }],
8943
+ disabledDates: [{
8944
+ type: i0.Input,
8945
+ args: [{
8946
+ isSignal: true,
8947
+ alias: "disabledDates",
8948
+ required: false
8949
+ }]
8950
+ }],
8951
+ firstDayOfWeek: [{
8952
+ type: i0.Input,
8953
+ args: [{
8954
+ isSignal: true,
8955
+ alias: "firstDayOfWeek",
8956
+ required: false
8957
+ }]
8958
+ }],
8959
+ locale: [{
8960
+ type: i0.Input,
8961
+ args: [{
8962
+ isSignal: true,
8963
+ alias: "locale",
8964
+ required: false
8965
+ }]
8966
+ }],
8967
+ ariaLabel: [{
8968
+ type: i0.Input,
8969
+ args: [{
8970
+ isSignal: true,
8971
+ alias: "ariaLabel",
8972
+ required: false
8973
+ }]
8974
+ }],
8975
+ ariaLabelledby: [{
8976
+ type: i0.Input,
8977
+ args: [{
8978
+ isSignal: true,
8979
+ alias: "ariaLabelledby",
8980
+ required: false
8981
+ }]
8982
+ }],
8983
+ presets: [{
8984
+ type: i0.Input,
8985
+ args: [{
8986
+ isSignal: true,
8987
+ alias: "presets",
8988
+ required: false
8989
+ }]
8990
+ }],
8991
+ presetDisplay: [{
8992
+ type: i0.Input,
8993
+ args: [{
8994
+ isSignal: true,
8995
+ alias: "presetDisplay",
8996
+ required: false
8997
+ }]
8998
+ }],
8999
+ presetsLabel: [{
9000
+ type: i0.Input,
9001
+ args: [{
9002
+ isSignal: true,
9003
+ alias: "presetsLabel",
9004
+ required: false
9005
+ }]
9006
+ }],
9007
+ presetRefusedLabel: [{
9008
+ type: i0.Input,
9009
+ args: [{
9010
+ isSignal: true,
9011
+ alias: "presetRefusedLabel",
9012
+ required: false
9013
+ }]
9014
+ }],
9015
+ value: [{
9016
+ type: i0.Input,
9017
+ args: [{
9018
+ isSignal: true,
9019
+ alias: "value",
9020
+ required: false
9021
+ }]
9022
+ }, {
9023
+ type: i0.Output,
9024
+ args: ["valueChange"]
9025
+ }],
9026
+ disabled: [{
9027
+ type: i0.Input,
9028
+ args: [{
9029
+ isSignal: true,
9030
+ alias: "disabled",
9031
+ required: false
9032
+ }]
9033
+ }],
9034
+ invalid: [{
9035
+ type: i0.Input,
9036
+ args: [{
9037
+ isSignal: true,
9038
+ alias: "invalid",
9039
+ required: false
9040
+ }]
9041
+ }],
9042
+ touch: [{
9043
+ type: i0.Output,
9044
+ args: ["touch"]
9045
+ }],
9046
+ field: [{
9047
+ type: i0.ViewChild,
9048
+ args: ["field", { isSignal: true }]
9049
+ }],
9050
+ calendar: [{
9051
+ type: i0.ViewChild,
9052
+ args: [i0.forwardRef(() => HxCalendar), { isSignal: true }]
9053
+ }]
9054
+ }
9055
+ });
9056
+ const EXPRESSION = /^now((?:[+-]\d+[smhdwMy]|\/[smhdwMy])*)$/;
9057
+ const TOKEN = /([+-])(\d+)([smhdwMy])|\/([smhdwMy])/g;
9058
+ const MS = {
9059
+ s: 1e3,
9060
+ m: 6e4,
9061
+ h: 36e5
9062
+ };
9063
+ function add(date, amount, unit) {
9064
+ switch (unit) {
9065
+ case "s":
9066
+ case "m":
9067
+ case "h": return new Date(date.getTime() + amount * MS[unit]);
9068
+ case "d":
9069
+ case "w": {
9070
+ const result = new Date(date);
9071
+ result.setDate(result.getDate() + amount * (unit === "w" ? 7 : 1));
9072
+ return result;
9073
+ }
9074
+ case "M": return addMonthsKeepingTime(date, amount);
9075
+ case "y": return addMonthsKeepingTime(date, amount * 12);
9076
+ }
9077
+ }
9078
+ function addMonthsKeepingTime(date, months) {
9079
+ const day = addMonths(date, months);
9080
+ day.setHours(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
9081
+ return day;
9082
+ }
9083
+ function startOf(date, unit, firstDayOfWeek) {
9084
+ const [y, mo, d, h, mi, s] = [
9085
+ date.getFullYear(),
9086
+ date.getMonth(),
9087
+ date.getDate(),
9088
+ date.getHours(),
9089
+ date.getMinutes(),
9090
+ date.getSeconds()
9091
+ ];
9092
+ switch (unit) {
9093
+ case "s": return new Date(y, mo, d, h, mi, s);
9094
+ case "m": return new Date(y, mo, d, h, mi);
9095
+ case "h": return new Date(y, mo, d, h);
9096
+ case "d": return new Date(y, mo, d);
9097
+ case "w": return new Date(y, mo, d - (date.getDay() - firstDayOfWeek + 7) % 7);
9098
+ case "M": return new Date(y, mo, 1);
9099
+ case "y": return new Date(y, 0, 1);
9100
+ }
9101
+ }
9102
+ function round(date, unit, options) {
9103
+ const start = startOf(date, unit, options.firstDayOfWeek ?? 0);
9104
+ if (!options.roundUp) return start;
9105
+ return /* @__PURE__ */ new Date(add(start, 1, unit).getTime() - 1);
9106
+ }
9107
+ function hxParseDateMath(expression, options = {}) {
9108
+ const match = typeof expression === "string" ? EXPRESSION.exec(expression.trim()) : null;
9109
+ const now = options.now ?? /* @__PURE__ */ new Date();
9110
+ if (!match || Number.isNaN(now.getTime())) return null;
9111
+ let result = new Date(now);
9112
+ for (const token of match[1].matchAll(TOKEN)) {
9113
+ const [, sign, amount, shiftUnit, roundUnit] = token;
9114
+ result = roundUnit ? round(result, roundUnit, options) : add(result, (sign === "-" ? -1 : 1) * Number(amount), shiftUnit);
9115
+ if (Number.isNaN(result.getTime())) return null;
9116
+ }
9117
+ return result;
9118
+ }
9119
+ function hxRelativeRangeExpressions(direction, amount, unit) {
9120
+ if (!Number.isSafeInteger(amount) || amount < 1) return null;
9121
+ return direction === "last" ? {
9122
+ from: `now-${amount}${unit}`,
9123
+ to: "now"
9124
+ } : {
9125
+ from: "now",
9126
+ to: `now+${amount}${unit}`
9127
+ };
9128
+ }
9129
+ const QUICK_SELECT_UNITS = [
9130
+ "s",
9131
+ "m",
9132
+ "h",
9133
+ "d",
9134
+ "w",
9135
+ "M",
9136
+ "y"
9137
+ ];
9138
+ const HX_QUICK_SELECT_LABELS = {
9139
+ quickSelect: "Quick select",
9140
+ last: "Last",
9141
+ next: "Next",
9142
+ amount: "Amount",
9143
+ unit: "Unit",
9144
+ direction: "Direction",
9145
+ apply: "Apply",
9146
+ commonlyUsed: "Commonly used",
9147
+ recentlyUsed: "Recently used",
9148
+ start: "Start",
9149
+ end: "End",
9150
+ absolute: "Absolute",
9151
+ relative: "Relative",
9152
+ now: "Now",
9153
+ nowHint: "Set to the current time when the range is applied.",
9154
+ incompleteRange: "Choose a start and an end that can be applied.",
9155
+ date: "Date",
9156
+ roundTo: "Round to the {unit}",
9157
+ lastRange: "Last {n} {unit}",
9158
+ nextRange: "Next {n} {unit}",
9159
+ range: "Start and end",
9160
+ nowSummary: "now",
9161
+ agoSummary: "~ {n} {unit} ago",
9162
+ fromNowSummary: "~ {n} {unit} from now",
9163
+ roundedSummary: "rounded to the {unit}",
9164
+ emptySide: "Not set",
9165
+ resolvesTo: "Resolves to {date}",
9166
+ units: {
9167
+ s: "seconds",
9168
+ m: "minutes",
9169
+ h: "hours",
9170
+ d: "days",
9171
+ w: "weeks",
9172
+ M: "months",
9173
+ y: "years"
9174
+ },
9175
+ unitsOne: {
9176
+ s: "second",
9177
+ m: "minute",
9178
+ h: "hour",
9179
+ d: "day",
9180
+ w: "week",
9181
+ M: "month",
9182
+ y: "year"
9183
+ },
9184
+ unitsAgo: {
9185
+ s: "Seconds ago",
9186
+ m: "Minutes ago",
9187
+ h: "Hours ago",
9188
+ d: "Days ago",
9189
+ w: "Weeks ago",
9190
+ M: "Months ago",
9191
+ y: "Years ago"
9192
+ },
9193
+ unitsFromNow: {
9194
+ s: "Seconds from now",
9195
+ m: "Minutes from now",
9196
+ h: "Hours from now",
9197
+ d: "Days from now",
9198
+ w: "Weeks from now",
9199
+ M: "Months from now",
9200
+ y: "Years from now"
9201
+ }
9202
+ };
9203
+ const HX_QUICK_SELECT_COMMONLY_USED = [
9204
+ {
9205
+ label: "Today",
9206
+ from: "now/d",
9207
+ to: "now/d"
9208
+ },
9209
+ {
9210
+ label: "This week",
9211
+ from: "now/w",
9212
+ to: "now/w"
9213
+ },
9214
+ {
9215
+ label: "Last 15 minutes",
9216
+ from: "now-15m",
9217
+ to: "now"
9218
+ },
9219
+ {
9220
+ label: "Last 30 minutes",
9221
+ from: "now-30m",
9222
+ to: "now"
9223
+ },
9224
+ {
9225
+ label: "Last 1 hour",
9226
+ from: "now-1h",
9227
+ to: "now"
9228
+ },
9229
+ {
9230
+ label: "Last 24 hours",
9231
+ from: "now-24h",
9232
+ to: "now"
9233
+ },
9234
+ {
9235
+ label: "Last 7 days",
9236
+ from: "now-7d",
9237
+ to: "now"
9238
+ },
9239
+ {
9240
+ label: "Last 30 days",
9241
+ from: "now-30d",
9242
+ to: "now"
9243
+ },
9244
+ {
9245
+ label: "Last 90 days",
9246
+ from: "now-90d",
9247
+ to: "now"
9248
+ },
9249
+ {
9250
+ label: "Last 1 year",
9251
+ from: "now-1y",
9252
+ to: "now"
9253
+ }
9254
+ ];
9255
+ const DEFAULT_SIDE = {
9256
+ mode: "absolute",
9257
+ amount: 15,
9258
+ unit: "m",
9259
+ direction: "ago",
9260
+ round: false,
9261
+ raw: null
9262
+ };
9263
+ const SIDE_MODES = [
9264
+ "absolute",
9265
+ "relative",
9266
+ "now"
9267
+ ];
9268
+ const ABSOLUTE_SIDES = {
9269
+ from: DEFAULT_SIDE,
9270
+ to: DEFAULT_SIDE
9271
+ };
9272
+ const SIMPLE = /^now(?:([+-])(\d+)([smhdwMy]))?(?:\/([smhdwMy]))?$/;
9273
+ function sideFromExpression(expression) {
9274
+ const text = expression.trim();
9275
+ if (text === "now") return {
9276
+ ...DEFAULT_SIDE,
9277
+ mode: "now"
9278
+ };
9279
+ const match = SIMPLE.exec(text);
9280
+ if (match) {
9281
+ const [, sign, amount, shiftUnit, roundUnit] = match;
9282
+ if (!shiftUnit || !roundUnit || shiftUnit === roundUnit) return {
9283
+ mode: "relative",
9284
+ amount: amount ? Number(amount) : 0,
9285
+ unit: shiftUnit ?? roundUnit,
9286
+ direction: sign === "+" ? "fromNow" : "ago",
9287
+ round: !!roundUnit,
9288
+ raw: null
9289
+ };
9290
+ }
9291
+ if (hxParseDateMath(text)) return {
9292
+ ...DEFAULT_SIDE,
9293
+ mode: "relative",
9294
+ raw: text
9295
+ };
9296
+ return { ...DEFAULT_SIDE };
9297
+ }
9298
+ function sideExpression(side) {
9299
+ if (side.mode === "now") return "now";
9300
+ if (side.mode === "absolute") return null;
9301
+ if (side.raw) return side.raw;
9302
+ if (side.amount === null || !Number.isFinite(side.amount) || side.amount < 0) return null;
9303
+ const amount = Math.floor(side.amount);
9304
+ return `now${amount > 0 ? `${side.direction === "ago" ? "-" : "+"}${amount}${side.unit}` : ""}${side.round ? `/${side.unit}` : ""}`;
9305
+ }
9306
+ const DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
9307
+ function hxResolveRangeSide(expression, options = {}) {
9308
+ const math = hxParseDateMath(expression, options);
9309
+ if (math) return math;
9310
+ const text = typeof expression === "string" ? expression.trim() : "";
9311
+ const day = DATE_ONLY.exec(text);
9312
+ if (day) {
9313
+ const [y, m, d] = [
9314
+ Number(day[1]),
9315
+ Number(day[2]) - 1,
9316
+ Number(day[3])
9317
+ ];
9318
+ const date = new Date(y, m, d);
9319
+ return date.getFullYear() === y && date.getMonth() === m && date.getDate() === d ? date : null;
9320
+ }
9321
+ if (!/^\d{4}-\d{2}-\d{2}T/.test(text)) return null;
9322
+ const date = new Date(text);
9323
+ return Number.isNaN(date.getTime()) ? null : date;
9324
+ }
9325
+ function hxResolveRangeExpression(range, options = {}) {
9326
+ return {
9327
+ from: hxResolveRangeSide(range.from, {
9328
+ ...options,
9329
+ roundUp: false
9330
+ }),
9331
+ to: hxResolveRangeSide(range.to, {
9332
+ ...options,
9333
+ roundUp: true
9334
+ })
9335
+ };
9336
+ }
9337
+ const fill = (template, n, unit) => template.replace("{n}", String(n)).replace("{unit}", unit);
9338
+ function describeSide(side, labels) {
9339
+ if (side.mode === "absolute") return null;
9340
+ if (side.mode === "now") return labels.nowSummary;
9341
+ if (side.raw) return side.raw;
9342
+ if (sideExpression(side) === null) return labels.emptySide;
9343
+ const n = Math.floor(side.amount ?? 0);
9344
+ const unit = n === 1 ? labels.unitsOne[side.unit] : labels.units[side.unit];
9345
+ const text = n === 0 ? labels.nowSummary : fill(side.direction === "ago" ? labels.agoSummary : labels.fromNowSummary, n, unit);
9346
+ return side.round ? `${text}, ${fill(labels.roundedSummary, n, labels.unitsOne[side.unit])}` : text;
9347
+ }
9348
+ function describeRange(range, labels, common, formatDate, separator = "-") {
9349
+ const known = common.find((c) => c.from === range.from && c.to === range.to);
9350
+ if (known) return known.label;
9351
+ const last = /^now-(\d+)([smhdwMy])$/.exec(range.from);
9352
+ const next = /^now\+(\d+)([smhdwMy])$/.exec(range.to);
9353
+ const unitName = (n, unit) => n === 1 ? labels.unitsOne[unit] : labels.units[unit];
9354
+ if (last && range.to === "now") {
9355
+ const n = Number(last[1]);
9356
+ return fill(labels.lastRange, n, unitName(n, last[2]));
9357
+ }
9358
+ if (next && range.from === "now") {
9359
+ const n = Number(next[1]);
9360
+ return fill(labels.nextRange, n, unitName(n, next[2]));
9361
+ }
9362
+ const side = (text) => {
9363
+ if (hxParseDateMath(text)) return text;
9364
+ const date = hxResolveRangeSide(text);
9365
+ return date ? formatDate(date) : text;
9366
+ };
9367
+ return `${side(range.from)} ${separator} ${side(range.to)}`;
9368
+ }
9369
+ const RECENT_SIDE_MAX = 64;
9370
+ const isRangeSide = (value) => typeof value === "string" && value.length <= RECENT_SIDE_MAX && hxResolveRangeSide(value) !== null;
9371
+ const isRange = (value) => !!value && isRangeSide(value.from) && isRangeSide(value.to);
9372
+ function storage() {
9373
+ try {
9374
+ return globalThis.localStorage ?? null;
9375
+ } catch {
9376
+ return null;
9377
+ }
9378
+ }
9379
+ function readRecentRanges(key) {
9380
+ if (!key) return null;
9381
+ let text;
9382
+ try {
9383
+ const store = storage();
9384
+ if (!store) return null;
9385
+ text = store.getItem(key);
9386
+ } catch {
9387
+ return null;
9388
+ }
9389
+ try {
9390
+ const parsed = JSON.parse(text ?? "[]");
9391
+ if (!Array.isArray(parsed)) return [];
9392
+ return parsed.filter(isRange).reduce((list, { from, to }) => list.some((r) => r.from === from && r.to === to) ? list : [...list, {
9393
+ from,
9394
+ to
9395
+ }], []).slice(0, 5);
9396
+ } catch {
9397
+ return [];
9398
+ }
9399
+ }
9400
+ function writeRecentRanges(key, ranges) {
9401
+ if (!key) return;
9402
+ try {
9403
+ storage()?.setItem(key, JSON.stringify(ranges));
9404
+ } catch {}
9405
+ }
9406
+ function addRecentRange(ranges, range, max = 5) {
9407
+ const rest = ranges.filter((r) => r.from !== range.from || r.to !== range.to);
9408
+ return [{
9409
+ from: range.from,
9410
+ to: range.to
9411
+ }, ...rest].slice(0, max);
9412
+ }
9413
+ const EMPTY$1 = {
9414
+ from: null,
9415
+ to: null
9416
+ };
9417
+ const RESOLVE_TOLERANCE_MS = 1e3;
9418
+ const sameTime$1 = (a, b, tolerance = 0) => a === null || b === null ? a === b : Math.abs(a.getTime() - b.getTime()) <= tolerance;
9419
+ const sameRange$1 = (a, b) => b !== null && sameTime$1(a.from, b.from) && sameTime$1(a.to, b.to);
9420
+ const SIDE_KEYS = ["from", "to"];
9421
+ const sidesFrom = (expression) => expression ? {
9422
+ from: sideFromExpression(expression.from),
9423
+ to: sideFromExpression(expression.to)
9424
+ } : ABSOLUTE_SIDES;
9425
+ var HxDateRangeQuickSelect = class HxDateRangeQuickSelect {
9426
+ labels = input({}, ...ngDevMode ? [{ debugName: "labels" }] : /* istanbul ignore next */ []);
9427
+ commonlyUsed = input(HX_QUICK_SELECT_COMMONLY_USED, ...ngDevMode ? [{ debugName: "commonlyUsed" }] : /* istanbul ignore next */ []);
9428
+ recentStorageKey = input("hx-date-range-recent", ...ngDevMode ? [{ debugName: "recentStorageKey" }] : /* istanbul ignore next */ []);
9429
+ expression = model(null, ...ngDevMode ? [{ debugName: "expression" }] : /* istanbul ignore next */ []);
9430
+ minDate = input(null, ...ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []);
9431
+ maxDate = input(null, ...ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []);
9432
+ firstDayOfWeek = input(0, {
9433
+ ...ngDevMode ? { debugName: "firstDayOfWeek" } : /* istanbul ignore next */ {},
9434
+ transform: numberAttribute
9435
+ });
9436
+ locale = input(...ngDevMode ? [void 0, { debugName: "locale" }] : /* istanbul ignore next */ []);
9437
+ dateFormat = input(...ngDevMode ? [void 0, { debugName: "dateFormat" }] : /* istanbul ignore next */ []);
9438
+ separator = input("-", ...ngDevMode ? [{ debugName: "separator" }] : /* istanbul ignore next */ []);
9439
+ placeholder = input("", ...ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []);
9440
+ chooseLabel = input("Choose date range", ...ngDevMode ? [{ debugName: "chooseLabel" }] : /* istanbul ignore next */ []);
9441
+ inputId = input(...ngDevMode ? [void 0, { debugName: "inputId" }] : /* istanbul ignore next */ []);
9442
+ ariaLabel = input(...ngDevMode ? [void 0, { debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
9443
+ ariaLabelledby = input(...ngDevMode ? [void 0, { debugName: "ariaLabelledby" }] : /* istanbul ignore next */ []);
9444
+ value = model(EMPTY$1, ...ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []);
9445
+ disabled = input(false, {
9446
+ ...ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {},
9447
+ transform: booleanAttribute
9448
+ });
9449
+ invalid = input(false, {
9450
+ ...ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {},
9451
+ transform: booleanAttribute
9452
+ });
9453
+ touch = output();
9454
+ #host = inject(ElementRef);
9455
+ #injector = inject(Injector);
9456
+ open = signal(false, ...ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []);
9457
+ popupId = nextId("hx-date-range-quick-select-popup");
9458
+ positions = [{
9459
+ originX: "start",
9460
+ originY: "bottom",
9461
+ overlayX: "start",
9462
+ overlayY: "top",
9463
+ offsetY: 2
9464
+ }, {
9465
+ originX: "start",
9466
+ originY: "top",
9467
+ overlayX: "start",
9468
+ overlayY: "bottom",
9469
+ offsetY: -2
9470
+ }];
9471
+ quickDirection = signal("last", ...ngDevMode ? [{ debugName: "quickDirection" }] : /* istanbul ignore next */ []);
9472
+ quickAmount = signal("15", ...ngDevMode ? [{ debugName: "quickAmount" }] : /* istanbul ignore next */ []);
9473
+ quickUnit = signal("m", ...ngDevMode ? [{ debugName: "quickUnit" }] : /* istanbul ignore next */ []);
9474
+ recent = signal([], ...ngDevMode ? [{ debugName: "recent" }] : /* istanbul ignore next */ []);
9475
+ quickError = signal(false, ...ngDevMode ? [{ debugName: "quickError" }] : /* istanbul ignore next */ []);
9476
+ quickErrorId = `${this.popupId}-error`;
9477
+ sideKeys = SIDE_KEYS;
9478
+ sideModes = SIDE_MODES;
9479
+ openSide = signal(null, ...ngDevMode ? [{ debugName: "openSide" }] : /* istanbul ignore next */ []);
9480
+ sides = signal(ABSOLUTE_SIDES, ...ngDevMode ? [{ debugName: "sides" }] : /* istanbul ignore next */ []);
9481
+ #appliedSides = signal(ABSOLUTE_SIDES, ...ngDevMode ? [{ debugName: "#appliedSides" }] : /* istanbul ignore next */ []);
9482
+ sideError = signal(false, ...ngDevMode ? [{ debugName: "sideError" }] : /* istanbul ignore next */ []);
9483
+ calendarFocus = signal(startOfDay(/* @__PURE__ */ new Date()), ...ngDevMode ? [{ debugName: "calendarFocus" }] : /* istanbul ignore next */ []);
9484
+ calendarView = signal("day", ...ngDevMode ? [{ debugName: "calendarView" }] : /* istanbul ignore next */ []);
9485
+ today = signal(startOfDay(/* @__PURE__ */ new Date()), ...ngDevMode ? [{ debugName: "today" }] : /* istanbul ignore next */ []);
9486
+ calendarTitleId = `${this.popupId}-calendar-title`;
9487
+ texts = computed(() => ({
9488
+ ...HX_QUICK_SELECT_LABELS,
9489
+ ...this.labels()
9490
+ }), ...ngDevMode ? [{ debugName: "texts" }] : /* istanbul ignore next */ []);
9491
+ directionOptions = computed(() => [{
9492
+ label: this.texts().last,
9493
+ value: "last"
9494
+ }, {
9495
+ label: this.texts().next,
9496
+ value: "next"
9497
+ }], ...ngDevMode ? [{ debugName: "directionOptions" }] : /* istanbul ignore next */ []);
9498
+ unitOptions = computed(() => QUICK_SELECT_UNITS.map((unit) => ({
9499
+ label: this.texts().units[unit],
9500
+ value: unit
9501
+ })), ...ngDevMode ? [{ debugName: "unitOptions" }] : /* istanbul ignore next */ []);
9502
+ relativeOptions = computed(() => {
9503
+ const l = this.texts();
9504
+ return [...QUICK_SELECT_UNITS.map((unit) => ({
9505
+ label: l.unitsAgo[unit],
9506
+ value: `${unit}-ago`
9507
+ })), ...QUICK_SELECT_UNITS.map((unit) => ({
9508
+ label: l.unitsFromNow[unit],
9509
+ value: `${unit}-fromNow`
9510
+ }))];
9511
+ }, ...ngDevMode ? [{ debugName: "relativeOptions" }] : /* istanbul ignore next */ []);
9512
+ recentItems = computed(() => this.recent().map((range) => ({
9513
+ range,
9514
+ label: this.#describe(range)
9515
+ })), ...ngDevMode ? [{ debugName: "recentItems" }] : /* istanbul ignore next */ []);
9516
+ isDisabled = computed(() => this.disabled() || this.#cvaDisabled(), ...ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []);
9517
+ text = computed(() => {
9518
+ const expression = this.expression();
9519
+ if (expression) return this.#describe(expression);
9520
+ const { from, to } = this.value();
9521
+ if (!from && !to) return "";
9522
+ const one = (d) => d ? this.#formatDate(d) : "";
9523
+ return `${one(from)} ${this.separator()} ${one(to)}`.trim();
9524
+ }, ...ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []);
9525
+ field = viewChild("field", ...ngDevMode ? [{ debugName: "field" }] : /* istanbul ignore next */ []);
9526
+ quickFirst = viewChild("quickFirst", {
9527
+ ...ngDevMode ? { debugName: "quickFirst" } : /* istanbul ignore next */ {},
9528
+ read: HxSelect
9529
+ });
9530
+ sideButtons = viewChildren("sideButton", ...ngDevMode ? [{ debugName: "sideButtons" }] : /* istanbul ignore next */ []);
9531
+ sideTabs = viewChildren("sideTab", ...ngDevMode ? [{ debugName: "sideTabs" }] : /* istanbul ignore next */ []);
9532
+ #cvaDisabled = signal(false, ...ngDevMode ? [{ debugName: "#cvaDisabled" }] : /* istanbul ignore next */ []);
9533
+ #format = computed(() => new Intl.DateTimeFormat(this.locale(), this.dateFormat() ?? {
9534
+ day: "numeric",
9535
+ month: "numeric",
9536
+ year: "numeric",
9537
+ hour: "numeric",
9538
+ minute: "2-digit",
9539
+ hourCycle: "h23"
9540
+ }), ...ngDevMode ? [{ debugName: "#format" }] : /* istanbul ignore next */ []);
9541
+ #onChange = () => {};
9542
+ #onTouched = () => {};
9543
+ #seenExpression = null;
9544
+ #expressionValue = null;
9545
+ #editedValue = null;
9546
+ #editedExpression = null;
9547
+ #editedRange = null;
9548
+ constructor() {
9549
+ effect(() => {
9550
+ if (this.isDisabled()) untracked(() => this.close());
9551
+ });
9552
+ effect(() => {
9553
+ const value = this.value();
9554
+ const expression = this.expression();
9555
+ untracked(() => {
9556
+ if (expression !== this.#seenExpression) {
9557
+ this.#seenExpression = expression;
9558
+ this.#expressionValue = value;
9559
+ } else if (expression !== null && value !== this.#expressionValue) if (sameRange$1(value, this.#expressionValue) || this.#resolvesTo(expression, value)) this.#expressionValue = value;
9560
+ else this.expression.set(null);
9561
+ if (value !== this.#editedValue || this.expression() !== this.#editedExpression) {
9562
+ this.#editedValue = null;
9563
+ this.#editedExpression = null;
9564
+ this.#editedRange = null;
9565
+ this.sideError.set(false);
9566
+ const sides = sidesFrom(this.expression());
9567
+ this.sides.set(sides);
9568
+ this.#appliedSides.set(sides);
9569
+ }
9570
+ });
9571
+ });
9572
+ }
9573
+ writeValue(value) {
9574
+ this.value.set({
9575
+ from: value?.from ?? null,
9576
+ to: value?.to ?? null
9577
+ });
9578
+ }
9579
+ registerOnChange(fn) {
9580
+ this.#onChange = fn;
9581
+ }
9582
+ registerOnTouched(fn) {
9583
+ this.#onTouched = fn;
9584
+ }
9585
+ setDisabledState(disabled) {
9586
+ this.#cvaDisabled.set(disabled);
9587
+ }
9588
+ focus() {
9589
+ this.field()?.nativeElement.focus();
9590
+ }
9591
+ show() {
9592
+ if (this.isDisabled() || this.open()) return;
9593
+ const stored = readRecentRanges(this.recentStorageKey());
9594
+ if (stored) this.recent.set(stored);
9595
+ this.quickError.set(false);
9596
+ this.#dropRefusedEdit();
9597
+ this.openSide.set(null);
9598
+ this.open.set(true);
9599
+ }
9600
+ toggle() {
9601
+ if (this.open()) this.close(true);
9602
+ else this.show();
9603
+ }
9604
+ close(refocus = false) {
9605
+ if (!this.open()) return;
9606
+ this.#dropRefusedEdit();
9607
+ this.openSide.set(null);
9608
+ if (this.#editedRange) this.#remember(this.#editedRange);
9609
+ this.#editedRange = null;
9610
+ this.open.set(false);
9611
+ if (refocus) this.field()?.nativeElement.focus();
9612
+ }
9613
+ onAttach() {
9614
+ afterNextRender(() => this.quickFirst()?.focus(), { injector: this.#injector });
9615
+ }
9616
+ onFieldKeydown(event) {
9617
+ if (event.key === "ArrowDown" || event.altKey && event.key === "ArrowUp" || event.key === "Enter" || event.key === " ") {
9618
+ event.preventDefault();
9619
+ this.show();
9620
+ }
9621
+ }
9622
+ onOverlayKeydown(event) {
9623
+ if (event.key !== "Escape") return;
9624
+ event.preventDefault();
9625
+ if (this.openSide()) this.closeSide();
9626
+ else this.close(true);
9627
+ }
9628
+ onOutsideClick(event) {
9629
+ if (isInSelectOverlay(event.target)) return;
9630
+ if (!this.#host.nativeElement.contains(event.target)) this.close();
9631
+ }
9632
+ setQuickDirection(direction) {
9633
+ if (direction === "last" || direction === "next") this.quickDirection.set(direction);
9634
+ }
9635
+ setQuickAmount(event) {
9636
+ this.quickError.set(false);
9637
+ this.quickAmount.set(event.target.value);
9638
+ }
9639
+ setQuickUnit(unit) {
9640
+ if (QUICK_SELECT_UNITS.includes(unit)) this.quickUnit.set(unit);
9641
+ }
9642
+ applyQuick() {
9643
+ const text = this.quickAmount().trim();
9644
+ const range = hxRelativeRangeExpressions(this.quickDirection(), text === "" ? NaN : Number(text), this.quickUnit());
9645
+ if (!range || !this.#applyRange(range)) this.quickError.set(true);
9646
+ }
9647
+ applyRange(range) {
9648
+ if (!this.#applyRange(range)) this.quickError.set(true);
9649
+ }
9650
+ sideSummary(side) {
9651
+ const relative = describeSide(this.#appliedSides()[side], this.texts());
9652
+ if (relative !== null) return relative;
9653
+ const date = this.value()[side];
9654
+ return date ? this.#formatDate(date) : this.texts().emptySide;
9655
+ }
9656
+ sideButtonId(side) {
9657
+ return `${this.popupId}-${side}-button`;
9658
+ }
9659
+ editorId(side) {
9660
+ return `${this.popupId}-${side}-editor`;
9661
+ }
9662
+ tabId(side, mode) {
9663
+ return `${this.popupId}-${side}-${mode}`;
9664
+ }
9665
+ panelId(side) {
9666
+ return `${this.popupId}-${side}-panel`;
9667
+ }
9668
+ toggleSide(side) {
9669
+ if (this.openSide() === side) {
9670
+ this.closeSide();
9671
+ return;
9672
+ }
9673
+ this.#dropRefusedEdit();
9674
+ this.openSide.set(side);
9675
+ this.#showDay(side);
9676
+ afterNextRender(() => this.#focusById(this.sideTabs(), this.tabId(side, this.sides()[side].mode)), { injector: this.#injector });
9677
+ }
9678
+ closeSide() {
9679
+ const side = this.openSide();
9680
+ if (!side) return;
9681
+ this.#dropRefusedEdit();
9682
+ this.openSide.set(null);
9683
+ this.#focusById(this.sideButtons(), this.sideButtonId(side));
9684
+ }
9685
+ setSideMode(side, mode) {
9686
+ const sides = this.sides();
9687
+ if (sides[side].mode === mode) return;
9688
+ this.#editSides({
9689
+ ...sides,
9690
+ [side]: {
9691
+ ...sides[side],
9692
+ mode
9693
+ }
9694
+ });
9695
+ if (mode === "absolute") this.#showDay(side);
9696
+ }
9697
+ onTabKeydown(side, event) {
9698
+ const index = SIDE_MODES.indexOf(this.sides()[side].mode);
9699
+ const last = SIDE_MODES.length - 1;
9700
+ const next = event.key === "ArrowRight" ? (index + 1) % SIDE_MODES.length : event.key === "ArrowLeft" ? (index + last) % SIDE_MODES.length : event.key === "Home" ? 0 : event.key === "End" ? last : -1;
9701
+ if (next < 0) return;
9702
+ event.preventDefault();
9703
+ this.setSideMode(side, SIDE_MODES[next]);
9704
+ event.currentTarget.querySelectorAll("[role=tab]")[next]?.focus();
9705
+ }
9706
+ setSideAmount(side, event) {
9707
+ const text = event.target.value.trim();
9708
+ this.#patchSide(side, { amount: text === "" ? null : Number(text) });
9709
+ }
9710
+ setSideUnit(side, value) {
9711
+ const [unit, direction] = String(value).split("-");
9712
+ if (!QUICK_SELECT_UNITS.includes(unit)) return;
9713
+ this.#patchSide(side, {
9714
+ unit,
9715
+ direction: direction === "fromNow" ? "fromNow" : "ago"
9716
+ });
9717
+ }
9718
+ setSideRound(side, event) {
9719
+ this.#patchSide(side, { round: event.target.checked });
9720
+ }
9721
+ sideUnitValue(side) {
9722
+ const state = this.sides()[side];
9723
+ return `${state.unit}-${state.direction}`;
9724
+ }
9725
+ sideRoundLabel(side) {
9726
+ return this.texts().roundTo.replace("{unit}", this.texts().unitsOne[this.sides()[side].unit]);
9727
+ }
9728
+ sideExpressionText(side) {
9729
+ return sideExpression(this.sides()[side]) ?? "";
9730
+ }
9731
+ sideResolvedText(side) {
9732
+ const state = this.sides()[side];
9733
+ const expression = sideExpression(state);
9734
+ const resolved = state.mode === "absolute" ? this.value()[side] : expression ? hxResolveRangeSide(expression, {
9735
+ firstDayOfWeek: this.firstDayOfWeek(),
9736
+ roundUp: side === "to"
9737
+ }) : null;
9738
+ if (!isValidDate(resolved)) return "";
9739
+ const date = clampTime(resolved, this.minDate(), this.maxDate());
9740
+ return this.texts().resolvesTo.replace("{date}", this.#formatDate(date));
9741
+ }
9742
+ sideText(side) {
9743
+ const date = this.value()[side];
9744
+ return date ? this.#formatDate(date) : "";
9745
+ }
9746
+ sideDays(side) {
9747
+ const date = this.value()[side];
9748
+ return date ? [date] : [];
9749
+ }
9750
+ setAbsoluteSide(side, event) {
9751
+ const field = event.target;
9752
+ const text = field.value.trim();
9753
+ if (text === this.sideText(side)) {
9754
+ this.#dropRefusedEdit();
9755
+ return;
9756
+ }
9757
+ let date = null;
9758
+ if (text !== "") {
9759
+ date = parseDateTimeText(text, {
9760
+ locale: this.locale(),
9761
+ showMinutes: true,
9762
+ timeOnly: false,
9763
+ fallbackDay: this.value()[side] ?? /* @__PURE__ */ new Date()
9764
+ }) ?? parseDateText(text, this.locale());
9765
+ const [min, max] = [this.minDate(), this.maxDate()];
9766
+ if (!date || min && date < min || max && date > max) {
9767
+ this.sideError.set(true);
9768
+ return;
9769
+ }
9770
+ }
9771
+ if (!this.#editSides(this.sides(), { [side]: date })) return;
9772
+ if (date) this.calendarFocus.set(startOfDay(date));
9773
+ field.value = this.sideText(this.openSide() ?? side);
9774
+ }
9775
+ pickDay(side, day) {
9776
+ const [min, max] = [this.minDate(), this.maxDate()];
9777
+ if (this.isDisabled() || isDateDisabled(day, {
9778
+ min,
9779
+ max
9780
+ })) return;
9781
+ const old = this.value()[side];
9782
+ const date = startOfDay(day);
9783
+ if (old) date.setHours(old.getHours(), old.getMinutes(), old.getSeconds(), old.getMilliseconds());
9784
+ else if (side === "to") date.setHours(23, 59, 59, 999);
9785
+ this.calendarFocus.set(startOfDay(day));
9786
+ this.#editSides(this.sides(), { [side]: clampTime(date, min, max) });
9787
+ }
9788
+ #patchSide(side, patch) {
9789
+ const sides = this.sides();
9790
+ this.#editSides({
9791
+ ...sides,
9792
+ [side]: {
9793
+ ...sides[side],
9794
+ ...patch,
9795
+ raw: null
9796
+ }
9797
+ });
9798
+ }
9799
+ #editSides(sides, dates = {}) {
9800
+ this.sides.set(sides);
9801
+ const applied = this.#applySides(sides, dates);
9802
+ this.sideError.set(!applied);
9803
+ return applied;
9804
+ }
9805
+ #applySides(edited, dates) {
9806
+ let sides = edited;
9807
+ const options = {
9808
+ now: /* @__PURE__ */ new Date(),
9809
+ firstDayOfWeek: this.firstDayOfWeek()
9810
+ };
9811
+ const resolved = {
9812
+ from: null,
9813
+ to: null
9814
+ };
9815
+ const texts = {
9816
+ from: null,
9817
+ to: null
9818
+ };
9819
+ for (const side of SIDE_KEYS) {
9820
+ const state = sides[side];
9821
+ if (state.mode === "absolute") {
9822
+ const date = side in dates ? dates[side] ?? null : this.value()[side];
9823
+ resolved[side] = date;
9824
+ texts[side] = date?.toISOString() ?? null;
9825
+ continue;
9826
+ }
9827
+ const expression = sideExpression(state);
9828
+ const date = expression ? hxResolveRangeSide(expression, {
9829
+ ...options,
9830
+ roundUp: side === "to"
9831
+ }) : null;
9832
+ if (!expression || !isValidDate(date)) return false;
9833
+ resolved[side] = date;
9834
+ texts[side] = expression;
9835
+ }
9836
+ if (resolved.from && resolved.to && resolved.from > resolved.to) {
9837
+ [resolved.from, resolved.to] = [resolved.to, resolved.from];
9838
+ [texts.from, texts.to] = [texts.to, texts.from];
9839
+ sides = {
9840
+ from: sides.to,
9841
+ to: sides.from
9842
+ };
9843
+ this.sides.set(sides);
9844
+ const open = this.openSide();
9845
+ if (open) this.openSide.set(open === "from" ? "to" : "from");
9846
+ }
9847
+ const inside = (d) => d && clampTime(d, this.minDate(), this.maxDate());
9848
+ const next = {
9849
+ from: inside(resolved.from),
9850
+ to: inside(resolved.to)
9851
+ };
9852
+ const range = texts.from !== null && texts.to !== null ? {
9853
+ from: texts.from,
9854
+ to: texts.to
9855
+ } : null;
9856
+ const expression = sides.from.mode !== "absolute" || sides.to.mode !== "absolute" ? range : null;
9857
+ this.#editedValue = next;
9858
+ this.#editedExpression = expression;
9859
+ this.#editedRange = range;
9860
+ this.#appliedSides.set(sides);
9861
+ this.#commit(next);
9862
+ this.expression.set(expression);
9863
+ return true;
9864
+ }
9865
+ #focusById(elements, id) {
9866
+ elements.find((e) => e.nativeElement.id === id)?.nativeElement.focus();
9867
+ }
9868
+ #dropRefusedEdit() {
9869
+ if (!this.sideError()) return;
9870
+ this.sideError.set(false);
9871
+ this.sides.set(this.#appliedSides());
9872
+ }
9873
+ #showDay(side) {
9874
+ const today = startOfDay(/* @__PURE__ */ new Date());
9875
+ this.today.set(today);
9876
+ const min = this.minDate();
9877
+ const date = this.value()[side] ?? clampTime(today, min && startOfDay(min), this.maxDate());
9878
+ this.calendarFocus.set(startOfDay(date));
9879
+ this.calendarView.set("day");
9880
+ }
9881
+ #applyRange(range) {
9882
+ const options = {
9883
+ now: /* @__PURE__ */ new Date(),
9884
+ firstDayOfWeek: this.firstDayOfWeek()
9885
+ };
9886
+ const from = hxResolveRangeSide(range.from, {
9887
+ ...options,
9888
+ roundUp: false
9889
+ });
9890
+ const to = hxResolveRangeSide(range.to, {
9891
+ ...options,
9892
+ roundUp: true
9893
+ });
9894
+ if (!isValidDate(from) || !isValidDate(to)) return false;
9895
+ const swapped = to < from;
9896
+ const stored = swapped ? {
9897
+ from: range.to,
9898
+ to: range.from
9899
+ } : {
9900
+ from: range.from,
9901
+ to: range.to
9902
+ };
9903
+ const inside = (d) => clampTime(d, this.minDate(), this.maxDate());
9904
+ const next = swapped ? {
9905
+ from: inside(to),
9906
+ to: inside(from)
9907
+ } : {
9908
+ from: inside(from),
9909
+ to: inside(to)
9910
+ };
9911
+ const relative = hxParseDateMath(range.from) !== null || hxParseDateMath(range.to) !== null;
9912
+ this.#editedRange = null;
9913
+ this.#remember(stored);
9914
+ this.#commit(next);
9915
+ this.expression.set(relative ? stored : null);
9916
+ this.close(true);
9917
+ return true;
9918
+ }
9919
+ #resolvesTo(expression, value) {
9920
+ const { from, to } = hxResolveRangeExpression(expression, { firstDayOfWeek: this.firstDayOfWeek() });
9921
+ const inside = (d) => isValidDate(d) ? clampTime(d, this.minDate(), this.maxDate()) : null;
9922
+ const near = (a, b) => sameTime$1(a, b, RESOLVE_TOLERANCE_MS);
9923
+ const matches = (start, end) => near(value.from, start) && near(value.to, end) || near(value.from, inside(start)) && near(value.to, inside(end));
9924
+ return matches(from, to) || matches(to, from);
9925
+ }
9926
+ #remember(range) {
9927
+ const next = addRecentRange(this.recent(), range);
9928
+ this.recent.set(next);
9929
+ writeRecentRanges(this.recentStorageKey(), next);
9930
+ }
9931
+ #describe(range) {
9932
+ return describeRange(range, this.texts(), this.commonlyUsed(), (d) => this.#formatDate(d), this.separator());
9933
+ }
9934
+ #formatDate(date) {
9935
+ return this.#format().format(date).replace(/,\s*/, " ");
9936
+ }
9937
+ onHostFocusOut(event) {
9938
+ const next = event.relatedTarget;
9939
+ if (isInSelectOverlay(next) || next?.closest(".hx-date-range-quick-select-popup") || this.#host.nativeElement.contains(next)) return;
9940
+ if (this.open() && !next) return;
9941
+ this.close();
9942
+ this.markTouched();
9943
+ }
9944
+ onPopupFocusOut(event) {
9945
+ const next = event.relatedTarget;
9946
+ if (!next || isInSelectOverlay(next) || next.closest(".hx-date-range-quick-select-popup") || this.#host.nativeElement.contains(next)) return;
9947
+ this.close();
9948
+ this.markTouched();
9949
+ }
9950
+ markTouched() {
9951
+ this.#onTouched();
9952
+ this.touch.emit();
9953
+ }
9954
+ #commit(next) {
9955
+ this.value.set(next);
9956
+ this.#onChange(next);
9957
+ }
9958
+ static ɵfac = i0.ɵɵngDeclareFactory({
9959
+ minVersion: "12.0.0",
9960
+ version: "22.2.1",
9961
+ ngImport: i0,
9962
+ type: HxDateRangeQuickSelect,
9963
+ deps: [],
9964
+ target: i0.ɵɵFactoryTarget.Component
9965
+ });
9966
+ static ɵcmp = i0.ɵɵngDeclareComponent({
9967
+ minVersion: "17.0.0",
9968
+ version: "22.2.1",
9969
+ type: HxDateRangeQuickSelect,
9970
+ isStandalone: true,
9971
+ selector: "hx-date-range-quick-select",
9972
+ inputs: {
9973
+ labels: {
9974
+ classPropertyName: "labels",
9975
+ publicName: "labels",
9976
+ isSignal: true,
9977
+ isRequired: false,
9978
+ transformFunction: null
9979
+ },
9980
+ commonlyUsed: {
9981
+ classPropertyName: "commonlyUsed",
9982
+ publicName: "commonlyUsed",
8033
9983
  isSignal: true,
8034
9984
  isRequired: false,
8035
9985
  transformFunction: null
8036
9986
  },
8037
- inline: {
8038
- classPropertyName: "inline",
8039
- publicName: "inline",
9987
+ recentStorageKey: {
9988
+ classPropertyName: "recentStorageKey",
9989
+ publicName: "recentStorageKey",
8040
9990
  isSignal: true,
8041
9991
  isRequired: false,
8042
9992
  transformFunction: null
8043
9993
  },
8044
- selectionMode: {
8045
- classPropertyName: "selectionMode",
8046
- publicName: "selectionMode",
9994
+ expression: {
9995
+ classPropertyName: "expression",
9996
+ publicName: "expression",
8047
9997
  isSignal: true,
8048
9998
  isRequired: false,
8049
9999
  transformFunction: null
@@ -8062,13 +10012,6 @@ var HxDatePicker = class HxDatePicker {
8062
10012
  isRequired: false,
8063
10013
  transformFunction: null
8064
10014
  },
8065
- disabledDates: {
8066
- classPropertyName: "disabledDates",
8067
- publicName: "disabledDates",
8068
- isSignal: true,
8069
- isRequired: false,
8070
- transformFunction: null
8071
- },
8072
10015
  firstDayOfWeek: {
8073
10016
  classPropertyName: "firstDayOfWeek",
8074
10017
  publicName: "firstDayOfWeek",
@@ -8083,6 +10026,41 @@ var HxDatePicker = class HxDatePicker {
8083
10026
  isRequired: false,
8084
10027
  transformFunction: null
8085
10028
  },
10029
+ dateFormat: {
10030
+ classPropertyName: "dateFormat",
10031
+ publicName: "dateFormat",
10032
+ isSignal: true,
10033
+ isRequired: false,
10034
+ transformFunction: null
10035
+ },
10036
+ separator: {
10037
+ classPropertyName: "separator",
10038
+ publicName: "separator",
10039
+ isSignal: true,
10040
+ isRequired: false,
10041
+ transformFunction: null
10042
+ },
10043
+ placeholder: {
10044
+ classPropertyName: "placeholder",
10045
+ publicName: "placeholder",
10046
+ isSignal: true,
10047
+ isRequired: false,
10048
+ transformFunction: null
10049
+ },
10050
+ chooseLabel: {
10051
+ classPropertyName: "chooseLabel",
10052
+ publicName: "chooseLabel",
10053
+ isSignal: true,
10054
+ isRequired: false,
10055
+ transformFunction: null
10056
+ },
10057
+ inputId: {
10058
+ classPropertyName: "inputId",
10059
+ publicName: "inputId",
10060
+ isSignal: true,
10061
+ isRequired: false,
10062
+ transformFunction: null
10063
+ },
8086
10064
  ariaLabel: {
8087
10065
  classPropertyName: "ariaLabel",
8088
10066
  publicName: "ariaLabel",
@@ -8120,41 +10098,50 @@ var HxDatePicker = class HxDatePicker {
8120
10098
  }
8121
10099
  },
8122
10100
  outputs: {
10101
+ expression: "expressionChange",
8123
10102
  value: "valueChange",
8124
10103
  touch: "touch"
8125
10104
  },
8126
10105
  host: {
8127
10106
  listeners: { "focusout": "onHostFocusOut($event)" },
8128
- properties: {
8129
- "class.hx-date-picker-inline": "inline()",
8130
- "class.hx-date-picker-disabled": "isDisabled()",
8131
- "class.hx-date-picker-invalid": "invalid()",
8132
- "class.hx-date-picker-open": "open()",
8133
- "class.hx-date-picker-has-icon": "showIcon() && !inline()",
8134
- "class.hx-filled": "!inline() && text() !== \"\""
8135
- },
8136
- classAttribute: "hx-date-picker"
10107
+ classAttribute: "hx-date-range-quick-select"
8137
10108
  },
8138
10109
  providers: [{
8139
10110
  provide: NG_VALUE_ACCESSOR,
8140
- useExisting: forwardRef(() => HxDatePicker),
10111
+ useExisting: forwardRef(() => HxDateRangeQuickSelect),
8141
10112
  multi: true
8142
10113
  }],
8143
- viewQueries: [{
8144
- propertyName: "field",
8145
- first: true,
8146
- predicate: ["field"],
8147
- descendants: true,
8148
- isSignal: true
8149
- }, {
8150
- propertyName: "calendar",
8151
- first: true,
8152
- predicate: HxCalendar,
8153
- descendants: true,
8154
- isSignal: true
8155
- }],
10114
+ viewQueries: [
10115
+ {
10116
+ propertyName: "field",
10117
+ first: true,
10118
+ predicate: ["field"],
10119
+ descendants: true,
10120
+ isSignal: true
10121
+ },
10122
+ {
10123
+ propertyName: "quickFirst",
10124
+ first: true,
10125
+ predicate: ["quickFirst"],
10126
+ descendants: true,
10127
+ read: HxSelect,
10128
+ isSignal: true
10129
+ },
10130
+ {
10131
+ propertyName: "sideButtons",
10132
+ predicate: ["sideButton"],
10133
+ descendants: true,
10134
+ isSignal: true
10135
+ },
10136
+ {
10137
+ propertyName: "sideTabs",
10138
+ predicate: ["sideTab"],
10139
+ descendants: true,
10140
+ isSignal: true
10141
+ }
10142
+ ],
8156
10143
  ngImport: i0,
8157
- template: "@if (inline()) {\n <ng-container [ngTemplateOutlet]=\"calendar\" />\n} @else {\n <div class=\"hx-date-picker-field\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n <input\n #field\n type=\"text\"\n class=\"hx-date-picker-input\"\n autocomplete=\"off\"\n aria-haspopup=\"dialog\"\n [attr.id]=\"inputId() ?? null\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"text()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? popupId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (input)=\"onTyping($event)\"\n (change)=\"commitTyping()\"\n (click)=\"show()\"\n (keydown)=\"onFieldKeydown($event)\"\n />\n @if (showIcon()) {\n <button\n type=\"button\"\n class=\"hx-date-picker-trigger\"\n aria-haspopup=\"dialog\"\n [attr.aria-label]=\"chooseLabel()\"\n [attr.aria-expanded]=\"open()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n >\n <span class=\"hx-date-picker-trigger-icon\" aria-hidden=\"true\"></span>\n </button>\n }\n </div>\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayPanelClass=\"hx-date-picker-overlay\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"open.set(false)\"\n >\n <div\n class=\"hx-date-picker-popup\"\n role=\"dialog\"\n aria-modal=\"false\"\n [id]=\"popupId\"\n [attr.aria-label]=\"ariaLabel() ?? 'Choose date'\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n >\n <ng-container [ngTemplateOutlet]=\"calendar\" />\n @if (showButtonBar()) {\n <div class=\"hx-date-picker-buttonbar\">\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"selectToday()\">{{ todayLabel() }}</button>\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"clear()\">{{ clearLabel() }}</button>\n </div>\n }\n </div>\n </ng-template>\n}\n\n<ng-template #calendar>\n<div\n class=\"hx-date-picker-panel\"\n role=\"group\"\n [attr.aria-label]=\"ariaLabel() ?? 'Calendar'\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (focusout)=\"onFocusOut($event)\"\n>\n <hx-calendar\n [(focusedDate)]=\"focusedDate\"\n [(view)]=\"view\"\n [selectedDates]=\"selectedDates()\"\n [selectionMode]=\"selectionMode()\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [disabledDates]=\"disabledDates()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n [titleId]=\"titleId\"\n [today]=\"today\"\n (picked)=\"pick($event)\"\n />\n</div>\n</ng-template>\n",
10144
+ template: "<div\n class=\"hx-date-picker hx-date-picker-has-icon hx-date-range-quick-select-control\"\n [class.hx-date-picker-open]=\"open()\"\n [class.hx-date-picker-disabled]=\"isDisabled()\"\n [class.hx-date-picker-invalid]=\"invalid()\"\n>\n <div class=\"hx-date-picker-field\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n <input\n #field\n type=\"text\"\n readonly\n class=\"hx-date-picker-input\"\n autocomplete=\"off\"\n aria-haspopup=\"dialog\"\n [attr.id]=\"inputId() ?? null\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"text()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? popupId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (click)=\"show()\"\n (keydown)=\"onFieldKeydown($event)\"\n />\n <button\n type=\"button\"\n class=\"hx-date-picker-trigger\"\n aria-haspopup=\"dialog\"\n [attr.aria-label]=\"chooseLabel()\"\n [attr.aria-expanded]=\"open()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n >\n <span class=\"hx-date-picker-trigger-icon\" aria-hidden=\"true\"></span>\n </button>\n </div>\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayPanelClass=\"hx-date-picker-overlay\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"close()\"\n >\n @let l = texts();\n <div\n class=\"hx-date-picker-popup hx-date-range-quick-select-popup\"\n role=\"dialog\"\n aria-modal=\"false\"\n [id]=\"popupId\"\n [attr.aria-label]=\"ariaLabel() ?? chooseLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (focusout)=\"onPopupFocusOut($event)\"\n >\n <section class=\"hx-date-range-quick-select-section\" [attr.aria-labelledby]=\"popupId + '-quick'\">\n <span class=\"hx-date-range-quick-select-caption\" [id]=\"popupId + '-quick'\">{{ l.quickSelect }}</span>\n <div class=\"hx-date-range-quick-select-row\">\n <hx-select\n #quickFirst\n class=\"hx-date-range-quick-select-direction\"\n [options]=\"directionOptions()\"\n [ariaLabel]=\"l.direction\"\n [value]=\"quickDirection()\"\n (valueChange)=\"setQuickDirection($event)\"\n />\n <input\n hx-input\n type=\"number\"\n min=\"1\"\n step=\"1\"\n class=\"hx-date-range-quick-select-amount\"\n [attr.aria-label]=\"l.amount\"\n [attr.aria-invalid]=\"quickError() ? 'true' : null\"\n [attr.aria-describedby]=\"quickError() ? quickErrorId : null\"\n [value]=\"quickAmount()\"\n (input)=\"setQuickAmount($event)\"\n (keydown.enter)=\"$event.preventDefault(); applyQuick()\"\n />\n <hx-select\n class=\"hx-date-range-quick-select-unit\"\n [options]=\"unitOptions()\"\n [ariaLabel]=\"l.unit\"\n [value]=\"quickUnit()\"\n (valueChange)=\"setQuickUnit($event)\"\n />\n <button\n type=\"button\"\n class=\"hx-date-picker-button hx-date-range-quick-select-apply\"\n [attr.aria-describedby]=\"quickError() ? quickErrorId : null\"\n (click)=\"applyQuick()\"\n >\n {{ l.apply }}\n </button>\n </div>\n </section>\n @if (commonlyUsed().length > 0) {\n <section class=\"hx-date-range-quick-select-section\" [attr.aria-labelledby]=\"popupId + '-common'\">\n <span class=\"hx-date-range-quick-select-caption\" [id]=\"popupId + '-common'\">{{ l.commonlyUsed }}</span>\n <ul class=\"hx-date-range-quick-select-ranges hx-date-range-quick-select-common\">\n @for (range of commonlyUsed(); track $index) {\n <li>\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"applyRange(range)\">{{ range.label }}</button>\n </li>\n }\n </ul>\n </section>\n }\n @if (recentItems().length > 0) {\n <section class=\"hx-date-range-quick-select-section\" [attr.aria-labelledby]=\"popupId + '-recent'\">\n <span class=\"hx-date-range-quick-select-caption\" [id]=\"popupId + '-recent'\">{{ l.recentlyUsed }}</span>\n <ul class=\"hx-date-range-quick-select-ranges hx-date-range-quick-select-recent\">\n @for (item of recentItems(); track item.range.from + ' ' + item.range.to) {\n <li>\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"applyRange(item.range)\">{{ item.label }}</button>\n </li>\n }\n </ul>\n </section>\n }\n <!-- one line per side; a click opens the editor of that side (Absolute / Relative / Now) below -->\n <div class=\"hx-date-range-quick-select-summary\" role=\"group\" [attr.aria-label]=\"l.range\">\n @for (s of sideKeys; track s) {\n <button\n #sideButton\n type=\"button\"\n class=\"hx-date-range-quick-select-side-line\"\n [class]=\"'hx-date-range-quick-select-side-line-' + s\"\n [id]=\"sideButtonId(s)\"\n [attr.aria-expanded]=\"openSide() === s\"\n [attr.aria-controls]=\"openSide() === s ? editorId(s) : null\"\n (click)=\"toggleSide(s)\"\n >\n <span class=\"hx-date-range-quick-select-side-name\">{{ s === 'from' ? l.start : l.end }}</span>&ngsp;\n <span class=\"hx-date-range-quick-select-side-value\">{{ sideSummary(s) }}</span>\n </button>\n }\n </div>\n @if (openSide(); as s) {\n @let state = sides()[s];\n @let sideName = s === 'from' ? l.start : l.end;\n <section\n class=\"hx-date-range-quick-select-editor\"\n [class]=\"'hx-date-range-quick-select-editor-' + s\"\n [id]=\"editorId(s)\"\n [attr.aria-labelledby]=\"sideButtonId(s)\"\n >\n <div\n class=\"hx-date-range-quick-select-tabs\"\n role=\"tablist\"\n [attr.aria-labelledby]=\"sideButtonId(s)\"\n (keydown)=\"onTabKeydown(s, $event)\"\n >\n @for (mode of sideModes; track mode) {\n <button\n #sideTab\n type=\"button\"\n role=\"tab\"\n class=\"hx-date-range-quick-select-tab\"\n [id]=\"tabId(s, mode)\"\n [attr.aria-selected]=\"state.mode === mode\"\n [attr.aria-controls]=\"panelId(s)\"\n [attr.tabindex]=\"state.mode === mode ? 0 : -1\"\n (click)=\"setSideMode(s, mode)\"\n >\n {{ mode === 'absolute' ? l.absolute : mode === 'relative' ? l.relative : l.now }}\n </button>\n }\n </div>\n <div\n class=\"hx-date-range-quick-select-tabpanel\"\n role=\"tabpanel\"\n tabindex=\"0\"\n [id]=\"panelId(s)\"\n [attr.aria-labelledby]=\"tabId(s, state.mode)\"\n [attr.aria-describedby]=\"sideError() ? quickErrorId : null\"\n >\n @switch (state.mode) {\n @case ('absolute') {\n <input\n hx-input\n fluid\n type=\"text\"\n autocomplete=\"off\"\n class=\"hx-date-range-quick-select-side-date\"\n [attr.aria-label]=\"sideName + ' ' + l.date\"\n [attr.aria-invalid]=\"sideError() ? 'true' : null\"\n [attr.aria-describedby]=\"sideError() ? quickErrorId : null\"\n [value]=\"sideText(s)\"\n (change)=\"setAbsoluteSide(s, $event)\"\n (keydown.enter)=\"$event.preventDefault(); setAbsoluteSide(s, $event)\"\n />\n <p class=\"hx-date-range-quick-select-side-resolved\">\n <span class=\"hx-date-range-quick-select-resolved-date\">{{ sideResolvedText(s) }}</span>\n </p>\n <div class=\"hx-date-range-quick-select-calendar\" role=\"group\" [attr.aria-label]=\"sideName + ' ' + l.date\">\n <hx-calendar\n [(focusedDate)]=\"calendarFocus\"\n [(view)]=\"calendarView\"\n [selectedDates]=\"sideDays(s)\"\n selectionMode=\"single\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n [titleId]=\"calendarTitleId\"\n [today]=\"today()\"\n (picked)=\"pickDay(s, $event)\"\n />\n </div>\n }\n @case ('relative') {\n <div class=\"hx-date-range-quick-select-row\">\n <input\n hx-input\n type=\"number\"\n min=\"0\"\n step=\"1\"\n class=\"hx-date-range-quick-select-side-amount\"\n [attr.aria-label]=\"l.amount\"\n [attr.aria-invalid]=\"sideError() ? 'true' : null\"\n [attr.aria-describedby]=\"sideError() ? quickErrorId : null\"\n [value]=\"state.amount ?? ''\"\n (input)=\"setSideAmount(s, $event)\"\n />\n <hx-select\n class=\"hx-date-range-quick-select-side-unit\"\n [options]=\"relativeOptions()\"\n [ariaLabel]=\"l.unit\"\n [value]=\"sideUnitValue(s)\"\n (valueChange)=\"setSideUnit(s, $event)\"\n />\n </div>\n <label class=\"hx-date-range-quick-select-side-round\">\n <input type=\"checkbox\" hx-checkbox [checked]=\"state.round\" (change)=\"setSideRound(s, $event)\" />\n {{ sideRoundLabel(s) }}\n </label>\n <p class=\"hx-date-range-quick-select-side-resolved\">\n <code class=\"hx-date-range-quick-select-expression\">{{ sideExpressionText(s) }}</code>&ngsp;\n <span class=\"hx-date-range-quick-select-resolved-date\">{{ sideResolvedText(s) }}</span>\n </p>\n }\n @case ('now') {\n <p class=\"hx-date-range-quick-select-now-hint\">{{ l.nowHint }}</p>\n <p class=\"hx-date-range-quick-select-side-resolved\">\n <span class=\"hx-date-range-quick-select-resolved-date\">{{ sideResolvedText(s) }}</span>\n </p>\n }\n }\n </div>\n </section>\n }\n @if (quickError() || sideError()) {\n <p class=\"hx-date-range-quick-select-error\" role=\"alert\" [id]=\"quickErrorId\">{{ l.incompleteRange }}</p>\n }\n </div>\n </ng-template>\n</div>\n",
8158
10145
  dependencies: [
8159
10146
  {
8160
10147
  kind: "directive",
@@ -8203,16 +10190,6 @@ var HxDatePicker = class HxDatePicker {
8203
10190
  selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]",
8204
10191
  exportAs: ["cdkOverlayOrigin"]
8205
10192
  },
8206
- {
8207
- kind: "directive",
8208
- type: NgTemplateOutlet,
8209
- selector: "[ngTemplateOutlet]",
8210
- inputs: [
8211
- "ngTemplateOutletContext",
8212
- "ngTemplateOutlet",
8213
- "ngTemplateOutletInjector"
8214
- ]
8215
- },
8216
10193
  {
8217
10194
  kind: "component",
8218
10195
  type: HxCalendar,
@@ -8236,6 +10213,55 @@ var HxDatePicker = class HxDatePicker {
8236
10213
  "viewChange",
8237
10214
  "picked"
8238
10215
  ]
10216
+ },
10217
+ {
10218
+ kind: "directive",
10219
+ type: HxCheckbox,
10220
+ selector: "input[hx-checkbox]",
10221
+ inputs: ["size"],
10222
+ exportAs: ["hx-checkbox"]
10223
+ },
10224
+ {
10225
+ kind: "directive",
10226
+ type: HxInput,
10227
+ selector: "input[hx-input], textarea[hx-input]",
10228
+ inputs: [
10229
+ "variant",
10230
+ "size",
10231
+ "fluid",
10232
+ "autoResize"
10233
+ ],
10234
+ exportAs: ["hx-input"]
10235
+ },
10236
+ {
10237
+ kind: "component",
10238
+ type: HxSelect,
10239
+ selector: "hx-select",
10240
+ inputs: [
10241
+ "options",
10242
+ "optionLabel",
10243
+ "optionValue",
10244
+ "optionDisabled",
10245
+ "placeholder",
10246
+ "emptyMessage",
10247
+ "filter",
10248
+ "filterPlaceholder",
10249
+ "filterBy",
10250
+ "emptyFilterMessage",
10251
+ "size",
10252
+ "variant",
10253
+ "fluid",
10254
+ "showClear",
10255
+ "inputId",
10256
+ "ariaLabel",
10257
+ "ariaLabelledby",
10258
+ "ariaDescribedby",
10259
+ "compareWith",
10260
+ "value",
10261
+ "disabled",
10262
+ "invalid"
10263
+ ],
10264
+ outputs: ["valueChange", "touch"]
8239
10265
  }
8240
10266
  ],
8241
10267
  changeDetection: i0.ChangeDetectionStrategy.OnPush
@@ -8245,155 +10271,138 @@ i0.ɵɵngDeclareClassMetadata({
8245
10271
  minVersion: "12.0.0",
8246
10272
  version: "22.2.1",
8247
10273
  ngImport: i0,
8248
- type: HxDatePicker,
10274
+ type: HxDateRangeQuickSelect,
8249
10275
  decorators: [{
8250
10276
  type: Component,
8251
10277
  args: [{
8252
- selector: "hx-date-picker",
10278
+ selector: "hx-date-range-quick-select",
8253
10279
  imports: [
8254
10280
  CdkConnectedOverlay,
8255
10281
  CdkOverlayOrigin,
8256
- NgTemplateOutlet,
8257
- HxCalendar
10282
+ HxCalendar,
10283
+ HxCheckbox,
10284
+ HxInput,
10285
+ HxSelect
8258
10286
  ],
8259
10287
  changeDetection: ChangeDetectionStrategy.OnPush,
8260
10288
  providers: [{
8261
10289
  provide: NG_VALUE_ACCESSOR,
8262
- useExisting: forwardRef(() => HxDatePicker),
10290
+ useExisting: forwardRef(() => HxDateRangeQuickSelect),
8263
10291
  multi: true
8264
10292
  }],
8265
10293
  host: {
8266
- class: "hx-date-picker",
8267
- "[class.hx-date-picker-inline]": "inline()",
8268
- "[class.hx-date-picker-disabled]": "isDisabled()",
8269
- "[class.hx-date-picker-invalid]": "invalid()",
8270
- "[class.hx-date-picker-open]": "open()",
8271
- "[class.hx-date-picker-has-icon]": "showIcon() && !inline()",
8272
- "[class.hx-filled]": "!inline() && text() !== \"\"",
10294
+ class: "hx-date-range-quick-select",
8273
10295
  "(focusout)": "onHostFocusOut($event)"
8274
10296
  },
8275
- template: "@if (inline()) {\n <ng-container [ngTemplateOutlet]=\"calendar\" />\n} @else {\n <div class=\"hx-date-picker-field\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n <input\n #field\n type=\"text\"\n class=\"hx-date-picker-input\"\n autocomplete=\"off\"\n aria-haspopup=\"dialog\"\n [attr.id]=\"inputId() ?? null\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"text()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? popupId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (input)=\"onTyping($event)\"\n (change)=\"commitTyping()\"\n (click)=\"show()\"\n (keydown)=\"onFieldKeydown($event)\"\n />\n @if (showIcon()) {\n <button\n type=\"button\"\n class=\"hx-date-picker-trigger\"\n aria-haspopup=\"dialog\"\n [attr.aria-label]=\"chooseLabel()\"\n [attr.aria-expanded]=\"open()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n >\n <span class=\"hx-date-picker-trigger-icon\" aria-hidden=\"true\"></span>\n </button>\n }\n </div>\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayPanelClass=\"hx-date-picker-overlay\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"open.set(false)\"\n >\n <div\n class=\"hx-date-picker-popup\"\n role=\"dialog\"\n aria-modal=\"false\"\n [id]=\"popupId\"\n [attr.aria-label]=\"ariaLabel() ?? 'Choose date'\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n >\n <ng-container [ngTemplateOutlet]=\"calendar\" />\n @if (showButtonBar()) {\n <div class=\"hx-date-picker-buttonbar\">\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"selectToday()\">{{ todayLabel() }}</button>\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"clear()\">{{ clearLabel() }}</button>\n </div>\n }\n </div>\n </ng-template>\n}\n\n<ng-template #calendar>\n<div\n class=\"hx-date-picker-panel\"\n role=\"group\"\n [attr.aria-label]=\"ariaLabel() ?? 'Calendar'\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (focusout)=\"onFocusOut($event)\"\n>\n <hx-calendar\n [(focusedDate)]=\"focusedDate\"\n [(view)]=\"view\"\n [selectedDates]=\"selectedDates()\"\n [selectionMode]=\"selectionMode()\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [disabledDates]=\"disabledDates()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n [titleId]=\"titleId\"\n [today]=\"today\"\n (picked)=\"pick($event)\"\n />\n</div>\n</ng-template>\n"
10297
+ template: "<div\n class=\"hx-date-picker hx-date-picker-has-icon hx-date-range-quick-select-control\"\n [class.hx-date-picker-open]=\"open()\"\n [class.hx-date-picker-disabled]=\"isDisabled()\"\n [class.hx-date-picker-invalid]=\"invalid()\"\n>\n <div class=\"hx-date-picker-field\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n <input\n #field\n type=\"text\"\n readonly\n class=\"hx-date-picker-input\"\n autocomplete=\"off\"\n aria-haspopup=\"dialog\"\n [attr.id]=\"inputId() ?? null\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"text()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? popupId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (click)=\"show()\"\n (keydown)=\"onFieldKeydown($event)\"\n />\n <button\n type=\"button\"\n class=\"hx-date-picker-trigger\"\n aria-haspopup=\"dialog\"\n [attr.aria-label]=\"chooseLabel()\"\n [attr.aria-expanded]=\"open()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n >\n <span class=\"hx-date-picker-trigger-icon\" aria-hidden=\"true\"></span>\n </button>\n </div>\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayPanelClass=\"hx-date-picker-overlay\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"close()\"\n >\n @let l = texts();\n <div\n class=\"hx-date-picker-popup hx-date-range-quick-select-popup\"\n role=\"dialog\"\n aria-modal=\"false\"\n [id]=\"popupId\"\n [attr.aria-label]=\"ariaLabel() ?? chooseLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (focusout)=\"onPopupFocusOut($event)\"\n >\n <section class=\"hx-date-range-quick-select-section\" [attr.aria-labelledby]=\"popupId + '-quick'\">\n <span class=\"hx-date-range-quick-select-caption\" [id]=\"popupId + '-quick'\">{{ l.quickSelect }}</span>\n <div class=\"hx-date-range-quick-select-row\">\n <hx-select\n #quickFirst\n class=\"hx-date-range-quick-select-direction\"\n [options]=\"directionOptions()\"\n [ariaLabel]=\"l.direction\"\n [value]=\"quickDirection()\"\n (valueChange)=\"setQuickDirection($event)\"\n />\n <input\n hx-input\n type=\"number\"\n min=\"1\"\n step=\"1\"\n class=\"hx-date-range-quick-select-amount\"\n [attr.aria-label]=\"l.amount\"\n [attr.aria-invalid]=\"quickError() ? 'true' : null\"\n [attr.aria-describedby]=\"quickError() ? quickErrorId : null\"\n [value]=\"quickAmount()\"\n (input)=\"setQuickAmount($event)\"\n (keydown.enter)=\"$event.preventDefault(); applyQuick()\"\n />\n <hx-select\n class=\"hx-date-range-quick-select-unit\"\n [options]=\"unitOptions()\"\n [ariaLabel]=\"l.unit\"\n [value]=\"quickUnit()\"\n (valueChange)=\"setQuickUnit($event)\"\n />\n <button\n type=\"button\"\n class=\"hx-date-picker-button hx-date-range-quick-select-apply\"\n [attr.aria-describedby]=\"quickError() ? quickErrorId : null\"\n (click)=\"applyQuick()\"\n >\n {{ l.apply }}\n </button>\n </div>\n </section>\n @if (commonlyUsed().length > 0) {\n <section class=\"hx-date-range-quick-select-section\" [attr.aria-labelledby]=\"popupId + '-common'\">\n <span class=\"hx-date-range-quick-select-caption\" [id]=\"popupId + '-common'\">{{ l.commonlyUsed }}</span>\n <ul class=\"hx-date-range-quick-select-ranges hx-date-range-quick-select-common\">\n @for (range of commonlyUsed(); track $index) {\n <li>\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"applyRange(range)\">{{ range.label }}</button>\n </li>\n }\n </ul>\n </section>\n }\n @if (recentItems().length > 0) {\n <section class=\"hx-date-range-quick-select-section\" [attr.aria-labelledby]=\"popupId + '-recent'\">\n <span class=\"hx-date-range-quick-select-caption\" [id]=\"popupId + '-recent'\">{{ l.recentlyUsed }}</span>\n <ul class=\"hx-date-range-quick-select-ranges hx-date-range-quick-select-recent\">\n @for (item of recentItems(); track item.range.from + ' ' + item.range.to) {\n <li>\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"applyRange(item.range)\">{{ item.label }}</button>\n </li>\n }\n </ul>\n </section>\n }\n <!-- one line per side; a click opens the editor of that side (Absolute / Relative / Now) below -->\n <div class=\"hx-date-range-quick-select-summary\" role=\"group\" [attr.aria-label]=\"l.range\">\n @for (s of sideKeys; track s) {\n <button\n #sideButton\n type=\"button\"\n class=\"hx-date-range-quick-select-side-line\"\n [class]=\"'hx-date-range-quick-select-side-line-' + s\"\n [id]=\"sideButtonId(s)\"\n [attr.aria-expanded]=\"openSide() === s\"\n [attr.aria-controls]=\"openSide() === s ? editorId(s) : null\"\n (click)=\"toggleSide(s)\"\n >\n <span class=\"hx-date-range-quick-select-side-name\">{{ s === 'from' ? l.start : l.end }}</span>&ngsp;\n <span class=\"hx-date-range-quick-select-side-value\">{{ sideSummary(s) }}</span>\n </button>\n }\n </div>\n @if (openSide(); as s) {\n @let state = sides()[s];\n @let sideName = s === 'from' ? l.start : l.end;\n <section\n class=\"hx-date-range-quick-select-editor\"\n [class]=\"'hx-date-range-quick-select-editor-' + s\"\n [id]=\"editorId(s)\"\n [attr.aria-labelledby]=\"sideButtonId(s)\"\n >\n <div\n class=\"hx-date-range-quick-select-tabs\"\n role=\"tablist\"\n [attr.aria-labelledby]=\"sideButtonId(s)\"\n (keydown)=\"onTabKeydown(s, $event)\"\n >\n @for (mode of sideModes; track mode) {\n <button\n #sideTab\n type=\"button\"\n role=\"tab\"\n class=\"hx-date-range-quick-select-tab\"\n [id]=\"tabId(s, mode)\"\n [attr.aria-selected]=\"state.mode === mode\"\n [attr.aria-controls]=\"panelId(s)\"\n [attr.tabindex]=\"state.mode === mode ? 0 : -1\"\n (click)=\"setSideMode(s, mode)\"\n >\n {{ mode === 'absolute' ? l.absolute : mode === 'relative' ? l.relative : l.now }}\n </button>\n }\n </div>\n <div\n class=\"hx-date-range-quick-select-tabpanel\"\n role=\"tabpanel\"\n tabindex=\"0\"\n [id]=\"panelId(s)\"\n [attr.aria-labelledby]=\"tabId(s, state.mode)\"\n [attr.aria-describedby]=\"sideError() ? quickErrorId : null\"\n >\n @switch (state.mode) {\n @case ('absolute') {\n <input\n hx-input\n fluid\n type=\"text\"\n autocomplete=\"off\"\n class=\"hx-date-range-quick-select-side-date\"\n [attr.aria-label]=\"sideName + ' ' + l.date\"\n [attr.aria-invalid]=\"sideError() ? 'true' : null\"\n [attr.aria-describedby]=\"sideError() ? quickErrorId : null\"\n [value]=\"sideText(s)\"\n (change)=\"setAbsoluteSide(s, $event)\"\n (keydown.enter)=\"$event.preventDefault(); setAbsoluteSide(s, $event)\"\n />\n <p class=\"hx-date-range-quick-select-side-resolved\">\n <span class=\"hx-date-range-quick-select-resolved-date\">{{ sideResolvedText(s) }}</span>\n </p>\n <div class=\"hx-date-range-quick-select-calendar\" role=\"group\" [attr.aria-label]=\"sideName + ' ' + l.date\">\n <hx-calendar\n [(focusedDate)]=\"calendarFocus\"\n [(view)]=\"calendarView\"\n [selectedDates]=\"sideDays(s)\"\n selectionMode=\"single\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n [titleId]=\"calendarTitleId\"\n [today]=\"today()\"\n (picked)=\"pickDay(s, $event)\"\n />\n </div>\n }\n @case ('relative') {\n <div class=\"hx-date-range-quick-select-row\">\n <input\n hx-input\n type=\"number\"\n min=\"0\"\n step=\"1\"\n class=\"hx-date-range-quick-select-side-amount\"\n [attr.aria-label]=\"l.amount\"\n [attr.aria-invalid]=\"sideError() ? 'true' : null\"\n [attr.aria-describedby]=\"sideError() ? quickErrorId : null\"\n [value]=\"state.amount ?? ''\"\n (input)=\"setSideAmount(s, $event)\"\n />\n <hx-select\n class=\"hx-date-range-quick-select-side-unit\"\n [options]=\"relativeOptions()\"\n [ariaLabel]=\"l.unit\"\n [value]=\"sideUnitValue(s)\"\n (valueChange)=\"setSideUnit(s, $event)\"\n />\n </div>\n <label class=\"hx-date-range-quick-select-side-round\">\n <input type=\"checkbox\" hx-checkbox [checked]=\"state.round\" (change)=\"setSideRound(s, $event)\" />\n {{ sideRoundLabel(s) }}\n </label>\n <p class=\"hx-date-range-quick-select-side-resolved\">\n <code class=\"hx-date-range-quick-select-expression\">{{ sideExpressionText(s) }}</code>&ngsp;\n <span class=\"hx-date-range-quick-select-resolved-date\">{{ sideResolvedText(s) }}</span>\n </p>\n }\n @case ('now') {\n <p class=\"hx-date-range-quick-select-now-hint\">{{ l.nowHint }}</p>\n <p class=\"hx-date-range-quick-select-side-resolved\">\n <span class=\"hx-date-range-quick-select-resolved-date\">{{ sideResolvedText(s) }}</span>\n </p>\n }\n }\n </div>\n </section>\n }\n @if (quickError() || sideError()) {\n <p class=\"hx-date-range-quick-select-error\" role=\"alert\" [id]=\"quickErrorId\">{{ l.incompleteRange }}</p>\n }\n </div>\n </ng-template>\n</div>\n"
8276
10298
  }]
8277
10299
  }],
8278
10300
  ctorParameters: () => [],
8279
10301
  propDecorators: {
8280
- placeholder: [{
8281
- type: i0.Input,
8282
- args: [{
8283
- isSignal: true,
8284
- alias: "placeholder",
8285
- required: false
8286
- }]
8287
- }],
8288
- showIcon: [{
8289
- type: i0.Input,
8290
- args: [{
8291
- isSignal: true,
8292
- alias: "showIcon",
8293
- required: false
8294
- }]
8295
- }],
8296
- showButtonBar: [{
10302
+ labels: [{
8297
10303
  type: i0.Input,
8298
10304
  args: [{
8299
10305
  isSignal: true,
8300
- alias: "showButtonBar",
10306
+ alias: "labels",
8301
10307
  required: false
8302
10308
  }]
8303
10309
  }],
8304
- dateFormat: [{
10310
+ commonlyUsed: [{
8305
10311
  type: i0.Input,
8306
10312
  args: [{
8307
10313
  isSignal: true,
8308
- alias: "dateFormat",
10314
+ alias: "commonlyUsed",
8309
10315
  required: false
8310
10316
  }]
8311
10317
  }],
8312
- todayLabel: [{
10318
+ recentStorageKey: [{
8313
10319
  type: i0.Input,
8314
10320
  args: [{
8315
10321
  isSignal: true,
8316
- alias: "todayLabel",
10322
+ alias: "recentStorageKey",
8317
10323
  required: false
8318
10324
  }]
8319
10325
  }],
8320
- clearLabel: [{
10326
+ expression: [{
8321
10327
  type: i0.Input,
8322
10328
  args: [{
8323
10329
  isSignal: true,
8324
- alias: "clearLabel",
10330
+ alias: "expression",
8325
10331
  required: false
8326
10332
  }]
10333
+ }, {
10334
+ type: i0.Output,
10335
+ args: ["expressionChange"]
8327
10336
  }],
8328
- chooseLabel: [{
10337
+ minDate: [{
8329
10338
  type: i0.Input,
8330
10339
  args: [{
8331
10340
  isSignal: true,
8332
- alias: "chooseLabel",
10341
+ alias: "minDate",
8333
10342
  required: false
8334
10343
  }]
8335
10344
  }],
8336
- inputId: [{
10345
+ maxDate: [{
8337
10346
  type: i0.Input,
8338
10347
  args: [{
8339
10348
  isSignal: true,
8340
- alias: "inputId",
10349
+ alias: "maxDate",
8341
10350
  required: false
8342
10351
  }]
8343
10352
  }],
8344
- inline: [{
10353
+ firstDayOfWeek: [{
8345
10354
  type: i0.Input,
8346
10355
  args: [{
8347
10356
  isSignal: true,
8348
- alias: "inline",
10357
+ alias: "firstDayOfWeek",
8349
10358
  required: false
8350
10359
  }]
8351
10360
  }],
8352
- selectionMode: [{
10361
+ locale: [{
8353
10362
  type: i0.Input,
8354
10363
  args: [{
8355
10364
  isSignal: true,
8356
- alias: "selectionMode",
10365
+ alias: "locale",
8357
10366
  required: false
8358
10367
  }]
8359
10368
  }],
8360
- minDate: [{
10369
+ dateFormat: [{
8361
10370
  type: i0.Input,
8362
10371
  args: [{
8363
10372
  isSignal: true,
8364
- alias: "minDate",
10373
+ alias: "dateFormat",
8365
10374
  required: false
8366
10375
  }]
8367
10376
  }],
8368
- maxDate: [{
10377
+ separator: [{
8369
10378
  type: i0.Input,
8370
10379
  args: [{
8371
10380
  isSignal: true,
8372
- alias: "maxDate",
10381
+ alias: "separator",
8373
10382
  required: false
8374
10383
  }]
8375
10384
  }],
8376
- disabledDates: [{
10385
+ placeholder: [{
8377
10386
  type: i0.Input,
8378
10387
  args: [{
8379
10388
  isSignal: true,
8380
- alias: "disabledDates",
10389
+ alias: "placeholder",
8381
10390
  required: false
8382
10391
  }]
8383
10392
  }],
8384
- firstDayOfWeek: [{
10393
+ chooseLabel: [{
8385
10394
  type: i0.Input,
8386
10395
  args: [{
8387
10396
  isSignal: true,
8388
- alias: "firstDayOfWeek",
10397
+ alias: "chooseLabel",
8389
10398
  required: false
8390
10399
  }]
8391
10400
  }],
8392
- locale: [{
10401
+ inputId: [{
8393
10402
  type: i0.Input,
8394
10403
  args: [{
8395
10404
  isSignal: true,
8396
- alias: "locale",
10405
+ alias: "inputId",
8397
10406
  required: false
8398
10407
  }]
8399
10408
  }],
@@ -8448,9 +10457,20 @@ i0.ɵɵngDeclareClassMetadata({
8448
10457
  type: i0.ViewChild,
8449
10458
  args: ["field", { isSignal: true }]
8450
10459
  }],
8451
- calendar: [{
10460
+ quickFirst: [{
8452
10461
  type: i0.ViewChild,
8453
- args: [i0.forwardRef(() => HxCalendar), { isSignal: true }]
10462
+ args: ["quickFirst", {
10463
+ read: HxSelect,
10464
+ isSignal: true
10465
+ }]
10466
+ }],
10467
+ sideButtons: [{
10468
+ type: i0.ViewChildren,
10469
+ args: ["sideButton", { isSignal: true }]
10470
+ }],
10471
+ sideTabs: [{
10472
+ type: i0.ViewChildren,
10473
+ args: ["sideTab", { isSignal: true }]
8454
10474
  }]
8455
10475
  }
8456
10476
  });
@@ -10672,6 +12692,7 @@ var HxDateTimeRangePicker = class HxDateTimeRangePicker {
10672
12692
  placeholder = input("", ...ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []);
10673
12693
  presetsLabel = input("Presets", ...ngDevMode ? [{ debugName: "presetsLabel" }] : /* istanbul ignore next */ []);
10674
12694
  presets = input([], ...ngDevMode ? [{ debugName: "presets" }] : /* istanbul ignore next */ []);
12695
+ presetDisplay = input("buttons", ...ngDevMode ? [{ debugName: "presetDisplay" }] : /* istanbul ignore next */ []);
10675
12696
  clearLabel = input("Clear", ...ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []);
10676
12697
  cancelLabel = input("Cancel", ...ngDevMode ? [{ debugName: "cancelLabel" }] : /* istanbul ignore next */ []);
10677
12698
  submitLabel = input("Submit", ...ngDevMode ? [{ debugName: "submitLabel" }] : /* istanbul ignore next */ []);
@@ -10739,6 +12760,7 @@ var HxDateTimeRangePicker = class HxDateTimeRangePicker {
10739
12760
  #injector = inject(Injector);
10740
12761
  open = signal(false, ...ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []);
10741
12762
  draft = signal(EMPTY, ...ngDevMode ? [{ debugName: "draft" }] : /* istanbul ignore next */ []);
12763
+ selectedPreset = signal(null, ...ngDevMode ? [{ debugName: "selectedPreset" }] : /* istanbul ignore next */ []);
10742
12764
  popupId = nextId("hx-date-time-range-picker-popup");
10743
12765
  positions = [{
10744
12766
  originX: "start",
@@ -10781,8 +12803,7 @@ var HxDateTimeRangePicker = class HxDateTimeRangePicker {
10781
12803
  if (typed !== null) return typed;
10782
12804
  const { from, to } = this.value();
10783
12805
  if (!from && !to) return "";
10784
- const fmt = this.#format();
10785
- const one = (d) => d ? fmt.format(d).replace(/,\s*/, " ") : "";
12806
+ const one = (d) => d ? this.#formatDate(d) : "";
10786
12807
  return `${one(from)} ${this.separator()} ${one(to)}`.trim();
10787
12808
  }, ...ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []);
10788
12809
  isDisabled = computed(() => this.disabled() || this.#cvaDisabled(), ...ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []);
@@ -10820,6 +12841,7 @@ var HxDateTimeRangePicker = class HxDateTimeRangePicker {
10820
12841
  show() {
10821
12842
  if (this.isDisabled() || this.open()) return;
10822
12843
  this.#stage(this.value());
12844
+ this.selectedPreset.set(null);
10823
12845
  this.open.set(true);
10824
12846
  }
10825
12847
  toggle() {
@@ -10911,23 +12933,24 @@ var HxDateTimeRangePicker = class HxDateTimeRangePicker {
10911
12933
  }
10912
12934
  }
10913
12935
  onOutsideClick(event) {
12936
+ if (this.#inSelectList(event.target)) return;
10914
12937
  if (!this.#host.nativeElement.contains(event.target)) this.close();
10915
12938
  }
10916
12939
  clear() {
10917
12940
  this.#stage(EMPTY);
10918
12941
  }
12942
+ selectPreset(preset) {
12943
+ if (this.applyPreset(preset)) this.selectedPreset.set(preset);
12944
+ }
12945
+ #inSelectList(target) {
12946
+ return isInSelectOverlay(target);
12947
+ }
10919
12948
  applyPreset(preset) {
10920
12949
  const { from: oldFrom, to: oldTo } = this.draft();
10921
- const from = this.#fitPreset(preset.from(), oldFrom);
10922
- const to = this.#fitPreset(preset.to(), oldTo ?? oldFrom);
10923
- if (from === void 0 || to === void 0) return;
10924
- this.#stage(from && to && to < from ? {
10925
- from: to,
10926
- to: from
10927
- } : {
10928
- from,
10929
- to
10930
- });
12950
+ const range = hxResolvePreset(preset, { firstDayOfWeek: this.firstDayOfWeek() }, (date, side) => this.#fitPreset(date, side === "from" ? oldFrom : oldTo ?? oldFrom));
12951
+ if (!range) return false;
12952
+ this.#stage(range);
12953
+ return true;
10931
12954
  }
10932
12955
  #fitPreset(date, old) {
10933
12956
  if (!isValidDate(date)) return null;
@@ -10941,16 +12964,19 @@ var HxDateTimeRangePicker = class HxDateTimeRangePicker {
10941
12964
  this.#commit(this.draft());
10942
12965
  this.close(true);
10943
12966
  }
12967
+ #formatDate(date) {
12968
+ return this.#format().format(date).replace(/,\s*/, " ");
12969
+ }
10944
12970
  onHostFocusOut(event) {
10945
12971
  const next = event.relatedTarget;
10946
- if (next?.closest(".hx-date-time-range-picker-popup") || this.#host.nativeElement.contains(next)) return;
12972
+ if (this.#inSelectList(next) || next?.closest(".hx-date-time-range-picker-popup") || this.#host.nativeElement.contains(next)) return;
10947
12973
  if (this.open() && !next) return;
10948
12974
  this.close();
10949
12975
  this.markTouched();
10950
12976
  }
10951
12977
  onPopupFocusOut(event) {
10952
12978
  const next = event.relatedTarget;
10953
- if (!next || next.closest(".hx-date-time-range-picker-popup") || this.#host.nativeElement.contains(next)) return;
12979
+ if (!next || this.#inSelectList(next) || next.closest(".hx-date-time-range-picker-popup") || this.#host.nativeElement.contains(next)) return;
10954
12980
  this.close();
10955
12981
  this.markTouched();
10956
12982
  }
@@ -11022,14 +13048,18 @@ var HxDateTimeRangePicker = class HxDateTimeRangePicker {
11022
13048
  this.touch.emit();
11023
13049
  }
11024
13050
  #stage(next) {
13051
+ const clean = this.#inside(next);
13052
+ this.selectedPreset.set(null);
13053
+ if (clean.from) this.#lastFrom = clean.from;
13054
+ if (clean.to) this.#lastTo = clean.to;
13055
+ this.draft.set(clean);
13056
+ }
13057
+ #inside(next) {
11025
13058
  const inside = (d) => isValidDate(d) ? clampTime(d, this.minDate(), this.maxDate()) : null;
11026
- const clean = {
13059
+ return {
11027
13060
  from: inside(next.from),
11028
13061
  to: inside(next.to)
11029
13062
  };
11030
- if (clean.from) this.#lastFrom = clean.from;
11031
- if (clean.to) this.#lastTo = clean.to;
11032
- this.draft.set(clean);
11033
13063
  }
11034
13064
  #commit(next) {
11035
13065
  this.value.set(next);
@@ -11092,6 +13122,13 @@ var HxDateTimeRangePicker = class HxDateTimeRangePicker {
11092
13122
  isRequired: false,
11093
13123
  transformFunction: null
11094
13124
  },
13125
+ presetDisplay: {
13126
+ classPropertyName: "presetDisplay",
13127
+ publicName: "presetDisplay",
13128
+ isSignal: true,
13129
+ isRequired: false,
13130
+ transformFunction: null
13131
+ },
11095
13132
  clearLabel: {
11096
13133
  classPropertyName: "clearLabel",
11097
13134
  publicName: "clearLabel",
@@ -11312,7 +13349,7 @@ var HxDateTimeRangePicker = class HxDateTimeRangePicker {
11312
13349
  }
11313
13350
  ],
11314
13351
  ngImport: i0,
11315
- template: "<div\n class=\"hx-date-picker hx-date-picker-has-icon hx-date-time-range-picker-control\"\n [class.hx-date-picker-open]=\"open()\"\n [class.hx-date-picker-disabled]=\"isDisabled()\"\n [class.hx-date-picker-invalid]=\"invalid()\"\n>\n <div class=\"hx-date-picker-field\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n <input\n #field\n type=\"text\"\n [readOnly]=\"!typeable()\"\n class=\"hx-date-picker-input\"\n autocomplete=\"off\"\n aria-haspopup=\"dialog\"\n [attr.id]=\"inputId() ?? null\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"text()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? popupId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (input)=\"onTyping($event)\"\n (change)=\"commitTyping()\"\n (click)=\"onFieldClick()\"\n (keydown)=\"onFieldKeydown($event)\"\n />\n <button\n type=\"button\"\n class=\"hx-date-picker-trigger\"\n aria-haspopup=\"dialog\"\n [attr.aria-label]=\"chooseLabel()\"\n [attr.aria-expanded]=\"open()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n >\n <span class=\"hx-date-picker-trigger-icon\" aria-hidden=\"true\"></span>\n </button>\n </div>\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayPanelClass=\"hx-date-picker-overlay\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"open.set(false)\"\n >\n <div\n class=\"hx-date-picker-popup hx-date-time-range-picker-popup\"\n role=\"dialog\"\n aria-modal=\"false\"\n [id]=\"popupId\"\n [attr.aria-label]=\"ariaLabel() ?? chooseLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (focusout)=\"onPopupFocusOut($event)\"\n >\n @if (presets().length > 0) {\n <div class=\"hx-date-time-range-picker-presets\" role=\"group\" [attr.aria-label]=\"presetsLabel()\">\n @for (preset of presets(); track $index) {\n <button type=\"button\" class=\"hx-date-picker-button hx-date-time-range-picker-preset\" (click)=\"applyPreset(preset)\">{{ preset.label }}</button>\n }\n </div>\n }\n <div class=\"hx-date-time-range-picker-body\">\n @if (!timeOnly()) {\n <hx-date-picker\n class=\"hx-date-time-range-picker-days\"\n inline\n selectionMode=\"range\"\n [ariaLabel]=\"chooseLabel()\"\n [value]=\"days()\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [locale]=\"locale()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n [disabledDates]=\"disabledDates()\"\n (valueChange)=\"setDays($event)\"\n />\n }\n @if (showTime() || timeOnly()) {\n <div class=\"hx-date-time-range-picker-times\">\n <div class=\"hx-date-time-range-picker-time\">\n <span class=\"hx-date-time-range-picker-caption\" aria-hidden=\"true\">{{ fromLabel() }}</span>\n <hx-time-picker\n inline\n class=\"hx-date-time-range-picker-from\"\n [ariaLabel]=\"fromLabel()\"\n [value]=\"fromValue()\"\n [hourFormat]=\"hourFormat()\"\n [showMinutes]=\"showMinutes()\"\n [showSeconds]=\"showSeconds()\"\n [stepHour]=\"stepHour()\"\n [stepMinute]=\"stepMinute()\"\n [stepSecond]=\"stepSecond()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n (valueChange)=\"setFromTime($event)\"\n />\n </div>\n <div class=\"hx-date-time-range-picker-time\">\n <span class=\"hx-date-time-range-picker-caption\" aria-hidden=\"true\">{{ toLabel() }}</span>\n <hx-time-picker\n inline\n class=\"hx-date-time-range-picker-to\"\n [ariaLabel]=\"toLabel()\"\n [value]=\"toValue()\"\n [hourFormat]=\"hourFormat()\"\n [showMinutes]=\"showMinutes()\"\n [showSeconds]=\"showSeconds()\"\n [stepHour]=\"stepHour()\"\n [stepMinute]=\"stepMinute()\"\n [stepSecond]=\"stepSecond()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n (valueChange)=\"setToTime($event)\"\n />\n </div>\n </div>\n }\n </div>\n <div class=\"hx-date-picker-buttonbar hx-date-time-range-picker-footer\">\n @if (showButtonBar()) {\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"clear()\">{{ clearLabel() }}</button>\n }\n <span class=\"hx-date-time-range-picker-spacer\"></span>\n <button type=\"button\" class=\"hx-date-picker-button hx-date-time-range-picker-cancel\" (click)=\"close(true)\">{{ cancelLabel() }}</button>\n <button type=\"button\" class=\"hx-date-picker-button hx-date-time-range-picker-submit\" (click)=\"submit()\">{{ submitLabel() }}</button>\n </div>\n </div>\n </ng-template>\n</div>\n",
13352
+ template: "<div\n class=\"hx-date-picker hx-date-picker-has-icon hx-date-time-range-picker-control\"\n [class.hx-date-picker-open]=\"open()\"\n [class.hx-date-picker-disabled]=\"isDisabled()\"\n [class.hx-date-picker-invalid]=\"invalid()\"\n>\n <div class=\"hx-date-picker-field\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n <input\n #field\n type=\"text\"\n [readOnly]=\"!typeable()\"\n class=\"hx-date-picker-input\"\n autocomplete=\"off\"\n aria-haspopup=\"dialog\"\n [attr.id]=\"inputId() ?? null\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"text()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? popupId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (input)=\"onTyping($event)\"\n (change)=\"commitTyping()\"\n (click)=\"onFieldClick()\"\n (keydown)=\"onFieldKeydown($event)\"\n />\n <button\n type=\"button\"\n class=\"hx-date-picker-trigger\"\n aria-haspopup=\"dialog\"\n [attr.aria-label]=\"chooseLabel()\"\n [attr.aria-expanded]=\"open()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n >\n <span class=\"hx-date-picker-trigger-icon\" aria-hidden=\"true\"></span>\n </button>\n </div>\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayPanelClass=\"hx-date-picker-overlay\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"open.set(false)\"\n >\n <div\n class=\"hx-date-picker-popup hx-date-time-range-picker-popup\"\n role=\"dialog\"\n aria-modal=\"false\"\n [id]=\"popupId\"\n [attr.aria-label]=\"ariaLabel() ?? chooseLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (focusout)=\"onPopupFocusOut($event)\"\n >\n @if (presets().length > 0) {\n <hx-range-presets\n [presets]=\"presets()\"\n [display]=\"presetDisplay()\"\n [label]=\"presetsLabel()\"\n [disabled]=\"isDisabled()\"\n [selected]=\"selectedPreset()\"\n (chosen)=\"selectPreset($event)\"\n />\n }\n <div class=\"hx-date-time-range-picker-body\">\n @if (!timeOnly()) {\n <hx-date-picker\n class=\"hx-date-time-range-picker-days\"\n inline\n selectionMode=\"range\"\n [ariaLabel]=\"chooseLabel()\"\n [value]=\"days()\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [locale]=\"locale()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n [disabledDates]=\"disabledDates()\"\n (valueChange)=\"setDays($event)\"\n />\n }\n @if (showTime() || timeOnly()) {\n <div class=\"hx-date-time-range-picker-times\">\n <div class=\"hx-date-time-range-picker-time\">\n <span class=\"hx-date-time-range-picker-caption\" aria-hidden=\"true\">{{ fromLabel() }}</span>\n <hx-time-picker\n inline\n class=\"hx-date-time-range-picker-from\"\n [ariaLabel]=\"fromLabel()\"\n [value]=\"fromValue()\"\n [hourFormat]=\"hourFormat()\"\n [showMinutes]=\"showMinutes()\"\n [showSeconds]=\"showSeconds()\"\n [stepHour]=\"stepHour()\"\n [stepMinute]=\"stepMinute()\"\n [stepSecond]=\"stepSecond()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n (valueChange)=\"setFromTime($event)\"\n />\n </div>\n <div class=\"hx-date-time-range-picker-time\">\n <span class=\"hx-date-time-range-picker-caption\" aria-hidden=\"true\">{{ toLabel() }}</span>\n <hx-time-picker\n inline\n class=\"hx-date-time-range-picker-to\"\n [ariaLabel]=\"toLabel()\"\n [value]=\"toValue()\"\n [hourFormat]=\"hourFormat()\"\n [showMinutes]=\"showMinutes()\"\n [showSeconds]=\"showSeconds()\"\n [stepHour]=\"stepHour()\"\n [stepMinute]=\"stepMinute()\"\n [stepSecond]=\"stepSecond()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n (valueChange)=\"setToTime($event)\"\n />\n </div>\n </div>\n }\n </div>\n <div class=\"hx-date-picker-buttonbar hx-date-time-range-picker-footer\">\n @if (showButtonBar()) {\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"clear()\">{{ clearLabel() }}</button>\n }\n <span class=\"hx-date-time-range-picker-spacer\"></span>\n <button type=\"button\" class=\"hx-date-picker-button hx-date-time-range-picker-cancel\" (click)=\"close(true)\">{{ cancelLabel() }}</button>\n <button\n type=\"button\"\n class=\"hx-date-picker-button hx-date-time-range-picker-submit\"\n (click)=\"submit()\"\n >{{ submitLabel() }}</button>\n </div>\n </div>\n </ng-template>\n</div>\n",
11316
13353
  dependencies: [
11317
13354
  {
11318
13355
  kind: "directive",
@@ -11383,12 +13420,30 @@ var HxDateTimeRangePicker = class HxDateTimeRangePicker {
11383
13420
  "locale",
11384
13421
  "ariaLabel",
11385
13422
  "ariaLabelledby",
13423
+ "presets",
13424
+ "presetDisplay",
13425
+ "presetsLabel",
13426
+ "presetRefusedLabel",
11386
13427
  "value",
11387
13428
  "disabled",
11388
13429
  "invalid"
11389
13430
  ],
11390
13431
  outputs: ["valueChange", "touch"]
11391
13432
  },
13433
+ {
13434
+ kind: "component",
13435
+ type: HxRangePresets,
13436
+ selector: "hx-range-presets",
13437
+ inputs: [
13438
+ "presets",
13439
+ "display",
13440
+ "label",
13441
+ "disabled",
13442
+ "selected",
13443
+ "describedBy"
13444
+ ],
13445
+ outputs: ["chosen"]
13446
+ },
11392
13447
  {
11393
13448
  kind: "component",
11394
13449
  type: HxTimePicker,
@@ -11442,6 +13497,7 @@ i0.ɵɵngDeclareClassMetadata({
11442
13497
  CdkConnectedOverlay,
11443
13498
  CdkOverlayOrigin,
11444
13499
  HxDatePicker,
13500
+ HxRangePresets,
11445
13501
  HxTimePicker
11446
13502
  ],
11447
13503
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -11454,7 +13510,7 @@ i0.ɵɵngDeclareClassMetadata({
11454
13510
  class: "hx-date-time-range-picker",
11455
13511
  "(focusout)": "onHostFocusOut($event)"
11456
13512
  },
11457
- template: "<div\n class=\"hx-date-picker hx-date-picker-has-icon hx-date-time-range-picker-control\"\n [class.hx-date-picker-open]=\"open()\"\n [class.hx-date-picker-disabled]=\"isDisabled()\"\n [class.hx-date-picker-invalid]=\"invalid()\"\n>\n <div class=\"hx-date-picker-field\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n <input\n #field\n type=\"text\"\n [readOnly]=\"!typeable()\"\n class=\"hx-date-picker-input\"\n autocomplete=\"off\"\n aria-haspopup=\"dialog\"\n [attr.id]=\"inputId() ?? null\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"text()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? popupId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (input)=\"onTyping($event)\"\n (change)=\"commitTyping()\"\n (click)=\"onFieldClick()\"\n (keydown)=\"onFieldKeydown($event)\"\n />\n <button\n type=\"button\"\n class=\"hx-date-picker-trigger\"\n aria-haspopup=\"dialog\"\n [attr.aria-label]=\"chooseLabel()\"\n [attr.aria-expanded]=\"open()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n >\n <span class=\"hx-date-picker-trigger-icon\" aria-hidden=\"true\"></span>\n </button>\n </div>\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayPanelClass=\"hx-date-picker-overlay\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"open.set(false)\"\n >\n <div\n class=\"hx-date-picker-popup hx-date-time-range-picker-popup\"\n role=\"dialog\"\n aria-modal=\"false\"\n [id]=\"popupId\"\n [attr.aria-label]=\"ariaLabel() ?? chooseLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (focusout)=\"onPopupFocusOut($event)\"\n >\n @if (presets().length > 0) {\n <div class=\"hx-date-time-range-picker-presets\" role=\"group\" [attr.aria-label]=\"presetsLabel()\">\n @for (preset of presets(); track $index) {\n <button type=\"button\" class=\"hx-date-picker-button hx-date-time-range-picker-preset\" (click)=\"applyPreset(preset)\">{{ preset.label }}</button>\n }\n </div>\n }\n <div class=\"hx-date-time-range-picker-body\">\n @if (!timeOnly()) {\n <hx-date-picker\n class=\"hx-date-time-range-picker-days\"\n inline\n selectionMode=\"range\"\n [ariaLabel]=\"chooseLabel()\"\n [value]=\"days()\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [locale]=\"locale()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n [disabledDates]=\"disabledDates()\"\n (valueChange)=\"setDays($event)\"\n />\n }\n @if (showTime() || timeOnly()) {\n <div class=\"hx-date-time-range-picker-times\">\n <div class=\"hx-date-time-range-picker-time\">\n <span class=\"hx-date-time-range-picker-caption\" aria-hidden=\"true\">{{ fromLabel() }}</span>\n <hx-time-picker\n inline\n class=\"hx-date-time-range-picker-from\"\n [ariaLabel]=\"fromLabel()\"\n [value]=\"fromValue()\"\n [hourFormat]=\"hourFormat()\"\n [showMinutes]=\"showMinutes()\"\n [showSeconds]=\"showSeconds()\"\n [stepHour]=\"stepHour()\"\n [stepMinute]=\"stepMinute()\"\n [stepSecond]=\"stepSecond()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n (valueChange)=\"setFromTime($event)\"\n />\n </div>\n <div class=\"hx-date-time-range-picker-time\">\n <span class=\"hx-date-time-range-picker-caption\" aria-hidden=\"true\">{{ toLabel() }}</span>\n <hx-time-picker\n inline\n class=\"hx-date-time-range-picker-to\"\n [ariaLabel]=\"toLabel()\"\n [value]=\"toValue()\"\n [hourFormat]=\"hourFormat()\"\n [showMinutes]=\"showMinutes()\"\n [showSeconds]=\"showSeconds()\"\n [stepHour]=\"stepHour()\"\n [stepMinute]=\"stepMinute()\"\n [stepSecond]=\"stepSecond()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n (valueChange)=\"setToTime($event)\"\n />\n </div>\n </div>\n }\n </div>\n <div class=\"hx-date-picker-buttonbar hx-date-time-range-picker-footer\">\n @if (showButtonBar()) {\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"clear()\">{{ clearLabel() }}</button>\n }\n <span class=\"hx-date-time-range-picker-spacer\"></span>\n <button type=\"button\" class=\"hx-date-picker-button hx-date-time-range-picker-cancel\" (click)=\"close(true)\">{{ cancelLabel() }}</button>\n <button type=\"button\" class=\"hx-date-picker-button hx-date-time-range-picker-submit\" (click)=\"submit()\">{{ submitLabel() }}</button>\n </div>\n </div>\n </ng-template>\n</div>\n"
13513
+ template: "<div\n class=\"hx-date-picker hx-date-picker-has-icon hx-date-time-range-picker-control\"\n [class.hx-date-picker-open]=\"open()\"\n [class.hx-date-picker-disabled]=\"isDisabled()\"\n [class.hx-date-picker-invalid]=\"invalid()\"\n>\n <div class=\"hx-date-picker-field\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n <input\n #field\n type=\"text\"\n [readOnly]=\"!typeable()\"\n class=\"hx-date-picker-input\"\n autocomplete=\"off\"\n aria-haspopup=\"dialog\"\n [attr.id]=\"inputId() ?? null\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"text()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? popupId : null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (input)=\"onTyping($event)\"\n (change)=\"commitTyping()\"\n (click)=\"onFieldClick()\"\n (keydown)=\"onFieldKeydown($event)\"\n />\n <button\n type=\"button\"\n class=\"hx-date-picker-trigger\"\n aria-haspopup=\"dialog\"\n [attr.aria-label]=\"chooseLabel()\"\n [attr.aria-expanded]=\"open()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n >\n <span class=\"hx-date-picker-trigger-icon\" aria-hidden=\"true\"></span>\n </button>\n </div>\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayPanelClass=\"hx-date-picker-overlay\"\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n (attach)=\"onAttach()\"\n (detach)=\"open.set(false)\"\n >\n <div\n class=\"hx-date-picker-popup hx-date-time-range-picker-popup\"\n role=\"dialog\"\n aria-modal=\"false\"\n [id]=\"popupId\"\n [attr.aria-label]=\"ariaLabel() ?? chooseLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby() ?? null\"\n (focusout)=\"onPopupFocusOut($event)\"\n >\n @if (presets().length > 0) {\n <hx-range-presets\n [presets]=\"presets()\"\n [display]=\"presetDisplay()\"\n [label]=\"presetsLabel()\"\n [disabled]=\"isDisabled()\"\n [selected]=\"selectedPreset()\"\n (chosen)=\"selectPreset($event)\"\n />\n }\n <div class=\"hx-date-time-range-picker-body\">\n @if (!timeOnly()) {\n <hx-date-picker\n class=\"hx-date-time-range-picker-days\"\n inline\n selectionMode=\"range\"\n [ariaLabel]=\"chooseLabel()\"\n [value]=\"days()\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [locale]=\"locale()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n [disabledDates]=\"disabledDates()\"\n (valueChange)=\"setDays($event)\"\n />\n }\n @if (showTime() || timeOnly()) {\n <div class=\"hx-date-time-range-picker-times\">\n <div class=\"hx-date-time-range-picker-time\">\n <span class=\"hx-date-time-range-picker-caption\" aria-hidden=\"true\">{{ fromLabel() }}</span>\n <hx-time-picker\n inline\n class=\"hx-date-time-range-picker-from\"\n [ariaLabel]=\"fromLabel()\"\n [value]=\"fromValue()\"\n [hourFormat]=\"hourFormat()\"\n [showMinutes]=\"showMinutes()\"\n [showSeconds]=\"showSeconds()\"\n [stepHour]=\"stepHour()\"\n [stepMinute]=\"stepMinute()\"\n [stepSecond]=\"stepSecond()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n (valueChange)=\"setFromTime($event)\"\n />\n </div>\n <div class=\"hx-date-time-range-picker-time\">\n <span class=\"hx-date-time-range-picker-caption\" aria-hidden=\"true\">{{ toLabel() }}</span>\n <hx-time-picker\n inline\n class=\"hx-date-time-range-picker-to\"\n [ariaLabel]=\"toLabel()\"\n [value]=\"toValue()\"\n [hourFormat]=\"hourFormat()\"\n [showMinutes]=\"showMinutes()\"\n [showSeconds]=\"showSeconds()\"\n [stepHour]=\"stepHour()\"\n [stepMinute]=\"stepMinute()\"\n [stepSecond]=\"stepSecond()\"\n [locale]=\"locale()\"\n [disabled]=\"isDisabled()\"\n (valueChange)=\"setToTime($event)\"\n />\n </div>\n </div>\n }\n </div>\n <div class=\"hx-date-picker-buttonbar hx-date-time-range-picker-footer\">\n @if (showButtonBar()) {\n <button type=\"button\" class=\"hx-date-picker-button\" (click)=\"clear()\">{{ clearLabel() }}</button>\n }\n <span class=\"hx-date-time-range-picker-spacer\"></span>\n <button type=\"button\" class=\"hx-date-picker-button hx-date-time-range-picker-cancel\" (click)=\"close(true)\">{{ cancelLabel() }}</button>\n <button\n type=\"button\"\n class=\"hx-date-picker-button hx-date-time-range-picker-submit\"\n (click)=\"submit()\"\n >{{ submitLabel() }}</button>\n </div>\n </div>\n </ng-template>\n</div>\n"
11458
13514
  }]
11459
13515
  }],
11460
13516
  ctorParameters: () => [],
@@ -11507,6 +13563,14 @@ i0.ɵɵngDeclareClassMetadata({
11507
13563
  required: false
11508
13564
  }]
11509
13565
  }],
13566
+ presetDisplay: [{
13567
+ type: i0.Input,
13568
+ args: [{
13569
+ isSignal: true,
13570
+ alias: "presetDisplay",
13571
+ required: false
13572
+ }]
13573
+ }],
11510
13574
  clearLabel: [{
11511
13575
  type: i0.Input,
11512
13576
  args: [{
@@ -23752,6 +25816,6 @@ i0.ɵɵngDeclareClassMetadata({
23752
25816
  }]
23753
25817
  }
23754
25818
  });
23755
- export { HX_DIALOG_DATA, HX_PRIMARY_COLORS, HX_SURFACES, HX_SURFACE_NAMES, HX_THEME_OPTIONS, HxAccordion, HxAccordionContent, HxAccordionHeader, HxAccordionPanel, HxAutoComplete, HxAvatar, HxAvatarGroup, HxBadge, HxBreadcrumb, HxButton, HxButtonGroup, HxCard, HxCarousel, HxCarouselItem, HxCell, HxCheckbox, HxChip, HxColumnHeader, HxConfirmDialog, HxConfirmPopup, HxConfirmationService, HxDataTable, HxDatePicker, HxDateTimePicker, HxDateTimeRangePicker, HxDialog, HxDialogRef, HxDialogService, HxDivider, HxDrawer, HxFieldset, HxFileUpload, HxFloatLabel, HxGalleria, HxGalleriaCaption, HxGalleriaItemTemplate, HxGalleriaThumbnail, HxIconField, HxImage, HxImageIndicator, HxInput, HxInputGroup, HxInputGroupAddon, HxInputIcon, HxInputNumber, HxListbox, HxMenu, HxMenubar, HxMessage, HxMessageService, HxMultiSelect, HxOverlayBadge, HxPaginator, HxPanel, HxPassword, HxPopover, HxProgressBar, HxProgressSpinner, HxRadio, HxRating, HxRowExpansion, HxSelect, HxSelectButton, HxSkeleton, HxSlider, HxSplitButton, HxStep, HxStepContent, HxStepList, HxStepPanel, HxStepPanels, HxStepper, HxSwitch, HxTab, HxTabContent, HxTabList, HxTabPanel, HxTabPanels, HxTable, HxTableBody, HxTableCaption, HxTableEmpty, HxTableFooter, HxTableHeader, HxTabs, HxTag, HxTheme, HxTimePicker, HxTimeline, HxTimelineContent, HxTimelineMarker, HxTimelineOpposite, HxToast, HxToastItem, HxToggleButton, HxToolbar, HxTooltip, HxTree, HxTreeNodeTemplate, compareValues, formatFileSize, matchesAccept, provideHxTheme, resolveField };
25819
+ export { HX_DATE_RANGE_DAY_PRESETS, HX_DATE_RANGE_PRESETS, HX_DIALOG_DATA, HX_PRIMARY_COLORS, HX_QUICK_SELECT_COMMONLY_USED, HX_QUICK_SELECT_LABELS, HX_SURFACES, HX_SURFACE_NAMES, HX_THEME_OPTIONS, HxAccordion, HxAccordionContent, HxAccordionHeader, HxAccordionPanel, HxAutoComplete, HxAvatar, HxAvatarGroup, HxBadge, HxBreadcrumb, HxButton, HxButtonGroup, HxCard, HxCarousel, HxCarouselItem, HxCell, HxCheckbox, HxChip, HxColumnHeader, HxConfirmDialog, HxConfirmPopup, HxConfirmationService, HxDataTable, HxDatePicker, HxDateRangeQuickSelect, HxDateTimePicker, HxDateTimeRangePicker, HxDialog, HxDialogRef, HxDialogService, HxDivider, HxDrawer, HxFieldset, HxFileUpload, HxFloatLabel, HxGalleria, HxGalleriaCaption, HxGalleriaItemTemplate, HxGalleriaThumbnail, HxIconField, HxImage, HxImageIndicator, HxInput, HxInputGroup, HxInputGroupAddon, HxInputIcon, HxInputNumber, HxListbox, HxMenu, HxMenubar, HxMessage, HxMessageService, HxMultiSelect, HxOverlayBadge, HxPaginator, HxPanel, HxPassword, HxPopover, HxProgressBar, HxProgressSpinner, HxRadio, HxRating, HxRowExpansion, HxSelect, HxSelectButton, HxSkeleton, HxSlider, HxSplitButton, HxStep, HxStepContent, HxStepList, HxStepPanel, HxStepPanels, HxStepper, HxSwitch, HxTab, HxTabContent, HxTabList, HxTabPanel, HxTabPanels, HxTable, HxTableBody, HxTableCaption, HxTableEmpty, HxTableFooter, HxTableHeader, HxTabs, HxTag, HxTheme, HxTimePicker, HxTimeline, HxTimelineContent, HxTimelineMarker, HxTimelineOpposite, HxToast, HxToastItem, HxToggleButton, HxToolbar, HxTooltip, HxTree, HxTreeNodeTemplate, compareValues, formatFileSize, hxDateRangePresets, hxParseDateMath, hxRelativeRangeExpressions, hxResolveRangeExpression, hxResolveRangeSide, matchesAccept, provideHxTheme, resolveField };
23756
25820
 
23757
25821
  //# sourceMappingURL=gravionlabs-helix-ui.mjs.map