kalendly 0.2.1 → 0.3.0
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 +263 -32
- package/dist/core/index.d.mts +50 -10
- package/dist/core/index.d.ts +50 -10
- package/dist/core/index.js +60 -26
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +56 -25
- package/dist/core/index.mjs.map +1 -1
- package/dist/index.d.mts +76 -10
- package/dist/index.d.ts +76 -10
- package/dist/index.js +373 -160
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +369 -159
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +363 -156
- package/dist/index.umd.js.map +1 -1
- package/dist/styles/calendar.css +477 -415
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ npm install kalendly
|
|
|
62
62
|
/>
|
|
63
63
|
<script src="https://unpkg.com/kalendly/dist/index.umd.js"></script>
|
|
64
64
|
|
|
65
|
-
<kal-calendar id="cal"
|
|
65
|
+
<kal-calendar id="cal" heading="My Calendar"></kal-calendar>
|
|
66
66
|
|
|
67
67
|
<script>
|
|
68
68
|
const cal = document.getElementById('cal');
|
|
@@ -104,7 +104,7 @@ import 'kalendly/styles';
|
|
|
104
104
|
function App() {
|
|
105
105
|
return (
|
|
106
106
|
<kal-calendar
|
|
107
|
-
|
|
107
|
+
heading="My Calendar"
|
|
108
108
|
events={events}
|
|
109
109
|
oncal-date-select={e => console.log(e.detail.date)}
|
|
110
110
|
oncal-month-change={e => console.log(e.detail.year, e.detail.month)}
|
|
@@ -145,12 +145,60 @@ function App() {
|
|
|
145
145
|
|
|
146
146
|
### Vue 3
|
|
147
147
|
|
|
148
|
-
Vue 3 supports custom elements natively — bind props with `:` and listen to events with
|
|
148
|
+
Vue 3 supports custom elements natively — bind props with `:` and listen to events with `@`.
|
|
149
|
+
|
|
150
|
+
> **Vue-specific:** Vue's template compiler warns on unknown tags. React, Solid.js, and Svelte treat hyphenated tags as DOM elements natively — no config needed. Angular uses `CUSTOM_ELEMENTS_SCHEMA` (see the Angular section below).
|
|
151
|
+
|
|
152
|
+
Tell Vue's compiler that `<kal-*>` tags are native custom elements. The config location depends on your build tool:
|
|
153
|
+
|
|
154
|
+
**Vite** (`vite.config.ts`):
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
vue({
|
|
158
|
+
template: {
|
|
159
|
+
compilerOptions: {
|
|
160
|
+
isCustomElement: tag => tag.startsWith('kal-'),
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Nuxt 3** (`nuxt.config.ts`):
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
export default defineNuxtConfig({
|
|
170
|
+
vue: {
|
|
171
|
+
compilerOptions: {
|
|
172
|
+
isCustomElement: tag => tag.startsWith('kal-'),
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**webpack / Vue CLI** (`vue.config.js`):
|
|
179
|
+
|
|
180
|
+
```js
|
|
181
|
+
module.exports = {
|
|
182
|
+
chainWebpack: config => {
|
|
183
|
+
config.module
|
|
184
|
+
.rule('vue')
|
|
185
|
+
.use('vue-loader')
|
|
186
|
+
.tap(options => ({
|
|
187
|
+
...options,
|
|
188
|
+
compilerOptions: {
|
|
189
|
+
isCustomElement: tag => tag.startsWith('kal-'),
|
|
190
|
+
},
|
|
191
|
+
}));
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Without this the component still renders correctly — Vue falls back to a native DOM element. This only suppresses the console warning.
|
|
149
197
|
|
|
150
198
|
```vue
|
|
151
199
|
<template>
|
|
152
200
|
<kal-calendar
|
|
153
|
-
|
|
201
|
+
heading="My Calendar"
|
|
154
202
|
:events="events"
|
|
155
203
|
@cal-date-select="onDateSelect"
|
|
156
204
|
@cal-month-change="onMonthChange"
|
|
@@ -188,7 +236,7 @@ import 'kalendly/styles';
|
|
|
188
236
|
```html
|
|
189
237
|
<!-- app.component.html -->
|
|
190
238
|
<kal-calendar
|
|
191
|
-
|
|
239
|
+
heading="My Calendar"
|
|
192
240
|
[events]="events"
|
|
193
241
|
(cal-date-select)="onDateSelect($event)"
|
|
194
242
|
(cal-month-change)="onMonthChange($event)"
|
|
@@ -232,7 +280,7 @@ import 'kalendly/styles';
|
|
|
232
280
|
function App() {
|
|
233
281
|
return (
|
|
234
282
|
<kal-calendar
|
|
235
|
-
|
|
283
|
+
heading="My Calendar"
|
|
236
284
|
prop:events={events}
|
|
237
285
|
on:cal-date-select={e => console.log(e.detail.date)}
|
|
238
286
|
/>
|
|
@@ -268,7 +316,7 @@ kalendly uses Light DOM — all standard CSS techniques work:
|
|
|
268
316
|
}
|
|
269
317
|
|
|
270
318
|
/* 2. Direct class overrides */
|
|
271
|
-
.kalendly-calendar .calendar
|
|
319
|
+
.kalendly-calendar .calendar-card {
|
|
272
320
|
border-radius: 12px;
|
|
273
321
|
}
|
|
274
322
|
```
|
|
@@ -287,8 +335,10 @@ Primitives are set as HTML attributes:
|
|
|
287
335
|
|
|
288
336
|
| Attribute | Type | Default | Description |
|
|
289
337
|
| ----------------------- | ---------------- | ---------------- | ------------------------------------------------ |
|
|
290
|
-
| `
|
|
338
|
+
| `heading` | `string` | — | Calendar heading |
|
|
339
|
+
| `title` | `string` | — | **Deprecated** — use `heading` |
|
|
291
340
|
| `initial-date` | `string` | today | ISO date string for initial view |
|
|
341
|
+
| `months` | `"1"\|"2"` | `"1"` | Render two months side by side |
|
|
292
342
|
| `min-year` | `string` | currentYear - 30 | Minimum year in picker |
|
|
293
343
|
| `max-year` | `string` | currentYear + 10 | Maximum year in picker |
|
|
294
344
|
| `week-starts-on` | `"0"\|"1"` | `"0"` | Week start: 0 = Sunday, 1 = Monday |
|
|
@@ -301,17 +351,23 @@ Primitives are set as HTML attributes:
|
|
|
301
351
|
|
|
302
352
|
Rich objects are set as JS properties (not attributes):
|
|
303
353
|
|
|
304
|
-
| Property
|
|
305
|
-
|
|
|
306
|
-
| `events`
|
|
307
|
-
| `loading`
|
|
308
|
-
| `theme`
|
|
309
|
-
| `categoryColors`
|
|
310
|
-
| `renderEvent`
|
|
311
|
-
| `renderNoEvents`
|
|
354
|
+
| Property | Type | Description |
|
|
355
|
+
| -------------------- | ---------------------------------- | ------------------------------------------------- |
|
|
356
|
+
| `events` | `CalendarEvent[]` | Events to display |
|
|
357
|
+
| `loading` | `boolean` | `true` = render skeleton cells; `false` = restore |
|
|
358
|
+
| `theme` | `CalendarTheme` | Custom theme colors |
|
|
359
|
+
| `categoryColors` | `CategoryColorMap` | Per-category color overrides |
|
|
360
|
+
| `renderEvent` | `(event: CalendarEvent) => string` | Custom event HTML renderer |
|
|
361
|
+
| `renderNoEvents` | `() => string` | Custom empty-state HTML renderer |
|
|
362
|
+
| `availabilityColors` | `Record<string, string>` | Colour per availability bucket |
|
|
363
|
+
| `selectableStatuses` | `string[]` | Buckets a range may start, end or span |
|
|
312
364
|
|
|
313
365
|
> `renderEvent` and `renderNoEvents` are ignored when `availability-mode` is set.
|
|
314
366
|
|
|
367
|
+
### Why `heading` and not `title`
|
|
368
|
+
|
|
369
|
+
`title` is a global HTML attribute, so the browser renders it as a tooltip floating over the whole calendar as well as using it as the heading. `heading` does the same job without the tooltip. `title` still works and warns once per page; it will be removed in a future release.
|
|
370
|
+
|
|
315
371
|
## Custom Events
|
|
316
372
|
|
|
317
373
|
| Event | `detail` shape | Description |
|
|
@@ -337,9 +393,77 @@ Hides all event details from the end user — only booked/free state is shown. D
|
|
|
337
393
|
<kal-calendar availability-mode="day"></kal-calendar>
|
|
338
394
|
```
|
|
339
395
|
|
|
340
|
-
|
|
396
|
+
Every event must declare `availabilityStatus`. Three buckets ship built in, coloured as a traffic light:
|
|
397
|
+
|
|
398
|
+
| Bucket | Colour | Meaning |
|
|
399
|
+
| ------------- | ------ | ----------------------------------------- |
|
|
400
|
+
| `open` | green | nothing claims this day |
|
|
401
|
+
| `conditional` | amber | claimed, but not necessarily hard-blocked |
|
|
402
|
+
| `blocked` | red | not available |
|
|
403
|
+
|
|
404
|
+
```js
|
|
405
|
+
cal.events = [
|
|
406
|
+
{ id: 1, date: '2026-03-02', availabilityStatus: 'blocked' },
|
|
407
|
+
{ id: 2, date: '2026-03-05', availabilityStatus: 'conditional' },
|
|
408
|
+
];
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
Only cells in the current month are colour-coded — other-month cells remain grayed out. Clicking a day fires no popup and reveals no event details.
|
|
412
|
+
|
|
413
|
+
A day holding several events resolves by severity: `blocked` beats `conditional` beats `open`, so a day with both a conditional and a blocked booking reads blocked. Precedence never depends on the order events arrive in.
|
|
414
|
+
|
|
415
|
+
#### Your own buckets
|
|
416
|
+
|
|
417
|
+
`availabilityColors` merges over the built-in three — override one, or add your own:
|
|
418
|
+
|
|
419
|
+
```js
|
|
420
|
+
cal.availabilityColors = {
|
|
421
|
+
conditional: '#7c3aed', // recolour a built-in
|
|
422
|
+
maintenance: '#0891b2', // add a bucket
|
|
423
|
+
};
|
|
424
|
+
cal.events = [{ id: 3, date: '2026-03-09', availabilityStatus: 'maintenance' }];
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
A bucket named in `availabilityColors` paints from an inline colour, which takes precedence over the same colour set through `theme`. The built-in three paint from CSS variables and are themeable the usual way.
|
|
428
|
+
|
|
429
|
+
Caller-defined buckets resolve by the order their keys appear in `availabilityColors`.
|
|
430
|
+
|
|
431
|
+
#### Which days are selectable
|
|
432
|
+
|
|
433
|
+
By default only `open` days can start, end or span a range. `selectableStatuses` widens that:
|
|
434
|
+
|
|
435
|
+
```js
|
|
436
|
+
cal.selectableStatuses = ['open', 'conditional'];
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
#### Misconfiguration throws
|
|
440
|
+
|
|
441
|
+
An event with no `availabilityStatus`, or one naming a bucket that is neither built in nor declared in `availabilityColors`, throws and names the offending events:
|
|
442
|
+
|
|
443
|
+
```
|
|
444
|
+
<kal-calendar> availability-mode requires availabilityStatus on every event. Missing on: 7, 9.
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Setting `events` throws where you set it. One case cannot: markup parsed before the module defines the element configures the calendar inside a custom element upgrade, and the browser reports exceptions there as uncaught rather than passing them to your code. The failure is kept, so the next call to `getEngine()`, `getCurrentDate()` or `goToDate()` throws it, and correcting `events` or `availabilityColors` clears it.
|
|
341
448
|
|
|
342
|
-
|
|
449
|
+
#### Two months side by side
|
|
450
|
+
|
|
451
|
+
```html
|
|
452
|
+
<kal-calendar
|
|
453
|
+
availability-mode="day"
|
|
454
|
+
months="2"
|
|
455
|
+
selectable="range"
|
|
456
|
+
></kal-calendar>
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
Navigation advances one month at a time, so a range spanning a month boundary stays visible. Ranges cross panes freely, and it works in standard and time modes too. Panes stack vertically on narrow screens.
|
|
460
|
+
|
|
461
|
+
<div align="center">
|
|
462
|
+
<img src="./docs/images/day.png" alt="Availability day view — month grid with red booked cells and green free cells"/>
|
|
463
|
+
<p><em>Day view: the month grid shows only booked/free state per day — event names, times, and attendees are never revealed</em></p>
|
|
464
|
+
</div>
|
|
465
|
+
|
|
466
|
+
Pass the minimal event shape — only `id` and `date` are required; `startTime`/`endTime` are optional and mark the whole day as booked regardless:
|
|
343
467
|
|
|
344
468
|
```js
|
|
345
469
|
cal.events = [
|
|
@@ -355,7 +479,12 @@ cal.events = [
|
|
|
355
479
|
<kal-calendar availability-mode="time"></kal-calendar>
|
|
356
480
|
```
|
|
357
481
|
|
|
358
|
-
Clicking a day opens a
|
|
482
|
+
Clicking a day opens a popup with a 24-slot hourly grid (00:00 – 23:00). Each slot shows only "Booked" or "Available" — no event name or organiser is ever rendered. A slot is booked if any event's time window overlaps that hour; the rest are free.
|
|
483
|
+
|
|
484
|
+
<div align="center">
|
|
485
|
+
<img src="./docs/images/time.png" alt="Availability time view — day popup showing 24 hourly slots coloured red (booked) or green (available)"/>
|
|
486
|
+
<p><em>Time view: clicking a day opens an hourly grid — booked slots in red, available slots in green; no event details exposed</em></p>
|
|
487
|
+
</div>
|
|
359
488
|
|
|
360
489
|
### Selectable range
|
|
361
490
|
|
|
@@ -431,6 +560,18 @@ cal.getEngine();
|
|
|
431
560
|
|
|
432
561
|
## CalendarEvent Interface
|
|
433
562
|
|
|
563
|
+
> **Event text renders as text.** `name`, `description`, `location`,
|
|
564
|
+
> `organizer`, `notes`, `tags` and `attendees` are HTML-escaped, so markup in
|
|
565
|
+
> those fields shows as characters rather than being parsed. Use `renderEvent`
|
|
566
|
+
> if you need to emit your own markup. `url` accepts `http:`, `https:`,
|
|
567
|
+
> `mailto:` and relative URLs; anything else becomes `#`. `color` accepts hex
|
|
568
|
+
> values and CSS colour keywords.
|
|
569
|
+
|
|
570
|
+
> **Custom values.** `status`, `category` and `priority` accept any string. An
|
|
571
|
+
> unrecognised value renders as an uppercased badge with a neutral fill, which
|
|
572
|
+
> you can style via `.badge.status-<your-value>` or recolour through
|
|
573
|
+
> `--calendar-badge-bg` / `--calendar-badge-text`.
|
|
574
|
+
|
|
434
575
|
```typescript
|
|
435
576
|
interface CalendarEvent {
|
|
436
577
|
id: string | number;
|
|
@@ -443,18 +584,18 @@ interface CalendarEvent {
|
|
|
443
584
|
|
|
444
585
|
description?: string;
|
|
445
586
|
color?: string;
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
| 'personal'
|
|
449
|
-
|
|
450
|
-
| 'deadline'
|
|
451
|
-
| 'appointment'
|
|
452
|
-
| 'other';
|
|
587
|
+
// Known values keep autocomplete; any other string is accepted
|
|
588
|
+
category?: Open<
|
|
589
|
+
'work' | 'personal' | 'meeting' | 'deadline' | 'appointment' | 'other'
|
|
590
|
+
>;
|
|
453
591
|
location?: string;
|
|
454
592
|
url?: string;
|
|
455
593
|
|
|
456
|
-
status?: 'scheduled' | 'completed' | 'cancelled' | 'tentative'
|
|
457
|
-
priority?: 'low' | 'medium' | 'high'
|
|
594
|
+
status?: Open<'scheduled' | 'completed' | 'cancelled' | 'tentative'>;
|
|
595
|
+
priority?: Open<'low' | 'medium' | 'high'>;
|
|
596
|
+
|
|
597
|
+
// Required under availability-mode; see Availability Mode below
|
|
598
|
+
availabilityStatus?: Open<'open' | 'conditional' | 'blocked'>;
|
|
458
599
|
|
|
459
600
|
attendees?: string[];
|
|
460
601
|
organizer?: string;
|
|
@@ -474,26 +615,77 @@ interface CalendarEvent {
|
|
|
474
615
|
|
|
475
616
|
## Theming
|
|
476
617
|
|
|
477
|
-
###
|
|
618
|
+
### Design tokens
|
|
619
|
+
|
|
620
|
+
Every colour, size, radius, shadow and spacing step is a custom property. Two
|
|
621
|
+
tiers: `--kal-*` holds the raw palette, `--calendar-*` names what each value is
|
|
622
|
+
for. Override the `--calendar-*` layer — the primitives are internal.
|
|
478
623
|
|
|
479
624
|
```css
|
|
480
625
|
:root {
|
|
626
|
+
/* Brand */
|
|
481
627
|
--calendar-primary-color: #fc8917;
|
|
482
628
|
--calendar-secondary-color: #fca045;
|
|
483
629
|
--calendar-tertiary-color: #fdb873;
|
|
630
|
+
|
|
631
|
+
/* Surfaces and text */
|
|
484
632
|
--calendar-text-color: #2c3e50;
|
|
485
633
|
--calendar-text-light: #6b7280;
|
|
486
|
-
--calendar-
|
|
487
|
-
--calendar-today-outline: #f7db04;
|
|
488
|
-
--calendar-event-indicator: #1890ff;
|
|
634
|
+
--calendar-on-accent: #fff;
|
|
489
635
|
--calendar-background: #fff;
|
|
636
|
+
--calendar-border-color: #dee2e6;
|
|
490
637
|
--calendar-cell-hover: #f3f4f6;
|
|
638
|
+
--calendar-header-bg: #f8f9fa;
|
|
491
639
|
--calendar-selected-bg: #eff6ff;
|
|
640
|
+
--calendar-popup-bg: #fff;
|
|
641
|
+
--calendar-picker-bg: #fff;
|
|
642
|
+
--calendar-today-outline: #f7db04;
|
|
643
|
+
--calendar-event-indicator: #1890ff;
|
|
644
|
+
--calendar-input-invalid: #ef4444;
|
|
645
|
+
--calendar-link: #2563eb;
|
|
646
|
+
--calendar-skeleton-base: #f0f0f0;
|
|
647
|
+
--calendar-skeleton-highlight: #e8e8e8;
|
|
648
|
+
|
|
649
|
+
/* Availability */
|
|
650
|
+
--calendar-open-bg: #dcfce7;
|
|
651
|
+
--calendar-open-fg: #16a34a;
|
|
652
|
+
--calendar-conditional-bg: #fef3c7;
|
|
653
|
+
--calendar-conditional-fg: #d97706;
|
|
654
|
+
--calendar-blocked-bg: #fee2e2;
|
|
655
|
+
--calendar-blocked-fg: #dc2626;
|
|
656
|
+
--calendar-range-bg: #16a34a;
|
|
657
|
+
--calendar-range-outline: #15803d;
|
|
658
|
+
--calendar-in-range-bg: #bbf7d0;
|
|
659
|
+
--calendar-in-range-outline: #86efac;
|
|
660
|
+
|
|
661
|
+
/* Badges — bg/text is the fallback for caller-defined values */
|
|
662
|
+
--calendar-badge-bg: #f3f4f6;
|
|
663
|
+
--calendar-badge-text: #4b5563;
|
|
664
|
+
--calendar-badge-success-bg: #d1fae5;
|
|
665
|
+
--calendar-badge-success-text: #059669;
|
|
666
|
+
--calendar-badge-info-bg: #dbeafe;
|
|
667
|
+
--calendar-badge-info-text: #2563eb;
|
|
668
|
+
--calendar-badge-warning-bg: #fef3c7;
|
|
669
|
+
--calendar-badge-warning-text: #d97706;
|
|
670
|
+
--calendar-badge-danger-bg: #fee2e2;
|
|
671
|
+
--calendar-badge-danger-text: #dc2626;
|
|
672
|
+
--calendar-badge-neutral-bg: #f3f4f6;
|
|
673
|
+
--calendar-badge-neutral-text: #6b7280;
|
|
674
|
+
--calendar-badge-positive-bg: #dcfce7;
|
|
675
|
+
--calendar-badge-positive-text: #16a34a;
|
|
676
|
+
--calendar-badge-tentative-bg: #e0e7ff;
|
|
677
|
+
--calendar-badge-tentative-text: #4f46e5;
|
|
492
678
|
}
|
|
493
679
|
```
|
|
494
680
|
|
|
681
|
+
Type, radius, elevation and spacing scales are exposed the same way —
|
|
682
|
+
`--calendar-font-*`, `--calendar-radius-*`, `--calendar-shadow-*` and
|
|
683
|
+
`--calendar-space-*`. See `dist/styles/calendar.css` for the full set.
|
|
684
|
+
|
|
495
685
|
### JS theme property (full reference)
|
|
496
686
|
|
|
687
|
+
Every `--calendar-*` colour token has a matching camelCase theme key.
|
|
688
|
+
|
|
497
689
|
```js
|
|
498
690
|
cal.theme = {
|
|
499
691
|
primary: '#3b82f6',
|
|
@@ -501,15 +693,54 @@ cal.theme = {
|
|
|
501
693
|
tertiary: '#93c5fd',
|
|
502
694
|
textColor: '#111827',
|
|
503
695
|
textLight: '#6b7280',
|
|
696
|
+
onAccent: '#ffffff',
|
|
504
697
|
background: '#ffffff',
|
|
505
698
|
cellHover: '#f3f4f6',
|
|
506
699
|
borderColor: '#e5e7eb',
|
|
507
700
|
todayOutline: '#fbbf24',
|
|
508
701
|
selectedBg: '#eff6ff',
|
|
702
|
+
headerBg: '#f8f9fa',
|
|
703
|
+
popupBg: '#ffffff',
|
|
704
|
+
pickerBg: '#ffffff',
|
|
705
|
+
pickerShadow: '0 4px 20px rgba(0, 0, 0, 0.15)',
|
|
509
706
|
eventIndicator: '#10b981',
|
|
707
|
+
link: '#2563eb',
|
|
708
|
+
|
|
709
|
+
// Availability
|
|
710
|
+
openBg: '#dcfce7',
|
|
711
|
+
openFg: '#16a34a',
|
|
712
|
+
conditionalBg: '#fef3c7',
|
|
713
|
+
conditionalFg: '#d97706',
|
|
714
|
+
blockedBg: '#fee2e2',
|
|
715
|
+
blockedFg: '#dc2626',
|
|
716
|
+
rangeBg: '#16a34a',
|
|
717
|
+
rangeOutline: '#15803d',
|
|
718
|
+
inRangeBg: '#bbf7d0',
|
|
719
|
+
inRangeOutline: '#86efac',
|
|
720
|
+
|
|
721
|
+
// Badges
|
|
722
|
+
badgeBg: '#f3f4f6',
|
|
723
|
+
badgeText: '#4b5563',
|
|
724
|
+
badgeSuccessBg: '#d1fae5',
|
|
725
|
+
badgeSuccessText: '#059669',
|
|
726
|
+
badgeInfoBg: '#dbeafe',
|
|
727
|
+
badgeInfoText: '#2563eb',
|
|
728
|
+
badgeWarningBg: '#fef3c7',
|
|
729
|
+
badgeWarningText: '#d97706',
|
|
730
|
+
badgeDangerBg: '#fee2e2',
|
|
731
|
+
badgeDangerText: '#dc2626',
|
|
732
|
+
badgeNeutralBg: '#f3f4f6',
|
|
733
|
+
badgeNeutralText: '#6b7280',
|
|
734
|
+
badgePositiveBg: '#dcfce7',
|
|
735
|
+
badgePositiveText: '#16a34a',
|
|
736
|
+
badgeTentativeBg: '#e0e7ff',
|
|
737
|
+
badgeTentativeText: '#4f46e5',
|
|
510
738
|
};
|
|
511
739
|
```
|
|
512
740
|
|
|
741
|
+
> `availabilityColors` writes an inline colour on the cell, so for any bucket it
|
|
742
|
+
> names it takes precedence over the matching `theme` key.
|
|
743
|
+
|
|
513
744
|
### Dark theme example
|
|
514
745
|
|
|
515
746
|
```js
|
package/dist/core/index.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
type Open<T extends string> = T | (string & {});
|
|
1
2
|
interface CalendarEvent {
|
|
2
3
|
id: string | number;
|
|
3
4
|
name: string;
|
|
@@ -7,11 +8,12 @@ interface CalendarEvent {
|
|
|
7
8
|
allDay?: boolean;
|
|
8
9
|
description?: string;
|
|
9
10
|
color?: string;
|
|
10
|
-
category?: 'work' | 'personal' | 'meeting' | 'deadline' | 'appointment' | 'other'
|
|
11
|
+
category?: Open<'work' | 'personal' | 'meeting' | 'deadline' | 'appointment' | 'other'>;
|
|
11
12
|
location?: string;
|
|
12
13
|
url?: string;
|
|
13
|
-
status?: 'scheduled' | 'completed' | 'cancelled' | 'tentative'
|
|
14
|
-
priority?: 'low' | 'medium' | 'high'
|
|
14
|
+
status?: Open<'scheduled' | 'completed' | 'cancelled' | 'tentative'>;
|
|
15
|
+
priority?: Open<'low' | 'medium' | 'high'>;
|
|
16
|
+
availabilityStatus?: Open<'open' | 'conditional' | 'blocked'>;
|
|
15
17
|
attendees?: string[];
|
|
16
18
|
organizer?: string;
|
|
17
19
|
reminders?: number[];
|
|
@@ -52,6 +54,13 @@ interface CalendarConfig {
|
|
|
52
54
|
maxYear?: number;
|
|
53
55
|
weekStartsOn?: 0 | 1;
|
|
54
56
|
categoryColors?: CategoryColorMap;
|
|
57
|
+
monthCount?: number;
|
|
58
|
+
}
|
|
59
|
+
interface CalendarPane {
|
|
60
|
+
year: number;
|
|
61
|
+
month: number;
|
|
62
|
+
monthAndYearText: string;
|
|
63
|
+
calendarDates: CalendarDate[][];
|
|
55
64
|
}
|
|
56
65
|
interface CalendarActions {
|
|
57
66
|
next: () => void;
|
|
@@ -62,18 +71,14 @@ interface CalendarActions {
|
|
|
62
71
|
selectDate: (date: Date) => void;
|
|
63
72
|
updateTasks: () => void;
|
|
64
73
|
}
|
|
65
|
-
interface PopupPosition {
|
|
66
|
-
class: 'popup-left' | 'popup-right' | 'popup-center-top' | 'popup-center-bottom';
|
|
67
|
-
style?: Record<string, string | number>;
|
|
68
|
-
}
|
|
69
74
|
interface CalendarViewModel extends CalendarState {
|
|
70
75
|
months: string[];
|
|
71
76
|
days: string[];
|
|
72
77
|
years: number[];
|
|
73
78
|
monthAndYearText: string;
|
|
74
79
|
scheduleDay: string;
|
|
80
|
+
panes: CalendarPane[];
|
|
75
81
|
calendarDates: CalendarDate[][];
|
|
76
|
-
popupPositionClass: string;
|
|
77
82
|
}
|
|
78
83
|
type CalendarEventHandler = (event: CalendarEvent) => void;
|
|
79
84
|
interface CalendarProps {
|
|
@@ -98,7 +103,39 @@ interface CalendarTheme {
|
|
|
98
103
|
borderColor?: string;
|
|
99
104
|
todayOutline?: string;
|
|
100
105
|
selectedBg?: string;
|
|
106
|
+
headerBg?: string;
|
|
107
|
+
popupBg?: string;
|
|
108
|
+
pickerBg?: string;
|
|
109
|
+
pickerShadow?: string;
|
|
101
110
|
eventIndicator?: string;
|
|
111
|
+
onAccent?: string;
|
|
112
|
+
link?: string;
|
|
113
|
+
openBg?: string;
|
|
114
|
+
openFg?: string;
|
|
115
|
+
conditionalBg?: string;
|
|
116
|
+
conditionalFg?: string;
|
|
117
|
+
blockedBg?: string;
|
|
118
|
+
blockedFg?: string;
|
|
119
|
+
rangeBg?: string;
|
|
120
|
+
rangeOutline?: string;
|
|
121
|
+
inRangeBg?: string;
|
|
122
|
+
inRangeOutline?: string;
|
|
123
|
+
badgeBg?: string;
|
|
124
|
+
badgeText?: string;
|
|
125
|
+
badgeSuccessBg?: string;
|
|
126
|
+
badgeSuccessText?: string;
|
|
127
|
+
badgeInfoBg?: string;
|
|
128
|
+
badgeInfoText?: string;
|
|
129
|
+
badgeWarningBg?: string;
|
|
130
|
+
badgeWarningText?: string;
|
|
131
|
+
badgeDangerBg?: string;
|
|
132
|
+
badgeDangerText?: string;
|
|
133
|
+
badgeNeutralBg?: string;
|
|
134
|
+
badgeNeutralText?: string;
|
|
135
|
+
badgePositiveBg?: string;
|
|
136
|
+
badgePositiveText?: string;
|
|
137
|
+
badgeTentativeBg?: string;
|
|
138
|
+
badgeTentativeText?: string;
|
|
102
139
|
}
|
|
103
140
|
|
|
104
141
|
declare const MONTHS: string[];
|
|
@@ -111,7 +148,6 @@ declare function generateYears(minYear?: number, maxYear?: number): number[];
|
|
|
111
148
|
declare function getEventsForDate(events: CalendarEvent[], date: Date): CalendarEvent[];
|
|
112
149
|
declare function hasEvents(events: CalendarEvent[], date: Date): boolean;
|
|
113
150
|
declare function generateCalendarDates(year: number, month: number, events?: CalendarEvent[], weekStartsOn?: 0 | 1): CalendarDate[][];
|
|
114
|
-
declare function getPopupPositionClass(selectedDayIndex: number | null): string;
|
|
115
151
|
declare function getCellClasses(calendarDate: CalendarDate): string[];
|
|
116
152
|
declare function formatDateForDisplay(date: Date): string;
|
|
117
153
|
declare function getMonthYearText(year: number, month: number): string;
|
|
@@ -123,6 +159,10 @@ declare function getDefaultEventColor(category?: string, customColors?: Category
|
|
|
123
159
|
declare function mergeCategoryColors(customColors?: CategoryColorMap): CategoryColorMap;
|
|
124
160
|
declare function isValidHexColor(color: string): boolean;
|
|
125
161
|
declare function getCategoryColor(category: string, customColors?: CategoryColorMap): string;
|
|
162
|
+
declare function escapeHtml(value: unknown): string;
|
|
163
|
+
declare function slugifyToken(value: string): string;
|
|
164
|
+
declare function safeUrl(value: string): string;
|
|
165
|
+
declare function safeColor(value: string): string;
|
|
126
166
|
|
|
127
167
|
declare class CalendarEngine {
|
|
128
168
|
private state;
|
|
@@ -220,4 +260,4 @@ declare class CalendarEngine {
|
|
|
220
260
|
destroy(): void;
|
|
221
261
|
}
|
|
222
262
|
|
|
223
|
-
export { type CalendarActions, type CalendarConfig, type CalendarDate, CalendarEngine, type CalendarEvent, type CalendarEventHandler, type CalendarProps, type CalendarState, type CalendarTheme, type CalendarViewModel, type CategoryColorMap, DAYS, DEFAULT_CATEGORY_COLORS, MONTHS, MONTHS_FULL,
|
|
263
|
+
export { type CalendarActions, type CalendarConfig, type CalendarDate, CalendarEngine, type CalendarEvent, type CalendarEventHandler, type CalendarPane, type CalendarProps, type CalendarState, type CalendarTheme, type CalendarViewModel, type CategoryColorMap, DAYS, DEFAULT_CATEGORY_COLORS, MONTHS, MONTHS_FULL, escapeHtml, formatAttendees, formatDateForDisplay, formatTimeRange, generateCalendarDates, generateYears, getCategoryColor, getCellClasses, getDefaultEventColor, getEventsForDate, getMonthYearText, hasEvents, isSameDay, isToday, isValidHexColor, mergeCategoryColors, normalizeDate, safeColor, safeUrl, slugifyToken, sortEventsByTime };
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
type Open<T extends string> = T | (string & {});
|
|
1
2
|
interface CalendarEvent {
|
|
2
3
|
id: string | number;
|
|
3
4
|
name: string;
|
|
@@ -7,11 +8,12 @@ interface CalendarEvent {
|
|
|
7
8
|
allDay?: boolean;
|
|
8
9
|
description?: string;
|
|
9
10
|
color?: string;
|
|
10
|
-
category?: 'work' | 'personal' | 'meeting' | 'deadline' | 'appointment' | 'other'
|
|
11
|
+
category?: Open<'work' | 'personal' | 'meeting' | 'deadline' | 'appointment' | 'other'>;
|
|
11
12
|
location?: string;
|
|
12
13
|
url?: string;
|
|
13
|
-
status?: 'scheduled' | 'completed' | 'cancelled' | 'tentative'
|
|
14
|
-
priority?: 'low' | 'medium' | 'high'
|
|
14
|
+
status?: Open<'scheduled' | 'completed' | 'cancelled' | 'tentative'>;
|
|
15
|
+
priority?: Open<'low' | 'medium' | 'high'>;
|
|
16
|
+
availabilityStatus?: Open<'open' | 'conditional' | 'blocked'>;
|
|
15
17
|
attendees?: string[];
|
|
16
18
|
organizer?: string;
|
|
17
19
|
reminders?: number[];
|
|
@@ -52,6 +54,13 @@ interface CalendarConfig {
|
|
|
52
54
|
maxYear?: number;
|
|
53
55
|
weekStartsOn?: 0 | 1;
|
|
54
56
|
categoryColors?: CategoryColorMap;
|
|
57
|
+
monthCount?: number;
|
|
58
|
+
}
|
|
59
|
+
interface CalendarPane {
|
|
60
|
+
year: number;
|
|
61
|
+
month: number;
|
|
62
|
+
monthAndYearText: string;
|
|
63
|
+
calendarDates: CalendarDate[][];
|
|
55
64
|
}
|
|
56
65
|
interface CalendarActions {
|
|
57
66
|
next: () => void;
|
|
@@ -62,18 +71,14 @@ interface CalendarActions {
|
|
|
62
71
|
selectDate: (date: Date) => void;
|
|
63
72
|
updateTasks: () => void;
|
|
64
73
|
}
|
|
65
|
-
interface PopupPosition {
|
|
66
|
-
class: 'popup-left' | 'popup-right' | 'popup-center-top' | 'popup-center-bottom';
|
|
67
|
-
style?: Record<string, string | number>;
|
|
68
|
-
}
|
|
69
74
|
interface CalendarViewModel extends CalendarState {
|
|
70
75
|
months: string[];
|
|
71
76
|
days: string[];
|
|
72
77
|
years: number[];
|
|
73
78
|
monthAndYearText: string;
|
|
74
79
|
scheduleDay: string;
|
|
80
|
+
panes: CalendarPane[];
|
|
75
81
|
calendarDates: CalendarDate[][];
|
|
76
|
-
popupPositionClass: string;
|
|
77
82
|
}
|
|
78
83
|
type CalendarEventHandler = (event: CalendarEvent) => void;
|
|
79
84
|
interface CalendarProps {
|
|
@@ -98,7 +103,39 @@ interface CalendarTheme {
|
|
|
98
103
|
borderColor?: string;
|
|
99
104
|
todayOutline?: string;
|
|
100
105
|
selectedBg?: string;
|
|
106
|
+
headerBg?: string;
|
|
107
|
+
popupBg?: string;
|
|
108
|
+
pickerBg?: string;
|
|
109
|
+
pickerShadow?: string;
|
|
101
110
|
eventIndicator?: string;
|
|
111
|
+
onAccent?: string;
|
|
112
|
+
link?: string;
|
|
113
|
+
openBg?: string;
|
|
114
|
+
openFg?: string;
|
|
115
|
+
conditionalBg?: string;
|
|
116
|
+
conditionalFg?: string;
|
|
117
|
+
blockedBg?: string;
|
|
118
|
+
blockedFg?: string;
|
|
119
|
+
rangeBg?: string;
|
|
120
|
+
rangeOutline?: string;
|
|
121
|
+
inRangeBg?: string;
|
|
122
|
+
inRangeOutline?: string;
|
|
123
|
+
badgeBg?: string;
|
|
124
|
+
badgeText?: string;
|
|
125
|
+
badgeSuccessBg?: string;
|
|
126
|
+
badgeSuccessText?: string;
|
|
127
|
+
badgeInfoBg?: string;
|
|
128
|
+
badgeInfoText?: string;
|
|
129
|
+
badgeWarningBg?: string;
|
|
130
|
+
badgeWarningText?: string;
|
|
131
|
+
badgeDangerBg?: string;
|
|
132
|
+
badgeDangerText?: string;
|
|
133
|
+
badgeNeutralBg?: string;
|
|
134
|
+
badgeNeutralText?: string;
|
|
135
|
+
badgePositiveBg?: string;
|
|
136
|
+
badgePositiveText?: string;
|
|
137
|
+
badgeTentativeBg?: string;
|
|
138
|
+
badgeTentativeText?: string;
|
|
102
139
|
}
|
|
103
140
|
|
|
104
141
|
declare const MONTHS: string[];
|
|
@@ -111,7 +148,6 @@ declare function generateYears(minYear?: number, maxYear?: number): number[];
|
|
|
111
148
|
declare function getEventsForDate(events: CalendarEvent[], date: Date): CalendarEvent[];
|
|
112
149
|
declare function hasEvents(events: CalendarEvent[], date: Date): boolean;
|
|
113
150
|
declare function generateCalendarDates(year: number, month: number, events?: CalendarEvent[], weekStartsOn?: 0 | 1): CalendarDate[][];
|
|
114
|
-
declare function getPopupPositionClass(selectedDayIndex: number | null): string;
|
|
115
151
|
declare function getCellClasses(calendarDate: CalendarDate): string[];
|
|
116
152
|
declare function formatDateForDisplay(date: Date): string;
|
|
117
153
|
declare function getMonthYearText(year: number, month: number): string;
|
|
@@ -123,6 +159,10 @@ declare function getDefaultEventColor(category?: string, customColors?: Category
|
|
|
123
159
|
declare function mergeCategoryColors(customColors?: CategoryColorMap): CategoryColorMap;
|
|
124
160
|
declare function isValidHexColor(color: string): boolean;
|
|
125
161
|
declare function getCategoryColor(category: string, customColors?: CategoryColorMap): string;
|
|
162
|
+
declare function escapeHtml(value: unknown): string;
|
|
163
|
+
declare function slugifyToken(value: string): string;
|
|
164
|
+
declare function safeUrl(value: string): string;
|
|
165
|
+
declare function safeColor(value: string): string;
|
|
126
166
|
|
|
127
167
|
declare class CalendarEngine {
|
|
128
168
|
private state;
|
|
@@ -220,4 +260,4 @@ declare class CalendarEngine {
|
|
|
220
260
|
destroy(): void;
|
|
221
261
|
}
|
|
222
262
|
|
|
223
|
-
export { type CalendarActions, type CalendarConfig, type CalendarDate, CalendarEngine, type CalendarEvent, type CalendarEventHandler, type CalendarProps, type CalendarState, type CalendarTheme, type CalendarViewModel, type CategoryColorMap, DAYS, DEFAULT_CATEGORY_COLORS, MONTHS, MONTHS_FULL,
|
|
263
|
+
export { type CalendarActions, type CalendarConfig, type CalendarDate, CalendarEngine, type CalendarEvent, type CalendarEventHandler, type CalendarPane, type CalendarProps, type CalendarState, type CalendarTheme, type CalendarViewModel, type CategoryColorMap, DAYS, DEFAULT_CATEGORY_COLORS, MONTHS, MONTHS_FULL, escapeHtml, formatAttendees, formatDateForDisplay, formatTimeRange, generateCalendarDates, generateYears, getCategoryColor, getCellClasses, getDefaultEventColor, getEventsForDate, getMonthYearText, hasEvents, isSameDay, isToday, isValidHexColor, mergeCategoryColors, normalizeDate, safeColor, safeUrl, slugifyToken, sortEventsByTime };
|