@brickclay/calendar 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.

Potentially problematic release.


This version of @brickclay/calendar might be problematic. Click here for more details.

package/README.md ADDED
@@ -0,0 +1,417 @@
1
+ # Calendar (Angular library)
2
+
3
+ Reusable calendar/date & time picker components packaged as an Angular library.
4
+
5
+ This package supports:
6
+ - date range selection
7
+ - single date selection
8
+ - multi-date selection
9
+ - optional time picker (12/24h, optional seconds)
10
+ - inline mode (always visible) or dropdown mode
11
+
12
+ ## Quick start (copy/paste)
13
+
14
+ ### 1) Install
15
+
16
+ After you publish to npm:
17
+
18
+ ```bash
19
+ npm i @brickclay/calendar
20
+ ```
21
+
22
+ Before publishing (install from local build):
23
+
24
+ ```bash
25
+ # from repo root
26
+ ng build calendar
27
+ cd dist/calendar
28
+ npm pack
29
+ # then install the generated .tgz in your app:
30
+ # (for scoped packages like @brickclay/calendar, npm pack outputs something like:)
31
+ # brickclay-calendar-<version>.tgz
32
+ npm i path/to/brickclay-calendar-<version>.tgz
33
+ ```
34
+
35
+ ### 2) Use in a standalone component (recommended)
36
+
37
+ ```ts
38
+ import { Component } from '@angular/core';
39
+ import { CalendarComponent, CalendarSelection } from '@brickclay/calendar';
40
+
41
+ @Component({
42
+ standalone: true,
43
+ selector: 'app-demo',
44
+ imports: [CalendarComponent],
45
+ template: `
46
+ <lib-calendar
47
+ [dualCalendar]="true"
48
+ [enableTimepicker]="true"
49
+ [autoApply]="true"
50
+ [closeOnAutoApply]="true"
51
+ [displayFormat]="'YYYY-MM-DD'"
52
+ (selected)="onSelected($event)"
53
+ />
54
+ `
55
+ })
56
+ export class DemoComponent {
57
+ onSelected(selection: CalendarSelection) {
58
+ console.log(selection);
59
+ }
60
+ }
61
+ ```
62
+
63
+ ## Peer dependencies (required in the consuming app)
64
+
65
+ This library declares these as **peerDependencies**. Your app must already include them:
66
+
67
+ - `@angular/common`
68
+ - `@angular/core`
69
+ - `@angular/forms`
70
+ - `rxjs`
71
+ - `moment`
72
+
73
+ ## Exports (what you can import from `'@brickclay/calendar'`)
74
+
75
+ ### Components
76
+
77
+ - **Wrapper**: `CalendarComponent` (selector: `<lib-calendar>`)
78
+ - Drop-in wrapper around `<app-custom-calendar>`
79
+ - Mirrors the same inputs/outputs, so you can use `<lib-calendar>` everywhere
80
+
81
+ - **Standalone components**
82
+ - `CustomCalendarComponent` (selector: `<app-custom-calendar>`) — the main calendar UI
83
+ - `ScheduledDatePickerComponent` (selector: `<app-scheduled-date-picker>`) — “single / multiple / range” scheduling UI
84
+ - `TimePickerComponent` (selector: `<app-time-picker>`) — standalone time picker
85
+
86
+ ### Module (optional)
87
+
88
+ - `CalendarModule` — exports the 3 standalone components above (for module-based apps)
89
+
90
+ ### Types & services
91
+
92
+ - Types: `CalendarSelection`, `CalendarRange`, etc.
93
+ - Service: `CalendarManagerService` (coordinates multiple open calendars)
94
+
95
+ Example import:
96
+
97
+ ```ts
98
+ import { CalendarComponent, CalendarSelection } from '@brickclay/calendar';
99
+ ```
100
+
101
+ ## Usage options
102
+
103
+ ### Option A (recommended): use `<lib-calendar>`
104
+
105
+ `<lib-calendar>` is a thin wrapper around the main calendar and is the easiest way to use the package.
106
+
107
+ #### Single date picker
108
+
109
+ ```html
110
+ <lib-calendar
111
+ [singleDatePicker]="true"
112
+ [autoApply]="true"
113
+ (selected)="onSelected($event)"
114
+ ></lib-calendar>
115
+ ```
116
+
117
+ #### Date range picker (default mode)
118
+
119
+ ```html
120
+ <lib-calendar
121
+ [singleDatePicker]="false"
122
+ [dualCalendar]="true"
123
+ (selected)="onSelected($event)"
124
+ ></lib-calendar>
125
+ ```
126
+
127
+ #### Multi-date selection
128
+
129
+ ```html
130
+ <lib-calendar
131
+ [multiDateSelection]="true"
132
+ [autoApply]="true"
133
+ (selected)="onSelected($event)"
134
+ ></lib-calendar>
135
+ ```
136
+
137
+ #### Inline mode (always visible, not a dropdown)
138
+
139
+ ```html
140
+ <lib-calendar
141
+ [inline]="true"
142
+ [dualCalendar]="true"
143
+ (selected)="onSelected($event)"
144
+ ></lib-calendar>
145
+ ```
146
+
147
+ #### With min/max date
148
+
149
+ ```html
150
+ <lib-calendar
151
+ [minDate]="minDate"
152
+ [maxDate]="maxDate"
153
+ (selected)="onSelected($event)"
154
+ ></lib-calendar>
155
+ ```
156
+
157
+ ```ts
158
+ minDate = new Date(2025, 0, 1);
159
+ maxDate = new Date(2025, 11, 31);
160
+ ```
161
+
162
+ #### Controlled value (set selection from parent)
163
+
164
+ Use `selectedValue` when you want to **drive the calendar from your own state**.
165
+
166
+ ```ts
167
+ import { CalendarSelection } from '@brickclay/calendar';
168
+
169
+ selectedValue: CalendarSelection = {
170
+ startDate: new Date(),
171
+ endDate: null
172
+ };
173
+ ```
174
+
175
+ ```html
176
+ <lib-calendar
177
+ [singleDatePicker]="true"
178
+ [selectedValue]="selectedValue"
179
+ (selected)="selectedValue = $event"
180
+ ></lib-calendar>
181
+ ```
182
+
183
+ ### Option B: use `<app-custom-calendar>` directly
184
+
185
+ If you don’t want the wrapper, you can import and use the standalone component directly:
186
+
187
+ ```ts
188
+ import { Component } from '@angular/core';
189
+ import { CustomCalendarComponent, CalendarSelection } from '@brickclay/calendar';
190
+
191
+ @Component({
192
+ standalone: true,
193
+ selector: 'app-demo',
194
+ imports: [CustomCalendarComponent],
195
+ template: `
196
+ <app-custom-calendar
197
+ [dualCalendar]="false"
198
+ [singleDatePicker]="true"
199
+ (selected)="onSelected($event)"
200
+ />
201
+ `
202
+ })
203
+ export class DemoComponent {
204
+ onSelected(selection: CalendarSelection) {
205
+ console.log(selection);
206
+ }
207
+ }
208
+ ```
209
+
210
+ ### Option C: module-based usage (`CalendarModule`)
211
+
212
+ ```ts
213
+ import { NgModule } from '@angular/core';
214
+ import { BrowserModule } from '@angular/platform-browser';
215
+ import { CalendarModule } from '@brickclay/calendar';
216
+ import { AppComponent } from './app.component';
217
+
218
+ @NgModule({
219
+ declarations: [AppComponent],
220
+ imports: [BrowserModule, CalendarModule]
221
+ })
222
+ export class AppModule {}
223
+ ```
224
+
225
+ Then use:
226
+
227
+ ```html
228
+ <app-custom-calendar></app-custom-calendar>
229
+ <app-scheduled-date-picker></app-scheduled-date-picker>
230
+ <app-time-picker></app-time-picker>
231
+ ```
232
+
233
+ ## Component guides
234
+
235
+ ### `CalendarComponent` (wrapper) — `<lib-calendar>`
236
+
237
+ This is a wrapper around `CustomCalendarComponent` that forwards all inputs/outputs.
238
+
239
+ - **Selector**: `<lib-calendar>`
240
+ - **When to use**: almost always (best default)
241
+
242
+ ### `CustomCalendarComponent` — `<app-custom-calendar>`
243
+
244
+ The main calendar UI. Supports range, single date, multi-date, optional time picker, inline mode, min/max, custom ranges.
245
+
246
+ - **Selector**: `<app-custom-calendar>`
247
+ - **Outputs**: `(selected)`, `(opened)`, `(closed)`
248
+
249
+ ### `ScheduledDatePickerComponent` — `<app-scheduled-date-picker>`
250
+
251
+ Higher-level scheduling UI with 3 tabs:
252
+ - single date + time
253
+ - multiple dates + time per date
254
+ - date range + time
255
+
256
+ Example:
257
+
258
+ ```ts
259
+ import { Component } from '@angular/core';
260
+ import { ScheduledDatePickerComponent, ScheduledDateSelection } from '@brickclay/calendar';
261
+
262
+ @Component({
263
+ standalone: true,
264
+ selector: 'app-demo-scheduled',
265
+ imports: [ScheduledDatePickerComponent],
266
+ template: `
267
+ <app-scheduled-date-picker
268
+ [timeFormat]="12"
269
+ [enableSeconds]="false"
270
+ (scheduled)="onScheduled($event)"
271
+ (cleared)="onCleared()"
272
+ />
273
+ `
274
+ })
275
+ export class DemoScheduledComponent {
276
+ onScheduled(value: ScheduledDateSelection) {
277
+ console.log(value);
278
+ }
279
+ onCleared() {}
280
+ }
281
+ ```
282
+
283
+ ### `TimePickerComponent` — `<app-time-picker>`
284
+
285
+ Standalone time picker used internally by the calendar/scheduler, but you can use it directly.
286
+
287
+ Example:
288
+
289
+ ```html
290
+ <app-time-picker
291
+ [value]="'1:00 AM'"
292
+ [timeFormat]="12"
293
+ [showSeconds]="false"
294
+ [pickerId]="'start-time'"
295
+ (timeChange)="startTime = $event"
296
+ ></app-time-picker>
297
+ ```
298
+
299
+ ## API reference
300
+
301
+ ### Types
302
+
303
+ #### `CalendarSelection`
304
+
305
+ ```ts
306
+ export interface CalendarSelection {
307
+ startDate: Date | null;
308
+ endDate: Date | null;
309
+ selectedDates?: Date[];
310
+ }
311
+ ```
312
+
313
+ #### `CalendarRange`
314
+
315
+ ```ts
316
+ export interface CalendarRange {
317
+ start: Date;
318
+ end: Date;
319
+ }
320
+ ```
321
+
322
+ ### Inputs/Outputs for `<lib-calendar>` and `<app-custom-calendar>`
323
+
324
+ They share the same API (the wrapper forwards everything).
325
+
326
+ #### Outputs
327
+
328
+ | Output | Type | When it fires |
329
+ | --- | --- | --- |
330
+ | `selected` | `EventEmitter<CalendarSelection>` | When selection changes (and on apply/autoApply depending on config) |
331
+ | `opened` | `EventEmitter<void>` | When the dropdown opens (not used in inline mode) |
332
+ | `closed` | `EventEmitter<void>` | When the dropdown closes (not used in inline mode) |
333
+
334
+ #### Inputs (with defaults)
335
+
336
+ | Input | Type | Default | Notes |
337
+ | --- | --- | --- | --- |
338
+ | `enableTimepicker` | `boolean` | `false` | Enables time selection UI |
339
+ | `autoApply` | `boolean` | `false` | Automatically applies after selecting end date (or date) |
340
+ | `closeOnAutoApply` | `boolean` | `false` | Closes dropdown after auto-apply (no-op in inline) |
341
+ | `showCancel` | `boolean` | `true` | Show Cancel button |
342
+ | `linkedCalendars` | `boolean` | `false` | Keeps calendars linked (if enabled by UI logic) |
343
+ | `singleDatePicker` | `boolean` | `false` | Single date mode |
344
+ | `showWeekNumbers` | `boolean` | `false` | Display week numbers |
345
+ | `showISOWeekNumbers` | `boolean` | `false` | Display ISO week numbers |
346
+ | `customRangeDirection` | `boolean` | `false` | Alters selection direction behavior |
347
+ | `lockStartDate` | `boolean` | `false` | Locks start date when selecting end date |
348
+ | `position` | `'center' \| 'left' \| 'right'` | `'left'` | Dropdown alignment |
349
+ | `drop` | `'up' \| 'down'` | `'down'` | Dropdown direction |
350
+ | `dualCalendar` | `boolean` | `false` | Show two calendars (left/right) |
351
+ | `showRanges` | `boolean` | `true` | Show ranges list (Today/Yesterday/...) |
352
+ | `timeFormat` | `12 \| 24` | `24` | Time display mode |
353
+ | `enableSeconds` | `boolean` | `false` | Show seconds in time selection |
354
+ | `customRanges` | `Record<string, CalendarRange>` | `undefined` | Provide your own ranges |
355
+ | `multiDateSelection` | `boolean` | `false` | Multi-date selection mode |
356
+ | `maxDate` | `Date` | `undefined` | Maximum selectable date |
357
+ | `minDate` | `Date` | `undefined` | Minimum selectable date |
358
+ | `placeholder` | `string` | `'Select date range'` | Input placeholder |
359
+ | `opens` | `'left' \| 'right' \| 'center'` | `'left'` | Popup position |
360
+ | `inline` | `boolean` | `false` | Always visible calendar (no dropdown) |
361
+ | `isDisplayCrossIcon` | `boolean` | `true` | Show/hide clear (X) icon |
362
+ | `selectedValue` | `CalendarSelection \| null` | `null` | Controlled value input |
363
+ | `displayFormat` | `string` | `'MM/DD/YYYY'` | Uses Moment formatting tokens |
364
+
365
+ ### Custom ranges example
366
+
367
+ ```ts
368
+ import { CalendarRange } from '@brickclay/calendar';
369
+
370
+ customRanges: Record<string, CalendarRange> = {
371
+ 'Last 7 Days': { start: new Date(Date.now() - 6 * 86400000), end: new Date() },
372
+ 'This Month': { start: new Date(new Date().getFullYear(), new Date().getMonth(), 1), end: new Date() }
373
+ };
374
+ ```
375
+
376
+ ```html
377
+ <lib-calendar [customRanges]="customRanges"></lib-calendar>
378
+ ```
379
+
380
+ ## Styling / theming
381
+
382
+ - The components ship with their own component styles.
383
+ - If your app uses view encapsulation/global resets, you may want to adjust spacing/colors by overriding styles in your app.
384
+
385
+ ## Troubleshooting
386
+
387
+ ### The package installs but Angular can’t resolve imports
388
+
389
+ - Ensure you import from `'@brickclay/calendar'` (the package entrypoint), not from deep paths.
390
+ - Ensure your app has the **peer dependencies** installed.
391
+
392
+ ### I don’t see the dropdown open/close events
393
+
394
+ - `opened` / `closed` are meaningful only when `inline` is `false`. In inline mode the calendar is always visible.
395
+
396
+ ### SSR (Angular Universal)
397
+
398
+ Some UI helpers use browser globals (e.g., DOM querying). If you render on the server, prefer rendering these components only in the browser.
399
+
400
+ ## Build & publish
401
+
402
+ Build:
403
+
404
+ ```bash
405
+ ng build calendar
406
+ ```
407
+
408
+ Publish:
409
+
410
+ ```bash
411
+ cd dist/calendar
412
+ npm publish
413
+ ```
414
+
415
+ Publishing checklist (recommended):
416
+ - update `projects/calendar/package.json` version
417
+ - ensure `dist/calendar/package.json` has the final `name`, `version`, `description`, `keywords`, etc.
@@ -0,0 +1,19 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g clip-path="url(#clip0_3797_46309)">
3
+ <path d="M14.545 5.45448V11.6363C14.545 13.8181 13.4541 15.2727 10.9086 15.2727H5.09047C2.54501 15.2727 1.4541 13.8181 1.4541 11.6363V5.45448C1.4541 3.27266 2.54501 1.81812 5.09047 1.81812H10.9086C13.4541 1.81812 14.545 3.27266 14.545 5.45448Z" stroke="#141414" stroke-width="1.2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
4
+ <path d="M5.09082 0.727295V2.90911" stroke="#141414" stroke-width="1.2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
5
+ <path d="M10.9092 0.727295V2.90911" stroke="#141414" stroke-width="1.2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
6
+ <path d="M1.81836 5.88354H14.182" stroke="#141414" stroke-width="1.2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
7
+ <path d="M10.6868 9.23619H10.6933" stroke="#141414" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
8
+ <path d="M10.6868 11.4181H10.6933" stroke="#141414" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
9
+ <path d="M7.99636 9.23619H8.00289" stroke="#141414" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
10
+ <path d="M7.99636 11.4181H8.00289" stroke="#141414" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
11
+ <path d="M5.30495 9.23644H5.31149" stroke="#141414" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
12
+ <path d="M5.30495 11.4181H5.31149" stroke="#141414" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
13
+ </g>
14
+ <defs>
15
+ <clipPath id="clip0_3797_46309">
16
+ <rect width="16" height="16" fill="white"/>
17
+ </clipPath>
18
+ </defs>
19
+ </svg>
@@ -0,0 +1,10 @@
1
+ <svg width="12" height="7" viewBox="0 0 12 7" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g clip-path="url(#clip0_535_3111)">
3
+ <path d="M0.835938 1.16797L5.83593 6.16797L10.8359 1.16797" stroke="#6B7080" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </g>
5
+ <defs>
6
+ <clipPath id="clip0_535_3111">
7
+ <rect width="7" height="12" fill="white" transform="matrix(0 -1 1 0 0 7)"/>
8
+ </clipPath>
9
+ </defs>
10
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="7" height="12" viewBox="0 0 7 12" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M5.83398 0.833313L0.833984 5.83331L5.83398 10.8333" stroke="#6B7080" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="7" height="12" viewBox="0 0 7 12" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M0.833984 10.8333L5.83398 5.83331L0.833984 0.833313" stroke="#6B7080" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1,10 @@
1
+ <svg width="12" height="7" viewBox="0 0 12 7" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g clip-path="url(#clip0_535_3113)">
3
+ <path d="M10.8359 6.16797L5.83593 1.16797L0.835938 6.16797" stroke="#6B7080" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </g>
5
+ <defs>
6
+ <clipPath id="clip0_535_3113">
7
+ <rect width="7" height="12" fill="white" transform="matrix(0 -1 1 0 0 7)"/>
8
+ </clipPath>
9
+ </defs>
10
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="6" height="10" viewBox="0 0 6 10" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M5 9L1 5L5 1" stroke="#B9BBC6" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1,10 @@
1
+ <svg width="6" height="10" viewBox="0 0 6 10" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g clip-path="url(#clip0_268_9)">
3
+ <path d="M1 9L5 5L1 1" stroke="#B9BBC6" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </g>
5
+ <defs>
6
+ <clipPath id="clip0_268_9">
7
+ <rect width="6" height="10" fill="white"/>
8
+ </clipPath>
9
+ </defs>
10
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M7 14C10.8593 14 14 10.8593 14 7C14 3.14067 10.8594 0 7 0C3.14063 0 0 3.14067 0 7C0 10.8593 3.14067 14 7 14ZM7 0.933318C10.346 0.933318 13.0667 3.65398 13.0667 7C13.0667 10.346 10.346 13.0667 7 13.0667C3.65398 13.0667 0.933318 10.346 0.933318 7C0.933318 3.65398 3.65401 0.933318 7 0.933318Z" fill="#BBBDC5"/>
3
+ <path d="M9.04153 9.23071C9.12788 9.3007 9.23052 9.33339 9.3332 9.33339C9.47086 9.33339 9.60619 9.27272 9.69718 9.15839C9.85819 8.95772 9.82549 8.66372 9.62486 8.50271L7.46652 6.77604V3.26671C7.46652 3.01004 7.25653 2.80005 6.99986 2.80005C6.74319 2.80005 6.5332 3.01004 6.5332 3.26671V7.00006C6.5332 7.1424 6.59855 7.27539 6.7082 7.36404L9.04153 9.23071Z" fill="#BBBDC5"/>
4
+ </svg>
@@ -0,0 +1,21 @@
1
+ import * as i0 from "@angular/core";
2
+ import * as i1 from "@angular/common";
3
+ import * as i2 from "./components/custom-calendar/custom-calendar.component";
4
+ import * as i3 from "./components/scheduled-date-picker/scheduled-date-picker.component";
5
+ import * as i4 from "./components/time-picker/time-picker.component";
6
+ /**
7
+ * Optional NgModule wrapper for projects that prefer module-based usage.
8
+ *
9
+ * Note:
10
+ * - The components themselves are standalone, so you can also import them
11
+ * directly into any standalone component without using this module.
12
+ * - This module is mainly for:
13
+ * - Existing apps that still use feature modules
14
+ * - Easier "plug-and-play" integration: import CalendarModule once and use
15
+ * the three exported components anywhere in your templates.
16
+ */
17
+ export declare class CalendarModule {
18
+ static ɵfac: i0.ɵɵFactoryDeclaration<CalendarModule, never>;
19
+ static ɵmod: i0.ɵɵNgModuleDeclaration<CalendarModule, never, [typeof i1.CommonModule, typeof i2.CustomCalendarComponent, typeof i3.ScheduledDatePickerComponent, typeof i4.TimePickerComponent], [typeof i2.CustomCalendarComponent, typeof i3.ScheduledDatePickerComponent, typeof i4.TimePickerComponent]>;
20
+ static ɵinj: i0.ɵɵInjectorDeclaration<CalendarModule>;
21
+ }