@sonny-ui/core 0.1.0-alpha.14 → 0.1.0-alpha.15

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.
@@ -3,7 +3,7 @@ import { twMerge } from 'tailwind-merge';
3
3
  import { cva } from 'class-variance-authority';
4
4
  export { cva } from 'class-variance-authority';
5
5
  import * as i0 from '@angular/core';
6
- import { inject, PLATFORM_ID, signal, computed, Injectable, InjectionToken, makeEnvironmentProviders, provideEnvironmentInitializer, input, Directive, ChangeDetectionStrategy, Component, ElementRef, model, viewChild, forwardRef, HostListener, TemplateRef, output, contentChildren, contentChild, effect, untracked, Injector, afterNextRender, Renderer2 } from '@angular/core';
6
+ import { inject, PLATFORM_ID, signal, computed, Injectable, InjectionToken, makeEnvironmentProviders, provideEnvironmentInitializer, input, Directive, ChangeDetectionStrategy, Component, ElementRef, model, viewChild, forwardRef, HostListener, TemplateRef, output, contentChildren, contentChild, effect, untracked, Injector, afterNextRender, Renderer2, linkedSignal } from '@angular/core';
7
7
  import { DOCUMENT, isPlatformBrowser, NgTemplateOutlet } from '@angular/common';
8
8
  import { Dialog, DialogRef } from '@angular/cdk/dialog';
9
9
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
@@ -5839,20 +5839,43 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
5839
5839
  }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
5840
5840
 
