@pure-ds/core 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/CSS-INTELLISENSE-LIMITATION.md +98 -0
- package/CSS-INTELLISENSE-QUICK-REF.md +238 -0
- package/INTELLISENSE.md +384 -0
- package/LICENSE +15 -0
- package/custom-elements-manifest.config.js +30 -0
- package/custom-elements.json +2003 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/packages/pds-configurator/src/figma-export.d.ts +13 -0
- package/dist/types/packages/pds-configurator/src/figma-export.d.ts.map +1 -0
- package/dist/types/packages/pds-configurator/src/pds-config-form.d.ts +2 -0
- package/dist/types/packages/pds-configurator/src/pds-config-form.d.ts.map +1 -0
- package/dist/types/packages/pds-configurator/src/pds-configurator.d.ts +2 -0
- package/dist/types/packages/pds-configurator/src/pds-configurator.d.ts.map +1 -0
- package/dist/types/packages/pds-configurator/src/pds-demo.d.ts +2 -0
- package/dist/types/packages/pds-configurator/src/pds-demo.d.ts.map +1 -0
- package/dist/types/pds.config.d.ts +13 -0
- package/dist/types/pds.config.d.ts.map +1 -0
- package/dist/types/pds.d.ts +408 -0
- package/dist/types/public/assets/js/app.d.ts +2 -0
- package/dist/types/public/assets/js/app.d.ts.map +1 -0
- package/dist/types/public/assets/js/pds.d.ts +23 -0
- package/dist/types/public/assets/js/pds.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-calendar.d.ts +23 -0
- package/dist/types/public/assets/pds/components/pds-calendar.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-drawer.d.ts +2 -0
- package/dist/types/public/assets/pds/components/pds-drawer.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-icon.d.ts +53 -0
- package/dist/types/public/assets/pds/components/pds-icon.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-jsonform.d.ts +104 -0
- package/dist/types/public/assets/pds/components/pds-jsonform.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-richtext.d.ts +121 -0
- package/dist/types/public/assets/pds/components/pds-richtext.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts +61 -0
- package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-splitpanel.d.ts +1 -0
- package/dist/types/public/assets/pds/components/pds-splitpanel.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-tabstrip.d.ts +39 -0
- package/dist/types/public/assets/pds/components/pds-tabstrip.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-toaster.d.ts +111 -0
- package/dist/types/public/assets/pds/components/pds-toaster.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-upload.d.ts +83 -0
- package/dist/types/public/assets/pds/components/pds-upload.d.ts.map +1 -0
- package/dist/types/src/js/app.d.ts +2 -0
- package/dist/types/src/js/app.d.ts.map +1 -0
- package/dist/types/src/js/common/ask.d.ts +22 -0
- package/dist/types/src/js/common/ask.d.ts.map +1 -0
- package/dist/types/src/js/common/common.d.ts +3 -0
- package/dist/types/src/js/common/common.d.ts.map +1 -0
- package/dist/types/src/js/common/font-loader.d.ts +24 -0
- package/dist/types/src/js/common/font-loader.d.ts.map +1 -0
- package/dist/types/src/js/common/msg.d.ts +3 -0
- package/dist/types/src/js/common/msg.d.ts.map +1 -0
- package/dist/types/src/js/lit.d.ts +25 -0
- package/dist/types/src/js/lit.d.ts.map +1 -0
- package/dist/types/src/js/pds-configurator/figma-export.d.ts +13 -0
- package/dist/types/src/js/pds-configurator/figma-export.d.ts.map +1 -0
- package/dist/types/src/js/pds-configurator/pds-config-form.d.ts +2 -0
- package/dist/types/src/js/pds-configurator/pds-config-form.d.ts.map +1 -0
- package/dist/types/src/js/pds-configurator/pds-configurator.d.ts +2 -0
- package/dist/types/src/js/pds-configurator/pds-configurator.d.ts.map +1 -0
- package/dist/types/src/js/pds-configurator/pds-demo.d.ts +2 -0
- package/dist/types/src/js/pds-configurator/pds-demo.d.ts.map +1 -0
- package/dist/types/src/js/pds-core/pds-config.d.ts +758 -0
- package/dist/types/src/js/pds-core/pds-config.d.ts.map +1 -0
- package/dist/types/src/js/pds-core/pds-enhancer-metadata.d.ts +6 -0
- package/dist/types/src/js/pds-core/pds-enhancer-metadata.d.ts.map +1 -0
- package/dist/types/src/js/pds-core/pds-enhancers.d.ts +14 -0
- package/dist/types/src/js/pds-core/pds-enhancers.d.ts.map +1 -0
- package/dist/types/src/js/pds-core/pds-enums.d.ts +87 -0
- package/dist/types/src/js/pds-core/pds-enums.d.ts.map +1 -0
- package/dist/types/src/js/pds-core/pds-generator.d.ts +741 -0
- package/dist/types/src/js/pds-core/pds-generator.d.ts.map +1 -0
- package/dist/types/src/js/pds-core/pds-ontology.d.ts +48 -0
- package/dist/types/src/js/pds-core/pds-ontology.d.ts.map +1 -0
- package/dist/types/src/js/pds-core/pds-paths.d.ts +37 -0
- package/dist/types/src/js/pds-core/pds-paths.d.ts.map +1 -0
- package/dist/types/src/js/pds-core/pds-query.d.ts +102 -0
- package/dist/types/src/js/pds-core/pds-query.d.ts.map +1 -0
- package/dist/types/src/js/pds-core/pds-registry.d.ts +40 -0
- package/dist/types/src/js/pds-core/pds-registry.d.ts.map +1 -0
- package/dist/types/src/js/pds.d.ts +109 -0
- package/dist/types/src/js/pds.d.ts.map +1 -0
- package/dist/types/src/pds-core/pds-api.d.ts +31 -0
- package/dist/types/src/pds-core/pds-api.d.ts.map +1 -0
- package/package.json +104 -0
- package/packages/pds-cli/README.md +15 -0
- package/packages/pds-cli/bin/generate-css-data.js +565 -0
- package/packages/pds-cli/bin/generate-manifest.js +352 -0
- package/packages/pds-cli/bin/pds-build-icons.js +152 -0
- package/packages/pds-cli/bin/pds-dx.js +114 -0
- package/packages/pds-cli/bin/pds-static.js +556 -0
- package/packages/pds-cli/bin/pds.js +127 -0
- package/packages/pds-cli/bin/postinstall.js +380 -0
- package/packages/pds-cli/bin/sync-assets.js +252 -0
- package/packages/pds-cli/lib/asset-roots.js +47 -0
- package/packages/pds-cli/lib/fs-writer.js +75 -0
- package/pds.css-data.json +5 -0
- package/pds.html-data.json +5 -0
- package/public/assets/js/app.js +5719 -0
- package/public/assets/js/lit.js +131 -0
- package/public/assets/js/pds.js +3423 -0
- package/public/assets/pds/components/pds-calendar.js +837 -0
- package/public/assets/pds/components/pds-drawer.js +857 -0
- package/public/assets/pds/components/pds-icon.js +338 -0
- package/public/assets/pds/components/pds-jsonform.js +1775 -0
- package/public/assets/pds/components/pds-richtext.js +1035 -0
- package/public/assets/pds/components/pds-scrollrow.js +331 -0
- package/public/assets/pds/components/pds-splitpanel.js +401 -0
- package/public/assets/pds/components/pds-tabstrip.js +251 -0
- package/public/assets/pds/components/pds-toaster.js +446 -0
- package/public/assets/pds/components/pds-upload.js +657 -0
- package/public/assets/pds/custom-elements.json +2003 -0
- package/public/assets/pds/icons/pds-icons.svg +498 -0
- package/public/assets/pds/pds-css-complete.json +1861 -0
- package/public/assets/pds/pds.css-data.json +2152 -0
- package/public/assets/pds/vscode-custom-data.json +824 -0
- package/readme.md +1870 -0
- package/src/js/pds-core/pds-config.js +1162 -0
- package/src/js/pds-core/pds-enhancer-metadata.js +75 -0
- package/src/js/pds-core/pds-enhancers.js +357 -0
- package/src/js/pds-core/pds-enums.js +86 -0
- package/src/js/pds-core/pds-generator.js +5317 -0
- package/src/js/pds-core/pds-ontology.js +256 -0
- package/src/js/pds-core/pds-paths.js +109 -0
- package/src/js/pds-core/pds-query.js +571 -0
- package/src/js/pds-core/pds-registry.js +129 -0
- package/src/js/pds-core/pds.d.ts +129 -0
- package/src/js/pds.d.ts +408 -0
- package/src/js/pds.js +1579 -0
|
@@ -0,0 +1,837 @@
|
|
|
1
|
+
function parseHTML(html) {
|
|
2
|
+
return new DOMParser().parseFromString(html, "text/html").body.childNodes;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
const PDS = window.PDS;
|
|
6
|
+
/**
|
|
7
|
+
* Simple class for efficient HTML string building
|
|
8
|
+
* @private
|
|
9
|
+
*/
|
|
10
|
+
export class HTMLBuilder {
|
|
11
|
+
#lines = [];
|
|
12
|
+
#container = "";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Constructor
|
|
16
|
+
* @param {String} container - use '{html}' for the built-up string to be placed in
|
|
17
|
+
*/
|
|
18
|
+
constructor(container = "{html}") {
|
|
19
|
+
this.#container = container;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Adds a string to the builder
|
|
24
|
+
* @param {String} htmlPart
|
|
25
|
+
*/
|
|
26
|
+
add(htmlPart) {
|
|
27
|
+
this.#lines.push(htmlPart);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Returns the built-up string, optionally using the given container for enclosing.
|
|
32
|
+
* @returns {String} html string
|
|
33
|
+
*/
|
|
34
|
+
toHTML() {
|
|
35
|
+
const html = this.#lines.join("");
|
|
36
|
+
|
|
37
|
+
if (this.#container.length) return this.#container.replace("{html}", html);
|
|
38
|
+
|
|
39
|
+
return html;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Helper class for date operations
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
class DateHelper {
|
|
48
|
+
#locale;
|
|
49
|
+
|
|
50
|
+
constructor(locale = "en-US") {
|
|
51
|
+
this.#locale = locale;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
parseDate(dateString) {
|
|
55
|
+
const timestamp = Date.parse(dateString);
|
|
56
|
+
return new Date(timestamp);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
getMonthNames() {
|
|
60
|
+
return Array.from({ length: 12 }, (_, i) => {
|
|
61
|
+
return new Date(0, i).toLocaleString(this.#locale, { month: "long" });
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
getDayNames(format = "long") {
|
|
66
|
+
return Array.from({ length: 7 }, (_, i) => {
|
|
67
|
+
// Create a new Date object for each day of the week, starting from Sunday
|
|
68
|
+
const date = new Date(Date.UTC(2024, 0, i + 15));
|
|
69
|
+
return new Intl.DateTimeFormat(this.#locale, { weekday: format }).format(
|
|
70
|
+
date
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @component pds-calendar
|
|
78
|
+
* @description A fully featured calendar component with month navigation, event display, and expandable day views
|
|
79
|
+
*
|
|
80
|
+
* @fires pds-calendar#month-rendered - Dispatched after the calendar month is rendered with event fill capability
|
|
81
|
+
*
|
|
82
|
+
* @attr {String} date - The date to display (defaults to current date). Accepts any valid date string
|
|
83
|
+
*
|
|
84
|
+
* @prop {Date} date - Gets or sets the current date being displayed
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* <caption>Basic calendar</caption>
|
|
88
|
+
* <pds-calendar></pds-calendar>
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* <caption>Calendar with specific date</caption>
|
|
92
|
+
* <pds-calendar date="2024-12-25"></pds-calendar>
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* <caption>Calendar with event handling</caption>
|
|
96
|
+
* <pds-calendar id="my-calendar"></pds-calendar>
|
|
97
|
+
* <script>
|
|
98
|
+
* const calendar = document.getElementById('my-calendar');
|
|
99
|
+
* calendar.addEventListener('month-rendered', (e) => {
|
|
100
|
+
* e.detail.fill({
|
|
101
|
+
* '15': [
|
|
102
|
+
* { title: 'Team Meeting', type: 'primary' },
|
|
103
|
+
* { title: 'Code Review', type: 'info' }
|
|
104
|
+
* ],
|
|
105
|
+
* '20': [
|
|
106
|
+
* { title: 'Project Deadline', type: 'danger' }
|
|
107
|
+
* ]
|
|
108
|
+
* });
|
|
109
|
+
* });
|
|
110
|
+
* </script>
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* <caption>Event types and styling</caption>
|
|
114
|
+
* // Event objects support the following types:
|
|
115
|
+
* // - 'primary' (blue)
|
|
116
|
+
* // - 'info' (light blue)
|
|
117
|
+
* // - 'warning' (yellow)
|
|
118
|
+
* // - 'danger' (red)
|
|
119
|
+
* {
|
|
120
|
+
* title: 'Event Title',
|
|
121
|
+
* type: 'primary' // optional, defaults to 'info'
|
|
122
|
+
* }
|
|
123
|
+
*
|
|
124
|
+
* @cssprop --surface-bg - Calendar background color
|
|
125
|
+
* @cssprop --surface-border - Border color for calendar elements
|
|
126
|
+
* @cssprop --surface-text-secondary - Secondary text color
|
|
127
|
+
* @cssprop --color-primary-500 - Primary color for events and highlights
|
|
128
|
+
* @cssprop --color-warning-500 - Warning event color
|
|
129
|
+
* @cssprop --color-danger-500 - Danger event color
|
|
130
|
+
* @cssprop --color-info-500 - Info event color
|
|
131
|
+
*
|
|
132
|
+
* @csspart calendar-container - The main container for the calendar
|
|
133
|
+
* @csspart calendar-header - The header containing month name and navigation
|
|
134
|
+
* @csspart calendar - The grid container for the calendar days
|
|
135
|
+
* @csspart day - Individual day cells
|
|
136
|
+
* @csspart task - Event items within days
|
|
137
|
+
*/
|
|
138
|
+
customElements.define(
|
|
139
|
+
"pds-calendar",
|
|
140
|
+
|
|
141
|
+
class extends HTMLElement {
|
|
142
|
+
#date;
|
|
143
|
+
#dayNames;
|
|
144
|
+
#monthNames;
|
|
145
|
+
|
|
146
|
+
static get observedAttributes() {
|
|
147
|
+
return ["date"];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
constructor() {
|
|
151
|
+
super();
|
|
152
|
+
this.#date = new Date();
|
|
153
|
+
|
|
154
|
+
this.dateHelper = new DateHelper();
|
|
155
|
+
this.#dayNames = this.dateHelper.getDayNames();
|
|
156
|
+
this.#monthNames = this.dateHelper.getMonthNames();
|
|
157
|
+
|
|
158
|
+
this.attachShadow({ mode: "open" });
|
|
159
|
+
|
|
160
|
+
this.reRender();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Called when observed attributes change
|
|
165
|
+
* @param {String} name - Attribute name
|
|
166
|
+
* @param {String} oldValue - Previous value
|
|
167
|
+
* @param {String} newValue - New value
|
|
168
|
+
*/
|
|
169
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
170
|
+
if (name === "date") {
|
|
171
|
+
this.date = newValue;
|
|
172
|
+
this.reRender();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Sets the current date for the calendar
|
|
178
|
+
* @param {String|Date} value - Date string or Date object
|
|
179
|
+
*/
|
|
180
|
+
set date(value) {
|
|
181
|
+
this.#date =
|
|
182
|
+
typeof value === "string"
|
|
183
|
+
? this.dateHelper.parseDate(value)
|
|
184
|
+
: new Date(value);
|
|
185
|
+
|
|
186
|
+
if (this.isRendered) this.reRender();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Gets the current date
|
|
191
|
+
* @returns {Date} The current date object
|
|
192
|
+
*/
|
|
193
|
+
get date() {
|
|
194
|
+
return this.#date;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async connectedCallback() {
|
|
198
|
+
const componentStyles = PDS.createStylesheet(
|
|
199
|
+
/*css*/
|
|
200
|
+
`
|
|
201
|
+
.calendar {
|
|
202
|
+
display: grid;
|
|
203
|
+
width: 100%;
|
|
204
|
+
min-height: 400px;
|
|
205
|
+
grid-template-columns: repeat(7, minmax(50px, 1fr));
|
|
206
|
+
grid-template-rows: 50px;
|
|
207
|
+
grid-auto-rows: 60px;
|
|
208
|
+
overflow: auto;
|
|
209
|
+
position: relative;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.calendar-container {
|
|
213
|
+
background-color: var(--surface-bg);
|
|
214
|
+
margin: auto;
|
|
215
|
+
overflow: visible;
|
|
216
|
+
box-shadow: var(--shadow-lg);
|
|
217
|
+
border-radius: var(--radius-lg);
|
|
218
|
+
position: relative;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.calendar-header {
|
|
222
|
+
display: grid;
|
|
223
|
+
grid-template-columns: auto 1fr auto;
|
|
224
|
+
|
|
225
|
+
padding: var(--spacing-5) 0;
|
|
226
|
+
border-bottom: var(--border-width-thin) solid var(--surface-border);
|
|
227
|
+
|
|
228
|
+
.month-name {
|
|
229
|
+
margin: 0;
|
|
230
|
+
font-size: var(--font-size-lg);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
button.btn-xs {
|
|
235
|
+
min-height: 0 !important;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.day-name {
|
|
239
|
+
text-align: center;
|
|
240
|
+
font-size: var(--font-size-sm);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.current-month {
|
|
244
|
+
cursor: pointer;
|
|
245
|
+
text-align: center;
|
|
246
|
+
font-size: var(--font-size-xs);
|
|
247
|
+
h3,
|
|
248
|
+
h3 {
|
|
249
|
+
margin: 0;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.year {
|
|
254
|
+
margin: var(--spacing-1) 0 0 0;
|
|
255
|
+
font-size: var(--font-size-sm);
|
|
256
|
+
font-weight: var(--font-weight-semibold);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.day {
|
|
260
|
+
border-bottom: var(--border-width-thin) solid var(--surface-base-border);
|
|
261
|
+
border-right: var(--border-width-thin) solid var(--surface-base-border);
|
|
262
|
+
padding: var(--spacing-1);
|
|
263
|
+
font-size: var(--font-size-xs);
|
|
264
|
+
box-sizing: border-box;
|
|
265
|
+
color: var(--surface-text-secondary);
|
|
266
|
+
position: relative;
|
|
267
|
+
pointer-events: none;
|
|
268
|
+
z-index: 1;
|
|
269
|
+
overflow: hidden;
|
|
270
|
+
|
|
271
|
+
&:nth-of-type(7n + 7) {
|
|
272
|
+
border-right: 0;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
&:nth-of-type(n + 1):nth-of-type(-n + 7) {
|
|
276
|
+
grid-row: 2;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
&:nth-of-type(n + 8):nth-of-type(-n + 14) {
|
|
280
|
+
grid-row: 3;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
&:nth-of-type(n + 15):nth-of-type(-n + 21) {
|
|
284
|
+
grid-row: 4;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
&:nth-of-type(n + 22):nth-of-type(-n + 28) {
|
|
288
|
+
grid-row: 5;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
&:nth-of-type(n + 29):nth-of-type(-n + 35) {
|
|
292
|
+
grid-row: 6;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
&:nth-of-type(7n + 1) {
|
|
296
|
+
grid-column: 1/1;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
&:nth-of-type(7n + 2) {
|
|
300
|
+
grid-column: 2/2;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
&:nth-of-type(7n + 3) {
|
|
304
|
+
grid-column: 3/3;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
&:nth-of-type(7n + 4) {
|
|
308
|
+
grid-column: 4/4;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
&:nth-of-type(7n + 5) {
|
|
312
|
+
grid-column: 5/5;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
&:nth-of-type(7n + 6) {
|
|
316
|
+
grid-column: 6/6;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
&:nth-of-type(7n + 7) {
|
|
320
|
+
grid-column: 7/7;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.nr {
|
|
324
|
+
position: absolute;
|
|
325
|
+
top: var(--spacing-1);
|
|
326
|
+
right: var(--spacing-1);
|
|
327
|
+
z-index: 2;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
&.has-events {
|
|
331
|
+
cursor: pointer;
|
|
332
|
+
pointer-events: all;
|
|
333
|
+
.nr {
|
|
334
|
+
font-weight: var(--font-weight-bold);
|
|
335
|
+
color: var(--color-primary-500);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.day-disabled {
|
|
341
|
+
opacity: 0.4;
|
|
342
|
+
cursor: not-allowed;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.day-name {
|
|
346
|
+
font-size: var(--font-size-xs);
|
|
347
|
+
text-transform: uppercase;
|
|
348
|
+
color: var(--surface-text-secondary);
|
|
349
|
+
text-align: center;
|
|
350
|
+
border-bottom: var(--border-width-thin) solid var(--surface-border);
|
|
351
|
+
line-height: 50px;
|
|
352
|
+
font-weight: var(--font-weight-medium);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
.day-today {
|
|
357
|
+
border: var(--border-width-thick) solid var(--color-primary-500) !important;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.task {
|
|
361
|
+
border-left-width: var(--border-width-thick);
|
|
362
|
+
padding: var(--spacing-1) var(--spacing-2);
|
|
363
|
+
border-left-style: solid;
|
|
364
|
+
font-size: var(--font-size-sm);
|
|
365
|
+
position: relative;
|
|
366
|
+
margin-bottom: var(--spacing-1);
|
|
367
|
+
background: var(--surface-hover);
|
|
368
|
+
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.task--warning {
|
|
372
|
+
border-left-color: var(--color-warning-500);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.task--danger {
|
|
376
|
+
border-left-color: var(--color-danger-500);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.task--info {
|
|
380
|
+
border-left-color: var(--color-info-500);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.task--primary {
|
|
384
|
+
border-left-color: var(--color-primary-500);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.task__detail {
|
|
388
|
+
color: var(--surface-text);
|
|
389
|
+
box-sizing: border-box;
|
|
390
|
+
z-index: 2;
|
|
391
|
+
|
|
392
|
+
h3 {
|
|
393
|
+
font-weight: var(--font-weight-normal);
|
|
394
|
+
font-size: var(--font-size-xs);
|
|
395
|
+
margin: 0;
|
|
396
|
+
|
|
397
|
+
&:hover {
|
|
398
|
+
+ p {
|
|
399
|
+
display: block;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
p {
|
|
405
|
+
display: none;
|
|
406
|
+
margin-top: var(--spacing-1);
|
|
407
|
+
font-size: var(--font-size-xs);
|
|
408
|
+
margin-bottom: 0;
|
|
409
|
+
font-weight: var(--font-weight-medium);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/* Day expansion styles */
|
|
414
|
+
.calendar.day-expanded {
|
|
415
|
+
.day-name {
|
|
416
|
+
opacity: 0;
|
|
417
|
+
pointer-events: none;
|
|
418
|
+
transition: opacity 0.2s;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.day:not(.expanded-cell) {
|
|
422
|
+
opacity: 0;
|
|
423
|
+
pointer-events: none;
|
|
424
|
+
transition: opacity 0.2s;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.day.has-events {
|
|
429
|
+
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.expanded-cell {
|
|
433
|
+
position: absolute !important;
|
|
434
|
+
top: 0 !important;
|
|
435
|
+
left: 0 !important;
|
|
436
|
+
right: 0 !important;
|
|
437
|
+
bottom: 0 !important;
|
|
438
|
+
width: auto !important;
|
|
439
|
+
height: auto !important;
|
|
440
|
+
grid-column: unset !important;
|
|
441
|
+
grid-row: unset !important;
|
|
442
|
+
z-index: 1000 !important;
|
|
443
|
+
background: var(--surface-bg) !important;
|
|
444
|
+
padding: 2rem !important;
|
|
445
|
+
overflow-y: auto !important;
|
|
446
|
+
border: none !important;
|
|
447
|
+
cursor: pointer !important;
|
|
448
|
+
|
|
449
|
+
.nr {
|
|
450
|
+
font-size: var(--font-size-2xl) !important;
|
|
451
|
+
font-weight: var(--font-weight-bold) !important;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.task {
|
|
455
|
+
font-size: var(--font-size-base) !important;
|
|
456
|
+
padding: var(--spacing-4) !important;
|
|
457
|
+
margin-bottom: var(--spacing-3) !important;
|
|
458
|
+
|
|
459
|
+
h3 {
|
|
460
|
+
font-size: var(--font-size-lg) !important;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
`
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
// Adopt primitives (buttons), components (.alert classes), and toaster-specific styles
|
|
471
|
+
await PDS.adoptLayers(
|
|
472
|
+
this.shadowRoot,
|
|
473
|
+
["primitives", "components"],
|
|
474
|
+
[componentStyles]
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
queueMicrotask(() => {
|
|
478
|
+
this.setupPaging();
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Attaches one or more event listeners with optional event delegation
|
|
484
|
+
* @param {String} eventNames - name(s) of the event to listen to, space-separated
|
|
485
|
+
* @param {Function|Object} funcOrObject - function, or object with selectors as keys and functions as values
|
|
486
|
+
* @private
|
|
487
|
+
*/
|
|
488
|
+
on(eventNames, funcOrObject) {
|
|
489
|
+
eventNames.split(" ").forEach((eventName) => {
|
|
490
|
+
if (typeof funcOrObject === "function")
|
|
491
|
+
this.addEventListener(eventName, funcOrObject);
|
|
492
|
+
else {
|
|
493
|
+
this.addEventListener(eventName, (e) => {
|
|
494
|
+
// Walk up the composed path to find matching elements
|
|
495
|
+
const path = e.composedPath();
|
|
496
|
+
|
|
497
|
+
Object.keys(funcOrObject).forEach((selector) => {
|
|
498
|
+
// Check each element in the path for a match
|
|
499
|
+
for (const element of path) {
|
|
500
|
+
if (element.matches && element.matches(selector)) {
|
|
501
|
+
funcOrObject[selector].apply(this, [e]);
|
|
502
|
+
break; // Stop after first match
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Renders the calendar HTML structure
|
|
513
|
+
* @returns {String} HTML string for the calendar
|
|
514
|
+
* @private
|
|
515
|
+
*/
|
|
516
|
+
render() {
|
|
517
|
+
this.month = this.date.getMonth();
|
|
518
|
+
this.year = this.date.getFullYear();
|
|
519
|
+
this.daysInMonth = new Date(this.year, this.month + 1, 0).getDate();
|
|
520
|
+
this.startDay = new Date(this.year, this.month, 0).getDay();
|
|
521
|
+
|
|
522
|
+
const calendarHtml = /*html*/ `
|
|
523
|
+
<div class="calendar-container">
|
|
524
|
+
<nav class="calendar-header">
|
|
525
|
+
<button class="btn-outline prev btn-xs"><pds-icon icon="arrow-left" size="xs"></pds-icon></button>
|
|
526
|
+
<div class="current-month">
|
|
527
|
+
<h3 class="month-name">${this.#monthNames[this.month]}</h3>
|
|
528
|
+
<h4 class="year">${this.year}</h4>
|
|
529
|
+
</div>
|
|
530
|
+
<button class="btn-outline next btn-xs"><pds-icon icon="arrow-right" size="xs"></pds-icon></button>
|
|
531
|
+
</nav>
|
|
532
|
+
|
|
533
|
+
<div class="calendar">
|
|
534
|
+
${this.getDayNamesHtml()}
|
|
535
|
+
${this.getDaysHtml()}
|
|
536
|
+
</div>
|
|
537
|
+
</div>
|
|
538
|
+
`;
|
|
539
|
+
|
|
540
|
+
clearTimeout(this.renderedTimeout);
|
|
541
|
+
|
|
542
|
+
this.renderedTimeout = setTimeout(() => {
|
|
543
|
+
this.dispatchRendered();
|
|
544
|
+
}, 100);
|
|
545
|
+
|
|
546
|
+
return calendarHtml;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Marks the component as rendered
|
|
551
|
+
* @private
|
|
552
|
+
*/
|
|
553
|
+
rendered() {
|
|
554
|
+
this.isRendered = true;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Re-renders the calendar
|
|
559
|
+
* @private
|
|
560
|
+
*/
|
|
561
|
+
reRender() {
|
|
562
|
+
this.shadowRoot.innerHTML = this.render();
|
|
563
|
+
queueMicrotask(() => {
|
|
564
|
+
this.setupDayExpansion();
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Refreshes the calendar display
|
|
570
|
+
* @public
|
|
571
|
+
*/
|
|
572
|
+
refresh() {
|
|
573
|
+
this.reRender();
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Sets up month navigation with accelerating paging on hold
|
|
578
|
+
* @private
|
|
579
|
+
*/
|
|
580
|
+
setupPaging() {
|
|
581
|
+
const MIN_CHANGE_MS = 2,
|
|
582
|
+
logGrowth = (x, base = 10, growthRate = 4) => {
|
|
583
|
+
return Math.exp((Math.log(x) / Math.log(base)) * growthRate);
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
let timeout,
|
|
587
|
+
timeoutMs = -1,
|
|
588
|
+
timeoutChangeMs = 2,
|
|
589
|
+
direction;
|
|
590
|
+
|
|
591
|
+
const moveDate = () => {
|
|
592
|
+
this.date.setMonth(this.date.getMonth() + direction);
|
|
593
|
+
queueMicrotask(() => {
|
|
594
|
+
this.reRender();
|
|
595
|
+
});
|
|
596
|
+
},
|
|
597
|
+
moveDateRecursive = () => {
|
|
598
|
+
moveDate();
|
|
599
|
+
timeout = setTimeout(() => {
|
|
600
|
+
moveDateRecursive();
|
|
601
|
+
|
|
602
|
+
timeoutChangeMs = logGrowth(timeoutChangeMs);
|
|
603
|
+
timeoutMs -= timeoutChangeMs;
|
|
604
|
+
}, timeoutMs);
|
|
605
|
+
},
|
|
606
|
+
startMoveDate = (newDirection) => {
|
|
607
|
+
timeoutChangeMs = MIN_CHANGE_MS;
|
|
608
|
+
direction = newDirection;
|
|
609
|
+
timeoutMs = 200;
|
|
610
|
+
timeout = setTimeout(() => {
|
|
611
|
+
moveDateRecursive();
|
|
612
|
+
}, timeoutMs);
|
|
613
|
+
},
|
|
614
|
+
stopMoveDate = () => {
|
|
615
|
+
if (timeoutChangeMs === MIN_CHANGE_MS) {
|
|
616
|
+
moveDate();
|
|
617
|
+
}
|
|
618
|
+
clearTimeout(timeout);
|
|
619
|
+
timeoutMs = -1;
|
|
620
|
+
timeout = null;
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
this.on("mousedown touchstart", {
|
|
624
|
+
".next": (e) => {
|
|
625
|
+
e.preventDefault();
|
|
626
|
+
startMoveDate(1);
|
|
627
|
+
},
|
|
628
|
+
".prev": (e) => {
|
|
629
|
+
e.preventDefault();
|
|
630
|
+
startMoveDate(-1);
|
|
631
|
+
},
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
this.on("mouseup pointerup", {
|
|
635
|
+
".next, .prev": (e) => {
|
|
636
|
+
e.preventDefault();
|
|
637
|
+
stopMoveDate();
|
|
638
|
+
},
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Sets up day expansion functionality for viewing events
|
|
644
|
+
* @private
|
|
645
|
+
*/
|
|
646
|
+
setupDayExpansion() {
|
|
647
|
+
if (this.expansionSetup) return; // Prevent multiple setups
|
|
648
|
+
this.expansionSetup = true;
|
|
649
|
+
|
|
650
|
+
let expandedDay = null;
|
|
651
|
+
|
|
652
|
+
// Use direct event delegation on shadowRoot
|
|
653
|
+
this.shadowRoot.addEventListener("click", async (e) => {
|
|
654
|
+
const month = e.target.closest(".current-month");
|
|
655
|
+
if (month) {
|
|
656
|
+
this.date = Date.now();
|
|
657
|
+
this.reRender();
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
const cell = e.target.closest(".day.has-events[data-day]");
|
|
662
|
+
if (!cell) return;
|
|
663
|
+
|
|
664
|
+
const day = cell.dataset.day;
|
|
665
|
+
const calendar = this.shadowRoot.querySelector(".calendar");
|
|
666
|
+
|
|
667
|
+
// Toggle if clicking same day
|
|
668
|
+
if (expandedDay === day) {
|
|
669
|
+
await this.collapseDay(calendar, cell);
|
|
670
|
+
expandedDay = null;
|
|
671
|
+
} else {
|
|
672
|
+
// Collapse previous day if exists
|
|
673
|
+
if (expandedDay) {
|
|
674
|
+
const prevCell = this.shadowRoot.querySelector(
|
|
675
|
+
`[data-day="${expandedDay}"]`
|
|
676
|
+
);
|
|
677
|
+
await this.collapseDay(calendar, prevCell);
|
|
678
|
+
}
|
|
679
|
+
await this.expandDay(calendar, cell);
|
|
680
|
+
expandedDay = day;
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Expands a day cell to full view
|
|
687
|
+
* @param {HTMLElement} calendar - The calendar container element
|
|
688
|
+
* @param {HTMLElement} cell - The day cell to expand
|
|
689
|
+
* @private
|
|
690
|
+
*/
|
|
691
|
+
async expandDay(calendar, cell) {
|
|
692
|
+
// Capture the cell's current position and size
|
|
693
|
+
const calendarRect = calendar.getBoundingClientRect();
|
|
694
|
+
const cellRect = cell.getBoundingClientRect();
|
|
695
|
+
|
|
696
|
+
const relativeTop = cellRect.top - calendarRect.top;
|
|
697
|
+
const relativeLeft = cellRect.left - calendarRect.left;
|
|
698
|
+
|
|
699
|
+
// Set initial absolute position to match grid position
|
|
700
|
+
cell.style.position = "absolute";
|
|
701
|
+
cell.style.top = `${relativeTop}px`;
|
|
702
|
+
cell.style.left = `${relativeLeft}px`;
|
|
703
|
+
cell.style.width = `${cellRect.width}px`;
|
|
704
|
+
cell.style.height = `${cellRect.height}px`;
|
|
705
|
+
cell.style.gridColumn = "unset";
|
|
706
|
+
cell.style.gridRow = "unset";
|
|
707
|
+
|
|
708
|
+
// Force a reflow
|
|
709
|
+
cell.offsetHeight;
|
|
710
|
+
|
|
711
|
+
// Now add classes to trigger transition to expanded state
|
|
712
|
+
calendar.classList.add("day-expanded");
|
|
713
|
+
cell.classList.add("expanded-cell");
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Collapses an expanded day cell back to grid view
|
|
718
|
+
* @param {HTMLElement} calendar - The calendar container element
|
|
719
|
+
* @param {HTMLElement} cell - The day cell to collapse
|
|
720
|
+
* @private
|
|
721
|
+
*/
|
|
722
|
+
async collapseDay(calendar, cell) {
|
|
723
|
+
if (!cell) return;
|
|
724
|
+
|
|
725
|
+
// Remove expanded classes
|
|
726
|
+
calendar.classList.remove("day-expanded");
|
|
727
|
+
cell.classList.remove("expanded-cell");
|
|
728
|
+
|
|
729
|
+
// Wait for transition to complete
|
|
730
|
+
await new Promise((resolve) => setTimeout(resolve, 400));
|
|
731
|
+
|
|
732
|
+
// Reset to grid positioning
|
|
733
|
+
cell.style.position = "";
|
|
734
|
+
cell.style.top = "";
|
|
735
|
+
cell.style.left = "";
|
|
736
|
+
cell.style.width = "";
|
|
737
|
+
cell.style.height = "";
|
|
738
|
+
cell.style.gridColumn = "";
|
|
739
|
+
cell.style.gridRow = "";
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Dispatches the month-rendered event with fill capability
|
|
744
|
+
* @fires pds-calendar#month-rendered
|
|
745
|
+
* @private
|
|
746
|
+
*/
|
|
747
|
+
dispatchRendered() {
|
|
748
|
+
this.dispatchEvent(
|
|
749
|
+
new CustomEvent("month-rendered", {
|
|
750
|
+
detail: {
|
|
751
|
+
date: this.date,
|
|
752
|
+
year: this.year,
|
|
753
|
+
month: this.month,
|
|
754
|
+
fill: (data) => {
|
|
755
|
+
if (!data) return;
|
|
756
|
+
let dayDivs = this.shadowRoot.querySelectorAll(`div[data-day]`);
|
|
757
|
+
|
|
758
|
+
for (const day of Object.keys(data)) {
|
|
759
|
+
const dayDiv = dayDivs[parseInt(day)];
|
|
760
|
+
const list = data[day];
|
|
761
|
+
if (list) {
|
|
762
|
+
dayDiv.classList.add("has-events");
|
|
763
|
+
for (const item of list) {
|
|
764
|
+
const html = /*html*/ `<div class="task task--${
|
|
765
|
+
item.type || "info"
|
|
766
|
+
}">
|
|
767
|
+
<div class="task__detail">
|
|
768
|
+
<h3>
|
|
769
|
+
${item.title}
|
|
770
|
+
</h3>
|
|
771
|
+
<p>
|
|
772
|
+
Test
|
|
773
|
+
</p>
|
|
774
|
+
</div>
|
|
775
|
+
</div>`;
|
|
776
|
+
|
|
777
|
+
dayDiv.appendChild(parseHTML(html)[0]);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
},
|
|
782
|
+
},
|
|
783
|
+
|
|
784
|
+
bubbles: true
|
|
785
|
+
})
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/**
|
|
790
|
+
* Generates HTML for day name headers
|
|
791
|
+
* @returns {String} HTML string for day names
|
|
792
|
+
* @private
|
|
793
|
+
*/
|
|
794
|
+
getDayNamesHtml() {
|
|
795
|
+
const html = new HTMLBuilder();
|
|
796
|
+
//let n = this.startDay;
|
|
797
|
+
for (let i = 0; i <= 6; i++) {
|
|
798
|
+
const dayName = this.#dayNames[i].substring(0, 3);
|
|
799
|
+
html.add(/*html*/ `<span class="day-name">${dayName}</span>`);
|
|
800
|
+
}
|
|
801
|
+
return html.toHTML();
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Generates HTML for calendar day cells
|
|
806
|
+
* @returns {String} HTML string for day cells
|
|
807
|
+
* @private
|
|
808
|
+
*/
|
|
809
|
+
getDaysHtml() {
|
|
810
|
+
const html = new HTMLBuilder();
|
|
811
|
+
const now = new Date();
|
|
812
|
+
const todayDay = now.getDate();
|
|
813
|
+
const todayMonth = now.getMonth();
|
|
814
|
+
const todayYear = now.getFullYear();
|
|
815
|
+
const isCurrentMonth =
|
|
816
|
+
this.month === todayMonth && this.year === todayYear;
|
|
817
|
+
|
|
818
|
+
for (let i = 0; i < this.startDay; i++) {
|
|
819
|
+
html.add(/*html*/ `<div class="day day-disabled"></div>`);
|
|
820
|
+
}
|
|
821
|
+
for (let i = 1; i <= this.daysInMonth; i++) {
|
|
822
|
+
const isTodayClass =
|
|
823
|
+
isCurrentMonth && i === todayDay ? "day-today" : "";
|
|
824
|
+
html.add(/*html*/ `
|
|
825
|
+
<div data-day="${i}" class="day ${isTodayClass}">
|
|
826
|
+
<span class="nr">${i}<span>
|
|
827
|
+
</div>`);
|
|
828
|
+
}
|
|
829
|
+
const endDay =
|
|
830
|
+
6 - new Date(this.year, this.month, this.daysInMonth).getDay();
|
|
831
|
+
for (let i = 1; i <= endDay; i++) {
|
|
832
|
+
html.add(/*html*/ `<div class="day day-disabled"></div>`);
|
|
833
|
+
}
|
|
834
|
+
return html.toHTML();
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
);
|