ten-protons-datepicker 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -6
- package/dist/core.css +4 -2
- package/dist/themes.css +2 -2
- package/dist/wc.d.ts +2 -1
- package/dist/wc.js +8 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,9 +22,11 @@ npm i ten-protons-datepicker
|
|
|
22
22
|
import 'ten-protons-datepicker/locales/uk'; // optional UI strings for locale="uk"
|
|
23
23
|
</script>
|
|
24
24
|
|
|
25
|
-
<
|
|
25
|
+
<ten-protons-datepicker name="period" mode="range" locale="uk" min="2025-01-01" label="Period"></ten-protons-datepicker>
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
`<x-datepicker>` is registered as an alias for the same element, so either tag works. Prefer `ten-protons-datepicker`: `x-datepicker` is a generic name another library could also claim, and the first one registered wins.
|
|
29
|
+
|
|
28
30
|
`mode="range"` / `mode="multiple"` and `enable-time` load their module on demand, so single-date pages don't pay for them.
|
|
29
31
|
|
|
30
32
|
| Attribute | Notes |
|
|
@@ -35,14 +37,37 @@ npm i ten-protons-datepicker
|
|
|
35
37
|
| `number-of-months`, `show-other-months`, `allow-input`, `close-on-select`, `disabled-days`, `output-timestamp`, `enable-time`, `value-in-utc`, `inline` | booleans: present = true, `="false"` = false |
|
|
36
38
|
|
|
37
39
|
```js
|
|
38
|
-
const el = document.querySelector('
|
|
40
|
+
const el = document.querySelector('ten-protons-datepicker');
|
|
39
41
|
el.value; // ISO string of the current selection
|
|
40
42
|
el.options = { disabledDates: (d) => d.getDay() === 0, onChange: console.log };
|
|
41
43
|
el.addEventListener('change', (e) => console.log(e.detail)); // also: open, close, monthChange, yearChange
|
|
42
44
|
await el.ready; // resolves with the underlying Datepicker
|
|
43
45
|
```
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
The input is styled out of the box to match the calendar (border, radius and colours, light and dark, red border on invalid input). Restyle it with `::part(input)` and `::part(toggle)`, e.g. `ten-protons-datepicker::part(input) { border-radius: 0 }`. The calendar button is the web component's own icon (at the start of the field, like `showIcon` on a plain input), so `showIcon` doesn't apply to it.
|
|
48
|
+
|
|
49
|
+
### Vue
|
|
50
|
+
|
|
51
|
+
Tell Vue that the tag is a custom element (Vite: `vue({ template: { compilerOptions: { isCustomElement: (tag) => tag === 'ten-protons-datepicker' } } })`), then bind `value` and listen to `change`:
|
|
52
|
+
|
|
53
|
+
```vue
|
|
54
|
+
<script setup lang="ts">
|
|
55
|
+
import 'ten-protons-datepicker/wc'; // its CSS is built in; enable-time loads the time module itself
|
|
56
|
+
|
|
57
|
+
defineProps<{ modelValue: number | null }>();
|
|
58
|
+
const emit = defineEmits<{ 'update:modelValue': [timestamp: number | null] }>();
|
|
59
|
+
const onChange = (e: Event) => {
|
|
60
|
+
const value = (e as CustomEvent).detail;
|
|
61
|
+
emit('update:modelValue', typeof value === 'number' ? value : null);
|
|
62
|
+
};
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<template>
|
|
66
|
+
<ten-protons-datepicker :value="modelValue ?? ''" label="Due" value-in-utc output-timestamp enable-time @change="onChange" />
|
|
67
|
+
</template>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Attributes such as `theme` and `max` can be bound the same way. The element is created and destroyed with the component, so there is nothing to clean up. Other frameworks work the same: set attributes, listen to `change`.
|
|
46
71
|
|
|
47
72
|
## Imperative API
|
|
48
73
|
|
|
@@ -149,7 +174,7 @@ const dp = withTime(new Datepicker(input, { dateFormat: 'dd.MM.yyyy', onChange:
|
|
|
149
174
|
```
|
|
150
175
|
|
|
151
176
|
```html
|
|
152
|
-
<
|
|
177
|
+
<ten-protons-datepicker enable-time output-timestamp name="meeting"></ten-protons-datepicker> <!-- loads the time module itself -->
|
|
153
178
|
```
|
|
154
179
|
|
|
155
180
|
How it behaves:
|
|
@@ -198,7 +223,7 @@ withTime(new Datepicker(input, { dateFormat: 'dd.MM.yyyy', outputTimestamp: true
|
|
|
198
223
|
// typed "1742044029" shows 15.03.2025 13:07:09 getDate() = 1742044029 exact round trip
|
|
199
224
|
```
|
|
200
225
|
|
|
201
|
-
Ranges work the same way: `withTime(withRange(new Datepicker(input, { outputTimestamp: true })))` returns `[1741597200, 1741804200]` for 10 March 09:00:00 to 12 March 18:30:00 (UTC). In the web component, `<
|
|
226
|
+
Ranges work the same way: `withTime(withRange(new Datepicker(input, { outputTimestamp: true })))` returns `[1741597200, 1741804200]` for 10 March 09:00:00 to 12 March 18:30:00 (UTC). In the web component, `<ten-protons-datepicker enable-time mode="range">` has the value `2025-03-10T09:00:00/2025-03-12T18:30:00`, or `1741597200/1741804200` with `output-timestamp`.
|
|
202
227
|
|
|
203
228
|
Things to know:
|
|
204
229
|
|
|
@@ -217,7 +242,7 @@ dp.getDate().toISOString(); // '2025-03-15T00:00:00.000Z', s
|
|
|
217
242
|
```
|
|
218
243
|
|
|
219
244
|
```html
|
|
220
|
-
<
|
|
245
|
+
<ten-protons-datepicker name="due" value-in-utc value="2025-03-15T00:00:00.000Z"></ten-protons-datepicker>
|
|
221
246
|
```
|
|
222
247
|
|
|
223
248
|
Without it, a user in Kyiv (UTC+2) who picks 15 March gets a `Date` for **local** midnight, and `toISOString()` sends `2025-03-14T22:00:00.000Z`: the backend stores the 14th. That is the bug this option removes.
|
package/dist/core.css
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
.tp-dp{
|
|
1
|
+
.tp-dp,:host{
|
|
2
2
|
--tp-bg:#fff;--tp-fg:#1f2328;--tp-muted:#656d76;--tp-border:#d0d7de;--tp-hover:#eef1f4;
|
|
3
3
|
--tp-accent:#2563eb;--tp-accent-fg:#fff;--tp-range:#dbe7fd;--tp-focus:#2563eb;
|
|
4
4
|
--tp-radius:.5rem;--tp-cell:2.25rem;--tp-pad:.75rem;--tp-z:1000;
|
|
5
|
-
--tp-shadow:0 8px 24px rgba(0,0,0,.15)
|
|
5
|
+
--tp-shadow:0 8px 24px rgba(0,0,0,.15)
|
|
6
|
+
}
|
|
7
|
+
.tp-dp{
|
|
6
8
|
position:relative;box-sizing:border-box;width:max-content;max-width:calc(100vw - 1rem);padding:var(--tp-pad);
|
|
7
9
|
background:var(--tp-bg);color:var(--tp-fg);border:1px solid var(--tp-border);border-radius:var(--tp-radius);
|
|
8
10
|
font:.875rem/1.4 var(--tp-font,inherit)
|
package/dist/themes.css
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/* Dark follows prefers-color-scheme unless data-theme="light"; data-theme="dark" forces it. */
|
|
2
|
-
.tp-dp[data-theme=dark]{
|
|
2
|
+
.tp-dp[data-theme=dark],:host([theme=dark]){
|
|
3
3
|
--tp-bg:#161b22;--tp-fg:#e6edf3;--tp-muted:#8d96a0;--tp-border:#30363d;--tp-hover:#21262d;
|
|
4
4
|
--tp-accent:#4c8dff;--tp-accent-fg:#0b1220;--tp-range:#1b2f52;--tp-focus:#79a8ff;--tp-shadow:0 8px 24px rgba(0,0,0,.5)
|
|
5
5
|
}
|
|
6
6
|
@media (prefers-color-scheme:dark){
|
|
7
|
-
.tp-dp:not([data-theme=light]){
|
|
7
|
+
.tp-dp:not([data-theme=light]),:host(:not([theme=light])){
|
|
8
8
|
--tp-bg:#161b22;--tp-fg:#e6edf3;--tp-muted:#8d96a0;--tp-border:#30363d;--tp-hover:#21262d;
|
|
9
9
|
--tp-accent:#4c8dff;--tp-accent-fg:#0b1220;--tp-range:#1b2f52;--tp-focus:#79a8ff;--tp-shadow:0 8px 24px rgba(0,0,0,.5)
|
|
10
10
|
}
|
package/dist/wc.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { a as Datepicker, d as DatepickerOptions } from './Datepicker-Dt5Dt_UX.j
|
|
|
2
2
|
|
|
3
3
|
declare const Base: typeof HTMLElement;
|
|
4
4
|
/**
|
|
5
|
-
* `<x-datepicker
|
|
5
|
+
* `<ten-protons-datepicker>` (alias `<x-datepicker>`): an input + calendar toggle with the popup inside its shadow root.
|
|
6
6
|
*
|
|
7
7
|
* Attributes: `value` (ISO or Unix seconds, ranges `a/b`, multiple `a,b`), `name`, `placeholder`, `label`, `disabled`,
|
|
8
8
|
* `mode`, `locale`, `min`, `max`, `date-format`, `first-day`, `position`, `theme`, `number-of-months`,
|
|
@@ -51,6 +51,7 @@ declare class XDatepicker extends Base {
|
|
|
51
51
|
declare global {
|
|
52
52
|
interface HTMLElementTagNameMap {
|
|
53
53
|
'x-datepicker': XDatepicker;
|
|
54
|
+
'ten-protons-datepicker': XDatepicker;
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
|
package/dist/wc.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {a as a$1}from'./chunk-MTBE7EMZ.js';import'./chunk-CUGUCENC.js';import'./chunk-Q2P4Y4T6.js';import'./chunk-BHROFXOE.js';import'./chunk-ANB32WKT.js';var
|
|
1
|
+
import {a as a$1}from'./chunk-MTBE7EMZ.js';import'./chunk-CUGUCENC.js';import'./chunk-Q2P4Y4T6.js';import'./chunk-BHROFXOE.js';import'./chunk-ANB32WKT.js';var l=`.tp-dp,:host{
|
|
2
2
|
--tp-bg:#fff;--tp-fg:#1f2328;--tp-muted:#656d76;--tp-border:#d0d7de;--tp-hover:#eef1f4;
|
|
3
3
|
--tp-accent:#2563eb;--tp-accent-fg:#fff;--tp-range:#dbe7fd;--tp-focus:#2563eb;
|
|
4
4
|
--tp-radius:.5rem;--tp-cell:2.25rem;--tp-pad:.75rem;--tp-z:1000;
|
|
5
|
-
--tp-shadow:0 8px 24px rgba(0,0,0,.15)
|
|
5
|
+
--tp-shadow:0 8px 24px rgba(0,0,0,.15)
|
|
6
|
+
}
|
|
7
|
+
.tp-dp{
|
|
6
8
|
position:relative;box-sizing:border-box;width:max-content;max-width:calc(100vw - 1rem);padding:var(--tp-pad);
|
|
7
9
|
background:var(--tp-bg);color:var(--tp-fg);border:1px solid var(--tp-border);border-radius:var(--tp-radius);
|
|
8
10
|
font:.875rem/1.4 var(--tp-font,inherit)
|
|
@@ -60,15 +62,15 @@ import {a as a$1}from'./chunk-MTBE7EMZ.js';import'./chunk-CUGUCENC.js';import'./
|
|
|
60
62
|
@media (forced-colors:active){
|
|
61
63
|
.tp-selected{forced-color-adjust:none;background:Highlight;color:HighlightText}
|
|
62
64
|
}
|
|
63
|
-
`;var
|
|
64
|
-
.tp-dp[data-theme=dark]{
|
|
65
|
+
`;var c=`/* Dark follows prefers-color-scheme unless data-theme="light"; data-theme="dark" forces it. */
|
|
66
|
+
.tp-dp[data-theme=dark],:host([theme=dark]){
|
|
65
67
|
--tp-bg:#161b22;--tp-fg:#e6edf3;--tp-muted:#8d96a0;--tp-border:#30363d;--tp-hover:#21262d;
|
|
66
68
|
--tp-accent:#4c8dff;--tp-accent-fg:#0b1220;--tp-range:#1b2f52;--tp-focus:#79a8ff;--tp-shadow:0 8px 24px rgba(0,0,0,.5)
|
|
67
69
|
}
|
|
68
70
|
@media (prefers-color-scheme:dark){
|
|
69
|
-
.tp-dp:not([data-theme=light]){
|
|
71
|
+
.tp-dp:not([data-theme=light]),:host(:not([theme=light])){
|
|
70
72
|
--tp-bg:#161b22;--tp-fg:#e6edf3;--tp-muted:#8d96a0;--tp-border:#30363d;--tp-hover:#21262d;
|
|
71
73
|
--tp-accent:#4c8dff;--tp-accent-fg:#0b1220;--tp-range:#1b2f52;--tp-focus:#79a8ff;--tp-shadow:0 8px 24px rgba(0,0,0,.5)
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
|
-
`;var
|
|
76
|
+
`;var v={range:()=>import('./range.js'),multiple:()=>import('./multiple.js')},k=()=>import('./time.js'),o=e=>e??void 0,u=e=>e===null?void 0:Number(e),a=e=>e===null?void 0:e!=="false",w=e=>e===null?void 0:e.split(",").map(Number),h=e=>e.split(/\s*[/,;]\s*/).filter(Boolean),g={mode:["mode",o],locale:["locale",o],min:["minDate",o],max:["maxDate",o],"date-format":["dateFormat",o],"first-day":["firstDayOfWeek",u],position:["position",o],theme:["theme",o],"number-of-months":["numberOfMonths",u],"show-other-months":["showOtherMonths",a],"allow-input":["allowInput",a],"close-on-select":["closeOnSelect",a],"disabled-days":["disabledDaysOfWeek",w],"output-timestamp":["outputTimestamp",a],"enable-time":["enableTime",a],"value-in-utc":["valueInUtc",a],inline:["inline",a]},y=["change","open","close","monthChange","yearChange"],x='<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M8 3v4M16 3v4M3 10h18"/></svg>',E=":host{display:inline-block}:host([hidden]){display:none}.wrap{position:relative;display:flex;align-items:center}input{box-sizing:border-box;width:100%;padding:.5rem .75rem;padding-inline-start:2.25rem;font:inherit;color:var(--tp-fg);background:var(--tp-bg);border:1px solid var(--tp-border);border-radius:var(--tp-radius)}input:disabled{opacity:.6}input[aria-invalid=true]{border-color:#d1242f}.toggle{position:absolute;inset-inline-start:.25rem;display:grid;place-items:center;width:1.75rem;height:1.75rem;padding:0;border:0;border-radius:.25rem;background:none;color:var(--tp-fg);cursor:pointer}.toggle:disabled{opacity:.4;cursor:default}:host([inline]) .toggle{display:none}",D=typeof HTMLElement>"u"?class{}:HTMLElement,n=class extends D{constructor(){super();this.ready=Promise.resolve(null);this.picker=null;this.extra={};this.gen=0;this.internals=this.attachInternals?.();let t=this.root=this.attachShadow({mode:"open",delegatesFocus:true});t.innerHTML=`<style>${l}${c}${E}</style><div class="wrap" part="wrap"><input part="input"><button type="button" class="toggle" part="toggle" aria-haspopup="dialog">${x}</button></div>`,this.wrap=t.querySelector(".wrap"),this.input=t.querySelector("input"),this.toggleBtn=t.querySelector("button"),this.iso=document.createElement("input"),this.toggleBtn.addEventListener("click",()=>this.picker?.toggle());}get value(){return this.iso.value}set value(t){this.setAttribute("value",t);}set options(t){this.extra={...this.extra,...t},this.apply();}open(){this.picker?.open();}close(){this.picker?.close();}toggle(){this.picker?.toggle();}connectedCallback(){this.ready=this.init();}disconnectedCallback(){this.teardown();}attributeChangedCallback(t,i,r){if(t==="placeholder")this.input.placeholder=r??"";else if(t==="label")r===null?this.input.removeAttribute("aria-label"):this.input.setAttribute("aria-label",r);else if(t==="disabled")this.setDisabled(r!==null);else if(this.picker)t==="value"?this.setValue(r):t==="inline"?(this.teardown(),this.ready=this.init()):this.apply();else return}formResetCallback(){this.setValue(this.getAttribute("value"));}formDisabledCallback(t){this.setDisabled(t);}opts(){let t={};for(let[i,[r,s]]of Object.entries(g))t[r]=s(this.getAttribute(i));return {...t,...this.extra}}async load({mode:t,enableTime:i}){await Promise.all([t&&v[t]?.(),i&&k()]);}async init(){if(this.picker)return this.picker;let t=++this.gen;if(await this.load(this.opts()),t!==this.gen||!this.isConnected)return null;let i=this.getAttribute("value"),r=this.picker=new a$1(this.input,{...this.opts(),showIcon:false,selected:i?h(i):null,isoInput:this.iso,anchor:this.wrap,appendTo:this.root});for(let s of y)r.addEventListener(s,b=>{s==="change"&&this.syncForm(),this.dispatchEvent(new CustomEvent(s,{detail:b.detail,bubbles:true,composed:true}));});return this.toggleBtn.setAttribute("aria-label",r.strings.label),this.setDisabled(this.hasAttribute("disabled")),this.syncForm(),r}teardown(){this.gen++,this.picker?.destroy(),this.picker=null;}async apply(){let t=this.opts();await this.load(t),this.picker&&(this.picker.setOptions(t),this.syncForm(),this.toggleBtn.setAttribute("aria-label",this.picker.strings.label));}setValue(t){this.picker?.setDate(t?h(t):[]),this.syncForm();}setDisabled(t){this.input.disabled=this.toggleBtn.disabled=t,t&&this.picker?.close();}syncForm(){this.internals?.setFormValue?.(this.iso.value||null);}};n.formAssociated=true,n.observedAttributes=[...Object.keys(g),"value","placeholder","label","disabled"];var M={"ten-protons-datepicker":class extends n{},"x-datepicker":n};if(typeof customElements<"u")for(let[e,p]of Object.entries(M))customElements.get(e)||customElements.define(e,p);export{n as XDatepicker};
|