@redvars/peacock 3.5.1 → 3.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/dist/{BaseButton-DuASuVth.js → BaseButton-BNFAYn-S.js} +2 -2
  2. package/dist/{BaseButton-DuASuVth.js.map → BaseButton-BNFAYn-S.js.map} +1 -1
  3. package/dist/BaseInput-14YmcfK7.js +27 -0
  4. package/dist/BaseInput-14YmcfK7.js.map +1 -0
  5. package/dist/banner.js +2 -3
  6. package/dist/banner.js.map +1 -1
  7. package/dist/{button-DouvOfEU.js → button-colors-Ccys3hvS.js} +5 -294
  8. package/dist/button-colors-Ccys3hvS.js.map +1 -0
  9. package/dist/button-group.js +226 -6
  10. package/dist/button-group.js.map +1 -1
  11. package/dist/button.js +294 -8
  12. package/dist/button.js.map +1 -1
  13. package/dist/calendar-column-view.js +634 -0
  14. package/dist/calendar-column-view.js.map +1 -0
  15. package/dist/calendar-event-BrQ_SEKD.js +199 -0
  16. package/dist/calendar-event-BrQ_SEKD.js.map +1 -0
  17. package/dist/calendar-month-view.js +376 -0
  18. package/dist/calendar-month-view.js.map +1 -0
  19. package/dist/calendar.js +339 -0
  20. package/dist/calendar.js.map +1 -0
  21. package/dist/canvas.js +361 -0
  22. package/dist/canvas.js.map +1 -0
  23. package/dist/cb-compound-expression.js +125 -0
  24. package/dist/cb-compound-expression.js.map +1 -0
  25. package/dist/cb-divider.js +150 -0
  26. package/dist/cb-divider.js.map +1 -0
  27. package/dist/cb-expression.js +75 -0
  28. package/dist/cb-expression.js.map +1 -0
  29. package/dist/cb-predicate.js +137 -0
  30. package/dist/cb-predicate.js.map +1 -0
  31. package/dist/code-editor.js +2 -1
  32. package/dist/code-editor.js.map +1 -1
  33. package/dist/code-highlighter.js +1 -1
  34. package/dist/code-highlighter.js.map +1 -1
  35. package/dist/condition-builder.js +58 -0
  36. package/dist/condition-builder.js.map +1 -0
  37. package/dist/custom-elements-jsdocs.json +8479 -3965
  38. package/dist/custom-elements.json +15228 -7544
  39. package/dist/dropdown-button.js +216 -0
  40. package/dist/dropdown-button.js.map +1 -0
  41. package/dist/event-manager-D-QCmUgR.js +113 -0
  42. package/dist/event-manager-D-QCmUgR.js.map +1 -0
  43. package/dist/fab.js +1 -1
  44. package/dist/flow-designer-DvTUrDp5.js +1656 -0
  45. package/dist/flow-designer-DvTUrDp5.js.map +1 -0
  46. package/dist/flow-designer-node-BWrPuxAR.js +548 -0
  47. package/dist/flow-designer-node-BWrPuxAR.js.map +1 -0
  48. package/dist/flow-designer-node.js +4 -0
  49. package/dist/flow-designer-node.js.map +1 -0
  50. package/dist/flow-designer.js +16 -0
  51. package/dist/flow-designer.js.map +1 -0
  52. package/dist/html-editor.js +27516 -0
  53. package/dist/html-editor.js.map +1 -0
  54. package/dist/icon-button-CK1ZuE-2.js +247 -0
  55. package/dist/icon-button-CK1ZuE-2.js.map +1 -0
  56. package/dist/index.js +29 -6
  57. package/dist/index.js.map +1 -1
  58. package/dist/{is-dark-mode-DicqGkCJ.js → is-dark-mode-DOcaw4Yq.js} +2 -27
  59. package/dist/is-dark-mode-DOcaw4Yq.js.map +1 -0
  60. package/dist/modal.js +412 -0
  61. package/dist/modal.js.map +1 -0
  62. package/dist/{navigation-rail-Lxetd5-Z.js → navigation-rail-DTTkqohi.js} +1049 -2391
  63. package/dist/navigation-rail-DTTkqohi.js.map +1 -0
  64. package/dist/notification-manager.js +268 -0
  65. package/dist/notification-manager.js.map +1 -0
  66. package/dist/peacock-loader.js +93 -8
  67. package/dist/peacock-loader.js.map +1 -1
  68. package/dist/popover-NC7b1lTq.js +1971 -0
  69. package/dist/popover-NC7b1lTq.js.map +1 -0
  70. package/dist/popover-content.js +125 -0
  71. package/dist/popover-content.js.map +1 -0
  72. package/dist/popover.js +4 -0
  73. package/dist/popover.js.map +1 -0
  74. package/dist/split-button.js +388 -0
  75. package/dist/split-button.js.map +1 -0
  76. package/dist/src/__controllers/floating-controller.d.ts +35 -0
  77. package/dist/src/calendar/base-event.d.ts +10 -0
  78. package/dist/src/calendar/calendar-column-view.d.ts +41 -0
  79. package/dist/src/calendar/calendar-event.d.ts +7 -0
  80. package/dist/src/calendar/calendar-month-view.d.ts +31 -0
  81. package/dist/src/calendar/calendar.d.ts +65 -0
  82. package/dist/src/calendar/event-manager.d.ts +17 -0
  83. package/dist/src/calendar/index.d.ts +4 -0
  84. package/dist/src/calendar/types.d.ts +13 -0
  85. package/dist/src/calendar/utils.d.ts +31 -0
  86. package/dist/src/canvas/canvas.d.ts +92 -0
  87. package/dist/src/canvas/index.d.ts +2 -0
  88. package/dist/src/condition-builder/cb-compound-expression.d.ts +31 -0
  89. package/dist/src/condition-builder/cb-divider.d.ts +26 -0
  90. package/dist/src/condition-builder/cb-expression.d.ts +31 -0
  91. package/dist/src/condition-builder/cb-predicate.d.ts +30 -0
  92. package/dist/src/condition-builder/condition-builder.d.ts +27 -0
  93. package/dist/src/condition-builder/index.d.ts +5 -0
  94. package/dist/src/dropdown-button/dropdown-button.d.ts +68 -0
  95. package/dist/src/dropdown-button/index.d.ts +1 -0
  96. package/dist/src/flow-designer/commands.d.ts +66 -0
  97. package/dist/src/flow-designer/flow-designer-node.d.ts +46 -0
  98. package/dist/src/flow-designer/flow-designer.d.ts +133 -0
  99. package/dist/src/flow-designer/index.d.ts +7 -0
  100. package/dist/src/flow-designer/layout.d.ts +30 -0
  101. package/dist/src/flow-designer/types.d.ts +142 -0
  102. package/dist/src/flow-designer/validation.d.ts +43 -0
  103. package/dist/src/flow-designer/workflow-utils.d.ts +40 -0
  104. package/dist/src/html-editor/html-editor.d.ts +89 -0
  105. package/dist/src/html-editor/index.d.ts +2 -0
  106. package/dist/src/index.d.ts +15 -0
  107. package/dist/src/list/index.d.ts +2 -0
  108. package/dist/src/list/list-item.d.ts +35 -0
  109. package/dist/src/list/list.d.ts +28 -0
  110. package/dist/src/menu/menu/menu.d.ts +5 -7
  111. package/dist/src/menu/menu-item/menu-item.d.ts +14 -13
  112. package/dist/src/modal/index.d.ts +1 -0
  113. package/dist/src/modal/modal.d.ts +57 -0
  114. package/dist/src/navigation-rail/navigation-rail.d.ts +3 -7
  115. package/dist/src/notification-manager/index.d.ts +1 -0
  116. package/dist/src/notification-manager/notification-manager.d.ts +44 -0
  117. package/dist/src/number-field/number-field.d.ts +2 -2
  118. package/dist/src/popover/index.d.ts +2 -0
  119. package/dist/src/popover/popover-content.d.ts +29 -0
  120. package/dist/src/popover/popover.d.ts +62 -0
  121. package/dist/src/split-button/index.d.ts +1 -0
  122. package/dist/src/split-button/split-button.d.ts +72 -0
  123. package/dist/src/svg/index.d.ts +1 -0
  124. package/dist/src/svg/svg.d.ts +38 -0
  125. package/dist/src/toolbar/toolbar.d.ts +3 -3
  126. package/dist/src/tooltip/tooltip.d.ts +2 -15
  127. package/dist/test/flow-designer.test.d.ts +1 -0
  128. package/dist/toolbar.js +3 -3
  129. package/dist/toolbar.js.map +1 -1
  130. package/dist/tsconfig.tsbuildinfo +1 -1
  131. package/package.json +10 -2
  132. package/readme.md +3 -3
  133. package/src/__controllers/floating-controller.ts +237 -0
  134. package/src/banner/banner.scss +2 -3
  135. package/src/button/button/button.ts +1 -0
  136. package/src/calendar/base-event.ts +49 -0
  137. package/src/calendar/calendar-column-view.scss +326 -0
  138. package/src/calendar/calendar-column-view.ts +392 -0
  139. package/src/calendar/calendar-event.ts +20 -0
  140. package/src/calendar/calendar-month-view.scss +192 -0
  141. package/src/calendar/calendar-month-view.ts +244 -0
  142. package/src/calendar/calendar.scss +71 -0
  143. package/src/calendar/calendar.ts +298 -0
  144. package/src/calendar/event-manager.ts +117 -0
  145. package/src/calendar/index.ts +4 -0
  146. package/src/calendar/types.ts +14 -0
  147. package/src/calendar/utils.ts +180 -0
  148. package/src/canvas/canvas.scss +60 -0
  149. package/src/canvas/canvas.ts +391 -0
  150. package/src/canvas/index.ts +2 -0
  151. package/src/code-highlighter/code-highlighter.ts +1 -1
  152. package/src/condition-builder/cb-compound-expression.scss +37 -0
  153. package/src/condition-builder/cb-compound-expression.ts +80 -0
  154. package/src/condition-builder/cb-divider.scss +93 -0
  155. package/src/condition-builder/cb-divider.ts +56 -0
  156. package/src/condition-builder/cb-expression.scss +14 -0
  157. package/src/condition-builder/cb-expression.ts +49 -0
  158. package/src/condition-builder/cb-predicate.scss +35 -0
  159. package/src/condition-builder/cb-predicate.ts +102 -0
  160. package/src/condition-builder/condition-builder.scss +13 -0
  161. package/src/condition-builder/condition-builder.ts +38 -0
  162. package/src/condition-builder/index.ts +5 -0
  163. package/src/dropdown-button/demo/index.html +110 -0
  164. package/src/dropdown-button/dropdown-button.scss +22 -0
  165. package/src/dropdown-button/dropdown-button.ts +206 -0
  166. package/src/dropdown-button/index.ts +1 -0
  167. package/src/flow-designer/DEMO.md +239 -0
  168. package/src/flow-designer/commands.ts +278 -0
  169. package/src/flow-designer/flow-designer-node.ts +172 -0
  170. package/src/flow-designer/flow-designer.scss +457 -0
  171. package/src/flow-designer/flow-designer.ts +611 -0
  172. package/src/flow-designer/index.ts +41 -0
  173. package/src/flow-designer/layout.ts +357 -0
  174. package/src/flow-designer/types.ts +166 -0
  175. package/src/flow-designer/validation.ts +284 -0
  176. package/src/flow-designer/workflow-utils.ts +282 -0
  177. package/src/html-editor/html-editor.scss +188 -0
  178. package/src/html-editor/html-editor.ts +491 -0
  179. package/src/html-editor/index.ts +3 -0
  180. package/src/index.ts +27 -1
  181. package/src/list/index.ts +2 -0
  182. package/src/list/list-item.scss +111 -0
  183. package/src/list/list-item.ts +175 -0
  184. package/src/list/list.scss +24 -0
  185. package/src/list/list.ts +51 -0
  186. package/src/menu/menu/menu.scss +2 -2
  187. package/src/menu/menu/menu.ts +91 -101
  188. package/src/menu/menu-item/menu-item.scss +4 -0
  189. package/src/menu/menu-item/menu-item.ts +82 -78
  190. package/src/modal/index.ts +1 -0
  191. package/src/modal/modal.scss +206 -0
  192. package/src/modal/modal.ts +195 -0
  193. package/src/navigation-rail/navigation-rail-item.scss +7 -38
  194. package/src/navigation-rail/navigation-rail-item.ts +1 -2
  195. package/src/navigation-rail/navigation-rail.scss +17 -21
  196. package/src/navigation-rail/navigation-rail.ts +6 -9
  197. package/src/notification-manager/index.ts +1 -0
  198. package/src/notification-manager/notification-manager.scss +113 -0
  199. package/src/notification-manager/notification-manager.ts +199 -0
  200. package/src/number-field/number-field.ts +2 -2
  201. package/src/peacock-loader.ts +83 -0
  202. package/src/popover/index.ts +2 -0
  203. package/src/popover/popover-content.scss +69 -0
  204. package/src/popover/popover-content.ts +51 -0
  205. package/src/popover/popover.scss +7 -0
  206. package/src/popover/popover.ts +170 -0
  207. package/src/split-button/index.ts +1 -0
  208. package/src/split-button/split-button-colors.scss +56 -0
  209. package/src/split-button/split-button-sizes.scss +28 -0
  210. package/src/split-button/split-button.scss +79 -0
  211. package/src/split-button/split-button.ts +236 -0
  212. package/src/svg/index.ts +1 -0
  213. package/src/svg/svg.scss +91 -0
  214. package/src/svg/svg.ts +160 -0
  215. package/src/table/table.ts +2 -2
  216. package/src/toolbar/toolbar.ts +3 -3
  217. package/src/tooltip/tooltip.scss +4 -3
  218. package/src/tooltip/tooltip.ts +46 -104
  219. package/dist/button-DouvOfEU.js.map +0 -1
  220. package/dist/button-group-CEdMwvJJ.js +0 -464
  221. package/dist/button-group-CEdMwvJJ.js.map +0 -1
  222. package/dist/is-dark-mode-DicqGkCJ.js.map +0 -1
  223. package/dist/navigation-rail-Lxetd5-Z.js.map +0 -1
  224. package/dist/src/menu/menu/MenuSurfaceController.d.ts +0 -18
  225. package/src/menu/menu/MenuSurfaceController.ts +0 -61
