wally-ui 1.15.0 → 1.16.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/dist/cli.js +0 -0
- package/package.json +1 -1
- package/playground/showcase/src/app/app.routes.server.ts +4 -0
- package/playground/showcase/src/app/components/combobox/combobox-content/combobox-content.css +0 -0
- package/playground/showcase/src/app/components/combobox/combobox-content/combobox-content.html +41 -0
- package/playground/showcase/src/app/components/combobox/combobox-content/combobox-content.spec.ts +228 -0
- package/playground/showcase/src/app/components/combobox/combobox-content/combobox-content.ts +217 -0
- package/playground/showcase/src/app/components/combobox/combobox-empty/combobox-empty.css +0 -0
- package/playground/showcase/src/app/components/combobox/combobox-empty/combobox-empty.html +3 -0
- package/playground/showcase/src/app/components/combobox/combobox-empty/combobox-empty.spec.ts +56 -0
- package/playground/showcase/src/app/components/combobox/combobox-empty/combobox-empty.ts +11 -0
- package/playground/showcase/src/app/components/combobox/combobox-group/combobox-group.css +0 -0
- package/playground/showcase/src/app/components/combobox/combobox-group/combobox-group.html +11 -0
- package/playground/showcase/src/app/components/combobox/combobox-group/combobox-group.spec.ts +57 -0
- package/playground/showcase/src/app/components/combobox/combobox-group/combobox-group.ts +11 -0
- package/playground/showcase/src/app/components/combobox/combobox-input/combobox-input.css +0 -0
- package/playground/showcase/src/app/components/combobox/combobox-input/combobox-input.html +71 -0
- package/playground/showcase/src/app/components/combobox/combobox-input/combobox-input.spec.ts +468 -0
- package/playground/showcase/src/app/components/combobox/combobox-input/combobox-input.ts +90 -0
- package/playground/showcase/src/app/components/combobox/combobox-item/combobox-item.css +0 -0
- package/playground/showcase/src/app/components/combobox/combobox-item/combobox-item.html +58 -0
- package/playground/showcase/src/app/components/combobox/combobox-item/combobox-item.spec.ts +173 -0
- package/playground/showcase/src/app/components/combobox/combobox-item/combobox-item.ts +37 -0
- package/playground/showcase/src/app/components/combobox/combobox-search/combobox-search.css +0 -0
- package/playground/showcase/src/app/components/combobox/combobox-search/combobox-search.html +11 -0
- package/playground/showcase/src/app/components/combobox/combobox-search/combobox-search.spec.ts +166 -0
- package/playground/showcase/src/app/components/combobox/combobox-search/combobox-search.ts +36 -0
- package/playground/showcase/src/app/components/combobox/combobox-trigger/combobox-trigger.css +0 -0
- package/playground/showcase/src/app/components/combobox/combobox-trigger/combobox-trigger.html +8 -0
- package/playground/showcase/src/app/components/combobox/combobox-trigger/combobox-trigger.spec.ts +137 -0
- package/playground/showcase/src/app/components/combobox/combobox-trigger/combobox-trigger.ts +30 -0
- package/playground/showcase/src/app/components/combobox/combobox.css +0 -0
- package/playground/showcase/src/app/components/combobox/combobox.html +3 -0
- package/playground/showcase/src/app/components/combobox/combobox.spec.ts +391 -0
- package/playground/showcase/src/app/components/combobox/combobox.ts +59 -0
- package/playground/showcase/src/app/components/combobox/lib/models/combobox.model.ts +13 -0
- package/playground/showcase/src/app/components/combobox/lib/service/combobox.service.spec.ts +530 -0
- package/playground/showcase/src/app/components/combobox/lib/service/combobox.service.ts +191 -0
- package/playground/showcase/src/app/components/combobox/lib/types/combobox-position.type.ts +1 -0
- package/playground/showcase/src/app/components/combobox/lib/types/combobox-trigger-mode.type.ts +1 -0
- package/playground/showcase/src/app/core/services/seo.service.ts +100 -0
- package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.component.css +0 -0
- package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.component.html +383 -0
- package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.component.spec.ts +23 -0
- package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.component.ts +333 -0
- package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.examples.ts +226 -0
- package/playground/showcase/src/app/pages/documentation/components/components.routes.ts +4 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
import { ComponentRef } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
import { Combobox } from './combobox';
|
|
5
|
+
import { ComboboxService } from './lib/service/combobox.service';
|
|
6
|
+
import { ComboboxInterface } from './lib/models/combobox.model';
|
|
7
|
+
|
|
8
|
+
describe('Combobox', () => {
|
|
9
|
+
let component: Combobox;
|
|
10
|
+
let fixture: ComponentFixture<Combobox>;
|
|
11
|
+
let componentRef: ComponentRef<Combobox>;
|
|
12
|
+
let service: ComboboxService;
|
|
13
|
+
|
|
14
|
+
const mockData: ComboboxInterface[] = [
|
|
15
|
+
{ value: 1, label: 'Apple', description: 'A red fruit' },
|
|
16
|
+
{ value: 2, label: 'Banana', description: 'A yellow fruit' },
|
|
17
|
+
{ value: 3, label: 'Orange', description: 'A citrus fruit' }
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const mockGroupedData: ComboboxInterface[] = [
|
|
21
|
+
{ value: 1, label: 'JavaScript', group: 'Frontend' },
|
|
22
|
+
{ value: 2, label: 'TypeScript', group: 'Frontend' },
|
|
23
|
+
{ value: 3, label: 'Python', group: 'Backend' }
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
beforeEach(async () => {
|
|
27
|
+
await TestBed.configureTestingModule({
|
|
28
|
+
imports: [Combobox]
|
|
29
|
+
})
|
|
30
|
+
.compileComponents();
|
|
31
|
+
|
|
32
|
+
fixture = TestBed.createComponent(Combobox);
|
|
33
|
+
component = fixture.componentInstance;
|
|
34
|
+
componentRef = fixture.componentRef;
|
|
35
|
+
service = component.comboboxService;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should create', () => {
|
|
39
|
+
expect(component).toBeTruthy();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should inject ComboboxService', () => {
|
|
43
|
+
expect(service).toBeTruthy();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('Input: data', () => {
|
|
47
|
+
it('should initialize with empty data', () => {
|
|
48
|
+
fixture.detectChanges();
|
|
49
|
+
expect(service.data()).toEqual([]);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should set data through input', () => {
|
|
53
|
+
componentRef.setInput('data', mockData);
|
|
54
|
+
fixture.detectChanges();
|
|
55
|
+
|
|
56
|
+
expect(service.data()).toEqual(mockData);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should update service when data input changes', () => {
|
|
60
|
+
componentRef.setInput('data', mockData);
|
|
61
|
+
fixture.detectChanges();
|
|
62
|
+
expect(service.data().length).toBe(3);
|
|
63
|
+
|
|
64
|
+
const newData = [{ value: 4, label: 'Mango' }];
|
|
65
|
+
componentRef.setInput('data', newData);
|
|
66
|
+
fixture.detectChanges();
|
|
67
|
+
|
|
68
|
+
expect(service.data()).toEqual(newData);
|
|
69
|
+
expect(service.data().length).toBe(1);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should not set empty data array', () => {
|
|
73
|
+
componentRef.setInput('data', []);
|
|
74
|
+
fixture.detectChanges();
|
|
75
|
+
|
|
76
|
+
// Service should still be empty
|
|
77
|
+
expect(service.data()).toEqual([]);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('Input: multiSelect', () => {
|
|
82
|
+
it('should initialize with single-select mode', () => {
|
|
83
|
+
fixture.detectChanges();
|
|
84
|
+
expect(service.multiSelect()).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should enable multi-select mode', () => {
|
|
88
|
+
componentRef.setInput('multiSelect', true);
|
|
89
|
+
fixture.detectChanges();
|
|
90
|
+
|
|
91
|
+
expect(service.multiSelect()).toBe(true);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should disable multi-select mode', () => {
|
|
95
|
+
componentRef.setInput('multiSelect', true);
|
|
96
|
+
fixture.detectChanges();
|
|
97
|
+
expect(service.multiSelect()).toBe(true);
|
|
98
|
+
|
|
99
|
+
componentRef.setInput('multiSelect', false);
|
|
100
|
+
fixture.detectChanges();
|
|
101
|
+
expect(service.multiSelect()).toBe(false);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should keep only first item when switching from multi to single', () => {
|
|
105
|
+
componentRef.setInput('data', mockData);
|
|
106
|
+
componentRef.setInput('multiSelect', true);
|
|
107
|
+
fixture.detectChanges();
|
|
108
|
+
|
|
109
|
+
service.selectItem(1);
|
|
110
|
+
service.selectItem(2);
|
|
111
|
+
service.selectItem(3);
|
|
112
|
+
expect(service.selectedValues().length).toBe(3);
|
|
113
|
+
|
|
114
|
+
componentRef.setInput('multiSelect', false);
|
|
115
|
+
fixture.detectChanges();
|
|
116
|
+
|
|
117
|
+
expect(service.selectedValues()).toEqual([1]);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe('Input: triggerMode', () => {
|
|
122
|
+
it('should initialize with input trigger mode', () => {
|
|
123
|
+
fixture.detectChanges();
|
|
124
|
+
expect(service.triggerMode()).toBe('input');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should set custom trigger mode', () => {
|
|
128
|
+
componentRef.setInput('triggerMode', 'custom');
|
|
129
|
+
fixture.detectChanges();
|
|
130
|
+
|
|
131
|
+
expect(service.triggerMode()).toBe('custom');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should switch between trigger modes', () => {
|
|
135
|
+
componentRef.setInput('triggerMode', 'custom');
|
|
136
|
+
fixture.detectChanges();
|
|
137
|
+
expect(service.triggerMode()).toBe('custom');
|
|
138
|
+
|
|
139
|
+
componentRef.setInput('triggerMode', 'input');
|
|
140
|
+
fixture.detectChanges();
|
|
141
|
+
expect(service.triggerMode()).toBe('input');
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe('Input: groupBy', () => {
|
|
146
|
+
beforeEach(() => {
|
|
147
|
+
componentRef.setInput('data', mockGroupedData);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should initialize without grouping', () => {
|
|
151
|
+
fixture.detectChanges();
|
|
152
|
+
expect(service.groupBy()).toBe(null);
|
|
153
|
+
expect(service.groupedData()).toBe(null);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should group data by property', () => {
|
|
157
|
+
componentRef.setInput('groupBy', 'group');
|
|
158
|
+
fixture.detectChanges();
|
|
159
|
+
|
|
160
|
+
expect(service.groupBy()).toBe('group');
|
|
161
|
+
expect(service.groupedData()).not.toBe(null);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should not set null groupBy if not provided', () => {
|
|
165
|
+
// Ensure null groupBy doesn't trigger setGroupBy unnecessarily
|
|
166
|
+
componentRef.setInput('groupBy', null);
|
|
167
|
+
fixture.detectChanges();
|
|
168
|
+
|
|
169
|
+
expect(service.groupBy()).toBe(null);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should update grouping when property changes', () => {
|
|
173
|
+
const mixedData = mockGroupedData.map(item => ({ ...item, category: item.group }));
|
|
174
|
+
componentRef.setInput('data', mixedData);
|
|
175
|
+
componentRef.setInput('groupBy', 'group');
|
|
176
|
+
fixture.detectChanges();
|
|
177
|
+
|
|
178
|
+
expect(service.groupBy()).toBe('group');
|
|
179
|
+
|
|
180
|
+
componentRef.setInput('groupBy', 'category');
|
|
181
|
+
fixture.detectChanges();
|
|
182
|
+
|
|
183
|
+
expect(service.groupBy()).toBe('category');
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe('Input: placeholder', () => {
|
|
188
|
+
it('should initialize with default placeholder', () => {
|
|
189
|
+
fixture.detectChanges();
|
|
190
|
+
expect(service.placeholder()).toBe('Search...');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should set custom placeholder', () => {
|
|
194
|
+
componentRef.setInput('placeholder', 'Select a fruit...');
|
|
195
|
+
fixture.detectChanges();
|
|
196
|
+
|
|
197
|
+
expect(service.placeholder()).toBe('Select a fruit...');
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should update placeholder dynamically', () => {
|
|
201
|
+
componentRef.setInput('placeholder', 'First');
|
|
202
|
+
fixture.detectChanges();
|
|
203
|
+
expect(service.placeholder()).toBe('First');
|
|
204
|
+
|
|
205
|
+
componentRef.setInput('placeholder', 'Second');
|
|
206
|
+
fixture.detectChanges();
|
|
207
|
+
expect(service.placeholder()).toBe('Second');
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
describe('Input: closeOnSelect', () => {
|
|
212
|
+
it('should initialize with closeOnSelect enabled', () => {
|
|
213
|
+
fixture.detectChanges();
|
|
214
|
+
expect(service.closeOnSelect()).toBe(true);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('should disable closeOnSelect', () => {
|
|
218
|
+
componentRef.setInput('closeOnSelect', false);
|
|
219
|
+
fixture.detectChanges();
|
|
220
|
+
|
|
221
|
+
expect(service.closeOnSelect()).toBe(false);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('should keep dropdown open when closeOnSelect is false', () => {
|
|
225
|
+
componentRef.setInput('data', mockData);
|
|
226
|
+
componentRef.setInput('closeOnSelect', false);
|
|
227
|
+
fixture.detectChanges();
|
|
228
|
+
|
|
229
|
+
service.open();
|
|
230
|
+
service.selectItem(1);
|
|
231
|
+
|
|
232
|
+
expect(service.isOpen()).toBe(true);
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
describe('Input: disabled', () => {
|
|
237
|
+
it('should initialize as not disabled', () => {
|
|
238
|
+
fixture.detectChanges();
|
|
239
|
+
expect(service.disabled()).toBe(false);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('should disable combobox', () => {
|
|
243
|
+
componentRef.setInput('disabled', true);
|
|
244
|
+
fixture.detectChanges();
|
|
245
|
+
|
|
246
|
+
expect(service.disabled()).toBe(true);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('should enable combobox', () => {
|
|
250
|
+
componentRef.setInput('disabled', true);
|
|
251
|
+
fixture.detectChanges();
|
|
252
|
+
|
|
253
|
+
componentRef.setInput('disabled', false);
|
|
254
|
+
fixture.detectChanges();
|
|
255
|
+
|
|
256
|
+
expect(service.disabled()).toBe(false);
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
describe('Output: selectionChange', () => {
|
|
261
|
+
it('should emit when selection changes', (done) => {
|
|
262
|
+
componentRef.setInput('data', mockData);
|
|
263
|
+
fixture.detectChanges();
|
|
264
|
+
|
|
265
|
+
component.selectionChange.subscribe((items: ComboboxInterface[]) => {
|
|
266
|
+
expect(items.length).toBe(1);
|
|
267
|
+
expect(items[0].value).toBe(1);
|
|
268
|
+
done();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
service.selectItem(1);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('should emit empty array when cleared', (done) => {
|
|
275
|
+
componentRef.setInput('data', mockData);
|
|
276
|
+
fixture.detectChanges();
|
|
277
|
+
|
|
278
|
+
service.selectItem(1);
|
|
279
|
+
|
|
280
|
+
component.selectionChange.subscribe((items: ComboboxInterface[]) => {
|
|
281
|
+
expect(items).toEqual([]);
|
|
282
|
+
done();
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
service.clearSelection();
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it('should emit multiple items in multi-select mode', (done) => {
|
|
289
|
+
componentRef.setInput('data', mockData);
|
|
290
|
+
componentRef.setInput('multiSelect', true);
|
|
291
|
+
fixture.detectChanges();
|
|
292
|
+
|
|
293
|
+
service.selectItem(1);
|
|
294
|
+
service.selectItem(2);
|
|
295
|
+
|
|
296
|
+
component.selectionChange.subscribe((items: ComboboxInterface[]) => {
|
|
297
|
+
if (items.length === 3) {
|
|
298
|
+
expect(items[0].value).toBe(1);
|
|
299
|
+
expect(items[1].value).toBe(2);
|
|
300
|
+
expect(items[2].value).toBe(3);
|
|
301
|
+
done();
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
service.selectItem(3);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('should emit updated selection when item is deselected', (done) => {
|
|
309
|
+
componentRef.setInput('data', mockData);
|
|
310
|
+
componentRef.setInput('multiSelect', true);
|
|
311
|
+
fixture.detectChanges();
|
|
312
|
+
|
|
313
|
+
service.selectItem(1);
|
|
314
|
+
service.selectItem(2);
|
|
315
|
+
|
|
316
|
+
component.selectionChange.subscribe((items: ComboboxInterface[]) => {
|
|
317
|
+
if (items.length === 1 && items[0].value === 1) {
|
|
318
|
+
done();
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
service.deselectItem(2);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
describe('Integration Tests', () => {
|
|
327
|
+
it('should sync all inputs to service on initialization', () => {
|
|
328
|
+
componentRef.setInput('data', mockData);
|
|
329
|
+
componentRef.setInput('multiSelect', true);
|
|
330
|
+
componentRef.setInput('triggerMode', 'custom');
|
|
331
|
+
componentRef.setInput('groupBy', 'group');
|
|
332
|
+
componentRef.setInput('placeholder', 'Custom placeholder');
|
|
333
|
+
componentRef.setInput('closeOnSelect', false);
|
|
334
|
+
componentRef.setInput('disabled', true);
|
|
335
|
+
fixture.detectChanges();
|
|
336
|
+
|
|
337
|
+
expect(service.data()).toEqual(mockData);
|
|
338
|
+
expect(service.multiSelect()).toBe(true);
|
|
339
|
+
expect(service.triggerMode()).toBe('custom');
|
|
340
|
+
expect(service.groupBy()).toBe('group');
|
|
341
|
+
expect(service.placeholder()).toBe('Custom placeholder');
|
|
342
|
+
expect(service.closeOnSelect()).toBe(false);
|
|
343
|
+
expect(service.disabled()).toBe(true);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('should handle input changes reactively', () => {
|
|
347
|
+
componentRef.setInput('data', mockData);
|
|
348
|
+
fixture.detectChanges();
|
|
349
|
+
|
|
350
|
+
expect(service.data().length).toBe(3);
|
|
351
|
+
|
|
352
|
+
const newData = [{ value: 4, label: 'New' }];
|
|
353
|
+
componentRef.setInput('data', newData);
|
|
354
|
+
fixture.detectChanges();
|
|
355
|
+
|
|
356
|
+
expect(service.data().length).toBe(1);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it('should complete selection workflow with inputs', (done) => {
|
|
360
|
+
componentRef.setInput('data', mockData);
|
|
361
|
+
componentRef.setInput('placeholder', 'Pick a fruit');
|
|
362
|
+
fixture.detectChanges();
|
|
363
|
+
|
|
364
|
+
component.selectionChange.subscribe((items: ComboboxInterface[]) => {
|
|
365
|
+
if (items.length === 1) {
|
|
366
|
+
expect(items[0].label).toBe('Apple');
|
|
367
|
+
expect(service.placeholder()).toBe('Pick a fruit');
|
|
368
|
+
done();
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
service.open();
|
|
373
|
+
service.selectItem(1);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it('should handle multi-select workflow with closeOnSelect', () => {
|
|
377
|
+
componentRef.setInput('data', mockData);
|
|
378
|
+
componentRef.setInput('multiSelect', true);
|
|
379
|
+
componentRef.setInput('closeOnSelect', false);
|
|
380
|
+
fixture.detectChanges();
|
|
381
|
+
|
|
382
|
+
service.open();
|
|
383
|
+
service.selectItem(1);
|
|
384
|
+
expect(service.isOpen()).toBe(true);
|
|
385
|
+
|
|
386
|
+
service.selectItem(2);
|
|
387
|
+
expect(service.isOpen()).toBe(true);
|
|
388
|
+
expect(service.selectedValues().length).toBe(2);
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Component, effect, inject, input, output } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
import { ComboboxService } from './lib/service/combobox.service';
|
|
4
|
+
import { ComboboxInterface } from './lib/models/combobox.model';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'wally-combobox',
|
|
8
|
+
imports: [],
|
|
9
|
+
providers: [ComboboxService],
|
|
10
|
+
templateUrl: './combobox.html',
|
|
11
|
+
styleUrl: './combobox.css'
|
|
12
|
+
})
|
|
13
|
+
export class Combobox {
|
|
14
|
+
comboboxService = inject(ComboboxService);
|
|
15
|
+
|
|
16
|
+
// Inputs para dados
|
|
17
|
+
data = input<ComboboxInterface[]>([]);
|
|
18
|
+
|
|
19
|
+
// Inputs para configuração
|
|
20
|
+
multiSelect = input<boolean>(false);
|
|
21
|
+
triggerMode = input<'input' | 'custom'>('input');
|
|
22
|
+
groupBy = input<string | null>(null);
|
|
23
|
+
placeholder = input<string>('Search...');
|
|
24
|
+
closeOnSelect = input<boolean>(true);
|
|
25
|
+
disabled = input<boolean>(false);
|
|
26
|
+
|
|
27
|
+
// Output para emitir mudanças de seleção
|
|
28
|
+
selectionChange = output<ComboboxInterface[]>();
|
|
29
|
+
|
|
30
|
+
constructor() {
|
|
31
|
+
// Effect para sincronizar inputs com serviço
|
|
32
|
+
effect(() => {
|
|
33
|
+
// Sincronizar dados
|
|
34
|
+
const dataValue = this.data();
|
|
35
|
+
if (dataValue.length > 0) {
|
|
36
|
+
this.comboboxService.setData(dataValue);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Sincronizar configurações
|
|
40
|
+
this.comboboxService.setMultiSelect(this.multiSelect());
|
|
41
|
+
this.comboboxService.setTriggerMode(this.triggerMode());
|
|
42
|
+
|
|
43
|
+
const groupByValue = this.groupBy();
|
|
44
|
+
if (groupByValue) {
|
|
45
|
+
this.comboboxService.setGroupBy(groupByValue);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
this.comboboxService.placeholder.set(this.placeholder());
|
|
49
|
+
this.comboboxService.closeOnSelect.set(this.closeOnSelect());
|
|
50
|
+
this.comboboxService.disabled.set(this.disabled());
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Effect para emitir mudanças de seleção
|
|
54
|
+
effect(() => {
|
|
55
|
+
const selected = this.comboboxService.selectedItems();
|
|
56
|
+
this.selectionChange.emit(selected);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ComboboxInterface {
|
|
2
|
+
value: string | number;
|
|
3
|
+
label: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
group?: string;
|
|
7
|
+
metadata?: Record<string, any>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ComboboxGroup {
|
|
11
|
+
label: string;
|
|
12
|
+
items: ComboboxInterface[];
|
|
13
|
+
}
|