@maro-tech/form 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/fesm2022/maro-tech-form.mjs +441 -162
- package/fesm2022/maro-tech-form.mjs.map +1 -1
- package/package.json +2 -2
- package/types/maro-tech-form.d.ts +111 -12
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { signal, Injectable, inject, InjectionToken, input, output, ViewChild, Component, ChangeDetectorRef, DestroyRef, EventEmitter, ElementRef, forwardRef, booleanAttribute, Output, Input, ChangeDetectionStrategy, ViewContainerRef, computed } from '@angular/core';
|
|
2
|
+
import { signal, Injectable, inject, InjectionToken, input, output, ViewChild, Component, ChangeDetectorRef, DestroyRef, EventEmitter, ElementRef, forwardRef, booleanAttribute, HostListener, Output, Input, ChangeDetectionStrategy, ViewContainerRef, computed } from '@angular/core';
|
|
3
3
|
import { HttpClient } from '@angular/common/http';
|
|
4
4
|
import * as i1$2 from '@angular/common';
|
|
5
5
|
import { CommonModule } from '@angular/common';
|
|
@@ -8,10 +8,10 @@ import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
|
8
8
|
import { Subject, debounceTime, distinctUntilChanged, forkJoin, Observable, from, switchMap, of } from 'rxjs';
|
|
9
9
|
import { BrowserMultiFormatOneDReader } from '@zxing/browser';
|
|
10
10
|
import { DecodeHintType, BarcodeFormat } from '@zxing/library';
|
|
11
|
-
import { UiButtonComponent } from '@maro-tech/
|
|
11
|
+
import { UiButtonComponent } from '@maro-tech/core';
|
|
12
12
|
import { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
|
|
13
13
|
import * as i1 from 'lucide-angular';
|
|
14
|
-
import { X, ChevronDown, Check, LucideAngularModule } from 'lucide-angular';
|
|
14
|
+
import { X, ChevronDown, Check, LucideAngularModule, CalendarDays, ChevronLeft, ChevronRight, Eye, EyeOff } from 'lucide-angular';
|
|
15
15
|
import * as i1$1 from '@angular/cdk/drag-drop';
|
|
16
16
|
import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
|
|
17
17
|
import { Router } from '@angular/router';
|
|
@@ -35,10 +35,10 @@ class UiFormContext {
|
|
|
35
35
|
this.errors.set({});
|
|
36
36
|
this.loading.set(false);
|
|
37
37
|
}
|
|
38
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
39
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
38
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiFormContext, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
39
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiFormContext });
|
|
40
40
|
}
|
|
41
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
41
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiFormContext, decorators: [{
|
|
42
42
|
type: Injectable
|
|
43
43
|
}] });
|
|
44
44
|
|
|
@@ -48,10 +48,10 @@ class MaroFormsApiService {
|
|
|
48
48
|
const suffix = query ? `?q=${encodeURIComponent(query)}` : '';
|
|
49
49
|
return this.http.get(`/api/suggest/${encodeURIComponent(name)}${suffix}`);
|
|
50
50
|
}
|
|
51
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
52
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
51
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: MaroFormsApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
52
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: MaroFormsApiService, providedIn: 'root' });
|
|
53
53
|
}
|
|
54
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
54
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: MaroFormsApiService, decorators: [{
|
|
55
55
|
type: Injectable,
|
|
56
56
|
args: [{ providedIn: 'root' }]
|
|
57
57
|
}] });
|
|
@@ -72,10 +72,10 @@ class UiFormLookupService {
|
|
|
72
72
|
: `/api${path}`;
|
|
73
73
|
return this.http.get(requestUrl);
|
|
74
74
|
}
|
|
75
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
76
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
75
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiFormLookupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
76
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiFormLookupService });
|
|
77
77
|
}
|
|
78
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
78
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiFormLookupService, decorators: [{
|
|
79
79
|
type: Injectable
|
|
80
80
|
}] });
|
|
81
81
|
|
|
@@ -365,8 +365,8 @@ class UiBarcodeScannerInputComponent {
|
|
|
365
365
|
return null;
|
|
366
366
|
}
|
|
367
367
|
}
|
|
368
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
369
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
368
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiBarcodeScannerInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
369
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiBarcodeScannerInputComponent, isStandalone: true, selector: "forms-barcode-scanner-input", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, autoOpen: { classPropertyName: "autoOpen", publicName: "autoOpen", isSignal: true, isRequired: false, transformFunction: null }, searchButtonLabel: { classPropertyName: "searchButtonLabel", publicName: "searchButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, openCameraLabel: { classPropertyName: "openCameraLabel", publicName: "openCameraLabel", isSignal: true, isRequired: false, transformFunction: null }, closeCameraLabel: { classPropertyName: "closeCameraLabel", publicName: "closeCameraLabel", isSignal: true, isRequired: false, transformFunction: null }, cameraTitle: { classPropertyName: "cameraTitle", publicName: "cameraTitle", isSignal: true, isRequired: false, transformFunction: null }, cameraStartingLabel: { classPropertyName: "cameraStartingLabel", publicName: "cameraStartingLabel", isSignal: true, isRequired: false, transformFunction: null }, cameraHint: { classPropertyName: "cameraHint", publicName: "cameraHint", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", scanned: "scanned", searchRequested: "searchRequested", cameraStateChange: "cameraStateChange" }, viewQueries: [{ propertyName: "cameraVideo", first: true, predicate: ["cameraVideo"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
370
370
|
<div class="space-y-2">
|
|
371
371
|
@if (label()) {
|
|
372
372
|
<label class="flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500" for="barcode-scanner-input">
|
|
@@ -388,7 +388,7 @@ class UiBarcodeScannerInputComponent {
|
|
|
388
388
|
[ngModel]="value()"
|
|
389
389
|
(ngModelChange)="onValueChange($event)"
|
|
390
390
|
(keydown.enter)="requestSearch()"
|
|
391
|
-
class="w-full rounded-
|
|
391
|
+
class="w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200"
|
|
392
392
|
[placeholder]="placeholder()"
|
|
393
393
|
/>
|
|
394
394
|
@if (hint()) {
|
|
@@ -421,7 +421,7 @@ class UiBarcodeScannerInputComponent {
|
|
|
421
421
|
</div>
|
|
422
422
|
|
|
423
423
|
@if (isCameraStarting()) {
|
|
424
|
-
<div class="rounded-
|
|
424
|
+
<div class="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-500">
|
|
425
425
|
{{ cameraStartingLabel() }}
|
|
426
426
|
</div>
|
|
427
427
|
}
|
|
@@ -442,7 +442,7 @@ class UiBarcodeScannerInputComponent {
|
|
|
442
442
|
</button>
|
|
443
443
|
</div>
|
|
444
444
|
|
|
445
|
-
<div class="overflow-hidden rounded-
|
|
445
|
+
<div class="overflow-hidden rounded-xl bg-black">
|
|
446
446
|
<video #cameraVideo class="h-[260px] w-full object-cover" autoplay muted playsinline></video>
|
|
447
447
|
</div>
|
|
448
448
|
|
|
@@ -453,14 +453,14 @@ class UiBarcodeScannerInputComponent {
|
|
|
453
453
|
}
|
|
454
454
|
|
|
455
455
|
@if (cameraError()) {
|
|
456
|
-
<div class="rounded-
|
|
456
|
+
<div class="rounded-xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700">
|
|
457
457
|
{{ cameraError() }}
|
|
458
458
|
</div>
|
|
459
459
|
}
|
|
460
460
|
</div>
|
|
461
461
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }] });
|
|
462
462
|
}
|
|
463
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
463
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiBarcodeScannerInputComponent, decorators: [{
|
|
464
464
|
type: Component,
|
|
465
465
|
args: [{
|
|
466
466
|
selector: 'forms-barcode-scanner-input',
|
|
@@ -488,7 +488,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
488
488
|
[ngModel]="value()"
|
|
489
489
|
(ngModelChange)="onValueChange($event)"
|
|
490
490
|
(keydown.enter)="requestSearch()"
|
|
491
|
-
class="w-full rounded-
|
|
491
|
+
class="w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200"
|
|
492
492
|
[placeholder]="placeholder()"
|
|
493
493
|
/>
|
|
494
494
|
@if (hint()) {
|
|
@@ -521,7 +521,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
521
521
|
</div>
|
|
522
522
|
|
|
523
523
|
@if (isCameraStarting()) {
|
|
524
|
-
<div class="rounded-
|
|
524
|
+
<div class="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-500">
|
|
525
525
|
{{ cameraStartingLabel() }}
|
|
526
526
|
</div>
|
|
527
527
|
}
|
|
@@ -542,7 +542,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
542
542
|
</button>
|
|
543
543
|
</div>
|
|
544
544
|
|
|
545
|
-
<div class="overflow-hidden rounded-
|
|
545
|
+
<div class="overflow-hidden rounded-xl bg-black">
|
|
546
546
|
<video #cameraVideo class="h-[260px] w-full object-cover" autoplay muted playsinline></video>
|
|
547
547
|
</div>
|
|
548
548
|
|
|
@@ -553,7 +553,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
553
553
|
}
|
|
554
554
|
|
|
555
555
|
@if (cameraError()) {
|
|
556
|
-
<div class="rounded-
|
|
556
|
+
<div class="rounded-xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700">
|
|
557
557
|
{{ cameraError() }}
|
|
558
558
|
</div>
|
|
559
559
|
}
|
|
@@ -565,14 +565,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
565
565
|
args: ['cameraVideo']
|
|
566
566
|
}] } });
|
|
567
567
|
|
|
568
|
+
class UiPopupService {
|
|
569
|
+
activeClose = null;
|
|
570
|
+
open(close) {
|
|
571
|
+
const previousClose = this.activeClose;
|
|
572
|
+
this.activeClose = close;
|
|
573
|
+
if (previousClose && previousClose !== close) {
|
|
574
|
+
previousClose();
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
close(close) {
|
|
578
|
+
if (this.activeClose === close) {
|
|
579
|
+
this.activeClose = null;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiPopupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
583
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiPopupService, providedIn: 'root' });
|
|
584
|
+
}
|
|
585
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiPopupService, decorators: [{
|
|
586
|
+
type: Injectable,
|
|
587
|
+
args: [{ providedIn: 'root' }]
|
|
588
|
+
}] });
|
|
589
|
+
|
|
568
590
|
class UiSelectComponent {
|
|
569
591
|
closeIcon = X;
|
|
570
592
|
chevronDownIcon = ChevronDown;
|
|
571
593
|
checkIcon = Check;
|
|
572
|
-
static openInstance = null;
|
|
573
594
|
cdr = inject(ChangeDetectorRef);
|
|
574
595
|
destroyRef = inject(DestroyRef);
|
|
575
596
|
http = inject(HttpClient);
|
|
597
|
+
popupService = inject(UiPopupService);
|
|
598
|
+
closeActivePopup = () => this.closeDropdown();
|
|
576
599
|
label;
|
|
577
600
|
placeholder;
|
|
578
601
|
name;
|
|
@@ -602,6 +625,9 @@ class UiSelectComponent {
|
|
|
602
625
|
panelClass = '';
|
|
603
626
|
valueChange = new EventEmitter();
|
|
604
627
|
searchChange = new EventEmitter();
|
|
628
|
+
popupMinWidth = 300;
|
|
629
|
+
popupViewportMargin = 16;
|
|
630
|
+
popupOffset = 8;
|
|
605
631
|
dropdownTrigger;
|
|
606
632
|
dropdownPositions = [
|
|
607
633
|
{
|
|
@@ -609,18 +635,18 @@ class UiSelectComponent {
|
|
|
609
635
|
originY: 'bottom',
|
|
610
636
|
overlayX: 'start',
|
|
611
637
|
overlayY: 'top',
|
|
612
|
-
offsetY:
|
|
638
|
+
offsetY: this.popupOffset,
|
|
613
639
|
},
|
|
614
640
|
{
|
|
615
641
|
originX: 'start',
|
|
616
642
|
originY: 'top',
|
|
617
643
|
overlayX: 'start',
|
|
618
644
|
overlayY: 'bottom',
|
|
619
|
-
offsetY: -
|
|
645
|
+
offsetY: -this.popupOffset,
|
|
620
646
|
},
|
|
621
647
|
];
|
|
622
648
|
isOpen = false;
|
|
623
|
-
|
|
649
|
+
popupWidth = 0;
|
|
624
650
|
value = '';
|
|
625
651
|
multiValue = [];
|
|
626
652
|
selectedOptions = [];
|
|
@@ -644,9 +670,6 @@ class UiSelectComponent {
|
|
|
644
670
|
this.destroyRef.onDestroy(() => {
|
|
645
671
|
this.searchChanges$.complete();
|
|
646
672
|
this.dictionaryRequestVersions.clear();
|
|
647
|
-
if (UiSelectComponent.openInstance === this) {
|
|
648
|
-
UiSelectComponent.openInstance = null;
|
|
649
|
-
}
|
|
650
673
|
});
|
|
651
674
|
}
|
|
652
675
|
ngOnChanges(changes) {
|
|
@@ -684,14 +707,12 @@ class UiSelectComponent {
|
|
|
684
707
|
this.closeDropdown();
|
|
685
708
|
return;
|
|
686
709
|
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
}
|
|
690
|
-
this.triggerWidth = this.dropdownTrigger?.nativeElement.getBoundingClientRect().width ?? 0;
|
|
710
|
+
const fieldWidth = this.dropdownTrigger.nativeElement.getBoundingClientRect().width;
|
|
711
|
+
this.popupWidth = Math.max(fieldWidth, this.popupMinWidth);
|
|
691
712
|
this.isOpen = true;
|
|
713
|
+
this.popupService.open(this.closeActivePopup);
|
|
692
714
|
this.searchTerm = '';
|
|
693
715
|
this.searchChanges$.next('');
|
|
694
|
-
UiSelectComponent.openInstance = this;
|
|
695
716
|
this.cdr.markForCheck();
|
|
696
717
|
}
|
|
697
718
|
selectOption(option, event) {
|
|
@@ -725,11 +746,19 @@ class UiSelectComponent {
|
|
|
725
746
|
this.onTouched();
|
|
726
747
|
this.searchTerm = '';
|
|
727
748
|
this.searchChanges$.next('');
|
|
728
|
-
|
|
729
|
-
UiSelectComponent.openInstance = null;
|
|
730
|
-
}
|
|
749
|
+
this.popupService.close(this.closeActivePopup);
|
|
731
750
|
this.cdr.markForCheck();
|
|
732
751
|
}
|
|
752
|
+
onDocumentClick() {
|
|
753
|
+
if (this.isOpen) {
|
|
754
|
+
this.closeDropdown();
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
onEscape() {
|
|
758
|
+
if (this.isOpen) {
|
|
759
|
+
this.closeDropdown();
|
|
760
|
+
}
|
|
761
|
+
}
|
|
733
762
|
get displayLabel() {
|
|
734
763
|
if (this.multiple) {
|
|
735
764
|
if (!this.selectedOptions.length) {
|
|
@@ -907,16 +936,16 @@ class UiSelectComponent {
|
|
|
907
936
|
loadSuggestItem(name, key) {
|
|
908
937
|
return this.http.get(`/api/suggest/${encodeURIComponent(name)}/${encodeURIComponent(key)}`);
|
|
909
938
|
}
|
|
910
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
911
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
939
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
940
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiSelectComponent, isStandalone: true, selector: "forms-select", inputs: { label: "label", placeholder: "placeholder", name: "name", data: "data", required: "required", fullWidth: "fullWidth", disabled: "disabled", multiple: ["multiple", "multiple", booleanAttribute], includeBlankOption: "includeBlankOption", blankOptionLabel: "blankOptionLabel", emptyStateLabel: "emptyStateLabel", searchable: "searchable", remoteSearch: "remoteSearch", searchPlaceholder: "searchPlaceholder", options: "options", error: "error", hint: "hint", triggerClass: "triggerClass", panelClass: "panelClass" }, outputs: { valueChange: "valueChange", searchChange: "searchChange" }, host: { listeners: { "document:click": "onDocumentClick()", "document:keydown.escape": "onEscape()" } }, providers: [
|
|
912
941
|
{
|
|
913
942
|
provide: NG_VALUE_ACCESSOR,
|
|
914
943
|
useExisting: forwardRef(() => UiSelectComponent),
|
|
915
944
|
multi: true,
|
|
916
945
|
},
|
|
917
|
-
], viewQueries: [{ propertyName: "dropdownTrigger", first: true, predicate: ["dropdownTrigger"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n>\n <!-- LABEL -->\n @if (label || (hint && !error)) {\n <div class=\"flex items-center justify-between\">\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) { <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span> }\n </span>\n\n @if (hint && !error) {\n <span class=\"text-[0.65rem] text-slate-400\">\n {{ hint }}\n </span>\n }\n </div>\n }\n\n <!-- SELECT -->\n <div class=\"relative\" [class.w-full]=\"fullWidth\">\n\n <button\n cdkOverlayOrigin\n #dropdownTrigger=\"cdkOverlayOrigin\"\n type=\"button\"\n class=\"flex w-full flex-
|
|
946
|
+
], viewQueries: [{ propertyName: "dropdownTrigger", first: true, predicate: ["dropdownTrigger"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n>\n <!-- LABEL -->\n @if (label || (hint && !error)) {\n <div class=\"flex items-center justify-between\">\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) { <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span> }\n </span>\n\n @if (hint && !error) {\n <span class=\"text-[0.65rem] text-slate-400\">\n {{ hint }}\n </span>\n }\n </div>\n }\n\n <!-- SELECT -->\n <div class=\"relative\" [class.w-full]=\"fullWidth\">\n\n <button\n cdkOverlayOrigin\n #dropdownTrigger=\"cdkOverlayOrigin\"\n type=\"button\"\n class=\"flex min-h-10 w-full flex-nowrap items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 transition hover:border-slate-300 focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [class]=\"triggerClass\"\n [class.opacity-50]=\"disabled\"\n [disabled]=\"disabled\"\n (click)=\"toggleDropdown($event)\"\n >\n\n <span class=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\" [class.-ml-2]=\"multiple\">\n <!-- MULTIPLE MODE -->\n @if (multiple) {\n\n @if (selectedOptions.length) {\n\n @for (option of selectedOptions; track option.value) {\n <span\n class=\"inline-flex h-6 shrink-0 items-center gap-1 rounded-md bg-slate-100 px-2 text-xs font-medium text-slate-700\"\n >\n {{ option.label }}\n\n <span\n role=\"button\"\n tabindex=\"0\"\n class=\"text-slate-400 hover:text-rose-500 transition-colors\"\n (click)=\"removeOption(option, $event)\"\n (keydown.enter)=\"removeOption(option, $event)\"\n (keydown.space)=\"$event.preventDefault(); removeOption(option, $event)\"\n >\n <lucide-icon [img]=\"closeIcon\" class=\"h-4 w-4 shrink-0\"></lucide-icon>\n </span>\n </span>\n }\n\n } @else {\n <span class=\"text-slate-400\">\n {{ placeholder ?? blankOptionLabel }}\n </span>\n }\n\n } @else {\n\n <!-- SINGLE MODE -->\n @if (selectedOptions[0]?.imageUrl) {\n <img [src]=\"selectedOptions[0]?.imageUrl\" alt=\"\" class=\"h-7 w-7 rounded object-cover\" />\n }\n <span class=\"min-w-0 truncate\">\n {{ selectedOptions[0]?.label ?? placeholder ?? blankOptionLabel }}\n </span>\n\n }\n </span>\n\n <lucide-icon [img]=\"chevronDownIcon\" class=\"shrink-0 text-xs text-slate-400\"></lucide-icon>\n\n </button>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"dropdownTrigger\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayPositions]=\"dropdownPositions\"\n [cdkConnectedOverlayViewportMargin]=\"popupViewportMargin\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n [cdkConnectedOverlayPush]=\"true\"\n (detach)=\"closeDropdown()\"\n >\n <!-- DROPDOWN -->\n <div\n class=\"z-50 w-full max-w-[calc(100vw-2rem)] rounded-xl border border-slate-200 bg-white shadow-lg\"\n [style.width.px]=\"popupWidth\"\n [style.max-width]=\"'calc(100vw - 2rem)'\"\n [class]=\"panelClass\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (searchable) {\n <div class=\"border-b border-slate-100 p-2\">\n <input\n type=\"text\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 outline-none transition focus:border-slate-900 focus:ring-2 focus:ring-slate-200\"\n [placeholder]=\"searchPlaceholder\"\n [ngModel]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange($event)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n />\n </div>\n }\n\n <div class=\"max-h-60 overflow-auto\">\n @if (!visibleOptions.length) {\n <div class=\"px-4 py-3 text-sm text-slate-500\">\n @if (isDictionaryLoading && data) {\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F...\n } @else {\n {{ emptyStateLabel }}\n }\n </div>\n } @else {\n @for (option of visibleOptions; track trackOption($index, option)) {\n <button\n type=\"button\"\n class=\"flex w-full items-start justify-between gap-3 whitespace-normal break-words px-4 py-2 text-left text-sm hover:bg-slate-50\"\n [class.bg-slate-100]=\"isSelected(option)\"\n (click)=\"selectOption(option, $event)\"\n >\n <span class=\"flex min-w-0 flex-1 items-center gap-2\">\n @if (option.imageUrl) {\n <img [src]=\"option.imageUrl\" alt=\"\" class=\"h-8 w-8 shrink-0 rounded object-cover\" />\n }\n <span class=\"whitespace-normal break-words\">{{ option.label }}</span>\n </span>\n\n @if (isSelected(option)) {\n <lucide-icon [img]=\"checkIcon\" class=\"text-xs text-sky-500\"></lucide-icon>\n }\n </button>\n }\n }\n </div>\n\n </div>\n </ng-template>\n\n </div>\n\n @if (error) {\n <p class=\"text-[0.7rem] text-rose-500\">\n {{ error }}\n </p>\n }\n\n</div>\n", dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
918
947
|
}
|
|
919
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
948
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiSelectComponent, decorators: [{
|
|
920
949
|
type: Component,
|
|
921
950
|
args: [{ selector: 'forms-select', standalone: true, imports: [LucideAngularModule, CommonModule, FormsModule, CdkConnectedOverlay, CdkOverlayOrigin], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
922
951
|
{
|
|
@@ -924,7 +953,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
924
953
|
useExisting: forwardRef(() => UiSelectComponent),
|
|
925
954
|
multi: true,
|
|
926
955
|
},
|
|
927
|
-
], template: "<div\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n>\n <!-- LABEL -->\n @if (label || (hint && !error)) {\n <div class=\"flex items-center justify-between\">\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) { <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span> }\n </span>\n\n @if (hint && !error) {\n <span class=\"text-[0.65rem] text-slate-400\">\n {{ hint }}\n </span>\n }\n </div>\n }\n\n <!-- SELECT -->\n <div class=\"relative\" [class.w-full]=\"fullWidth\">\n\n <button\n cdkOverlayOrigin\n #dropdownTrigger=\"cdkOverlayOrigin\"\n type=\"button\"\n class=\"flex w-full flex-
|
|
956
|
+
], template: "<div\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n>\n <!-- LABEL -->\n @if (label || (hint && !error)) {\n <div class=\"flex items-center justify-between\">\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) { <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span> }\n </span>\n\n @if (hint && !error) {\n <span class=\"text-[0.65rem] text-slate-400\">\n {{ hint }}\n </span>\n }\n </div>\n }\n\n <!-- SELECT -->\n <div class=\"relative\" [class.w-full]=\"fullWidth\">\n\n <button\n cdkOverlayOrigin\n #dropdownTrigger=\"cdkOverlayOrigin\"\n type=\"button\"\n class=\"flex min-h-10 w-full flex-nowrap items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 transition hover:border-slate-300 focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [class]=\"triggerClass\"\n [class.opacity-50]=\"disabled\"\n [disabled]=\"disabled\"\n (click)=\"toggleDropdown($event)\"\n >\n\n <span class=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\" [class.-ml-2]=\"multiple\">\n <!-- MULTIPLE MODE -->\n @if (multiple) {\n\n @if (selectedOptions.length) {\n\n @for (option of selectedOptions; track option.value) {\n <span\n class=\"inline-flex h-6 shrink-0 items-center gap-1 rounded-md bg-slate-100 px-2 text-xs font-medium text-slate-700\"\n >\n {{ option.label }}\n\n <span\n role=\"button\"\n tabindex=\"0\"\n class=\"text-slate-400 hover:text-rose-500 transition-colors\"\n (click)=\"removeOption(option, $event)\"\n (keydown.enter)=\"removeOption(option, $event)\"\n (keydown.space)=\"$event.preventDefault(); removeOption(option, $event)\"\n >\n <lucide-icon [img]=\"closeIcon\" class=\"h-4 w-4 shrink-0\"></lucide-icon>\n </span>\n </span>\n }\n\n } @else {\n <span class=\"text-slate-400\">\n {{ placeholder ?? blankOptionLabel }}\n </span>\n }\n\n } @else {\n\n <!-- SINGLE MODE -->\n @if (selectedOptions[0]?.imageUrl) {\n <img [src]=\"selectedOptions[0]?.imageUrl\" alt=\"\" class=\"h-7 w-7 rounded object-cover\" />\n }\n <span class=\"min-w-0 truncate\">\n {{ selectedOptions[0]?.label ?? placeholder ?? blankOptionLabel }}\n </span>\n\n }\n </span>\n\n <lucide-icon [img]=\"chevronDownIcon\" class=\"shrink-0 text-xs text-slate-400\"></lucide-icon>\n\n </button>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"dropdownTrigger\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayPositions]=\"dropdownPositions\"\n [cdkConnectedOverlayViewportMargin]=\"popupViewportMargin\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n [cdkConnectedOverlayPush]=\"true\"\n (detach)=\"closeDropdown()\"\n >\n <!-- DROPDOWN -->\n <div\n class=\"z-50 w-full max-w-[calc(100vw-2rem)] rounded-xl border border-slate-200 bg-white shadow-lg\"\n [style.width.px]=\"popupWidth\"\n [style.max-width]=\"'calc(100vw - 2rem)'\"\n [class]=\"panelClass\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (searchable) {\n <div class=\"border-b border-slate-100 p-2\">\n <input\n type=\"text\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 outline-none transition focus:border-slate-900 focus:ring-2 focus:ring-slate-200\"\n [placeholder]=\"searchPlaceholder\"\n [ngModel]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange($event)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n />\n </div>\n }\n\n <div class=\"max-h-60 overflow-auto\">\n @if (!visibleOptions.length) {\n <div class=\"px-4 py-3 text-sm text-slate-500\">\n @if (isDictionaryLoading && data) {\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F...\n } @else {\n {{ emptyStateLabel }}\n }\n </div>\n } @else {\n @for (option of visibleOptions; track trackOption($index, option)) {\n <button\n type=\"button\"\n class=\"flex w-full items-start justify-between gap-3 whitespace-normal break-words px-4 py-2 text-left text-sm hover:bg-slate-50\"\n [class.bg-slate-100]=\"isSelected(option)\"\n (click)=\"selectOption(option, $event)\"\n >\n <span class=\"flex min-w-0 flex-1 items-center gap-2\">\n @if (option.imageUrl) {\n <img [src]=\"option.imageUrl\" alt=\"\" class=\"h-8 w-8 shrink-0 rounded object-cover\" />\n }\n <span class=\"whitespace-normal break-words\">{{ option.label }}</span>\n </span>\n\n @if (isSelected(option)) {\n <lucide-icon [img]=\"checkIcon\" class=\"text-xs text-sky-500\"></lucide-icon>\n }\n </button>\n }\n }\n </div>\n\n </div>\n </ng-template>\n\n </div>\n\n @if (error) {\n <p class=\"text-[0.7rem] text-rose-500\">\n {{ error }}\n </p>\n }\n\n</div>\n" }]
|
|
928
957
|
}], ctorParameters: () => [], propDecorators: { label: [{
|
|
929
958
|
type: Input
|
|
930
959
|
}], placeholder: [{
|
|
@@ -971,10 +1000,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
971
1000
|
}], dropdownTrigger: [{
|
|
972
1001
|
type: ViewChild,
|
|
973
1002
|
args: ['dropdownTrigger', { static: true, read: ElementRef }]
|
|
1003
|
+
}], onDocumentClick: [{
|
|
1004
|
+
type: HostListener,
|
|
1005
|
+
args: ['document:click']
|
|
1006
|
+
}], onEscape: [{
|
|
1007
|
+
type: HostListener,
|
|
1008
|
+
args: ['document:keydown.escape']
|
|
974
1009
|
}] } });
|
|
975
1010
|
|
|
976
1011
|
class UiDateInputComponent {
|
|
977
1012
|
cdr = inject(ChangeDetectorRef);
|
|
1013
|
+
popupService = inject(UiPopupService);
|
|
1014
|
+
closeActivePopup = () => this.closeCalendar();
|
|
978
1015
|
label;
|
|
979
1016
|
hint;
|
|
980
1017
|
placeholder;
|
|
@@ -982,10 +1019,13 @@ class UiDateInputComponent {
|
|
|
982
1019
|
id;
|
|
983
1020
|
type = 'date';
|
|
984
1021
|
element = 'input';
|
|
1022
|
+
calendarIcon = CalendarDays;
|
|
1023
|
+
previousMonthIcon = ChevronLeft;
|
|
1024
|
+
nextMonthIcon = ChevronRight;
|
|
985
1025
|
rows = 4;
|
|
986
1026
|
required = false;
|
|
987
1027
|
fullWidth = false;
|
|
988
|
-
autocomplete;
|
|
1028
|
+
autocomplete = 'off';
|
|
989
1029
|
readonly = false;
|
|
990
1030
|
pattern;
|
|
991
1031
|
error;
|
|
@@ -994,6 +1034,9 @@ class UiDateInputComponent {
|
|
|
994
1034
|
value = '';
|
|
995
1035
|
static nextId = 0;
|
|
996
1036
|
generatedId = `ui-input-${UiDateInputComponent.nextId++}`;
|
|
1037
|
+
visibleMonth = this.startOfMonth(new Date());
|
|
1038
|
+
calendarView = 'days';
|
|
1039
|
+
isCalendarOpen = false;
|
|
997
1040
|
actionTriggered = new EventEmitter();
|
|
998
1041
|
get controlId() {
|
|
999
1042
|
return this.id ?? this.generatedId;
|
|
@@ -1002,8 +1045,131 @@ class UiDateInputComponent {
|
|
|
1002
1045
|
onTouched = () => undefined;
|
|
1003
1046
|
writeValue(value) {
|
|
1004
1047
|
this.value = value ?? '';
|
|
1048
|
+
const selectedDate = this.parseDate(this.value);
|
|
1049
|
+
if (selectedDate) {
|
|
1050
|
+
this.visibleMonth = this.startOfMonth(selectedDate);
|
|
1051
|
+
}
|
|
1005
1052
|
this.cdr.markForCheck();
|
|
1006
1053
|
}
|
|
1054
|
+
get monthLabel() {
|
|
1055
|
+
return this.visibleMonth.toLocaleDateString('uk-UA', { month: 'long', year: 'numeric' });
|
|
1056
|
+
}
|
|
1057
|
+
get monthName() {
|
|
1058
|
+
return this.visibleMonth.toLocaleDateString('uk-UA', { month: 'long' });
|
|
1059
|
+
}
|
|
1060
|
+
get yearLabel() {
|
|
1061
|
+
return this.visibleMonth.getFullYear();
|
|
1062
|
+
}
|
|
1063
|
+
get monthOptions() {
|
|
1064
|
+
return Array.from({ length: 12 }, (_, value) => ({
|
|
1065
|
+
value,
|
|
1066
|
+
label: new Date(2000, value, 1).toLocaleDateString('uk-UA', { month: 'long' }),
|
|
1067
|
+
}));
|
|
1068
|
+
}
|
|
1069
|
+
get yearOptions() {
|
|
1070
|
+
const year = this.visibleMonth.getFullYear();
|
|
1071
|
+
return Array.from({ length: 12 }, (_, index) => year - 5 + index);
|
|
1072
|
+
}
|
|
1073
|
+
get calendarDays() {
|
|
1074
|
+
const firstDay = this.startOfMonth(this.visibleMonth);
|
|
1075
|
+
const mondayOffset = (firstDay.getDay() + 6) % 7;
|
|
1076
|
+
const firstGridDay = new Date(firstDay);
|
|
1077
|
+
firstGridDay.setDate(firstGridDay.getDate() - mondayOffset);
|
|
1078
|
+
return Array.from({ length: 42 }, (_, index) => {
|
|
1079
|
+
const date = new Date(firstGridDay);
|
|
1080
|
+
date.setDate(firstGridDay.getDate() + index);
|
|
1081
|
+
return {
|
|
1082
|
+
date: this.toDateValue(date),
|
|
1083
|
+
day: date.getDate(),
|
|
1084
|
+
currentMonth: date.getMonth() === this.visibleMonth.getMonth(),
|
|
1085
|
+
};
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1088
|
+
get displayValue() {
|
|
1089
|
+
const date = this.selectedDate;
|
|
1090
|
+
return date ? date.toLocaleDateString('uk-UA') : String(this.value ?? '');
|
|
1091
|
+
}
|
|
1092
|
+
get selectedDate() {
|
|
1093
|
+
return this.parseDate(this.value);
|
|
1094
|
+
}
|
|
1095
|
+
openCalendar(event) {
|
|
1096
|
+
event.stopPropagation();
|
|
1097
|
+
if (this.disabled) {
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
this.isCalendarOpen = true;
|
|
1101
|
+
this.popupService.open(this.closeActivePopup);
|
|
1102
|
+
this.calendarView = 'days';
|
|
1103
|
+
this.cdr.markForCheck();
|
|
1104
|
+
}
|
|
1105
|
+
closeCalendar() {
|
|
1106
|
+
this.isCalendarOpen = false;
|
|
1107
|
+
this.popupService.close(this.closeActivePopup);
|
|
1108
|
+
this.cdr.markForCheck();
|
|
1109
|
+
}
|
|
1110
|
+
showMonthPicker(event) {
|
|
1111
|
+
event.stopPropagation();
|
|
1112
|
+
this.calendarView = 'months';
|
|
1113
|
+
this.cdr.markForCheck();
|
|
1114
|
+
}
|
|
1115
|
+
showYearPicker(event) {
|
|
1116
|
+
event.stopPropagation();
|
|
1117
|
+
this.calendarView = 'years';
|
|
1118
|
+
this.cdr.markForCheck();
|
|
1119
|
+
}
|
|
1120
|
+
selectMonth(month, event) {
|
|
1121
|
+
event.stopPropagation();
|
|
1122
|
+
this.visibleMonth = new Date(this.visibleMonth.getFullYear(), month, 1);
|
|
1123
|
+
this.calendarView = 'days';
|
|
1124
|
+
this.cdr.markForCheck();
|
|
1125
|
+
}
|
|
1126
|
+
selectYear(year, event) {
|
|
1127
|
+
event.stopPropagation();
|
|
1128
|
+
this.visibleMonth = new Date(year, this.visibleMonth.getMonth(), 1);
|
|
1129
|
+
this.calendarView = 'months';
|
|
1130
|
+
this.cdr.markForCheck();
|
|
1131
|
+
}
|
|
1132
|
+
changeMonth(offset, event) {
|
|
1133
|
+
event.stopPropagation();
|
|
1134
|
+
if (this.calendarView === 'years') {
|
|
1135
|
+
this.visibleMonth = new Date(this.visibleMonth.getFullYear() + offset * 12, this.visibleMonth.getMonth(), 1);
|
|
1136
|
+
}
|
|
1137
|
+
else if (this.calendarView === 'months') {
|
|
1138
|
+
this.visibleMonth = new Date(this.visibleMonth.getFullYear() + offset, this.visibleMonth.getMonth(), 1);
|
|
1139
|
+
}
|
|
1140
|
+
else {
|
|
1141
|
+
this.visibleMonth = new Date(this.visibleMonth.getFullYear(), this.visibleMonth.getMonth() + offset, 1);
|
|
1142
|
+
}
|
|
1143
|
+
this.cdr.markForCheck();
|
|
1144
|
+
}
|
|
1145
|
+
selectDate(dateValue, event) {
|
|
1146
|
+
event.stopPropagation();
|
|
1147
|
+
this.visibleMonth = this.startOfMonth(this.parseDate(dateValue));
|
|
1148
|
+
this.value = dateValue;
|
|
1149
|
+
this.onChange(dateValue);
|
|
1150
|
+
this.closeCalendar();
|
|
1151
|
+
this.onTouched();
|
|
1152
|
+
this.cdr.markForCheck();
|
|
1153
|
+
}
|
|
1154
|
+
isSelected(dateValue) {
|
|
1155
|
+
return this.value === dateValue;
|
|
1156
|
+
}
|
|
1157
|
+
isSelectedMonth(month) {
|
|
1158
|
+
return this.selectedDate?.getMonth() === month && this.selectedDate?.getFullYear() === this.visibleMonth.getFullYear();
|
|
1159
|
+
}
|
|
1160
|
+
isSelectedYear(year) {
|
|
1161
|
+
return this.selectedDate?.getFullYear() === year;
|
|
1162
|
+
}
|
|
1163
|
+
onDocumentClick() {
|
|
1164
|
+
if (this.isCalendarOpen) {
|
|
1165
|
+
this.closeCalendar();
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
onEscape() {
|
|
1169
|
+
if (this.isCalendarOpen) {
|
|
1170
|
+
this.closeCalendar();
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1007
1173
|
registerOnChange(fn) {
|
|
1008
1174
|
this.onChange = fn;
|
|
1009
1175
|
}
|
|
@@ -1015,31 +1181,84 @@ class UiDateInputComponent {
|
|
|
1015
1181
|
this.cdr.markForCheck();
|
|
1016
1182
|
}
|
|
1017
1183
|
onValueChange(value) {
|
|
1018
|
-
const
|
|
1019
|
-
|
|
1020
|
-
this.
|
|
1184
|
+
const maskedValue = this.applyDateMask(value);
|
|
1185
|
+
const date = this.parseInputDate(maskedValue);
|
|
1186
|
+
this.value = date ? this.toDateValue(date) : maskedValue;
|
|
1187
|
+
this.onChange(this.value);
|
|
1188
|
+
if (date) {
|
|
1189
|
+
this.visibleMonth = this.startOfMonth(date);
|
|
1190
|
+
}
|
|
1191
|
+
this.cdr.markForCheck();
|
|
1192
|
+
}
|
|
1193
|
+
allowDateKey(event) {
|
|
1194
|
+
if (event.ctrlKey || event.metaKey || ['Backspace', 'Delete', 'Tab', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key))
|
|
1195
|
+
return;
|
|
1196
|
+
if (!/^\d$/.test(event.key))
|
|
1197
|
+
event.preventDefault();
|
|
1198
|
+
}
|
|
1199
|
+
applyDateMask(value) {
|
|
1200
|
+
const digits = value.replace(/\D/g, '').slice(0, 8);
|
|
1201
|
+
const day = digits.slice(0, 2);
|
|
1202
|
+
const month = digits.slice(2, 4);
|
|
1203
|
+
const year = digits.slice(4, 8);
|
|
1204
|
+
return [day, month, year].filter(Boolean).join('.');
|
|
1021
1205
|
}
|
|
1022
1206
|
triggerAction(action) {
|
|
1023
1207
|
this.actionTriggered.emit(action);
|
|
1024
1208
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1209
|
+
startOfMonth(date) {
|
|
1210
|
+
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
1211
|
+
}
|
|
1212
|
+
parseDate(value) {
|
|
1213
|
+
if (!value) {
|
|
1214
|
+
return null;
|
|
1215
|
+
}
|
|
1216
|
+
const [year, month, day] = String(value).slice(0, 10).split('-').map(Number);
|
|
1217
|
+
if (!year || !month || !day) {
|
|
1218
|
+
return null;
|
|
1219
|
+
}
|
|
1220
|
+
return new Date(year, month - 1, day);
|
|
1221
|
+
}
|
|
1222
|
+
parseInputDate(value) {
|
|
1223
|
+
const normalized = value.trim();
|
|
1224
|
+
const isoDate = this.parseDate(normalized);
|
|
1225
|
+
if (isoDate) {
|
|
1226
|
+
return isoDate;
|
|
1227
|
+
}
|
|
1228
|
+
const match = normalized.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/);
|
|
1229
|
+
if (!match) {
|
|
1230
|
+
return null;
|
|
1231
|
+
}
|
|
1232
|
+
const [, day, month, year] = match;
|
|
1233
|
+
const date = new Date(Number(year), Number(month) - 1, Number(day));
|
|
1234
|
+
return date.getFullYear() === Number(year) && date.getMonth() === Number(month) - 1 && date.getDate() === Number(day)
|
|
1235
|
+
? date
|
|
1236
|
+
: null;
|
|
1237
|
+
}
|
|
1238
|
+
toDateValue(date) {
|
|
1239
|
+
const year = date.getFullYear();
|
|
1240
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
1241
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
1242
|
+
return `${year}-${month}-${day}`;
|
|
1243
|
+
}
|
|
1244
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiDateInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1245
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiDateInputComponent, isStandalone: true, selector: "forms-date-input", inputs: { label: "label", hint: "hint", placeholder: "placeholder", name: "name", id: "id", rows: "rows", required: "required", fullWidth: "fullWidth", autocomplete: "autocomplete", readonly: "readonly", pattern: "pattern", error: "error", actions: "actions" }, outputs: { actionTriggered: "actionTriggered" }, host: { listeners: { "document:click": "onDocumentClick()", "document:keydown.escape": "onEscape()" } }, providers: [
|
|
1027
1246
|
{
|
|
1028
1247
|
provide: NG_VALUE_ACCESSOR,
|
|
1029
1248
|
useExisting: forwardRef(() => UiDateInputComponent),
|
|
1030
1249
|
multi: true,
|
|
1031
1250
|
},
|
|
1032
|
-
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n
|
|
1251
|
+
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <div class=\"relative\">\n <input\n type=\"text\"\n [attr.placeholder]=\"placeholder ?? '\u0414\u0414.\u041C\u041C.\u0420\u0420\u0420\u0420'\"\n maxlength=\"10\"\n inputmode=\"numeric\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 pr-10 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"displayValue\"\n (click)=\"openCalendar($event)\"\n (keydown)=\"allowDateKey($event)\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n />\n <lucide-icon\n [img]=\"calendarIcon\"\n class=\"pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400\"\n aria-hidden=\"true\"\n ></lucide-icon>\n\n @if (isCalendarOpen) {\n <div\n class=\"absolute left-0 top-full z-50 mt-2 w-[min(20rem,calc(100vw-2rem))] rounded-xl border border-slate-200 bg-white p-4 shadow-xl\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"mb-4 flex items-center justify-between\" [class.justify-center]=\"calendarView === 'months'\">\n @if (calendarView !== 'months') {\n <button\n type=\"button\"\n class=\"rounded-lg p-2 text-slate-500 transition hover:bg-slate-100 hover:text-slate-900\"\n aria-label=\"\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0456\u0439 \u043C\u0456\u0441\u044F\u0446\u044C\"\n (click)=\"changeMonth(-1, $event)\"\n >\n <lucide-icon [img]=\"previousMonthIcon\" class=\"h-4 w-4\"></lucide-icon>\n </button>\n }\n <div class=\"flex items-center gap-1\">\n <button\n type=\"button\"\n class=\"rounded-lg px-2 py-1 text-sm font-semibold capitalize text-slate-900 transition hover:bg-slate-100\"\n (click)=\"showMonthPicker($event)\"\n >\n {{ monthName }}\n </button>\n <button\n type=\"button\"\n class=\"rounded-lg px-2 py-1 text-sm font-semibold text-slate-900 transition hover:bg-slate-100\"\n (click)=\"showYearPicker($event)\"\n >\n {{ yearLabel }}\n </button>\n </div>\n @if (calendarView !== 'months') {\n <button\n type=\"button\"\n class=\"rounded-lg p-2 text-slate-500 transition hover:bg-slate-100 hover:text-slate-900\"\n aria-label=\"\u041D\u0430\u0441\u0442\u0443\u043F\u043D\u0438\u0439 \u043C\u0456\u0441\u044F\u0446\u044C\"\n (click)=\"changeMonth(1, $event)\"\n >\n <lucide-icon [img]=\"nextMonthIcon\" class=\"h-4 w-4\"></lucide-icon>\n </button>\n }\n </div>\n\n @if (calendarView === 'days') {\n <div class=\"mb-2 grid grid-cols-7 text-center text-xs font-medium text-slate-400\">\n @for (weekday of ['\u041F\u043D', '\u0412\u0442', '\u0421\u0440', '\u0427\u0442', '\u041F\u0442', '\u0421\u0431', '\u041D\u0434']; track weekday) {\n <span class=\"py-1\">{{ weekday }}</span>\n }\n </div>\n\n <div class=\"grid grid-cols-7 gap-1\">\n @for (day of calendarDays; track day.date) {\n <button\n type=\"button\"\n class=\"aspect-square rounded-lg text-sm transition hover:bg-slate-100 hover:text-slate-900\"\n [class.text-slate-300]=\"!day.currentMonth\"\n [class.text-slate-700]=\"day.currentMonth && !isSelected(day.date)\"\n [class.bg-slate-900]=\"isSelected(day.date)\"\n [class.text-white]=\"isSelected(day.date)\"\n (click)=\"selectDate(day.date, $event)\"\n >\n {{ day.day }}\n </button>\n }\n </div>\n } @else if (calendarView === 'months') {\n <div class=\"grid grid-cols-3 gap-2\">\n @for (month of monthOptions; track month.value) {\n <button\n type=\"button\"\n class=\"rounded-lg px-2 py-3 text-sm capitalize text-slate-700 transition hover:bg-slate-100 hover:text-slate-900\"\n [class.bg-slate-900]=\"isSelectedMonth(month.value)\"\n [class.text-white]=\"isSelectedMonth(month.value)\"\n (click)=\"selectMonth(month.value, $event)\"\n >\n {{ month.label }}\n </button>\n }\n </div>\n } @else {\n <div class=\"grid grid-cols-3 gap-2\">\n @for (year of yearOptions; track year) {\n <button\n type=\"button\"\n class=\"rounded-lg px-2 py-3 text-sm text-slate-700 transition hover:bg-slate-100 hover:text-slate-900\"\n [class.bg-slate-900]=\"isSelectedYear(year)\"\n [class.text-white]=\"isSelectedYear(year)\"\n (click)=\"selectYear(year, $event)\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1033
1252
|
}
|
|
1034
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1253
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiDateInputComponent, decorators: [{
|
|
1035
1254
|
type: Component,
|
|
1036
|
-
args: [{ selector: 'forms-date-input', standalone: true, imports: [CommonModule, FormsModule, UiButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
1255
|
+
args: [{ selector: 'forms-date-input', standalone: true, imports: [CommonModule, FormsModule, UiButtonComponent, LucideAngularModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
1037
1256
|
{
|
|
1038
1257
|
provide: NG_VALUE_ACCESSOR,
|
|
1039
1258
|
useExisting: forwardRef(() => UiDateInputComponent),
|
|
1040
1259
|
multi: true,
|
|
1041
1260
|
},
|
|
1042
|
-
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n
|
|
1261
|
+
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <div class=\"relative\">\n <input\n type=\"text\"\n [attr.placeholder]=\"placeholder ?? '\u0414\u0414.\u041C\u041C.\u0420\u0420\u0420\u0420'\"\n maxlength=\"10\"\n inputmode=\"numeric\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 pr-10 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"displayValue\"\n (click)=\"openCalendar($event)\"\n (keydown)=\"allowDateKey($event)\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n />\n <lucide-icon\n [img]=\"calendarIcon\"\n class=\"pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400\"\n aria-hidden=\"true\"\n ></lucide-icon>\n\n @if (isCalendarOpen) {\n <div\n class=\"absolute left-0 top-full z-50 mt-2 w-[min(20rem,calc(100vw-2rem))] rounded-xl border border-slate-200 bg-white p-4 shadow-xl\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"mb-4 flex items-center justify-between\" [class.justify-center]=\"calendarView === 'months'\">\n @if (calendarView !== 'months') {\n <button\n type=\"button\"\n class=\"rounded-lg p-2 text-slate-500 transition hover:bg-slate-100 hover:text-slate-900\"\n aria-label=\"\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0456\u0439 \u043C\u0456\u0441\u044F\u0446\u044C\"\n (click)=\"changeMonth(-1, $event)\"\n >\n <lucide-icon [img]=\"previousMonthIcon\" class=\"h-4 w-4\"></lucide-icon>\n </button>\n }\n <div class=\"flex items-center gap-1\">\n <button\n type=\"button\"\n class=\"rounded-lg px-2 py-1 text-sm font-semibold capitalize text-slate-900 transition hover:bg-slate-100\"\n (click)=\"showMonthPicker($event)\"\n >\n {{ monthName }}\n </button>\n <button\n type=\"button\"\n class=\"rounded-lg px-2 py-1 text-sm font-semibold text-slate-900 transition hover:bg-slate-100\"\n (click)=\"showYearPicker($event)\"\n >\n {{ yearLabel }}\n </button>\n </div>\n @if (calendarView !== 'months') {\n <button\n type=\"button\"\n class=\"rounded-lg p-2 text-slate-500 transition hover:bg-slate-100 hover:text-slate-900\"\n aria-label=\"\u041D\u0430\u0441\u0442\u0443\u043F\u043D\u0438\u0439 \u043C\u0456\u0441\u044F\u0446\u044C\"\n (click)=\"changeMonth(1, $event)\"\n >\n <lucide-icon [img]=\"nextMonthIcon\" class=\"h-4 w-4\"></lucide-icon>\n </button>\n }\n </div>\n\n @if (calendarView === 'days') {\n <div class=\"mb-2 grid grid-cols-7 text-center text-xs font-medium text-slate-400\">\n @for (weekday of ['\u041F\u043D', '\u0412\u0442', '\u0421\u0440', '\u0427\u0442', '\u041F\u0442', '\u0421\u0431', '\u041D\u0434']; track weekday) {\n <span class=\"py-1\">{{ weekday }}</span>\n }\n </div>\n\n <div class=\"grid grid-cols-7 gap-1\">\n @for (day of calendarDays; track day.date) {\n <button\n type=\"button\"\n class=\"aspect-square rounded-lg text-sm transition hover:bg-slate-100 hover:text-slate-900\"\n [class.text-slate-300]=\"!day.currentMonth\"\n [class.text-slate-700]=\"day.currentMonth && !isSelected(day.date)\"\n [class.bg-slate-900]=\"isSelected(day.date)\"\n [class.text-white]=\"isSelected(day.date)\"\n (click)=\"selectDate(day.date, $event)\"\n >\n {{ day.day }}\n </button>\n }\n </div>\n } @else if (calendarView === 'months') {\n <div class=\"grid grid-cols-3 gap-2\">\n @for (month of monthOptions; track month.value) {\n <button\n type=\"button\"\n class=\"rounded-lg px-2 py-3 text-sm capitalize text-slate-700 transition hover:bg-slate-100 hover:text-slate-900\"\n [class.bg-slate-900]=\"isSelectedMonth(month.value)\"\n [class.text-white]=\"isSelectedMonth(month.value)\"\n (click)=\"selectMonth(month.value, $event)\"\n >\n {{ month.label }}\n </button>\n }\n </div>\n } @else {\n <div class=\"grid grid-cols-3 gap-2\">\n @for (year of yearOptions; track year) {\n <button\n type=\"button\"\n class=\"rounded-lg px-2 py-3 text-sm text-slate-700 transition hover:bg-slate-100 hover:text-slate-900\"\n [class.bg-slate-900]=\"isSelectedYear(year)\"\n [class.text-white]=\"isSelectedYear(year)\"\n (click)=\"selectYear(year, $event)\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n" }]
|
|
1043
1262
|
}], propDecorators: { label: [{
|
|
1044
1263
|
type: Input
|
|
1045
1264
|
}], hint: [{
|
|
@@ -1068,75 +1287,118 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
1068
1287
|
type: Input
|
|
1069
1288
|
}], actionTriggered: [{
|
|
1070
1289
|
type: Output
|
|
1290
|
+
}], onDocumentClick: [{
|
|
1291
|
+
type: HostListener,
|
|
1292
|
+
args: ['document:click']
|
|
1293
|
+
}], onEscape: [{
|
|
1294
|
+
type: HostListener,
|
|
1295
|
+
args: ['document:keydown.escape']
|
|
1071
1296
|
}] } });
|
|
1072
1297
|
|
|
1073
1298
|
class UiDatetimeInputComponent {
|
|
1074
1299
|
cdr = inject(ChangeDetectorRef);
|
|
1300
|
+
popupService = inject(UiPopupService);
|
|
1301
|
+
closeActivePopup = () => this.closeCalendar();
|
|
1075
1302
|
label;
|
|
1076
1303
|
hint;
|
|
1077
1304
|
placeholder;
|
|
1078
1305
|
name;
|
|
1079
1306
|
id;
|
|
1080
|
-
type = 'datetime-local';
|
|
1081
|
-
element = 'input';
|
|
1082
1307
|
rows = 4;
|
|
1083
1308
|
required = false;
|
|
1084
1309
|
fullWidth = false;
|
|
1085
|
-
autocomplete;
|
|
1310
|
+
autocomplete = 'off';
|
|
1086
1311
|
readonly = false;
|
|
1087
1312
|
pattern;
|
|
1088
1313
|
error;
|
|
1089
1314
|
actions = [];
|
|
1315
|
+
type = 'datetime-local';
|
|
1316
|
+
calendarIcon = CalendarDays;
|
|
1317
|
+
previousMonthIcon = ChevronLeft;
|
|
1318
|
+
nextMonthIcon = ChevronRight;
|
|
1090
1319
|
disabled = false;
|
|
1091
1320
|
value = '';
|
|
1321
|
+
isCalendarOpen = false;
|
|
1322
|
+
calendarView = 'days';
|
|
1323
|
+
visibleMonth = this.startOfMonth(new Date());
|
|
1324
|
+
selectedHour = 12;
|
|
1325
|
+
selectedMinute = 0;
|
|
1092
1326
|
static nextId = 0;
|
|
1093
1327
|
generatedId = `ui-input-${UiDatetimeInputComponent.nextId++}`;
|
|
1094
1328
|
actionTriggered = new EventEmitter();
|
|
1095
|
-
get controlId() {
|
|
1096
|
-
return this.id ?? this.generatedId;
|
|
1097
|
-
}
|
|
1098
1329
|
onChange = () => undefined;
|
|
1099
1330
|
onTouched = () => undefined;
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
this.
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
this.
|
|
1117
|
-
this.
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1331
|
+
get controlId() { return this.id ?? this.generatedId; }
|
|
1332
|
+
get selectedDate() { const match = String(this.value ?? '').match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})/); return match ? new Date(+match[1], +match[2] - 1, +match[3]) : null; }
|
|
1333
|
+
get displayValue() { const match = String(this.value ?? '').match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})/); return match ? `${match[3]}.${match[2]}.${match[1]} ${match[4]}:${match[5]}` : String(this.value ?? ''); }
|
|
1334
|
+
get monthName() { return this.visibleMonth.toLocaleDateString('uk-UA', { month: 'long' }); }
|
|
1335
|
+
get yearLabel() { return this.visibleMonth.getFullYear(); }
|
|
1336
|
+
get monthOptions() { return Array.from({ length: 12 }, (_, value) => ({ value, label: new Date(2000, value, 1).toLocaleDateString('uk-UA', { month: 'long' }) })); }
|
|
1337
|
+
get yearOptions() { const year = this.visibleMonth.getFullYear(); return Array.from({ length: 12 }, (_, index) => year - 5 + index); }
|
|
1338
|
+
get calendarDays() {
|
|
1339
|
+
const first = this.startOfMonth(this.visibleMonth);
|
|
1340
|
+
const offset = (first.getDay() + 6) % 7;
|
|
1341
|
+
const start = new Date(first);
|
|
1342
|
+
start.setDate(start.getDate() - offset);
|
|
1343
|
+
return Array.from({ length: 42 }, (_, index) => { const date = new Date(start); date.setDate(start.getDate() + index); return { date: this.toDateValue(date), day: date.getDate(), currentMonth: date.getMonth() === this.visibleMonth.getMonth() }; });
|
|
1344
|
+
}
|
|
1345
|
+
writeValue(value) { this.value = value ?? ''; const date = this.selectedDate; if (date) {
|
|
1346
|
+
this.visibleMonth = this.startOfMonth(date);
|
|
1347
|
+
this.selectedHour = +(String(value).slice(11, 13));
|
|
1348
|
+
this.selectedMinute = +(String(value).slice(14, 16));
|
|
1349
|
+
} this.cdr.markForCheck(); }
|
|
1350
|
+
registerOnChange(fn) { this.onChange = fn; }
|
|
1351
|
+
registerOnTouched(fn) { this.onTouched = fn; }
|
|
1352
|
+
setDisabledState(disabled) { this.disabled = disabled; this.cdr.markForCheck(); }
|
|
1353
|
+
openCalendar(event) { event.stopPropagation(); if (this.disabled)
|
|
1354
|
+
return; this.isCalendarOpen = true; this.calendarView = 'days'; this.popupService.open(this.closeActivePopup); this.cdr.markForCheck(); }
|
|
1355
|
+
closeCalendar() { this.isCalendarOpen = false; this.popupService.close(this.closeActivePopup); this.cdr.markForCheck(); }
|
|
1356
|
+
changeMonth(offset, event) { event.stopPropagation(); const year = this.visibleMonth.getFullYear(); const month = this.visibleMonth.getMonth(); this.visibleMonth = this.calendarView === 'years' ? new Date(year + offset * 12, month, 1) : new Date(year + (this.calendarView === 'months' ? offset : 0), month + (this.calendarView === 'days' ? offset : 0), 1); this.cdr.markForCheck(); }
|
|
1357
|
+
showMonthPicker(event) { event.stopPropagation(); this.calendarView = 'months'; this.cdr.markForCheck(); }
|
|
1358
|
+
showYearPicker(event) { event.stopPropagation(); this.calendarView = 'years'; this.cdr.markForCheck(); }
|
|
1359
|
+
selectMonth(month, event) { event.stopPropagation(); this.visibleMonth = new Date(this.visibleMonth.getFullYear(), month, 1); this.calendarView = 'days'; this.cdr.markForCheck(); }
|
|
1360
|
+
selectYear(year, event) { event.stopPropagation(); this.visibleMonth = new Date(year, this.visibleMonth.getMonth(), 1); this.calendarView = 'months'; this.cdr.markForCheck(); }
|
|
1361
|
+
selectDate(dateValue, event) { event.stopPropagation(); const date = this.parseDate(dateValue); this.visibleMonth = this.startOfMonth(date); this.setDateTime(dateValue); }
|
|
1362
|
+
setDateTime(dateValue, close = true) { const hour = String(this.selectedHour).padStart(2, '0'); const minute = String(this.selectedMinute).padStart(2, '0'); this.value = `${dateValue}T${hour}:${minute}`; this.onChange(this.value); if (close)
|
|
1363
|
+
this.closeCalendar(); if (close)
|
|
1364
|
+
this.onTouched(); this.cdr.markForCheck(); }
|
|
1365
|
+
onTimeChange() { const date = this.selectedDate; if (date) {
|
|
1366
|
+
this.setDateTime(this.toDateValue(date), false);
|
|
1367
|
+
} }
|
|
1368
|
+
onValueChange(input) { const masked = this.applyMask(input); const match = masked.match(/^(\d{2})\.(\d{2})\.(\d{4}) (\d{2}):(\d{2})$/); if (match) {
|
|
1369
|
+
const date = new Date(+match[3], +match[2] - 1, +match[1]);
|
|
1370
|
+
if (date.getFullYear() === +match[3] && date.getMonth() === +match[2] - 1 && date.getDate() === +match[1] && +match[4] < 24 && +match[5] < 60) {
|
|
1371
|
+
this.value = `${match[3]}-${match[2]}-${match[1]}T${match[4]}:${match[5]}`;
|
|
1372
|
+
this.visibleMonth = this.startOfMonth(date);
|
|
1373
|
+
this.selectedHour = +match[4];
|
|
1374
|
+
this.selectedMinute = +match[5];
|
|
1375
|
+
}
|
|
1376
|
+
else
|
|
1377
|
+
this.value = masked;
|
|
1378
|
+
}
|
|
1379
|
+
else
|
|
1380
|
+
this.value = masked; this.onChange(this.value); this.cdr.markForCheck(); }
|
|
1381
|
+
allowDateKey(event) { if (event.ctrlKey || event.metaKey || ['Backspace', 'Delete', 'Tab', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key))
|
|
1382
|
+
return; if (!/^\d$/.test(event.key))
|
|
1383
|
+
event.preventDefault(); }
|
|
1384
|
+
applyMask(value) { const digits = value.replace(/\D/g, '').slice(0, 12); const date = [digits.slice(0, 2), digits.slice(2, 4), digits.slice(4, 8)].filter(Boolean).join('.'); const time = [digits.slice(8, 10), digits.slice(10, 12)].filter(Boolean).join(':'); return [date, time].filter(Boolean).join(' '); }
|
|
1385
|
+
isSelected(date) { return this.selectedDate ? this.toDateValue(this.selectedDate) === date : false; }
|
|
1386
|
+
isSelectedMonth(month) { return this.selectedDate?.getMonth() === month && this.selectedDate?.getFullYear() === this.visibleMonth.getFullYear(); }
|
|
1387
|
+
isSelectedYear(year) { return this.selectedDate?.getFullYear() === year; }
|
|
1388
|
+
onDocumentClick() { if (this.isCalendarOpen)
|
|
1389
|
+
this.closeCalendar(); }
|
|
1390
|
+
onEscape() { if (this.isCalendarOpen)
|
|
1391
|
+
this.closeCalendar(); }
|
|
1392
|
+
triggerAction(action) { this.actionTriggered.emit(action); }
|
|
1393
|
+
startOfMonth(date) { return new Date(date.getFullYear(), date.getMonth(), 1); }
|
|
1394
|
+
parseDate(value) { const [year, month, day] = value.split('-').map(Number); return year && month && day ? new Date(year, month - 1, day) : null; }
|
|
1395
|
+
toDateValue(date) { return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`; }
|
|
1396
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiDatetimeInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1397
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiDatetimeInputComponent, isStandalone: true, selector: "forms-datetime-input", inputs: { label: "label", hint: "hint", placeholder: "placeholder", name: "name", id: "id", rows: "rows", required: "required", fullWidth: "fullWidth", autocomplete: "autocomplete", readonly: "readonly", pattern: "pattern", error: "error", actions: "actions" }, outputs: { actionTriggered: "actionTriggered" }, host: { listeners: { "document:click": "onDocumentClick()", "document:keydown.escape": "onEscape()" } }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => UiDatetimeInputComponent), multi: true }], ngImport: i0, template: "<div class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\" [class.w-full]=\"fullWidth\">\n @if (label) { <span class=\"text-[0.7rem] font-semibold text-slate-600\">{{ label }} @if (required) { <span class=\"text-rose-500\"> *</span> }</span> }\n <div class=\"flex items-end gap-2\"><div class=\"min-w-0 flex-1\"><div class=\"relative\">\n <input type=\"text\" [attr.placeholder]=\"placeholder ?? '\u0414\u0414.\u041C\u041C.\u0420\u0420\u0420\u0420 \u0413\u0413:\u0425\u0425'\" maxlength=\"16\" inputmode=\"numeric\" [attr.name]=\"name\" [attr.autocomplete]=\"autocomplete\" [readonly]=\"readonly\" [disabled]=\"disabled\" class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 pr-10 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\" [attr.id]=\"controlId\" [value]=\"displayValue\" (click)=\"openCalendar($event)\" (keydown)=\"allowDateKey($event)\" (input)=\"onValueChange($any($event.target).value)\" (blur)=\"onTouched()\" />\n <lucide-icon [img]=\"calendarIcon\" class=\"pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400\"></lucide-icon>\n @if (isCalendarOpen) { <div class=\"absolute left-0 top-full z-50 mt-2 w-[min(22rem,calc(100vw-2rem))] rounded-xl border border-slate-200 bg-white p-4 shadow-xl\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-4 flex items-center justify-between\" [class.justify-center]=\"calendarView === 'months'\">\n @if (calendarView !== 'months') { <button type=\"button\" class=\"rounded-lg p-2 text-slate-500 hover:bg-slate-100\" aria-label=\"\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0456\u0439 \u043F\u0435\u0440\u0456\u043E\u0434\" (click)=\"changeMonth(-1, $event)\"><lucide-icon [img]=\"previousMonthIcon\" class=\"h-4 w-4\"></lucide-icon></button> }\n <div class=\"flex items-center gap-1\"><button type=\"button\" class=\"rounded-lg px-2 py-1 text-sm font-semibold capitalize text-slate-900 hover:bg-slate-100\" (click)=\"showMonthPicker($event)\">{{ monthName }}</button><button type=\"button\" class=\"rounded-lg px-2 py-1 text-sm font-semibold text-slate-900 hover:bg-slate-100\" (click)=\"showYearPicker($event)\">{{ yearLabel }}</button></div>\n @if (calendarView !== 'months') { <button type=\"button\" class=\"rounded-lg p-2 text-slate-500 hover:bg-slate-100\" aria-label=\"\u041D\u0430\u0441\u0442\u0443\u043F\u043D\u0438\u0439 \u043F\u0435\u0440\u0456\u043E\u0434\" (click)=\"changeMonth(1, $event)\"><lucide-icon [img]=\"nextMonthIcon\" class=\"h-4 w-4\"></lucide-icon></button> }\n </div>\n @if (calendarView === 'days') {\n <div class=\"mb-2 grid grid-cols-7 text-center text-xs font-medium text-slate-400\">@for (weekday of ['\u041F\u043D','\u0412\u0442','\u0421\u0440','\u0427\u0442','\u041F\u0442','\u0421\u0431','\u041D\u0434']; track weekday) { <span class=\"py-1\">{{ weekday }}</span> }</div>\n <div class=\"grid grid-cols-7 gap-1\">@for (day of calendarDays; track day.date) { <button type=\"button\" class=\"aspect-square rounded-lg text-sm hover:bg-slate-100 hover:text-slate-900\" [class.text-slate-300]=\"!day.currentMonth\" [class.text-slate-700]=\"day.currentMonth && !isSelected(day.date)\" [class.bg-slate-900]=\"isSelected(day.date)\" [class.text-white]=\"isSelected(day.date)\" (click)=\"selectDate(day.date, $event)\">{{ day.day }}</button> }</div>\n <div class=\"mt-4 grid grid-cols-2 gap-2 border-t border-slate-100 pt-3\"><label class=\"text-[0.65rem] font-medium text-slate-500\">\u0413\u043E\u0434\u0438\u043D\u0438<input type=\"number\" min=\"0\" max=\"23\" [value]=\"selectedHour\" (input)=\"selectedHour = +$any($event.target).value; onTimeChange()\" class=\"mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\" /></label><label class=\"text-[0.65rem] font-medium text-slate-500\">\u0425\u0432\u0438\u043B\u0438\u043D\u0438<input type=\"number\" min=\"0\" max=\"59\" [value]=\"selectedMinute\" (input)=\"selectedMinute = +$any($event.target).value; onTimeChange()\" class=\"mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\" /></label></div>\n } @else if (calendarView === 'months') { <div class=\"grid grid-cols-3 gap-2\">@for (month of monthOptions; track month.value) { <button type=\"button\" class=\"rounded-lg px-2 py-3 text-sm capitalize text-slate-700 hover:bg-slate-100 hover:text-slate-900\" [class.bg-slate-900]=\"isSelectedMonth(month.value)\" [class.text-white]=\"isSelectedMonth(month.value)\" (click)=\"selectMonth(month.value, $event)\">{{ month.label }}</button> }</div>\n } @else { <div class=\"grid grid-cols-3 gap-2\">@for (year of yearOptions; track year) { <button type=\"button\" class=\"rounded-lg px-2 py-3 text-sm text-slate-700 hover:bg-slate-100 hover:text-slate-900\" [class.bg-slate-900]=\"isSelectedYear(year)\" [class.text-white]=\"isSelectedYear(year)\" (click)=\"selectYear(year, $event)\">{{ year }}</button> }</div> }\n </div> }\n </div></div>\n @if (actions.length) { <div class=\"flex flex-none items-center gap-2 pb-0.5\">@for (action of actions; track action.id) { <ui-button type=\"button\" [variant]=\"action.variant ?? 'secondary'\" [icon]=\"action.icon || ''\" size=\"sm\" [disabled]=\"disabled\" (click)=\"triggerAction(action)\">{{ action.label }}</ui-button> }</div> }\n </div>\n @if (hint) { <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p> } @if (error) { <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p> }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1130
1398
|
}
|
|
1131
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1399
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiDatetimeInputComponent, decorators: [{
|
|
1132
1400
|
type: Component,
|
|
1133
|
-
args: [{ selector: 'forms-datetime-input', standalone: true, imports: [CommonModule, FormsModule, UiButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
1134
|
-
{
|
|
1135
|
-
provide: NG_VALUE_ACCESSOR,
|
|
1136
|
-
useExisting: forwardRef(() => UiDatetimeInputComponent),
|
|
1137
|
-
multi: true,
|
|
1138
|
-
},
|
|
1139
|
-
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-2xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-sky-400 focus:outline-none\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <input\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.pattern]=\"pattern\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-2xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-sky-400 focus:outline-none\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n />\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n\n\n" }]
|
|
1401
|
+
args: [{ selector: 'forms-datetime-input', standalone: true, imports: [CommonModule, FormsModule, UiButtonComponent, LucideAngularModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => UiDatetimeInputComponent), multi: true }], template: "<div class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\" [class.w-full]=\"fullWidth\">\n @if (label) { <span class=\"text-[0.7rem] font-semibold text-slate-600\">{{ label }} @if (required) { <span class=\"text-rose-500\"> *</span> }</span> }\n <div class=\"flex items-end gap-2\"><div class=\"min-w-0 flex-1\"><div class=\"relative\">\n <input type=\"text\" [attr.placeholder]=\"placeholder ?? '\u0414\u0414.\u041C\u041C.\u0420\u0420\u0420\u0420 \u0413\u0413:\u0425\u0425'\" maxlength=\"16\" inputmode=\"numeric\" [attr.name]=\"name\" [attr.autocomplete]=\"autocomplete\" [readonly]=\"readonly\" [disabled]=\"disabled\" class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 pr-10 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\" [attr.id]=\"controlId\" [value]=\"displayValue\" (click)=\"openCalendar($event)\" (keydown)=\"allowDateKey($event)\" (input)=\"onValueChange($any($event.target).value)\" (blur)=\"onTouched()\" />\n <lucide-icon [img]=\"calendarIcon\" class=\"pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400\"></lucide-icon>\n @if (isCalendarOpen) { <div class=\"absolute left-0 top-full z-50 mt-2 w-[min(22rem,calc(100vw-2rem))] rounded-xl border border-slate-200 bg-white p-4 shadow-xl\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-4 flex items-center justify-between\" [class.justify-center]=\"calendarView === 'months'\">\n @if (calendarView !== 'months') { <button type=\"button\" class=\"rounded-lg p-2 text-slate-500 hover:bg-slate-100\" aria-label=\"\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0456\u0439 \u043F\u0435\u0440\u0456\u043E\u0434\" (click)=\"changeMonth(-1, $event)\"><lucide-icon [img]=\"previousMonthIcon\" class=\"h-4 w-4\"></lucide-icon></button> }\n <div class=\"flex items-center gap-1\"><button type=\"button\" class=\"rounded-lg px-2 py-1 text-sm font-semibold capitalize text-slate-900 hover:bg-slate-100\" (click)=\"showMonthPicker($event)\">{{ monthName }}</button><button type=\"button\" class=\"rounded-lg px-2 py-1 text-sm font-semibold text-slate-900 hover:bg-slate-100\" (click)=\"showYearPicker($event)\">{{ yearLabel }}</button></div>\n @if (calendarView !== 'months') { <button type=\"button\" class=\"rounded-lg p-2 text-slate-500 hover:bg-slate-100\" aria-label=\"\u041D\u0430\u0441\u0442\u0443\u043F\u043D\u0438\u0439 \u043F\u0435\u0440\u0456\u043E\u0434\" (click)=\"changeMonth(1, $event)\"><lucide-icon [img]=\"nextMonthIcon\" class=\"h-4 w-4\"></lucide-icon></button> }\n </div>\n @if (calendarView === 'days') {\n <div class=\"mb-2 grid grid-cols-7 text-center text-xs font-medium text-slate-400\">@for (weekday of ['\u041F\u043D','\u0412\u0442','\u0421\u0440','\u0427\u0442','\u041F\u0442','\u0421\u0431','\u041D\u0434']; track weekday) { <span class=\"py-1\">{{ weekday }}</span> }</div>\n <div class=\"grid grid-cols-7 gap-1\">@for (day of calendarDays; track day.date) { <button type=\"button\" class=\"aspect-square rounded-lg text-sm hover:bg-slate-100 hover:text-slate-900\" [class.text-slate-300]=\"!day.currentMonth\" [class.text-slate-700]=\"day.currentMonth && !isSelected(day.date)\" [class.bg-slate-900]=\"isSelected(day.date)\" [class.text-white]=\"isSelected(day.date)\" (click)=\"selectDate(day.date, $event)\">{{ day.day }}</button> }</div>\n <div class=\"mt-4 grid grid-cols-2 gap-2 border-t border-slate-100 pt-3\"><label class=\"text-[0.65rem] font-medium text-slate-500\">\u0413\u043E\u0434\u0438\u043D\u0438<input type=\"number\" min=\"0\" max=\"23\" [value]=\"selectedHour\" (input)=\"selectedHour = +$any($event.target).value; onTimeChange()\" class=\"mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\" /></label><label class=\"text-[0.65rem] font-medium text-slate-500\">\u0425\u0432\u0438\u043B\u0438\u043D\u0438<input type=\"number\" min=\"0\" max=\"59\" [value]=\"selectedMinute\" (input)=\"selectedMinute = +$any($event.target).value; onTimeChange()\" class=\"mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\" /></label></div>\n } @else if (calendarView === 'months') { <div class=\"grid grid-cols-3 gap-2\">@for (month of monthOptions; track month.value) { <button type=\"button\" class=\"rounded-lg px-2 py-3 text-sm capitalize text-slate-700 hover:bg-slate-100 hover:text-slate-900\" [class.bg-slate-900]=\"isSelectedMonth(month.value)\" [class.text-white]=\"isSelectedMonth(month.value)\" (click)=\"selectMonth(month.value, $event)\">{{ month.label }}</button> }</div>\n } @else { <div class=\"grid grid-cols-3 gap-2\">@for (year of yearOptions; track year) { <button type=\"button\" class=\"rounded-lg px-2 py-3 text-sm text-slate-700 hover:bg-slate-100 hover:text-slate-900\" [class.bg-slate-900]=\"isSelectedYear(year)\" [class.text-white]=\"isSelectedYear(year)\" (click)=\"selectYear(year, $event)\">{{ year }}</button> }</div> }\n </div> }\n </div></div>\n @if (actions.length) { <div class=\"flex flex-none items-center gap-2 pb-0.5\">@for (action of actions; track action.id) { <ui-button type=\"button\" [variant]=\"action.variant ?? 'secondary'\" [icon]=\"action.icon || ''\" size=\"sm\" [disabled]=\"disabled\" (click)=\"triggerAction(action)\">{{ action.label }}</ui-button> }</div> }\n </div>\n @if (hint) { <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p> } @if (error) { <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p> }\n</div>\n" }]
|
|
1140
1402
|
}], propDecorators: { label: [{
|
|
1141
1403
|
type: Input
|
|
1142
1404
|
}], hint: [{
|
|
@@ -1165,6 +1427,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
1165
1427
|
type: Input
|
|
1166
1428
|
}], actionTriggered: [{
|
|
1167
1429
|
type: Output
|
|
1430
|
+
}], onDocumentClick: [{
|
|
1431
|
+
type: HostListener,
|
|
1432
|
+
args: ['document:click']
|
|
1433
|
+
}], onEscape: [{
|
|
1434
|
+
type: HostListener,
|
|
1435
|
+
args: ['document:keydown.escape']
|
|
1168
1436
|
}] } });
|
|
1169
1437
|
|
|
1170
1438
|
class UiEmailInputComponent {
|
|
@@ -1216,16 +1484,16 @@ class UiEmailInputComponent {
|
|
|
1216
1484
|
triggerAction(action) {
|
|
1217
1485
|
this.actionTriggered.emit(action);
|
|
1218
1486
|
}
|
|
1219
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1220
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1487
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiEmailInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1488
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiEmailInputComponent, isStandalone: true, selector: "forms-email-input", inputs: { label: "label", hint: "hint", placeholder: "placeholder", name: "name", id: "id", rows: "rows", required: "required", fullWidth: "fullWidth", autocomplete: "autocomplete", readonly: "readonly", pattern: "pattern", error: "error", actions: "actions" }, outputs: { actionTriggered: "actionTriggered" }, providers: [
|
|
1221
1489
|
{
|
|
1222
1490
|
provide: NG_VALUE_ACCESSOR,
|
|
1223
1491
|
useExisting: forwardRef(() => UiEmailInputComponent),
|
|
1224
1492
|
multi: true,
|
|
1225
1493
|
},
|
|
1226
|
-
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-
|
|
1494
|
+
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <input\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.pattern]=\"pattern\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n />\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1227
1495
|
}
|
|
1228
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1496
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiEmailInputComponent, decorators: [{
|
|
1229
1497
|
type: Component,
|
|
1230
1498
|
args: [{ selector: 'forms-email-input', standalone: true, imports: [CommonModule, FormsModule, UiButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
1231
1499
|
{
|
|
@@ -1233,7 +1501,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
1233
1501
|
useExisting: forwardRef(() => UiEmailInputComponent),
|
|
1234
1502
|
multi: true,
|
|
1235
1503
|
},
|
|
1236
|
-
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-
|
|
1504
|
+
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <input\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.pattern]=\"pattern\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n />\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n\n\n" }]
|
|
1237
1505
|
}], propDecorators: { label: [{
|
|
1238
1506
|
type: Input
|
|
1239
1507
|
}], hint: [{
|
|
@@ -1310,19 +1578,22 @@ class UiNumberInputComponent {
|
|
|
1310
1578
|
this.value = parsed;
|
|
1311
1579
|
this.onChange(parsed);
|
|
1312
1580
|
}
|
|
1581
|
+
preventWheelChange(event) {
|
|
1582
|
+
event.preventDefault();
|
|
1583
|
+
}
|
|
1313
1584
|
triggerAction(action) {
|
|
1314
1585
|
this.actionTriggered.emit(action);
|
|
1315
1586
|
}
|
|
1316
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1317
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1587
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiNumberInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1588
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiNumberInputComponent, isStandalone: true, selector: "forms-number-input", inputs: { label: "label", hint: "hint", placeholder: "placeholder", name: "name", id: "id", rows: "rows", required: "required", fullWidth: "fullWidth", autocomplete: "autocomplete", readonly: "readonly", disabled: "disabled", pattern: "pattern", error: "error", actions: "actions" }, outputs: { actionTriggered: "actionTriggered" }, providers: [
|
|
1318
1589
|
{
|
|
1319
1590
|
provide: NG_VALUE_ACCESSOR,
|
|
1320
1591
|
useExisting: forwardRef(() => UiNumberInputComponent),
|
|
1321
1592
|
multi: true,
|
|
1322
1593
|
},
|
|
1323
|
-
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-
|
|
1594
|
+
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <input\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.pattern]=\"pattern\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full appearance-none rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (wheel)=\"preventWheelChange($event)\"\n (blur)=\"onTouched()\"\n />\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n", styles: ["input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{appearance:none;-webkit-appearance:none;margin:0}\n", "input[type=number]{-moz-appearance:textfield}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1324
1595
|
}
|
|
1325
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1596
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiNumberInputComponent, decorators: [{
|
|
1326
1597
|
type: Component,
|
|
1327
1598
|
args: [{ selector: 'forms-number-input', standalone: true, imports: [CommonModule, FormsModule, UiButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
1328
1599
|
{
|
|
@@ -1330,7 +1601,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
1330
1601
|
useExisting: forwardRef(() => UiNumberInputComponent),
|
|
1331
1602
|
multi: true,
|
|
1332
1603
|
},
|
|
1333
|
-
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-
|
|
1604
|
+
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <input\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.pattern]=\"pattern\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full appearance-none rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (wheel)=\"preventWheelChange($event)\"\n (blur)=\"onTouched()\"\n />\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n", styles: ["input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{appearance:none;-webkit-appearance:none;margin:0}\n", "input[type=number]{-moz-appearance:textfield}\n"] }]
|
|
1334
1605
|
}], propDecorators: { label: [{
|
|
1335
1606
|
type: Input
|
|
1336
1607
|
}], hint: [{
|
|
@@ -1371,6 +1642,8 @@ class UiPasswordInputComponent {
|
|
|
1371
1642
|
name;
|
|
1372
1643
|
id;
|
|
1373
1644
|
type = 'password';
|
|
1645
|
+
showPasswordIcon = Eye;
|
|
1646
|
+
hidePasswordIcon = EyeOff;
|
|
1374
1647
|
element = 'input';
|
|
1375
1648
|
rows = 4;
|
|
1376
1649
|
required = false;
|
|
@@ -1381,6 +1654,7 @@ class UiPasswordInputComponent {
|
|
|
1381
1654
|
error;
|
|
1382
1655
|
actions = [];
|
|
1383
1656
|
disabled = false;
|
|
1657
|
+
isPasswordVisible = false;
|
|
1384
1658
|
value = '';
|
|
1385
1659
|
static nextId = 0;
|
|
1386
1660
|
generatedId = `ui-input-${UiPasswordInputComponent.nextId++}`;
|
|
@@ -1409,27 +1683,32 @@ class UiPasswordInputComponent {
|
|
|
1409
1683
|
this.value = parsed;
|
|
1410
1684
|
this.onChange(parsed);
|
|
1411
1685
|
}
|
|
1686
|
+
togglePassword(event) {
|
|
1687
|
+
event.stopPropagation();
|
|
1688
|
+
this.isPasswordVisible = !this.isPasswordVisible;
|
|
1689
|
+
this.cdr.markForCheck();
|
|
1690
|
+
}
|
|
1412
1691
|
triggerAction(action) {
|
|
1413
1692
|
this.actionTriggered.emit(action);
|
|
1414
1693
|
}
|
|
1415
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1416
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1694
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiPasswordInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1695
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiPasswordInputComponent, isStandalone: true, selector: "forms-password-input", inputs: { label: "label", hint: "hint", placeholder: "placeholder", name: "name", id: "id", rows: "rows", required: "required", fullWidth: "fullWidth", autocomplete: "autocomplete", readonly: "readonly", pattern: "pattern", error: "error", actions: "actions" }, outputs: { actionTriggered: "actionTriggered" }, providers: [
|
|
1417
1696
|
{
|
|
1418
1697
|
provide: NG_VALUE_ACCESSOR,
|
|
1419
1698
|
useExisting: forwardRef(() => UiPasswordInputComponent),
|
|
1420
1699
|
multi: true,
|
|
1421
1700
|
},
|
|
1422
|
-
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-
|
|
1701
|
+
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <div class=\"relative\">\n <input\n [attr.type]=\"isPasswordVisible ? 'text' : type\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.pattern]=\"pattern\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 pr-10 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n />\n <button\n type=\"button\"\n class=\"absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 transition hover:text-slate-700 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.aria-label]=\"isPasswordVisible ? '\u0421\u0445\u043E\u0432\u0430\u0442\u0438 \u043F\u0430\u0440\u043E\u043B\u044C' : '\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u0438 \u043F\u0430\u0440\u043E\u043B\u044C'\"\n [disabled]=\"disabled\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"togglePassword($event)\"\n >\n <lucide-icon\n [img]=\"isPasswordVisible ? hidePasswordIcon : showPasswordIcon\"\n class=\"h-4 w-4\"\n aria-hidden=\"true\"\n ></lucide-icon>\n </button>\n </div>\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1423
1702
|
}
|
|
1424
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1703
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiPasswordInputComponent, decorators: [{
|
|
1425
1704
|
type: Component,
|
|
1426
|
-
args: [{ selector: 'forms-password-input', standalone: true, imports: [CommonModule, FormsModule, UiButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
1705
|
+
args: [{ selector: 'forms-password-input', standalone: true, imports: [CommonModule, FormsModule, UiButtonComponent, LucideAngularModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
1427
1706
|
{
|
|
1428
1707
|
provide: NG_VALUE_ACCESSOR,
|
|
1429
1708
|
useExisting: forwardRef(() => UiPasswordInputComponent),
|
|
1430
1709
|
multi: true,
|
|
1431
1710
|
},
|
|
1432
|
-
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-
|
|
1711
|
+
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <div class=\"relative\">\n <input\n [attr.type]=\"isPasswordVisible ? 'text' : type\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.pattern]=\"pattern\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 pr-10 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n />\n <button\n type=\"button\"\n class=\"absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 transition hover:text-slate-700 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.aria-label]=\"isPasswordVisible ? '\u0421\u0445\u043E\u0432\u0430\u0442\u0438 \u043F\u0430\u0440\u043E\u043B\u044C' : '\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u0438 \u043F\u0430\u0440\u043E\u043B\u044C'\"\n [disabled]=\"disabled\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"togglePassword($event)\"\n >\n <lucide-icon\n [img]=\"isPasswordVisible ? hidePasswordIcon : showPasswordIcon\"\n class=\"h-4 w-4\"\n aria-hidden=\"true\"\n ></lucide-icon>\n </button>\n </div>\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n\n" }]
|
|
1433
1712
|
}], propDecorators: { label: [{
|
|
1434
1713
|
type: Input
|
|
1435
1714
|
}], hint: [{
|
|
@@ -1509,16 +1788,16 @@ class UiTextInputComponent {
|
|
|
1509
1788
|
triggerAction(action) {
|
|
1510
1789
|
this.actionTriggered.emit(action);
|
|
1511
1790
|
}
|
|
1512
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1513
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1791
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiTextInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1792
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiTextInputComponent, isStandalone: true, selector: "forms-text-input", inputs: { label: "label", hint: "hint", placeholder: "placeholder", name: "name", id: "id", rows: "rows", required: "required", fullWidth: "fullWidth", autocomplete: "autocomplete", readonly: "readonly", pattern: "pattern", error: "error", actions: "actions" }, outputs: { actionTriggered: "actionTriggered" }, providers: [
|
|
1514
1793
|
{
|
|
1515
1794
|
provide: NG_VALUE_ACCESSOR,
|
|
1516
1795
|
useExisting: forwardRef(() => UiTextInputComponent),
|
|
1517
1796
|
multi: true,
|
|
1518
1797
|
},
|
|
1519
|
-
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-
|
|
1798
|
+
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <input\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.pattern]=\"pattern\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n />\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1520
1799
|
}
|
|
1521
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1800
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiTextInputComponent, decorators: [{
|
|
1522
1801
|
type: Component,
|
|
1523
1802
|
args: [{ selector: 'forms-text-input', standalone: true, imports: [CommonModule, FormsModule, UiButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
1524
1803
|
{
|
|
@@ -1526,7 +1805,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
1526
1805
|
useExisting: forwardRef(() => UiTextInputComponent),
|
|
1527
1806
|
multi: true,
|
|
1528
1807
|
},
|
|
1529
|
-
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-
|
|
1808
|
+
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <input\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.pattern]=\"pattern\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n />\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n\n\n" }]
|
|
1530
1809
|
}], propDecorators: { label: [{
|
|
1531
1810
|
type: Input
|
|
1532
1811
|
}], hint: [{
|
|
@@ -1606,16 +1885,16 @@ class UiTextareaInputComponent {
|
|
|
1606
1885
|
triggerAction(action) {
|
|
1607
1886
|
this.actionTriggered.emit(action);
|
|
1608
1887
|
}
|
|
1609
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1610
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1888
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiTextareaInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1889
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiTextareaInputComponent, isStandalone: true, selector: "forms-textarea-input", inputs: { label: "label", hint: "hint", placeholder: "placeholder", name: "name", id: "id", rows: "rows", required: "required", fullWidth: "fullWidth", autocomplete: "autocomplete", readonly: "readonly", pattern: "pattern", error: "error", actions: "actions" }, outputs: { actionTriggered: "actionTriggered" }, providers: [
|
|
1611
1890
|
{
|
|
1612
1891
|
provide: NG_VALUE_ACCESSOR,
|
|
1613
1892
|
useExisting: forwardRef(() => UiTextareaInputComponent),
|
|
1614
1893
|
multi: true,
|
|
1615
1894
|
},
|
|
1616
|
-
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-
|
|
1895
|
+
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <input\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.pattern]=\"pattern\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n />\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1617
1896
|
}
|
|
1618
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1897
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiTextareaInputComponent, decorators: [{
|
|
1619
1898
|
type: Component,
|
|
1620
1899
|
args: [{ selector: 'forms-textarea-input', standalone: true, imports: [CommonModule, FormsModule, UiButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
1621
1900
|
{
|
|
@@ -1623,7 +1902,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
1623
1902
|
useExisting: forwardRef(() => UiTextareaInputComponent),
|
|
1624
1903
|
multi: true,
|
|
1625
1904
|
},
|
|
1626
|
-
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-
|
|
1905
|
+
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <input\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.pattern]=\"pattern\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n />\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n\n\n" }]
|
|
1627
1906
|
}], propDecorators: { label: [{
|
|
1628
1907
|
type: Input
|
|
1629
1908
|
}], hint: [{
|
|
@@ -1715,10 +1994,10 @@ class UiFormInputHostComponent {
|
|
|
1715
1994
|
instance.writeValue?.(this.value);
|
|
1716
1995
|
instance.setDisabledState?.(this.disabled || !!field.disabled);
|
|
1717
1996
|
}
|
|
1718
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1719
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.
|
|
1997
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiFormInputHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1998
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.20", type: UiFormInputHostComponent, isStandalone: true, selector: "forms-form-input-host", inputs: { field: "field", value: "value", error: "error", disabled: "disabled", actions: "actions", options: "options" }, outputs: { valueChange: "valueChange", actionTriggered: "actionTriggered" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true });
|
|
1720
1999
|
}
|
|
1721
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2000
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiFormInputHostComponent, decorators: [{
|
|
1722
2001
|
type: Component,
|
|
1723
2002
|
args: [{
|
|
1724
2003
|
selector: 'forms-form-input-host',
|
|
@@ -1771,10 +2050,10 @@ class UiFileInputComponent {
|
|
|
1771
2050
|
this.valueChange.emit(value);
|
|
1772
2051
|
this.filesChange.emit(files);
|
|
1773
2052
|
}
|
|
1774
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1775
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
2053
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiFileInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2054
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiFileInputComponent, isStandalone: true, selector: "forms-file-input", inputs: { label: "label", hint: "hint", accept: "accept", multiple: "multiple", disabled: "disabled", value: "value" }, outputs: { valueChange: "valueChange", filesChange: "filesChange" }, ngImport: i0, template: "<label class=\"flex flex-col gap-2 text-[0.7rem] font-semibold uppercase tracking-[0.2em] text-slate-600\">\n @if (label) { <span>{{ label }}</span> }\n <input\n type=\"file\"\n class=\"rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm normal-case tracking-normal text-slate-800 file:mr-3 file:rounded-lg file:border-0 file:bg-slate-900 file:px-3 file:py-2 file:text-sm file:font-medium file:text-white\"\n [attr.accept]=\"accept ?? null\"\n [attr.multiple]=\"multiple ? '' : null\"\n [disabled]=\"disabled\"\n (change)=\"onFilesSelected($event)\"\n />\n @if (hint) { <span class=\"text-[0.7rem] font-normal normal-case tracking-normal text-slate-500\">{{ hint }}</span> }\n @if (selectedFiles.length) {\n <div class=\"flex flex-col gap-1 text-[0.7rem] font-normal normal-case tracking-normal text-slate-700\">\n @for (file of selectedFiles; track file.name + file.size; let i = $index) {\n <div class=\"flex items-center justify-between rounded border border-slate-200 bg-slate-50 px-2 py-1\">\n <span class=\"truncate pr-2\">{{ file.name }}</span>\n <button type=\"button\" class=\"text-rose-600\" [disabled]=\"disabled\" (click)=\"remove(i)\">\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438</button>\n </div>\n }\n </div>\n }\n</label>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
1776
2055
|
}
|
|
1777
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2056
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiFileInputComponent, decorators: [{
|
|
1778
2057
|
type: Component,
|
|
1779
2058
|
args: [{ selector: 'forms-file-input', standalone: true, imports: [CommonModule], template: "<label class=\"flex flex-col gap-2 text-[0.7rem] font-semibold uppercase tracking-[0.2em] text-slate-600\">\n @if (label) { <span>{{ label }}</span> }\n <input\n type=\"file\"\n class=\"rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm normal-case tracking-normal text-slate-800 file:mr-3 file:rounded-lg file:border-0 file:bg-slate-900 file:px-3 file:py-2 file:text-sm file:font-medium file:text-white\"\n [attr.accept]=\"accept ?? null\"\n [attr.multiple]=\"multiple ? '' : null\"\n [disabled]=\"disabled\"\n (change)=\"onFilesSelected($event)\"\n />\n @if (hint) { <span class=\"text-[0.7rem] font-normal normal-case tracking-normal text-slate-500\">{{ hint }}</span> }\n @if (selectedFiles.length) {\n <div class=\"flex flex-col gap-1 text-[0.7rem] font-normal normal-case tracking-normal text-slate-700\">\n @for (file of selectedFiles; track file.name + file.size; let i = $index) {\n <div class=\"flex items-center justify-between rounded border border-slate-200 bg-slate-50 px-2 py-1\">\n <span class=\"truncate pr-2\">{{ file.name }}</span>\n <button type=\"button\" class=\"text-rose-600\" [disabled]=\"disabled\" (click)=\"remove(i)\">\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438</button>\n </div>\n }\n </div>\n }\n</label>\n" }]
|
|
1780
2059
|
}], propDecorators: { label: [{
|
|
@@ -1917,10 +2196,10 @@ class UiPhotoInputComponent {
|
|
|
1917
2196
|
const normalized = value.toLowerCase();
|
|
1918
2197
|
return normalized.startsWith('image/') || normalized === 'application/pdf';
|
|
1919
2198
|
}
|
|
1920
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1921
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
2199
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiPhotoInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2200
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiPhotoInputComponent, isStandalone: true, selector: "forms-photo-input", inputs: { label: "label", hint: "hint", accept: "accept", multiple: "multiple", limit: "limit", disabled: "disabled", value: "value", uploadPhoto: "uploadPhoto" }, outputs: { valueChange: "valueChange", filesChange: "filesChange", uploadingChange: "uploadingChange" }, usesOnChanges: true, ngImport: i0, template: "<label class=\"flex flex-col gap-2 text-[0.7rem] font-semibold uppercase tracking-[0.2em] text-slate-600\">\n @if (label) { <span>{{ label }}</span> }\n <button type=\"button\" class=\"flex min-h-24 items-center justify-center rounded-xl border border-dashed border-slate-300 bg-slate-50 px-4 py-3 text-xs font-semibold uppercase tracking-[0.15em] text-slate-600 transition hover:bg-slate-100 disabled:opacity-60\" [disabled]=\"disabled || !canSelectMore\" (click)=\"photoInput.click()\">\n {{ previews.length ? '\u0414\u043E\u0434\u0430\u0442\u0438 \u0449\u0435 \u0444\u0430\u0439\u043B' : '\u041E\u0431\u0440\u0430\u0442\u0438 \u0444\u0430\u0439\u043B' }}\n </button>\n <input #photoInput type=\"file\" class=\"hidden\" [attr.accept]=\"accept\" [attr.multiple]=\"multiple && canSelectMore ? '' : null\" [disabled]=\"disabled\" (change)=\"onFilesSelected($event)\" />\n @if (hint) { <span class=\"text-[0.7rem] font-normal normal-case tracking-normal text-slate-500\">{{ hint }}</span> }\n @if (previews.length) {\n <div class=\"grid grid-cols-2 gap-2 md:grid-cols-4\" cdkDropList cdkDropListOrientation=\"mixed\" [cdkDropListData]=\"previews\" (cdkDropListDropped)=\"drop($event)\">\n @for (preview of previews; track preview.url; let i = $index) {\n <div class=\"relative overflow-hidden rounded-lg border border-slate-200 bg-slate-50\" cdkDrag [cdkDragDisabled]=\"disabled || preview.source === 'file'\">\n @if (preview.isImage) { <img [src]=\"preview.url\" [alt]=\"preview.name\" class=\"h-28 w-full object-cover\" /> }\n @else { <div class=\"flex h-28 items-center justify-center px-2 text-center text-[0.65rem] text-slate-600\">{{ preview.name }}</div> }\n <div class=\"absolute left-1 top-1 rounded bg-slate-900/85 px-2 py-1 text-[10px] font-semibold text-white\">#{{ i + 1 }}</div>\n <button type=\"button\" class=\"absolute right-1 top-1 rounded bg-white/95 px-2 py-1 text-[10px] text-rose-600\" [disabled]=\"disabled\" (click)=\"remove(i)\">\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438</button>\n </div>\n }\n </div>\n }\n</label>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1$1.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1$1.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }] });
|
|
1922
2201
|
}
|
|
1923
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2202
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiPhotoInputComponent, decorators: [{
|
|
1924
2203
|
type: Component,
|
|
1925
2204
|
args: [{ selector: 'forms-photo-input', standalone: true, imports: [CommonModule, DragDropModule], template: "<label class=\"flex flex-col gap-2 text-[0.7rem] font-semibold uppercase tracking-[0.2em] text-slate-600\">\n @if (label) { <span>{{ label }}</span> }\n <button type=\"button\" class=\"flex min-h-24 items-center justify-center rounded-xl border border-dashed border-slate-300 bg-slate-50 px-4 py-3 text-xs font-semibold uppercase tracking-[0.15em] text-slate-600 transition hover:bg-slate-100 disabled:opacity-60\" [disabled]=\"disabled || !canSelectMore\" (click)=\"photoInput.click()\">\n {{ previews.length ? '\u0414\u043E\u0434\u0430\u0442\u0438 \u0449\u0435 \u0444\u0430\u0439\u043B' : '\u041E\u0431\u0440\u0430\u0442\u0438 \u0444\u0430\u0439\u043B' }}\n </button>\n <input #photoInput type=\"file\" class=\"hidden\" [attr.accept]=\"accept\" [attr.multiple]=\"multiple && canSelectMore ? '' : null\" [disabled]=\"disabled\" (change)=\"onFilesSelected($event)\" />\n @if (hint) { <span class=\"text-[0.7rem] font-normal normal-case tracking-normal text-slate-500\">{{ hint }}</span> }\n @if (previews.length) {\n <div class=\"grid grid-cols-2 gap-2 md:grid-cols-4\" cdkDropList cdkDropListOrientation=\"mixed\" [cdkDropListData]=\"previews\" (cdkDropListDropped)=\"drop($event)\">\n @for (preview of previews; track preview.url; let i = $index) {\n <div class=\"relative overflow-hidden rounded-lg border border-slate-200 bg-slate-50\" cdkDrag [cdkDragDisabled]=\"disabled || preview.source === 'file'\">\n @if (preview.isImage) { <img [src]=\"preview.url\" [alt]=\"preview.name\" class=\"h-28 w-full object-cover\" /> }\n @else { <div class=\"flex h-28 items-center justify-center px-2 text-center text-[0.65rem] text-slate-600\">{{ preview.name }}</div> }\n <div class=\"absolute left-1 top-1 rounded bg-slate-900/85 px-2 py-1 text-[10px] font-semibold text-white\">#{{ i + 1 }}</div>\n <button type=\"button\" class=\"absolute right-1 top-1 rounded bg-white/95 px-2 py-1 text-[10px] text-rose-600\" [disabled]=\"disabled\" (click)=\"remove(i)\">\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438</button>\n </div>\n }\n </div>\n }\n</label>\n" }]
|
|
1926
2205
|
}], propDecorators: { label: [{
|
|
@@ -1955,10 +2234,10 @@ class UiCheckboxInputComponent {
|
|
|
1955
2234
|
onValueChange(event) {
|
|
1956
2235
|
this.valueChange.emit(event.target.checked);
|
|
1957
2236
|
}
|
|
1958
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1959
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.
|
|
2237
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiCheckboxInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2238
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.20", type: UiCheckboxInputComponent, isStandalone: true, selector: "forms-checkbox-input", inputs: { label: "label", disabled: "disabled", value: "value" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<label class=\"inline-flex items-center gap-3 text-sm text-slate-700\">\n <input\n type=\"checkbox\"\n class=\"h-4 w-4 rounded border-slate-300 text-slate-900 focus:ring-slate-400\"\n [checked]=\"value\"\n [disabled]=\"disabled\"\n (change)=\"onValueChange($event)\"\n />\n <span>{{ label }}</span>\n</label>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
1960
2239
|
}
|
|
1961
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2240
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiCheckboxInputComponent, decorators: [{
|
|
1962
2241
|
type: Component,
|
|
1963
2242
|
args: [{ selector: 'forms-checkbox-input', standalone: true, imports: [CommonModule], template: "<label class=\"inline-flex items-center gap-3 text-sm text-slate-700\">\n <input\n type=\"checkbox\"\n class=\"h-4 w-4 rounded border-slate-300 text-slate-900 focus:ring-slate-400\"\n [checked]=\"value\"\n [disabled]=\"disabled\"\n (change)=\"onValueChange($event)\"\n />\n <span>{{ label }}</span>\n</label>\n" }]
|
|
1964
2243
|
}], propDecorators: { label: [{
|
|
@@ -2027,16 +2306,16 @@ class UiColorInputComponent {
|
|
|
2027
2306
|
isColorValue(value) {
|
|
2028
2307
|
return /^#([0-9a-fA-F]{6})$/.test(value.trim());
|
|
2029
2308
|
}
|
|
2030
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2031
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
2309
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiColorInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2310
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiColorInputComponent, isStandalone: true, selector: "forms-color-input", inputs: { label: "label", hint: "hint", name: "name", id: "id", required: "required", fullWidth: "fullWidth", error: "error" }, providers: [
|
|
2032
2311
|
{
|
|
2033
2312
|
provide: NG_VALUE_ACCESSOR,
|
|
2034
2313
|
useExisting: forwardRef(() => UiColorInputComponent),
|
|
2035
2314
|
multi: true,
|
|
2036
2315
|
},
|
|
2037
|
-
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-center gap-3\">\n <label\n class=\"relative inline-flex h-11 w-11 cursor-pointer items-center justify-center rounded-full border border-slate-200 bg-white shadow-sm transition hover:border-slate-300\"\n [class.cursor-not-allowed]=\"disabled\"\n [class.opacity-60]=\"disabled\"\n [attr.for]=\"controlId\"\n >\n <span\n class=\"block h-9 w-9 rounded-full border border-black/10\"\n [style.backgroundColor]=\"pickerValue\"\n ></span>\n <input\n class=\"absolute inset-0 h-full w-full cursor-pointer opacity-0\"\n type=\"color\"\n [attr.id]=\"controlId\"\n [attr.name]=\"name ? name + '-picker' : null\"\n [disabled]=\"disabled\"\n [value]=\"pickerValue\"\n (input)=\"onPickerChange($event.target.value)\"\n (blur)=\"markTouched()\"\n />\n </label>\n <input\n class=\"min-w-[110px] rounded-xl border border-slate-200 bg-slate-50 px-3 py-2 text-xs font-semibold uppercase text-slate-700 transition focus:border-
|
|
2316
|
+
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-center gap-3\">\n <label\n class=\"relative inline-flex h-11 w-11 cursor-pointer items-center justify-center rounded-full border border-slate-200 bg-white shadow-sm transition hover:border-slate-300\"\n [class.cursor-not-allowed]=\"disabled\"\n [class.opacity-60]=\"disabled\"\n [attr.for]=\"controlId\"\n >\n <span\n class=\"block h-9 w-9 rounded-full border border-black/10\"\n [style.backgroundColor]=\"pickerValue\"\n ></span>\n <input\n class=\"absolute inset-0 h-full w-full cursor-pointer opacity-0\"\n type=\"color\"\n [attr.id]=\"controlId\"\n [attr.name]=\"name ? name + '-picker' : null\"\n [disabled]=\"disabled\"\n [value]=\"pickerValue\"\n (input)=\"onPickerChange($event.target.value)\"\n (blur)=\"markTouched()\"\n />\n </label>\n <input\n class=\"min-w-[110px] rounded-xl border border-slate-200 bg-slate-50 px-3 py-2 text-xs font-semibold uppercase text-slate-700 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200 disabled:cursor-not-allowed disabled:opacity-60\"\n type=\"text\"\n [attr.name]=\"name\"\n [disabled]=\"disabled\"\n [value]=\"value\"\n (input)=\"onHexInput($event.target.value)\"\n (blur)=\"markTouched()\"\n />\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2038
2317
|
}
|
|
2039
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2318
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiColorInputComponent, decorators: [{
|
|
2040
2319
|
type: Component,
|
|
2041
2320
|
args: [{ selector: 'forms-color-input', standalone: true, imports: [CommonModule, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
2042
2321
|
{
|
|
@@ -2044,7 +2323,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
2044
2323
|
useExisting: forwardRef(() => UiColorInputComponent),
|
|
2045
2324
|
multi: true,
|
|
2046
2325
|
},
|
|
2047
|
-
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-center gap-3\">\n <label\n class=\"relative inline-flex h-11 w-11 cursor-pointer items-center justify-center rounded-full border border-slate-200 bg-white shadow-sm transition hover:border-slate-300\"\n [class.cursor-not-allowed]=\"disabled\"\n [class.opacity-60]=\"disabled\"\n [attr.for]=\"controlId\"\n >\n <span\n class=\"block h-9 w-9 rounded-full border border-black/10\"\n [style.backgroundColor]=\"pickerValue\"\n ></span>\n <input\n class=\"absolute inset-0 h-full w-full cursor-pointer opacity-0\"\n type=\"color\"\n [attr.id]=\"controlId\"\n [attr.name]=\"name ? name + '-picker' : null\"\n [disabled]=\"disabled\"\n [value]=\"pickerValue\"\n (input)=\"onPickerChange($event.target.value)\"\n (blur)=\"markTouched()\"\n />\n </label>\n <input\n class=\"min-w-[110px] rounded-xl border border-slate-200 bg-slate-50 px-3 py-2 text-xs font-semibold uppercase text-slate-700 transition focus:border-
|
|
2326
|
+
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-center gap-3\">\n <label\n class=\"relative inline-flex h-11 w-11 cursor-pointer items-center justify-center rounded-full border border-slate-200 bg-white shadow-sm transition hover:border-slate-300\"\n [class.cursor-not-allowed]=\"disabled\"\n [class.opacity-60]=\"disabled\"\n [attr.for]=\"controlId\"\n >\n <span\n class=\"block h-9 w-9 rounded-full border border-black/10\"\n [style.backgroundColor]=\"pickerValue\"\n ></span>\n <input\n class=\"absolute inset-0 h-full w-full cursor-pointer opacity-0\"\n type=\"color\"\n [attr.id]=\"controlId\"\n [attr.name]=\"name ? name + '-picker' : null\"\n [disabled]=\"disabled\"\n [value]=\"pickerValue\"\n (input)=\"onPickerChange($event.target.value)\"\n (blur)=\"markTouched()\"\n />\n </label>\n <input\n class=\"min-w-[110px] rounded-xl border border-slate-200 bg-slate-50 px-3 py-2 text-xs font-semibold uppercase text-slate-700 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200 disabled:cursor-not-allowed disabled:opacity-60\"\n type=\"text\"\n [attr.name]=\"name\"\n [disabled]=\"disabled\"\n [value]=\"value\"\n (input)=\"onHexInput($event.target.value)\"\n (blur)=\"markTouched()\"\n />\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n" }]
|
|
2048
2327
|
}], propDecorators: { label: [{
|
|
2049
2328
|
type: Input
|
|
2050
2329
|
}], hint: [{
|
|
@@ -2109,16 +2388,16 @@ class UiSlugInputComponent {
|
|
|
2109
2388
|
.replace(/\s+/g, '_')
|
|
2110
2389
|
.replace(/[^a-z0-9_]/g, '');
|
|
2111
2390
|
}
|
|
2112
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2113
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
2391
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiSlugInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2392
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiSlugInputComponent, isStandalone: true, selector: "forms-slug-input", inputs: { label: "label", hint: "hint", placeholder: "placeholder", name: "name", id: "id", required: "required", fullWidth: "fullWidth", autocomplete: "autocomplete", readonly: "readonly", error: "error" }, outputs: { invalidInput: "invalidInput" }, providers: [
|
|
2114
2393
|
{
|
|
2115
2394
|
provide: NG_VALUE_ACCESSOR,
|
|
2116
2395
|
useExisting: forwardRef(() => UiSlugInputComponent),
|
|
2117
2396
|
multi: true,
|
|
2118
2397
|
},
|
|
2119
|
-
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <input\n type=\"text\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"rounded-
|
|
2398
|
+
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <input\n type=\"text\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target))\"\n (blur)=\"onTouched()\"\n />\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2120
2399
|
}
|
|
2121
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2400
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiSlugInputComponent, decorators: [{
|
|
2122
2401
|
type: Component,
|
|
2123
2402
|
args: [{ selector: 'forms-slug-input', standalone: true, imports: [CommonModule, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
2124
2403
|
{
|
|
@@ -2126,7 +2405,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
2126
2405
|
useExisting: forwardRef(() => UiSlugInputComponent),
|
|
2127
2406
|
multi: true,
|
|
2128
2407
|
},
|
|
2129
|
-
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <input\n type=\"text\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"rounded-
|
|
2408
|
+
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <input\n type=\"text\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target))\"\n (blur)=\"onTouched()\"\n />\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n" }]
|
|
2130
2409
|
}], propDecorators: { label: [{
|
|
2131
2410
|
type: Input
|
|
2132
2411
|
}], hint: [{
|
|
@@ -2572,10 +2851,10 @@ class UiDynamicFormComponent {
|
|
|
2572
2851
|
getLeafFields() {
|
|
2573
2852
|
return this.getFlatFields().filter((field) => field.type !== 'container' && field.type !== 'template');
|
|
2574
2853
|
}
|
|
2575
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2576
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: UiDynamicFormComponent, isStandalone: true, selector: "forms-dynamic-form", inputs: { fields: "fields", value: "value", errors: "errors", submitLabel: "submitLabel", showSubmit: "showSubmit", disabled: "disabled", uploadPhoto: "uploadPhoto" }, outputs: { valueChange: "valueChange", lookupCompleted: "lookupCompleted", submitted: "submitted", filesChange: "filesChange", uploadingChange: "uploadingChange", fieldActionTriggered: "fieldActionTriggered" }, providers: [UiFormContext, UiFormLookupService], usesOnChanges: true, ngImport: i0, template: "<form class=\"grid grid-cols-1 gap-4 md:grid-cols-12\" (ngSubmit)=\"submitForm()\" #dynamicForm=\"ngForm\">\n <ng-template #renderField let-field>\n @if (isFieldVisible(field)) {\n @if (isContainerField(field)) {\n @if (getContainerTag(field) === 'aside') {\n <aside [ngClass]=\"getContainerClass(field)\">\n @if (field.label || field.title || getActions(field).length || field.hint) {\n <header class=\"flex flex-col gap-3 border-b border-slate-100 pb-3 md:flex-row md:items-center md:justify-between\">\n <div class=\"min-w-0\">\n @if (field.label || field.title) {\n <p class=\"text-xs font-semibold uppercase tracking-[0.22em] text-slate-500\">\n {{ field.label || field.title }}\n </p>\n }\n @if (field.hint) {\n <h3 class=\"mt-1 text-lg font-semibold text-slate-900\">{{ field.hint }}</h3>\n }\n </div>\n\n @if (getActions(field).length) {\n <div class=\"flex flex-wrap gap-2 md:justify-end\">\n @for (action of getActions(field); track action.id; let i = $index) {\n <ui-button\n [variant]=\"action.variant || (i === 0 ? 'primary' : 'ghost')\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n (click)=\"onFieldActionTriggered(field.id, action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </header>\n }\n\n <div [ngClass]=\"getContainerContentClass(field)\">\n @for (child of field.fields; track child.id) {\n <ng-container *ngTemplateOutlet=\"renderField; context: { $implicit: child }\"></ng-container>\n }\n </div>\n </aside>\n } @else if (getContainerTag(field) === 'fieldset') {\n <fieldset [ngClass]=\"getContainerClass(field)\">\n @if (field.label || field.title || getActions(field).length || field.hint) {\n <header class=\"flex flex-col gap-3 border-b border-slate-100 pb-3 md:flex-row md:items-center md:justify-between\">\n <div class=\"min-w-0\">\n @if (field.label || field.title) {\n <legend class=\"text-lg font-semibold text-slate-900\">{{ field.label || field.title }}</legend>\n }\n @if (field.hint) {\n <p class=\"mt-1 text-sm text-slate-500\">{{ field.hint }}</p>\n }\n </div>\n\n @if (getActions(field).length) {\n <div class=\"flex flex-wrap gap-2 md:justify-end\">\n @for (action of getActions(field); track action.id; let i = $index) {\n <ui-button\n [variant]=\"action.variant || (i === 0 ? 'primary' : 'ghost')\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n (click)=\"onFieldActionTriggered(field.id, action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </header>\n }\n\n <div [ngClass]=\"getContainerContentClass(field)\">\n @for (child of field.fields; track child.id) {\n <ng-container *ngTemplateOutlet=\"renderField; context: { $implicit: child }\"></ng-container>\n }\n </div>\n </fieldset>\n } @else {\n <section [ngClass]=\"getContainerClass(field)\">\n @if (field.label || field.title || getActions(field).length || field.hint) {\n <header class=\"flex flex-col gap-3 border-b border-slate-100 pb-3 md:flex-row md:items-center md:justify-between\">\n <div class=\"min-w-0\">\n @if (field.label || field.title) {\n <h3 class=\"text-lg font-semibold text-slate-900\">{{ field.label || field.title }}</h3>\n }\n @if (field.hint) {\n <p class=\"mt-1 text-sm text-slate-500\">{{ field.hint }}</p>\n }\n </div>\n\n @if (getActions(field).length) {\n <div class=\"flex flex-wrap gap-2 md:justify-end\">\n @for (action of getActions(field); track action.id; let i = $index) {\n <ui-button\n [variant]=\"action.variant || (i === 0 ? 'primary' : 'ghost')\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n (click)=\"onFieldActionTriggered(field.id, action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </header>\n }\n\n <div [ngClass]=\"getContainerContentClass(field)\">\n @for (child of field.fields; track child.id) {\n <ng-container *ngTemplateOutlet=\"renderField; context: { $implicit: child }\"></ng-container>\n }\n </div>\n </section>\n }\n } @else if (isTemplateField(field)) {\n <div [ngClass]=\"resolveClassName(field.className)\" [innerHTML]=\"renderTemplate(field)\"></div>\n } @else {\n <div [ngClass]=\"getFieldClass(field)\">\n @if (isBarcodeField(field)) {\n <forms-barcode-scanner-input\n [label]=\"field.label || '\u0428\u0442\u0440\u0438\u0445\u043A\u043E\u0434'\"\n [placeholder]=\"field.placeholder || '\u0412\u0456\u0434\u0441\u043A\u0430\u043D\u0443\u0439\u0442\u0435 \u0430\u0431\u043E \u0432\u0432\u0435\u0434\u0456\u0442\u044C \u0448\u0442\u0440\u0438\u0445\u043A\u043E\u0434'\"\n [hint]=\"field.hint || '\u0421\u043A\u0430\u043D\u0435\u0440 \u043C\u043E\u0436\u0435 \u043F\u0440\u043E\u0441\u0442\u043E \u0432\u0432\u0435\u0441\u0442\u0438 \u043A\u043E\u0434 \u0456 \u043D\u0430\u0442\u0438\u0441\u043D\u0443\u0442\u0438 Enter.'\"\n [disabled]=\"isFieldDisabled(field) || isLookupLoading(field.id)\"\n [autoOpen]=\"field.autoOpen !== false\"\n [value]=\"getStringValue(field.id)\"\n [searchButtonLabel]=\"field.searchButtonLabel || '\u0417\u043D\u0430\u0439\u0442\u0438'\"\n [openCameraLabel]=\"field.openCameraLabel || '\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043A\u0430\u043C\u0435\u0440\u0443'\"\n [closeCameraLabel]=\"field.closeCameraLabel || '\u0417\u0430\u043A\u0440\u0438\u0442\u0438 \u043A\u0430\u043C\u0435\u0440\u0443'\"\n [cameraTitle]=\"field.cameraTitle || '\u041A\u0430\u043C\u0435\u0440\u0430'\"\n [cameraStartingLabel]=\"field.cameraStartingLabel || '\u0417\u0430\u043F\u0443\u0441\u043A\u0430\u0454\u043C\u043E \u043A\u0430\u043C\u0435\u0440\u0443\u2026'\"\n [cameraHint]=\"field.cameraHint || '\u041D\u0430\u0432\u0435\u0434\u0456\u0442\u044C \u043A\u0430\u043C\u0435\u0440\u0443 \u043D\u0430 \u0448\u0442\u0440\u0438\u0445\u043A\u043E\u0434. \u041F\u0456\u0441\u043B\u044F \u0437\u0447\u0438\u0442\u0443\u0432\u0430\u043D\u043D\u044F \u043A\u043E\u0434 \u043F\u0456\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C\u0441\u044F \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u043D\u043E.'\"\n (valueChange)=\"onBarcodeValueChange(field, $event)\"\n (searchRequested)=\"runBarcodeLookup(field)\"\n (scanned)=\"onBarcodeScanned(field, $event)\"\n ></forms-barcode-scanner-input>\n @if (getLookupError(field.id)) {\n <div class=\"mt-3 rounded-2xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700\">\n {{ getLookupError(field.id) }}\n </div>\n }\n }\n\n @if (isInputField(field)) {\n <forms-form-input-host\n [field]=\"field\"\n [value]=\"modelSignal()[field.id]\"\n [disabled]=\"disabled\"\n [error]=\"errors[field.id] ?? ''\"\n [actions]=\"resolveFieldActions(field)\"\n (valueChange)=\"updateField(field.id, $any($event))\"\n (actionTriggered)=\"onFieldActionTriggered(field.id, $event)\"\n ></forms-form-input-host>\n }\n\n @if (field.type === 'select') {\n <forms-select\n [name]=\"field.id\"\n [label]=\"field.label\"\n [placeholder]=\"field.placeholder\"\n [hint]=\"field.hint\"\n [data]=\"field.data\"\n [required]=\"!!field.required\"\n [multiple]=\"!!field.multiple\"\n [disabled]=\"isFieldDisabled(field)\"\n [options]=\"resolveSelectOptions(field)\"\n [searchable]=\"(field.searchable ?? !!field.data) || !!field.optionsSource\"\n [remoteSearch]=\"!!field.optionsSource\"\n (searchChange)=\"field.optionsSource ? onSelectSearchChange(field, $event) : null\"\n [fullWidth]=\"field.fullWidth !== false\"\n [error]=\"errors[field.id] ?? ''\"\n [ngModel]=\"modelSignal()[field.id]\"\n (ngModelChange)=\"onSelectValueChange(field, $event)\">\n </forms-select>\n @if (field.lookupApi && getLookupError(field.id)) {\n <div class=\"mt-3 rounded-2xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700\">\n {{ getLookupError(field.id) }}\n </div>\n }\n }\n\n @if (field.type === 'checkbox') {\n <forms-checkbox-input\n [label]=\"field.label\"\n [disabled]=\"isFieldDisabled(field)\"\n [value]=\"!!modelSignal()[field.id]\"\n (valueChange)=\"updateField(field.id, $event)\"\n ></forms-checkbox-input>\n }\n\n @if (field.type === 'color') {\n <forms-color-input\n [name]=\"field.id\"\n [id]=\"field.id\"\n [label]=\"field.label\"\n [hint]=\"field.hint\"\n [required]=\"!!field.required\"\n [disabled]=\"isFieldDisabled(field)\"\n [fullWidth]=\"field.fullWidth !== false\"\n [error]=\"errors[field.id] ?? ''\"\n [ngModel]=\"modelSignal()[field.id]\"\n (ngModelChange)=\"updateField(field.id, $event)\"\n ></forms-color-input>\n }\n\n @if (field.type === 'slug') {\n <forms-slug-input\n [name]=\"field.id\"\n [id]=\"field.id\"\n [label]=\"field.label\"\n [placeholder]=\"field.placeholder\"\n [hint]=\"field.hint\"\n [required]=\"!!field.required\"\n [readonly]=\"!!field.readonly\"\n [disabled]=\"isFieldDisabled(field)\"\n [fullWidth]=\"field.fullWidth !== false\"\n [error]=\"errors[field.id] ?? ''\"\n [ngModel]=\"modelSignal()[field.id]\"\n (ngModelChange)=\"updateField(field.id, $event)\"\n ></forms-slug-input>\n }\n\n @if (field.type === 'photo') {\n <forms-photo-input\n [label]=\"field.label\"\n [hint]=\"field.hint\"\n [accept]=\"field.accept ?? 'image/*'\"\n [multiple]=\"!!field.multiple\"\n [limit]=\"field.limit ?? 0\"\n [disabled]=\"isFieldDisabled(field)\"\n [value]=\"$any(modelSignal()[field.id])\"\n [uploadPhoto]=\"uploadPhoto\"\n (valueChange)=\"updateField(field.id, $event)\"\n (filesChange)=\"filesChange.emit({ fieldId: field.id, files: $event })\"\n (uploadingChange)=\"uploadingChange.emit($event)\"\n ></forms-photo-input>\n }\n @if (field.type === 'file') {\n <forms-file-input\n [label]=\"field.label\"\n [hint]=\"field.hint\"\n [accept]=\"field.accept\"\n [multiple]=\"!!field.multiple\"\n [disabled]=\"isFieldDisabled(field)\"\n [value]=\"$any(modelSignal()[field.id])\"\n (valueChange)=\"updateField(field.id, $event)\"\n (filesChange)=\"filesChange.emit({ fieldId: field.id, files: $event })\"\n ></forms-file-input>\n }\n </div>\n }\n }\n </ng-template>\n\n @for (field of fields; track field.id) {\n <ng-container *ngTemplateOutlet=\"renderField; context: { $implicit: field }\"></ng-container>\n }\n\n @if (showSubmit) {\n <div class=\"flex justify-end md:col-span-12\">\n <button\n type=\"submit\"\n class=\"inline-flex items-center rounded-xl bg-slate-900 px-4 py-2 text-sm font-medium text-white transition hover:bg-slate-800 disabled:opacity-50\"\n [disabled]=\"disabled || !dynamicForm.form.valid\"\n >\n {{ submitLabel }}\n </button>\n </div>\n }\n</form>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: UiFormInputHostComponent, selector: "forms-form-input-host", inputs: ["field", "value", "error", "disabled", "actions", "options"], outputs: ["valueChange", "actionTriggered"] }, { kind: "component", type: UiFileInputComponent, selector: "forms-file-input", inputs: ["label", "hint", "accept", "multiple", "disabled", "value"], outputs: ["valueChange", "filesChange"] }, { kind: "component", type: UiPhotoInputComponent, selector: "forms-photo-input", inputs: ["label", "hint", "accept", "multiple", "limit", "disabled", "value", "uploadPhoto"], outputs: ["valueChange", "filesChange", "uploadingChange"] }, { kind: "component", type: UiCheckboxInputComponent, selector: "forms-checkbox-input", inputs: ["label", "disabled", "value"], outputs: ["valueChange"] }, { kind: "component", type: UiColorInputComponent, selector: "forms-color-input", inputs: ["label", "hint", "name", "id", "required", "fullWidth", "error"] }, { kind: "component", type: UiSlugInputComponent, selector: "forms-slug-input", inputs: ["label", "hint", "placeholder", "name", "id", "required", "fullWidth", "autocomplete", "readonly", "error"], outputs: ["invalidInput"] }, { kind: "component", type: UiBarcodeScannerInputComponent, selector: "forms-barcode-scanner-input", inputs: ["value", "label", "placeholder", "hint", "disabled", "autoOpen", "searchButtonLabel", "openCameraLabel", "closeCameraLabel", "cameraTitle", "cameraStartingLabel", "cameraHint"], outputs: ["valueChange", "scanned", "searchRequested", "cameraStateChange"] }, { kind: "component", type: UiSelectComponent, selector: "forms-select", inputs: ["label", "placeholder", "name", "data", "required", "fullWidth", "disabled", "multiple", "includeBlankOption", "blankOptionLabel", "emptyStateLabel", "searchable", "remoteSearch", "searchPlaceholder", "options", "error", "hint", "triggerClass", "panelClass"], outputs: ["valueChange", "searchChange"] }] });
|
|
2854
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiDynamicFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2855
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiDynamicFormComponent, isStandalone: true, selector: "forms-dynamic-form", inputs: { fields: "fields", value: "value", errors: "errors", submitLabel: "submitLabel", showSubmit: "showSubmit", disabled: "disabled", uploadPhoto: "uploadPhoto" }, outputs: { valueChange: "valueChange", lookupCompleted: "lookupCompleted", submitted: "submitted", filesChange: "filesChange", uploadingChange: "uploadingChange", fieldActionTriggered: "fieldActionTriggered" }, providers: [UiFormContext, UiFormLookupService], usesOnChanges: true, ngImport: i0, template: "<form class=\"grid grid-cols-1 gap-4 md:grid-cols-12\" (ngSubmit)=\"submitForm()\" #dynamicForm=\"ngForm\">\n <ng-template #renderField let-field>\n @if (isFieldVisible(field)) {\n @if (isContainerField(field)) {\n @if (getContainerTag(field) === 'aside') {\n <aside [ngClass]=\"getContainerClass(field)\">\n @if (field.label || field.title || getActions(field).length || field.hint) {\n <header class=\"flex flex-col gap-3 border-b border-slate-100 pb-3 md:flex-row md:items-center md:justify-between\">\n <div class=\"min-w-0\">\n @if (field.label || field.title) {\n <p class=\"text-xs font-semibold uppercase tracking-[0.22em] text-slate-500\">\n {{ field.label || field.title }}\n </p>\n }\n @if (field.hint) {\n <h3 class=\"mt-1 text-lg font-semibold text-slate-900\">{{ field.hint }}</h3>\n }\n </div>\n\n @if (getActions(field).length) {\n <div class=\"flex flex-wrap gap-2 md:justify-end\">\n @for (action of getActions(field); track action.id; let i = $index) {\n <ui-button\n [variant]=\"action.variant || (i === 0 ? 'primary' : 'ghost')\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n (click)=\"onFieldActionTriggered(field.id, action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </header>\n }\n\n <div [ngClass]=\"getContainerContentClass(field)\">\n @for (child of field.fields; track child.id) {\n <ng-container *ngTemplateOutlet=\"renderField; context: { $implicit: child }\"></ng-container>\n }\n </div>\n </aside>\n } @else if (getContainerTag(field) === 'fieldset') {\n <fieldset [ngClass]=\"getContainerClass(field)\">\n @if (field.label || field.title || getActions(field).length || field.hint) {\n <header class=\"flex flex-col gap-3 border-b border-slate-100 pb-3 md:flex-row md:items-center md:justify-between\">\n <div class=\"min-w-0\">\n @if (field.label || field.title) {\n <legend class=\"text-lg font-semibold text-slate-900\">{{ field.label || field.title }}</legend>\n }\n @if (field.hint) {\n <p class=\"mt-1 text-sm text-slate-500\">{{ field.hint }}</p>\n }\n </div>\n\n @if (getActions(field).length) {\n <div class=\"flex flex-wrap gap-2 md:justify-end\">\n @for (action of getActions(field); track action.id; let i = $index) {\n <ui-button\n [variant]=\"action.variant || (i === 0 ? 'primary' : 'ghost')\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n (click)=\"onFieldActionTriggered(field.id, action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </header>\n }\n\n <div [ngClass]=\"getContainerContentClass(field)\">\n @for (child of field.fields; track child.id) {\n <ng-container *ngTemplateOutlet=\"renderField; context: { $implicit: child }\"></ng-container>\n }\n </div>\n </fieldset>\n } @else {\n <section [ngClass]=\"getContainerClass(field)\">\n @if (field.label || field.title || getActions(field).length || field.hint) {\n <header class=\"flex flex-col gap-3 border-b border-slate-100 pb-3 md:flex-row md:items-center md:justify-between\">\n <div class=\"min-w-0\">\n @if (field.label || field.title) {\n <h3 class=\"text-lg font-semibold text-slate-900\">{{ field.label || field.title }}</h3>\n }\n @if (field.hint) {\n <p class=\"mt-1 text-sm text-slate-500\">{{ field.hint }}</p>\n }\n </div>\n\n @if (getActions(field).length) {\n <div class=\"flex flex-wrap gap-2 md:justify-end\">\n @for (action of getActions(field); track action.id; let i = $index) {\n <ui-button\n [variant]=\"action.variant || (i === 0 ? 'primary' : 'ghost')\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n (click)=\"onFieldActionTriggered(field.id, action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </header>\n }\n\n <div [ngClass]=\"getContainerContentClass(field)\">\n @for (child of field.fields; track child.id) {\n <ng-container *ngTemplateOutlet=\"renderField; context: { $implicit: child }\"></ng-container>\n }\n </div>\n </section>\n }\n } @else if (isTemplateField(field)) {\n <div [ngClass]=\"resolveClassName(field.className)\" [innerHTML]=\"renderTemplate(field)\"></div>\n } @else {\n <div [ngClass]=\"getFieldClass(field)\">\n @if (isBarcodeField(field)) {\n <forms-barcode-scanner-input\n [label]=\"field.label || '\u0428\u0442\u0440\u0438\u0445\u043A\u043E\u0434'\"\n [placeholder]=\"field.placeholder || '\u0412\u0456\u0434\u0441\u043A\u0430\u043D\u0443\u0439\u0442\u0435 \u0430\u0431\u043E \u0432\u0432\u0435\u0434\u0456\u0442\u044C \u0448\u0442\u0440\u0438\u0445\u043A\u043E\u0434'\"\n [hint]=\"field.hint || '\u0421\u043A\u0430\u043D\u0435\u0440 \u043C\u043E\u0436\u0435 \u043F\u0440\u043E\u0441\u0442\u043E \u0432\u0432\u0435\u0441\u0442\u0438 \u043A\u043E\u0434 \u0456 \u043D\u0430\u0442\u0438\u0441\u043D\u0443\u0442\u0438 Enter.'\"\n [disabled]=\"isFieldDisabled(field) || isLookupLoading(field.id)\"\n [autoOpen]=\"field.autoOpen !== false\"\n [value]=\"getStringValue(field.id)\"\n [searchButtonLabel]=\"field.searchButtonLabel || '\u0417\u043D\u0430\u0439\u0442\u0438'\"\n [openCameraLabel]=\"field.openCameraLabel || '\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043A\u0430\u043C\u0435\u0440\u0443'\"\n [closeCameraLabel]=\"field.closeCameraLabel || '\u0417\u0430\u043A\u0440\u0438\u0442\u0438 \u043A\u0430\u043C\u0435\u0440\u0443'\"\n [cameraTitle]=\"field.cameraTitle || '\u041A\u0430\u043C\u0435\u0440\u0430'\"\n [cameraStartingLabel]=\"field.cameraStartingLabel || '\u0417\u0430\u043F\u0443\u0441\u043A\u0430\u0454\u043C\u043E \u043A\u0430\u043C\u0435\u0440\u0443\u2026'\"\n [cameraHint]=\"field.cameraHint || '\u041D\u0430\u0432\u0435\u0434\u0456\u0442\u044C \u043A\u0430\u043C\u0435\u0440\u0443 \u043D\u0430 \u0448\u0442\u0440\u0438\u0445\u043A\u043E\u0434. \u041F\u0456\u0441\u043B\u044F \u0437\u0447\u0438\u0442\u0443\u0432\u0430\u043D\u043D\u044F \u043A\u043E\u0434 \u043F\u0456\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C\u0441\u044F \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u043D\u043E.'\"\n (valueChange)=\"onBarcodeValueChange(field, $event)\"\n (searchRequested)=\"runBarcodeLookup(field)\"\n (scanned)=\"onBarcodeScanned(field, $event)\"\n ></forms-barcode-scanner-input>\n @if (getLookupError(field.id)) {\n <div class=\"mt-3 rounded-2xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700\">\n {{ getLookupError(field.id) }}\n </div>\n }\n }\n\n @if (isInputField(field)) {\n <forms-form-input-host\n [field]=\"field\"\n [value]=\"modelSignal()[field.id]\"\n [disabled]=\"disabled\"\n [error]=\"errors[field.id] ?? ''\"\n [actions]=\"resolveFieldActions(field)\"\n (valueChange)=\"updateField(field.id, $any($event))\"\n (actionTriggered)=\"onFieldActionTriggered(field.id, $event)\"\n ></forms-form-input-host>\n }\n\n @if (field.type === 'select') {\n <forms-select\n [name]=\"field.id\"\n [label]=\"field.label\"\n [placeholder]=\"field.placeholder\"\n [hint]=\"field.hint\"\n [data]=\"field.data\"\n [required]=\"!!field.required\"\n [multiple]=\"!!field.multiple\"\n [disabled]=\"isFieldDisabled(field)\"\n [options]=\"resolveSelectOptions(field)\"\n [searchable]=\"(field.searchable ?? !!field.data) || !!field.optionsSource\"\n [remoteSearch]=\"!!field.optionsSource\"\n (searchChange)=\"field.optionsSource ? onSelectSearchChange(field, $event) : null\"\n [fullWidth]=\"field.fullWidth !== false\"\n [error]=\"errors[field.id] ?? ''\"\n [ngModel]=\"modelSignal()[field.id]\"\n (ngModelChange)=\"onSelectValueChange(field, $event)\">\n </forms-select>\n @if (field.lookupApi && getLookupError(field.id)) {\n <div class=\"mt-3 rounded-2xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700\">\n {{ getLookupError(field.id) }}\n </div>\n }\n }\n\n @if (field.type === 'checkbox') {\n <forms-checkbox-input\n [label]=\"field.label\"\n [disabled]=\"isFieldDisabled(field)\"\n [value]=\"!!modelSignal()[field.id]\"\n (valueChange)=\"updateField(field.id, $event)\"\n ></forms-checkbox-input>\n }\n\n @if (field.type === 'color') {\n <forms-color-input\n [name]=\"field.id\"\n [id]=\"field.id\"\n [label]=\"field.label\"\n [hint]=\"field.hint\"\n [required]=\"!!field.required\"\n [disabled]=\"isFieldDisabled(field)\"\n [fullWidth]=\"field.fullWidth !== false\"\n [error]=\"errors[field.id] ?? ''\"\n [ngModel]=\"modelSignal()[field.id]\"\n (ngModelChange)=\"updateField(field.id, $event)\"\n ></forms-color-input>\n }\n\n @if (field.type === 'slug') {\n <forms-slug-input\n [name]=\"field.id\"\n [id]=\"field.id\"\n [label]=\"field.label\"\n [placeholder]=\"field.placeholder\"\n [hint]=\"field.hint\"\n [required]=\"!!field.required\"\n [readonly]=\"!!field.readonly\"\n [disabled]=\"isFieldDisabled(field)\"\n [fullWidth]=\"field.fullWidth !== false\"\n [error]=\"errors[field.id] ?? ''\"\n [ngModel]=\"modelSignal()[field.id]\"\n (ngModelChange)=\"updateField(field.id, $event)\"\n ></forms-slug-input>\n }\n\n @if (field.type === 'photo') {\n <forms-photo-input\n [label]=\"field.label\"\n [hint]=\"field.hint\"\n [accept]=\"field.accept ?? 'image/*'\"\n [multiple]=\"!!field.multiple\"\n [limit]=\"field.limit ?? 0\"\n [disabled]=\"isFieldDisabled(field)\"\n [value]=\"$any(modelSignal()[field.id])\"\n [uploadPhoto]=\"uploadPhoto\"\n (valueChange)=\"updateField(field.id, $event)\"\n (filesChange)=\"filesChange.emit({ fieldId: field.id, files: $event })\"\n (uploadingChange)=\"uploadingChange.emit($event)\"\n ></forms-photo-input>\n }\n @if (field.type === 'file') {\n <forms-file-input\n [label]=\"field.label\"\n [hint]=\"field.hint\"\n [accept]=\"field.accept\"\n [multiple]=\"!!field.multiple\"\n [disabled]=\"isFieldDisabled(field)\"\n [value]=\"$any(modelSignal()[field.id])\"\n (valueChange)=\"updateField(field.id, $event)\"\n (filesChange)=\"filesChange.emit({ fieldId: field.id, files: $event })\"\n ></forms-file-input>\n }\n </div>\n }\n }\n </ng-template>\n\n @for (field of fields; track field.id) {\n <ng-container *ngTemplateOutlet=\"renderField; context: { $implicit: field }\"></ng-container>\n }\n\n @if (showSubmit) {\n <div class=\"flex justify-end md:col-span-12\">\n <button\n type=\"submit\"\n class=\"inline-flex items-center rounded-xl bg-slate-900 px-4 py-2 text-sm font-medium text-white transition hover:bg-slate-800 disabled:opacity-50\"\n [disabled]=\"disabled || !dynamicForm.form.valid\"\n >\n {{ submitLabel }}\n </button>\n </div>\n }\n</form>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: UiFormInputHostComponent, selector: "forms-form-input-host", inputs: ["field", "value", "error", "disabled", "actions", "options"], outputs: ["valueChange", "actionTriggered"] }, { kind: "component", type: UiFileInputComponent, selector: "forms-file-input", inputs: ["label", "hint", "accept", "multiple", "disabled", "value"], outputs: ["valueChange", "filesChange"] }, { kind: "component", type: UiPhotoInputComponent, selector: "forms-photo-input", inputs: ["label", "hint", "accept", "multiple", "limit", "disabled", "value", "uploadPhoto"], outputs: ["valueChange", "filesChange", "uploadingChange"] }, { kind: "component", type: UiCheckboxInputComponent, selector: "forms-checkbox-input", inputs: ["label", "disabled", "value"], outputs: ["valueChange"] }, { kind: "component", type: UiColorInputComponent, selector: "forms-color-input", inputs: ["label", "hint", "name", "id", "required", "fullWidth", "error"] }, { kind: "component", type: UiSlugInputComponent, selector: "forms-slug-input", inputs: ["label", "hint", "placeholder", "name", "id", "required", "fullWidth", "autocomplete", "readonly", "error"], outputs: ["invalidInput"] }, { kind: "component", type: UiBarcodeScannerInputComponent, selector: "forms-barcode-scanner-input", inputs: ["value", "label", "placeholder", "hint", "disabled", "autoOpen", "searchButtonLabel", "openCameraLabel", "closeCameraLabel", "cameraTitle", "cameraStartingLabel", "cameraHint"], outputs: ["valueChange", "scanned", "searchRequested", "cameraStateChange"] }, { kind: "component", type: UiSelectComponent, selector: "forms-select", inputs: ["label", "placeholder", "name", "data", "required", "fullWidth", "disabled", "multiple", "includeBlankOption", "blankOptionLabel", "emptyStateLabel", "searchable", "remoteSearch", "searchPlaceholder", "options", "error", "hint", "triggerClass", "panelClass"], outputs: ["valueChange", "searchChange"] }] });
|
|
2577
2856
|
}
|
|
2578
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2857
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiDynamicFormComponent, decorators: [{
|
|
2579
2858
|
type: Component,
|
|
2580
2859
|
args: [{ selector: 'forms-dynamic-form', standalone: true, imports: [CommonModule, FormsModule, UiButtonComponent, UiFormInputHostComponent, UiFileInputComponent, UiPhotoInputComponent, UiCheckboxInputComponent, UiColorInputComponent, UiSlugInputComponent, UiBarcodeScannerInputComponent, UiSelectComponent], providers: [UiFormContext, UiFormLookupService], template: "<form class=\"grid grid-cols-1 gap-4 md:grid-cols-12\" (ngSubmit)=\"submitForm()\" #dynamicForm=\"ngForm\">\n <ng-template #renderField let-field>\n @if (isFieldVisible(field)) {\n @if (isContainerField(field)) {\n @if (getContainerTag(field) === 'aside') {\n <aside [ngClass]=\"getContainerClass(field)\">\n @if (field.label || field.title || getActions(field).length || field.hint) {\n <header class=\"flex flex-col gap-3 border-b border-slate-100 pb-3 md:flex-row md:items-center md:justify-between\">\n <div class=\"min-w-0\">\n @if (field.label || field.title) {\n <p class=\"text-xs font-semibold uppercase tracking-[0.22em] text-slate-500\">\n {{ field.label || field.title }}\n </p>\n }\n @if (field.hint) {\n <h3 class=\"mt-1 text-lg font-semibold text-slate-900\">{{ field.hint }}</h3>\n }\n </div>\n\n @if (getActions(field).length) {\n <div class=\"flex flex-wrap gap-2 md:justify-end\">\n @for (action of getActions(field); track action.id; let i = $index) {\n <ui-button\n [variant]=\"action.variant || (i === 0 ? 'primary' : 'ghost')\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n (click)=\"onFieldActionTriggered(field.id, action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </header>\n }\n\n <div [ngClass]=\"getContainerContentClass(field)\">\n @for (child of field.fields; track child.id) {\n <ng-container *ngTemplateOutlet=\"renderField; context: { $implicit: child }\"></ng-container>\n }\n </div>\n </aside>\n } @else if (getContainerTag(field) === 'fieldset') {\n <fieldset [ngClass]=\"getContainerClass(field)\">\n @if (field.label || field.title || getActions(field).length || field.hint) {\n <header class=\"flex flex-col gap-3 border-b border-slate-100 pb-3 md:flex-row md:items-center md:justify-between\">\n <div class=\"min-w-0\">\n @if (field.label || field.title) {\n <legend class=\"text-lg font-semibold text-slate-900\">{{ field.label || field.title }}</legend>\n }\n @if (field.hint) {\n <p class=\"mt-1 text-sm text-slate-500\">{{ field.hint }}</p>\n }\n </div>\n\n @if (getActions(field).length) {\n <div class=\"flex flex-wrap gap-2 md:justify-end\">\n @for (action of getActions(field); track action.id; let i = $index) {\n <ui-button\n [variant]=\"action.variant || (i === 0 ? 'primary' : 'ghost')\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n (click)=\"onFieldActionTriggered(field.id, action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </header>\n }\n\n <div [ngClass]=\"getContainerContentClass(field)\">\n @for (child of field.fields; track child.id) {\n <ng-container *ngTemplateOutlet=\"renderField; context: { $implicit: child }\"></ng-container>\n }\n </div>\n </fieldset>\n } @else {\n <section [ngClass]=\"getContainerClass(field)\">\n @if (field.label || field.title || getActions(field).length || field.hint) {\n <header class=\"flex flex-col gap-3 border-b border-slate-100 pb-3 md:flex-row md:items-center md:justify-between\">\n <div class=\"min-w-0\">\n @if (field.label || field.title) {\n <h3 class=\"text-lg font-semibold text-slate-900\">{{ field.label || field.title }}</h3>\n }\n @if (field.hint) {\n <p class=\"mt-1 text-sm text-slate-500\">{{ field.hint }}</p>\n }\n </div>\n\n @if (getActions(field).length) {\n <div class=\"flex flex-wrap gap-2 md:justify-end\">\n @for (action of getActions(field); track action.id; let i = $index) {\n <ui-button\n [variant]=\"action.variant || (i === 0 ? 'primary' : 'ghost')\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n (click)=\"onFieldActionTriggered(field.id, action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </header>\n }\n\n <div [ngClass]=\"getContainerContentClass(field)\">\n @for (child of field.fields; track child.id) {\n <ng-container *ngTemplateOutlet=\"renderField; context: { $implicit: child }\"></ng-container>\n }\n </div>\n </section>\n }\n } @else if (isTemplateField(field)) {\n <div [ngClass]=\"resolveClassName(field.className)\" [innerHTML]=\"renderTemplate(field)\"></div>\n } @else {\n <div [ngClass]=\"getFieldClass(field)\">\n @if (isBarcodeField(field)) {\n <forms-barcode-scanner-input\n [label]=\"field.label || '\u0428\u0442\u0440\u0438\u0445\u043A\u043E\u0434'\"\n [placeholder]=\"field.placeholder || '\u0412\u0456\u0434\u0441\u043A\u0430\u043D\u0443\u0439\u0442\u0435 \u0430\u0431\u043E \u0432\u0432\u0435\u0434\u0456\u0442\u044C \u0448\u0442\u0440\u0438\u0445\u043A\u043E\u0434'\"\n [hint]=\"field.hint || '\u0421\u043A\u0430\u043D\u0435\u0440 \u043C\u043E\u0436\u0435 \u043F\u0440\u043E\u0441\u0442\u043E \u0432\u0432\u0435\u0441\u0442\u0438 \u043A\u043E\u0434 \u0456 \u043D\u0430\u0442\u0438\u0441\u043D\u0443\u0442\u0438 Enter.'\"\n [disabled]=\"isFieldDisabled(field) || isLookupLoading(field.id)\"\n [autoOpen]=\"field.autoOpen !== false\"\n [value]=\"getStringValue(field.id)\"\n [searchButtonLabel]=\"field.searchButtonLabel || '\u0417\u043D\u0430\u0439\u0442\u0438'\"\n [openCameraLabel]=\"field.openCameraLabel || '\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043A\u0430\u043C\u0435\u0440\u0443'\"\n [closeCameraLabel]=\"field.closeCameraLabel || '\u0417\u0430\u043A\u0440\u0438\u0442\u0438 \u043A\u0430\u043C\u0435\u0440\u0443'\"\n [cameraTitle]=\"field.cameraTitle || '\u041A\u0430\u043C\u0435\u0440\u0430'\"\n [cameraStartingLabel]=\"field.cameraStartingLabel || '\u0417\u0430\u043F\u0443\u0441\u043A\u0430\u0454\u043C\u043E \u043A\u0430\u043C\u0435\u0440\u0443\u2026'\"\n [cameraHint]=\"field.cameraHint || '\u041D\u0430\u0432\u0435\u0434\u0456\u0442\u044C \u043A\u0430\u043C\u0435\u0440\u0443 \u043D\u0430 \u0448\u0442\u0440\u0438\u0445\u043A\u043E\u0434. \u041F\u0456\u0441\u043B\u044F \u0437\u0447\u0438\u0442\u0443\u0432\u0430\u043D\u043D\u044F \u043A\u043E\u0434 \u043F\u0456\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C\u0441\u044F \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u043D\u043E.'\"\n (valueChange)=\"onBarcodeValueChange(field, $event)\"\n (searchRequested)=\"runBarcodeLookup(field)\"\n (scanned)=\"onBarcodeScanned(field, $event)\"\n ></forms-barcode-scanner-input>\n @if (getLookupError(field.id)) {\n <div class=\"mt-3 rounded-2xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700\">\n {{ getLookupError(field.id) }}\n </div>\n }\n }\n\n @if (isInputField(field)) {\n <forms-form-input-host\n [field]=\"field\"\n [value]=\"modelSignal()[field.id]\"\n [disabled]=\"disabled\"\n [error]=\"errors[field.id] ?? ''\"\n [actions]=\"resolveFieldActions(field)\"\n (valueChange)=\"updateField(field.id, $any($event))\"\n (actionTriggered)=\"onFieldActionTriggered(field.id, $event)\"\n ></forms-form-input-host>\n }\n\n @if (field.type === 'select') {\n <forms-select\n [name]=\"field.id\"\n [label]=\"field.label\"\n [placeholder]=\"field.placeholder\"\n [hint]=\"field.hint\"\n [data]=\"field.data\"\n [required]=\"!!field.required\"\n [multiple]=\"!!field.multiple\"\n [disabled]=\"isFieldDisabled(field)\"\n [options]=\"resolveSelectOptions(field)\"\n [searchable]=\"(field.searchable ?? !!field.data) || !!field.optionsSource\"\n [remoteSearch]=\"!!field.optionsSource\"\n (searchChange)=\"field.optionsSource ? onSelectSearchChange(field, $event) : null\"\n [fullWidth]=\"field.fullWidth !== false\"\n [error]=\"errors[field.id] ?? ''\"\n [ngModel]=\"modelSignal()[field.id]\"\n (ngModelChange)=\"onSelectValueChange(field, $event)\">\n </forms-select>\n @if (field.lookupApi && getLookupError(field.id)) {\n <div class=\"mt-3 rounded-2xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700\">\n {{ getLookupError(field.id) }}\n </div>\n }\n }\n\n @if (field.type === 'checkbox') {\n <forms-checkbox-input\n [label]=\"field.label\"\n [disabled]=\"isFieldDisabled(field)\"\n [value]=\"!!modelSignal()[field.id]\"\n (valueChange)=\"updateField(field.id, $event)\"\n ></forms-checkbox-input>\n }\n\n @if (field.type === 'color') {\n <forms-color-input\n [name]=\"field.id\"\n [id]=\"field.id\"\n [label]=\"field.label\"\n [hint]=\"field.hint\"\n [required]=\"!!field.required\"\n [disabled]=\"isFieldDisabled(field)\"\n [fullWidth]=\"field.fullWidth !== false\"\n [error]=\"errors[field.id] ?? ''\"\n [ngModel]=\"modelSignal()[field.id]\"\n (ngModelChange)=\"updateField(field.id, $event)\"\n ></forms-color-input>\n }\n\n @if (field.type === 'slug') {\n <forms-slug-input\n [name]=\"field.id\"\n [id]=\"field.id\"\n [label]=\"field.label\"\n [placeholder]=\"field.placeholder\"\n [hint]=\"field.hint\"\n [required]=\"!!field.required\"\n [readonly]=\"!!field.readonly\"\n [disabled]=\"isFieldDisabled(field)\"\n [fullWidth]=\"field.fullWidth !== false\"\n [error]=\"errors[field.id] ?? ''\"\n [ngModel]=\"modelSignal()[field.id]\"\n (ngModelChange)=\"updateField(field.id, $event)\"\n ></forms-slug-input>\n }\n\n @if (field.type === 'photo') {\n <forms-photo-input\n [label]=\"field.label\"\n [hint]=\"field.hint\"\n [accept]=\"field.accept ?? 'image/*'\"\n [multiple]=\"!!field.multiple\"\n [limit]=\"field.limit ?? 0\"\n [disabled]=\"isFieldDisabled(field)\"\n [value]=\"$any(modelSignal()[field.id])\"\n [uploadPhoto]=\"uploadPhoto\"\n (valueChange)=\"updateField(field.id, $event)\"\n (filesChange)=\"filesChange.emit({ fieldId: field.id, files: $event })\"\n (uploadingChange)=\"uploadingChange.emit($event)\"\n ></forms-photo-input>\n }\n @if (field.type === 'file') {\n <forms-file-input\n [label]=\"field.label\"\n [hint]=\"field.hint\"\n [accept]=\"field.accept\"\n [multiple]=\"!!field.multiple\"\n [disabled]=\"isFieldDisabled(field)\"\n [value]=\"$any(modelSignal()[field.id])\"\n (valueChange)=\"updateField(field.id, $event)\"\n (filesChange)=\"filesChange.emit({ fieldId: field.id, files: $event })\"\n ></forms-file-input>\n }\n </div>\n }\n }\n </ng-template>\n\n @for (field of fields; track field.id) {\n <ng-container *ngTemplateOutlet=\"renderField; context: { $implicit: field }\"></ng-container>\n }\n\n @if (showSubmit) {\n <div class=\"flex justify-end md:col-span-12\">\n <button\n type=\"submit\"\n class=\"inline-flex items-center rounded-xl bg-slate-900 px-4 py-2 text-sm font-medium text-white transition hover:bg-slate-800 disabled:opacity-50\"\n [disabled]=\"disabled || !dynamicForm.form.valid\"\n >\n {{ submitLabel }}\n </button>\n </div>\n }\n</form>\n" }]
|
|
2581
2860
|
}], propDecorators: { fields: [{
|
|
@@ -2730,10 +3009,10 @@ class UiActionFormModalComponent {
|
|
|
2730
3009
|
if (target && !target.includes(':'))
|
|
2731
3010
|
void this.router.navigateByUrl(target.startsWith('/') ? target : `/${target}`);
|
|
2732
3011
|
}
|
|
2733
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2734
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
3012
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiActionFormModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3013
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiActionFormModalComponent, isStandalone: true, selector: "forms-action-form-modal", inputs: { formId: { classPropertyName: "formId", publicName: "formId", isSignal: true, isRequired: false, transformFunction: null }, recordId: { classPropertyName: "recordId", publicName: "recordId", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, initialValue: { classPropertyName: "initialValue", publicName: "initialValue", isSignal: true, isRequired: false, transformFunction: null }, uploadPhoto: { classPropertyName: "uploadPhoto", publicName: "uploadPhoto", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", completed: "completed" }, usesOnChanges: true, ngImport: i0, template: "@if (isOpen()) {\n <div class=\"fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-slate-950/40 p-4 sm:items-center sm:p-6\" role=\"dialog\" aria-modal=\"true\">\n <div class=\"my-2 flex min-h-0 max-h-[calc(100vh-1rem)] w-full flex-col overflow-hidden rounded-2xl bg-slate-50 shadow-2xl sm:my-0 sm:max-h-[calc(100vh-3rem)]\" [ngClass]=\"panelClass()\">\n <div class=\"flex shrink-0 items-center justify-between border-b border-slate-200 bg-white px-5 py-4 sm:px-6\">\n <h2 class=\"text-lg font-semibold\">{{ formConfig()?.title || 'Form' }}</h2>\n <button type=\"button\" class=\"text-xl text-slate-400 hover:text-slate-900\" aria-label=\"Close\" (click)=\"close()\">\u00D7</button>\n </div>\n <div class=\"min-h-0 flex-1 overflow-y-auto p-4 sm:p-6\">\n @if (isLoading()) {\n <p class=\"text-sm text-slate-500\">Loading form\u2026</p>\n } @else {\n <forms-dynamic-form [fields]=\"fields()\" [value]=\"formValue()\" [showSubmit]=\"false\" [uploadPhoto]=\"uploadPhoto()\" (valueChange)=\"onValueChange($event)\" (lookupCompleted)=\"onLookupCompleted($event)\" (uploadingChange)=\"onUploadingChange($event)\" (fieldActionTriggered)=\"onFieldActionTriggered($event)\"></forms-dynamic-form>\n }\n </div>\n <div class=\"relative z-10 flex shrink-0 justify-end gap-3 border-t border-slate-200 bg-white px-5 py-4 sm:px-6\">\n <ui-button variant=\"ghost\" (click)=\"close()\">Cancel</ui-button>\n @if (submitAction()) { <ui-button variant=\"primary\" [disabled]=\"isLoading() || isSubmitting() || isUploading()\" (click)=\"confirm()\">{{ submitLabel() }}</ui-button> }\n </div>\n </div>\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: UiDynamicFormComponent, selector: "forms-dynamic-form", inputs: ["fields", "value", "errors", "submitLabel", "showSubmit", "disabled", "uploadPhoto"], outputs: ["valueChange", "lookupCompleted", "submitted", "filesChange", "uploadingChange", "fieldActionTriggered"] }] });
|
|
2735
3014
|
}
|
|
2736
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
3015
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiActionFormModalComponent, decorators: [{
|
|
2737
3016
|
type: Component,
|
|
2738
3017
|
args: [{ selector: 'forms-action-form-modal', standalone: true, imports: [CommonModule, UiButtonComponent, UiDynamicFormComponent], template: "@if (isOpen()) {\n <div class=\"fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-slate-950/40 p-4 sm:items-center sm:p-6\" role=\"dialog\" aria-modal=\"true\">\n <div class=\"my-2 flex min-h-0 max-h-[calc(100vh-1rem)] w-full flex-col overflow-hidden rounded-2xl bg-slate-50 shadow-2xl sm:my-0 sm:max-h-[calc(100vh-3rem)]\" [ngClass]=\"panelClass()\">\n <div class=\"flex shrink-0 items-center justify-between border-b border-slate-200 bg-white px-5 py-4 sm:px-6\">\n <h2 class=\"text-lg font-semibold\">{{ formConfig()?.title || 'Form' }}</h2>\n <button type=\"button\" class=\"text-xl text-slate-400 hover:text-slate-900\" aria-label=\"Close\" (click)=\"close()\">\u00D7</button>\n </div>\n <div class=\"min-h-0 flex-1 overflow-y-auto p-4 sm:p-6\">\n @if (isLoading()) {\n <p class=\"text-sm text-slate-500\">Loading form\u2026</p>\n } @else {\n <forms-dynamic-form [fields]=\"fields()\" [value]=\"formValue()\" [showSubmit]=\"false\" [uploadPhoto]=\"uploadPhoto()\" (valueChange)=\"onValueChange($event)\" (lookupCompleted)=\"onLookupCompleted($event)\" (uploadingChange)=\"onUploadingChange($event)\" (fieldActionTriggered)=\"onFieldActionTriggered($event)\"></forms-dynamic-form>\n }\n </div>\n <div class=\"relative z-10 flex shrink-0 justify-end gap-3 border-t border-slate-200 bg-white px-5 py-4 sm:px-6\">\n <ui-button variant=\"ghost\" (click)=\"close()\">Cancel</ui-button>\n @if (submitAction()) { <ui-button variant=\"primary\" [disabled]=\"isLoading() || isSubmitting() || isUploading()\" (click)=\"confirm()\">{{ submitLabel() }}</ui-button> }\n </div>\n </div>\n </div>\n}\n" }]
|
|
2739
3018
|
}], propDecorators: { formId: [{ type: i0.Input, args: [{ isSignal: true, alias: "formId", required: false }] }], recordId: [{ type: i0.Input, args: [{ isSignal: true, alias: "recordId", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }], initialValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialValue", required: false }] }], uploadPhoto: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadPhoto", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], completed: [{ type: i0.Output, args: ["completed"] }] } });
|
|
@@ -2787,16 +3066,16 @@ class UiInputComponent {
|
|
|
2787
3066
|
triggerAction(action) {
|
|
2788
3067
|
this.actionTriggered.emit(action);
|
|
2789
3068
|
}
|
|
2790
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2791
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
3069
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3070
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiInputComponent, isStandalone: true, selector: "forms-input", inputs: { label: "label", hint: "hint", placeholder: "placeholder", name: "name", id: "id", type: "type", element: "element", rows: "rows", required: "required", fullWidth: "fullWidth", autocomplete: "autocomplete", readonly: "readonly", pattern: "pattern", error: "error", actions: "actions" }, outputs: { actionTriggered: "actionTriggered" }, providers: [
|
|
2792
3071
|
{
|
|
2793
3072
|
provide: NG_VALUE_ACCESSOR,
|
|
2794
3073
|
useExisting: forwardRef(() => UiInputComponent),
|
|
2795
3074
|
multi: true,
|
|
2796
3075
|
},
|
|
2797
|
-
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-
|
|
3076
|
+
], ngImport: i0, template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <input\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.pattern]=\"pattern\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n />\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2798
3077
|
}
|
|
2799
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
3078
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiInputComponent, decorators: [{
|
|
2800
3079
|
type: Component,
|
|
2801
3080
|
args: [{ selector: 'forms-input', standalone: true, imports: [CommonModule, FormsModule, UiButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
2802
3081
|
{
|
|
@@ -2804,7 +3083,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
2804
3083
|
useExisting: forwardRef(() => UiInputComponent),
|
|
2805
3084
|
multi: true,
|
|
2806
3085
|
},
|
|
2807
|
-
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-
|
|
3086
|
+
], template: "<label\n class=\"flex flex-col gap-1 text-[0.65rem] uppercase tracking-[0.3em] text-slate-500\"\n [class.w-full]=\"fullWidth\"\n [attr.for]=\"controlId\"\n>\n @if (label) {\n <span class=\"text-[0.7rem] font-semibold text-slate-600\">\n {{ label }}\n @if (required) {\n <span aria-hidden=\"true\" class=\"text-rose-500\"> *</span>\n }\n </span>\n }\n\n <div class=\"flex items-end gap-2\">\n <div class=\"min-w-0 flex-1\">\n @if (element === 'textarea') {\n <textarea\n [attr.rows]=\"rows\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.id]=\"controlId\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n ></textarea>\n } @else {\n <input\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.name]=\"name\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.pattern]=\"pattern\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 placeholder:text-slate-400 transition focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [attr.id]=\"controlId\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (blur)=\"onTouched()\"\n />\n }\n </div>\n\n @if (actions.length) {\n <div class=\"flex flex-none items-center gap-2 pb-0.5\">\n @for (action of actions; track action.id) {\n <ui-button\n type=\"button\"\n [variant]=\"action.variant ?? 'secondary'\"\n [icon]=\"action.icon || ''\"\n size=\"sm\"\n [disabled]=\"disabled\"\n (click)=\"triggerAction(action)\"\n >\n {{ action.label }}\n </ui-button>\n }\n </div>\n }\n </div>\n\n @if (hint) {\n <p class=\"text-[0.5rem] text-slate-500\">{{ hint }}</p>\n }\n @if (error) {\n <p class=\"text-[0.5rem] text-rose-400\">{{ error }}</p>\n }\n</label>\n\n\n\n" }]
|
|
2808
3087
|
}], propDecorators: { label: [{
|
|
2809
3088
|
type: Input
|
|
2810
3089
|
}], hint: [{
|
|
@@ -2976,10 +3255,10 @@ class UiPhotoGalleryFieldComponent {
|
|
|
2976
3255
|
},
|
|
2977
3256
|
});
|
|
2978
3257
|
}
|
|
2979
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2980
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
3258
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiPhotoGalleryFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3259
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiPhotoGalleryFieldComponent, isStandalone: true, selector: "forms-photo-gallery-field", inputs: { label: "label", orderLabel: "orderLabel", imageIds: "imageIds", disabled: "disabled", afterUpload: "afterUpload", uploadPhoto: "uploadPhoto", resolveImageUrl: "resolveImageUrl", notify: "notify" }, outputs: { imageIdsChange: "imageIdsChange" }, usesOnChanges: true, ngImport: i0, template: "<label class=\"flex flex-col gap-1 md:col-span-12\">\n <span class=\"text-sm\">{{ label }}</span>\n <div class=\"text-xs text-slate-500\">\u041A\u0456\u043B\u044C\u043A\u0456\u0441\u0442\u044C \u0444\u043E\u0442\u043E: {{ photoCount }}</div>\n</label>\n\n<div class=\"md:col-span-12\">\n <p class=\"mb-2 text-xs uppercase tracking-[0.2em] text-slate-500\">{{ orderLabel }}</p>\n <div class=\"grid gap-3 md:grid-cols-4\" cdkDropList [cdkDropListData]=\"entries\" (cdkDropListDropped)=\"onDrop($event)\">\n @for (entry of entries; let i = $index; track entry.clientKey + '-' + i) {\n <div class=\"image-drag-item relative overflow-hidden rounded-xl border border-slate-200 bg-white\" cdkDrag [cdkDragDisabled]=\"disabled || (!entry.imageId && !entry.file)\">\n <label class=\"block h-full w-full cursor-pointer\">\n @if (entry.preview) {\n <img [src]=\"entry.preview\" alt=\"photo\" class=\"h-48 w-full object-cover\" />\n } @else {\n <button type=\"button\" class=\"flex h-48 w-full items-center justify-center bg-slate-50 text-xs text-slate-500\" (click)=\"openFilePicker(fileInput, $event)\">+ \u0414\u043E\u0434\u0430\u0442\u0438 \u0444\u043E\u0442\u043E</button>\n }\n <input #fileInput type=\"file\" class=\"hidden\" [disabled]=\"disabled\" multiple (change)=\"onFilesChange($event, i)\" />\n </label>\n @if (entry.imageId || entry.file) {\n @if (i === 0) {\n <span class=\"absolute left-2 top-2 rounded-full border border-slate-200 bg-white/95 px-2 py-1 text-[10px] font-semibold uppercase tracking-[0.15em] text-slate-700\">\u041E\u0431\u043A\u043B\u0430\u0434\u0438\u043D\u043A\u0430</span>\n }\n <span class=\"absolute left-2 bottom-2 rounded-full bg-slate-900/85 px-2 py-1 text-[10px] font-semibold text-white\">#{{ i + 1 }}</span>\n <button type=\"button\" class=\"absolute right-2 top-2 rounded-full bg-white/95 px-2 py-1 text-xs text-rose-600 shadow\" [disabled]=\"disabled\" (click)=\"removeAt(i)\">\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438</button>\n }\n </div>\n }\n </div>\n</div>\n", styles: [".image-drag-item.cdk-drag-preview{transform:scale(1.03) rotate(.6deg);box-shadow:0 28px 60px #0f172a66;border-radius:.9rem}.image-drag-item.cdk-drag-placeholder{opacity:.4;outline:2px dashed #94a3b8;outline-offset:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1$1.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1$1.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }] });
|
|
2981
3260
|
}
|
|
2982
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
3261
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiPhotoGalleryFieldComponent, decorators: [{
|
|
2983
3262
|
type: Component,
|
|
2984
3263
|
args: [{ selector: 'forms-photo-gallery-field', standalone: true, imports: [CommonModule, DragDropModule], template: "<label class=\"flex flex-col gap-1 md:col-span-12\">\n <span class=\"text-sm\">{{ label }}</span>\n <div class=\"text-xs text-slate-500\">\u041A\u0456\u043B\u044C\u043A\u0456\u0441\u0442\u044C \u0444\u043E\u0442\u043E: {{ photoCount }}</div>\n</label>\n\n<div class=\"md:col-span-12\">\n <p class=\"mb-2 text-xs uppercase tracking-[0.2em] text-slate-500\">{{ orderLabel }}</p>\n <div class=\"grid gap-3 md:grid-cols-4\" cdkDropList [cdkDropListData]=\"entries\" (cdkDropListDropped)=\"onDrop($event)\">\n @for (entry of entries; let i = $index; track entry.clientKey + '-' + i) {\n <div class=\"image-drag-item relative overflow-hidden rounded-xl border border-slate-200 bg-white\" cdkDrag [cdkDragDisabled]=\"disabled || (!entry.imageId && !entry.file)\">\n <label class=\"block h-full w-full cursor-pointer\">\n @if (entry.preview) {\n <img [src]=\"entry.preview\" alt=\"photo\" class=\"h-48 w-full object-cover\" />\n } @else {\n <button type=\"button\" class=\"flex h-48 w-full items-center justify-center bg-slate-50 text-xs text-slate-500\" (click)=\"openFilePicker(fileInput, $event)\">+ \u0414\u043E\u0434\u0430\u0442\u0438 \u0444\u043E\u0442\u043E</button>\n }\n <input #fileInput type=\"file\" class=\"hidden\" [disabled]=\"disabled\" multiple (change)=\"onFilesChange($event, i)\" />\n </label>\n @if (entry.imageId || entry.file) {\n @if (i === 0) {\n <span class=\"absolute left-2 top-2 rounded-full border border-slate-200 bg-white/95 px-2 py-1 text-[10px] font-semibold uppercase tracking-[0.15em] text-slate-700\">\u041E\u0431\u043A\u043B\u0430\u0434\u0438\u043D\u043A\u0430</span>\n }\n <span class=\"absolute left-2 bottom-2 rounded-full bg-slate-900/85 px-2 py-1 text-[10px] font-semibold text-white\">#{{ i + 1 }}</span>\n <button type=\"button\" class=\"absolute right-2 top-2 rounded-full bg-white/95 px-2 py-1 text-xs text-rose-600 shadow\" [disabled]=\"disabled\" (click)=\"removeAt(i)\">\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438</button>\n }\n </div>\n }\n </div>\n</div>\n", styles: [".image-drag-item.cdk-drag-preview{transform:scale(1.03) rotate(.6deg);box-shadow:0 28px 60px #0f172a66;border-radius:.9rem}.image-drag-item.cdk-drag-placeholder{opacity:.4;outline:2px dashed #94a3b8;outline-offset:4px}\n"] }]
|
|
2985
3264
|
}], propDecorators: { label: [{
|
|
@@ -3091,8 +3370,8 @@ class UiRangeSliderComponent {
|
|
|
3091
3370
|
input.step = String(this.safeStep);
|
|
3092
3371
|
input.value = String(value);
|
|
3093
3372
|
}
|
|
3094
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
3095
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.
|
|
3373
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiRangeSliderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3374
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.20", type: UiRangeSliderComponent, isStandalone: true, selector: "forms-range-slider", inputs: { min: "min", max: "max", step: "step", startValue: "startValue", endValue: "endValue", startLabel: "startLabel", endLabel: "endLabel" }, outputs: { startValueChange: "startValueChange", endValueChange: "endValueChange", interactionEnd: "interactionEnd" }, viewQueries: [{ propertyName: "startInput", first: true, predicate: ["startInput"], descendants: true }, { propertyName: "endInput", first: true, predicate: ["endInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
3096
3375
|
<div class="range-slider">
|
|
3097
3376
|
<div class="range-slider__track"></div>
|
|
3098
3377
|
<div
|
|
@@ -3127,7 +3406,7 @@ class UiRangeSliderComponent {
|
|
|
3127
3406
|
</div>
|
|
3128
3407
|
`, isInline: true, styles: [".range-slider{position:relative;height:2rem;width:100%;display:flex;align-items:center}.range-slider__track,.range-slider__range{position:absolute;left:0;right:0;height:6px;border-radius:999px}.range-slider__track{background:#dbe1ea}.range-slider__range{background:linear-gradient(90deg,#334155,#0f172a)}.range-slider__input{pointer-events:none;position:absolute;left:0;width:100%;height:2rem;margin:0;background:transparent;appearance:none;-webkit-appearance:none}.range-slider__input::-webkit-slider-runnable-track{height:6px;background:transparent}.range-slider__input::-moz-range-track{height:6px;background:transparent}.range-slider__input::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;pointer-events:auto;width:20px;height:20px;margin-top:-7px;border-radius:50%;border:2px solid #ffffff;background:#0f172a;box-shadow:0 8px 22px #0f172a38;cursor:pointer}.range-slider__input::-moz-range-thumb{pointer-events:auto;width:20px;height:20px;border-radius:50%;border:2px solid #ffffff;background:#0f172a;box-shadow:0 8px 22px #0f172a38;cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
3129
3408
|
}
|
|
3130
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
3409
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiRangeSliderComponent, decorators: [{
|
|
3131
3410
|
type: Component,
|
|
3132
3411
|
args: [{ selector: 'forms-range-slider', standalone: true, imports: [CommonModule], template: `
|
|
3133
3412
|
<div class="range-slider">
|