@nepdatejs/vanilla 0.0.0-stage → 0.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/LICENSE +21 -0
- package/README.md +124 -2
- package/dist/auto-define.cjs +11 -0
- package/dist/auto-define.cjs.map +1 -0
- package/dist/auto-define.d.cts +2 -0
- package/dist/auto-define.d.ts +2 -0
- package/dist/auto-define.js +9 -0
- package/dist/auto-define.js.map +1 -0
- package/dist/calendar-BAcO-jYq.js +142 -0
- package/dist/calendar-BAcO-jYq.js.map +1 -0
- package/dist/calendar-BNdN8qJv.d.ts +87 -0
- package/dist/calendar-C1LZI7XN.cjs +159 -0
- package/dist/calendar-C1LZI7XN.cjs.map +1 -0
- package/dist/calendar-QWPX0IfD.d.cts +87 -0
- package/dist/calendar.cjs +7 -0
- package/dist/calendar.d.cts +2 -0
- package/dist/calendar.d.ts +2 -0
- package/dist/calendar.js +3 -0
- package/dist/date-picker-BidCGOz0.d.cts +74 -0
- package/dist/date-picker-BwlrlU5Y.js +560 -0
- package/dist/date-picker-BwlrlU5Y.js.map +1 -0
- package/dist/date-picker-CgjYsf1w.cjs +583 -0
- package/dist/date-picker-CgjYsf1w.cjs.map +1 -0
- package/dist/date-picker-DyvpYe29.d.ts +74 -0
- package/dist/date-picker.cjs +6 -0
- package/dist/date-picker.d.cts +3 -0
- package/dist/date-picker.d.ts +3 -0
- package/dist/date-picker.js +1 -0
- package/dist/date-range-picker-D3eNvlgv.d.ts +98 -0
- package/dist/date-range-picker-NwetXUC-.js +449 -0
- package/dist/date-range-picker-NwetXUC-.js.map +1 -0
- package/dist/date-range-picker-SIl0vhUV.d.cts +98 -0
- package/dist/date-range-picker-VrQZFZED.cjs +472 -0
- package/dist/date-range-picker-VrQZFZED.cjs.map +1 -0
- package/dist/date-range-picker.cjs +6 -0
- package/dist/date-range-picker.d.cts +2 -0
- package/dist/date-range-picker.d.ts +2 -0
- package/dist/date-range-picker.js +1 -0
- package/dist/date-time-picker-BzSyQxrf.d.cts +92 -0
- package/dist/date-time-picker-ChHIBTBw.cjs +492 -0
- package/dist/date-time-picker-ChHIBTBw.cjs.map +1 -0
- package/dist/date-time-picker-CxqC95aM.js +469 -0
- package/dist/date-time-picker-CxqC95aM.js.map +1 -0
- package/dist/date-time-picker-DzDpzLMZ.d.ts +92 -0
- package/dist/date-time-picker.cjs +6 -0
- package/dist/date-time-picker.d.cts +2 -0
- package/dist/date-time-picker.d.ts +2 -0
- package/dist/date-time-picker.js +1 -0
- package/dist/define-B8NUA3yj.d.cts +16 -0
- package/dist/define-B8NUA3yj.d.ts +16 -0
- package/dist/define-BbTIFHtH.cjs +23 -0
- package/dist/define-BbTIFHtH.cjs.map +1 -0
- package/dist/define-D96w8Zu2.js +18 -0
- package/dist/define-D96w8Zu2.js.map +1 -0
- package/dist/element-utils-BVye8UQq.d.cts +82 -0
- package/dist/element-utils-C-r5gPlk.d.ts +82 -0
- package/dist/index.cjs +30 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/multi-date-picker-B2mQbjZM.d.ts +105 -0
- package/dist/multi-date-picker-BUNf5zyJ.d.cts +105 -0
- package/dist/multi-date-picker-C3Lr0Dq-.js +424 -0
- package/dist/multi-date-picker-C3Lr0Dq-.js.map +1 -0
- package/dist/multi-date-picker-DUyuO-nH.cjs +447 -0
- package/dist/multi-date-picker-DUyuO-nH.cjs.map +1 -0
- package/dist/multi-date-picker.cjs +6 -0
- package/dist/multi-date-picker.d.cts +2 -0
- package/dist/multi-date-picker.d.ts +2 -0
- package/dist/multi-date-picker.js +1 -0
- package/dist/nepdate-picker.global.js +3 -0
- package/dist/nepdate-picker.global.js.map +1 -0
- package/dist/preset-list-BYCZm61I.cjs +97 -0
- package/dist/preset-list-BYCZm61I.cjs.map +1 -0
- package/dist/preset-list-DmE6fJjr.js +80 -0
- package/dist/preset-list-DmE6fJjr.js.map +1 -0
- package/dist/registry-3qzdVB7H.cjs +591 -0
- package/dist/registry-3qzdVB7H.cjs.map +1 -0
- package/dist/registry-BvkGnkvV.js +466 -0
- package/dist/registry-BvkGnkvV.js.map +1 -0
- package/package.json +162 -3
- package/src/auto-define.ts +6 -0
- package/src/calendar-element.ts +129 -0
- package/src/calendar-view.ts +406 -0
- package/src/calendar.ts +45 -0
- package/src/date-picker-element.ts +249 -0
- package/src/date-picker.ts +91 -0
- package/src/date-range-picker-element.ts +201 -0
- package/src/date-range-picker.ts +20 -0
- package/src/date-time-picker-element.ts +191 -0
- package/src/date-time-picker.ts +20 -0
- package/src/datetime-view.ts +434 -0
- package/src/define.ts +16 -0
- package/src/dom.ts +109 -0
- package/src/element-utils.ts +86 -0
- package/src/global.ts +7 -0
- package/src/index.ts +15 -0
- package/src/multi-date-picker-element.ts +187 -0
- package/src/multi-date-picker.ts +53 -0
- package/src/multi-view.ts +323 -0
- package/src/panel.ts +61 -0
- package/src/picker-view.ts +423 -0
- package/src/preset-list.ts +51 -0
- package/src/range-view.ts +368 -0
- package/src/registry.ts +27 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/** `@nepdatejs/vanilla/date-picker`: just the date picker (element, view and mount function). */
|
|
2
|
+
import type { DatePickerState } from '@nepdatejs/datepicker';
|
|
3
|
+
import { NepDatePickerElement } from './date-picker-element';
|
|
4
|
+
import { DatePickerView, type DatePickerViewOptions } from './picker-view';
|
|
5
|
+
import { defineElement, ELEMENT_NAMES } from './registry';
|
|
6
|
+
|
|
7
|
+
export { NepDatePickerElement };
|
|
8
|
+
export { DatePickerView, type DatePickerViewOptions, type Theme } from './picker-view';
|
|
9
|
+
|
|
10
|
+
/** Register <nep-date-picker> (skipped if already defined). */
|
|
11
|
+
export function defineDatePicker(registry?: CustomElementRegistry): void {
|
|
12
|
+
defineElement(ELEMENT_NAMES.datePicker, NepDatePickerElement, registry);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface DatePickerHandle {
|
|
16
|
+
readonly view: DatePickerView;
|
|
17
|
+
getValue(): string;
|
|
18
|
+
getState(): DatePickerState;
|
|
19
|
+
setValue(value: string): void;
|
|
20
|
+
setOptions(changes: Partial<DatePickerViewOptions>): void;
|
|
21
|
+
open(): void;
|
|
22
|
+
close(): void;
|
|
23
|
+
destroy(): void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Mount a date picker without custom elements.
|
|
28
|
+
*
|
|
29
|
+
* - Given a container, renders the field into it.
|
|
30
|
+
* - Given an <input>, hides it and keeps its value in step with the picker
|
|
31
|
+
* (AD "YYYY-MM-DD"), so existing forms and server code keep working.
|
|
32
|
+
*/
|
|
33
|
+
export function createDatePicker(
|
|
34
|
+
target: HTMLElement,
|
|
35
|
+
options: DatePickerViewOptions = {},
|
|
36
|
+
): DatePickerHandle {
|
|
37
|
+
const enhanced = target instanceof HTMLInputElement ? target : null;
|
|
38
|
+
let host = target;
|
|
39
|
+
if (enhanced) {
|
|
40
|
+
host = document.createElement('span');
|
|
41
|
+
enhanced.after(host);
|
|
42
|
+
enhanced.hidden = true;
|
|
43
|
+
}
|
|
44
|
+
const view = new DatePickerView(host, {
|
|
45
|
+
...(enhanced
|
|
46
|
+
? {
|
|
47
|
+
defaultValue: enhanced.value,
|
|
48
|
+
name: undefined,
|
|
49
|
+
required: enhanced.required,
|
|
50
|
+
disabled: enhanced.disabled,
|
|
51
|
+
}
|
|
52
|
+
: {}),
|
|
53
|
+
...options,
|
|
54
|
+
onChange: (value, detail) => {
|
|
55
|
+
if (enhanced) {
|
|
56
|
+
enhanced.value = value;
|
|
57
|
+
enhanced.dispatchEvent(new Event('input', { bubbles: true }));
|
|
58
|
+
enhanced.dispatchEvent(new Event('change', { bubbles: true }));
|
|
59
|
+
}
|
|
60
|
+
options.onChange?.(value, detail);
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
view,
|
|
66
|
+
getValue: () => view.getState().value,
|
|
67
|
+
getState: () => view.getState(),
|
|
68
|
+
setValue: (value) => {
|
|
69
|
+
view.store.actions.setValue(value);
|
|
70
|
+
if (enhanced) {
|
|
71
|
+
enhanced.value = view.getState().value;
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
setOptions: (changes) => {
|
|
75
|
+
view.setOptions(changes);
|
|
76
|
+
},
|
|
77
|
+
open: () => {
|
|
78
|
+
view.open();
|
|
79
|
+
},
|
|
80
|
+
close: () => {
|
|
81
|
+
view.close();
|
|
82
|
+
},
|
|
83
|
+
destroy: () => {
|
|
84
|
+
view.destroy();
|
|
85
|
+
if (enhanced) {
|
|
86
|
+
host.remove();
|
|
87
|
+
enhanced.hidden = false;
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import type { RangePreset } from '@nepdatejs/datepicker';
|
|
2
|
+
import { DateRangePickerView, type DateRangePickerViewOptions } from './range-view';
|
|
3
|
+
import {
|
|
4
|
+
Base,
|
|
5
|
+
str,
|
|
6
|
+
bool,
|
|
7
|
+
calendarAttr,
|
|
8
|
+
int,
|
|
9
|
+
onUnlessFalse,
|
|
10
|
+
panelLayout,
|
|
11
|
+
theme,
|
|
12
|
+
presetIds,
|
|
13
|
+
swallowInnerChange,
|
|
14
|
+
type RichProps,
|
|
15
|
+
} from './element-utils';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* <nep-date-range-picker name="leave" min-days="1"></nep-date-range-picker>
|
|
19
|
+
*
|
|
20
|
+
* Two BS/AD fields sharing one panel. The form receives `${name}-start` and
|
|
21
|
+
* `${name}-end` (or `start-name` / `end-name`). Fires `change` with { value }.
|
|
22
|
+
*/
|
|
23
|
+
export class NepDateRangePickerElement extends Base {
|
|
24
|
+
static readonly formAssociated = true;
|
|
25
|
+
static readonly observedAttributes: readonly string[] = [
|
|
26
|
+
'start',
|
|
27
|
+
'end',
|
|
28
|
+
'name',
|
|
29
|
+
'start-name',
|
|
30
|
+
'end-name',
|
|
31
|
+
'min',
|
|
32
|
+
'max',
|
|
33
|
+
'calendar',
|
|
34
|
+
'default-calendar',
|
|
35
|
+
'locale',
|
|
36
|
+
'min-days',
|
|
37
|
+
'max-days',
|
|
38
|
+
'disabled',
|
|
39
|
+
'required',
|
|
40
|
+
'theme',
|
|
41
|
+
'panel-layout',
|
|
42
|
+
'mask',
|
|
43
|
+
'inline',
|
|
44
|
+
'start-label',
|
|
45
|
+
'end-label',
|
|
46
|
+
'presets',
|
|
47
|
+
'fiscal-years',
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
view: DateRangePickerView | null = null;
|
|
51
|
+
private readonly internals: ElementInternals | null;
|
|
52
|
+
private rich: RichProps = {};
|
|
53
|
+
private customPresets: readonly RangePreset[] | undefined;
|
|
54
|
+
private unsubscribe: (() => void) | null = null;
|
|
55
|
+
|
|
56
|
+
constructor() {
|
|
57
|
+
super();
|
|
58
|
+
this.internals =
|
|
59
|
+
typeof this.attachInternals === 'function' ? this.attachInternals() : null;
|
|
60
|
+
swallowInnerChange(this);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get value(): { start: string; end: string } {
|
|
64
|
+
return this.view?.getState().value ?? { start: '', end: '' };
|
|
65
|
+
}
|
|
66
|
+
set value(next: { start: string; end: string }) {
|
|
67
|
+
this.view?.store.actions.setValue(next);
|
|
68
|
+
}
|
|
69
|
+
set holidays(next: RichProps['holidays']) {
|
|
70
|
+
this.rich = { ...this.rich, holidays: next };
|
|
71
|
+
this.view?.setOptions({ holidays: next });
|
|
72
|
+
}
|
|
73
|
+
set isDateDisabled(next: RichProps['isDateDisabled']) {
|
|
74
|
+
this.rich = { ...this.rich, isDateDisabled: next };
|
|
75
|
+
this.view?.setOptions({ isDateDisabled: next });
|
|
76
|
+
}
|
|
77
|
+
/** Shortcuts, including custom { id, label, resolve } ones. Overrides the presets attribute. */
|
|
78
|
+
get presets(): readonly RangePreset[] | undefined {
|
|
79
|
+
return this.customPresets ?? (presetIds(this) as readonly RangePreset[] | undefined);
|
|
80
|
+
}
|
|
81
|
+
set presets(next: readonly RangePreset[] | undefined) {
|
|
82
|
+
this.customPresets = next;
|
|
83
|
+
this.view?.setOptions({ presets: this.presets });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
connectedCallback(): void {
|
|
87
|
+
if (this.view) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const view = new DateRangePickerView(this, {
|
|
91
|
+
...this.readOptions(),
|
|
92
|
+
defaultValue: { start: str(this, 'start') ?? '', end: str(this, 'end') ?? '' },
|
|
93
|
+
onChange: (value) => {
|
|
94
|
+
this.dispatchEvent(
|
|
95
|
+
new CustomEvent('change', { bubbles: true, detail: { value } }),
|
|
96
|
+
);
|
|
97
|
+
},
|
|
98
|
+
onOpenChange: (open) => {
|
|
99
|
+
this.dispatchEvent(
|
|
100
|
+
new CustomEvent(open ? 'nep-open' : 'nep-close', { bubbles: true }),
|
|
101
|
+
);
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
this.view = view;
|
|
105
|
+
this.unsubscribe = view.store.subscribe(() => {
|
|
106
|
+
this.syncForm();
|
|
107
|
+
});
|
|
108
|
+
this.syncForm();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
disconnectedCallback(): void {
|
|
112
|
+
this.unsubscribe?.();
|
|
113
|
+
this.view?.destroy();
|
|
114
|
+
this.view = null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
attributeChangedCallback(): void {
|
|
118
|
+
this.view?.setOptions(this.readOptions());
|
|
119
|
+
this.syncForm();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
formResetCallback(): void {
|
|
123
|
+
this.view?.store.actions.reset();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
formDisabledCallback(disabled: boolean): void {
|
|
127
|
+
this.view?.setOptions({ disabled: disabled || bool(this, 'disabled') });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private names(): { start: string | undefined; end: string | undefined } {
|
|
131
|
+
const name = str(this, 'name');
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
start: str(this, 'start-name') ?? (name ? `${name}-start` : undefined),
|
|
135
|
+
end: str(this, 'end-name') ?? (name ? `${name}-end` : undefined),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private readOptions(): DateRangePickerViewOptions {
|
|
140
|
+
const names = this.names();
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
...this.rich,
|
|
144
|
+
startName: names.start,
|
|
145
|
+
endName: names.end,
|
|
146
|
+
hiddenInput: this.internals === null,
|
|
147
|
+
min: str(this, 'min'),
|
|
148
|
+
max: str(this, 'max'),
|
|
149
|
+
calendar: calendarAttr(this, 'calendar'),
|
|
150
|
+
defaultCalendar: calendarAttr(this, 'default-calendar'),
|
|
151
|
+
locale: str(this, 'locale'),
|
|
152
|
+
minDays: int(this, 'min-days'),
|
|
153
|
+
maxDays: int(this, 'max-days'),
|
|
154
|
+
disabled: bool(this, 'disabled'),
|
|
155
|
+
required: bool(this, 'required'),
|
|
156
|
+
theme: theme(this),
|
|
157
|
+
panelLayout: panelLayout(this),
|
|
158
|
+
mask: onUnlessFalse(this, 'mask'),
|
|
159
|
+
inline: this.hasAttribute('inline'),
|
|
160
|
+
startLabel: str(this, 'start-label'),
|
|
161
|
+
endLabel: str(this, 'end-label'),
|
|
162
|
+
fiscalYearView: bool(this, 'fiscal-years'),
|
|
163
|
+
presets: this.presets,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private syncForm(): void {
|
|
168
|
+
const view = this.view;
|
|
169
|
+
if (!view || !this.internals) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const state = view.getState();
|
|
173
|
+
const names = this.names();
|
|
174
|
+
const data = new FormData();
|
|
175
|
+
if (names.start && state.value.start) {
|
|
176
|
+
data.append(names.start, state.value.start);
|
|
177
|
+
}
|
|
178
|
+
if (names.end && state.value.end) {
|
|
179
|
+
data.append(names.end, state.value.end);
|
|
180
|
+
}
|
|
181
|
+
this.internals.setFormValue(data);
|
|
182
|
+
if (state.error) {
|
|
183
|
+
this.internals.setValidity(
|
|
184
|
+
{ customError: true },
|
|
185
|
+
state.error.message,
|
|
186
|
+
view.inputs.start,
|
|
187
|
+
);
|
|
188
|
+
} else if (
|
|
189
|
+
bool(this, 'required') &&
|
|
190
|
+
(state.value.start === '' || state.value.end === '')
|
|
191
|
+
) {
|
|
192
|
+
this.internals.setValidity(
|
|
193
|
+
{ valueMissing: true },
|
|
194
|
+
'Please choose a start and end date.',
|
|
195
|
+
view.inputs.start,
|
|
196
|
+
);
|
|
197
|
+
} else {
|
|
198
|
+
this.internals.setValidity({});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** `@nepdatejs/vanilla/date-range-picker`: just the range picker. */
|
|
2
|
+
import { NepDateRangePickerElement } from './date-range-picker-element';
|
|
3
|
+
import { DateRangePickerView, type DateRangePickerViewOptions } from './range-view';
|
|
4
|
+
import { defineElement, ELEMENT_NAMES } from './registry';
|
|
5
|
+
|
|
6
|
+
export { NepDateRangePickerElement };
|
|
7
|
+
export { DateRangePickerView, type DateRangePickerViewOptions } from './range-view';
|
|
8
|
+
|
|
9
|
+
/** Register <nep-date-range-picker> (skipped if already defined). */
|
|
10
|
+
export function defineDateRangePicker(registry?: CustomElementRegistry): void {
|
|
11
|
+
defineElement(ELEMENT_NAMES.dateRangePicker, NepDateRangePickerElement, registry);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Mount a date range picker into a container. */
|
|
15
|
+
export function createDateRangePicker(
|
|
16
|
+
container: HTMLElement,
|
|
17
|
+
options: DateRangePickerViewOptions = {},
|
|
18
|
+
): DateRangePickerView {
|
|
19
|
+
return new DateRangePickerView(container, options);
|
|
20
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import type { SinglePreset } from '@nepdatejs/datepicker';
|
|
2
|
+
import { DateTimePickerView, type DateTimePickerViewOptions } from './datetime-view';
|
|
3
|
+
import {
|
|
4
|
+
Base,
|
|
5
|
+
str,
|
|
6
|
+
bool,
|
|
7
|
+
calendarAttr,
|
|
8
|
+
int,
|
|
9
|
+
onUnlessFalse,
|
|
10
|
+
panelLayout,
|
|
11
|
+
theme,
|
|
12
|
+
presetIds,
|
|
13
|
+
swallowInnerChange,
|
|
14
|
+
type RichProps,
|
|
15
|
+
} from './element-utils';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* <nep-date-time-picker name="starts-at" minute-step="15"></nep-date-time-picker>
|
|
19
|
+
*
|
|
20
|
+
* A form-associated BS/AD date + time field. The form receives one instant as
|
|
21
|
+
* an ISO timestamp with the zone's offset ("2026-10-18T14:30:00+05:45").
|
|
22
|
+
* Fires `change` with { value, ad, bs, time }.
|
|
23
|
+
*/
|
|
24
|
+
export class NepDateTimePickerElement extends Base {
|
|
25
|
+
static readonly formAssociated = true;
|
|
26
|
+
static readonly observedAttributes: readonly string[] = [
|
|
27
|
+
'value',
|
|
28
|
+
'min',
|
|
29
|
+
'max',
|
|
30
|
+
'calendar',
|
|
31
|
+
'default-calendar',
|
|
32
|
+
'locale',
|
|
33
|
+
'name',
|
|
34
|
+
'required',
|
|
35
|
+
'disabled',
|
|
36
|
+
'theme',
|
|
37
|
+
'panel-layout',
|
|
38
|
+
'mask',
|
|
39
|
+
'inline',
|
|
40
|
+
'time-zone',
|
|
41
|
+
'hour12',
|
|
42
|
+
'minute-step',
|
|
43
|
+
'default-time',
|
|
44
|
+
'label',
|
|
45
|
+
'time-label',
|
|
46
|
+
'presets',
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
view: DateTimePickerView | null = null;
|
|
50
|
+
private readonly internals: ElementInternals | null;
|
|
51
|
+
private rich: RichProps = {};
|
|
52
|
+
private unsubscribe: (() => void) | null = null;
|
|
53
|
+
|
|
54
|
+
constructor() {
|
|
55
|
+
super();
|
|
56
|
+
this.internals =
|
|
57
|
+
typeof this.attachInternals === 'function' ? this.attachInternals() : null;
|
|
58
|
+
swallowInnerChange(this);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get value(): string {
|
|
62
|
+
return this.view?.getState().value ?? '';
|
|
63
|
+
}
|
|
64
|
+
set value(next: string) {
|
|
65
|
+
this.view?.store.actions.setValue(next);
|
|
66
|
+
}
|
|
67
|
+
set holidays(next: RichProps['holidays']) {
|
|
68
|
+
this.rich = { ...this.rich, holidays: next };
|
|
69
|
+
this.view?.setOptions({ holidays: next });
|
|
70
|
+
}
|
|
71
|
+
set isDateDisabled(next: RichProps['isDateDisabled']) {
|
|
72
|
+
this.rich = { ...this.rich, isDateDisabled: next };
|
|
73
|
+
this.view?.setOptions({ isDateDisabled: next });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
connectedCallback(): void {
|
|
77
|
+
if (this.view) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const view = new DateTimePickerView(this, {
|
|
81
|
+
...this.readOptions(),
|
|
82
|
+
defaultValue: str(this, 'value'),
|
|
83
|
+
onChange: (value, detail) => {
|
|
84
|
+
this.dispatchEvent(
|
|
85
|
+
new CustomEvent('change', {
|
|
86
|
+
bubbles: true,
|
|
87
|
+
detail: {
|
|
88
|
+
value,
|
|
89
|
+
ad: detail?.ad ?? null,
|
|
90
|
+
bs: detail?.bs ?? null,
|
|
91
|
+
time: detail?.time ?? null,
|
|
92
|
+
},
|
|
93
|
+
}),
|
|
94
|
+
);
|
|
95
|
+
},
|
|
96
|
+
onOpenChange: (open) => {
|
|
97
|
+
this.dispatchEvent(
|
|
98
|
+
new CustomEvent(open ? 'nep-open' : 'nep-close', { bubbles: true }),
|
|
99
|
+
);
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
this.view = view;
|
|
103
|
+
this.unsubscribe = view.store.subscribe(() => {
|
|
104
|
+
this.syncForm();
|
|
105
|
+
});
|
|
106
|
+
this.syncForm();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
disconnectedCallback(): void {
|
|
110
|
+
this.unsubscribe?.();
|
|
111
|
+
this.view?.destroy();
|
|
112
|
+
this.view = null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
attributeChangedCallback(
|
|
116
|
+
name: string,
|
|
117
|
+
previous: string | null,
|
|
118
|
+
next: string | null,
|
|
119
|
+
): void {
|
|
120
|
+
if (!this.view || previous === next) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (name === 'value') {
|
|
124
|
+
this.view.store.actions.setValue(next ?? '');
|
|
125
|
+
}
|
|
126
|
+
this.view.setOptions(this.readOptions());
|
|
127
|
+
this.syncForm();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
formResetCallback(): void {
|
|
131
|
+
this.view?.store.actions.reset();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
formDisabledCallback(disabled: boolean): void {
|
|
135
|
+
this.view?.setOptions({ disabled: disabled || bool(this, 'disabled') });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
override focus(options?: FocusOptions): void {
|
|
139
|
+
this.view?.dateInput.focus(options);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private readOptions(): DateTimePickerViewOptions {
|
|
143
|
+
return {
|
|
144
|
+
...this.rich,
|
|
145
|
+
min: str(this, 'min'),
|
|
146
|
+
max: str(this, 'max'),
|
|
147
|
+
calendar: calendarAttr(this, 'calendar'),
|
|
148
|
+
defaultCalendar: calendarAttr(this, 'default-calendar'),
|
|
149
|
+
locale: str(this, 'locale'),
|
|
150
|
+
name: str(this, 'name'),
|
|
151
|
+
hiddenInput: this.internals === null,
|
|
152
|
+
required: bool(this, 'required'),
|
|
153
|
+
disabled: bool(this, 'disabled'),
|
|
154
|
+
theme: theme(this),
|
|
155
|
+
panelLayout: panelLayout(this),
|
|
156
|
+
mask: onUnlessFalse(this, 'mask'),
|
|
157
|
+
inline: this.hasAttribute('inline'),
|
|
158
|
+
timeZone: str(this, 'time-zone'),
|
|
159
|
+
hour12: bool(this, 'hour12'),
|
|
160
|
+
minuteStep: int(this, 'minute-step'),
|
|
161
|
+
defaultTime: str(this, 'default-time'),
|
|
162
|
+
ariaLabel: str(this, 'label'),
|
|
163
|
+
timeLabel: str(this, 'time-label'),
|
|
164
|
+
presets: presetIds(this) as readonly SinglePreset[] | undefined,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private syncForm(): void {
|
|
169
|
+
const view = this.view;
|
|
170
|
+
if (!view || !this.internals) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const state = view.getState();
|
|
174
|
+
this.internals.setFormValue(state.value === '' ? null : state.value);
|
|
175
|
+
if (state.error) {
|
|
176
|
+
this.internals.setValidity(
|
|
177
|
+
{ customError: true },
|
|
178
|
+
state.error.message,
|
|
179
|
+
state.error.field === 'time' ? view.timeInput : view.dateInput,
|
|
180
|
+
);
|
|
181
|
+
} else if (bool(this, 'required') && state.value === '') {
|
|
182
|
+
this.internals.setValidity(
|
|
183
|
+
{ valueMissing: true },
|
|
184
|
+
'Please choose a date and time.',
|
|
185
|
+
view.dateInput,
|
|
186
|
+
);
|
|
187
|
+
} else {
|
|
188
|
+
this.internals.setValidity({});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** `@nepdatejs/vanilla/date-time-picker`: just the date + time picker. */
|
|
2
|
+
import { NepDateTimePickerElement } from './date-time-picker-element';
|
|
3
|
+
import { DateTimePickerView, type DateTimePickerViewOptions } from './datetime-view';
|
|
4
|
+
import { defineElement, ELEMENT_NAMES } from './registry';
|
|
5
|
+
|
|
6
|
+
export { NepDateTimePickerElement };
|
|
7
|
+
export { DateTimePickerView, type DateTimePickerViewOptions } from './datetime-view';
|
|
8
|
+
|
|
9
|
+
/** Register <nep-date-time-picker> (skipped if already defined). */
|
|
10
|
+
export function defineDateTimePicker(registry?: CustomElementRegistry): void {
|
|
11
|
+
defineElement(ELEMENT_NAMES.dateTimePicker, NepDateTimePickerElement, registry);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Mount a date + time picker into a container. */
|
|
15
|
+
export function createDateTimePicker(
|
|
16
|
+
container: HTMLElement,
|
|
17
|
+
options: DateTimePickerViewOptions = {},
|
|
18
|
+
): DateTimePickerView {
|
|
19
|
+
return new DateTimePickerView(container, options);
|
|
20
|
+
}
|