@triptease/tt-calendar 6.0.2 → 6.0.4
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/CHANGELOG.md +7 -0
- package/README.md +0 -1
- package/custom-elements.json +3 -3
- package/demo/index.html +18 -25
- package/dist/src/DateSelectionContext.js.map +1 -1
- package/dist/src/Styles.js +8 -9
- package/dist/src/Styles.js.map +1 -1
- package/dist/src/TtCalendar.js +64 -51
- package/dist/src/TtCalendar.js.map +1 -1
- package/dist/src/helpers.js.map +1 -1
- package/package.json +5 -43
- package/test/tt-calendar.test.ts +25 -60
- package/tsconfig.json +1 -1
package/CHANGELOG.md
ADDED
package/README.md
CHANGED
package/custom-elements.json
CHANGED
|
@@ -155,7 +155,7 @@
|
|
|
155
155
|
{
|
|
156
156
|
"kind": "variable",
|
|
157
157
|
"name": "styles",
|
|
158
|
-
"default": "css` :host { display: block; } button { appearance: none; padding: 0; border-width: 0; background-color: transparent; border-radius: var(--space-scale-1); padding-block: var(--space-scale-1); padding-inline: var(--space-scale-2); &.compact { padding-block: 0; padding-inline: 0; } &:hover { cursor: pointer; box-shadow: 0px 2px 5px 0px rgba(60, 66, 87, 0.08), 0px 1px 1px 0px rgba(0, 0, 0, 0.12); } &:focus { outline: 1px solid var(--color-primary-400); } svg { display: block; } &.right svg { transform: rotate(180deg); } } h2 { font-weight: var(--font-weight-semibold); color: var(--color-text-500); font-size: var(--font-size-400); display: contents; } .calendar-header { display: flex; justify-content: space-between; align-items: center; padding: 24px 24px 16px 24px; } .calendar-grid { text-align: center; border-top: var(--color-border-200) 1px solid; padding: 0 24px; table { width: 100%; border-collapse: collapse; } tbody { display: grid; row-gap: 4px; } tr { display: grid; grid-template-columns: repeat(7, 48px); } th { color: var(--color-text-400); font-size: var(--font-size-100); font-weight: var(--font-weight-normal); line-height: 20px; padding: 16px 0; } td { font-size: var(--font-size-100); font-weight: var(--font-weight-normal); } } .calendar-footer { display: flex; flex-direction: column; //gap: var(--space-scale-2); svg { vertical-align: middle; } .actions { display: flex; flex: 1 0 auto; padding: var(--space-scale-2) var(--space-scale-3) var(--space-scale-3); button { background-color: var(--color-surface-200); border-color: var(--color-primary-400); border-width: 1px; border-style: solid; color: var(--color-primary-400); font-weight: var(--font-weight-semibold); width: 100%; height: 40px; } } } .day { aspect-ratio: 1; cursor: pointer; position: relative; // For focus outline box-sizing: border-box; height: auto; display: flex; align-items: center; justify-content: center; } .day.in-range { background: var(--color-primary-300); &:first-child { border-top-left-radius: var(--space-scale-1); border-bottom-left-radius: var(--space-scale-1); } &:last-child { border-top-right-radius: var(--space-scale-1); border-bottom-right-radius: var(--space-scale-1); } } .day[aria-disabled
|
|
158
|
+
"default": "css` :host { display: block; } button { appearance: none; padding: 0; border-width: 0; background-color: transparent; border-radius: var(--space-scale-1); padding-block: var(--space-scale-1); padding-inline: var(--space-scale-2); &.compact { padding-block: 0; padding-inline: 0; } &:hover { cursor: pointer; box-shadow: 0px 2px 5px 0px rgba(60, 66, 87, 0.08), 0px 1px 1px 0px rgba(0, 0, 0, 0.12); } &:focus { outline: 1px solid var(--color-primary-400); } svg { display: block; } &.right svg { transform: rotate(180deg); } } h2 { font-weight: var(--font-weight-semibold); color: var(--color-text-500); font-size: var(--font-size-400); display: contents; } .calendar-header { display: flex; justify-content: space-between; align-items: center; padding: 24px 24px 16px 24px; } .calendar-grid { text-align: center; border-top: var(--color-border-200) 1px solid; padding: 0 24px; table { width: 100%; border-collapse: collapse; } tbody { display: grid; row-gap: 4px; } tr { display: grid; grid-template-columns: repeat(7, 48px); } th { color: var(--color-text-400); font-size: var(--font-size-100); font-weight: var(--font-weight-normal); line-height: 20px; padding: 16px 0; } td { font-size: var(--font-size-100); font-weight: var(--font-weight-normal); } } .calendar-footer { display: flex; flex-direction: column; //gap: var(--space-scale-2); svg { vertical-align: middle; } .actions { display: flex; flex: 1 0 auto; padding: var(--space-scale-2) var(--space-scale-3) var(--space-scale-3); button { background-color: var(--color-surface-200); border-color: var(--color-primary-400); border-width: 1px; border-style: solid; color: var(--color-primary-400); font-weight: var(--font-weight-semibold); width: 100%; height: 40px; } } } .day { aspect-ratio: 1; cursor: pointer; position: relative; // For focus outline box-sizing: border-box; height: auto; display: flex; align-items: center; justify-content: center; } .day.in-range { background: var(--color-primary-300); &:first-child { border-top-left-radius: var(--space-scale-1); border-bottom-left-radius: var(--space-scale-1); } &:last-child { border-top-right-radius: var(--space-scale-1); border-bottom-right-radius: var(--space-scale-1); } } .day[aria-disabled='true'] { opacity: 0.7; background-color: var(--color-surface-300); cursor: not-allowed; pointer-events: none; } .day.start-date:has(+ .in-range):after { content: ' '; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: var(--color-primary-300); z-index: -1; border-radius: var(--space-scale-1); border-bottom-right-radius: 0; border-top-right-radius: 0; } .day.in-range + :is(.day:hover, .day:not(.in-range)):before { content: ' '; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: var(--color-primary-300); z-index: -1; border-radius: var(--space-scale-1); border-bottom-left-radius: 0; border-top-left-radius: 0; } .day[aria-selected='true']:not(.in-range), .day:hover { background: var(--color-primary-400); color: var(--color-text-100); border-radius: var(--space-scale-1); font-weight: var(--font-weight-semibold); &.in-range { &:before { content: ' '; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: var(--color-primary-300); z-index: -1; border-radius: var(--bg-border-radius, 0); } &:first-child { --bg-border-radius: var(--space-scale-1) 0 0 var(--space-scale-1); } &:last-child { --bg-border-radius: 0 var(--space-scale-1) var(--space-scale-1) 0; } } } .side-panel-wrapper { border-right: 1px solid var(--color-border-200, var(--color-surface-300)); display: flex; align-items: start; } .side-panel { padding: var(--space-scale-3); grid-template-columns: 1fr; display: grid; gap: var(--space-scale-3); button { font-size: var(--font-size-200); text-wrap: nowrap; line-height: var(--space-scale-3); padding-block: 0; padding-inline: 0; &:hover { color: var(--color-primary-400); box-shadow: none; } &[aria-selected='true'] { color: var(--color-primary-400); } } } details { border-top: 1px solid var(--color-border-200); font-size: var(--font-size-100); font-weight: var(--font-weight-normal); padding: var(--space-scale-2) var(--space-scale-3) var(--space-scale-3); summary { font-weight: var(--font-weight-semibold); position: relative; display: flex; align-items: center; gap: var(--space-scale-1); &::marker { content: ''; } svg.chevron-down { margin-left: var(--space-scale-1); transform: rotate(-90deg); } } &[open] svg.chevron-down { transform: rotate(0deg); } } `"
|
|
159
159
|
}
|
|
160
160
|
],
|
|
161
161
|
"exports": [
|
|
@@ -185,7 +185,7 @@
|
|
|
185
185
|
"text": "object"
|
|
186
186
|
},
|
|
187
187
|
"static": true,
|
|
188
|
-
"default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true }"
|
|
188
|
+
"default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }"
|
|
189
189
|
},
|
|
190
190
|
{
|
|
191
191
|
"kind": "field",
|
|
@@ -284,7 +284,7 @@
|
|
|
284
284
|
"kind": "field",
|
|
285
285
|
"name": "visible",
|
|
286
286
|
"type": {
|
|
287
|
-
"text": "
|
|
287
|
+
"text": "boolean"
|
|
288
288
|
},
|
|
289
289
|
"privacy": "private",
|
|
290
290
|
"default": "false"
|
package/demo/index.html
CHANGED
|
@@ -1,30 +1,23 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html lang="en-GB">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
</head>
|
|
12
|
-
<body>
|
|
13
|
-
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
|
+
<style>
|
|
7
|
+
body {
|
|
8
|
+
background: #fafafa;
|
|
9
|
+
}
|
|
10
|
+
</style>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="demo"></div>
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
<script type="module">
|
|
16
|
+
import { html, render } from 'lit';
|
|
17
|
+
import '../dist/src/tt-calendar.js';
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
some light-dom
|
|
24
|
-
</tt-calendar>
|
|
25
|
-
`,
|
|
26
|
-
document.querySelector('#demo')
|
|
27
|
-
);
|
|
28
|
-
</script>
|
|
29
|
-
</body>
|
|
19
|
+
const header = 'Hello owc World!';
|
|
20
|
+
render(html` <tt-calendar .header=${header}> some light-dom </tt-calendar> `, document.querySelector('#demo'));
|
|
21
|
+
</script>
|
|
22
|
+
</body>
|
|
30
23
|
</html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateSelectionContext.js","sourceRoot":"","sources":["../../src/DateSelectionContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"DateSelectionContext.js","sourceRoot":"","sources":["../../src/DateSelectionContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAuB7C,MAAM,OAAO,kBAAmB,SAAQ,WAAmB;IACzD,YAAY,aAAqB;QAC/B,KAAK,CAAC,gBAAgB,EAAE;YACtB,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,aAAa;SACtB,CAAC,CAAC;IACL,CAAC;IAEM,MAAM,CAAC,EAAE,CAAC,KAAY;QAC3B,OAAO,KAAK,CAAC,IAAI,KAAK,gBAAgB,CAAC;IACzC,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,WAAsB;IACjE,YAAY,kBAA6B;QACvC,KAAK,CAAC,sBAAsB,EAAE;YAC5B,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,kBAAkB;SAC3B,CAAC,CAAC;IACL,CAAC;IAEM,MAAM,CAAC,EAAE,CAAC,KAAY;QAC3B,OAAO,KAAK,CAAC,IAAI,KAAK,sBAAsB,CAAC;IAC/C,CAAC;CACF;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,aAAa,CAAgB,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC;AAEnG,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,SAAwB,EAAoC,EAAE;IAClG,OAAO,cAAc,IAAI,SAAS,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,SAAwB,EAAmC,EAAE;IAChG,OAAO,OAAO,IAAI,SAAS,CAAC;AAC9B,CAAC,CAAC","sourcesContent":["import { createContext } from '@lit/context';\n\nexport interface SingleDateSelection {\n selectedDate: Date | null;\n minDate?: Date;\n maxDate?: Date;\n timezone?: string;\n}\n\nexport interface DateRange {\n startDate?: string;\n endDate?: string;\n}\n\nexport interface DateRangeSelection {\n range: DateRange;\n minDate?: Date;\n maxDate?: Date;\n timezone?: string;\n}\n\nexport type DateSelection = SingleDateSelection | DateRangeSelection;\n\nexport class DateSelectionEvent extends CustomEvent<string> {\n constructor(dateSelection: string) {\n super('date-selection', {\n bubbles: true,\n composed: true,\n detail: dateSelection,\n });\n }\n\n public static is(event: Event): event is DateSelectionEvent {\n return event.type === 'date-selection';\n }\n}\n\nexport class DateRangeSelectionEvent extends CustomEvent<DateRange> {\n constructor(dateRangeSelection: DateRange) {\n super('date-range-selection', {\n bubbles: true,\n composed: true,\n detail: dateRangeSelection,\n });\n }\n\n public static is(event: Event): event is DateRangeSelectionEvent {\n return event.type === 'date-range-selection';\n }\n}\n\nexport const DateSelectionContext = createContext<DateSelection>(Symbol('date-selection-context'));\n\nexport const isSingleDateSelection = (selection: DateSelection): selection is SingleDateSelection => {\n return 'selectedDate' in selection;\n};\n\nexport const isDateRangeSelection = (selection: DateSelection): selection is DateRangeSelection => {\n return 'range' in selection;\n};\n"]}
|
package/dist/src/Styles.js
CHANGED
|
@@ -20,7 +20,9 @@ export const styles = css `
|
|
|
20
20
|
|
|
21
21
|
&:hover {
|
|
22
22
|
cursor: pointer;
|
|
23
|
-
box-shadow:
|
|
23
|
+
box-shadow:
|
|
24
|
+
0px 2px 5px 0px rgba(60, 66, 87, 0.08),
|
|
25
|
+
0px 1px 1px 0px rgba(0, 0, 0, 0.12);
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
&:focus {
|
|
@@ -60,7 +62,6 @@ export const styles = css `
|
|
|
60
62
|
border-collapse: collapse;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
|
|
64
65
|
tbody {
|
|
65
66
|
display: grid;
|
|
66
67
|
row-gap: 4px;
|
|
@@ -99,7 +100,6 @@ export const styles = css `
|
|
|
99
100
|
flex: 1 0 auto;
|
|
100
101
|
padding: var(--space-scale-2) var(--space-scale-3) var(--space-scale-3);
|
|
101
102
|
|
|
102
|
-
|
|
103
103
|
button {
|
|
104
104
|
background-color: var(--color-surface-200);
|
|
105
105
|
border-color: var(--color-primary-400);
|
|
@@ -138,7 +138,7 @@ export const styles = css `
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
.day[aria-disabled=
|
|
141
|
+
.day[aria-disabled='true'] {
|
|
142
142
|
opacity: 0.7;
|
|
143
143
|
background-color: var(--color-surface-300);
|
|
144
144
|
cursor: not-allowed;
|
|
@@ -146,7 +146,7 @@ export const styles = css `
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
.day.start-date:has(+ .in-range):after {
|
|
149
|
-
content:
|
|
149
|
+
content: ' ';
|
|
150
150
|
position: absolute;
|
|
151
151
|
top: 0;
|
|
152
152
|
left: 0;
|
|
@@ -160,7 +160,7 @@ export const styles = css `
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
.day.in-range + :is(.day:hover, .day:not(.in-range)):before {
|
|
163
|
-
content:
|
|
163
|
+
content: ' ';
|
|
164
164
|
position: absolute;
|
|
165
165
|
top: 0;
|
|
166
166
|
left: 0;
|
|
@@ -182,7 +182,7 @@ export const styles = css `
|
|
|
182
182
|
|
|
183
183
|
&.in-range {
|
|
184
184
|
&:before {
|
|
185
|
-
content:
|
|
185
|
+
content: ' ';
|
|
186
186
|
position: absolute;
|
|
187
187
|
top: 0;
|
|
188
188
|
left: 0;
|
|
@@ -227,7 +227,6 @@ export const styles = css `
|
|
|
227
227
|
box-shadow: none;
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
|
|
231
230
|
&[aria-selected='true'] {
|
|
232
231
|
color: var(--color-primary-400);
|
|
233
232
|
}
|
|
@@ -248,7 +247,7 @@ export const styles = css `
|
|
|
248
247
|
gap: var(--space-scale-1);
|
|
249
248
|
|
|
250
249
|
&::marker {
|
|
251
|
-
content:
|
|
250
|
+
content: '';
|
|
252
251
|
}
|
|
253
252
|
|
|
254
253
|
svg.chevron-down {
|
package/dist/src/Styles.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Styles.js","sourceRoot":"","sources":["../../src/Styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"Styles.js","sourceRoot":"","sources":["../../src/Styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqQxB,CAAC","sourcesContent":["import { css } from 'lit';\n\nexport const styles = css`\n :host {\n display: block;\n }\n\n button {\n appearance: none;\n padding: 0;\n border-width: 0;\n background-color: transparent;\n border-radius: var(--space-scale-1);\n padding-block: var(--space-scale-1);\n padding-inline: var(--space-scale-2);\n\n &.compact {\n padding-block: 0;\n padding-inline: 0;\n }\n\n &:hover {\n cursor: pointer;\n box-shadow:\n 0px 2px 5px 0px rgba(60, 66, 87, 0.08),\n 0px 1px 1px 0px rgba(0, 0, 0, 0.12);\n }\n\n &:focus {\n outline: 1px solid var(--color-primary-400);\n }\n\n svg {\n display: block;\n }\n\n &.right svg {\n transform: rotate(180deg);\n }\n }\n\n h2 {\n font-weight: var(--font-weight-semibold);\n color: var(--color-text-500);\n font-size: var(--font-size-400);\n display: contents;\n }\n\n .calendar-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 24px 24px 16px 24px;\n }\n\n .calendar-grid {\n text-align: center;\n border-top: var(--color-border-200) 1px solid;\n padding: 0 24px;\n\n table {\n width: 100%;\n border-collapse: collapse;\n }\n\n tbody {\n display: grid;\n row-gap: 4px;\n }\n\n tr {\n display: grid;\n grid-template-columns: repeat(7, 48px);\n }\n\n th {\n color: var(--color-text-400);\n font-size: var(--font-size-100);\n font-weight: var(--font-weight-normal);\n line-height: 20px;\n padding: 16px 0;\n }\n\n td {\n font-size: var(--font-size-100);\n font-weight: var(--font-weight-normal);\n }\n }\n\n .calendar-footer {\n display: flex;\n flex-direction: column;\n //gap: var(--space-scale-2);\n\n svg {\n vertical-align: middle;\n }\n\n .actions {\n display: flex;\n flex: 1 0 auto;\n padding: var(--space-scale-2) var(--space-scale-3) var(--space-scale-3);\n\n button {\n background-color: var(--color-surface-200);\n border-color: var(--color-primary-400);\n border-width: 1px;\n border-style: solid;\n color: var(--color-primary-400);\n font-weight: var(--font-weight-semibold);\n width: 100%;\n height: 40px;\n }\n }\n }\n\n .day {\n aspect-ratio: 1;\n cursor: pointer;\n position: relative; // For focus outline\n box-sizing: border-box;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .day.in-range {\n background: var(--color-primary-300);\n\n &:first-child {\n border-top-left-radius: var(--space-scale-1);\n border-bottom-left-radius: var(--space-scale-1);\n }\n\n &:last-child {\n border-top-right-radius: var(--space-scale-1);\n border-bottom-right-radius: var(--space-scale-1);\n }\n }\n\n .day[aria-disabled='true'] {\n opacity: 0.7;\n background-color: var(--color-surface-300);\n cursor: not-allowed;\n pointer-events: none;\n }\n\n .day.start-date:has(+ .in-range):after {\n content: ' ';\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: var(--color-primary-300);\n z-index: -1;\n border-radius: var(--space-scale-1);\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n }\n\n .day.in-range + :is(.day:hover, .day:not(.in-range)):before {\n content: ' ';\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: var(--color-primary-300);\n z-index: -1;\n border-radius: var(--space-scale-1);\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n }\n\n .day[aria-selected='true']:not(.in-range),\n .day:hover {\n background: var(--color-primary-400);\n color: var(--color-text-100);\n border-radius: var(--space-scale-1);\n font-weight: var(--font-weight-semibold);\n\n &.in-range {\n &:before {\n content: ' ';\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: var(--color-primary-300);\n z-index: -1;\n border-radius: var(--bg-border-radius, 0);\n }\n\n &:first-child {\n --bg-border-radius: var(--space-scale-1) 0 0 var(--space-scale-1);\n }\n\n &:last-child {\n --bg-border-radius: 0 var(--space-scale-1) var(--space-scale-1) 0;\n }\n }\n }\n\n .side-panel-wrapper {\n border-right: 1px solid var(--color-border-200, var(--color-surface-300));\n display: flex;\n align-items: start;\n }\n\n .side-panel {\n padding: var(--space-scale-3);\n grid-template-columns: 1fr;\n display: grid;\n gap: var(--space-scale-3);\n\n button {\n font-size: var(--font-size-200);\n text-wrap: nowrap;\n line-height: var(--space-scale-3);\n padding-block: 0;\n padding-inline: 0;\n\n &:hover {\n color: var(--color-primary-400);\n box-shadow: none;\n }\n\n &[aria-selected='true'] {\n color: var(--color-primary-400);\n }\n }\n }\n\n details {\n border-top: 1px solid var(--color-border-200);\n font-size: var(--font-size-100);\n font-weight: var(--font-weight-normal);\n padding: var(--space-scale-2) var(--space-scale-3) var(--space-scale-3);\n\n summary {\n font-weight: var(--font-weight-semibold);\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--space-scale-1);\n\n &::marker {\n content: '';\n }\n\n svg.chevron-down {\n margin-left: var(--space-scale-1);\n transform: rotate(-90deg);\n }\n }\n\n &[open] svg.chevron-down {\n transform: rotate(0deg);\n }\n }\n`;\n"]}
|
package/dist/src/TtCalendar.js
CHANGED
|
@@ -35,8 +35,12 @@ export class Calendar extends LitElement {
|
|
|
35
35
|
}
|
|
36
36
|
get internalRangeValue() {
|
|
37
37
|
if (this.range && this.value) {
|
|
38
|
-
const startDate = this.value?.startDate
|
|
39
|
-
|
|
38
|
+
const startDate = this.value?.startDate
|
|
39
|
+
? DateTime.fromISO(this.value.startDate)
|
|
40
|
+
: undefined;
|
|
41
|
+
const endDate = this.value?.endDate
|
|
42
|
+
? DateTime.fromISO(this.value.endDate)
|
|
43
|
+
: undefined;
|
|
40
44
|
return { startDate, endDate };
|
|
41
45
|
}
|
|
42
46
|
return { startDate: undefined, endDate: undefined };
|
|
@@ -55,7 +59,7 @@ export class Calendar extends LitElement {
|
|
|
55
59
|
this.focusedDate = parsedDate.isValid ? parsedDate : this.today;
|
|
56
60
|
}
|
|
57
61
|
else {
|
|
58
|
-
this.focusedDate =
|
|
62
|
+
this.focusedDate = this.internalRangeValue?.startDate || this.today;
|
|
59
63
|
}
|
|
60
64
|
});
|
|
61
65
|
}
|
|
@@ -71,7 +75,7 @@ export class Calendar extends LitElement {
|
|
|
71
75
|
this.calendarDiv.focus();
|
|
72
76
|
this.calendarDiv.scrollIntoView({
|
|
73
77
|
behavior: 'smooth',
|
|
74
|
-
block: 'nearest'
|
|
78
|
+
block: 'nearest',
|
|
75
79
|
});
|
|
76
80
|
});
|
|
77
81
|
if (!this.range) {
|
|
@@ -80,7 +84,9 @@ export class Calendar extends LitElement {
|
|
|
80
84
|
this.focusedDate = parsedDate.isValid ? parsedDate : this.today;
|
|
81
85
|
}
|
|
82
86
|
else {
|
|
83
|
-
this.focusedDate = this.value?.startDate
|
|
87
|
+
this.focusedDate = this.value?.startDate
|
|
88
|
+
? DateTime.fromISO(this.value.startDate)
|
|
89
|
+
: this.today;
|
|
84
90
|
}
|
|
85
91
|
}
|
|
86
92
|
}
|
|
@@ -252,7 +258,7 @@ export class Calendar extends LitElement {
|
|
|
252
258
|
if (details.open) {
|
|
253
259
|
details.scrollIntoView({
|
|
254
260
|
behavior: 'smooth',
|
|
255
|
-
block: 'nearest'
|
|
261
|
+
block: 'nearest',
|
|
256
262
|
});
|
|
257
263
|
}
|
|
258
264
|
}
|
|
@@ -260,13 +266,17 @@ export class Calendar extends LitElement {
|
|
|
260
266
|
const weeks = this.getDaysInMonth(this.focusedDate);
|
|
261
267
|
const monthYear = this.focusedDate.toLocaleString({
|
|
262
268
|
month: 'long',
|
|
263
|
-
year: 'numeric'
|
|
269
|
+
year: 'numeric',
|
|
264
270
|
});
|
|
265
271
|
return html `
|
|
266
272
|
<div class="calendar-panel" @keydown=${this.handleKeyDown} role="application" aria-label="${monthYear}">
|
|
267
273
|
<div class="calendar-header">
|
|
268
|
-
<button
|
|
269
|
-
|
|
274
|
+
<button
|
|
275
|
+
@click=${this.previousYear}
|
|
276
|
+
@keydown=${this.handleButtonKeyDown}
|
|
277
|
+
aria-label="Previous year"
|
|
278
|
+
class="compact"
|
|
279
|
+
>
|
|
270
280
|
${unsafeSVG(doubleChevron)}
|
|
271
281
|
</button>
|
|
272
282
|
<button
|
|
@@ -285,66 +295,69 @@ export class Calendar extends LitElement {
|
|
|
285
295
|
class="compact right"
|
|
286
296
|
>
|
|
287
297
|
${unsafeSVG(chevron)}
|
|
288
|
-
|
|
289
298
|
</button>
|
|
290
|
-
<button
|
|
291
|
-
|
|
299
|
+
<button
|
|
300
|
+
@click=${this.nextYear}
|
|
301
|
+
@keydown=${this.handleButtonKeyDown}
|
|
302
|
+
aria-label="Next year"
|
|
303
|
+
class="compact right"
|
|
304
|
+
>
|
|
292
305
|
${unsafeSVG(doubleChevron)}
|
|
293
306
|
</button>
|
|
294
307
|
</div>
|
|
295
308
|
<div class="calendar-grid">
|
|
296
|
-
<table
|
|
297
|
-
|
|
309
|
+
<table
|
|
310
|
+
role="grid"
|
|
311
|
+
aria-labelledby="month-year"
|
|
312
|
+
data-range="${this.range}"
|
|
313
|
+
class="${this.isSelectingRange ? 'selecting' : ''}"
|
|
314
|
+
>
|
|
298
315
|
<thead>
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
</tr>
|
|
316
|
+
<tr>
|
|
317
|
+
${this.getWeekdayLabels().map((label) => html ` <th>${label}</th>`)}
|
|
318
|
+
</tr>
|
|
303
319
|
</thead>
|
|
304
320
|
|
|
305
321
|
<tbody>
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
${week.map(day => {
|
|
322
|
+
${weeks.map((week) => html ` <tr>
|
|
323
|
+
${week.map((day) => {
|
|
309
324
|
if (!day) {
|
|
310
|
-
return html `
|
|
311
|
-
<td></td>`;
|
|
325
|
+
return html ` <td></td>`;
|
|
312
326
|
}
|
|
313
327
|
const isDisabled = this.dayIsDisabled(day);
|
|
314
|
-
return html `
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
'day': true,
|
|
328
|
+
return html ` <td
|
|
329
|
+
class="${classMap({
|
|
330
|
+
day: true,
|
|
318
331
|
'in-range': this.isInRange(day),
|
|
319
332
|
'start-date': this.isStartDate(day),
|
|
320
|
-
'end-date': this.isEndDate(day)
|
|
333
|
+
'end-date': this.isEndDate(day),
|
|
321
334
|
})}"
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
335
|
+
@click=${() => this.handleDayClick(day)}
|
|
336
|
+
role="gridcell"
|
|
337
|
+
data-date="${day.toISODate()}"
|
|
338
|
+
aria-label="${day.toLocaleString({ dateStyle: 'long' })}"
|
|
339
|
+
aria-selected="${this.isSelected(day)}"
|
|
340
|
+
aria-disabled="${isDisabled}"
|
|
341
|
+
tabindex="-1"
|
|
342
|
+
@mouseenter="${this.onDayHover}"
|
|
343
|
+
>
|
|
344
|
+
${day.day}
|
|
345
|
+
</td>`;
|
|
333
346
|
})}
|
|
334
|
-
|
|
347
|
+
</tr>`)}
|
|
335
348
|
</tbody>
|
|
336
349
|
</table>
|
|
337
350
|
</div>
|
|
338
351
|
|
|
339
352
|
<div class="calendar-footer">
|
|
340
353
|
<div class="actions" @keydown="${this.handleButtonKeyDown}">
|
|
341
|
-
${this.isRange()
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
`}
|
|
354
|
+
${this.isRange()
|
|
355
|
+
? html `
|
|
356
|
+
<button @click=${() => this.handleClearSelection()} data-theme="secondary" id="clear-selection">
|
|
357
|
+
Clear selection
|
|
358
|
+
</button>
|
|
359
|
+
`
|
|
360
|
+
: html ` <button @click=${() => this.handleDayClick(this.today)} data-theme="secondary">Today</button> `}
|
|
348
361
|
</div>
|
|
349
362
|
<div>
|
|
350
363
|
<details @keydown=${this.handleButtonKeyDown} @toggle=${this.handleToggle}>
|
|
@@ -370,10 +383,10 @@ export class Calendar extends LitElement {
|
|
|
370
383
|
return true;
|
|
371
384
|
if (this.minDate && day < this.minDate)
|
|
372
385
|
return true;
|
|
373
|
-
if (this.range && this.isSelectingRange) {
|
|
374
|
-
if (day < this.internalRangeValue
|
|
386
|
+
if (this.range && this.isSelectingRange && this.internalRangeValue?.startDate) {
|
|
387
|
+
if (day < this.internalRangeValue.startDate)
|
|
375
388
|
return true;
|
|
376
|
-
if (this.maxDays && day > this.internalRangeValue
|
|
389
|
+
if (this.maxDays && day > this.internalRangeValue.startDate.plus({ days: this.maxDays }))
|
|
377
390
|
return true;
|
|
378
391
|
}
|
|
379
392
|
return false;
|
|
@@ -382,7 +395,7 @@ export class Calendar extends LitElement {
|
|
|
382
395
|
Calendar.styles = styles;
|
|
383
396
|
Calendar.shadowRootOptions = {
|
|
384
397
|
...LitElement.shadowRootOptions,
|
|
385
|
-
delegatesFocus: true
|
|
398
|
+
delegatesFocus: true,
|
|
386
399
|
};
|
|
387
400
|
__decorate([
|
|
388
401
|
property({ type: String })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TtCalendar.js","sourceRoot":"","sources":["../../src/TtCalendar.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, LitElement, PropertyValues } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js';\nimport { DateTime, Interval } from 'luxon';\nimport { DateRange, DateRangeSelectionEvent, DateSelectionEvent } from './DateSelectionContext.js';\nimport { chevron, chevronDown, doubleChevron, keyboard } from '@triptease/icons';\nimport { styles } from './Styles.js';\nimport { dateConverter, dateTimeConverter } from './helpers.js';\n\ntype WeekdayList = [\n DateTime | null,\n DateTime | null,\n DateTime | null,\n DateTime | null,\n DateTime | null,\n DateTime | null,\n DateTime | null,\n];\n\ninterface CalendarWithRange {\n value?: DateRange;\n range: true;\n}\n\ninterface InternalDateRange {\n startDate?: DateTime;\n endDate?: DateTime;\n}\n\nexport class Calendar extends LitElement {\n static styles = styles;\n\n static shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true\n };\n\n\n // Start public properties\n\n @property({ type: String })\n public value?: string | DateRange;\n\n @property({ type: Boolean })\n public range = false;\n\n @property({ attribute: 'max-date', converter: dateTimeConverter })\n public maxDate?: DateTime;\n\n @property({ type: Number, attribute: 'max-days' })\n public maxDays?: number;\n\n @property({ attribute: 'min-date', converter: dateTimeConverter })\n public minDate?: DateTime;\n\n @property({ type: Number, attribute: 'min-days' })\n public minDays?: number;\n\n get internalRangeValue(): InternalDateRange {\n if (this.range && this.value) {\n const startDate = (this.value as DateRange)?.startDate ? DateTime.fromISO((this.value as DateRange).startDate!) : undefined;\n const endDate = (this.value as DateRange)?.endDate ? DateTime.fromISO((this.value as DateRange).endDate!) : undefined;\n return { startDate, endDate };\n }\n return { startDate: undefined, endDate: undefined };\n }\n\n getRange(): Interval {\n if (this.range && this.internalRangeValue.startDate && this.internalRangeValue.endDate) {\n return Interval.fromDateTimes(this.internalRangeValue.startDate, this.internalRangeValue.endDate.plus({ days: 1 }));\n }\n return Interval.invalid('Invalid range');\n }\n\n public updated(changedProperties: PropertyValues) {\n if (changedProperties.has('value') && this.value) {\n super.updateComplete.then(() => {\n if (!this.range) {\n const parsedDate = DateTime.fromISO(this.value as string);\n this.focusedDate = parsedDate.isValid ? parsedDate : this.today;\n } else {\n this.focusedDate = (this.internalRangeValue?.startDate || this.today);\n }\n });\n }\n super.updated(changedProperties);\n }\n\n public toggleVisibility() {\n if (this.visible) {\n this.visible = false;\n } else {\n this.visible = true;\n this.updateComplete.then(() => {\n this.calendarDiv.focus();\n this.calendarDiv.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest'\n });\n });\n if (!this.range) {\n console.log('received value' ,this.value)\n\n const parsedDate = DateTime.fromISO(this.value as string ?? this.today);\n this.focusedDate = parsedDate.isValid ? parsedDate : this.today;\n } else {\n this.focusedDate = (this.value as DateRange)?.startDate ? DateTime.fromISO((this.value as DateRange).startDate!) : this.today;\n }\n }\n }\n\n // end public properties\n\n @query('.calendar-panel')\n private calendarDiv!: HTMLElement;\n\n @state()\n private focusedDate: DateTime = this.today;\n\n @state()\n private visible: Boolean = false;\n\n private handleKeyDown(event: KeyboardEvent) {\n const currentDate = this.focusedDate;\n switch (event.key) {\n case 'ArrowLeft':\n event.preventDefault();\n this.focusDay(currentDate.minus({ day: 1 }));\n break;\n case 'ArrowRight':\n event.preventDefault();\n this.focusDay(currentDate.plus({ day: 1 }));\n break;\n case 'ArrowUp':\n event.preventDefault();\n this.focusDay(currentDate.minus({ week: 1 }));\n break;\n case 'ArrowDown':\n event.preventDefault();\n this.focusDay(currentDate.plus({ week: 1 }));\n break;\n case 'Home':\n event.preventDefault();\n // Move to first day of week\n this.focusDay(currentDate.startOf('week'));\n break;\n case 'End':\n event.preventDefault();\n // Move to last day of week\n this.focusDay(currentDate.endOf('week'));\n break;\n case 'PageUp':\n event.preventDefault();\n if (event.shiftKey) {\n // Previous year\n this.focusDay(currentDate.minus({ year: 1 }));\n } else {\n // Previous month\n this.focusDay(currentDate.minus({ month: 1 }));\n }\n break;\n case 'PageDown':\n event.preventDefault();\n if (event.shiftKey) {\n // Next year\n this.focusDay(currentDate.plus({ year: 1 }));\n } else {\n // Next month\n this.focusDay(currentDate.plus({ month: 1 }));\n }\n break;\n case 'Enter':\n case ' ':\n event.preventDefault();\n this.handleDayClick(this.focusedDate);\n return;\n\n default:\n return;\n }\n\n event.preventDefault();\n }\n\n private focusDay(date: DateTime) {\n this.focusedDate = date;\n this.updateComplete.then(() => {\n const dayElement = <HTMLElement | undefined>this.shadowRoot?.querySelector(\n `.day[data-date=\"${date.toISO()}\"]`\n );\n if (dayElement) {\n dayElement.focus();\n }\n });\n }\n\n private newWeek = () => new Array(7).fill(null) as WeekdayList;\n\n private getDaysInMonth(date: DateTime): WeekdayList[] {\n\n const startOfMonth = date.startOf('month');\n const endOfMonth = date.endOf('month');\n\n const weeks: WeekdayList[] = [];\n let currentWeek: WeekdayList = this.newWeek();\n\n let currentDay = startOfMonth;\n\n while (currentDay <= endOfMonth) {\n // Get the day of week (0-6, Sunday=0, Saturday=6)\n const dayOfWeek = currentDay.weekday === 7 ? 0 : currentDay.weekday;\n\n currentWeek[dayOfWeek] = currentDay;\n\n const isWeekComplete = dayOfWeek === 6; // Saturday (last day of week)\n const isLastDayOfMonth = currentDay.hasSame(endOfMonth, 'day');\n\n if (isWeekComplete || isLastDayOfMonth) {\n weeks.push(currentWeek);\n\n if (!isLastDayOfMonth) {\n currentWeek = this.newWeek();\n }\n }\n\n currentDay = currentDay.plus({ days: 1 });\n }\n\n return weeks;\n }\n\n private previousYear() {\n this.focusedDate = this.focusedDate.minus({ year: 1 });\n }\n\n private previousMonth() {\n this.focusedDate = this.focusedDate.minus({ month: 1 });\n }\n\n private nextMonth() {\n this.focusedDate = this.focusedDate.plus({ month: 1 });\n }\n\n private nextYear() {\n this.focusedDate = this.focusedDate.plus({ year: 1 });\n }\n\n private get today(): DateTime {\n return DateTime.local();\n }\n\n private handleDayClick(day: DateTime) {\n if (this.isRange()) {\n if (!this.value?.startDate || this.value?.endDate) {\n this.value = { startDate: day.toISODate()! };\n this.focusedDate = day;\n return;\n }\n\n if (!this.value.endDate) {\n this.value = { ...this.value as DateRange, endDate: day.toISODate()! };\n this.focusedDate = day;\n this.dispatchEvent(new DateRangeSelectionEvent(this.value));\n return;\n }\n }\n\n if (day.isValid) {\n this.dispatchEvent(new DateSelectionEvent(day.toISODate()!));\n }\n\n }\n\n private handleButtonKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.stopPropagation();\n }\n };\n\n private getWeekdayLabels(): string[] {\n const monday = DateTime.fromISO('2024-06-02T00:00:00Z').startOf('week'); //Weeks start on Monday in Luxon https://moment.github.io/luxon/api-docs/index.html#datetimestartof\n const sunday = monday.plus({ days: 6 });\n return Array.from({ length: 7 }, (_, i) => {\n const date = sunday.plus({ days: i });\n return date.toLocaleString({ weekday: 'short' });\n });\n }\n\n private isSelected(date: DateTime): boolean {\n if (date.equals(this.focusedDate)) return true;\n\n if (this.isRange() && this.internalRangeValue.startDate) {\n if (!this.internalRangeValue.endDate) {\n const range = Interval.fromDateTimes(this.internalRangeValue.startDate, this.focusedDate.plus({ days: 1 }));\n return range.contains(date);\n }\n\n const range = this.getRange();\n return range.contains(date);\n }\n\n return false;\n }\n\n private isInRange(date: DateTime): boolean {\n if (!this.isRange() || !this.internalRangeValue?.startDate) {\n return false;\n }\n\n if (!this.internalRangeValue?.endDate) {\n const range = Interval.fromDateTimes(this.internalRangeValue.startDate, this.focusedDate);\n return range.contains(date) && !this.isStartDate(date) && !date.equals(this.focusedDate);\n }\n\n const range = this.getRange();\n return range.contains(date) && !this.isStartDate(date) && !this.isEndDate(date);\n }\n\n private isRange(): this is CalendarWithRange {\n return this.range;\n }\n\n private get isSelectingRange(): boolean {\n return Boolean(this.isRange() && this.value?.startDate && !this.value?.endDate);\n }\n\n private onDayHover = (event: MouseEvent) => {\n const day = (event.target as HTMLElement).dataset.date;\n if (!day) return;\n\n this.focusedDate = DateTime.fromISO(day);\n };\n\n private isStartDate = (date: DateTime): boolean => Boolean(this.isRange() && this.internalRangeValue?.startDate && this.internalRangeValue.startDate.equals(date));\n\n private isEndDate = (date: DateTime): boolean => Boolean(this.isRange() && this.internalRangeValue?.endDate && this.internalRangeValue.endDate.equals(date));\n\n private handleClearSelection = () => {\n this.value = { startDate: undefined, endDate: undefined };\n this.dispatchEvent(new DateRangeSelectionEvent({ startDate: undefined, endDate: undefined }));\n };\n\n private handleToggle(e: Event) {\n const details = e.target as HTMLDetailsElement;\n if (details.open) {\n details.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest'\n });\n }\n }\n\n render() {\n const weeks = this.getDaysInMonth(this.focusedDate);\n const monthYear = this.focusedDate.toLocaleString({\n month: 'long',\n year: 'numeric'\n });\n\n return html`\n <div class=\"calendar-panel\" @keydown=${this.handleKeyDown} role=\"application\" aria-label=\"${monthYear}\">\n <div class=\"calendar-header\">\n <button @click=${this.previousYear} @keydown=${this.handleButtonKeyDown} aria-label=\"Previous year\"\n class=\"compact\">\n ${unsafeSVG(doubleChevron)}\n </button>\n <button\n @click=${this.previousMonth}\n @keydown=\"${this.handleButtonKeyDown}\"\n aria-label=\"Previous month\"\n class=\"compact\"\n >\n ${unsafeSVG(chevron)}\n </button>\n <h2>${monthYear}</h2>\n <button\n @click=${this.nextMonth}\n @keydown=\"${this.handleButtonKeyDown}\"\n aria-label=\"Next month\"\n class=\"compact right\"\n >\n ${unsafeSVG(chevron)}\n\n </button>\n <button @click=${this.nextYear} @keydown=${this.handleButtonKeyDown} aria-label=\"Next year\"\n class=\"compact right\">\n ${unsafeSVG(doubleChevron)}\n </button>\n </div>\n <div class=\"calendar-grid\">\n <table role=\"grid\" aria-labelledby=\"month-year\" data-range=\"${this.range}\"\n class=\"${this.isSelectingRange ? 'selecting' : ''}\">\n <thead>\n <tr>\n ${this.getWeekdayLabels().map(\n label => html`\n <th>${label}</th>`\n )}\n </tr>\n </thead>\n\n <tbody>\n ${weeks.map(week => html`\n <tr>\n ${week.map(day => {\n if (!day) {\n return html`\n <td></td>`;\n }\n\n const isDisabled = this.dayIsDisabled(day);\n\n return html`\n <td\n class=\"${classMap({\n 'day': true,\n 'in-range': this.isInRange(day),\n 'start-date': this.isStartDate(day),\n 'end-date': this.isEndDate(day)\n })}\"\n @click=${() => this.handleDayClick(day)}\n role=\"gridcell\"\n data-date=\"${day.toISODate()}\"\n aria-label=\"${day.toLocaleString({ dateStyle: 'long' })}\"\n aria-selected=\"${this.isSelected(day)}\"\n aria-disabled=\"${isDisabled}\"\n tabindex=\"-1\"\n @mouseenter=\"${this.onDayHover}\"\n >\n ${day.day}\n </td>`;\n })}\n </tr>`)}\n </tbody>\n </table>\n </div>\n\n <div class=\"calendar-footer\">\n <div class=\"actions\" @keydown=\"${this.handleButtonKeyDown}\">\n ${this.isRange() ? html`\n <button @click=${() => this.handleClearSelection()} data-theme=\"secondary\" id=\"clear-selection\">Clear\n selection\n </button>\n ` : html`\n <button @click=${() => this.handleDayClick(this.today)} data-theme=\"secondary\">Today</button>\n `}\n </div>\n <div>\n <details @keydown=${this.handleButtonKeyDown} @toggle=${this.handleToggle}>\n <summary>${unsafeSVG(keyboard)} Keyboard commands ${unsafeSVG(chevronDown)}</summary>\n <p>Arrow keys: navigate the calendar</p>\n <p>Enter or Space: select the date</p>\n <p>Escape: close the calendar without selecting a date</p>\n <p>Tab: navigate between the calendar and the presets</p>\n <p>Home: move to first day of week</p>\n <p>End: move to last day of week</p>\n <p>Page Up: move to previous month</p>\n <p>Page Down: move to next month</p>\n <p>Shift + Page Up: move to next year</p>\n <p>Shift + Page Down: move to previous year</p>\n </details>\n </div>\n </div>\n </div>\n `;\n }\n\n private dayIsDisabled(day: DateTime) {\n if (this.maxDate && day > this.maxDate) return true;\n\n if (this.minDate && day < this.minDate) return true;\n\n if (this.range && this.isSelectingRange) {\n if (day < this.internalRangeValue?.startDate!) return true;\n\n if (this.maxDays && day > this.internalRangeValue?.startDate!.plus({ days: this.maxDays })) return true;\n }\n\n return false;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'tt-calendar': Calendar;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"TtCalendar.js","sourceRoot":"","sources":["../../src/TtCalendar.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, LitElement, PropertyValues } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js';\nimport { DateTime, Interval } from 'luxon';\nimport { DateRange, DateRangeSelectionEvent, DateSelectionEvent } from './DateSelectionContext.js';\nimport { chevron, chevronDown, doubleChevron, keyboard } from '@triptease/icons';\nimport { styles } from './Styles.js';\nimport { dateTimeConverter } from './helpers.js';\n\ntype WeekdayList = [\n DateTime | null,\n DateTime | null,\n DateTime | null,\n DateTime | null,\n DateTime | null,\n DateTime | null,\n DateTime | null,\n];\n\ninterface CalendarWithRange {\n value?: DateRange;\n range: true;\n}\n\ninterface InternalDateRange {\n startDate?: DateTime;\n endDate?: DateTime;\n}\n\nexport class Calendar extends LitElement {\n static styles = styles;\n\n static shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n // Start public properties\n\n @property({ type: String })\n public value?: string | DateRange;\n\n @property({ type: Boolean })\n public range = false;\n\n @property({ attribute: 'max-date', converter: dateTimeConverter })\n public maxDate?: DateTime;\n\n @property({ type: Number, attribute: 'max-days' })\n public maxDays?: number;\n\n @property({ attribute: 'min-date', converter: dateTimeConverter })\n public minDate?: DateTime;\n\n @property({ type: Number, attribute: 'min-days' })\n public minDays?: number;\n\n get internalRangeValue(): InternalDateRange {\n if (this.range && this.value) {\n const startDate = (this.value as DateRange)?.startDate\n ? DateTime.fromISO((this.value as DateRange).startDate!)\n : undefined;\n const endDate = (this.value as DateRange)?.endDate\n ? DateTime.fromISO((this.value as DateRange).endDate!)\n : undefined;\n return { startDate, endDate };\n }\n return { startDate: undefined, endDate: undefined };\n }\n\n getRange(): Interval {\n if (this.range && this.internalRangeValue.startDate && this.internalRangeValue.endDate) {\n return Interval.fromDateTimes(\n this.internalRangeValue.startDate,\n this.internalRangeValue.endDate.plus({ days: 1 })\n );\n }\n return Interval.invalid('Invalid range');\n }\n\n public updated(changedProperties: PropertyValues) {\n if (changedProperties.has('value') && this.value) {\n super.updateComplete.then(() => {\n if (!this.range) {\n const parsedDate = DateTime.fromISO(this.value as string);\n this.focusedDate = parsedDate.isValid ? parsedDate : this.today;\n } else {\n this.focusedDate = this.internalRangeValue?.startDate || this.today;\n }\n });\n }\n super.updated(changedProperties);\n }\n\n public toggleVisibility() {\n if (this.visible) {\n this.visible = false;\n } else {\n this.visible = true;\n this.updateComplete.then(() => {\n this.calendarDiv.focus();\n this.calendarDiv.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n });\n });\n if (!this.range) {\n console.log('received value', this.value);\n\n const parsedDate = DateTime.fromISO((this.value as string) ?? this.today);\n this.focusedDate = parsedDate.isValid ? parsedDate : this.today;\n } else {\n this.focusedDate = (this.value as DateRange)?.startDate\n ? DateTime.fromISO((this.value as DateRange).startDate!)\n : this.today;\n }\n }\n }\n\n // end public properties\n\n @query('.calendar-panel')\n private calendarDiv!: HTMLElement;\n\n @state()\n private focusedDate: DateTime = this.today;\n\n @state()\n private visible: boolean = false;\n\n private handleKeyDown(event: KeyboardEvent) {\n const currentDate = this.focusedDate;\n switch (event.key) {\n case 'ArrowLeft':\n event.preventDefault();\n this.focusDay(currentDate.minus({ day: 1 }));\n break;\n case 'ArrowRight':\n event.preventDefault();\n this.focusDay(currentDate.plus({ day: 1 }));\n break;\n case 'ArrowUp':\n event.preventDefault();\n this.focusDay(currentDate.minus({ week: 1 }));\n break;\n case 'ArrowDown':\n event.preventDefault();\n this.focusDay(currentDate.plus({ week: 1 }));\n break;\n case 'Home':\n event.preventDefault();\n // Move to first day of week\n this.focusDay(currentDate.startOf('week'));\n break;\n case 'End':\n event.preventDefault();\n // Move to last day of week\n this.focusDay(currentDate.endOf('week'));\n break;\n case 'PageUp':\n event.preventDefault();\n if (event.shiftKey) {\n // Previous year\n this.focusDay(currentDate.minus({ year: 1 }));\n } else {\n // Previous month\n this.focusDay(currentDate.minus({ month: 1 }));\n }\n break;\n case 'PageDown':\n event.preventDefault();\n if (event.shiftKey) {\n // Next year\n this.focusDay(currentDate.plus({ year: 1 }));\n } else {\n // Next month\n this.focusDay(currentDate.plus({ month: 1 }));\n }\n break;\n case 'Enter':\n case ' ':\n event.preventDefault();\n this.handleDayClick(this.focusedDate);\n return;\n\n default:\n return;\n }\n\n event.preventDefault();\n }\n\n private focusDay(date: DateTime) {\n this.focusedDate = date;\n this.updateComplete.then(() => {\n const dayElement = <HTMLElement | undefined>this.shadowRoot?.querySelector(`.day[data-date=\"${date.toISO()}\"]`);\n if (dayElement) {\n dayElement.focus();\n }\n });\n }\n\n private newWeek = () => new Array(7).fill(null) as WeekdayList;\n\n private getDaysInMonth(date: DateTime): WeekdayList[] {\n const startOfMonth = date.startOf('month');\n const endOfMonth = date.endOf('month');\n\n const weeks: WeekdayList[] = [];\n let currentWeek: WeekdayList = this.newWeek();\n\n let currentDay = startOfMonth;\n\n while (currentDay <= endOfMonth) {\n // Get the day of week (0-6, Sunday=0, Saturday=6)\n const dayOfWeek = currentDay.weekday === 7 ? 0 : currentDay.weekday;\n\n currentWeek[dayOfWeek] = currentDay;\n\n const isWeekComplete = dayOfWeek === 6; // Saturday (last day of week)\n const isLastDayOfMonth = currentDay.hasSame(endOfMonth, 'day');\n\n if (isWeekComplete || isLastDayOfMonth) {\n weeks.push(currentWeek);\n\n if (!isLastDayOfMonth) {\n currentWeek = this.newWeek();\n }\n }\n\n currentDay = currentDay.plus({ days: 1 });\n }\n\n return weeks;\n }\n\n private previousYear() {\n this.focusedDate = this.focusedDate.minus({ year: 1 });\n }\n\n private previousMonth() {\n this.focusedDate = this.focusedDate.minus({ month: 1 });\n }\n\n private nextMonth() {\n this.focusedDate = this.focusedDate.plus({ month: 1 });\n }\n\n private nextYear() {\n this.focusedDate = this.focusedDate.plus({ year: 1 });\n }\n\n private get today(): DateTime {\n return DateTime.local();\n }\n\n private handleDayClick(day: DateTime) {\n if (this.isRange()) {\n if (!this.value?.startDate || this.value?.endDate) {\n this.value = { startDate: day.toISODate()! };\n this.focusedDate = day;\n return;\n }\n\n if (!this.value.endDate) {\n this.value = { ...(this.value as DateRange), endDate: day.toISODate()! };\n this.focusedDate = day;\n this.dispatchEvent(new DateRangeSelectionEvent(this.value));\n return;\n }\n }\n\n if (day.isValid) {\n this.dispatchEvent(new DateSelectionEvent(day.toISODate()!));\n }\n }\n\n private handleButtonKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.stopPropagation();\n }\n };\n\n private getWeekdayLabels(): string[] {\n const monday = DateTime.fromISO('2024-06-02T00:00:00Z').startOf('week'); //Weeks start on Monday in Luxon https://moment.github.io/luxon/api-docs/index.html#datetimestartof\n const sunday = monday.plus({ days: 6 });\n return Array.from({ length: 7 }, (_, i) => {\n const date = sunday.plus({ days: i });\n return date.toLocaleString({ weekday: 'short' });\n });\n }\n\n private isSelected(date: DateTime): boolean {\n if (date.equals(this.focusedDate)) return true;\n\n if (this.isRange() && this.internalRangeValue.startDate) {\n if (!this.internalRangeValue.endDate) {\n const range = Interval.fromDateTimes(this.internalRangeValue.startDate, this.focusedDate.plus({ days: 1 }));\n return range.contains(date);\n }\n\n const range = this.getRange();\n return range.contains(date);\n }\n\n return false;\n }\n\n private isInRange(date: DateTime): boolean {\n if (!this.isRange() || !this.internalRangeValue?.startDate) {\n return false;\n }\n\n if (!this.internalRangeValue?.endDate) {\n const range = Interval.fromDateTimes(this.internalRangeValue.startDate, this.focusedDate);\n return range.contains(date) && !this.isStartDate(date) && !date.equals(this.focusedDate);\n }\n\n const range = this.getRange();\n return range.contains(date) && !this.isStartDate(date) && !this.isEndDate(date);\n }\n\n private isRange(): this is CalendarWithRange {\n return this.range;\n }\n\n private get isSelectingRange(): boolean {\n return Boolean(this.isRange() && this.value?.startDate && !this.value?.endDate);\n }\n\n private onDayHover = (event: MouseEvent) => {\n const day = (event.target as HTMLElement).dataset.date;\n if (!day) return;\n\n this.focusedDate = DateTime.fromISO(day);\n };\n\n private isStartDate = (date: DateTime): boolean =>\n Boolean(this.isRange() && this.internalRangeValue?.startDate && this.internalRangeValue.startDate.equals(date));\n\n private isEndDate = (date: DateTime): boolean =>\n Boolean(this.isRange() && this.internalRangeValue?.endDate && this.internalRangeValue.endDate.equals(date));\n\n private handleClearSelection = () => {\n this.value = { startDate: undefined, endDate: undefined };\n this.dispatchEvent(new DateRangeSelectionEvent({ startDate: undefined, endDate: undefined }));\n };\n\n private handleToggle(e: Event) {\n const details = e.target as HTMLDetailsElement;\n if (details.open) {\n details.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n });\n }\n }\n\n render() {\n const weeks = this.getDaysInMonth(this.focusedDate);\n const monthYear = this.focusedDate.toLocaleString({\n month: 'long',\n year: 'numeric',\n });\n\n return html`\n <div class=\"calendar-panel\" @keydown=${this.handleKeyDown} role=\"application\" aria-label=\"${monthYear}\">\n <div class=\"calendar-header\">\n <button\n @click=${this.previousYear}\n @keydown=${this.handleButtonKeyDown}\n aria-label=\"Previous year\"\n class=\"compact\"\n >\n ${unsafeSVG(doubleChevron)}\n </button>\n <button\n @click=${this.previousMonth}\n @keydown=\"${this.handleButtonKeyDown}\"\n aria-label=\"Previous month\"\n class=\"compact\"\n >\n ${unsafeSVG(chevron)}\n </button>\n <h2>${monthYear}</h2>\n <button\n @click=${this.nextMonth}\n @keydown=\"${this.handleButtonKeyDown}\"\n aria-label=\"Next month\"\n class=\"compact right\"\n >\n ${unsafeSVG(chevron)}\n </button>\n <button\n @click=${this.nextYear}\n @keydown=${this.handleButtonKeyDown}\n aria-label=\"Next year\"\n class=\"compact right\"\n >\n ${unsafeSVG(doubleChevron)}\n </button>\n </div>\n <div class=\"calendar-grid\">\n <table\n role=\"grid\"\n aria-labelledby=\"month-year\"\n data-range=\"${this.range}\"\n class=\"${this.isSelectingRange ? 'selecting' : ''}\"\n >\n <thead>\n <tr>\n ${this.getWeekdayLabels().map((label) => html` <th>${label}</th>`)}\n </tr>\n </thead>\n\n <tbody>\n ${weeks.map(\n (week) =>\n html` <tr>\n ${week.map((day) => {\n if (!day) {\n return html` <td></td>`;\n }\n\n const isDisabled = this.dayIsDisabled(day);\n\n return html` <td\n class=\"${classMap({\n day: true,\n 'in-range': this.isInRange(day),\n 'start-date': this.isStartDate(day),\n 'end-date': this.isEndDate(day),\n })}\"\n @click=${() => this.handleDayClick(day)}\n role=\"gridcell\"\n data-date=\"${day.toISODate()}\"\n aria-label=\"${day.toLocaleString({ dateStyle: 'long' })}\"\n aria-selected=\"${this.isSelected(day)}\"\n aria-disabled=\"${isDisabled}\"\n tabindex=\"-1\"\n @mouseenter=\"${this.onDayHover}\"\n >\n ${day.day}\n </td>`;\n })}\n </tr>`\n )}\n </tbody>\n </table>\n </div>\n\n <div class=\"calendar-footer\">\n <div class=\"actions\" @keydown=\"${this.handleButtonKeyDown}\">\n ${this.isRange()\n ? html`\n <button @click=${() => this.handleClearSelection()} data-theme=\"secondary\" id=\"clear-selection\">\n Clear selection\n </button>\n `\n : html` <button @click=${() => this.handleDayClick(this.today)} data-theme=\"secondary\">Today</button> `}\n </div>\n <div>\n <details @keydown=${this.handleButtonKeyDown} @toggle=${this.handleToggle}>\n <summary>${unsafeSVG(keyboard)} Keyboard commands ${unsafeSVG(chevronDown)}</summary>\n <p>Arrow keys: navigate the calendar</p>\n <p>Enter or Space: select the date</p>\n <p>Escape: close the calendar without selecting a date</p>\n <p>Tab: navigate between the calendar and the presets</p>\n <p>Home: move to first day of week</p>\n <p>End: move to last day of week</p>\n <p>Page Up: move to previous month</p>\n <p>Page Down: move to next month</p>\n <p>Shift + Page Up: move to next year</p>\n <p>Shift + Page Down: move to previous year</p>\n </details>\n </div>\n </div>\n </div>\n `;\n }\n\n private dayIsDisabled(day: DateTime) {\n if (this.maxDate && day > this.maxDate) return true;\n\n if (this.minDate && day < this.minDate) return true;\n\n if (this.range && this.isSelectingRange && this.internalRangeValue?.startDate) {\n if (day < this.internalRangeValue.startDate) return true;\n\n if (this.maxDays && day > this.internalRangeValue.startDate.plus({ days: this.maxDays })) return true;\n }\n\n return false;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'tt-calendar': Calendar;\n }\n}\n"]}
|
package/dist/src/helpers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjC,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAoB,EAAoB,EAAE,
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjC,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAoB,EAAoB,EAAE,CACtE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAEzD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAoB,EAAwB,EAAE,CAC9E,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC","sourcesContent":["import { DateTime } from 'luxon';\n\nexport const dateConverter = (value: string | null): Date | undefined =>\n value ? DateTime.fromISO(value).toJSDate() : undefined;\n\nexport const dateTimeConverter = (value: string | null): DateTime | undefined =>\n value ? DateTime.fromISO(value) : undefined;\n"]}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Webcomponent tt-calendar following open-wc recommendations",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "@triptease",
|
|
6
|
-
"version": "6.0.
|
|
6
|
+
"version": "6.0.4",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "dist/src/index.js",
|
|
9
9
|
"module": "dist/src/index.js",
|
|
@@ -18,16 +18,14 @@
|
|
|
18
18
|
"build": "yarn build:node && yarn build:web",
|
|
19
19
|
"build:web": "node ../../scripts/esbuild.mjs",
|
|
20
20
|
"build:node": "tsc && npm run analyze -- --exclude dist",
|
|
21
|
+
"build:node:watch": "tsc --watch",
|
|
21
22
|
"prepublish": "tsc && npm run analyze -- --exclude dist",
|
|
22
|
-
"lint": "eslint --ext .ts,.html . --ignore-path .gitignore && prettier \"**/*.ts\" --check --ignore-path .gitignore",
|
|
23
|
-
"format": "eslint --ext .ts,.html . --fix --ignore-path .gitignore && prettier \"**/*.ts\" --write --ignore-path .gitignore",
|
|
24
|
-
"prepare": "husky",
|
|
25
23
|
"test": "tsc && wtr",
|
|
26
24
|
"test:watch": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wtr --watch\""
|
|
27
25
|
},
|
|
28
26
|
"dependencies": {
|
|
29
27
|
"@lit/context": "^1.1.5",
|
|
30
|
-
"@triptease/icons": "
|
|
28
|
+
"@triptease/icons": "workspace:*",
|
|
31
29
|
"@types/luxon": "^3.6.2",
|
|
32
30
|
"lit": "^3.1.4",
|
|
33
31
|
"luxon": "^3.6.1"
|
|
@@ -42,47 +40,11 @@
|
|
|
42
40
|
"@web/dev-server": "^0.4.6",
|
|
43
41
|
"@web/test-runner": "^0.18.2",
|
|
44
42
|
"concurrently": "^8.2.2",
|
|
45
|
-
"eslint": "^8.57.0",
|
|
46
|
-
"eslint-config-prettier": "^9.1.0",
|
|
47
|
-
"husky": "^9.0.11",
|
|
48
|
-
"lint-staged": "^15.2.7",
|
|
49
|
-
"prettier": "^3.3.2",
|
|
50
43
|
"tslib": "^2.6.3",
|
|
51
44
|
"typescript": "^5.5.3"
|
|
52
45
|
},
|
|
53
46
|
"customElements": "custom-elements.json",
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"extends": [
|
|
57
|
-
"@open-wc",
|
|
58
|
-
"prettier"
|
|
59
|
-
],
|
|
60
|
-
"plugins": [
|
|
61
|
-
"@typescript-eslint"
|
|
62
|
-
],
|
|
63
|
-
"rules": {
|
|
64
|
-
"no-unused-vars": "off",
|
|
65
|
-
"@typescript-eslint/no-unused-vars": [
|
|
66
|
-
"error"
|
|
67
|
-
],
|
|
68
|
-
"import/no-unresolved": "off",
|
|
69
|
-
"import/extensions": [
|
|
70
|
-
"error",
|
|
71
|
-
"always",
|
|
72
|
-
{
|
|
73
|
-
"ignorePackages": true
|
|
74
|
-
}
|
|
75
|
-
]
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
"prettier": {
|
|
79
|
-
"singleQuote": true,
|
|
80
|
-
"arrowParens": "avoid"
|
|
81
|
-
},
|
|
82
|
-
"lint-staged": {
|
|
83
|
-
"*.ts": [
|
|
84
|
-
"eslint --fix",
|
|
85
|
-
"prettier --write"
|
|
86
|
-
]
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
87
49
|
}
|
|
88
50
|
}
|
package/test/tt-calendar.test.ts
CHANGED
|
@@ -3,38 +3,29 @@ import { DateTime, Settings } from 'luxon';
|
|
|
3
3
|
import '../src/tt-calendar.js'; // This handles the registration
|
|
4
4
|
import { Calendar } from '../src/TtCalendar.js';
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
describe('Calendar', () => {
|
|
8
7
|
describe('initialization', () => {
|
|
9
|
-
const originalNow = DateTime.now().toMillis()
|
|
8
|
+
const originalNow = DateTime.now().toMillis();
|
|
10
9
|
|
|
11
10
|
afterEach(() => {
|
|
12
11
|
Settings.defaultZone = 'system';
|
|
13
|
-
Settings.now = () => originalNow
|
|
12
|
+
Settings.now = () => originalNow;
|
|
14
13
|
});
|
|
15
14
|
|
|
16
15
|
it('should render with default props', async () => {
|
|
17
|
-
const el = await fixture<Calendar>(html`
|
|
18
|
-
<tt-calendar></tt-calendar>`);
|
|
16
|
+
const el = await fixture<Calendar>(html` <tt-calendar></tt-calendar>`);
|
|
19
17
|
expect(el).to.exist;
|
|
20
18
|
expect(el.range).to.be.false;
|
|
21
19
|
expect(el.value).to.be.undefined;
|
|
22
20
|
});
|
|
23
21
|
|
|
24
|
-
[
|
|
25
|
-
'Australia/Brisbane',
|
|
26
|
-
'America/New_York',
|
|
27
|
-
'Europe/London',
|
|
28
|
-
'Asia/Tokyo',
|
|
29
|
-
'Etc/UTC'
|
|
30
|
-
].forEach((timezone) => {
|
|
22
|
+
['Australia/Brisbane', 'America/New_York', 'Europe/London', 'Asia/Tokyo', 'Etc/UTC'].forEach((timezone) => {
|
|
31
23
|
it(`should render the correct days of the week in ${timezone} timezone`, async () => {
|
|
32
24
|
Settings.defaultZone = timezone;
|
|
33
|
-
const now = DateTime.local(2025,6,4,22,0,0).toMillis();
|
|
25
|
+
const now = DateTime.local(2025, 6, 4, 22, 0, 0).toMillis();
|
|
34
26
|
Settings.now = () => now;
|
|
35
27
|
const today = DateTime.now().toISO()!;
|
|
36
|
-
const el = await fixture<Calendar>(html`
|
|
37
|
-
<tt-calendar value="${today}"></tt-calendar>`);
|
|
28
|
+
const el = await fixture<Calendar>(html` <tt-calendar value="${today}"></tt-calendar>`);
|
|
38
29
|
|
|
39
30
|
const sunday = DateTime.fromISO(today).startOf('week').plus({ days: 6 }).toFormat('ccc');
|
|
40
31
|
|
|
@@ -51,8 +42,7 @@ describe('Calendar', () => {
|
|
|
51
42
|
|
|
52
43
|
describe('visibility', () => {
|
|
53
44
|
xit('should toggle visibility when calling toggleVisibility', async () => {
|
|
54
|
-
const el = await fixture<Calendar>(html`
|
|
55
|
-
<tt-calendar></tt-calendar>`);
|
|
45
|
+
const el = await fixture<Calendar>(html` <tt-calendar></tt-calendar>`);
|
|
56
46
|
|
|
57
47
|
expect(el).to.be.instanceOf(Calendar);
|
|
58
48
|
|
|
@@ -67,13 +57,12 @@ describe('Calendar', () => {
|
|
|
67
57
|
});
|
|
68
58
|
|
|
69
59
|
xit('should close on outside click', async () => {
|
|
70
|
-
const el = await fixture<Calendar>(html`
|
|
71
|
-
<tt-calendar></tt-calendar>`);
|
|
60
|
+
const el = await fixture<Calendar>(html` <tt-calendar></tt-calendar>`);
|
|
72
61
|
el.toggleVisibility();
|
|
73
62
|
await elementUpdated(el);
|
|
74
63
|
|
|
75
64
|
const focusOutEvent = new FocusEvent('focusout', {
|
|
76
|
-
relatedTarget: document.body
|
|
65
|
+
relatedTarget: document.body,
|
|
77
66
|
});
|
|
78
67
|
el.shadowRoot!.querySelector('[part="calendar"]')?.dispatchEvent(focusOutEvent);
|
|
79
68
|
await elementUpdated(el);
|
|
@@ -82,8 +71,7 @@ describe('Calendar', () => {
|
|
|
82
71
|
});
|
|
83
72
|
|
|
84
73
|
xit('should focus calendar div when opened', async () => {
|
|
85
|
-
const el = await fixture<Calendar>(html`
|
|
86
|
-
<tt-calendar></tt-calendar>`);
|
|
74
|
+
const el = await fixture<Calendar>(html` <tt-calendar></tt-calendar>`);
|
|
87
75
|
el.toggleVisibility();
|
|
88
76
|
|
|
89
77
|
await elementUpdated(el);
|
|
@@ -94,19 +82,13 @@ describe('Calendar', () => {
|
|
|
94
82
|
});
|
|
95
83
|
});
|
|
96
84
|
|
|
97
|
-
[
|
|
98
|
-
'Australia/Brisbane',
|
|
99
|
-
'America/New_York',
|
|
100
|
-
'Europe/London',
|
|
101
|
-
'Asia/Tokyo',
|
|
102
|
-
'Etc/UTC'
|
|
103
|
-
].forEach((timezone) => {
|
|
85
|
+
['Australia/Brisbane', 'America/New_York', 'Europe/London', 'Asia/Tokyo', 'Etc/UTC'].forEach((timezone) => {
|
|
104
86
|
describe(`single date selection in ${timezone} timezone`, () => {
|
|
105
|
-
const originalNow = DateTime.now().toMillis()
|
|
87
|
+
const originalNow = DateTime.now().toMillis();
|
|
106
88
|
|
|
107
89
|
afterEach(() => {
|
|
108
90
|
Settings.defaultZone = 'system';
|
|
109
|
-
Settings.now = () => originalNow
|
|
91
|
+
Settings.now = () => originalNow;
|
|
110
92
|
});
|
|
111
93
|
|
|
112
94
|
const selectDay = (day: string, el: HTMLElement): void => {
|
|
@@ -115,16 +97,13 @@ describe('Calendar', () => {
|
|
|
115
97
|
}
|
|
116
98
|
|
|
117
99
|
const allCells = el.shadowRoot.querySelectorAll('td[role="gridcell"]');
|
|
118
|
-
const dayCell = Array.from(allCells).filter(
|
|
119
|
-
(cell) => cell.textContent?.trim() === day
|
|
120
|
-
)[0] as HTMLElement;
|
|
100
|
+
const dayCell = Array.from(allCells).filter((cell) => cell.textContent?.trim() === day)[0] as HTMLElement;
|
|
121
101
|
dayCell.click();
|
|
122
102
|
};
|
|
123
103
|
|
|
124
104
|
it('should emit date-selection event when selecting a date', async () => {
|
|
125
105
|
Settings.defaultZone = timezone;
|
|
126
|
-
const el = await fixture<Calendar>(html`
|
|
127
|
-
<tt-calendar value="2025-01-09"></tt-calendar>`);
|
|
106
|
+
const el = await fixture<Calendar>(html` <tt-calendar value="2025-01-09"></tt-calendar>`);
|
|
128
107
|
const listener = oneEvent(el, 'date-selection');
|
|
129
108
|
await elementUpdated(el);
|
|
130
109
|
selectDay('4', el);
|
|
@@ -133,25 +112,17 @@ describe('Calendar', () => {
|
|
|
133
112
|
|
|
134
113
|
const { detail } = await listener;
|
|
135
114
|
const actual = detail as Date;
|
|
136
|
-
const expected =
|
|
115
|
+
const expected = '2025-01-04';
|
|
137
116
|
expect(actual).to.equal(expected);
|
|
138
117
|
});
|
|
139
118
|
});
|
|
140
119
|
});
|
|
141
|
-
[
|
|
142
|
-
'Australia/Brisbane',
|
|
143
|
-
'America/New_York',
|
|
144
|
-
'Europe/London',
|
|
145
|
-
'Asia/Tokyo',
|
|
146
|
-
'Etc/UTC'
|
|
147
|
-
].forEach((timezone) => {
|
|
120
|
+
['Australia/Brisbane', 'America/New_York', 'Europe/London', 'Asia/Tokyo', 'Etc/UTC'].forEach((timezone) => {
|
|
148
121
|
describe('date range selection', () => {
|
|
149
|
-
|
|
150
122
|
it(`should emit date-range-selection event when selecting range in ${timezone} timezone`, async () => {
|
|
151
123
|
Settings.defaultZone = timezone;
|
|
152
124
|
Settings.now = () => DateTime.local(2025, 7, 1, 22, 0, 0).toMillis();
|
|
153
|
-
const el = await fixture<Calendar>(html`
|
|
154
|
-
<tt-calendar range></tt-calendar>`);
|
|
125
|
+
const el = await fixture<Calendar>(html` <tt-calendar range></tt-calendar>`);
|
|
155
126
|
const listener = oneEvent(el, 'date-range-selection');
|
|
156
127
|
|
|
157
128
|
el.toggleVisibility();
|
|
@@ -172,16 +143,15 @@ describe('Calendar', () => {
|
|
|
172
143
|
expect(detail).to.have.property('endDate');
|
|
173
144
|
|
|
174
145
|
const { startDate, endDate } = detail;
|
|
175
|
-
const expectedStartDate =
|
|
176
|
-
const expectedEndDate =
|
|
146
|
+
const expectedStartDate = '2025-07-01';
|
|
147
|
+
const expectedEndDate = '2025-07-06';
|
|
177
148
|
await expect(startDate).to.equal(expectedStartDate);
|
|
178
149
|
await expect(endDate).to.equal(expectedEndDate);
|
|
179
150
|
});
|
|
180
151
|
|
|
181
152
|
it('should disable dates before the start of the range when selecting', async () => {
|
|
182
153
|
Settings.defaultZone = timezone;
|
|
183
|
-
const el = await fixture<Calendar>(html`
|
|
184
|
-
<tt-calendar range></tt-calendar>`);
|
|
154
|
+
const el = await fixture<Calendar>(html` <tt-calendar range></tt-calendar>`);
|
|
185
155
|
el.toggleVisibility();
|
|
186
156
|
await elementUpdated(el);
|
|
187
157
|
|
|
@@ -194,11 +164,9 @@ describe('Calendar', () => {
|
|
|
194
164
|
});
|
|
195
165
|
});
|
|
196
166
|
|
|
197
|
-
|
|
198
167
|
describe('clear selection', () => {
|
|
199
168
|
it('should clear selection', async () => {
|
|
200
|
-
const el = await fixture<Calendar>(html`
|
|
201
|
-
<tt-calendar range></tt-calendar>`);
|
|
169
|
+
const el = await fixture<Calendar>(html` <tt-calendar range></tt-calendar>`);
|
|
202
170
|
const listener = oneEvent(el, 'date-range-selection');
|
|
203
171
|
|
|
204
172
|
el.toggleVisibility();
|
|
@@ -216,21 +184,19 @@ describe('Calendar', () => {
|
|
|
216
184
|
|
|
217
185
|
describe('a11y', () => {
|
|
218
186
|
it('should have proper ARIA attributes', async () => {
|
|
219
|
-
const el = await fixture<Calendar>(html`
|
|
220
|
-
<tt-calendar></tt-calendar>`);
|
|
187
|
+
const el = await fixture<Calendar>(html` <tt-calendar></tt-calendar>`);
|
|
221
188
|
el.toggleVisibility();
|
|
222
189
|
await elementUpdated(el);
|
|
223
190
|
|
|
224
191
|
const days = el.shadowRoot!.querySelectorAll('.day');
|
|
225
|
-
days.forEach(day => {
|
|
192
|
+
days.forEach((day) => {
|
|
226
193
|
expect(day.getAttribute('role')).to.equal('gridcell');
|
|
227
194
|
expect(day.getAttribute('aria-label')).to.exist;
|
|
228
195
|
});
|
|
229
196
|
});
|
|
230
197
|
|
|
231
198
|
it('should have proper ARIA selected states', async () => {
|
|
232
|
-
const el = await fixture<Calendar>(html`
|
|
233
|
-
<tt-calendar range></tt-calendar>`);
|
|
199
|
+
const el = await fixture<Calendar>(html` <tt-calendar range></tt-calendar>`);
|
|
234
200
|
el.toggleVisibility();
|
|
235
201
|
await elementUpdated(el);
|
|
236
202
|
|
|
@@ -243,4 +209,3 @@ describe('Calendar', () => {
|
|
|
243
209
|
});
|
|
244
210
|
});
|
|
245
211
|
});
|
|
246
|
-
|
package/tsconfig.json
CHANGED