@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.
@@ -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":"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"}
@@ -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
+ }