@brickclay-org/ui 0.0.4 β†’ 0.0.6

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 CHANGED
@@ -1,795 +1,1385 @@
1
- # @brickclay-org/ui
2
-
3
- A comprehensive Angular UI component library featuring a rich collection of customizable, accessible components. Built with modern Angular standards, this library provides everything you need to build beautiful and functional user interfaces.
4
-
5
- ## 🌟 Features
6
-
7
- - πŸ“¦ **Comprehensive Component Library** - Rich set of UI components for common use cases
8
- - β™Ώ **Accessible by Default** - WCAG compliant components with keyboard navigation and screen reader support
9
- - πŸš€ **Angular 20+ Ready** - Built with latest Angular features and standalone components
10
- - πŸ“± **Responsive Design** - Mobile-first components that work on all screen sizes
11
- - 🎯 **Type-Safe** - Full TypeScript support with comprehensive type definitions
12
- - ⚑ **Lightweight** - Tree-shakeable and optimized for performance
13
- - πŸŽ›οΈ **Highly Customizable** - Extensive configuration options for every component
14
-
15
- ## πŸ“š Available Components
16
-
17
- ### Calendar Components
18
-
19
- A powerful calendar suite with advanced date and time selection capabilities. The calendar components support single date selection, date ranges, multiple date selection, and integrated time pickers.
20
-
21
- ### Toggle Component
22
-
23
- A customizable toggle/switch component with support for Angular forms integration via `ngModel` and reactive forms. Features three size variants (small, medium, large), disabled state, and full accessibility support.
24
-
25
- *More components coming soon...*
26
-
27
- ## Installation
28
-
29
- ```bash
30
- npm install @brickclay-org/ui
31
- ```
32
-
33
- ### Peer Dependencies
34
-
35
- This library requires Angular 20.3.0 or higher:
36
-
37
- ```bash
38
- npm install @angular/common@^20.3.0 @angular/core@^20.3.0 moment
39
- ```
40
-
41
- ## Quick Start
42
-
43
- ### Standalone Component Usage (Recommended)
44
-
45
- ```typescript
46
- import { Component } from '@angular/core';
47
- import { CustomCalendarComponent, CalendarSelection } from '@brickclay/ui';
48
-
49
- @Component({
50
- standalone: true,
51
- selector: 'app-my-component',
52
- imports: [CustomCalendarComponent],
53
- template: `
54
- <brickclay-custom-calendar
55
- (selected)="onDateSelected($event)">
56
- </brickclay-custom-calendar>
57
- `
58
- })
59
- export class MyComponent {
60
- onDateSelected(selection: CalendarSelection) {
61
- console.log('Selected:', selection);
62
- }
63
- }
64
- ```
65
-
66
- ### Module-based Usage
67
-
68
- ```typescript
69
- import { NgModule } from '@angular/core';
70
- import { CalendarModule } from '@brickclay/ui';
71
-
72
- @NgModule({
73
- imports: [CalendarModule],
74
- // ...
75
- })
76
- export class AppModule {}
77
- ```
78
-
79
- ## πŸ“… Calendar
80
-
81
- The calendar components provide a complete solution for date and time selection in your Angular applications. All components are standalone and can be imported individually or as part of the `CalendarModule`.
82
-
83
- ### Components Overview
84
-
85
- 1. **CustomCalendarComponent** (`brickclay-custom-calendar`) - Main calendar component with support for single date, date range, and multiple date selection
86
- 2. **ScheduledDatePickerComponent** (`brickclay-scheduled-date-picker`) - Advanced scheduling component with time configuration for events
87
- 3. **TimePickerComponent** (`brickclay-time-picker`) - Standalone time selection component with scrollable pickers
88
-
89
- ### CustomCalendarComponent
90
-
91
- A versatile calendar component that supports single date, date range, and multiple date selection modes.
92
-
93
- #### Basic Example
94
-
95
- ```typescript
96
- import { CustomCalendarComponent, CalendarSelection } from '@brickclay/ui';
97
-
98
- @Component({
99
- template: `
100
- <brickclay-custom-calendar
101
- [singleDatePicker]="false"
102
- [dualCalendar]="true"
103
- [enableTimepicker]="true"
104
- [showRanges]="true"
105
- [placeholder]="'Select date range'"
106
- (selected)="onDateSelected($event)">
107
- </brickclay-custom-calendar>
108
- `
109
- })
110
- export class MyComponent {
111
- onDateSelected(selection: CalendarSelection) {
112
- console.log('Start:', selection.startDate);
113
- console.log('End:', selection.endDate);
114
- }
115
- }
116
- ```
117
-
118
- #### Component Selector
119
-
120
- `<brickclay-custom-calendar>`
121
-
122
- #### Inputs
123
-
124
- | Input | Type | Default | Description |
125
- |-------|------|---------|-------------|
126
- | `enableTimepicker` | `boolean` | `false` | Enable time selection |
127
- | `autoApply` | `boolean` | `false` | Automatically apply selection when date is chosen |
128
- | `closeOnAutoApply` | `boolean` | `false` | Close calendar after auto-apply |
129
- | `showCancel` | `boolean` | `true` | Show cancel button in footer |
130
- | `singleDatePicker` | `boolean` | `false` | Enable single date selection mode |
131
- | `dualCalendar` | `boolean` | `false` | Show two calendars side-by-side |
132
- | `showRanges` | `boolean` | `true` | Show predefined date range buttons |
133
- | `multiDateSelection` | `boolean` | `false` | Enable multiple date selection |
134
- | `inline` | `boolean` | `false` | Always show calendar (no dropdown) |
135
- | `minDate` | `Date` | `undefined` | Minimum selectable date |
136
- | `maxDate` | `Date` | `undefined` | Maximum selectable date |
137
- | `placeholder` | `string` | `'Select date range'` | Input placeholder text |
138
- | `opens` | `'left' \| 'right' \| 'center'` | `'left'` | Dropdown alignment |
139
- | `drop` | `'up' \| 'down'` | `'down'` | Dropdown direction |
140
- | `displayFormat` | `string` | `'MM/DD/YYYY'` | Date display format (moment format) |
141
- | `customRanges` | `Record<string, CalendarRange>` | `undefined` | Custom predefined ranges |
142
- | `selectedValue` | `CalendarSelection \| null` | `null` | Pre-selected date(s) |
143
- | `isDisplayCrossIcon` | `boolean` | `true` | Show/hide clear button |
144
-
145
- #### Outputs
146
-
147
- | Output | Type | Description |
148
- |--------|------|-------------|
149
- | `selected` | `EventEmitter<CalendarSelection>` | Emitted when date selection changes |
150
- | `opened` | `EventEmitter<void>` | Emitted when calendar opens |
151
- | `closed` | `EventEmitter<void>` | Emitted when calendar closes |
152
-
153
- #### Usage Examples
154
-
155
- **Single Date Selection:**
156
-
157
- ```typescript
158
- <brickclay-custom-calendar
159
- [singleDatePicker]="true"
160
- [placeholder]="'Select a date'"
161
- (selected)="onDateSelected($event)">
162
- </brickclay-custom-calendar>
163
- ```
164
-
165
- **Date Range with Time Picker:**
166
-
167
- ```typescript
168
- <brickclay-custom-calendar
169
- [dualCalendar]="true"
170
- [enableTimepicker]="true"
171
- [enableSeconds]="true"
172
- (selected)="onRangeSelected($event)">
173
- </brickclay-custom-calendar>
174
- ```
175
-
176
- **Multiple Date Selection:**
177
-
178
- ```typescript
179
- <brickclay-custom-calendar
180
- [multiDateSelection]="true"
181
- [inline]="true"
182
- (selected)="onMultipleDatesSelected($event)">
183
- </brickclay-custom-calendar>
184
- ```
185
-
186
- **Inline Calendar:**
187
-
188
- ```typescript
189
- <brickclay-custom-calendar
190
- [inline]="true"
191
- [dualCalendar]="false"
192
- [showRanges]="false"
193
- (selected)="onDateSelected($event)">
194
- </brickclay-custom-calendar>
195
- ```
196
-
197
- **Custom Date Ranges:**
198
-
199
- ```typescript
200
- import { CalendarRange } from '@brickclay/ui';
201
-
202
- const customRanges: Record<string, CalendarRange> = {
203
- 'Last Week': {
204
- start: new Date(2024, 0, 1),
205
- end: new Date(2024, 0, 7)
206
- },
207
- 'This Quarter': {
208
- start: new Date(2024, 0, 1),
209
- end: new Date(2024, 2, 31)
210
- }
211
- };
212
-
213
- <brickclay-custom-calendar
214
- [customRanges]="customRanges"
215
- [showRanges]="true"
216
- (selected)="onDateSelected($event)">
217
- </brickclay-custom-calendar>
218
- ```
219
-
220
- **Date Constraints:**
221
-
222
- ```typescript
223
- <brickclay-custom-calendar
224
- [minDate]="new Date(2024, 0, 1)"
225
- [maxDate]="new Date(2024, 11, 31)"
226
- (selected)="onDateSelected($event)">
227
- </brickclay-custom-calendar>
228
- ```
229
-
230
- **Pre-selected Values:**
231
-
232
- ```typescript
233
- export class MyComponent {
234
- selectedValue: CalendarSelection = {
235
- startDate: new Date(2024, 5, 15),
236
- endDate: new Date(2024, 5, 20)
237
- };
238
-
239
- onDateChange() {
240
- this.selectedValue = {
241
- startDate: new Date(),
242
- endDate: new Date()
243
- };
244
- }
245
- }
246
-
247
- <brickclay-custom-calendar
248
- [selectedValue]="selectedValue"
249
- (selected)="onDateSelected($event)">
250
- </brickclay-custom-calendar>
251
- ```
252
-
253
- ### ScheduledDatePickerComponent
254
-
255
- A comprehensive date and time scheduling component with three modes: single date, multiple dates, and date range, each with time configuration.
256
-
257
- #### Basic Example
258
-
259
- ```typescript
260
- import { ScheduledDatePickerComponent, ScheduledDateSelection } from '@brickclay/ui';
261
-
262
- @Component({
263
- template: `
264
- <brickclay-scheduled-date-picker
265
- [timeFormat]="12"
266
- (scheduled)="onScheduled($event)">
267
- </brickclay-scheduled-date-picker>
268
- `
269
- })
270
- export class MyComponent {
271
- onScheduled(selection: ScheduledDateSelection) {
272
- console.log('Mode:', selection.mode);
273
- if (selection.mode === 'single' && selection.singleDate) {
274
- console.log('Start:', selection.singleDate.startDate);
275
- console.log('End:', selection.singleDate.endDate);
276
- console.log('All Day:', selection.singleDate.allDay);
277
- }
278
- }
279
- }
280
- ```
281
-
282
- #### Component Selector
283
-
284
- `<brickclay-scheduled-date-picker>`
285
-
286
- #### Inputs
287
-
288
- | Input | Type | Default | Description |
289
- |-------|------|---------|-------------|
290
- | `timeFormat` | `12 \| 24` | `12` | Time format (12-hour or 24-hour) |
291
- | `enableSeconds` | `boolean` | `false` | Enable seconds in time picker |
292
-
293
- #### Outputs
294
-
295
- | Output | Type | Description |
296
- |--------|------|-------------|
297
- | `scheduled` | `EventEmitter<ScheduledDateSelection>` | Emitted when selection changes |
298
- | `cleared` | `EventEmitter<void>` | Emitted when clear button is clicked |
299
-
300
- #### Features
301
-
302
- - **Single Date Mode**: Select one date with optional start and end times
303
- - **Multiple Dates Mode**: Select multiple dates, each with individual time configuration
304
- - **Date Range Mode**: Select a date range with start and end times
305
- - **All Day Toggle**: Mark dates as all-day events
306
- - **Time Configuration**: Individual time pickers for each date/range
307
-
308
- ### TimePickerComponent
309
-
310
- A standalone time picker component with scrollable hour, minute, and AM/PM selectors.
311
-
312
- #### Basic Example
313
-
314
- ```typescript
315
- import { TimePickerComponent } from '@brickclay/ui';
316
-
317
- @Component({
318
- template: `
319
- <brickclay-time-picker
320
- [value]="selectedTime"
321
- [label]="'Start Time'"
322
- [timeFormat]="12"
323
- (timeChange)="onTimeChange($event)">
324
- </brickclay-time-picker>
325
- `
326
- })
327
- export class MyComponent {
328
- selectedTime = '1:00 AM';
329
-
330
- onTimeChange(time: string) {
331
- this.selectedTime = time;
332
- console.log('New time:', time);
333
- }
334
- }
335
- ```
336
-
337
- #### Component Selector
338
-
339
- `<brickclay-time-picker>`
340
-
341
- #### Inputs
342
-
343
- | Input | Type | Default | Description |
344
- |-------|------|---------|-------------|
345
- | `value` | `string` | `'1:00 AM'` | Current time value (format: "H:MM AM/PM" or "HH:MM") |
346
- | `label` | `string` | `'Time'` | Label text |
347
- | `placeholder` | `string` | `'Select time'` | Placeholder text |
348
- | `position` | `'left' \| 'right'` | `'left'` | Dropdown position |
349
- | `pickerId` | `string` | `''` | Unique identifier for the picker |
350
- | `closePicker` | `number` | `0` | Counter to trigger picker close |
351
- | `timeFormat` | `12 \| 24` | `12` | Time format (12-hour or 24-hour) |
352
- | `showSeconds` | `boolean` | `false` | Show seconds selector |
353
-
354
- #### Outputs
355
-
356
- | Output | Type | Description |
357
- |--------|------|-------------|
358
- | `timeChange` | `EventEmitter<string>` | Emitted when time changes |
359
- | `pickerOpened` | `EventEmitter<string>` | Emitted when picker opens |
360
- | `pickerClosed` | `EventEmitter<string>` | Emitted when picker closes |
361
-
362
- #### Features
363
-
364
- - Scrollable time selectors
365
- - Keyboard navigation support
366
- - 12-hour and 24-hour formats
367
- - Optional seconds support
368
- - Multiple picker coordination (only one open at a time)
369
- - Click outside to close
370
-
371
- #### Time Format Examples
372
-
373
- **12-hour format:**
374
- ```typescript
375
- value="1:00 AM"
376
- value="12:30 PM"
377
- value="11:45 PM"
378
- ```
379
-
380
- **24-hour format:**
381
- ```typescript
382
- value="01:00"
383
- value="13:30"
384
- value="23:45"
385
- ```
386
-
387
- ## πŸ”˜ Toggle
388
-
389
- A versatile toggle/switch component that integrates seamlessly with Angular forms. Supports both template-driven forms (`ngModel`) and reactive forms, with full accessibility features and keyboard navigation.
390
-
391
- ### ToggleComponent
392
-
393
- A standalone toggle component that implements `ControlValueAccessor` for seamless Angular forms integration.
394
-
395
- #### Basic Example
396
-
397
- ```typescript
398
- import { ToggleComponent } from '@brickclay/ui';
399
- import { FormsModule } from '@angular/forms';
400
-
401
- @Component({
402
- template: `
403
- <brickclay-toggle
404
- [(ngModel)]="isEnabled"
405
- [label]="'Enable notifications'"
406
- (change)="onToggleChange($event)">
407
- </brickclay-toggle>
408
- `,
409
- imports: [ToggleComponent, FormsModule]
410
- })
411
- export class MyComponent {
412
- isEnabled = false;
413
-
414
- onToggleChange(value: boolean) {
415
- console.log('Toggle state:', value);
416
- }
417
- }
418
- ```
419
-
420
- #### Component Selector
421
-
422
- `<brickclay-toggle>`
423
-
424
- #### Inputs
425
-
426
- | Input | Type | Default | Description |
427
- |-------|------|---------|-------------|
428
- | `label` | `string` | `''` | Optional label text displayed next to the toggle |
429
- | `disabled` | `boolean` | `false` | Disables the toggle interaction |
430
- | `toggleClass` | `string` | `'toggle-md'` | CSS class for size styling. Options: `'toggle-sm'`, `'toggle-md'`, `'toggle-lg'` |
431
-
432
- #### Outputs
433
-
434
- | Output | Type | Description |
435
- |--------|------|-------------|
436
- | `change` | `EventEmitter<boolean>` | Emitted when toggle state changes (returns new boolean value) |
437
-
438
- #### Features
439
-
440
- - βœ… **Angular Forms Integration** - Full support for `ngModel` and reactive forms
441
- - βœ… **Three Size Variants** - Small (`toggle-sm`), Medium (`toggle-md`), Large (`toggle-lg`)
442
- - βœ… **Accessibility** - ARIA attributes, keyboard navigation, and screen reader support
443
- - βœ… **Disabled State** - Visual and functional disabled state
444
- - βœ… **Customizable Styling** - Custom CSS classes for size and appearance
445
- - βœ… **Event Handling** - `change` event for state change notifications
446
-
447
- #### Usage Examples
448
-
449
- **Basic Toggle with ngModel:**
450
-
451
- ```typescript
452
- import { ToggleComponent } from '@brickclay/ui';
453
- import { FormsModule } from '@angular/forms';
454
-
455
- @Component({
456
- template: `
457
- <brickclay-toggle
458
- [(ngModel)]="isActive"
459
- [label]="'Active Status'">
460
- </brickclay-toggle>
461
- `,
462
- imports: [ToggleComponent, FormsModule]
463
- })
464
- export class MyComponent {
465
- isActive = true;
466
- }
467
- ```
468
-
469
- **Different Sizes:**
470
-
471
- ```typescript
472
- <brickclay-toggle
473
- [(ngModel)]="value1"
474
- [toggleClass]="'toggle-sm'"
475
- [label]="'Small Toggle'">
476
- </brickclay-toggle>
477
-
478
- <brickclay-toggle
479
- [(ngModel)]="value2"
480
- [toggleClass]="'toggle-md'"
481
- [label]="'Medium Toggle'">
482
- </brickclay-toggle>
483
-
484
- <brickclay-toggle
485
- [(ngModel)]="value3"
486
- [toggleClass]="'toggle-lg'"
487
- [label]="'Large Toggle'">
488
- </brickclay-toggle>
489
- ```
490
-
491
- **Disabled State:**
492
-
493
- ```typescript
494
- <brickclay-toggle
495
- [ngModel]="true"
496
- [disabled]="true"
497
- [label]="'Disabled Toggle'">
498
- </brickclay-toggle>
499
- ```
500
-
501
- **With Event Handler:**
502
-
503
- ```typescript
504
- @Component({
505
- template: `
506
- <brickclay-toggle
507
- [(ngModel)]="notificationsEnabled"
508
- [label]="'Email Notifications'"
509
- (change)="onNotificationToggle($event)">
510
- </brickclay-toggle>
511
- `
512
- })
513
- export class MyComponent {
514
- notificationsEnabled = false;
515
-
516
- onNotificationToggle(enabled: boolean) {
517
- if (enabled) {
518
- this.enableNotifications();
519
- } else {
520
- this.disableNotifications();
521
- }
522
- }
523
- }
524
- ```
525
-
526
- **Reactive Forms Integration:**
527
-
528
- ```typescript
529
- import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
530
- import { ToggleComponent } from '@brickclay/ui';
531
-
532
- @Component({
533
- template: `
534
- <form [formGroup]="settingsForm">
535
- <brickclay-toggle
536
- formControlName="darkMode"
537
- [label]="'Dark Mode'">
538
- </brickclay-toggle>
539
-
540
- <brickclay-toggle
541
- formControlName="notifications"
542
- [label]="'Push Notifications'">
543
- </brickclay-toggle>
544
- </form>
545
- `,
546
- imports: [ToggleComponent, ReactiveFormsModule]
547
- })
548
- export class SettingsComponent {
549
- settingsForm: FormGroup;
550
-
551
- constructor(private fb: FormBuilder) {
552
- this.settingsForm = this.fb.group({
553
- darkMode: [false],
554
- notifications: [true]
555
- });
556
- }
557
- }
558
- ```
559
-
560
- **Without Label:**
561
-
562
- ```typescript
563
- <brickclay-toggle
564
- [(ngModel)]="isEnabled"
565
- [toggleClass]="'toggle-md'">
566
- </brickclay-toggle>
567
- ```
568
-
569
- #### Styling
570
-
571
- The toggle component uses CSS classes for size variants:
572
-
573
- - **Small**: `toggle-sm` - Width: 28px (w-7)
574
- - **Medium**: `toggle-md` - Width: 36px (w-9) - Default
575
- - **Large**: `toggle-lg` - Width: 44px (w-11)
576
-
577
- The component includes built-in styles for:
578
- - On state (green background: `#22973F`)
579
- - Off state (gray background: `#BBBDC5`)
580
- - Disabled state (light gray: `#D6D7DC`)
581
- - Hover states
582
- - Focus ring for accessibility
583
- - Smooth transitions
584
-
585
- #### Accessibility
586
-
587
- The toggle component includes:
588
- - `role="switch"` for screen readers
589
- - `aria-checked` attribute that reflects the current state
590
- - Keyboard navigation support
591
- - Focus visible ring for keyboard users
592
- - Disabled state properly communicated to assistive technologies
593
-
594
- ## πŸ“ TypeScript Interfaces
595
-
596
- ### CalendarRange
597
-
598
- ```typescript
599
- interface CalendarRange {
600
- start: Date;
601
- end: Date;
602
- }
603
- ```
604
-
605
- ### CalendarSelection
606
-
607
- ```typescript
608
- interface CalendarSelection {
609
- startDate: Date | null;
610
- endDate: Date | null;
611
- selectedDates?: Date[]; // For multi-date selection
612
- }
613
- ```
614
-
615
- ### TimeConfiguration
616
-
617
- ```typescript
618
- interface TimeConfiguration {
619
- date: Date;
620
- allDay: boolean;
621
- startTime: string; // Format: "HH:mm" or "HH:mm:ss"
622
- endTime: string;
623
- }
624
- ```
625
-
626
- ### ScheduledDateSelection
627
-
628
- ```typescript
629
- interface ScheduledDateSelection {
630
- mode: 'single' | 'multiple' | 'range';
631
- singleDate?: {
632
- startDate: Date;
633
- endDate: Date;
634
- allDay: boolean;
635
- startTime: string;
636
- endTime: string;
637
- };
638
- multipleDates?: TimeConfiguration[];
639
- dateRange?: {
640
- startDate: Date;
641
- endDate: Date;
642
- allDay: boolean;
643
- startTime: string;
644
- endTime: string;
645
- };
646
- }
647
- ```
648
-
649
- ## 🎯 Common Use Cases
650
-
651
- ### Form Integration
652
-
653
- ```typescript
654
- import { FormBuilder, FormGroup, Validators } from '@angular/forms';
655
- import { CustomCalendarComponent } from '@brickclay/ui';
656
-
657
- export class BookingFormComponent {
658
- bookingForm: FormGroup;
659
-
660
- constructor(private fb: FormBuilder) {
661
- this.bookingForm = this.fb.group({
662
- checkIn: [null, Validators.required],
663
- checkOut: [null, Validators.required]
664
- });
665
- }
666
-
667
- onDateSelected(selection: CalendarSelection) {
668
- this.bookingForm.patchValue({
669
- checkIn: selection.startDate,
670
- checkOut: selection.endDate
671
- });
672
- }
673
- }
674
- ```
675
-
676
- ### Reactive Forms
677
-
678
- ```typescript
679
- <brickclay-custom-calendar
680
- [selectedValue]="form.get('dateRange')?.value"
681
- (selected)="form.patchValue({ dateRange: $event })">
682
- </brickclay-custom-calendar>
683
- ```
684
-
685
- ### Date Filtering
686
-
687
- ```typescript
688
- export class DataTableComponent {
689
- filterDates: CalendarSelection = { startDate: null, endDate: null };
690
-
691
- onDateFilter(selection: CalendarSelection) {
692
- this.filterDates = selection;
693
- this.loadFilteredData();
694
- }
695
-
696
- loadFilteredData() {
697
- const filtered = this.data.filter(item => {
698
- if (!this.filterDates.startDate || !this.filterDates.endDate) {
699
- return true;
700
- }
701
- return item.date >= this.filterDates.startDate! &&
702
- item.date <= this.filterDates.endDate!;
703
- });
704
- }
705
- }
706
- ```
707
-
708
- ## πŸ“¦ Assets Configuration
709
-
710
- The calendar components require SVG icons. Configure your `angular.json` to copy assets:
711
-
712
- ```json
713
- {
714
- "glob": "**/*",
715
- "input": "node_modules/@brickclay/ui/assets",
716
- "output": "assets"
717
- }
718
- ```
719
-
720
- Or manually copy assets from:
721
- ```
722
- node_modules/@brickclay/ui/assets/calender/* β†’ your-app/public/assets/calender/
723
- ```
724
-
725
- ## πŸ”§ Service
726
-
727
- ### CalendarManagerService
728
-
729
- A service that manages multiple calendar instances, ensuring only one calendar is open at a time when not in inline mode. Used internally by `CustomCalendarComponent`.
730
-
731
- ## 🌐 Browser Support
732
-
733
- - Chrome (latest)
734
- - Firefox (latest)
735
- - Safari (latest)
736
- - Edge (latest)
737
-
738
- ## πŸ“¦ Dependencies
739
-
740
- - Angular 20.3.0+
741
- - moment (for date formatting)
742
-
743
- ## 🀝 Contributing
744
-
745
- We welcome contributions! Please see our contributing guidelines for more information.
746
-
747
- ## πŸ“„ License
748
-
749
- MIT
750
-
751
- ## πŸ“ž Support
752
-
753
- For issues, feature requests, or contributions, please visit our [GitHub repository](https://github.com/brickclay/ui).
754
-
755
- ## πŸ—ΊοΈ Roadmap
756
-
757
- - [ ] Button components
758
- - [ ] Input components
759
- - [ ] Card components
760
- - [ ] Modal/Dialog components
761
- - [ ] Table components
762
- - [ ] Form components
763
- - [ ] Navigation components
764
- - [ ] Loading/Spinner components
765
- - [ ] Toast/Notification components
766
- - [ ] More calendar features
767
-
768
- ## πŸ“ Changelog
769
-
770
- ### Version 0.0.1
771
-
772
- **Initial Release:**
773
- - βœ… Calendar component suite
774
- - Single date selection
775
- - Date range selection
776
- - Multiple date selection
777
- - Time picker integration
778
- - Inline and dropdown modes
779
- - Dual calendar view
780
- - Custom date ranges
781
- - Date constraints (min/max)
782
- - βœ… Scheduled date picker component
783
- - βœ… Standalone time picker component
784
- - βœ… Toggle/Switch component
785
- - Angular forms integration (ngModel & reactive forms)
786
- - Three size variants (small, medium, large)
787
- - Disabled state support
788
- - Full accessibility features
789
- - Customizable styling
790
- - βœ… TypeScript definitions
791
- - βœ… Comprehensive documentation
792
-
793
- ---
794
-
795
- **Built with ❀️ by the Brickclay team**
1
+ # @brickclay-org/ui
2
+
3
+ A comprehensive Angular UI component library featuring a rich collection of customizable, accessible components. Built with modern Angular standards, this library provides everything you need to build beautiful and functional user interfaces.
4
+
5
+ ## 🌟 Features
6
+
7
+ - πŸ“¦ **Comprehensive Component Library** - Rich set of UI components for common use cases
8
+ - β™Ώ **Accessible by Default** - WCAG compliant components with keyboard navigation and screen reader support
9
+ - πŸš€ **Angular 20+ Ready** - Built with latest Angular features and standalone components
10
+ - πŸ“± **Responsive Design** - Mobile-first components that work on all screen sizes
11
+ - 🎯 **Type-Safe** - Full TypeScript support with comprehensive type definitions
12
+ - ⚑ **Lightweight** - Tree-shakeable and optimized for performance
13
+ - πŸŽ›οΈ **Highly Customizable** - Extensive configuration options for every component
14
+
15
+ ## πŸ“š Available Components
16
+
17
+ ### Calendar Components
18
+
19
+ A powerful calendar suite with advanced date and time selection capabilities. The calendar components support single date selection, date ranges, multiple date selection, and integrated time pickers.
20
+
21
+ ### Toggle Component
22
+
23
+ A customizable toggle/switch component with support for Angular forms integration via `ngModel` and reactive forms. Features three size variants (small, medium, large), disabled state, and full accessibility support.
24
+
25
+ ### Checkbox Component
26
+
27
+ A fully accessible checkbox component with Angular forms integration. Features customizable styling via CSS classes, disabled state, keyboard navigation, and seamless integration with both template-driven and reactive forms.
28
+
29
+ ### Radio Component
30
+
31
+ A fully accessible radio button component with Angular forms integration. Features two visual variants (dot and tick), customizable styling, disabled state, keyboard navigation, and seamless integration with both template-driven and reactive forms.
32
+
33
+ *More components coming soon...*
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ npm i @brickclay-org/ui@0.0.5
39
+ ```
40
+
41
+ ### Peer Dependencies
42
+
43
+ This library requires Angular 20.3.0 or higher:
44
+
45
+ ```bash
46
+ npm install @angular/common@^20.3.0 @angular/core@^20.3.0 moment
47
+ ```
48
+
49
+ ## Quick Start
50
+
51
+ ### Standalone Component Usage (Recommended)
52
+
53
+ ```typescript
54
+ import { Component } from '@angular/core';
55
+ import { CustomCalendarComponent, CalendarSelection } from '@brickclay/ui';
56
+
57
+ @Component({
58
+ standalone: true,
59
+ selector: 'app-my-component',
60
+ imports: [CustomCalendarComponent],
61
+ template: `
62
+ <brickclay-custom-calendar
63
+ (selected)="onDateSelected($event)">
64
+ </brickclay-custom-calendar>
65
+ `
66
+ })
67
+ export class MyComponent {
68
+ onDateSelected(selection: CalendarSelection) {
69
+ console.log('Selected:', selection);
70
+ }
71
+ }
72
+ ```
73
+
74
+ ### Module-based Usage
75
+
76
+ ```typescript
77
+ import { NgModule } from '@angular/core';
78
+ import { CalendarModule } from '@brickclay/ui';
79
+
80
+ @NgModule({
81
+ imports: [CalendarModule],
82
+ // ...
83
+ })
84
+ export class AppModule {}
85
+ ```
86
+
87
+ ## πŸ“… Calendar
88
+
89
+ The calendar components provide a complete solution for date and time selection in your Angular applications. All components are standalone and can be imported individually or as part of the `CalendarModule`.
90
+
91
+ ### Components Overview
92
+
93
+ 1. **CustomCalendarComponent** (`brickclay-custom-calendar`) - Main calendar component with support for single date, date range, and multiple date selection
94
+ 2. **ScheduledDatePickerComponent** (`brickclay-scheduled-date-picker`) - Advanced scheduling component with time configuration for events
95
+ 3. **TimePickerComponent** (`brickclay-time-picker`) - Standalone time selection component with scrollable pickers
96
+
97
+ ### CustomCalendarComponent
98
+
99
+ A versatile calendar component that supports single date, date range, and multiple date selection modes.
100
+
101
+ #### Basic Example
102
+
103
+ ```typescript
104
+ import { CustomCalendarComponent, CalendarSelection } from '@brickclay/ui';
105
+
106
+ @Component({
107
+ template: `
108
+ <brickclay-custom-calendar
109
+ [singleDatePicker]="false"
110
+ [dualCalendar]="true"
111
+ [enableTimepicker]="true"
112
+ [showRanges]="true"
113
+ [placeholder]="'Select date range'"
114
+ (selected)="onDateSelected($event)">
115
+ </brickclay-custom-calendar>
116
+ `
117
+ })
118
+ export class MyComponent {
119
+ onDateSelected(selection: CalendarSelection) {
120
+ console.log('Start:', selection.startDate);
121
+ console.log('End:', selection.endDate);
122
+ }
123
+ }
124
+ ```
125
+
126
+ #### Component Selector
127
+
128
+ `<brickclay-custom-calendar>`
129
+
130
+ #### Inputs
131
+
132
+ | Input | Type | Default | Description |
133
+ |-------|------|---------|-------------|
134
+ | `enableTimepicker` | `boolean` | `false` | Enable time selection |
135
+ | `autoApply` | `boolean` | `false` | Automatically apply selection when date is chosen |
136
+ | `closeOnAutoApply` | `boolean` | `false` | Close calendar after auto-apply |
137
+ | `showCancel` | `boolean` | `true` | Show cancel button in footer |
138
+ | `singleDatePicker` | `boolean` | `false` | Enable single date selection mode |
139
+ | `dualCalendar` | `boolean` | `false` | Show two calendars side-by-side |
140
+ | `showRanges` | `boolean` | `true` | Show predefined date range buttons |
141
+ | `multiDateSelection` | `boolean` | `false` | Enable multiple date selection |
142
+ | `inline` | `boolean` | `false` | Always show calendar (no dropdown) |
143
+ | `minDate` | `Date` | `undefined` | Minimum selectable date |
144
+ | `maxDate` | `Date` | `undefined` | Maximum selectable date |
145
+ | `placeholder` | `string` | `'Select date range'` | Input placeholder text |
146
+ | `opens` | `'left' \| 'right' \| 'center'` | `'left'` | Dropdown alignment |
147
+ | `drop` | `'up' \| 'down'` | `'down'` | Dropdown direction |
148
+ | `displayFormat` | `string` | `'MM/DD/YYYY'` | Date display format (moment format) |
149
+ | `customRanges` | `Record<string, CalendarRange>` | `undefined` | Custom predefined ranges |
150
+ | `selectedValue` | `CalendarSelection \| null` | `null` | Pre-selected date(s) |
151
+ | `isDisplayCrossIcon` | `boolean` | `true` | Show/hide clear button |
152
+
153
+ #### Outputs
154
+
155
+ | Output | Type | Description |
156
+ |--------|------|-------------|
157
+ | `selected` | `EventEmitter<CalendarSelection>` | Emitted when date selection changes |
158
+ | `opened` | `EventEmitter<void>` | Emitted when calendar opens |
159
+ | `closed` | `EventEmitter<void>` | Emitted when calendar closes |
160
+
161
+ #### Usage Examples
162
+
163
+ **Single Date Selection:**
164
+
165
+ ```typescript
166
+ <brickclay-custom-calendar
167
+ [singleDatePicker]="true"
168
+ [placeholder]="'Select a date'"
169
+ (selected)="onDateSelected($event)">
170
+ </brickclay-custom-calendar>
171
+ ```
172
+
173
+ **Date Range with Time Picker:**
174
+
175
+ ```typescript
176
+ <brickclay-custom-calendar
177
+ [dualCalendar]="true"
178
+ [enableTimepicker]="true"
179
+ [enableSeconds]="true"
180
+ (selected)="onRangeSelected($event)">
181
+ </brickclay-custom-calendar>
182
+ ```
183
+
184
+ **Multiple Date Selection:**
185
+
186
+ ```typescript
187
+ <brickclay-custom-calendar
188
+ [multiDateSelection]="true"
189
+ [inline]="true"
190
+ (selected)="onMultipleDatesSelected($event)">
191
+ </brickclay-custom-calendar>
192
+ ```
193
+
194
+ **Inline Calendar:**
195
+
196
+ ```typescript
197
+ <brickclay-custom-calendar
198
+ [inline]="true"
199
+ [dualCalendar]="false"
200
+ [showRanges]="false"
201
+ (selected)="onDateSelected($event)">
202
+ </brickclay-custom-calendar>
203
+ ```
204
+
205
+ **Custom Date Ranges:**
206
+
207
+ ```typescript
208
+ import { CalendarRange } from '@brickclay/ui';
209
+
210
+ const customRanges: Record<string, CalendarRange> = {
211
+ 'Last Week': {
212
+ start: new Date(2024, 0, 1),
213
+ end: new Date(2024, 0, 7)
214
+ },
215
+ 'This Quarter': {
216
+ start: new Date(2024, 0, 1),
217
+ end: new Date(2024, 2, 31)
218
+ }
219
+ };
220
+
221
+ <brickclay-custom-calendar
222
+ [customRanges]="customRanges"
223
+ [showRanges]="true"
224
+ (selected)="onDateSelected($event)">
225
+ </brickclay-custom-calendar>
226
+ ```
227
+
228
+ **Date Constraints:**
229
+
230
+ ```typescript
231
+ <brickclay-custom-calendar
232
+ [minDate]="new Date(2024, 0, 1)"
233
+ [maxDate]="new Date(2024, 11, 31)"
234
+ (selected)="onDateSelected($event)">
235
+ </brickclay-custom-calendar>
236
+ ```
237
+
238
+ **Pre-selected Values:**
239
+
240
+ ```typescript
241
+ export class MyComponent {
242
+ selectedValue: CalendarSelection = {
243
+ startDate: new Date(2024, 5, 15),
244
+ endDate: new Date(2024, 5, 20)
245
+ };
246
+
247
+ onDateChange() {
248
+ this.selectedValue = {
249
+ startDate: new Date(),
250
+ endDate: new Date()
251
+ };
252
+ }
253
+ }
254
+
255
+ <brickclay-custom-calendar
256
+ [selectedValue]="selectedValue"
257
+ (selected)="onDateSelected($event)">
258
+ </brickclay-custom-calendar>
259
+ ```
260
+
261
+ ### ScheduledDatePickerComponent
262
+
263
+ A comprehensive date and time scheduling component with three modes: single date, multiple dates, and date range, each with time configuration.
264
+
265
+ #### Basic Example
266
+
267
+ ```typescript
268
+ import { ScheduledDatePickerComponent, ScheduledDateSelection } from '@brickclay/ui';
269
+
270
+ @Component({
271
+ template: `
272
+ <brickclay-scheduled-date-picker
273
+ [timeFormat]="12"
274
+ (scheduled)="onScheduled($event)">
275
+ </brickclay-scheduled-date-picker>
276
+ `
277
+ })
278
+ export class MyComponent {
279
+ onScheduled(selection: ScheduledDateSelection) {
280
+ console.log('Mode:', selection.mode);
281
+ if (selection.mode === 'single' && selection.singleDate) {
282
+ console.log('Start:', selection.singleDate.startDate);
283
+ console.log('End:', selection.singleDate.endDate);
284
+ console.log('All Day:', selection.singleDate.allDay);
285
+ }
286
+ }
287
+ }
288
+ ```
289
+
290
+ #### Component Selector
291
+
292
+ `<brickclay-scheduled-date-picker>`
293
+
294
+ #### Inputs
295
+
296
+ | Input | Type | Default | Description |
297
+ |-------|------|---------|-------------|
298
+ | `timeFormat` | `12 \| 24` | `12` | Time format (12-hour or 24-hour) |
299
+ | `enableSeconds` | `boolean` | `false` | Enable seconds in time picker |
300
+
301
+ #### Outputs
302
+
303
+ | Output | Type | Description |
304
+ |--------|------|-------------|
305
+ | `scheduled` | `EventEmitter<ScheduledDateSelection>` | Emitted when selection changes |
306
+ | `cleared` | `EventEmitter<void>` | Emitted when clear button is clicked |
307
+
308
+ #### Features
309
+
310
+ - **Single Date Mode**: Select one date with optional start and end times
311
+ - **Multiple Dates Mode**: Select multiple dates, each with individual time configuration
312
+ - **Date Range Mode**: Select a date range with start and end times
313
+ - **All Day Toggle**: Mark dates as all-day events
314
+ - **Time Configuration**: Individual time pickers for each date/range
315
+
316
+ ### TimePickerComponent
317
+
318
+ A standalone time picker component with scrollable hour, minute, and AM/PM selectors.
319
+
320
+ #### Basic Example
321
+
322
+ ```typescript
323
+ import { TimePickerComponent } from '@brickclay/ui';
324
+
325
+ @Component({
326
+ template: `
327
+ <brickclay-time-picker
328
+ [value]="selectedTime"
329
+ [label]="'Start Time'"
330
+ [timeFormat]="12"
331
+ (timeChange)="onTimeChange($event)">
332
+ </brickclay-time-picker>
333
+ `
334
+ })
335
+ export class MyComponent {
336
+ selectedTime = '1:00 AM';
337
+
338
+ onTimeChange(time: string) {
339
+ this.selectedTime = time;
340
+ console.log('New time:', time);
341
+ }
342
+ }
343
+ ```
344
+
345
+ #### Component Selector
346
+
347
+ `<brickclay-time-picker>`
348
+
349
+ #### Inputs
350
+
351
+ | Input | Type | Default | Description |
352
+ |-------|------|---------|-------------|
353
+ | `value` | `string` | `'1:00 AM'` | Current time value (format: "H:MM AM/PM" or "HH:MM") |
354
+ | `label` | `string` | `'Time'` | Label text |
355
+ | `placeholder` | `string` | `'Select time'` | Placeholder text |
356
+ | `position` | `'left' \| 'right'` | `'left'` | Dropdown position |
357
+ | `pickerId` | `string` | `''` | Unique identifier for the picker |
358
+ | `closePicker` | `number` | `0` | Counter to trigger picker close |
359
+ | `timeFormat` | `12 \| 24` | `12` | Time format (12-hour or 24-hour) |
360
+ | `showSeconds` | `boolean` | `false` | Show seconds selector |
361
+
362
+ #### Outputs
363
+
364
+ | Output | Type | Description |
365
+ |--------|------|-------------|
366
+ | `timeChange` | `EventEmitter<string>` | Emitted when time changes |
367
+ | `pickerOpened` | `EventEmitter<string>` | Emitted when picker opens |
368
+ | `pickerClosed` | `EventEmitter<string>` | Emitted when picker closes |
369
+
370
+ #### Features
371
+
372
+ - Scrollable time selectors
373
+ - Keyboard navigation support
374
+ - 12-hour and 24-hour formats
375
+ - Optional seconds support
376
+ - Multiple picker coordination (only one open at a time)
377
+ - Click outside to close
378
+
379
+ #### Time Format Examples
380
+
381
+ **12-hour format:**
382
+ ```typescript
383
+ value="1:00 AM"
384
+ value="12:30 PM"
385
+ value="11:45 PM"
386
+ ```
387
+
388
+ **24-hour format:**
389
+ ```typescript
390
+ value="01:00"
391
+ value="13:30"
392
+ value="23:45"
393
+ ```
394
+
395
+ ## πŸ”˜ Toggle
396
+
397
+ A versatile toggle/switch component that integrates seamlessly with Angular forms. Supports both template-driven forms (`ngModel`) and reactive forms, with full accessibility features and keyboard navigation.
398
+
399
+ ### ToggleComponent
400
+
401
+ A standalone toggle component that implements `ControlValueAccessor` for seamless Angular forms integration.
402
+
403
+ #### Basic Example
404
+
405
+ ```typescript
406
+ import { ToggleComponent } from '@brickclay/ui';
407
+ import { FormsModule } from '@angular/forms';
408
+
409
+ @Component({
410
+ template: `
411
+ <brickclay-toggle
412
+ [(ngModel)]="isEnabled"
413
+ [label]="'Enable notifications'"
414
+ (change)="onToggleChange($event)">
415
+ </brickclay-toggle>
416
+ `,
417
+ imports: [ToggleComponent, FormsModule]
418
+ })
419
+ export class MyComponent {
420
+ isEnabled = false;
421
+
422
+ onToggleChange(value: boolean) {
423
+ console.log('Toggle state:', value);
424
+ }
425
+ }
426
+ ```
427
+
428
+ #### Component Selector
429
+
430
+ `<brickclay-toggle>`
431
+
432
+ #### Inputs
433
+
434
+ | Input | Type | Default | Description |
435
+ |-------|------|---------|-------------|
436
+ | `label` | `string` | `''` | Optional label text displayed next to the toggle |
437
+ | `disabled` | `boolean` | `false` | Disables the toggle interaction |
438
+ | `toggleClass` | `string` | `'toggle-md'` | CSS class for size styling. Options: `'toggle-sm'`, `'toggle-md'`, `'toggle-lg'` |
439
+
440
+ #### Outputs
441
+
442
+ | Output | Type | Description |
443
+ |--------|------|-------------|
444
+ | `change` | `EventEmitter<boolean>` | Emitted when toggle state changes (returns new boolean value) |
445
+
446
+ #### Features
447
+
448
+ - βœ… **Angular Forms Integration** - Full support for `ngModel` and reactive forms
449
+ - βœ… **Three Size Variants** - Small (`toggle-sm`), Medium (`toggle-md`), Large (`toggle-lg`)
450
+ - βœ… **Accessibility** - ARIA attributes, keyboard navigation, and screen reader support
451
+ - βœ… **Disabled State** - Visual and functional disabled state
452
+ - βœ… **Customizable Styling** - Custom CSS classes for size and appearance
453
+ - βœ… **Event Handling** - `change` event for state change notifications
454
+
455
+ #### Usage Examples
456
+
457
+ **Basic Toggle with ngModel:**
458
+
459
+ ```typescript
460
+ import { ToggleComponent } from '@brickclay/ui';
461
+ import { FormsModule } from '@angular/forms';
462
+
463
+ @Component({
464
+ template: `
465
+ <brickclay-toggle
466
+ [(ngModel)]="isActive"
467
+ [label]="'Active Status'">
468
+ </brickclay-toggle>
469
+ `,
470
+ imports: [ToggleComponent, FormsModule]
471
+ })
472
+ export class MyComponent {
473
+ isActive = true;
474
+ }
475
+ ```
476
+
477
+ **Different Sizes:**
478
+
479
+ ```typescript
480
+ <brickclay-toggle
481
+ [(ngModel)]="value1"
482
+ [toggleClass]="'toggle-sm'"
483
+ [label]="'Small Toggle'">
484
+ </brickclay-toggle>
485
+
486
+ <brickclay-toggle
487
+ [(ngModel)]="value2"
488
+ [toggleClass]="'toggle-md'"
489
+ [label]="'Medium Toggle'">
490
+ </brickclay-toggle>
491
+
492
+ <brickclay-toggle
493
+ [(ngModel)]="value3"
494
+ [toggleClass]="'toggle-lg'"
495
+ [label]="'Large Toggle'">
496
+ </brickclay-toggle>
497
+ ```
498
+
499
+ **Disabled State:**
500
+
501
+ ```typescript
502
+ <brickclay-toggle
503
+ [ngModel]="true"
504
+ [disabled]="true"
505
+ [label]="'Disabled Toggle'">
506
+ </brickclay-toggle>
507
+ ```
508
+
509
+ **With Event Handler:**
510
+
511
+ ```typescript
512
+ @Component({
513
+ template: `
514
+ <brickclay-toggle
515
+ [(ngModel)]="notificationsEnabled"
516
+ [label]="'Email Notifications'"
517
+ (change)="onNotificationToggle($event)">
518
+ </brickclay-toggle>
519
+ `
520
+ })
521
+ export class MyComponent {
522
+ notificationsEnabled = false;
523
+
524
+ onNotificationToggle(enabled: boolean) {
525
+ if (enabled) {
526
+ this.enableNotifications();
527
+ } else {
528
+ this.disableNotifications();
529
+ }
530
+ }
531
+ }
532
+ ```
533
+
534
+ **Reactive Forms Integration:**
535
+
536
+ ```typescript
537
+ import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
538
+ import { ToggleComponent } from '@brickclay/ui';
539
+
540
+ @Component({
541
+ template: `
542
+ <form [formGroup]="settingsForm">
543
+ <brickclay-toggle
544
+ formControlName="darkMode"
545
+ [label]="'Dark Mode'">
546
+ </brickclay-toggle>
547
+
548
+ <brickclay-toggle
549
+ formControlName="notifications"
550
+ [label]="'Push Notifications'">
551
+ </brickclay-toggle>
552
+ </form>
553
+ `,
554
+ imports: [ToggleComponent, ReactiveFormsModule]
555
+ })
556
+ export class SettingsComponent {
557
+ settingsForm: FormGroup;
558
+
559
+ constructor(private fb: FormBuilder) {
560
+ this.settingsForm = this.fb.group({
561
+ darkMode: [false],
562
+ notifications: [true]
563
+ });
564
+ }
565
+ }
566
+ ```
567
+
568
+ **Without Label:**
569
+
570
+ ```typescript
571
+ <brickclay-toggle
572
+ [(ngModel)]="isEnabled"
573
+ [toggleClass]="'toggle-md'">
574
+ </brickclay-toggle>
575
+ ```
576
+
577
+ #### Styling
578
+
579
+ The toggle component uses CSS classes for size variants:
580
+
581
+ - **Small**: `toggle-sm` - Width: 28px (w-7)
582
+ - **Medium**: `toggle-md` - Width: 36px (w-9) - Default
583
+ - **Large**: `toggle-lg` - Width: 44px (w-11)
584
+
585
+ The component includes built-in styles for:
586
+ - On state (green background: `#22973F`)
587
+ - Off state (gray background: `#BBBDC5`)
588
+ - Disabled state (light gray: `#D6D7DC`)
589
+ - Hover states
590
+ - Focus ring for accessibility
591
+ - Smooth transitions
592
+
593
+ #### Accessibility
594
+
595
+ The toggle component includes:
596
+ - `role="switch"` for screen readers
597
+ - `aria-checked` attribute that reflects the current state
598
+ - Keyboard navigation support
599
+ - Focus visible ring for keyboard users
600
+ - Disabled state properly communicated to assistive technologies
601
+
602
+ ## β˜‘οΈ Checkbox
603
+
604
+ A fully accessible checkbox component that integrates seamlessly with Angular forms. Supports both template-driven forms (`ngModel`) and reactive forms, with customizable styling and comprehensive accessibility features.
605
+
606
+ ### CheckboxComponent
607
+
608
+ A standalone checkbox component that implements `ControlValueAccessor` for seamless Angular forms integration.
609
+
610
+ #### Basic Example
611
+
612
+ ```typescript
613
+ import { CheckboxComponent } from '@brickclay/ui';
614
+ import { FormsModule } from '@angular/forms';
615
+
616
+ @Component({
617
+ template: `
618
+ <brickclay-checkbox
619
+ [(ngModel)]="isAccepted"
620
+ [label]="'I agree to the terms and conditions'"
621
+ (change)="onCheckboxChange($event)">
622
+ </brickclay-checkbox>
623
+ `,
624
+ imports: [CheckboxComponent, FormsModule]
625
+ })
626
+ export class MyComponent {
627
+ isAccepted = false;
628
+
629
+ onCheckboxChange(value: boolean) {
630
+ console.log('Checkbox state:', value);
631
+ }
632
+ }
633
+ ```
634
+
635
+ #### Component Selector
636
+
637
+ `<brickclay-checkbox>`
638
+
639
+ #### Inputs
640
+
641
+ | Input | Type | Default | Description |
642
+ |-------|------|---------|-------------|
643
+ | `label` | `string` | `''` | Optional label text displayed next to the checkbox |
644
+ | `disabled` | `boolean` | `false` | Disables the checkbox interaction |
645
+ | `checkboxClass` | `string` | `''` | CSS class for size styling. Options: `'xsm'`, `'sm'`, `'md'`, `'lg'` |
646
+ | `labelClass` | `string` | `''` | Custom CSS classes for the label text |
647
+
648
+ #### Outputs
649
+
650
+ | Output | Type | Description |
651
+ |--------|------|-------------|
652
+ | `change` | `EventEmitter<boolean>` | Emitted when checkbox state changes (returns new boolean value) |
653
+
654
+ #### Features
655
+
656
+ - βœ… **Angular Forms Integration** - Full support for `ngModel` and reactive forms
657
+ - βœ… **Four Size Variants** - Extra Small (`xsm`), Small (`sm`), Medium (`md`), Large (`lg`)
658
+ - βœ… **Accessibility** - ARIA attributes, keyboard navigation (Enter/Space), and screen reader support
659
+ - βœ… **Disabled State** - Visual and functional disabled state
660
+ - βœ… **Keyboard Support** - Full keyboard navigation with Enter and Space keys
661
+ - βœ… **Focus Management** - Focus visible ring for keyboard users
662
+ - βœ… **Event Handling** - `change` event for state change notifications
663
+
664
+ #### Usage Examples
665
+
666
+ **Basic Checkbox with ngModel:**
667
+
668
+ ```typescript
669
+ import { CheckboxComponent } from '@brickclay/ui';
670
+ import { FormsModule } from '@angular/forms';
671
+
672
+ @Component({
673
+ template: `
674
+ <brickclay-checkbox
675
+ [(ngModel)]="isChecked"
676
+ [label]="'Accept terms'">
677
+ </brickclay-checkbox>
678
+ `,
679
+ imports: [CheckboxComponent, FormsModule]
680
+ })
681
+ export class MyComponent {
682
+ isChecked = false;
683
+ }
684
+ ```
685
+
686
+ **Different Sizes:**
687
+
688
+ ```typescript
689
+ <!-- Extra Small checkbox -->
690
+ <brickclay-checkbox
691
+ [(ngModel)]="value1"
692
+ [checkboxClass]="'xsm'"
693
+ [label]="'Extra Small Checkbox'">
694
+ </brickclay-checkbox>
695
+
696
+ <!-- Small checkbox -->
697
+ <brickclay-checkbox
698
+ [(ngModel)]="value2"
699
+ [checkboxClass]="'sm'"
700
+ [label]="'Small Checkbox'">
701
+ </brickclay-checkbox>
702
+
703
+ <!-- Medium checkbox -->
704
+ <brickclay-checkbox
705
+ [(ngModel)]="value3"
706
+ [checkboxClass]="'md'"
707
+ [label]="'Medium Checkbox'">
708
+ </brickclay-checkbox>
709
+
710
+ <!-- Large checkbox with custom label styling -->
711
+ <brickclay-checkbox
712
+ [(ngModel)]="value4"
713
+ [checkboxClass]="'lg'"
714
+ [labelClass]="'text-lg font-bold'"
715
+ [label]="'Large Checkbox'">
716
+ </brickclay-checkbox>
717
+ ```
718
+
719
+ **Disabled State:**
720
+
721
+ ```typescript
722
+ <brickclay-checkbox
723
+ [ngModel]="true"
724
+ [disabled]="true"
725
+ [label]="'Disabled Checkbox'">
726
+ </brickclay-checkbox>
727
+ ```
728
+
729
+ **With Event Handler:**
730
+
731
+ ```typescript
732
+ @Component({
733
+ template: `
734
+ <brickclay-checkbox
735
+ [(ngModel)]="newsletterSubscribed"
736
+ [label]="'Subscribe to newsletter'"
737
+ (change)="onNewsletterToggle($event)">
738
+ </brickclay-checkbox>
739
+ `
740
+ })
741
+ export class MyComponent {
742
+ newsletterSubscribed = false;
743
+
744
+ onNewsletterToggle(subscribed: boolean) {
745
+ if (subscribed) {
746
+ this.subscribeToNewsletter();
747
+ } else {
748
+ this.unsubscribeFromNewsletter();
749
+ }
750
+ }
751
+ }
752
+ ```
753
+
754
+ **Reactive Forms Integration:**
755
+
756
+ ```typescript
757
+ import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
758
+ import { CheckboxComponent } from '@brickclay/ui';
759
+
760
+ @Component({
761
+ template: `
762
+ <form [formGroup]="registrationForm">
763
+ <brickclay-checkbox
764
+ formControlName="acceptTerms"
765
+ [label]="'I accept the terms and conditions'">
766
+ </brickclay-checkbox>
767
+
768
+ <brickclay-checkbox
769
+ formControlName="receiveUpdates"
770
+ [label]="'Receive product updates'">
771
+ </brickclay-checkbox>
772
+ </form>
773
+ `,
774
+ imports: [CheckboxComponent, ReactiveFormsModule]
775
+ })
776
+ export class RegistrationComponent {
777
+ registrationForm: FormGroup;
778
+
779
+ constructor(private fb: FormBuilder) {
780
+ this.registrationForm = this.fb.group({
781
+ acceptTerms: [false, Validators.requiredTrue],
782
+ receiveUpdates: [false]
783
+ });
784
+ }
785
+ }
786
+ ```
787
+
788
+ **Without Label:**
789
+
790
+ ```typescript
791
+ <brickclay-checkbox
792
+ [(ngModel)]="isSelected"
793
+ [checkboxClass]="'md'">
794
+ </brickclay-checkbox>
795
+ ```
796
+
797
+ **Multiple Checkboxes:**
798
+
799
+ ```typescript
800
+ @Component({
801
+ template: `
802
+ <div>
803
+ <brickclay-checkbox
804
+ *ngFor="let option of options"
805
+ [(ngModel)]="option.selected"
806
+ [label]="option.label"
807
+ (change)="onOptionChange(option)">
808
+ </brickclay-checkbox>
809
+ </div>
810
+ `
811
+ })
812
+ export class MyComponent {
813
+ options = [
814
+ { label: 'Option 1', selected: false },
815
+ { label: 'Option 2', selected: false },
816
+ { label: 'Option 3', selected: false }
817
+ ];
818
+
819
+ onOptionChange(option: any) {
820
+ console.log(`${option.label} is now ${option.selected ? 'selected' : 'deselected'}`);
821
+ }
822
+ }
823
+ ```
824
+
825
+ #### Styling
826
+
827
+ The checkbox component supports predefined size classes:
828
+
829
+ - **Extra Small**: `xsm` - 14px Γ— 14px
830
+ - **Small**: `sm` - 16px Γ— 16px
831
+ - **Medium**: `md` - 18px Γ— 18px
832
+ - **Large**: `lg` - 20px Γ— 20px
833
+
834
+ Use `labelClass` to style the label text (font size, weight, color, etc.)
835
+
836
+ The component includes built-in styles for:
837
+ - Checked state (black background with white checkmark/tick icon)
838
+ - Unchecked state (white background with gray border)
839
+ - Hover states (darker border on hover)
840
+ - Disabled states (gray background and border)
841
+ - Focus ring for accessibility (blue ring with offset)
842
+ - Smooth transitions for state changes
843
+
844
+ #### Accessibility
845
+
846
+ The checkbox component includes:
847
+ - Keyboard navigation support (Enter and Space keys)
848
+ - Focus visible ring for keyboard users
849
+ - Proper ARIA attributes
850
+ - Disabled state properly communicated to assistive technologies
851
+ - Tab navigation support
852
+
853
+ ## πŸ”˜ Radio Button
854
+
855
+ A fully accessible radio button component that integrates seamlessly with Angular forms. Supports both template-driven forms (`ngModel`) and reactive forms, with two visual variants (dot and tick) and comprehensive accessibility features.
856
+
857
+ ### RadioComponent
858
+
859
+ A standalone radio button component that implements `ControlValueAccessor` for seamless Angular forms integration. Radio buttons are used when only one option can be selected from a group.
860
+
861
+ #### Basic Example
862
+
863
+ ```typescript
864
+ import { RadioComponent } from '@brickclay/ui';
865
+ import { FormsModule } from '@angular/forms';
866
+
867
+ @Component({
868
+ template: `
869
+ <brickclay-radio-button
870
+ [(ngModel)]="selectedOption"
871
+ [value]="'option1'"
872
+ [label]="'Option 1'"
873
+ (change)="onRadioChange($event)">
874
+ </brickclay-radio-button>
875
+
876
+ <brickclay-radio-button
877
+ [(ngModel)]="selectedOption"
878
+ [value]="'option2'"
879
+ [label]="'Option 2'">
880
+ </brickclay-radio-button>
881
+ `,
882
+ imports: [RadioComponent, FormsModule]
883
+ })
884
+ export class MyComponent {
885
+ selectedOption = 'option1';
886
+
887
+ onRadioChange(value: any) {
888
+ console.log('Selected option:', value);
889
+ }
890
+ }
891
+ ```
892
+
893
+ #### Component Selector
894
+
895
+ `<brickclay-radio-button>`
896
+
897
+ #### Inputs
898
+
899
+ | Input | Type | Default | Description |
900
+ |-------|------|---------|-------------|
901
+ | `label` | `string` | `''` | Optional label text displayed next to the radio button |
902
+ | `value` | `any` | `undefined` | The value associated with this radio button (required for radio groups) |
903
+ | `disabled` | `boolean` | `false` | Disables the radio button interaction |
904
+ | `variant` | `'dot' \| 'tick'` | `'dot'` | Visual variant. `'dot'` shows a filled circle, `'tick'` shows a checkmark |
905
+ | `radioClass` | `string` | `''` | CSS class for size styling. Options: `'xsm'`, `'sm'`, `'md'`, `'lg'` |
906
+ | `labelClass` | `string` | `''` | Custom CSS classes for the label text |
907
+
908
+ #### Outputs
909
+
910
+ | Output | Type | Description |
911
+ |--------|------|-------------|
912
+ | `change` | `EventEmitter<any>` | Emitted when radio button is selected (returns the value) |
913
+
914
+ #### Features
915
+
916
+ - βœ… **Angular Forms Integration** - Full support for `ngModel` and reactive forms
917
+ - βœ… **Two Visual Variants** - Dot (filled circle) and Tick (checkmark) styles
918
+ - βœ… **Four Size Variants** - Extra Small (`xsm`), Small (`sm`), Medium (`md`), Large (`lg`)
919
+ - βœ… **Radio Groups** - Automatically groups radio buttons with the same `ngModel` binding
920
+ - βœ… **Accessibility** - ARIA attributes, keyboard navigation (Enter/Space), and screen reader support
921
+ - βœ… **Disabled State** - Visual and functional disabled state
922
+ - βœ… **Keyboard Support** - Full keyboard navigation with Enter and Space keys
923
+ - βœ… **Focus Management** - Focus visible ring for keyboard users
924
+ - βœ… **Event Handling** - `change` event for selection notifications
925
+
926
+ #### Usage Examples
927
+
928
+ **Basic Radio Group with ngModel:**
929
+
930
+ ```typescript
931
+ import { RadioComponent } from '@brickclay/ui';
932
+ import { FormsModule } from '@angular/forms';
933
+
934
+ @Component({
935
+ template: `
936
+ <brickclay-radio-button
937
+ [(ngModel)]="selectedPayment"
938
+ [value]="'credit'"
939
+ [label]="'Credit Card'">
940
+ </brickclay-radio-button>
941
+
942
+ <brickclay-radio-button
943
+ [(ngModel)]="selectedPayment"
944
+ [value]="'debit'"
945
+ [label]="'Debit Card'">
946
+ </brickclay-radio-button>
947
+
948
+ <brickclay-radio-button
949
+ [(ngModel)]="selectedPayment"
950
+ [value]="'paypal'"
951
+ [label]="'PayPal'">
952
+ </brickclay-radio-button>
953
+ `,
954
+ imports: [RadioComponent, FormsModule]
955
+ })
956
+ export class MyComponent {
957
+ selectedPayment = 'credit';
958
+ }
959
+ ```
960
+
961
+ **Dot Variant (Default):**
962
+
963
+ ```typescript
964
+ <brickclay-radio-button
965
+ [(ngModel)]="selectedOption"
966
+ [value]="'option1'"
967
+ [variant]="'dot'"
968
+ [label]="'Option with Dot'">
969
+ </brickclay-radio-button>
970
+ ```
971
+
972
+ **Tick Variant:**
973
+
974
+ ```typescript
975
+ <brickclay-radio-button
976
+ [(ngModel)]="selectedOption"
977
+ [value]="'option2'"
978
+ [variant]="'tick'"
979
+ [label]="'Option with Tick'">
980
+ </brickclay-radio-button>
981
+ ```
982
+
983
+ **Different Sizes:**
984
+
985
+ ```typescript
986
+ <!-- Extra Small radio -->
987
+ <brickclay-radio-button
988
+ [(ngModel)]="selectedOption"
989
+ [value]="'xsm'"
990
+ [radioClass]="'xsm'"
991
+ [label]="'Extra Small Radio'">
992
+ </brickclay-radio-button>
993
+
994
+ <!-- Small radio -->
995
+ <brickclay-radio-button
996
+ [(ngModel)]="selectedOption"
997
+ [value]="'sm'"
998
+ [radioClass]="'sm'"
999
+ [label]="'Small Radio'">
1000
+ </brickclay-radio-button>
1001
+
1002
+ <!-- Medium radio -->
1003
+ <brickclay-radio-button
1004
+ [(ngModel)]="selectedOption"
1005
+ [value]="'md'"
1006
+ [radioClass]="'md'"
1007
+ [label]="'Medium Radio'">
1008
+ </brickclay-radio-button>
1009
+
1010
+ <!-- Large radio with custom label styling -->
1011
+ <brickclay-radio-button
1012
+ [(ngModel)]="selectedOption"
1013
+ [value]="'lg'"
1014
+ [radioClass]="'lg'"
1015
+ [labelClass]="'text-lg font-bold'"
1016
+ [label]="'Large Radio'">
1017
+ </brickclay-radio-button>
1018
+ ```
1019
+
1020
+ **Disabled State:**
1021
+
1022
+ ```typescript
1023
+ <brickclay-radio-button
1024
+ [(ngModel)]="selectedOption"
1025
+ [value]="'disabled-option'"
1026
+ [disabled]="true"
1027
+ [label]="'Disabled Option'">
1028
+ </brickclay-radio-button>
1029
+ ```
1030
+
1031
+ **With Event Handler:**
1032
+
1033
+ ```typescript
1034
+ @Component({
1035
+ template: `
1036
+ <brickclay-radio-button
1037
+ *ngFor="let option of options"
1038
+ [(ngModel)]="selectedOption"
1039
+ [value]="option.value"
1040
+ [label]="option.label"
1041
+ (change)="onOptionChange($event)">
1042
+ </brickclay-radio-button>
1043
+ `
1044
+ })
1045
+ export class MyComponent {
1046
+ options = [
1047
+ { value: 'option1', label: 'Option 1' },
1048
+ { value: 'option2', label: 'Option 2' },
1049
+ { value: 'option3', label: 'Option 3' }
1050
+ ];
1051
+ selectedOption = 'option1';
1052
+
1053
+ onOptionChange(value: any) {
1054
+ console.log('Selected:', value);
1055
+ }
1056
+ }
1057
+ ```
1058
+
1059
+ **Reactive Forms Integration:**
1060
+
1061
+ ```typescript
1062
+ import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
1063
+ import { RadioComponent } from '@brickclay/ui';
1064
+
1065
+ @Component({
1066
+ template: `
1067
+ <form [formGroup]="surveyForm">
1068
+ <brickclay-radio-button
1069
+ formControlName="rating"
1070
+ [value]="'excellent'"
1071
+ [label]="'Excellent'">
1072
+ </brickclay-radio-button>
1073
+
1074
+ <brickclay-radio-button
1075
+ formControlName="rating"
1076
+ [value]="'good'"
1077
+ [label]="'Good'">
1078
+ </brickclay-radio-button>
1079
+
1080
+ <brickclay-radio-button
1081
+ formControlName="rating"
1082
+ [value]="'fair'"
1083
+ [label]="'Fair'">
1084
+ </brickclay-radio-button>
1085
+ </form>
1086
+ `,
1087
+ imports: [RadioComponent, ReactiveFormsModule]
1088
+ })
1089
+ export class SurveyComponent {
1090
+ surveyForm: FormGroup;
1091
+
1092
+ constructor(private fb: FormBuilder) {
1093
+ this.surveyForm = this.fb.group({
1094
+ rating: ['good', Validators.required]
1095
+ });
1096
+ }
1097
+ }
1098
+ ```
1099
+
1100
+ **Without Label:**
1101
+
1102
+ ```typescript
1103
+ <brickclay-radio-button
1104
+ [(ngModel)]="selectedOption"
1105
+ [value]="'option1'"
1106
+ [radioClass]="'md'">
1107
+ </brickclay-radio-button>
1108
+ ```
1109
+
1110
+ **Dynamic Radio Group:**
1111
+
1112
+ ```typescript
1113
+ @Component({
1114
+ template: `
1115
+ <div>
1116
+ <brickclay-radio-button
1117
+ *ngFor="let item of items"
1118
+ [(ngModel)]="selectedItem"
1119
+ [value]="item.id"
1120
+ [label]="item.name"
1121
+ [variant]="item.variant || 'dot'">
1122
+ </brickclay-radio-button>
1123
+ </div>
1124
+ `
1125
+ })
1126
+ export class MyComponent {
1127
+ items = [
1128
+ { id: 1, name: 'Item 1', variant: 'dot' },
1129
+ { id: 2, name: 'Item 2', variant: 'tick' },
1130
+ { id: 3, name: 'Item 3', variant: 'dot' }
1131
+ ];
1132
+ selectedItem = 1;
1133
+ }
1134
+ ```
1135
+
1136
+ #### Styling
1137
+
1138
+ The radio button component supports predefined size classes:
1139
+
1140
+ - **Extra Small**: `xsm` - 14px Γ— 14px
1141
+ - **Small**: `sm` - 16px Γ— 16px
1142
+ - **Medium**: `md` - 18px Γ— 18px
1143
+ - **Large**: `lg` - 19px Γ— 19px
1144
+
1145
+ Use `labelClass` to style the label text (font size, weight, color, etc.)
1146
+
1147
+ The component includes built-in styles for:
1148
+ - **Dot Variant**: Filled circle indicator when selected (size varies by radioClass)
1149
+ - **Tick Variant**: Checkmark indicator when selected (size varies by radioClass)
1150
+ - Unselected state (white background with gray border)
1151
+ - Hover states (darker border on hover)
1152
+ - Disabled states (gray background and border)
1153
+ - Focus ring for accessibility (blue ring with offset)
1154
+ - Smooth transitions for state changes
1155
+
1156
+ #### Accessibility
1157
+
1158
+ The radio button component includes:
1159
+ - Keyboard navigation support (Enter and Space keys)
1160
+ - Focus visible ring for keyboard users
1161
+ - Proper ARIA attributes
1162
+ - Disabled state properly communicated to assistive technologies
1163
+ - Tab navigation support
1164
+ - Radio group semantics for screen readers
1165
+
1166
+ #### Radio Groups
1167
+
1168
+ Radio buttons are automatically grouped when they share the same `ngModel` binding. Only one radio button in a group can be selected at a time. When a radio button is selected, the previously selected one in the same group is automatically deselected.
1169
+
1170
+ ## πŸ“ TypeScript Interfaces
1171
+
1172
+ ### CalendarRange
1173
+
1174
+ ```typescript
1175
+ interface CalendarRange {
1176
+ start: Date;
1177
+ end: Date;
1178
+ }
1179
+ ```
1180
+
1181
+ ### CalendarSelection
1182
+
1183
+ ```typescript
1184
+ interface CalendarSelection {
1185
+ startDate: Date | null;
1186
+ endDate: Date | null;
1187
+ selectedDates?: Date[]; // For multi-date selection
1188
+ }
1189
+ ```
1190
+
1191
+ ### TimeConfiguration
1192
+
1193
+ ```typescript
1194
+ interface TimeConfiguration {
1195
+ date: Date;
1196
+ allDay: boolean;
1197
+ startTime: string; // Format: "HH:mm" or "HH:mm:ss"
1198
+ endTime: string;
1199
+ }
1200
+ ```
1201
+
1202
+ ### ScheduledDateSelection
1203
+
1204
+ ```typescript
1205
+ interface ScheduledDateSelection {
1206
+ mode: 'single' | 'multiple' | 'range';
1207
+ singleDate?: {
1208
+ startDate: Date;
1209
+ endDate: Date;
1210
+ allDay: boolean;
1211
+ startTime: string;
1212
+ endTime: string;
1213
+ };
1214
+ multipleDates?: TimeConfiguration[];
1215
+ dateRange?: {
1216
+ startDate: Date;
1217
+ endDate: Date;
1218
+ allDay: boolean;
1219
+ startTime: string;
1220
+ endTime: string;
1221
+ };
1222
+ }
1223
+ ```
1224
+
1225
+ ## 🎯 Common Use Cases
1226
+
1227
+ ### Form Integration
1228
+
1229
+ ```typescript
1230
+ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
1231
+ import { CustomCalendarComponent } from '@brickclay/ui';
1232
+
1233
+ export class BookingFormComponent {
1234
+ bookingForm: FormGroup;
1235
+
1236
+ constructor(private fb: FormBuilder) {
1237
+ this.bookingForm = this.fb.group({
1238
+ checkIn: [null, Validators.required],
1239
+ checkOut: [null, Validators.required]
1240
+ });
1241
+ }
1242
+
1243
+ onDateSelected(selection: CalendarSelection) {
1244
+ this.bookingForm.patchValue({
1245
+ checkIn: selection.startDate,
1246
+ checkOut: selection.endDate
1247
+ });
1248
+ }
1249
+ }
1250
+ ```
1251
+
1252
+ ### Reactive Forms
1253
+
1254
+ ```typescript
1255
+ <brickclay-custom-calendar
1256
+ [selectedValue]="form.get('dateRange')?.value"
1257
+ (selected)="form.patchValue({ dateRange: $event })">
1258
+ </brickclay-custom-calendar>
1259
+ ```
1260
+
1261
+ ### Date Filtering
1262
+
1263
+ ```typescript
1264
+ export class DataTableComponent {
1265
+ filterDates: CalendarSelection = { startDate: null, endDate: null };
1266
+
1267
+ onDateFilter(selection: CalendarSelection) {
1268
+ this.filterDates = selection;
1269
+ this.loadFilteredData();
1270
+ }
1271
+
1272
+ loadFilteredData() {
1273
+ const filtered = this.data.filter(item => {
1274
+ if (!this.filterDates.startDate || !this.filterDates.endDate) {
1275
+ return true;
1276
+ }
1277
+ return item.date >= this.filterDates.startDate! &&
1278
+ item.date <= this.filterDates.endDate!;
1279
+ });
1280
+ }
1281
+ }
1282
+ ```
1283
+
1284
+ ## πŸ“¦ Assets Configuration
1285
+
1286
+ The calendar components require SVG icons. Configure your `angular.json` to copy assets:
1287
+
1288
+ ```json
1289
+ {
1290
+ "glob": "**/*",
1291
+ "input": "node_modules/@brickclay/ui/assets",
1292
+ "output": "assets"
1293
+ }
1294
+ ```
1295
+
1296
+ Or manually copy assets from:
1297
+ ```
1298
+ node_modules/@brickclay/ui/assets/calender/* β†’ your-app/public/assets/calender/
1299
+ ```
1300
+
1301
+ ## πŸ”§ Service
1302
+
1303
+ ### CalendarManagerService
1304
+
1305
+ A service that manages multiple calendar instances, ensuring only one calendar is open at a time when not in inline mode. Used internally by `CustomCalendarComponent`.
1306
+
1307
+ ## 🌐 Browser Support
1308
+
1309
+ - Chrome (latest)
1310
+ - Firefox (latest)
1311
+ - Safari (latest)
1312
+ - Edge (latest)
1313
+
1314
+ ## πŸ“¦ Dependencies
1315
+
1316
+ - Angular 20.3.0+
1317
+ - moment (for date formatting)
1318
+
1319
+ ## 🀝 Contributing
1320
+
1321
+ We welcome contributions! Please see our contributing guidelines for more information.
1322
+
1323
+ ## πŸ“„ License
1324
+
1325
+ MIT
1326
+
1327
+ ## πŸ“ž Support
1328
+
1329
+ For issues, feature requests, or contributions, please visit our [GitHub repository](https://github.com/brickclay/ui).
1330
+
1331
+ ## πŸ—ΊοΈ Roadmap
1332
+
1333
+ - [ ] Button components
1334
+ - [ ] Input components
1335
+ - [ ] Card components
1336
+ - [ ] Modal/Dialog components
1337
+ - [ ] Table components
1338
+ - [ ] Form components
1339
+ - [ ] Navigation components
1340
+ - [ ] Loading/Spinner components
1341
+ - [ ] Toast/Notification components
1342
+ - [ ] More calendar features
1343
+
1344
+ ## πŸ“ Changelog
1345
+
1346
+ ### Version 0.0.1
1347
+
1348
+ **Initial Release:**
1349
+ - βœ… Calendar component suite
1350
+ - Single date selection
1351
+ - Date range selection
1352
+ - Multiple date selection
1353
+ - Time picker integration
1354
+ - Inline and dropdown modes
1355
+ - Dual calendar view
1356
+ - Custom date ranges
1357
+ - Date constraints (min/max)
1358
+ - βœ… Scheduled date picker component
1359
+ - βœ… Standalone time picker component
1360
+ - βœ… Toggle/Switch component
1361
+ - Angular forms integration (ngModel & reactive forms)
1362
+ - Three size variants (small, medium, large)
1363
+ - Disabled state support
1364
+ - Full accessibility features
1365
+ - Customizable styling
1366
+ - βœ… Checkbox component
1367
+ - Angular forms integration (ngModel & reactive forms)
1368
+ - Customizable styling via CSS classes
1369
+ - Disabled state support
1370
+ - Full keyboard navigation support
1371
+ - Complete accessibility features
1372
+ - βœ… Radio button component
1373
+ - Angular forms integration (ngModel & reactive forms)
1374
+ - Two visual variants (dot and tick)
1375
+ - Radio group support
1376
+ - Customizable styling via CSS classes
1377
+ - Disabled state support
1378
+ - Full keyboard navigation support
1379
+ - Complete accessibility features
1380
+ - βœ… TypeScript definitions
1381
+ - βœ… Comprehensive documentation
1382
+
1383
+ ---
1384
+
1385
+ **Built with ❀️ by the Brickclay team**