imx-select-datepicker 0.0.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 ADDED
@@ -0,0 +1,64 @@
1
+ # imx-select-datepicker - InputGroup
2
+
3
+ A component for managing date inputs with separate controls for day and month.
4
+
5
+ ## Constructor
6
+
7
+ ```javascript
8
+ const inputGroup = new InputGroup(startDate, endDate);
9
+ ```
10
+
11
+ **Parameters:**
12
+ - `startDate` (Date, optional) - The start date for the possible select options. Defaults to the current date minus 1 year.
13
+ - `endDate` (Date, optional) - The end date for the possible select options. Defaults to the current date plus 1 year.
14
+
15
+ ## Usage as single date picker
16
+
17
+ ```javascript
18
+ const inputGroup = new InputGroup();
19
+ inputDate.appendChild(inputGroup.markup);
20
+
21
+ inputGroup.update(new Date('2026-01-01'));
22
+ ```
23
+
24
+ ## Usage as range date picker
25
+
26
+ ```javascript
27
+ const inputGroupFrom = new InputGroup();
28
+ inputDate.appendChild(inputGroupFrom.markup);
29
+
30
+ const inputGroupTo = new InputGroup();
31
+ inputDate.appendChild(inputGroupTo.markup);
32
+
33
+ inputGroupFrom.update(new Date('2026-01-01'));
34
+ inputGroupTo.update(new Date('2026-12-31'));
35
+ ```
36
+
37
+ ## Properties
38
+
39
+ - **`markup`** - The DOM element of the component that can be inserted into the document
40
+ - **`daySelect.select`** - Select element for day selection, to register a change listener.
41
+ - **`monthSelect.select`** - Select element for month selection, to register a change listener.
42
+
43
+ ## Methods
44
+
45
+ ### `update(date)`
46
+ Updates the input fields with a new date.
47
+
48
+ **Parameters:**
49
+ - `date` (Date) - The new date
50
+
51
+ ### `setMinDate(date)`
52
+ Sets the minimum selectable date for the input fields.
53
+
54
+ **Parameters:**
55
+ - `date` (Date) - The minimum date
56
+
57
+ ## Events
58
+
59
+ ```javascript
60
+ inputGroupFrom.daySelect.select.addEventListener('change', (event) => {
61
+ const newDate = new Date(event.target.value);
62
+ console.log('New date:', newDate);
63
+ });
64
+ ```
package/index.js ADDED
@@ -0,0 +1 @@
1
+ export { InputGroup } from "./src/InputGroup/InputGroup.js";
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "imx-select-datepicker",
3
+ "version": "0.0.1",
4
+ "description": "A simple keyboard accessible select based datepicker",
5
+ "keywords": [
6
+ "accessibility",
7
+ "datepicker"
8
+ ],
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git@gitlab.infomax.dev:haunerdinger/imx-select-datepicker.git"
12
+ },
13
+ "license": "ISC",
14
+ "author": "Markus Haunerdinger",
15
+ "type": "module",
16
+ "main": "index.js",
17
+ "scripts": {
18
+ "test": "echo \"Error: no test specified\" && exit 1"
19
+ },
20
+ "dependencies": {
21
+ "dayjs": "^1.11.19"
22
+ }
23
+ }
@@ -0,0 +1,75 @@
1
+ import dayjs from 'dayjs';
2
+ import { OptionGroup } from './utils/OptionGroup.js';
3
+ import { DaySelect } from './utils/DaySelect.js';
4
+ import { DomHelper } from './utils/DomHelper.js';
5
+ import { DateHelper } from './utils/DateHelper.js';
6
+ import { MonthSelect } from './utils/MonthSelect.js';
7
+
8
+ export class InputGroup {
9
+
10
+ constructor(startDate = dayjs().subtract(1, 'y').toDate(), endDate = dayjs().add(1, 'y').toDate()) {
11
+ const startOfMonth = dayjs(startDate).startOf('month');
12
+ const endOfMonth = dayjs(endDate).endOf('month');
13
+
14
+ this.optionGroups = OptionGroup.createOptions(
15
+ DateHelper.range(startOfMonth, endOfMonth, 'month')
16
+ );
17
+
18
+ this.daySelect = new DaySelect();
19
+ this.monthSelect = new MonthSelect(this.optionGroups);
20
+
21
+ this.registerEventListeners(this.monthSelect);
22
+
23
+ this.markup = DomHelper.createMarkup(this.monthSelect.select, this.daySelect.select);
24
+ this.updateDayOptions(startDate);
25
+ };
26
+
27
+ setMinDate(jsDateObject) {
28
+ this.monthSelect.setMinDate(jsDateObject);
29
+ this.daySelect.setMinDate(jsDateObject);
30
+ }
31
+
32
+ getValue() {
33
+ return this.daySelect.select.value;
34
+ }
35
+
36
+ update(jsDateObject) {
37
+ if(dayjs(jsDateObject).isValid()) {
38
+ this.updateMonth(jsDateObject);
39
+ this.updateDayOptions(jsDateObject);
40
+ this.updateDay(jsDateObject);
41
+ } else {
42
+ console.warn('Update with invalid date:', jsDateObject);
43
+ }
44
+ }
45
+
46
+ updateDay(jsDateObject) {
47
+ const dayJsDate = dayjs(jsDateObject);
48
+ this.daySelect.setValue(dayJsDate);
49
+ }
50
+
51
+ updateMonth(jsDateObject) {
52
+ const dayJsDate = dayjs(jsDateObject);
53
+
54
+ const optionGroup = this.optionGroups.find((optionGroup) => {
55
+ return dayjs(optionGroup.index).isSame(dayJsDate, 'month');
56
+ });
57
+
58
+ if(optionGroup) {
59
+ this.monthSelect.setValue(optionGroup.index);
60
+ } else {
61
+ console.warn('No matching month option found for date:', jsDateObject);
62
+ }
63
+ }
64
+
65
+ updateDayOptions(jsDateObject) {
66
+ const dayJsDate = dayjs(jsDateObject)
67
+ this.daySelect.updateOptions(dayJsDate);
68
+ }
69
+
70
+ registerEventListeners(monthSelect) {
71
+ monthSelect.select.addEventListener('change', (event) => {
72
+ this.daySelect.updateOptions(dayjs(event.target.value));
73
+ });
74
+ }
75
+ }
@@ -0,0 +1,13 @@
1
+ export class DateHelper {
2
+ static range(start, end, interval){
3
+ let date = start;
4
+ const dateArray = [];
5
+
6
+ while(date.isBefore(end, interval) || date.isSame(end, interval)) {
7
+ dateArray.push(date)
8
+ date = date.add(1, interval);
9
+ }
10
+
11
+ return dateArray;
12
+ }
13
+ }
@@ -0,0 +1,64 @@
1
+ import dayjs from 'dayjs';
2
+ import { Select } from './Select.js';
3
+ import { OptionGroup } from './OptionGroup.js';
4
+
5
+ export class DaySelect {
6
+ constructor() {
7
+ this._select = Select.createDaySelect();
8
+ this._minDate = null;
9
+ }
10
+
11
+ get select() {
12
+ return this._select;
13
+ }
14
+
15
+ set select(node) {
16
+ this._select = node;
17
+ }
18
+
19
+ getOptions() {
20
+ return Array.from(this._select.options);
21
+ }
22
+
23
+ setValue(dayJsDate) {
24
+ this._select.value = dayJsDate.format('YYYY-MM-DD');
25
+ }
26
+
27
+ enableOptions() {
28
+ this.getOptions().forEach((option) => {
29
+ option.disabled = false;
30
+ });
31
+ }
32
+
33
+ setMinDate(jsDateObject) {
34
+ if(!jsDateObject) {
35
+ this._minDate = null;
36
+ } else {
37
+ this._minDate = dayjs(jsDateObject).format('YYYY-MM-DD');
38
+ }
39
+ this._evalMinDate();
40
+ }
41
+
42
+ _evalMinDate() {
43
+ if(!this._minDate) {
44
+ this.enableOptions();
45
+ } else {
46
+ const minDate = dayjs(this._minDate);
47
+
48
+ this.getOptions().forEach((option) => {
49
+ option.disabled = dayjs(option.value).isBefore(minDate, 'day');
50
+ });
51
+ }
52
+ }
53
+
54
+ updateOptions(dayJsDate) {
55
+ const dayOptions = OptionGroup.createDayOptions(dayJsDate);
56
+
57
+ if(dayOptions.length > 0) {
58
+ this._select.innerHTML = dayOptions.map((day) => day.outerHTML).join('');
59
+ this._evalMinDate();
60
+ } else {
61
+ console.warn('No options found for:', dayJsDate);
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,11 @@
1
+ export class DomHelper {
2
+ static createMarkup(daySelect, monthSelect) {
3
+ const wrapper = document.createElement("div");
4
+ wrapper.classList.add("inputGroup");
5
+
6
+ wrapper.appendChild(daySelect);
7
+ wrapper.appendChild(monthSelect);
8
+
9
+ return wrapper;
10
+ }
11
+ }
@@ -0,0 +1,42 @@
1
+ import dayjs from 'dayjs';
2
+ import { Select } from './Select.js';
3
+ import { OptionGroup } from './OptionGroup.js';
4
+
5
+ export class MonthSelect {
6
+ constructor(optionGroups) {
7
+ this._select = Select.createMonthSelect(OptionGroup.getMonthOptions(optionGroups))
8
+ }
9
+
10
+ get select() {
11
+ return this._select;
12
+ }
13
+
14
+ set select(node) {
15
+ this._select = node;
16
+ }
17
+
18
+ getOptions() {
19
+ return Array.from(this._select.options);
20
+ }
21
+
22
+ setValue(dateString) {
23
+ this._select.value = dateString;
24
+ }
25
+
26
+ enableOptions() {
27
+ this.getOptions().forEach((option) => {
28
+ option.disabled = false;
29
+ });
30
+ }
31
+
32
+ setMinDate(jsDateObject) {
33
+ if(!jsDateObject) {
34
+ this.enableOptions();
35
+ } else {
36
+ const dayJsDate = dayjs(jsDateObject);
37
+ this.getOptions().forEach((option) => {
38
+ option.disabled = dayJsDate.isAfter(dayjs(option.value), 'month');
39
+ });
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,18 @@
1
+ export class Option {
2
+ static createMonthOption(date) {
3
+ const formatted = date.format('MMMM YYYY');
4
+ return this.createOption(date.format('YYYY-MM-DD'), formatted);
5
+ }
6
+
7
+ static createDayOption(date) {
8
+ const formatted = date.format('ddd D');
9
+ return this.createOption(date.format('YYYY-MM-DD'), formatted);
10
+ }
11
+
12
+ static createOption(value, text) {
13
+ const option = document.createElement("option");
14
+ option.value = value;
15
+ option.textContent = text;
16
+ return option;
17
+ }
18
+ }
@@ -0,0 +1,27 @@
1
+ import { Option } from './Option.js';
2
+ import { DateHelper } from './DateHelper.js';
3
+
4
+ export class OptionGroup {
5
+ static createOptions(months) {
6
+ const options = [];
7
+
8
+ months.forEach((month) => {
9
+ options.push({
10
+ index: month.format('YYYY-MM-DD'),
11
+ month: Option.createMonthOption(month)
12
+ });
13
+ });
14
+
15
+ return options;
16
+ }
17
+
18
+ static createDayOptions(dayJsDate) {
19
+ const days = DateHelper.range(dayJsDate.subtract(1, 'month'), dayJsDate.add(1, 'month'), 'day');
20
+ const daysOfMonth = days.filter((day) => dayJsDate.isSame(day, 'month'));
21
+ return daysOfMonth.map((day) => Option.createDayOption(day));
22
+ }
23
+
24
+ static getMonthOptions(optionGroups) {
25
+ return optionGroups.map((group) => group.month.outerHTML).join('');
26
+ }
27
+ }
@@ -0,0 +1,11 @@
1
+ export class Select {
2
+ static createDaySelect() {
3
+ return document.createElement("select");
4
+ }
5
+
6
+ static createMonthSelect(monthOptions) {
7
+ const monthSelect = document.createElement("select");
8
+ monthSelect.innerHTML = monthOptions;
9
+ return monthSelect;
10
+ }
11
+ }