@m1z23r/ngx-ui 1.1.57 → 1.1.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/m1z23r-ngx-ui.mjs +883 -2
- package/fesm2022/m1z23r-ngx-ui.mjs.map +1 -1
- package/package.json +3 -2
- package/styles/_variables.scss +30 -0
- package/types/m1z23r-ngx-ui.d.ts +303 -12
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, PLATFORM_ID, signal, Injectable, computed, InjectionToken, ApplicationRef, EnvironmentInjector, createComponent, Injector, input,
|
|
2
|
+
import { inject, PLATFORM_ID, signal, Injectable, computed, InjectionToken, ApplicationRef, EnvironmentInjector, createComponent, Injector, input, model, ChangeDetectionStrategy, Component, viewChild, afterNextRender, HostListener, output, ElementRef, effect, Directive, Pipe, contentChildren, TemplateRef, contentChild, ViewChild, afterRenderEffect, DestroyRef } from '@angular/core';
|
|
3
3
|
import { isPlatformBrowser, DOCUMENT, NgTemplateOutlet, NgComponentOutlet, DecimalPipe } from '@angular/common';
|
|
4
4
|
import * as i1 from '@angular/forms';
|
|
5
5
|
import { FormsModule } from '@angular/forms';
|
|
6
|
+
import { RouterLink } from '@angular/router';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Collection of built-in validators for form inputs
|
|
@@ -426,6 +427,207 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
|
|
|
426
427
|
args: [{ providedIn: 'root' }]
|
|
427
428
|
}] });
|
|
428
429
|
|
|
430
|
+
class CarouselComponent {
|
|
431
|
+
images = input.required(...(ngDevMode ? [{ debugName: "images" }] : []));
|
|
432
|
+
startIndex = input(0, ...(ngDevMode ? [{ debugName: "startIndex" }] : []));
|
|
433
|
+
loop = input(true, ...(ngDevMode ? [{ debugName: "loop" }] : []));
|
|
434
|
+
showCounter = input(true, ...(ngDevMode ? [{ debugName: "showCounter" }] : []));
|
|
435
|
+
ariaLabel = input('Image carousel', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
436
|
+
index = model(...(ngDevMode ? [undefined, { debugName: "index" }] : []));
|
|
437
|
+
/** Horizontal drag offset in px while a swipe is in progress */
|
|
438
|
+
dragOffset = signal(0, ...(ngDevMode ? [{ debugName: "dragOffset" }] : []));
|
|
439
|
+
dragging = signal(false, ...(ngDevMode ? [{ debugName: "dragging" }] : []));
|
|
440
|
+
pointerId = null;
|
|
441
|
+
dragStartX = 0;
|
|
442
|
+
dragStartY = 0;
|
|
443
|
+
dragAxis = null;
|
|
444
|
+
currentIndex = computed(() => {
|
|
445
|
+
const count = this.images().length;
|
|
446
|
+
if (count === 0)
|
|
447
|
+
return 0;
|
|
448
|
+
const index = this.index() ?? this.startIndex();
|
|
449
|
+
return Math.max(0, Math.min(count - 1, index));
|
|
450
|
+
}, ...(ngDevMode ? [{ debugName: "currentIndex" }] : []));
|
|
451
|
+
hasPrev = computed(() => {
|
|
452
|
+
return this.loop() ? this.images().length > 1 : this.currentIndex() > 0;
|
|
453
|
+
}, ...(ngDevMode ? [{ debugName: "hasPrev" }] : []));
|
|
454
|
+
hasNext = computed(() => {
|
|
455
|
+
return this.loop()
|
|
456
|
+
? this.images().length > 1
|
|
457
|
+
: this.currentIndex() < this.images().length - 1;
|
|
458
|
+
}, ...(ngDevMode ? [{ debugName: "hasNext" }] : []));
|
|
459
|
+
prev() {
|
|
460
|
+
if (!this.hasPrev())
|
|
461
|
+
return;
|
|
462
|
+
const count = this.images().length;
|
|
463
|
+
this.index.set((this.currentIndex() - 1 + count) % count);
|
|
464
|
+
}
|
|
465
|
+
next() {
|
|
466
|
+
if (!this.hasNext())
|
|
467
|
+
return;
|
|
468
|
+
const count = this.images().length;
|
|
469
|
+
this.index.set((this.currentIndex() + 1) % count);
|
|
470
|
+
}
|
|
471
|
+
handleKeyDown(event) {
|
|
472
|
+
switch (event.key) {
|
|
473
|
+
case 'ArrowLeft':
|
|
474
|
+
event.preventDefault();
|
|
475
|
+
this.prev();
|
|
476
|
+
break;
|
|
477
|
+
case 'ArrowRight':
|
|
478
|
+
event.preventDefault();
|
|
479
|
+
this.next();
|
|
480
|
+
break;
|
|
481
|
+
case 'Home':
|
|
482
|
+
event.preventDefault();
|
|
483
|
+
this.index.set(0);
|
|
484
|
+
break;
|
|
485
|
+
case 'End':
|
|
486
|
+
event.preventDefault();
|
|
487
|
+
this.index.set(this.images().length - 1);
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
onPointerDown(event) {
|
|
492
|
+
if (this.images().length < 2)
|
|
493
|
+
return;
|
|
494
|
+
this.pointerId = event.pointerId;
|
|
495
|
+
this.dragStartX = event.clientX;
|
|
496
|
+
this.dragStartY = event.clientY;
|
|
497
|
+
this.dragAxis = null;
|
|
498
|
+
this.dragging.set(true);
|
|
499
|
+
}
|
|
500
|
+
onPointerMove(event) {
|
|
501
|
+
if (this.pointerId !== event.pointerId)
|
|
502
|
+
return;
|
|
503
|
+
const deltaX = event.clientX - this.dragStartX;
|
|
504
|
+
const deltaY = event.clientY - this.dragStartY;
|
|
505
|
+
// Lock the gesture axis once movement is unambiguous, so vertical
|
|
506
|
+
// page scrolling on touch devices is not hijacked
|
|
507
|
+
if (this.dragAxis === null && (Math.abs(deltaX) > 8 || Math.abs(deltaY) > 8)) {
|
|
508
|
+
this.dragAxis = Math.abs(deltaX) > Math.abs(deltaY) ? 'x' : 'y';
|
|
509
|
+
if (this.dragAxis === 'x') {
|
|
510
|
+
event.target.setPointerCapture?.(event.pointerId);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
if (this.dragAxis === 'x') {
|
|
514
|
+
this.dragOffset.set(deltaX);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
onPointerUp(event) {
|
|
518
|
+
if (this.pointerId !== event.pointerId)
|
|
519
|
+
return;
|
|
520
|
+
const offset = this.dragOffset();
|
|
521
|
+
const threshold = 48;
|
|
522
|
+
if (this.dragAxis === 'x') {
|
|
523
|
+
if (offset <= -threshold) {
|
|
524
|
+
this.next();
|
|
525
|
+
}
|
|
526
|
+
else if (offset >= threshold) {
|
|
527
|
+
this.prev();
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
this.pointerId = null;
|
|
531
|
+
this.dragAxis = null;
|
|
532
|
+
this.dragOffset.set(0);
|
|
533
|
+
this.dragging.set(false);
|
|
534
|
+
}
|
|
535
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
536
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: CarouselComponent, isStandalone: true, selector: "ui-carousel", inputs: { images: { classPropertyName: "images", publicName: "images", isSignal: true, isRequired: true, transformFunction: null }, startIndex: { classPropertyName: "startIndex", publicName: "startIndex", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", isSignal: true, isRequired: false, transformFunction: null }, showCounter: { classPropertyName: "showCounter", publicName: "showCounter", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, index: { classPropertyName: "index", publicName: "index", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { index: "indexChange" }, ngImport: i0, template: "<div\n class=\"ui-carousel\"\n role=\"group\"\n aria-roledescription=\"carousel\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n <div\n class=\"ui-carousel__viewport\"\n tabindex=\"0\"\n (keydown)=\"handleKeyDown($event)\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n >\n <div\n class=\"ui-carousel__track\"\n [class.ui-carousel__track--dragging]=\"dragging()\"\n [style.transform]=\"'translateX(calc(-' + currentIndex() * 100 + '% + ' + dragOffset() + 'px))'\"\n >\n @for (image of images(); track image.src; let i = $index) {\n <div\n class=\"ui-carousel__slide\"\n role=\"group\"\n aria-roledescription=\"slide\"\n [attr.aria-label]=\"(i + 1) + ' of ' + images().length\"\n [attr.aria-hidden]=\"i !== currentIndex()\"\n >\n <img\n class=\"ui-carousel__image\"\n [src]=\"image.src\"\n [alt]=\"image.alt || ''\"\n draggable=\"false\"\n [attr.loading]=\"i === currentIndex() ? null : 'lazy'\"\n />\n </div>\n }\n </div>\n </div>\n\n @if (hasPrev()) {\n <button\n type=\"button\"\n class=\"ui-carousel__arrow ui-carousel__arrow--prev\"\n aria-label=\"Previous image\"\n (click)=\"prev()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"/>\n </svg>\n </button>\n }\n @if (hasNext()) {\n <button\n type=\"button\"\n class=\"ui-carousel__arrow ui-carousel__arrow--next\"\n aria-label=\"Next image\"\n (click)=\"next()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 6l6 6-6 6\"/>\n </svg>\n </button>\n }\n\n @if (showCounter() && images().length > 0) {\n <span class=\"ui-carousel__counter\" aria-live=\"polite\">\n {{ currentIndex() + 1 }}/{{ images().length }}\n </span>\n }\n</div>\n", styles: [":host{display:block}.ui-carousel{position:relative;overflow:hidden;height:100%;border-radius:var(--ui-radius-lg);background-color:var(--ui-bg-tertiary)}.ui-carousel__viewport{overflow:hidden;touch-action:pan-y;height:100%}.ui-carousel__viewport:focus-visible{outline:2px solid var(--ui-primary);outline-offset:-2px}.ui-carousel__track{display:flex;height:100%;transition:transform var(--ui-transition-normal)}.ui-carousel__track--dragging{transition:none}.ui-carousel__slide{flex:0 0 100%;min-width:0;display:flex;align-items:center;justify-content:center}.ui-carousel__image{max-width:100%;max-height:100%;width:100%;height:100%;object-fit:cover;-webkit-user-select:none;user-select:none}.ui-carousel__arrow{position:absolute;top:50%;transform:translateY(-50%);display:flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:none;border-radius:50%;background-color:var(--ui-carousel-control-bg);color:var(--ui-carousel-control-text);cursor:pointer;opacity:0;transition:opacity var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-carousel__arrow--prev{left:var(--ui-spacing-sm)}.ui-carousel__arrow--next{right:var(--ui-spacing-sm)}.ui-carousel:hover .ui-carousel__arrow,.ui-carousel__arrow:focus-visible{opacity:1}@media(hover:none){.ui-carousel__arrow{opacity:1}}.ui-carousel__arrow:hover{background-color:color-mix(in srgb,var(--ui-carousel-control-bg) 80%,#000000)}.ui-carousel__arrow:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-carousel__counter{position:absolute;right:var(--ui-spacing-sm);bottom:var(--ui-spacing-sm);padding:2px var(--ui-spacing-sm);border-radius:var(--ui-radius-sm);background-color:var(--ui-carousel-counter-bg);color:var(--ui-carousel-control-text);font-size:var(--ui-font-xs);font-weight:500;pointer-events:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
537
|
+
}
|
|
538
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CarouselComponent, decorators: [{
|
|
539
|
+
type: Component,
|
|
540
|
+
args: [{ selector: 'ui-carousel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"ui-carousel\"\n role=\"group\"\n aria-roledescription=\"carousel\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n <div\n class=\"ui-carousel__viewport\"\n tabindex=\"0\"\n (keydown)=\"handleKeyDown($event)\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n >\n <div\n class=\"ui-carousel__track\"\n [class.ui-carousel__track--dragging]=\"dragging()\"\n [style.transform]=\"'translateX(calc(-' + currentIndex() * 100 + '% + ' + dragOffset() + 'px))'\"\n >\n @for (image of images(); track image.src; let i = $index) {\n <div\n class=\"ui-carousel__slide\"\n role=\"group\"\n aria-roledescription=\"slide\"\n [attr.aria-label]=\"(i + 1) + ' of ' + images().length\"\n [attr.aria-hidden]=\"i !== currentIndex()\"\n >\n <img\n class=\"ui-carousel__image\"\n [src]=\"image.src\"\n [alt]=\"image.alt || ''\"\n draggable=\"false\"\n [attr.loading]=\"i === currentIndex() ? null : 'lazy'\"\n />\n </div>\n }\n </div>\n </div>\n\n @if (hasPrev()) {\n <button\n type=\"button\"\n class=\"ui-carousel__arrow ui-carousel__arrow--prev\"\n aria-label=\"Previous image\"\n (click)=\"prev()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"/>\n </svg>\n </button>\n }\n @if (hasNext()) {\n <button\n type=\"button\"\n class=\"ui-carousel__arrow ui-carousel__arrow--next\"\n aria-label=\"Next image\"\n (click)=\"next()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 6l6 6-6 6\"/>\n </svg>\n </button>\n }\n\n @if (showCounter() && images().length > 0) {\n <span class=\"ui-carousel__counter\" aria-live=\"polite\">\n {{ currentIndex() + 1 }}/{{ images().length }}\n </span>\n }\n</div>\n", styles: [":host{display:block}.ui-carousel{position:relative;overflow:hidden;height:100%;border-radius:var(--ui-radius-lg);background-color:var(--ui-bg-tertiary)}.ui-carousel__viewport{overflow:hidden;touch-action:pan-y;height:100%}.ui-carousel__viewport:focus-visible{outline:2px solid var(--ui-primary);outline-offset:-2px}.ui-carousel__track{display:flex;height:100%;transition:transform var(--ui-transition-normal)}.ui-carousel__track--dragging{transition:none}.ui-carousel__slide{flex:0 0 100%;min-width:0;display:flex;align-items:center;justify-content:center}.ui-carousel__image{max-width:100%;max-height:100%;width:100%;height:100%;object-fit:cover;-webkit-user-select:none;user-select:none}.ui-carousel__arrow{position:absolute;top:50%;transform:translateY(-50%);display:flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:none;border-radius:50%;background-color:var(--ui-carousel-control-bg);color:var(--ui-carousel-control-text);cursor:pointer;opacity:0;transition:opacity var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-carousel__arrow--prev{left:var(--ui-spacing-sm)}.ui-carousel__arrow--next{right:var(--ui-spacing-sm)}.ui-carousel:hover .ui-carousel__arrow,.ui-carousel__arrow:focus-visible{opacity:1}@media(hover:none){.ui-carousel__arrow{opacity:1}}.ui-carousel__arrow:hover{background-color:color-mix(in srgb,var(--ui-carousel-control-bg) 80%,#000000)}.ui-carousel__arrow:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-carousel__counter{position:absolute;right:var(--ui-spacing-sm);bottom:var(--ui-spacing-sm);padding:2px var(--ui-spacing-sm);border-radius:var(--ui-radius-sm);background-color:var(--ui-carousel-counter-bg);color:var(--ui-carousel-control-text);font-size:var(--ui-font-xs);font-weight:500;pointer-events:none}\n"] }]
|
|
541
|
+
}], propDecorators: { images: [{ type: i0.Input, args: [{ isSignal: true, alias: "images", required: true }] }], startIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "startIndex", required: false }] }], loop: [{ type: i0.Input, args: [{ isSignal: true, alias: "loop", required: false }] }], showCounter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCounter", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], index: [{ type: i0.Input, args: [{ isSignal: true, alias: "index", required: false }] }, { type: i0.Output, args: ["indexChange"] }] } });
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Fullscreen image lightbox. Opened via LightboxService — not meant to be
|
|
545
|
+
* embedded directly in templates.
|
|
546
|
+
*/
|
|
547
|
+
class LightboxComponent {
|
|
548
|
+
config = inject(DIALOG_DATA);
|
|
549
|
+
dialogRef = inject(DIALOG_REF);
|
|
550
|
+
carousel = viewChild.required(CarouselComponent);
|
|
551
|
+
viewport = viewChild.required('container');
|
|
552
|
+
/** Tracks if mousedown started on the backdrop (to prevent close on drag-out) */
|
|
553
|
+
mouseDownOnBackdrop = signal(false, ...(ngDevMode ? [{ debugName: "mouseDownOnBackdrop" }] : []));
|
|
554
|
+
constructor() {
|
|
555
|
+
afterNextRender(() => {
|
|
556
|
+
this.viewport().nativeElement.focus();
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
onKeyDown(event) {
|
|
560
|
+
switch (event.key) {
|
|
561
|
+
case 'Escape':
|
|
562
|
+
event.preventDefault();
|
|
563
|
+
this.close();
|
|
564
|
+
break;
|
|
565
|
+
case 'ArrowLeft':
|
|
566
|
+
event.preventDefault();
|
|
567
|
+
this.carousel().prev();
|
|
568
|
+
break;
|
|
569
|
+
case 'ArrowRight':
|
|
570
|
+
event.preventDefault();
|
|
571
|
+
this.carousel().next();
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
onBackdropMouseDown(event) {
|
|
576
|
+
this.mouseDownOnBackdrop.set(event.target === event.currentTarget);
|
|
577
|
+
}
|
|
578
|
+
onBackdropClick(event) {
|
|
579
|
+
if (this.mouseDownOnBackdrop() && event.target === event.currentTarget) {
|
|
580
|
+
this.close();
|
|
581
|
+
}
|
|
582
|
+
this.mouseDownOnBackdrop.set(false);
|
|
583
|
+
}
|
|
584
|
+
close() {
|
|
585
|
+
this.dialogRef.close();
|
|
586
|
+
}
|
|
587
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: LightboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
588
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.1", type: LightboxComponent, isStandalone: true, selector: "ui-lightbox", host: { listeners: { "document:keydown": "onKeyDown($event)" } }, viewQueries: [{ propertyName: "carousel", first: true, predicate: CarouselComponent, descendants: true, isSignal: true }, { propertyName: "viewport", first: true, predicate: ["container"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"ui-lightbox__backdrop\"\n (mousedown)=\"onBackdropMouseDown($event)\"\n (click)=\"onBackdropClick($event)\"\n>\n <div\n #container\n class=\"ui-lightbox__container\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Image gallery\"\n tabindex=\"-1\"\n >\n <button\n type=\"button\"\n class=\"ui-lightbox__close\"\n aria-label=\"Close\"\n (click)=\"close()\"\n >\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n\n <ui-carousel\n class=\"ui-lightbox__carousel\"\n [images]=\"config.images\"\n [startIndex]=\"config.startIndex ?? 0\"\n [showCounter]=\"true\"\n />\n </div>\n</div>\n", styles: [".ui-lightbox__backdrop{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;background-color:var(--ui-lightbox-backdrop);animation:fadeIn var(--ui-transition-fast)}.ui-lightbox__container{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center;padding:var(--ui-spacing-xl);outline:none;pointer-events:none}.ui-lightbox__carousel{width:100%;height:100%;max-width:100%;max-height:100%;pointer-events:auto}.ui-lightbox__carousel ::ng-deep .ui-carousel{height:100%;background:transparent;border-radius:0}.ui-lightbox__carousel ::ng-deep .ui-carousel__image{object-fit:contain}.ui-lightbox__carousel ::ng-deep .ui-carousel__counter{right:50%;transform:translate(50%);font-size:var(--ui-font-sm)}.ui-lightbox__close{position:absolute;top:var(--ui-spacing-md);right:var(--ui-spacing-md);z-index:1;display:flex;align-items:center;justify-content:center;width:40px;height:40px;padding:0;border:none;border-radius:50%;background-color:var(--ui-lightbox-control-bg);color:var(--ui-lightbox-control-text);cursor:pointer;pointer-events:auto;transition:background-color var(--ui-transition-fast)}.ui-lightbox__close:hover{background-color:color-mix(in srgb,var(--ui-lightbox-control-bg) 80%,#000000)}.ui-lightbox__close:focus-visible{outline:2px solid var(--ui-lightbox-control-text);outline-offset:2px}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "component", type: CarouselComponent, selector: "ui-carousel", inputs: ["images", "startIndex", "loop", "showCounter", "ariaLabel", "index"], outputs: ["indexChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
589
|
+
}
|
|
590
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: LightboxComponent, decorators: [{
|
|
591
|
+
type: Component,
|
|
592
|
+
args: [{ selector: 'ui-lightbox', standalone: true, imports: [CarouselComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"ui-lightbox__backdrop\"\n (mousedown)=\"onBackdropMouseDown($event)\"\n (click)=\"onBackdropClick($event)\"\n>\n <div\n #container\n class=\"ui-lightbox__container\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Image gallery\"\n tabindex=\"-1\"\n >\n <button\n type=\"button\"\n class=\"ui-lightbox__close\"\n aria-label=\"Close\"\n (click)=\"close()\"\n >\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n\n <ui-carousel\n class=\"ui-lightbox__carousel\"\n [images]=\"config.images\"\n [startIndex]=\"config.startIndex ?? 0\"\n [showCounter]=\"true\"\n />\n </div>\n</div>\n", styles: [".ui-lightbox__backdrop{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;background-color:var(--ui-lightbox-backdrop);animation:fadeIn var(--ui-transition-fast)}.ui-lightbox__container{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center;padding:var(--ui-spacing-xl);outline:none;pointer-events:none}.ui-lightbox__carousel{width:100%;height:100%;max-width:100%;max-height:100%;pointer-events:auto}.ui-lightbox__carousel ::ng-deep .ui-carousel{height:100%;background:transparent;border-radius:0}.ui-lightbox__carousel ::ng-deep .ui-carousel__image{object-fit:contain}.ui-lightbox__carousel ::ng-deep .ui-carousel__counter{right:50%;transform:translate(50%);font-size:var(--ui-font-sm)}.ui-lightbox__close{position:absolute;top:var(--ui-spacing-md);right:var(--ui-spacing-md);z-index:1;display:flex;align-items:center;justify-content:center;width:40px;height:40px;padding:0;border:none;border-radius:50%;background-color:var(--ui-lightbox-control-bg);color:var(--ui-lightbox-control-text);cursor:pointer;pointer-events:auto;transition:background-color var(--ui-transition-fast)}.ui-lightbox__close:hover{background-color:color-mix(in srgb,var(--ui-lightbox-control-bg) 80%,#000000)}.ui-lightbox__close:focus-visible{outline:2px solid var(--ui-lightbox-control-text);outline-offset:2px}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}\n"] }]
|
|
593
|
+
}], ctorParameters: () => [], propDecorators: { carousel: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CarouselComponent), { isSignal: true }] }], viewport: [{ type: i0.ViewChild, args: ['container', { isSignal: true }] }], onKeyDown: [{
|
|
594
|
+
type: HostListener,
|
|
595
|
+
args: ['document:keydown', ['$event']]
|
|
596
|
+
}] } });
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Service for opening a fullscreen image lightbox.
|
|
600
|
+
*
|
|
601
|
+
* @example
|
|
602
|
+
* ```typescript
|
|
603
|
+
* const ref = this.lightboxService.open({
|
|
604
|
+
* images: [{ src: '/photos/1.jpg', alt: 'Living room' }],
|
|
605
|
+
* startIndex: 0,
|
|
606
|
+
* });
|
|
607
|
+
*
|
|
608
|
+
* await ref.afterClosed();
|
|
609
|
+
* ```
|
|
610
|
+
*/
|
|
611
|
+
class LightboxService {
|
|
612
|
+
dialogService = inject(DialogService);
|
|
613
|
+
/**
|
|
614
|
+
* Opens the lightbox with the given images.
|
|
615
|
+
*
|
|
616
|
+
* @returns A DialogRef that resolves when the lightbox is closed
|
|
617
|
+
*/
|
|
618
|
+
open(config) {
|
|
619
|
+
return this.dialogService.open(LightboxComponent, {
|
|
620
|
+
data: config,
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: LightboxService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
624
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: LightboxService, providedIn: 'root' });
|
|
625
|
+
}
|
|
626
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: LightboxService, decorators: [{
|
|
627
|
+
type: Injectable,
|
|
628
|
+
args: [{ providedIn: 'root' }]
|
|
629
|
+
}] });
|
|
630
|
+
|
|
429
631
|
class ToastComponent {
|
|
430
632
|
data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
431
633
|
dismissed = output();
|
|
@@ -4251,6 +4453,256 @@ function pad(n) {
|
|
|
4251
4453
|
return n < 10 ? `0${n}` : String(n);
|
|
4252
4454
|
}
|
|
4253
4455
|
|
|
4456
|
+
class NumberRangeSliderComponent {
|
|
4457
|
+
min = input(0, ...(ngDevMode ? [{ debugName: "min" }] : []));
|
|
4458
|
+
max = input(100, ...(ngDevMode ? [{ debugName: "max" }] : []));
|
|
4459
|
+
step = input(1, ...(ngDevMode ? [{ debugName: "step" }] : []));
|
|
4460
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
4461
|
+
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
4462
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
4463
|
+
bubbles = input('always', ...(ngDevMode ? [{ debugName: "bubbles" }] : []));
|
|
4464
|
+
showRange = input(false, ...(ngDevMode ? [{ debugName: "showRange" }] : []));
|
|
4465
|
+
prefix = input('', ...(ngDevMode ? [{ debugName: "prefix" }] : []));
|
|
4466
|
+
suffix = input('', ...(ngDevMode ? [{ debugName: "suffix" }] : []));
|
|
4467
|
+
decimals = input(0, ...(ngDevMode ? [{ debugName: "decimals" }] : []));
|
|
4468
|
+
formatValue = input(null, ...(ngDevMode ? [{ debugName: "formatValue" }] : []));
|
|
4469
|
+
value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
4470
|
+
valueCommit = output();
|
|
4471
|
+
trackEl = viewChild('track', ...(ngDevMode ? [{ debugName: "trackEl" }] : []));
|
|
4472
|
+
startVal = signal(0, ...(ngDevMode ? [{ debugName: "startVal" }] : []));
|
|
4473
|
+
endVal = signal(0, ...(ngDevMode ? [{ debugName: "endVal" }] : []));
|
|
4474
|
+
dragging = signal(null, ...(ngDevMode ? [{ debugName: "dragging" }] : []));
|
|
4475
|
+
focusedThumb = signal(null, ...(ngDevMode ? [{ debugName: "focusedThumb" }] : []));
|
|
4476
|
+
hoveredThumb = signal(null, ...(ngDevMode ? [{ debugName: "hoveredThumb" }] : []));
|
|
4477
|
+
lastEmitted = null;
|
|
4478
|
+
range = computed(() => Math.max(0, this.max() - this.min()), ...(ngDevMode ? [{ debugName: "range" }] : []));
|
|
4479
|
+
startPercent = computed(() => this.toPercent(this.startVal()), ...(ngDevMode ? [{ debugName: "startPercent" }] : []));
|
|
4480
|
+
endPercent = computed(() => this.toPercent(this.endVal()), ...(ngDevMode ? [{ debugName: "endPercent" }] : []));
|
|
4481
|
+
fillStyle = computed(() => {
|
|
4482
|
+
const start = this.startPercent();
|
|
4483
|
+
const end = this.endPercent();
|
|
4484
|
+
return { left: `${start}%`, width: `${Math.max(0, end - start)}%` };
|
|
4485
|
+
}, ...(ngDevMode ? [{ debugName: "fillStyle" }] : []));
|
|
4486
|
+
startLabel = computed(() => this.format(this.startVal()), ...(ngDevMode ? [{ debugName: "startLabel" }] : []));
|
|
4487
|
+
endLabel = computed(() => this.format(this.endVal()), ...(ngDevMode ? [{ debugName: "endLabel" }] : []));
|
|
4488
|
+
bubbleVisible = computed(() => {
|
|
4489
|
+
const mode = this.bubbles();
|
|
4490
|
+
if (mode === 'never')
|
|
4491
|
+
return { start: false, end: false };
|
|
4492
|
+
if (mode === 'always')
|
|
4493
|
+
return { start: true, end: true };
|
|
4494
|
+
const active = (t) => this.dragging() === t || this.focusedThumb() === t || this.hoveredThumb() === t;
|
|
4495
|
+
return { start: active('start'), end: active('end') };
|
|
4496
|
+
}, ...(ngDevMode ? [{ debugName: "bubbleVisible" }] : []));
|
|
4497
|
+
rootClasses = computed(() => {
|
|
4498
|
+
const classes = ['ui-number-range-slider', `ui-number-range-slider--${this.size()}`];
|
|
4499
|
+
if (this.disabled())
|
|
4500
|
+
classes.push('ui-number-range-slider--disabled');
|
|
4501
|
+
return classes.join(' ');
|
|
4502
|
+
}, ...(ngDevMode ? [{ debugName: "rootClasses" }] : []));
|
|
4503
|
+
constructor() {
|
|
4504
|
+
// Sync external value → internal thumb positions. Falls back to [min, max] when null.
|
|
4505
|
+
effect(() => {
|
|
4506
|
+
const min = this.min();
|
|
4507
|
+
const max = this.max();
|
|
4508
|
+
const v = this.value();
|
|
4509
|
+
if (v) {
|
|
4510
|
+
this.startVal.set(this.snap(this.clamp(v.start)));
|
|
4511
|
+
this.endVal.set(this.snap(this.clamp(v.end)));
|
|
4512
|
+
this.lastEmitted = v;
|
|
4513
|
+
}
|
|
4514
|
+
else {
|
|
4515
|
+
this.startVal.set(min);
|
|
4516
|
+
this.endVal.set(max);
|
|
4517
|
+
this.lastEmitted = null;
|
|
4518
|
+
}
|
|
4519
|
+
});
|
|
4520
|
+
}
|
|
4521
|
+
/** Push current thumb state into the value model (live, during interaction). */
|
|
4522
|
+
writeValue() {
|
|
4523
|
+
const next = { start: this.startVal(), end: this.endVal() };
|
|
4524
|
+
const prev = this.lastEmitted;
|
|
4525
|
+
if (prev && prev.start === next.start && prev.end === next.end) {
|
|
4526
|
+
return;
|
|
4527
|
+
}
|
|
4528
|
+
this.lastEmitted = next;
|
|
4529
|
+
this.value.set(next);
|
|
4530
|
+
}
|
|
4531
|
+
// -- Pointer handling -------------------------------------------------
|
|
4532
|
+
onThumbPointerDown(event, thumb) {
|
|
4533
|
+
if (this.disabled())
|
|
4534
|
+
return;
|
|
4535
|
+
event.preventDefault();
|
|
4536
|
+
const target = event.target;
|
|
4537
|
+
target.setPointerCapture(event.pointerId);
|
|
4538
|
+
this.dragging.set(thumb);
|
|
4539
|
+
this.focusedThumb.set(thumb);
|
|
4540
|
+
target.focus();
|
|
4541
|
+
}
|
|
4542
|
+
onThumbPointerMove(event, thumb) {
|
|
4543
|
+
if (this.dragging() !== thumb)
|
|
4544
|
+
return;
|
|
4545
|
+
event.preventDefault();
|
|
4546
|
+
const val = this.pixelToVal(event.clientX);
|
|
4547
|
+
this.setThumb(thumb, val);
|
|
4548
|
+
}
|
|
4549
|
+
onThumbPointerUp(event, thumb) {
|
|
4550
|
+
if (this.dragging() !== thumb)
|
|
4551
|
+
return;
|
|
4552
|
+
const target = event.target;
|
|
4553
|
+
if (target.hasPointerCapture(event.pointerId)) {
|
|
4554
|
+
target.releasePointerCapture(event.pointerId);
|
|
4555
|
+
}
|
|
4556
|
+
this.dragging.set(null);
|
|
4557
|
+
this.commit();
|
|
4558
|
+
}
|
|
4559
|
+
onTrackPointerDown(event) {
|
|
4560
|
+
if (this.disabled())
|
|
4561
|
+
return;
|
|
4562
|
+
if (event.target.dataset['thumb'])
|
|
4563
|
+
return; // ignore thumb hits
|
|
4564
|
+
const val = this.pixelToVal(event.clientX);
|
|
4565
|
+
const thumb = Math.abs(val - this.startVal()) <= Math.abs(val - this.endVal()) ? 'start' : 'end';
|
|
4566
|
+
this.setThumb(thumb, val);
|
|
4567
|
+
this.commit();
|
|
4568
|
+
}
|
|
4569
|
+
// -- Keyboard ---------------------------------------------------------
|
|
4570
|
+
onThumbKeyDown(event, thumb) {
|
|
4571
|
+
if (this.disabled())
|
|
4572
|
+
return;
|
|
4573
|
+
const step = this.effectiveStep();
|
|
4574
|
+
const big = step * 10;
|
|
4575
|
+
let delta = 0;
|
|
4576
|
+
let target = null;
|
|
4577
|
+
switch (event.key) {
|
|
4578
|
+
case 'ArrowLeft':
|
|
4579
|
+
case 'ArrowDown':
|
|
4580
|
+
delta = event.shiftKey ? -big : -step;
|
|
4581
|
+
break;
|
|
4582
|
+
case 'ArrowRight':
|
|
4583
|
+
case 'ArrowUp':
|
|
4584
|
+
delta = event.shiftKey ? big : step;
|
|
4585
|
+
break;
|
|
4586
|
+
case 'Home':
|
|
4587
|
+
target = thumb === 'start' ? this.min() : this.startVal();
|
|
4588
|
+
break;
|
|
4589
|
+
case 'End':
|
|
4590
|
+
target = thumb === 'end' ? this.max() : this.endVal();
|
|
4591
|
+
break;
|
|
4592
|
+
default:
|
|
4593
|
+
return;
|
|
4594
|
+
}
|
|
4595
|
+
event.preventDefault();
|
|
4596
|
+
if (target !== null) {
|
|
4597
|
+
this.setThumb(thumb, target);
|
|
4598
|
+
}
|
|
4599
|
+
else {
|
|
4600
|
+
const current = thumb === 'start' ? this.startVal() : this.endVal();
|
|
4601
|
+
this.setThumb(thumb, current + delta);
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
onThumbKeyUp(event) {
|
|
4605
|
+
const keys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End'];
|
|
4606
|
+
if (keys.includes(event.key)) {
|
|
4607
|
+
this.commit();
|
|
4608
|
+
}
|
|
4609
|
+
}
|
|
4610
|
+
onThumbFocus(thumb) {
|
|
4611
|
+
this.focusedThumb.set(thumb);
|
|
4612
|
+
}
|
|
4613
|
+
onThumbBlur() {
|
|
4614
|
+
this.focusedThumb.set(null);
|
|
4615
|
+
}
|
|
4616
|
+
onThumbEnter(thumb) {
|
|
4617
|
+
this.hoveredThumb.set(thumb);
|
|
4618
|
+
}
|
|
4619
|
+
onThumbLeave() {
|
|
4620
|
+
this.hoveredThumb.set(null);
|
|
4621
|
+
}
|
|
4622
|
+
// -- Internal helpers -------------------------------------------------
|
|
4623
|
+
effectiveStep() {
|
|
4624
|
+
const step = this.step();
|
|
4625
|
+
return step > 0 ? step : 1;
|
|
4626
|
+
}
|
|
4627
|
+
setThumb(thumb, raw) {
|
|
4628
|
+
const snapped = this.snap(this.clamp(raw));
|
|
4629
|
+
let changed = false;
|
|
4630
|
+
if (thumb === 'start') {
|
|
4631
|
+
const next = Math.min(snapped, this.endVal());
|
|
4632
|
+
if (next !== this.startVal()) {
|
|
4633
|
+
this.startVal.set(next);
|
|
4634
|
+
changed = true;
|
|
4635
|
+
}
|
|
4636
|
+
}
|
|
4637
|
+
else {
|
|
4638
|
+
const next = Math.max(snapped, this.startVal());
|
|
4639
|
+
if (next !== this.endVal()) {
|
|
4640
|
+
this.endVal.set(next);
|
|
4641
|
+
changed = true;
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
if (changed)
|
|
4645
|
+
this.writeValue();
|
|
4646
|
+
}
|
|
4647
|
+
commit() {
|
|
4648
|
+
if (this.lastEmitted) {
|
|
4649
|
+
this.valueCommit.emit(this.lastEmitted);
|
|
4650
|
+
}
|
|
4651
|
+
}
|
|
4652
|
+
clamp(val) {
|
|
4653
|
+
return Math.min(this.max(), Math.max(this.min(), val));
|
|
4654
|
+
}
|
|
4655
|
+
snap(val) {
|
|
4656
|
+
const min = this.min();
|
|
4657
|
+
const max = this.max();
|
|
4658
|
+
const step = this.step();
|
|
4659
|
+
if (step <= 0 || min >= max)
|
|
4660
|
+
return val;
|
|
4661
|
+
const offset = val - min;
|
|
4662
|
+
const snapped = min + Math.round(offset / step) * step;
|
|
4663
|
+
if (snapped > max)
|
|
4664
|
+
return max;
|
|
4665
|
+
if (snapped < min)
|
|
4666
|
+
return min;
|
|
4667
|
+
return snapped;
|
|
4668
|
+
}
|
|
4669
|
+
toPercent(val) {
|
|
4670
|
+
const range = this.range();
|
|
4671
|
+
if (range <= 0)
|
|
4672
|
+
return 0;
|
|
4673
|
+
return ((val - this.min()) / range) * 100;
|
|
4674
|
+
}
|
|
4675
|
+
pixelToVal(clientX) {
|
|
4676
|
+
const el = this.trackEl()?.nativeElement;
|
|
4677
|
+
if (!el)
|
|
4678
|
+
return this.min();
|
|
4679
|
+
const rect = el.getBoundingClientRect();
|
|
4680
|
+
if (rect.width <= 0)
|
|
4681
|
+
return this.min();
|
|
4682
|
+
const ratio = (clientX - rect.left) / rect.width;
|
|
4683
|
+
const clamped = Math.min(1, Math.max(0, ratio));
|
|
4684
|
+
return this.min() + clamped * this.range();
|
|
4685
|
+
}
|
|
4686
|
+
// -- Formatting -------------------------------------------------------
|
|
4687
|
+
format(val) {
|
|
4688
|
+
const fn = this.formatValue();
|
|
4689
|
+
if (fn)
|
|
4690
|
+
return fn(val);
|
|
4691
|
+
const decimals = this.decimals();
|
|
4692
|
+
const body = val.toLocaleString(undefined, {
|
|
4693
|
+
minimumFractionDigits: decimals,
|
|
4694
|
+
maximumFractionDigits: decimals,
|
|
4695
|
+
});
|
|
4696
|
+
return `${this.prefix()}${body}${this.suffix()}`;
|
|
4697
|
+
}
|
|
4698
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: NumberRangeSliderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4699
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: NumberRangeSliderComponent, isStandalone: true, selector: "ui-number-range-slider", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, bubbles: { classPropertyName: "bubbles", publicName: "bubbles", isSignal: true, isRequired: false, transformFunction: null }, showRange: { classPropertyName: "showRange", publicName: "showRange", isSignal: true, isRequired: false, transformFunction: null }, prefix: { classPropertyName: "prefix", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null }, suffix: { classPropertyName: "suffix", publicName: "suffix", isSignal: true, isRequired: false, transformFunction: null }, decimals: { classPropertyName: "decimals", publicName: "decimals", isSignal: true, isRequired: false, transformFunction: null }, formatValue: { classPropertyName: "formatValue", publicName: "formatValue", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", valueCommit: "valueCommit" }, viewQueries: [{ propertyName: "trackEl", first: true, predicate: ["track"], descendants: true, isSignal: true }], ngImport: i0, template: "@let isDisabled = disabled();\n@let bubbleVis = bubbleVisible();\n@let rangeOn = showRange();\n@let startPct = startPercent();\n@let endPct = endPercent();\n@let fill = fillStyle();\n\n<div [class]=\"rootClasses()\">\n @if (label()) {\n <label class=\"ui-number-range-slider__label\">{{ label() }}</label>\n }\n\n <div\n #track\n class=\"ui-number-range-slider__track\"\n (pointerdown)=\"onTrackPointerDown($event)\"\n >\n <div\n class=\"ui-number-range-slider__fill\"\n [style.left]=\"fill.left\"\n [style.width]=\"fill.width\"\n ></div>\n\n <div\n class=\"ui-number-range-slider__thumb ui-number-range-slider__thumb--start\"\n role=\"slider\"\n tabindex=\"0\"\n data-thumb=\"start\"\n [attr.aria-valuemin]=\"min()\"\n [attr.aria-valuemax]=\"endVal()\"\n [attr.aria-valuenow]=\"startVal()\"\n [attr.aria-valuetext]=\"startLabel()\"\n [attr.aria-disabled]=\"isDisabled\"\n aria-label=\"Start\"\n aria-orientation=\"horizontal\"\n [style.left.%]=\"startPct\"\n (pointerdown)=\"onThumbPointerDown($event, 'start')\"\n (pointermove)=\"onThumbPointerMove($event, 'start')\"\n (pointerup)=\"onThumbPointerUp($event, 'start')\"\n (pointercancel)=\"onThumbPointerUp($event, 'start')\"\n (pointerenter)=\"onThumbEnter('start')\"\n (pointerleave)=\"onThumbLeave()\"\n (keydown)=\"onThumbKeyDown($event, 'start')\"\n (keyup)=\"onThumbKeyUp($event)\"\n (focus)=\"onThumbFocus('start')\"\n (blur)=\"onThumbBlur()\"\n >\n @if (bubbleVis.start) {\n <span class=\"ui-number-range-slider__bubble\">{{ startLabel() }}</span>\n }\n </div>\n\n <div\n class=\"ui-number-range-slider__thumb ui-number-range-slider__thumb--end\"\n role=\"slider\"\n tabindex=\"0\"\n data-thumb=\"end\"\n [attr.aria-valuemin]=\"startVal()\"\n [attr.aria-valuemax]=\"max()\"\n [attr.aria-valuenow]=\"endVal()\"\n [attr.aria-valuetext]=\"endLabel()\"\n [attr.aria-disabled]=\"isDisabled\"\n aria-label=\"End\"\n aria-orientation=\"horizontal\"\n [style.left.%]=\"endPct\"\n (pointerdown)=\"onThumbPointerDown($event, 'end')\"\n (pointermove)=\"onThumbPointerMove($event, 'end')\"\n (pointerup)=\"onThumbPointerUp($event, 'end')\"\n (pointercancel)=\"onThumbPointerUp($event, 'end')\"\n (pointerenter)=\"onThumbEnter('end')\"\n (pointerleave)=\"onThumbLeave()\"\n (keydown)=\"onThumbKeyDown($event, 'end')\"\n (keyup)=\"onThumbKeyUp($event)\"\n (focus)=\"onThumbFocus('end')\"\n (blur)=\"onThumbBlur()\"\n >\n @if (bubbleVis.end) {\n <span class=\"ui-number-range-slider__bubble\">{{ endLabel() }}</span>\n }\n </div>\n </div>\n\n @if (rangeOn) {\n <div class=\"ui-number-range-slider__range\">\n <span>{{ startLabel() }}</span>\n <span class=\"ui-number-range-slider__range-arrow\" aria-hidden=\"true\">\u2192</span>\n <span>{{ endLabel() }}</span>\n </div>\n }\n</div>\n", styles: [":host{display:block}.ui-number-range-slider{display:flex;flex-direction:column;gap:var(--ui-spacing-sm);user-select:none;-webkit-user-select:none}.ui-number-range-slider__label{font-size:var(--ui-font-sm);font-weight:500;color:var(--ui-text)}.ui-number-range-slider__track{position:relative;width:100%;background:var(--ui-bg-tertiary);border-radius:var(--ui-radius-xl);cursor:pointer;touch-action:none;margin-top:var(--ui-spacing-lg)}.ui-number-range-slider__fill{position:absolute;top:0;bottom:0;background:var(--ui-primary);border-radius:var(--ui-radius-xl);pointer-events:none}.ui-number-range-slider__thumb{position:absolute;top:50%;border-radius:50%;background:var(--ui-primary);border:2px solid var(--ui-bg);box-shadow:var(--ui-shadow-sm);cursor:grab;outline:none;transition:box-shadow var(--ui-transition-fast),transform var(--ui-transition-fast);touch-action:none;transform:translate(-50%,-50%)}.ui-number-range-slider__thumb:hover:not([aria-disabled=true]){transform:translate(-50%,-50%) scale(1.1)}.ui-number-range-slider__thumb:focus-visible{box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-primary) 20%,transparent)}.ui-number-range-slider__thumb:active:not([aria-disabled=true]){cursor:grabbing;transform:translate(-50%,-50%) scale(1.15);box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-primary) 20%,transparent);z-index:3}.ui-number-range-slider__bubble{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translate(-50%);background:var(--ui-bg);border:1px solid var(--ui-border);color:var(--ui-text);font-size:var(--ui-font-xs);font-weight:500;padding:2px var(--ui-spacing-sm);border-radius:var(--ui-radius-sm);box-shadow:var(--ui-shadow-sm);white-space:nowrap;pointer-events:none;font-variant-numeric:tabular-nums;animation:ui-number-range-slider-bubble-in var(--ui-transition-fast) ease-out}.ui-number-range-slider__bubble:after{content:\"\";position:absolute;top:100%;left:50%;transform:translate(-50%);border:4px solid transparent;border-top-color:var(--ui-border)}.ui-number-range-slider__bubble:before{content:\"\";position:absolute;top:calc(100% - 1px);left:50%;transform:translate(-50%);border:4px solid transparent;border-top-color:var(--ui-bg);z-index:1}.ui-number-range-slider__range{display:flex;align-items:center;gap:var(--ui-spacing-xs);font-size:var(--ui-font-sm);color:var(--ui-text-muted);font-variant-numeric:tabular-nums}.ui-number-range-slider__range-arrow{color:var(--ui-text-disabled)}.ui-number-range-slider--sm .ui-number-range-slider__track{height:4px}.ui-number-range-slider--sm .ui-number-range-slider__thumb{width:14px;height:14px}.ui-number-range-slider--md .ui-number-range-slider__track{height:6px}.ui-number-range-slider--md .ui-number-range-slider__thumb{width:18px;height:18px}.ui-number-range-slider--lg .ui-number-range-slider__track{height:8px}.ui-number-range-slider--lg .ui-number-range-slider__thumb{width:24px;height:24px}.ui-number-range-slider--disabled{opacity:.5}.ui-number-range-slider--disabled .ui-number-range-slider__track,.ui-number-range-slider--disabled .ui-number-range-slider__thumb{cursor:not-allowed}.ui-number-range-slider--disabled .ui-number-range-slider__thumb:hover,.ui-number-range-slider--disabled .ui-number-range-slider__thumb:active{transform:translate(-50%,-50%);box-shadow:var(--ui-shadow-sm)}@keyframes ui-number-range-slider-bubble-in{0%{opacity:0;transform:translate(-50%) translateY(4px)}to{opacity:1;transform:translate(-50%) translateY(0)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4700
|
+
}
|
|
4701
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: NumberRangeSliderComponent, decorators: [{
|
|
4702
|
+
type: Component,
|
|
4703
|
+
args: [{ selector: 'ui-number-range-slider', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let isDisabled = disabled();\n@let bubbleVis = bubbleVisible();\n@let rangeOn = showRange();\n@let startPct = startPercent();\n@let endPct = endPercent();\n@let fill = fillStyle();\n\n<div [class]=\"rootClasses()\">\n @if (label()) {\n <label class=\"ui-number-range-slider__label\">{{ label() }}</label>\n }\n\n <div\n #track\n class=\"ui-number-range-slider__track\"\n (pointerdown)=\"onTrackPointerDown($event)\"\n >\n <div\n class=\"ui-number-range-slider__fill\"\n [style.left]=\"fill.left\"\n [style.width]=\"fill.width\"\n ></div>\n\n <div\n class=\"ui-number-range-slider__thumb ui-number-range-slider__thumb--start\"\n role=\"slider\"\n tabindex=\"0\"\n data-thumb=\"start\"\n [attr.aria-valuemin]=\"min()\"\n [attr.aria-valuemax]=\"endVal()\"\n [attr.aria-valuenow]=\"startVal()\"\n [attr.aria-valuetext]=\"startLabel()\"\n [attr.aria-disabled]=\"isDisabled\"\n aria-label=\"Start\"\n aria-orientation=\"horizontal\"\n [style.left.%]=\"startPct\"\n (pointerdown)=\"onThumbPointerDown($event, 'start')\"\n (pointermove)=\"onThumbPointerMove($event, 'start')\"\n (pointerup)=\"onThumbPointerUp($event, 'start')\"\n (pointercancel)=\"onThumbPointerUp($event, 'start')\"\n (pointerenter)=\"onThumbEnter('start')\"\n (pointerleave)=\"onThumbLeave()\"\n (keydown)=\"onThumbKeyDown($event, 'start')\"\n (keyup)=\"onThumbKeyUp($event)\"\n (focus)=\"onThumbFocus('start')\"\n (blur)=\"onThumbBlur()\"\n >\n @if (bubbleVis.start) {\n <span class=\"ui-number-range-slider__bubble\">{{ startLabel() }}</span>\n }\n </div>\n\n <div\n class=\"ui-number-range-slider__thumb ui-number-range-slider__thumb--end\"\n role=\"slider\"\n tabindex=\"0\"\n data-thumb=\"end\"\n [attr.aria-valuemin]=\"startVal()\"\n [attr.aria-valuemax]=\"max()\"\n [attr.aria-valuenow]=\"endVal()\"\n [attr.aria-valuetext]=\"endLabel()\"\n [attr.aria-disabled]=\"isDisabled\"\n aria-label=\"End\"\n aria-orientation=\"horizontal\"\n [style.left.%]=\"endPct\"\n (pointerdown)=\"onThumbPointerDown($event, 'end')\"\n (pointermove)=\"onThumbPointerMove($event, 'end')\"\n (pointerup)=\"onThumbPointerUp($event, 'end')\"\n (pointercancel)=\"onThumbPointerUp($event, 'end')\"\n (pointerenter)=\"onThumbEnter('end')\"\n (pointerleave)=\"onThumbLeave()\"\n (keydown)=\"onThumbKeyDown($event, 'end')\"\n (keyup)=\"onThumbKeyUp($event)\"\n (focus)=\"onThumbFocus('end')\"\n (blur)=\"onThumbBlur()\"\n >\n @if (bubbleVis.end) {\n <span class=\"ui-number-range-slider__bubble\">{{ endLabel() }}</span>\n }\n </div>\n </div>\n\n @if (rangeOn) {\n <div class=\"ui-number-range-slider__range\">\n <span>{{ startLabel() }}</span>\n <span class=\"ui-number-range-slider__range-arrow\" aria-hidden=\"true\">\u2192</span>\n <span>{{ endLabel() }}</span>\n </div>\n }\n</div>\n", styles: [":host{display:block}.ui-number-range-slider{display:flex;flex-direction:column;gap:var(--ui-spacing-sm);user-select:none;-webkit-user-select:none}.ui-number-range-slider__label{font-size:var(--ui-font-sm);font-weight:500;color:var(--ui-text)}.ui-number-range-slider__track{position:relative;width:100%;background:var(--ui-bg-tertiary);border-radius:var(--ui-radius-xl);cursor:pointer;touch-action:none;margin-top:var(--ui-spacing-lg)}.ui-number-range-slider__fill{position:absolute;top:0;bottom:0;background:var(--ui-primary);border-radius:var(--ui-radius-xl);pointer-events:none}.ui-number-range-slider__thumb{position:absolute;top:50%;border-radius:50%;background:var(--ui-primary);border:2px solid var(--ui-bg);box-shadow:var(--ui-shadow-sm);cursor:grab;outline:none;transition:box-shadow var(--ui-transition-fast),transform var(--ui-transition-fast);touch-action:none;transform:translate(-50%,-50%)}.ui-number-range-slider__thumb:hover:not([aria-disabled=true]){transform:translate(-50%,-50%) scale(1.1)}.ui-number-range-slider__thumb:focus-visible{box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-primary) 20%,transparent)}.ui-number-range-slider__thumb:active:not([aria-disabled=true]){cursor:grabbing;transform:translate(-50%,-50%) scale(1.15);box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-primary) 20%,transparent);z-index:3}.ui-number-range-slider__bubble{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translate(-50%);background:var(--ui-bg);border:1px solid var(--ui-border);color:var(--ui-text);font-size:var(--ui-font-xs);font-weight:500;padding:2px var(--ui-spacing-sm);border-radius:var(--ui-radius-sm);box-shadow:var(--ui-shadow-sm);white-space:nowrap;pointer-events:none;font-variant-numeric:tabular-nums;animation:ui-number-range-slider-bubble-in var(--ui-transition-fast) ease-out}.ui-number-range-slider__bubble:after{content:\"\";position:absolute;top:100%;left:50%;transform:translate(-50%);border:4px solid transparent;border-top-color:var(--ui-border)}.ui-number-range-slider__bubble:before{content:\"\";position:absolute;top:calc(100% - 1px);left:50%;transform:translate(-50%);border:4px solid transparent;border-top-color:var(--ui-bg);z-index:1}.ui-number-range-slider__range{display:flex;align-items:center;gap:var(--ui-spacing-xs);font-size:var(--ui-font-sm);color:var(--ui-text-muted);font-variant-numeric:tabular-nums}.ui-number-range-slider__range-arrow{color:var(--ui-text-disabled)}.ui-number-range-slider--sm .ui-number-range-slider__track{height:4px}.ui-number-range-slider--sm .ui-number-range-slider__thumb{width:14px;height:14px}.ui-number-range-slider--md .ui-number-range-slider__track{height:6px}.ui-number-range-slider--md .ui-number-range-slider__thumb{width:18px;height:18px}.ui-number-range-slider--lg .ui-number-range-slider__track{height:8px}.ui-number-range-slider--lg .ui-number-range-slider__thumb{width:24px;height:24px}.ui-number-range-slider--disabled{opacity:.5}.ui-number-range-slider--disabled .ui-number-range-slider__track,.ui-number-range-slider--disabled .ui-number-range-slider__thumb{cursor:not-allowed}.ui-number-range-slider--disabled .ui-number-range-slider__thumb:hover,.ui-number-range-slider--disabled .ui-number-range-slider__thumb:active{transform:translate(-50%,-50%);box-shadow:var(--ui-shadow-sm)}@keyframes ui-number-range-slider-bubble-in{0%{opacity:0;transform:translate(-50%) translateY(4px)}to{opacity:1;transform:translate(-50%) translateY(0)}}\n"] }]
|
|
4704
|
+
}], ctorParameters: () => [], propDecorators: { min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], bubbles: [{ type: i0.Input, args: [{ isSignal: true, alias: "bubbles", required: false }] }], showRange: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRange", required: false }] }], prefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "prefix", required: false }] }], suffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffix", required: false }] }], decimals: [{ type: i0.Input, args: [{ isSignal: true, alias: "decimals", required: false }] }], formatValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatValue", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], valueCommit: [{ type: i0.Output, args: ["valueCommit"] }], trackEl: [{ type: i0.ViewChild, args: ['track', { isSignal: true }] }] } });
|
|
4705
|
+
|
|
4254
4706
|
/** Directive to mark a custom chip template */
|
|
4255
4707
|
class ChipTemplateDirective {
|
|
4256
4708
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ChipTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
@@ -6391,6 +6843,435 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
|
|
|
6391
6843
|
args: ['document:click', ['$event']]
|
|
6392
6844
|
}] } });
|
|
6393
6845
|
|
|
6846
|
+
class SegmentedComponent {
|
|
6847
|
+
options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
6848
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
6849
|
+
fullWidth = input(false, ...(ngDevMode ? [{ debugName: "fullWidth" }] : []));
|
|
6850
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
6851
|
+
ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
6852
|
+
value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
|
|
6853
|
+
track = viewChild.required('track');
|
|
6854
|
+
segmentedClasses = computed(() => {
|
|
6855
|
+
const classes = [`ui-segmented--${this.size()}`];
|
|
6856
|
+
if (this.fullWidth()) {
|
|
6857
|
+
classes.push('ui-segmented--full-width');
|
|
6858
|
+
}
|
|
6859
|
+
if (this.disabled()) {
|
|
6860
|
+
classes.push('ui-segmented--disabled');
|
|
6861
|
+
}
|
|
6862
|
+
return classes.join(' ');
|
|
6863
|
+
}, ...(ngDevMode ? [{ debugName: "segmentedClasses" }] : []));
|
|
6864
|
+
selectedIndex = computed(() => {
|
|
6865
|
+
return this.options().findIndex(option => option.value === this.value());
|
|
6866
|
+
}, ...(ngDevMode ? [{ debugName: "selectedIndex" }] : []));
|
|
6867
|
+
isSegmentDisabled(option) {
|
|
6868
|
+
return this.disabled() || !!option.disabled;
|
|
6869
|
+
}
|
|
6870
|
+
isTabbable(index) {
|
|
6871
|
+
const selected = this.selectedIndex();
|
|
6872
|
+
if (selected >= 0)
|
|
6873
|
+
return index === selected;
|
|
6874
|
+
// No selection yet: first enabled segment holds the tab stop
|
|
6875
|
+
const firstEnabled = this.options().findIndex(option => !this.isSegmentDisabled(option));
|
|
6876
|
+
return index === firstEnabled;
|
|
6877
|
+
}
|
|
6878
|
+
selectSegment(option) {
|
|
6879
|
+
if (this.isSegmentDisabled(option))
|
|
6880
|
+
return;
|
|
6881
|
+
this.value.set(option.value);
|
|
6882
|
+
}
|
|
6883
|
+
handleKeyDown(event, currentIndex) {
|
|
6884
|
+
const enabledSegments = this.options()
|
|
6885
|
+
.map((option, index) => ({ option, index }))
|
|
6886
|
+
.filter(({ option }) => !this.isSegmentDisabled(option));
|
|
6887
|
+
if (enabledSegments.length === 0)
|
|
6888
|
+
return;
|
|
6889
|
+
const currentEnabledIndex = enabledSegments.findIndex(({ index }) => index === currentIndex);
|
|
6890
|
+
let nextEnabledIndex = -1;
|
|
6891
|
+
switch (event.key) {
|
|
6892
|
+
case 'ArrowRight':
|
|
6893
|
+
case 'ArrowDown':
|
|
6894
|
+
event.preventDefault();
|
|
6895
|
+
nextEnabledIndex = (currentEnabledIndex + 1) % enabledSegments.length;
|
|
6896
|
+
break;
|
|
6897
|
+
case 'ArrowLeft':
|
|
6898
|
+
case 'ArrowUp':
|
|
6899
|
+
event.preventDefault();
|
|
6900
|
+
nextEnabledIndex = (currentEnabledIndex - 1 + enabledSegments.length) % enabledSegments.length;
|
|
6901
|
+
break;
|
|
6902
|
+
case 'Home':
|
|
6903
|
+
event.preventDefault();
|
|
6904
|
+
nextEnabledIndex = 0;
|
|
6905
|
+
break;
|
|
6906
|
+
case 'End':
|
|
6907
|
+
event.preventDefault();
|
|
6908
|
+
nextEnabledIndex = enabledSegments.length - 1;
|
|
6909
|
+
break;
|
|
6910
|
+
default:
|
|
6911
|
+
return;
|
|
6912
|
+
}
|
|
6913
|
+
if (nextEnabledIndex >= 0) {
|
|
6914
|
+
const { option, index } = enabledSegments[nextEnabledIndex];
|
|
6915
|
+
this.selectSegment(option);
|
|
6916
|
+
this.focusSegment(index);
|
|
6917
|
+
}
|
|
6918
|
+
}
|
|
6919
|
+
focusSegment(index) {
|
|
6920
|
+
const buttons = this.track().nativeElement.querySelectorAll('.ui-segmented__segment');
|
|
6921
|
+
buttons[index]?.focus();
|
|
6922
|
+
}
|
|
6923
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SegmentedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6924
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: SegmentedComponent, isStandalone: true, selector: "ui-segmented", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, viewQueries: [{ propertyName: "track", first: true, predicate: ["track"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #track\n class=\"ui-segmented\"\n [class]=\"segmentedClasses()\"\n role=\"radiogroup\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-disabled]=\"disabled() || null\"\n>\n @for (option of options(); track option.value; let i = $index) {\n <button\n type=\"button\"\n class=\"ui-segmented__segment\"\n role=\"radio\"\n [class.ui-segmented__segment--active]=\"i === selectedIndex()\"\n [class.ui-segmented__segment--disabled]=\"isSegmentDisabled(option)\"\n [attr.aria-checked]=\"i === selectedIndex()\"\n [attr.tabindex]=\"isTabbable(i) ? 0 : -1\"\n [disabled]=\"isSegmentDisabled(option)\"\n (click)=\"selectSegment(option)\"\n (keydown)=\"handleKeyDown($event, i)\"\n >\n {{ option.label }}\n </button>\n }\n</div>\n", styles: [":host{display:inline-block}.ui-segmented{display:inline-flex;padding:3px;gap:2px;background-color:var(--ui-segmented-track-bg);border-radius:var(--ui-radius-md)}.ui-segmented__segment{flex:0 1 auto;border:none;background:transparent;color:var(--ui-text-muted);font-weight:500;white-space:nowrap;cursor:pointer;border-radius:var(--ui-radius-sm);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast)}.ui-segmented__segment:hover:not(:disabled):not(.ui-segmented__segment--active){color:var(--ui-text)}.ui-segmented__segment:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-segmented__segment--active{background-color:var(--ui-segmented-active-bg);color:var(--ui-segmented-active-text);box-shadow:var(--ui-shadow-sm)}.ui-segmented__segment--disabled{opacity:.5;cursor:not-allowed}.ui-segmented--disabled{opacity:.7}:host:has(.ui-segmented--full-width){display:block}.ui-segmented--full-width{display:flex;width:100%}.ui-segmented--full-width .ui-segmented__segment{flex:1 1 0}.ui-segmented--sm .ui-segmented__segment{padding:.25rem .75rem;font-size:var(--ui-font-sm)}.ui-segmented--md .ui-segmented__segment{padding:.375rem 1rem;font-size:var(--ui-font-sm)}.ui-segmented--lg .ui-segmented__segment{padding:.5rem 1.25rem;font-size:var(--ui-font-md)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6925
|
+
}
|
|
6926
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SegmentedComponent, decorators: [{
|
|
6927
|
+
type: Component,
|
|
6928
|
+
args: [{ selector: 'ui-segmented', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n #track\n class=\"ui-segmented\"\n [class]=\"segmentedClasses()\"\n role=\"radiogroup\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-disabled]=\"disabled() || null\"\n>\n @for (option of options(); track option.value; let i = $index) {\n <button\n type=\"button\"\n class=\"ui-segmented__segment\"\n role=\"radio\"\n [class.ui-segmented__segment--active]=\"i === selectedIndex()\"\n [class.ui-segmented__segment--disabled]=\"isSegmentDisabled(option)\"\n [attr.aria-checked]=\"i === selectedIndex()\"\n [attr.tabindex]=\"isTabbable(i) ? 0 : -1\"\n [disabled]=\"isSegmentDisabled(option)\"\n (click)=\"selectSegment(option)\"\n (keydown)=\"handleKeyDown($event, i)\"\n >\n {{ option.label }}\n </button>\n }\n</div>\n", styles: [":host{display:inline-block}.ui-segmented{display:inline-flex;padding:3px;gap:2px;background-color:var(--ui-segmented-track-bg);border-radius:var(--ui-radius-md)}.ui-segmented__segment{flex:0 1 auto;border:none;background:transparent;color:var(--ui-text-muted);font-weight:500;white-space:nowrap;cursor:pointer;border-radius:var(--ui-radius-sm);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast)}.ui-segmented__segment:hover:not(:disabled):not(.ui-segmented__segment--active){color:var(--ui-text)}.ui-segmented__segment:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-segmented__segment--active{background-color:var(--ui-segmented-active-bg);color:var(--ui-segmented-active-text);box-shadow:var(--ui-shadow-sm)}.ui-segmented__segment--disabled{opacity:.5;cursor:not-allowed}.ui-segmented--disabled{opacity:.7}:host:has(.ui-segmented--full-width){display:block}.ui-segmented--full-width{display:flex;width:100%}.ui-segmented--full-width .ui-segmented__segment{flex:1 1 0}.ui-segmented--sm .ui-segmented__segment{padding:.25rem .75rem;font-size:var(--ui-font-sm)}.ui-segmented--md .ui-segmented__segment{padding:.375rem 1rem;font-size:var(--ui-font-sm)}.ui-segmented--lg .ui-segmented__segment{padding:.5rem 1.25rem;font-size:var(--ui-font-md)}\n"] }]
|
|
6929
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], track: [{ type: i0.ViewChild, args: ['track', { isSignal: true }] }] } });
|
|
6930
|
+
|
|
6931
|
+
class StepperComponent {
|
|
6932
|
+
steps = input.required(...(ngDevMode ? [{ debugName: "steps" }] : []));
|
|
6933
|
+
linear = input(true, ...(ngDevMode ? [{ debugName: "linear" }] : []));
|
|
6934
|
+
ariaLabel = input('Progress', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
6935
|
+
activeIndex = model(0, ...(ngDevMode ? [{ debugName: "activeIndex" }] : []));
|
|
6936
|
+
stepClick = output();
|
|
6937
|
+
stepStates = computed(() => {
|
|
6938
|
+
const active = this.activeIndex();
|
|
6939
|
+
return this.steps().map((step, index) => ({
|
|
6940
|
+
step,
|
|
6941
|
+
index,
|
|
6942
|
+
completed: index < active,
|
|
6943
|
+
active: index === active,
|
|
6944
|
+
clickable: this.linear() ? index < active : index !== active,
|
|
6945
|
+
}));
|
|
6946
|
+
}, ...(ngDevMode ? [{ debugName: "stepStates" }] : []));
|
|
6947
|
+
selectStep(index, clickable) {
|
|
6948
|
+
if (!clickable)
|
|
6949
|
+
return;
|
|
6950
|
+
this.activeIndex.set(index);
|
|
6951
|
+
this.stepClick.emit(index);
|
|
6952
|
+
}
|
|
6953
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: StepperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6954
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: StepperComponent, isStandalone: true, selector: "ui-stepper", inputs: { steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: true, transformFunction: null }, linear: { classPropertyName: "linear", publicName: "linear", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeIndex: "activeIndexChange", stepClick: "stepClick" }, ngImport: i0, template: "<ol class=\"ui-stepper\" [attr.aria-label]=\"ariaLabel()\">\n @for (state of stepStates(); track state.step.key) {\n <li\n class=\"ui-stepper__step\"\n [class.ui-stepper__step--completed]=\"state.completed\"\n [class.ui-stepper__step--active]=\"state.active\"\n [attr.aria-current]=\"state.active ? 'step' : null\"\n >\n @if (!$first) {\n <span class=\"ui-stepper__connector\" aria-hidden=\"true\"></span>\n }\n @if (state.clickable) {\n <button\n type=\"button\"\n class=\"ui-stepper__button\"\n (click)=\"selectStep(state.index, true)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"stepContent\"\n [ngTemplateOutletContext]=\"{ $implicit: state }\"\n />\n </button>\n } @else {\n <span class=\"ui-stepper__button ui-stepper__button--static\">\n <ng-container\n [ngTemplateOutlet]=\"stepContent\"\n [ngTemplateOutletContext]=\"{ $implicit: state }\"\n />\n </span>\n }\n </li>\n }\n</ol>\n\n<ng-template #stepContent let-state>\n <span class=\"ui-stepper__circle\" aria-hidden=\"true\">\n @if (state.completed) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\">\n <path d=\"M20 6L9 17l-5-5\"/>\n </svg>\n } @else {\n {{ state.index + 1 }}\n }\n </span>\n <span class=\"ui-stepper__label\">{{ state.step.label }}</span>\n</ng-template>\n", styles: [":host{display:block}.ui-stepper{display:flex;margin:0;padding:0;list-style:none}.ui-stepper__step{display:flex;align-items:center;flex:0 1 auto;min-width:0}.ui-stepper__step:not(:first-child){flex:1 1 0}.ui-stepper__connector{flex:1 1 0;height:2px;min-width:var(--ui-spacing-md);margin:0 var(--ui-spacing-sm);background-color:var(--ui-stepper-connector);transition:background-color var(--ui-transition-normal)}.ui-stepper__step--completed .ui-stepper__connector,.ui-stepper__step--active .ui-stepper__connector{background-color:var(--ui-stepper-completed)}.ui-stepper__button{display:inline-flex;align-items:center;gap:var(--ui-spacing-sm);padding:var(--ui-spacing-xs);border:none;background:transparent;font:inherit;color:var(--ui-text-muted);border-radius:var(--ui-radius-md);white-space:nowrap;min-width:0}button.ui-stepper__button{cursor:pointer;transition:color var(--ui-transition-fast)}button.ui-stepper__button:hover{color:var(--ui-text)}button.ui-stepper__button:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-stepper__circle{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ui-stepper-circle-size);height:var(--ui-stepper-circle-size);border:2px solid var(--ui-stepper-connector);border-radius:50%;font-size:var(--ui-font-sm);font-weight:600;color:var(--ui-text-muted);background-color:var(--ui-bg);transition:all var(--ui-transition-normal)}.ui-stepper__label{font-size:var(--ui-font-sm);font-weight:500;overflow:hidden;text-overflow:ellipsis}.ui-stepper__step--completed .ui-stepper__circle{border-color:var(--ui-stepper-completed);background-color:var(--ui-stepper-completed);color:var(--ui-stepper-completed-text)}.ui-stepper__step--completed .ui-stepper__label{color:var(--ui-text)}.ui-stepper__step--active .ui-stepper__circle{border-color:var(--ui-primary);color:var(--ui-primary)}.ui-stepper__step--active .ui-stepper__label{color:var(--ui-text);font-weight:600}@media(max-width:768px){.ui-stepper__step:not(.ui-stepper__step--active) .ui-stepper__label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6955
|
+
}
|
|
6956
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: StepperComponent, decorators: [{
|
|
6957
|
+
type: Component,
|
|
6958
|
+
args: [{ selector: 'ui-stepper', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ol class=\"ui-stepper\" [attr.aria-label]=\"ariaLabel()\">\n @for (state of stepStates(); track state.step.key) {\n <li\n class=\"ui-stepper__step\"\n [class.ui-stepper__step--completed]=\"state.completed\"\n [class.ui-stepper__step--active]=\"state.active\"\n [attr.aria-current]=\"state.active ? 'step' : null\"\n >\n @if (!$first) {\n <span class=\"ui-stepper__connector\" aria-hidden=\"true\"></span>\n }\n @if (state.clickable) {\n <button\n type=\"button\"\n class=\"ui-stepper__button\"\n (click)=\"selectStep(state.index, true)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"stepContent\"\n [ngTemplateOutletContext]=\"{ $implicit: state }\"\n />\n </button>\n } @else {\n <span class=\"ui-stepper__button ui-stepper__button--static\">\n <ng-container\n [ngTemplateOutlet]=\"stepContent\"\n [ngTemplateOutletContext]=\"{ $implicit: state }\"\n />\n </span>\n }\n </li>\n }\n</ol>\n\n<ng-template #stepContent let-state>\n <span class=\"ui-stepper__circle\" aria-hidden=\"true\">\n @if (state.completed) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\">\n <path d=\"M20 6L9 17l-5-5\"/>\n </svg>\n } @else {\n {{ state.index + 1 }}\n }\n </span>\n <span class=\"ui-stepper__label\">{{ state.step.label }}</span>\n</ng-template>\n", styles: [":host{display:block}.ui-stepper{display:flex;margin:0;padding:0;list-style:none}.ui-stepper__step{display:flex;align-items:center;flex:0 1 auto;min-width:0}.ui-stepper__step:not(:first-child){flex:1 1 0}.ui-stepper__connector{flex:1 1 0;height:2px;min-width:var(--ui-spacing-md);margin:0 var(--ui-spacing-sm);background-color:var(--ui-stepper-connector);transition:background-color var(--ui-transition-normal)}.ui-stepper__step--completed .ui-stepper__connector,.ui-stepper__step--active .ui-stepper__connector{background-color:var(--ui-stepper-completed)}.ui-stepper__button{display:inline-flex;align-items:center;gap:var(--ui-spacing-sm);padding:var(--ui-spacing-xs);border:none;background:transparent;font:inherit;color:var(--ui-text-muted);border-radius:var(--ui-radius-md);white-space:nowrap;min-width:0}button.ui-stepper__button{cursor:pointer;transition:color var(--ui-transition-fast)}button.ui-stepper__button:hover{color:var(--ui-text)}button.ui-stepper__button:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-stepper__circle{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ui-stepper-circle-size);height:var(--ui-stepper-circle-size);border:2px solid var(--ui-stepper-connector);border-radius:50%;font-size:var(--ui-font-sm);font-weight:600;color:var(--ui-text-muted);background-color:var(--ui-bg);transition:all var(--ui-transition-normal)}.ui-stepper__label{font-size:var(--ui-font-sm);font-weight:500;overflow:hidden;text-overflow:ellipsis}.ui-stepper__step--completed .ui-stepper__circle{border-color:var(--ui-stepper-completed);background-color:var(--ui-stepper-completed);color:var(--ui-stepper-completed-text)}.ui-stepper__step--completed .ui-stepper__label{color:var(--ui-text)}.ui-stepper__step--active .ui-stepper__circle{border-color:var(--ui-primary);color:var(--ui-primary)}.ui-stepper__step--active .ui-stepper__label{color:var(--ui-text);font-weight:600}@media(max-width:768px){.ui-stepper__step:not(.ui-stepper__step--active) .ui-stepper__label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}}\n"] }]
|
|
6959
|
+
}], propDecorators: { steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: true }] }], linear: [{ type: i0.Input, args: [{ isSignal: true, alias: "linear", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], activeIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIndex", required: false }] }, { type: i0.Output, args: ["activeIndexChange"] }], stepClick: [{ type: i0.Output, args: ["stepClick"] }] } });
|
|
6960
|
+
|
|
6961
|
+
class BreadcrumbSeparatorDirective {
|
|
6962
|
+
templateRef = inject((TemplateRef));
|
|
6963
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: BreadcrumbSeparatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
6964
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: BreadcrumbSeparatorDirective, isStandalone: true, selector: "[uiBreadcrumbSeparator]", ngImport: i0 });
|
|
6965
|
+
}
|
|
6966
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: BreadcrumbSeparatorDirective, decorators: [{
|
|
6967
|
+
type: Directive,
|
|
6968
|
+
args: [{
|
|
6969
|
+
selector: '[uiBreadcrumbSeparator]',
|
|
6970
|
+
standalone: true,
|
|
6971
|
+
}]
|
|
6972
|
+
}] });
|
|
6973
|
+
|
|
6974
|
+
class BreadcrumbComponent {
|
|
6975
|
+
items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
6976
|
+
separator = input('/', ...(ngDevMode ? [{ debugName: "separator" }] : []));
|
|
6977
|
+
separatorTemplate = contentChild(BreadcrumbSeparatorDirective, ...(ngDevMode ? [{ debugName: "separatorTemplate" }] : []));
|
|
6978
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: BreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6979
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: BreadcrumbComponent, isStandalone: true, selector: "ui-breadcrumb", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "separatorTemplate", first: true, predicate: BreadcrumbSeparatorDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<nav class=\"ui-breadcrumb\" aria-label=\"Breadcrumb\">\n <ol class=\"ui-breadcrumb__list\">\n @for (item of items(); track $index) {\n <li class=\"ui-breadcrumb__item\">\n @if (!$first) {\n <span class=\"ui-breadcrumb__separator\" aria-hidden=\"true\">\n @if (separatorTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl.templateRef\" />\n } @else {\n {{ separator() }}\n }\n </span>\n }\n @if (item.url && !$last) {\n <a class=\"ui-breadcrumb__link\" [routerLink]=\"item.url\">{{ item.label }}</a>\n } @else {\n <span\n class=\"ui-breadcrumb__current\"\n [attr.aria-current]=\"$last ? 'page' : null\"\n >{{ item.label }}</span>\n }\n </li>\n }\n </ol>\n</nav>\n", styles: [":host{display:block}.ui-breadcrumb__list{display:flex;align-items:center;flex-wrap:wrap;margin:0;padding:0;list-style:none}.ui-breadcrumb__item{display:flex;align-items:center;min-width:0;font-size:var(--ui-font-sm)}.ui-breadcrumb__separator{display:inline-flex;align-items:center;margin:0 var(--ui-spacing-sm);color:var(--ui-text-muted);-webkit-user-select:none;user-select:none}.ui-breadcrumb__link,.ui-breadcrumb__current{max-width:16rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-breadcrumb__link{color:var(--ui-text-muted);text-decoration:none;border-radius:var(--ui-radius-sm);transition:color var(--ui-transition-fast)}.ui-breadcrumb__link:hover{color:var(--ui-text);text-decoration:underline}.ui-breadcrumb__link:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-breadcrumb__current{color:var(--ui-text);font-weight:500}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6980
|
+
}
|
|
6981
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: BreadcrumbComponent, decorators: [{
|
|
6982
|
+
type: Component,
|
|
6983
|
+
args: [{ selector: 'ui-breadcrumb', standalone: true, imports: [NgTemplateOutlet, RouterLink], changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav class=\"ui-breadcrumb\" aria-label=\"Breadcrumb\">\n <ol class=\"ui-breadcrumb__list\">\n @for (item of items(); track $index) {\n <li class=\"ui-breadcrumb__item\">\n @if (!$first) {\n <span class=\"ui-breadcrumb__separator\" aria-hidden=\"true\">\n @if (separatorTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl.templateRef\" />\n } @else {\n {{ separator() }}\n }\n </span>\n }\n @if (item.url && !$last) {\n <a class=\"ui-breadcrumb__link\" [routerLink]=\"item.url\">{{ item.label }}</a>\n } @else {\n <span\n class=\"ui-breadcrumb__current\"\n [attr.aria-current]=\"$last ? 'page' : null\"\n >{{ item.label }}</span>\n }\n </li>\n }\n </ol>\n</nav>\n", styles: [":host{display:block}.ui-breadcrumb__list{display:flex;align-items:center;flex-wrap:wrap;margin:0;padding:0;list-style:none}.ui-breadcrumb__item{display:flex;align-items:center;min-width:0;font-size:var(--ui-font-sm)}.ui-breadcrumb__separator{display:inline-flex;align-items:center;margin:0 var(--ui-spacing-sm);color:var(--ui-text-muted);-webkit-user-select:none;user-select:none}.ui-breadcrumb__link,.ui-breadcrumb__current{max-width:16rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-breadcrumb__link{color:var(--ui-text-muted);text-decoration:none;border-radius:var(--ui-radius-sm);transition:color var(--ui-transition-fast)}.ui-breadcrumb__link:hover{color:var(--ui-text);text-decoration:underline}.ui-breadcrumb__link:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-breadcrumb__current{color:var(--ui-text);font-weight:500}\n"] }]
|
|
6984
|
+
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], separatorTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => BreadcrumbSeparatorDirective), { isSignal: true }] }] } });
|
|
6985
|
+
|
|
6986
|
+
class SkeletonComponent {
|
|
6987
|
+
variant = input('line', ...(ngDevMode ? [{ debugName: "variant" }] : []));
|
|
6988
|
+
width = input(...(ngDevMode ? [undefined, { debugName: "width" }] : []));
|
|
6989
|
+
height = input(...(ngDevMode ? [undefined, { debugName: "height" }] : []));
|
|
6990
|
+
count = input(1, ...(ngDevMode ? [{ debugName: "count" }] : []));
|
|
6991
|
+
items = computed(() => {
|
|
6992
|
+
return Array.from({ length: Math.max(1, this.count()) }, (_, i) => i);
|
|
6993
|
+
}, ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
6994
|
+
itemWidth(index) {
|
|
6995
|
+
// Last line of a multi-line paragraph placeholder is shortened
|
|
6996
|
+
if (this.variant() === 'line' && this.count() > 1 && index === this.count() - 1) {
|
|
6997
|
+
return '60%';
|
|
6998
|
+
}
|
|
6999
|
+
return this.width() ?? null;
|
|
7000
|
+
}
|
|
7001
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SkeletonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7002
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: SkeletonComponent, isStandalone: true, selector: "ui-skeleton", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, count: { classPropertyName: "count", publicName: "count", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"ui-skeleton\" aria-hidden=\"true\">\n @for (item of items(); track item) {\n <span\n class=\"ui-skeleton__item\"\n [class]=\"'ui-skeleton__item--' + variant()\"\n [style.width]=\"itemWidth(item)\"\n [style.height]=\"height() ?? null\"\n ></span>\n }\n</div>\n", styles: [":host{display:block}.ui-skeleton{display:flex;flex-direction:column;gap:var(--ui-spacing-sm)}.ui-skeleton__item{display:block;background:linear-gradient(90deg,var(--ui-skeleton-base) 25%,var(--ui-skeleton-highlight) 37%,var(--ui-skeleton-base) 63%);background-size:400% 100%;animation:ui-skeleton-shimmer 1.4s ease infinite}.ui-skeleton__item--line{width:100%;height:.875rem;border-radius:var(--ui-radius-sm)}.ui-skeleton__item--box{width:100%;height:6rem;border-radius:var(--ui-radius-md)}.ui-skeleton__item--circle{width:3rem;height:3rem;border-radius:50%}@keyframes ui-skeleton-shimmer{0%{background-position:100% 50%}to{background-position:0 50%}}@media(prefers-reduced-motion:reduce){.ui-skeleton__item{background:var(--ui-skeleton-base);animation:ui-skeleton-pulse 2s ease-in-out infinite}@keyframes ui-skeleton-pulse{0%,to{opacity:1}50%{opacity:.6}}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7003
|
+
}
|
|
7004
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SkeletonComponent, decorators: [{
|
|
7005
|
+
type: Component,
|
|
7006
|
+
args: [{ selector: 'ui-skeleton', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ui-skeleton\" aria-hidden=\"true\">\n @for (item of items(); track item) {\n <span\n class=\"ui-skeleton__item\"\n [class]=\"'ui-skeleton__item--' + variant()\"\n [style.width]=\"itemWidth(item)\"\n [style.height]=\"height() ?? null\"\n ></span>\n }\n</div>\n", styles: [":host{display:block}.ui-skeleton{display:flex;flex-direction:column;gap:var(--ui-spacing-sm)}.ui-skeleton__item{display:block;background:linear-gradient(90deg,var(--ui-skeleton-base) 25%,var(--ui-skeleton-highlight) 37%,var(--ui-skeleton-base) 63%);background-size:400% 100%;animation:ui-skeleton-shimmer 1.4s ease infinite}.ui-skeleton__item--line{width:100%;height:.875rem;border-radius:var(--ui-radius-sm)}.ui-skeleton__item--box{width:100%;height:6rem;border-radius:var(--ui-radius-md)}.ui-skeleton__item--circle{width:3rem;height:3rem;border-radius:50%}@keyframes ui-skeleton-shimmer{0%{background-position:100% 50%}to{background-position:0 50%}}@media(prefers-reduced-motion:reduce){.ui-skeleton__item{background:var(--ui-skeleton-base);animation:ui-skeleton-pulse 2s ease-in-out infinite}@keyframes ui-skeleton-pulse{0%,to{opacity:1}50%{opacity:.6}}}\n"] }]
|
|
7007
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], count: [{ type: i0.Input, args: [{ isSignal: true, alias: "count", required: false }] }] } });
|
|
7008
|
+
|
|
7009
|
+
class ImageUploaderComponent {
|
|
7010
|
+
maxCount = input(30, ...(ngDevMode ? [{ debugName: "maxCount" }] : []));
|
|
7011
|
+
accept = input('image/*', ...(ngDevMode ? [{ debugName: "accept" }] : []));
|
|
7012
|
+
maxFileSizeMb = input(...(ngDevMode ? [undefined, { debugName: "maxFileSizeMb" }] : []));
|
|
7013
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
7014
|
+
coverLabel = input('Cover', ...(ngDevMode ? [{ debugName: "coverLabel" }] : []));
|
|
7015
|
+
addLabel = input('Add images', ...(ngDevMode ? [{ debugName: "addLabel" }] : []));
|
|
7016
|
+
items = model([], ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
7017
|
+
filesAdded = output();
|
|
7018
|
+
filesRejected = output();
|
|
7019
|
+
removed = output();
|
|
7020
|
+
reordered = output();
|
|
7021
|
+
fileInput = viewChild.required('fileInput');
|
|
7022
|
+
grid = viewChild.required('grid');
|
|
7023
|
+
dragOver = signal(false, ...(ngDevMode ? [{ debugName: "dragOver" }] : []));
|
|
7024
|
+
/** Id of the tile currently grabbed for keyboard reordering */
|
|
7025
|
+
grabbedId = signal(null, ...(ngDevMode ? [{ debugName: "grabbedId" }] : []));
|
|
7026
|
+
/** Announcement for screen readers after a keyboard move */
|
|
7027
|
+
liveMessage = signal('', ...(ngDevMode ? [{ debugName: "liveMessage" }] : []));
|
|
7028
|
+
/** Id of the tile being pointer-dragged */
|
|
7029
|
+
dragId = signal(null, ...(ngDevMode ? [{ debugName: "dragId" }] : []));
|
|
7030
|
+
ghostX = signal(0, ...(ngDevMode ? [{ debugName: "ghostX" }] : []));
|
|
7031
|
+
ghostY = signal(0, ...(ngDevMode ? [{ debugName: "ghostY" }] : []));
|
|
7032
|
+
ghostSize = signal(0, ...(ngDevMode ? [{ debugName: "ghostSize" }] : []));
|
|
7033
|
+
pointerId = null;
|
|
7034
|
+
pointerDownX = 0;
|
|
7035
|
+
pointerDownY = 0;
|
|
7036
|
+
pointerDownId = null;
|
|
7037
|
+
dragStarted = false;
|
|
7038
|
+
canAdd = computed(() => {
|
|
7039
|
+
return !this.disabled() && this.items().length < this.maxCount();
|
|
7040
|
+
}, ...(ngDevMode ? [{ debugName: "canAdd" }] : []));
|
|
7041
|
+
dragItem = computed(() => {
|
|
7042
|
+
const id = this.dragId();
|
|
7043
|
+
return id === null ? null : this.items().find(item => item.id === id) ?? null;
|
|
7044
|
+
}, ...(ngDevMode ? [{ debugName: "dragItem" }] : []));
|
|
7045
|
+
tileLabel(item, index) {
|
|
7046
|
+
const position = `Image ${index + 1} of ${this.items().length}`;
|
|
7047
|
+
const cover = index === 0 ? ', cover image' : '';
|
|
7048
|
+
const error = item.error ? `, error: ${item.error}` : '';
|
|
7049
|
+
return `${position}${cover}${error}`;
|
|
7050
|
+
}
|
|
7051
|
+
// --- Adding files ---
|
|
7052
|
+
openFilePicker() {
|
|
7053
|
+
if (this.canAdd()) {
|
|
7054
|
+
this.fileInput().nativeElement.click();
|
|
7055
|
+
}
|
|
7056
|
+
}
|
|
7057
|
+
onFileSelected(event) {
|
|
7058
|
+
const input = event.target;
|
|
7059
|
+
if (input.files && input.files.length > 0) {
|
|
7060
|
+
this.processFiles(Array.from(input.files));
|
|
7061
|
+
input.value = '';
|
|
7062
|
+
}
|
|
7063
|
+
}
|
|
7064
|
+
onDragOver(event) {
|
|
7065
|
+
event.preventDefault();
|
|
7066
|
+
event.stopPropagation();
|
|
7067
|
+
if (this.canAdd()) {
|
|
7068
|
+
this.dragOver.set(true);
|
|
7069
|
+
}
|
|
7070
|
+
}
|
|
7071
|
+
onDragLeave(event) {
|
|
7072
|
+
event.preventDefault();
|
|
7073
|
+
event.stopPropagation();
|
|
7074
|
+
this.dragOver.set(false);
|
|
7075
|
+
}
|
|
7076
|
+
onDrop(event) {
|
|
7077
|
+
event.preventDefault();
|
|
7078
|
+
event.stopPropagation();
|
|
7079
|
+
this.dragOver.set(false);
|
|
7080
|
+
if (!this.canAdd())
|
|
7081
|
+
return;
|
|
7082
|
+
const files = event.dataTransfer?.files;
|
|
7083
|
+
if (files && files.length > 0) {
|
|
7084
|
+
this.processFiles(Array.from(files));
|
|
7085
|
+
}
|
|
7086
|
+
}
|
|
7087
|
+
processFiles(files) {
|
|
7088
|
+
const accepted = [];
|
|
7089
|
+
const rejected = [];
|
|
7090
|
+
const remaining = this.maxCount() - this.items().length;
|
|
7091
|
+
const maxBytes = this.maxFileSizeMb() != null ? this.maxFileSizeMb() * 1024 * 1024 : null;
|
|
7092
|
+
for (const file of files) {
|
|
7093
|
+
if (accepted.length >= remaining) {
|
|
7094
|
+
rejected.push({ file, reason: `Maximum ${this.maxCount()} image(s) allowed` });
|
|
7095
|
+
continue;
|
|
7096
|
+
}
|
|
7097
|
+
if (!this.isFileTypeAccepted(file)) {
|
|
7098
|
+
rejected.push({ file, reason: 'File type not accepted' });
|
|
7099
|
+
continue;
|
|
7100
|
+
}
|
|
7101
|
+
if (maxBytes !== null && file.size > maxBytes) {
|
|
7102
|
+
rejected.push({ file, reason: `File exceeds maximum size of ${this.maxFileSizeMb()} MB` });
|
|
7103
|
+
continue;
|
|
7104
|
+
}
|
|
7105
|
+
accepted.push(file);
|
|
7106
|
+
}
|
|
7107
|
+
if (accepted.length > 0) {
|
|
7108
|
+
this.filesAdded.emit(accepted);
|
|
7109
|
+
}
|
|
7110
|
+
if (rejected.length > 0) {
|
|
7111
|
+
this.filesRejected.emit(rejected);
|
|
7112
|
+
}
|
|
7113
|
+
}
|
|
7114
|
+
isFileTypeAccepted(file) {
|
|
7115
|
+
const accept = this.accept();
|
|
7116
|
+
if (!accept)
|
|
7117
|
+
return true;
|
|
7118
|
+
const acceptedTypes = accept.split(',').map(t => t.trim().toLowerCase());
|
|
7119
|
+
for (const type of acceptedTypes) {
|
|
7120
|
+
if (type === file.type.toLowerCase())
|
|
7121
|
+
return true;
|
|
7122
|
+
if (type.endsWith('/*')) {
|
|
7123
|
+
const category = type.slice(0, -2);
|
|
7124
|
+
if (file.type.toLowerCase().startsWith(category + '/'))
|
|
7125
|
+
return true;
|
|
7126
|
+
}
|
|
7127
|
+
if (type.startsWith('.')) {
|
|
7128
|
+
const ext = file.name.toLowerCase().slice(file.name.lastIndexOf('.'));
|
|
7129
|
+
if (ext === type)
|
|
7130
|
+
return true;
|
|
7131
|
+
}
|
|
7132
|
+
}
|
|
7133
|
+
return false;
|
|
7134
|
+
}
|
|
7135
|
+
// --- Removing ---
|
|
7136
|
+
removeItem(event, id) {
|
|
7137
|
+
event.stopPropagation();
|
|
7138
|
+
if (this.disabled())
|
|
7139
|
+
return;
|
|
7140
|
+
this.items.update(items => items.filter(item => item.id !== id));
|
|
7141
|
+
this.removed.emit(id);
|
|
7142
|
+
}
|
|
7143
|
+
// --- Pointer drag to reorder ---
|
|
7144
|
+
onTilePointerDown(event, id) {
|
|
7145
|
+
if (this.disabled())
|
|
7146
|
+
return;
|
|
7147
|
+
// Ignore drags starting on the remove button
|
|
7148
|
+
if (event.target.closest('.ui-image-uploader__remove'))
|
|
7149
|
+
return;
|
|
7150
|
+
this.pointerId = event.pointerId;
|
|
7151
|
+
this.pointerDownX = event.clientX;
|
|
7152
|
+
this.pointerDownY = event.clientY;
|
|
7153
|
+
this.pointerDownId = id;
|
|
7154
|
+
this.dragStarted = false;
|
|
7155
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
7156
|
+
}
|
|
7157
|
+
onTilePointerMove(event) {
|
|
7158
|
+
if (this.pointerId !== event.pointerId || this.pointerDownId === null)
|
|
7159
|
+
return;
|
|
7160
|
+
if (!this.dragStarted) {
|
|
7161
|
+
const distance = Math.hypot(event.clientX - this.pointerDownX, event.clientY - this.pointerDownY);
|
|
7162
|
+
if (distance < 6)
|
|
7163
|
+
return;
|
|
7164
|
+
this.dragStarted = true;
|
|
7165
|
+
this.dragId.set(this.pointerDownId);
|
|
7166
|
+
const tile = this.findTileElement(this.pointerDownId);
|
|
7167
|
+
this.ghostSize.set(tile?.offsetWidth ?? 0);
|
|
7168
|
+
}
|
|
7169
|
+
this.ghostX.set(event.clientX);
|
|
7170
|
+
this.ghostY.set(event.clientY);
|
|
7171
|
+
const targetIndex = this.tileIndexAtPoint(event.clientX, event.clientY);
|
|
7172
|
+
if (targetIndex === null)
|
|
7173
|
+
return;
|
|
7174
|
+
const currentIndex = this.items().findIndex(item => item.id === this.dragId());
|
|
7175
|
+
if (currentIndex >= 0 && targetIndex !== currentIndex) {
|
|
7176
|
+
this.moveItem(currentIndex, targetIndex, false);
|
|
7177
|
+
}
|
|
7178
|
+
}
|
|
7179
|
+
onTilePointerUp(event) {
|
|
7180
|
+
if (this.pointerId !== event.pointerId)
|
|
7181
|
+
return;
|
|
7182
|
+
if (this.dragStarted) {
|
|
7183
|
+
this.reordered.emit(this.items().map(item => item.id));
|
|
7184
|
+
}
|
|
7185
|
+
this.pointerId = null;
|
|
7186
|
+
this.pointerDownId = null;
|
|
7187
|
+
this.dragStarted = false;
|
|
7188
|
+
this.dragId.set(null);
|
|
7189
|
+
}
|
|
7190
|
+
findTileElement(id) {
|
|
7191
|
+
return this.grid().nativeElement.querySelector(`.ui-image-uploader__tile[data-id="${CSS.escape(id)}"]`);
|
|
7192
|
+
}
|
|
7193
|
+
tileIndexAtPoint(x, y) {
|
|
7194
|
+
const tiles = this.grid().nativeElement.querySelectorAll('.ui-image-uploader__tile');
|
|
7195
|
+
for (let i = 0; i < tiles.length; i++) {
|
|
7196
|
+
const rect = tiles[i].getBoundingClientRect();
|
|
7197
|
+
if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
|
|
7198
|
+
return i;
|
|
7199
|
+
}
|
|
7200
|
+
}
|
|
7201
|
+
return null;
|
|
7202
|
+
}
|
|
7203
|
+
// --- Keyboard reorder ---
|
|
7204
|
+
onTileKeyDown(event, id, index) {
|
|
7205
|
+
if (this.disabled())
|
|
7206
|
+
return;
|
|
7207
|
+
switch (event.key) {
|
|
7208
|
+
case ' ':
|
|
7209
|
+
case 'Enter':
|
|
7210
|
+
event.preventDefault();
|
|
7211
|
+
if (this.grabbedId() === id) {
|
|
7212
|
+
this.grabbedId.set(null);
|
|
7213
|
+
this.liveMessage.set(`Image dropped at position ${index + 1}`);
|
|
7214
|
+
}
|
|
7215
|
+
else {
|
|
7216
|
+
this.grabbedId.set(id);
|
|
7217
|
+
this.liveMessage.set(`Image ${index + 1} grabbed. Use arrow keys to move, Space to drop, Escape to cancel.`);
|
|
7218
|
+
}
|
|
7219
|
+
break;
|
|
7220
|
+
case 'Escape':
|
|
7221
|
+
if (this.grabbedId() === id) {
|
|
7222
|
+
event.preventDefault();
|
|
7223
|
+
this.grabbedId.set(null);
|
|
7224
|
+
this.liveMessage.set('Move cancelled');
|
|
7225
|
+
}
|
|
7226
|
+
break;
|
|
7227
|
+
case 'ArrowLeft':
|
|
7228
|
+
case 'ArrowUp':
|
|
7229
|
+
if (this.grabbedId() === id) {
|
|
7230
|
+
event.preventDefault();
|
|
7231
|
+
this.moveByKeyboard(index, index - 1, id);
|
|
7232
|
+
}
|
|
7233
|
+
break;
|
|
7234
|
+
case 'ArrowRight':
|
|
7235
|
+
case 'ArrowDown':
|
|
7236
|
+
if (this.grabbedId() === id) {
|
|
7237
|
+
event.preventDefault();
|
|
7238
|
+
this.moveByKeyboard(index, index + 1, id);
|
|
7239
|
+
}
|
|
7240
|
+
break;
|
|
7241
|
+
case 'Delete':
|
|
7242
|
+
case 'Backspace':
|
|
7243
|
+
event.preventDefault();
|
|
7244
|
+
this.removeItem(event, id);
|
|
7245
|
+
break;
|
|
7246
|
+
}
|
|
7247
|
+
}
|
|
7248
|
+
moveByKeyboard(from, to, id) {
|
|
7249
|
+
if (to < 0 || to >= this.items().length)
|
|
7250
|
+
return;
|
|
7251
|
+
this.moveItem(from, to, true);
|
|
7252
|
+
this.liveMessage.set(`Image moved to position ${to + 1} of ${this.items().length}`);
|
|
7253
|
+
// Keep focus on the moved tile after the DOM reorders
|
|
7254
|
+
setTimeout(() => this.findTileElement(id)?.focus());
|
|
7255
|
+
}
|
|
7256
|
+
moveItem(from, to, emit) {
|
|
7257
|
+
this.items.update(items => {
|
|
7258
|
+
const next = [...items];
|
|
7259
|
+
const [moved] = next.splice(from, 1);
|
|
7260
|
+
next.splice(to, 0, moved);
|
|
7261
|
+
return next;
|
|
7262
|
+
});
|
|
7263
|
+
if (emit) {
|
|
7264
|
+
this.reordered.emit(this.items().map(item => item.id));
|
|
7265
|
+
}
|
|
7266
|
+
}
|
|
7267
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ImageUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7268
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: ImageUploaderComponent, isStandalone: true, selector: "ui-image-uploader", inputs: { maxCount: { classPropertyName: "maxCount", publicName: "maxCount", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, maxFileSizeMb: { classPropertyName: "maxFileSizeMb", publicName: "maxFileSizeMb", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, coverLabel: { classPropertyName: "coverLabel", publicName: "coverLabel", isSignal: true, isRequired: false, transformFunction: null }, addLabel: { classPropertyName: "addLabel", publicName: "addLabel", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { items: "itemsChange", filesAdded: "filesAdded", filesRejected: "filesRejected", removed: "removed", reordered: "reordered" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, isSignal: true }, { propertyName: "grid", first: true, predicate: ["grid"], descendants: true, isSignal: true }], ngImport: i0, template: "<ul\n #grid\n class=\"ui-image-uploader\"\n [class.ui-image-uploader--drag-over]=\"dragOver()\"\n [class.ui-image-uploader--disabled]=\"disabled()\"\n role=\"list\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n @for (item of items(); track item.id; let i = $index) {\n <li\n class=\"ui-image-uploader__tile\"\n [class.ui-image-uploader__tile--error]=\"item.error\"\n [class.ui-image-uploader__tile--grabbed]=\"grabbedId() === item.id\"\n [class.ui-image-uploader__tile--dragging]=\"dragId() === item.id\"\n [attr.data-id]=\"item.id\"\n [attr.tabindex]=\"disabled() ? null : 0\"\n [attr.aria-label]=\"tileLabel(item, i)\"\n [attr.title]=\"item.error || null\"\n (pointerdown)=\"onTilePointerDown($event, item.id)\"\n (pointermove)=\"onTilePointerMove($event)\"\n (pointerup)=\"onTilePointerUp($event)\"\n (pointercancel)=\"onTilePointerUp($event)\"\n (keydown)=\"onTileKeyDown($event, item.id, i)\"\n >\n <img class=\"ui-image-uploader__image\" [src]=\"item.previewUrl\" alt=\"\" draggable=\"false\" />\n\n @if (i === 0) {\n <span class=\"ui-image-uploader__cover-badge\">{{ coverLabel() }}</span>\n }\n\n @if (item.progress != null && item.progress < 100) {\n <span class=\"ui-image-uploader__progress\" aria-hidden=\"true\">\n <span class=\"ui-image-uploader__progress-bar\">\n <span\n class=\"ui-image-uploader__progress-fill\"\n [style.width.%]=\"item.progress\"\n ></span>\n </span>\n <span class=\"ui-image-uploader__progress-text\">{{ item.progress }}%</span>\n </span>\n }\n\n @if (item.error) {\n <span class=\"ui-image-uploader__error-icon\" aria-hidden=\"true\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"/>\n <path d=\"M12 8v4M12 16h.01\"/>\n </svg>\n </span>\n }\n\n @if (!disabled()) {\n <button\n type=\"button\"\n class=\"ui-image-uploader__remove\"\n aria-label=\"Remove image\"\n (click)=\"removeItem($event, item.id)\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n }\n </li>\n }\n\n @if (canAdd()) {\n <li class=\"ui-image-uploader__add-item\">\n <button\n type=\"button\"\n class=\"ui-image-uploader__add\"\n [attr.aria-label]=\"addLabel()\"\n (click)=\"openFilePicker()\"\n >\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M12 5v14M5 12h14\"/>\n </svg>\n <span class=\"ui-image-uploader__add-text\">{{ addLabel() }}</span>\n </button>\n </li>\n }\n</ul>\n\n@if (dragItem(); as item) {\n <img\n class=\"ui-image-uploader__ghost\"\n [src]=\"item.previewUrl\"\n alt=\"\"\n aria-hidden=\"true\"\n [style.width.px]=\"ghostSize()\"\n [style.height.px]=\"ghostSize()\"\n [style.left.px]=\"ghostX()\"\n [style.top.px]=\"ghostY()\"\n />\n}\n\n<span class=\"ui-visually-hidden\" aria-live=\"polite\">{{ liveMessage() }}</span>\n\n<input\n #fileInput\n type=\"file\"\n class=\"ui-image-uploader__input\"\n [accept]=\"accept()\"\n multiple\n (change)=\"onFileSelected($event)\"\n/>\n", styles: [":host{display:block}.ui-image-uploader{display:grid;grid-template-columns:repeat(auto-fill,minmax(7.5rem,1fr));gap:var(--ui-spacing-sm);margin:0;padding:var(--ui-spacing-sm);list-style:none;border:2px dashed transparent;border-radius:var(--ui-radius-lg);transition:border-color var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-image-uploader--drag-over{border-color:var(--ui-primary);background-color:color-mix(in srgb,var(--ui-primary) 6%,transparent)}.ui-image-uploader--disabled{opacity:.6}.ui-image-uploader__tile{position:relative;aspect-ratio:1;overflow:hidden;border:1px solid var(--ui-image-uploader-tile-border);border-radius:var(--ui-radius-md);background-color:var(--ui-image-uploader-tile-bg);cursor:grab;touch-action:none;-webkit-user-select:none;user-select:none}.ui-image-uploader__tile:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-image-uploader__tile--grabbed{outline:2px solid var(--ui-primary);outline-offset:2px;box-shadow:var(--ui-shadow-md)}.ui-image-uploader__tile--dragging{opacity:.4;cursor:grabbing}.ui-image-uploader__tile--error{border:2px solid var(--ui-danger)}.ui-image-uploader__image{width:100%;height:100%;object-fit:cover;display:block;pointer-events:none}.ui-image-uploader__tile--error .ui-image-uploader__image{opacity:.5}.ui-image-uploader__cover-badge{position:absolute;left:var(--ui-spacing-xs);bottom:var(--ui-spacing-xs);padding:1px var(--ui-spacing-sm);border-radius:var(--ui-radius-sm);background-color:var(--ui-primary);color:var(--ui-primary-text);font-size:var(--ui-font-xs);font-weight:600;pointer-events:none}.ui-image-uploader__remove{position:absolute;top:var(--ui-spacing-xs);right:var(--ui-spacing-xs);display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:50%;background-color:var(--ui-image-uploader-overlay-bg);color:#fff;cursor:pointer;transition:background-color var(--ui-transition-fast)}.ui-image-uploader__remove:hover{background-color:var(--ui-danger)}.ui-image-uploader__remove:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-image-uploader__progress{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--ui-spacing-xs);padding:var(--ui-spacing-sm);background-color:var(--ui-image-uploader-overlay-bg);pointer-events:none}.ui-image-uploader__progress-bar{width:80%;height:4px;border-radius:2px;background-color:#ffffff4d;overflow:hidden}.ui-image-uploader__progress-fill{display:block;height:100%;border-radius:2px;background-color:var(--ui-primary);transition:width var(--ui-transition-fast)}.ui-image-uploader__progress-text{color:#fff;font-size:var(--ui-font-xs);font-weight:600}.ui-image-uploader__error-icon{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:var(--ui-danger);pointer-events:none}.ui-image-uploader__add-item{aspect-ratio:1}.ui-image-uploader__add{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--ui-spacing-xs);width:100%;height:100%;border:2px dashed var(--ui-border);border-radius:var(--ui-radius-md);background:transparent;color:var(--ui-text-muted);cursor:pointer;transition:border-color var(--ui-transition-fast),color var(--ui-transition-fast)}.ui-image-uploader__add:hover{border-color:var(--ui-border-hover);color:var(--ui-text)}.ui-image-uploader__add:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-image-uploader__add-text{font-size:var(--ui-font-xs);font-weight:500}.ui-image-uploader__ghost{position:fixed;z-index:1000;transform:translate(-50%,-50%) scale(.9);border-radius:var(--ui-radius-md);object-fit:cover;box-shadow:var(--ui-shadow-lg);opacity:.9;pointer-events:none}.ui-image-uploader__input{display:none}.ui-visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7269
|
+
}
|
|
7270
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ImageUploaderComponent, decorators: [{
|
|
7271
|
+
type: Component,
|
|
7272
|
+
args: [{ selector: 'ui-image-uploader', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ul\n #grid\n class=\"ui-image-uploader\"\n [class.ui-image-uploader--drag-over]=\"dragOver()\"\n [class.ui-image-uploader--disabled]=\"disabled()\"\n role=\"list\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n @for (item of items(); track item.id; let i = $index) {\n <li\n class=\"ui-image-uploader__tile\"\n [class.ui-image-uploader__tile--error]=\"item.error\"\n [class.ui-image-uploader__tile--grabbed]=\"grabbedId() === item.id\"\n [class.ui-image-uploader__tile--dragging]=\"dragId() === item.id\"\n [attr.data-id]=\"item.id\"\n [attr.tabindex]=\"disabled() ? null : 0\"\n [attr.aria-label]=\"tileLabel(item, i)\"\n [attr.title]=\"item.error || null\"\n (pointerdown)=\"onTilePointerDown($event, item.id)\"\n (pointermove)=\"onTilePointerMove($event)\"\n (pointerup)=\"onTilePointerUp($event)\"\n (pointercancel)=\"onTilePointerUp($event)\"\n (keydown)=\"onTileKeyDown($event, item.id, i)\"\n >\n <img class=\"ui-image-uploader__image\" [src]=\"item.previewUrl\" alt=\"\" draggable=\"false\" />\n\n @if (i === 0) {\n <span class=\"ui-image-uploader__cover-badge\">{{ coverLabel() }}</span>\n }\n\n @if (item.progress != null && item.progress < 100) {\n <span class=\"ui-image-uploader__progress\" aria-hidden=\"true\">\n <span class=\"ui-image-uploader__progress-bar\">\n <span\n class=\"ui-image-uploader__progress-fill\"\n [style.width.%]=\"item.progress\"\n ></span>\n </span>\n <span class=\"ui-image-uploader__progress-text\">{{ item.progress }}%</span>\n </span>\n }\n\n @if (item.error) {\n <span class=\"ui-image-uploader__error-icon\" aria-hidden=\"true\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"/>\n <path d=\"M12 8v4M12 16h.01\"/>\n </svg>\n </span>\n }\n\n @if (!disabled()) {\n <button\n type=\"button\"\n class=\"ui-image-uploader__remove\"\n aria-label=\"Remove image\"\n (click)=\"removeItem($event, item.id)\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n }\n </li>\n }\n\n @if (canAdd()) {\n <li class=\"ui-image-uploader__add-item\">\n <button\n type=\"button\"\n class=\"ui-image-uploader__add\"\n [attr.aria-label]=\"addLabel()\"\n (click)=\"openFilePicker()\"\n >\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M12 5v14M5 12h14\"/>\n </svg>\n <span class=\"ui-image-uploader__add-text\">{{ addLabel() }}</span>\n </button>\n </li>\n }\n</ul>\n\n@if (dragItem(); as item) {\n <img\n class=\"ui-image-uploader__ghost\"\n [src]=\"item.previewUrl\"\n alt=\"\"\n aria-hidden=\"true\"\n [style.width.px]=\"ghostSize()\"\n [style.height.px]=\"ghostSize()\"\n [style.left.px]=\"ghostX()\"\n [style.top.px]=\"ghostY()\"\n />\n}\n\n<span class=\"ui-visually-hidden\" aria-live=\"polite\">{{ liveMessage() }}</span>\n\n<input\n #fileInput\n type=\"file\"\n class=\"ui-image-uploader__input\"\n [accept]=\"accept()\"\n multiple\n (change)=\"onFileSelected($event)\"\n/>\n", styles: [":host{display:block}.ui-image-uploader{display:grid;grid-template-columns:repeat(auto-fill,minmax(7.5rem,1fr));gap:var(--ui-spacing-sm);margin:0;padding:var(--ui-spacing-sm);list-style:none;border:2px dashed transparent;border-radius:var(--ui-radius-lg);transition:border-color var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-image-uploader--drag-over{border-color:var(--ui-primary);background-color:color-mix(in srgb,var(--ui-primary) 6%,transparent)}.ui-image-uploader--disabled{opacity:.6}.ui-image-uploader__tile{position:relative;aspect-ratio:1;overflow:hidden;border:1px solid var(--ui-image-uploader-tile-border);border-radius:var(--ui-radius-md);background-color:var(--ui-image-uploader-tile-bg);cursor:grab;touch-action:none;-webkit-user-select:none;user-select:none}.ui-image-uploader__tile:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-image-uploader__tile--grabbed{outline:2px solid var(--ui-primary);outline-offset:2px;box-shadow:var(--ui-shadow-md)}.ui-image-uploader__tile--dragging{opacity:.4;cursor:grabbing}.ui-image-uploader__tile--error{border:2px solid var(--ui-danger)}.ui-image-uploader__image{width:100%;height:100%;object-fit:cover;display:block;pointer-events:none}.ui-image-uploader__tile--error .ui-image-uploader__image{opacity:.5}.ui-image-uploader__cover-badge{position:absolute;left:var(--ui-spacing-xs);bottom:var(--ui-spacing-xs);padding:1px var(--ui-spacing-sm);border-radius:var(--ui-radius-sm);background-color:var(--ui-primary);color:var(--ui-primary-text);font-size:var(--ui-font-xs);font-weight:600;pointer-events:none}.ui-image-uploader__remove{position:absolute;top:var(--ui-spacing-xs);right:var(--ui-spacing-xs);display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:50%;background-color:var(--ui-image-uploader-overlay-bg);color:#fff;cursor:pointer;transition:background-color var(--ui-transition-fast)}.ui-image-uploader__remove:hover{background-color:var(--ui-danger)}.ui-image-uploader__remove:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-image-uploader__progress{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--ui-spacing-xs);padding:var(--ui-spacing-sm);background-color:var(--ui-image-uploader-overlay-bg);pointer-events:none}.ui-image-uploader__progress-bar{width:80%;height:4px;border-radius:2px;background-color:#ffffff4d;overflow:hidden}.ui-image-uploader__progress-fill{display:block;height:100%;border-radius:2px;background-color:var(--ui-primary);transition:width var(--ui-transition-fast)}.ui-image-uploader__progress-text{color:#fff;font-size:var(--ui-font-xs);font-weight:600}.ui-image-uploader__error-icon{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:var(--ui-danger);pointer-events:none}.ui-image-uploader__add-item{aspect-ratio:1}.ui-image-uploader__add{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--ui-spacing-xs);width:100%;height:100%;border:2px dashed var(--ui-border);border-radius:var(--ui-radius-md);background:transparent;color:var(--ui-text-muted);cursor:pointer;transition:border-color var(--ui-transition-fast),color var(--ui-transition-fast)}.ui-image-uploader__add:hover{border-color:var(--ui-border-hover);color:var(--ui-text)}.ui-image-uploader__add:focus-visible{outline:2px solid var(--ui-primary);outline-offset:2px}.ui-image-uploader__add-text{font-size:var(--ui-font-xs);font-weight:500}.ui-image-uploader__ghost{position:fixed;z-index:1000;transform:translate(-50%,-50%) scale(.9);border-radius:var(--ui-radius-md);object-fit:cover;box-shadow:var(--ui-shadow-lg);opacity:.9;pointer-events:none}.ui-image-uploader__input{display:none}.ui-visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
|
|
7273
|
+
}], propDecorators: { maxCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxCount", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxFileSizeMb: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSizeMb", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], coverLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "coverLabel", required: false }] }], addLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addLabel", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }, { type: i0.Output, args: ["itemsChange"] }], filesAdded: [{ type: i0.Output, args: ["filesAdded"] }], filesRejected: [{ type: i0.Output, args: ["filesRejected"] }], removed: [{ type: i0.Output, args: ["removed"] }], reordered: [{ type: i0.Output, args: ["reordered"] }], fileInput: [{ type: i0.ViewChild, args: ['fileInput', { isSignal: true }] }], grid: [{ type: i0.ViewChild, args: ['grid', { isSignal: true }] }] } });
|
|
7274
|
+
|
|
6394
7275
|
class ShellComponent {
|
|
6395
7276
|
variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : []));
|
|
6396
7277
|
sidebarService = inject(SidebarService);
|
|
@@ -7729,5 +8610,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
|
|
|
7729
8610
|
* Generated bundle index. Do not edit.
|
|
7730
8611
|
*/
|
|
7731
8612
|
|
|
7732
|
-
export { AccordionComponent, AccordionHeaderDirective, AccordionItemComponent, AlertComponent, BadgeComponent, ButtonComponent, CardComponent, CellTemplateDirective, CellValuePipe, CheckboxComponent, ChipInputComponent, ChipTemplateDirective, CircularProgressComponent, ContentComponent, ContextMenuDirective, DIALOG_DATA, DIALOG_REF, DatepickerComponent, DatetimepickerComponent, DialogRef, DialogService, DropdownComponent, DropdownDividerComponent, DropdownItemComponent, DropdownTriggerDirective, DynamicTabsComponent, FileChooserComponent, FilePreviewPipe, FileSizePipe, FooterComponent, InputComponent, JsonTreeComponent, LOADABLE, LoadingDirective, LoadingService, ModalComponent, NavbarComponent, OptionComponent, OptionTemplateDirective, PaginationComponent, ProgressComponent, RadioComponent, RadioGroupComponent, RangeSliderComponent, SelectComponent, ShellComponent, SidebarComponent, SidebarService, SidebarToggleComponent, SliderComponent, SpinnerComponent, SplitComponent, SplitPaneComponent, SwitchComponent, TAB_DATA, TAB_REF, TREE_HOST, TabActivePipe, TabComponent, TabIconDirective, TabRef, TableComponent, TabsComponent, TabsService, TemplateInputComponent, TemplateInputSuffixDirective, TextareaComponent, TimepickerComponent, ToastRef, ToastService, TooltipDirective, TreeComponent, TreeNodeComponent, Validators, VariablePopoverDirective, jsonToTreeNodes };
|
|
8613
|
+
export { AccordionComponent, AccordionHeaderDirective, AccordionItemComponent, AlertComponent, BadgeComponent, BreadcrumbComponent, BreadcrumbSeparatorDirective, ButtonComponent, CardComponent, CarouselComponent, CellTemplateDirective, CellValuePipe, CheckboxComponent, ChipInputComponent, ChipTemplateDirective, CircularProgressComponent, ContentComponent, ContextMenuDirective, DIALOG_DATA, DIALOG_REF, DatepickerComponent, DatetimepickerComponent, DialogRef, DialogService, DropdownComponent, DropdownDividerComponent, DropdownItemComponent, DropdownTriggerDirective, DynamicTabsComponent, FileChooserComponent, FilePreviewPipe, FileSizePipe, FooterComponent, ImageUploaderComponent, InputComponent, JsonTreeComponent, LOADABLE, LightboxComponent, LightboxService, LoadingDirective, LoadingService, ModalComponent, NavbarComponent, NumberRangeSliderComponent, OptionComponent, OptionTemplateDirective, PaginationComponent, ProgressComponent, RadioComponent, RadioGroupComponent, RangeSliderComponent, SegmentedComponent, SelectComponent, ShellComponent, SidebarComponent, SidebarService, SidebarToggleComponent, SkeletonComponent, SliderComponent, SpinnerComponent, SplitComponent, SplitPaneComponent, StepperComponent, SwitchComponent, TAB_DATA, TAB_REF, TREE_HOST, TabActivePipe, TabComponent, TabIconDirective, TabRef, TableComponent, TabsComponent, TabsService, TemplateInputComponent, TemplateInputSuffixDirective, TextareaComponent, TimepickerComponent, ToastRef, ToastService, TooltipDirective, TreeComponent, TreeNodeComponent, Validators, VariablePopoverDirective, jsonToTreeNodes };
|
|
7733
8614
|
//# sourceMappingURL=m1z23r-ngx-ui.mjs.map
|