mn-angular-lib 1.0.116 → 1.0.117

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.
@@ -2938,10 +2938,12 @@ const ARROWS_ZONE_WIDTH = 88;
2938
2938
  * the gap beside it.
2939
2939
  */
2940
2940
  const CONTROLS_ZONE_WIDTH = 150;
2941
- /** Space the month caption claims beside the strip. */
2942
- const MONTH_CAPTION_WIDTH = 88;
2943
- /** Everything on the row that isn't a day tile. */
2944
- const RESERVED_WIDTH = ARROWS_ZONE_WIDTH + CONTROLS_ZONE_WIDTH + MONTH_CAPTION_WIDTH;
2941
+ /**
2942
+ * Everything on the controls row that isn't a day tile. The month is a full-width
2943
+ * header on its own line now, so it no longer competes with the days for room —
2944
+ * which is why more of them fit at a given width than they used to.
2945
+ */
2946
+ const RESERVED_WIDTH = ARROWS_ZONE_WIDTH + CONTROLS_ZONE_WIDTH;
2945
2947
  /** Below this the strip can't hold even {@link MIN_TILE_COUNT} days. */
2946
2948
  const COMPACT_MAX_WIDTH = MIN_TILE_COUNT * TILE_SLOT_WIDTH + RESERVED_WIDTH;
2947
2949
  /** Assumed width before the first measurement (and during server-side rendering). */
@@ -2951,7 +2953,7 @@ let instanceCounter$1 = 0;
2951
2953
  /**
2952
2954
  * Reusable, responsive date selector bar.
2953
2955
  *
2954
- * Renders a "Today" button, a month caption, previous/next arrows and a strip of
2956
+ * Renders a "Today" button, a month header, previous/next arrows and a strip of
2955
2957
  * day tiles. Selecting a tile or pressing "Today" emits the chosen day via
2956
2958
  * {@link dateSelected}. The arrows only shift the visible days and never emit.
2957
2959
  *
@@ -3106,31 +3108,32 @@ class MnDateSelectorBar {
3106
3108
  return tiles;
3107
3109
  }, ...(ngDevMode ? [{ debugName: "dayTiles" }] : []));
3108
3110
  /**
3109
- * Names the month the strip is currently in, so the days are never just loose
3110
- * numbers. Reads as a range when the strip straddles two months, and carries
3111
- * both years when it straddles two of those.
3111
+ * The month the strip is currently in, spelled out for the header that titles
3112
+ * the bar so the days below are never just loose numbers. Reads as a range
3113
+ * when the strip straddles two months, and carries both years when it straddles
3114
+ * two of those.
3112
3115
  */
3113
3116
  monthCaption = computed(() => {
3114
3117
  const locale = this.effectiveLocale();
3115
3118
  const tiles = this.dayTiles();
3116
- // With no strip to describe — the compact layout — the caption names the
3119
+ // With no strip to describe — the compact layout — the header names the
3117
3120
  // month the selection sits in, so the bar is never unlabelled.
3118
3121
  if (!tiles.length) {
3119
- return this.selectedDate().toLocaleDateString(locale, { month: 'short', year: 'numeric' });
3122
+ return this.selectedDate().toLocaleDateString(locale, { month: 'long', year: 'numeric' });
3120
3123
  }
3121
3124
  const first = tiles[0].date;
3122
3125
  const last = tiles[tiles.length - 1].date;
3123
3126
  if (first.getFullYear() !== last.getFullYear()) {
3124
- const from = first.toLocaleDateString(locale, { month: 'short', year: 'numeric' });
3125
- const to = last.toLocaleDateString(locale, { month: 'short', year: 'numeric' });
3127
+ const from = first.toLocaleDateString(locale, { month: 'long', year: 'numeric' });
3128
+ const to = last.toLocaleDateString(locale, { month: 'long', year: 'numeric' });
3126
3129
  return `${from} – ${to}`;
3127
3130
  }
3128
3131
  if (first.getMonth() !== last.getMonth()) {
3129
- const from = first.toLocaleDateString(locale, { month: 'short' });
3130
- const to = last.toLocaleDateString(locale, { month: 'short', year: 'numeric' });
3132
+ const from = first.toLocaleDateString(locale, { month: 'long' });
3133
+ const to = last.toLocaleDateString(locale, { month: 'long', year: 'numeric' });
3131
3134
  return `${from} – ${to}`;
3132
3135
  }
3133
- return first.toLocaleDateString(locale, { month: 'short', year: 'numeric' });
3136
+ return first.toLocaleDateString(locale, { month: 'long', year: 'numeric' });
3134
3137
  }, ...(ngDevMode ? [{ debugName: "monthCaption" }] : []));
