@fovestta2/web-angular 1.0.21 → 1.0.22
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/esm2022/lib/fv-dropdown/fv-dropdown.component.mjs +111 -37
- package/esm2022/lib/fv-file-selector/fv-file-selector.component.mjs +3 -3
- package/esm2022/public-api.mjs +1 -1
- package/fesm2022/fovestta2-web-angular.mjs +112 -38
- package/fesm2022/fovestta2-web-angular.mjs.map +1 -1
- package/lib/fv-dropdown/fv-dropdown.component.d.ts +19 -5
- package/package.json +1 -1
- package/public-api.d.ts +1 -1
package/esm2022/public-api.mjs
CHANGED
|
@@ -26,4 +26,4 @@ export * from './lib/fv-email-field/fv-email-field.component';
|
|
|
26
26
|
export * from './lib/fv-password-field/fv-password-field.component';
|
|
27
27
|
export * from './lib/fv-document-field/fv-document-field.component';
|
|
28
28
|
export * from './lib/fv-service-period/fv-service-period.component';
|
|
29
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
29
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL2Z2LWNvbnRyb2xzL3NyYy9wdWJsaWMtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYywwQkFBMEIsQ0FBQztBQUN6QyxjQUFjLCtDQUErQyxDQUFDO0FBQzlELGNBQWMsNkNBQTZDLENBQUM7QUFDNUQsY0FBYyx5REFBeUQsQ0FBQztBQUN4RSxjQUFjLGlEQUFpRCxDQUFDO0FBQ2hFLGNBQWMseUNBQXlDLENBQUM7QUFDeEQsT0FBTyxFQUNMLHFCQUFxQixHQUV0QixNQUFNLCtDQUErQyxDQUFDO0FBQ3ZELE9BQU8sRUFDTCxtQkFBbUIsR0FHcEIsTUFBTSx5Q0FBeUMsQ0FBQztBQUNqRCxPQUFPLEVBQ0wsdUJBQXVCLEdBRXhCLE1BQU0sbURBQW1ELENBQUM7QUFDM0QsT0FBTyxFQUNMLHdCQUF3QixHQUV6QixNQUFNLHFEQUFxRCxDQUFDO0FBQzdELGNBQWMseURBQXlELENBQUM7QUFDeEUsY0FBYyxpREFBaUQsQ0FBQztBQUNoRSxjQUFjLHVDQUF1QyxDQUFDO0FBQ3RELE9BQU8sRUFDTCxtQkFBbUIsRUFFcEIsTUFBTSwyQ0FBMkMsQ0FBQztBQUNuRCxjQUFjLCtDQUErQyxDQUFDO0FBQzlELGNBQWMsMkNBQTJDLENBQUM7QUFDMUQsY0FBYyx5Q0FBeUMsQ0FBQztBQUN4RCxjQUFjLDJDQUEyQyxDQUFDO0FBQzFELGNBQWMsNkNBQTZDLENBQUM7QUFDNUQsY0FBYyw2Q0FBNkMsQ0FBQztBQUM1RCxjQUFjLDZDQUE2QyxDQUFDO0FBQzVELGNBQWMsK0NBQStDLENBQUM7QUFDOUQsY0FBYyxxREFBcUQsQ0FBQztBQUNwRSxjQUFjLHFEQUFxRCxDQUFDO0FBQ3BFLGNBQWMscURBQXFELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxyXG4gKiBQdWJsaWMgQVBJIFN1cmZhY2Ugb2YgZnYtY29udHJvbHNcclxuICovXHJcblxyXG5leHBvcnQgKiBmcm9tICcuL2xpYi9mdi1jb250cm9scy5tb2R1bGUnO1xyXG5leHBvcnQgKiBmcm9tICcuL2xpYi9mdi1lbnRyeS1maWVsZC9mdi1lbnRyeS1maWVsZC5jb21wb25lbnQnO1xyXG5leHBvcnQgKiBmcm9tICcuL2xpYi9mdi1kYXRlLWZpZWxkL2Z2LWRhdGUtZmllbGQuY29tcG9uZW50JztcclxuZXhwb3J0ICogZnJvbSAnLi9saWIvZnYtbW9udGgteWVhci1maWVsZC9mdi1tb250aC15ZWFyLWZpZWxkLmNvbXBvbmVudCc7XHJcbmV4cG9ydCAqIGZyb20gJy4vbGliL2Z2LW51bWJlci1maWVsZC9mdi1udW1iZXItZmllbGQuY29tcG9uZW50JztcclxuZXhwb3J0ICogZnJvbSAnLi9saWIvZnYtY2hlY2tib3gvZnYtY2hlY2tib3guY29tcG9uZW50JztcclxuZXhwb3J0IHtcclxuICBGdlJhZGlvR3JvdXBDb21wb25lbnQsXHJcbiAgdHlwZSBSYWRpb09wdGlvbixcclxufSBmcm9tICcuL2xpYi9mdi1yYWRpby1ncm91cC9mdi1yYWRpby1ncm91cC5jb21wb25lbnQnO1xyXG5leHBvcnQge1xyXG4gIEZ2RHJvcGRvd25Db21wb25lbnQsXHJcbiAgdHlwZSBEcm9wZG93bk9wdGlvbixcclxuICB0eXBlIERyb3Bkb3duR3JvdXAsXHJcbn0gZnJvbSAnLi9saWIvZnYtZHJvcGRvd24vZnYtZHJvcGRvd24uY29tcG9uZW50JztcclxuZXhwb3J0IHtcclxuICBGdkZpbGVTZWxlY3RvckNvbXBvbmVudCxcclxuICB0eXBlIEZpbGVJbmZvLFxyXG59IGZyb20gJy4vbGliL2Z2LWZpbGUtc2VsZWN0b3IvZnYtZmlsZS1zZWxlY3Rvci5jb21wb25lbnQnO1xyXG5leHBvcnQge1xyXG4gIEZ2SW1hZ2VTZWxlY3RvckNvbXBvbmVudCxcclxuICB0eXBlIEltYWdlSW5mbyxcclxufSBmcm9tICcuL2xpYi9mdi1pbWFnZS1zZWxlY3Rvci9mdi1pbWFnZS1zZWxlY3Rvci5jb21wb25lbnQnO1xyXG5leHBvcnQgKiBmcm9tICcuL2xpYi9mdi1yaWNoLXRleHQtZWRpdG9yL2Z2LXJpY2gtdGV4dC1lZGl0b3IuY29tcG9uZW50JztcclxuZXhwb3J0ICogZnJvbSAnLi9saWIvYWRkLXVwZGF0ZS1mb3JtL2FkZC11cGRhdGUtZm9ybS5jb21wb25lbnQnO1xyXG5leHBvcnQgKiBmcm9tICcuL2xpYi9xdWVyeS1mb3JtL3F1ZXJ5LWZvcm0uY29tcG9uZW50JztcclxuZXhwb3J0IHtcclxuICBGdk5hbWVDb2RlQ29tcG9uZW50LFxyXG4gIHR5cGUgU2VhcmNoU2VsZWN0T3B0aW9uXHJcbn0gZnJvbSAnLi9saWIvZnYtbmFtZS1jb2RlL2Z2LW5hbWUtY29kZS5jb21wb25lbnQnO1xyXG5leHBvcnQgKiBmcm9tICcuL2xpYi9mdi1waG9uZS1maWVsZC9mdi1waG9uZS1maWVsZC5jb21wb25lbnQnO1xyXG5leHBvcnQgKiBmcm9tICcuL2xpYi9mdi11YW4tZmllbGQvZnYtdWFuLWZpZWxkLmNvbXBvbmVudCc7XHJcbmV4cG9ydCAqIGZyb20gJy4vbGliL2Z2LXBmLWZpZWxkL2Z2LXBmLWZpZWxkLmNvbXBvbmVudCc7XHJcbmV4cG9ydCAqIGZyb20gJy4vbGliL2Z2LWVzaS1maWVsZC9mdi1lc2ktZmllbGQuY29tcG9uZW50JztcclxuZXhwb3J0ICogZnJvbSAnLi9saWIvZnYtaWZzYy1maWVsZC9mdi1pZnNjLWZpZWxkLmNvbXBvbmVudCc7XHJcbmV4cG9ydCAqIGZyb20gJy4vbGliL2Z2LW1pY3ItZmllbGQvZnYtbWljci1maWVsZC5jb21wb25lbnQnO1xyXG5leHBvcnQgKiBmcm9tICcuL2xpYi9mdi1pYmFuLWZpZWxkL2Z2LWliYW4tZmllbGQuY29tcG9uZW50JztcclxuZXhwb3J0ICogZnJvbSAnLi9saWIvZnYtZW1haWwtZmllbGQvZnYtZW1haWwtZmllbGQuY29tcG9uZW50JztcclxuZXhwb3J0ICogZnJvbSAnLi9saWIvZnYtcGFzc3dvcmQtZmllbGQvZnYtcGFzc3dvcmQtZmllbGQuY29tcG9uZW50JztcclxuZXhwb3J0ICogZnJvbSAnLi9saWIvZnYtZG9jdW1lbnQtZmllbGQvZnYtZG9jdW1lbnQtZmllbGQuY29tcG9uZW50JztcclxuZXhwb3J0ICogZnJvbSAnLi9saWIvZnYtc2VydmljZS1wZXJpb2QvZnYtc2VydmljZS1wZXJpb2QuY29tcG9uZW50JztcclxuXHJcblxyXG5cclxuIl19
|
|
@@ -659,7 +659,7 @@ class FvDropdownComponent {
|
|
|
659
659
|
console.error('FvDropdown: control is required');
|
|
660
660
|
return;
|
|
661
661
|
}
|
|
662
|
-
this.
|
|
662
|
+
this.filterOptions('');
|
|
663
663
|
if (!this.schema) {
|
|
664
664
|
console.warn('FvDropdown: schema is not provided, validation will be skipped');
|
|
665
665
|
return;
|
|
@@ -669,7 +669,7 @@ class FvDropdownComponent {
|
|
|
669
669
|
this.validateValue(value);
|
|
670
670
|
this.valueChange.emit(value);
|
|
671
671
|
// Sync search text
|
|
672
|
-
const selected = this.
|
|
672
|
+
const selected = this.findOption(value);
|
|
673
673
|
if (selected) {
|
|
674
674
|
this.searchControl.setValue(selected.label, { emitEvent: false });
|
|
675
675
|
}
|
|
@@ -684,7 +684,7 @@ class FvDropdownComponent {
|
|
|
684
684
|
// Validate initial value
|
|
685
685
|
this.validateValue(this.control.value);
|
|
686
686
|
if (this.control.value) {
|
|
687
|
-
const selected = this.
|
|
687
|
+
const selected = this.findOption(this.control.value);
|
|
688
688
|
if (selected) {
|
|
689
689
|
this.searchControl.setValue(selected.label, { emitEvent: false });
|
|
690
690
|
}
|
|
@@ -695,11 +695,8 @@ class FvDropdownComponent {
|
|
|
695
695
|
}
|
|
696
696
|
ngOnChanges(changes) {
|
|
697
697
|
if (changes['options'] && changes['options'].currentValue) {
|
|
698
|
-
this.filteredOptions = this.options;
|
|
699
698
|
// Re-filter if search text exists
|
|
700
|
-
|
|
701
|
-
this.filterOptions(this.searchControl.value);
|
|
702
|
-
}
|
|
699
|
+
this.filterOptions(this.searchControl.value || '');
|
|
703
700
|
}
|
|
704
701
|
if (changes['disabled']) {
|
|
705
702
|
if (this.disabled) {
|
|
@@ -723,14 +720,72 @@ class FvDropdownComponent {
|
|
|
723
720
|
}
|
|
724
721
|
}
|
|
725
722
|
filterOptions(term) {
|
|
726
|
-
|
|
727
|
-
|
|
723
|
+
this.filteredOptions = this.generateViewItems(this.options, term);
|
|
724
|
+
// Adjust highlight index if needed (reset if search changed)
|
|
725
|
+
if (this.filteredOptions.length === 1 && !this.filteredOptions[0].isGroupLabel) {
|
|
726
|
+
this.highlightedIndex = 0;
|
|
728
727
|
}
|
|
729
728
|
else {
|
|
730
|
-
|
|
731
|
-
|
|
729
|
+
this.highlightedIndex = -1;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
// Flattens the mixed options input into a view-ready list
|
|
733
|
+
generateViewItems(options, term) {
|
|
734
|
+
const result = [];
|
|
735
|
+
const lowerTerm = term ? term.toLowerCase() : '';
|
|
736
|
+
for (const item of options) {
|
|
737
|
+
if (this.isGroup(item)) {
|
|
738
|
+
// It's a group
|
|
739
|
+
let matchingItems = item.items;
|
|
740
|
+
if (lowerTerm) {
|
|
741
|
+
matchingItems = item.items.filter(opt => opt.label.toLowerCase().includes(lowerTerm));
|
|
742
|
+
}
|
|
743
|
+
if (matchingItems.length > 0) {
|
|
744
|
+
// Add header
|
|
745
|
+
result.push({ isGroupLabel: true, label: item.label });
|
|
746
|
+
// Add items
|
|
747
|
+
matchingItems.forEach(opt => {
|
|
748
|
+
result.push({
|
|
749
|
+
isGroupLabel: false,
|
|
750
|
+
label: opt.label,
|
|
751
|
+
value: opt.value,
|
|
752
|
+
option: opt,
|
|
753
|
+
isChild: true
|
|
754
|
+
});
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
// It's a standalone option
|
|
760
|
+
if (!lowerTerm || item.label.toLowerCase().includes(lowerTerm)) {
|
|
761
|
+
result.push({
|
|
762
|
+
isGroupLabel: false,
|
|
763
|
+
label: item.label,
|
|
764
|
+
value: item.value,
|
|
765
|
+
option: item,
|
|
766
|
+
isChild: false
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
return result;
|
|
772
|
+
}
|
|
773
|
+
isGroup(item) {
|
|
774
|
+
return 'items' in item && Array.isArray(item.items);
|
|
775
|
+
}
|
|
776
|
+
findOption(value) {
|
|
777
|
+
for (const item of this.options) {
|
|
778
|
+
if (this.isGroup(item)) {
|
|
779
|
+
const found = item.items.find(opt => opt.value === value);
|
|
780
|
+
if (found)
|
|
781
|
+
return found;
|
|
782
|
+
}
|
|
783
|
+
else {
|
|
784
|
+
if (item.value === value)
|
|
785
|
+
return item;
|
|
786
|
+
}
|
|
732
787
|
}
|
|
733
|
-
|
|
788
|
+
return undefined;
|
|
734
789
|
}
|
|
735
790
|
toggleDropdown() {
|
|
736
791
|
if (!this.disabled) {
|
|
@@ -746,16 +801,25 @@ class FvDropdownComponent {
|
|
|
746
801
|
if (!this.disabled) {
|
|
747
802
|
this.isOpen = true;
|
|
748
803
|
this.focus.emit();
|
|
749
|
-
// Filter based on current text
|
|
804
|
+
// Filter based on current text
|
|
750
805
|
this.filterOptions(this.searchControl.value || '');
|
|
751
|
-
|
|
806
|
+
// Highlight selected option if available
|
|
807
|
+
if (this.control.value) {
|
|
808
|
+
const idx = this.filteredOptions.findIndex(v => !v.isGroupLabel && v.value === this.control.value);
|
|
809
|
+
if (idx >= 0)
|
|
810
|
+
this.highlightedIndex = idx;
|
|
811
|
+
}
|
|
812
|
+
else if (this.filteredOptions.length === 1 && !this.filteredOptions[0].isGroupLabel) {
|
|
813
|
+
this.highlightedIndex = 0;
|
|
814
|
+
}
|
|
815
|
+
else {
|
|
816
|
+
this.highlightedIndex = -1;
|
|
817
|
+
}
|
|
752
818
|
}
|
|
753
819
|
}
|
|
754
820
|
onContainerClick(event) {
|
|
755
821
|
if (this.disabled)
|
|
756
822
|
return;
|
|
757
|
-
// If click is on the arrow or input, let them handle it.
|
|
758
|
-
// But if on the padding of div, focus input.
|
|
759
823
|
const target = event.target;
|
|
760
824
|
if (!target.classList.contains('fv-dropdown-input') && !target.classList.contains('fv-dropdown-arrow')) {
|
|
761
825
|
this.searchInput.nativeElement.focus();
|
|
@@ -767,7 +831,7 @@ class FvDropdownComponent {
|
|
|
767
831
|
this.isOpen = false;
|
|
768
832
|
this.highlightedIndex = -1;
|
|
769
833
|
// Restore label
|
|
770
|
-
const selected = this.
|
|
834
|
+
const selected = this.findOption(this.control.value);
|
|
771
835
|
if (selected) {
|
|
772
836
|
this.searchControl.setValue(selected.label, { emitEvent: false });
|
|
773
837
|
}
|
|
@@ -776,14 +840,14 @@ class FvDropdownComponent {
|
|
|
776
840
|
this.searchControl.setValue('', { emitEvent: false });
|
|
777
841
|
}
|
|
778
842
|
}
|
|
779
|
-
selectOption(
|
|
780
|
-
if (!option)
|
|
843
|
+
selectOption(viewItem) {
|
|
844
|
+
if (viewItem.isGroupLabel || !viewItem.option)
|
|
781
845
|
return;
|
|
782
|
-
this.control.setValue(
|
|
783
|
-
this.searchControl.setValue(
|
|
846
|
+
this.control.setValue(viewItem.value);
|
|
847
|
+
this.searchControl.setValue(viewItem.label, { emitEvent: false });
|
|
784
848
|
this.isOpen = false;
|
|
785
849
|
this.highlightedIndex = -1;
|
|
786
|
-
this.searchInput.nativeElement.blur();
|
|
850
|
+
this.searchInput.nativeElement.blur();
|
|
787
851
|
this.blur.emit();
|
|
788
852
|
}
|
|
789
853
|
onKeyDown(event) {
|
|
@@ -797,20 +861,17 @@ class FvDropdownComponent {
|
|
|
797
861
|
switch (event.key) {
|
|
798
862
|
case 'ArrowDown':
|
|
799
863
|
event.preventDefault();
|
|
800
|
-
this.
|
|
864
|
+
this.moveHighlight(1);
|
|
801
865
|
this.scrollToHighlighted();
|
|
802
866
|
break;
|
|
803
867
|
case 'ArrowUp':
|
|
804
868
|
event.preventDefault();
|
|
805
|
-
this.
|
|
869
|
+
this.moveHighlight(-1);
|
|
806
870
|
this.scrollToHighlighted();
|
|
807
871
|
break;
|
|
808
872
|
case 'Enter':
|
|
809
873
|
event.preventDefault();
|
|
810
|
-
if (this.filteredOptions.length
|
|
811
|
-
this.selectOption(this.filteredOptions[0]);
|
|
812
|
-
}
|
|
813
|
-
else if (this.highlightedIndex >= 0 && this.highlightedIndex < this.filteredOptions.length) {
|
|
874
|
+
if (this.highlightedIndex >= 0 && this.highlightedIndex < this.filteredOptions.length) {
|
|
814
875
|
this.selectOption(this.filteredOptions[this.highlightedIndex]);
|
|
815
876
|
}
|
|
816
877
|
break;
|
|
@@ -822,6 +883,21 @@ class FvDropdownComponent {
|
|
|
822
883
|
break;
|
|
823
884
|
}
|
|
824
885
|
}
|
|
886
|
+
moveHighlight(step) {
|
|
887
|
+
let nextIndex = this.highlightedIndex;
|
|
888
|
+
const len = this.filteredOptions.length;
|
|
889
|
+
if (len === 0)
|
|
890
|
+
return;
|
|
891
|
+
// Loop to find next non-group item
|
|
892
|
+
// Max iterations to avoid infinite loop (though unlikely)
|
|
893
|
+
for (let i = 0; i < len; i++) {
|
|
894
|
+
nextIndex = (nextIndex + step + len) % len;
|
|
895
|
+
if (!this.filteredOptions[nextIndex].isGroupLabel) {
|
|
896
|
+
this.highlightedIndex = nextIndex;
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
825
901
|
scrollToHighlighted() {
|
|
826
902
|
const list = this.el.nativeElement.querySelector('.fv-dropdown-options');
|
|
827
903
|
const items = this.el.nativeElement.querySelectorAll('.fv-dropdown-option');
|
|
@@ -866,19 +942,17 @@ class FvDropdownComponent {
|
|
|
866
942
|
};
|
|
867
943
|
return errorMessages[this.errorMessage] || this.errorMessage;
|
|
868
944
|
}
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
isSelected(option) {
|
|
874
|
-
return option.value === this.control?.value;
|
|
945
|
+
isSelected(viewItem) {
|
|
946
|
+
if (viewItem.value === undefined || viewItem.value === null)
|
|
947
|
+
return false;
|
|
948
|
+
return viewItem.value === this.control?.value;
|
|
875
949
|
}
|
|
876
950
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvDropdownComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
877
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvDropdownComponent, isStandalone: true, selector: "fv-dropdown", inputs: { label: "label", placeholder: "placeholder", options: "options", schema: "schema", control: "control", disabled: "disabled" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, host: { listeners: { "keydown": "onKeyDown($event)", "document:click": "onClickOutside($event)" } }, viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-dropdown-container\">\r\n <label *ngIf=\"label\" class=\"fv-dropdown-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-dropdown-wrapper\">\r\n <div class=\"fv-dropdown\" [class.fv-dropdown-error]=\"errorMessage && control?.touched\"\r\n [class.fv-dropdown-disabled]=\"disabled\" [class.fv-dropdown-open]=\"isOpen\"\r\n (click)=\"onContainerClick($event)\">\r\n <input #searchInput type=\"text\" class=\"fv-dropdown-input\" [formControl]=\"searchControl\"\r\n [placeholder]=\"placeholder\" (focus)=\"onInputFocus()\" (click)=\"$event.stopPropagation()\"\r\n autocomplete=\"off\">\r\n <span class=\"fv-dropdown-arrow\" [class.arrow-up]=\"isOpen\" (click)=\"toggleDropdown()\">\u25BC</span>\r\n </div>\r\n\r\n <div *ngIf=\"isOpen\" class=\"fv-dropdown-options\">\r\n <
|
|
951
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvDropdownComponent, isStandalone: true, selector: "fv-dropdown", inputs: { label: "label", placeholder: "placeholder", options: "options", schema: "schema", control: "control", disabled: "disabled" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, host: { listeners: { "keydown": "onKeyDown($event)", "document:click": "onClickOutside($event)" } }, viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-dropdown-container\">\r\n <label *ngIf=\"label\" class=\"fv-dropdown-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-dropdown-wrapper\">\r\n <div class=\"fv-dropdown\" [class.fv-dropdown-error]=\"errorMessage && control?.touched\"\r\n [class.fv-dropdown-disabled]=\"disabled\" [class.fv-dropdown-open]=\"isOpen\"\r\n (click)=\"onContainerClick($event)\">\r\n <input #searchInput type=\"text\" class=\"fv-dropdown-input\" [formControl]=\"searchControl\"\r\n [placeholder]=\"placeholder\" (focus)=\"onInputFocus()\" (click)=\"$event.stopPropagation()\"\r\n autocomplete=\"off\">\r\n <span class=\"fv-dropdown-arrow\" [class.arrow-up]=\"isOpen\" (click)=\"toggleDropdown()\">\u25BC</span>\r\n </div>\r\n\r\n <div *ngIf=\"isOpen\" class=\"fv-dropdown-options\">\r\n <ng-container *ngFor=\"let option of filteredOptions; let i = index\">\r\n <div *ngIf=\"option.isGroupLabel\" class=\"fv-dropdown-group-label\">\r\n {{ option.label }}\r\n </div>\r\n <div *ngIf=\"!option.isGroupLabel\" class=\"fv-dropdown-option\"\r\n [class.fv-dropdown-option-selected]=\"isSelected(option)\"\r\n [class.fv-dropdown-option-highlighted]=\"i === highlightedIndex\"\r\n [class.child-option]=\"option.isChild\" (mouseenter)=\"highlightedIndex = i\"\r\n (click)=\"selectOption(option)\">\r\n {{ option.label }}\r\n </div>\r\n </ng-container>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"fv-dropdown-option fv-no-results\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage && control?.touched\" class=\"fv-dropdown-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.material-icons{font-family:Material Icons!important}.fv-dropdown-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-dropdown-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-dropdown-wrapper{position:relative}.fv-dropdown{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;background-color:#fff;cursor:pointer;display:flex;justify-content:space-between;align-items:center;transition:border-color .2s;outline:none;font-size:14px;font-weight:400;color:#1f2b41;box-sizing:border-box;height:34px}.fv-dropdown:hover:not(.fv-dropdown-disabled){border-color:#3498db}.fv-dropdown:focus-within:not(.fv-dropdown-disabled){border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-dropdown-error{border-color:#dc3545!important}.fv-dropdown-disabled{background-color:#ecf0f1;opacity:.6;cursor:not-allowed}.fv-dropdown-open{border-color:#3498db}.fv-dropdown-selected{font-size:14px;font-weight:400;color:#1f2b41;flex:1}.fv-dropdown-placeholder{color:#999}.fv-dropdown-arrow{font-size:10px;color:#666;margin-left:8px;margin-right:5px;transition:transform .2s}.arrow-up{transform:rotate(180deg)}.fv-dropdown-options{position:absolute;top:100%;left:0;right:0;margin-top:4px;background-color:#fff;border:1px solid #cccccc;border-radius:4px;max-height:300px;overflow-y:auto;z-index:1000;box-shadow:0 4px 6px #0000001a}.fv-dropdown-option{padding:12px 16px;font-size:14px;color:#151d48;cursor:pointer;transition:background-color .2s;border-bottom:1px solid #eeeeee}.fv-dropdown-option:last-child{border-bottom:none}.fv-dropdown-option:hover,.fv-dropdown-option-highlighted{background-color:#f8f9fa}.fv-dropdown-option-selected{background-color:#e7f3ff;color:#007bff;font-weight:600}.fv-dropdown-error-message{margin-top:4px;font-size:12px;color:#dc3545}.fv-dropdown-input{border:none!important;outline:none!important;box-shadow:none!important;background:transparent;flex:1;width:100%;min-width:0;appearance:none;-webkit-appearance:none;font-size:14px;color:#1f2b41;padding:0;margin:0;cursor:text;z-index:2;position:relative;pointer-events:auto;height:100%}.fv-dropdown-input::placeholder{color:#999}.fv-no-results{color:#999;font-style:italic;cursor:default;text-align:center}.fv-dropdown-group-label{font-weight:600;color:#151d48;padding:8px 16px;background-color:#f9f9f9;cursor:default;pointer-events:none;font-size:14px;letter-spacing:normal;border-bottom:1px solid #eee}.fv-dropdown-option.child-option{padding-left:32px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { 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.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
|
|
878
952
|
}
|
|
879
953
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvDropdownComponent, decorators: [{
|
|
880
954
|
type: Component,
|
|
881
|
-
args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-dropdown', template: "<div class=\"fv-dropdown-container\">\r\n <label *ngIf=\"label\" class=\"fv-dropdown-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-dropdown-wrapper\">\r\n <div class=\"fv-dropdown\" [class.fv-dropdown-error]=\"errorMessage && control?.touched\"\r\n [class.fv-dropdown-disabled]=\"disabled\" [class.fv-dropdown-open]=\"isOpen\"\r\n (click)=\"onContainerClick($event)\">\r\n <input #searchInput type=\"text\" class=\"fv-dropdown-input\" [formControl]=\"searchControl\"\r\n [placeholder]=\"placeholder\" (focus)=\"onInputFocus()\" (click)=\"$event.stopPropagation()\"\r\n autocomplete=\"off\">\r\n <span class=\"fv-dropdown-arrow\" [class.arrow-up]=\"isOpen\" (click)=\"toggleDropdown()\">\u25BC</span>\r\n </div>\r\n\r\n <div *ngIf=\"isOpen\" class=\"fv-dropdown-options\">\r\n <
|
|
955
|
+
args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-dropdown', template: "<div class=\"fv-dropdown-container\">\r\n <label *ngIf=\"label\" class=\"fv-dropdown-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-dropdown-wrapper\">\r\n <div class=\"fv-dropdown\" [class.fv-dropdown-error]=\"errorMessage && control?.touched\"\r\n [class.fv-dropdown-disabled]=\"disabled\" [class.fv-dropdown-open]=\"isOpen\"\r\n (click)=\"onContainerClick($event)\">\r\n <input #searchInput type=\"text\" class=\"fv-dropdown-input\" [formControl]=\"searchControl\"\r\n [placeholder]=\"placeholder\" (focus)=\"onInputFocus()\" (click)=\"$event.stopPropagation()\"\r\n autocomplete=\"off\">\r\n <span class=\"fv-dropdown-arrow\" [class.arrow-up]=\"isOpen\" (click)=\"toggleDropdown()\">\u25BC</span>\r\n </div>\r\n\r\n <div *ngIf=\"isOpen\" class=\"fv-dropdown-options\">\r\n <ng-container *ngFor=\"let option of filteredOptions; let i = index\">\r\n <div *ngIf=\"option.isGroupLabel\" class=\"fv-dropdown-group-label\">\r\n {{ option.label }}\r\n </div>\r\n <div *ngIf=\"!option.isGroupLabel\" class=\"fv-dropdown-option\"\r\n [class.fv-dropdown-option-selected]=\"isSelected(option)\"\r\n [class.fv-dropdown-option-highlighted]=\"i === highlightedIndex\"\r\n [class.child-option]=\"option.isChild\" (mouseenter)=\"highlightedIndex = i\"\r\n (click)=\"selectOption(option)\">\r\n {{ option.label }}\r\n </div>\r\n </ng-container>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"fv-dropdown-option fv-no-results\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage && control?.touched\" class=\"fv-dropdown-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.material-icons{font-family:Material Icons!important}.fv-dropdown-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-dropdown-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-dropdown-wrapper{position:relative}.fv-dropdown{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;background-color:#fff;cursor:pointer;display:flex;justify-content:space-between;align-items:center;transition:border-color .2s;outline:none;font-size:14px;font-weight:400;color:#1f2b41;box-sizing:border-box;height:34px}.fv-dropdown:hover:not(.fv-dropdown-disabled){border-color:#3498db}.fv-dropdown:focus-within:not(.fv-dropdown-disabled){border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-dropdown-error{border-color:#dc3545!important}.fv-dropdown-disabled{background-color:#ecf0f1;opacity:.6;cursor:not-allowed}.fv-dropdown-open{border-color:#3498db}.fv-dropdown-selected{font-size:14px;font-weight:400;color:#1f2b41;flex:1}.fv-dropdown-placeholder{color:#999}.fv-dropdown-arrow{font-size:10px;color:#666;margin-left:8px;margin-right:5px;transition:transform .2s}.arrow-up{transform:rotate(180deg)}.fv-dropdown-options{position:absolute;top:100%;left:0;right:0;margin-top:4px;background-color:#fff;border:1px solid #cccccc;border-radius:4px;max-height:300px;overflow-y:auto;z-index:1000;box-shadow:0 4px 6px #0000001a}.fv-dropdown-option{padding:12px 16px;font-size:14px;color:#151d48;cursor:pointer;transition:background-color .2s;border-bottom:1px solid #eeeeee}.fv-dropdown-option:last-child{border-bottom:none}.fv-dropdown-option:hover,.fv-dropdown-option-highlighted{background-color:#f8f9fa}.fv-dropdown-option-selected{background-color:#e7f3ff;color:#007bff;font-weight:600}.fv-dropdown-error-message{margin-top:4px;font-size:12px;color:#dc3545}.fv-dropdown-input{border:none!important;outline:none!important;box-shadow:none!important;background:transparent;flex:1;width:100%;min-width:0;appearance:none;-webkit-appearance:none;font-size:14px;color:#1f2b41;padding:0;margin:0;cursor:text;z-index:2;position:relative;pointer-events:auto;height:100%}.fv-dropdown-input::placeholder{color:#999}.fv-no-results{color:#999;font-style:italic;cursor:default;text-align:center}.fv-dropdown-group-label{font-weight:600;color:#151d48;padding:8px 16px;background-color:#f9f9f9;cursor:default;pointer-events:none;font-size:14px;letter-spacing:normal;border-bottom:1px solid #eee}.fv-dropdown-option.child-option{padding-left:32px}\n"] }]
|
|
882
956
|
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { label: [{
|
|
883
957
|
type: Input
|
|
884
958
|
}], placeholder: [{
|
|
@@ -1043,11 +1117,11 @@ class FvFileSelectorComponent {
|
|
|
1043
1117
|
return errorMessages[this.errorMessage] || this.errorMessage;
|
|
1044
1118
|
}
|
|
1045
1119
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvFileSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1046
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvFileSelectorComponent, isStandalone: true, selector: "fv-file-selector", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", accept: "accept", maxSize: "maxSize" }, outputs: { valueChange: "valueChange", blur: "blur" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-file-selector-container\" *ngIf=\"control\">\r\n <label *ngIf=\"label\" class=\"fv-file-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #fileInput type=\"file\" [accept]=\"accept\" (change)=\"onFileSelected($event)\" style=\"display: none\" />\r\n\r\n <div *ngIf=\"!selectedFile\">\r\n <button type=\"button\" class=\"fv-file-selector-button\"\r\n [class.fv-file-selector-button-error]=\"errorMessage && control?.touched\"\r\n [class.fv-file-selector-button-disabled]=\"disabled\" (click)=\"openFileDialog()\" [disabled]=\"disabled\">\r\n <span class=\"fv-upload-text\">{{ placeholder }}</span>\r\n <span class=\"fv-upload-icon-section\">\r\n <svg viewBox=\"0 0 24 24\" class=\"upload-icon\">\r\n <path d=\"M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z\" fill=\"currentColor\" />\r\n </svg>\r\n </span>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"selectedFile\" class=\"fv-preview-row\">\r\n <div class=\"fv-preview-wrapper\">\r\n <div class=\"fv-file-icon-preview\" [ngClass]=\"getFileIcon()\">\r\n <span class=\"material-icons\">{{ getFileIcon() }}</span>\r\n </div>\r\n </div>\r\n <span class=\"fv-filename\">{{ selectedFile.name }}</span>\r\n <button type=\"button\" class=\"fv-trash-btn\" (click)=\"removeFile()\" [disabled]=\"disabled\">\r\n <svg viewBox=\"0 0 24 24\" class=\"trash-icon\">\r\n <path d=\"M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage && control?.touched\" class=\"fv-file-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-file-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:fit-content;max-width:100%}.fv-file-selector-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-file-selector-button{display:flex;align-items:center;border:1px solid #dcdcdc;border-radius:8px;background-color:#fff;padding:0;cursor:pointer;overflow:hidden;height:34px;width:
|
|
1120
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvFileSelectorComponent, isStandalone: true, selector: "fv-file-selector", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", accept: "accept", maxSize: "maxSize" }, outputs: { valueChange: "valueChange", blur: "blur" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-file-selector-container\" *ngIf=\"control\">\r\n <label *ngIf=\"label\" class=\"fv-file-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #fileInput type=\"file\" [accept]=\"accept\" (change)=\"onFileSelected($event)\" style=\"display: none\" />\r\n\r\n <div *ngIf=\"!selectedFile\">\r\n <button type=\"button\" class=\"fv-file-selector-button\"\r\n [class.fv-file-selector-button-error]=\"errorMessage && control?.touched\"\r\n [class.fv-file-selector-button-disabled]=\"disabled\" (click)=\"openFileDialog()\" [disabled]=\"disabled\">\r\n <span class=\"fv-upload-text\">{{ placeholder }}</span>\r\n <span class=\"fv-upload-icon-section\">\r\n <svg viewBox=\"0 0 24 24\" class=\"upload-icon\">\r\n <path d=\"M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z\" fill=\"currentColor\" />\r\n </svg>\r\n </span>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"selectedFile\" class=\"fv-preview-row\">\r\n <div class=\"fv-preview-wrapper\">\r\n <div class=\"fv-file-icon-preview\" [ngClass]=\"getFileIcon()\">\r\n <span class=\"material-icons\">{{ getFileIcon() }}</span>\r\n </div>\r\n </div>\r\n <span class=\"fv-filename\">{{ selectedFile.name }}</span>\r\n <button type=\"button\" class=\"fv-trash-btn\" (click)=\"removeFile()\" [disabled]=\"disabled\">\r\n <svg viewBox=\"0 0 24 24\" class=\"trash-icon\">\r\n <path d=\"M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage && control?.touched\" class=\"fv-file-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-file-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:fit-content;max-width:100%}.fv-file-selector-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-file-selector-button{display:flex;align-items:center;border:1px solid #dcdcdc;border-radius:8px;background-color:#fff;padding:0;cursor:pointer;overflow:hidden;height:34px;width:150px;transition:all .2s ease}.fv-file-selector-button:hover:not(:disabled){border-color:#bbb;box-shadow:0 2px 4px #0000000d}.fv-file-selector-button-error{border-color:#e74c3c}.fv-file-selector-button-disabled{background-color:#f9f9f9;border-color:#dcdcdc;color:#7f8c8d;opacity:.6;cursor:not-allowed}.fv-upload-text{flex:1;padding:0 16px;font-size:14px;color:#1f2b41;text-align:left;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fv-upload-icon-section{background:#f4f5f7;padding:0 10px;border-left:1px solid #dcdcdc;display:flex;align-items:center;justify-content:center;color:#333;height:100%}.upload-icon{width:20px;height:20px}.fv-preview-row{display:flex;align-items:center;gap:8px;padding:8px 0;width:100px;box-sizing:border-box}.fv-preview-wrapper{position:relative;width:40px;height:40px}.fv-file-icon-preview{width:40px;height:40px;border-radius:8px;background:#f4f5f7;display:flex;align-items:center;justify-content:center;color:#3498db;border:1px solid #dcdcdc}.fv-file-icon-preview.picture_as_pdf{color:#e74c3c;background:#fdf2f2}.fv-file-icon-preview.image{color:#3498db;background:#f1f8fe}.fv-file-icon-preview.table_view{color:#27ae60;background:#f1f9f4}.material-icons{font-size:24px}.fv-filename{flex:1;font-size:14px;color:#666;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:300px}.fv-trash-btn{background:none;border:none;cursor:pointer;padding:6px;border-radius:50%;transition:background .2s;display:flex}.fv-trash-btn:hover:not(:disabled){background:#fee}.trash-icon{width:22px;height:22px;fill:red}.fv-file-selector-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }] });
|
|
1047
1121
|
}
|
|
1048
1122
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvFileSelectorComponent, decorators: [{
|
|
1049
1123
|
type: Component,
|
|
1050
|
-
args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-file-selector', template: "<div class=\"fv-file-selector-container\" *ngIf=\"control\">\r\n <label *ngIf=\"label\" class=\"fv-file-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #fileInput type=\"file\" [accept]=\"accept\" (change)=\"onFileSelected($event)\" style=\"display: none\" />\r\n\r\n <div *ngIf=\"!selectedFile\">\r\n <button type=\"button\" class=\"fv-file-selector-button\"\r\n [class.fv-file-selector-button-error]=\"errorMessage && control?.touched\"\r\n [class.fv-file-selector-button-disabled]=\"disabled\" (click)=\"openFileDialog()\" [disabled]=\"disabled\">\r\n <span class=\"fv-upload-text\">{{ placeholder }}</span>\r\n <span class=\"fv-upload-icon-section\">\r\n <svg viewBox=\"0 0 24 24\" class=\"upload-icon\">\r\n <path d=\"M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z\" fill=\"currentColor\" />\r\n </svg>\r\n </span>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"selectedFile\" class=\"fv-preview-row\">\r\n <div class=\"fv-preview-wrapper\">\r\n <div class=\"fv-file-icon-preview\" [ngClass]=\"getFileIcon()\">\r\n <span class=\"material-icons\">{{ getFileIcon() }}</span>\r\n </div>\r\n </div>\r\n <span class=\"fv-filename\">{{ selectedFile.name }}</span>\r\n <button type=\"button\" class=\"fv-trash-btn\" (click)=\"removeFile()\" [disabled]=\"disabled\">\r\n <svg viewBox=\"0 0 24 24\" class=\"trash-icon\">\r\n <path d=\"M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage && control?.touched\" class=\"fv-file-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-file-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:fit-content;max-width:100%}.fv-file-selector-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-file-selector-button{display:flex;align-items:center;border:1px solid #dcdcdc;border-radius:8px;background-color:#fff;padding:0;cursor:pointer;overflow:hidden;height:34px;width:
|
|
1124
|
+
args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-file-selector', template: "<div class=\"fv-file-selector-container\" *ngIf=\"control\">\r\n <label *ngIf=\"label\" class=\"fv-file-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #fileInput type=\"file\" [accept]=\"accept\" (change)=\"onFileSelected($event)\" style=\"display: none\" />\r\n\r\n <div *ngIf=\"!selectedFile\">\r\n <button type=\"button\" class=\"fv-file-selector-button\"\r\n [class.fv-file-selector-button-error]=\"errorMessage && control?.touched\"\r\n [class.fv-file-selector-button-disabled]=\"disabled\" (click)=\"openFileDialog()\" [disabled]=\"disabled\">\r\n <span class=\"fv-upload-text\">{{ placeholder }}</span>\r\n <span class=\"fv-upload-icon-section\">\r\n <svg viewBox=\"0 0 24 24\" class=\"upload-icon\">\r\n <path d=\"M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z\" fill=\"currentColor\" />\r\n </svg>\r\n </span>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"selectedFile\" class=\"fv-preview-row\">\r\n <div class=\"fv-preview-wrapper\">\r\n <div class=\"fv-file-icon-preview\" [ngClass]=\"getFileIcon()\">\r\n <span class=\"material-icons\">{{ getFileIcon() }}</span>\r\n </div>\r\n </div>\r\n <span class=\"fv-filename\">{{ selectedFile.name }}</span>\r\n <button type=\"button\" class=\"fv-trash-btn\" (click)=\"removeFile()\" [disabled]=\"disabled\">\r\n <svg viewBox=\"0 0 24 24\" class=\"trash-icon\">\r\n <path d=\"M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage && control?.touched\" class=\"fv-file-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-file-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:fit-content;max-width:100%}.fv-file-selector-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-file-selector-button{display:flex;align-items:center;border:1px solid #dcdcdc;border-radius:8px;background-color:#fff;padding:0;cursor:pointer;overflow:hidden;height:34px;width:150px;transition:all .2s ease}.fv-file-selector-button:hover:not(:disabled){border-color:#bbb;box-shadow:0 2px 4px #0000000d}.fv-file-selector-button-error{border-color:#e74c3c}.fv-file-selector-button-disabled{background-color:#f9f9f9;border-color:#dcdcdc;color:#7f8c8d;opacity:.6;cursor:not-allowed}.fv-upload-text{flex:1;padding:0 16px;font-size:14px;color:#1f2b41;text-align:left;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fv-upload-icon-section{background:#f4f5f7;padding:0 10px;border-left:1px solid #dcdcdc;display:flex;align-items:center;justify-content:center;color:#333;height:100%}.upload-icon{width:20px;height:20px}.fv-preview-row{display:flex;align-items:center;gap:8px;padding:8px 0;width:100px;box-sizing:border-box}.fv-preview-wrapper{position:relative;width:40px;height:40px}.fv-file-icon-preview{width:40px;height:40px;border-radius:8px;background:#f4f5f7;display:flex;align-items:center;justify-content:center;color:#3498db;border:1px solid #dcdcdc}.fv-file-icon-preview.picture_as_pdf{color:#e74c3c;background:#fdf2f2}.fv-file-icon-preview.image{color:#3498db;background:#f1f8fe}.fv-file-icon-preview.table_view{color:#27ae60;background:#f1f9f4}.material-icons{font-size:24px}.fv-filename{flex:1;font-size:14px;color:#666;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:300px}.fv-trash-btn{background:none;border:none;cursor:pointer;padding:6px;border-radius:50%;transition:background .2s;display:flex}.fv-trash-btn:hover:not(:disabled){background:#fee}.trash-icon{width:22px;height:22px;fill:red}.fv-file-selector-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"] }]
|
|
1051
1125
|
}], propDecorators: { label: [{
|
|
1052
1126
|
type: Input
|
|
1053
1127
|
}], placeholder: [{
|