@brickclay-org/ui 0.0.39 → 0.0.40

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.
Files changed (56) hide show
  1. package/ASSETS_SETUP.md +59 -0
  2. package/ng-package.json +29 -0
  3. package/package.json +15 -26
  4. package/src/lib/assets/icons.ts +8 -0
  5. package/src/lib/badge/badge.html +24 -0
  6. package/src/lib/badge/badge.ts +42 -0
  7. package/src/lib/brickclay-lib.spec.ts +23 -0
  8. package/src/lib/brickclay-lib.ts +15 -0
  9. package/src/lib/button-group/button-group.html +12 -0
  10. package/src/lib/button-group/button-group.ts +73 -0
  11. package/src/lib/calender/calendar.module.ts +35 -0
  12. package/src/lib/calender/components/custom-calendar/custom-calendar.component.css +698 -0
  13. package/src/lib/calender/components/custom-calendar/custom-calendar.component.html +230 -0
  14. package/src/lib/calender/components/custom-calendar/custom-calendar.component.spec.ts +23 -0
  15. package/src/lib/calender/components/custom-calendar/custom-calendar.component.ts +1554 -0
  16. package/src/lib/calender/components/scheduled-date-picker/scheduled-date-picker.component.css +373 -0
  17. package/src/lib/calender/components/scheduled-date-picker/scheduled-date-picker.component.html +210 -0
  18. package/src/lib/calender/components/scheduled-date-picker/scheduled-date-picker.component.ts +361 -0
  19. package/src/lib/calender/components/time-picker/time-picker.component.css +174 -0
  20. package/src/lib/calender/components/time-picker/time-picker.component.html +60 -0
  21. package/src/lib/calender/components/time-picker/time-picker.component.ts +283 -0
  22. package/src/lib/calender/services/calendar-manager.service.ts +45 -0
  23. package/src/lib/checkbox/checkbox.html +42 -0
  24. package/src/lib/checkbox/checkbox.ts +67 -0
  25. package/src/lib/chips/chips.html +74 -0
  26. package/src/lib/chips/chips.ts +222 -0
  27. package/src/lib/grid/components/grid/grid.html +97 -0
  28. package/src/lib/grid/components/grid/grid.ts +139 -0
  29. package/src/lib/grid/models/grid.model.ts +20 -0
  30. package/src/lib/input/input.html +127 -0
  31. package/src/lib/input/input.ts +394 -0
  32. package/src/lib/pill/pill.html +24 -0
  33. package/src/lib/pill/pill.ts +39 -0
  34. package/src/lib/radio/radio.html +58 -0
  35. package/src/lib/radio/radio.ts +72 -0
  36. package/src/lib/select/select.html +111 -0
  37. package/src/lib/select/select.ts +401 -0
  38. package/src/lib/spinner/spinner.html +5 -0
  39. package/src/lib/spinner/spinner.ts +22 -0
  40. package/src/lib/tabs/tabs.html +28 -0
  41. package/src/lib/tabs/tabs.ts +48 -0
  42. package/src/lib/textarea/textarea.html +80 -0
  43. package/src/lib/textarea/textarea.ts +172 -0
  44. package/src/lib/toggle/toggle.html +24 -0
  45. package/src/lib/toggle/toggle.ts +62 -0
  46. package/src/lib/ui-button/ui-button.html +25 -0
  47. package/src/lib/ui-button/ui-button.ts +55 -0
  48. package/src/lib/ui-icon-button/ui-icon-button.html +7 -0
  49. package/src/lib/ui-icon-button/ui-icon-button.ts +38 -0
  50. package/src/public-api.ts +43 -0
  51. package/tsconfig.lib.json +19 -0
  52. package/tsconfig.lib.prod.json +11 -0
  53. package/tsconfig.spec.json +15 -0
  54. package/fesm2022/brickclay-org-ui.mjs +0 -4035
  55. package/fesm2022/brickclay-org-ui.mjs.map +0 -1
  56. package/index.d.ts +0 -857