3135
3138
  /** The selected date formatted as YYYY-MM-DD for the date-picker input. */
3136
3139
  selectedDateString = computed(() => {
@@ -3331,7 +3334,7 @@ class MnDateSelectorBar {
3331
3334
  a.getDate() === b.getDate());
3332
3335
  }
3333
3336
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: MnDateSelectorBar, deps: [], target: i0.ɵɵFactoryTarget.Component });
3334
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: MnDateSelectorBar, isStandalone: true, selector: "mn-date-selector-bar", inputs: { selectedDate: { classPropertyName: "selectedDate", publicName: "selectedDate", isSignal: true, isRequired: false, transformFunction: null }, todayLabel: { classPropertyName: "todayLabel", publicName: "todayLabel", isSignal: true, isRequired: false, transformFunction: null }, pickDateLabel: { classPropertyName: "pickDateLabel", publicName: "pickDateLabel", isSignal: true, isRequired: false, transformFunction: null }, previousLabel: { classPropertyName: "previousLabel", publicName: "previousLabel", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, dayStripLabel: { classPropertyName: "dayStripLabel", publicName: "dayStripLabel", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dateSelected: "dateSelected" }, host: { classAttribute: "block" }, viewQueries: [{ propertyName: "tileButtons", predicate: ["tileButton"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Date selector bar. Layout is driven by the bar's own measured width, so it\n rearranges for the space the bar was given, not for the viewport. It never\n stacks: as room runs out it shows fewer days, then hands over to the picker.\n Nothing here is boxed \u2014 spacing does the grouping, not borders. -->\n<div class=\"flex items-center gap-4 px-4 py-3\">\n\n <!-- Today: returns the strip and the selection to the current day, and the\n control people reach for most, so it carries the weight of a filled button. -->\n <button (click)=\"goToToday()\"\n [data]=\"{ variant: 'fill', color: 'primary', size: 'md' }\"\n class=\"shrink-0\"\n mnButton\n type=\"button\">\n {{ todayLabel() }}\n </button>\n\n <!-- Too narrow for a usable strip, so the picker takes its place beside Today.\n Every date stays reachable on a phone, in one tap rather than by paging.\n The caption comes along, so the compact bar is labelled like the wide one \u2014\n it names the selected day's month rather than a visible range. -->\n @if (!showDayStrip()) {\n <span aria-hidden=\"true\"\n class=\"shrink-0 text-xs font-semibold tracking-wide whitespace-nowrap uppercase opacity-55\">\n {{ monthCaption() }}\n </span>\n\n <mn-lib-datetime (ngModelChange)=\"onDateModelChanged($event)\"\n [ngModel]=\"selectedDateString()\"\n [props]=\"pickerProps()\"\n class=\"block min-w-0 flex-1\"></mn-lib-datetime>\n }\n\n <!-- The strip takes the room left over and centres its contents in it, so on a\n wide bar the days sit in the middle rather than trailing off to one side. -->\n @if (showDayStrip()) {\n <div [attr.aria-label]=\"dayStripLabel()\"\n class=\"flex min-w-0 flex-1 items-center justify-center gap-3\"\n role=\"group\">\n <!-- Names the month the strip is in, so the day numbers are never loose. -->\n <span aria-hidden=\"true\"\n class=\"shrink-0 text-xs font-semibold tracking-wide whitespace-nowrap uppercase opacity-55\">\n {{ monthCaption() }}\n </span>\n\n <button (click)=\"navigatePrevious()\"\n [attr.aria-label]=\"previousLabel()\"\n [data]=\"{ variant: 'text', size: 'md', color: 'gray' }\"\n class=\"shrink-0\"\n mnButton\n type=\"button\">\n <svg [size]=\"18\" lucideChevronLeft></svg>\n </button>\n\n <!-- Days read on one line so each sits at the same height as the buttons\n either side of it. Roving tabindex: one day is in the tab order, the\n arrow keys move between the rest and page the strip at either end. -->\n <div class=\"flex min-w-0 gap-1\">\n @for (tile of dayTiles(); track tile.date.getTime(); let i = $index) {\n <!-- A month break is marked by extra breathing room rather than a rule,\n so the run of days stays unbroken; the caption names both months. -->\n <button #tileButton\n (click)=\"selectDate(tile.date)\"\n (focus)=\"onTileFocus(i)\"\n (keydown)=\"onTileKeydown($event, i)\"\n [attr.aria-current]=\"tile.isToday ? 'date' : null\"\n [attr.aria-label]=\"tile.accessibleLabel\"\n [attr.aria-pressed]=\"tile.isSelected\"\n [attr.tabindex]=\"isTabbable(i) ? 0 : -1\"\n [class.bg-primary]=\"tile.isSelected\"\n [class.hover:bg-base-200]=\"!tile.isSelected\"\n [class.ml-3]=\"tile.startsNewMonth\"\n [class.text-primary-content]=\"tile.isSelected\"\n class=\"flex min-w-16 shrink-0 cursor-pointer items-center justify-center gap-1.5 rounded-lg px-3 py-2 text-sm transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary motion-reduce:transition-none\"\n type=\"button\">\n <span [class.opacity-60]=\"!tile.isSelected\"\n [class.opacity-90]=\"tile.isSelected\"\n aria-hidden=\"true\"\n class=\"text-xs font-medium uppercase\">\n {{ tile.dayName }}\n </span>\n <span aria-hidden=\"true\" class=\"font-bold tabular-nums\">{{ tile.dayNumber }}</span>\n <!-- Today's dot. Every day reserves the space so no tile changes\n width; only its colour says which one is today, and exactly one\n colour class applies at a time so they can't fight. -->\n <span [class.bg-primary-content]=\"tile.isToday && tile.isSelected\"\n [class.bg-primary]=\"tile.isToday && !tile.isSelected\"\n aria-hidden=\"true\"\n class=\"size-1 shrink-0 rounded-full\"></span>\n </button>\n }\n </div>\n\n <button (click)=\"navigateNext()\"\n [attr.aria-label]=\"nextLabel()\"\n [data]=\"{ variant: 'text', size: 'md', color: 'gray' }\"\n class=\"shrink-0\"\n mnButton\n type=\"button\">\n <svg [size]=\"18\" lucideChevronRight></svg>\n </button>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MnButton, selector: "button[mnButton], a[mnButton]", inputs: ["data"] }, { kind: "component", type: MnDatetime, selector: "mn-lib-datetime", inputs: ["props"] }, { kind: "component", type: LucideChevronLeft, selector: "svg[lucideChevronLeft]" }, { kind: "component", type: LucideChevronRight, selector: "svg[lucideChevronRight]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3337
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: MnDateSelectorBar, isStandalone: true, selector: "mn-date-selector-bar", inputs: { selectedDate: { classPropertyName: "selectedDate", publicName: "selectedDate", isSignal: true, isRequired: false, transformFunction: null }, todayLabel: { classPropertyName: "todayLabel", publicName: "todayLabel", isSignal: true, isRequired: false, transformFunction: null }, pickDateLabel: { classPropertyName: "pickDateLabel", publicName: "pickDateLabel", isSignal: true, isRequired: false, transformFunction: null }, previousLabel: { classPropertyName: "previousLabel", publicName: "previousLabel", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, dayStripLabel: { classPropertyName: "dayStripLabel", publicName: "dayStripLabel", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dateSelected: "dateSelected" }, host: { classAttribute: "block" }, viewQueries: [{ propertyName: "tileButtons", predicate: ["tileButton"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Date selector bar. Layout is driven by the bar's own measured width, so it\n rearranges for the space the bar was given, not for the viewport. The strip\n never stacks: as room runs out it shows fewer days, then hands over to the\n picker. Nothing here is boxed \u2014 spacing does the grouping, not borders. -->\n<div class=\"flex flex-col gap-2 px-4 py-3\">\n\n <!-- Month header. Titles the whole bar so the day numbers below are never loose:\n it names the month the strip is in (or, when compact, the month the\n selection sits in), reading as a range where the strip crosses a boundary.\n On its own line it has room to be spelled out, and no longer steals width\n from the days the way the old inline caption did. -->\n <div aria-hidden=\"true\"\n class=\"text-center text-sm font-semibold tracking-wide whitespace-nowrap opacity-80\">\n {{ monthCaption() }}\n </div>\n\n <!-- Controls row. Today and the strip travel together as one centred cluster, so\n Today sits right beside the days instead of stranded against the far edge;\n the gap between them matches the strip's own spacing. When the strip gives\n way to the picker, the picker fills the row and Today anchors its left. -->\n <div class=\"flex items-center justify-center gap-3\">\n\n <!-- Today: returns the strip and the selection to the current day. Outlined\n rather than filled, so the one filled-primary element on the bar is the\n selected day \u2014 Today shares the primary accent without competing with it. -->\n <button (click)=\"goToToday()\"\n [data]=\"{ variant: 'outline', color: 'primary', size: 'md' }\"\n class=\"shrink-0\"\n mnButton\n type=\"button\">\n {{ todayLabel() }}\n </button>\n\n <!-- Too narrow for a usable strip, so the picker takes its place beside Today.\n Every date stays reachable on a phone, in one tap rather than by paging;\n the month header above keeps the compact bar labelled like the wide one. -->\n @if (!showDayStrip()) {\n <mn-lib-datetime (ngModelChange)=\"onDateModelChanged($event)\"\n [ngModel]=\"selectedDateString()\"\n [props]=\"pickerProps()\"\n class=\"block min-w-0 flex-1\"></mn-lib-datetime>\n }\n\n <!-- Arrows and days, sized to their own content so the row can centre them\n together with Today as a single cluster \u2014 rather than the days drifting to\n the middle of the leftover space, away from the button. -->\n @if (showDayStrip()) {\n <div [attr.aria-label]=\"dayStripLabel()\"\n class=\"flex min-w-0 items-center gap-3\"\n role=\"group\">\n <button (click)=\"navigatePrevious()\"\n [attr.aria-label]=\"previousLabel()\"\n [data]=\"{ variant: 'text', size: 'md', color: 'gray' }\"\n class=\"shrink-0\"\n mnButton\n type=\"button\">\n <svg [size]=\"18\" lucideChevronLeft></svg>\n </button>\n\n <!-- Days read on one line so each sits at the same height as the buttons\n either side of it. Roving tabindex: one day is in the tab order, the\n arrow keys move between the rest and page the strip at either end. -->\n <div class=\"flex min-w-0 gap-1\">\n @for (tile of dayTiles(); track tile.date.getTime(); let i = $index) {\n <!-- Selected is the filled pill; today is called out by its number\n alone, tinted primary \u2014 no box, in keeping with a bar that groups\n by spacing rather than borders. When today is also the selected\n day the fill takes over, since there is nothing left to tell apart.\n A month break is marked by extra breathing room rather than a rule,\n so the run of days stays unbroken; the header names both months. -->\n <button #tileButton\n (click)=\"selectDate(tile.date)\"\n (focus)=\"onTileFocus(i)\"\n (keydown)=\"onTileKeydown($event, i)\"\n [attr.aria-current]=\"tile.isToday ? 'date' : null\"\n [attr.aria-label]=\"tile.accessibleLabel\"\n [attr.aria-pressed]=\"tile.isSelected\"\n [attr.tabindex]=\"isTabbable(i) ? 0 : -1\"\n [class.bg-primary]=\"tile.isSelected\"\n [class.hover:bg-base-200]=\"!tile.isSelected\"\n [class.ml-3]=\"tile.startsNewMonth\"\n [class.text-primary-content]=\"tile.isSelected\"\n class=\"flex min-w-16 shrink-0 cursor-pointer items-center justify-center gap-1.5 rounded-lg px-3 py-2 text-sm transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary motion-reduce:transition-none\"\n type=\"button\">\n <span [class.opacity-60]=\"!tile.isSelected\"\n [class.opacity-90]=\"tile.isSelected\"\n aria-hidden=\"true\"\n class=\"text-xs font-medium uppercase\">\n {{ tile.dayName }}\n </span>\n <!-- Today's number carries the primary tint, unless the tile is\n filled \u2014 then it wears the fill's own text colour instead. -->\n <span [class.text-primary]=\"tile.isToday && !tile.isSelected\"\n aria-hidden=\"true\"\n class=\"font-bold tabular-nums\">{{ tile.dayNumber }}</span>\n </button>\n }\n </div>\n\n <button (click)=\"navigateNext()\"\n [attr.aria-label]=\"nextLabel()\"\n [data]=\"{ variant: 'text', size: 'md', color: 'gray' }\"\n class=\"shrink-0\"\n mnButton\n type=\"button\">\n <svg [size]=\"18\" lucideChevronRight></svg>\n </button>\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MnButton, selector: "button[mnButton], a[mnButton]", inputs: ["data"] }, { kind: "component", type: MnDatetime, selector: "mn-lib-datetime", inputs: ["props"] }, { kind: "component", type: LucideChevronLeft, selector: "svg[lucideChevronLeft]" }, { kind: "component", type: LucideChevronRight, selector: "svg[lucideChevronRight]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3335
3338
  }
3336
3339
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: MnDateSelectorBar, decorators: [{
3337
3340
  type: Component,
@@ -3342,7 +3345,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
3342
3345
  MnDatetime,
3343
3346
  LucideChevronLeft,
3344
3347
  LucideChevronRight,
3345
- ], changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'block' }, template: "<!-- Date selector bar. Layout is driven by the bar's own measured width, so it\n rearranges for the space the bar was given, not for the viewport. It never\n stacks: as room runs out it shows fewer days, then hands over to the picker.\n Nothing here is boxed \u2014 spacing does the grouping, not borders. -->\n<div class=\"flex items-center gap-4 px-4 py-3\">\n\n <!-- Today: returns the strip and the selection to the current day, and the\n control people reach for most, so it carries the weight of a filled button. -->\n <button (click)=\"goToToday()\"\n [data]=\"{ variant: 'fill', color: 'primary', size: 'md' }\"\n class=\"shrink-0\"\n mnButton\n type=\"button\">\n {{ todayLabel() }}\n </button>\n\n <!-- Too narrow for a usable strip, so the picker takes its place beside Today.\n Every date stays reachable on a phone, in one tap rather than by paging.\n The caption comes along, so the compact bar is labelled like the wide one \u2014\n it names the selected day's month rather than a visible range. -->\n @if (!showDayStrip()) {\n <span aria-hidden=\"true\"\n class=\"shrink-0 text-xs font-semibold tracking-wide whitespace-nowrap uppercase opacity-55\">\n {{ monthCaption() }}\n </span>\n\n <mn-lib-datetime (ngModelChange)=\"onDateModelChanged($event)\"\n [ngModel]=\"selectedDateString()\"\n [props]=\"pickerProps()\"\n class=\"block min-w-0 flex-1\"></mn-lib-datetime>\n }\n\n <!-- The strip takes the room left over and centres its contents in it, so on a\n wide bar the days sit in the middle rather than trailing off to one side. -->\n @if (showDayStrip()) {\n <div [attr.aria-label]=\"dayStripLabel()\"\n class=\"flex min-w-0 flex-1 items-center justify-center gap-3\"\n role=\"group\">\n <!-- Names the month the strip is in, so the day numbers are never loose. -->\n <span aria-hidden=\"true\"\n class=\"shrink-0 text-xs font-semibold tracking-wide whitespace-nowrap uppercase opacity-55\">\n {{ monthCaption() }}\n </span>\n\n <button (click)=\"navigatePrevious()\"\n [attr.aria-label]=\"previousLabel()\"\n [data]=\"{ variant: 'text', size: 'md', color: 'gray' }\"\n class=\"shrink-0\"\n mnButton\n type=\"button\">\n <svg [size]=\"18\" lucideChevronLeft></svg>\n </button>\n\n <!-- Days read on one line so each sits at the same height as the buttons\n either side of it. Roving tabindex: one day is in the tab order, the\n arrow keys move between the rest and page the strip at either end. -->\n <div class=\"flex min-w-0 gap-1\">\n @for (tile of dayTiles(); track tile.date.getTime(); let i = $index) {\n <!-- A month break is marked by extra breathing room rather than a rule,\n so the run of days stays unbroken; the caption names both months. -->\n <button #tileButton\n (click)=\"selectDate(tile.date)\"\n (focus)=\"onTileFocus(i)\"\n (keydown)=\"onTileKeydown($event, i)\"\n [attr.aria-current]=\"tile.isToday ? 'date' : null\"\n [attr.aria-label]=\"tile.accessibleLabel\"\n [attr.aria-pressed]=\"tile.isSelected\"\n [attr.tabindex]=\"isTabbable(i) ? 0 : -1\"\n [class.bg-primary]=\"tile.isSelected\"\n [class.hover:bg-base-200]=\"!tile.isSelected\"\n [class.ml-3]=\"tile.startsNewMonth\"\n [class.text-primary-content]=\"tile.isSelected\"\n class=\"flex min-w-16 shrink-0 cursor-pointer items-center justify-center gap-1.5 rounded-lg px-3 py-2 text-sm transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary motion-reduce:transition-none\"\n type=\"button\">\n <span [class.opacity-60]=\"!tile.isSelected\"\n [class.opacity-90]=\"tile.isSelected\"\n aria-hidden=\"true\"\n class=\"text-xs font-medium uppercase\">\n {{ tile.dayName }}\n </span>\n <span aria-hidden=\"true\" class=\"font-bold tabular-nums\">{{ tile.dayNumber }}</span>\n <!-- Today's dot. Every day reserves the space so no tile changes\n width; only its colour says which one is today, and exactly one\n colour class applies at a time so they can't fight. -->\n <span [class.bg-primary-content]=\"tile.isToday && tile.isSelected\"\n [class.bg-primary]=\"tile.isToday && !tile.isSelected\"\n aria-hidden=\"true\"\n class=\"size-1 shrink-0 rounded-full\"></span>\n </button>\n }\n </div>\n\n <button (click)=\"navigateNext()\"\n [attr.aria-label]=\"nextLabel()\"\n [data]=\"{ variant: 'text', size: 'md', color: 'gray' }\"\n class=\"shrink-0\"\n mnButton\n type=\"button\">\n <svg [size]=\"18\" lucideChevronRight></svg>\n </button>\n </div>\n }\n</div>\n" }]
3348
+ ], changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'block' }, template: "<!-- Date selector bar. Layout is driven by the bar's own measured width, so it\n rearranges for the space the bar was given, not for the viewport. The strip\n never stacks: as room runs out it shows fewer days, then hands over to the\n picker. Nothing here is boxed \u2014 spacing does the grouping, not borders. -->\n<div class=\"flex flex-col gap-2 px-4 py-3\">\n\n <!-- Month header. Titles the whole bar so the day numbers below are never loose:\n it names the month the strip is in (or, when compact, the month the\n selection sits in), reading as a range where the strip crosses a boundary.\n On its own line it has room to be spelled out, and no longer steals width\n from the days the way the old inline caption did. -->\n <div aria-hidden=\"true\"\n class=\"text-center text-sm font-semibold tracking-wide whitespace-nowrap opacity-80\">\n {{ monthCaption() }}\n </div>\n\n <!-- Controls row. Today and the strip travel together as one centred cluster, so\n Today sits right beside the days instead of stranded against the far edge;\n the gap between them matches the strip's own spacing. When the strip gives\n way to the picker, the picker fills the row and Today anchors its left. -->\n <div class=\"flex items-center justify-center gap-3\">\n\n <!-- Today: returns the strip and the selection to the current day. Outlined\n rather than filled, so the one filled-primary element on the bar is the\n selected day \u2014 Today shares the primary accent without competing with it. -->\n <button (click)=\"goToToday()\"\n [data]=\"{ variant: 'outline', color: 'primary', size: 'md' }\"\n class=\"shrink-0\"\n mnButton\n type=\"button\">\n {{ todayLabel() }}\n </button>\n\n <!-- Too narrow for a usable strip, so the picker takes its place beside Today.\n Every date stays reachable on a phone, in one tap rather than by paging;\n the month header above keeps the compact bar labelled like the wide one. -->\n @if (!showDayStrip()) {\n <mn-lib-datetime (ngModelChange)=\"onDateModelChanged($event)\"\n [ngModel]=\"selectedDateString()\"\n [props]=\"pickerProps()\"\n class=\"block min-w-0 flex-1\"></mn-lib-datetime>\n }\n\n <!-- Arrows and days, sized to their own content so the row can centre them\n together with Today as a single cluster \u2014 rather than the days drifting to\n the middle of the leftover space, away from the button. -->\n @if (showDayStrip()) {\n <div [attr.aria-label]=\"dayStripLabel()\"\n class=\"flex min-w-0 items-center gap-3\"\n role=\"group\">\n <button (click)=\"navigatePrevious()\"\n [attr.aria-label]=\"previousLabel()\"\n [data]=\"{ variant: 'text', size: 'md', color: 'gray' }\"\n class=\"shrink-0\"\n mnButton\n type=\"button\">\n <svg [size]=\"18\" lucideChevronLeft></svg>\n </button>\n\n <!-- Days read on one line so each sits at the same height as the buttons\n either side of it. Roving tabindex: one day is in the tab order, the\n arrow keys move between the rest and page the strip at either end. -->\n <div class=\"flex min-w-0 gap-1\">\n @for (tile of dayTiles(); track tile.date.getTime(); let i = $index) {\n <!-- Selected is the filled pill; today is called out by its number\n alone, tinted primary \u2014 no box, in keeping with a bar that groups\n by spacing rather than borders. When today is also the selected\n day the fill takes over, since there is nothing left to tell apart.\n A month break is marked by extra breathing room rather than a rule,\n so the run of days stays unbroken; the header names both months. -->\n <button #tileButton\n (click)=\"selectDate(tile.date)\"\n (focus)=\"onTileFocus(i)\"\n (keydown)=\"onTileKeydown($event, i)\"\n [attr.aria-current]=\"tile.isToday ? 'date' : null\"\n [attr.aria-label]=\"tile.accessibleLabel\"\n [attr.aria-pressed]=\"tile.isSelected\"\n [attr.tabindex]=\"isTabbable(i) ? 0 : -1\"\n [class.bg-primary]=\"tile.isSelected\"\n [class.hover:bg-base-200]=\"!tile.isSelected\"\n [class.ml-3]=\"tile.startsNewMonth\"\n [class.text-primary-content]=\"tile.isSelected\"\n class=\"flex min-w-16 shrink-0 cursor-pointer items-center justify-center gap-1.5 rounded-lg px-3 py-2 text-sm transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary motion-reduce:transition-none\"\n type=\"button\">\n <span [class.opacity-60]=\"!tile.isSelected\"\n [class.opacity-90]=\"tile.isSelected\"\n aria-hidden=\"true\"\n class=\"text-xs font-medium uppercase\">\n {{ tile.dayName }}\n </span>\n <!-- Today's number carries the primary tint, unless the tile is\n filled \u2014 then it wears the fill's own text colour instead. -->\n <span [class.text-primary]=\"tile.isToday && !tile.isSelected\"\n aria-hidden=\"true\"\n class=\"font-bold tabular-nums\">{{ tile.dayNumber }}</span>\n </button>\n }\n </div>\n\n <button (click)=\"navigateNext()\"\n [attr.aria-label]=\"nextLabel()\"\n [data]=\"{ variant: 'text', size: 'md', color: 'gray' }\"\n class=\"shrink-0\"\n mnButton\n type=\"button\">\n <svg [size]=\"18\" lucideChevronRight></svg>\n </button>\n </div>\n }\n </div>\n</div>\n" }]
3346
3349
  }], propDecorators: { selectedDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedDate", required: false }] }], todayLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "todayLabel", required: false }] }], pickDateLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "pickDateLabel", required: false }] }], previousLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "previousLabel", required: false }] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }], dayStripLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "dayStripLabel", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], dateSelected: [{ type: i0.Output, args: ["dateSelected"] }], tileButtons: [{ type: i0.ViewChildren, args: ['tileButton', { isSignal: true }] }] } });
3347
3350
 
3348
3351
  const mnMultiSelectVariants = tv({