@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.
- package/fesm2022/sonny-ui-core.mjs +870 -68
- package/fesm2022/sonny-ui-core.mjs.map +1 -1
- package/package.json +1 -1
- package/src/lib/calendar/calendar.component.spec.ts +87 -0
- package/src/lib/calendar/calendar.component.ts +184 -61
- package/src/lib/calendar/calendar.types.ts +24 -0
- package/src/lib/calendar/index.ts +6 -0
- package/src/lib/date-picker/date-picker.component.spec.ts +131 -0
- package/src/lib/date-picker/date-picker.component.ts +220 -0
- package/src/lib/date-picker/date-picker.variants.ts +17 -0
- package/src/lib/date-picker/index.ts +2 -0
- package/src/lib/date-range-picker/date-range-picker.component.spec.ts +151 -0
- package/src/lib/date-range-picker/date-range-picker.component.ts +340 -0
- package/src/lib/date-range-picker/index.ts +1 -0
- package/types/sonny-ui-core.d.ts +127 -6
|
@@ -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
|
-
|
|
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.
|
|
5854
|
-
|
|
5855
|
-
|
|
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.
|
|
5927
|
+
this.viewDate.set(new Date(this.viewDate().getFullYear(), this.viewDate().getMonth() - 1, 1));
|
|
5904
5928
|
}
|
|
5905
5929
|
nextMonth() {
|
|
5906
|
-
this.viewDate.
|
|
5930
|
+
this.viewDate.set(new Date(this.viewDate().getFullYear(), this.viewDate().getMonth() + 1, 1));
|
|
5907
5931
|
}
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
this.
|
|
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
|
-
|
|
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) ||
|
|
5950
|
-
|
|
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": "
|
|
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
|
-
|
|
5962
|
-
<
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
class="
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
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"
|
|
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
|
|
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
|
-
|
|
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]': '
|
|
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
|
-
|
|
6013
|
-
<
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
class="
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
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"
|
|
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
|
|
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
|
-
|
|
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
|