@cqa-lib/cqa-ui 0.0.1

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,953 @@
1
+ import * as i0 from '@angular/core';
2
+ import { EventEmitter, Component, HostBinding, Input, Output, HostListener, ViewChildren, ViewChild, ChangeDetectionStrategy, NgModule, InjectionToken, Injector, Injectable } from '@angular/core';
3
+ import * as i2 from '@angular/common';
4
+ import { CommonModule } from '@angular/common';
5
+ import * as i2$1 from '@angular/forms';
6
+ import { FormsModule } from '@angular/forms';
7
+ import * as i1 from '@angular/material/icon';
8
+ import { MatIconModule } from '@angular/material/icon';
9
+ import * as i1$1 from '@angular/cdk/overlay';
10
+ import { OverlayModule, OverlayConfig } from '@angular/cdk/overlay';
11
+ import * as i3 from '@angular/cdk/portal';
12
+ import { TemplatePortal, CdkPortalOutlet, PortalModule, ComponentPortal } from '@angular/cdk/portal';
13
+ import { filter } from 'rxjs/operators';
14
+ import { Subject } from 'rxjs';
15
+
16
+ class ButtonComponent {
17
+ constructor() {
18
+ this.id = 'cqa-ui-root';
19
+ this.display = 'contents';
20
+ this.variant = 'filled';
21
+ this.disabled = false;
22
+ this.iconPosition = 'start';
23
+ this.type = 'button';
24
+ this.clicked = new EventEmitter();
25
+ // Internal state tracking
26
+ this.isHovered = false;
27
+ this.isFocused = false;
28
+ this.isPressed = false;
29
+ }
30
+ get hasIcon() {
31
+ return !!this.icon;
32
+ }
33
+ get buttonClasses() {
34
+ const baseClasses = [
35
+ 'flex',
36
+ 'flex-col',
37
+ 'justify-center',
38
+ 'items-center',
39
+ 'p-0',
40
+ 'gap-2',
41
+ 'rounded-lg',
42
+ 'cursor-pointer',
43
+ 'font-inter',
44
+ 'font-semibold',
45
+ 'text-sm',
46
+ 'leading-[14px]',
47
+ 'transition-all',
48
+ 'duration-200',
49
+ 'outline-none'
50
+ ];
51
+ if (this.disabled) {
52
+ baseClasses.push('cursor-not-allowed');
53
+ }
54
+ // Add variant and state specific classes
55
+ const variantClasses = this.getVariantClasses();
56
+ return [...baseClasses, ...variantClasses].join(' ');
57
+ }
58
+ get stateLayerClasses() {
59
+ const classes = [
60
+ 'flex',
61
+ 'flex-row',
62
+ 'justify-center',
63
+ 'items-center',
64
+ 'gap-2',
65
+ 'w-full',
66
+ 'h-full',
67
+ 'py-[10px]',
68
+ 'px-6',
69
+ ];
70
+ return classes.join(' ');
71
+ }
72
+ get labelClasses() {
73
+ const classes = [
74
+ 'flex',
75
+ 'items-center',
76
+ 'text-center',
77
+ 'font-inter',
78
+ 'font-semibold',
79
+ 'text-sm',
80
+ 'leading-[14px]',
81
+ 'flex-none',
82
+ this.textClass,
83
+ ];
84
+ if (this.disabled) {
85
+ classes.push('opacity-[0.38]');
86
+ }
87
+ return classes.join(' ');
88
+ }
89
+ get iconClasses() {
90
+ const classes = [
91
+ 'flex',
92
+ 'items-center',
93
+ 'justify-center',
94
+ 'w-[14px]',
95
+ 'h-[14px]',
96
+ 'shrink-0',
97
+ 'flex-none'
98
+ ];
99
+ if (this.disabled) {
100
+ classes.push('opacity-[0.38]');
101
+ }
102
+ return classes.join(' ');
103
+ }
104
+ getVariantClasses() {
105
+ const classes = [];
106
+ if (this.variant === 'filled') {
107
+ if (this.disabled) {
108
+ classes.push('bg-primary-muted');
109
+ }
110
+ else {
111
+ classes.push('bg-primary');
112
+ if (this.isHovered) {
113
+ classes.push('shadow-[0px_1px_2px_rgba(0,0,0,0.3),0px_1px_3px_1px_rgba(0,0,0,0.15)]');
114
+ }
115
+ }
116
+ }
117
+ else if (this.variant === 'outlined') {
118
+ if (this.disabled) {
119
+ classes.push('bg-transparent', 'border', 'border-primary-muted');
120
+ }
121
+ else {
122
+ if (this.isFocused) {
123
+ classes.push('bg-primary-surface-alt', 'border', 'border-primary-hover', 'shadow-[0px_4px_4px_rgba(0,0,0,0.25)]');
124
+ }
125
+ else if (this.isHovered || this.isPressed) {
126
+ classes.push('bg-primary-surface', 'border', 'border-primary');
127
+ }
128
+ else {
129
+ classes.push('bg-transparent', 'border', 'border-slate');
130
+ }
131
+ }
132
+ }
133
+ else if (this.variant === 'text') {
134
+ if (this.disabled) {
135
+ classes.push('bg-transparent');
136
+ }
137
+ else {
138
+ classes.push('bg-transparent');
139
+ if (this.isHovered || this.isFocused || this.isPressed) {
140
+ classes.push('bg-primary-surface');
141
+ }
142
+ }
143
+ }
144
+ else if (this.variant === 'elevated') {
145
+ if (this.disabled) {
146
+ classes.push('bg-primary-muted', 'shadow-none');
147
+ }
148
+ else {
149
+ if (this.isFocused) {
150
+ classes.push('bg-primary-surface-alt', 'shadow-[0px_4px_4px_rgba(0,0,0,0.25)]');
151
+ }
152
+ else if (this.isPressed) {
153
+ classes.push('bg-primary-surface', 'shadow-[0px_1px_2px_rgba(0,0,0,0.3),0px_1px_3px_1px_rgba(0,0,0,0.15)]');
154
+ }
155
+ else if (this.isHovered) {
156
+ classes.push('bg-primary-surface-alt', 'shadow-[0px_1px_2px_rgba(0,0,0,0.3),0px_2px_6px_2px_rgba(0,0,0,0.15)]');
157
+ }
158
+ else {
159
+ classes.push('bg-primary-surface', 'shadow-[0px_1px_2px_rgba(0,0,0,0.3),0px_1px_3px_1px_rgba(0,0,0,0.15)]');
160
+ }
161
+ }
162
+ }
163
+ else if (this.variant === 'tonal') {
164
+ if (this.disabled) {
165
+ classes.push('bg-primary-muted');
166
+ }
167
+ else {
168
+ if (this.isHovered) {
169
+ classes.push('bg-tonal-hover', 'shadow-[0px_1px_2px_rgba(0,0,0,0.3),0px_1px_3px_1px_rgba(0,0,0,0.15)]');
170
+ }
171
+ else {
172
+ classes.push('bg-primary-surface-alt');
173
+ }
174
+ }
175
+ }
176
+ return classes;
177
+ }
178
+ get textClass() {
179
+ if (this.disabled) {
180
+ if (this.variant === 'outlined' || this.variant === 'text') {
181
+ return 'text-ink';
182
+ }
183
+ return 'text-ink-muted';
184
+ }
185
+ switch (this.variant) {
186
+ case 'filled':
187
+ return 'text-surface-default';
188
+ case 'outlined':
189
+ if (this.isFocused || this.isHovered || this.isPressed) {
190
+ return 'text-primary-hover';
191
+ }
192
+ return 'text-slate';
193
+ case 'text':
194
+ case 'elevated':
195
+ return 'text-primary-hover';
196
+ case 'tonal':
197
+ return 'text-ink';
198
+ default:
199
+ return '';
200
+ }
201
+ }
202
+ onMouseEnter() {
203
+ if (!this.disabled) {
204
+ this.isHovered = true;
205
+ }
206
+ }
207
+ onMouseLeave() {
208
+ this.isHovered = false;
209
+ this.isPressed = false;
210
+ }
211
+ onMouseDown() {
212
+ if (!this.disabled) {
213
+ this.isPressed = true;
214
+ }
215
+ }
216
+ onMouseUp() {
217
+ this.isPressed = false;
218
+ }
219
+ onFocus() {
220
+ if (!this.disabled) {
221
+ this.isFocused = true;
222
+ }
223
+ }
224
+ onBlur() {
225
+ this.isFocused = false;
226
+ this.isPressed = false;
227
+ }
228
+ onClick(event) {
229
+ if (!this.disabled) {
230
+ this.clicked.emit(event);
231
+ }
232
+ }
233
+ }
234
+ ButtonComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
235
+ ButtonComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ButtonComponent, selector: "cqa-button", inputs: { variant: "variant", disabled: "disabled", icon: "icon", iconPosition: "iconPosition", type: "type" }, outputs: { clicked: "clicked" }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "mousedown": "onMouseDown()", "mouseup": "onMouseUp()", "focus": "onFocus()", "blur": "onBlur()" }, properties: { "attr.id": "this.id", "style.display": "this.display" } }, ngImport: i0, template: "<button\n [type]=\"type\"\n [disabled]=\"disabled\"\n [attr.aria-disabled]=\"disabled\"\n [class]=\"buttonClasses\"\n (click)=\"onClick($event)\"\n>\n <span [class]=\"stateLayerClasses\">\n <span *ngIf=\"icon && iconPosition === 'start'\" [class]=\"iconClasses\" [ngClass]=\"textClass\">\n <mat-icon class=\"text-[18px] leading-[18px] w-[18px] h-[18px]\">\n {{ icon }}\n </mat-icon>\n </span>\n <span [class]=\"labelClasses\" [ngClass]=\"textClass\">\n <ng-content></ng-content>\n </span>\n <span *ngIf=\"icon && iconPosition === 'end'\" [class]=\"iconClasses\" [ngClass]=\"textClass\">\n <mat-icon class=\"text-[18px] leading-[18px] w-[18px] h-[18px]\">\n {{ icon }}\n </mat-icon>\n </span>\n </span>\n</button>\n\n", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
236
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ButtonComponent, decorators: [{
237
+ type: Component,
238
+ args: [{ selector: 'cqa-button', template: "<button\n [type]=\"type\"\n [disabled]=\"disabled\"\n [attr.aria-disabled]=\"disabled\"\n [class]=\"buttonClasses\"\n (click)=\"onClick($event)\"\n>\n <span [class]=\"stateLayerClasses\">\n <span *ngIf=\"icon && iconPosition === 'start'\" [class]=\"iconClasses\" [ngClass]=\"textClass\">\n <mat-icon class=\"text-[18px] leading-[18px] w-[18px] h-[18px]\">\n {{ icon }}\n </mat-icon>\n </span>\n <span [class]=\"labelClasses\" [ngClass]=\"textClass\">\n <ng-content></ng-content>\n </span>\n <span *ngIf=\"icon && iconPosition === 'end'\" [class]=\"iconClasses\" [ngClass]=\"textClass\">\n <mat-icon class=\"text-[18px] leading-[18px] w-[18px] h-[18px]\">\n {{ icon }}\n </mat-icon>\n </span>\n </span>\n</button>\n\n", styles: [] }]
239
+ }], propDecorators: { id: [{
240
+ type: HostBinding,
241
+ args: ['attr.id']
242
+ }], display: [{
243
+ type: HostBinding,
244
+ args: ['style.display']
245
+ }], variant: [{
246
+ type: Input
247
+ }], disabled: [{
248
+ type: Input
249
+ }], icon: [{
250
+ type: Input
251
+ }], iconPosition: [{
252
+ type: Input
253
+ }], type: [{
254
+ type: Input
255
+ }], clicked: [{
256
+ type: Output
257
+ }], onMouseEnter: [{
258
+ type: HostListener,
259
+ args: ['mouseenter']
260
+ }], onMouseLeave: [{
261
+ type: HostListener,
262
+ args: ['mouseleave']
263
+ }], onMouseDown: [{
264
+ type: HostListener,
265
+ args: ['mousedown']
266
+ }], onMouseUp: [{
267
+ type: HostListener,
268
+ args: ['mouseup']
269
+ }], onFocus: [{
270
+ type: HostListener,
271
+ args: ['focus']
272
+ }], onBlur: [{
273
+ type: HostListener,
274
+ args: ['blur']
275
+ }] } });
276
+
277
+ class SearchBarComponent {
278
+ constructor() {
279
+ this.id = 'cqa-ui-root';
280
+ /** Placeholder text for the input */
281
+ this.placeholder = 'Search';
282
+ /** Initial value or externally controlled value */
283
+ this.value = '';
284
+ /** Disable interactions */
285
+ this.disabled = false;
286
+ /** Whether the clear button should be visible when there is text */
287
+ this.showClear = true;
288
+ /** Accessible label for the input */
289
+ this.ariaLabel = 'Search';
290
+ /** Automatically focus the input when rendered */
291
+ this.autoFocus = false;
292
+ /** Search bar size */
293
+ this.size = 'md';
294
+ /** Stretch to fill container width */
295
+ this.fullWidth = false;
296
+ /** Emit on value changes (e.g. for two-way binding) */
297
+ this.valueChange = new EventEmitter();
298
+ /** Emit when user submits search (Enter key or form submit) */
299
+ this.search = new EventEmitter();
300
+ /** Emit when the value is cleared via the clear button */
301
+ this.cleared = new EventEmitter();
302
+ this.inputValue = '';
303
+ this.widthClasses = {
304
+ sm: 'w-[295px]',
305
+ md: 'w-[395px]',
306
+ lg: 'w-[495px]',
307
+ };
308
+ }
309
+ get displayStyle() {
310
+ return this.fullWidth ? 'block' : 'inline-block';
311
+ }
312
+ get widthStyle() {
313
+ return this.fullWidth ? '100%' : 'auto';
314
+ }
315
+ ngOnChanges(changes) {
316
+ if (changes['value'] && changes['value'].currentValue !== undefined) {
317
+ const newValue = changes['value'].currentValue ?? '';
318
+ if (newValue !== this.inputValue) {
319
+ this.inputValue = newValue;
320
+ }
321
+ }
322
+ }
323
+ onInput(event) {
324
+ const target = event.target;
325
+ const nextValue = target?.value ?? '';
326
+ this.inputValue = nextValue;
327
+ this.valueChange.emit(this.inputValue);
328
+ }
329
+ onSubmit(event) {
330
+ event.preventDefault();
331
+ if (this.disabled) {
332
+ return;
333
+ }
334
+ this.search.emit(this.inputValue.trim());
335
+ }
336
+ clear() {
337
+ if (this.disabled || this.inputValue === '') {
338
+ return;
339
+ }
340
+ this.inputValue = '';
341
+ this.valueChange.emit('');
342
+ this.cleared.emit();
343
+ }
344
+ }
345
+ SearchBarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SearchBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
346
+ SearchBarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: SearchBarComponent, selector: "cqa-search-bar", inputs: { placeholder: "placeholder", value: "value", disabled: "disabled", showClear: "showClear", ariaLabel: "ariaLabel", autoFocus: "autoFocus", size: "size", fullWidth: "fullWidth" }, outputs: { valueChange: "valueChange", search: "search", cleared: "cleared" }, host: { properties: { "attr.id": "this.id", "style.display": "this.displayStyle", "style.width": "this.widthStyle" } }, usesOnChanges: true, ngImport: i0, template: "<form\n class=\"inline-flex items-center gap-2 px-6 py-3 text-[14px] border border-gray-200 rounded-md bg-white shadow-sm transition-colors\"\n [ngClass]=\"fullWidth ? 'w-full' : widthClasses[size]\"\n (submit)=\"onSubmit($event)\"\n>\n <span\n class=\"flex-none flex items-center justify-center text-gray-400 w-4 h-4\"\n [ngClass]=\"{ 'opacity-[0.38]': disabled }\"\n >\n <mat-icon\n class=\"flex items-center justify-center leading-none p-0\"\n [style.width.px]=\"16\"\n [style.height.px]=\"16\"\n [style.fontSize.px]=\"16\"\n >\n search\n </mat-icon>\n </span>\n\n <input\n type=\"text\"\n class=\"flex-1 min-w-[180px] border-none outline-none bg-transparent placeholder:text-gray-400 disabled:text-gray-400 disabled:cursor-not-allowed font-['SF_Pro_Text'] font-normal text-[12.3px] leading-none tracking-normal align-middle text-[#99999E]\"\n style=\"font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; letter-spacing: 0;\"\n [placeholder]=\"placeholder\"\n [value]=\"inputValue\"\n (input)=\"onInput($event)\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"ariaLabel\"\n autocomplete=\"off\"\n autocapitalize=\"none\"\n spellcheck=\"false\"\n [attr.autofocus]=\"autoFocus ? '' : null\"\n />\n\n <button\n *ngIf=\"showClear && inputValue\"\n type=\"button\"\n class=\"flex items-center justify-center p-0 w-4 h-4 border-0 bg-transparent cursor-pointer text-gray-500 hover:text-gray-700 disabled:text-gray-300 transition-colors leading-none\"\n (click)=\"clear()\"\n [disabled]=\"disabled\"\n aria-label=\"Clear search\"\n >\n <mat-icon\n class=\"flex items-center justify-center leading-none p-0\"\n [style.width.px]=\"16\"\n [style.height.px]=\"16\"\n [style.fontSize.px]=\"16\"\n [ngClass]=\"{ 'opacity-[0.38]': disabled }\"\n >\n close\n </mat-icon>\n </button>\n</form>\n", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
347
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SearchBarComponent, decorators: [{
348
+ type: Component,
349
+ args: [{ selector: 'cqa-search-bar', template: "<form\n class=\"inline-flex items-center gap-2 px-6 py-3 text-[14px] border border-gray-200 rounded-md bg-white shadow-sm transition-colors\"\n [ngClass]=\"fullWidth ? 'w-full' : widthClasses[size]\"\n (submit)=\"onSubmit($event)\"\n>\n <span\n class=\"flex-none flex items-center justify-center text-gray-400 w-4 h-4\"\n [ngClass]=\"{ 'opacity-[0.38]': disabled }\"\n >\n <mat-icon\n class=\"flex items-center justify-center leading-none p-0\"\n [style.width.px]=\"16\"\n [style.height.px]=\"16\"\n [style.fontSize.px]=\"16\"\n >\n search\n </mat-icon>\n </span>\n\n <input\n type=\"text\"\n class=\"flex-1 min-w-[180px] border-none outline-none bg-transparent placeholder:text-gray-400 disabled:text-gray-400 disabled:cursor-not-allowed font-['SF_Pro_Text'] font-normal text-[12.3px] leading-none tracking-normal align-middle text-[#99999E]\"\n style=\"font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; letter-spacing: 0;\"\n [placeholder]=\"placeholder\"\n [value]=\"inputValue\"\n (input)=\"onInput($event)\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"ariaLabel\"\n autocomplete=\"off\"\n autocapitalize=\"none\"\n spellcheck=\"false\"\n [attr.autofocus]=\"autoFocus ? '' : null\"\n />\n\n <button\n *ngIf=\"showClear && inputValue\"\n type=\"button\"\n class=\"flex items-center justify-center p-0 w-4 h-4 border-0 bg-transparent cursor-pointer text-gray-500 hover:text-gray-700 disabled:text-gray-300 transition-colors leading-none\"\n (click)=\"clear()\"\n [disabled]=\"disabled\"\n aria-label=\"Clear search\"\n >\n <mat-icon\n class=\"flex items-center justify-center leading-none p-0\"\n [style.width.px]=\"16\"\n [style.height.px]=\"16\"\n [style.fontSize.px]=\"16\"\n [ngClass]=\"{ 'opacity-[0.38]': disabled }\"\n >\n close\n </mat-icon>\n </button>\n</form>\n", styles: [] }]
350
+ }], propDecorators: { id: [{
351
+ type: HostBinding,
352
+ args: ['attr.id']
353
+ }], displayStyle: [{
354
+ type: HostBinding,
355
+ args: ['style.display']
356
+ }], widthStyle: [{
357
+ type: HostBinding,
358
+ args: ['style.width']
359
+ }], placeholder: [{
360
+ type: Input
361
+ }], value: [{
362
+ type: Input
363
+ }], disabled: [{
364
+ type: Input
365
+ }], showClear: [{
366
+ type: Input
367
+ }], ariaLabel: [{
368
+ type: Input
369
+ }], autoFocus: [{
370
+ type: Input
371
+ }], size: [{
372
+ type: Input
373
+ }], fullWidth: [{
374
+ type: Input
375
+ }], valueChange: [{
376
+ type: Output
377
+ }], search: [{
378
+ type: Output
379
+ }], cleared: [{
380
+ type: Output
381
+ }] } });
382
+
383
+ class SegmentControlComponent {
384
+ constructor() {
385
+ this.id = 'cqa-ui-root';
386
+ this.display = 'inline-block';
387
+ this.segments = [
388
+ { label: 'Tab Group', value: 'tab-group-1' },
389
+ { label: 'Tab Group', value: 'tab-group-2' },
390
+ ];
391
+ this.disabled = false;
392
+ this.valueChange = new EventEmitter();
393
+ this.indicatorStyle = {};
394
+ this.indicatorVisible = false;
395
+ }
396
+ ngOnChanges(changes) {
397
+ if (changes['segments'] || changes['value']) {
398
+ this.ensureSelectedValue();
399
+ }
400
+ }
401
+ ngAfterViewInit() {
402
+ this.buttonChangesSub = this.segmentButtons.changes.subscribe(() => this.updateIndicator());
403
+ this.ensureSelectedValue();
404
+ this.updateIndicator();
405
+ }
406
+ ngOnDestroy() {
407
+ this.buttonChangesSub?.unsubscribe?.();
408
+ }
409
+ trackByValue(_index, option) {
410
+ return option.value;
411
+ }
412
+ isSelected(option) {
413
+ return option.value === this.value;
414
+ }
415
+ select(option, index) {
416
+ if (this.disabled || option.disabled) {
417
+ return;
418
+ }
419
+ const nextValue = option.value;
420
+ if (nextValue !== this.value) {
421
+ this.value = nextValue;
422
+ this.valueChange.emit(nextValue);
423
+ }
424
+ this.focusButton(index);
425
+ this.updateIndicator();
426
+ }
427
+ onKeyDown(event, currentIndex) {
428
+ if (this.disabled) {
429
+ return;
430
+ }
431
+ switch (event.key) {
432
+ case 'ArrowRight':
433
+ case 'ArrowDown':
434
+ event.preventDefault();
435
+ this.moveSelection(1, currentIndex);
436
+ break;
437
+ case 'ArrowLeft':
438
+ case 'ArrowUp':
439
+ event.preventDefault();
440
+ this.moveSelection(-1, currentIndex);
441
+ break;
442
+ case 'Home':
443
+ event.preventDefault();
444
+ this.selectFirstEnabled();
445
+ break;
446
+ case 'End':
447
+ event.preventDefault();
448
+ this.selectLastEnabled();
449
+ break;
450
+ case ' ':
451
+ case 'Enter':
452
+ event.preventDefault();
453
+ this.select(this.segments[currentIndex], currentIndex);
454
+ break;
455
+ default:
456
+ break;
457
+ }
458
+ }
459
+ moveSelection(step, startIndex) {
460
+ const enabledIndexes = this.getEnabledIndexes();
461
+ if (enabledIndexes.length === 0) {
462
+ return;
463
+ }
464
+ const currentEnabledIndex = enabledIndexes.indexOf(startIndex);
465
+ const fallbackIndex = this.getSelectedIndex(enabledIndexes);
466
+ const baseIndex = currentEnabledIndex >= 0 ? currentEnabledIndex : fallbackIndex;
467
+ const nextPosition = (baseIndex + step + enabledIndexes.length) % enabledIndexes.length;
468
+ const targetIndex = enabledIndexes[nextPosition];
469
+ this.select(this.segments[targetIndex], targetIndex);
470
+ }
471
+ selectFirstEnabled() {
472
+ const enabledIndexes = this.getEnabledIndexes();
473
+ if (enabledIndexes.length > 0) {
474
+ const index = enabledIndexes[0];
475
+ this.select(this.segments[index], index);
476
+ this.updateIndicator();
477
+ }
478
+ }
479
+ selectLastEnabled() {
480
+ const enabledIndexes = this.getEnabledIndexes();
481
+ if (enabledIndexes.length > 0) {
482
+ const index = enabledIndexes[enabledIndexes.length - 1];
483
+ this.select(this.segments[index], index);
484
+ this.updateIndicator();
485
+ }
486
+ }
487
+ getEnabledIndexes() {
488
+ return this.segments
489
+ .map((option, index) => ({ option, index }))
490
+ .filter(({ option }) => !option.disabled)
491
+ .map(({ index }) => index);
492
+ }
493
+ getSelectedIndex(enabledIndexes) {
494
+ const current = this.segments.findIndex((option) => option.value === this.value && !option.disabled);
495
+ if (current >= 0) {
496
+ return enabledIndexes.indexOf(current);
497
+ }
498
+ return 0;
499
+ }
500
+ ensureSelectedValue() {
501
+ const enabled = this.segments.filter((option) => !option.disabled);
502
+ if (enabled.length === 0) {
503
+ this.value = undefined;
504
+ return;
505
+ }
506
+ if (!this.value || !this.segments.some((option) => option.value === this.value)) {
507
+ this.value = enabled[0].value;
508
+ this.valueChange.emit(this.value);
509
+ const index = this.segments.indexOf(enabled[0]);
510
+ this.focusButton(index);
511
+ this.updateIndicator(index);
512
+ return;
513
+ }
514
+ const selected = this.segments.find((option) => option.value === this.value);
515
+ if (selected?.disabled) {
516
+ this.value = enabled[0].value;
517
+ this.valueChange.emit(this.value);
518
+ const index = this.segments.indexOf(enabled[0]);
519
+ this.focusButton(index);
520
+ this.updateIndicator(index);
521
+ }
522
+ this.updateIndicator();
523
+ }
524
+ focusButton(index) {
525
+ queueMicrotask(() => {
526
+ const button = this.segmentButtons?.get(index)?.nativeElement;
527
+ button?.focus();
528
+ });
529
+ }
530
+ updateIndicator(preferredIndex) {
531
+ queueMicrotask(() => {
532
+ const container = this.segmentContainer?.nativeElement;
533
+ const buttons = this.segmentButtons?.toArray() ?? [];
534
+ if (!container || buttons.length === 0) {
535
+ this.indicatorVisible = false;
536
+ this.indicatorStyle = {};
537
+ return;
538
+ }
539
+ const index = preferredIndex ?? buttons.findIndex((button, idx) => this.segments[idx]?.value === this.value);
540
+ if (index === -1) {
541
+ this.indicatorVisible = false;
542
+ this.indicatorStyle = {};
543
+ return;
544
+ }
545
+ const buttonEl = buttons[index]?.nativeElement;
546
+ if (!buttonEl) {
547
+ this.indicatorVisible = false;
548
+ this.indicatorStyle = {};
549
+ return;
550
+ }
551
+ const containerRect = container.getBoundingClientRect();
552
+ const buttonRect = buttonEl.getBoundingClientRect();
553
+ const offsetLeft = buttonEl.offsetLeft;
554
+ const offsetTop = buttonEl.offsetTop;
555
+ const width = buttonEl.offsetWidth;
556
+ const height = buttonEl.offsetHeight;
557
+ const isDisabled = this.disabled || this.segments[index]?.disabled;
558
+ this.indicatorStyle = {
559
+ width: `${width}px`,
560
+ height: `${height}px`,
561
+ left: `${offsetLeft}px`,
562
+ top: `${offsetTop}px`,
563
+ backgroundColor: isDisabled ? '#9BA0F4' : '#3F43EE',
564
+ };
565
+ this.indicatorVisible = true;
566
+ });
567
+ }
568
+ get isIndicatorVisible() {
569
+ return this.indicatorVisible;
570
+ }
571
+ }
572
+ SegmentControlComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SegmentControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
573
+ SegmentControlComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: SegmentControlComponent, selector: "cqa-segment-control", inputs: { segments: "segments", value: "value", disabled: "disabled" }, outputs: { valueChange: "valueChange" }, host: { properties: { "attr.id": "this.id", "style.display": "this.display" } }, viewQueries: [{ propertyName: "segmentContainer", first: true, predicate: ["segmentContainer"], descendants: true }, { propertyName: "segmentButtons", predicate: ["segmentButton"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #segmentContainer\n class=\"relative inline-flex flex-row items-start p-[3.5px] h-[31.5px] bg-[#F5F5F5] rounded-[8px]\"\n role=\"tablist\"\n [attr.aria-disabled]=\"disabled || null\"\n>\n <div\n class=\"absolute rounded-[8px] transition-all duration-200 ease-in-out pointer-events-none\"\n [class.opacity-0]=\"!isIndicatorVisible\"\n [ngStyle]=\"indicatorStyle\"\n aria-hidden=\"true\"\n ></div>\n\n <button\n *ngFor=\"let segment of segments; index as index; trackBy: trackByValue\"\n #segmentButton\n type=\"button\"\n role=\"tab\"\n class=\"relative z-10 flex flex-col justify-center items-center px-[14px] py-[3.5px] h-[25px] rounded-[8px] transition-all duration-200 ease-in-out whitespace-nowrap text-center focus:outline-none focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 flex-none\"\n [ngClass]=\"{\n 'text-white font-medium': isSelected(segment),\n 'text-[#99999E]': !isSelected(segment) && !(disabled || segment.disabled),\n 'cursor-not-allowed': disabled || segment.disabled,\n 'text-[#C7C7C7]': (disabled || segment.disabled) && !isSelected(segment),\n 'hover:text-black': !isSelected(segment) && !disabled && !segment.disabled\n }\"\n [disabled]=\"disabled || segment.disabled\"\n [attr.aria-selected]=\"isSelected(segment)\"\n [attr.tabindex]=\"!disabled && !segment.disabled ? (isSelected(segment) ? 0 : -1) : -1\"\n (click)=\"select(segment, index)\"\n (keydown)=\"onKeyDown($event, index)\"\n >\n <span class=\"flex items-center justify-center h-[18px] font-['Inter'] font-normal text-[12px] leading-[12px] text-center align-middle\">\n {{ segment.label }}\n </span>\n </button>\n</div>\n", directives: [{ type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
574
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SegmentControlComponent, decorators: [{
575
+ type: Component,
576
+ args: [{ selector: 'cqa-segment-control', template: "<div\n #segmentContainer\n class=\"relative inline-flex flex-row items-start p-[3.5px] h-[31.5px] bg-[#F5F5F5] rounded-[8px]\"\n role=\"tablist\"\n [attr.aria-disabled]=\"disabled || null\"\n>\n <div\n class=\"absolute rounded-[8px] transition-all duration-200 ease-in-out pointer-events-none\"\n [class.opacity-0]=\"!isIndicatorVisible\"\n [ngStyle]=\"indicatorStyle\"\n aria-hidden=\"true\"\n ></div>\n\n <button\n *ngFor=\"let segment of segments; index as index; trackBy: trackByValue\"\n #segmentButton\n type=\"button\"\n role=\"tab\"\n class=\"relative z-10 flex flex-col justify-center items-center px-[14px] py-[3.5px] h-[25px] rounded-[8px] transition-all duration-200 ease-in-out whitespace-nowrap text-center focus:outline-none focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 flex-none\"\n [ngClass]=\"{\n 'text-white font-medium': isSelected(segment),\n 'text-[#99999E]': !isSelected(segment) && !(disabled || segment.disabled),\n 'cursor-not-allowed': disabled || segment.disabled,\n 'text-[#C7C7C7]': (disabled || segment.disabled) && !isSelected(segment),\n 'hover:text-black': !isSelected(segment) && !disabled && !segment.disabled\n }\"\n [disabled]=\"disabled || segment.disabled\"\n [attr.aria-selected]=\"isSelected(segment)\"\n [attr.tabindex]=\"!disabled && !segment.disabled ? (isSelected(segment) ? 0 : -1) : -1\"\n (click)=\"select(segment, index)\"\n (keydown)=\"onKeyDown($event, index)\"\n >\n <span class=\"flex items-center justify-center h-[18px] font-['Inter'] font-normal text-[12px] leading-[12px] text-center align-middle\">\n {{ segment.label }}\n </span>\n </button>\n</div>\n", styles: [] }]
577
+ }], propDecorators: { id: [{
578
+ type: HostBinding,
579
+ args: ['attr.id']
580
+ }], display: [{
581
+ type: HostBinding,
582
+ args: ['style.display']
583
+ }], segments: [{
584
+ type: Input
585
+ }], value: [{
586
+ type: Input
587
+ }], disabled: [{
588
+ type: Input
589
+ }], valueChange: [{
590
+ type: Output
591
+ }], segmentButtons: [{
592
+ type: ViewChildren,
593
+ args: ['segmentButton']
594
+ }], segmentContainer: [{
595
+ type: ViewChild,
596
+ args: ['segmentContainer']
597
+ }] } });
598
+
599
+ class DialogComponent {
600
+ constructor(viewContainerRef, cdr) {
601
+ this.viewContainerRef = viewContainerRef;
602
+ this.cdr = cdr;
603
+ this.id = 'cqa-ui-root';
604
+ this.display = 'block';
605
+ this.contentAttached = false;
606
+ }
607
+ attachTemplate(template, context) {
608
+ if (!this.portalOutlet) {
609
+ return;
610
+ }
611
+ const templateContext = context ??
612
+ {
613
+ $implicit: this.config?.data,
614
+ data: this.config?.data,
615
+ };
616
+ const portal = new TemplatePortal(template, this.viewContainerRef, templateContext);
617
+ this.portalOutlet.attachTemplatePortal(portal);
618
+ this.markContentAttached();
619
+ }
620
+ attachComponent(component) {
621
+ if (!this.portalOutlet) {
622
+ return undefined;
623
+ }
624
+ const componentRef = this.portalOutlet.attachComponentPortal(component);
625
+ this.markContentAttached();
626
+ return componentRef;
627
+ }
628
+ async onButtonClick(button) {
629
+ const closeOnClick = button.closeOnClick ?? true;
630
+ let handlerResult = undefined;
631
+ if (button.handler) {
632
+ handlerResult = button.handler(this.dialogRef);
633
+ }
634
+ const resolved = handlerResult instanceof Promise ? await handlerResult : handlerResult;
635
+ if (!closeOnClick || resolved === false) {
636
+ return;
637
+ }
638
+ this.dialogRef.close(resolved);
639
+ }
640
+ get buttonAlignmentClass() {
641
+ const alignment = this.config?.buttonAlignment ?? 'right';
642
+ return this.mapAlignmentToClass(alignment);
643
+ }
644
+ get panelClassList() {
645
+ const baseClasses = [
646
+ 'relative',
647
+ 'w-full',
648
+ 'bg-white',
649
+ 'rounded-2xl',
650
+ 'shadow-md',
651
+ 'border',
652
+ 'border-[#E5E7EB]',
653
+ 'p-6',
654
+ 'text-left',
655
+ ];
656
+ const custom = this.config?.panelClass;
657
+ if (!custom) {
658
+ return baseClasses;
659
+ }
660
+ return Array.isArray(custom) ? [...baseClasses, ...custom] : [...baseClasses, custom];
661
+ }
662
+ get panelStyles() {
663
+ return {
664
+ width: this.config?.width,
665
+ maxWidth: this.config?.maxWidth ?? '480px',
666
+ };
667
+ }
668
+ buttonVariant(button) {
669
+ const role = this.normalizeRole(button.role);
670
+ switch (role) {
671
+ case 'secondary':
672
+ return 'outlined';
673
+ case 'text':
674
+ return 'text';
675
+ case 'tonal':
676
+ return 'tonal';
677
+ case 'elevated':
678
+ return 'elevated';
679
+ case 'filled':
680
+ case 'primary':
681
+ case 'warn':
682
+ default:
683
+ return 'filled';
684
+ }
685
+ }
686
+ buttonHostClasses(button) {
687
+ const role = this.normalizeRole(button.role);
688
+ if (role === 'warn') {
689
+ return ['cqa-dialog-btn-warn'];
690
+ }
691
+ return [];
692
+ }
693
+ mapAlignmentToClass(alignment) {
694
+ switch (alignment) {
695
+ case 'left':
696
+ return 'justify-start';
697
+ case 'center':
698
+ return 'justify-center';
699
+ case 'right':
700
+ default:
701
+ return 'justify-end';
702
+ }
703
+ }
704
+ markContentAttached() {
705
+ this.contentAttached = true;
706
+ this.cdr.markForCheck();
707
+ }
708
+ normalizeRole(role) {
709
+ return (role ?? 'secondary').trim().split(/\s+/)[0];
710
+ }
711
+ }
712
+ DialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: DialogComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
713
+ DialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: DialogComponent, selector: "cqa-dialog", host: { properties: { "attr.id": "this.id", "style.display": "this.display" } }, viewQueries: [{ propertyName: "portalOutlet", first: true, predicate: CdkPortalOutlet, descendants: true, static: true }], ngImport: i0, template: "<div class=\"flex w-full justify-center px-4 sm:px-6\">\n <div [ngClass]=\"panelClassList\" [ngStyle]=\"panelStyles\">\n <div class=\"flex flex-col gap-5\">\n <div class=\"flex flex-col gap-3\">\n <h2 class=\"text-lg font-semibold text-[#111827]\">\n {{ config.title }}\n </h2>\n\n <p *ngIf=\"config.description\" class=\"text-sm leading-6 text-[#4B5563]\">\n {{ config.description }}\n </p>\n\n <div\n *ngIf=\"config.warning\"\n class=\"rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm leading-5 text-red-700\"\n >\n {{ config.warning }}\n </div>\n </div>\n\n <div class=\"text-sm text-[#111827]\" [class.hidden]=\"!contentAttached\">\n <ng-template cdkPortalOutlet></ng-template>\n </div>\n\n <div class=\"mt-4 flex flex-wrap gap-3\" [ngClass]=\"buttonAlignmentClass\">\n <cqa-button\n *ngFor=\"let button of config.buttons\"\n type=\"button\"\n [variant]=\"buttonVariant(button)\"\n [ngClass]=\"buttonHostClasses(button)\"\n (clicked)=\"onButtonClick(button)\"\n >\n {{ button.label }}\n </cqa-button>\n </div>\n </div>\n </div>\n</div>\n\n\n", components: [{ type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "disabled", "icon", "iconPosition", "type"], outputs: ["clicked"] }], directives: [{ type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
714
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: DialogComponent, decorators: [{
715
+ type: Component,
716
+ args: [{ selector: 'cqa-dialog', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex w-full justify-center px-4 sm:px-6\">\n <div [ngClass]=\"panelClassList\" [ngStyle]=\"panelStyles\">\n <div class=\"flex flex-col gap-5\">\n <div class=\"flex flex-col gap-3\">\n <h2 class=\"text-lg font-semibold text-[#111827]\">\n {{ config.title }}\n </h2>\n\n <p *ngIf=\"config.description\" class=\"text-sm leading-6 text-[#4B5563]\">\n {{ config.description }}\n </p>\n\n <div\n *ngIf=\"config.warning\"\n class=\"rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm leading-5 text-red-700\"\n >\n {{ config.warning }}\n </div>\n </div>\n\n <div class=\"text-sm text-[#111827]\" [class.hidden]=\"!contentAttached\">\n <ng-template cdkPortalOutlet></ng-template>\n </div>\n\n <div class=\"mt-4 flex flex-wrap gap-3\" [ngClass]=\"buttonAlignmentClass\">\n <cqa-button\n *ngFor=\"let button of config.buttons\"\n type=\"button\"\n [variant]=\"buttonVariant(button)\"\n [ngClass]=\"buttonHostClasses(button)\"\n (clicked)=\"onButtonClick(button)\"\n >\n {{ button.label }}\n </cqa-button>\n </div>\n </div>\n </div>\n</div>\n\n\n", styles: [] }]
717
+ }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { id: [{
718
+ type: HostBinding,
719
+ args: ['attr.id']
720
+ }], display: [{
721
+ type: HostBinding,
722
+ args: ['style.display']
723
+ }], portalOutlet: [{
724
+ type: ViewChild,
725
+ args: [CdkPortalOutlet, { static: true }]
726
+ }] } });
727
+
728
+ class RootWrapperComponent {
729
+ constructor() {
730
+ this.display = 'inline-block';
731
+ this.fullWidth = false;
732
+ }
733
+ get rootStyles() {
734
+ const styles = {
735
+ display: this.fullWidth ? 'block' : this.display
736
+ };
737
+ if (this.fullWidth) {
738
+ styles['width'] = '100%';
739
+ }
740
+ else if (this.width) {
741
+ styles['width'] = this.width;
742
+ }
743
+ return styles;
744
+ }
745
+ }
746
+ RootWrapperComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: RootWrapperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
747
+ RootWrapperComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: RootWrapperComponent, selector: "cqa-ui-root", inputs: { display: "display", width: "width", fullWidth: "fullWidth" }, ngImport: i0, template: "<div id=\"cqa-ui-root\" [ngStyle]=\"rootStyles\">\n <ng-content></ng-content>\n</div>\n\n", directives: [{ type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
748
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: RootWrapperComponent, decorators: [{
749
+ type: Component,
750
+ args: [{ selector: 'cqa-ui-root', styles: [], template: "<div id=\"cqa-ui-root\" [ngStyle]=\"rootStyles\">\n <ng-content></ng-content>\n</div>\n\n" }]
751
+ }], propDecorators: { display: [{
752
+ type: Input
753
+ }], width: [{
754
+ type: Input
755
+ }], fullWidth: [{
756
+ type: Input
757
+ }] } });
758
+
759
+ // import { CardComponent } from './card/card.component';
760
+ // import { InputComponent } from './input/input.component';
761
+ // import { IconButtonComponent } from './icon-button/icon-button.component';
762
+ class UiKitModule {
763
+ }
764
+ UiKitModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: UiKitModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
765
+ UiKitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: UiKitModule, declarations: [ButtonComponent,
766
+ SearchBarComponent,
767
+ SegmentControlComponent,
768
+ DialogComponent,
769
+ RootWrapperComponent], imports: [CommonModule,
770
+ FormsModule,
771
+ MatIconModule,
772
+ OverlayModule,
773
+ PortalModule], exports: [ButtonComponent,
774
+ SearchBarComponent,
775
+ SegmentControlComponent,
776
+ DialogComponent,
777
+ RootWrapperComponent] });
778
+ UiKitModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: UiKitModule, imports: [[
779
+ CommonModule,
780
+ FormsModule,
781
+ MatIconModule,
782
+ OverlayModule,
783
+ PortalModule
784
+ ]] });
785
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: UiKitModule, decorators: [{
786
+ type: NgModule,
787
+ args: [{
788
+ declarations: [
789
+ ButtonComponent,
790
+ SearchBarComponent,
791
+ SegmentControlComponent,
792
+ DialogComponent,
793
+ RootWrapperComponent,
794
+ // CardComponent,
795
+ // InputComponent,
796
+ // IconButtonComponent
797
+ ],
798
+ imports: [
799
+ CommonModule,
800
+ FormsModule,
801
+ MatIconModule,
802
+ OverlayModule,
803
+ PortalModule
804
+ ],
805
+ exports: [
806
+ ButtonComponent,
807
+ SearchBarComponent,
808
+ SegmentControlComponent,
809
+ DialogComponent,
810
+ RootWrapperComponent,
811
+ // CardComponent,
812
+ // InputComponent,
813
+ // IconButtonComponent
814
+ ]
815
+ }]
816
+ }] });
817
+
818
+ class DialogRef {
819
+ constructor(overlayRef) {
820
+ this.overlayRef = overlayRef;
821
+ this.closed$ = new Subject();
822
+ this.isClosed = false;
823
+ this.overlayRef.detachments().subscribe(() => {
824
+ this.finishClose(undefined);
825
+ });
826
+ }
827
+ close(result) {
828
+ if (this.isClosed) {
829
+ return;
830
+ }
831
+ this.finishClose(result);
832
+ this.overlayRef.dispose();
833
+ }
834
+ afterClosed() {
835
+ return this.closed$.asObservable();
836
+ }
837
+ setComponentInstance(instance) {
838
+ this.componentInstance = instance;
839
+ }
840
+ getComponentInstance() {
841
+ return this.componentInstance;
842
+ }
843
+ finishClose(result) {
844
+ if (this.isClosed) {
845
+ return;
846
+ }
847
+ this.isClosed = true;
848
+ this.closed$.next(result);
849
+ this.closed$.complete();
850
+ }
851
+ }
852
+
853
+ const DIALOG_REF = new InjectionToken('CQA_DIALOG_REF');
854
+ const DIALOG_DATA = new InjectionToken('CQA_DIALOG_DATA');
855
+
856
+ class DialogService {
857
+ constructor(overlay, injector) {
858
+ this.overlay = overlay;
859
+ this.injector = injector;
860
+ }
861
+ open(config) {
862
+ this.assertValidConfig(config);
863
+ const overlayRef = this.overlay.create(this.buildOverlayConfig(config));
864
+ const dialogRef = new DialogRef(overlayRef);
865
+ const injector = Injector.create({
866
+ parent: this.injector,
867
+ providers: [
868
+ { provide: DIALOG_REF, useValue: dialogRef },
869
+ { provide: DIALOG_DATA, useValue: config.data },
870
+ ],
871
+ });
872
+ const containerPortal = new ComponentPortal(DialogComponent, undefined, injector);
873
+ const containerRef = overlayRef.attach(containerPortal);
874
+ const containerInstance = containerRef.instance;
875
+ containerInstance.config = config;
876
+ containerInstance.dialogRef = dialogRef;
877
+ if (config.content?.type === 'template') {
878
+ containerInstance.attachTemplate(config.content.template, config.content.context ?? {
879
+ $implicit: config.data,
880
+ data: config.data,
881
+ });
882
+ }
883
+ if (config.content?.type === 'component') {
884
+ const componentPortal = new ComponentPortal(config.content.component, undefined, Injector.create({
885
+ parent: injector,
886
+ providers: [
887
+ { provide: DIALOG_REF, useValue: dialogRef },
888
+ { provide: DIALOG_DATA, useValue: config.data },
889
+ ],
890
+ }));
891
+ const componentRef = containerInstance.attachComponent(componentPortal);
892
+ if (componentRef && config.content.inputs) {
893
+ Object.entries(config.content.inputs).forEach(([key, value]) => {
894
+ componentRef.instance[key] = value;
895
+ });
896
+ componentRef.changeDetectorRef.markForCheck();
897
+ }
898
+ if (componentRef) {
899
+ dialogRef.setComponentInstance(componentRef.instance);
900
+ }
901
+ }
902
+ containerRef.changeDetectorRef.markForCheck();
903
+ if (!config.disableClose) {
904
+ overlayRef.backdropClick().subscribe(() => dialogRef.close());
905
+ overlayRef
906
+ .keydownEvents()
907
+ .pipe(filter((event) => {
908
+ return event.key === 'Escape' || event.key === 'Esc';
909
+ }))
910
+ .subscribe(() => dialogRef.close());
911
+ }
912
+ return dialogRef;
913
+ }
914
+ assertValidConfig(config) {
915
+ if (!config.title) {
916
+ throw new Error('Dialog title is required.');
917
+ }
918
+ if (!config.buttons || config.buttons.length < 2) {
919
+ throw new Error('Dialog requires at least two buttons to be provided.');
920
+ }
921
+ }
922
+ buildOverlayConfig(config) {
923
+ const panelClass = Array.isArray(config.panelClass)
924
+ ? config.panelClass
925
+ : config.panelClass
926
+ ? [config.panelClass]
927
+ : [];
928
+ return new OverlayConfig({
929
+ hasBackdrop: true,
930
+ backdropClass: ['cdk-overlay-dark-backdrop', 'cqa-dialog-backdrop'],
931
+ scrollStrategy: this.overlay.scrollStrategies.block(),
932
+ positionStrategy: this.overlay.position().global().centerHorizontally().centerVertically(),
933
+ width: config.width,
934
+ maxWidth: config.maxWidth ?? '90vw',
935
+ panelClass: ['cqa-dialog-panel', ...panelClass],
936
+ });
937
+ }
938
+ }
939
+ DialogService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: DialogService, deps: [{ token: i1$1.Overlay }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
940
+ DialogService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: DialogService, providedIn: 'root' });
941
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: DialogService, decorators: [{
942
+ type: Injectable,
943
+ args: [{
944
+ providedIn: 'root',
945
+ }]
946
+ }], ctorParameters: function () { return [{ type: i1$1.Overlay }, { type: i0.Injector }]; } });
947
+
948
+ /**
949
+ * Generated bundle index. Do not edit.
950
+ */
951
+
952
+ export { ButtonComponent, DIALOG_DATA, DIALOG_REF, DialogComponent, DialogRef, DialogService, RootWrapperComponent, SearchBarComponent, SegmentControlComponent, UiKitModule };
953
+ //# sourceMappingURL=cqa-lib-cqa-ui.mjs.map