@brickclay-org/ui 0.0.9 → 0.0.13
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/README.md +1 -1
- package/package.json +16 -15
- package/ng-package.json +0 -8
- package/src/lib/assets/icons.ts +0 -8
- package/src/lib/brickclay-lib.spec.ts +0 -23
- package/src/lib/brickclay-lib.ts +0 -15
- package/src/lib/calender/calendar.module.ts +0 -35
- package/src/lib/calender/components/custom-calendar/custom-calendar.component.css +0 -698
- package/src/lib/calender/components/custom-calendar/custom-calendar.component.html +0 -230
- package/src/lib/calender/components/custom-calendar/custom-calendar.component.spec.ts +0 -23
- package/src/lib/calender/components/custom-calendar/custom-calendar.component.ts +0 -1534
- package/src/lib/calender/components/scheduled-date-picker/scheduled-date-picker.component.css +0 -373
- package/src/lib/calender/components/scheduled-date-picker/scheduled-date-picker.component.html +0 -210
- package/src/lib/calender/components/scheduled-date-picker/scheduled-date-picker.component.ts +0 -360
- package/src/lib/calender/components/time-picker/time-picker.component.css +0 -174
- package/src/lib/calender/components/time-picker/time-picker.component.html +0 -60
- package/src/lib/calender/components/time-picker/time-picker.component.ts +0 -283
- package/src/lib/calender/services/calendar-manager.service.ts +0 -45
- package/src/lib/checkbox/checkbox.css +0 -26
- package/src/lib/checkbox/checkbox.html +0 -42
- package/src/lib/checkbox/checkbox.ts +0 -67
- package/src/lib/radio/radio.css +0 -39
- package/src/lib/radio/radio.html +0 -58
- package/src/lib/radio/radio.ts +0 -77
- package/src/lib/toggle/components/toggle.component.css +0 -74
- package/src/lib/toggle/components/toggle.component.html +0 -24
- package/src/lib/toggle/components/toggle.component.ts +0 -62
- package/src/public-api.ts +0 -20
- package/tsconfig.lib.json +0 -19
- package/tsconfig.lib.prod.json +0 -11
- package/tsconfig.spec.json +0 -15
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
import { BrickclayIcons } from '../../../assets/icons';
|
|
2
|
-
import { Component, Input, Output, EventEmitter, OnInit, OnChanges, AfterViewInit, QueryList, ViewChildren, ElementRef, HostListener, SimpleChanges } from '@angular/core';
|
|
3
|
-
import { CommonModule } from '@angular/common';
|
|
4
|
-
|
|
5
|
-
@Component({
|
|
6
|
-
selector: 'brickclay-time-picker',
|
|
7
|
-
standalone: true,
|
|
8
|
-
imports: [CommonModule],
|
|
9
|
-
templateUrl: './time-picker.component.html',
|
|
10
|
-
styleUrls: ['./time-picker.component.css']
|
|
11
|
-
})
|
|
12
|
-
export class TimePickerComponent implements OnInit, OnChanges, AfterViewInit {
|
|
13
|
-
@Input() value: string = '1:00 AM'; // Time in format "H:MM AM/PM"
|
|
14
|
-
@Input() label: string = 'Time';
|
|
15
|
-
@Input() placeholder: string = 'Select time';
|
|
16
|
-
@Input() position: 'left' | 'right' = 'left';
|
|
17
|
-
@Input() pickerId: string = ''; // Unique ID for this picker
|
|
18
|
-
@Input() closePicker: number = 0; // Close counter from parent (triggers close when changed)
|
|
19
|
-
@Input() timeFormat: 12 | 24 = 12; // Visual mode: 12h or 24h
|
|
20
|
-
@Input() showSeconds = false; // Whether to show/edit seconds
|
|
21
|
-
@Output() timeChange = new EventEmitter<string>();
|
|
22
|
-
@Output() pickerOpened = new EventEmitter<string>(); // Notify parent when opened
|
|
23
|
-
@Output() pickerClosed = new EventEmitter<string>(); // Notify parent when closed
|
|
24
|
-
|
|
25
|
-
@ViewChildren('timeScroll') timeScrollElements!: QueryList<ElementRef>;
|
|
26
|
-
|
|
27
|
-
showPicker = false;
|
|
28
|
-
currentHour = 1;
|
|
29
|
-
currentMinute = 0;
|
|
30
|
-
currentAMPM = 'AM';
|
|
31
|
-
currentSecond = 0;
|
|
32
|
-
|
|
33
|
-
brickclayIcons=BrickclayIcons;
|
|
34
|
-
|
|
35
|
-
ngOnInit() {
|
|
36
|
-
this.parseTimeValue();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
ngAfterViewInit() {
|
|
40
|
-
if (this.showPicker) {
|
|
41
|
-
setTimeout(() => {
|
|
42
|
-
this.scrollToSelectedTimes();
|
|
43
|
-
}, 100);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
parseTimeValue() {
|
|
48
|
-
const parsed = this.parseTimeStringToComponents(this.value);
|
|
49
|
-
this.currentHour = parsed.hour;
|
|
50
|
-
this.currentMinute = parsed.minute;
|
|
51
|
-
this.currentSecond = parsed.second;
|
|
52
|
-
this.currentAMPM = parsed.ampm;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
getHours(): number[] {
|
|
56
|
-
// 12-hour: 1-12, 24-hour: 0-23
|
|
57
|
-
if (this.timeFormat === 24) {
|
|
58
|
-
return Array.from({ length: 24 }, (_, i) => i);
|
|
59
|
-
}
|
|
60
|
-
return Array.from({ length: 12 }, (_, i) => i + 1);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
getMinutes(): number[] {
|
|
64
|
-
return Array.from({ length: 60 }, (_, i) => i);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
getSeconds(): number[] {
|
|
68
|
-
return Array.from({ length: 60 }, (_, i) => i);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
getAMPMOptions(): string[] {
|
|
72
|
-
return ['AM', 'PM'];
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
parseTimeStringToComponents(timeStr: string): { hour: number; minute: number; second: number; ampm: string } {
|
|
76
|
-
// Supports:
|
|
77
|
-
// - "H:MM AM/PM"
|
|
78
|
-
// - "H:MM:SS AM/PM"
|
|
79
|
-
// - "HH:MM" (24h)
|
|
80
|
-
// - "HH:MM:SS" (24h)
|
|
81
|
-
if (!timeStr) {
|
|
82
|
-
return {
|
|
83
|
-
hour: this.timeFormat === 24 ? 0 : 12,
|
|
84
|
-
minute: 0,
|
|
85
|
-
second: 0,
|
|
86
|
-
ampm: this.timeFormat === 24 ? '' : 'AM'
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const parts = timeStr.trim().split(' ');
|
|
91
|
-
const timePart = parts[0] || (this.timeFormat === 24 ? '00:00' : '12:00');
|
|
92
|
-
let ampm = (parts[1] || '').toUpperCase();
|
|
93
|
-
|
|
94
|
-
const [hoursStr, minutesStr, secondsStr] = timePart.split(':');
|
|
95
|
-
let hour = parseInt(hoursStr || (this.timeFormat === 24 ? '0' : '12'), 10);
|
|
96
|
-
const minute = parseInt(minutesStr || '0', 10);
|
|
97
|
-
const second = parseInt(secondsStr || '0', 10);
|
|
98
|
-
|
|
99
|
-
if (this.timeFormat === 24) {
|
|
100
|
-
// In 24-hour mode we ignore AM/PM and keep hour as 0-23
|
|
101
|
-
return {
|
|
102
|
-
hour: isNaN(hour) ? 0 : Math.min(Math.max(hour, 0), 23),
|
|
103
|
-
minute: isNaN(minute) ? 0 : Math.min(Math.max(minute, 0), 59),
|
|
104
|
-
second: isNaN(second) ? 0 : Math.min(Math.max(second, 0), 59),
|
|
105
|
-
ampm: ''
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// 12-hour mode: normalize AM/PM and convert 24h inputs if needed
|
|
110
|
-
let ampmValue = ampm === 'PM' || ampm === 'AM' ? ampm : '';
|
|
111
|
-
if (!ampmValue) {
|
|
112
|
-
// No AM/PM provided -> interpret as 24-hour and convert to 12-hour with AM/PM
|
|
113
|
-
if (hour >= 12) {
|
|
114
|
-
ampmValue = 'PM';
|
|
115
|
-
if (hour > 12) hour -= 12;
|
|
116
|
-
} else {
|
|
117
|
-
ampmValue = 'AM';
|
|
118
|
-
if (hour === 0) hour = 12;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Clamp to 1-12 range
|
|
123
|
-
if (hour < 1) hour = 1;
|
|
124
|
-
if (hour > 12) hour = 12;
|
|
125
|
-
|
|
126
|
-
return {
|
|
127
|
-
hour,
|
|
128
|
-
minute: isNaN(minute) ? 0 : Math.min(Math.max(minute, 0), 59),
|
|
129
|
-
second: isNaN(second) ? 0 : Math.min(Math.max(second, 0), 59),
|
|
130
|
-
ampm: ampmValue
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
formatTimeFromComponents(hour: number, minute: number, second: number, ampm: string): string {
|
|
135
|
-
const hStr = hour.toString().padStart(2, '0');
|
|
136
|
-
const minuteStr = minute.toString().padStart(2, '0');
|
|
137
|
-
const secondStr = second.toString().padStart(2, '0');
|
|
138
|
-
|
|
139
|
-
if (this.timeFormat === 24) {
|
|
140
|
-
// "HH:mm" or "HH:mm:ss"
|
|
141
|
-
return this.showSeconds
|
|
142
|
-
? `${hStr}:${minuteStr}:${secondStr}`
|
|
143
|
-
: `${hStr}:${minuteStr}`;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// 12-hour: "H:MM" or "H:MM:SS" with AM/PM
|
|
147
|
-
const displayHour = hour; // already 1-12
|
|
148
|
-
return this.showSeconds
|
|
149
|
-
? `${displayHour}:${minuteStr}:${secondStr} ${ampm}`
|
|
150
|
-
: `${displayHour}:${minuteStr} ${ampm}`;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
togglePicker() {
|
|
154
|
-
if (!this.showPicker) {
|
|
155
|
-
this.showPicker = true;
|
|
156
|
-
this.parseTimeValue();
|
|
157
|
-
this.pickerOpened.emit(this.pickerId);
|
|
158
|
-
setTimeout(() => {
|
|
159
|
-
this.scrollToSelectedTimes();
|
|
160
|
-
}, 100);
|
|
161
|
-
} else {
|
|
162
|
-
this.showPicker = false;
|
|
163
|
-
this.pickerClosed.emit(this.pickerId);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
onHourChange(hour: number) {
|
|
168
|
-
this.currentHour = hour;
|
|
169
|
-
this.updateTime();
|
|
170
|
-
setTimeout(() => {
|
|
171
|
-
this.scrollToSelectedTimes();
|
|
172
|
-
}, 50);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
onMinuteChange(minute: number) {
|
|
176
|
-
this.currentMinute = minute;
|
|
177
|
-
this.updateTime();
|
|
178
|
-
setTimeout(() => {
|
|
179
|
-
this.scrollToSelectedTimes();
|
|
180
|
-
}, 50);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
onSecondChange(second: number) {
|
|
184
|
-
this.currentSecond = second;
|
|
185
|
-
this.updateTime();
|
|
186
|
-
setTimeout(() => {
|
|
187
|
-
this.scrollToSelectedTimes();
|
|
188
|
-
}, 50);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
onAMPMChange(ampm: string) {
|
|
192
|
-
this.currentAMPM = ampm;
|
|
193
|
-
this.updateTime();
|
|
194
|
-
setTimeout(() => {
|
|
195
|
-
this.scrollToSelectedTimes();
|
|
196
|
-
}, 50);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
updateTime() {
|
|
200
|
-
const newTime = this.formatTimeFromComponents(
|
|
201
|
-
this.currentHour,
|
|
202
|
-
this.currentMinute,
|
|
203
|
-
this.currentSecond,
|
|
204
|
-
this.currentAMPM
|
|
205
|
-
);
|
|
206
|
-
this.value = newTime;
|
|
207
|
-
this.timeChange.emit(newTime);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
scrollToSelectedTimes() {
|
|
211
|
-
this.timeScrollElements.forEach((elementRef) => {
|
|
212
|
-
const element = elementRef.nativeElement;
|
|
213
|
-
const selectedItem = element.querySelector('.time-item.selected');
|
|
214
|
-
if (selectedItem) {
|
|
215
|
-
const scrollTop = selectedItem.offsetTop - element.offsetHeight / 40 + selectedItem.offsetHeight / 40;
|
|
216
|
-
element.scrollTop = scrollTop;
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
@HostListener('document:click', ['$event'])
|
|
222
|
-
onDocumentClick(event: MouseEvent) {
|
|
223
|
-
const target = event.target as HTMLElement;
|
|
224
|
-
if (!target.closest('.time-picker-wrapper') && this.showPicker) {
|
|
225
|
-
this.showPicker = false;
|
|
226
|
-
this.pickerClosed.emit(this.pickerId);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
private previousCloseCounter: number = 0;
|
|
231
|
-
|
|
232
|
-
ngOnChanges(changes: SimpleChanges) {
|
|
233
|
-
if (changes['value'] && changes['value'].currentValue) {
|
|
234
|
-
this.parseTimeValue();
|
|
235
|
-
}
|
|
236
|
-
if (changes['closePicker'] && this.showPicker) {
|
|
237
|
-
const newCounter = changes['closePicker'].currentValue;
|
|
238
|
-
// If counter increased, close the picker
|
|
239
|
-
if (newCounter > this.previousCloseCounter) {
|
|
240
|
-
this.showPicker = false;
|
|
241
|
-
this.pickerClosed.emit(this.pickerId);
|
|
242
|
-
this.previousCloseCounter = newCounter;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Basic keyboard support on the input (combobox behavior)
|
|
248
|
-
onInputKeydown(event: KeyboardEvent) {
|
|
249
|
-
const key = event.key;
|
|
250
|
-
|
|
251
|
-
if (key === 'Enter' || key === ' ') {
|
|
252
|
-
event.preventDefault();
|
|
253
|
-
this.togglePicker();
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (key === 'Escape' && this.showPicker) {
|
|
258
|
-
this.showPicker = false;
|
|
259
|
-
this.pickerClosed.emit(this.pickerId);
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Simple hour increment/decrement when closed
|
|
264
|
-
if (!this.showPicker && (key === 'ArrowUp' || key === 'ArrowDown')) {
|
|
265
|
-
event.preventDefault();
|
|
266
|
-
if (this.timeFormat === 24) {
|
|
267
|
-
if (key === 'ArrowUp') {
|
|
268
|
-
this.currentHour = (this.currentHour + 1) % 24;
|
|
269
|
-
} else {
|
|
270
|
-
this.currentHour = this.currentHour <= 0 ? 23 : this.currentHour - 1;
|
|
271
|
-
}
|
|
272
|
-
} else {
|
|
273
|
-
if (key === 'ArrowUp') {
|
|
274
|
-
this.currentHour = this.currentHour >= 12 ? 1 : this.currentHour + 1;
|
|
275
|
-
} else {
|
|
276
|
-
this.currentHour = this.currentHour <= 1 ? 12 : this.currentHour - 1;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
this.updateTime();
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Injectable } from '@angular/core';
|
|
2
|
-
import { Subject } from 'rxjs';
|
|
3
|
-
|
|
4
|
-
@Injectable({
|
|
5
|
-
providedIn: 'root'
|
|
6
|
-
})
|
|
7
|
-
export class CalendarManagerService {
|
|
8
|
-
private calendarInstances: Set<() => void> = new Set();
|
|
9
|
-
private closeAllSubject = new Subject<void>();
|
|
10
|
-
|
|
11
|
-
closeAll$ = this.closeAllSubject.asObservable();
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Register a calendar instance with its close function
|
|
15
|
-
*/
|
|
16
|
-
register(closeFn: () => void): () => void {
|
|
17
|
-
this.calendarInstances.add(closeFn);
|
|
18
|
-
|
|
19
|
-
// Return unregister function
|
|
20
|
-
return () => {
|
|
21
|
-
this.calendarInstances.delete(closeFn);
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Close all calendars except the one being opened
|
|
27
|
-
*/
|
|
28
|
-
closeAllExcept(exceptCloseFn: () => void): void {
|
|
29
|
-
this.calendarInstances.forEach(closeFn => {
|
|
30
|
-
if (closeFn !== exceptCloseFn) {
|
|
31
|
-
closeFn();
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Close all calendars
|
|
38
|
-
*/
|
|
39
|
-
closeAll(): void {
|
|
40
|
-
this.closeAllSubject.next();
|
|
41
|
-
this.calendarInstances.forEach(closeFn => closeFn());
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/*---- Checkbox Sizes Class ---- */
|
|
2
|
-
.xsm {
|
|
3
|
-
@apply size-[14px];
|
|
4
|
-
}
|
|
5
|
-
.sm {
|
|
6
|
-
@apply size-[16px];
|
|
7
|
-
}
|
|
8
|
-
.md {
|
|
9
|
-
@apply size-[18px];
|
|
10
|
-
}
|
|
11
|
-
.lg {
|
|
12
|
-
@apply size-[20px];
|
|
13
|
-
}
|
|
14
|
-
/*---- Tick Sizes Class ---- */
|
|
15
|
-
.xsm svg {
|
|
16
|
-
@apply size-[10.5px];
|
|
17
|
-
}
|
|
18
|
-
.sm svg {
|
|
19
|
-
@apply size-[12px];
|
|
20
|
-
}
|
|
21
|
-
.md svg {
|
|
22
|
-
@apply size-[13.5px];
|
|
23
|
-
}
|
|
24
|
-
.lg svg {
|
|
25
|
-
@apply size-[14px];
|
|
26
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
<div
|
|
2
|
-
class="inline-flex items-center gap-2 cursor-pointer group outline-none"
|
|
3
|
-
(click)="toggle()"
|
|
4
|
-
(keydown.enter)="toggle()"
|
|
5
|
-
(keydown.space)="$event.preventDefault(); toggle()"
|
|
6
|
-
tabindex="0"
|
|
7
|
-
[attr.aria-disabled]="disabled">
|
|
8
|
-
<div
|
|
9
|
-
class="relative flex items-center justify-center border-2 transition-all duration-200 ease-in-out rounded group-focus-visible:ring-2 group-focus-visible:ring-blue-600 group-focus-visible:ring-offset-2"
|
|
10
|
-
[ngClass]="[
|
|
11
|
-
checkboxClass,
|
|
12
|
-
isChecked && !disabled ? 'bg-black border-black' : '',
|
|
13
|
-
!isChecked && !disabled ? 'bg-white border-gray-300 group-hover:border-gray-400' : '',
|
|
14
|
-
disabled && isChecked ? 'bg-gray-300 border-gray-300' : '',
|
|
15
|
-
disabled && !isChecked ? 'bg-gray-100 border-gray-200' : '',
|
|
16
|
-
disabled ? 'cursor-not-allowed' : ''
|
|
17
|
-
]"
|
|
18
|
-
>
|
|
19
|
-
<svg
|
|
20
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
-
viewBox="0 0 24 24"
|
|
22
|
-
fill="none"
|
|
23
|
-
stroke="currentColor"
|
|
24
|
-
stroke-width="3.5"
|
|
25
|
-
stroke-linecap="round"
|
|
26
|
-
stroke-linejoin="round"
|
|
27
|
-
class="text-white pointer-events-none transition-opacity duration-200"
|
|
28
|
-
[class.opacity-0]="!isChecked"
|
|
29
|
-
[class.opacity-100]="isChecked"
|
|
30
|
-
>
|
|
31
|
-
<polyline points="20 6 9 17 4 12"></polyline>
|
|
32
|
-
</svg>
|
|
33
|
-
</div>
|
|
34
|
-
@if(label){
|
|
35
|
-
<span
|
|
36
|
-
[ngClass]="disabled ? 'text-gray-400' : ''"
|
|
37
|
-
class="font-medium text-xs text-[#1B223A] select-none {{labelClass}}"
|
|
38
|
-
>
|
|
39
|
-
{{ label }}
|
|
40
|
-
</span>
|
|
41
|
-
}
|
|
42
|
-
</div>
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { Component, Input, Output, EventEmitter, forwardRef, ViewEncapsulation } from '@angular/core';
|
|
2
|
-
import { CommonModule } from '@angular/common';
|
|
3
|
-
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
4
|
-
|
|
5
|
-
@Component({
|
|
6
|
-
selector: 'brickclay-checkbox',
|
|
7
|
-
standalone: true,
|
|
8
|
-
imports: [CommonModule],
|
|
9
|
-
encapsulation: ViewEncapsulation.None,
|
|
10
|
-
templateUrl: './checkbox.html',
|
|
11
|
-
styleUrls: ['./checkbox.css'],
|
|
12
|
-
providers: [
|
|
13
|
-
{
|
|
14
|
-
provide: NG_VALUE_ACCESSOR,
|
|
15
|
-
useExisting: forwardRef(() => CheckboxComponent),
|
|
16
|
-
multi: true
|
|
17
|
-
}
|
|
18
|
-
]
|
|
19
|
-
})
|
|
20
|
-
export class CheckboxComponent implements ControlValueAccessor {
|
|
21
|
-
|
|
22
|
-
@Input() checkboxClass: string = '';
|
|
23
|
-
@Input() label: string = '';
|
|
24
|
-
@Input() labelClass: string = '';
|
|
25
|
-
@Input() disabled: boolean = false;
|
|
26
|
-
|
|
27
|
-
@Output() change = new EventEmitter<boolean>();
|
|
28
|
-
|
|
29
|
-
// This is the value bound via ngModel
|
|
30
|
-
isChecked: boolean = false;
|
|
31
|
-
|
|
32
|
-
// ControlValueAccessor callbacks
|
|
33
|
-
private onChange = (_: any) => {};
|
|
34
|
-
private onTouched = () => {};
|
|
35
|
-
|
|
36
|
-
// Toggle function for click / keyboard
|
|
37
|
-
toggle() {
|
|
38
|
-
if (this.disabled) return;
|
|
39
|
-
|
|
40
|
-
this.isChecked = !this.isChecked;
|
|
41
|
-
|
|
42
|
-
// Update ngModel value
|
|
43
|
-
this.onChange(this.isChecked);
|
|
44
|
-
this.onTouched();
|
|
45
|
-
|
|
46
|
-
// Emit the change event
|
|
47
|
-
this.change.emit(this.isChecked);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** ------------------ ControlValueAccessor methods ------------------ */
|
|
51
|
-
|
|
52
|
-
writeValue(value: boolean): void {
|
|
53
|
-
this.isChecked = value ?? false; // handle null/undefined safely
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
registerOnChange(fn: any): void {
|
|
57
|
-
this.onChange = fn;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
registerOnTouched(fn: any): void {
|
|
61
|
-
this.onTouched = fn;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
setDisabledState(isDisabled: boolean): void {
|
|
65
|
-
this.disabled = isDisabled;
|
|
66
|
-
}
|
|
67
|
-
}
|
package/src/lib/radio/radio.css
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/*---- Checkbox Sizes Class ---- */
|
|
2
|
-
.xsm {
|
|
3
|
-
@apply size-[14px];
|
|
4
|
-
}
|
|
5
|
-
.sm {
|
|
6
|
-
@apply size-[16px];
|
|
7
|
-
}
|
|
8
|
-
.md {
|
|
9
|
-
@apply size-[18px];
|
|
10
|
-
}
|
|
11
|
-
.lg {
|
|
12
|
-
@apply size-[19px];
|
|
13
|
-
}
|
|
14
|
-
/*---- Dot Sizes Class ---- */
|
|
15
|
-
.xsm .dot {
|
|
16
|
-
@apply size-[6px];
|
|
17
|
-
}
|
|
18
|
-
.sm .dot {
|
|
19
|
-
@apply size-[8px];
|
|
20
|
-
}
|
|
21
|
-
.md .dot {
|
|
22
|
-
@apply size-[10px];
|
|
23
|
-
}
|
|
24
|
-
.lg .dot {
|
|
25
|
-
@apply size-[11px];
|
|
26
|
-
}
|
|
27
|
-
/*---- Tick Sizes Class ---- */
|
|
28
|
-
.xsm .tick {
|
|
29
|
-
@apply size-[8px];
|
|
30
|
-
}
|
|
31
|
-
.sm .tick {
|
|
32
|
-
@apply size-[9px];
|
|
33
|
-
}
|
|
34
|
-
.md .tick {
|
|
35
|
-
@apply size-[12px];
|
|
36
|
-
}
|
|
37
|
-
.lg .tick {
|
|
38
|
-
@apply size-[13px];
|
|
39
|
-
}
|
package/src/lib/radio/radio.html
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
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
|
|
11
|
-
group-focus-visible:ring-2 group-focus-visible:ring-blue-600 group-focus-visible:ring-offset-2"
|
|
12
|
-
[ngClass]="[
|
|
13
|
-
radioClass,
|
|
14
|
-
!isChecked && !disabled ? 'bg-white border-gray-300 group-hover:border-gray-400' : '',
|
|
15
|
-
variant === 'dot' && isChecked && !disabled ? 'border-black bg-white' : '',
|
|
16
|
-
variant === 'tick' && isChecked && !disabled ? 'bg-black border-black' : '',
|
|
17
|
-
disabled && isChecked && variant === 'tick' ? 'bg-gray-300 border-gray-300' : '',
|
|
18
|
-
disabled && isChecked && variant === 'dot' ? 'border-gray-300 bg-gray-50' : '',
|
|
19
|
-
disabled && !isChecked ? 'bg-gray-100 border-gray-200' : '',
|
|
20
|
-
disabled ? 'cursor-not-allowed' : ''
|
|
21
|
-
]"
|
|
22
|
-
>
|
|
23
|
-
|
|
24
|
-
@if (variant === 'dot') {
|
|
25
|
-
<span
|
|
26
|
-
class="rounded-full bg-black transition-transform duration-200 transform dot"
|
|
27
|
-
[class.scale-0]="!isChecked"
|
|
28
|
-
[class.scale-100]="isChecked"
|
|
29
|
-
[class.bg-gray-400]="disabled">
|
|
30
|
-
</span>
|
|
31
|
-
}
|
|
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
|
-
<polyline points="20 6 9 17 4 12"></polyline>
|
|
46
|
-
</svg>
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
</div>
|
|
50
|
-
|
|
51
|
-
@if (label) {
|
|
52
|
-
<span
|
|
53
|
-
class="font-medium text-xs text-[#1B223A] select-none"
|
|
54
|
-
[ngClass]="[labelClass, disabled ? 'text-gray-400' : '']">
|
|
55
|
-
{{ label }}
|
|
56
|
-
</span>
|
|
57
|
-
}
|
|
58
|
-
</div>
|
package/src/lib/radio/radio.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
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 {
|
|
11
|
-
ControlValueAccessor,
|
|
12
|
-
NG_VALUE_ACCESSOR,
|
|
13
|
-
FormsModule
|
|
14
|
-
} from '@angular/forms';
|
|
15
|
-
|
|
16
|
-
@Component({
|
|
17
|
-
selector: 'brickclay-radio-button',
|
|
18
|
-
standalone: true,
|
|
19
|
-
imports: [CommonModule, FormsModule],
|
|
20
|
-
encapsulation: ViewEncapsulation.None,
|
|
21
|
-
templateUrl: './radio.html',
|
|
22
|
-
styleUrl: './radio.css',
|
|
23
|
-
providers: [
|
|
24
|
-
{
|
|
25
|
-
provide: NG_VALUE_ACCESSOR,
|
|
26
|
-
useExisting: forwardRef(() => RadioComponent),
|
|
27
|
-
multi: true
|
|
28
|
-
}
|
|
29
|
-
]
|
|
30
|
-
})
|
|
31
|
-
export class RadioComponent implements ControlValueAccessor {
|
|
32
|
-
|
|
33
|
-
@Input() radioClass = '';
|
|
34
|
-
@Input() label = '';
|
|
35
|
-
@Input() labelClass = '';
|
|
36
|
-
@Input() value: any;
|
|
37
|
-
@Input() disabled = false;
|
|
38
|
-
@Input() variant: 'dot' | 'tick' = 'dot';
|
|
39
|
-
|
|
40
|
-
@Output() change = new EventEmitter<any>();
|
|
41
|
-
|
|
42
|
-
modelValue: any;
|
|
43
|
-
|
|
44
|
-
onChange = (_: any) => {};
|
|
45
|
-
onTouched = () => {};
|
|
46
|
-
|
|
47
|
-
select(): void {
|
|
48
|
-
if (this.disabled) return;
|
|
49
|
-
|
|
50
|
-
if (this.modelValue !== this.value) {
|
|
51
|
-
this.modelValue = this.value;
|
|
52
|
-
this.onChange(this.value);
|
|
53
|
-
this.onTouched();
|
|
54
|
-
this.change.emit(this.value);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
get isChecked(): boolean {
|
|
59
|
-
return this.modelValue === this.value;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
writeValue(value: any): void {
|
|
63
|
-
this.modelValue = value;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
registerOnChange(fn: any): void {
|
|
67
|
-
this.onChange = fn;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
registerOnTouched(fn: any): void {
|
|
71
|
-
this.onTouched = fn;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
setDisabledState(isDisabled: boolean): void {
|
|
75
|
-
this.disabled = isDisabled;
|
|
76
|
-
}
|
|
77
|
-
}
|