@muxima-ui/multi-select 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2020/index.mjs +2 -0
- package/esm2020/lib/multi-select/multi-select.component.mjs +137 -0
- package/esm2020/muxima-ui-multi-select.mjs +5 -0
- package/fesm2015/muxima-ui-multi-select.mjs +144 -0
- package/fesm2015/muxima-ui-multi-select.mjs.map +1 -0
- package/fesm2020/muxima-ui-multi-select.mjs +144 -0
- package/fesm2020/muxima-ui-multi-select.mjs.map +1 -0
- package/index.d.ts +1 -0
- package/lib/multi-select/multi-select.component.d.ts +39 -0
- package/package.json +56 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export * from './lib/multi-select/multi-select.component';
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9mb3JtL211bHRpLXNlbGVjdC9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYywyQ0FBMkMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vbGliL211bHRpLXNlbGVjdC9tdWx0aS1zZWxlY3QuY29tcG9uZW50JztcclxuIl19
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
import * as i1 from "@angular/common";
|
|
6
|
+
import * as i2 from "@angular/forms";
|
|
7
|
+
export class MultiSelectComponent {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.options = [];
|
|
10
|
+
this.placeholder = 'Select items...';
|
|
11
|
+
this.disabled = false;
|
|
12
|
+
this.searchable = true;
|
|
13
|
+
this.clearable = true;
|
|
14
|
+
this.selectionChange = new EventEmitter();
|
|
15
|
+
this.selectedValues = [];
|
|
16
|
+
this.isOpen = false;
|
|
17
|
+
this.searchTerm = '';
|
|
18
|
+
this.filteredOptions = [];
|
|
19
|
+
this.onChange = () => { };
|
|
20
|
+
this.onTouched = () => { };
|
|
21
|
+
}
|
|
22
|
+
ngOnInit() {
|
|
23
|
+
this.updateFilteredOptions();
|
|
24
|
+
}
|
|
25
|
+
writeValue(value) {
|
|
26
|
+
this.selectedValues = value || [];
|
|
27
|
+
}
|
|
28
|
+
registerOnChange(fn) {
|
|
29
|
+
this.onChange = fn;
|
|
30
|
+
}
|
|
31
|
+
registerOnTouched(fn) {
|
|
32
|
+
this.onTouched = fn;
|
|
33
|
+
}
|
|
34
|
+
setDisabledState(isDisabled) {
|
|
35
|
+
this.disabled = isDisabled;
|
|
36
|
+
}
|
|
37
|
+
toggleDropdown() {
|
|
38
|
+
if (!this.disabled) {
|
|
39
|
+
this.isOpen = !this.isOpen;
|
|
40
|
+
if (this.isOpen) {
|
|
41
|
+
this.updateFilteredOptions();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
toggleOption(option) {
|
|
46
|
+
if (option.disabled)
|
|
47
|
+
return;
|
|
48
|
+
const index = this.selectedValues.findIndex(v => v === option.value);
|
|
49
|
+
if (index >= 0) {
|
|
50
|
+
this.selectedValues.splice(index, 1);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
if (!this.maxSelections || this.selectedValues.length < this.maxSelections) {
|
|
54
|
+
this.selectedValues.push(option.value);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
this.onChange(this.selectedValues);
|
|
58
|
+
this.selectionChange.emit(this.selectedValues);
|
|
59
|
+
}
|
|
60
|
+
isSelected(option) {
|
|
61
|
+
return this.selectedValues.includes(option.value);
|
|
62
|
+
}
|
|
63
|
+
removeTag(value, event) {
|
|
64
|
+
event.stopPropagation();
|
|
65
|
+
const index = this.selectedValues.findIndex(v => v === value);
|
|
66
|
+
if (index >= 0) {
|
|
67
|
+
this.selectedValues.splice(index, 1);
|
|
68
|
+
this.onChange(this.selectedValues);
|
|
69
|
+
this.selectionChange.emit(this.selectedValues);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
clearAll(event) {
|
|
73
|
+
event.stopPropagation();
|
|
74
|
+
this.selectedValues = [];
|
|
75
|
+
this.onChange(this.selectedValues);
|
|
76
|
+
this.selectionChange.emit(this.selectedValues);
|
|
77
|
+
}
|
|
78
|
+
onSearch(event) {
|
|
79
|
+
const input = event.target;
|
|
80
|
+
this.searchTerm = input.value;
|
|
81
|
+
this.updateFilteredOptions();
|
|
82
|
+
}
|
|
83
|
+
updateFilteredOptions() {
|
|
84
|
+
const allOptions = this.options.map(opt => typeof opt === 'string' ? { value: opt, label: opt } : opt);
|
|
85
|
+
if (!this.searchTerm) {
|
|
86
|
+
this.filteredOptions = allOptions;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const term = this.searchTerm.toLowerCase();
|
|
90
|
+
this.filteredOptions = allOptions.filter(opt => opt.label.toLowerCase().includes(term));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
getOptionLabel(value) {
|
|
94
|
+
const allOptions = this.options.map(opt => typeof opt === 'string' ? { value: opt, label: opt } : opt);
|
|
95
|
+
const option = allOptions.find(opt => opt.value === value);
|
|
96
|
+
return option ? option.label : value;
|
|
97
|
+
}
|
|
98
|
+
onBlur() {
|
|
99
|
+
setTimeout(() => {
|
|
100
|
+
this.isOpen = false;
|
|
101
|
+
this.onTouched();
|
|
102
|
+
}, 200);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
MultiSelectComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
106
|
+
MultiSelectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: MultiSelectComponent, isStandalone: true, selector: "muxima-multi-select", inputs: { options: "options", placeholder: "placeholder", maxSelections: "maxSelections", disabled: "disabled", searchable: "searchable", clearable: "clearable" }, outputs: { selectionChange: "selectionChange" }, providers: [
|
|
107
|
+
{
|
|
108
|
+
provide: NG_VALUE_ACCESSOR,
|
|
109
|
+
useExisting: forwardRef(() => MultiSelectComponent),
|
|
110
|
+
multi: true
|
|
111
|
+
}
|
|
112
|
+
], ngImport: i0, template: "<div class=\"multi-select-wrapper\" (blur)=\"onBlur()\">\r\n <div class=\"multi-select-container\" (click)=\"toggleDropdown()\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\">\r\n <div class=\"multi-select-content\">\r\n <div class=\"selected-tags\" *ngIf=\"selectedValues.length > 0\">\r\n <span *ngFor=\"let value of selectedValues\" class=\"tag\">\r\n {{ getOptionLabel(value) }}\r\n <svg class=\"tag-remove\" (click)=\"removeTag(value, $event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n </span>\r\n </div>\r\n \r\n <span *ngIf=\"selectedValues.length === 0\" class=\"placeholder\">\r\n {{ placeholder }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"multi-select-icons\">\r\n <svg *ngIf=\"clearable && selectedValues.length > 0\" class=\"clear-icon\" (click)=\"clearAll($event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n \r\n <svg class=\"arrow-icon\" [class.open]=\"isOpen\" viewBox=\"0 0 24 24\">\r\n <path d=\"M7 10l5 5 5-5z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n <div class=\"multi-select-dropdown\" *ngIf=\"isOpen\">\r\n <div *ngIf=\"searchable\" class=\"search-container\">\r\n <input\r\n type=\"text\"\r\n class=\"search-input\"\r\n placeholder=\"Search...\"\r\n [(ngModel)]=\"searchTerm\"\r\n (input)=\"onSearch($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n\r\n <div class=\"options-container\">\r\n <div\r\n *ngFor=\"let option of filteredOptions\"\r\n class=\"option\"\r\n [class.selected]=\"isSelected(option)\"\r\n [class.disabled]=\"option.disabled\"\r\n (click)=\"toggleOption(option)\"\r\n >\r\n <div class=\"option-checkbox\">\r\n <svg *ngIf=\"isSelected(option)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"option-label\">{{ option.label }}</span>\r\n </div>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"empty-message\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".multi-select-wrapper{position:relative;width:100%}.multi-select-container{min-height:48px;padding:8px 48px 8px 12px;background:white;border:2px solid #e5e7eb;border-radius:12px;cursor:pointer;transition:all .3s ease;position:relative;display:flex;align-items:center}.multi-select-container:hover:not(.disabled){border-color:#667eea}.multi-select-container.open{border-color:#667eea;box-shadow:0 0 0 4px #667eea1a}.multi-select-container.disabled{background:#f3f4f6;cursor:not-allowed;opacity:.6}.multi-select-content{flex:1;min-height:32px;display:flex;align-items:center;flex-wrap:wrap;gap:6px}.selected-tags{display:flex;flex-wrap:wrap;gap:6px}.tag{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border-radius:8px;font-size:14px;font-weight:500;animation:tagIn .2s ease}@keyframes tagIn{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}.tag-remove{width:16px;height:16px;fill:#fff;cursor:pointer;transition:transform .2s ease}.tag-remove:hover{transform:scale(1.2)}.placeholder{color:#9ca3af;font-size:16px}.multi-select-icons{position:absolute;right:12px;top:50%;transform:translateY(-50%);display:flex;align-items:center;gap:8px}.multi-select-icons svg{width:20px;height:20px;fill:#6b7280;transition:all .2s ease}.clear-icon{cursor:pointer}.clear-icon:hover{fill:#ef4444;transform:scale(1.1)}.arrow-icon{transition:transform .3s ease}.arrow-icon.open{transform:rotate(180deg)}.multi-select-dropdown{position:absolute;top:calc(100% + 8px);left:0;right:0;max-height:320px;background:white;border:2px solid #e5e7eb;border-radius:12px;box-shadow:0 10px 25px -5px #0000001a;z-index:1000;animation:slideDown .2s ease;overflow:hidden}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.search-container{padding:12px;border-bottom:1px solid #e5e7eb}.search-input{width:100%;padding:8px 12px;border:1px solid #e5e7eb;border-radius:8px;font-size:14px;outline:none}.search-input:focus{border-color:#667eea}.options-container{max-height:240px;overflow-y:auto}.options-container::-webkit-scrollbar{width:8px}.options-container::-webkit-scrollbar-track{background:#f3f4f6}.options-container::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:12px}.option{display:flex;align-items:center;gap:12px;padding:12px 16px;cursor:pointer;transition:all .2s ease}.option:hover:not(.disabled){background:linear-gradient(135deg,rgba(102,126,234,.1) 0%,rgba(118,75,162,.1) 100%)}.option.selected{background:linear-gradient(135deg,rgba(102,126,234,.15) 0%,rgba(118,75,162,.15) 100%);color:#667eea;font-weight:600}.option.disabled{opacity:.5;cursor:not-allowed}.option-checkbox{width:20px;height:20px;border:2px solid #667eea;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:all .2s ease}.option.selected .option-checkbox{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)}.option-checkbox svg{width:16px;height:16px;fill:#fff}.option-label{flex:1;font-size:15px}.empty-message{padding:24px;text-align:center;color:#9ca3af;font-size:14px}\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: 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"] }] });
|
|
113
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MultiSelectComponent, decorators: [{
|
|
114
|
+
type: Component,
|
|
115
|
+
args: [{ selector: 'muxima-multi-select', standalone: true, imports: [CommonModule, FormsModule], providers: [
|
|
116
|
+
{
|
|
117
|
+
provide: NG_VALUE_ACCESSOR,
|
|
118
|
+
useExisting: forwardRef(() => MultiSelectComponent),
|
|
119
|
+
multi: true
|
|
120
|
+
}
|
|
121
|
+
], template: "<div class=\"multi-select-wrapper\" (blur)=\"onBlur()\">\r\n <div class=\"multi-select-container\" (click)=\"toggleDropdown()\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\">\r\n <div class=\"multi-select-content\">\r\n <div class=\"selected-tags\" *ngIf=\"selectedValues.length > 0\">\r\n <span *ngFor=\"let value of selectedValues\" class=\"tag\">\r\n {{ getOptionLabel(value) }}\r\n <svg class=\"tag-remove\" (click)=\"removeTag(value, $event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n </span>\r\n </div>\r\n \r\n <span *ngIf=\"selectedValues.length === 0\" class=\"placeholder\">\r\n {{ placeholder }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"multi-select-icons\">\r\n <svg *ngIf=\"clearable && selectedValues.length > 0\" class=\"clear-icon\" (click)=\"clearAll($event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n \r\n <svg class=\"arrow-icon\" [class.open]=\"isOpen\" viewBox=\"0 0 24 24\">\r\n <path d=\"M7 10l5 5 5-5z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n <div class=\"multi-select-dropdown\" *ngIf=\"isOpen\">\r\n <div *ngIf=\"searchable\" class=\"search-container\">\r\n <input\r\n type=\"text\"\r\n class=\"search-input\"\r\n placeholder=\"Search...\"\r\n [(ngModel)]=\"searchTerm\"\r\n (input)=\"onSearch($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n\r\n <div class=\"options-container\">\r\n <div\r\n *ngFor=\"let option of filteredOptions\"\r\n class=\"option\"\r\n [class.selected]=\"isSelected(option)\"\r\n [class.disabled]=\"option.disabled\"\r\n (click)=\"toggleOption(option)\"\r\n >\r\n <div class=\"option-checkbox\">\r\n <svg *ngIf=\"isSelected(option)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"option-label\">{{ option.label }}</span>\r\n </div>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"empty-message\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".multi-select-wrapper{position:relative;width:100%}.multi-select-container{min-height:48px;padding:8px 48px 8px 12px;background:white;border:2px solid #e5e7eb;border-radius:12px;cursor:pointer;transition:all .3s ease;position:relative;display:flex;align-items:center}.multi-select-container:hover:not(.disabled){border-color:#667eea}.multi-select-container.open{border-color:#667eea;box-shadow:0 0 0 4px #667eea1a}.multi-select-container.disabled{background:#f3f4f6;cursor:not-allowed;opacity:.6}.multi-select-content{flex:1;min-height:32px;display:flex;align-items:center;flex-wrap:wrap;gap:6px}.selected-tags{display:flex;flex-wrap:wrap;gap:6px}.tag{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border-radius:8px;font-size:14px;font-weight:500;animation:tagIn .2s ease}@keyframes tagIn{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}.tag-remove{width:16px;height:16px;fill:#fff;cursor:pointer;transition:transform .2s ease}.tag-remove:hover{transform:scale(1.2)}.placeholder{color:#9ca3af;font-size:16px}.multi-select-icons{position:absolute;right:12px;top:50%;transform:translateY(-50%);display:flex;align-items:center;gap:8px}.multi-select-icons svg{width:20px;height:20px;fill:#6b7280;transition:all .2s ease}.clear-icon{cursor:pointer}.clear-icon:hover{fill:#ef4444;transform:scale(1.1)}.arrow-icon{transition:transform .3s ease}.arrow-icon.open{transform:rotate(180deg)}.multi-select-dropdown{position:absolute;top:calc(100% + 8px);left:0;right:0;max-height:320px;background:white;border:2px solid #e5e7eb;border-radius:12px;box-shadow:0 10px 25px -5px #0000001a;z-index:1000;animation:slideDown .2s ease;overflow:hidden}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.search-container{padding:12px;border-bottom:1px solid #e5e7eb}.search-input{width:100%;padding:8px 12px;border:1px solid #e5e7eb;border-radius:8px;font-size:14px;outline:none}.search-input:focus{border-color:#667eea}.options-container{max-height:240px;overflow-y:auto}.options-container::-webkit-scrollbar{width:8px}.options-container::-webkit-scrollbar-track{background:#f3f4f6}.options-container::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:12px}.option{display:flex;align-items:center;gap:12px;padding:12px 16px;cursor:pointer;transition:all .2s ease}.option:hover:not(.disabled){background:linear-gradient(135deg,rgba(102,126,234,.1) 0%,rgba(118,75,162,.1) 100%)}.option.selected{background:linear-gradient(135deg,rgba(102,126,234,.15) 0%,rgba(118,75,162,.15) 100%);color:#667eea;font-weight:600}.option.disabled{opacity:.5;cursor:not-allowed}.option-checkbox{width:20px;height:20px;border:2px solid #667eea;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:all .2s ease}.option.selected .option-checkbox{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)}.option-checkbox svg{width:16px;height:16px;fill:#fff}.option-label{flex:1;font-size:15px}.empty-message{padding:24px;text-align:center;color:#9ca3af;font-size:14px}\n"] }]
|
|
122
|
+
}], propDecorators: { options: [{
|
|
123
|
+
type: Input
|
|
124
|
+
}], placeholder: [{
|
|
125
|
+
type: Input
|
|
126
|
+
}], maxSelections: [{
|
|
127
|
+
type: Input
|
|
128
|
+
}], disabled: [{
|
|
129
|
+
type: Input
|
|
130
|
+
}], searchable: [{
|
|
131
|
+
type: Input
|
|
132
|
+
}], clearable: [{
|
|
133
|
+
type: Input
|
|
134
|
+
}], selectionChange: [{
|
|
135
|
+
type: Output
|
|
136
|
+
}] } });
|
|
137
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXVsdGktc2VsZWN0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2Zvcm0vbXVsdGktc2VsZWN0L3NyYy9saWIvbXVsdGktc2VsZWN0L211bHRpLXNlbGVjdC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9mb3JtL211bHRpLXNlbGVjdC9zcmMvbGliL211bHRpLXNlbGVjdC9tdWx0aS1zZWxlY3QuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkYsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBd0IsV0FBVyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7Ozs7QUFzQnRGLE1BQU0sT0FBTyxvQkFBb0I7SUFkakM7UUFlVyxZQUFPLEdBQW1DLEVBQUUsQ0FBQztRQUM3QyxnQkFBVyxHQUFHLGlCQUFpQixDQUFDO1FBRWhDLGFBQVEsR0FBRyxLQUFLLENBQUM7UUFDakIsZUFBVSxHQUFHLElBQUksQ0FBQztRQUNsQixjQUFTLEdBQUcsSUFBSSxDQUFDO1FBRWhCLG9CQUFlLEdBQUcsSUFBSSxZQUFZLEVBQVMsQ0FBQztRQUV0RCxtQkFBYyxHQUFVLEVBQUUsQ0FBQztRQUMzQixXQUFNLEdBQUcsS0FBSyxDQUFDO1FBQ2YsZUFBVSxHQUFHLEVBQUUsQ0FBQztRQUNoQixvQkFBZSxHQUF3QixFQUFFLENBQUM7UUFFbEMsYUFBUSxHQUEyQixHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUM7UUFDNUMsY0FBUyxHQUFlLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQztLQXdHMUM7SUF0R0MsUUFBUTtRQUNOLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO0lBQy9CLENB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QUN2QyxDQUFDO0lBRUQsTUFBTTtRQUNKLFVBQVUsQ0FBQyxHQUFHLEVBQUU7WUFDZCxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztZQUNwQixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDbkIsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ1YsQ0FBQzs7a0hBdkhVLG9CQUFvQjtzR0FBcEIsb0JBQW9CLHVSQVJwQjtRQUNUO1lBQ0UsT0FBTyxFQUFFLGlCQUFpQjtZQUMxQixXQUFXLEVBQUUsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLG9CQUFvQixDQUFDO1lBQ25ELEtBQUssRUFBRSxJQUFJO1NBQ1o7S0FDRiwwQkN0QkgsMDhFQThEQSwrb0dEakRZLFlBQVksK1BBQUUsV0FBVzs0RkFXeEIsb0JBQW9CO2tCQWRoQyxTQUFTOytCQUNFLHFCQUFxQixjQUNuQixJQUFJLFdBQ1AsQ0FBQyxZQUFZLEVBQUUsV0FBVyxDQUFDLGFBR3pCO3dCQUNUOzRCQUNFLE9BQU8sRUFBRSxpQkFBaUI7NEJBQzFCLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLHFCQUFxQixDQUFDOzRCQUNuRCxLQUFLLEVBQUUsSUFBSTt5QkFDWjtxQkFDRjs4QkFHUSxPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csV0FBVztzQkFBbkIsS0FBSztnQkFDRyxhQUFhO3NCQUFyQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQUVJLGVBQWU7c0JBQXhCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgZm9yd2FyZFJlZiwgSW5wdXQsIE91dHB1dCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgRm9ybXNNb2R1bGUsIE5HX1ZBTFVFX0FDQ0VTU09SIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBNdWx0aVNlbGVjdE9wdGlvbiB7XHJcbiAgdmFsdWU6IGFueTtcclxuICBsYWJlbDogc3RyaW5nO1xyXG4gIGRpc2FibGVkPzogYm9vbGVhbjtcclxufVxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdtdXhpbWEtbXVsdGktc2VsZWN0JyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGUsIEZvcm1zTW9kdWxlXSxcclxuICB0ZW1wbGF0ZVVybDogJy4vbXVsdGktc2VsZWN0LmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybHM6IFsnLi9tdWx0aS1zZWxlY3QuY29tcG9uZW50LnNjc3MnXSxcclxuICBwcm92aWRlcnM6IFtcclxuICAgIHtcclxuICAgICAgcHJvdmlkZTogTkdfVkFMVUVfQUNDRVNTT1IsXHJcbiAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IE11bHRpU2VsZWN0Q29tcG9uZW50KSxcclxuICAgICAgbXVsdGk6IHRydWVcclxuICAgIH1cclxuICBdXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBNdWx0aVNlbGVjdENvbXBvbmVudCBpbXBsZW1lbnRzIENvbnRyb2xWYWx1ZUFjY2Vzc29yIHtcclxuICBASW5wdXQoKSBvcHRpb25zOiAoc3RyaW5nIHwgTXVsdGlTZWxlY3RPcHRpb24pW10gPSBbXTtcclxuICBASW5wdXQoKSBwbGFjZWhvbGRlciA9ICdTZWxlY3QgaXRlbXMuLi4nO1xyXG4gIEBJbnB1dCgpIG1heFNlbGVjdGlvbnM/OiBudW1iZXI7XHJcbiAgQElucHV0KCkgZGlzYWJsZWQgPSBmYWxzZTtcclxuICBASW5wdXQoKSBzZWFyY2hhYmxlID0gdHJ1ZTtcclxuICBASW5wdXQoKSBjbGVhcmFibGUgPSB0cnVlO1xyXG4gIFxyXG4gIEBPdXRwdXQoKSBzZWxlY3Rpb25DaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPGFueVtdPigpO1xyXG4gIFxyXG4gIHNlbGVjdGVkVmFsdWVzOiBhbnlbXSA9IFtdO1xyXG4gIGlzT3BlbiA9IGZhbHNlO1xyXG4gIHNlYXJjaFRlcm0gPSAnJztcclxuICBmaWx0ZXJlZE9wdGlvbnM6IE11bHRpU2VsZWN0T3B0aW9uW10gPSBbXTtcclxuICBcclxuICBwcml2YXRlIG9uQ2hhbmdlOiAodmFsdWU6IGFueVtdKSA9PiB2b2lkID0gKCkgPT4ge307XHJcbiAgcHJpdmF0ZSBvblRvdWNoZWQ6ICgpID0+IHZvaWQgPSAoKSA9PiB7fTtcclxuXHJcbiAgbmdPbkluaXQoKTogdm9pZCB7XHJcbiAgICB0aGlzLnVwZGF0ZUZpbHRlcmVkT3B0aW9ucygpO1xyXG4gIH1cclxuXHJcbiAgd3JpdGVWYWx1ZSh2YWx1ZTogYW55W10pOiB2b2lkIHtcclxuICAgIHRoaXMuc2VsZWN0ZWRWYWx1ZXMgPSB2YWx1ZSB8fCBbXTtcclxuICB9XHJcblxyXG4gIHJlZ2lzdGVyT25DaGFuZ2UoZm46IGFueSk6IHZvaWQge1xyXG4gICAgdGhpcy5vbkNoYW5nZSA9IGZuO1xyXG4gIH1cclxuXHJcbiAgcmVnaXN0ZXJPblRvdWNoZWQoZm46IGFueSk6IHZvaWQge1xyXG4gICAgdGhpcy5vblRvdWNoZWQgPSBmbjtcclxuICB9XHJcblxyXG4gIHNldERpc2FibGVkU3RhdGUoaXNEaXNhYmxlZDogYm9vbGVhbik6IHZvaWQge1xyXG4gICAgdGhpcy5kaXNhYmxlZCA9IGlzRGlzYWJsZWQ7XHJcbiAgfVxyXG5cclxuICB0b2dnbGVEcm9wZG93bigpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5kaXNhYmxlZCkge1xyXG4gICAgICB0aGlzLmlzT3BlbiA9ICF0aGlzLmlzT3BlbjtcclxuICAgICAgaWYgKHRoaXMuaXNPcGVuKSB7XHJcbiAgICAgICAgdGhpcy51cGRhdGVGaWx0ZXJlZE9wdGlvbnMoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgdG9nZ2xlT3B0aW9uKG9wdGlvbjogTXVsdGlTZWxlY3RPcHRpb24pOiB2b2lkIHtcclxuICAgIGlmIChvcHRpb24uZGlzYWJsZWQpIHJldHVybjtcclxuXHJcbiAgICBjb25zdCBpbmRleCA9IHRoaXMuc2VsZWN0ZWRWYWx1ZXMuZmluZEluZGV4KHYgPT4gdiA9PT0gb3B0aW9uLnZhbHVlKTtcclxuICAgIFxyXG4gICAgaWYgKGluZGV4ID49IDApIHtcclxuICAgICAgdGhpcy5zZWxlY3RlZFZhbHVlcy5zcGxpY2UoaW5kZXgsIDEpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgaWYgKCF0aGlzLm1heFNlbGVjdGlvbnMgfHwgdGhpcy5zZWxlY3RlZFZhbHVlcy5sZW5ndGggPCB0aGlzLm1heFNlbGVjdGlvbnMpIHtcclxuICAgICAgICB0aGlzLnNlbGVjdGVkVmFsdWVzLnB1c2gob3B0aW9uLnZhbHVlKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgXHJcbiAgICB0aGlzLm9uQ2hhbmdlKHRoaXMuc2VsZWN0ZWRWYWx1ZXMpO1xyXG4gICAgdGhpcy5zZWxlY3Rpb25DaGFuZ2UuZW1pdCh0aGlzLnNlbGVjdGVkVmFsdWVzKTtcclxuICB9XHJcblxyXG4gIGlzU2VsZWN0ZWQob3B0aW9uOiBNdWx0aVNlbGVjdE9wdGlvbik6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuc2VsZWN0ZWRWYWx1ZXMuaW5jbHVkZXMob3B0aW9uLnZhbHVlKTtcclxuICB9XHJcblxyXG4gIHJlbW92ZVRhZyh2YWx1ZTogYW55LCBldmVudDogRXZlbnQpOiB2b2lkIHtcclxuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgY29uc3QgaW5kZXggPSB0aGlzLnNlbGVjdGVkVmFsdWVzLmZpbmRJbmRleCh2ID0+IHYgPT09IHZhbHVlKTtcclxuICAgIGlmIChpbmRleCA+PSAwKSB7XHJcbiAgICAgIHRoaXMuc2VsZWN0ZWRWYWx1ZXMuc3BsaWNlKGluZGV4LCAxKTtcclxuICAgICAgdGhpcy5vbkNoYW5nZSh0aGlzLnNlbGVjdGVkVmFsdWVzKTtcclxuICAgICAgdGhpcy5zZWxlY3Rpb25DaGFuZ2UuZW1pdCh0aGlzLnNlbGVjdGVkVmFsdWVzKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGNsZWFyQWxsKGV2ZW50OiBFdmVudCk6IHZvaWQge1xyXG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XHJcbiAgICB0aGlzLnNlbGVjdGVkVmFsdWVzID0gW107XHJcbiAgICB0aGlzLm9uQ2hhbmdlKHRoaXMuc2VsZWN0ZWRWYWx1ZXMpO1xyXG4gICAgdGhpcy5zZWxlY3Rpb25DaGFuZ2UuZW1pdCh0aGlzLnNlbGVjdGVkVmFsdWVzKTtcclxuICB9XHJcblxyXG4gIG9uU2VhcmNoKGV2ZW50OiBFdmVudCk6IHZvaWQge1xyXG4gICAgY29uc3QgaW5wdXQgPSBldmVudC50YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudDtcclxuICAgIHRoaXMuc2VhcmNoVGVybSA9IGlucHV0LnZhbHVlO1xyXG4gICAgdGhpcy51cGRhdGVGaWx0ZXJlZE9wdGlvbnMoKTtcclxuICB9XHJcblxyXG4gIHVwZGF0ZUZpbHRlcmVkT3B0aW9ucygpOiB2b2lkIHtcclxuICAgIGNvbnN0IGFsbE9wdGlvbnMgPSB0aGlzLm9wdGlvbnMubWFwKG9wdCA9PiBcclxuICAgICAgdHlwZW9mIG9wdCA9PT0gJ3N0cmluZycgPyB7IHZhbHVlOiBvcHQsIGxhYmVsOiBvcHQgfSA6IG9wdFxyXG4gICAgKTtcclxuICAgIFxyXG4gICAgaWYgKCF0aGlzLnNlYXJjaFRlcm0pIHtcclxuICAgICAgdGhpcy5maWx0ZXJlZE9wdGlvbnMgPSBhbGxPcHRpb25zO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgY29uc3QgdGVybSA9IHRoaXMuc2VhcmNoVGVybS50b0xvd2VyQ2FzZSgpO1xyXG4gICAgICB0aGlzLmZpbHRlcmVkT3B0aW9ucyA9IGFsbE9wdGlvbnMuZmlsdGVyKG9wdCA9PiBcclxuICAgICAgICBvcHQubGFiZWwudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyh0ZXJtKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZ2V0T3B0aW9uTGFiZWwodmFsdWU6IGFueSk6IHN0cmluZyB7XHJcbiAgICBjb25zdCBhbGxPcHRpb25zID0gdGhpcy5vcHRpb25zLm1hcChvcHQgPT4gXHJcbiAgICAgIHR5cGVvZiBvcHQgPT09ICdzdHJpbmcnID8geyB2YWx1ZTogb3B0LCBsYWJlbDogb3B0IH0gOiBvcHRcclxuICAgICk7XHJcbiAgICBjb25zdCBvcHRpb24gPSBhbGxPcHRpb25zLmZpbmQob3B0ID0+IG9wdC52YWx1ZSA9PT0gdmFsdWUpO1xyXG4gICAgcmV0dXJuIG9wdGlvbiA/IG9wdGlvbi5sYWJlbCA6IHZhbHVlO1xyXG4gIH1cclxuXHJcbiAgb25CbHVyKCk6IHZvaWQge1xyXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgIHRoaXMuaXNPcGVuID0gZmFsc2U7XHJcbiAgICAgIHRoaXMub25Ub3VjaGVkKCk7XHJcbiAgICB9LCAyMDApO1xyXG4gIH1cclxufVxyXG4iLCI8ZGl2IGNsYXNzPVwibXVsdGktc2VsZWN0LXdyYXBwZXJcIiAoYmx1cik9XCJvbkJsdXIoKVwiPlxyXG4gIDxkaXYgY2xhc3M9XCJtdWx0aS1zZWxlY3QtY29udGFpbmVyXCIgKGNsaWNrKT1cInRvZ2dsZURyb3Bkb3duKClcIiBbY2xhc3MuZGlzYWJsZWRdPVwiZGlzYWJsZWRcIiBbY2xhc3Mub3Blbl09XCJpc09wZW5cIj5cclxuICAgIDxkaXYgY2xhc3M9XCJtdWx0aS1zZWxlY3QtY29udGVudFwiPlxyXG4gICAgICA8ZGl2IGNsYXNzPVwic2VsZWN0ZWQtdGFnc1wiICpuZ0lmPVwic2VsZWN0ZWRWYWx1ZXMubGVuZ3RoID4gMFwiPlxyXG4gICAgICAgIDxzcGFuICpuZ0Zvcj1cImxldCB2YWx1ZSBvZiBzZWxlY3RlZFZhbHVlc1wiIGNsYXNzPVwidGFnXCI+XHJcbiAgICAgICAgICB7eyBnZXRPcHRpb25MYWJlbCh2YWx1ZSkgfX1cclxuICAgICAgICAgIDxzdmcgY2xhc3M9XCJ0YWctcmVtb3ZlXCIgKGNsaWNrKT1cInJlbW92ZVRhZyh2YWx1ZSwgJGV2ZW50KVwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIj5cclxuICAgICAgICAgICAgPHBhdGggZD1cIk0xOSA2LjQxTDE3LjU5IDUgMTIgMTAuNTkgNi40MSA1IDUgNi40MSAxMC41OSAxMiA1IDE3LjU5IDYuNDEgMTkgMTIgMTMuNDEgMTcuNTkgMTkgMTkgMTcuNTkgMTMuNDEgMTJ6XCIvPlxyXG4gICAgICAgICAgPC9zdmc+XHJcbiAgICAgICAgPC9zcGFuPlxyXG4gICAgICA8L2Rpdj5cclxuICAgICAgXHJcbiAgICAgIDxzcGFuICpuZ0lmPVwic2VsZWN0ZWRWYWx1ZXMubGVuZ3RoID09PSAwXCIgY2xhc3M9XCJwbGFjZWhvbGRlclwiPlxyXG4gICAgICAgIHt7IHBsYWNlaG9sZGVyIH19XHJcbiAgICAgIDwvc3Bhbj5cclxuICAgIDwvZGl2PlxyXG5cclxuICAgIDxkaXYgY2xhc3M9XCJtdWx0aS1zZWxlY3QtaWNvbnNcIj5cclxuICAgICAgPHN2ZyAqbmdJZj1cImNsZWFyYWJsZSAmJiBzZWxlY3RlZFZhbHVlcy5sZW5ndGggPiAwXCIgY2xhc3M9XCJjbGVhci1pY29uXCIgKGNsaWNrKT1cImNsZWFyQWxsKCRldmVudClcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCI+XHJcbiAgICAgICAgPHBhdGggZD1cIk0xOSA2LjQxTDE3LjU5IDUgMTIgMTAuNTkgNi40MSA1IDUgNi40MSAxMC41OSAxMiA1IDE3LjU5IDYuNDEgMTkgMTIgMTMuNDEgMTcuNTkgMTkgMTkgMTcuNTkgMTMuNDEgMTJ6XCIvPlxyXG4gICAgICA8L3N2Zz5cclxuICAgICAgXHJcbiAgICAgIDxzdmcgY2xhc3M9XCJhcnJvdy1pY29uXCIgW2NsYXNzLm9wZW5dPVwiaXNPcGVuXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiPlxyXG4gICAgICAgIDxwYXRoIGQ9XCJNNyAxMGw1IDUgNS01elwiLz5cclxuICAgICAgPC9zdmc+XHJcbiAgICA8L2Rpdj5cclxuICA8L2Rpdj5cclxuXHJcbiAgPGRpdiBjbGFzcz1cIm11bHRpLXNlbGVjdC1kcm9wZG93blwiICpuZ0lmPVwiaXNPcGVuXCI+XHJcbiAgICA8ZGl2ICpuZ0lmPVwic2VhcmNoYWJsZVwiIGNsYXNzPVwic2VhcmNoLWNvbnRhaW5lclwiPlxyXG4gICAgICA8aW5wdXRcclxuICAgICAgICB0eXBlPVwidGV4dFwiXHJcbiAgICAgICAgY2xhc3M9XCJzZWFyY2gtaW5wdXRcIlxyXG4gICAgICAgIHBsYWNlaG9sZGVyPVwiU2VhcmNoLi4uXCJcclxuICAgICAgICBbKG5nTW9kZWwpXT1cInNlYXJjaFRlcm1cIlxyXG4gICAgICAgIChpbnB1dCk9XCJvblNlYXJjaCgkZXZlbnQpXCJcclxuICAgICAgICAoY2xpY2spPVwiJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCJcclxuICAgICAgLz5cclxuICAgIDwvZGl2PlxyXG5cclxuICAgIDxkaXYgY2xhc3M9XCJvcHRpb25zLWNvbnRhaW5lclwiPlxyXG4gICAgICA8ZGl2XHJcbiAgICAgICAgKm5nRm9yPVwibGV0IG9wdGlvbiBvZiBmaWx0ZXJlZE9wdGlvbnNcIlxyXG4gICAgICAgIGNsYXNzPVwib3B0aW9uXCJcclxuICAgICAgICBbY2xhc3Muc2VsZWN0ZWRdPVwiaXNTZWxlY3RlZChvcHRpb24pXCJcclxuICAgICAgICBbY2xhc3MuZGlzYWJsZWRdPVwib3B0aW9uLmRpc2FibGVkXCJcclxuICAgICAgICAoY2xpY2spPVwidG9nZ2xlT3B0aW9uKG9wdGlvbilcIlxyXG4gICAgICA+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cIm9wdGlvbi1jaGVja2JveFwiPlxyXG4gICAgICAgICAgPHN2ZyAqbmdJZj1cImlzU2VsZWN0ZWQob3B0aW9uKVwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIj5cclxuICAgICAgICAgICAgPHBhdGggZD1cIk05IDE2LjE3TDQuODMgMTJsLTEuNDIgMS40MUw5IDE5IDIxIDdsLTEuNDEtMS40MXpcIi8+XHJcbiAgICAgICAgICA8L3N2Zz5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8c3BhbiBjbGFzcz1cIm9wdGlvbi1sYWJlbFwiPnt7IG9wdGlvbi5sYWJlbCB9fTwvc3Bhbj5cclxuICAgICAgPC9kaXY+XHJcblxyXG4gICAgICA8ZGl2ICpuZ0lmPVwiZmlsdGVyZWRPcHRpb25zLmxlbmd0aCA9PT0gMFwiIGNsYXNzPVwiZW1wdHktbWVzc2FnZVwiPlxyXG4gICAgICAgIE5vIG9wdGlvbnMgZm91bmRcclxuICAgICAgPC9kaXY+XHJcbiAgICA8L2Rpdj5cclxuICA8L2Rpdj5cclxuPC9kaXY+XHJcbiJdfQ==
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated bundle index. Do not edit.
|
|
3
|
+
*/
|
|
4
|
+
export * from './index';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXV4aW1hLXVpLW11bHRpLXNlbGVjdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2Zvcm0vbXVsdGktc2VsZWN0L3NyYy9tdXhpbWEtdWktbXVsdGktc2VsZWN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxTQUFTLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vaW5kZXgnO1xuIl19
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { EventEmitter, forwardRef, Component, Input, Output } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/common';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
import * as i2 from '@angular/forms';
|
|
6
|
+
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
|
|
7
|
+
|
|
8
|
+
class MultiSelectComponent {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.options = [];
|
|
11
|
+
this.placeholder = 'Select items...';
|
|
12
|
+
this.disabled = false;
|
|
13
|
+
this.searchable = true;
|
|
14
|
+
this.clearable = true;
|
|
15
|
+
this.selectionChange = new EventEmitter();
|
|
16
|
+
this.selectedValues = [];
|
|
17
|
+
this.isOpen = false;
|
|
18
|
+
this.searchTerm = '';
|
|
19
|
+
this.filteredOptions = [];
|
|
20
|
+
this.onChange = () => { };
|
|
21
|
+
this.onTouched = () => { };
|
|
22
|
+
}
|
|
23
|
+
ngOnInit() {
|
|
24
|
+
this.updateFilteredOptions();
|
|
25
|
+
}
|
|
26
|
+
writeValue(value) {
|
|
27
|
+
this.selectedValues = value || [];
|
|
28
|
+
}
|
|
29
|
+
registerOnChange(fn) {
|
|
30
|
+
this.onChange = fn;
|
|
31
|
+
}
|
|
32
|
+
registerOnTouched(fn) {
|
|
33
|
+
this.onTouched = fn;
|
|
34
|
+
}
|
|
35
|
+
setDisabledState(isDisabled) {
|
|
36
|
+
this.disabled = isDisabled;
|
|
37
|
+
}
|
|
38
|
+
toggleDropdown() {
|
|
39
|
+
if (!this.disabled) {
|
|
40
|
+
this.isOpen = !this.isOpen;
|
|
41
|
+
if (this.isOpen) {
|
|
42
|
+
this.updateFilteredOptions();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
toggleOption(option) {
|
|
47
|
+
if (option.disabled)
|
|
48
|
+
return;
|
|
49
|
+
const index = this.selectedValues.findIndex(v => v === option.value);
|
|
50
|
+
if (index >= 0) {
|
|
51
|
+
this.selectedValues.splice(index, 1);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
if (!this.maxSelections || this.selectedValues.length < this.maxSelections) {
|
|
55
|
+
this.selectedValues.push(option.value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
this.onChange(this.selectedValues);
|
|
59
|
+
this.selectionChange.emit(this.selectedValues);
|
|
60
|
+
}
|
|
61
|
+
isSelected(option) {
|
|
62
|
+
return this.selectedValues.includes(option.value);
|
|
63
|
+
}
|
|
64
|
+
removeTag(value, event) {
|
|
65
|
+
event.stopPropagation();
|
|
66
|
+
const index = this.selectedValues.findIndex(v => v === value);
|
|
67
|
+
if (index >= 0) {
|
|
68
|
+
this.selectedValues.splice(index, 1);
|
|
69
|
+
this.onChange(this.selectedValues);
|
|
70
|
+
this.selectionChange.emit(this.selectedValues);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
clearAll(event) {
|
|
74
|
+
event.stopPropagation();
|
|
75
|
+
this.selectedValues = [];
|
|
76
|
+
this.onChange(this.selectedValues);
|
|
77
|
+
this.selectionChange.emit(this.selectedValues);
|
|
78
|
+
}
|
|
79
|
+
onSearch(event) {
|
|
80
|
+
const input = event.target;
|
|
81
|
+
this.searchTerm = input.value;
|
|
82
|
+
this.updateFilteredOptions();
|
|
83
|
+
}
|
|
84
|
+
updateFilteredOptions() {
|
|
85
|
+
const allOptions = this.options.map(opt => typeof opt === 'string' ? { value: opt, label: opt } : opt);
|
|
86
|
+
if (!this.searchTerm) {
|
|
87
|
+
this.filteredOptions = allOptions;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const term = this.searchTerm.toLowerCase();
|
|
91
|
+
this.filteredOptions = allOptions.filter(opt => opt.label.toLowerCase().includes(term));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
getOptionLabel(value) {
|
|
95
|
+
const allOptions = this.options.map(opt => typeof opt === 'string' ? { value: opt, label: opt } : opt);
|
|
96
|
+
const option = allOptions.find(opt => opt.value === value);
|
|
97
|
+
return option ? option.label : value;
|
|
98
|
+
}
|
|
99
|
+
onBlur() {
|
|
100
|
+
setTimeout(() => {
|
|
101
|
+
this.isOpen = false;
|
|
102
|
+
this.onTouched();
|
|
103
|
+
}, 200);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
MultiSelectComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
107
|
+
MultiSelectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: MultiSelectComponent, isStandalone: true, selector: "muxima-multi-select", inputs: { options: "options", placeholder: "placeholder", maxSelections: "maxSelections", disabled: "disabled", searchable: "searchable", clearable: "clearable" }, outputs: { selectionChange: "selectionChange" }, providers: [
|
|
108
|
+
{
|
|
109
|
+
provide: NG_VALUE_ACCESSOR,
|
|
110
|
+
useExisting: forwardRef(() => MultiSelectComponent),
|
|
111
|
+
multi: true
|
|
112
|
+
}
|
|
113
|
+
], ngImport: i0, template: "<div class=\"multi-select-wrapper\" (blur)=\"onBlur()\">\r\n <div class=\"multi-select-container\" (click)=\"toggleDropdown()\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\">\r\n <div class=\"multi-select-content\">\r\n <div class=\"selected-tags\" *ngIf=\"selectedValues.length > 0\">\r\n <span *ngFor=\"let value of selectedValues\" class=\"tag\">\r\n {{ getOptionLabel(value) }}\r\n <svg class=\"tag-remove\" (click)=\"removeTag(value, $event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n </span>\r\n </div>\r\n \r\n <span *ngIf=\"selectedValues.length === 0\" class=\"placeholder\">\r\n {{ placeholder }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"multi-select-icons\">\r\n <svg *ngIf=\"clearable && selectedValues.length > 0\" class=\"clear-icon\" (click)=\"clearAll($event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n \r\n <svg class=\"arrow-icon\" [class.open]=\"isOpen\" viewBox=\"0 0 24 24\">\r\n <path d=\"M7 10l5 5 5-5z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n <div class=\"multi-select-dropdown\" *ngIf=\"isOpen\">\r\n <div *ngIf=\"searchable\" class=\"search-container\">\r\n <input\r\n type=\"text\"\r\n class=\"search-input\"\r\n placeholder=\"Search...\"\r\n [(ngModel)]=\"searchTerm\"\r\n (input)=\"onSearch($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n\r\n <div class=\"options-container\">\r\n <div\r\n *ngFor=\"let option of filteredOptions\"\r\n class=\"option\"\r\n [class.selected]=\"isSelected(option)\"\r\n [class.disabled]=\"option.disabled\"\r\n (click)=\"toggleOption(option)\"\r\n >\r\n <div class=\"option-checkbox\">\r\n <svg *ngIf=\"isSelected(option)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"option-label\">{{ option.label }}</span>\r\n </div>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"empty-message\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".multi-select-wrapper{position:relative;width:100%}.multi-select-container{min-height:48px;padding:8px 48px 8px 12px;background:white;border:2px solid #e5e7eb;border-radius:12px;cursor:pointer;transition:all .3s ease;position:relative;display:flex;align-items:center}.multi-select-container:hover:not(.disabled){border-color:#667eea}.multi-select-container.open{border-color:#667eea;box-shadow:0 0 0 4px #667eea1a}.multi-select-container.disabled{background:#f3f4f6;cursor:not-allowed;opacity:.6}.multi-select-content{flex:1;min-height:32px;display:flex;align-items:center;flex-wrap:wrap;gap:6px}.selected-tags{display:flex;flex-wrap:wrap;gap:6px}.tag{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border-radius:8px;font-size:14px;font-weight:500;animation:tagIn .2s ease}@keyframes tagIn{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}.tag-remove{width:16px;height:16px;fill:#fff;cursor:pointer;transition:transform .2s ease}.tag-remove:hover{transform:scale(1.2)}.placeholder{color:#9ca3af;font-size:16px}.multi-select-icons{position:absolute;right:12px;top:50%;transform:translateY(-50%);display:flex;align-items:center;gap:8px}.multi-select-icons svg{width:20px;height:20px;fill:#6b7280;transition:all .2s ease}.clear-icon{cursor:pointer}.clear-icon:hover{fill:#ef4444;transform:scale(1.1)}.arrow-icon{transition:transform .3s ease}.arrow-icon.open{transform:rotate(180deg)}.multi-select-dropdown{position:absolute;top:calc(100% + 8px);left:0;right:0;max-height:320px;background:white;border:2px solid #e5e7eb;border-radius:12px;box-shadow:0 10px 25px -5px #0000001a;z-index:1000;animation:slideDown .2s ease;overflow:hidden}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.search-container{padding:12px;border-bottom:1px solid #e5e7eb}.search-input{width:100%;padding:8px 12px;border:1px solid #e5e7eb;border-radius:8px;font-size:14px;outline:none}.search-input:focus{border-color:#667eea}.options-container{max-height:240px;overflow-y:auto}.options-container::-webkit-scrollbar{width:8px}.options-container::-webkit-scrollbar-track{background:#f3f4f6}.options-container::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:12px}.option{display:flex;align-items:center;gap:12px;padding:12px 16px;cursor:pointer;transition:all .2s ease}.option:hover:not(.disabled){background:linear-gradient(135deg,rgba(102,126,234,.1) 0%,rgba(118,75,162,.1) 100%)}.option.selected{background:linear-gradient(135deg,rgba(102,126,234,.15) 0%,rgba(118,75,162,.15) 100%);color:#667eea;font-weight:600}.option.disabled{opacity:.5;cursor:not-allowed}.option-checkbox{width:20px;height:20px;border:2px solid #667eea;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:all .2s ease}.option.selected .option-checkbox{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)}.option-checkbox svg{width:16px;height:16px;fill:#fff}.option-label{flex:1;font-size:15px}.empty-message{padding:24px;text-align:center;color:#9ca3af;font-size:14px}\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: 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"] }] });
|
|
114
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MultiSelectComponent, decorators: [{
|
|
115
|
+
type: Component,
|
|
116
|
+
args: [{ selector: 'muxima-multi-select', standalone: true, imports: [CommonModule, FormsModule], providers: [
|
|
117
|
+
{
|
|
118
|
+
provide: NG_VALUE_ACCESSOR,
|
|
119
|
+
useExisting: forwardRef(() => MultiSelectComponent),
|
|
120
|
+
multi: true
|
|
121
|
+
}
|
|
122
|
+
], template: "<div class=\"multi-select-wrapper\" (blur)=\"onBlur()\">\r\n <div class=\"multi-select-container\" (click)=\"toggleDropdown()\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\">\r\n <div class=\"multi-select-content\">\r\n <div class=\"selected-tags\" *ngIf=\"selectedValues.length > 0\">\r\n <span *ngFor=\"let value of selectedValues\" class=\"tag\">\r\n {{ getOptionLabel(value) }}\r\n <svg class=\"tag-remove\" (click)=\"removeTag(value, $event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n </span>\r\n </div>\r\n \r\n <span *ngIf=\"selectedValues.length === 0\" class=\"placeholder\">\r\n {{ placeholder }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"multi-select-icons\">\r\n <svg *ngIf=\"clearable && selectedValues.length > 0\" class=\"clear-icon\" (click)=\"clearAll($event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n \r\n <svg class=\"arrow-icon\" [class.open]=\"isOpen\" viewBox=\"0 0 24 24\">\r\n <path d=\"M7 10l5 5 5-5z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n <div class=\"multi-select-dropdown\" *ngIf=\"isOpen\">\r\n <div *ngIf=\"searchable\" class=\"search-container\">\r\n <input\r\n type=\"text\"\r\n class=\"search-input\"\r\n placeholder=\"Search...\"\r\n [(ngModel)]=\"searchTerm\"\r\n (input)=\"onSearch($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n\r\n <div class=\"options-container\">\r\n <div\r\n *ngFor=\"let option of filteredOptions\"\r\n class=\"option\"\r\n [class.selected]=\"isSelected(option)\"\r\n [class.disabled]=\"option.disabled\"\r\n (click)=\"toggleOption(option)\"\r\n >\r\n <div class=\"option-checkbox\">\r\n <svg *ngIf=\"isSelected(option)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"option-label\">{{ option.label }}</span>\r\n </div>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"empty-message\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".multi-select-wrapper{position:relative;width:100%}.multi-select-container{min-height:48px;padding:8px 48px 8px 12px;background:white;border:2px solid #e5e7eb;border-radius:12px;cursor:pointer;transition:all .3s ease;position:relative;display:flex;align-items:center}.multi-select-container:hover:not(.disabled){border-color:#667eea}.multi-select-container.open{border-color:#667eea;box-shadow:0 0 0 4px #667eea1a}.multi-select-container.disabled{background:#f3f4f6;cursor:not-allowed;opacity:.6}.multi-select-content{flex:1;min-height:32px;display:flex;align-items:center;flex-wrap:wrap;gap:6px}.selected-tags{display:flex;flex-wrap:wrap;gap:6px}.tag{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border-radius:8px;font-size:14px;font-weight:500;animation:tagIn .2s ease}@keyframes tagIn{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}.tag-remove{width:16px;height:16px;fill:#fff;cursor:pointer;transition:transform .2s ease}.tag-remove:hover{transform:scale(1.2)}.placeholder{color:#9ca3af;font-size:16px}.multi-select-icons{position:absolute;right:12px;top:50%;transform:translateY(-50%);display:flex;align-items:center;gap:8px}.multi-select-icons svg{width:20px;height:20px;fill:#6b7280;transition:all .2s ease}.clear-icon{cursor:pointer}.clear-icon:hover{fill:#ef4444;transform:scale(1.1)}.arrow-icon{transition:transform .3s ease}.arrow-icon.open{transform:rotate(180deg)}.multi-select-dropdown{position:absolute;top:calc(100% + 8px);left:0;right:0;max-height:320px;background:white;border:2px solid #e5e7eb;border-radius:12px;box-shadow:0 10px 25px -5px #0000001a;z-index:1000;animation:slideDown .2s ease;overflow:hidden}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.search-container{padding:12px;border-bottom:1px solid #e5e7eb}.search-input{width:100%;padding:8px 12px;border:1px solid #e5e7eb;border-radius:8px;font-size:14px;outline:none}.search-input:focus{border-color:#667eea}.options-container{max-height:240px;overflow-y:auto}.options-container::-webkit-scrollbar{width:8px}.options-container::-webkit-scrollbar-track{background:#f3f4f6}.options-container::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:12px}.option{display:flex;align-items:center;gap:12px;padding:12px 16px;cursor:pointer;transition:all .2s ease}.option:hover:not(.disabled){background:linear-gradient(135deg,rgba(102,126,234,.1) 0%,rgba(118,75,162,.1) 100%)}.option.selected{background:linear-gradient(135deg,rgba(102,126,234,.15) 0%,rgba(118,75,162,.15) 100%);color:#667eea;font-weight:600}.option.disabled{opacity:.5;cursor:not-allowed}.option-checkbox{width:20px;height:20px;border:2px solid #667eea;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:all .2s ease}.option.selected .option-checkbox{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)}.option-checkbox svg{width:16px;height:16px;fill:#fff}.option-label{flex:1;font-size:15px}.empty-message{padding:24px;text-align:center;color:#9ca3af;font-size:14px}\n"] }]
|
|
123
|
+
}], propDecorators: { options: [{
|
|
124
|
+
type: Input
|
|
125
|
+
}], placeholder: [{
|
|
126
|
+
type: Input
|
|
127
|
+
}], maxSelections: [{
|
|
128
|
+
type: Input
|
|
129
|
+
}], disabled: [{
|
|
130
|
+
type: Input
|
|
131
|
+
}], searchable: [{
|
|
132
|
+
type: Input
|
|
133
|
+
}], clearable: [{
|
|
134
|
+
type: Input
|
|
135
|
+
}], selectionChange: [{
|
|
136
|
+
type: Output
|
|
137
|
+
}] } });
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Generated bundle index. Do not edit.
|
|
141
|
+
*/
|
|
142
|
+
|
|
143
|
+
export { MultiSelectComponent };
|
|
144
|
+
//# sourceMappingURL=muxima-ui-multi-select.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"muxima-ui-multi-select.mjs","sources":["../../../../form/multi-select/src/lib/multi-select/multi-select.component.ts","../../../../form/multi-select/src/lib/multi-select/multi-select.component.html","../../../../form/multi-select/src/muxima-ui-multi-select.ts"],"sourcesContent":["import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\r\n\r\nexport interface MultiSelectOption {\r\n value: any;\r\n label: string;\r\n disabled?: boolean;\r\n}\r\n\r\n@Component({\r\n selector: 'muxima-multi-select',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule],\r\n templateUrl: './multi-select.component.html',\r\n styleUrls: ['./multi-select.component.scss'],\r\n providers: [\r\n {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: forwardRef(() => MultiSelectComponent),\r\n multi: true\r\n }\r\n ]\r\n})\r\nexport class MultiSelectComponent implements ControlValueAccessor {\r\n @Input() options: (string | MultiSelectOption)[] = [];\r\n @Input() placeholder = 'Select items...';\r\n @Input() maxSelections?: number;\r\n @Input() disabled = false;\r\n @Input() searchable = true;\r\n @Input() clearable = true;\r\n \r\n @Output() selectionChange = new EventEmitter<any[]>();\r\n \r\n selectedValues: any[] = [];\r\n isOpen = false;\r\n searchTerm = '';\r\n filteredOptions: MultiSelectOption[] = [];\r\n \r\n private onChange: (value: any[]) => void = () => {};\r\n private onTouched: () => void = () => {};\r\n\r\n ngOnInit(): void {\r\n this.updateFilteredOptions();\r\n }\r\n\r\n writeValue(value: any[]): void {\r\n this.selectedValues = value || [];\r\n }\r\n\r\n registerOnChange(fn: any): void {\r\n this.onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: any): void {\r\n this.onTouched = fn;\r\n }\r\n\r\n setDisabledState(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n }\r\n\r\n toggleDropdown(): void {\r\n if (!this.disabled) {\r\n this.isOpen = !this.isOpen;\r\n if (this.isOpen) {\r\n this.updateFilteredOptions();\r\n }\r\n }\r\n }\r\n\r\n toggleOption(option: MultiSelectOption): void {\r\n if (option.disabled) return;\r\n\r\n const index = this.selectedValues.findIndex(v => v === option.value);\r\n \r\n if (index >= 0) {\r\n this.selectedValues.splice(index, 1);\r\n } else {\r\n if (!this.maxSelections || this.selectedValues.length < this.maxSelections) {\r\n this.selectedValues.push(option.value);\r\n }\r\n }\r\n \r\n this.onChange(this.selectedValues);\r\n this.selectionChange.emit(this.selectedValues);\r\n }\r\n\r\n isSelected(option: MultiSelectOption): boolean {\r\n return this.selectedValues.includes(option.value);\r\n }\r\n\r\n removeTag(value: any, event: Event): void {\r\n event.stopPropagation();\r\n const index = this.selectedValues.findIndex(v => v === value);\r\n if (index >= 0) {\r\n this.selectedValues.splice(index, 1);\r\n this.onChange(this.selectedValues);\r\n this.selectionChange.emit(this.selectedValues);\r\n }\r\n }\r\n\r\n clearAll(event: Event): void {\r\n event.stopPropagation();\r\n this.selectedValues = [];\r\n this.onChange(this.selectedValues);\r\n this.selectionChange.emit(this.selectedValues);\r\n }\r\n\r\n onSearch(event: Event): void {\r\n const input = event.target as HTMLInputElement;\r\n this.searchTerm = input.value;\r\n this.updateFilteredOptions();\r\n }\r\n\r\n updateFilteredOptions(): void {\r\n const allOptions = this.options.map(opt => \r\n typeof opt === 'string' ? { value: opt, label: opt } : opt\r\n );\r\n \r\n if (!this.searchTerm) {\r\n this.filteredOptions = allOptions;\r\n } else {\r\n const term = this.searchTerm.toLowerCase();\r\n this.filteredOptions = allOptions.filter(opt => \r\n opt.label.toLowerCase().includes(term)\r\n );\r\n }\r\n }\r\n\r\n getOptionLabel(value: any): string {\r\n const allOptions = this.options.map(opt => \r\n typeof opt === 'string' ? { value: opt, label: opt } : opt\r\n );\r\n const option = allOptions.find(opt => opt.value === value);\r\n return option ? option.label : value;\r\n }\r\n\r\n onBlur(): void {\r\n setTimeout(() => {\r\n this.isOpen = false;\r\n this.onTouched();\r\n }, 200);\r\n }\r\n}\r\n","<div class=\"multi-select-wrapper\" (blur)=\"onBlur()\">\r\n <div class=\"multi-select-container\" (click)=\"toggleDropdown()\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\">\r\n <div class=\"multi-select-content\">\r\n <div class=\"selected-tags\" *ngIf=\"selectedValues.length > 0\">\r\n <span *ngFor=\"let value of selectedValues\" class=\"tag\">\r\n {{ getOptionLabel(value) }}\r\n <svg class=\"tag-remove\" (click)=\"removeTag(value, $event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n </span>\r\n </div>\r\n \r\n <span *ngIf=\"selectedValues.length === 0\" class=\"placeholder\">\r\n {{ placeholder }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"multi-select-icons\">\r\n <svg *ngIf=\"clearable && selectedValues.length > 0\" class=\"clear-icon\" (click)=\"clearAll($event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n \r\n <svg class=\"arrow-icon\" [class.open]=\"isOpen\" viewBox=\"0 0 24 24\">\r\n <path d=\"M7 10l5 5 5-5z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n <div class=\"multi-select-dropdown\" *ngIf=\"isOpen\">\r\n <div *ngIf=\"searchable\" class=\"search-container\">\r\n <input\r\n type=\"text\"\r\n class=\"search-input\"\r\n placeholder=\"Search...\"\r\n [(ngModel)]=\"searchTerm\"\r\n (input)=\"onSearch($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n\r\n <div class=\"options-container\">\r\n <div\r\n *ngFor=\"let option of filteredOptions\"\r\n class=\"option\"\r\n [class.selected]=\"isSelected(option)\"\r\n [class.disabled]=\"option.disabled\"\r\n (click)=\"toggleOption(option)\"\r\n >\r\n <div class=\"option-checkbox\">\r\n <svg *ngIf=\"isSelected(option)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"option-label\">{{ option.label }}</span>\r\n </div>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"empty-message\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;MAwBa,oBAAoB,CAAA;AAdjC,IAAA,WAAA,GAAA;AAeW,QAAA,IAAO,CAAA,OAAA,GAAmC,EAAE,CAAC;AAC7C,QAAA,IAAW,CAAA,WAAA,GAAG,iBAAiB,CAAC;AAEhC,QAAA,IAAQ,CAAA,QAAA,GAAG,KAAK,CAAC;AACjB,QAAA,IAAU,CAAA,UAAA,GAAG,IAAI,CAAC;AAClB,QAAA,IAAS,CAAA,SAAA,GAAG,IAAI,CAAC;AAEhB,QAAA,IAAA,CAAA,eAAe,GAAG,IAAI,YAAY,EAAS,CAAC;AAEtD,QAAA,IAAc,CAAA,cAAA,GAAU,EAAE,CAAC;AAC3B,QAAA,IAAM,CAAA,MAAA,GAAG,KAAK,CAAC;AACf,QAAA,IAAU,CAAA,UAAA,GAAG,EAAE,CAAC;AAChB,QAAA,IAAe,CAAA,eAAA,GAAwB,EAAE,CAAC;AAElC,QAAA,IAAA,CAAA,QAAQ,GAA2B,MAAK,GAAG,CAAC;AAC5C,QAAA,IAAA,CAAA,SAAS,GAAe,MAAK,GAAG,CAAC;KAwG1C;IAtGC,QAAQ,GAAA;QACN,IAAI,CAAC,qBAAqB,EAAE,CAAC;KAC9B;AAED,IAAA,UAAU,CAAC,KAAY,EAAA;AACrB,QAAA,IAAI,CAAC,cAAc,GAAG,KAAK,IAAI,EAAE,CAAC;KACnC;AAED,IAAA,gBAAgB,CAAC,EAAO,EAAA;AACtB,QAAA,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;KACpB;AAED,IAAA,iBAAiB,CAAC,EAAO,EAAA;AACvB,QAAA,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;KACrB;AAED,IAAA,gBAAgB,CAAC,UAAmB,EAAA;AAClC,QAAA,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC;KAC5B;IAED,cAAc,GAAA;AACZ,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;AAClB,YAAA,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;YAC3B,IAAI,IAAI,CAAC,MAAM,EAAE;gBACf,IAAI,CAAC,qBAAqB,EAAE,CAAC;AAC9B,aAAA;AACF,SAAA;KACF;AAED,IAAA,YAAY,CAAC,MAAyB,EAAA;QACpC,IAAI,MAAM,CAAC,QAAQ;YAAE,OAAO;AAE5B,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC;QAErE,IAAI,KAAK,IAAI,CAAC,EAAE;YACd,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AACtC,SAAA;AAAM,aAAA;AACL,YAAA,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE;gBAC1E,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxC,aAAA;AACF,SAAA;AAED,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACnC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;KAChD;AAED,IAAA,UAAU,CAAC,MAAyB,EAAA;QAClC,OAAO,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;KACnD;IAED,SAAS,CAAC,KAAU,EAAE,KAAY,EAAA;QAChC,KAAK,CAAC,eAAe,EAAE,CAAC;AACxB,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC;QAC9D,IAAI,KAAK,IAAI,CAAC,EAAE;YACd,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AACrC,YAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YACnC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;AAChD,SAAA;KACF;AAED,IAAA,QAAQ,CAAC,KAAY,EAAA;QACnB,KAAK,CAAC,eAAe,EAAE,CAAC;AACxB,QAAA,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC;AACzB,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACnC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;KAChD;AAED,IAAA,QAAQ,CAAC,KAAY,EAAA;AACnB,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,MAA0B,CAAC;AAC/C,QAAA,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC;QAC9B,IAAI,CAAC,qBAAqB,EAAE,CAAC;KAC9B;IAED,qBAAqB,GAAA;AACnB,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IACrC,OAAO,GAAG,KAAK,QAAQ,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,GAAG,CAC3D,CAAC;AAEF,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;AACpB,YAAA,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC;AACnC,SAAA;AAAM,aAAA;YACL,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;YAC3C,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,IAC1C,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CACvC,CAAC;AACH,SAAA;KACF;AAED,IAAA,cAAc,CAAC,KAAU,EAAA;AACvB,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IACrC,OAAO,GAAG,KAAK,QAAQ,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,GAAG,CAC3D,CAAC;AACF,QAAA,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QAC3D,OAAO,MAAM,GAAG,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;KACtC;IAED,MAAM,GAAA;QACJ,UAAU,CAAC,MAAK;AACd,YAAA,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;YACpB,IAAI,CAAC,SAAS,EAAE,CAAC;SAClB,EAAE,GAAG,CAAC,CAAC;KACT;;kHAvHU,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAApB,oBAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,oBAAoB,EARpB,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,EAAA,OAAA,EAAA,SAAA,EAAA,WAAA,EAAA,aAAA,EAAA,aAAA,EAAA,eAAA,EAAA,QAAA,EAAA,UAAA,EAAA,UAAA,EAAA,YAAA,EAAA,SAAA,EAAA,WAAA,EAAA,EAAA,OAAA,EAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,EAAA,SAAA,EAAA;AACT,QAAA;AACE,YAAA,OAAO,EAAE,iBAAiB;AAC1B,YAAA,WAAW,EAAE,UAAU,CAAC,MAAM,oBAAoB,CAAC;AACnD,YAAA,KAAK,EAAE,IAAI;AACZ,SAAA;AACF,KAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECtBH,08EA8DA,EAAA,MAAA,EAAA,CAAA,wlGAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDjDY,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,cAAA,EAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,IAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,CAAA,EAAA,CAAA,CAAA;4FAWxB,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBAdhC,SAAS;+BACE,qBAAqB,EAAA,UAAA,EACnB,IAAI,EACP,OAAA,EAAA,CAAC,YAAY,EAAE,WAAW,CAAC,EAGzB,SAAA,EAAA;AACT,wBAAA;AACE,4BAAA,OAAO,EAAE,iBAAiB;AAC1B,4BAAA,WAAW,EAAE,UAAU,CAAC,0BAA0B,CAAC;AACnD,4BAAA,KAAK,EAAE,IAAI;AACZ,yBAAA;qBACF,EAAA,QAAA,EAAA,08EAAA,EAAA,MAAA,EAAA,CAAA,wlGAAA,CAAA,EAAA,CAAA;8BAGQ,OAAO,EAAA,CAAA;sBAAf,KAAK;gBACG,WAAW,EAAA,CAAA;sBAAnB,KAAK;gBACG,aAAa,EAAA,CAAA;sBAArB,KAAK;gBACG,QAAQ,EAAA,CAAA;sBAAhB,KAAK;gBACG,UAAU,EAAA,CAAA;sBAAlB,KAAK;gBACG,SAAS,EAAA,CAAA;sBAAjB,KAAK;gBAEI,eAAe,EAAA,CAAA;sBAAxB,MAAM;;;AEhCT;;AAEG;;;;"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { EventEmitter, forwardRef, Component, Input, Output } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/common';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
import * as i2 from '@angular/forms';
|
|
6
|
+
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
|
|
7
|
+
|
|
8
|
+
class MultiSelectComponent {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.options = [];
|
|
11
|
+
this.placeholder = 'Select items...';
|
|
12
|
+
this.disabled = false;
|
|
13
|
+
this.searchable = true;
|
|
14
|
+
this.clearable = true;
|
|
15
|
+
this.selectionChange = new EventEmitter();
|
|
16
|
+
this.selectedValues = [];
|
|
17
|
+
this.isOpen = false;
|
|
18
|
+
this.searchTerm = '';
|
|
19
|
+
this.filteredOptions = [];
|
|
20
|
+
this.onChange = () => { };
|
|
21
|
+
this.onTouched = () => { };
|
|
22
|
+
}
|
|
23
|
+
ngOnInit() {
|
|
24
|
+
this.updateFilteredOptions();
|
|
25
|
+
}
|
|
26
|
+
writeValue(value) {
|
|
27
|
+
this.selectedValues = value || [];
|
|
28
|
+
}
|
|
29
|
+
registerOnChange(fn) {
|
|
30
|
+
this.onChange = fn;
|
|
31
|
+
}
|
|
32
|
+
registerOnTouched(fn) {
|
|
33
|
+
this.onTouched = fn;
|
|
34
|
+
}
|
|
35
|
+
setDisabledState(isDisabled) {
|
|
36
|
+
this.disabled = isDisabled;
|
|
37
|
+
}
|
|
38
|
+
toggleDropdown() {
|
|
39
|
+
if (!this.disabled) {
|
|
40
|
+
this.isOpen = !this.isOpen;
|
|
41
|
+
if (this.isOpen) {
|
|
42
|
+
this.updateFilteredOptions();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
toggleOption(option) {
|
|
47
|
+
if (option.disabled)
|
|
48
|
+
return;
|
|
49
|
+
const index = this.selectedValues.findIndex(v => v === option.value);
|
|
50
|
+
if (index >= 0) {
|
|
51
|
+
this.selectedValues.splice(index, 1);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
if (!this.maxSelections || this.selectedValues.length < this.maxSelections) {
|
|
55
|
+
this.selectedValues.push(option.value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
this.onChange(this.selectedValues);
|
|
59
|
+
this.selectionChange.emit(this.selectedValues);
|
|
60
|
+
}
|
|
61
|
+
isSelected(option) {
|
|
62
|
+
return this.selectedValues.includes(option.value);
|
|
63
|
+
}
|
|
64
|
+
removeTag(value, event) {
|
|
65
|
+
event.stopPropagation();
|
|
66
|
+
const index = this.selectedValues.findIndex(v => v === value);
|
|
67
|
+
if (index >= 0) {
|
|
68
|
+
this.selectedValues.splice(index, 1);
|
|
69
|
+
this.onChange(this.selectedValues);
|
|
70
|
+
this.selectionChange.emit(this.selectedValues);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
clearAll(event) {
|
|
74
|
+
event.stopPropagation();
|
|
75
|
+
this.selectedValues = [];
|
|
76
|
+
this.onChange(this.selectedValues);
|
|
77
|
+
this.selectionChange.emit(this.selectedValues);
|
|
78
|
+
}
|
|
79
|
+
onSearch(event) {
|
|
80
|
+
const input = event.target;
|
|
81
|
+
this.searchTerm = input.value;
|
|
82
|
+
this.updateFilteredOptions();
|
|
83
|
+
}
|
|
84
|
+
updateFilteredOptions() {
|
|
85
|
+
const allOptions = this.options.map(opt => typeof opt === 'string' ? { value: opt, label: opt } : opt);
|
|
86
|
+
if (!this.searchTerm) {
|
|
87
|
+
this.filteredOptions = allOptions;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const term = this.searchTerm.toLowerCase();
|
|
91
|
+
this.filteredOptions = allOptions.filter(opt => opt.label.toLowerCase().includes(term));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
getOptionLabel(value) {
|
|
95
|
+
const allOptions = this.options.map(opt => typeof opt === 'string' ? { value: opt, label: opt } : opt);
|
|
96
|
+
const option = allOptions.find(opt => opt.value === value);
|
|
97
|
+
return option ? option.label : value;
|
|
98
|
+
}
|
|
99
|
+
onBlur() {
|
|
100
|
+
setTimeout(() => {
|
|
101
|
+
this.isOpen = false;
|
|
102
|
+
this.onTouched();
|
|
103
|
+
}, 200);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
MultiSelectComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
107
|
+
MultiSelectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: MultiSelectComponent, isStandalone: true, selector: "muxima-multi-select", inputs: { options: "options", placeholder: "placeholder", maxSelections: "maxSelections", disabled: "disabled", searchable: "searchable", clearable: "clearable" }, outputs: { selectionChange: "selectionChange" }, providers: [
|
|
108
|
+
{
|
|
109
|
+
provide: NG_VALUE_ACCESSOR,
|
|
110
|
+
useExisting: forwardRef(() => MultiSelectComponent),
|
|
111
|
+
multi: true
|
|
112
|
+
}
|
|
113
|
+
], ngImport: i0, template: "<div class=\"multi-select-wrapper\" (blur)=\"onBlur()\">\r\n <div class=\"multi-select-container\" (click)=\"toggleDropdown()\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\">\r\n <div class=\"multi-select-content\">\r\n <div class=\"selected-tags\" *ngIf=\"selectedValues.length > 0\">\r\n <span *ngFor=\"let value of selectedValues\" class=\"tag\">\r\n {{ getOptionLabel(value) }}\r\n <svg class=\"tag-remove\" (click)=\"removeTag(value, $event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n </span>\r\n </div>\r\n \r\n <span *ngIf=\"selectedValues.length === 0\" class=\"placeholder\">\r\n {{ placeholder }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"multi-select-icons\">\r\n <svg *ngIf=\"clearable && selectedValues.length > 0\" class=\"clear-icon\" (click)=\"clearAll($event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n \r\n <svg class=\"arrow-icon\" [class.open]=\"isOpen\" viewBox=\"0 0 24 24\">\r\n <path d=\"M7 10l5 5 5-5z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n <div class=\"multi-select-dropdown\" *ngIf=\"isOpen\">\r\n <div *ngIf=\"searchable\" class=\"search-container\">\r\n <input\r\n type=\"text\"\r\n class=\"search-input\"\r\n placeholder=\"Search...\"\r\n [(ngModel)]=\"searchTerm\"\r\n (input)=\"onSearch($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n\r\n <div class=\"options-container\">\r\n <div\r\n *ngFor=\"let option of filteredOptions\"\r\n class=\"option\"\r\n [class.selected]=\"isSelected(option)\"\r\n [class.disabled]=\"option.disabled\"\r\n (click)=\"toggleOption(option)\"\r\n >\r\n <div class=\"option-checkbox\">\r\n <svg *ngIf=\"isSelected(option)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"option-label\">{{ option.label }}</span>\r\n </div>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"empty-message\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".multi-select-wrapper{position:relative;width:100%}.multi-select-container{min-height:48px;padding:8px 48px 8px 12px;background:white;border:2px solid #e5e7eb;border-radius:12px;cursor:pointer;transition:all .3s ease;position:relative;display:flex;align-items:center}.multi-select-container:hover:not(.disabled){border-color:#667eea}.multi-select-container.open{border-color:#667eea;box-shadow:0 0 0 4px #667eea1a}.multi-select-container.disabled{background:#f3f4f6;cursor:not-allowed;opacity:.6}.multi-select-content{flex:1;min-height:32px;display:flex;align-items:center;flex-wrap:wrap;gap:6px}.selected-tags{display:flex;flex-wrap:wrap;gap:6px}.tag{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border-radius:8px;font-size:14px;font-weight:500;animation:tagIn .2s ease}@keyframes tagIn{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}.tag-remove{width:16px;height:16px;fill:#fff;cursor:pointer;transition:transform .2s ease}.tag-remove:hover{transform:scale(1.2)}.placeholder{color:#9ca3af;font-size:16px}.multi-select-icons{position:absolute;right:12px;top:50%;transform:translateY(-50%);display:flex;align-items:center;gap:8px}.multi-select-icons svg{width:20px;height:20px;fill:#6b7280;transition:all .2s ease}.clear-icon{cursor:pointer}.clear-icon:hover{fill:#ef4444;transform:scale(1.1)}.arrow-icon{transition:transform .3s ease}.arrow-icon.open{transform:rotate(180deg)}.multi-select-dropdown{position:absolute;top:calc(100% + 8px);left:0;right:0;max-height:320px;background:white;border:2px solid #e5e7eb;border-radius:12px;box-shadow:0 10px 25px -5px #0000001a;z-index:1000;animation:slideDown .2s ease;overflow:hidden}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.search-container{padding:12px;border-bottom:1px solid #e5e7eb}.search-input{width:100%;padding:8px 12px;border:1px solid #e5e7eb;border-radius:8px;font-size:14px;outline:none}.search-input:focus{border-color:#667eea}.options-container{max-height:240px;overflow-y:auto}.options-container::-webkit-scrollbar{width:8px}.options-container::-webkit-scrollbar-track{background:#f3f4f6}.options-container::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:12px}.option{display:flex;align-items:center;gap:12px;padding:12px 16px;cursor:pointer;transition:all .2s ease}.option:hover:not(.disabled){background:linear-gradient(135deg,rgba(102,126,234,.1) 0%,rgba(118,75,162,.1) 100%)}.option.selected{background:linear-gradient(135deg,rgba(102,126,234,.15) 0%,rgba(118,75,162,.15) 100%);color:#667eea;font-weight:600}.option.disabled{opacity:.5;cursor:not-allowed}.option-checkbox{width:20px;height:20px;border:2px solid #667eea;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:all .2s ease}.option.selected .option-checkbox{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)}.option-checkbox svg{width:16px;height:16px;fill:#fff}.option-label{flex:1;font-size:15px}.empty-message{padding:24px;text-align:center;color:#9ca3af;font-size:14px}\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: 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"] }] });
|
|
114
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MultiSelectComponent, decorators: [{
|
|
115
|
+
type: Component,
|
|
116
|
+
args: [{ selector: 'muxima-multi-select', standalone: true, imports: [CommonModule, FormsModule], providers: [
|
|
117
|
+
{
|
|
118
|
+
provide: NG_VALUE_ACCESSOR,
|
|
119
|
+
useExisting: forwardRef(() => MultiSelectComponent),
|
|
120
|
+
multi: true
|
|
121
|
+
}
|
|
122
|
+
], template: "<div class=\"multi-select-wrapper\" (blur)=\"onBlur()\">\r\n <div class=\"multi-select-container\" (click)=\"toggleDropdown()\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\">\r\n <div class=\"multi-select-content\">\r\n <div class=\"selected-tags\" *ngIf=\"selectedValues.length > 0\">\r\n <span *ngFor=\"let value of selectedValues\" class=\"tag\">\r\n {{ getOptionLabel(value) }}\r\n <svg class=\"tag-remove\" (click)=\"removeTag(value, $event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n </span>\r\n </div>\r\n \r\n <span *ngIf=\"selectedValues.length === 0\" class=\"placeholder\">\r\n {{ placeholder }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"multi-select-icons\">\r\n <svg *ngIf=\"clearable && selectedValues.length > 0\" class=\"clear-icon\" (click)=\"clearAll($event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n \r\n <svg class=\"arrow-icon\" [class.open]=\"isOpen\" viewBox=\"0 0 24 24\">\r\n <path d=\"M7 10l5 5 5-5z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n <div class=\"multi-select-dropdown\" *ngIf=\"isOpen\">\r\n <div *ngIf=\"searchable\" class=\"search-container\">\r\n <input\r\n type=\"text\"\r\n class=\"search-input\"\r\n placeholder=\"Search...\"\r\n [(ngModel)]=\"searchTerm\"\r\n (input)=\"onSearch($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n\r\n <div class=\"options-container\">\r\n <div\r\n *ngFor=\"let option of filteredOptions\"\r\n class=\"option\"\r\n [class.selected]=\"isSelected(option)\"\r\n [class.disabled]=\"option.disabled\"\r\n (click)=\"toggleOption(option)\"\r\n >\r\n <div class=\"option-checkbox\">\r\n <svg *ngIf=\"isSelected(option)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"option-label\">{{ option.label }}</span>\r\n </div>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"empty-message\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".multi-select-wrapper{position:relative;width:100%}.multi-select-container{min-height:48px;padding:8px 48px 8px 12px;background:white;border:2px solid #e5e7eb;border-radius:12px;cursor:pointer;transition:all .3s ease;position:relative;display:flex;align-items:center}.multi-select-container:hover:not(.disabled){border-color:#667eea}.multi-select-container.open{border-color:#667eea;box-shadow:0 0 0 4px #667eea1a}.multi-select-container.disabled{background:#f3f4f6;cursor:not-allowed;opacity:.6}.multi-select-content{flex:1;min-height:32px;display:flex;align-items:center;flex-wrap:wrap;gap:6px}.selected-tags{display:flex;flex-wrap:wrap;gap:6px}.tag{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border-radius:8px;font-size:14px;font-weight:500;animation:tagIn .2s ease}@keyframes tagIn{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}.tag-remove{width:16px;height:16px;fill:#fff;cursor:pointer;transition:transform .2s ease}.tag-remove:hover{transform:scale(1.2)}.placeholder{color:#9ca3af;font-size:16px}.multi-select-icons{position:absolute;right:12px;top:50%;transform:translateY(-50%);display:flex;align-items:center;gap:8px}.multi-select-icons svg{width:20px;height:20px;fill:#6b7280;transition:all .2s ease}.clear-icon{cursor:pointer}.clear-icon:hover{fill:#ef4444;transform:scale(1.1)}.arrow-icon{transition:transform .3s ease}.arrow-icon.open{transform:rotate(180deg)}.multi-select-dropdown{position:absolute;top:calc(100% + 8px);left:0;right:0;max-height:320px;background:white;border:2px solid #e5e7eb;border-radius:12px;box-shadow:0 10px 25px -5px #0000001a;z-index:1000;animation:slideDown .2s ease;overflow:hidden}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.search-container{padding:12px;border-bottom:1px solid #e5e7eb}.search-input{width:100%;padding:8px 12px;border:1px solid #e5e7eb;border-radius:8px;font-size:14px;outline:none}.search-input:focus{border-color:#667eea}.options-container{max-height:240px;overflow-y:auto}.options-container::-webkit-scrollbar{width:8px}.options-container::-webkit-scrollbar-track{background:#f3f4f6}.options-container::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:12px}.option{display:flex;align-items:center;gap:12px;padding:12px 16px;cursor:pointer;transition:all .2s ease}.option:hover:not(.disabled){background:linear-gradient(135deg,rgba(102,126,234,.1) 0%,rgba(118,75,162,.1) 100%)}.option.selected{background:linear-gradient(135deg,rgba(102,126,234,.15) 0%,rgba(118,75,162,.15) 100%);color:#667eea;font-weight:600}.option.disabled{opacity:.5;cursor:not-allowed}.option-checkbox{width:20px;height:20px;border:2px solid #667eea;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:all .2s ease}.option.selected .option-checkbox{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)}.option-checkbox svg{width:16px;height:16px;fill:#fff}.option-label{flex:1;font-size:15px}.empty-message{padding:24px;text-align:center;color:#9ca3af;font-size:14px}\n"] }]
|
|
123
|
+
}], propDecorators: { options: [{
|
|
124
|
+
type: Input
|
|
125
|
+
}], placeholder: [{
|
|
126
|
+
type: Input
|
|
127
|
+
}], maxSelections: [{
|
|
128
|
+
type: Input
|
|
129
|
+
}], disabled: [{
|
|
130
|
+
type: Input
|
|
131
|
+
}], searchable: [{
|
|
132
|
+
type: Input
|
|
133
|
+
}], clearable: [{
|
|
134
|
+
type: Input
|
|
135
|
+
}], selectionChange: [{
|
|
136
|
+
type: Output
|
|
137
|
+
}] } });
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Generated bundle index. Do not edit.
|
|
141
|
+
*/
|
|
142
|
+
|
|
143
|
+
export { MultiSelectComponent };
|
|
144
|
+
//# sourceMappingURL=muxima-ui-multi-select.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"muxima-ui-multi-select.mjs","sources":["../../../../form/multi-select/src/lib/multi-select/multi-select.component.ts","../../../../form/multi-select/src/lib/multi-select/multi-select.component.html","../../../../form/multi-select/src/muxima-ui-multi-select.ts"],"sourcesContent":["import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\r\n\r\nexport interface MultiSelectOption {\r\n value: any;\r\n label: string;\r\n disabled?: boolean;\r\n}\r\n\r\n@Component({\r\n selector: 'muxima-multi-select',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule],\r\n templateUrl: './multi-select.component.html',\r\n styleUrls: ['./multi-select.component.scss'],\r\n providers: [\r\n {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: forwardRef(() => MultiSelectComponent),\r\n multi: true\r\n }\r\n ]\r\n})\r\nexport class MultiSelectComponent implements ControlValueAccessor {\r\n @Input() options: (string | MultiSelectOption)[] = [];\r\n @Input() placeholder = 'Select items...';\r\n @Input() maxSelections?: number;\r\n @Input() disabled = false;\r\n @Input() searchable = true;\r\n @Input() clearable = true;\r\n \r\n @Output() selectionChange = new EventEmitter<any[]>();\r\n \r\n selectedValues: any[] = [];\r\n isOpen = false;\r\n searchTerm = '';\r\n filteredOptions: MultiSelectOption[] = [];\r\n \r\n private onChange: (value: any[]) => void = () => {};\r\n private onTouched: () => void = () => {};\r\n\r\n ngOnInit(): void {\r\n this.updateFilteredOptions();\r\n }\r\n\r\n writeValue(value: any[]): void {\r\n this.selectedValues = value || [];\r\n }\r\n\r\n registerOnChange(fn: any): void {\r\n this.onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: any): void {\r\n this.onTouched = fn;\r\n }\r\n\r\n setDisabledState(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n }\r\n\r\n toggleDropdown(): void {\r\n if (!this.disabled) {\r\n this.isOpen = !this.isOpen;\r\n if (this.isOpen) {\r\n this.updateFilteredOptions();\r\n }\r\n }\r\n }\r\n\r\n toggleOption(option: MultiSelectOption): void {\r\n if (option.disabled) return;\r\n\r\n const index = this.selectedValues.findIndex(v => v === option.value);\r\n \r\n if (index >= 0) {\r\n this.selectedValues.splice(index, 1);\r\n } else {\r\n if (!this.maxSelections || this.selectedValues.length < this.maxSelections) {\r\n this.selectedValues.push(option.value);\r\n }\r\n }\r\n \r\n this.onChange(this.selectedValues);\r\n this.selectionChange.emit(this.selectedValues);\r\n }\r\n\r\n isSelected(option: MultiSelectOption): boolean {\r\n return this.selectedValues.includes(option.value);\r\n }\r\n\r\n removeTag(value: any, event: Event): void {\r\n event.stopPropagation();\r\n const index = this.selectedValues.findIndex(v => v === value);\r\n if (index >= 0) {\r\n this.selectedValues.splice(index, 1);\r\n this.onChange(this.selectedValues);\r\n this.selectionChange.emit(this.selectedValues);\r\n }\r\n }\r\n\r\n clearAll(event: Event): void {\r\n event.stopPropagation();\r\n this.selectedValues = [];\r\n this.onChange(this.selectedValues);\r\n this.selectionChange.emit(this.selectedValues);\r\n }\r\n\r\n onSearch(event: Event): void {\r\n const input = event.target as HTMLInputElement;\r\n this.searchTerm = input.value;\r\n this.updateFilteredOptions();\r\n }\r\n\r\n updateFilteredOptions(): void {\r\n const allOptions = this.options.map(opt => \r\n typeof opt === 'string' ? { value: opt, label: opt } : opt\r\n );\r\n \r\n if (!this.searchTerm) {\r\n this.filteredOptions = allOptions;\r\n } else {\r\n const term = this.searchTerm.toLowerCase();\r\n this.filteredOptions = allOptions.filter(opt => \r\n opt.label.toLowerCase().includes(term)\r\n );\r\n }\r\n }\r\n\r\n getOptionLabel(value: any): string {\r\n const allOptions = this.options.map(opt => \r\n typeof opt === 'string' ? { value: opt, label: opt } : opt\r\n );\r\n const option = allOptions.find(opt => opt.value === value);\r\n return option ? option.label : value;\r\n }\r\n\r\n onBlur(): void {\r\n setTimeout(() => {\r\n this.isOpen = false;\r\n this.onTouched();\r\n }, 200);\r\n }\r\n}\r\n","<div class=\"multi-select-wrapper\" (blur)=\"onBlur()\">\r\n <div class=\"multi-select-container\" (click)=\"toggleDropdown()\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\">\r\n <div class=\"multi-select-content\">\r\n <div class=\"selected-tags\" *ngIf=\"selectedValues.length > 0\">\r\n <span *ngFor=\"let value of selectedValues\" class=\"tag\">\r\n {{ getOptionLabel(value) }}\r\n <svg class=\"tag-remove\" (click)=\"removeTag(value, $event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n </span>\r\n </div>\r\n \r\n <span *ngIf=\"selectedValues.length === 0\" class=\"placeholder\">\r\n {{ placeholder }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"multi-select-icons\">\r\n <svg *ngIf=\"clearable && selectedValues.length > 0\" class=\"clear-icon\" (click)=\"clearAll($event)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n \r\n <svg class=\"arrow-icon\" [class.open]=\"isOpen\" viewBox=\"0 0 24 24\">\r\n <path d=\"M7 10l5 5 5-5z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n <div class=\"multi-select-dropdown\" *ngIf=\"isOpen\">\r\n <div *ngIf=\"searchable\" class=\"search-container\">\r\n <input\r\n type=\"text\"\r\n class=\"search-input\"\r\n placeholder=\"Search...\"\r\n [(ngModel)]=\"searchTerm\"\r\n (input)=\"onSearch($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n\r\n <div class=\"options-container\">\r\n <div\r\n *ngFor=\"let option of filteredOptions\"\r\n class=\"option\"\r\n [class.selected]=\"isSelected(option)\"\r\n [class.disabled]=\"option.disabled\"\r\n (click)=\"toggleOption(option)\"\r\n >\r\n <div class=\"option-checkbox\">\r\n <svg *ngIf=\"isSelected(option)\" viewBox=\"0 0 24 24\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"option-label\">{{ option.label }}</span>\r\n </div>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"empty-message\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './lib/multi-select/multi-select.component';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { EventEmitter } from '@angular/core';
|
|
2
|
+
import { ControlValueAccessor } from '@angular/forms';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export interface MultiSelectOption {
|
|
5
|
+
value: any;
|
|
6
|
+
label: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare class MultiSelectComponent implements ControlValueAccessor {
|
|
10
|
+
options: (string | MultiSelectOption)[];
|
|
11
|
+
placeholder: string;
|
|
12
|
+
maxSelections?: number;
|
|
13
|
+
disabled: boolean;
|
|
14
|
+
searchable: boolean;
|
|
15
|
+
clearable: boolean;
|
|
16
|
+
selectionChange: EventEmitter<any[]>;
|
|
17
|
+
selectedValues: any[];
|
|
18
|
+
isOpen: boolean;
|
|
19
|
+
searchTerm: string;
|
|
20
|
+
filteredOptions: MultiSelectOption[];
|
|
21
|
+
private onChange;
|
|
22
|
+
private onTouched;
|
|
23
|
+
ngOnInit(): void;
|
|
24
|
+
writeValue(value: any[]): void;
|
|
25
|
+
registerOnChange(fn: any): void;
|
|
26
|
+
registerOnTouched(fn: any): void;
|
|
27
|
+
setDisabledState(isDisabled: boolean): void;
|
|
28
|
+
toggleDropdown(): void;
|
|
29
|
+
toggleOption(option: MultiSelectOption): void;
|
|
30
|
+
isSelected(option: MultiSelectOption): boolean;
|
|
31
|
+
removeTag(value: any, event: Event): void;
|
|
32
|
+
clearAll(event: Event): void;
|
|
33
|
+
onSearch(event: Event): void;
|
|
34
|
+
updateFilteredOptions(): void;
|
|
35
|
+
getOptionLabel(value: any): string;
|
|
36
|
+
onBlur(): void;
|
|
37
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MultiSelectComponent, never>;
|
|
38
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<MultiSelectComponent, "muxima-multi-select", never, { "options": "options"; "placeholder": "placeholder"; "maxSelections": "maxSelections"; "disabled": "disabled"; "searchable": "searchable"; "clearable": "clearable"; }, { "selectionChange": "selectionChange"; }, never, never, true, never>;
|
|
39
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@muxima-ui/multi-select",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Multi-select dropdown component for Angular 18+ - Muxima UI",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"angular",
|
|
7
|
+
"multi-select",
|
|
8
|
+
"dropdown",
|
|
9
|
+
"select",
|
|
10
|
+
"form",
|
|
11
|
+
"muxima-ui"
|
|
12
|
+
],
|
|
13
|
+
"author": "Muxima UI Team (jokerscript)",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/Aldemiro20/muxima-ui.git",
|
|
18
|
+
"directory": "packages/form/multi-select"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://muxima-ui.vercel.app/components/multi-select",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/Aldemiro20/muxima-ui/issues"
|
|
23
|
+
},
|
|
24
|
+
"documentation": "https://muxima-ui.vercel.app",
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@angular/common": "^18.0.0",
|
|
30
|
+
"@angular/core": "^18.0.0",
|
|
31
|
+
"@angular/forms": "^18.0.0"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"tslib": "^2.3.0"
|
|
35
|
+
},
|
|
36
|
+
"sideEffects": false,
|
|
37
|
+
"module": "fesm2015/muxima-ui-multi-select.mjs",
|
|
38
|
+
"es2020": "fesm2020/muxima-ui-multi-select.mjs",
|
|
39
|
+
"esm2020": "esm2020/muxima-ui-multi-select.mjs",
|
|
40
|
+
"fesm2020": "fesm2020/muxima-ui-multi-select.mjs",
|
|
41
|
+
"fesm2015": "fesm2015/muxima-ui-multi-select.mjs",
|
|
42
|
+
"typings": "index.d.ts",
|
|
43
|
+
"exports": {
|
|
44
|
+
"./package.json": {
|
|
45
|
+
"default": "./package.json"
|
|
46
|
+
},
|
|
47
|
+
".": {
|
|
48
|
+
"types": "./index.d.ts",
|
|
49
|
+
"esm2020": "./esm2020/muxima-ui-multi-select.mjs",
|
|
50
|
+
"es2020": "./fesm2020/muxima-ui-multi-select.mjs",
|
|
51
|
+
"es2015": "./fesm2015/muxima-ui-multi-select.mjs",
|
|
52
|
+
"node": "./fesm2015/muxima-ui-multi-select.mjs",
|
|
53
|
+
"default": "./fesm2020/muxima-ui-multi-select.mjs"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|