@lekoala/date-picker 0.1.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/LICENSE +21 -0
- package/README.md +236 -0
- package/custom-elements.json +366 -0
- package/dist/date-picker.css +344 -0
- package/dist/date-picker.js +2693 -0
- package/dist/date-picker.min.css +1 -0
- package/dist/date-picker.min.js +17 -0
- package/dist/date-picker.standalone.min.js +361 -0
- package/dist/types/calendar-model.d.ts +34 -0
- package/dist/types/calendar-model.d.ts.map +1 -0
- package/dist/types/date-calendar.d.ts +228 -0
- package/dist/types/date-calendar.d.ts.map +1 -0
- package/dist/types/date-field.d.ts +94 -0
- package/dist/types/date-field.d.ts.map +1 -0
- package/dist/types/date-picker.d.ts +258 -0
- package/dist/types/date-picker.d.ts.map +1 -0
- package/dist/types/date-range.d.ts +89 -0
- package/dist/types/date-range.d.ts.map +1 -0
- package/dist/types/date.d.ts +61 -0
- package/dist/types/date.d.ts.map +1 -0
- package/dist/types/define.d.ts +2 -0
- package/dist/types/define.d.ts.map +1 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/intl.d.ts +33 -0
- package/dist/types/intl.d.ts.map +1 -0
- package/dist/types/locales/ar.d.ts +22 -0
- package/dist/types/locales/ar.d.ts.map +1 -0
- package/dist/types/locales/de.d.ts +22 -0
- package/dist/types/locales/de.d.ts.map +1 -0
- package/dist/types/locales/en.d.ts +22 -0
- package/dist/types/locales/en.d.ts.map +1 -0
- package/dist/types/locales/es.d.ts +22 -0
- package/dist/types/locales/es.d.ts.map +1 -0
- package/dist/types/locales/fr.d.ts +22 -0
- package/dist/types/locales/fr.d.ts.map +1 -0
- package/dist/types/locales/hi.d.ts +22 -0
- package/dist/types/locales/hi.d.ts.map +1 -0
- package/dist/types/locales/id.d.ts +22 -0
- package/dist/types/locales/id.d.ts.map +1 -0
- package/dist/types/locales/it.d.ts +22 -0
- package/dist/types/locales/it.d.ts.map +1 -0
- package/dist/types/locales/ja.d.ts +22 -0
- package/dist/types/locales/ja.d.ts.map +1 -0
- package/dist/types/locales/ko.d.ts +22 -0
- package/dist/types/locales/ko.d.ts.map +1 -0
- package/dist/types/locales/nl.d.ts +22 -0
- package/dist/types/locales/nl.d.ts.map +1 -0
- package/dist/types/locales/pl.d.ts +22 -0
- package/dist/types/locales/pl.d.ts.map +1 -0
- package/dist/types/locales/pt-BR.d.ts +22 -0
- package/dist/types/locales/pt-BR.d.ts.map +1 -0
- package/dist/types/locales/pt-PT.d.ts +22 -0
- package/dist/types/locales/pt-PT.d.ts.map +1 -0
- package/dist/types/locales/ru.d.ts +22 -0
- package/dist/types/locales/ru.d.ts.map +1 -0
- package/dist/types/locales/tr.d.ts +22 -0
- package/dist/types/locales/tr.d.ts.map +1 -0
- package/dist/types/locales/zh-CN.d.ts +22 -0
- package/dist/types/locales/zh-CN.d.ts.map +1 -0
- package/dist/types/messages.d.ts +43 -0
- package/dist/types/messages.d.ts.map +1 -0
- package/dist/types/source.d.ts +28 -0
- package/dist/types/source.d.ts.map +1 -0
- package/docs/ACCESSIBILITY.md +128 -0
- package/docs/API.md +289 -0
- package/docs/ARCHITECTURE.md +183 -0
- package/docs/AT-CHECKLIST.md +63 -0
- package/docs/CALENDAR-INTEGRATION.md +70 -0
- package/docs/DECISIONS.md +40 -0
- package/docs/MIGRATION-FLATPICKR.md +92 -0
- package/docs/ROADMAP.md +105 -0
- package/docs/TESTING.md +73 -0
- package/docs/USE_CASES.md +128 -0
- package/package.json +174 -0
- package/src/calendar-model.js +80 -0
- package/src/date-calendar.js +800 -0
- package/src/date-field.js +203 -0
- package/src/date-picker.css +344 -0
- package/src/date-picker.js +1140 -0
- package/src/date-range.js +172 -0
- package/src/date.js +203 -0
- package/src/define.js +9 -0
- package/src/index.js +15 -0
- package/src/intl.js +155 -0
- package/src/locales/ar.js +20 -0
- package/src/locales/de.js +20 -0
- package/src/locales/en.js +20 -0
- package/src/locales/es.js +20 -0
- package/src/locales/fr.js +20 -0
- package/src/locales/hi.js +20 -0
- package/src/locales/id.js +20 -0
- package/src/locales/it.js +20 -0
- package/src/locales/ja.js +20 -0
- package/src/locales/ko.js +20 -0
- package/src/locales/nl.js +20 -0
- package/src/locales/pl.js +20 -0
- package/src/locales/pt-BR.js +20 -0
- package/src/locales/pt-PT.js +20 -0
- package/src/locales/ru.js +20 -0
- package/src/locales/tr.js +20 -0
- package/src/locales/zh-CN.js +20 -0
- package/src/messages.js +31 -0
- package/src/source.js +50 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { isDate } from "./date.js";
|
|
2
|
+
import { createDateAdapter } from "./intl.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Owns a single editable form field inside a picker: the visible input, its
|
|
6
|
+
* hidden canonical ISO field, the Intl adapter and the text commit pipeline
|
|
7
|
+
* (parsing, availability gate, stale-response protection).
|
|
8
|
+
*
|
|
9
|
+
* It deliberately knows nothing about calendars, popups or ranges. Remote
|
|
10
|
+
* availability is injected as an async `confirm(date)` callback and the
|
|
11
|
+
* committed canonical value is applied by the coordinator, so all canonical
|
|
12
|
+
* reflection and events stay at the picker level.
|
|
13
|
+
*/
|
|
14
|
+
export class DateFieldController {
|
|
15
|
+
/**
|
|
16
|
+
* @param {HTMLInputElement} input
|
|
17
|
+
* @param {{messages?: Record<string, string>, locale?: string}} [options]
|
|
18
|
+
*/
|
|
19
|
+
constructor(input, options = {}) {
|
|
20
|
+
this.input = input;
|
|
21
|
+
this.messages = options.messages || {};
|
|
22
|
+
this.adapter = createDateAdapter(options.locale || "");
|
|
23
|
+
/** @type {HTMLInputElement | null} */
|
|
24
|
+
this.hidden = null;
|
|
25
|
+
/** Current canonical value (YYYY-MM-DD or ""). */
|
|
26
|
+
this.canonical = "";
|
|
27
|
+
this._dirty = false;
|
|
28
|
+
this._commitId = 0;
|
|
29
|
+
this._originalName = input.getAttribute("name") || "";
|
|
30
|
+
/** @type {MutationObserver | null} */
|
|
31
|
+
this._attributeObserver = null;
|
|
32
|
+
/** @type {(() => void) | null} */
|
|
33
|
+
this.onAttributesChanged = null;
|
|
34
|
+
/**
|
|
35
|
+
* Async availability gate for a parsed date. Returning `{ ok: false }`
|
|
36
|
+
* marks the target unavailable. Swappable at runtime.
|
|
37
|
+
* @type {((date: string) => Promise<{ok: boolean, message?: string}>) | null}
|
|
38
|
+
*/
|
|
39
|
+
this.confirm = null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** @param {string} locale */
|
|
43
|
+
setLocale(locale) {
|
|
44
|
+
this.adapter = createDateAdapter(locale || "");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** @param {Record<string, string>} messages */
|
|
48
|
+
setMessages(messages) {
|
|
49
|
+
this.messages = messages || {};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** @param {string} value */
|
|
53
|
+
format(value) {
|
|
54
|
+
return this.adapter.format(value);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** @param {string} text */
|
|
58
|
+
parse(text) {
|
|
59
|
+
return this.adapter.parse(text);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get placeholder() {
|
|
63
|
+
return this.adapter.placeholder;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get isDisabled() {
|
|
67
|
+
return this.input.disabled;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get isReadOnly() {
|
|
71
|
+
return this.input.readOnly;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Create the hidden canonical field for an authored `name` and observe the
|
|
75
|
+
* input for dynamic name/form/disabled changes. */
|
|
76
|
+
setupFormValue() {
|
|
77
|
+
const input = this.input;
|
|
78
|
+
this._originalName = input.getAttribute("name") || "";
|
|
79
|
+
this._attributeObserver = new MutationObserver(() => this.onAttributesChanged?.());
|
|
80
|
+
this._attributeObserver.observe(input, {
|
|
81
|
+
attributes: true,
|
|
82
|
+
attributeFilter: ["disabled", "readonly", "name", "form"],
|
|
83
|
+
});
|
|
84
|
+
this.syncInputState();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Sync the hidden field with the current dynamic attributes. */
|
|
88
|
+
syncInputState() {
|
|
89
|
+
const input = this.input;
|
|
90
|
+
const name = input.getAttribute("name") || "";
|
|
91
|
+
if (name) {
|
|
92
|
+
if (!this.hidden) {
|
|
93
|
+
const hidden = document.createElement("input");
|
|
94
|
+
hidden.type = "hidden";
|
|
95
|
+
hidden.value = this.canonical;
|
|
96
|
+
input.insertAdjacentElement("afterend", hidden);
|
|
97
|
+
this.hidden = hidden;
|
|
98
|
+
}
|
|
99
|
+
if (this.hidden) this.hidden.name = name;
|
|
100
|
+
input.removeAttribute("name");
|
|
101
|
+
}
|
|
102
|
+
if (this.hidden) {
|
|
103
|
+
if (input.hasAttribute("form")) this.hidden.setAttribute("form", input.getAttribute("form") || "");
|
|
104
|
+
else this.hidden.removeAttribute("form");
|
|
105
|
+
this.hidden.disabled = input.disabled;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Invalidate any pending (possibly in-flight) commit. */
|
|
110
|
+
dirty() {
|
|
111
|
+
this._commitId++;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Whether the user edited the visible text since the last application. */
|
|
115
|
+
get isDirty() {
|
|
116
|
+
return this._dirty;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Live text input: the raw text no longer matches the canonical value, so
|
|
120
|
+
* the hidden ISO must not submit it. */
|
|
121
|
+
handleInput() {
|
|
122
|
+
const input = this.input;
|
|
123
|
+
this._dirty = true;
|
|
124
|
+
this.dirty();
|
|
125
|
+
if (this.hidden) this.hidden.value = "";
|
|
126
|
+
const text = input.value.trim();
|
|
127
|
+
if (!text) {
|
|
128
|
+
input.setCustomValidity("");
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const canonical = this.canonical ? this.adapter.format(this.canonical) : "";
|
|
132
|
+
input.setCustomValidity(text === canonical ? "" : this.messages.invalidDate);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Commit the visible text. Returns the parsed canonical date on success, the
|
|
137
|
+
* empty string on a clear, or a falsy marker for invalid/stale commits. The
|
|
138
|
+
* caller applies the canonical value so reflection and events stay central.
|
|
139
|
+
* @returns {Promise<{status: "ok" | "clear" | "invalid" | "stale", value?: string}>}
|
|
140
|
+
*/
|
|
141
|
+
async commit() {
|
|
142
|
+
const input = this.input;
|
|
143
|
+
const commitId = ++this._commitId;
|
|
144
|
+
const text = input.value.trim();
|
|
145
|
+
if (!text) {
|
|
146
|
+
if (commitId !== this._commitId) return { status: "stale" };
|
|
147
|
+
input.setCustomValidity("");
|
|
148
|
+
return { status: "clear", value: "" };
|
|
149
|
+
}
|
|
150
|
+
const parsed = this.adapter.parse(text);
|
|
151
|
+
if (!parsed) {
|
|
152
|
+
if (commitId !== this._commitId) return { status: "stale" };
|
|
153
|
+
if (this.hidden) this.hidden.value = "";
|
|
154
|
+
input.setCustomValidity(this.messages.invalidDate);
|
|
155
|
+
return { status: "invalid" };
|
|
156
|
+
}
|
|
157
|
+
if (this.confirm) {
|
|
158
|
+
const result = await this.confirm(parsed);
|
|
159
|
+
if (commitId !== this._commitId) return { status: "stale" };
|
|
160
|
+
if (!result?.ok) {
|
|
161
|
+
if (this.hidden) this.hidden.value = "";
|
|
162
|
+
input.setCustomValidity(result?.message || this.messages.unavailableDate);
|
|
163
|
+
return { status: "invalid" };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return { status: "ok", value: parsed };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* @param {string} value
|
|
171
|
+
* @param {{format?: boolean}} [options]
|
|
172
|
+
*/
|
|
173
|
+
setCanonical(value, options = {}) {
|
|
174
|
+
const next = value || "";
|
|
175
|
+
if (next && !isDate(next)) throw new TypeError(`Invalid date-picker value: ${next}`);
|
|
176
|
+
// A programmatic/coordinator application supersedes any in-flight text
|
|
177
|
+
// commit, so an older pending result can never overwrite a newer value.
|
|
178
|
+
this.dirty();
|
|
179
|
+
this.canonical = next;
|
|
180
|
+
this._dirty = false;
|
|
181
|
+
if (this.hidden) this.hidden.value = next;
|
|
182
|
+
if (options.format !== false) this.input.value = next ? this.adapter.format(next) : "";
|
|
183
|
+
this.input.setCustomValidity("");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Restore value from `input.defaultValue` (native form reset). */
|
|
187
|
+
restoreDefault() {
|
|
188
|
+
const text = String(this.input.defaultValue ?? "").trim();
|
|
189
|
+
const parsed = isDate(text) ? text : this.adapter.parse(text);
|
|
190
|
+
return parsed && isDate(parsed) ? parsed : "";
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Remove the hidden field and attribute observer, restoring the original
|
|
194
|
+
* authored `name` on the visible input. */
|
|
195
|
+
teardown() {
|
|
196
|
+
this._attributeObserver?.disconnect();
|
|
197
|
+
this._attributeObserver = null;
|
|
198
|
+
const hiddenName = this.hidden?.getAttribute("name") || this._originalName;
|
|
199
|
+
if (hiddenName) this.input.setAttribute("name", hiddenName);
|
|
200
|
+
this.hidden?.remove();
|
|
201
|
+
this.hidden = null;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
:where(date-calendar, date-picker) {
|
|
2
|
+
--dp-bg: Canvas;
|
|
3
|
+
--dp-fg: CanvasText;
|
|
4
|
+
--dp-muted: color-mix(in srgb, CanvasText 58%, Canvas);
|
|
5
|
+
--dp-border: color-mix(in srgb, CanvasText 22%, Canvas);
|
|
6
|
+
--dp-hover: color-mix(in srgb, CanvasText 7%, Canvas);
|
|
7
|
+
--dp-accent: Highlight;
|
|
8
|
+
--dp-accent-fg: HighlightText;
|
|
9
|
+
--dp-radius: 0.5rem;
|
|
10
|
+
--dp-day-size: 2.75rem;
|
|
11
|
+
--dp-gap: 0.25rem;
|
|
12
|
+
color: var(--dp-fg);
|
|
13
|
+
font: inherit;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.dp-visually-hidden {
|
|
17
|
+
position: absolute !important;
|
|
18
|
+
inline-size: 1px !important;
|
|
19
|
+
block-size: 1px !important;
|
|
20
|
+
padding: 0 !important;
|
|
21
|
+
margin: -1px !important;
|
|
22
|
+
overflow: hidden !important;
|
|
23
|
+
clip: rect(0 0 0 0) !important;
|
|
24
|
+
white-space: nowrap !important;
|
|
25
|
+
border: 0 !important;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
date-calendar {
|
|
29
|
+
display: block;
|
|
30
|
+
inline-size: max-content;
|
|
31
|
+
max-inline-size: 100%;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.dp-calendar-shell {
|
|
35
|
+
inline-size: max-content;
|
|
36
|
+
max-inline-size: 100%;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.dp-calendar-header {
|
|
40
|
+
display: grid;
|
|
41
|
+
grid-template-columns: minmax(0, 1fr) auto auto auto;
|
|
42
|
+
align-items: center;
|
|
43
|
+
gap: var(--dp-gap);
|
|
44
|
+
margin-block-end: 0.4rem;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.dp-calendar-header .dp-prev {
|
|
48
|
+
margin-inline-start: calc(var(--dp-gap) * 2.5);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.dp-calendar-header :where(button, select, input) {
|
|
52
|
+
min-block-size: 2.25rem;
|
|
53
|
+
border: 1px solid var(--dp-border);
|
|
54
|
+
border-radius: calc(var(--dp-radius) * 0.75);
|
|
55
|
+
background: var(--dp-bg);
|
|
56
|
+
color: var(--dp-fg);
|
|
57
|
+
font: inherit;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.dp-calendar-header select,
|
|
61
|
+
.dp-calendar-header input {
|
|
62
|
+
min-inline-size: 0;
|
|
63
|
+
padding-inline: 0.45rem;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.dp-month-select {
|
|
67
|
+
inline-size: 100%;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.dp-year-input {
|
|
71
|
+
inline-size: 5.5rem;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.dp-nav {
|
|
75
|
+
display: grid;
|
|
76
|
+
place-items: center;
|
|
77
|
+
inline-size: 2.25rem;
|
|
78
|
+
padding: 0;
|
|
79
|
+
font-size: 1.35rem;
|
|
80
|
+
line-height: 1;
|
|
81
|
+
cursor: pointer;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.dp-nav svg {
|
|
85
|
+
display: block;
|
|
86
|
+
inline-size: 1rem;
|
|
87
|
+
block-size: 1rem;
|
|
88
|
+
pointer-events: none;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.dp-calendar-header :where(button, select, input):disabled,
|
|
92
|
+
.dp-picker-button:disabled {
|
|
93
|
+
cursor: not-allowed;
|
|
94
|
+
opacity: 0.45;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.dp-nav:hover:not(:disabled) {
|
|
98
|
+
background: var(--dp-hover);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.dp-day:hover:not([data-disabled="true"]):not([data-selected="true"]):not([data-range-start="true"]):not(
|
|
102
|
+
[data-range-end="true"]
|
|
103
|
+
) {
|
|
104
|
+
background: var(--dp-hover);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.dp-calendar-heading {
|
|
108
|
+
margin: 0 0 0.35rem;
|
|
109
|
+
font-size: 0.875rem;
|
|
110
|
+
font-weight: 600;
|
|
111
|
+
text-align: center;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.dp-grid {
|
|
115
|
+
border-collapse: separate;
|
|
116
|
+
/* --dp-gap scopes to the header grid; day-cell spacing stays fixed. */
|
|
117
|
+
border-spacing: 0 0.25rem;
|
|
118
|
+
table-layout: fixed;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.dp-grid :where(th, td) {
|
|
122
|
+
box-sizing: border-box;
|
|
123
|
+
inline-size: var(--dp-day-size);
|
|
124
|
+
block-size: var(--dp-day-size);
|
|
125
|
+
padding: 0;
|
|
126
|
+
text-align: center;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.dp-grid thead th {
|
|
130
|
+
block-size: 1.6rem;
|
|
131
|
+
color: var(--dp-muted);
|
|
132
|
+
font-size: 0.72rem;
|
|
133
|
+
font-weight: 600;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.dp-day {
|
|
137
|
+
position: relative;
|
|
138
|
+
border: 1px solid transparent;
|
|
139
|
+
border-radius: calc(var(--dp-radius) * 0.75);
|
|
140
|
+
cursor: pointer;
|
|
141
|
+
outline: none;
|
|
142
|
+
vertical-align: middle;
|
|
143
|
+
font-size: 0.875rem;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.dp-day:focus-visible {
|
|
147
|
+
outline: 2px solid var(--dp-accent);
|
|
148
|
+
outline-offset: 1px;
|
|
149
|
+
z-index: 1;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.dp-day[data-selected="true"] {
|
|
153
|
+
background: var(--dp-accent);
|
|
154
|
+
color: var(--dp-accent-fg);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.dp-day[data-today="true"]:not([data-selected="true"]) {
|
|
158
|
+
border-color: var(--dp-accent);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.dp-day[data-outside-month="true"] {
|
|
162
|
+
color: var(--dp-muted);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.dp-day[data-disabled="true"] {
|
|
166
|
+
cursor: not-allowed;
|
|
167
|
+
opacity: 0.42;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.dp-day[data-range-start="true"],
|
|
171
|
+
.dp-day[data-range-end="true"] {
|
|
172
|
+
background: var(--dp-accent);
|
|
173
|
+
color: var(--dp-accent-fg);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.dp-day[data-in-range="true"] {
|
|
177
|
+
border-radius: 0;
|
|
178
|
+
background: color-mix(in srgb, var(--dp-accent) 18%, var(--dp-bg));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* Join the band without gaps, including the corners beside each endpoint. */
|
|
182
|
+
.dp-day[data-range-start="true"]:has(+ [data-in-range="true"], + [data-range-end="true"]) {
|
|
183
|
+
border-start-end-radius: 0;
|
|
184
|
+
border-end-end-radius: 0;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.dp-day:is([data-in-range="true"], [data-range-start="true"]) + .dp-day[data-range-end="true"] {
|
|
188
|
+
border-start-start-radius: 0;
|
|
189
|
+
border-end-start-radius: 0;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.dp-day[data-in-range="true"]:first-of-type {
|
|
193
|
+
border-start-start-radius: var(--dp-radius);
|
|
194
|
+
border-end-start-radius: var(--dp-radius);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.dp-day[data-in-range="true"]:last-of-type {
|
|
198
|
+
border-start-end-radius: var(--dp-radius);
|
|
199
|
+
border-end-end-radius: var(--dp-radius);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.dp-day-number {
|
|
203
|
+
display: block;
|
|
204
|
+
font-variant-numeric: tabular-nums;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.dp-day-extra {
|
|
208
|
+
position: absolute;
|
|
209
|
+
inset-inline: 2px;
|
|
210
|
+
inset-block-end: 1px;
|
|
211
|
+
display: flex;
|
|
212
|
+
justify-content: center;
|
|
213
|
+
gap: 2px;
|
|
214
|
+
min-block-size: 0.35rem;
|
|
215
|
+
font-size: 0.55rem;
|
|
216
|
+
line-height: 1;
|
|
217
|
+
pointer-events: none;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.dp-week-number,
|
|
221
|
+
.dp-week-heading {
|
|
222
|
+
inline-size: 1.6rem !important;
|
|
223
|
+
color: var(--dp-muted);
|
|
224
|
+
font-size: 0.65rem;
|
|
225
|
+
font-weight: 500;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
date-picker {
|
|
229
|
+
position: relative;
|
|
230
|
+
display: inline-grid;
|
|
231
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
232
|
+
align-items: stretch;
|
|
233
|
+
max-inline-size: 100%;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
date-picker > input:not([type="hidden"]) {
|
|
237
|
+
grid-column: 1;
|
|
238
|
+
min-inline-size: 0;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
date-picker[range] > input:not([type="hidden"]) {
|
|
242
|
+
grid-column: 1;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
date-picker[range] > input[data-range-start] {
|
|
246
|
+
grid-row: 1;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
date-picker[range] > input[data-range-end] {
|
|
250
|
+
grid-row: 2;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.dp-picker-button {
|
|
254
|
+
grid-column: 2;
|
|
255
|
+
min-inline-size: 2.5rem;
|
|
256
|
+
border: 1px solid var(--dp-border);
|
|
257
|
+
border-inline-start: 0;
|
|
258
|
+
border-start-start-radius: 0;
|
|
259
|
+
border-end-start-radius: 0;
|
|
260
|
+
border-start-end-radius: var(--dp-radius);
|
|
261
|
+
border-end-end-radius: var(--dp-radius);
|
|
262
|
+
background: var(--dp-bg);
|
|
263
|
+
color: var(--dp-fg);
|
|
264
|
+
font: inherit;
|
|
265
|
+
cursor: pointer;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
date-picker[range] > .dp-picker-button {
|
|
269
|
+
grid-row: 1 / span 2;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.dp-picker-panel[popover] {
|
|
273
|
+
position: fixed;
|
|
274
|
+
inset: auto;
|
|
275
|
+
margin: 0;
|
|
276
|
+
padding: 0.65rem;
|
|
277
|
+
border: 1px solid var(--dp-border);
|
|
278
|
+
border-radius: var(--dp-radius);
|
|
279
|
+
background: var(--dp-bg);
|
|
280
|
+
color: var(--dp-fg);
|
|
281
|
+
box-shadow: 0 0.5rem 1.5rem rgb(0 0 0 / 0.16);
|
|
282
|
+
max-block-size: var(--available-height, 90svh);
|
|
283
|
+
max-inline-size: calc(100vi - 1rem);
|
|
284
|
+
overflow: auto;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.dp-picker-panel:not(:popover-open) {
|
|
288
|
+
display: none;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
@media (forced-colors: active) {
|
|
292
|
+
.dp-day[data-selected="true"] {
|
|
293
|
+
border: 2px solid Highlight;
|
|
294
|
+
background-color: Canvas;
|
|
295
|
+
color: CanvasText;
|
|
296
|
+
font-weight: 700;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.dp-day[data-range-start="true"],
|
|
300
|
+
.dp-day[data-range-end="true"] {
|
|
301
|
+
border: 2px solid Highlight;
|
|
302
|
+
background-color: Canvas;
|
|
303
|
+
color: CanvasText;
|
|
304
|
+
font-weight: 700;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.dp-day[data-in-range="true"] {
|
|
308
|
+
color: CanvasText;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.dp-day[data-in-range="true"]::after {
|
|
312
|
+
content: "";
|
|
313
|
+
position: absolute;
|
|
314
|
+
inset-inline: 3px;
|
|
315
|
+
inset-block-end: 4px;
|
|
316
|
+
block-size: 1px;
|
|
317
|
+
background-color: Highlight;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.dp-day[data-selected="true"]::before {
|
|
321
|
+
content: "";
|
|
322
|
+
position: absolute;
|
|
323
|
+
inset: 3px;
|
|
324
|
+
border: 1px solid CanvasText;
|
|
325
|
+
border-radius: calc(var(--dp-radius) * 0.5);
|
|
326
|
+
pointer-events: none;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.dp-day[data-today="true"] {
|
|
330
|
+
border-color: Highlight;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.dp-day-extra {
|
|
334
|
+
color: CanvasText;
|
|
335
|
+
forced-color-adjust: none;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.dp-day[data-disabled="true"],
|
|
339
|
+
.dp-calendar-header :where(button, select, input):disabled,
|
|
340
|
+
.dp-picker-button:disabled {
|
|
341
|
+
opacity: 1;
|
|
342
|
+
color: GrayText;
|
|
343
|
+
}
|
|
344
|
+
}
|