5841
5841
  class SnyCalendarComponent {
5842
+ // Existing inputs (backwards compatible)
5842
5843
  value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
5843
5844
  min = input(undefined, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
5844
5845
  max = input(undefined, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
5845
5846
  locale = input('en-US', ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
5846
5847
  class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
5848
+ // Range mode inputs
5849
+ mode = input('single', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
5850
+ rangeValue = model(null, ...(ngDevMode ? [{ debugName: "rangeValue" }] : /* istanbul ignore next */ []));
5851
+ showNavigation = input(true, ...(ngDevMode ? [{ debugName: "showNavigation" }] : /* istanbul ignore next */ []));
5852
+ initialViewDate = input(undefined, ...(ngDevMode ? [{ debugName: "initialViewDate" }] : /* istanbul ignore next */ []));
5853
+ borderless = input(false, ...(ngDevMode ? [{ debugName: "borderless" }] : /* istanbul ignore next */ []));
5854
+ hostClass = computed(() => this.borderless()
5855
+ ? 'inline-block p-3 bg-background'
5856
+ : 'inline-block p-4 rounded-md border border-border bg-background', ...(ngDevMode ? [{ debugName: "hostClass" }] : /* istanbul ignore next */ []));
5857
+ // Internal state
5847
5858
  _disabledByCva = signal(false, ...(ngDevMode ? [{ debugName: "_disabledByCva" }] : /* istanbul ignore next */ []));
5848
- viewDate = signal(new Date(), ...(ngDevMode ? [{ debugName: "viewDate" }] : /* istanbul ignore next */ []));
5859
+ hoveredDate = signal(null, ...(ngDevMode ? [{ debugName: "hoveredDate" }] : /* istanbul ignore next */ []));
5860
+ viewDate = linkedSignal(() => this.initialViewDate() ?? new Date(), ...(ngDevMode ? [{ debugName: "viewDate" }] : /* istanbul ignore next */ []));
5849
5861
  weekDays = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
5862
+ // CVA
5850
5863
  _onChange = () => { };
5851
5864
  onTouched = () => { };
5852
5865
  writeValue(val) {
5853
- this.value.set(val ?? null);
5854
- if (val) {
5855
- this.viewDate.set(new Date(val.getFullYear(), val.getMonth(), 1));
5866
+ if (this.mode() === 'range') {
5867
+ this.rangeValue.set(val ?? null);
5868
+ const range = val;
5869
+ if (range?.start) {
5870
+ this.viewDate.set(new Date(range.start.getFullYear(), range.start.getMonth(), 1));
5871
+ }
5872
+ }
5873
+ else {
5874
+ this.value.set(val ?? null);
5875
+ if (val) {
5876
+ const d = val;
5877
+ this.viewDate.set(new Date(d.getFullYear(), d.getMonth(), 1));
5878
+ }
5856
5879
  }
5857
5880
  }
5858
5881
  registerOnChange(fn) {
@@ -5864,6 +5887,7 @@ class SnyCalendarComponent {
5864
5887
  setDisabledState(isDisabled) {
5865
5888
  this._disabledByCva.set(isDisabled);
5866
5889
  }
5890
+ // Computed
5867
5891
  monthYearLabel = computed(() => {
5868
5892
  const d = this.viewDate();
5869
5893
  return d.toLocaleDateString(this.locale(), { month: 'long', year: 'numeric' });
@@ -5874,6 +5898,8 @@ class SnyCalendarComponent {
5874
5898
  const month = view.getMonth();
5875
5899
  const today = new Date();
5876
5900
  const selected = this.value();
5901
+ const rangeVal = this.mode() === 'range' ? this.rangeValue() : null;
5902
+ const hovered = this.hoveredDate();
5877
5903
  const minDate = this.min();
5878
5904
  const maxDate = this.max();
5879
5905
  const firstDay = new Date(year, month, 1);
@@ -5881,37 +5907,64 @@ class SnyCalendarComponent {
5881
5907
  const daysInMonth = new Date(year, month + 1, 0).getDate();
5882
5908
  const daysInPrevMonth = new Date(year, month, 0).getDate();
5883
5909
  const days = [];
5884
- // Previous month
5885
5910
  for (let i = startDay - 1; i >= 0; i--) {
5886
5911
  const date = new Date(year, month - 1, daysInPrevMonth - i);
5887
- days.push(this.createDay(date, false, today, selected, minDate, maxDate));
5912
+ days.push(this.createDay(date, false, today, selected, rangeVal, hovered, minDate, maxDate));
5888
5913
  }
5889
- // Current month
5890
5914
  for (let d = 1; d <= daysInMonth; d++) {
5891
5915
  const date = new Date(year, month, d);
5892
- days.push(this.createDay(date, true, today, selected, minDate, maxDate));
5916
+ days.push(this.createDay(date, true, today, selected, rangeVal, hovered, minDate, maxDate));
5893
5917
  }
5894
- // Next month fill
5895
5918
  const remaining = 42 - days.length;
5896
5919
  for (let d = 1; d <= remaining; d++) {
5897
5920
  const date = new Date(year, month + 1, d);
5898
- days.push(this.createDay(date, false, today, selected, minDate, maxDate));
5921
+ days.push(this.createDay(date, false, today, selected, rangeVal, hovered, minDate, maxDate));
5899
5922
  }
5900
5923
  return days;
5901
5924
  }, ...(ngDevMode ? [{ debugName: "days" }] : /* istanbul ignore next */ []));
5925
+ // Navigation
5902
5926
  prevMonth() {
5903
- this.viewDate.update((d) => new Date(d.getFullYear(), d.getMonth() - 1, 1));
5927
+ this.viewDate.set(new Date(this.viewDate().getFullYear(), this.viewDate().getMonth() - 1, 1));
5904
5928
  }
5905
5929
  nextMonth() {
5906
- this.viewDate.update((d) => new Date(d.getFullYear(), d.getMonth() + 1, 1));
5930
+ this.viewDate.set(new Date(this.viewDate().getFullYear(), this.viewDate().getMonth() + 1, 1));
5907
5931
  }
5908
- selectDate(date) {
5909
- this.value.set(date);
5910
- this._onChange(date);
5932
+ // Click handler
5933
+ onDayClick(date) {
5934
+ if (this.mode() === 'single') {
5935
+ this.value.set(date);
5936
+ this._onChange(date);
5937
+ this.onTouched();
5938
+ return;
5939
+ }
5940
+ // Range mode
5941
+ const current = this.rangeValue();
5942
+ if (!current?.start || (current.start && current.end)) {
5943
+ this.rangeValue.set({ start: date, end: null });
5944
+ }
5945
+ else {
5946
+ const start = current.start;
5947
+ if (date < start) {
5948
+ this.rangeValue.set({ start: date, end: start });
5949
+ }
5950
+ else if (this.isSameDay(date, start)) {
5951
+ this.rangeValue.set({ start: date, end: date });
5952
+ }
5953
+ else {
5954
+ this.rangeValue.set({ start, end: date });
5955
+ }
5956
+ }
5957
+ this._onChange(this.rangeValue());
5911
5958
  this.onTouched();
5912
5959
  }
5960
+ // Hover handler
5961
+ onDayHover(date) {
5962
+ if (this.mode() === 'range') {
5963
+ this.hoveredDate.set(date);
5964
+ }
5965
+ }
5966
+ // Keyboard
5913
5967
  onKeydown(event) {
5914
- // Simplified keyboard navigation
5915
5968
  switch (event.key) {
5916
5969
  case 'ArrowLeft':
5917
5970
  event.preventDefault();
@@ -5931,9 +5984,29 @@ class SnyCalendarComponent {
5931
5984
  break;
5932
5985
  }
5933
5986
  }
5987
+ // Styling
5934
5988
  dayClass(day) {
5935
- return cn('inline-flex items-center justify-center rounded-md text-sm h-8 w-8 transition-colors', day.isCurrentMonth ? 'text-foreground' : 'text-muted-foreground/50', day.isToday && !day.isSelected && 'bg-accent font-bold', day.isSelected && 'bg-primary text-primary-foreground', day.isDisabled && 'opacity-50 cursor-not-allowed', !day.isDisabled && !day.isSelected && 'hover:bg-accent cursor-pointer');
5936
- }
5989
+ const isEndpoint = day.isRangeStart || day.isRangeEnd;
5990
+ return cn('inline-flex items-center justify-center text-sm h-9 w-9 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
5991
+ // Shape
5992
+ day.isRangeStart && !day.isRangeEnd ? 'rounded-l-md rounded-r-none' :
5993
+ day.isRangeEnd && !day.isRangeStart ? 'rounded-r-md rounded-l-none' :
5994
+ day.isInRange || day.isRangePreview ? 'rounded-none' :
5995
+ 'rounded-md',
5996
+ // Base text color
5997
+ !day.isCurrentMonth && 'text-muted-foreground/40', day.isCurrentMonth && !day.isSelected && !isEndpoint && 'text-foreground',
5998
+ // Today indicator
5999
+ day.isToday && !day.isSelected && !isEndpoint && 'bg-accent text-accent-foreground font-semibold',
6000
+ // Single selected
6001
+ day.isSelected && this.mode() === 'single' && 'bg-primary text-primary-foreground font-semibold shadow-sm',
6002
+ // Range endpoints
6003
+ isEndpoint && 'bg-primary text-primary-foreground font-semibold shadow-sm',
6004
+ // Range band
6005
+ day.isInRange && 'bg-primary/10 text-foreground', day.isRangePreview && 'bg-primary/5 text-foreground',
6006
+ // States
6007
+ day.isDisabled && 'opacity-40 cursor-not-allowed pointer-events-none', !day.isDisabled && !day.isSelected && !isEndpoint && 'hover:bg-accent hover:text-accent-foreground cursor-pointer');
6008
+ }
6009
+ // Private helpers
5937
6010
  navigateDays(offset) {
5938
6011
  const current = this.value() ?? new Date();
5939
6012
  const next = new Date(current);
@@ -5942,12 +6015,41 @@ class SnyCalendarComponent {
5942
6015
  this._onChange(next);
5943
6016
  this.viewDate.set(new Date(next.getFullYear(), next.getMonth(), 1));
5944
6017
  }
5945
- createDay(date, isCurrentMonth, today, selected, minDate, maxDate) {
6018
+ createDay(date, isCurrentMonth, today, selected, rangeVal, hoveredDate, minDate, maxDate) {
5946
6019
  const isToday = this.isSameDay(date, today);
5947
6020
  const isSelected = selected ? this.isSameDay(date, selected) : false;
5948
6021
  const isDisabled = this._disabledByCva() ||
5949
- (minDate ? date < minDate : false) || (maxDate ? date > maxDate : false);
5950
- return { date, day: date.getDate(), isCurrentMonth, isToday, isSelected, isDisabled };
6022
+ (minDate ? date < minDate : false) ||
6023
+ (maxDate ? date > maxDate : false);
6024
+ let isRangeStart = false;
6025
+ let isRangeEnd = false;
6026
+ let isInRange = false;
6027
+ let isRangePreview = false;
6028
+ if (rangeVal) {
6029
+ const { start, end } = rangeVal;
6030
+ if (start)
6031
+ isRangeStart = this.isSameDay(date, start);
6032
+ if (end)
6033
+ isRangeEnd = this.isSameDay(date, end);
6034
+ if (start && end) {
6035
+ isInRange = date > start && date < end && !isRangeStart && !isRangeEnd;
6036
+ }
6037
+ // Preview: start set, no end yet, user hovering
6038
+ if (start && !end && hoveredDate && !this.isSameDay(hoveredDate, start)) {
6039
+ const previewStart = hoveredDate > start ? start : hoveredDate;
6040
+ const previewEnd = hoveredDate > start ? hoveredDate : start;
6041
+ if (date > previewStart && date < previewEnd) {
6042
+ isRangePreview = true;
6043
+ }
6044
+ if (this.isSameDay(date, hoveredDate) && !isRangeStart) {
6045
+ isRangePreview = true;
6046
+ }
6047
+ }
6048
+ }
6049
+ return {
6050
+ date, day: date.getDate(), isCurrentMonth, isToday, isSelected, isDisabled,
6051
+ isRangeStart, isRangeEnd, isInRange, isRangePreview,
6052
+ };
5951
6053
  }
5952
6054
  isSameDay(a, b) {
5953
6055
  return (a.getFullYear() === b.getFullYear() &&
@@ -5955,39 +6057,48 @@ class SnyCalendarComponent {
5955
6057
  a.getDate() === b.getDate());
5956
6058
  }
5957
6059
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5958
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: SnyCalendarComponent, isStandalone: true, selector: "sny-calendar", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { listeners: { "keydown": "onKeydown($event)" }, properties: { "class": "\"inline-block p-3 rounded-md border bg-background\"" } }, providers: [
6060
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: SnyCalendarComponent, isStandalone: true, selector: "sny-calendar", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, rangeValue: { classPropertyName: "rangeValue", publicName: "rangeValue", isSignal: true, isRequired: false, transformFunction: null }, showNavigation: { classPropertyName: "showNavigation", publicName: "showNavigation", isSignal: true, isRequired: false, transformFunction: null }, initialViewDate: { classPropertyName: "initialViewDate", publicName: "initialViewDate", isSignal: true, isRequired: false, transformFunction: null }, borderless: { classPropertyName: "borderless", publicName: "borderless", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", rangeValue: "rangeValueChange" }, host: { attributes: { "role": "application", "aria-label": "Calendar" }, listeners: { "keydown": "onKeydown($event)" }, properties: { "class": "hostClass()" } }, providers: [
5959
6061
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SnyCalendarComponent), multi: true },
5960
6062
  ], ngImport: i0, template: `
5961
- <div class="flex items-center justify-between mb-4">
5962
- <button
5963
- class="inline-flex items-center justify-center rounded-md text-sm h-7 w-7 hover:bg-accent"
5964
- (click)="prevMonth()"
5965
- aria-label="Previous month"
5966
- >
5967
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m15 18-6-6 6-6"/></svg>
5968
- </button>
5969
- <span class="text-sm font-medium">{{ monthYearLabel() }}</span>
5970
- <button
5971
- class="inline-flex items-center justify-center rounded-md text-sm h-7 w-7 hover:bg-accent"
5972
- (click)="nextMonth()"
5973
- aria-label="Next month"
5974
- >
5975
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m9 18 6-6-6-6"/></svg>
5976
- </button>
5977
- </div>
6063
+ @if (showNavigation()) {
6064
+ <div class="flex items-center justify-between mb-3">
6065
+ <button
6066
+ type="button"
6067
+ class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
6068
+ (click)="prevMonth()"
6069
+ aria-label="Previous month"
6070
+ >
6071
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
6072
+ </button>
6073
+ <span class="text-sm font-semibold tracking-tight">{{ monthYearLabel() }}</span>
6074
+ <button
6075
+ type="button"
6076
+ class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
6077
+ (click)="nextMonth()"
6078
+ aria-label="Next month"
6079
+ >
6080
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
6081
+ </button>
6082
+ </div>
6083
+ }
5978
6084
 
5979
- <div role="grid" aria-label="Calendar" class="grid grid-cols-7 gap-0">
6085
+ <div role="grid" class="grid grid-cols-7 gap-1">
5980
6086
  @for (dayName of weekDays; track dayName) {
5981
- <div class="text-center text-xs text-muted-foreground font-medium py-1">{{ dayName }}</div>
6087
+ <div class="text-center text-xs text-muted-foreground font-medium h-9 flex items-center justify-center" role="columnheader">{{ dayName }}</div>
5982
6088
  }
5983
6089
  @for (day of days(); track day.date.getTime()) {
5984
6090
  <button
6091
+ type="button"
5985
6092
  [class]="dayClass(day)"
5986
6093
  [disabled]="day.isDisabled"
5987
- [attr.aria-selected]="day.isSelected || null"
6094
+ [attr.aria-selected]="day.isSelected || day.isRangeStart || day.isRangeEnd || null"
5988
6095
  [attr.aria-current]="day.isToday ? 'date' : null"
5989
6096
  [attr.aria-disabled]="day.isDisabled || null"
5990
- (click)="selectDate(day.date)"
6097
+ [attr.aria-label]="day.date.toLocaleDateString(locale(), { month: 'long', day: 'numeric', year: 'numeric' })"
6098
+ role="gridcell"
6099
+ (click)="onDayClick(day.date)"
6100
+ (mouseenter)="onDayHover(day.date)"
6101
+ (mouseleave)="onDayHover(null)"
5991
6102
  >
5992
6103
  {{ day.day }}
5993
6104
  </button>
@@ -6002,43 +6113,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
6002
6113
  standalone: true,
6003
6114
  changeDetection: ChangeDetectionStrategy.OnPush,
6004
6115
  host: {
6005
- '[class]': '"inline-block p-3 rounded-md border bg-background"',
6116
+ '[class]': 'hostClass()',
6006
6117
  '(keydown)': 'onKeydown($event)',
6118
+ 'role': 'application',
6119
+ 'aria-label': 'Calendar',
6007
6120
  },
6008
6121
  providers: [
6009
6122
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SnyCalendarComponent), multi: true },
6010
6123
  ],
6011
6124
  template: `
6012
- <div class="flex items-center justify-between mb-4">
6013
- <button
6014
- class="inline-flex items-center justify-center rounded-md text-sm h-7 w-7 hover:bg-accent"
6015
- (click)="prevMonth()"
6016
- aria-label="Previous month"
6017
- >
6018
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m15 18-6-6 6-6"/></svg>
6019
- </button>
6020
- <span class="text-sm font-medium">{{ monthYearLabel() }}</span>
6021
- <button
6022
- class="inline-flex items-center justify-center rounded-md text-sm h-7 w-7 hover:bg-accent"
6023
- (click)="nextMonth()"
6024
- aria-label="Next month"
6025
- >
6026
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m9 18 6-6-6-6"/></svg>
6027
- </button>
6028
- </div>
6125
+ @if (showNavigation()) {
6126
+ <div class="flex items-center justify-between mb-3">
6127
+ <button
6128
+ type="button"
6129
+ class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
6130
+ (click)="prevMonth()"
6131
+ aria-label="Previous month"
6132
+ >
6133
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
6134
+ </button>
6135
+ <span class="text-sm font-semibold tracking-tight">{{ monthYearLabel() }}</span>
6136
+ <button
6137
+ type="button"
6138
+ class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
6139
+ (click)="nextMonth()"
6140
+ aria-label="Next month"
6141
+ >
6142
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
6143
+ </button>
6144
+ </div>
6145
+ }
6029
6146
 
6030
- <div role="grid" aria-label="Calendar" class="grid grid-cols-7 gap-0">
6147
+ <div role="grid" class="grid grid-cols-7 gap-1">
6031
6148
  @for (dayName of weekDays; track dayName) {
6032
- <div class="text-center text-xs text-muted-foreground font-medium py-1">{{ dayName }}</div>
6149
+ <div class="text-center text-xs text-muted-foreground font-medium h-9 flex items-center justify-center" role="columnheader">{{ dayName }}</div>
6033
6150
  }
6034
6151
  @for (day of days(); track day.date.getTime()) {
6035
6152
  <button
6153
+ type="button"
6036
6154
  [class]="dayClass(day)"
6037
6155
  [disabled]="day.isDisabled"
6038
- [attr.aria-selected]="day.isSelected || null"
6156
+ [attr.aria-selected]="day.isSelected || day.isRangeStart || day.isRangeEnd || null"
6039
6157
  [attr.aria-current]="day.isToday ? 'date' : null"
6040
6158
  [attr.aria-disabled]="day.isDisabled || null"
6041
- (click)="selectDate(day.date)"
6159
+ [attr.aria-label]="day.date.toLocaleDateString(locale(), { month: 'long', day: 'numeric', year: 'numeric' })"
6160
+ role="gridcell"
6161
+ (click)="onDayClick(day.date)"
6162
+ (mouseenter)="onDayHover(day.date)"
6163
+ (mouseleave)="onDayHover(null)"
6042
6164
  >
6043
6165
  {{ day.day }}
6044
6166
  </button>
@@ -6046,7 +6168,687 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
6046
6168
  </div>
6047
6169
  `,
6048
6170
  }]
6049
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
6171
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], rangeValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeValue", required: false }] }, { type: i0.Output, args: ["rangeValueChange"] }], showNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "showNavigation", required: false }] }], initialViewDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialViewDate", required: false }] }], borderless: [{ type: i0.Input, args: [{ isSignal: true, alias: "borderless", required: false }] }] } });
6172
+
6173
+ const datePickerTriggerVariants = cva('inline-flex w-full items-center justify-between whitespace-nowrap rounded-sm border border-border bg-background px-3 py-2 text-sm ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', {
6174
+ variants: {
6175
+ size: {
6176
+ sm: 'h-9 text-xs',
6177
+ md: 'h-10 text-sm',
6178
+ lg: 'h-11 text-base',
6179
+ },
6180
+ },
6181
+ defaultVariants: { size: 'md' },
6182
+ });
6183
+
6184
+ class SnyDatePickerComponent {
6185
+ value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
6186
+ placeholder = input('Pick a date...', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
6187
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
6188
+ locale = input('en-US', ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
6189
+ dateFormat = input({
6190
+ month: 'short',
6191
+ day: 'numeric',
6192
+ year: 'numeric',
6193
+ }, ...(ngDevMode ? [{ debugName: "dateFormat" }] : /* istanbul ignore next */ []));
6194
+ min = input(undefined, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
6195
+ max = input(undefined, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
6196
+ clearable = input(true, ...(ngDevMode ? [{ debugName: "clearable" }] : /* istanbul ignore next */ []));
6197
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
6198
+ class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
6199
+ open = signal(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
6200
+ internalValue = signal(null, ...(ngDevMode ? [{ debugName: "internalValue" }] : /* istanbul ignore next */ []));
6201
+ _disabledByCva = signal(false, ...(ngDevMode ? [{ debugName: "_disabledByCva" }] : /* istanbul ignore next */ []));
6202
+ isDisabled = computed(() => this.disabled() || this._disabledByCva(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
6203
+ triggerRef = viewChild('triggerEl', ...(ngDevMode ? [{ debugName: "triggerRef" }] : /* istanbul ignore next */ []));
6204
+ dropdownRef = viewChild('dropdownEl', ...(ngDevMode ? [{ debugName: "dropdownRef" }] : /* istanbul ignore next */ []));
6205
+ elRef = inject(ElementRef);
6206
+ scrollHandler = null;
6207
+ resizeHandler = null;
6208
+ _onChange = () => { };
6209
+ onTouched = () => { };
6210
+ // CVA
6211
+ writeValue(val) {
6212
+ this.value.set(val ?? null);
6213
+ this.internalValue.set(val ?? null);
6214
+ }
6215
+ registerOnChange(fn) {
6216
+ this._onChange = fn;
6217
+ }
6218
+ registerOnTouched(fn) {
6219
+ this.onTouched = fn;
6220
+ }
6221
+ setDisabledState(isDisabled) {
6222
+ this._disabledByCva.set(isDisabled);
6223
+ }
6224
+ // Display
6225
+ displayValue = computed(() => {
6226
+ const d = this.value();
6227
+ if (!d)
6228
+ return '';
6229
+ return d.toLocaleDateString(this.locale(), this.dateFormat());
6230
+ }, ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
6231
+ triggerClass = computed(() => cn(datePickerTriggerVariants({ size: this.size() }), this.class()), ...(ngDevMode ? [{ debugName: "triggerClass" }] : /* istanbul ignore next */ []));
6232
+ // Actions
6233
+ onDateSelected(date) {
6234
+ this.value.set(date);
6235
+ this._onChange(date);
6236
+ this.close();
6237
+ }
6238
+ clear(event) {
6239
+ event.stopPropagation();
6240
+ this.value.set(null);
6241
+ this.internalValue.set(null);
6242
+ this._onChange(null);
6243
+ }
6244
+ toggle() {
6245
+ if (this.open()) {
6246
+ this.close();
6247
+ }
6248
+ else {
6249
+ this.internalValue.set(this.value());
6250
+ this.updateDropdownPosition();
6251
+ this.open.set(true);
6252
+ this.addGlobalListeners();
6253
+ setTimeout(() => this.updateDropdownPosition());
6254
+ }
6255
+ }
6256
+ close() {
6257
+ this.open.set(false);
6258
+ this.removeGlobalListeners();
6259
+ }
6260
+ // Positioning (combobox pattern)
6261
+ updateDropdownPosition() {
6262
+ const trigger = this.triggerRef()?.nativeElement;
6263
+ if (!trigger)
6264
+ return;
6265
+ const rect = trigger.getBoundingClientRect();
6266
+ const dropdown = this.dropdownRef()?.nativeElement;
6267
+ if (dropdown) {
6268
+ dropdown.style.top = `${rect.bottom + 4}px`;
6269
+ dropdown.style.left = `${rect.left}px`;
6270
+ }
6271
+ }
6272
+ addGlobalListeners() {
6273
+ this.removeGlobalListeners();
6274
+ this.scrollHandler = () => {
6275
+ requestAnimationFrame(() => this.updateDropdownPosition());
6276
+ };
6277
+ this.resizeHandler = () => {
6278
+ requestAnimationFrame(() => this.updateDropdownPosition());
6279
+ };
6280
+ document.addEventListener('scroll', this.scrollHandler, { capture: true, passive: true });
6281
+ window.addEventListener('resize', this.resizeHandler, { passive: true });
6282
+ }
6283
+ removeGlobalListeners() {
6284
+ if (this.scrollHandler) {
6285
+ document.removeEventListener('scroll', this.scrollHandler, { capture: true });
6286
+ this.scrollHandler = null;
6287
+ }
6288
+ if (this.resizeHandler) {
6289
+ window.removeEventListener('resize', this.resizeHandler);
6290
+ this.resizeHandler = null;
6291
+ }
6292
+ }
6293
+ ngOnDestroy() {
6294
+ this.removeGlobalListeners();
6295
+ }
6296
+ onDocumentClick(event) {
6297
+ if (!this.elRef.nativeElement.contains(event.target)) {
6298
+ this.close();
6299
+ }
6300
+ }
6301
+ onEscape() {
6302
+ this.close();
6303
+ }
6304
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6305
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: SnyDatePickerComponent, isStandalone: true, selector: "sny-date-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { listeners: { "document:click": "onDocumentClick($event)", "keydown.escape": "onEscape()" }, classAttribute: "relative inline-block w-full" }, providers: [
6306
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SnyDatePickerComponent), multi: true },
6307
+ ], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "dropdownRef", first: true, predicate: ["dropdownEl"], descendants: true, isSignal: true }], ngImport: i0, template: `
6308
+ <button
6309
+ #triggerEl
6310
+ type="button"
6311
+ role="combobox"
6312
+ [attr.aria-expanded]="open()"
6313
+ aria-haspopup="dialog"
6314
+ [disabled]="isDisabled()"
6315
+ [class]="triggerClass()"
6316
+ (click)="toggle()"
6317
+ (blur)="onTouched()"
6318
+ >
6319
+ <span [class]="displayValue() ? 'truncate' : 'text-muted-foreground truncate'">
6320
+ {{ displayValue() || placeholder() }}
6321
+ </span>
6322
+ <div class="flex items-center gap-1 shrink-0">
6323
+ @if (clearable() && value()) {
6324
+ <button
6325
+ type="button"
6326
+ class="rounded-sm p-0.5 hover:bg-muted transition-colors text-muted-foreground hover:text-foreground"
6327
+ (click)="clear($event)"
6328
+ aria-label="Clear date"
6329
+ >
6330
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
6331
+ </button>
6332
+ }
6333
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-muted-foreground"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
6334
+ </div>
6335
+ </button>
6336
+
6337
+ @if (open()) {
6338
+ <div
6339
+ #dropdownEl
6340
+ role="dialog"
6341
+ aria-modal="true"
6342
+ aria-label="Choose date"
6343
+ class="fixed z-50 rounded-md border border-border bg-popover text-popover-foreground shadow-lg animate-in fade-in-0 zoom-in-95"
6344
+ >
6345
+ <sny-calendar
6346
+ [(value)]="internalValue"
6347
+ [min]="min()"
6348
+ [max]="max()"
6349
+ [locale]="locale()"
6350
+ (valueChange)="onDateSelected($event)"
6351
+ />
6352
+ </div>
6353
+ }
6354
+ `, isInline: true, dependencies: [{ kind: "component", type: SnyCalendarComponent, selector: "sny-calendar", inputs: ["value", "min", "max", "locale", "class", "mode", "rangeValue", "showNavigation", "initialViewDate", "borderless"], outputs: ["valueChange", "rangeValueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6355
+ }
6356
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDatePickerComponent, decorators: [{
6357
+ type: Component,
6358
+ args: [{
6359
+ selector: 'sny-date-picker',
6360
+ standalone: true,
6361
+ changeDetection: ChangeDetectionStrategy.OnPush,
6362
+ imports: [SnyCalendarComponent],
6363
+ host: { class: 'relative inline-block w-full' },
6364
+ providers: [
6365
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SnyDatePickerComponent), multi: true },
6366
+ ],
6367
+ template: `
6368
+ <button
6369
+ #triggerEl
6370
+ type="button"
6371
+ role="combobox"
6372
+ [attr.aria-expanded]="open()"
6373
+ aria-haspopup="dialog"
6374
+ [disabled]="isDisabled()"
6375
+ [class]="triggerClass()"
6376
+ (click)="toggle()"
6377
+ (blur)="onTouched()"
6378
+ >
6379
+ <span [class]="displayValue() ? 'truncate' : 'text-muted-foreground truncate'">
6380
+ {{ displayValue() || placeholder() }}
6381
+ </span>
6382
+ <div class="flex items-center gap-1 shrink-0">
6383
+ @if (clearable() && value()) {
6384
+ <button
6385
+ type="button"
6386
+ class="rounded-sm p-0.5 hover:bg-muted transition-colors text-muted-foreground hover:text-foreground"
6387
+ (click)="clear($event)"
6388
+ aria-label="Clear date"
6389
+ >
6390
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
6391
+ </button>
6392
+ }
6393
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-muted-foreground"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
6394
+ </div>
6395
+ </button>
6396
+
6397
+ @if (open()) {
6398
+ <div
6399
+ #dropdownEl
6400
+ role="dialog"
6401
+ aria-modal="true"
6402
+ aria-label="Choose date"
6403
+ class="fixed z-50 rounded-md border border-border bg-popover text-popover-foreground shadow-lg animate-in fade-in-0 zoom-in-95"
6404
+ >
6405
+ <sny-calendar
6406
+ [(value)]="internalValue"
6407
+ [min]="min()"
6408
+ [max]="max()"
6409
+ [locale]="locale()"
6410
+ (valueChange)="onDateSelected($event)"
6411
+ />
6412
+ </div>
6413
+ }
6414
+ `,
6415
+ }]
6416
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], triggerRef: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], dropdownRef: [{ type: i0.ViewChild, args: ['dropdownEl', { isSignal: true }] }], onDocumentClick: [{
6417
+ type: HostListener,
6418
+ args: ['document:click', ['$event']]
6419
+ }], onEscape: [{
6420
+ type: HostListener,
6421
+ args: ['keydown.escape']
6422
+ }] } });
6423
+
6424
+ class SnyDateRangePickerComponent {
6425
+ value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
6426
+ placeholder = input('Pick a date range...', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
6427
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
6428
+ locale = input('en-US', ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
6429
+ dateFormat = input({
6430
+ month: 'short',
6431
+ day: 'numeric',
6432
+ year: 'numeric',
6433
+ }, ...(ngDevMode ? [{ debugName: "dateFormat" }] : /* istanbul ignore next */ []));
6434
+ separator = input(' \u2014 ', ...(ngDevMode ? [{ debugName: "separator" }] : /* istanbul ignore next */ []));
6435
+ dualCalendar = input(false, ...(ngDevMode ? [{ debugName: "dualCalendar" }] : /* istanbul ignore next */ []));
6436
+ presets = input([], ...(ngDevMode ? [{ debugName: "presets" }] : /* istanbul ignore next */ []));
6437
+ min = input(undefined, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
6438
+ max = input(undefined, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
6439
+ clearable = input(true, ...(ngDevMode ? [{ debugName: "clearable" }] : /* istanbul ignore next */ []));
6440
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
6441
+ class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
6442
+ open = signal(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
6443
+ internalRange = signal(null, ...(ngDevMode ? [{ debugName: "internalRange" }] : /* istanbul ignore next */ []));
6444
+ leftViewDate = signal(new Date(), ...(ngDevMode ? [{ debugName: "leftViewDate" }] : /* istanbul ignore next */ []));
6445
+ _disabledByCva = signal(false, ...(ngDevMode ? [{ debugName: "_disabledByCva" }] : /* istanbul ignore next */ []));
6446
+ isDisabled = computed(() => this.disabled() || this._disabledByCva(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
6447
+ triggerRef = viewChild('triggerEl', ...(ngDevMode ? [{ debugName: "triggerRef" }] : /* istanbul ignore next */ []));
6448
+ dropdownRef = viewChild('dropdownEl', ...(ngDevMode ? [{ debugName: "dropdownRef" }] : /* istanbul ignore next */ []));
6449
+ elRef = inject(ElementRef);
6450
+ scrollHandler = null;
6451
+ resizeHandler = null;
6452
+ _onChange = () => { };
6453
+ onTouched = () => { };
6454
+ // Computed
6455
+ rightViewDate = computed(() => {
6456
+ const d = this.leftViewDate();
6457
+ return new Date(d.getFullYear(), d.getMonth() + 1, 1);
6458
+ }, ...(ngDevMode ? [{ debugName: "rightViewDate" }] : /* istanbul ignore next */ []));
6459
+ leftMonthLabel = computed(() => this.leftViewDate().toLocaleDateString(this.locale(), { month: 'long', year: 'numeric' }), ...(ngDevMode ? [{ debugName: "leftMonthLabel" }] : /* istanbul ignore next */ []));
6460
+ rightMonthLabel = computed(() => this.rightViewDate().toLocaleDateString(this.locale(), { month: 'long', year: 'numeric' }), ...(ngDevMode ? [{ debugName: "rightMonthLabel" }] : /* istanbul ignore next */ []));
6461
+ displayValue = computed(() => {
6462
+ const r = this.value();
6463
+ if (!r?.start)
6464
+ return '';
6465
+ const fmt = (d) => d.toLocaleDateString(this.locale(), this.dateFormat());
6466
+ if (!r.end)
6467
+ return fmt(r.start) + this.separator() + '...';
6468
+ return fmt(r.start) + this.separator() + fmt(r.end);
6469
+ }, ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
6470
+ triggerClass = computed(() => cn(datePickerTriggerVariants({ size: this.size() }), this.class()), ...(ngDevMode ? [{ debugName: "triggerClass" }] : /* istanbul ignore next */ []));
6471
+ // CVA
6472
+ writeValue(val) {
6473
+ this.value.set(val ?? null);
6474
+ this.internalRange.set(val ?? null);
6475
+ if (val?.start) {
6476
+ this.leftViewDate.set(new Date(val.start.getFullYear(), val.start.getMonth(), 1));
6477
+ }
6478
+ }
6479
+ registerOnChange(fn) {
6480
+ this._onChange = fn;
6481
+ }
6482
+ registerOnTouched(fn) {
6483
+ this.onTouched = fn;
6484
+ }
6485
+ setDisabledState(isDisabled) {
6486
+ this._disabledByCva.set(isDisabled);
6487
+ }
6488
+ // Actions
6489
+ onRangeChanged(range) {
6490
+ this.internalRange.set(range);
6491
+ if (range?.start && range?.end) {
6492
+ this.value.set(range);
6493
+ this._onChange(range);
6494
+ setTimeout(() => this.close(), 150);
6495
+ }
6496
+ }
6497
+ selectPreset(preset) {
6498
+ this.value.set(preset.range);
6499
+ this.internalRange.set(preset.range);
6500
+ this._onChange(preset.range);
6501
+ this.close();
6502
+ }
6503
+ clear(event) {
6504
+ event.stopPropagation();
6505
+ this.value.set(null);
6506
+ this.internalRange.set(null);
6507
+ this._onChange(null);
6508
+ }
6509
+ prevMonth() {
6510
+ this.leftViewDate.update((d) => new Date(d.getFullYear(), d.getMonth() - 1, 1));
6511
+ }
6512
+ nextMonth() {
6513
+ this.leftViewDate.update((d) => new Date(d.getFullYear(), d.getMonth() + 1, 1));
6514
+ }
6515
+ toggle() {
6516
+ if (this.open()) {
6517
+ this.close();
6518
+ }
6519
+ else {
6520
+ this.internalRange.set(this.value());
6521
+ this.updateDropdownPosition();
6522
+ this.open.set(true);
6523
+ this.addGlobalListeners();
6524
+ setTimeout(() => this.updateDropdownPosition());
6525
+ }
6526
+ }
6527
+ close() {
6528
+ this.open.set(false);
6529
+ this.removeGlobalListeners();
6530
+ }
6531
+ // Positioning
6532
+ updateDropdownPosition() {
6533
+ const trigger = this.triggerRef()?.nativeElement;
6534
+ if (!trigger)
6535
+ return;
6536
+ const rect = trigger.getBoundingClientRect();
6537
+ const dropdown = this.dropdownRef()?.nativeElement;
6538
+ if (dropdown) {
6539
+ dropdown.style.top = `${rect.bottom + 4}px`;
6540
+ dropdown.style.left = `${rect.left}px`;
6541
+ }
6542
+ }
6543
+ addGlobalListeners() {
6544
+ this.removeGlobalListeners();
6545
+ this.scrollHandler = () => {
6546
+ requestAnimationFrame(() => this.updateDropdownPosition());
6547
+ };
6548
+ this.resizeHandler = () => {
6549
+ requestAnimationFrame(() => this.updateDropdownPosition());
6550
+ };
6551
+ document.addEventListener('scroll', this.scrollHandler, { capture: true, passive: true });
6552
+ window.addEventListener('resize', this.resizeHandler, { passive: true });
6553
+ }
6554
+ removeGlobalListeners() {
6555
+ if (this.scrollHandler) {
6556
+ document.removeEventListener('scroll', this.scrollHandler, { capture: true });
6557
+ this.scrollHandler = null;
6558
+ }
6559
+ if (this.resizeHandler) {
6560
+ window.removeEventListener('resize', this.resizeHandler);
6561
+ this.resizeHandler = null;
6562
+ }
6563
+ }
6564
+ ngOnDestroy() {
6565
+ this.removeGlobalListeners();
6566
+ }
6567
+ onDocumentClick(event) {
6568
+ if (!this.elRef.nativeElement.contains(event.target)) {
6569
+ this.close();
6570
+ }
6571
+ }
6572
+ onEscape() {
6573
+ this.close();
6574
+ }
6575
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDateRangePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6576
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: SnyDateRangePickerComponent, isStandalone: true, selector: "sny-date-range-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, dualCalendar: { classPropertyName: "dualCalendar", publicName: "dualCalendar", isSignal: true, isRequired: false, transformFunction: null }, presets: { classPropertyName: "presets", publicName: "presets", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { listeners: { "document:click": "onDocumentClick($event)", "keydown.escape": "onEscape()" }, classAttribute: "relative inline-block w-full" }, providers: [
6577
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SnyDateRangePickerComponent), multi: true },
6578
+ ], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "dropdownRef", first: true, predicate: ["dropdownEl"], descendants: true, isSignal: true }], ngImport: i0, template: `
6579
+ <button
6580
+ #triggerEl
6581
+ type="button"
6582
+ role="combobox"
6583
+ [attr.aria-expanded]="open()"
6584
+ aria-haspopup="dialog"
6585
+ [disabled]="isDisabled()"
6586
+ [class]="triggerClass()"
6587
+ (click)="toggle()"
6588
+ (blur)="onTouched()"
6589
+ >
6590
+ <span [class]="displayValue() ? 'truncate' : 'text-muted-foreground truncate'">
6591
+ {{ displayValue() || placeholder() }}
6592
+ </span>
6593
+ <div class="flex items-center gap-1 shrink-0">
6594
+ @if (clearable() && value()?.start) {
6595
+ <button
6596
+ type="button"
6597
+ class="rounded-sm p-0.5 hover:bg-muted transition-colors text-muted-foreground hover:text-foreground"
6598
+ (click)="clear($event)"
6599
+ aria-label="Clear date range"
6600
+ >
6601
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
6602
+ </button>
6603
+ }
6604
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-muted-foreground"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
6605
+ </div>
6606
+ </button>
6607
+
6608
+ @if (open()) {
6609
+ <div
6610
+ #dropdownEl
6611
+ role="dialog"
6612
+ aria-modal="true"
6613
+ aria-label="Choose date range"
6614
+ class="fixed z-50 rounded-md border border-border bg-popover text-popover-foreground shadow-lg animate-in fade-in-0 zoom-in-95"
6615
+ >
6616
+ <div class="flex flex-col sm:flex-row">
6617
+ <!-- Presets sidebar -->
6618
+ @if (presets().length > 0) {
6619
+ <div class="border-b sm:border-b-0 sm:border-r border-border p-3 space-y-0.5 sm:min-w-[150px]">
6620
+ <p class="px-3 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wider">Presets</p>
6621
+ @for (preset of presets(); track preset.label) {
6622
+ <button
6623
+ type="button"
6624
+ class="w-full text-left px-3 py-2 text-sm rounded-md hover:bg-accent hover:text-accent-foreground transition-colors cursor-pointer"
6625
+ (mousedown)="selectPreset(preset); $event.preventDefault()"
6626
+ >
6627
+ {{ preset.label }}
6628
+ </button>
6629
+ }
6630
+ </div>
6631
+ }
6632
+
6633
+ <!-- Calendar(s) -->
6634
+ <div class="flex flex-col sm:flex-row">
6635
+ @if (dualCalendar()) {
6636
+ <!-- Left calendar -->
6637
+ <div class="p-1">
6638
+ <div class="flex items-center justify-between px-3 py-2">
6639
+ <button
6640
+ type="button"
6641
+ class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
6642
+ (click)="prevMonth()"
6643
+ aria-label="Previous month"
6644
+ >
6645
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
6646
+ </button>
6647
+ <span class="text-sm font-semibold tracking-tight">{{ leftMonthLabel() }}</span>
6648
+ <div class="w-8"></div>
6649
+ </div>
6650
+ <sny-calendar
6651
+ mode="range"
6652
+ [(rangeValue)]="internalRange"
6653
+ [min]="min()"
6654
+ [max]="max()"
6655
+ [locale]="locale()"
6656
+ [showNavigation]="false"
6657
+ [borderless]="true"
6658
+ [initialViewDate]="leftViewDate()"
6659
+ (rangeValueChange)="onRangeChanged($event)"
6660
+ />
6661
+ </div>
6662
+ <div class="border-t sm:border-t-0 sm:border-l border-border"></div>
6663
+ <!-- Right calendar -->
6664
+ <div class="p-1">
6665
+ <div class="flex items-center justify-between px-3 py-2">
6666
+ <div class="w-8"></div>
6667
+ <span class="text-sm font-semibold tracking-tight">{{ rightMonthLabel() }}</span>
6668
+ <button
6669
+ type="button"
6670
+ class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
6671
+ (click)="nextMonth()"
6672
+ aria-label="Next month"
6673
+ >
6674
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
6675
+ </button>
6676
+ </div>
6677
+ <sny-calendar
6678
+ mode="range"
6679
+ [(rangeValue)]="internalRange"
6680
+ [min]="min()"
6681
+ [max]="max()"
6682
+ [locale]="locale()"
6683
+ [showNavigation]="false"
6684
+ [borderless]="true"
6685
+ [initialViewDate]="rightViewDate()"
6686
+ (rangeValueChange)="onRangeChanged($event)"
6687
+ />
6688
+ </div>
6689
+ } @else {
6690
+ <!-- Single calendar -->
6691
+ <sny-calendar
6692
+ mode="range"
6693
+ [(rangeValue)]="internalRange"
6694
+ [min]="min()"
6695
+ [max]="max()"
6696
+ [locale]="locale()"
6697
+ (rangeValueChange)="onRangeChanged($event)"
6698
+ />
6699
+ }
6700
+ </div>
6701
+ </div>
6702
+ </div>
6703
+ }
6704
+ `, isInline: true, dependencies: [{ kind: "component", type: SnyCalendarComponent, selector: "sny-calendar", inputs: ["value", "min", "max", "locale", "class", "mode", "rangeValue", "showNavigation", "initialViewDate", "borderless"], outputs: ["valueChange", "rangeValueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6705
+ }
6706
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDateRangePickerComponent, decorators: [{
6707
+ type: Component,
6708
+ args: [{
6709
+ selector: 'sny-date-range-picker',
6710
+ standalone: true,
6711
+ changeDetection: ChangeDetectionStrategy.OnPush,
6712
+ imports: [SnyCalendarComponent],
6713
+ host: { class: 'relative inline-block w-full' },
6714
+ providers: [
6715
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SnyDateRangePickerComponent), multi: true },
6716
+ ],
6717
+ template: `
6718
+ <button
6719
+ #triggerEl
6720
+ type="button"
6721
+ role="combobox"
6722
+ [attr.aria-expanded]="open()"
6723
+ aria-haspopup="dialog"
6724
+ [disabled]="isDisabled()"
6725
+ [class]="triggerClass()"
6726
+ (click)="toggle()"
6727
+ (blur)="onTouched()"
6728
+ >
6729
+ <span [class]="displayValue() ? 'truncate' : 'text-muted-foreground truncate'">
6730
+ {{ displayValue() || placeholder() }}
6731
+ </span>
6732
+ <div class="flex items-center gap-1 shrink-0">
6733
+ @if (clearable() && value()?.start) {
6734
+ <button
6735
+ type="button"
6736
+ class="rounded-sm p-0.5 hover:bg-muted transition-colors text-muted-foreground hover:text-foreground"
6737
+ (click)="clear($event)"
6738
+ aria-label="Clear date range"
6739
+ >
6740
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
6741
+ </button>
6742
+ }
6743
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-muted-foreground"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
6744
+ </div>
6745
+ </button>
6746
+
6747
+ @if (open()) {
6748
+ <div
6749
+ #dropdownEl
6750
+ role="dialog"
6751
+ aria-modal="true"
6752
+ aria-label="Choose date range"
6753
+ class="fixed z-50 rounded-md border border-border bg-popover text-popover-foreground shadow-lg animate-in fade-in-0 zoom-in-95"
6754
+ >
6755
+ <div class="flex flex-col sm:flex-row">
6756
+ <!-- Presets sidebar -->
6757
+ @if (presets().length > 0) {
6758
+ <div class="border-b sm:border-b-0 sm:border-r border-border p-3 space-y-0.5 sm:min-w-[150px]">
6759
+ <p class="px-3 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wider">Presets</p>
6760
+ @for (preset of presets(); track preset.label) {
6761
+ <button
6762
+ type="button"
6763
+ class="w-full text-left px-3 py-2 text-sm rounded-md hover:bg-accent hover:text-accent-foreground transition-colors cursor-pointer"
6764
+ (mousedown)="selectPreset(preset); $event.preventDefault()"
6765
+ >
6766
+ {{ preset.label }}
6767
+ </button>
6768
+ }
6769
+ </div>
6770
+ }
6771
+
6772
+ <!-- Calendar(s) -->
6773
+ <div class="flex flex-col sm:flex-row">
6774
+ @if (dualCalendar()) {
6775
+ <!-- Left calendar -->
6776
+ <div class="p-1">
6777
+ <div class="flex items-center justify-between px-3 py-2">
6778
+ <button
6779
+ type="button"
6780
+ class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
6781
+ (click)="prevMonth()"
6782
+ aria-label="Previous month"
6783
+ >
6784
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
6785
+ </button>
6786
+ <span class="text-sm font-semibold tracking-tight">{{ leftMonthLabel() }}</span>
6787
+ <div class="w-8"></div>
6788
+ </div>
6789
+ <sny-calendar
6790
+ mode="range"
6791
+ [(rangeValue)]="internalRange"
6792
+ [min]="min()"
6793
+ [max]="max()"
6794
+ [locale]="locale()"
6795
+ [showNavigation]="false"
6796
+ [borderless]="true"
6797
+ [initialViewDate]="leftViewDate()"
6798
+ (rangeValueChange)="onRangeChanged($event)"
6799
+ />
6800
+ </div>
6801
+ <div class="border-t sm:border-t-0 sm:border-l border-border"></div>
6802
+ <!-- Right calendar -->
6803
+ <div class="p-1">
6804
+ <div class="flex items-center justify-between px-3 py-2">
6805
+ <div class="w-8"></div>
6806
+ <span class="text-sm font-semibold tracking-tight">{{ rightMonthLabel() }}</span>
6807
+ <button
6808
+ type="button"
6809
+ class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
6810
+ (click)="nextMonth()"
6811
+ aria-label="Next month"
6812
+ >
6813
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
6814
+ </button>
6815
+ </div>
6816
+ <sny-calendar
6817
+ mode="range"
6818
+ [(rangeValue)]="internalRange"
6819
+ [min]="min()"
6820
+ [max]="max()"
6821
+ [locale]="locale()"
6822
+ [showNavigation]="false"
6823
+ [borderless]="true"
6824
+ [initialViewDate]="rightViewDate()"
6825
+ (rangeValueChange)="onRangeChanged($event)"
6826
+ />
6827
+ </div>
6828
+ } @else {
6829
+ <!-- Single calendar -->
6830
+ <sny-calendar
6831
+ mode="range"
6832
+ [(rangeValue)]="internalRange"
6833
+ [min]="min()"
6834
+ [max]="max()"
6835
+ [locale]="locale()"
6836
+ (rangeValueChange)="onRangeChanged($event)"
6837
+ />
6838
+ }
6839
+ </div>
6840
+ </div>
6841
+ </div>
6842
+ }
6843
+ `,
6844
+ }]
6845
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], dualCalendar: [{ type: i0.Input, args: [{ isSignal: true, alias: "dualCalendar", required: false }] }], presets: [{ type: i0.Input, args: [{ isSignal: true, alias: "presets", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], triggerRef: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], dropdownRef: [{ type: i0.ViewChild, args: ['dropdownEl', { isSignal: true }] }], onDocumentClick: [{
6846
+ type: HostListener,
6847
+ args: ['document:click', ['$event']]
6848
+ }], onEscape: [{
6849
+ type: HostListener,
6850
+ args: ['keydown.escape']
6851
+ }] } });
6050
6852
 
6051
6853
  class SnyValidatorDirective {
6052
6854
  control = input(null, ...(ngDevMode ? [{ debugName: "control" }] : /* istanbul ignore next */ []));
@@ -6107,5 +6909,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
6107
6909
  * Generated bundle index. Do not edit.
6108
6910
  */
6109
6911
 
6110
- export { SNY_ACCORDION, SNY_ACCORDION_ITEM, SNY_CAROUSEL, SNY_CHAT_BUBBLE, SNY_CONFIG, SNY_DIALOG_DATA, SNY_DRAWER, SNY_DROPDOWN, SNY_FAB, SNY_SHEET_DATA, SNY_STEPS, SNY_TABLE, SNY_TABS, SNY_TIMELINE, SnyAccordionContentDirective, SnyAccordionDirective, SnyAccordionItemDirective, SnyAccordionTriggerDirective, SnyAlertDescriptionDirective, SnyAlertDirective, SnyAlertTitleDirective, SnyAvatarComponent, SnyBadgeDirective, SnyBreadcrumbDirective, SnyBreadcrumbItemDirective, SnyBreadcrumbLinkDirective, SnyBreadcrumbListDirective, SnyBreadcrumbPageDirective, SnyBreadcrumbSeparatorDirective, SnyBulkActionsDefDirective, SnyButtonDirective, SnyButtonGroupDirective, SnyCalendarComponent, SnyCardContentDirective, SnyCardDescriptionDirective, SnyCardDirective, SnyCardFooterDirective, SnyCardHeaderDirective, SnyCardTitleDirective, SnyCarouselContentDirective, SnyCarouselDirective, SnyCarouselItemDirective, SnyCarouselNextDirective, SnyCarouselPrevDirective, SnyCellDefDirective, SnyChatBubbleAvatarDirective, SnyChatBubbleBodyDirective, SnyChatBubbleContentDirective, SnyChatBubbleDirective, SnyChatBubbleFooterDirective, SnyChatBubbleHeaderDirective, SnyCheckboxDirective, SnyComboboxComponent, SnyDataTableComponent, SnyDialogCloseDirective, SnyDialogContentDirective, SnyDialogDescriptionDirective, SnyDialogFooterDirective, SnyDialogHeaderDirective, SnyDialogRef, SnyDialogService, SnyDialogTitleDirective, SnyDiffComponent, SnyDividerComponent, SnyDockDirective, SnyDockItemDirective, SnyDrawerContentDirective, SnyDrawerLayoutComponent, SnyDrawerLayoutDirective, SnyDrawerSideDirective, SnyDropdownContentDirective, SnyDropdownDirective, SnyDropdownTriggerDirective, SnyFabActionDirective, SnyFabDirective, SnyFabTriggerDirective, SnyFieldsetContentDirective, SnyFieldsetDirective, SnyFieldsetLegendDirective, SnyFileInputComponent, SnyHeaderCellDefDirective, SnyIndicatorBadgeDirective, SnyIndicatorDirective, SnyInputDirective, SnyKbdDirective, SnyLabelDirective, SnyLinkDirective, SnyListDirective, SnyListItemActionDirective, SnyListItemContentDirective, SnyListItemDirective, SnyListItemIconDirective, SnyLoaderComponent, SnyMenuContentDirective, SnyMenuItemDirective, SnyMenuLabelDirective, SnyMenuSeparatorDirective, SnyNavbarBrandDirective, SnyNavbarContentDirective, SnyNavbarDirective, SnyNavbarEndDirective, SnyPaginationComponent, SnyProgressComponent, SnyRadialProgressComponent, SnyRadioDirective, SnyRatingComponent, SnyRowExpandDefDirective, SnySelectComponent, SnySheetCloseDirective, SnySheetContentDirective, SnySheetDescriptionDirective, SnySheetHeaderDirective, SnySheetRef, SnySheetService, SnySheetTitleDirective, SnySkeletonDirective, SnySliderComponent, SnyStatDescriptionDirective, SnyStatDirective, SnyStatFigureDirective, SnyStatTitleDirective, SnyStatValueDirective, SnyStatusDirective, SnyStepDirective, SnyStepsDirective, SnySwitchComponent, SnyTableBodyDirective, SnyTableCaptionDirective, SnyTableCellDirective, SnyTableDirective, SnyTableFooterDirective, SnyTableHeadDirective, SnyTableHeaderDirective, SnyTableRowDirective, SnyTabsContentDirective, SnyTabsDirective, SnyTabsListDirective, SnyTabsTriggerDirective, SnyTextareaDirective, SnyTimelineDirective, SnyTimelineEndDirective, SnyTimelineItemDirective, SnyTimelineMiddleDirective, SnyTimelineStartDirective, SnyToastService, SnyToasterComponent, SnyToggleDirective, SnyTooltipDirective, SnyValidatorDirective, SnyValidatorHintDirective, ThemeService, alertVariants, avatarVariants, badgeVariants, buttonGroupVariants, buttonVariants, cardVariants, checkboxVariants, cn, comboboxTriggerVariants, dividerVariants, dropdownContentVariants, dropdownItemVariants, fieldsetVariants, fileInputVariants, inputVariants, kbdVariants, labelVariants, linkVariants, loaderVariants, paginationItemVariants, progressBarVariants, progressTrackVariants, provideSonnyUI, radioVariants, ratingVariants, selectTriggerVariants, skeletonVariants, sliderTrackVariants, statusVariants, switchTrackVariants, tableCellVariants, tableVariants, tabsListVariants, tabsTriggerVariants, textareaVariants, toastVariants, toggleVariants, tooltipVariants };
6912
+ export { SNY_ACCORDION, SNY_ACCORDION_ITEM, SNY_CAROUSEL, SNY_CHAT_BUBBLE, SNY_CONFIG, SNY_DIALOG_DATA, SNY_DRAWER, SNY_DROPDOWN, SNY_FAB, SNY_SHEET_DATA, SNY_STEPS, SNY_TABLE, SNY_TABS, SNY_TIMELINE, SnyAccordionContentDirective, SnyAccordionDirective, SnyAccordionItemDirective, SnyAccordionTriggerDirective, SnyAlertDescriptionDirective, SnyAlertDirective, SnyAlertTitleDirective, SnyAvatarComponent, SnyBadgeDirective, SnyBreadcrumbDirective, SnyBreadcrumbItemDirective, SnyBreadcrumbLinkDirective, SnyBreadcrumbListDirective, SnyBreadcrumbPageDirective, SnyBreadcrumbSeparatorDirective, SnyBulkActionsDefDirective, SnyButtonDirective, SnyButtonGroupDirective, SnyCalendarComponent, SnyCardContentDirective, SnyCardDescriptionDirective, SnyCardDirective, SnyCardFooterDirective, SnyCardHeaderDirective, SnyCardTitleDirective, SnyCarouselContentDirective, SnyCarouselDirective, SnyCarouselItemDirective, SnyCarouselNextDirective, SnyCarouselPrevDirective, SnyCellDefDirective, SnyChatBubbleAvatarDirective, SnyChatBubbleBodyDirective, SnyChatBubbleContentDirective, SnyChatBubbleDirective, SnyChatBubbleFooterDirective, SnyChatBubbleHeaderDirective, SnyCheckboxDirective, SnyComboboxComponent, SnyDataTableComponent, SnyDatePickerComponent, SnyDateRangePickerComponent, SnyDialogCloseDirective, SnyDialogContentDirective, SnyDialogDescriptionDirective, SnyDialogFooterDirective, SnyDialogHeaderDirective, SnyDialogRef, SnyDialogService, SnyDialogTitleDirective, SnyDiffComponent, SnyDividerComponent, SnyDockDirective, SnyDockItemDirective, SnyDrawerContentDirective, SnyDrawerLayoutComponent, SnyDrawerLayoutDirective, SnyDrawerSideDirective, SnyDropdownContentDirective, SnyDropdownDirective, SnyDropdownTriggerDirective, SnyFabActionDirective, SnyFabDirective, SnyFabTriggerDirective, SnyFieldsetContentDirective, SnyFieldsetDirective, SnyFieldsetLegendDirective, SnyFileInputComponent, SnyHeaderCellDefDirective, SnyIndicatorBadgeDirective, SnyIndicatorDirective, SnyInputDirective, SnyKbdDirective, SnyLabelDirective, SnyLinkDirective, SnyListDirective, SnyListItemActionDirective, SnyListItemContentDirective, SnyListItemDirective, SnyListItemIconDirective, SnyLoaderComponent, SnyMenuContentDirective, SnyMenuItemDirective, SnyMenuLabelDirective, SnyMenuSeparatorDirective, SnyNavbarBrandDirective, SnyNavbarContentDirective, SnyNavbarDirective, SnyNavbarEndDirective, SnyPaginationComponent, SnyProgressComponent, SnyRadialProgressComponent, SnyRadioDirective, SnyRatingComponent, SnyRowExpandDefDirective, SnySelectComponent, SnySheetCloseDirective, SnySheetContentDirective, SnySheetDescriptionDirective, SnySheetHeaderDirective, SnySheetRef, SnySheetService, SnySheetTitleDirective, SnySkeletonDirective, SnySliderComponent, SnyStatDescriptionDirective, SnyStatDirective, SnyStatFigureDirective, SnyStatTitleDirective, SnyStatValueDirective, SnyStatusDirective, SnyStepDirective, SnyStepsDirective, SnySwitchComponent, SnyTableBodyDirective, SnyTableCaptionDirective, SnyTableCellDirective, SnyTableDirective, SnyTableFooterDirective, SnyTableHeadDirective, SnyTableHeaderDirective, SnyTableRowDirective, SnyTabsContentDirective, SnyTabsDirective, SnyTabsListDirective, SnyTabsTriggerDirective, SnyTextareaDirective, SnyTimelineDirective, SnyTimelineEndDirective, SnyTimelineItemDirective, SnyTimelineMiddleDirective, SnyTimelineStartDirective, SnyToastService, SnyToasterComponent, SnyToggleDirective, SnyTooltipDirective, SnyValidatorDirective, SnyValidatorHintDirective, ThemeService, alertVariants, avatarVariants, badgeVariants, buttonGroupVariants, buttonVariants, cardVariants, checkboxVariants, cn, comboboxTriggerVariants, datePickerTriggerVariants, dividerVariants, dropdownContentVariants, dropdownItemVariants, fieldsetVariants, fileInputVariants, inputVariants, kbdVariants, labelVariants, linkVariants, loaderVariants, paginationItemVariants, progressBarVariants, progressTrackVariants, provideSonnyUI, radioVariants, ratingVariants, selectTriggerVariants, skeletonVariants, sliderTrackVariants, statusVariants, switchTrackVariants, tableCellVariants, tableVariants, tabsListVariants, tabsTriggerVariants, textareaVariants, toastVariants, toggleVariants, tooltipVariants };
6111
6913
  //# sourceMappingURL=sonny-ui-core.mjs.map