@devjuliovilla/jv-ui 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/fesm2022/devjuliovilla-jv-ui.mjs +667 -181
- package/fesm2022/devjuliovilla-jv-ui.mjs.map +1 -1
- package/package.json +4 -1
- package/types/devjuliovilla-jv-ui.d.ts +102 -7
|
@@ -18717,9 +18717,135 @@ const JV_UI_DEFAULT_CONFIG = {
|
|
|
18717
18717
|
density: 'normal',
|
|
18718
18718
|
language: 'es-MX',
|
|
18719
18719
|
locale: 'es',
|
|
18720
|
+
messagesLocale: 'es',
|
|
18721
|
+
formatLocale: 'es-MX',
|
|
18722
|
+
formats: {
|
|
18723
|
+
date: { day: '2-digit', month: '2-digit', year: 'numeric' },
|
|
18724
|
+
time: { hour: '2-digit', minute: '2-digit' },
|
|
18725
|
+
datetime: { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' },
|
|
18726
|
+
integer: { maximumFractionDigits: 0 },
|
|
18727
|
+
number: { minimumFractionDigits: 0, maximumFractionDigits: 2 },
|
|
18728
|
+
currency: { style: 'currency', currency: 'MXN', minimumFractionDigits: 2, maximumFractionDigits: 2 },
|
|
18729
|
+
percent: { style: 'percent', minimumFractionDigits: 0, maximumFractionDigits: 2 },
|
|
18730
|
+
},
|
|
18720
18731
|
toastPosition: 'bottom-right',
|
|
18721
18732
|
};
|
|
18722
18733
|
|
|
18734
|
+
class JvFormatService {
|
|
18735
|
+
config = inject(JvUiConfigService);
|
|
18736
|
+
formatLocale = signal(this.config.snapshot.formatLocale || this.config.snapshot.language || 'es-MX', ...(ngDevMode ? [{ debugName: "formatLocale" }] : /* istanbul ignore next */ []));
|
|
18737
|
+
formats = signal(this.resolveFormats(this.config.snapshot.formats), ...(ngDevMode ? [{ debugName: "formats" }] : /* istanbul ignore next */ []));
|
|
18738
|
+
firstDayOfWeek = computed(() => this.resolveFirstDayOfWeek(this.formatLocale()), ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : /* istanbul ignore next */ []));
|
|
18739
|
+
initialize() {
|
|
18740
|
+
this.formatLocale.set(this.config.snapshot.formatLocale || this.config.snapshot.language || 'es-MX');
|
|
18741
|
+
this.formats.set(this.resolveFormats(this.config.snapshot.formats));
|
|
18742
|
+
}
|
|
18743
|
+
setFormatLocale(locale) {
|
|
18744
|
+
this.formatLocale.set(locale);
|
|
18745
|
+
}
|
|
18746
|
+
setFormats(formats) {
|
|
18747
|
+
this.formats.update((current) => this.resolveFormats({ ...current, ...formats }));
|
|
18748
|
+
}
|
|
18749
|
+
format(kind, value, overrides) {
|
|
18750
|
+
if (value == null || value === '')
|
|
18751
|
+
return '';
|
|
18752
|
+
if (kind === 'date' || kind === 'time' || kind === 'datetime') {
|
|
18753
|
+
const date = this.toDate(value);
|
|
18754
|
+
if (!date)
|
|
18755
|
+
return String(value);
|
|
18756
|
+
return new Intl.DateTimeFormat(this.formatLocale(), this.resolveDateOptions(kind, overrides)).format(date);
|
|
18757
|
+
}
|
|
18758
|
+
const number = this.toNumber(value);
|
|
18759
|
+
if (number === null)
|
|
18760
|
+
return String(value);
|
|
18761
|
+
return new Intl.NumberFormat(this.formatLocale(), this.resolveNumberOptions(kind, overrides)).format(number);
|
|
18762
|
+
}
|
|
18763
|
+
toComparable(kind, value) {
|
|
18764
|
+
if (value == null || value === '')
|
|
18765
|
+
return null;
|
|
18766
|
+
if (kind === 'date' || kind === 'time' || kind === 'datetime') {
|
|
18767
|
+
const date = this.toDate(value);
|
|
18768
|
+
return date ? date.getTime() : String(value);
|
|
18769
|
+
}
|
|
18770
|
+
if (kind === 'integer' || kind === 'number' || kind === 'currency' || kind === 'percent') {
|
|
18771
|
+
const number = this.toNumber(value);
|
|
18772
|
+
return number ?? String(value);
|
|
18773
|
+
}
|
|
18774
|
+
return String(value);
|
|
18775
|
+
}
|
|
18776
|
+
toDate(value) {
|
|
18777
|
+
if (value instanceof Date) {
|
|
18778
|
+
return Number.isNaN(value.getTime()) ? null : value;
|
|
18779
|
+
}
|
|
18780
|
+
if (typeof value === 'number' || typeof value === 'string') {
|
|
18781
|
+
const date = new Date(value);
|
|
18782
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
18783
|
+
}
|
|
18784
|
+
return null;
|
|
18785
|
+
}
|
|
18786
|
+
toNumber(value) {
|
|
18787
|
+
if (typeof value === 'number') {
|
|
18788
|
+
return Number.isFinite(value) ? value : null;
|
|
18789
|
+
}
|
|
18790
|
+
if (typeof value === 'string') {
|
|
18791
|
+
const normalized = value.trim().replace(/[%,$\s]/g, '').replace(/,/g, '');
|
|
18792
|
+
if (!normalized)
|
|
18793
|
+
return null;
|
|
18794
|
+
const parsed = Number(normalized);
|
|
18795
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
18796
|
+
}
|
|
18797
|
+
return null;
|
|
18798
|
+
}
|
|
18799
|
+
toSearchValue(kind, value) {
|
|
18800
|
+
if (value == null)
|
|
18801
|
+
return '';
|
|
18802
|
+
if (kind === 'date' || kind === 'time' || kind === 'datetime') {
|
|
18803
|
+
const date = this.toDate(value);
|
|
18804
|
+
if (!date)
|
|
18805
|
+
return String(value).toLowerCase();
|
|
18806
|
+
return date.toISOString().toLowerCase();
|
|
18807
|
+
}
|
|
18808
|
+
return String(value).toLowerCase();
|
|
18809
|
+
}
|
|
18810
|
+
resolveFormats(formats) {
|
|
18811
|
+
const defaults = this.config.snapshot.formats;
|
|
18812
|
+
return {
|
|
18813
|
+
date: { ...defaults.date, ...formats?.date },
|
|
18814
|
+
time: { ...defaults.time, ...formats?.time },
|
|
18815
|
+
datetime: { ...defaults.datetime, ...formats?.datetime },
|
|
18816
|
+
integer: { ...defaults.integer, ...formats?.integer },
|
|
18817
|
+
number: { ...defaults.number, ...formats?.number },
|
|
18818
|
+
currency: { ...defaults.currency, ...formats?.currency },
|
|
18819
|
+
percent: { ...defaults.percent, ...formats?.percent },
|
|
18820
|
+
};
|
|
18821
|
+
}
|
|
18822
|
+
resolveDateOptions(kind, overrides) {
|
|
18823
|
+
return { ...this.formats()[kind], ...overrides };
|
|
18824
|
+
}
|
|
18825
|
+
resolveNumberOptions(kind, overrides) {
|
|
18826
|
+
return { ...this.formats()[kind], ...overrides };
|
|
18827
|
+
}
|
|
18828
|
+
resolveFirstDayOfWeek(locale) {
|
|
18829
|
+
try {
|
|
18830
|
+
const intlLocale = new Intl.Locale(locale);
|
|
18831
|
+
const firstDay = intlLocale.weekInfo?.firstDay;
|
|
18832
|
+
if (typeof firstDay === 'number') {
|
|
18833
|
+
return firstDay % 7;
|
|
18834
|
+
}
|
|
18835
|
+
}
|
|
18836
|
+
catch {
|
|
18837
|
+
// Ignore unsupported Intl.Locale implementations.
|
|
18838
|
+
}
|
|
18839
|
+
return 0;
|
|
18840
|
+
}
|
|
18841
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
18842
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, providedIn: 'root' });
|
|
18843
|
+
}
|
|
18844
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, decorators: [{
|
|
18845
|
+
type: Injectable,
|
|
18846
|
+
args: [{ providedIn: 'root' }]
|
|
18847
|
+
}] });
|
|
18848
|
+
|
|
18723
18849
|
class JvThemeService {
|
|
18724
18850
|
document = inject(DOCUMENT);
|
|
18725
18851
|
config = inject(JvUiConfigService);
|
|
@@ -18810,6 +18936,7 @@ function provideJvUi(config = {}) {
|
|
|
18810
18936
|
useValue: () => {
|
|
18811
18937
|
inject(JvThemeService).initialize();
|
|
18812
18938
|
inject(JvTranslationService).initialize();
|
|
18939
|
+
inject(JvFormatService).initialize();
|
|
18813
18940
|
},
|
|
18814
18941
|
},
|
|
18815
18942
|
]);
|
|
@@ -18817,9 +18944,19 @@ function provideJvUi(config = {}) {
|
|
|
18817
18944
|
|
|
18818
18945
|
class JvUiConfigService {
|
|
18819
18946
|
defaults = inject(JV_UI_CONFIG_DEFAULTS);
|
|
18820
|
-
configLayers = inject(JV_UI_CONFIG, { optional: true }) ?? [];
|
|
18947
|
+
configLayers = (inject(JV_UI_CONFIG, { optional: true }) ?? []);
|
|
18821
18948
|
get snapshot() {
|
|
18822
|
-
return this.configLayers.reduce((merged, layer) => ({
|
|
18949
|
+
return this.configLayers.reduce((merged, layer) => ({
|
|
18950
|
+
...merged,
|
|
18951
|
+
...layer,
|
|
18952
|
+
formats: {
|
|
18953
|
+
...merged.formats,
|
|
18954
|
+
...(layer.formats ?? {}),
|
|
18955
|
+
},
|
|
18956
|
+
}), {
|
|
18957
|
+
...this.defaults,
|
|
18958
|
+
formats: { ...this.defaults.formats },
|
|
18959
|
+
});
|
|
18823
18960
|
}
|
|
18824
18961
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
18825
18962
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, providedIn: 'root' });
|
|
@@ -18878,6 +19015,12 @@ const ES = {
|
|
|
18878
19015
|
'modalSelector.results': '{count} resultados',
|
|
18879
19016
|
'modalSelector.selected': '{label} seleccionado',
|
|
18880
19017
|
'modalSelector.selectionCleared': 'Seleccion limpiada',
|
|
19018
|
+
'fileInput.dropLabel': 'Arrastre archivos aqui o haga clic para seleccionarlos',
|
|
19019
|
+
'fileInput.helperText': 'Compatible con seleccion multiple y arrastrar y soltar',
|
|
19020
|
+
'fileInput.selectionSummary': '{count} de {max} archivos seleccionados',
|
|
19021
|
+
'fileInput.invalidFiles': '{count} archivos no coinciden con el tipo permitido',
|
|
19022
|
+
'fileInput.tooManyFiles': 'Solo se permiten hasta {max} archivos',
|
|
19023
|
+
'fileInput.removeFile': 'Quitar archivo {name}',
|
|
18881
19024
|
'dialog.confirmTitle': 'Confirmar',
|
|
18882
19025
|
'dialog.confirm': 'Aceptar',
|
|
18883
19026
|
'dialog.cancel': 'Cancelar',
|
|
@@ -18934,6 +19077,12 @@ const EN = {
|
|
|
18934
19077
|
'modalSelector.results': '{count} results',
|
|
18935
19078
|
'modalSelector.selected': '{label} selected',
|
|
18936
19079
|
'modalSelector.selectionCleared': 'Selection cleared',
|
|
19080
|
+
'fileInput.dropLabel': 'Drag files here or click to choose them',
|
|
19081
|
+
'fileInput.helperText': 'Supports multiple selection and drag and drop',
|
|
19082
|
+
'fileInput.selectionSummary': '{count} of {max} files selected',
|
|
19083
|
+
'fileInput.invalidFiles': '{count} files do not match the allowed type',
|
|
19084
|
+
'fileInput.tooManyFiles': 'Only up to {max} files are allowed',
|
|
19085
|
+
'fileInput.removeFile': 'Remove file {name}',
|
|
18937
19086
|
'dialog.confirmTitle': 'Confirm',
|
|
18938
19087
|
'dialog.confirm': 'Confirm',
|
|
18939
19088
|
'dialog.cancel': 'Cancel',
|
|
@@ -18949,14 +19098,17 @@ const JV_DEFAULT_LOCALE = 'es';
|
|
|
18949
19098
|
|
|
18950
19099
|
class JvTranslationService {
|
|
18951
19100
|
config = inject(JvUiConfigService);
|
|
18952
|
-
locale = signal(this.config.snapshot.locale, ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
19101
|
+
locale = signal(this.resolveLocale(this.config.snapshot.messagesLocale ?? this.config.snapshot.locale), ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
18953
19102
|
initialize() {
|
|
18954
|
-
const locale = this.resolveLocale(this.config.snapshot.locale);
|
|
19103
|
+
const locale = this.resolveLocale(this.config.snapshot.messagesLocale ?? this.config.snapshot.locale);
|
|
18955
19104
|
this.locale.set(locale);
|
|
18956
19105
|
}
|
|
18957
19106
|
setLocale(locale) {
|
|
18958
19107
|
this.locale.set(locale);
|
|
18959
19108
|
}
|
|
19109
|
+
setMessagesLocale(locale) {
|
|
19110
|
+
this.setLocale(locale);
|
|
19111
|
+
}
|
|
18960
19112
|
translate(key, params) {
|
|
18961
19113
|
const dict = JV_LOCALE_DICTIONARIES[this.locale()] ?? JV_LOCALE_DICTIONARIES[JV_DEFAULT_LOCALE];
|
|
18962
19114
|
let value = dict[key];
|
|
@@ -18971,6 +19123,8 @@ class JvTranslationService {
|
|
|
18971
19123
|
return value;
|
|
18972
19124
|
}
|
|
18973
19125
|
resolveLocale(locale) {
|
|
19126
|
+
if (!locale)
|
|
19127
|
+
return JV_DEFAULT_LOCALE;
|
|
18974
19128
|
if (locale === 'es' || locale === 'en')
|
|
18975
19129
|
return locale;
|
|
18976
19130
|
return locale.startsWith('es') ? 'es' : 'en';
|
|
@@ -19749,6 +19903,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
19749
19903
|
let datePickerIdSequence = 0;
|
|
19750
19904
|
class JvDatePickerComponent {
|
|
19751
19905
|
translation = inject(JvTranslationService);
|
|
19906
|
+
formatService = inject(JvFormatService);
|
|
19752
19907
|
announcementService = inject(JvAnnouncementService);
|
|
19753
19908
|
instanceId = ++datePickerIdSequence;
|
|
19754
19909
|
calendarRootRef = viewChild('calendarRoot', ...(ngDevMode ? [{ debugName: "calendarRootRef" }] : /* istanbul ignore next */ []));
|
|
@@ -19781,14 +19936,10 @@ class JvDatePickerComponent {
|
|
|
19781
19936
|
if (!value) {
|
|
19782
19937
|
return this.placeholder() || this.translation.translate('datePicker.placeholder');
|
|
19783
19938
|
}
|
|
19784
|
-
return
|
|
19785
|
-
day: '2-digit',
|
|
19786
|
-
month: '2-digit',
|
|
19787
|
-
year: 'numeric',
|
|
19788
|
-
}).format(value);
|
|
19939
|
+
return this.formatService.format('date', value);
|
|
19789
19940
|
}, ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
|
|
19790
19941
|
monthOptions = computed(() => {
|
|
19791
|
-
const formatter = new Intl.DateTimeFormat(this.
|
|
19942
|
+
const formatter = new Intl.DateTimeFormat(this.formatService.formatLocale(), { month: 'long' });
|
|
19792
19943
|
return Array.from({ length: 12 }, (_, month) => ({
|
|
19793
19944
|
label: capitalize(formatter.format(new Date(2026, month, 1))),
|
|
19794
19945
|
value: String(month),
|
|
@@ -19802,7 +19953,7 @@ class JvDatePickerComponent {
|
|
|
19802
19953
|
}, ...(ngDevMode ? [{ debugName: "yearOptions" }] : /* istanbul ignore next */ []));
|
|
19803
19954
|
weekdayLabels = computed(() => {
|
|
19804
19955
|
const startDay = this.firstDayOfWeek();
|
|
19805
|
-
const formatter = new Intl.DateTimeFormat(this.
|
|
19956
|
+
const formatter = new Intl.DateTimeFormat(this.formatService.formatLocale(), { weekday: 'short' });
|
|
19806
19957
|
return Array.from({ length: 7 }, (_, index) => capitalize(formatter.format(addDays(new Date(2026, 5, 7), startDay + index))));
|
|
19807
19958
|
}, ...(ngDevMode ? [{ debugName: "weekdayLabels" }] : /* istanbul ignore next */ []));
|
|
19808
19959
|
calendarCells = computed(() => {
|
|
@@ -19944,10 +20095,10 @@ class JvDatePickerComponent {
|
|
|
19944
20095
|
root?.querySelector(`[data-jv-date="${this.isoDate(date)}"]`)?.focus();
|
|
19945
20096
|
}
|
|
19946
20097
|
firstDayOfWeek() {
|
|
19947
|
-
return this.
|
|
20098
|
+
return this.formatService.firstDayOfWeek();
|
|
19948
20099
|
}
|
|
19949
20100
|
displayDateForAnnouncement(date) {
|
|
19950
|
-
return new Intl.DateTimeFormat(this.
|
|
20101
|
+
return new Intl.DateTimeFormat(this.formatService.formatLocale(), {
|
|
19951
20102
|
weekday: 'long',
|
|
19952
20103
|
day: 'numeric',
|
|
19953
20104
|
month: 'long',
|
|
@@ -19961,83 +20112,83 @@ class JvDatePickerComponent {
|
|
|
19961
20112
|
useExisting: forwardRef(() => JvDatePickerComponent),
|
|
19962
20113
|
multi: true,
|
|
19963
20114
|
},
|
|
19964
|
-
], viewQueries: [{ propertyName: "calendarRootRef", first: true, predicate: ["calendarRoot"], descendants: true, isSignal: true }, { propertyName: "triggerButtonRef", first: true, predicate: ["triggerButton"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
19965
|
-
<jv-form-container
|
|
19966
|
-
[label]="label()"
|
|
19967
|
-
[inputId]="inputId()"
|
|
19968
|
-
[required]="required()"
|
|
19969
|
-
[invalid]="invalid()"
|
|
19970
|
-
[hint]="hint()"
|
|
19971
|
-
[error]="error()"
|
|
19972
|
-
>
|
|
19973
|
-
<button
|
|
19974
|
-
#triggerButton
|
|
19975
|
-
type="button"
|
|
19976
|
-
class="jv-date-picker-trigger"
|
|
19977
|
-
[class.is-invalid]="invalid()"
|
|
19978
|
-
[id]="inputId()"
|
|
19979
|
-
[disabled]="disabled"
|
|
19980
|
-
[attr.aria-haspopup]="'dialog'"
|
|
19981
|
-
[attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
|
|
19982
|
-
[attr.aria-controls]="dialogId"
|
|
19983
|
-
[attr.aria-invalid]="invalid() ? 'true' : null"
|
|
19984
|
-
[attr.aria-describedby]="describedBy() || null"
|
|
19985
|
-
[attr.aria-label]="triggerAriaLabel()"
|
|
19986
|
-
[attr.title]="displayValue()"
|
|
19987
|
-
(click)="openDialog()"
|
|
19988
|
-
(blur)="handleBlur()"
|
|
19989
|
-
>
|
|
19990
|
-
<span [class.jv-date-picker-placeholder]="!currentValue()">{{ displayValue() }}</span>
|
|
19991
|
-
<jv-icon name="calendar-days" [size]="18" />
|
|
19992
|
-
</button>
|
|
19993
|
-
</jv-form-container>
|
|
19994
|
-
|
|
19995
|
-
<jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" (closed)="closeDialog()">
|
|
19996
|
-
<div #calendarRoot [id]="dialogId" class="jv-date-picker-dialog">
|
|
19997
|
-
<div class="jv-date-picker-toolbar">
|
|
19998
|
-
<jv-icon-button icon="chevron-left" variant="ghost" [ariaLabel]="translation.translate('datePicker.prevMonth')" (click)="shiftMonth(-1)" />
|
|
19999
|
-
|
|
20000
|
-
<div class="jv-date-picker-selects">
|
|
20001
|
-
<jv-select [options]="monthOptions()" [modelValue]="visibleMonth().getMonth().toString()" (selectionChange)="handleMonthChange($event)" />
|
|
20002
|
-
<jv-select [options]="yearOptions()" [modelValue]="visibleMonth().getFullYear().toString()" (selectionChange)="handleYearChange($event)" />
|
|
20003
|
-
</div>
|
|
20004
|
-
|
|
20005
|
-
<jv-icon-button icon="chevron-right" variant="ghost" [ariaLabel]="translation.translate('datePicker.nextMonth')" (click)="shiftMonth(1)" />
|
|
20006
|
-
</div>
|
|
20007
|
-
|
|
20008
|
-
<div class="jv-date-picker-weekdays" aria-hidden="true">
|
|
20009
|
-
@for (weekday of weekdayLabels(); track weekday) {
|
|
20010
|
-
<span>{{ weekday }}</span>
|
|
20011
|
-
}
|
|
20012
|
-
</div>
|
|
20013
|
-
|
|
20014
|
-
<div class="jv-date-picker-grid" role="grid" [attr.aria-label]="resolvedDialogTitle()">
|
|
20015
|
-
@for (cell of calendarCells(); track isoDate(cell.date)) {
|
|
20016
|
-
<button
|
|
20017
|
-
type="button"
|
|
20018
|
-
class="jv-date-picker-day"
|
|
20019
|
-
[class.jv-date-picker-day--outside]="!cell.currentMonth"
|
|
20020
|
-
[class.jv-date-picker-day--today]="cell.isToday"
|
|
20021
|
-
[class.jv-date-picker-day--selected]="isSelected(cell.date)"
|
|
20022
|
-
[attr.data-jv-date]="isoDate(cell.date)"
|
|
20023
|
-
[attr.tabindex]="isFocusedDate(cell.date) ? 0 : -1"
|
|
20024
|
-
[attr.aria-selected]="isSelected(cell.date) ? 'true' : 'false'"
|
|
20025
|
-
(click)="selectDate(cell.date)"
|
|
20026
|
-
(keydown)="handleDayKeydown($event, cell.date)"
|
|
20027
|
-
>
|
|
20028
|
-
{{ cell.date.getDate() }}
|
|
20029
|
-
</button>
|
|
20030
|
-
}
|
|
20031
|
-
</div>
|
|
20032
|
-
</div>
|
|
20033
|
-
|
|
20034
|
-
<div dialog-actions class="jv-date-picker-actions">
|
|
20035
|
-
@if (currentValue()) {
|
|
20036
|
-
<jv-button variant="ghost" (click)="clearSelection()">{{ translation.translate('datePicker.clear') }}</jv-button>
|
|
20037
|
-
}
|
|
20038
|
-
<jv-button variant="outline" (click)="closeDialog()">{{ translation.translate('datePicker.close') }}</jv-button>
|
|
20039
|
-
</div>
|
|
20040
|
-
</jv-dialog>
|
|
20115
|
+
], viewQueries: [{ propertyName: "calendarRootRef", first: true, predicate: ["calendarRoot"], descendants: true, isSignal: true }, { propertyName: "triggerButtonRef", first: true, predicate: ["triggerButton"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
20116
|
+
<jv-form-container
|
|
20117
|
+
[label]="label()"
|
|
20118
|
+
[inputId]="inputId()"
|
|
20119
|
+
[required]="required()"
|
|
20120
|
+
[invalid]="invalid()"
|
|
20121
|
+
[hint]="hint()"
|
|
20122
|
+
[error]="error()"
|
|
20123
|
+
>
|
|
20124
|
+
<button
|
|
20125
|
+
#triggerButton
|
|
20126
|
+
type="button"
|
|
20127
|
+
class="jv-date-picker-trigger"
|
|
20128
|
+
[class.is-invalid]="invalid()"
|
|
20129
|
+
[id]="inputId()"
|
|
20130
|
+
[disabled]="disabled"
|
|
20131
|
+
[attr.aria-haspopup]="'dialog'"
|
|
20132
|
+
[attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
|
|
20133
|
+
[attr.aria-controls]="dialogId"
|
|
20134
|
+
[attr.aria-invalid]="invalid() ? 'true' : null"
|
|
20135
|
+
[attr.aria-describedby]="describedBy() || null"
|
|
20136
|
+
[attr.aria-label]="triggerAriaLabel()"
|
|
20137
|
+
[attr.title]="displayValue()"
|
|
20138
|
+
(click)="openDialog()"
|
|
20139
|
+
(blur)="handleBlur()"
|
|
20140
|
+
>
|
|
20141
|
+
<span [class.jv-date-picker-placeholder]="!currentValue()">{{ displayValue() }}</span>
|
|
20142
|
+
<jv-icon name="calendar-days" [size]="18" />
|
|
20143
|
+
</button>
|
|
20144
|
+
</jv-form-container>
|
|
20145
|
+
|
|
20146
|
+
<jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" (closed)="closeDialog()">
|
|
20147
|
+
<div #calendarRoot [id]="dialogId" class="jv-date-picker-dialog">
|
|
20148
|
+
<div class="jv-date-picker-toolbar">
|
|
20149
|
+
<jv-icon-button icon="chevron-left" variant="ghost" [ariaLabel]="translation.translate('datePicker.prevMonth')" (click)="shiftMonth(-1)" />
|
|
20150
|
+
|
|
20151
|
+
<div class="jv-date-picker-selects">
|
|
20152
|
+
<jv-select [options]="monthOptions()" [modelValue]="visibleMonth().getMonth().toString()" (selectionChange)="handleMonthChange($event)" />
|
|
20153
|
+
<jv-select [options]="yearOptions()" [modelValue]="visibleMonth().getFullYear().toString()" (selectionChange)="handleYearChange($event)" />
|
|
20154
|
+
</div>
|
|
20155
|
+
|
|
20156
|
+
<jv-icon-button icon="chevron-right" variant="ghost" [ariaLabel]="translation.translate('datePicker.nextMonth')" (click)="shiftMonth(1)" />
|
|
20157
|
+
</div>
|
|
20158
|
+
|
|
20159
|
+
<div class="jv-date-picker-weekdays" aria-hidden="true">
|
|
20160
|
+
@for (weekday of weekdayLabels(); track weekday) {
|
|
20161
|
+
<span>{{ weekday }}</span>
|
|
20162
|
+
}
|
|
20163
|
+
</div>
|
|
20164
|
+
|
|
20165
|
+
<div class="jv-date-picker-grid" role="grid" [attr.aria-label]="resolvedDialogTitle()">
|
|
20166
|
+
@for (cell of calendarCells(); track isoDate(cell.date)) {
|
|
20167
|
+
<button
|
|
20168
|
+
type="button"
|
|
20169
|
+
class="jv-date-picker-day"
|
|
20170
|
+
[class.jv-date-picker-day--outside]="!cell.currentMonth"
|
|
20171
|
+
[class.jv-date-picker-day--today]="cell.isToday"
|
|
20172
|
+
[class.jv-date-picker-day--selected]="isSelected(cell.date)"
|
|
20173
|
+
[attr.data-jv-date]="isoDate(cell.date)"
|
|
20174
|
+
[attr.tabindex]="isFocusedDate(cell.date) ? 0 : -1"
|
|
20175
|
+
[attr.aria-selected]="isSelected(cell.date) ? 'true' : 'false'"
|
|
20176
|
+
(click)="selectDate(cell.date)"
|
|
20177
|
+
(keydown)="handleDayKeydown($event, cell.date)"
|
|
20178
|
+
>
|
|
20179
|
+
{{ cell.date.getDate() }}
|
|
20180
|
+
</button>
|
|
20181
|
+
}
|
|
20182
|
+
</div>
|
|
20183
|
+
</div>
|
|
20184
|
+
|
|
20185
|
+
<div dialog-actions class="jv-date-picker-actions">
|
|
20186
|
+
@if (currentValue()) {
|
|
20187
|
+
<jv-button variant="ghost" (click)="clearSelection()">{{ translation.translate('datePicker.clear') }}</jv-button>
|
|
20188
|
+
}
|
|
20189
|
+
<jv-button variant="outline" (click)="closeDialog()">{{ translation.translate('datePicker.close') }}</jv-button>
|
|
20190
|
+
</div>
|
|
20191
|
+
</jv-dialog>
|
|
20041
20192
|
`, isInline: true, styles: [".jv-date-picker-trigger{width:100%;min-height:var(--jv-density-control-height);display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-sm);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer}.jv-date-picker-trigger.is-invalid{border-color:var(--jv-color-danger)}.jv-date-picker-trigger:disabled{opacity:.7;cursor:not-allowed}.jv-date-picker-trigger:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-date-picker-placeholder{color:var(--jv-color-foreground-muted)}.jv-date-picker-dialog,.jv-date-picker-actions{display:grid;gap:var(--jv-spacing-md)}.jv-date-picker-toolbar,.jv-date-picker-selects,.jv-date-picker-weekdays,.jv-date-picker-grid{display:grid;gap:var(--jv-spacing-sm)}.jv-date-picker-toolbar{grid-template-columns:auto 1fr auto;align-items:center}.jv-date-picker-selects{grid-template-columns:1fr 1fr}.jv-date-picker-weekdays,.jv-date-picker-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.jv-date-picker-weekdays span{text-align:center;font-size:.8125rem;font-weight:600;color:var(--jv-color-foreground-muted)}.jv-date-picker-day{min-height:2.5rem;border:1px solid transparent;border-radius:var(--jv-radius-md);background:transparent;color:var(--jv-color-foreground);font:inherit;cursor:pointer;transition:background-color .16s ease,border-color .16s ease,color .16s ease}.jv-date-picker-day:hover,.jv-date-picker-day:focus-visible{background:var(--jv-color-surface-muted)}.jv-date-picker-day:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-date-picker-day--outside{color:var(--jv-color-foreground-muted)}.jv-date-picker-day--today{border-color:var(--jv-color-primary)}.jv-date-picker-day--selected{background:var(--jv-color-primary);color:#fff}\n"], dependencies: [{ kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvDialogComponent, selector: "jv-dialog", inputs: ["open", "title"], outputs: ["closed"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvIconButtonComponent, selector: "jv-icon-button", inputs: ["icon", "ariaLabel", "variant", "disabled"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "component", type: JvSelectComponent, selector: "jv-select", inputs: ["options", "placeholder", "required", "invalid", "describedBy", "inputId", "modelValue"], outputs: ["selectionChange"] }] });
|
|
20042
20193
|
}
|
|
20043
20194
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDatePickerComponent, decorators: [{
|
|
@@ -20048,83 +20199,83 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
20048
20199
|
useExisting: forwardRef(() => JvDatePickerComponent),
|
|
20049
20200
|
multi: true,
|
|
20050
20201
|
},
|
|
20051
|
-
], template: `
|
|
20052
|
-
<jv-form-container
|
|
20053
|
-
[label]="label()"
|
|
20054
|
-
[inputId]="inputId()"
|
|
20055
|
-
[required]="required()"
|
|
20056
|
-
[invalid]="invalid()"
|
|
20057
|
-
[hint]="hint()"
|
|
20058
|
-
[error]="error()"
|
|
20059
|
-
>
|
|
20060
|
-
<button
|
|
20061
|
-
#triggerButton
|
|
20062
|
-
type="button"
|
|
20063
|
-
class="jv-date-picker-trigger"
|
|
20064
|
-
[class.is-invalid]="invalid()"
|
|
20065
|
-
[id]="inputId()"
|
|
20066
|
-
[disabled]="disabled"
|
|
20067
|
-
[attr.aria-haspopup]="'dialog'"
|
|
20068
|
-
[attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
|
|
20069
|
-
[attr.aria-controls]="dialogId"
|
|
20070
|
-
[attr.aria-invalid]="invalid() ? 'true' : null"
|
|
20071
|
-
[attr.aria-describedby]="describedBy() || null"
|
|
20072
|
-
[attr.aria-label]="triggerAriaLabel()"
|
|
20073
|
-
[attr.title]="displayValue()"
|
|
20074
|
-
(click)="openDialog()"
|
|
20075
|
-
(blur)="handleBlur()"
|
|
20076
|
-
>
|
|
20077
|
-
<span [class.jv-date-picker-placeholder]="!currentValue()">{{ displayValue() }}</span>
|
|
20078
|
-
<jv-icon name="calendar-days" [size]="18" />
|
|
20079
|
-
</button>
|
|
20080
|
-
</jv-form-container>
|
|
20081
|
-
|
|
20082
|
-
<jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" (closed)="closeDialog()">
|
|
20083
|
-
<div #calendarRoot [id]="dialogId" class="jv-date-picker-dialog">
|
|
20084
|
-
<div class="jv-date-picker-toolbar">
|
|
20085
|
-
<jv-icon-button icon="chevron-left" variant="ghost" [ariaLabel]="translation.translate('datePicker.prevMonth')" (click)="shiftMonth(-1)" />
|
|
20086
|
-
|
|
20087
|
-
<div class="jv-date-picker-selects">
|
|
20088
|
-
<jv-select [options]="monthOptions()" [modelValue]="visibleMonth().getMonth().toString()" (selectionChange)="handleMonthChange($event)" />
|
|
20089
|
-
<jv-select [options]="yearOptions()" [modelValue]="visibleMonth().getFullYear().toString()" (selectionChange)="handleYearChange($event)" />
|
|
20090
|
-
</div>
|
|
20091
|
-
|
|
20092
|
-
<jv-icon-button icon="chevron-right" variant="ghost" [ariaLabel]="translation.translate('datePicker.nextMonth')" (click)="shiftMonth(1)" />
|
|
20093
|
-
</div>
|
|
20094
|
-
|
|
20095
|
-
<div class="jv-date-picker-weekdays" aria-hidden="true">
|
|
20096
|
-
@for (weekday of weekdayLabels(); track weekday) {
|
|
20097
|
-
<span>{{ weekday }}</span>
|
|
20098
|
-
}
|
|
20099
|
-
</div>
|
|
20100
|
-
|
|
20101
|
-
<div class="jv-date-picker-grid" role="grid" [attr.aria-label]="resolvedDialogTitle()">
|
|
20102
|
-
@for (cell of calendarCells(); track isoDate(cell.date)) {
|
|
20103
|
-
<button
|
|
20104
|
-
type="button"
|
|
20105
|
-
class="jv-date-picker-day"
|
|
20106
|
-
[class.jv-date-picker-day--outside]="!cell.currentMonth"
|
|
20107
|
-
[class.jv-date-picker-day--today]="cell.isToday"
|
|
20108
|
-
[class.jv-date-picker-day--selected]="isSelected(cell.date)"
|
|
20109
|
-
[attr.data-jv-date]="isoDate(cell.date)"
|
|
20110
|
-
[attr.tabindex]="isFocusedDate(cell.date) ? 0 : -1"
|
|
20111
|
-
[attr.aria-selected]="isSelected(cell.date) ? 'true' : 'false'"
|
|
20112
|
-
(click)="selectDate(cell.date)"
|
|
20113
|
-
(keydown)="handleDayKeydown($event, cell.date)"
|
|
20114
|
-
>
|
|
20115
|
-
{{ cell.date.getDate() }}
|
|
20116
|
-
</button>
|
|
20117
|
-
}
|
|
20118
|
-
</div>
|
|
20119
|
-
</div>
|
|
20120
|
-
|
|
20121
|
-
<div dialog-actions class="jv-date-picker-actions">
|
|
20122
|
-
@if (currentValue()) {
|
|
20123
|
-
<jv-button variant="ghost" (click)="clearSelection()">{{ translation.translate('datePicker.clear') }}</jv-button>
|
|
20124
|
-
}
|
|
20125
|
-
<jv-button variant="outline" (click)="closeDialog()">{{ translation.translate('datePicker.close') }}</jv-button>
|
|
20126
|
-
</div>
|
|
20127
|
-
</jv-dialog>
|
|
20202
|
+
], template: `
|
|
20203
|
+
<jv-form-container
|
|
20204
|
+
[label]="label()"
|
|
20205
|
+
[inputId]="inputId()"
|
|
20206
|
+
[required]="required()"
|
|
20207
|
+
[invalid]="invalid()"
|
|
20208
|
+
[hint]="hint()"
|
|
20209
|
+
[error]="error()"
|
|
20210
|
+
>
|
|
20211
|
+
<button
|
|
20212
|
+
#triggerButton
|
|
20213
|
+
type="button"
|
|
20214
|
+
class="jv-date-picker-trigger"
|
|
20215
|
+
[class.is-invalid]="invalid()"
|
|
20216
|
+
[id]="inputId()"
|
|
20217
|
+
[disabled]="disabled"
|
|
20218
|
+
[attr.aria-haspopup]="'dialog'"
|
|
20219
|
+
[attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
|
|
20220
|
+
[attr.aria-controls]="dialogId"
|
|
20221
|
+
[attr.aria-invalid]="invalid() ? 'true' : null"
|
|
20222
|
+
[attr.aria-describedby]="describedBy() || null"
|
|
20223
|
+
[attr.aria-label]="triggerAriaLabel()"
|
|
20224
|
+
[attr.title]="displayValue()"
|
|
20225
|
+
(click)="openDialog()"
|
|
20226
|
+
(blur)="handleBlur()"
|
|
20227
|
+
>
|
|
20228
|
+
<span [class.jv-date-picker-placeholder]="!currentValue()">{{ displayValue() }}</span>
|
|
20229
|
+
<jv-icon name="calendar-days" [size]="18" />
|
|
20230
|
+
</button>
|
|
20231
|
+
</jv-form-container>
|
|
20232
|
+
|
|
20233
|
+
<jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" (closed)="closeDialog()">
|
|
20234
|
+
<div #calendarRoot [id]="dialogId" class="jv-date-picker-dialog">
|
|
20235
|
+
<div class="jv-date-picker-toolbar">
|
|
20236
|
+
<jv-icon-button icon="chevron-left" variant="ghost" [ariaLabel]="translation.translate('datePicker.prevMonth')" (click)="shiftMonth(-1)" />
|
|
20237
|
+
|
|
20238
|
+
<div class="jv-date-picker-selects">
|
|
20239
|
+
<jv-select [options]="monthOptions()" [modelValue]="visibleMonth().getMonth().toString()" (selectionChange)="handleMonthChange($event)" />
|
|
20240
|
+
<jv-select [options]="yearOptions()" [modelValue]="visibleMonth().getFullYear().toString()" (selectionChange)="handleYearChange($event)" />
|
|
20241
|
+
</div>
|
|
20242
|
+
|
|
20243
|
+
<jv-icon-button icon="chevron-right" variant="ghost" [ariaLabel]="translation.translate('datePicker.nextMonth')" (click)="shiftMonth(1)" />
|
|
20244
|
+
</div>
|
|
20245
|
+
|
|
20246
|
+
<div class="jv-date-picker-weekdays" aria-hidden="true">
|
|
20247
|
+
@for (weekday of weekdayLabels(); track weekday) {
|
|
20248
|
+
<span>{{ weekday }}</span>
|
|
20249
|
+
}
|
|
20250
|
+
</div>
|
|
20251
|
+
|
|
20252
|
+
<div class="jv-date-picker-grid" role="grid" [attr.aria-label]="resolvedDialogTitle()">
|
|
20253
|
+
@for (cell of calendarCells(); track isoDate(cell.date)) {
|
|
20254
|
+
<button
|
|
20255
|
+
type="button"
|
|
20256
|
+
class="jv-date-picker-day"
|
|
20257
|
+
[class.jv-date-picker-day--outside]="!cell.currentMonth"
|
|
20258
|
+
[class.jv-date-picker-day--today]="cell.isToday"
|
|
20259
|
+
[class.jv-date-picker-day--selected]="isSelected(cell.date)"
|
|
20260
|
+
[attr.data-jv-date]="isoDate(cell.date)"
|
|
20261
|
+
[attr.tabindex]="isFocusedDate(cell.date) ? 0 : -1"
|
|
20262
|
+
[attr.aria-selected]="isSelected(cell.date) ? 'true' : 'false'"
|
|
20263
|
+
(click)="selectDate(cell.date)"
|
|
20264
|
+
(keydown)="handleDayKeydown($event, cell.date)"
|
|
20265
|
+
>
|
|
20266
|
+
{{ cell.date.getDate() }}
|
|
20267
|
+
</button>
|
|
20268
|
+
}
|
|
20269
|
+
</div>
|
|
20270
|
+
</div>
|
|
20271
|
+
|
|
20272
|
+
<div dialog-actions class="jv-date-picker-actions">
|
|
20273
|
+
@if (currentValue()) {
|
|
20274
|
+
<jv-button variant="ghost" (click)="clearSelection()">{{ translation.translate('datePicker.clear') }}</jv-button>
|
|
20275
|
+
}
|
|
20276
|
+
<jv-button variant="outline" (click)="closeDialog()">{{ translation.translate('datePicker.close') }}</jv-button>
|
|
20277
|
+
</div>
|
|
20278
|
+
</jv-dialog>
|
|
20128
20279
|
`, styles: [".jv-date-picker-trigger{width:100%;min-height:var(--jv-density-control-height);display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-sm);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer}.jv-date-picker-trigger.is-invalid{border-color:var(--jv-color-danger)}.jv-date-picker-trigger:disabled{opacity:.7;cursor:not-allowed}.jv-date-picker-trigger:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-date-picker-placeholder{color:var(--jv-color-foreground-muted)}.jv-date-picker-dialog,.jv-date-picker-actions{display:grid;gap:var(--jv-spacing-md)}.jv-date-picker-toolbar,.jv-date-picker-selects,.jv-date-picker-weekdays,.jv-date-picker-grid{display:grid;gap:var(--jv-spacing-sm)}.jv-date-picker-toolbar{grid-template-columns:auto 1fr auto;align-items:center}.jv-date-picker-selects{grid-template-columns:1fr 1fr}.jv-date-picker-weekdays,.jv-date-picker-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.jv-date-picker-weekdays span{text-align:center;font-size:.8125rem;font-weight:600;color:var(--jv-color-foreground-muted)}.jv-date-picker-day{min-height:2.5rem;border:1px solid transparent;border-radius:var(--jv-radius-md);background:transparent;color:var(--jv-color-foreground);font:inherit;cursor:pointer;transition:background-color .16s ease,border-color .16s ease,color .16s ease}.jv-date-picker-day:hover,.jv-date-picker-day:focus-visible{background:var(--jv-color-surface-muted)}.jv-date-picker-day:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-date-picker-day--outside{color:var(--jv-color-foreground-muted)}.jv-date-picker-day--today{border-color:var(--jv-color-primary)}.jv-date-picker-day--selected{background:var(--jv-color-primary);color:#fff}\n"] }]
|
|
20129
20280
|
}], propDecorators: { calendarRootRef: [{ type: i0.ViewChild, args: ['calendarRoot', { isSignal: true }] }], triggerButtonRef: [{ type: i0.ViewChild, args: ['triggerButton', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], dialogTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "dialogTitle", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], describedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "describedBy", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], valueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
|
|
20130
20281
|
function daysInMonth(year, month) {
|
|
@@ -20149,6 +20300,297 @@ function capitalize(value) {
|
|
|
20149
20300
|
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
20150
20301
|
}
|
|
20151
20302
|
|
|
20303
|
+
let fileInputIdSequence = 0;
|
|
20304
|
+
class JvFileInputComponent {
|
|
20305
|
+
translation = inject(JvTranslationService);
|
|
20306
|
+
instanceId = ++fileInputIdSequence;
|
|
20307
|
+
nativeInputRef = viewChild('nativeInput', ...(ngDevMode ? [{ debugName: "nativeInputRef" }] : /* istanbul ignore next */ []));
|
|
20308
|
+
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
20309
|
+
hint = input('', ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
|
|
20310
|
+
error = input('', ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
20311
|
+
describedBy = input('', ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
|
|
20312
|
+
inputId = input(`jv-file-input-${this.instanceId}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
|
|
20313
|
+
accept = input('', ...(ngDevMode ? [{ debugName: "accept" }] : /* istanbul ignore next */ []));
|
|
20314
|
+
multiple = input(true, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
|
|
20315
|
+
maxFiles = input(10, ...(ngDevMode ? [{ debugName: "maxFiles" }] : /* istanbul ignore next */ []));
|
|
20316
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
20317
|
+
required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
20318
|
+
invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
|
|
20319
|
+
filesInput = input(undefined, { ...(ngDevMode ? { debugName: "filesInput" } : /* istanbul ignore next */ {}), alias: 'files' });
|
|
20320
|
+
filesChange = output();
|
|
20321
|
+
filesRejected = output();
|
|
20322
|
+
dragActive = signal(false, ...(ngDevMode ? [{ debugName: "dragActive" }] : /* istanbul ignore next */ []));
|
|
20323
|
+
rejectionMessage = signal('', ...(ngDevMode ? [{ debugName: "rejectionMessage" }] : /* istanbul ignore next */ []));
|
|
20324
|
+
internalFiles = signal([], ...(ngDevMode ? [{ debugName: "internalFiles" }] : /* istanbul ignore next */ []));
|
|
20325
|
+
currentFiles = computed(() => {
|
|
20326
|
+
const externalFiles = this.filesInput();
|
|
20327
|
+
return externalFiles !== undefined ? [...(externalFiles ?? [])] : this.internalFiles();
|
|
20328
|
+
}, ...(ngDevMode ? [{ debugName: "currentFiles" }] : /* istanbul ignore next */ []));
|
|
20329
|
+
selectionSummary = computed(() => this.translation.translate('fileInput.selectionSummary', { count: this.currentFiles().length, max: this.maxFiles() }), ...(ngDevMode ? [{ debugName: "selectionSummary" }] : /* istanbul ignore next */ []));
|
|
20330
|
+
dropzoneAriaLabel = computed(() => `${this.label() || this.translation.translate('fileInput.dropLabel')}. ${this.selectionSummary()}`, ...(ngDevMode ? [{ debugName: "dropzoneAriaLabel" }] : /* istanbul ignore next */ []));
|
|
20331
|
+
openFileDialog() {
|
|
20332
|
+
if (this.disabled())
|
|
20333
|
+
return;
|
|
20334
|
+
this.nativeInputRef()?.nativeElement.click();
|
|
20335
|
+
}
|
|
20336
|
+
handleDropzoneKeydown(event) {
|
|
20337
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
20338
|
+
event.preventDefault();
|
|
20339
|
+
this.openFileDialog();
|
|
20340
|
+
}
|
|
20341
|
+
}
|
|
20342
|
+
onNativeInputChange(fileList) {
|
|
20343
|
+
this.consumeFiles(fileList ? Array.from(fileList) : []);
|
|
20344
|
+
const input = this.nativeInputRef()?.nativeElement;
|
|
20345
|
+
if (input) {
|
|
20346
|
+
input.value = '';
|
|
20347
|
+
}
|
|
20348
|
+
}
|
|
20349
|
+
onDragEnter(event) {
|
|
20350
|
+
if (this.disabled())
|
|
20351
|
+
return;
|
|
20352
|
+
event.preventDefault();
|
|
20353
|
+
this.dragActive.set(true);
|
|
20354
|
+
}
|
|
20355
|
+
onDragOver(event) {
|
|
20356
|
+
if (this.disabled())
|
|
20357
|
+
return;
|
|
20358
|
+
event.preventDefault();
|
|
20359
|
+
this.dragActive.set(true);
|
|
20360
|
+
}
|
|
20361
|
+
onDragLeave(event) {
|
|
20362
|
+
if (event.currentTarget?.contains(event.relatedTarget)) {
|
|
20363
|
+
return;
|
|
20364
|
+
}
|
|
20365
|
+
this.dragActive.set(false);
|
|
20366
|
+
}
|
|
20367
|
+
onDrop(event) {
|
|
20368
|
+
if (this.disabled())
|
|
20369
|
+
return;
|
|
20370
|
+
event.preventDefault();
|
|
20371
|
+
this.dragActive.set(false);
|
|
20372
|
+
this.consumeFiles(Array.from(event.dataTransfer?.files ?? []));
|
|
20373
|
+
}
|
|
20374
|
+
removeFile(index) {
|
|
20375
|
+
if (this.disabled())
|
|
20376
|
+
return;
|
|
20377
|
+
const nextFiles = [...this.currentFiles()];
|
|
20378
|
+
nextFiles.splice(index, 1);
|
|
20379
|
+
this.updateFiles(nextFiles);
|
|
20380
|
+
}
|
|
20381
|
+
trackFile(index, file) {
|
|
20382
|
+
return `${file.name}-${file.size}-${file.lastModified}-${index}`;
|
|
20383
|
+
}
|
|
20384
|
+
formatBytes(size) {
|
|
20385
|
+
if (size < 1024)
|
|
20386
|
+
return `${size} B`;
|
|
20387
|
+
if (size < 1024 * 1024)
|
|
20388
|
+
return `${(size / 1024).toFixed(1)} KB`;
|
|
20389
|
+
return `${(size / (1024 * 1024)).toFixed(1)} MB`;
|
|
20390
|
+
}
|
|
20391
|
+
consumeFiles(files) {
|
|
20392
|
+
if (files.length === 0)
|
|
20393
|
+
return;
|
|
20394
|
+
const accepted = [];
|
|
20395
|
+
const rejectedByAccept = [];
|
|
20396
|
+
const currentFiles = this.currentFiles();
|
|
20397
|
+
const remainingSlots = this.multiple() ? Math.max(this.maxFiles() - currentFiles.length, 0) : 1;
|
|
20398
|
+
for (const file of files) {
|
|
20399
|
+
if (!this.matchesAccept(file)) {
|
|
20400
|
+
rejectedByAccept.push(file);
|
|
20401
|
+
continue;
|
|
20402
|
+
}
|
|
20403
|
+
accepted.push(file);
|
|
20404
|
+
}
|
|
20405
|
+
const nextAccepted = this.multiple() ? accepted.slice(0, remainingSlots) : accepted.slice(0, 1);
|
|
20406
|
+
const rejectedByCount = this.multiple() ? accepted.slice(remainingSlots) : accepted.slice(1);
|
|
20407
|
+
const nextFiles = this.multiple() ? [...currentFiles, ...nextAccepted] : nextAccepted;
|
|
20408
|
+
this.rejectionMessage.set('');
|
|
20409
|
+
if (rejectedByAccept.length > 0) {
|
|
20410
|
+
this.rejectionMessage.set(this.translation.translate('fileInput.invalidFiles', { count: rejectedByAccept.length }));
|
|
20411
|
+
this.filesRejected.emit({ files: rejectedByAccept, reason: 'accept' });
|
|
20412
|
+
}
|
|
20413
|
+
if (rejectedByCount.length > 0) {
|
|
20414
|
+
this.rejectionMessage.set(this.translation.translate('fileInput.tooManyFiles', { max: this.maxFiles() }));
|
|
20415
|
+
this.filesRejected.emit({ files: rejectedByCount, reason: 'maxFiles' });
|
|
20416
|
+
}
|
|
20417
|
+
this.updateFiles(nextFiles);
|
|
20418
|
+
}
|
|
20419
|
+
updateFiles(files) {
|
|
20420
|
+
if (this.filesInput() === undefined) {
|
|
20421
|
+
this.internalFiles.set(files);
|
|
20422
|
+
}
|
|
20423
|
+
this.filesChange.emit(files);
|
|
20424
|
+
}
|
|
20425
|
+
matchesAccept(file) {
|
|
20426
|
+
const accept = this.accept().trim();
|
|
20427
|
+
if (!accept)
|
|
20428
|
+
return true;
|
|
20429
|
+
const type = file.type.toLowerCase();
|
|
20430
|
+
const name = file.name.toLowerCase();
|
|
20431
|
+
return accept
|
|
20432
|
+
.split(',')
|
|
20433
|
+
.map((entry) => entry.trim().toLowerCase())
|
|
20434
|
+
.some((rule) => {
|
|
20435
|
+
if (!rule)
|
|
20436
|
+
return false;
|
|
20437
|
+
if (rule.startsWith('.'))
|
|
20438
|
+
return name.endsWith(rule);
|
|
20439
|
+
if (rule.endsWith('/*'))
|
|
20440
|
+
return type.startsWith(`${rule.slice(0, -1)}`);
|
|
20441
|
+
return type === rule;
|
|
20442
|
+
});
|
|
20443
|
+
}
|
|
20444
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFileInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
20445
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvFileInputComponent, isStandalone: true, selector: "jv-file-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, describedBy: { classPropertyName: "describedBy", publicName: "describedBy", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxFiles: { classPropertyName: "maxFiles", publicName: "maxFiles", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, filesInput: { classPropertyName: "filesInput", publicName: "files", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filesChange: "filesChange", filesRejected: "filesRejected" }, viewQueries: [{ propertyName: "nativeInputRef", first: true, predicate: ["nativeInput"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
20446
|
+
<jv-form-container
|
|
20447
|
+
[label]="label()"
|
|
20448
|
+
[inputId]="inputId()"
|
|
20449
|
+
[required]="required()"
|
|
20450
|
+
[invalid]="invalid()"
|
|
20451
|
+
[hint]="hint()"
|
|
20452
|
+
[error]="error()"
|
|
20453
|
+
>
|
|
20454
|
+
<input
|
|
20455
|
+
#nativeInput
|
|
20456
|
+
class="jv-file-input-native"
|
|
20457
|
+
type="file"
|
|
20458
|
+
[id]="inputId()"
|
|
20459
|
+
[attr.accept]="accept() || null"
|
|
20460
|
+
[attr.multiple]="multiple() ? '' : null"
|
|
20461
|
+
[disabled]="disabled()"
|
|
20462
|
+
[attr.aria-describedby]="describedBy() || null"
|
|
20463
|
+
(change)="onNativeInputChange($any($event.target).files)"
|
|
20464
|
+
/>
|
|
20465
|
+
|
|
20466
|
+
<div
|
|
20467
|
+
class="jv-file-input-dropzone"
|
|
20468
|
+
[class.jv-file-input-dropzone--disabled]="disabled()"
|
|
20469
|
+
[class.jv-file-input-dropzone--dragover]="dragActive()"
|
|
20470
|
+
[class.jv-file-input-dropzone--invalid]="invalid()"
|
|
20471
|
+
role="button"
|
|
20472
|
+
tabindex="0"
|
|
20473
|
+
[attr.aria-disabled]="disabled() ? 'true' : 'false'"
|
|
20474
|
+
[attr.aria-label]="dropzoneAriaLabel()"
|
|
20475
|
+
(click)="openFileDialog()"
|
|
20476
|
+
(keydown)="handleDropzoneKeydown($event)"
|
|
20477
|
+
(dragenter)="onDragEnter($event)"
|
|
20478
|
+
(dragover)="onDragOver($event)"
|
|
20479
|
+
(dragleave)="onDragLeave($event)"
|
|
20480
|
+
(drop)="onDrop($event)"
|
|
20481
|
+
>
|
|
20482
|
+
<jv-icon name="upload-cloud" [size]="24" />
|
|
20483
|
+
<div class="jv-file-input-copy">
|
|
20484
|
+
<strong>{{ translation.translate('fileInput.dropLabel') }}</strong>
|
|
20485
|
+
<span>{{ translation.translate('fileInput.helperText') }}</span>
|
|
20486
|
+
<span class="jv-file-input-meta">{{ selectionSummary() }}</span>
|
|
20487
|
+
</div>
|
|
20488
|
+
</div>
|
|
20489
|
+
|
|
20490
|
+
@if (rejectionMessage()) {
|
|
20491
|
+
<p class="jv-file-input-rejection" aria-live="polite">{{ rejectionMessage() }}</p>
|
|
20492
|
+
}
|
|
20493
|
+
|
|
20494
|
+
@if (currentFiles().length > 0) {
|
|
20495
|
+
<ul class="jv-file-input-list">
|
|
20496
|
+
@for (file of currentFiles(); track trackFile($index, file); let index = $index) {
|
|
20497
|
+
<li class="jv-file-input-item">
|
|
20498
|
+
<div class="jv-file-input-item-copy">
|
|
20499
|
+
<span class="jv-file-input-item-name">{{ file.name }}</span>
|
|
20500
|
+
<span class="jv-file-input-item-meta">{{ formatBytes(file.size) }}</span>
|
|
20501
|
+
</div>
|
|
20502
|
+
<button
|
|
20503
|
+
type="button"
|
|
20504
|
+
class="jv-file-input-remove"
|
|
20505
|
+
[disabled]="disabled()"
|
|
20506
|
+
[attr.aria-label]="translation.translate('fileInput.removeFile', { name: file.name })"
|
|
20507
|
+
(click)="removeFile(index)"
|
|
20508
|
+
>
|
|
20509
|
+
<jv-icon name="x" [size]="16" />
|
|
20510
|
+
</button>
|
|
20511
|
+
</li>
|
|
20512
|
+
}
|
|
20513
|
+
</ul>
|
|
20514
|
+
}
|
|
20515
|
+
</jv-form-container>
|
|
20516
|
+
`, isInline: true, styles: [".jv-file-input-native{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.jv-file-input-dropzone{display:grid;grid-template-columns:auto 1fr;gap:var(--jv-spacing-md);align-items:center;padding:var(--jv-spacing-lg);border:1px dashed var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);cursor:pointer;transition:border-color .16s ease,background-color .16s ease,box-shadow .16s ease;outline:none}.jv-file-input-dropzone:hover,.jv-file-input-dropzone:focus-visible,.jv-file-input-dropzone--dragover{border-color:var(--jv-color-primary);background:var(--jv-color-surface-muted);box-shadow:inset 0 0 0 1px var(--jv-color-primary)}.jv-file-input-dropzone--invalid{border-color:var(--jv-color-danger)}.jv-file-input-dropzone--disabled{opacity:.65;cursor:not-allowed}.jv-file-input-copy{display:grid;gap:.25rem;min-width:0}.jv-file-input-copy span,.jv-file-input-meta,.jv-file-input-item-meta,.jv-file-input-rejection{color:var(--jv-color-foreground-muted)}.jv-file-input-rejection{margin:var(--jv-spacing-sm) 0 0;font-size:.875rem}.jv-file-input-list{list-style:none;padding:0;margin:var(--jv-spacing-md) 0 0;display:grid;gap:var(--jv-spacing-sm)}.jv-file-input-item{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-sm) var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface)}.jv-file-input-item-copy{min-width:0;display:grid;gap:.125rem}.jv-file-input-item-name{font-weight:600;color:var(--jv-color-foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.jv-file-input-remove{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;border-radius:999px;background:transparent;color:var(--jv-color-foreground-muted);cursor:pointer}.jv-file-input-remove:hover,.jv-file-input-remove:focus-visible{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground);outline:none}.jv-file-input-remove:disabled{opacity:.5;cursor:not-allowed}\n"], dependencies: [{ kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }] });
|
|
20517
|
+
}
|
|
20518
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFileInputComponent, decorators: [{
|
|
20519
|
+
type: Component,
|
|
20520
|
+
args: [{ selector: 'jv-file-input', standalone: true, imports: [JvFormContainerComponent, JvIconComponent], template: `
|
|
20521
|
+
<jv-form-container
|
|
20522
|
+
[label]="label()"
|
|
20523
|
+
[inputId]="inputId()"
|
|
20524
|
+
[required]="required()"
|
|
20525
|
+
[invalid]="invalid()"
|
|
20526
|
+
[hint]="hint()"
|
|
20527
|
+
[error]="error()"
|
|
20528
|
+
>
|
|
20529
|
+
<input
|
|
20530
|
+
#nativeInput
|
|
20531
|
+
class="jv-file-input-native"
|
|
20532
|
+
type="file"
|
|
20533
|
+
[id]="inputId()"
|
|
20534
|
+
[attr.accept]="accept() || null"
|
|
20535
|
+
[attr.multiple]="multiple() ? '' : null"
|
|
20536
|
+
[disabled]="disabled()"
|
|
20537
|
+
[attr.aria-describedby]="describedBy() || null"
|
|
20538
|
+
(change)="onNativeInputChange($any($event.target).files)"
|
|
20539
|
+
/>
|
|
20540
|
+
|
|
20541
|
+
<div
|
|
20542
|
+
class="jv-file-input-dropzone"
|
|
20543
|
+
[class.jv-file-input-dropzone--disabled]="disabled()"
|
|
20544
|
+
[class.jv-file-input-dropzone--dragover]="dragActive()"
|
|
20545
|
+
[class.jv-file-input-dropzone--invalid]="invalid()"
|
|
20546
|
+
role="button"
|
|
20547
|
+
tabindex="0"
|
|
20548
|
+
[attr.aria-disabled]="disabled() ? 'true' : 'false'"
|
|
20549
|
+
[attr.aria-label]="dropzoneAriaLabel()"
|
|
20550
|
+
(click)="openFileDialog()"
|
|
20551
|
+
(keydown)="handleDropzoneKeydown($event)"
|
|
20552
|
+
(dragenter)="onDragEnter($event)"
|
|
20553
|
+
(dragover)="onDragOver($event)"
|
|
20554
|
+
(dragleave)="onDragLeave($event)"
|
|
20555
|
+
(drop)="onDrop($event)"
|
|
20556
|
+
>
|
|
20557
|
+
<jv-icon name="upload-cloud" [size]="24" />
|
|
20558
|
+
<div class="jv-file-input-copy">
|
|
20559
|
+
<strong>{{ translation.translate('fileInput.dropLabel') }}</strong>
|
|
20560
|
+
<span>{{ translation.translate('fileInput.helperText') }}</span>
|
|
20561
|
+
<span class="jv-file-input-meta">{{ selectionSummary() }}</span>
|
|
20562
|
+
</div>
|
|
20563
|
+
</div>
|
|
20564
|
+
|
|
20565
|
+
@if (rejectionMessage()) {
|
|
20566
|
+
<p class="jv-file-input-rejection" aria-live="polite">{{ rejectionMessage() }}</p>
|
|
20567
|
+
}
|
|
20568
|
+
|
|
20569
|
+
@if (currentFiles().length > 0) {
|
|
20570
|
+
<ul class="jv-file-input-list">
|
|
20571
|
+
@for (file of currentFiles(); track trackFile($index, file); let index = $index) {
|
|
20572
|
+
<li class="jv-file-input-item">
|
|
20573
|
+
<div class="jv-file-input-item-copy">
|
|
20574
|
+
<span class="jv-file-input-item-name">{{ file.name }}</span>
|
|
20575
|
+
<span class="jv-file-input-item-meta">{{ formatBytes(file.size) }}</span>
|
|
20576
|
+
</div>
|
|
20577
|
+
<button
|
|
20578
|
+
type="button"
|
|
20579
|
+
class="jv-file-input-remove"
|
|
20580
|
+
[disabled]="disabled()"
|
|
20581
|
+
[attr.aria-label]="translation.translate('fileInput.removeFile', { name: file.name })"
|
|
20582
|
+
(click)="removeFile(index)"
|
|
20583
|
+
>
|
|
20584
|
+
<jv-icon name="x" [size]="16" />
|
|
20585
|
+
</button>
|
|
20586
|
+
</li>
|
|
20587
|
+
}
|
|
20588
|
+
</ul>
|
|
20589
|
+
}
|
|
20590
|
+
</jv-form-container>
|
|
20591
|
+
`, styles: [".jv-file-input-native{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.jv-file-input-dropzone{display:grid;grid-template-columns:auto 1fr;gap:var(--jv-spacing-md);align-items:center;padding:var(--jv-spacing-lg);border:1px dashed var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);cursor:pointer;transition:border-color .16s ease,background-color .16s ease,box-shadow .16s ease;outline:none}.jv-file-input-dropzone:hover,.jv-file-input-dropzone:focus-visible,.jv-file-input-dropzone--dragover{border-color:var(--jv-color-primary);background:var(--jv-color-surface-muted);box-shadow:inset 0 0 0 1px var(--jv-color-primary)}.jv-file-input-dropzone--invalid{border-color:var(--jv-color-danger)}.jv-file-input-dropzone--disabled{opacity:.65;cursor:not-allowed}.jv-file-input-copy{display:grid;gap:.25rem;min-width:0}.jv-file-input-copy span,.jv-file-input-meta,.jv-file-input-item-meta,.jv-file-input-rejection{color:var(--jv-color-foreground-muted)}.jv-file-input-rejection{margin:var(--jv-spacing-sm) 0 0;font-size:.875rem}.jv-file-input-list{list-style:none;padding:0;margin:var(--jv-spacing-md) 0 0;display:grid;gap:var(--jv-spacing-sm)}.jv-file-input-item{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-sm) var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface)}.jv-file-input-item-copy{min-width:0;display:grid;gap:.125rem}.jv-file-input-item-name{font-weight:600;color:var(--jv-color-foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.jv-file-input-remove{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;border-radius:999px;background:transparent;color:var(--jv-color-foreground-muted);cursor:pointer}.jv-file-input-remove:hover,.jv-file-input-remove:focus-visible{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground);outline:none}.jv-file-input-remove:disabled{opacity:.5;cursor:not-allowed}\n"] }]
|
|
20592
|
+
}], propDecorators: { nativeInputRef: [{ type: i0.ViewChild, args: ['nativeInput', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], describedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "describedBy", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], maxFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFiles", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], filesInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "files", required: false }] }], filesChange: [{ type: i0.Output, args: ["filesChange"] }], filesRejected: [{ type: i0.Output, args: ["filesRejected"] }] } });
|
|
20593
|
+
|
|
20152
20594
|
class JvListComponent {
|
|
20153
20595
|
role = input('list', ...(ngDevMode ? [{ debugName: "role" }] : /* istanbul ignore next */ []));
|
|
20154
20596
|
ariaRole = input(null, ...(ngDevMode ? [{ debugName: "ariaRole" }] : /* istanbul ignore next */ []));
|
|
@@ -22154,6 +22596,7 @@ const JV_GRID_DEFAULT_OPTIONS = {
|
|
|
22154
22596
|
let gridIdSequence = 0;
|
|
22155
22597
|
class JvGridComponent {
|
|
22156
22598
|
gridId = `jv-grid-${++gridIdSequence}`;
|
|
22599
|
+
formatService = inject(JvFormatService);
|
|
22157
22600
|
translationService = inject(JvTranslationService);
|
|
22158
22601
|
data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
22159
22602
|
columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
@@ -22222,7 +22665,7 @@ class JvGridComponent {
|
|
|
22222
22665
|
const value = this.getRawCellValue(row, col);
|
|
22223
22666
|
if (value == null)
|
|
22224
22667
|
return false;
|
|
22225
|
-
return
|
|
22668
|
+
return this.getSearchValue(value, col).includes(term);
|
|
22226
22669
|
});
|
|
22227
22670
|
});
|
|
22228
22671
|
}
|
|
@@ -22236,7 +22679,7 @@ class JvGridComponent {
|
|
|
22236
22679
|
const col = this.columns().find(c => this.colKey(c) === key);
|
|
22237
22680
|
if (!col || col.filterable === false)
|
|
22238
22681
|
return true;
|
|
22239
|
-
const value =
|
|
22682
|
+
const value = this.getSearchValue(this.getRawCellValue(row, col), col);
|
|
22240
22683
|
const fv = filter.value.toLowerCase();
|
|
22241
22684
|
switch (filter.operator) {
|
|
22242
22685
|
case 'contains': return value.includes(fv);
|
|
@@ -22258,8 +22701,9 @@ class JvGridComponent {
|
|
|
22258
22701
|
if (!columnKey || !direction)
|
|
22259
22702
|
return items;
|
|
22260
22703
|
return [...items].sort((a, b) => {
|
|
22261
|
-
const
|
|
22262
|
-
const
|
|
22704
|
+
const col = this.findColumn(columnKey);
|
|
22705
|
+
const va = this.getComparableValue(this.getRawCellValue(a, col), col);
|
|
22706
|
+
const vb = this.getComparableValue(this.getRawCellValue(b, col), col);
|
|
22263
22707
|
if (va == null)
|
|
22264
22708
|
return 1;
|
|
22265
22709
|
if (vb == null)
|
|
@@ -22363,14 +22807,56 @@ class JvGridComponent {
|
|
|
22363
22807
|
const val = this.getCellValue(row, col);
|
|
22364
22808
|
return val == null ? '' : String(val);
|
|
22365
22809
|
}
|
|
22366
|
-
formatValue(value, col) {
|
|
22810
|
+
formatValue(value, col, _row) {
|
|
22367
22811
|
if (value == null)
|
|
22368
22812
|
return '';
|
|
22369
|
-
|
|
22370
|
-
|
|
22813
|
+
const type = this.resolveColumnType(col);
|
|
22814
|
+
if (type === 'text' || type === 'boolean') {
|
|
22815
|
+
return String(value);
|
|
22816
|
+
}
|
|
22817
|
+
return this.formatService.format(type, value, this.getFormatOverrides(col));
|
|
22818
|
+
}
|
|
22819
|
+
getComparableValue(value, col) {
|
|
22820
|
+
const type = this.resolveColumnType(col);
|
|
22821
|
+
if (value == null || value === '')
|
|
22822
|
+
return null;
|
|
22823
|
+
if (type === 'text') {
|
|
22824
|
+
return String(value).toLowerCase();
|
|
22825
|
+
}
|
|
22826
|
+
if (type === 'boolean') {
|
|
22827
|
+
return Boolean(value);
|
|
22828
|
+
}
|
|
22829
|
+
return this.formatService.toComparable(type, value);
|
|
22830
|
+
}
|
|
22831
|
+
getSearchValue(value, col) {
|
|
22832
|
+
const type = this.resolveColumnType(col);
|
|
22833
|
+
if (type === 'text' || type === 'boolean') {
|
|
22834
|
+
return String(value ?? '').toLowerCase();
|
|
22835
|
+
}
|
|
22836
|
+
return this.formatService.toSearchValue(type, value);
|
|
22837
|
+
}
|
|
22838
|
+
getExportValue(value, col) {
|
|
22839
|
+
if (value == null)
|
|
22840
|
+
return '';
|
|
22841
|
+
const type = this.resolveColumnType(col);
|
|
22842
|
+
if (type === 'date' || type === 'time' || type === 'datetime') {
|
|
22843
|
+
const date = this.formatService.toDate(value);
|
|
22844
|
+
if (!date)
|
|
22845
|
+
return String(value);
|
|
22846
|
+
if (type === 'date')
|
|
22847
|
+
return date.toISOString().slice(0, 10);
|
|
22848
|
+
if (type === 'time')
|
|
22849
|
+
return date.toISOString().slice(11, 19);
|
|
22850
|
+
return date.toISOString();
|
|
22371
22851
|
}
|
|
22372
22852
|
return String(value);
|
|
22373
22853
|
}
|
|
22854
|
+
resolveColumnType(col) {
|
|
22855
|
+
return col.type ?? 'text';
|
|
22856
|
+
}
|
|
22857
|
+
getFormatOverrides(col) {
|
|
22858
|
+
return col.formatOptions;
|
|
22859
|
+
}
|
|
22374
22860
|
getAriaSort(col) {
|
|
22375
22861
|
if (col.sortable === false || !this.resolvedOptions().sortable)
|
|
22376
22862
|
return null;
|
|
@@ -22618,14 +23104,14 @@ class JvGridComponent {
|
|
|
22618
23104
|
}
|
|
22619
23105
|
// Export
|
|
22620
23106
|
exportCsv() {
|
|
22621
|
-
const cols = this.visibleColumns().map(c => ({ key: this.colKey(c), header: c.header }));
|
|
23107
|
+
const cols = this.visibleColumns().map(c => ({ key: this.colKey(c), header: c.header, column: c }));
|
|
22622
23108
|
const allData = this.effectiveOptions().serverSide ? this.data() : this.sortedData();
|
|
22623
23109
|
const headerRow = cols.map(c => `"${c.header}"`).join(',');
|
|
22624
23110
|
const dataRows = allData.map(row => cols.map(col => {
|
|
22625
23111
|
const val = row[col.key];
|
|
22626
23112
|
if (val == null)
|
|
22627
23113
|
return '';
|
|
22628
|
-
return `"${
|
|
23114
|
+
return `"${this.getExportValue(val, col.column).replace(/"/g, '""')}"`;
|
|
22629
23115
|
}).join(','));
|
|
22630
23116
|
const csv = [headerRow, ...dataRows].join('\r\n');
|
|
22631
23117
|
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
|
|
@@ -22637,13 +23123,13 @@ class JvGridComponent {
|
|
|
22637
23123
|
URL.revokeObjectURL(url);
|
|
22638
23124
|
}
|
|
22639
23125
|
exportExcel() {
|
|
22640
|
-
const cols = this.visibleColumns().map(c => ({ key: this.colKey(c), header: c.header }));
|
|
23126
|
+
const cols = this.visibleColumns().map(c => ({ key: this.colKey(c), header: c.header, column: c }));
|
|
22641
23127
|
const allData = this.effectiveOptions().serverSide ? this.data() : this.sortedData();
|
|
22642
23128
|
let html = '<table>';
|
|
22643
23129
|
html += '<thead><tr>' + cols.map(c => `<th>${c.header}</th>`).join('') + '</tr></thead>';
|
|
22644
23130
|
html += '<tbody>';
|
|
22645
23131
|
for (const row of allData) {
|
|
22646
|
-
html += '<tr>' + cols.map(col => `<td>${row[col.key]
|
|
23132
|
+
html += '<tr>' + cols.map(col => `<td>${this.getExportValue(row[col.key], col.column)}</td>`).join('') + '</tr>';
|
|
22647
23133
|
}
|
|
22648
23134
|
html += '</tbody></table>';
|
|
22649
23135
|
const blob = new Blob([html], { type: 'application/vnd.ms-excel' });
|
|
@@ -22924,7 +23410,7 @@ class JvGridComponent {
|
|
|
22924
23410
|
} @else if (col.format) {
|
|
22925
23411
|
{{ col.format(value, row) }}
|
|
22926
23412
|
} @else {
|
|
22927
|
-
{{ formatValue(value, col) }}
|
|
23413
|
+
{{ formatValue(value, col, row) }}
|
|
22928
23414
|
}
|
|
22929
23415
|
}
|
|
22930
23416
|
</td>
|
|
@@ -23275,7 +23761,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
23275
23761
|
} @else if (col.format) {
|
|
23276
23762
|
{{ col.format(value, row) }}
|
|
23277
23763
|
} @else {
|
|
23278
|
-
{{ formatValue(value, col) }}
|
|
23764
|
+
{{ formatValue(value, col, row) }}
|
|
23279
23765
|
}
|
|
23280
23766
|
}
|
|
23281
23767
|
</td>
|
|
@@ -23524,5 +24010,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
23524
24010
|
* Generated bundle index. Do not edit.
|
|
23525
24011
|
*/
|
|
23526
24012
|
|
|
23527
|
-
export { EN, ES, JV_DEFAULT_LOCALE, JV_FALLBACK_ICON_NAME, JV_GRID_DEFAULT_OPTIONS, JV_LOCALE_DICTIONARIES, JV_LUCIDE_ICON_REGISTRY, JV_UI_CONFIG, JV_UI_CONFIG_DEFAULTS, JV_UI_DEFAULT_CONFIG, JvAccordionComponent, JvAccordionPanelDirective, JvAlertComponent, JvAnnouncementService, JvBadgeComponent, JvBreadcrumbComponent, JvButtonComponent, JvButtonGroupComponent, JvCardComponent, JvChangePasswordPageComponent, JvCheckboxComponent, JvCodeComponent, JvCollapsiblePanelComponent, JvConfirmDialogComponent, JvDashboardShellComponent, JvDatePickerComponent, JvDialogComponent, JvDialogService, JvDividerComponent, JvForgotPasswordPageComponent, JvFormContainerComponent, JvGridComponent, JvIconButtonComponent, JvIconComponent, JvInputComponent, JvListComponent, JvListItemComponent, JvLoaderComponent, JvLoaderService, JvLoginPageComponent, JvModalSelectorComponent, JvPageComponent, JvPaginationComponent, JvRadioComponent, JvSectionComponent, JvSelectComponent, JvSidebarComponent, JvSwitchComponent, JvTabPanelDirective, JvTabsComponent, JvTextareaComponent, JvThemeService, JvToastComponent, JvToastService, JvTooltipDirective, JvTopbarComponent, JvTranslationService, provideJvUi };
|
|
24013
|
+
export { EN, ES, JV_DEFAULT_LOCALE, JV_FALLBACK_ICON_NAME, JV_GRID_DEFAULT_OPTIONS, JV_LOCALE_DICTIONARIES, JV_LUCIDE_ICON_REGISTRY, JV_UI_CONFIG, JV_UI_CONFIG_DEFAULTS, JV_UI_DEFAULT_CONFIG, JvAccordionComponent, JvAccordionPanelDirective, JvAlertComponent, JvAnnouncementService, JvBadgeComponent, JvBreadcrumbComponent, JvButtonComponent, JvButtonGroupComponent, JvCardComponent, JvChangePasswordPageComponent, JvCheckboxComponent, JvCodeComponent, JvCollapsiblePanelComponent, JvConfirmDialogComponent, JvDashboardShellComponent, JvDatePickerComponent, JvDialogComponent, JvDialogService, JvDividerComponent, JvFileInputComponent, JvForgotPasswordPageComponent, JvFormContainerComponent, JvFormatService, JvGridComponent, JvIconButtonComponent, JvIconComponent, JvInputComponent, JvListComponent, JvListItemComponent, JvLoaderComponent, JvLoaderService, JvLoginPageComponent, JvModalSelectorComponent, JvPageComponent, JvPaginationComponent, JvRadioComponent, JvSectionComponent, JvSelectComponent, JvSidebarComponent, JvSwitchComponent, JvTabPanelDirective, JvTabsComponent, JvTextareaComponent, JvThemeService, JvToastComponent, JvToastService, JvTooltipDirective, JvTopbarComponent, JvTranslationService, provideJvUi };
|
|
23528
24014
|
//# sourceMappingURL=devjuliovilla-jv-ui.mjs.map
|