@devjuliovilla/jv-ui 1.11.0 → 1.11.2
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 +16 -15
- package/fesm2022/devjuliovilla-jv-ui.mjs +799 -533
- package/fesm2022/devjuliovilla-jv-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/devjuliovilla-jv-ui.d.ts +5 -1
|
@@ -19936,10 +19936,10 @@ class JvDatePickerComponent {
|
|
|
19936
19936
|
visibleMonth = signal(firstOfMonth(new Date()), ...(ngDevMode ? [{ debugName: "visibleMonth" }] : /* istanbul ignore next */ []));
|
|
19937
19937
|
focusedDate = signal(startOfDay(new Date()), ...(ngDevMode ? [{ debugName: "focusedDate" }] : /* istanbul ignore next */ []));
|
|
19938
19938
|
dialogId = `jv-date-picker-dialog-${this.instanceId}`;
|
|
19939
|
-
value = null;
|
|
19939
|
+
value = signal(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
19940
19940
|
disabled = false;
|
|
19941
19941
|
resolvedDialogTitle = computed(() => this.dialogTitle() || this.translation.translate('datePicker.dialogTitle'), ...(ngDevMode ? [{ debugName: "resolvedDialogTitle" }] : /* istanbul ignore next */ []));
|
|
19942
|
-
currentValue = computed(() => this.valueInput() !== undefined ? this.valueInput() : this.value, ...(ngDevMode ? [{ debugName: "currentValue" }] : /* istanbul ignore next */ []));
|
|
19942
|
+
currentValue = computed(() => this.valueInput() !== undefined ? this.valueInput() : this.value(), ...(ngDevMode ? [{ debugName: "currentValue" }] : /* istanbul ignore next */ []));
|
|
19943
19943
|
triggerAriaLabel = computed(() => {
|
|
19944
19944
|
const name = this.label() || this.resolvedDialogTitle();
|
|
19945
19945
|
return `${name}. ${this.displayValue()}`;
|
|
@@ -19987,7 +19987,7 @@ class JvDatePickerComponent {
|
|
|
19987
19987
|
onChange = () => undefined;
|
|
19988
19988
|
onTouched = () => undefined;
|
|
19989
19989
|
writeValue(value) {
|
|
19990
|
-
this.value
|
|
19990
|
+
this.value.set(value ? startOfDay(value) : null);
|
|
19991
19991
|
}
|
|
19992
19992
|
registerOnChange(fn) {
|
|
19993
19993
|
this.onChange = fn;
|
|
@@ -20093,7 +20093,7 @@ class JvDatePickerComponent {
|
|
|
20093
20093
|
this.onTouched();
|
|
20094
20094
|
}
|
|
20095
20095
|
updateValue(value) {
|
|
20096
|
-
this.value
|
|
20096
|
+
this.value.set(value);
|
|
20097
20097
|
this.onChange(value);
|
|
20098
20098
|
this.selectionChange.emit(value);
|
|
20099
20099
|
}
|
|
@@ -21361,172 +21361,172 @@ class JvImageGalleryComponent {
|
|
|
21361
21361
|
this.slideDirection.set(direction);
|
|
21362
21362
|
}
|
|
21363
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>
|
|
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
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
21446
|
}
|
|
21447
21447
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvImageGalleryComponent, decorators: [{
|
|
21448
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>
|
|
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
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
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
21532
|
type: HostListener,
|
|
@@ -21620,164 +21620,164 @@ class JvImageSliderComponent {
|
|
|
21620
21620
|
}
|
|
21621
21621
|
}
|
|
21622
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>
|
|
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
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
21701
|
}
|
|
21702
21702
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvImageSliderComponent, decorators: [{
|
|
21703
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>
|
|
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
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
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
21783
|
type: HostListener,
|
|
@@ -22831,192 +22831,192 @@ class JvTabsComponent {
|
|
|
22831
22831
|
return (Array.from(tabList.querySelectorAll('[data-jv-tab-id]')).find((button) => button.dataset['jvTabId'] === tabId) ?? null);
|
|
22832
22832
|
}
|
|
22833
22833
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
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: `
|
|
22835
|
-
<div class="jv-tabs">
|
|
22836
|
-
<div class="jv-tabs-header">
|
|
22837
|
-
<div class="jv-tabs-scroll" #tabList role="tablist" aria-orientation="horizontal" (scroll)="updateScrollControls()">
|
|
22838
|
-
@for (tab of tabs(); track tab.id) {
|
|
22839
|
-
<button
|
|
22840
|
-
type="button"
|
|
22841
|
-
class="jv-tab"
|
|
22842
|
-
[class.jv-tab--active]="isActive(tab.id)"
|
|
22843
|
-
[class.jv-tab--disabled]="tab.disabled ?? false"
|
|
22844
|
-
[id]="tabButtonId(tab.id)"
|
|
22845
|
-
[attr.data-jv-tab-id]="tab.id"
|
|
22846
|
-
role="tab"
|
|
22847
|
-
[attr.aria-selected]="isActive(tab.id) ? 'true' : 'false'"
|
|
22848
|
-
[attr.aria-controls]="panelId(tab.id)"
|
|
22849
|
-
[attr.tabindex]="getTabIndex(tab.id, tab.disabled ?? false)"
|
|
22850
|
-
[disabled]="tab.disabled ?? false"
|
|
22851
|
-
(click)="activateTab(tab.id)"
|
|
22852
|
-
(keydown)="handleKeydown($event, tab.id)"
|
|
22853
|
-
>
|
|
22854
|
-
@if (tab.icon) {
|
|
22855
|
-
<jv-icon [name]="tab.icon" [size]="16" />
|
|
22856
|
-
}
|
|
22857
|
-
<span>{{ tab.label }}</span>
|
|
22858
|
-
</button>
|
|
22859
|
-
}
|
|
22860
|
-
</div>
|
|
22861
|
-
|
|
22862
|
-
@if (showScrollLeft() || showScrollRight()) {
|
|
22863
|
-
<div class="jv-tabs-controls" aria-hidden="true">
|
|
22864
|
-
<button type="button" class="jv-tabs-scroll-button" [disabled]="!showScrollLeft()" (click)="scrollTabs(-1)">
|
|
22865
|
-
<jv-icon name="chevron-left" [size]="16" />
|
|
22866
|
-
</button>
|
|
22867
|
-
<button type="button" class="jv-tabs-scroll-button" [disabled]="!showScrollRight()" (click)="scrollTabs(1)">
|
|
22868
|
-
<jv-icon name="chevron-right" [size]="16" />
|
|
22869
|
-
</button>
|
|
22870
|
-
</div>
|
|
22871
|
-
}
|
|
22872
|
-
</div>
|
|
22873
|
-
|
|
22874
|
-
<div class="jv-tabs-panels">
|
|
22875
|
-
@if (keepMounted()) {
|
|
22876
|
-
@for (tab of tabs(); track tab.id) {
|
|
22877
|
-
<div
|
|
22878
|
-
class="jv-tab-panel"
|
|
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'"
|
|
22883
|
-
[id]="panelId(tab.id)"
|
|
22884
|
-
role="tabpanel"
|
|
22885
|
-
[attr.aria-labelledby]="tabButtonId(tab.id)"
|
|
22886
|
-
[attr.tabindex]="isActive(tab.id) ? 0 : null"
|
|
22887
|
-
>
|
|
22888
|
-
<ng-container [ngTemplateOutlet]="panelTemplate(tab.id) ?? null" />
|
|
22889
|
-
</div>
|
|
22890
|
-
}
|
|
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
|
-
}
|
|
22922
|
-
}
|
|
22923
|
-
</div>
|
|
22924
|
-
</div>
|
|
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: `
|
|
22835
|
+
<div class="jv-tabs">
|
|
22836
|
+
<div class="jv-tabs-header">
|
|
22837
|
+
<div class="jv-tabs-scroll" #tabList role="tablist" aria-orientation="horizontal" (scroll)="updateScrollControls()">
|
|
22838
|
+
@for (tab of tabs(); track tab.id) {
|
|
22839
|
+
<button
|
|
22840
|
+
type="button"
|
|
22841
|
+
class="jv-tab"
|
|
22842
|
+
[class.jv-tab--active]="isActive(tab.id)"
|
|
22843
|
+
[class.jv-tab--disabled]="tab.disabled ?? false"
|
|
22844
|
+
[id]="tabButtonId(tab.id)"
|
|
22845
|
+
[attr.data-jv-tab-id]="tab.id"
|
|
22846
|
+
role="tab"
|
|
22847
|
+
[attr.aria-selected]="isActive(tab.id) ? 'true' : 'false'"
|
|
22848
|
+
[attr.aria-controls]="panelId(tab.id)"
|
|
22849
|
+
[attr.tabindex]="getTabIndex(tab.id, tab.disabled ?? false)"
|
|
22850
|
+
[disabled]="tab.disabled ?? false"
|
|
22851
|
+
(click)="activateTab(tab.id)"
|
|
22852
|
+
(keydown)="handleKeydown($event, tab.id)"
|
|
22853
|
+
>
|
|
22854
|
+
@if (tab.icon) {
|
|
22855
|
+
<jv-icon [name]="tab.icon" [size]="16" />
|
|
22856
|
+
}
|
|
22857
|
+
<span>{{ tab.label }}</span>
|
|
22858
|
+
</button>
|
|
22859
|
+
}
|
|
22860
|
+
</div>
|
|
22861
|
+
|
|
22862
|
+
@if (showScrollLeft() || showScrollRight()) {
|
|
22863
|
+
<div class="jv-tabs-controls" aria-hidden="true">
|
|
22864
|
+
<button type="button" class="jv-tabs-scroll-button" [disabled]="!showScrollLeft()" (click)="scrollTabs(-1)">
|
|
22865
|
+
<jv-icon name="chevron-left" [size]="16" />
|
|
22866
|
+
</button>
|
|
22867
|
+
<button type="button" class="jv-tabs-scroll-button" [disabled]="!showScrollRight()" (click)="scrollTabs(1)">
|
|
22868
|
+
<jv-icon name="chevron-right" [size]="16" />
|
|
22869
|
+
</button>
|
|
22870
|
+
</div>
|
|
22871
|
+
}
|
|
22872
|
+
</div>
|
|
22873
|
+
|
|
22874
|
+
<div class="jv-tabs-panels">
|
|
22875
|
+
@if (keepMounted()) {
|
|
22876
|
+
@for (tab of tabs(); track tab.id) {
|
|
22877
|
+
<div
|
|
22878
|
+
class="jv-tab-panel"
|
|
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'"
|
|
22883
|
+
[id]="panelId(tab.id)"
|
|
22884
|
+
role="tabpanel"
|
|
22885
|
+
[attr.aria-labelledby]="tabButtonId(tab.id)"
|
|
22886
|
+
[attr.tabindex]="isActive(tab.id) ? 0 : null"
|
|
22887
|
+
>
|
|
22888
|
+
<ng-container [ngTemplateOutlet]="panelTemplate(tab.id) ?? null" />
|
|
22889
|
+
</div>
|
|
22890
|
+
}
|
|
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
|
+
}
|
|
22922
|
+
}
|
|
22923
|
+
</div>
|
|
22924
|
+
</div>
|
|
22925
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"] }] });
|
|
22926
22926
|
}
|
|
22927
22927
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTabsComponent, decorators: [{
|
|
22928
22928
|
type: Component,
|
|
22929
|
-
args: [{ selector: 'jv-tabs', standalone: true, imports: [NgTemplateOutlet, JvIconComponent], template: `
|
|
22930
|
-
<div class="jv-tabs">
|
|
22931
|
-
<div class="jv-tabs-header">
|
|
22932
|
-
<div class="jv-tabs-scroll" #tabList role="tablist" aria-orientation="horizontal" (scroll)="updateScrollControls()">
|
|
22933
|
-
@for (tab of tabs(); track tab.id) {
|
|
22934
|
-
<button
|
|
22935
|
-
type="button"
|
|
22936
|
-
class="jv-tab"
|
|
22937
|
-
[class.jv-tab--active]="isActive(tab.id)"
|
|
22938
|
-
[class.jv-tab--disabled]="tab.disabled ?? false"
|
|
22939
|
-
[id]="tabButtonId(tab.id)"
|
|
22940
|
-
[attr.data-jv-tab-id]="tab.id"
|
|
22941
|
-
role="tab"
|
|
22942
|
-
[attr.aria-selected]="isActive(tab.id) ? 'true' : 'false'"
|
|
22943
|
-
[attr.aria-controls]="panelId(tab.id)"
|
|
22944
|
-
[attr.tabindex]="getTabIndex(tab.id, tab.disabled ?? false)"
|
|
22945
|
-
[disabled]="tab.disabled ?? false"
|
|
22946
|
-
(click)="activateTab(tab.id)"
|
|
22947
|
-
(keydown)="handleKeydown($event, tab.id)"
|
|
22948
|
-
>
|
|
22949
|
-
@if (tab.icon) {
|
|
22950
|
-
<jv-icon [name]="tab.icon" [size]="16" />
|
|
22951
|
-
}
|
|
22952
|
-
<span>{{ tab.label }}</span>
|
|
22953
|
-
</button>
|
|
22954
|
-
}
|
|
22955
|
-
</div>
|
|
22956
|
-
|
|
22957
|
-
@if (showScrollLeft() || showScrollRight()) {
|
|
22958
|
-
<div class="jv-tabs-controls" aria-hidden="true">
|
|
22959
|
-
<button type="button" class="jv-tabs-scroll-button" [disabled]="!showScrollLeft()" (click)="scrollTabs(-1)">
|
|
22960
|
-
<jv-icon name="chevron-left" [size]="16" />
|
|
22961
|
-
</button>
|
|
22962
|
-
<button type="button" class="jv-tabs-scroll-button" [disabled]="!showScrollRight()" (click)="scrollTabs(1)">
|
|
22963
|
-
<jv-icon name="chevron-right" [size]="16" />
|
|
22964
|
-
</button>
|
|
22965
|
-
</div>
|
|
22966
|
-
}
|
|
22967
|
-
</div>
|
|
22968
|
-
|
|
22969
|
-
<div class="jv-tabs-panels">
|
|
22970
|
-
@if (keepMounted()) {
|
|
22971
|
-
@for (tab of tabs(); track tab.id) {
|
|
22972
|
-
<div
|
|
22973
|
-
class="jv-tab-panel"
|
|
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'"
|
|
22978
|
-
[id]="panelId(tab.id)"
|
|
22979
|
-
role="tabpanel"
|
|
22980
|
-
[attr.aria-labelledby]="tabButtonId(tab.id)"
|
|
22981
|
-
[attr.tabindex]="isActive(tab.id) ? 0 : null"
|
|
22982
|
-
>
|
|
22983
|
-
<ng-container [ngTemplateOutlet]="panelTemplate(tab.id) ?? null" />
|
|
22984
|
-
</div>
|
|
22985
|
-
}
|
|
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
|
-
}
|
|
23017
|
-
}
|
|
23018
|
-
</div>
|
|
23019
|
-
</div>
|
|
22929
|
+
args: [{ selector: 'jv-tabs', standalone: true, imports: [NgTemplateOutlet, JvIconComponent], template: `
|
|
22930
|
+
<div class="jv-tabs">
|
|
22931
|
+
<div class="jv-tabs-header">
|
|
22932
|
+
<div class="jv-tabs-scroll" #tabList role="tablist" aria-orientation="horizontal" (scroll)="updateScrollControls()">
|
|
22933
|
+
@for (tab of tabs(); track tab.id) {
|
|
22934
|
+
<button
|
|
22935
|
+
type="button"
|
|
22936
|
+
class="jv-tab"
|
|
22937
|
+
[class.jv-tab--active]="isActive(tab.id)"
|
|
22938
|
+
[class.jv-tab--disabled]="tab.disabled ?? false"
|
|
22939
|
+
[id]="tabButtonId(tab.id)"
|
|
22940
|
+
[attr.data-jv-tab-id]="tab.id"
|
|
22941
|
+
role="tab"
|
|
22942
|
+
[attr.aria-selected]="isActive(tab.id) ? 'true' : 'false'"
|
|
22943
|
+
[attr.aria-controls]="panelId(tab.id)"
|
|
22944
|
+
[attr.tabindex]="getTabIndex(tab.id, tab.disabled ?? false)"
|
|
22945
|
+
[disabled]="tab.disabled ?? false"
|
|
22946
|
+
(click)="activateTab(tab.id)"
|
|
22947
|
+
(keydown)="handleKeydown($event, tab.id)"
|
|
22948
|
+
>
|
|
22949
|
+
@if (tab.icon) {
|
|
22950
|
+
<jv-icon [name]="tab.icon" [size]="16" />
|
|
22951
|
+
}
|
|
22952
|
+
<span>{{ tab.label }}</span>
|
|
22953
|
+
</button>
|
|
22954
|
+
}
|
|
22955
|
+
</div>
|
|
22956
|
+
|
|
22957
|
+
@if (showScrollLeft() || showScrollRight()) {
|
|
22958
|
+
<div class="jv-tabs-controls" aria-hidden="true">
|
|
22959
|
+
<button type="button" class="jv-tabs-scroll-button" [disabled]="!showScrollLeft()" (click)="scrollTabs(-1)">
|
|
22960
|
+
<jv-icon name="chevron-left" [size]="16" />
|
|
22961
|
+
</button>
|
|
22962
|
+
<button type="button" class="jv-tabs-scroll-button" [disabled]="!showScrollRight()" (click)="scrollTabs(1)">
|
|
22963
|
+
<jv-icon name="chevron-right" [size]="16" />
|
|
22964
|
+
</button>
|
|
22965
|
+
</div>
|
|
22966
|
+
}
|
|
22967
|
+
</div>
|
|
22968
|
+
|
|
22969
|
+
<div class="jv-tabs-panels">
|
|
22970
|
+
@if (keepMounted()) {
|
|
22971
|
+
@for (tab of tabs(); track tab.id) {
|
|
22972
|
+
<div
|
|
22973
|
+
class="jv-tab-panel"
|
|
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'"
|
|
22978
|
+
[id]="panelId(tab.id)"
|
|
22979
|
+
role="tabpanel"
|
|
22980
|
+
[attr.aria-labelledby]="tabButtonId(tab.id)"
|
|
22981
|
+
[attr.tabindex]="isActive(tab.id) ? 0 : null"
|
|
22982
|
+
>
|
|
22983
|
+
<ng-container [ngTemplateOutlet]="panelTemplate(tab.id) ?? null" />
|
|
22984
|
+
</div>
|
|
22985
|
+
}
|
|
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
|
+
}
|
|
23017
|
+
}
|
|
23018
|
+
</div>
|
|
23019
|
+
</div>
|
|
23020
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
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: [{
|
|
23022
23022
|
type: HostListener,
|
|
@@ -23212,10 +23212,286 @@ const JV_GRID_DEFAULT_OPTIONS = {
|
|
|
23212
23212
|
virtualScroll: false,
|
|
23213
23213
|
virtualScrollRowHeight: 48,
|
|
23214
23214
|
exportable: false,
|
|
23215
|
+
exportFileName: '',
|
|
23215
23216
|
columnFilters: false,
|
|
23216
23217
|
rowDoubleClick: false,
|
|
23217
23218
|
};
|
|
23218
23219
|
|
|
23220
|
+
const MAIN_NS = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main';
|
|
23221
|
+
const REL_NS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
|
|
23222
|
+
const PKG_REL_NS = 'http://schemas.openxmlformats.org/package/2006/relationships';
|
|
23223
|
+
const CONTENT_TYPES_NS = 'http://schemas.openxmlformats.org/package/2006/content-types';
|
|
23224
|
+
const XML_DECL = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
|
|
23225
|
+
/**
|
|
23226
|
+
* Builds a real Office Open XML (.xlsx) spreadsheet as a Blob.
|
|
23227
|
+
*
|
|
23228
|
+
* The package is assembled in memory with the ZIP "store" method (no
|
|
23229
|
+
* compression) so no third-party dependency is required. All cell text is
|
|
23230
|
+
* written as `inlineStr`, which keeps every character (including UTF-8
|
|
23231
|
+
* accented glyphs) intact and is understood by Microsoft Excel and Apple
|
|
23232
|
+
* Numbers alike.
|
|
23233
|
+
*/
|
|
23234
|
+
function buildXlsxBlob(sheets) {
|
|
23235
|
+
return new Blob([buildXlsxBuffer(sheets)], {
|
|
23236
|
+
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
23237
|
+
});
|
|
23238
|
+
}
|
|
23239
|
+
/**
|
|
23240
|
+
* Returns the raw bytes of a minimal valid .xlsx package. Exposed separately
|
|
23241
|
+
* from the Blob wrapper to make the package easy to assert on in tests.
|
|
23242
|
+
*/
|
|
23243
|
+
function buildXlsxBuffer(sheets) {
|
|
23244
|
+
const parts = [];
|
|
23245
|
+
const sheetXml = sheets.map((sheet, index) => buildSheetXml(sheet, index));
|
|
23246
|
+
const sheetNames = sheets.length > 0 ? sheets.map((s) => s.name) : ['Sheet1'];
|
|
23247
|
+
parts.push({ name: '[Content_Types].xml', data: utf8(buildContentTypes(sheets.length)) });
|
|
23248
|
+
parts.push({ name: '_rels/.rels', data: utf8(buildRootRels()) });
|
|
23249
|
+
parts.push({ name: 'xl/workbook.xml', data: utf8(buildWorkbook(sheetNames)) });
|
|
23250
|
+
parts.push({ name: 'xl/_rels/workbook.xml.rels', data: utf8(buildWorkbookRels(sheets.length)) });
|
|
23251
|
+
parts.push({ name: 'xl/styles.xml', data: utf8(buildStyles()) });
|
|
23252
|
+
for (let i = 0; i < sheetXml.length; i++) {
|
|
23253
|
+
parts.push({ name: `xl/worksheets/sheet${i + 1}.xml`, data: utf8(sheetXml[i]) });
|
|
23254
|
+
}
|
|
23255
|
+
return toZip(parts);
|
|
23256
|
+
}
|
|
23257
|
+
function buildContentTypes(sheetCount) {
|
|
23258
|
+
let xml = XML_DECL;
|
|
23259
|
+
xml += `<Types xmlns="${CONTENT_TYPES_NS}">`;
|
|
23260
|
+
xml += `<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>`;
|
|
23261
|
+
xml += `<Default Extension="xml" ContentType="application/xml"/>`;
|
|
23262
|
+
xml += `<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>`;
|
|
23263
|
+
for (let i = 0; i < sheetCount; i++) {
|
|
23264
|
+
xml += `<Override PartName="/xl/worksheets/sheet${i + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>`;
|
|
23265
|
+
}
|
|
23266
|
+
xml += `<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>`;
|
|
23267
|
+
xml += `</Types>`;
|
|
23268
|
+
return xml;
|
|
23269
|
+
}
|
|
23270
|
+
function buildRootRels() {
|
|
23271
|
+
return XML_DECL +
|
|
23272
|
+
`<Relationships xmlns="${PKG_REL_NS}">` +
|
|
23273
|
+
`<Relationship Id="rId1" Type="${REL_NS}/officeDocument" Target="xl/workbook.xml"/>` +
|
|
23274
|
+
`</Relationships>`;
|
|
23275
|
+
}
|
|
23276
|
+
function buildWorkbook(sheetNames) {
|
|
23277
|
+
let xml = XML_DECL;
|
|
23278
|
+
xml += `<workbook xmlns="${MAIN_NS}" xmlns:r="${REL_NS}">`;
|
|
23279
|
+
xml += `<sheets>`;
|
|
23280
|
+
for (let i = 0; i < sheetNames.length; i++) {
|
|
23281
|
+
const name = sanitizeSheetName(sheetNames[i]) || `Sheet${i + 1}`;
|
|
23282
|
+
xml += `<sheet name="${escapeXml(name)}" sheetId="${i + 1}" r:id="rId${i + 1}"/>`;
|
|
23283
|
+
}
|
|
23284
|
+
xml += `</sheets></workbook>`;
|
|
23285
|
+
return xml;
|
|
23286
|
+
}
|
|
23287
|
+
function buildWorkbookRels(sheetCount) {
|
|
23288
|
+
let xml = XML_DECL;
|
|
23289
|
+
xml += `<Relationships xmlns="${PKG_REL_NS}">`;
|
|
23290
|
+
for (let i = 0; i < sheetCount; i++) {
|
|
23291
|
+
xml += `<Relationship Id="rId${i + 1}" Type="${REL_NS}/worksheet" Target="worksheets/sheet${i + 1}.xml"/>`;
|
|
23292
|
+
}
|
|
23293
|
+
xml += `<Relationship Id="rId${sheetCount + 1}" Type="${REL_NS}/styles" Target="styles.xml"/>`;
|
|
23294
|
+
xml += `</Relationships>`;
|
|
23295
|
+
return xml;
|
|
23296
|
+
}
|
|
23297
|
+
function buildSheetXml(sheet, index) {
|
|
23298
|
+
const rows = sheet.rows;
|
|
23299
|
+
const rowCount = rows.length;
|
|
23300
|
+
const colCount = rows.reduce((max, row) => Math.max(max, row.length), 0);
|
|
23301
|
+
const dimension = rowCount === 0 || colCount === 0 ? 'A1' : `A1:${columnName(colCount - 1)}${rowCount}`;
|
|
23302
|
+
let xml = XML_DECL;
|
|
23303
|
+
xml += `<worksheet xmlns="${MAIN_NS}">`;
|
|
23304
|
+
xml += `<dimension ref="${dimension}"/>`;
|
|
23305
|
+
xml += `<sheetViews><sheetView workbookViewId="0"/></sheetViews>`;
|
|
23306
|
+
xml += `<sheetFormatPr defaultRowHeight="15"/>`;
|
|
23307
|
+
xml += `<sheetData>`;
|
|
23308
|
+
for (let r = 0; r < rowCount; r++) {
|
|
23309
|
+
const row = rows[r];
|
|
23310
|
+
xml += `<row r="${r + 1}">`;
|
|
23311
|
+
for (let c = 0; c < row.length; c++) {
|
|
23312
|
+
xml += `<c r="${columnName(c)}${r + 1}" t="inlineStr"><is><t xml:space="preserve">${escapeXml(String(row[c]))}</t></is></c>`;
|
|
23313
|
+
}
|
|
23314
|
+
xml += `</row>`;
|
|
23315
|
+
}
|
|
23316
|
+
xml += `</sheetData></worksheet>`;
|
|
23317
|
+
void index;
|
|
23318
|
+
return xml;
|
|
23319
|
+
}
|
|
23320
|
+
function buildStyles() {
|
|
23321
|
+
return XML_DECL +
|
|
23322
|
+
`<styleSheet xmlns="${MAIN_NS}">` +
|
|
23323
|
+
`<fonts count="1"><font><sz val="11"/><name val="Calibri"/></font></fonts>` +
|
|
23324
|
+
`<fills count="1"><fill><patternFill patternType="none"/></fill></fills>` +
|
|
23325
|
+
`<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>` +
|
|
23326
|
+
`<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>` +
|
|
23327
|
+
`<cellXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/></cellXfs>` +
|
|
23328
|
+
`<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>` +
|
|
23329
|
+
`</styleSheet>`;
|
|
23330
|
+
}
|
|
23331
|
+
function columnName(index) {
|
|
23332
|
+
let value = '';
|
|
23333
|
+
let n = index;
|
|
23334
|
+
while (n >= 0) {
|
|
23335
|
+
value = String.fromCharCode((n % 26) + 65) + value;
|
|
23336
|
+
n = Math.floor(n / 26) - 1;
|
|
23337
|
+
}
|
|
23338
|
+
return value;
|
|
23339
|
+
}
|
|
23340
|
+
function sanitizeSheetName(name) {
|
|
23341
|
+
return name.replace(/[\[\]:*?/\\]/g, '').slice(0, 31);
|
|
23342
|
+
}
|
|
23343
|
+
function escapeXml(value) {
|
|
23344
|
+
return value
|
|
23345
|
+
.replace(/&/g, '&')
|
|
23346
|
+
.replace(/</g, '<')
|
|
23347
|
+
.replace(/>/g, '>')
|
|
23348
|
+
.replace(/"/g, '"')
|
|
23349
|
+
.replace(/'/g, ''');
|
|
23350
|
+
}
|
|
23351
|
+
function utf8(value) {
|
|
23352
|
+
return new TextEncoder().encode(value);
|
|
23353
|
+
}
|
|
23354
|
+
// ---------------------------------------------------------------------------
|
|
23355
|
+
// Minimal ZIP writer ("store" method, no compression)
|
|
23356
|
+
// ---------------------------------------------------------------------------
|
|
23357
|
+
const CRC_TABLE = (() => {
|
|
23358
|
+
const table = new Array(256);
|
|
23359
|
+
for (let n = 0; n < 256; n++) {
|
|
23360
|
+
let c = n;
|
|
23361
|
+
for (let k = 0; k < 8; k++) {
|
|
23362
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
23363
|
+
}
|
|
23364
|
+
table[n] = c >>> 0;
|
|
23365
|
+
}
|
|
23366
|
+
return table;
|
|
23367
|
+
})();
|
|
23368
|
+
function crc32(bytes) {
|
|
23369
|
+
let crc = 0xffffffff;
|
|
23370
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
23371
|
+
crc = CRC_TABLE[(crc ^ bytes[i]) & 0xff] ^ (crc >>> 8);
|
|
23372
|
+
}
|
|
23373
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
23374
|
+
}
|
|
23375
|
+
function toZip(files) {
|
|
23376
|
+
const encoder = new TextEncoder();
|
|
23377
|
+
const chunks = [];
|
|
23378
|
+
const centralDirectory = new Uint8Array(0);
|
|
23379
|
+
const centralRecords = [];
|
|
23380
|
+
let offset = 0;
|
|
23381
|
+
for (const file of files) {
|
|
23382
|
+
const nameBytes = encoder.encode(file.name);
|
|
23383
|
+
const crc = crc32(file.data);
|
|
23384
|
+
// Local file header
|
|
23385
|
+
const local = new DataView(new ArrayBuffer(30));
|
|
23386
|
+
local.setUint32(0, 0x04034b50, true);
|
|
23387
|
+
local.setUint16(4, 20, true);
|
|
23388
|
+
local.setUint16(6, 0x0800, true);
|
|
23389
|
+
local.setUint16(8, 0, true); // store (no compression)
|
|
23390
|
+
local.setUint16(10, 0, true);
|
|
23391
|
+
local.setUint16(12, 0, true);
|
|
23392
|
+
local.setUint32(14, crc, true);
|
|
23393
|
+
local.setUint32(18, file.data.length, true);
|
|
23394
|
+
local.setUint32(22, file.data.length, true);
|
|
23395
|
+
local.setUint16(26, nameBytes.length, true);
|
|
23396
|
+
local.setUint16(28, 0, true);
|
|
23397
|
+
chunks.push(new Uint8Array(local.buffer), nameBytes, file.data);
|
|
23398
|
+
// Central directory header
|
|
23399
|
+
const central = new DataView(new ArrayBuffer(46));
|
|
23400
|
+
central.setUint32(0, 0x02014b50, true);
|
|
23401
|
+
central.setUint16(4, 20, true); // version made by
|
|
23402
|
+
central.setUint16(6, 20, true); // version needed
|
|
23403
|
+
central.setUint16(8, 0x0800, true); // UTF-8 filename flag
|
|
23404
|
+
central.setUint16(10, 0, true); // store (no compression)
|
|
23405
|
+
central.setUint16(12, 0, true); // mod time
|
|
23406
|
+
central.setUint16(14, 0, true); // mod date
|
|
23407
|
+
central.setUint32(16, crc, true);
|
|
23408
|
+
central.setUint32(20, file.data.length, true); // compressed size
|
|
23409
|
+
central.setUint32(24, file.data.length, true); // uncompressed size
|
|
23410
|
+
central.setUint16(28, nameBytes.length, true);
|
|
23411
|
+
central.setUint16(30, 0, true); // extra field length
|
|
23412
|
+
central.setUint16(32, 0, true); // comment length
|
|
23413
|
+
central.setUint16(34, 0, true); // disk number start
|
|
23414
|
+
central.setUint16(36, 0, true); // internal file attributes
|
|
23415
|
+
central.setUint32(38, 0, true); // external file attributes
|
|
23416
|
+
central.setUint32(42, offset, true); // local header offset
|
|
23417
|
+
centralRecords.push(new Uint8Array(central.buffer), nameBytes);
|
|
23418
|
+
offset += 30 + nameBytes.length + file.data.length;
|
|
23419
|
+
}
|
|
23420
|
+
const centralSize = centralRecords.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
23421
|
+
const eocd = new DataView(new ArrayBuffer(22));
|
|
23422
|
+
eocd.setUint32(0, 0x06054b50, true);
|
|
23423
|
+
eocd.setUint16(4, 0, true);
|
|
23424
|
+
eocd.setUint16(6, 0, true);
|
|
23425
|
+
eocd.setUint16(8, files.length, true);
|
|
23426
|
+
eocd.setUint16(10, files.length, true);
|
|
23427
|
+
eocd.setUint32(12, centralSize, true);
|
|
23428
|
+
eocd.setUint32(16, offset, true);
|
|
23429
|
+
eocd.setUint16(20, 0, true);
|
|
23430
|
+
const result = new Uint8Array(offset + centralSize + 22);
|
|
23431
|
+
let pointer = 0;
|
|
23432
|
+
for (const chunk of chunks) {
|
|
23433
|
+
result.set(chunk, pointer);
|
|
23434
|
+
pointer += chunk.length;
|
|
23435
|
+
}
|
|
23436
|
+
for (const chunk of centralRecords) {
|
|
23437
|
+
result.set(chunk, pointer);
|
|
23438
|
+
pointer += chunk.length;
|
|
23439
|
+
}
|
|
23440
|
+
result.set(new Uint8Array(eocd.buffer), pointer);
|
|
23441
|
+
void centralDirectory;
|
|
23442
|
+
return result;
|
|
23443
|
+
}
|
|
23444
|
+
|
|
23445
|
+
/**
|
|
23446
|
+
* Triggers a browser download for the given Blob.
|
|
23447
|
+
*/
|
|
23448
|
+
function downloadBlob(blob, filename) {
|
|
23449
|
+
const url = URL.createObjectURL(blob);
|
|
23450
|
+
const a = document.createElement('a');
|
|
23451
|
+
a.href = url;
|
|
23452
|
+
a.download = filename;
|
|
23453
|
+
a.click();
|
|
23454
|
+
URL.revokeObjectURL(url);
|
|
23455
|
+
}
|
|
23456
|
+
const CSV_BOM = '\uFEFF';
|
|
23457
|
+
/**
|
|
23458
|
+
* Builds the raw CSV text (including the UTF-8 BOM) for the given header and
|
|
23459
|
+
* rows. Exposed separately from the downloader to keep it easy to test.
|
|
23460
|
+
*/
|
|
23461
|
+
function buildCsv(header, rows) {
|
|
23462
|
+
const escapeCell = (value) => {
|
|
23463
|
+
const text = value == null ? '' : String(value);
|
|
23464
|
+
return `"${text.replace(/"/g, '""')}"`;
|
|
23465
|
+
};
|
|
23466
|
+
const lines = [];
|
|
23467
|
+
lines.push(header.map(escapeCell).join(','));
|
|
23468
|
+
for (const row of rows) {
|
|
23469
|
+
lines.push(row.map(escapeCell).join(','));
|
|
23470
|
+
}
|
|
23471
|
+
return CSV_BOM + lines.join('\r\n');
|
|
23472
|
+
}
|
|
23473
|
+
/**
|
|
23474
|
+
* Serializes a grid/table to CSV and downloads it.
|
|
23475
|
+
*
|
|
23476
|
+
* A UTF-8 BOM is prepended so Microsoft Excel recognises the file as UTF-8
|
|
23477
|
+
* and renders accented characters correctly.
|
|
23478
|
+
*/
|
|
23479
|
+
function exportGridToCsv(header, rows, filename = 'export.csv') {
|
|
23480
|
+
const csv = buildCsv(header, rows);
|
|
23481
|
+
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
|
|
23482
|
+
downloadBlob(blob, filename);
|
|
23483
|
+
}
|
|
23484
|
+
/**
|
|
23485
|
+
* Serializes a grid/table to a real Open XML (.xlsx) spreadsheet and downloads it.
|
|
23486
|
+
*
|
|
23487
|
+
* Generates an actual xlsx package (not an HTML file with an .xls extension),
|
|
23488
|
+
* preserving UTF-8 characters. Comma-separated columns are exported as-is.
|
|
23489
|
+
*/
|
|
23490
|
+
function exportGridToExcel(header, rows, filename = 'export.xlsx') {
|
|
23491
|
+
const blob = buildXlsxBlob([{ name: 'Sheet1', rows: [header, ...rows] }]);
|
|
23492
|
+
downloadBlob(blob, filename);
|
|
23493
|
+
}
|
|
23494
|
+
|
|
23219
23495
|
let gridIdSequence = 0;
|
|
23220
23496
|
class JvGridComponent {
|
|
23221
23497
|
gridId = `jv-grid-${++gridIdSequence}`;
|
|
@@ -23727,41 +24003,31 @@ class JvGridComponent {
|
|
|
23727
24003
|
}
|
|
23728
24004
|
// Export
|
|
23729
24005
|
exportCsv() {
|
|
23730
|
-
const
|
|
23731
|
-
|
|
23732
|
-
const headerRow = cols.map(c => `"${c.header}"`).join(',');
|
|
23733
|
-
const dataRows = allData.map(row => cols.map(col => {
|
|
23734
|
-
const val = row[col.key];
|
|
23735
|
-
if (val == null)
|
|
23736
|
-
return '';
|
|
23737
|
-
return `"${this.getExportValue(val, col.column).replace(/"/g, '""')}"`;
|
|
23738
|
-
}).join(','));
|
|
23739
|
-
const csv = [headerRow, ...dataRows].join('\r\n');
|
|
23740
|
-
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
|
|
23741
|
-
const url = URL.createObjectURL(blob);
|
|
23742
|
-
const a = document.createElement('a');
|
|
23743
|
-
a.href = url;
|
|
23744
|
-
a.download = 'grid-export.csv';
|
|
23745
|
-
a.click();
|
|
23746
|
-
URL.revokeObjectURL(url);
|
|
24006
|
+
const { header, rows } = this.buildExportMatrix();
|
|
24007
|
+
exportGridToCsv(header, rows, this.resolveExportFileName('csv'));
|
|
23747
24008
|
}
|
|
23748
24009
|
exportExcel() {
|
|
24010
|
+
const { header, rows } = this.buildExportMatrix();
|
|
24011
|
+
exportGridToExcel(header, rows, this.resolveExportFileName('xlsx'));
|
|
24012
|
+
}
|
|
24013
|
+
resolveExportFileName(extension) {
|
|
24014
|
+
const configuredName = this.effectiveOptions().exportFileName?.trim();
|
|
24015
|
+
const fallbackName = `grid-export.${extension}`;
|
|
24016
|
+
if (!configuredName) {
|
|
24017
|
+
return fallbackName;
|
|
24018
|
+
}
|
|
24019
|
+
if (configuredName.toLowerCase().endsWith(`.${extension}`)) {
|
|
24020
|
+
return configuredName;
|
|
24021
|
+
}
|
|
24022
|
+
return configuredName.replace(/\.(csv|xlsx)$/i, '') + `.${extension}`;
|
|
24023
|
+
}
|
|
24024
|
+
buildExportMatrix() {
|
|
23749
24025
|
const cols = this.visibleColumns().map(c => ({ key: this.colKey(c), header: c.header, column: c }));
|
|
23750
24026
|
const allData = this.effectiveOptions().serverSide ? this.data() : this.sortedData();
|
|
23751
|
-
|
|
23752
|
-
|
|
23753
|
-
|
|
23754
|
-
|
|
23755
|
-
html += '<tr>' + cols.map(col => `<td>${this.getExportValue(row[col.key], col.column)}</td>`).join('') + '</tr>';
|
|
23756
|
-
}
|
|
23757
|
-
html += '</tbody></table>';
|
|
23758
|
-
const blob = new Blob([html], { type: 'application/vnd.ms-excel' });
|
|
23759
|
-
const url = URL.createObjectURL(blob);
|
|
23760
|
-
const a = document.createElement('a');
|
|
23761
|
-
a.href = url;
|
|
23762
|
-
a.download = 'grid-export.xls';
|
|
23763
|
-
a.click();
|
|
23764
|
-
URL.revokeObjectURL(url);
|
|
24027
|
+
return {
|
|
24028
|
+
header: cols.map(c => c.header),
|
|
24029
|
+
rows: allData.map(row => cols.map(col => this.getExportValue(row[col.key], col.column))),
|
|
24030
|
+
};
|
|
23765
24031
|
}
|
|
23766
24032
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
23767
24033
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvGridComponent, isStandalone: true, selector: "jv-grid", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowClick: "rowClick", rowDoubleClick: "rowDoubleClick", actionClick: "actionClick", selectionChange: "selectionChange", pageChange: "pageChange", searchChange: "searchChange", sortChange: "sortChange", columnFilter: "columnFilter", columnResize: "columnResize", columnReorder: "columnReorder", rowEdit: "rowEdit" }, ngImport: i0, template: `
|