@@ -0,0 +1,244 @@
1
+ import { LitElement, html, nothing } from 'lit';
2
+ import { property, state } from 'lit/decorators.js';
3
+ import {
4
+ addDays,
5
+ differenceInDays,
6
+ startOfDay,
7
+ endOfDay,
8
+ calculateMonthRange,
9
+ formatDate,
10
+ getTimePercent,
11
+ LONG_EVENT_PADDING,
12
+ } from './utils.js';
13
+ import { BaseEvent } from './base-event.js';
14
+ import { CalendarEvent } from './calendar-event.js';
15
+ import { MonthEventManager } from './event-manager.js';
16
+ import type { ColumnEvent } from './event-manager.js';
17
+ import IndividualComponent from '@/IndividualComponent.js';
18
+ import styles from './calendar-month-view.scss';
19
+
20
+ /**
21
+ * @label Calendar Month View
22
+ * @tag wc-calendar-month-view
23
+ * @rawTag calendar-month-view
24
+ * @parentRawTag calendar
25
+ * @summary Internal month view component for the calendar.
26
+ */
27
+ @IndividualComponent
28
+ export class CalendarMonthView extends LitElement {
29
+ static styles = [styles];
30
+
31
+ @property({ type: Array })
32
+ events: CalendarEvent[] = [];
33
+
34
+ @property({ type: Boolean, attribute: 'event-clickable' })
35
+ eventClickable: boolean = true;
36
+
37
+ @property({ type: Object, attribute: false })
38
+ currentTime: Date = new Date();
39
+
40
+ @property({ type: Object, attribute: false })
41
+ contextDate: Date = new Date();
42
+
43
+ @state()
44
+ private dateRange: any = {};
45
+
46
+ @state()
47
+ private weekDayEvents: ColumnEvent[][][] = [];
48
+
49
+ override connectedCallback() {
50
+ super.connectedCallback();
51
+ this._processEvents();
52
+ }
53
+
54
+ override willUpdate(changedProperties: Map<string, unknown>) {
55
+ if (
56
+ changedProperties.has('events') ||
57
+ changedProperties.has('contextDate')
58
+ ) {
59
+ this._processEvents();
60
+ }
61
+ }
62
+
63
+ override firstUpdated() {
64
+ const viewBody = this.renderRoot.querySelector('.view-body');
65
+ if (viewBody) {
66
+ const viewBodyHeight = viewBody.scrollHeight;
67
+ viewBody.scrollTo({
68
+ top:
69
+ (getTimePercent(this.currentTime) / 100) * viewBodyHeight - 150,
70
+ });
71
+ }
72
+ }
73
+
74
+ private _processEvents() {
75
+ this.dateRange = calculateMonthRange(this.contextDate, 1);
76
+ this.weekDayEvents = [];
77
+
78
+ for (
79
+ let i = new Date(this.dateRange.startDate), j = 0;
80
+ j < 6;
81
+ i = addDays(i, 7), j++
82
+ ) {
83
+ const manager = new MonthEventManager();
84
+ manager.addEvents(
85
+ this.events.filter(event =>
86
+ event.isOverlapping(
87
+ new BaseEvent(startOfDay(i), endOfDay(addDays(i, 6))),
88
+ ),
89
+ ),
90
+ );
91
+ manager.process();
92
+ this.weekDayEvents.push(manager.columns);
93
+ }
94
+ }
95
+
96
+ private _getDatePercent(date: Date, dateRangeStartDate: Date): number {
97
+ const currentDay = differenceInDays(startOfDay(date), dateRangeStartDate);
98
+ const percent = (currentDay / 7) * 100;
99
+ if (percent < 0) return 0;
100
+ if (percent > 100) return 100;
101
+ return percent;
102
+ }
103
+
104
+ private _getDayClass(date: Date): string {
105
+ const diff = differenceInDays(
106
+ startOfDay(date),
107
+ startOfDay(this.currentTime),
108
+ );
109
+ if (diff === 0) return 'column today';
110
+ if (diff < 0) return 'column past';
111
+ return 'column future';
112
+ }
113
+
114
+ private _populateColorVars(
115
+ styles: Record<string, string>,
116
+ color: string,
117
+ ) {
118
+ styles['--calendar-event-bg-color'] = `var(--color-${color}-container)`;
119
+ styles['--calendar-event-bg-color--hover'] = `var(--color-inverse-${color})`;
120
+ styles['--calendar-event-border-color'] = `var(--color-${color})`;
121
+ styles['--calendar-event-text-color'] = `var(--color-on-${color}-container)`;
122
+ styles['--calendar-event-text-color--hover'] = `var(--color-on-${color})`;
123
+ }
124
+
125
+ private _emitEventClick(event: any) {
126
+ this.dispatchEvent(
127
+ new CustomEvent('month-view-event-click', {
128
+ detail: { event },
129
+ bubbles: true,
130
+ composed: true,
131
+ }),
132
+ );
133
+ }
134
+
135
+ private _renderHeader() {
136
+ const columns: any[] = [];
137
+ for (
138
+ let i = new Date(this.dateRange.startDate), j = 0;
139
+ j < 7;
140
+ i = addDays(i, 1), j++
141
+ ) {
142
+ columns.push(html`
143
+ <div class="column">
144
+ <div class="column-content">
145
+ <div class="day">${formatDate(i, 'EEEE')}</div>
146
+ </div>
147
+ </div>
148
+ `);
149
+ }
150
+ return columns;
151
+ }
152
+
153
+ private _renderMultiDayBackground(sd: Date) {
154
+ const columns: any[] = [];
155
+ for (let i = new Date(sd), j = 0; j < 7; i = addDays(i, 1), j++) {
156
+ columns.push(html`
157
+ <div class=${this._getDayClass(i)}>
158
+ <div class="column-content">
159
+ <div class="column-header">
160
+ <div class="day">${formatDate(i, 'd')}</div>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ `);
165
+ }
166
+ return columns;
167
+ }
168
+
169
+ private _renderEvents() {
170
+ return this.weekDayEvents.map((eventDay, index) => {
171
+ const weekStartDate = addDays(this.dateRange.startDate, index * 7);
172
+ return html`
173
+ <div class="multi-day-section">
174
+ <div class="multi-day-body-scroll">
175
+ <div class="multi-day-background">
176
+ <div class="columns">
177
+ ${this._renderMultiDayBackground(weekStartDate)}
178
+ </div>
179
+ </div>
180
+ <div class="multi-events">
181
+ <div class="row-content">
182
+ ${eventDay.map(
183
+ nodes => html`
184
+ <div class="row">
185
+ ${nodes.map(node => {
186
+ const evtCls = this.eventClickable
187
+ ? 'event clickable'
188
+ : 'event';
189
+ const evtStyles: Record<string, string> = {
190
+ left: `${this._getDatePercent(node.start, weekStartDate) + LONG_EVENT_PADDING}%`,
191
+ width: `${this._getDatePercent(addDays(node.end, 1), weekStartDate) - this._getDatePercent(node.start, weekStartDate) - 2 * LONG_EVENT_PADDING}%`,
192
+ };
193
+ if (node.color) {
194
+ this._populateColorVars(evtStyles, node.color);
195
+ }
196
+ return html`
197
+ <div
198
+ class=${evtCls}
199
+ style=${this._styleMap(evtStyles)}
200
+ @click=${() => {
201
+ if (this.eventClickable)
202
+ this._emitEventClick(node.data);
203
+ }}
204
+ >
205
+ <div class="event-title">
206
+ ${node.title || '(no title)'}
207
+ </div>
208
+ </div>
209
+ `;
210
+ })}
211
+ </div>
212
+ `,
213
+ )}
214
+ <div class="row-spacer"></div>
215
+ </div>
216
+ </div>
217
+ </div>
218
+ </div>
219
+ `;
220
+ });
221
+ }
222
+
223
+ private _styleMap(styles: Record<string, string>): string {
224
+ return Object.entries(styles)
225
+ .map(([k, v]) => `${k}:${v}`)
226
+ .join(';');
227
+ }
228
+
229
+ render() {
230
+ return html`
231
+ <div class="calendar-month-view">
232
+ <div class="view-header">
233
+ <div class="columns">${this._renderHeader()}</div>
234
+ <div class="scrollbar-placeholder"></div>
235
+ </div>
236
+ <div class="view-body">
237
+ <div class="view-body-scroll">
238
+ <div class="drawing-area">${this._renderEvents()}</div>
239
+ </div>
240
+ </div>
241
+ </div>
242
+ `;
243
+ }
244
+ }
@@ -0,0 +1,71 @@
1
+ @use '../../scss/mixin';
2
+
3
+ @include mixin.base-styles;
4
+
5
+ :host {
6
+ display: block;
7
+ height: 100%;
8
+ min-height: 20em;
9
+
10
+ --calendar-border-color: var(--color-outline-variant);
11
+ --calendar-scale-color: var(--color-outline-variant);
12
+
13
+ --calendar-event-bg-color: var(--color-primary-container);
14
+ --calendar-event-bg-color--hover: var(--color-inverse-primary);
15
+ --calendar-event-border-color: var(--color-primary);
16
+ --calendar-event-text-color: var(--color-on-primary-container);
17
+ --calendar-event-text-color--hover: var(--color-on-primary);
18
+
19
+ --calendar-surface: var(--color-surface);
20
+ --calendar-surface-variant: var(--color-surface-variant);
21
+ --calendar-on-surface: var(--color-on-surface);
22
+ --calendar-on-surface-variant: var(--color-on-surface-variant);
23
+ }
24
+
25
+ .calendar {
26
+ height: 100%;
27
+ display: flex;
28
+ flex-direction: column;
29
+ background: var(--calendar-surface);
30
+ border-radius: var(--shape-corner-large);
31
+ overflow: hidden;
32
+ }
33
+
34
+ .calendar-header {
35
+ .calendar-header-classic {
36
+ display: flex;
37
+ align-items: center;
38
+ padding: 0.75rem 1rem;
39
+ gap: 0.5rem;
40
+
41
+ .header-left {
42
+ display: flex;
43
+ gap: 0.5rem;
44
+ align-items: center;
45
+ flex: 1;
46
+
47
+ .title {
48
+ display: flex;
49
+ align-items: center;
50
+ font-weight: 500;
51
+ font-size: 1rem;
52
+ color: var(--calendar-on-surface);
53
+ padding-inline-start: 0.5rem;
54
+ }
55
+ }
56
+
57
+ .header-right {
58
+ display: flex;
59
+ align-items: center;
60
+ }
61
+ }
62
+ }
63
+
64
+ .calendar-body {
65
+ flex: 1;
66
+ overflow: auto;
67
+
68
+ .view-container {
69
+ height: 100%;
70
+ }
71
+ }
@@ -0,0 +1,298 @@
1
+ import { LitElement, html, nothing } from 'lit';
2
+ import { property, state } from 'lit/decorators.js';
3
+ import { addDays, addMonths, formatDate } from './utils.js';
4
+ import { CalendarEvent } from './calendar-event.js';
5
+ import type { CalendarViewType, EventType } from './types.js';
6
+ import IndividualComponent from '@/IndividualComponent.js';
7
+ import styles from './calendar.scss';
8
+
9
+ /**
10
+ * @label Calendar
11
+ * @tag wc-calendar
12
+ * @rawTag calendar
13
+ * @summary A Material 3 inspired full calendar component for displaying events in day, week, or month views.
14
+ *
15
+ * @cssprop --calendar-border-color - Border color used throughout the calendar grid.
16
+ * @cssprop --calendar-event-bg-color - Background color for calendar events.
17
+ * @cssprop --calendar-event-border-color - Left border color for calendar events.
18
+ *
19
+ * @fires {CustomEvent} event-click - Dispatched when a calendar event is clicked. Detail contains `{ event }`.
20
+ * @fires {CustomEvent} view-change - Dispatched when the calendar view changes. Detail contains `{ view }`.
21
+ * @fires {CustomEvent} date-change - Dispatched when the context date changes. Detail contains `{ date }`.
22
+ *
23
+ * @example
24
+ * ```html
25
+ * <wc-calendar view="week" style="height: 600px"></wc-calendar>
26
+ * ```
27
+ */
28
+ @IndividualComponent
29
+ export class Calendar extends LitElement {
30
+ static styles = [styles];
31
+
32
+ /**
33
+ * Calendar events array.
34
+ */
35
+ @property({ type: Array })
36
+ events: EventType[] = [];
37
+
38
+ /**
39
+ * Available views configuration.
40
+ */
41
+ @property({ type: Array, attribute: 'available-views' })
42
+ availableViews: CalendarViewType[] = [
43
+ { label: 'Day', value: 'day', type: 'column', days: 1 },
44
+ { label: 'Week', value: 'week', type: 'column', days: 7 },
45
+ { label: 'Month', value: 'month', type: 'month' },
46
+ ];
47
+
48
+ /**
49
+ * Current calendar view.
50
+ */
51
+ @property({ type: String, reflect: true })
52
+ view: string = 'week';
53
+
54
+ /**
55
+ * Whether events are clickable.
56
+ */
57
+ @property({ type: Boolean, attribute: 'event-clickable' })
58
+ eventClickable: boolean = true;
59
+
60
+ /**
61
+ * Show loading state.
62
+ */
63
+ @property({ type: Boolean, attribute: 'show-loader' })
64
+ showLoader: boolean = false;
65
+
66
+ /**
67
+ * Timezone string (e.g. 'America/New_York').
68
+ */
69
+ @property({ type: String })
70
+ timezone: string = '';
71
+
72
+ /**
73
+ * The context date for the calendar view.
74
+ */
75
+ @property({ type: Object, attribute: false })
76
+ contextDate: Date | null = null;
77
+
78
+ @state()
79
+ private _currentTime: Date = new Date();
80
+
81
+ @state()
82
+ private _currentView: CalendarViewType | undefined;
83
+
84
+ override connectedCallback() {
85
+ super.connectedCallback();
86
+ if (this.timezone) {
87
+ this._currentTime = new Date(
88
+ new Date().toLocaleString('en', { timeZone: this.timezone }),
89
+ );
90
+ } else {
91
+ this._currentTime = new Date();
92
+ }
93
+ if (!this.contextDate) {
94
+ this.contextDate = this._currentTime;
95
+ }
96
+ }
97
+
98
+ override willUpdate(changedProperties: Map<string, unknown>) {
99
+ if (changedProperties.has('view') || changedProperties.has('availableViews')) {
100
+ this._currentView = this.availableViews.find(v => v.value === this.view);
101
+ }
102
+ }
103
+
104
+ private _onColumnViewDateClick(evt: CustomEvent) {
105
+ evt.stopPropagation();
106
+ this.view = 'day';
107
+ this.contextDate = evt.detail.date;
108
+ this.dispatchEvent(
109
+ new CustomEvent('view-change', {
110
+ detail: { view: this.view },
111
+ bubbles: true,
112
+ composed: true,
113
+ }),
114
+ );
115
+ this.dispatchEvent(
116
+ new CustomEvent('date-change', {
117
+ detail: { date: this.contextDate },
118
+ bubbles: true,
119
+ composed: true,
120
+ }),
121
+ );
122
+ }
123
+
124
+ private _onEventClick(evt: CustomEvent) {
125
+ evt.stopPropagation();
126
+ this.dispatchEvent(
127
+ new CustomEvent('event-click', {
128
+ detail: { event: evt.detail.event },
129
+ bubbles: true,
130
+ composed: true,
131
+ }),
132
+ );
133
+ }
134
+
135
+ previous() {
136
+ if (!this._currentView) return;
137
+ if (this._currentView.days) {
138
+ this.contextDate = addDays(
139
+ this.contextDate!,
140
+ -1 * this._currentView.days,
141
+ );
142
+ } else if (this._currentView.type === 'month') {
143
+ this.contextDate = addMonths(this.contextDate!, -1);
144
+ }
145
+ this.dispatchEvent(
146
+ new CustomEvent('date-change', {
147
+ detail: { date: this.contextDate },
148
+ bubbles: true,
149
+ composed: true,
150
+ }),
151
+ );
152
+ }
153
+
154
+ next() {
155
+ if (!this._currentView) return;
156
+ if (this._currentView.days) {
157
+ this.contextDate = addDays(
158
+ this.contextDate!,
159
+ this._currentView.days,
160
+ );
161
+ } else if (this._currentView.type === 'month') {
162
+ this.contextDate = addMonths(this.contextDate!, 1);
163
+ }
164
+ this.dispatchEvent(
165
+ new CustomEvent('date-change', {
166
+ detail: { date: this.contextDate },
167
+ bubbles: true,
168
+ composed: true,
169
+ }),
170
+ );
171
+ }
172
+
173
+ private _goToToday() {
174
+ this.contextDate = this._currentTime;
175
+ this.dispatchEvent(
176
+ new CustomEvent('date-change', {
177
+ detail: { date: this.contextDate },
178
+ bubbles: true,
179
+ composed: true,
180
+ }),
181
+ );
182
+ }
183
+
184
+ private _onViewSegmentChange(evt: CustomEvent<{ value: string | null }>) {
185
+ if (!evt.detail.value) return;
186
+ this.view = evt.detail.value;
187
+ this.dispatchEvent(
188
+ new CustomEvent('view-change', {
189
+ detail: { view: this.view },
190
+ bubbles: true,
191
+ composed: true,
192
+ }),
193
+ );
194
+ }
195
+
196
+ private _renderHeader() {
197
+ return html`
198
+ <div class="calendar-header-classic">
199
+ <div class="header-left">
200
+ <wc-button
201
+ variant="outlined"
202
+ size="sm"
203
+ class="color-secondary"
204
+ @click=${() => this._goToToday()}
205
+ >
206
+ Today
207
+ </wc-button>
208
+ <wc-icon-button
209
+ variant="text"
210
+ size="sm"
211
+ class="color-secondary"
212
+ @click=${() => this.previous()}
213
+ >
214
+ <wc-icon name="chevron_left"></wc-icon>
215
+ </wc-icon-button>
216
+ <wc-icon-button
217
+ variant="text"
218
+ size="sm"
219
+ class="color-secondary"
220
+ @click=${() => this.next()}
221
+ >
222
+ <wc-icon name="chevron_right"></wc-icon>
223
+ </wc-icon-button>
224
+ <div class="title">
225
+ ${this.contextDate
226
+ ? formatDate(this.contextDate, 'MMMM d, yyyy')
227
+ : ''}
228
+ </div>
229
+ </div>
230
+ <div class="header-right">
231
+ <wc-segmented-button-group @change=${this._onViewSegmentChange}>
232
+ ${this.availableViews.map(
233
+ v =>
234
+ html`<wc-segmented-button
235
+ .value=${v.value}
236
+ ?selected=${this.view === v.value}
237
+ >
238
+ ${v.label}
239
+ </wc-segmented-button>`,
240
+ )}
241
+ </wc-segmented-button-group>
242
+ </div>
243
+ </div>
244
+ `;
245
+ }
246
+
247
+ private _renderCalendarView() {
248
+ if (!this._currentView) return html`<div>Invalid view</div>`;
249
+
250
+ const calEvents = this.events.map(
251
+ event =>
252
+ new CalendarEvent(
253
+ event.start,
254
+ event.end,
255
+ event.title,
256
+ event.color,
257
+ event,
258
+ ),
259
+ );
260
+
261
+ if (this._currentView.type === 'column') {
262
+ return html`
263
+ <wc-calendar-column-view
264
+ .events=${calEvents}
265
+ .view=${this._currentView.value}
266
+ .days=${this._currentView.days || 7}
267
+ .currentTime=${this._currentTime}
268
+ .contextDate=${this.contextDate}
269
+ ?event-clickable=${this.eventClickable}
270
+ @column-view-date-click=${this._onColumnViewDateClick}
271
+ @column-view-event-click=${this._onEventClick}
272
+ ></wc-calendar-column-view>
273
+ `;
274
+ } else if (this._currentView.type === 'month') {
275
+ return html`
276
+ <wc-calendar-month-view
277
+ .events=${calEvents}
278
+ .currentTime=${this._currentTime}
279
+ .contextDate=${this.contextDate}
280
+ ?event-clickable=${this.eventClickable}
281
+ @month-view-event-click=${this._onEventClick}
282
+ ></wc-calendar-month-view>
283
+ `;
284
+ }
285
+ return nothing;
286
+ }
287
+
288
+ render() {
289
+ return html`
290
+ <div class="calendar">
291
+ <div class="calendar-header">${this._renderHeader()}</div>
292
+ <div class="calendar-body">
293
+ <div class="view-container">${this._renderCalendarView()}</div>
294
+ </div>
295
+ </div>
296
+ `;
297
+ }
298
+ }