@devjuliovilla/jv-ui 1.9.0 → 1.11.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 +266 -3
- package/fesm2022/devjuliovilla-jv-ui.mjs +1317 -208
- package/fesm2022/devjuliovilla-jv-ui.mjs.map +1 -1
- package/package.json +4 -1
- package/types/devjuliovilla-jv-ui.d.ts +193 -9
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, computed, Component, forwardRef, inject, output, Directive, Injectable, signal, InjectionToken, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, effect, contentChildren, HostListener, viewChild, viewChildren, afterNextRender, Renderer2, ElementRef } from '@angular/core';
|
|
2
|
+
import { input, computed, Component, forwardRef, inject, output, Directive, Injectable, signal, InjectionToken, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, effect, contentChildren, HostListener, viewChild, viewChildren, numberAttribute, afterNextRender, Renderer2, ElementRef } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/forms';
|
|
4
4
|
import { NG_VALUE_ACCESSOR, FormBuilder, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
|
|
5
5
|
import { CommonModule, DOCUMENT, NgTemplateOutlet } from '@angular/common';
|
|
@@ -18717,9 +18717,136 @@ 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',
|
|
18732
|
+
tabsTransition: 'none',
|
|
18721
18733
|
};
|
|
18722
18734
|
|
|
18735
|
+
class JvFormatService {
|
|
18736
|
+
config = inject(JvUiConfigService);
|
|
18737
|
+
formatLocale = signal(this.config.snapshot.formatLocale || this.config.snapshot.language || 'es-MX', ...(ngDevMode ? [{ debugName: "formatLocale" }] : /* istanbul ignore next */ []));
|
|
18738
|
+
formats = signal(this.resolveFormats(this.config.snapshot.formats), ...(ngDevMode ? [{ debugName: "formats" }] : /* istanbul ignore next */ []));
|
|
18739
|
+
firstDayOfWeek = computed(() => this.resolveFirstDayOfWeek(this.formatLocale()), ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : /* istanbul ignore next */ []));
|
|
18740
|
+
initialize() {
|
|
18741
|
+
this.formatLocale.set(this.config.snapshot.formatLocale || this.config.snapshot.language || 'es-MX');
|
|
18742
|
+
this.formats.set(this.resolveFormats(this.config.snapshot.formats));
|
|
18743
|
+
}
|
|
18744
|
+
setFormatLocale(locale) {
|
|
18745
|
+
this.formatLocale.set(locale);
|
|
18746
|
+
}
|
|
18747
|
+
setFormats(formats) {
|
|
18748
|
+
this.formats.update((current) => this.resolveFormats({ ...current, ...formats }));
|
|
18749
|
+
}
|
|
18750
|
+
format(kind, value, overrides) {
|
|
18751
|
+
if (value == null || value === '')
|
|
18752
|
+
return '';
|
|
18753
|
+
if (kind === 'date' || kind === 'time' || kind === 'datetime') {
|
|
18754
|
+
const date = this.toDate(value);
|
|
18755
|
+
if (!date)
|
|
18756
|
+
return String(value);
|
|
18757
|
+
return new Intl.DateTimeFormat(this.formatLocale(), this.resolveDateOptions(kind, overrides)).format(date);
|
|
18758
|
+
}
|
|
18759
|
+
const number = this.toNumber(value);
|
|
18760
|
+
if (number === null)
|
|
18761
|
+
return String(value);
|
|
18762
|
+
return new Intl.NumberFormat(this.formatLocale(), this.resolveNumberOptions(kind, overrides)).format(number);
|
|
18763
|
+
}
|
|
18764
|
+
toComparable(kind, value) {
|
|
18765
|
+
if (value == null || value === '')
|
|
18766
|
+
return null;
|
|
18767
|
+
if (kind === 'date' || kind === 'time' || kind === 'datetime') {
|
|
18768
|
+
const date = this.toDate(value);
|
|
18769
|
+
return date ? date.getTime() : String(value);
|
|
18770
|
+
}
|
|
18771
|
+
if (kind === 'integer' || kind === 'number' || kind === 'currency' || kind === 'percent') {
|
|
18772
|
+
const number = this.toNumber(value);
|
|
18773
|
+
return number ?? String(value);
|
|
18774
|
+
}
|
|
18775
|
+
return String(value);
|
|
18776
|
+
}
|
|
18777
|
+
toDate(value) {
|
|
18778
|
+
if (value instanceof Date) {
|
|
18779
|
+
return Number.isNaN(value.getTime()) ? null : value;
|
|
18780
|
+
}
|
|
18781
|
+
if (typeof value === 'number' || typeof value === 'string') {
|
|
18782
|
+
const date = new Date(value);
|
|
18783
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
18784
|
+
}
|
|
18785
|
+
return null;
|
|
18786
|
+
}
|
|
18787
|
+
toNumber(value) {
|
|
18788
|
+
if (typeof value === 'number') {
|
|
18789
|
+
return Number.isFinite(value) ? value : null;
|
|
18790
|
+
}
|
|
18791
|
+
if (typeof value === 'string') {
|
|
18792
|
+
const normalized = value.trim().replace(/[%,$\s]/g, '').replace(/,/g, '');
|
|
18793
|
+
if (!normalized)
|
|
18794
|
+
return null;
|
|
18795
|
+
const parsed = Number(normalized);
|
|
18796
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
18797
|
+
}
|
|
18798
|
+
return null;
|
|
18799
|
+
}
|
|
18800
|
+
toSearchValue(kind, value) {
|
|
18801
|
+
if (value == null)
|
|
18802
|
+
return '';
|
|
18803
|
+
if (kind === 'date' || kind === 'time' || kind === 'datetime') {
|
|
18804
|
+
const date = this.toDate(value);
|
|
18805
|
+
if (!date)
|
|
18806
|
+
return String(value).toLowerCase();
|
|
18807
|
+
return date.toISOString().toLowerCase();
|
|
18808
|
+
}
|
|
18809
|
+
return String(value).toLowerCase();
|
|
18810
|
+
}
|
|
18811
|
+
resolveFormats(formats) {
|
|
18812
|
+
const defaults = this.config.snapshot.formats;
|
|
18813
|
+
return {
|
|
18814
|
+
date: { ...defaults.date, ...formats?.date },
|
|
18815
|
+
time: { ...defaults.time, ...formats?.time },
|
|
18816
|
+
datetime: { ...defaults.datetime, ...formats?.datetime },
|
|
18817
|
+
integer: { ...defaults.integer, ...formats?.integer },
|
|
18818
|
+
number: { ...defaults.number, ...formats?.number },
|
|
18819
|
+
currency: { ...defaults.currency, ...formats?.currency },
|
|
18820
|
+
percent: { ...defaults.percent, ...formats?.percent },
|
|
18821
|
+
};
|
|
18822
|
+
}
|
|
18823
|
+
resolveDateOptions(kind, overrides) {
|
|
18824
|
+
return { ...this.formats()[kind], ...overrides };
|
|
18825
|
+
}
|
|
18826
|
+
resolveNumberOptions(kind, overrides) {
|
|
18827
|
+
return { ...this.formats()[kind], ...overrides };
|
|
18828
|
+
}
|
|
18829
|
+
resolveFirstDayOfWeek(locale) {
|
|
18830
|
+
try {
|
|
18831
|
+
const intlLocale = new Intl.Locale(locale);
|
|
18832
|
+
const firstDay = intlLocale.weekInfo?.firstDay;
|
|
18833
|
+
if (typeof firstDay === 'number') {
|
|
18834
|
+
return firstDay % 7;
|
|
18835
|
+
}
|
|
18836
|
+
}
|
|
18837
|
+
catch {
|
|
18838
|
+
// Ignore unsupported Intl.Locale implementations.
|
|
18839
|
+
}
|
|
18840
|
+
return 0;
|
|
18841
|
+
}
|
|
18842
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
18843
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, providedIn: 'root' });
|
|
18844
|
+
}
|
|
18845
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, decorators: [{
|
|
18846
|
+
type: Injectable,
|
|
18847
|
+
args: [{ providedIn: 'root' }]
|
|
18848
|
+
}] });
|
|
18849
|
+
|
|
18723
18850
|
class JvThemeService {
|
|
18724
18851
|
document = inject(DOCUMENT);
|
|
18725
18852
|
config = inject(JvUiConfigService);
|
|
@@ -18810,6 +18937,7 @@ function provideJvUi(config = {}) {
|
|
|
18810
18937
|
useValue: () => {
|
|
18811
18938
|
inject(JvThemeService).initialize();
|
|
18812
18939
|
inject(JvTranslationService).initialize();
|
|
18940
|
+
inject(JvFormatService).initialize();
|
|
18813
18941
|
},
|
|
18814
18942
|
},
|
|
18815
18943
|
]);
|
|
@@ -18817,9 +18945,19 @@ function provideJvUi(config = {}) {
|
|
|
18817
18945
|
|
|
18818
18946
|
class JvUiConfigService {
|
|
18819
18947
|
defaults = inject(JV_UI_CONFIG_DEFAULTS);
|
|
18820
|
-
configLayers = inject(JV_UI_CONFIG, { optional: true }) ?? [];
|
|
18948
|
+
configLayers = (inject(JV_UI_CONFIG, { optional: true }) ?? []);
|
|
18821
18949
|
get snapshot() {
|
|
18822
|
-
return this.configLayers.reduce((merged, layer) => ({
|
|
18950
|
+
return this.configLayers.reduce((merged, layer) => ({
|
|
18951
|
+
...merged,
|
|
18952
|
+
...layer,
|
|
18953
|
+
formats: {
|
|
18954
|
+
...merged.formats,
|
|
18955
|
+
...(layer.formats ?? {}),
|
|
18956
|
+
},
|
|
18957
|
+
}), {
|
|
18958
|
+
...this.defaults,
|
|
18959
|
+
formats: { ...this.defaults.formats },
|
|
18960
|
+
});
|
|
18823
18961
|
}
|
|
18824
18962
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
18825
18963
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, providedIn: 'root' });
|
|
@@ -18878,11 +19016,23 @@ const ES = {
|
|
|
18878
19016
|
'modalSelector.results': '{count} resultados',
|
|
18879
19017
|
'modalSelector.selected': '{label} seleccionado',
|
|
18880
19018
|
'modalSelector.selectionCleared': 'Seleccion limpiada',
|
|
19019
|
+
'fileInput.dropLabel': 'Arrastre archivos aqui o haga clic para seleccionarlos',
|
|
19020
|
+
'fileInput.helperText': 'Compatible con seleccion multiple y arrastrar y soltar',
|
|
19021
|
+
'fileInput.selectionSummary': '{count} de {max} archivos seleccionados',
|
|
19022
|
+
'fileInput.invalidFiles': '{count} archivos no coinciden con el tipo permitido',
|
|
19023
|
+
'fileInput.tooManyFiles': 'Solo se permiten hasta {max} archivos',
|
|
19024
|
+
'fileInput.removeFile': 'Quitar archivo {name}',
|
|
18881
19025
|
'dialog.confirmTitle': 'Confirmar',
|
|
18882
19026
|
'dialog.confirm': 'Aceptar',
|
|
18883
19027
|
'dialog.cancel': 'Cancelar',
|
|
18884
19028
|
'common.expanded': 'Expandido',
|
|
18885
19029
|
'common.collapsed': 'Colapsado',
|
|
19030
|
+
'slider.prevImage': 'Imagen anterior',
|
|
19031
|
+
'slider.nextImage': 'Imagen siguiente',
|
|
19032
|
+
'slider.thumbnailList': 'Miniaturas de imagenes',
|
|
19033
|
+
'gallery.close': 'Cerrar',
|
|
19034
|
+
'gallery.prevImage': 'Imagen anterior',
|
|
19035
|
+
'gallery.nextImage': 'Imagen siguiente',
|
|
18886
19036
|
};
|
|
18887
19037
|
|
|
18888
19038
|
const EN = {
|
|
@@ -18934,11 +19084,23 @@ const EN = {
|
|
|
18934
19084
|
'modalSelector.results': '{count} results',
|
|
18935
19085
|
'modalSelector.selected': '{label} selected',
|
|
18936
19086
|
'modalSelector.selectionCleared': 'Selection cleared',
|
|
19087
|
+
'fileInput.dropLabel': 'Drag files here or click to choose them',
|
|
19088
|
+
'fileInput.helperText': 'Supports multiple selection and drag and drop',
|
|
19089
|
+
'fileInput.selectionSummary': '{count} of {max} files selected',
|
|
19090
|
+
'fileInput.invalidFiles': '{count} files do not match the allowed type',
|
|
19091
|
+
'fileInput.tooManyFiles': 'Only up to {max} files are allowed',
|
|
19092
|
+
'fileInput.removeFile': 'Remove file {name}',
|
|
18937
19093
|
'dialog.confirmTitle': 'Confirm',
|
|
18938
19094
|
'dialog.confirm': 'Confirm',
|
|
18939
19095
|
'dialog.cancel': 'Cancel',
|
|
18940
19096
|
'common.expanded': 'Expanded',
|
|
18941
19097
|
'common.collapsed': 'Collapsed',
|
|
19098
|
+
'slider.prevImage': 'Previous image',
|
|
19099
|
+
'slider.nextImage': 'Next image',
|
|
19100
|
+
'slider.thumbnailList': 'Image thumbnails',
|
|
19101
|
+
'gallery.close': 'Close',
|
|
19102
|
+
'gallery.prevImage': 'Previous image',
|
|
19103
|
+
'gallery.nextImage': 'Next image',
|
|
18942
19104
|
};
|
|
18943
19105
|
|
|
18944
19106
|
const JV_LOCALE_DICTIONARIES = {
|
|
@@ -18949,14 +19111,17 @@ const JV_DEFAULT_LOCALE = 'es';
|
|
|
18949
19111
|
|
|
18950
19112
|
class JvTranslationService {
|
|
18951
19113
|
config = inject(JvUiConfigService);
|
|
18952
|
-
locale = signal(this.config.snapshot.locale, ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
19114
|
+
locale = signal(this.resolveLocale(this.config.snapshot.messagesLocale ?? this.config.snapshot.locale), ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
18953
19115
|
initialize() {
|
|
18954
|
-
const locale = this.resolveLocale(this.config.snapshot.locale);
|
|
19116
|
+
const locale = this.resolveLocale(this.config.snapshot.messagesLocale ?? this.config.snapshot.locale);
|
|
18955
19117
|
this.locale.set(locale);
|
|
18956
19118
|
}
|
|
18957
19119
|
setLocale(locale) {
|
|
18958
19120
|
this.locale.set(locale);
|
|
18959
19121
|
}
|
|
19122
|
+
setMessagesLocale(locale) {
|
|
19123
|
+
this.setLocale(locale);
|
|
19124
|
+
}
|
|
18960
19125
|
translate(key, params) {
|
|
18961
19126
|
const dict = JV_LOCALE_DICTIONARIES[this.locale()] ?? JV_LOCALE_DICTIONARIES[JV_DEFAULT_LOCALE];
|
|
18962
19127
|
let value = dict[key];
|
|
@@ -18971,6 +19136,8 @@ class JvTranslationService {
|
|
|
18971
19136
|
return value;
|
|
18972
19137
|
}
|
|
18973
19138
|
resolveLocale(locale) {
|
|
19139
|
+
if (!locale)
|
|
19140
|
+
return JV_DEFAULT_LOCALE;
|
|
18974
19141
|
if (locale === 'es' || locale === 'en')
|
|
18975
19142
|
return locale;
|
|
18976
19143
|
return locale.startsWith('es') ? 'es' : 'en';
|
|
@@ -19749,6 +19916,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
19749
19916
|
let datePickerIdSequence = 0;
|
|
19750
19917
|
class JvDatePickerComponent {
|
|
19751
19918
|
translation = inject(JvTranslationService);
|
|
19919
|
+
formatService = inject(JvFormatService);
|
|
19752
19920
|
announcementService = inject(JvAnnouncementService);
|
|
19753
19921
|
instanceId = ++datePickerIdSequence;
|
|
19754
19922
|
calendarRootRef = viewChild('calendarRoot', ...(ngDevMode ? [{ debugName: "calendarRootRef" }] : /* istanbul ignore next */ []));
|
|
@@ -19781,14 +19949,10 @@ class JvDatePickerComponent {
|
|
|
19781
19949
|
if (!value) {
|
|
19782
19950
|
return this.placeholder() || this.translation.translate('datePicker.placeholder');
|
|
19783
19951
|
}
|
|
19784
|
-
return
|
|
19785
|
-
day: '2-digit',
|
|
19786
|
-
month: '2-digit',
|
|
19787
|
-
year: 'numeric',
|
|
19788
|
-
}).format(value);
|
|
19952
|
+
return this.formatService.format('date', value);
|
|
19789
19953
|
}, ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
|
|
19790
19954
|
monthOptions = computed(() => {
|
|
19791
|
-
const formatter = new Intl.DateTimeFormat(this.
|
|
19955
|
+
const formatter = new Intl.DateTimeFormat(this.formatService.formatLocale(), { month: 'long' });
|
|
19792
19956
|
return Array.from({ length: 12 }, (_, month) => ({
|
|
19793
19957
|
label: capitalize(formatter.format(new Date(2026, month, 1))),
|
|
19794
19958
|
value: String(month),
|
|
@@ -19802,7 +19966,7 @@ class JvDatePickerComponent {
|
|
|
19802
19966
|
}, ...(ngDevMode ? [{ debugName: "yearOptions" }] : /* istanbul ignore next */ []));
|
|
19803
19967
|
weekdayLabels = computed(() => {
|
|
19804
19968
|
const startDay = this.firstDayOfWeek();
|
|
19805
|
-
const formatter = new Intl.DateTimeFormat(this.
|
|
19969
|
+
const formatter = new Intl.DateTimeFormat(this.formatService.formatLocale(), { weekday: 'short' });
|
|
19806
19970
|
return Array.from({ length: 7 }, (_, index) => capitalize(formatter.format(addDays(new Date(2026, 5, 7), startDay + index))));
|
|
19807
19971
|
}, ...(ngDevMode ? [{ debugName: "weekdayLabels" }] : /* istanbul ignore next */ []));
|
|
19808
19972
|
calendarCells = computed(() => {
|
|
@@ -19944,10 +20108,10 @@ class JvDatePickerComponent {
|
|
|
19944
20108
|
root?.querySelector(`[data-jv-date="${this.isoDate(date)}"]`)?.focus();
|
|
19945
20109
|
}
|
|
19946
20110
|
firstDayOfWeek() {
|
|
19947
|
-
return this.
|
|
20111
|
+
return this.formatService.firstDayOfWeek();
|
|
19948
20112
|
}
|
|
19949
20113
|
displayDateForAnnouncement(date) {
|
|
19950
|
-
return new Intl.DateTimeFormat(this.
|
|
20114
|
+
return new Intl.DateTimeFormat(this.formatService.formatLocale(), {
|
|
19951
20115
|
weekday: 'long',
|
|
19952
20116
|
day: 'numeric',
|
|
19953
20117
|
month: 'long',
|
|
@@ -19961,83 +20125,83 @@ class JvDatePickerComponent {
|
|
|
19961
20125
|
useExisting: forwardRef(() => JvDatePickerComponent),
|
|
19962
20126
|
multi: true,
|
|
19963
20127
|
},
|
|
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>
|
|
20128
|
+
], viewQueries: [{ propertyName: "calendarRootRef", first: true, predicate: ["calendarRoot"], descendants: true, isSignal: true }, { propertyName: "triggerButtonRef", first: true, predicate: ["triggerButton"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
20129
|
+
<jv-form-container
|
|
20130
|
+
[label]="label()"
|
|
20131
|
+
[inputId]="inputId()"
|
|
20132
|
+
[required]="required()"
|
|
20133
|
+
[invalid]="invalid()"
|
|
20134
|
+
[hint]="hint()"
|
|
20135
|
+
[error]="error()"
|
|
20136
|
+
>
|
|
20137
|
+
<button
|
|
20138
|
+
#triggerButton
|
|
20139
|
+
type="button"
|
|
20140
|
+
class="jv-date-picker-trigger"
|
|
20141
|
+
[class.is-invalid]="invalid()"
|
|
20142
|
+
[id]="inputId()"
|
|
20143
|
+
[disabled]="disabled"
|
|
20144
|
+
[attr.aria-haspopup]="'dialog'"
|
|
20145
|
+
[attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
|
|
20146
|
+
[attr.aria-controls]="dialogId"
|
|
20147
|
+
[attr.aria-invalid]="invalid() ? 'true' : null"
|
|
20148
|
+
[attr.aria-describedby]="describedBy() || null"
|
|
20149
|
+
[attr.aria-label]="triggerAriaLabel()"
|
|
20150
|
+
[attr.title]="displayValue()"
|
|
20151
|
+
(click)="openDialog()"
|
|
20152
|
+
(blur)="handleBlur()"
|
|
20153
|
+
>
|
|
20154
|
+
<span [class.jv-date-picker-placeholder]="!currentValue()">{{ displayValue() }}</span>
|
|
20155
|
+
<jv-icon name="calendar-days" [size]="18" />
|
|
20156
|
+
</button>
|
|
20157
|
+
</jv-form-container>
|
|
20158
|
+
|
|
20159
|
+
<jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" (closed)="closeDialog()">
|
|
20160
|
+
<div #calendarRoot [id]="dialogId" class="jv-date-picker-dialog">
|
|
20161
|
+
<div class="jv-date-picker-toolbar">
|
|
20162
|
+
<jv-icon-button icon="chevron-left" variant="ghost" [ariaLabel]="translation.translate('datePicker.prevMonth')" (click)="shiftMonth(-1)" />
|
|
20163
|
+
|
|
20164
|
+
<div class="jv-date-picker-selects">
|
|
20165
|
+
<jv-select [options]="monthOptions()" [modelValue]="visibleMonth().getMonth().toString()" (selectionChange)="handleMonthChange($event)" />
|
|
20166
|
+
<jv-select [options]="yearOptions()" [modelValue]="visibleMonth().getFullYear().toString()" (selectionChange)="handleYearChange($event)" />
|
|
20167
|
+
</div>
|
|
20168
|
+
|
|
20169
|
+
<jv-icon-button icon="chevron-right" variant="ghost" [ariaLabel]="translation.translate('datePicker.nextMonth')" (click)="shiftMonth(1)" />
|
|
20170
|
+
</div>
|
|
20171
|
+
|
|
20172
|
+
<div class="jv-date-picker-weekdays" aria-hidden="true">
|
|
20173
|
+
@for (weekday of weekdayLabels(); track weekday) {
|
|
20174
|
+
<span>{{ weekday }}</span>
|
|
20175
|
+
}
|
|
20176
|
+
</div>
|
|
20177
|
+
|
|
20178
|
+
<div class="jv-date-picker-grid" role="grid" [attr.aria-label]="resolvedDialogTitle()">
|
|
20179
|
+
@for (cell of calendarCells(); track isoDate(cell.date)) {
|
|
20180
|
+
<button
|
|
20181
|
+
type="button"
|
|
20182
|
+
class="jv-date-picker-day"
|
|
20183
|
+
[class.jv-date-picker-day--outside]="!cell.currentMonth"
|
|
20184
|
+
[class.jv-date-picker-day--today]="cell.isToday"
|
|
20185
|
+
[class.jv-date-picker-day--selected]="isSelected(cell.date)"
|
|
20186
|
+
[attr.data-jv-date]="isoDate(cell.date)"
|
|
20187
|
+
[attr.tabindex]="isFocusedDate(cell.date) ? 0 : -1"
|
|
20188
|
+
[attr.aria-selected]="isSelected(cell.date) ? 'true' : 'false'"
|
|
20189
|
+
(click)="selectDate(cell.date)"
|
|
20190
|
+
(keydown)="handleDayKeydown($event, cell.date)"
|
|
20191
|
+
>
|
|
20192
|
+
{{ cell.date.getDate() }}
|
|
20193
|
+
</button>
|
|
20194
|
+
}
|
|
20195
|
+
</div>
|
|
20196
|
+
</div>
|
|
20197
|
+
|
|
20198
|
+
<div dialog-actions class="jv-date-picker-actions">
|
|
20199
|
+
@if (currentValue()) {
|
|
20200
|
+
<jv-button variant="ghost" (click)="clearSelection()">{{ translation.translate('datePicker.clear') }}</jv-button>
|
|
20201
|
+
}
|
|
20202
|
+
<jv-button variant="outline" (click)="closeDialog()">{{ translation.translate('datePicker.close') }}</jv-button>
|
|
20203
|
+
</div>
|
|
20204
|
+
</jv-dialog>
|
|
20041
20205
|
`, 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
20206
|
}
|
|
20043
20207
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDatePickerComponent, decorators: [{
|
|
@@ -20048,83 +20212,83 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
20048
20212
|
useExisting: forwardRef(() => JvDatePickerComponent),
|
|
20049
20213
|
multi: true,
|
|
20050
20214
|
},
|
|
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>
|
|
20215
|
+
], template: `
|
|
20216
|
+
<jv-form-container
|
|
20217
|
+
[label]="label()"
|
|
20218
|
+
[inputId]="inputId()"
|
|
20219
|
+
[required]="required()"
|
|
20220
|
+
[invalid]="invalid()"
|
|
20221
|
+
[hint]="hint()"
|
|
20222
|
+
[error]="error()"
|
|
20223
|
+
>
|
|
20224
|
+
<button
|
|
20225
|
+
#triggerButton
|
|
20226
|
+
type="button"
|
|
20227
|
+
class="jv-date-picker-trigger"
|
|
20228
|
+
[class.is-invalid]="invalid()"
|
|
20229
|
+
[id]="inputId()"
|
|
20230
|
+
[disabled]="disabled"
|
|
20231
|
+
[attr.aria-haspopup]="'dialog'"
|
|
20232
|
+
[attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
|
|
20233
|
+
[attr.aria-controls]="dialogId"
|
|
20234
|
+
[attr.aria-invalid]="invalid() ? 'true' : null"
|
|
20235
|
+
[attr.aria-describedby]="describedBy() || null"
|
|
20236
|
+
[attr.aria-label]="triggerAriaLabel()"
|
|
20237
|
+
[attr.title]="displayValue()"
|
|
20238
|
+
(click)="openDialog()"
|
|
20239
|
+
(blur)="handleBlur()"
|
|
20240
|
+
>
|
|
20241
|
+
<span [class.jv-date-picker-placeholder]="!currentValue()">{{ displayValue() }}</span>
|
|
20242
|
+
<jv-icon name="calendar-days" [size]="18" />
|
|
20243
|
+
</button>
|
|
20244
|
+
</jv-form-container>
|
|
20245
|
+
|
|
20246
|
+
<jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" (closed)="closeDialog()">
|
|
20247
|
+
<div #calendarRoot [id]="dialogId" class="jv-date-picker-dialog">
|
|
20248
|
+
<div class="jv-date-picker-toolbar">
|
|
20249
|
+
<jv-icon-button icon="chevron-left" variant="ghost" [ariaLabel]="translation.translate('datePicker.prevMonth')" (click)="shiftMonth(-1)" />
|
|
20250
|
+
|
|
20251
|
+
<div class="jv-date-picker-selects">
|
|
20252
|
+
<jv-select [options]="monthOptions()" [modelValue]="visibleMonth().getMonth().toString()" (selectionChange)="handleMonthChange($event)" />
|
|
20253
|
+
<jv-select [options]="yearOptions()" [modelValue]="visibleMonth().getFullYear().toString()" (selectionChange)="handleYearChange($event)" />
|
|
20254
|
+
</div>
|
|
20255
|
+
|
|
20256
|
+
<jv-icon-button icon="chevron-right" variant="ghost" [ariaLabel]="translation.translate('datePicker.nextMonth')" (click)="shiftMonth(1)" />
|
|
20257
|
+
</div>
|
|
20258
|
+
|
|
20259
|
+
<div class="jv-date-picker-weekdays" aria-hidden="true">
|
|
20260
|
+
@for (weekday of weekdayLabels(); track weekday) {
|
|
20261
|
+
<span>{{ weekday }}</span>
|
|
20262
|
+
}
|
|
20263
|
+
</div>
|
|
20264
|
+
|
|
20265
|
+
<div class="jv-date-picker-grid" role="grid" [attr.aria-label]="resolvedDialogTitle()">
|
|
20266
|
+
@for (cell of calendarCells(); track isoDate(cell.date)) {
|
|
20267
|
+
<button
|
|
20268
|
+
type="button"
|
|
20269
|
+
class="jv-date-picker-day"
|
|
20270
|
+
[class.jv-date-picker-day--outside]="!cell.currentMonth"
|
|
20271
|
+
[class.jv-date-picker-day--today]="cell.isToday"
|
|
20272
|
+
[class.jv-date-picker-day--selected]="isSelected(cell.date)"
|
|
20273
|
+
[attr.data-jv-date]="isoDate(cell.date)"
|
|
20274
|
+
[attr.tabindex]="isFocusedDate(cell.date) ? 0 : -1"
|
|
20275
|
+
[attr.aria-selected]="isSelected(cell.date) ? 'true' : 'false'"
|
|
20276
|
+
(click)="selectDate(cell.date)"
|
|
20277
|
+
(keydown)="handleDayKeydown($event, cell.date)"
|
|
20278
|
+
>
|
|
20279
|
+
{{ cell.date.getDate() }}
|
|
20280
|
+
</button>
|
|
20281
|
+
}
|
|
20282
|
+
</div>
|
|
20283
|
+
</div>
|
|
20284
|
+
|
|
20285
|
+
<div dialog-actions class="jv-date-picker-actions">
|
|
20286
|
+
@if (currentValue()) {
|
|
20287
|
+
<jv-button variant="ghost" (click)="clearSelection()">{{ translation.translate('datePicker.clear') }}</jv-button>
|
|
20288
|
+
}
|
|
20289
|
+
<jv-button variant="outline" (click)="closeDialog()">{{ translation.translate('datePicker.close') }}</jv-button>
|
|
20290
|
+
</div>
|
|
20291
|
+
</jv-dialog>
|
|
20128
20292
|
`, 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
20293
|
}], 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
20294
|
function daysInMonth(year, month) {
|
|
@@ -20149,6 +20313,297 @@ function capitalize(value) {
|
|
|
20149
20313
|
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
20150
20314
|
}
|
|
20151
20315
|
|
|
20316
|
+
let fileInputIdSequence = 0;
|
|
20317
|
+
class JvFileInputComponent {
|
|
20318
|
+
translation = inject(JvTranslationService);
|
|
20319
|
+
instanceId = ++fileInputIdSequence;
|
|
20320
|
+
nativeInputRef = viewChild('nativeInput', ...(ngDevMode ? [{ debugName: "nativeInputRef" }] : /* istanbul ignore next */ []));
|
|
20321
|
+
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
20322
|
+
hint = input('', ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
|
|
20323
|
+
error = input('', ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
20324
|
+
describedBy = input('', ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
|
|
20325
|
+
inputId = input(`jv-file-input-${this.instanceId}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
|
|
20326
|
+
accept = input('', ...(ngDevMode ? [{ debugName: "accept" }] : /* istanbul ignore next */ []));
|
|
20327
|
+
multiple = input(true, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
|
|
20328
|
+
maxFiles = input(10, ...(ngDevMode ? [{ debugName: "maxFiles" }] : /* istanbul ignore next */ []));
|
|
20329
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
20330
|
+
required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
20331
|
+
invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
|
|
20332
|
+
filesInput = input(undefined, { ...(ngDevMode ? { debugName: "filesInput" } : /* istanbul ignore next */ {}), alias: 'files' });
|
|
20333
|
+
filesChange = output();
|
|
20334
|
+
filesRejected = output();
|
|
20335
|
+
dragActive = signal(false, ...(ngDevMode ? [{ debugName: "dragActive" }] : /* istanbul ignore next */ []));
|
|
20336
|
+
rejectionMessage = signal('', ...(ngDevMode ? [{ debugName: "rejectionMessage" }] : /* istanbul ignore next */ []));
|
|
20337
|
+
internalFiles = signal([], ...(ngDevMode ? [{ debugName: "internalFiles" }] : /* istanbul ignore next */ []));
|
|
20338
|
+
currentFiles = computed(() => {
|
|
20339
|
+
const externalFiles = this.filesInput();
|
|
20340
|
+
return externalFiles !== undefined ? [...(externalFiles ?? [])] : this.internalFiles();
|
|
20341
|
+
}, ...(ngDevMode ? [{ debugName: "currentFiles" }] : /* istanbul ignore next */ []));
|
|
20342
|
+
selectionSummary = computed(() => this.translation.translate('fileInput.selectionSummary', { count: this.currentFiles().length, max: this.maxFiles() }), ...(ngDevMode ? [{ debugName: "selectionSummary" }] : /* istanbul ignore next */ []));
|
|
20343
|
+
dropzoneAriaLabel = computed(() => `${this.label() || this.translation.translate('fileInput.dropLabel')}. ${this.selectionSummary()}`, ...(ngDevMode ? [{ debugName: "dropzoneAriaLabel" }] : /* istanbul ignore next */ []));
|
|
20344
|
+
openFileDialog() {
|
|
20345
|
+
if (this.disabled())
|
|
20346
|
+
return;
|
|
20347
|
+
this.nativeInputRef()?.nativeElement.click();
|
|
20348
|
+
}
|
|
20349
|
+
handleDropzoneKeydown(event) {
|
|
20350
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
20351
|
+
event.preventDefault();
|
|
20352
|
+
this.openFileDialog();
|
|
20353
|
+
}
|
|
20354
|
+
}
|
|
20355
|
+
onNativeInputChange(fileList) {
|
|
20356
|
+
this.consumeFiles(fileList ? Array.from(fileList) : []);
|
|
20357
|
+
const input = this.nativeInputRef()?.nativeElement;
|
|
20358
|
+
if (input) {
|
|
20359
|
+
input.value = '';
|
|
20360
|
+
}
|
|
20361
|
+
}
|
|
20362
|
+
onDragEnter(event) {
|
|
20363
|
+
if (this.disabled())
|
|
20364
|
+
return;
|
|
20365
|
+
event.preventDefault();
|
|
20366
|
+
this.dragActive.set(true);
|
|
20367
|
+
}
|
|
20368
|
+
onDragOver(event) {
|
|
20369
|
+
if (this.disabled())
|
|
20370
|
+
return;
|
|
20371
|
+
event.preventDefault();
|
|
20372
|
+
this.dragActive.set(true);
|
|
20373
|
+
}
|
|
20374
|
+
onDragLeave(event) {
|
|
20375
|
+
if (event.currentTarget?.contains(event.relatedTarget)) {
|
|
20376
|
+
return;
|
|
20377
|
+
}
|
|
20378
|
+
this.dragActive.set(false);
|
|
20379
|
+
}
|
|
20380
|
+
onDrop(event) {
|
|
20381
|
+
if (this.disabled())
|
|
20382
|
+
return;
|
|
20383
|
+
event.preventDefault();
|
|
20384
|
+
this.dragActive.set(false);
|
|
20385
|
+
this.consumeFiles(Array.from(event.dataTransfer?.files ?? []));
|
|
20386
|
+
}
|
|
20387
|
+
removeFile(index) {
|
|
20388
|
+
if (this.disabled())
|
|
20389
|
+
return;
|
|
20390
|
+
const nextFiles = [...this.currentFiles()];
|
|
20391
|
+
nextFiles.splice(index, 1);
|
|
20392
|
+
this.updateFiles(nextFiles);
|
|
20393
|
+
}
|
|
20394
|
+
trackFile(index, file) {
|
|
20395
|
+
return `${file.name}-${file.size}-${file.lastModified}-${index}`;
|
|
20396
|
+
}
|
|
20397
|
+
formatBytes(size) {
|
|
20398
|
+
if (size < 1024)
|
|
20399
|
+
return `${size} B`;
|
|
20400
|
+
if (size < 1024 * 1024)
|
|
20401
|
+
return `${(size / 1024).toFixed(1)} KB`;
|
|
20402
|
+
return `${(size / (1024 * 1024)).toFixed(1)} MB`;
|
|
20403
|
+
}
|
|
20404
|
+
consumeFiles(files) {
|
|
20405
|
+
if (files.length === 0)
|
|
20406
|
+
return;
|
|
20407
|
+
const accepted = [];
|
|
20408
|
+
const rejectedByAccept = [];
|
|
20409
|
+
const currentFiles = this.currentFiles();
|
|
20410
|
+
const remainingSlots = this.multiple() ? Math.max(this.maxFiles() - currentFiles.length, 0) : 1;
|
|
20411
|
+
for (const file of files) {
|
|
20412
|
+
if (!this.matchesAccept(file)) {
|
|
20413
|
+
rejectedByAccept.push(file);
|
|
20414
|
+
continue;
|
|
20415
|
+
}
|
|
20416
|
+
accepted.push(file);
|
|
20417
|
+
}
|
|
20418
|
+
const nextAccepted = this.multiple() ? accepted.slice(0, remainingSlots) : accepted.slice(0, 1);
|
|
20419
|
+
const rejectedByCount = this.multiple() ? accepted.slice(remainingSlots) : accepted.slice(1);
|
|
20420
|
+
const nextFiles = this.multiple() ? [...currentFiles, ...nextAccepted] : nextAccepted;
|
|
20421
|
+
this.rejectionMessage.set('');
|
|
20422
|
+
if (rejectedByAccept.length > 0) {
|
|
20423
|
+
this.rejectionMessage.set(this.translation.translate('fileInput.invalidFiles', { count: rejectedByAccept.length }));
|
|
20424
|
+
this.filesRejected.emit({ files: rejectedByAccept, reason: 'accept' });
|
|
20425
|
+
}
|
|
20426
|
+
if (rejectedByCount.length > 0) {
|
|
20427
|
+
this.rejectionMessage.set(this.translation.translate('fileInput.tooManyFiles', { max: this.maxFiles() }));
|
|
20428
|
+
this.filesRejected.emit({ files: rejectedByCount, reason: 'maxFiles' });
|
|
20429
|
+
}
|
|
20430
|
+
this.updateFiles(nextFiles);
|
|
20431
|
+
}
|
|
20432
|
+
updateFiles(files) {
|
|
20433
|
+
if (this.filesInput() === undefined) {
|
|
20434
|
+
this.internalFiles.set(files);
|
|
20435
|
+
}
|
|
20436
|
+
this.filesChange.emit(files);
|
|
20437
|
+
}
|
|
20438
|
+
matchesAccept(file) {
|
|
20439
|
+
const accept = this.accept().trim();
|
|
20440
|
+
if (!accept)
|
|
20441
|
+
return true;
|
|
20442
|
+
const type = file.type.toLowerCase();
|
|
20443
|
+
const name = file.name.toLowerCase();
|
|
20444
|
+
return accept
|
|
20445
|
+
.split(',')
|
|
20446
|
+
.map((entry) => entry.trim().toLowerCase())
|
|
20447
|
+
.some((rule) => {
|
|
20448
|
+
if (!rule)
|
|
20449
|
+
return false;
|
|
20450
|
+
if (rule.startsWith('.'))
|
|
20451
|
+
return name.endsWith(rule);
|
|
20452
|
+
if (rule.endsWith('/*'))
|
|
20453
|
+
return type.startsWith(`${rule.slice(0, -1)}`);
|
|
20454
|
+
return type === rule;
|
|
20455
|
+
});
|
|
20456
|
+
}
|
|
20457
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFileInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
20458
|
+
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: `
|
|
20459
|
+
<jv-form-container
|
|
20460
|
+
[label]="label()"
|
|
20461
|
+
[inputId]="inputId()"
|
|
20462
|
+
[required]="required()"
|
|
20463
|
+
[invalid]="invalid()"
|
|
20464
|
+
[hint]="hint()"
|
|
20465
|
+
[error]="error()"
|
|
20466
|
+
>
|
|
20467
|
+
<input
|
|
20468
|
+
#nativeInput
|
|
20469
|
+
class="jv-file-input-native"
|
|
20470
|
+
type="file"
|
|
20471
|
+
[id]="inputId()"
|
|
20472
|
+
[attr.accept]="accept() || null"
|
|
20473
|
+
[attr.multiple]="multiple() ? '' : null"
|
|
20474
|
+
[disabled]="disabled()"
|
|
20475
|
+
[attr.aria-describedby]="describedBy() || null"
|
|
20476
|
+
(change)="onNativeInputChange($any($event.target).files)"
|
|
20477
|
+
/>
|
|
20478
|
+
|
|
20479
|
+
<div
|
|
20480
|
+
class="jv-file-input-dropzone"
|
|
20481
|
+
[class.jv-file-input-dropzone--disabled]="disabled()"
|
|
20482
|
+
[class.jv-file-input-dropzone--dragover]="dragActive()"
|
|
20483
|
+
[class.jv-file-input-dropzone--invalid]="invalid()"
|
|
20484
|
+
role="button"
|
|
20485
|
+
tabindex="0"
|
|
20486
|
+
[attr.aria-disabled]="disabled() ? 'true' : 'false'"
|
|
20487
|
+
[attr.aria-label]="dropzoneAriaLabel()"
|
|
20488
|
+
(click)="openFileDialog()"
|
|
20489
|
+
(keydown)="handleDropzoneKeydown($event)"
|
|
20490
|
+
(dragenter)="onDragEnter($event)"
|
|
20491
|
+
(dragover)="onDragOver($event)"
|
|
20492
|
+
(dragleave)="onDragLeave($event)"
|
|
20493
|
+
(drop)="onDrop($event)"
|
|
20494
|
+
>
|
|
20495
|
+
<jv-icon name="upload-cloud" [size]="24" />
|
|
20496
|
+
<div class="jv-file-input-copy">
|
|
20497
|
+
<strong>{{ translation.translate('fileInput.dropLabel') }}</strong>
|
|
20498
|
+
<span>{{ translation.translate('fileInput.helperText') }}</span>
|
|
20499
|
+
<span class="jv-file-input-meta">{{ selectionSummary() }}</span>
|
|
20500
|
+
</div>
|
|
20501
|
+
</div>
|
|
20502
|
+
|
|
20503
|
+
@if (rejectionMessage()) {
|
|
20504
|
+
<p class="jv-file-input-rejection" aria-live="polite">{{ rejectionMessage() }}</p>
|
|
20505
|
+
}
|
|
20506
|
+
|
|
20507
|
+
@if (currentFiles().length > 0) {
|
|
20508
|
+
<ul class="jv-file-input-list">
|
|
20509
|
+
@for (file of currentFiles(); track trackFile($index, file); let index = $index) {
|
|
20510
|
+
<li class="jv-file-input-item">
|
|
20511
|
+
<div class="jv-file-input-item-copy">
|
|
20512
|
+
<span class="jv-file-input-item-name">{{ file.name }}</span>
|
|
20513
|
+
<span class="jv-file-input-item-meta">{{ formatBytes(file.size) }}</span>
|
|
20514
|
+
</div>
|
|
20515
|
+
<button
|
|
20516
|
+
type="button"
|
|
20517
|
+
class="jv-file-input-remove"
|
|
20518
|
+
[disabled]="disabled()"
|
|
20519
|
+
[attr.aria-label]="translation.translate('fileInput.removeFile', { name: file.name })"
|
|
20520
|
+
(click)="removeFile(index)"
|
|
20521
|
+
>
|
|
20522
|
+
<jv-icon name="x" [size]="16" />
|
|
20523
|
+
</button>
|
|
20524
|
+
</li>
|
|
20525
|
+
}
|
|
20526
|
+
</ul>
|
|
20527
|
+
}
|
|
20528
|
+
</jv-form-container>
|
|
20529
|
+
`, 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"] }] });
|
|
20530
|
+
}
|
|
20531
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFileInputComponent, decorators: [{
|
|
20532
|
+
type: Component,
|
|
20533
|
+
args: [{ selector: 'jv-file-input', standalone: true, imports: [JvFormContainerComponent, JvIconComponent], template: `
|
|
20534
|
+
<jv-form-container
|
|
20535
|
+
[label]="label()"
|
|
20536
|
+
[inputId]="inputId()"
|
|
20537
|
+
[required]="required()"
|
|
20538
|
+
[invalid]="invalid()"
|
|
20539
|
+
[hint]="hint()"
|
|
20540
|
+
[error]="error()"
|
|
20541
|
+
>
|
|
20542
|
+
<input
|
|
20543
|
+
#nativeInput
|
|
20544
|
+
class="jv-file-input-native"
|
|
20545
|
+
type="file"
|
|
20546
|
+
[id]="inputId()"
|
|
20547
|
+
[attr.accept]="accept() || null"
|
|
20548
|
+
[attr.multiple]="multiple() ? '' : null"
|
|
20549
|
+
[disabled]="disabled()"
|
|
20550
|
+
[attr.aria-describedby]="describedBy() || null"
|
|
20551
|
+
(change)="onNativeInputChange($any($event.target).files)"
|
|
20552
|
+
/>
|
|
20553
|
+
|
|
20554
|
+
<div
|
|
20555
|
+
class="jv-file-input-dropzone"
|
|
20556
|
+
[class.jv-file-input-dropzone--disabled]="disabled()"
|
|
20557
|
+
[class.jv-file-input-dropzone--dragover]="dragActive()"
|
|
20558
|
+
[class.jv-file-input-dropzone--invalid]="invalid()"
|
|
20559
|
+
role="button"
|
|
20560
|
+
tabindex="0"
|
|
20561
|
+
[attr.aria-disabled]="disabled() ? 'true' : 'false'"
|
|
20562
|
+
[attr.aria-label]="dropzoneAriaLabel()"
|
|
20563
|
+
(click)="openFileDialog()"
|
|
20564
|
+
(keydown)="handleDropzoneKeydown($event)"
|
|
20565
|
+
(dragenter)="onDragEnter($event)"
|
|
20566
|
+
(dragover)="onDragOver($event)"
|
|
20567
|
+
(dragleave)="onDragLeave($event)"
|
|
20568
|
+
(drop)="onDrop($event)"
|
|
20569
|
+
>
|
|
20570
|
+
<jv-icon name="upload-cloud" [size]="24" />
|
|
20571
|
+
<div class="jv-file-input-copy">
|
|
20572
|
+
<strong>{{ translation.translate('fileInput.dropLabel') }}</strong>
|
|
20573
|
+
<span>{{ translation.translate('fileInput.helperText') }}</span>
|
|
20574
|
+
<span class="jv-file-input-meta">{{ selectionSummary() }}</span>
|
|
20575
|
+
</div>
|
|
20576
|
+
</div>
|
|
20577
|
+
|
|
20578
|
+
@if (rejectionMessage()) {
|
|
20579
|
+
<p class="jv-file-input-rejection" aria-live="polite">{{ rejectionMessage() }}</p>
|
|
20580
|
+
}
|
|
20581
|
+
|
|
20582
|
+
@if (currentFiles().length > 0) {
|
|
20583
|
+
<ul class="jv-file-input-list">
|
|
20584
|
+
@for (file of currentFiles(); track trackFile($index, file); let index = $index) {
|
|
20585
|
+
<li class="jv-file-input-item">
|
|
20586
|
+
<div class="jv-file-input-item-copy">
|
|
20587
|
+
<span class="jv-file-input-item-name">{{ file.name }}</span>
|
|
20588
|
+
<span class="jv-file-input-item-meta">{{ formatBytes(file.size) }}</span>
|
|
20589
|
+
</div>
|
|
20590
|
+
<button
|
|
20591
|
+
type="button"
|
|
20592
|
+
class="jv-file-input-remove"
|
|
20593
|
+
[disabled]="disabled()"
|
|
20594
|
+
[attr.aria-label]="translation.translate('fileInput.removeFile', { name: file.name })"
|
|
20595
|
+
(click)="removeFile(index)"
|
|
20596
|
+
>
|
|
20597
|
+
<jv-icon name="x" [size]="16" />
|
|
20598
|
+
</button>
|
|
20599
|
+
</li>
|
|
20600
|
+
}
|
|
20601
|
+
</ul>
|
|
20602
|
+
}
|
|
20603
|
+
</jv-form-container>
|
|
20604
|
+
`, 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"] }]
|
|
20605
|
+
}], 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"] }] } });
|
|
20606
|
+
|
|
20152
20607
|
class JvListComponent {
|
|
20153
20608
|
role = input('list', ...(ngDevMode ? [{ debugName: "role" }] : /* istanbul ignore next */ []));
|
|
20154
20609
|
ariaRole = input(null, ...(ngDevMode ? [{ debugName: "ariaRole" }] : /* istanbul ignore next */ []));
|
|
@@ -20800,6 +21255,535 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
20800
21255
|
`, styles: [".jv-textarea{width:100%;min-height:var(--jv-density-control-height);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);color:var(--jv-color-foreground);resize:vertical;font-family:inherit;font-size:inherit;line-height:inherit;box-sizing:border-box}.jv-textarea::placeholder{color:var(--jv-color-foreground-muted)}.jv-textarea.is-invalid{border-color:var(--jv-color-danger)}.jv-textarea:disabled{opacity:.7;cursor:not-allowed}.jv-textarea:read-only{background:var(--jv-color-surface-muted);cursor:default}\n"] }]
|
|
20801
21256
|
}], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], describedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "describedBy", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], cols: [{ type: i0.Input, args: [{ isSignal: true, alias: "cols", required: false }] }], maxlength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxlength", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }] } });
|
|
20802
21257
|
|
|
21258
|
+
class JvImageGalleryComponent {
|
|
21259
|
+
translation = inject(JvTranslationService);
|
|
21260
|
+
images = input([], ...(ngDevMode ? [{ debugName: "images" }] : /* istanbul ignore next */ []));
|
|
21261
|
+
stripHeightVh = input(25, { ...(ngDevMode ? { debugName: "stripHeightVh" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
21262
|
+
actions = input([], ...(ngDevMode ? [{ debugName: "actions" }] : /* istanbul ignore next */ []));
|
|
21263
|
+
imageClick = output();
|
|
21264
|
+
actionClick = output();
|
|
21265
|
+
strip = viewChild('strip', ...(ngDevMode ? [{ debugName: "strip" }] : /* istanbul ignore next */ []));
|
|
21266
|
+
dialogOpen = signal(false, ...(ngDevMode ? [{ debugName: "dialogOpen" }] : /* istanbul ignore next */ []));
|
|
21267
|
+
currentIndex = signal(0, ...(ngDevMode ? [{ debugName: "currentIndex" }] : /* istanbul ignore next */ []));
|
|
21268
|
+
slideDirection = signal(null, ...(ngDevMode ? [{ debugName: "slideDirection" }] : /* istanbul ignore next */ []));
|
|
21269
|
+
hasMultiple = computed(() => this.images().length > 1, ...(ngDevMode ? [{ debugName: "hasMultiple" }] : /* istanbul ignore next */ []));
|
|
21270
|
+
stripHeightStyle = computed(() => `${this.clampStripHeight(this.stripHeightVh())}vh`, ...(ngDevMode ? [{ debugName: "stripHeightStyle" }] : /* istanbul ignore next */ []));
|
|
21271
|
+
currentImage = computed(() => this.images()[this.currentIndex()] ?? null, ...(ngDevMode ? [{ debugName: "currentImage" }] : /* istanbul ignore next */ []));
|
|
21272
|
+
dialogTitle = computed(() => {
|
|
21273
|
+
const image = this.currentImage();
|
|
21274
|
+
if (!image)
|
|
21275
|
+
return '';
|
|
21276
|
+
const counter = this.hasMultiple() ? ` (${this.currentIndex() + 1}/${this.images().length})` : '';
|
|
21277
|
+
return `${image.alt}${counter}`;
|
|
21278
|
+
}, ...(ngDevMode ? [{ debugName: "dialogTitle" }] : /* istanbul ignore next */ []));
|
|
21279
|
+
translatedLabels = computed(() => ({
|
|
21280
|
+
close: this.translation.translate('gallery.close'),
|
|
21281
|
+
prev: this.translation.translate('gallery.prevImage'),
|
|
21282
|
+
next: this.translation.translate('gallery.nextImage'),
|
|
21283
|
+
}), ...(ngDevMode ? [{ debugName: "translatedLabels" }] : /* istanbul ignore next */ []));
|
|
21284
|
+
handleKeydown(event) {
|
|
21285
|
+
if (!this.dialogOpen())
|
|
21286
|
+
return;
|
|
21287
|
+
switch (event.key) {
|
|
21288
|
+
case 'ArrowLeft':
|
|
21289
|
+
event.preventDefault();
|
|
21290
|
+
this.previous();
|
|
21291
|
+
break;
|
|
21292
|
+
case 'ArrowRight':
|
|
21293
|
+
event.preventDefault();
|
|
21294
|
+
this.next();
|
|
21295
|
+
break;
|
|
21296
|
+
}
|
|
21297
|
+
}
|
|
21298
|
+
onWheel(event) {
|
|
21299
|
+
const el = this.strip()?.nativeElement;
|
|
21300
|
+
if (!el)
|
|
21301
|
+
return;
|
|
21302
|
+
if (Math.abs(event.deltaY) > Math.abs(event.deltaX)) {
|
|
21303
|
+
const delta = event.deltaMode === WheelEvent.DOM_DELTA_LINE
|
|
21304
|
+
? event.deltaY * 32
|
|
21305
|
+
: event.deltaMode === WheelEvent.DOM_DELTA_PAGE
|
|
21306
|
+
? event.deltaY * el.clientWidth
|
|
21307
|
+
: event.deltaY;
|
|
21308
|
+
const firstThumb = el.querySelector('.jv-gallery-thumb');
|
|
21309
|
+
const gap = Number.parseFloat(getComputedStyle(el).columnGap || getComputedStyle(el).gap || '0') || 0;
|
|
21310
|
+
const step = firstThumb ? firstThumb.getBoundingClientRect().width + gap : 0;
|
|
21311
|
+
const offset = Math.sign(delta) * Math.max(Math.abs(delta), step);
|
|
21312
|
+
event.preventDefault();
|
|
21313
|
+
el.scrollLeft += offset;
|
|
21314
|
+
}
|
|
21315
|
+
}
|
|
21316
|
+
openDialog(index) {
|
|
21317
|
+
this.currentIndex.set(index);
|
|
21318
|
+
this.slideDirection.set(null);
|
|
21319
|
+
this.dialogOpen.set(true);
|
|
21320
|
+
this.imageClick.emit(this.images()[index]);
|
|
21321
|
+
}
|
|
21322
|
+
closeDialog() {
|
|
21323
|
+
this.dialogOpen.set(false);
|
|
21324
|
+
this.slideDirection.set(null);
|
|
21325
|
+
}
|
|
21326
|
+
previous() {
|
|
21327
|
+
if (!this.hasMultiple())
|
|
21328
|
+
return;
|
|
21329
|
+
const newIndex = this.currentIndex() === 0
|
|
21330
|
+
? this.images().length - 1
|
|
21331
|
+
: this.currentIndex() - 1;
|
|
21332
|
+
this.showImage(newIndex, 'right');
|
|
21333
|
+
}
|
|
21334
|
+
next() {
|
|
21335
|
+
if (!this.hasMultiple())
|
|
21336
|
+
return;
|
|
21337
|
+
const newIndex = this.currentIndex() === this.images().length - 1
|
|
21338
|
+
? 0
|
|
21339
|
+
: this.currentIndex() + 1;
|
|
21340
|
+
this.showImage(newIndex, 'left');
|
|
21341
|
+
}
|
|
21342
|
+
onAction(action) {
|
|
21343
|
+
const image = this.currentImage();
|
|
21344
|
+
if (image) {
|
|
21345
|
+
this.actionClick.emit({ actionId: action.id, image });
|
|
21346
|
+
}
|
|
21347
|
+
}
|
|
21348
|
+
clampStripHeight(value) {
|
|
21349
|
+
if (!Number.isFinite(value)) {
|
|
21350
|
+
return 25;
|
|
21351
|
+
}
|
|
21352
|
+
return Math.min(100, Math.max(0, value));
|
|
21353
|
+
}
|
|
21354
|
+
showImage(index, direction) {
|
|
21355
|
+
this.slideDirection.set(null);
|
|
21356
|
+
this.currentIndex.set(index);
|
|
21357
|
+
if (typeof requestAnimationFrame === 'function') {
|
|
21358
|
+
requestAnimationFrame(() => this.slideDirection.set(direction));
|
|
21359
|
+
return;
|
|
21360
|
+
}
|
|
21361
|
+
this.slideDirection.set(direction);
|
|
21362
|
+
}
|
|
21363
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvImageGalleryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
21364
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvImageGalleryComponent, isStandalone: true, selector: "jv-image-gallery", inputs: { images: { classPropertyName: "images", publicName: "images", isSignal: true, isRequired: false, transformFunction: null }, stripHeightVh: { classPropertyName: "stripHeightVh", publicName: "stripHeightVh", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { imageClick: "imageClick", actionClick: "actionClick" }, host: { listeners: { "document:keydown": "handleKeydown($event)" } }, viewQueries: [{ propertyName: "strip", first: true, predicate: ["strip"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
21365
|
+
<div class="jv-gallery">
|
|
21366
|
+
<div class="jv-gallery-strip" #strip [style.height]="stripHeightStyle()" (wheel)="onWheel($event)">
|
|
21367
|
+
@for (image of images(); track image.src; let i = $index) {
|
|
21368
|
+
<button
|
|
21369
|
+
type="button"
|
|
21370
|
+
class="jv-gallery-thumb"
|
|
21371
|
+
[class.jv-gallery-thumb--active]="dialogOpen() && currentIndex() === i"
|
|
21372
|
+
[attr.aria-label]="image.alt"
|
|
21373
|
+
(wheel)="onWheel($event)"
|
|
21374
|
+
(click)="openDialog(i)"
|
|
21375
|
+
>
|
|
21376
|
+
<img
|
|
21377
|
+
class="jv-gallery-thumb-image"
|
|
21378
|
+
[src]="image.thumbnail || image.src"
|
|
21379
|
+
[alt]="image.alt"
|
|
21380
|
+
loading="lazy"
|
|
21381
|
+
/>
|
|
21382
|
+
</button>
|
|
21383
|
+
}
|
|
21384
|
+
</div>
|
|
21385
|
+
|
|
21386
|
+
<jv-dialog
|
|
21387
|
+
[open]="dialogOpen()"
|
|
21388
|
+
[title]="dialogTitle()"
|
|
21389
|
+
(closed)="closeDialog()"
|
|
21390
|
+
>
|
|
21391
|
+
<div class="jv-gallery-viewer" tabindex="0">
|
|
21392
|
+
@if (currentImage(); as image) {
|
|
21393
|
+
<img
|
|
21394
|
+
class="jv-gallery-viewer-image"
|
|
21395
|
+
[class.jv-gallery-viewer-image--slide-left]="slideDirection() === 'left'"
|
|
21396
|
+
[class.jv-gallery-viewer-image--slide-right]="slideDirection() === 'right'"
|
|
21397
|
+
[src]="image.src"
|
|
21398
|
+
[alt]="image.alt"
|
|
21399
|
+
/>
|
|
21400
|
+
}
|
|
21401
|
+
|
|
21402
|
+
@if (hasMultiple()) {
|
|
21403
|
+
<button
|
|
21404
|
+
type="button"
|
|
21405
|
+
class="jv-gallery-viewer-nav jv-gallery-viewer-nav--prev"
|
|
21406
|
+
[attr.aria-label]="translatedLabels().prev"
|
|
21407
|
+
(click)="previous(); $event.stopPropagation()"
|
|
21408
|
+
>
|
|
21409
|
+
<jv-icon name="chevron-left" [size]="24" />
|
|
21410
|
+
</button>
|
|
21411
|
+
|
|
21412
|
+
<button
|
|
21413
|
+
type="button"
|
|
21414
|
+
class="jv-gallery-viewer-nav jv-gallery-viewer-nav--next"
|
|
21415
|
+
[attr.aria-label]="translatedLabels().next"
|
|
21416
|
+
(click)="next(); $event.stopPropagation()"
|
|
21417
|
+
>
|
|
21418
|
+
<jv-icon name="chevron-right" [size]="24" />
|
|
21419
|
+
</button>
|
|
21420
|
+
|
|
21421
|
+
<span class="jv-gallery-viewer-counter">
|
|
21422
|
+
{{ currentIndex() + 1 }} / {{ images().length }}
|
|
21423
|
+
</span>
|
|
21424
|
+
}
|
|
21425
|
+
</div>
|
|
21426
|
+
|
|
21427
|
+
<div dialog-actions>
|
|
21428
|
+
@for (action of actions(); track action.id) {
|
|
21429
|
+
<jv-button
|
|
21430
|
+
[variant]="action.tone ?? 'outline'"
|
|
21431
|
+
(click)="onAction(action)"
|
|
21432
|
+
>
|
|
21433
|
+
@if (action.icon) {
|
|
21434
|
+
<jv-icon [name]="action.icon" [size]="16" />
|
|
21435
|
+
}
|
|
21436
|
+
{{ action.label }}
|
|
21437
|
+
</jv-button>
|
|
21438
|
+
}
|
|
21439
|
+
<jv-button variant="ghost" (click)="closeDialog()">
|
|
21440
|
+
{{ translatedLabels().close }}
|
|
21441
|
+
</jv-button>
|
|
21442
|
+
</div>
|
|
21443
|
+
</jv-dialog>
|
|
21444
|
+
</div>
|
|
21445
|
+
`, isInline: true, styles: [".jv-gallery{display:block;width:100%;max-width:100vw}.jv-gallery-strip{display:flex;gap:5px;width:100%;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scrollbar-width:none;-ms-overflow-style:none;scroll-snap-type:x proximity;scroll-behavior:smooth;-webkit-overflow-scrolling:touch}.jv-gallery-strip::-webkit-scrollbar{display:none}.jv-gallery-thumb{flex:0 0 auto;width:calc((100vw - 20px)/4);min-width:120px;height:100%;padding:0;border:2px solid transparent;border-radius:var(--jv-radius-sm);background:transparent;cursor:pointer;overflow:hidden;scroll-snap-align:start;transition:border-color .16s ease,opacity .16s ease}.jv-gallery-thumb:hover{opacity:.85}.jv-gallery-thumb--active{border-color:var(--jv-color-primary)}.jv-gallery-thumb:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-gallery-thumb-image{display:block;width:100%;height:100%;object-fit:cover;pointer-events:none}.jv-gallery-viewer{position:relative;display:flex;align-items:center;justify-content:center;width:100%;height:70vh;min-height:300px;background:#000;border-radius:var(--jv-radius-md);overflow:hidden}.jv-gallery-viewer:focus{outline:none}.jv-gallery-viewer-image{display:block;max-width:100%;max-height:100%;object-fit:contain;-webkit-user-select:none;user-select:none}@keyframes gallery-slide-left{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes gallery-slide-right{0%{transform:translate(-100%);opacity:0}to{transform:translate(0);opacity:1}}.jv-gallery-viewer-image--slide-left{animation:gallery-slide-left .28s ease-out}.jv-gallery-viewer-image--slide-right{animation:gallery-slide-right .28s ease-out}.jv-gallery-viewer-nav{position:absolute;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:3rem;height:3rem;border:none;border-radius:var(--jv-radius-md);background:#00000080;color:#fff;cursor:pointer;transition:background-color .16s ease;z-index:1}.jv-gallery-viewer-nav:hover{background:#000000bf}.jv-gallery-viewer-nav:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-gallery-viewer-nav--prev{left:var(--jv-spacing-md)}.jv-gallery-viewer-nav--next{right:var(--jv-spacing-md)}.jv-gallery-viewer-counter{position:absolute;bottom:var(--jv-spacing-md);left:50%;transform:translate(-50%);padding:var(--jv-spacing-xs) var(--jv-spacing-sm);border-radius:var(--jv-radius-sm);background:#0009;color:#fff;font-size:.8125rem;font-variant-numeric:tabular-nums;pointer-events:none}@media(max-width:768px){.jv-gallery-thumb{width:calc(100vw - 20px);min-width:200px}.jv-gallery-viewer-nav{width:2.5rem;height:2.5rem}.jv-gallery-viewer-nav--prev{left:var(--jv-spacing-sm)}.jv-gallery-viewer-nav--next{right:var(--jv-spacing-sm)}}@media(prefers-reduced-motion:reduce){.jv-gallery-strip{scroll-behavior:auto}.jv-gallery-viewer-image--slide-left,.jv-gallery-viewer-image--slide-right{animation:none}}\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: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }] });
|
|
21446
|
+
}
|
|
21447
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvImageGalleryComponent, decorators: [{
|
|
21448
|
+
type: Component,
|
|
21449
|
+
args: [{ selector: 'jv-image-gallery', standalone: true, imports: [JvButtonComponent, JvDialogComponent, JvIconComponent], template: `
|
|
21450
|
+
<div class="jv-gallery">
|
|
21451
|
+
<div class="jv-gallery-strip" #strip [style.height]="stripHeightStyle()" (wheel)="onWheel($event)">
|
|
21452
|
+
@for (image of images(); track image.src; let i = $index) {
|
|
21453
|
+
<button
|
|
21454
|
+
type="button"
|
|
21455
|
+
class="jv-gallery-thumb"
|
|
21456
|
+
[class.jv-gallery-thumb--active]="dialogOpen() && currentIndex() === i"
|
|
21457
|
+
[attr.aria-label]="image.alt"
|
|
21458
|
+
(wheel)="onWheel($event)"
|
|
21459
|
+
(click)="openDialog(i)"
|
|
21460
|
+
>
|
|
21461
|
+
<img
|
|
21462
|
+
class="jv-gallery-thumb-image"
|
|
21463
|
+
[src]="image.thumbnail || image.src"
|
|
21464
|
+
[alt]="image.alt"
|
|
21465
|
+
loading="lazy"
|
|
21466
|
+
/>
|
|
21467
|
+
</button>
|
|
21468
|
+
}
|
|
21469
|
+
</div>
|
|
21470
|
+
|
|
21471
|
+
<jv-dialog
|
|
21472
|
+
[open]="dialogOpen()"
|
|
21473
|
+
[title]="dialogTitle()"
|
|
21474
|
+
(closed)="closeDialog()"
|
|
21475
|
+
>
|
|
21476
|
+
<div class="jv-gallery-viewer" tabindex="0">
|
|
21477
|
+
@if (currentImage(); as image) {
|
|
21478
|
+
<img
|
|
21479
|
+
class="jv-gallery-viewer-image"
|
|
21480
|
+
[class.jv-gallery-viewer-image--slide-left]="slideDirection() === 'left'"
|
|
21481
|
+
[class.jv-gallery-viewer-image--slide-right]="slideDirection() === 'right'"
|
|
21482
|
+
[src]="image.src"
|
|
21483
|
+
[alt]="image.alt"
|
|
21484
|
+
/>
|
|
21485
|
+
}
|
|
21486
|
+
|
|
21487
|
+
@if (hasMultiple()) {
|
|
21488
|
+
<button
|
|
21489
|
+
type="button"
|
|
21490
|
+
class="jv-gallery-viewer-nav jv-gallery-viewer-nav--prev"
|
|
21491
|
+
[attr.aria-label]="translatedLabels().prev"
|
|
21492
|
+
(click)="previous(); $event.stopPropagation()"
|
|
21493
|
+
>
|
|
21494
|
+
<jv-icon name="chevron-left" [size]="24" />
|
|
21495
|
+
</button>
|
|
21496
|
+
|
|
21497
|
+
<button
|
|
21498
|
+
type="button"
|
|
21499
|
+
class="jv-gallery-viewer-nav jv-gallery-viewer-nav--next"
|
|
21500
|
+
[attr.aria-label]="translatedLabels().next"
|
|
21501
|
+
(click)="next(); $event.stopPropagation()"
|
|
21502
|
+
>
|
|
21503
|
+
<jv-icon name="chevron-right" [size]="24" />
|
|
21504
|
+
</button>
|
|
21505
|
+
|
|
21506
|
+
<span class="jv-gallery-viewer-counter">
|
|
21507
|
+
{{ currentIndex() + 1 }} / {{ images().length }}
|
|
21508
|
+
</span>
|
|
21509
|
+
}
|
|
21510
|
+
</div>
|
|
21511
|
+
|
|
21512
|
+
<div dialog-actions>
|
|
21513
|
+
@for (action of actions(); track action.id) {
|
|
21514
|
+
<jv-button
|
|
21515
|
+
[variant]="action.tone ?? 'outline'"
|
|
21516
|
+
(click)="onAction(action)"
|
|
21517
|
+
>
|
|
21518
|
+
@if (action.icon) {
|
|
21519
|
+
<jv-icon [name]="action.icon" [size]="16" />
|
|
21520
|
+
}
|
|
21521
|
+
{{ action.label }}
|
|
21522
|
+
</jv-button>
|
|
21523
|
+
}
|
|
21524
|
+
<jv-button variant="ghost" (click)="closeDialog()">
|
|
21525
|
+
{{ translatedLabels().close }}
|
|
21526
|
+
</jv-button>
|
|
21527
|
+
</div>
|
|
21528
|
+
</jv-dialog>
|
|
21529
|
+
</div>
|
|
21530
|
+
`, styles: [".jv-gallery{display:block;width:100%;max-width:100vw}.jv-gallery-strip{display:flex;gap:5px;width:100%;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scrollbar-width:none;-ms-overflow-style:none;scroll-snap-type:x proximity;scroll-behavior:smooth;-webkit-overflow-scrolling:touch}.jv-gallery-strip::-webkit-scrollbar{display:none}.jv-gallery-thumb{flex:0 0 auto;width:calc((100vw - 20px)/4);min-width:120px;height:100%;padding:0;border:2px solid transparent;border-radius:var(--jv-radius-sm);background:transparent;cursor:pointer;overflow:hidden;scroll-snap-align:start;transition:border-color .16s ease,opacity .16s ease}.jv-gallery-thumb:hover{opacity:.85}.jv-gallery-thumb--active{border-color:var(--jv-color-primary)}.jv-gallery-thumb:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-gallery-thumb-image{display:block;width:100%;height:100%;object-fit:cover;pointer-events:none}.jv-gallery-viewer{position:relative;display:flex;align-items:center;justify-content:center;width:100%;height:70vh;min-height:300px;background:#000;border-radius:var(--jv-radius-md);overflow:hidden}.jv-gallery-viewer:focus{outline:none}.jv-gallery-viewer-image{display:block;max-width:100%;max-height:100%;object-fit:contain;-webkit-user-select:none;user-select:none}@keyframes gallery-slide-left{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes gallery-slide-right{0%{transform:translate(-100%);opacity:0}to{transform:translate(0);opacity:1}}.jv-gallery-viewer-image--slide-left{animation:gallery-slide-left .28s ease-out}.jv-gallery-viewer-image--slide-right{animation:gallery-slide-right .28s ease-out}.jv-gallery-viewer-nav{position:absolute;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:3rem;height:3rem;border:none;border-radius:var(--jv-radius-md);background:#00000080;color:#fff;cursor:pointer;transition:background-color .16s ease;z-index:1}.jv-gallery-viewer-nav:hover{background:#000000bf}.jv-gallery-viewer-nav:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-gallery-viewer-nav--prev{left:var(--jv-spacing-md)}.jv-gallery-viewer-nav--next{right:var(--jv-spacing-md)}.jv-gallery-viewer-counter{position:absolute;bottom:var(--jv-spacing-md);left:50%;transform:translate(-50%);padding:var(--jv-spacing-xs) var(--jv-spacing-sm);border-radius:var(--jv-radius-sm);background:#0009;color:#fff;font-size:.8125rem;font-variant-numeric:tabular-nums;pointer-events:none}@media(max-width:768px){.jv-gallery-thumb{width:calc(100vw - 20px);min-width:200px}.jv-gallery-viewer-nav{width:2.5rem;height:2.5rem}.jv-gallery-viewer-nav--prev{left:var(--jv-spacing-sm)}.jv-gallery-viewer-nav--next{right:var(--jv-spacing-sm)}}@media(prefers-reduced-motion:reduce){.jv-gallery-strip{scroll-behavior:auto}.jv-gallery-viewer-image--slide-left,.jv-gallery-viewer-image--slide-right{animation:none}}\n"] }]
|
|
21531
|
+
}], propDecorators: { images: [{ type: i0.Input, args: [{ isSignal: true, alias: "images", required: false }] }], stripHeightVh: [{ type: i0.Input, args: [{ isSignal: true, alias: "stripHeightVh", required: false }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], imageClick: [{ type: i0.Output, args: ["imageClick"] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }], strip: [{ type: i0.ViewChild, args: ['strip', { isSignal: true }] }], handleKeydown: [{
|
|
21532
|
+
type: HostListener,
|
|
21533
|
+
args: ['document:keydown', ['$event']]
|
|
21534
|
+
}] } });
|
|
21535
|
+
|
|
21536
|
+
class JvImageSliderComponent {
|
|
21537
|
+
thumbnailStripRef = viewChild('thumbnailStrip', ...(ngDevMode ? [{ debugName: "thumbnailStripRef" }] : /* istanbul ignore next */ []));
|
|
21538
|
+
translation = inject(JvTranslationService);
|
|
21539
|
+
images = input([], ...(ngDevMode ? [{ debugName: "images" }] : /* istanbul ignore next */ []));
|
|
21540
|
+
showThumbnails = input(true, ...(ngDevMode ? [{ debugName: "showThumbnails" }] : /* istanbul ignore next */ []));
|
|
21541
|
+
showDescription = input(true, ...(ngDevMode ? [{ debugName: "showDescription" }] : /* istanbul ignore next */ []));
|
|
21542
|
+
imageChange = output();
|
|
21543
|
+
currentIndex = signal(0, ...(ngDevMode ? [{ debugName: "currentIndex" }] : /* istanbul ignore next */ []));
|
|
21544
|
+
hasMultiple = computed(() => this.images().length > 1, ...(ngDevMode ? [{ debugName: "hasMultiple" }] : /* istanbul ignore next */ []));
|
|
21545
|
+
currentImage = computed(() => this.images()[this.currentIndex()] ?? null, ...(ngDevMode ? [{ debugName: "currentImage" }] : /* istanbul ignore next */ []));
|
|
21546
|
+
translatedAriaLabels = computed(() => ({
|
|
21547
|
+
prev: this.translation.translate('slider.prevImage'),
|
|
21548
|
+
next: this.translation.translate('slider.nextImage'),
|
|
21549
|
+
thumbnailList: this.translation.translate('slider.thumbnailList'),
|
|
21550
|
+
}), ...(ngDevMode ? [{ debugName: "translatedAriaLabels" }] : /* istanbul ignore next */ []));
|
|
21551
|
+
constructor() {
|
|
21552
|
+
effect(() => {
|
|
21553
|
+
const images = this.images();
|
|
21554
|
+
if (images.length > 0 && this.currentIndex() >= images.length) {
|
|
21555
|
+
this.currentIndex.set(0);
|
|
21556
|
+
}
|
|
21557
|
+
});
|
|
21558
|
+
}
|
|
21559
|
+
handleKeydown(event) {
|
|
21560
|
+
if (!this.hasMultiple()) {
|
|
21561
|
+
return;
|
|
21562
|
+
}
|
|
21563
|
+
switch (event.key) {
|
|
21564
|
+
case 'ArrowLeft':
|
|
21565
|
+
event.preventDefault();
|
|
21566
|
+
this.previous();
|
|
21567
|
+
break;
|
|
21568
|
+
case 'ArrowRight':
|
|
21569
|
+
event.preventDefault();
|
|
21570
|
+
this.next();
|
|
21571
|
+
break;
|
|
21572
|
+
case 'Home':
|
|
21573
|
+
event.preventDefault();
|
|
21574
|
+
this.goTo(0);
|
|
21575
|
+
break;
|
|
21576
|
+
case 'End':
|
|
21577
|
+
event.preventDefault();
|
|
21578
|
+
this.goTo(this.images().length - 1);
|
|
21579
|
+
break;
|
|
21580
|
+
}
|
|
21581
|
+
}
|
|
21582
|
+
previous() {
|
|
21583
|
+
if (!this.hasMultiple()) {
|
|
21584
|
+
return;
|
|
21585
|
+
}
|
|
21586
|
+
const newIndex = this.currentIndex() === 0
|
|
21587
|
+
? this.images().length - 1
|
|
21588
|
+
: this.currentIndex() - 1;
|
|
21589
|
+
this.goTo(newIndex);
|
|
21590
|
+
}
|
|
21591
|
+
next() {
|
|
21592
|
+
if (!this.hasMultiple()) {
|
|
21593
|
+
return;
|
|
21594
|
+
}
|
|
21595
|
+
const newIndex = this.currentIndex() === this.images().length - 1
|
|
21596
|
+
? 0
|
|
21597
|
+
: this.currentIndex() + 1;
|
|
21598
|
+
this.goTo(newIndex);
|
|
21599
|
+
}
|
|
21600
|
+
goTo(index) {
|
|
21601
|
+
if (index === this.currentIndex() || index < 0 || index >= this.images().length) {
|
|
21602
|
+
return;
|
|
21603
|
+
}
|
|
21604
|
+
this.currentIndex.set(index);
|
|
21605
|
+
this.imageChange.emit(index);
|
|
21606
|
+
this.scrollThumbnailIntoView(index);
|
|
21607
|
+
}
|
|
21608
|
+
scrollThumbnailIntoView(index) {
|
|
21609
|
+
const strip = this.thumbnailStripRef()?.nativeElement;
|
|
21610
|
+
if (!strip) {
|
|
21611
|
+
return;
|
|
21612
|
+
}
|
|
21613
|
+
const thumbnails = strip.children;
|
|
21614
|
+
if (thumbnails[index]) {
|
|
21615
|
+
thumbnails[index].scrollIntoView({
|
|
21616
|
+
behavior: 'smooth',
|
|
21617
|
+
block: 'nearest',
|
|
21618
|
+
inline: 'center',
|
|
21619
|
+
});
|
|
21620
|
+
}
|
|
21621
|
+
}
|
|
21622
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvImageSliderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
21623
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvImageSliderComponent, isStandalone: true, selector: "jv-image-slider", inputs: { images: { classPropertyName: "images", publicName: "images", isSignal: true, isRequired: false, transformFunction: null }, showThumbnails: { classPropertyName: "showThumbnails", publicName: "showThumbnails", isSignal: true, isRequired: false, transformFunction: null }, showDescription: { classPropertyName: "showDescription", publicName: "showDescription", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { imageChange: "imageChange" }, host: { listeners: { "keydown": "handleKeydown($event)" } }, viewQueries: [{ propertyName: "thumbnailStripRef", first: true, predicate: ["thumbnailStrip"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
21624
|
+
<div class="jv-slider">
|
|
21625
|
+
<div class="jv-slider-main">
|
|
21626
|
+
@if (hasMultiple()) {
|
|
21627
|
+
<button
|
|
21628
|
+
type="button"
|
|
21629
|
+
class="jv-slider-nav jv-slider-nav--prev"
|
|
21630
|
+
[attr.aria-label]="translatedAriaLabels().prev"
|
|
21631
|
+
(click)="previous()"
|
|
21632
|
+
>
|
|
21633
|
+
<jv-icon name="chevron-left" [size]="20" />
|
|
21634
|
+
</button>
|
|
21635
|
+
}
|
|
21636
|
+
|
|
21637
|
+
<div class="jv-slider-stage">
|
|
21638
|
+
@for (image of images(); track image.src; let i = $index) {
|
|
21639
|
+
<div
|
|
21640
|
+
class="jv-slider-slide"
|
|
21641
|
+
[class.jv-slider-slide--active]="i === currentIndex()"
|
|
21642
|
+
>
|
|
21643
|
+
<img
|
|
21644
|
+
class="jv-slider-image"
|
|
21645
|
+
[src]="image.src"
|
|
21646
|
+
[alt]="image.alt"
|
|
21647
|
+
loading="lazy"
|
|
21648
|
+
/>
|
|
21649
|
+
</div>
|
|
21650
|
+
}
|
|
21651
|
+
</div>
|
|
21652
|
+
|
|
21653
|
+
@if (hasMultiple()) {
|
|
21654
|
+
<button
|
|
21655
|
+
type="button"
|
|
21656
|
+
class="jv-slider-nav jv-slider-nav--next"
|
|
21657
|
+
[attr.aria-label]="translatedAriaLabels().next"
|
|
21658
|
+
(click)="next()"
|
|
21659
|
+
>
|
|
21660
|
+
<jv-icon name="chevron-right" [size]="20" />
|
|
21661
|
+
</button>
|
|
21662
|
+
}
|
|
21663
|
+
</div>
|
|
21664
|
+
|
|
21665
|
+
@if (currentImage(); as image) {
|
|
21666
|
+
@if (showDescription() && image.description) {
|
|
21667
|
+
<div class="jv-slider-description">
|
|
21668
|
+
<p>{{ image.description }}</p>
|
|
21669
|
+
</div>
|
|
21670
|
+
}
|
|
21671
|
+
}
|
|
21672
|
+
|
|
21673
|
+
@if (hasMultiple() && showThumbnails()) {
|
|
21674
|
+
<div class="jv-slider-thumbnails" #thumbnailStrip role="tablist" [attr.aria-label]="translatedAriaLabels().thumbnailList">
|
|
21675
|
+
@for (image of images(); track image.src; let i = $index) {
|
|
21676
|
+
<button
|
|
21677
|
+
type="button"
|
|
21678
|
+
class="jv-slider-thumbnail"
|
|
21679
|
+
[class.jv-slider-thumbnail--active]="i === currentIndex()"
|
|
21680
|
+
role="tab"
|
|
21681
|
+
[attr.aria-selected]="i === currentIndex() ? 'true' : 'false'"
|
|
21682
|
+
[attr.aria-label]="image.alt"
|
|
21683
|
+
(click)="goTo(i)"
|
|
21684
|
+
>
|
|
21685
|
+
<img
|
|
21686
|
+
class="jv-slider-thumbnail-image"
|
|
21687
|
+
[src]="image.thumbnail || image.src"
|
|
21688
|
+
[alt]="image.alt"
|
|
21689
|
+
loading="lazy"
|
|
21690
|
+
/>
|
|
21691
|
+
</button>
|
|
21692
|
+
}
|
|
21693
|
+
</div>
|
|
21694
|
+
|
|
21695
|
+
<div class="jv-slider-counter">
|
|
21696
|
+
{{ currentIndex() + 1 }} / {{ images().length }}
|
|
21697
|
+
</div>
|
|
21698
|
+
}
|
|
21699
|
+
</div>
|
|
21700
|
+
`, isInline: true, styles: [".jv-slider{display:grid;gap:var(--jv-spacing-sm);width:100%;max-width:100%}.jv-slider-main{position:relative;display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:var(--jv-spacing-xs)}.jv-slider-stage{position:relative;aspect-ratio:16 / 9;overflow:hidden;border-radius:var(--jv-radius-md);background:var(--jv-color-surface-muted)}.jv-slider-slide{position:absolute;inset:0;opacity:0;transition:opacity .2s ease;pointer-events:none}.jv-slider-slide--active{opacity:1;pointer-events:auto}.jv-slider-image{display:block;width:100%;height:100%;object-fit:contain;-webkit-user-select:none;user-select:none}.jv-slider-nav{display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);cursor:pointer;transition:background-color .16s ease,border-color .16s ease,color .16s ease;flex-shrink:0;z-index:1}.jv-slider-nav:hover{background:var(--jv-color-surface-muted);border-color:var(--jv-color-foreground-muted)}.jv-slider-nav:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-slider-description{padding:var(--jv-spacing-sm) 0}.jv-slider-description p{margin:0;font-size:var(--jv-density-font-size);color:var(--jv-color-foreground-muted);line-height:1.5}.jv-slider-thumbnails{display:flex;gap:var(--jv-spacing-xs);overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;padding:var(--jv-spacing-xs) 0}.jv-slider-thumbnails::-webkit-scrollbar{display:none}.jv-slider-thumbnail{flex:0 0 auto;width:3.5rem;height:3.5rem;padding:0;border:2px solid transparent;border-radius:var(--jv-radius-sm);background:transparent;cursor:pointer;overflow:hidden;transition:border-color .16s ease,opacity .16s ease;opacity:.6}.jv-slider-thumbnail:hover{opacity:.85}.jv-slider-thumbnail--active{border-color:var(--jv-color-primary);opacity:1}.jv-slider-thumbnail:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-slider-thumbnail-image{display:block;width:100%;height:100%;object-fit:cover}.jv-slider-counter{text-align:center;font-size:.8125rem;color:var(--jv-color-foreground-muted);font-variant-numeric:tabular-nums}@media(max-width:640px){.jv-slider-nav{width:2rem;height:2rem}.jv-slider-thumbnail{width:2.75rem;height:2.75rem}}@media(prefers-reduced-motion:reduce){.jv-slider-slide{transition:none}}\n"], dependencies: [{ kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }] });
|
|
21701
|
+
}
|
|
21702
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvImageSliderComponent, decorators: [{
|
|
21703
|
+
type: Component,
|
|
21704
|
+
args: [{ selector: 'jv-image-slider', standalone: true, imports: [JvIconComponent], template: `
|
|
21705
|
+
<div class="jv-slider">
|
|
21706
|
+
<div class="jv-slider-main">
|
|
21707
|
+
@if (hasMultiple()) {
|
|
21708
|
+
<button
|
|
21709
|
+
type="button"
|
|
21710
|
+
class="jv-slider-nav jv-slider-nav--prev"
|
|
21711
|
+
[attr.aria-label]="translatedAriaLabels().prev"
|
|
21712
|
+
(click)="previous()"
|
|
21713
|
+
>
|
|
21714
|
+
<jv-icon name="chevron-left" [size]="20" />
|
|
21715
|
+
</button>
|
|
21716
|
+
}
|
|
21717
|
+
|
|
21718
|
+
<div class="jv-slider-stage">
|
|
21719
|
+
@for (image of images(); track image.src; let i = $index) {
|
|
21720
|
+
<div
|
|
21721
|
+
class="jv-slider-slide"
|
|
21722
|
+
[class.jv-slider-slide--active]="i === currentIndex()"
|
|
21723
|
+
>
|
|
21724
|
+
<img
|
|
21725
|
+
class="jv-slider-image"
|
|
21726
|
+
[src]="image.src"
|
|
21727
|
+
[alt]="image.alt"
|
|
21728
|
+
loading="lazy"
|
|
21729
|
+
/>
|
|
21730
|
+
</div>
|
|
21731
|
+
}
|
|
21732
|
+
</div>
|
|
21733
|
+
|
|
21734
|
+
@if (hasMultiple()) {
|
|
21735
|
+
<button
|
|
21736
|
+
type="button"
|
|
21737
|
+
class="jv-slider-nav jv-slider-nav--next"
|
|
21738
|
+
[attr.aria-label]="translatedAriaLabels().next"
|
|
21739
|
+
(click)="next()"
|
|
21740
|
+
>
|
|
21741
|
+
<jv-icon name="chevron-right" [size]="20" />
|
|
21742
|
+
</button>
|
|
21743
|
+
}
|
|
21744
|
+
</div>
|
|
21745
|
+
|
|
21746
|
+
@if (currentImage(); as image) {
|
|
21747
|
+
@if (showDescription() && image.description) {
|
|
21748
|
+
<div class="jv-slider-description">
|
|
21749
|
+
<p>{{ image.description }}</p>
|
|
21750
|
+
</div>
|
|
21751
|
+
}
|
|
21752
|
+
}
|
|
21753
|
+
|
|
21754
|
+
@if (hasMultiple() && showThumbnails()) {
|
|
21755
|
+
<div class="jv-slider-thumbnails" #thumbnailStrip role="tablist" [attr.aria-label]="translatedAriaLabels().thumbnailList">
|
|
21756
|
+
@for (image of images(); track image.src; let i = $index) {
|
|
21757
|
+
<button
|
|
21758
|
+
type="button"
|
|
21759
|
+
class="jv-slider-thumbnail"
|
|
21760
|
+
[class.jv-slider-thumbnail--active]="i === currentIndex()"
|
|
21761
|
+
role="tab"
|
|
21762
|
+
[attr.aria-selected]="i === currentIndex() ? 'true' : 'false'"
|
|
21763
|
+
[attr.aria-label]="image.alt"
|
|
21764
|
+
(click)="goTo(i)"
|
|
21765
|
+
>
|
|
21766
|
+
<img
|
|
21767
|
+
class="jv-slider-thumbnail-image"
|
|
21768
|
+
[src]="image.thumbnail || image.src"
|
|
21769
|
+
[alt]="image.alt"
|
|
21770
|
+
loading="lazy"
|
|
21771
|
+
/>
|
|
21772
|
+
</button>
|
|
21773
|
+
}
|
|
21774
|
+
</div>
|
|
21775
|
+
|
|
21776
|
+
<div class="jv-slider-counter">
|
|
21777
|
+
{{ currentIndex() + 1 }} / {{ images().length }}
|
|
21778
|
+
</div>
|
|
21779
|
+
}
|
|
21780
|
+
</div>
|
|
21781
|
+
`, styles: [".jv-slider{display:grid;gap:var(--jv-spacing-sm);width:100%;max-width:100%}.jv-slider-main{position:relative;display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:var(--jv-spacing-xs)}.jv-slider-stage{position:relative;aspect-ratio:16 / 9;overflow:hidden;border-radius:var(--jv-radius-md);background:var(--jv-color-surface-muted)}.jv-slider-slide{position:absolute;inset:0;opacity:0;transition:opacity .2s ease;pointer-events:none}.jv-slider-slide--active{opacity:1;pointer-events:auto}.jv-slider-image{display:block;width:100%;height:100%;object-fit:contain;-webkit-user-select:none;user-select:none}.jv-slider-nav{display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);cursor:pointer;transition:background-color .16s ease,border-color .16s ease,color .16s ease;flex-shrink:0;z-index:1}.jv-slider-nav:hover{background:var(--jv-color-surface-muted);border-color:var(--jv-color-foreground-muted)}.jv-slider-nav:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-slider-description{padding:var(--jv-spacing-sm) 0}.jv-slider-description p{margin:0;font-size:var(--jv-density-font-size);color:var(--jv-color-foreground-muted);line-height:1.5}.jv-slider-thumbnails{display:flex;gap:var(--jv-spacing-xs);overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;padding:var(--jv-spacing-xs) 0}.jv-slider-thumbnails::-webkit-scrollbar{display:none}.jv-slider-thumbnail{flex:0 0 auto;width:3.5rem;height:3.5rem;padding:0;border:2px solid transparent;border-radius:var(--jv-radius-sm);background:transparent;cursor:pointer;overflow:hidden;transition:border-color .16s ease,opacity .16s ease;opacity:.6}.jv-slider-thumbnail:hover{opacity:.85}.jv-slider-thumbnail--active{border-color:var(--jv-color-primary);opacity:1}.jv-slider-thumbnail:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-slider-thumbnail-image{display:block;width:100%;height:100%;object-fit:cover}.jv-slider-counter{text-align:center;font-size:.8125rem;color:var(--jv-color-foreground-muted);font-variant-numeric:tabular-nums}@media(max-width:640px){.jv-slider-nav{width:2rem;height:2rem}.jv-slider-thumbnail{width:2.75rem;height:2.75rem}}@media(prefers-reduced-motion:reduce){.jv-slider-slide{transition:none}}\n"] }]
|
|
21782
|
+
}], ctorParameters: () => [], propDecorators: { thumbnailStripRef: [{ type: i0.ViewChild, args: ['thumbnailStrip', { isSignal: true }] }], images: [{ type: i0.Input, args: [{ isSignal: true, alias: "images", required: false }] }], showThumbnails: [{ type: i0.Input, args: [{ isSignal: true, alias: "showThumbnails", required: false }] }], showDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDescription", required: false }] }], imageChange: [{ type: i0.Output, args: ["imageChange"] }], handleKeydown: [{
|
|
21783
|
+
type: HostListener,
|
|
21784
|
+
args: ['keydown', ['$event']]
|
|
21785
|
+
}] } });
|
|
21786
|
+
|
|
20803
21787
|
class JvDialogService {
|
|
20804
21788
|
announcementService = inject(JvAnnouncementService);
|
|
20805
21789
|
translation = inject(JvTranslationService);
|
|
@@ -21683,12 +22667,25 @@ class JvTabsComponent {
|
|
|
21683
22667
|
instanceId = ++tabsSequence;
|
|
21684
22668
|
panelTemplates = contentChildren(JvTabPanelDirective, ...(ngDevMode ? [{ debugName: "panelTemplates" }] : /* istanbul ignore next */ []));
|
|
21685
22669
|
tabListRef = viewChild('tabList', ...(ngDevMode ? [{ debugName: "tabListRef" }] : /* istanbul ignore next */ []));
|
|
22670
|
+
config = inject(JvUiConfigService);
|
|
21686
22671
|
tabs = input([], ...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
|
|
21687
22672
|
activeTabId = input(null, ...(ngDevMode ? [{ debugName: "activeTabId" }] : /* istanbul ignore next */ []));
|
|
21688
22673
|
keepMounted = input(true, ...(ngDevMode ? [{ debugName: "keepMounted" }] : /* istanbul ignore next */ []));
|
|
22674
|
+
transition = input(null, ...(ngDevMode ? [{ debugName: "transition" }] : /* istanbul ignore next */ []));
|
|
21689
22675
|
activeTabChange = output();
|
|
21690
22676
|
showScrollLeft = signal(false, ...(ngDevMode ? [{ debugName: "showScrollLeft" }] : /* istanbul ignore next */ []));
|
|
21691
22677
|
showScrollRight = signal(false, ...(ngDevMode ? [{ debugName: "showScrollRight" }] : /* istanbul ignore next */ []));
|
|
22678
|
+
slideDirection = signal('right', ...(ngDevMode ? [{ debugName: "slideDirection" }] : /* istanbul ignore next */ []));
|
|
22679
|
+
outgoingPanelId = signal(null, ...(ngDevMode ? [{ debugName: "outgoingPanelId" }] : /* istanbul ignore next */ []));
|
|
22680
|
+
previousActiveTabId = signal(null, ...(ngDevMode ? [{ debugName: "previousActiveTabId" }] : /* istanbul ignore next */ []));
|
|
22681
|
+
effectiveTransition = computed(() => {
|
|
22682
|
+
const local = this.transition();
|
|
22683
|
+
if (local !== null) {
|
|
22684
|
+
return local === 'slide' && this.keepMounted() ? 'fade' : local;
|
|
22685
|
+
}
|
|
22686
|
+
const global = this.config.snapshot.tabsTransition;
|
|
22687
|
+
return global === 'slide' && this.keepMounted() ? 'fade' : global;
|
|
22688
|
+
}, ...(ngDevMode ? [{ debugName: "effectiveTransition" }] : /* istanbul ignore next */ []));
|
|
21692
22689
|
resolvedActiveTabId = computed(() => {
|
|
21693
22690
|
const enabledTabs = this.tabs().filter((tab) => !tab.disabled);
|
|
21694
22691
|
const requestedId = this.activeTabId();
|
|
@@ -21708,6 +22705,20 @@ class JvTabsComponent {
|
|
|
21708
22705
|
this.updateScrollControls();
|
|
21709
22706
|
});
|
|
21710
22707
|
});
|
|
22708
|
+
effect(() => {
|
|
22709
|
+
const activeId = this.resolvedActiveTabId();
|
|
22710
|
+
const prevId = this.previousActiveTabId();
|
|
22711
|
+
if (activeId !== prevId && prevId !== null && !this.keepMounted()) {
|
|
22712
|
+
const enabledTabs = this.tabs().filter((t) => !t.disabled);
|
|
22713
|
+
const newIndex = enabledTabs.findIndex((t) => t.id === activeId);
|
|
22714
|
+
const oldIndex = enabledTabs.findIndex((t) => t.id === prevId);
|
|
22715
|
+
if (newIndex !== oldIndex) {
|
|
22716
|
+
this.slideDirection.set(newIndex > oldIndex ? 'left' : 'right');
|
|
22717
|
+
}
|
|
22718
|
+
this.outgoingPanelId.set(prevId);
|
|
22719
|
+
}
|
|
22720
|
+
this.previousActiveTabId.set(activeId);
|
|
22721
|
+
});
|
|
21711
22722
|
}
|
|
21712
22723
|
ngAfterViewInit() {
|
|
21713
22724
|
this.updateScrollControls();
|
|
@@ -21732,6 +22743,14 @@ class JvTabsComponent {
|
|
|
21732
22743
|
this.activeTabChange.emit(tabId);
|
|
21733
22744
|
queueMicrotask(() => this.focusTabButton(tabId));
|
|
21734
22745
|
}
|
|
22746
|
+
handleTransitionEnd(event) {
|
|
22747
|
+
if (event.propertyName !== 'opacity' && event.propertyName !== 'transform') {
|
|
22748
|
+
return;
|
|
22749
|
+
}
|
|
22750
|
+
if (!this.keepMounted() && this.outgoingPanelId()) {
|
|
22751
|
+
this.outgoingPanelId.set(null);
|
|
22752
|
+
}
|
|
22753
|
+
}
|
|
21735
22754
|
handleKeydown(event, currentTabId) {
|
|
21736
22755
|
const enabledTabs = this.tabs().filter((tab) => !tab.disabled);
|
|
21737
22756
|
if (enabledTabs.length === 0) {
|
|
@@ -21812,7 +22831,7 @@ class JvTabsComponent {
|
|
|
21812
22831
|
return (Array.from(tabList.querySelectorAll('[data-jv-tab-id]')).find((button) => button.dataset['jvTabId'] === tabId) ?? null);
|
|
21813
22832
|
}
|
|
21814
22833
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
21815
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvTabsComponent, isStandalone: true, selector: "jv-tabs", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, activeTabId: { classPropertyName: "activeTabId", publicName: "activeTabId", isSignal: true, isRequired: false, transformFunction: null }, keepMounted: { classPropertyName: "keepMounted", publicName: "keepMounted", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeTabChange: "activeTabChange" }, host: { listeners: { "window:resize": "handleWindowResize()" } }, queries: [{ propertyName: "panelTemplates", predicate: JvTabPanelDirective, isSignal: true }], viewQueries: [{ propertyName: "tabListRef", first: true, predicate: ["tabList"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
22834
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvTabsComponent, isStandalone: true, selector: "jv-tabs", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, activeTabId: { classPropertyName: "activeTabId", publicName: "activeTabId", isSignal: true, isRequired: false, transformFunction: null }, keepMounted: { classPropertyName: "keepMounted", publicName: "keepMounted", isSignal: true, isRequired: false, transformFunction: null }, transition: { classPropertyName: "transition", publicName: "transition", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeTabChange: "activeTabChange" }, host: { listeners: { "window:resize": "handleWindowResize()" } }, queries: [{ propertyName: "panelTemplates", predicate: JvTabPanelDirective, isSignal: true }], viewQueries: [{ propertyName: "tabListRef", first: true, predicate: ["tabList"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
21816
22835
|
<div class="jv-tabs">
|
|
21817
22836
|
<div class="jv-tabs-header">
|
|
21818
22837
|
<div class="jv-tabs-scroll" #tabList role="tablist" aria-orientation="horizontal" (scroll)="updateScrollControls()">
|
|
@@ -21858,29 +22877,52 @@ class JvTabsComponent {
|
|
|
21858
22877
|
<div
|
|
21859
22878
|
class="jv-tab-panel"
|
|
21860
22879
|
[class.jv-tab-panel--hidden]="!isActive(tab.id)"
|
|
22880
|
+
[class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
|
|
22881
|
+
[class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
|
|
22882
|
+
[class.jv-tab-panel--slide-right]="effectiveTransition() === 'slide' && slideDirection() === 'right'"
|
|
21861
22883
|
[id]="panelId(tab.id)"
|
|
21862
22884
|
role="tabpanel"
|
|
21863
22885
|
[attr.aria-labelledby]="tabButtonId(tab.id)"
|
|
21864
22886
|
[attr.tabindex]="isActive(tab.id) ? 0 : null"
|
|
21865
|
-
[hidden]="!isActive(tab.id)"
|
|
21866
22887
|
>
|
|
21867
22888
|
<ng-container [ngTemplateOutlet]="panelTemplate(tab.id) ?? null" />
|
|
21868
22889
|
</div>
|
|
21869
22890
|
}
|
|
21870
|
-
} @else
|
|
21871
|
-
|
|
21872
|
-
|
|
21873
|
-
|
|
21874
|
-
|
|
21875
|
-
|
|
21876
|
-
|
|
21877
|
-
|
|
21878
|
-
|
|
21879
|
-
|
|
22891
|
+
} @else {
|
|
22892
|
+
@if (outgoingPanelId(); as outgoingId) {
|
|
22893
|
+
<div
|
|
22894
|
+
class="jv-tab-panel jv-tab-panel--exit"
|
|
22895
|
+
[class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
|
|
22896
|
+
[class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
|
|
22897
|
+
[class.jv-tab-panel--slide-right]="effectiveTransition() === 'slide' && slideDirection() === 'right'"
|
|
22898
|
+
[id]="panelId(outgoingId)"
|
|
22899
|
+
role="tabpanel"
|
|
22900
|
+
[attr.aria-labelledby]="tabButtonId(outgoingId)"
|
|
22901
|
+
tabindex="-1"
|
|
22902
|
+
(transitionend)="handleTransitionEnd($event)"
|
|
22903
|
+
>
|
|
22904
|
+
<ng-container [ngTemplateOutlet]="panelTemplate(outgoingId) ?? null" />
|
|
22905
|
+
</div>
|
|
22906
|
+
}
|
|
22907
|
+
|
|
22908
|
+
@if (resolvedActiveTabId(); as activeId) {
|
|
22909
|
+
<div
|
|
22910
|
+
class="jv-tab-panel jv-tab-panel--entering"
|
|
22911
|
+
[class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
|
|
22912
|
+
[class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
|
|
22913
|
+
[class.jv-tab-panel--slide-right]="effectiveTransition() === 'slide' && slideDirection() === 'right'"
|
|
22914
|
+
[id]="panelId(activeId)"
|
|
22915
|
+
role="tabpanel"
|
|
22916
|
+
[attr.aria-labelledby]="tabButtonId(activeId)"
|
|
22917
|
+
tabindex="0"
|
|
22918
|
+
>
|
|
22919
|
+
<ng-container [ngTemplateOutlet]="panelTemplate(activeId) ?? null" />
|
|
22920
|
+
</div>
|
|
22921
|
+
}
|
|
21880
22922
|
}
|
|
21881
22923
|
</div>
|
|
21882
22924
|
</div>
|
|
21883
|
-
`, isInline: true, styles: [".jv-tabs{display:grid;gap:var(--jv-spacing-md)}.jv-tabs-header{display:flex;align-items:center;gap:var(--jv-spacing-sm);min-width:0}.jv-tabs-scroll{flex:1;min-width:0;display:flex;align-items:stretch;gap:var(--jv-spacing-xs);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none;border-bottom:1px solid var(--jv-color-border);scroll-behavior:smooth}.jv-tabs-scroll::-webkit-scrollbar{display:none}.jv-tab{position:relative;display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);flex:0 0 auto;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:0;border-bottom:2px solid transparent;background:transparent;color:var(--jv-color-foreground-muted);font:inherit;font-weight:600;white-space:nowrap;cursor:pointer;transition:color .16s ease,border-color .16s ease,background-color .16s ease}.jv-tab:hover:not(:disabled){color:var(--jv-color-foreground);background:color-mix(in srgb,var(--jv-color-primary) 6%,transparent)}.jv-tab:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px;border-radius:var(--jv-radius-sm) var(--jv-radius-sm) 0 0}.jv-tab--active{color:var(--jv-color-primary);border-bottom-color:var(--jv-color-primary)}.jv-tab--disabled{opacity:.5;cursor:not-allowed}.jv-tabs-controls{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-tabs-scroll-button{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);cursor:pointer}.jv-tabs-scroll-button:disabled{opacity:.4;cursor:default}.jv-tab-panel{outline:none}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }] });
|
|
22925
|
+
`, isInline: true, styles: [".jv-tabs{display:grid;gap:var(--jv-spacing-md)}.jv-tabs-header{display:flex;align-items:center;gap:var(--jv-spacing-sm);min-width:0}.jv-tabs-scroll{flex:1;min-width:0;display:flex;align-items:stretch;gap:var(--jv-spacing-xs);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none;border-bottom:1px solid var(--jv-color-border);scroll-behavior:smooth}.jv-tabs-scroll::-webkit-scrollbar{display:none}.jv-tab{position:relative;display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);flex:0 0 auto;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:0;border-bottom:2px solid transparent;background:transparent;color:var(--jv-color-foreground-muted);font:inherit;font-weight:600;white-space:nowrap;cursor:pointer;transition:color .16s ease,border-color .16s ease,background-color .16s ease}.jv-tab:hover:not(:disabled){color:var(--jv-color-foreground);background:color-mix(in srgb,var(--jv-color-primary) 6%,transparent)}.jv-tab:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px;border-radius:var(--jv-radius-sm) var(--jv-radius-sm) 0 0}.jv-tab--active{color:var(--jv-color-primary);border-bottom-color:var(--jv-color-primary)}.jv-tab--disabled{opacity:.5;cursor:not-allowed}.jv-tabs-controls{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-tabs-scroll-button{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);cursor:pointer}.jv-tabs-scroll-button:disabled{opacity:.4;cursor:default}.jv-tab-panel{outline:none}.jv-tab-panel--hidden{display:none}.jv-tab-panel--fade{transition:opacity .18s ease}.jv-tab-panel--hidden.jv-tab-panel--fade{display:block;opacity:0;pointer-events:none}.jv-tab-panel--slide-left,.jv-tab-panel--slide-right{transition:opacity .18s ease,transform .18s ease}.jv-tab-panel--hidden.jv-tab-panel--slide-left{display:block;opacity:0;transform:translate(20px);pointer-events:none}.jv-tab-panel--hidden.jv-tab-panel--slide-right{display:block;opacity:0;transform:translate(-20px);pointer-events:none}.jv-tab-panel--exit.jv-tab-panel--fade{position:absolute;opacity:0;pointer-events:none}.jv-tab-panel--exit.jv-tab-panel--slide-left{position:absolute;opacity:0;transform:translate(-20px);pointer-events:none}.jv-tab-panel--exit.jv-tab-panel--slide-right{position:absolute;opacity:0;transform:translate(20px);pointer-events:none}.jv-tab-panel--entering{animation:jv-tab-enter .18s ease forwards}.jv-tab-panel--entering.jv-tab-panel--slide-left{animation-name:jv-tab-slide-from-right}.jv-tab-panel--entering.jv-tab-panel--slide-right{animation-name:jv-tab-slide-from-left}@keyframes jv-tab-enter{0%{opacity:0}to{opacity:1}}@keyframes jv-tab-slide-from-right{0%{opacity:0;transform:translate(20px)}to{opacity:1;transform:translate(0)}}@keyframes jv-tab-slide-from-left{0%{opacity:0;transform:translate(-20px)}to{opacity:1;transform:translate(0)}}@media(prefers-reduced-motion:reduce){.jv-tab-panel--fade,.jv-tab-panel--slide-left,.jv-tab-panel--slide-right,.jv-tab-panel--entering{transition:none;animation:none}.jv-tab-panel--hidden.jv-tab-panel--fade,.jv-tab-panel--hidden.jv-tab-panel--slide-left,.jv-tab-panel--hidden.jv-tab-panel--slide-right{opacity:0}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }] });
|
|
21884
22926
|
}
|
|
21885
22927
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTabsComponent, decorators: [{
|
|
21886
22928
|
type: Component,
|
|
@@ -21930,30 +22972,53 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
21930
22972
|
<div
|
|
21931
22973
|
class="jv-tab-panel"
|
|
21932
22974
|
[class.jv-tab-panel--hidden]="!isActive(tab.id)"
|
|
22975
|
+
[class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
|
|
22976
|
+
[class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
|
|
22977
|
+
[class.jv-tab-panel--slide-right]="effectiveTransition() === 'slide' && slideDirection() === 'right'"
|
|
21933
22978
|
[id]="panelId(tab.id)"
|
|
21934
22979
|
role="tabpanel"
|
|
21935
22980
|
[attr.aria-labelledby]="tabButtonId(tab.id)"
|
|
21936
22981
|
[attr.tabindex]="isActive(tab.id) ? 0 : null"
|
|
21937
|
-
[hidden]="!isActive(tab.id)"
|
|
21938
22982
|
>
|
|
21939
22983
|
<ng-container [ngTemplateOutlet]="panelTemplate(tab.id) ?? null" />
|
|
21940
22984
|
</div>
|
|
21941
22985
|
}
|
|
21942
|
-
} @else
|
|
21943
|
-
|
|
21944
|
-
|
|
21945
|
-
|
|
21946
|
-
|
|
21947
|
-
|
|
21948
|
-
|
|
21949
|
-
|
|
21950
|
-
|
|
21951
|
-
|
|
22986
|
+
} @else {
|
|
22987
|
+
@if (outgoingPanelId(); as outgoingId) {
|
|
22988
|
+
<div
|
|
22989
|
+
class="jv-tab-panel jv-tab-panel--exit"
|
|
22990
|
+
[class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
|
|
22991
|
+
[class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
|
|
22992
|
+
[class.jv-tab-panel--slide-right]="effectiveTransition() === 'slide' && slideDirection() === 'right'"
|
|
22993
|
+
[id]="panelId(outgoingId)"
|
|
22994
|
+
role="tabpanel"
|
|
22995
|
+
[attr.aria-labelledby]="tabButtonId(outgoingId)"
|
|
22996
|
+
tabindex="-1"
|
|
22997
|
+
(transitionend)="handleTransitionEnd($event)"
|
|
22998
|
+
>
|
|
22999
|
+
<ng-container [ngTemplateOutlet]="panelTemplate(outgoingId) ?? null" />
|
|
23000
|
+
</div>
|
|
23001
|
+
}
|
|
23002
|
+
|
|
23003
|
+
@if (resolvedActiveTabId(); as activeId) {
|
|
23004
|
+
<div
|
|
23005
|
+
class="jv-tab-panel jv-tab-panel--entering"
|
|
23006
|
+
[class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
|
|
23007
|
+
[class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
|
|
23008
|
+
[class.jv-tab-panel--slide-right]="effectiveTransition() === 'slide' && slideDirection() === 'right'"
|
|
23009
|
+
[id]="panelId(activeId)"
|
|
23010
|
+
role="tabpanel"
|
|
23011
|
+
[attr.aria-labelledby]="tabButtonId(activeId)"
|
|
23012
|
+
tabindex="0"
|
|
23013
|
+
>
|
|
23014
|
+
<ng-container [ngTemplateOutlet]="panelTemplate(activeId) ?? null" />
|
|
23015
|
+
</div>
|
|
23016
|
+
}
|
|
21952
23017
|
}
|
|
21953
23018
|
</div>
|
|
21954
23019
|
</div>
|
|
21955
|
-
`, styles: [".jv-tabs{display:grid;gap:var(--jv-spacing-md)}.jv-tabs-header{display:flex;align-items:center;gap:var(--jv-spacing-sm);min-width:0}.jv-tabs-scroll{flex:1;min-width:0;display:flex;align-items:stretch;gap:var(--jv-spacing-xs);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none;border-bottom:1px solid var(--jv-color-border);scroll-behavior:smooth}.jv-tabs-scroll::-webkit-scrollbar{display:none}.jv-tab{position:relative;display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);flex:0 0 auto;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:0;border-bottom:2px solid transparent;background:transparent;color:var(--jv-color-foreground-muted);font:inherit;font-weight:600;white-space:nowrap;cursor:pointer;transition:color .16s ease,border-color .16s ease,background-color .16s ease}.jv-tab:hover:not(:disabled){color:var(--jv-color-foreground);background:color-mix(in srgb,var(--jv-color-primary) 6%,transparent)}.jv-tab:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px;border-radius:var(--jv-radius-sm) var(--jv-radius-sm) 0 0}.jv-tab--active{color:var(--jv-color-primary);border-bottom-color:var(--jv-color-primary)}.jv-tab--disabled{opacity:.5;cursor:not-allowed}.jv-tabs-controls{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-tabs-scroll-button{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);cursor:pointer}.jv-tabs-scroll-button:disabled{opacity:.4;cursor:default}.jv-tab-panel{outline:none}\n"] }]
|
|
21956
|
-
}], ctorParameters: () => [], propDecorators: { panelTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => JvTabPanelDirective), { isSignal: true }] }], tabListRef: [{ type: i0.ViewChild, args: ['tabList', { isSignal: true }] }], tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: false }] }], activeTabId: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeTabId", required: false }] }], keepMounted: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepMounted", required: false }] }], activeTabChange: [{ type: i0.Output, args: ["activeTabChange"] }], handleWindowResize: [{
|
|
23020
|
+
`, styles: [".jv-tabs{display:grid;gap:var(--jv-spacing-md)}.jv-tabs-header{display:flex;align-items:center;gap:var(--jv-spacing-sm);min-width:0}.jv-tabs-scroll{flex:1;min-width:0;display:flex;align-items:stretch;gap:var(--jv-spacing-xs);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none;border-bottom:1px solid var(--jv-color-border);scroll-behavior:smooth}.jv-tabs-scroll::-webkit-scrollbar{display:none}.jv-tab{position:relative;display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);flex:0 0 auto;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:0;border-bottom:2px solid transparent;background:transparent;color:var(--jv-color-foreground-muted);font:inherit;font-weight:600;white-space:nowrap;cursor:pointer;transition:color .16s ease,border-color .16s ease,background-color .16s ease}.jv-tab:hover:not(:disabled){color:var(--jv-color-foreground);background:color-mix(in srgb,var(--jv-color-primary) 6%,transparent)}.jv-tab:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px;border-radius:var(--jv-radius-sm) var(--jv-radius-sm) 0 0}.jv-tab--active{color:var(--jv-color-primary);border-bottom-color:var(--jv-color-primary)}.jv-tab--disabled{opacity:.5;cursor:not-allowed}.jv-tabs-controls{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-tabs-scroll-button{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);cursor:pointer}.jv-tabs-scroll-button:disabled{opacity:.4;cursor:default}.jv-tab-panel{outline:none}.jv-tab-panel--hidden{display:none}.jv-tab-panel--fade{transition:opacity .18s ease}.jv-tab-panel--hidden.jv-tab-panel--fade{display:block;opacity:0;pointer-events:none}.jv-tab-panel--slide-left,.jv-tab-panel--slide-right{transition:opacity .18s ease,transform .18s ease}.jv-tab-panel--hidden.jv-tab-panel--slide-left{display:block;opacity:0;transform:translate(20px);pointer-events:none}.jv-tab-panel--hidden.jv-tab-panel--slide-right{display:block;opacity:0;transform:translate(-20px);pointer-events:none}.jv-tab-panel--exit.jv-tab-panel--fade{position:absolute;opacity:0;pointer-events:none}.jv-tab-panel--exit.jv-tab-panel--slide-left{position:absolute;opacity:0;transform:translate(-20px);pointer-events:none}.jv-tab-panel--exit.jv-tab-panel--slide-right{position:absolute;opacity:0;transform:translate(20px);pointer-events:none}.jv-tab-panel--entering{animation:jv-tab-enter .18s ease forwards}.jv-tab-panel--entering.jv-tab-panel--slide-left{animation-name:jv-tab-slide-from-right}.jv-tab-panel--entering.jv-tab-panel--slide-right{animation-name:jv-tab-slide-from-left}@keyframes jv-tab-enter{0%{opacity:0}to{opacity:1}}@keyframes jv-tab-slide-from-right{0%{opacity:0;transform:translate(20px)}to{opacity:1;transform:translate(0)}}@keyframes jv-tab-slide-from-left{0%{opacity:0;transform:translate(-20px)}to{opacity:1;transform:translate(0)}}@media(prefers-reduced-motion:reduce){.jv-tab-panel--fade,.jv-tab-panel--slide-left,.jv-tab-panel--slide-right,.jv-tab-panel--entering{transition:none;animation:none}.jv-tab-panel--hidden.jv-tab-panel--fade,.jv-tab-panel--hidden.jv-tab-panel--slide-left,.jv-tab-panel--hidden.jv-tab-panel--slide-right{opacity:0}}\n"] }]
|
|
23021
|
+
}], ctorParameters: () => [], propDecorators: { panelTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => JvTabPanelDirective), { isSignal: true }] }], tabListRef: [{ type: i0.ViewChild, args: ['tabList', { isSignal: true }] }], tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: false }] }], activeTabId: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeTabId", required: false }] }], keepMounted: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepMounted", required: false }] }], transition: [{ type: i0.Input, args: [{ isSignal: true, alias: "transition", required: false }] }], activeTabChange: [{ type: i0.Output, args: ["activeTabChange"] }], handleWindowResize: [{
|
|
21957
23022
|
type: HostListener,
|
|
21958
23023
|
args: ['window:resize']
|
|
21959
23024
|
}] } });
|
|
@@ -22154,6 +23219,7 @@ const JV_GRID_DEFAULT_OPTIONS = {
|
|
|
22154
23219
|
let gridIdSequence = 0;
|
|
22155
23220
|
class JvGridComponent {
|
|
22156
23221
|
gridId = `jv-grid-${++gridIdSequence}`;
|
|
23222
|
+
formatService = inject(JvFormatService);
|
|
22157
23223
|
translationService = inject(JvTranslationService);
|
|
22158
23224
|
data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
22159
23225
|
columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
@@ -22222,7 +23288,7 @@ class JvGridComponent {
|
|
|
22222
23288
|
const value = this.getRawCellValue(row, col);
|
|
22223
23289
|
if (value == null)
|
|
22224
23290
|
return false;
|
|
22225
|
-
return
|
|
23291
|
+
return this.getSearchValue(value, col).includes(term);
|
|
22226
23292
|
});
|
|
22227
23293
|
});
|
|
22228
23294
|
}
|
|
@@ -22236,7 +23302,7 @@ class JvGridComponent {
|
|
|
22236
23302
|
const col = this.columns().find(c => this.colKey(c) === key);
|
|
22237
23303
|
if (!col || col.filterable === false)
|
|
22238
23304
|
return true;
|
|
22239
|
-
const value =
|
|
23305
|
+
const value = this.getSearchValue(this.getRawCellValue(row, col), col);
|
|
22240
23306
|
const fv = filter.value.toLowerCase();
|
|
22241
23307
|
switch (filter.operator) {
|
|
22242
23308
|
case 'contains': return value.includes(fv);
|
|
@@ -22258,8 +23324,9 @@ class JvGridComponent {
|
|
|
22258
23324
|
if (!columnKey || !direction)
|
|
22259
23325
|
return items;
|
|
22260
23326
|
return [...items].sort((a, b) => {
|
|
22261
|
-
const
|
|
22262
|
-
const
|
|
23327
|
+
const col = this.findColumn(columnKey);
|
|
23328
|
+
const va = this.getComparableValue(this.getRawCellValue(a, col), col);
|
|
23329
|
+
const vb = this.getComparableValue(this.getRawCellValue(b, col), col);
|
|
22263
23330
|
if (va == null)
|
|
22264
23331
|
return 1;
|
|
22265
23332
|
if (vb == null)
|
|
@@ -22363,14 +23430,56 @@ class JvGridComponent {
|
|
|
22363
23430
|
const val = this.getCellValue(row, col);
|
|
22364
23431
|
return val == null ? '' : String(val);
|
|
22365
23432
|
}
|
|
22366
|
-
formatValue(value, col) {
|
|
23433
|
+
formatValue(value, col, _row) {
|
|
22367
23434
|
if (value == null)
|
|
22368
23435
|
return '';
|
|
22369
|
-
|
|
22370
|
-
|
|
23436
|
+
const type = this.resolveColumnType(col);
|
|
23437
|
+
if (type === 'text' || type === 'boolean') {
|
|
23438
|
+
return String(value);
|
|
23439
|
+
}
|
|
23440
|
+
return this.formatService.format(type, value, this.getFormatOverrides(col));
|
|
23441
|
+
}
|
|
23442
|
+
getComparableValue(value, col) {
|
|
23443
|
+
const type = this.resolveColumnType(col);
|
|
23444
|
+
if (value == null || value === '')
|
|
23445
|
+
return null;
|
|
23446
|
+
if (type === 'text') {
|
|
23447
|
+
return String(value).toLowerCase();
|
|
23448
|
+
}
|
|
23449
|
+
if (type === 'boolean') {
|
|
23450
|
+
return Boolean(value);
|
|
23451
|
+
}
|
|
23452
|
+
return this.formatService.toComparable(type, value);
|
|
23453
|
+
}
|
|
23454
|
+
getSearchValue(value, col) {
|
|
23455
|
+
const type = this.resolveColumnType(col);
|
|
23456
|
+
if (type === 'text' || type === 'boolean') {
|
|
23457
|
+
return String(value ?? '').toLowerCase();
|
|
23458
|
+
}
|
|
23459
|
+
return this.formatService.toSearchValue(type, value);
|
|
23460
|
+
}
|
|
23461
|
+
getExportValue(value, col) {
|
|
23462
|
+
if (value == null)
|
|
23463
|
+
return '';
|
|
23464
|
+
const type = this.resolveColumnType(col);
|
|
23465
|
+
if (type === 'date' || type === 'time' || type === 'datetime') {
|
|
23466
|
+
const date = this.formatService.toDate(value);
|
|
23467
|
+
if (!date)
|
|
23468
|
+
return String(value);
|
|
23469
|
+
if (type === 'date')
|
|
23470
|
+
return date.toISOString().slice(0, 10);
|
|
23471
|
+
if (type === 'time')
|
|
23472
|
+
return date.toISOString().slice(11, 19);
|
|
23473
|
+
return date.toISOString();
|
|
22371
23474
|
}
|
|
22372
23475
|
return String(value);
|
|
22373
23476
|
}
|
|
23477
|
+
resolveColumnType(col) {
|
|
23478
|
+
return col.type ?? 'text';
|
|
23479
|
+
}
|
|
23480
|
+
getFormatOverrides(col) {
|
|
23481
|
+
return col.formatOptions;
|
|
23482
|
+
}
|
|
22374
23483
|
getAriaSort(col) {
|
|
22375
23484
|
if (col.sortable === false || !this.resolvedOptions().sortable)
|
|
22376
23485
|
return null;
|
|
@@ -22618,14 +23727,14 @@ class JvGridComponent {
|
|
|
22618
23727
|
}
|
|
22619
23728
|
// Export
|
|
22620
23729
|
exportCsv() {
|
|
22621
|
-
const cols = this.visibleColumns().map(c => ({ key: this.colKey(c), header: c.header }));
|
|
23730
|
+
const cols = this.visibleColumns().map(c => ({ key: this.colKey(c), header: c.header, column: c }));
|
|
22622
23731
|
const allData = this.effectiveOptions().serverSide ? this.data() : this.sortedData();
|
|
22623
23732
|
const headerRow = cols.map(c => `"${c.header}"`).join(',');
|
|
22624
23733
|
const dataRows = allData.map(row => cols.map(col => {
|
|
22625
23734
|
const val = row[col.key];
|
|
22626
23735
|
if (val == null)
|
|
22627
23736
|
return '';
|
|
22628
|
-
return `"${
|
|
23737
|
+
return `"${this.getExportValue(val, col.column).replace(/"/g, '""')}"`;
|
|
22629
23738
|
}).join(','));
|
|
22630
23739
|
const csv = [headerRow, ...dataRows].join('\r\n');
|
|
22631
23740
|
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
|
|
@@ -22637,13 +23746,13 @@ class JvGridComponent {
|
|
|
22637
23746
|
URL.revokeObjectURL(url);
|
|
22638
23747
|
}
|
|
22639
23748
|
exportExcel() {
|
|
22640
|
-
const cols = this.visibleColumns().map(c => ({ key: this.colKey(c), header: c.header }));
|
|
23749
|
+
const cols = this.visibleColumns().map(c => ({ key: this.colKey(c), header: c.header, column: c }));
|
|
22641
23750
|
const allData = this.effectiveOptions().serverSide ? this.data() : this.sortedData();
|
|
22642
23751
|
let html = '<table>';
|
|
22643
23752
|
html += '<thead><tr>' + cols.map(c => `<th>${c.header}</th>`).join('') + '</tr></thead>';
|
|
22644
23753
|
html += '<tbody>';
|
|
22645
23754
|
for (const row of allData) {
|
|
22646
|
-
html += '<tr>' + cols.map(col => `<td>${row[col.key]
|
|
23755
|
+
html += '<tr>' + cols.map(col => `<td>${this.getExportValue(row[col.key], col.column)}</td>`).join('') + '</tr>';
|
|
22647
23756
|
}
|
|
22648
23757
|
html += '</tbody></table>';
|
|
22649
23758
|
const blob = new Blob([html], { type: 'application/vnd.ms-excel' });
|
|
@@ -22924,7 +24033,7 @@ class JvGridComponent {
|
|
|
22924
24033
|
} @else if (col.format) {
|
|
22925
24034
|
{{ col.format(value, row) }}
|
|
22926
24035
|
} @else {
|
|
22927
|
-
{{ formatValue(value, col) }}
|
|
24036
|
+
{{ formatValue(value, col, row) }}
|
|
22928
24037
|
}
|
|
22929
24038
|
}
|
|
22930
24039
|
</td>
|
|
@@ -23275,7 +24384,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
23275
24384
|
} @else if (col.format) {
|
|
23276
24385
|
{{ col.format(value, row) }}
|
|
23277
24386
|
} @else {
|
|
23278
|
-
{{ formatValue(value, col) }}
|
|
24387
|
+
{{ formatValue(value, col, row) }}
|
|
23279
24388
|
}
|
|
23280
24389
|
}
|
|
23281
24390
|
</td>
|
|
@@ -23524,5 +24633,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
23524
24633
|
* Generated bundle index. Do not edit.
|
|
23525
24634
|
*/
|
|
23526
24635
|
|
|
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 };
|
|
24636
|
+
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, JvImageGalleryComponent, JvImageSliderComponent, 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
24637
|
//# sourceMappingURL=devjuliovilla-jv-ui.mjs.map
|