@@ -0,0 +1,394 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { NgxMaskDirective, provideNgxMask } from 'ngx-mask';
3
+ import {
4
+ Component,
5
+ Input,
6
+ OnInit,
7
+ OnDestroy,
8
+ HostListener,
9
+ ElementRef,
10
+ ViewChild,
11
+ forwardRef,
12
+ Output,
13
+ EventEmitter
14
+ } from '@angular/core';
15
+ import {
16
+ ControlValueAccessor,
17
+ FormsModule,
18
+ NG_VALUE_ACCESSOR
19
+ } from '@angular/forms';
20
+
21
+
22
+ export type BkInputType =
23
+ | 'text'
24
+ | 'email'
25
+ | 'password'
26
+ | 'number'
27
+ | 'url'
28
+ | 'tel';
29
+ export type BkInputAutoComplete =
30
+ | 'on'
31
+ | 'off'
32
+ | 'name'
33
+ | 'honorific-prefix'
34
+ | 'given-name'
35
+ | 'additional-name'
36
+ | 'family-name'
37
+ | 'honorific-suffix'
38
+ | 'nickname'
39
+ | 'email'
40
+ | 'username'
41
+ | 'new-password'
42
+ | 'current-password'
43
+ | 'organization-title'
44
+ | 'organization'
45
+ | 'street-address'
46
+ | 'address-line1'
47
+ | 'address-line2'
48
+ | 'address-line3'
49
+ | 'address-level4'
50
+ | 'address-level3'
51
+ | 'address-level2'
52
+ | 'address-level1'
53
+ | 'country'
54
+ | 'country-name'
55
+ | 'postal-code'
56
+ | 'cc-name'
57
+ | 'cc-given-name'
58
+ | 'cc-additional-name'
59
+ | 'cc-family-name'
60
+ | 'cc-number'
61
+ | 'cc-exp'
62
+ | 'cc-exp-month'
63
+ | 'cc-exp-year'
64
+ | 'cc-csc'
65
+ | 'cc-type'
66
+ | 'transaction-currency'
67
+ | 'transaction-amount'
68
+ | 'language'
69
+ | 'bday'
70
+ | 'bday-day'
71
+ | 'bday-month'
72
+ | 'bday-year'
73
+ | 'sex'
74
+ | 'tel'
75
+ | 'tel-country-code'
76
+ | 'tel-national'
77
+ | 'tel-area-code'
78
+ | 'tel-local'
79
+ | 'tel-extension'
80
+ | 'impp'
81
+ | 'url'
82
+ | 'photo';
83
+
84
+ export type BkInputAutoCapitalize =
85
+ | 'off'
86
+ | 'none'
87
+ | 'on'
88
+ | 'sentences'
89
+ | 'words'
90
+ | 'characters';
91
+
92
+ export type BkInputMode =
93
+ | 'none'
94
+ | 'text'
95
+ | 'tel'
96
+ | 'url'
97
+ | 'email'
98
+ | 'numeric'
99
+ | 'decimal'
100
+ | 'search';
101
+
102
+ export type IconOrientation = 'left' | 'right';
103
+ export interface CountryOption {
104
+ code: string;
105
+ name: string;
106
+ mask: string;
107
+ prefix:string;
108
+ placeholder:string;
109
+ }
110
+ @Component({
111
+ selector: 'bk-input',
112
+ imports: [CommonModule,NgxMaskDirective,FormsModule],
113
+ templateUrl: './input.html',
114
+ styleUrl: './input.css',
115
+ standalone: true,
116
+ providers: [
117
+ provideNgxMask(),
118
+ {
119
+ provide: NG_VALUE_ACCESSOR,
120
+ useExisting: forwardRef(() => BkInput),
121
+ multi: true
122
+ }
123
+ ]
124
+ })
125
+ export class BkInput implements OnInit, OnDestroy, ControlValueAccessor {
126
+
127
+ // =================== Inputs (all your original ones) ===================
128
+ @Input() id!: string ;
129
+ @Input() name!: string ;
130
+ @Input() mask: string | null= null;
131
+ @Input() autoComplete : BkInputAutoComplete = 'off';
132
+ @Input() label: string = '';
133
+ @Input() placeholder: string = 'stephend@i2cinc.com';
134
+ @Input() hint: string = '';
135
+ @Input() required: boolean = false;
136
+ @Input() type: BkInputType = 'text';
137
+ @Input() value: string = '';
138
+ @Input() hasError: boolean = false;
139
+ @Input() showErrorIcon:boolean=false;
140
+ @Input() errorMessage: string = '';
141
+ @Input() disabled: boolean = false;
142
+ @Input() tabIndex: number | null = null;
143
+ @Input() readOnly: boolean = false;
144
+ @Input() autoCapitalize: BkInputAutoComplete | null = null;
145
+ @Input() inputMode: BkInputMode | null = null;
146
+ @Input() iconSrc?: string;
147
+ @Input() iconAlt: string = 'icon';
148
+ @Input() showIcon: boolean = true;
149
+ @Input() phone: boolean = false;
150
+ @Input() countryCode: string = 'US';
151
+ @Input() countryOptions: CountryOption[] = [
152
+ { code: 'US', name: 'US', mask: '(000) 000-0000', prefix: '+1 ',placeholder:'(000) 000-0000' },
153
+ { code: 'MT', name: 'MT', mask: '(000) 000-0000', prefix: '+356 ',placeholder:'(000) 000-0000' },
154
+ { code: 'PL', name: 'PL', mask: '(000) 000-0000', prefix: '+48 ',placeholder:'(000) 000-0000' },
155
+ { code: 'CH', name: 'CH', mask: '(000) 000-0000', prefix: '+41 ' ,placeholder:'(000) 000-0000'},
156
+ { code: 'TR', name: 'TR', mask: '(000) 000-0000', prefix: '+90 ' ,placeholder:'(000) 000-0000'},
157
+ { code: 'UG', name: 'UG', mask: '(000) 000-0000', prefix: '+256 ',placeholder:'(000) 000-0000' },
158
+ { code: 'ZM', name: 'ZM', mask: '(000) 000-0000', prefix: '+260 ',placeholder:'(000) 000-0000' }
159
+ ];
160
+
161
+ selectedCountry: CountryOption= this.countryOptions[0];
162
+ @Input() iconOrientation: IconOrientation = 'left'
163
+
164
+ @Input() password: boolean = false;
165
+ @Input() showPassword: boolean = false;
166
+
167
+ @Input() pattern?: string|null;
168
+ @Input() max: number|null = null;
169
+ @Input() min: number|null = null;
170
+ @Input() step: number|null = null;
171
+ @Input() maxlength: number|null = null;
172
+ @Input() minlength: number|null = null;
173
+ // =================== ViewChild ===================
174
+ @ViewChild('dropdownRef') dropdownRef?: ElementRef;
175
+ @ViewChild('selectRef') selectRef?: ElementRef;
176
+ @ViewChild('inputField') inputField?: ElementRef<HTMLInputElement>;
177
+
178
+ // =================== Internal State ===================
179
+ isFocused: boolean = false;
180
+ inputValue: string = '';
181
+ isDropdownOpen: boolean = false;
182
+
183
+
184
+ // =================== Output Emitter ===================
185
+ @Output() input = new EventEmitter<Event>();
186
+ @Output() change = new EventEmitter<Event>();
187
+ @Output() focus = new EventEmitter<Event>();
188
+ @Output() blur = new EventEmitter<Event>();
189
+ @Output() clicked = new EventEmitter<boolean>();
190
+
191
+ get placeHolderText(): string {
192
+ if (this.phone) {
193
+ const country = this.countryOptions.find(c => c.code === this.countryCode);
194
+ return country?.placeholder || '';
195
+ }
196
+ return this.placeholder;
197
+ }
198
+
199
+ get maskValue(): string {
200
+ if (this.mask) return this.mask;
201
+ if (this.phone) {
202
+ const country = this.countryOptions.find(c => c.code === this.countryCode);
203
+ return country?.mask || '';
204
+ }
205
+ return '';
206
+ }
207
+
208
+ get maskPrefixValue(): string {
209
+ if (this.phone) {
210
+
211
+ const country = this.countryOptions.find(c => c.code === this.countryCode);
212
+ return country?.prefix || '';
213
+ }
214
+ return '';
215
+ }
216
+
217
+ // =================== CVA Callbacks ===================
218
+ private onChange = (value: any) => {};
219
+ private onTouched = () => {};
220
+
221
+ writeValue(value: any): void {
222
+ this.value = value || '';
223
+ this.inputValue = this.value;
224
+ }
225
+
226
+ registerOnChange(fn: any): void {
227
+ this.onChange = fn;
228
+ }
229
+
230
+ registerOnTouched(fn: any): void {
231
+ this.onTouched = fn;
232
+ }
233
+
234
+ setDisabledState(isDisabled: boolean): void {
235
+ this.disabled = isDisabled;
236
+ }
237
+
238
+ // =================== Lifecycle ===================
239
+ private closeAllDropdownsHandler = () => {
240
+ if (this.phone && this.isDropdownOpen) this.isDropdownOpen = false;
241
+ };
242
+
243
+ ngOnInit(): void {
244
+ if (this.value) this.inputValue = this.value;
245
+ if (this.password && this.type !== 'password') this.type = 'password';
246
+ if (this.phone) {
247
+ const country = this.countryOptions.find(c => c.code === this.countryCode);
248
+
249
+ if (country) this.selectedCountry = country;
250
+ document.addEventListener('closeAllPhoneDropdowns', this.closeAllDropdownsHandler);
251
+ }
252
+ }
253
+
254
+ ngOnDestroy(): void {
255
+ if (this.phone) {
256
+ document.removeEventListener('closeAllPhoneDropdowns', this.closeAllDropdownsHandler);
257
+ }
258
+ }
259
+
260
+ // =================== Host Listener ===================
261
+ @HostListener('document:click', ['$event'])
262
+ onDocumentClick(event: MouseEvent): void {
263
+ if (this.phone && this.isDropdownOpen) {
264
+ const target = event.target as HTMLElement;
265
+ if (this.selectRef?.nativeElement && this.dropdownRef?.nativeElement) {
266
+ const clickedInside =
267
+ this.selectRef.nativeElement.contains(target) ||
268
+ this.dropdownRef.nativeElement.contains(target);
269
+ if (!clickedInside) this.isDropdownOpen = false;
270
+ }
271
+ }
272
+ }
273
+
274
+ // =================== Event Handlers ===================
275
+ handleFocus(event: Event): void {
276
+ this.focus.emit(event);
277
+ if (!this.disabled) this.isFocused = true;
278
+ }
279
+
280
+ handleBlur(event:Event): void {
281
+ this.isFocused = false;
282
+ this.onTouched();
283
+ this.blur.emit(event);
284
+ }
285
+ handleInput(event: Event): void {
286
+ const val = (event.target as HTMLInputElement).value;
287
+ this.inputValue = val;
288
+ this.value = val; // update CVA value
289
+ this.onChange(val); // propagate to parent form
290
+ this.input.emit(event); // emit raw event
291
+ }
292
+
293
+ handleClicked():void {
294
+ this.clicked.emit(true);
295
+ }
296
+
297
+ handleChange(event: Event) {
298
+ this.change.emit(event); // emit raw change event
299
+ }
300
+
301
+ toggleDropdown(event?: Event): void {
302
+ if (!this.disabled && this.phone) {
303
+ if (!this.isDropdownOpen) {
304
+ document.dispatchEvent(new CustomEvent('closeAllPhoneDropdowns'));
305
+ setTimeout(() => (this.isDropdownOpen = true), 0);
306
+ } else {
307
+ this.isDropdownOpen = false;
308
+ }
309
+ event?.stopPropagation();
310
+ }
311
+ }
312
+
313
+ selectCountry(country: CountryOption): void {
314
+ const oldCountry = this.selectedCountry;
315
+ this.selectedCountry = country;
316
+ this.countryCode = country.code;
317
+ this.isDropdownOpen = false;
318
+
319
+ const currentRaw = this.inputField?.nativeElement?.value || this.inputValue;
320
+ let newPhone = '';
321
+
322
+ if (currentRaw && currentRaw.trim() !== '') {
323
+ // Input has some value → replace old prefix
324
+ if (oldCountry?.prefix && oldCountry.code !== country.code) {
325
+ const oldPrefixEscaped = oldCountry.prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
326
+ const regex = new RegExp(`^${oldPrefixEscaped}\\s?`);
327
+ const oldMaskedValue = currentRaw.replace(regex, '');
328
+ newPhone = country.prefix + oldMaskedValue;
329
+ } else {
330
+ newPhone = country.prefix + currentRaw;
331
+ }
332
+ } else {
333
+ // Input is empty → show only the new prefix OR empty
334
+ newPhone = ''; // optionally: newPhone = country.prefix;
335
+ }
336
+
337
+ this.inputValue = newPhone;
338
+ this.value = newPhone;
339
+ this.onChange(newPhone);
340
+
341
+ setTimeout(() => {
342
+ if (this.inputField?.nativeElement) {
343
+ this.inputField.nativeElement.value = newPhone;
344
+ this.inputField.nativeElement.dispatchEvent(
345
+ new Event('input', { bubbles: true })
346
+ );
347
+ }
348
+ }, 0);
349
+ }
350
+
351
+
352
+
353
+
354
+
355
+ togglePasswordVisibility(event: Event): void {
356
+ if (!this.disabled && this.password) {
357
+ event.preventDefault();
358
+ event.stopPropagation();
359
+ this.showPassword = !this.showPassword;
360
+ this.type = this.showPassword ? 'text' : 'password';
361
+ }
362
+ }
363
+
364
+ handleIconClick(event: Event): void {
365
+ if (this.disabled || this.readOnly) {
366
+ event.preventDefault();
367
+ event.stopPropagation();
368
+ return;
369
+ }
370
+ this.clicked.emit(true);
371
+ }
372
+
373
+ // =================== Getters ===================
374
+ get isFilled(): boolean {
375
+ return this.inputValue.length > 0;
376
+ }
377
+
378
+ get inputState(): 'default' | 'focused' | 'filled' | 'error' | 'disabled' {
379
+ if (this.disabled) return 'disabled';
380
+ if (this.hasError) return 'error';
381
+ if (this.isFocused || this.isDropdownOpen) return 'focused';
382
+ if (this.isFilled) return 'filled';
383
+ return 'default';
384
+ }
385
+
386
+ get currentInputType(): string {
387
+ if (this.password) return this.showPassword ? 'text' : 'password';
388
+ return this.type;
389
+ }
390
+
391
+
392
+
393
+
394
+ }
@@ -0,0 +1,24 @@
1
+ <span [className]="containerClasses">
2
+
3
+ @if (dot === 'left') {
4
+ <span class="dot"></span>
5
+ }
6
+
7
+ <span>{{ label }}</span>
8
+
9
+ @if (dot === 'right') {
10
+ <span class="dot"></span>
11
+ }
12
+
13
+ @if (removable) {
14
+ <button
15
+ (click)="onRemove($event)"
16
+ class="pill-close "> <svg
17
+ xmlns="http://www.w3.org/2000/svg"
18
+ viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
19
+ <line x1="18" y1="6" x2="6" y2="18"></line>
20
+ <line x1="6" y1="6" x2="18" y2="18"></line>
21
+ </svg>
22
+ </button>
23
+ }
24
+ </span>
@@ -0,0 +1,39 @@
1
+ import { Component, EventEmitter, Input, Output } from '@angular/core';
2
+ export type PillVariant = 'Light' | 'Solid' | 'Outline' | 'Transparent';
3
+ export type PillColor = 'Gray' | 'Primary' | 'Error' | 'Warning' | 'Success' | 'Purple' | 'Cyan';
4
+ export type PillSize = 'xsm' |'sm' | 'md' | 'lg';
5
+ @Component({
6
+ selector: 'bk-pill',
7
+ standalone: true,
8
+ templateUrl: './pill.html',
9
+ styleUrl: './pill.css',
10
+ })
11
+ export class BkPill {
12
+ @Input() label: string = '';
13
+ @Input() variant: PillVariant = 'Light';
14
+ @Input() color: PillColor = 'Gray';
15
+ @Input() size: PillSize = 'md';
16
+ @Input() dot: 'left' | 'right' | 'none' = 'none';
17
+ @Input() removable: boolean = false;
18
+ @Input() customClass: string = '';
19
+
20
+ @Output() clicked = new EventEmitter<string>();
21
+
22
+ get containerClasses(): string {
23
+ // 1. Size Class
24
+ const sizeClass = `pill-${this.size}`;
25
+
26
+ // 2. Color/Variant Class (Dynamic Generation)
27
+ const styleClass = `${this.color}-${this.variant}`;
28
+
29
+ // 3. customClasses
30
+ const customClass = `${this.customClass}`;
31
+
32
+ return `pill ${sizeClass} ${styleClass} ${customClass}`;
33
+ }
34
+
35
+ onRemove(e: Event) {
36
+ e.stopPropagation();
37
+ this.clicked.emit(this.label);
38
+ }
39
+ }
@@ -0,0 +1,58 @@
1
+ <div
2
+ class="inline-flex items-center gap-2 cursor-pointer group outline-none"
3
+ (click)="select()"
4
+ (keydown.enter)="select()"
5
+ (keydown.space)="$event.preventDefault(); select()"
6
+ tabindex="0"
7
+ [attr.aria-disabled]="disabled">
8
+
9
+ <div
10
+ class="relative flex items-center justify-center rounded-full border-2 transition-all duration-200 flex-shrink-0 group-focus-visible:ring-2 group-focus-visible:ring-blue-600 group-focus-visible:ring-offset-2 radio"
11
+ [ngClass]="[
12
+ radioClass,
13
+ !isChecked && !disabled ? 'bg-white border-gray-300 group-hover:border-gray-400' : '',
14
+
15
+ variant === 'dot' && isChecked && !disabled ? 'border-black bg-white' : '',
16
+
17
+ variant === 'tick' && isChecked && !disabled ? 'bg-black border-black' : '',
18
+
19
+ disabled && isChecked && variant === 'tick' ? 'bg-gray-300 border-gray-300' : '',
20
+ disabled && isChecked && variant === 'dot' ? 'border-gray-300 bg-gray-50' : '',
21
+ disabled && !isChecked ? 'bg-gray-100 border-gray-200' : '',
22
+ disabled ? 'cursor-not-allowed' : ''
23
+ ]"
24
+ >
25
+ @if(variant === 'dot'){
26
+ <span
27
+ class="rounded-full bg-black transition-transform duration-200 transform dot"
28
+ [class.scale-0]="!isChecked"
29
+ [class.scale-100]="isChecked"
30
+ [class.bg-gray-400]="disabled"
31
+ ></span>
32
+ }
33
+ @if (variant === 'tick'){
34
+ <svg
35
+ xmlns="http://www.w3.org/2000/svg"
36
+ viewBox="0 0 24 24"
37
+ fill="none"
38
+ stroke="currentColor"
39
+ stroke-width="3.5"
40
+ stroke-linecap="round"
41
+ stroke-linejoin="round"
42
+ class="text-white pointer-events-none transition-opacity duration-200 tick"
43
+ [class.opacity-0]="!isChecked"
44
+ [class.opacity-100]="isChecked"
45
+
46
+ >
47
+ <polyline points="20 6 9 17 4 12"></polyline>
48
+ </svg>
49
+ }
50
+ </div>
51
+
52
+ @if(label) {
53
+ <span class="font-medium text-xs text-[#1B223A] select-none {{labelClass}}"
54
+ [ngClass]="disabled ? 'text-gray-400' : ''">
55
+ {{ label }}
56
+ </span>
57
+ }
58
+ </div>
@@ -0,0 +1,72 @@
1
+ import {
2
+ Component,
3
+ Input,
4
+ Output,
5
+ EventEmitter,
6
+ forwardRef,
7
+ ViewEncapsulation,
8
+ } from '@angular/core';
9
+ import { CommonModule } from '@angular/common';
10
+ import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
11
+ @Component({
12
+ selector: 'bk-radio-button',
13
+ standalone: true,
14
+ imports: [CommonModule, FormsModule],
15
+ encapsulation: ViewEncapsulation.None,
16
+ templateUrl: './radio.html',
17
+ styleUrl: './radio.css',
18
+ providers: [
19
+ {
20
+ provide: NG_VALUE_ACCESSOR,
21
+ useExisting: forwardRef(() => BkRadioButton),
22
+ multi: true,
23
+ },
24
+ ],
25
+ })
26
+ export class BkRadioButton implements ControlValueAccessor {
27
+
28
+ @Input() radioClass = '';
29
+ @Input() label = '';
30
+ @Input() labelClass = '';
31
+ @Input() value: any;
32
+ @Input() disabled = false;
33
+ @Input() variant: 'dot' | 'tick' = 'dot';
34
+
35
+ @Output() change = new EventEmitter<any>();
36
+
37
+ modelValue: any;
38
+
39
+ onChange = (_: any) => {};
40
+ onTouched = () => {};
41
+
42
+ select(): void {
43
+ if (this.disabled) return;
44
+
45
+ if (this.modelValue !== this.value) {
46
+ this.modelValue = this.value;
47
+ this.onChange(this.value);
48
+ this.onTouched();
49
+ this.change.emit(this.value);
50
+ }
51
+ }
52
+
53
+ get isChecked(): boolean {
54
+ return this.modelValue === this.value;
55
+ }
56
+
57
+ writeValue(value: any): void {
58
+ this.modelValue = value;
59
+ }
60
+
61
+ registerOnChange(fn: any): void {
62
+ this.onChange = fn;
63
+ }
64
+
65
+ registerOnTouched(fn: any): void {
66
+ this.onTouched = fn;
67
+ }
68
+
69
+ setDisabledState(isDisabled: boolean): void {
70
+ this.disabled = isDisabled;
71
+ }
72
+ }