@nepdatejs/vanilla 0.0.0-stage → 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.
Files changed (104) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -2
  3. package/dist/auto-define.cjs +11 -0
  4. package/dist/auto-define.cjs.map +1 -0
  5. package/dist/auto-define.d.cts +2 -0
  6. package/dist/auto-define.d.ts +2 -0
  7. package/dist/auto-define.js +9 -0
  8. package/dist/auto-define.js.map +1 -0
  9. package/dist/calendar-BAcO-jYq.js +142 -0
  10. package/dist/calendar-BAcO-jYq.js.map +1 -0
  11. package/dist/calendar-BNdN8qJv.d.ts +87 -0
  12. package/dist/calendar-C1LZI7XN.cjs +159 -0
  13. package/dist/calendar-C1LZI7XN.cjs.map +1 -0
  14. package/dist/calendar-QWPX0IfD.d.cts +87 -0
  15. package/dist/calendar.cjs +7 -0
  16. package/dist/calendar.d.cts +2 -0
  17. package/dist/calendar.d.ts +2 -0
  18. package/dist/calendar.js +3 -0
  19. package/dist/date-picker-BidCGOz0.d.cts +74 -0
  20. package/dist/date-picker-CQoabjlj.cjs +600 -0
  21. package/dist/date-picker-CQoabjlj.cjs.map +1 -0
  22. package/dist/date-picker-DyvpYe29.d.ts +74 -0
  23. package/dist/date-picker-ucoEFnMW.js +577 -0
  24. package/dist/date-picker-ucoEFnMW.js.map +1 -0
  25. package/dist/date-picker.cjs +6 -0
  26. package/dist/date-picker.d.cts +3 -0
  27. package/dist/date-picker.d.ts +3 -0
  28. package/dist/date-picker.js +1 -0
  29. package/dist/date-range-picker-BQKcZeqG.cjs +489 -0
  30. package/dist/date-range-picker-BQKcZeqG.cjs.map +1 -0
  31. package/dist/date-range-picker-D3eNvlgv.d.ts +98 -0
  32. package/dist/date-range-picker-DAkCzVgT.js +466 -0
  33. package/dist/date-range-picker-DAkCzVgT.js.map +1 -0
  34. package/dist/date-range-picker-SIl0vhUV.d.cts +98 -0
  35. package/dist/date-range-picker.cjs +6 -0
  36. package/dist/date-range-picker.d.cts +2 -0
  37. package/dist/date-range-picker.d.ts +2 -0
  38. package/dist/date-range-picker.js +1 -0
  39. package/dist/date-time-picker-BqweOP2u.js +487 -0
  40. package/dist/date-time-picker-BqweOP2u.js.map +1 -0
  41. package/dist/date-time-picker-Bxfn-a9T.cjs +510 -0
  42. package/dist/date-time-picker-Bxfn-a9T.cjs.map +1 -0
  43. package/dist/date-time-picker-BzSyQxrf.d.cts +92 -0
  44. package/dist/date-time-picker-DzDpzLMZ.d.ts +92 -0
  45. package/dist/date-time-picker.cjs +6 -0
  46. package/dist/date-time-picker.d.cts +2 -0
  47. package/dist/date-time-picker.d.ts +2 -0
  48. package/dist/date-time-picker.js +1 -0
  49. package/dist/define-7natoEH4.js +18 -0
  50. package/dist/define-7natoEH4.js.map +1 -0
  51. package/dist/define-B8NUA3yj.d.cts +16 -0
  52. package/dist/define-B8NUA3yj.d.ts +16 -0
  53. package/dist/define-DTTdLfIM.cjs +23 -0
  54. package/dist/define-DTTdLfIM.cjs.map +1 -0
  55. package/dist/element-utils-BVye8UQq.d.cts +82 -0
  56. package/dist/element-utils-C-r5gPlk.d.ts +82 -0
  57. package/dist/index.cjs +30 -0
  58. package/dist/index.d.cts +8 -0
  59. package/dist/index.d.ts +8 -0
  60. package/dist/index.js +8 -0
  61. package/dist/multi-date-picker-B2mQbjZM.d.ts +105 -0
  62. package/dist/multi-date-picker-BMEYUPBa.cjs +462 -0
  63. package/dist/multi-date-picker-BMEYUPBa.cjs.map +1 -0
  64. package/dist/multi-date-picker-BUNf5zyJ.d.cts +105 -0
  65. package/dist/multi-date-picker-XCg8Y0sF.js +439 -0
  66. package/dist/multi-date-picker-XCg8Y0sF.js.map +1 -0
  67. package/dist/multi-date-picker.cjs +6 -0
  68. package/dist/multi-date-picker.d.cts +2 -0
  69. package/dist/multi-date-picker.d.ts +2 -0
  70. package/dist/multi-date-picker.js +1 -0
  71. package/dist/nepdate-picker.global.js +3 -0
  72. package/dist/nepdate-picker.global.js.map +1 -0
  73. package/dist/preset-list-CASwnwmS.js +45 -0
  74. package/dist/preset-list-CASwnwmS.js.map +1 -0
  75. package/dist/preset-list-Cs8H12Wp.cjs +50 -0
  76. package/dist/preset-list-Cs8H12Wp.cjs.map +1 -0
  77. package/dist/registry-3qzdVB7H.cjs +591 -0
  78. package/dist/registry-3qzdVB7H.cjs.map +1 -0
  79. package/dist/registry-BvkGnkvV.js +466 -0
  80. package/dist/registry-BvkGnkvV.js.map +1 -0
  81. package/package.json +162 -3
  82. package/src/auto-define.ts +6 -0
  83. package/src/calendar-element.ts +129 -0
  84. package/src/calendar-view.ts +406 -0
  85. package/src/calendar.ts +45 -0
  86. package/src/date-picker-element.ts +249 -0
  87. package/src/date-picker.ts +91 -0
  88. package/src/date-range-picker-element.ts +201 -0
  89. package/src/date-range-picker.ts +20 -0
  90. package/src/date-time-picker-element.ts +191 -0
  91. package/src/date-time-picker.ts +20 -0
  92. package/src/datetime-view.ts +459 -0
  93. package/src/define.ts +16 -0
  94. package/src/dom.ts +109 -0
  95. package/src/element-utils.ts +86 -0
  96. package/src/global.ts +7 -0
  97. package/src/index.ts +15 -0
  98. package/src/multi-date-picker-element.ts +187 -0
  99. package/src/multi-date-picker.ts +53 -0
  100. package/src/multi-view.ts +345 -0
  101. package/src/picker-view.ts +448 -0
  102. package/src/preset-list.ts +51 -0
  103. package/src/range-view.ts +393 -0
  104. package/src/registry.ts +27 -0
@@ -0,0 +1,45 @@
1
+ import { b as setText, g as el, v as setAttrs } from "./registry-BvkGnkvV.js";
2
+ //#region src/preset-list.ts
3
+ /** The shortcut buttons beside the calendar. Hidden when there are none. */
4
+ var PresetList = class {
5
+ constructor(onApply) {
6
+ this.ids = "";
7
+ this.element = el("div", {
8
+ class: "ndp-presets",
9
+ role: "group",
10
+ hidden: true
11
+ });
12
+ this.element.addEventListener("click", (event) => {
13
+ const button = event.target instanceof Element ? event.target.closest(".ndp-preset") : null;
14
+ const id = button?.dataset["preset"];
15
+ if (id !== void 0 && button && !button.disabled) onApply(id);
16
+ });
17
+ }
18
+ render(presets, label) {
19
+ this.element.hidden = presets.length === 0;
20
+ setAttrs(this.element, { "aria-label": label });
21
+ const ids = presets.map((preset) => preset.id).join("\n");
22
+ if (ids !== this.ids) {
23
+ this.ids = ids;
24
+ this.element.replaceChildren(...presets.map((preset) => el("button", {
25
+ type: "button",
26
+ class: "ndp-preset",
27
+ "data-preset": preset.id
28
+ })));
29
+ }
30
+ presets.forEach((preset, index) => {
31
+ const button = this.element.children[index];
32
+ if (button) {
33
+ setText(button, preset.label);
34
+ setAttrs(button, {
35
+ "aria-pressed": preset.isActive ? "true" : "false",
36
+ disabled: preset.isDisabled
37
+ });
38
+ }
39
+ });
40
+ }
41
+ };
42
+ //#endregion
43
+ export { PresetList as t };
44
+
45
+ //# sourceMappingURL=preset-list-CASwnwmS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset-list-CASwnwmS.js","names":[],"sources":["../src/preset-list.ts"],"sourcesContent":["import type { PresetState } from '@nepdatejs/datepicker';\nimport { el, setAttrs, setText } from './dom';\n\n/** Panel width with and without the presets column. */\nexport const PANEL_WIDTH = 320;\nexport const PANEL_WIDTH_WITH_PRESETS = 492;\nexport const TIME_COLUMNS_WIDTH = 136;\n\n/** The shortcut buttons beside the calendar. Hidden when there are none. */\nexport class PresetList {\n readonly element: HTMLDivElement;\n private ids = '';\n\n constructor(onApply: (id: string) => void) {\n this.element = el('div', { class: 'ndp-presets', role: 'group', hidden: true });\n this.element.addEventListener('click', (event) => {\n const button =\n event.target instanceof Element\n ? event.target.closest<HTMLButtonElement>('.ndp-preset')\n : null;\n const id = button?.dataset['preset'];\n if (id !== undefined && button && !button.disabled) {\n onApply(id);\n }\n });\n }\n\n render(presets: readonly PresetState[], label: string): void {\n this.element.hidden = presets.length === 0;\n setAttrs(this.element, { 'aria-label': label });\n const ids = presets.map((preset) => preset.id).join('\\n');\n if (ids !== this.ids) {\n this.ids = ids;\n this.element.replaceChildren(\n ...presets.map((preset) =>\n el('button', { type: 'button', class: 'ndp-preset', 'data-preset': preset.id }),\n ),\n );\n }\n presets.forEach((preset, index) => {\n const button = this.element.children[index];\n if (button) {\n setText(button, preset.label);\n setAttrs(button, {\n 'aria-pressed': preset.isActive ? 'true' : 'false',\n disabled: preset.isDisabled,\n });\n }\n });\n }\n}\n"],"mappings":";;;AASA,IAAa,aAAb,MAAwB;CAItB,YAAY,SAA+B;EAF3C,KAAQ,MAAM;EAGZ,KAAK,UAAU,GAAG,OAAO;GAAE,OAAO;GAAe,MAAM;GAAS,QAAQ;EAAK,CAAC;EAC9E,KAAK,QAAQ,iBAAiB,UAAU,UAAU;GAChD,MAAM,SACJ,MAAM,kBAAkB,UACpB,MAAM,OAAO,QAA2B,aAAa,IACrD;GACN,MAAM,KAAK,QAAQ,QAAQ;GAC3B,IAAI,OAAO,KAAA,KAAa,UAAU,CAAC,OAAO,UACxC,QAAQ,EAAE;EAEd,CAAC;CACH;CAEA,OAAO,SAAiC,OAAqB;EAC3D,KAAK,QAAQ,SAAS,QAAQ,WAAW;EACzC,SAAS,KAAK,SAAS,EAAE,cAAc,MAAM,CAAC;EAC9C,MAAM,MAAM,QAAQ,KAAK,WAAW,OAAO,EAAE,CAAC,CAAC,KAAK,IAAI;EACxD,IAAI,QAAQ,KAAK,KAAK;GACpB,KAAK,MAAM;GACX,KAAK,QAAQ,gBACX,GAAG,QAAQ,KAAK,WACd,GAAG,UAAU;IAAE,MAAM;IAAU,OAAO;IAAc,eAAe,OAAO;GAAG,CAAC,CAChF,CACF;EACF;EACA,QAAQ,SAAS,QAAQ,UAAU;GACjC,MAAM,SAAS,KAAK,QAAQ,SAAS;GACrC,IAAI,QAAQ;IACV,QAAQ,QAAQ,OAAO,KAAK;IAC5B,SAAS,QAAQ;KACf,gBAAgB,OAAO,WAAW,SAAS;KAC3C,UAAU,OAAO;IACnB,CAAC;GACH;EACF,CAAC;CACH;AACF"}
@@ -0,0 +1,50 @@
1
+ const require_registry = require("./registry-3qzdVB7H.cjs");
2
+ //#region src/preset-list.ts
3
+ /** The shortcut buttons beside the calendar. Hidden when there are none. */
4
+ var PresetList = class {
5
+ constructor(onApply) {
6
+ this.ids = "";
7
+ this.element = require_registry.el("div", {
8
+ class: "ndp-presets",
9
+ role: "group",
10
+ hidden: true
11
+ });
12
+ this.element.addEventListener("click", (event) => {
13
+ const button = event.target instanceof Element ? event.target.closest(".ndp-preset") : null;
14
+ const id = button?.dataset["preset"];
15
+ if (id !== void 0 && button && !button.disabled) onApply(id);
16
+ });
17
+ }
18
+ render(presets, label) {
19
+ this.element.hidden = presets.length === 0;
20
+ require_registry.setAttrs(this.element, { "aria-label": label });
21
+ const ids = presets.map((preset) => preset.id).join("\n");
22
+ if (ids !== this.ids) {
23
+ this.ids = ids;
24
+ this.element.replaceChildren(...presets.map((preset) => require_registry.el("button", {
25
+ type: "button",
26
+ class: "ndp-preset",
27
+ "data-preset": preset.id
28
+ })));
29
+ }
30
+ presets.forEach((preset, index) => {
31
+ const button = this.element.children[index];
32
+ if (button) {
33
+ require_registry.setText(button, preset.label);
34
+ require_registry.setAttrs(button, {
35
+ "aria-pressed": preset.isActive ? "true" : "false",
36
+ disabled: preset.isDisabled
37
+ });
38
+ }
39
+ });
40
+ }
41
+ };
42
+ //#endregion
43
+ Object.defineProperty(exports, "PresetList", {
44
+ enumerable: true,
45
+ get: function() {
46
+ return PresetList;
47
+ }
48
+ });
49
+
50
+ //# sourceMappingURL=preset-list-Cs8H12Wp.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset-list-Cs8H12Wp.cjs","names":["el"],"sources":["../src/preset-list.ts"],"sourcesContent":["import type { PresetState } from '@nepdatejs/datepicker';\nimport { el, setAttrs, setText } from './dom';\n\n/** Panel width with and without the presets column. */\nexport const PANEL_WIDTH = 320;\nexport const PANEL_WIDTH_WITH_PRESETS = 492;\nexport const TIME_COLUMNS_WIDTH = 136;\n\n/** The shortcut buttons beside the calendar. Hidden when there are none. */\nexport class PresetList {\n readonly element: HTMLDivElement;\n private ids = '';\n\n constructor(onApply: (id: string) => void) {\n this.element = el('div', { class: 'ndp-presets', role: 'group', hidden: true });\n this.element.addEventListener('click', (event) => {\n const button =\n event.target instanceof Element\n ? event.target.closest<HTMLButtonElement>('.ndp-preset')\n : null;\n const id = button?.dataset['preset'];\n if (id !== undefined && button && !button.disabled) {\n onApply(id);\n }\n });\n }\n\n render(presets: readonly PresetState[], label: string): void {\n this.element.hidden = presets.length === 0;\n setAttrs(this.element, { 'aria-label': label });\n const ids = presets.map((preset) => preset.id).join('\\n');\n if (ids !== this.ids) {\n this.ids = ids;\n this.element.replaceChildren(\n ...presets.map((preset) =>\n el('button', { type: 'button', class: 'ndp-preset', 'data-preset': preset.id }),\n ),\n );\n }\n presets.forEach((preset, index) => {\n const button = this.element.children[index];\n if (button) {\n setText(button, preset.label);\n setAttrs(button, {\n 'aria-pressed': preset.isActive ? 'true' : 'false',\n disabled: preset.isDisabled,\n });\n }\n });\n }\n}\n"],"mappings":";;;AASA,IAAa,aAAb,MAAwB;CAItB,YAAY,SAA+B;EAF3C,KAAQ,MAAM;EAGZ,KAAK,UAAUA,iBAAAA,GAAG,OAAO;GAAE,OAAO;GAAe,MAAM;GAAS,QAAQ;EAAK,CAAC;EAC9E,KAAK,QAAQ,iBAAiB,UAAU,UAAU;GAChD,MAAM,SACJ,MAAM,kBAAkB,UACpB,MAAM,OAAO,QAA2B,aAAa,IACrD;GACN,MAAM,KAAK,QAAQ,QAAQ;GAC3B,IAAI,OAAO,KAAA,KAAa,UAAU,CAAC,OAAO,UACxC,QAAQ,EAAE;EAEd,CAAC;CACH;CAEA,OAAO,SAAiC,OAAqB;EAC3D,KAAK,QAAQ,SAAS,QAAQ,WAAW;EACzC,iBAAA,SAAS,KAAK,SAAS,EAAE,cAAc,MAAM,CAAC;EAC9C,MAAM,MAAM,QAAQ,KAAK,WAAW,OAAO,EAAE,CAAC,CAAC,KAAK,IAAI;EACxD,IAAI,QAAQ,KAAK,KAAK;GACpB,KAAK,MAAM;GACX,KAAK,QAAQ,gBACX,GAAG,QAAQ,KAAK,WACdA,iBAAAA,GAAG,UAAU;IAAE,MAAM;IAAU,OAAO;IAAc,eAAe,OAAO;GAAG,CAAC,CAChF,CACF;EACF;EACA,QAAQ,SAAS,QAAQ,UAAU;GACjC,MAAM,SAAS,KAAK,QAAQ,SAAS;GACrC,IAAI,QAAQ;IACV,iBAAA,QAAQ,QAAQ,OAAO,KAAK;IAC5B,iBAAA,SAAS,QAAQ;KACf,gBAAgB,OAAO,WAAW,SAAS;KAC3C,UAAU,OAAO;IACnB,CAAC;GACH;EACF,CAAC;CACH;AACF"}
@@ -0,0 +1,591 @@
1
+ let _nepdatejs_core = require("@nepdatejs/core");
2
+ //#region src/dom.ts
3
+ function el(tag, attrs = {}, children = []) {
4
+ const node = document.createElement(tag);
5
+ setAttrs(node, attrs);
6
+ node.append(...children);
7
+ return node;
8
+ }
9
+ /** Set, update or remove attributes: false/null/undefined removes, true sets "". */
10
+ function setAttrs(node, attrs) {
11
+ for (const [name, value] of Object.entries(attrs)) if (value === false || value === null || value === void 0) node.removeAttribute(name);
12
+ else {
13
+ const text = value === true ? "" : String(value);
14
+ if (node.getAttribute(name) !== text) node.setAttribute(name, text);
15
+ }
16
+ }
17
+ function setText(node, text) {
18
+ if (node.textContent !== text) node.textContent = text;
19
+ }
20
+ let counter = 0;
21
+ /** A document-unique id for aria-controls / aria-describedby. */
22
+ function uid(prefix) {
23
+ counter += 1;
24
+ return `${prefix}-${counter}`;
25
+ }
26
+ const SVG = "http://www.w3.org/2000/svg";
27
+ const PATHS = {
28
+ "chevron-left": ["M10 3.5 5.5 8l4.5 4.5"],
29
+ "chevron-right": ["M6 3.5 10.5 8 6 12.5"],
30
+ calendar: [
31
+ "M2 6.5h12",
32
+ "M5.5 1.5v3",
33
+ "M10.5 1.5v3",
34
+ "M4 3h8a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z"
35
+ ],
36
+ close: ["M4 4l8 8", "M12 4l-8 8"]
37
+ };
38
+ /** The Figma icon set at 16px, drawn with currentColor. */
39
+ function icon(name) {
40
+ const svg = document.createElementNS(SVG, "svg");
41
+ svg.setAttribute("viewBox", "0 0 16 16");
42
+ svg.setAttribute("fill", "none");
43
+ svg.setAttribute("stroke", "currentColor");
44
+ svg.setAttribute("stroke-width", "1.5");
45
+ svg.setAttribute("stroke-linecap", "round");
46
+ svg.setAttribute("stroke-linejoin", "round");
47
+ svg.setAttribute("aria-hidden", "true");
48
+ svg.setAttribute("focusable", "false");
49
+ for (const d of PATHS[name]) {
50
+ const path = document.createElementNS(SVG, "path");
51
+ path.setAttribute("d", d);
52
+ svg.append(path);
53
+ }
54
+ return svg;
55
+ }
56
+ /**
57
+ * Popup or inline: an inline picker's calendar is always in the page, so its
58
+ * inputs are plain text fields, its toggle is hidden and its panel is a group
59
+ * in normal flow rather than a top-layer dialog.
60
+ */
61
+ function setPopupMode(state, inputs, toggle, panel) {
62
+ const { inline } = state;
63
+ for (const input of inputs) setAttrs(input, {
64
+ role: inline ? null : "combobox",
65
+ "aria-haspopup": inline ? null : "dialog",
66
+ "aria-expanded": inline ? null : String(state.open)
67
+ });
68
+ toggle.hidden = inline;
69
+ setAttrs(panel, {
70
+ role: inline ? "group" : "dialog",
71
+ popover: inline ? null : "manual"
72
+ });
73
+ if (inline) panel.dataset["layout"] = "inline";
74
+ else if (panel.dataset["layout"] === "inline") delete panel.dataset["layout"];
75
+ }
76
+ //#endregion
77
+ //#region src/calendar-view.ts
78
+ const FOCUS_KEYS = /* @__PURE__ */ new Set([
79
+ "ArrowLeft",
80
+ "ArrowRight",
81
+ "ArrowUp",
82
+ "ArrowDown",
83
+ "Home",
84
+ "End",
85
+ "PageUp",
86
+ "PageDown"
87
+ ]);
88
+ /**
89
+ * Renders a calendar store into `root` with the @nepdatejs/styles markup and
90
+ * keeps it in step. Elements are updated in place, so a click or focus never
91
+ * lands on a replaced button; only switching view or row count rebuilds the body.
92
+ */
93
+ var CalendarView = class {
94
+ constructor(root, store, options = {}) {
95
+ this.bodyKey = "";
96
+ this.cells = [];
97
+ this.tiles = [];
98
+ this.focusAfterRender = false;
99
+ this.onClick = (event) => {
100
+ const target = event.target instanceof Element ? event.target : null;
101
+ const action = target?.closest("[data-action]")?.dataset["action"];
102
+ const { actions } = this.store;
103
+ switch (action) {
104
+ case "prev":
105
+ actions.prev();
106
+ return;
107
+ case "next":
108
+ actions.next();
109
+ return;
110
+ case "view-month":
111
+ actions.setView("month");
112
+ this.focusAfterRender = true;
113
+ this.render();
114
+ return;
115
+ case "view-year":
116
+ actions.setView("year");
117
+ this.focusAfterRender = true;
118
+ this.render();
119
+ return;
120
+ case "view-day":
121
+ actions.setView("day");
122
+ return;
123
+ }
124
+ const option = target?.closest(".ndp-option");
125
+ if (option) {
126
+ const index = [...this.body.querySelectorAll(".ndp-option")].indexOf(option);
127
+ const tile = this.tiles[index];
128
+ if (tile && !tile.isDisabled) {
129
+ this.focusAfterRender = true;
130
+ const view = this.store.getState().view;
131
+ if (view === "month") actions.chooseMonth(tile.value);
132
+ else if (view === "year") actions.chooseYear(tile.value);
133
+ else actions.chooseFiscalYear(tile.value);
134
+ this.render();
135
+ }
136
+ return;
137
+ }
138
+ const cell = this.cellOf(target);
139
+ if (cell && !cell.isDisabled) (this.options.onDayActivate ?? ((date) => actions.select(date)))(cell.date);
140
+ };
141
+ this.onKeyDown = (event) => {
142
+ if (!FOCUS_KEYS.has(event.key) || !this.cellOf(event.target)) return;
143
+ event.preventDefault();
144
+ this.focusAfterRender = true;
145
+ this.store.actions.moveFocus(event.key, { shift: event.shiftKey });
146
+ this.flushFocus();
147
+ };
148
+ this.onMouseOver = (event) => {
149
+ const cell = this.cellOf(event.target);
150
+ if (cell && this.store.getState().selectionMode === "range") this.store.actions.hover(cell.isDisabled ? null : cell.date);
151
+ };
152
+ this.onMouseLeave = () => {
153
+ if (this.store.getState().selectionMode === "range") this.store.actions.hover(null);
154
+ };
155
+ this.onFocusIn = (event) => {
156
+ const cell = this.cellOf(event.target);
157
+ if (cell && !cell.isFocusTarget) this.store.actions.focus(cell.date);
158
+ };
159
+ this.store = store;
160
+ this.options = options;
161
+ this.prev = el("button", {
162
+ type: "button",
163
+ class: "ndp-icon-button",
164
+ "data-action": "prev"
165
+ }, [icon("chevron-left")]);
166
+ this.next = el("button", {
167
+ type: "button",
168
+ class: "ndp-icon-button",
169
+ "data-action": "next"
170
+ }, [icon("chevron-right")]);
171
+ this.title = el("div", {
172
+ class: "ndp-calendar__title",
173
+ "aria-live": "polite"
174
+ });
175
+ this.body = el("div");
176
+ this.element = el("div", { class: "ndp-calendar" }, [el("div", { class: "ndp-calendar__header" }, [
177
+ this.prev,
178
+ this.title,
179
+ this.next
180
+ ]), this.body]);
181
+ this.element.addEventListener("click", this.onClick);
182
+ this.element.addEventListener("keydown", this.onKeyDown);
183
+ this.element.addEventListener("mouseover", this.onMouseOver);
184
+ this.element.addEventListener("mouseleave", this.onMouseLeave);
185
+ this.element.addEventListener("focusin", this.onFocusIn);
186
+ root.append(this.element);
187
+ this.unsubscribe = store.subscribe(() => {
188
+ this.render();
189
+ });
190
+ this.render();
191
+ }
192
+ /** Move keyboard focus to the day that should have it. */
193
+ focusGrid() {
194
+ this.element.querySelector(".ndp-day[tabindex=\"0\"], .ndp-option[tabindex=\"0\"]")?.focus();
195
+ }
196
+ destroy() {
197
+ this.unsubscribe();
198
+ this.element.remove();
199
+ }
200
+ render() {
201
+ const state = this.store.getState();
202
+ const labels = (0, _nepdatejs_core.getLocale)(this.options.locale?.()).labels;
203
+ const stepLabels = state.view === "day" ? [labels.previousMonth, labels.nextMonth] : [labels.previousYear, labels.nextYear];
204
+ setAttrs(this.prev, {
205
+ "aria-label": stepLabels[0],
206
+ disabled: !state.canPrev
207
+ });
208
+ setAttrs(this.next, {
209
+ "aria-label": stepLabels[1],
210
+ disabled: !state.canNext
211
+ });
212
+ this.renderTitle(state, labels.month, labels.year);
213
+ const key = `${state.view}:${state.view === "day" ? state.weeks.length : 12}`;
214
+ if (key !== this.bodyKey) {
215
+ this.bodyKey = key;
216
+ this.body.replaceChildren(state.view === "day" ? this.buildGrid(state) : this.buildOptions());
217
+ }
218
+ if (state.view === "day") this.patchGrid(state);
219
+ else this.patchOptions(state.view === "month" ? state.months : state.view === "year" ? state.years : state.fiscalYears);
220
+ this.flushFocus();
221
+ }
222
+ /** Focus the grid if a keyboard move or view change asked for it. */
223
+ flushFocus() {
224
+ if (this.focusAfterRender) {
225
+ this.focusAfterRender = false;
226
+ this.focusGrid();
227
+ }
228
+ }
229
+ renderTitle(state, monthLabel, yearLabel) {
230
+ const [monthName, yearText] = state.view === "day" ? splitTitle(state.title) : ["", state.title];
231
+ const wanted = state.view === "day" ? [{
232
+ action: "view-month",
233
+ text: monthName,
234
+ label: `${monthLabel}: ${monthName}`
235
+ }, {
236
+ action: "view-year",
237
+ text: yearText,
238
+ label: `${yearLabel}: ${yearText}`
239
+ }] : [{
240
+ action: state.view === "month" ? "view-year" : "view-day",
241
+ text: state.title,
242
+ label: state.view === "fiscal" ? state.title : `${yearLabel}: ${state.title}`
243
+ }];
244
+ if ([...this.title.children].length !== wanted.length) this.title.replaceChildren(...wanted.map(() => el("button", {
245
+ type: "button",
246
+ class: "ndp-calendar__title-button"
247
+ })));
248
+ wanted.forEach((item, index) => {
249
+ const button = this.title.children[index];
250
+ setAttrs(button, {
251
+ "data-action": item.action,
252
+ "aria-label": item.label
253
+ });
254
+ setText(button, item.text);
255
+ });
256
+ }
257
+ buildGrid(state) {
258
+ const head = el("tr", { role: "row" });
259
+ for (let i = 0; i < 7; i++) head.append(el("th", {
260
+ class: "ndp-weekday",
261
+ scope: "col",
262
+ role: "columnheader"
263
+ }));
264
+ const rows = state.weeks.map(() => {
265
+ const row = el("tr", { role: "row" });
266
+ for (let i = 0; i < 7; i++) row.append(el("td", { role: "gridcell" }, [el("button", {
267
+ type: "button",
268
+ class: "ndp-day"
269
+ }, [
270
+ el("span", { class: "ndp-sr-only" }),
271
+ el("span", {
272
+ class: "ndp-day__label",
273
+ "aria-hidden": "true"
274
+ }),
275
+ el("span", {
276
+ class: "ndp-day__sub",
277
+ "aria-hidden": "true"
278
+ }),
279
+ el("span", {
280
+ class: "ndp-day__dot",
281
+ "aria-hidden": "true",
282
+ hidden: true
283
+ })
284
+ ])]));
285
+ return row;
286
+ });
287
+ return el("table", {
288
+ class: "ndp-grid",
289
+ role: "grid"
290
+ }, [el("thead", {}, [head]), el("tbody", {}, rows)]);
291
+ }
292
+ patchGrid(state) {
293
+ const table = this.body.firstElementChild;
294
+ setAttrs(table, { "aria-label": state.title });
295
+ const headers = table.querySelectorAll("th");
296
+ state.weekdays.forEach((weekday, index) => {
297
+ const th = headers[index];
298
+ if (th) {
299
+ setAttrs(th, {
300
+ abbr: weekday.longLabel,
301
+ "data-weekend": weekday.isWeekend
302
+ });
303
+ setText(th, weekday.label);
304
+ }
305
+ });
306
+ this.cells = state.weeks.flat();
307
+ const buttons = table.querySelectorAll(".ndp-day");
308
+ this.cells.forEach((cell, index) => {
309
+ const button = buttons[index];
310
+ if (button) patchDay(button, cell);
311
+ });
312
+ }
313
+ buildOptions() {
314
+ return el("div", {
315
+ class: "ndp-options",
316
+ role: "group"
317
+ }, Array.from({ length: 12 }, () => el("button", {
318
+ type: "button",
319
+ class: "ndp-option"
320
+ }, [
321
+ el("span", { class: "ndp-sr-only" }),
322
+ el("span", {
323
+ class: "ndp-option__label",
324
+ "aria-hidden": "true"
325
+ }),
326
+ el("span", {
327
+ class: "ndp-option__sub",
328
+ "aria-hidden": "true"
329
+ })
330
+ ])));
331
+ }
332
+ patchOptions(tiles) {
333
+ this.tiles = [...tiles];
334
+ const focusIndex = Math.max(0, tiles.findIndex((tile) => tile.isSelected) === -1 ? tiles.findIndex((tile) => tile.isCurrent) : tiles.findIndex((tile) => tile.isSelected));
335
+ const buttons = this.body.querySelectorAll(".ndp-option");
336
+ tiles.forEach((tile, index) => {
337
+ const button = buttons[index];
338
+ if (!button) return;
339
+ setAttrs(button, {
340
+ "data-state": tile.isSelected ? "selected" : tile.isCurrent ? "current" : "default",
341
+ "aria-pressed": tile.isSelected ? "true" : "false",
342
+ tabindex: index === focusIndex ? 0 : -1,
343
+ disabled: tile.isDisabled
344
+ });
345
+ const [name, label, sub] = button.children;
346
+ if (name && label && sub) {
347
+ setText(name, tile.subLabel ? `${tile.label} (${tile.subLabel})` : tile.label);
348
+ setText(label, tile.label);
349
+ setText(sub, tile.subLabel ?? "");
350
+ }
351
+ });
352
+ }
353
+ cellOf(target) {
354
+ const button = target instanceof Element ? target.closest(".ndp-day") : null;
355
+ if (!button || !this.element.contains(button)) return null;
356
+ const index = [...this.element.querySelectorAll(".ndp-day")].indexOf(button);
357
+ return this.cells[index] ?? null;
358
+ }
359
+ };
360
+ function patchDay(button, cell) {
361
+ const td = button.parentElement;
362
+ if (!cell) {
363
+ button.hidden = true;
364
+ setAttrs(button, {
365
+ tabindex: -1,
366
+ "data-key": null
367
+ });
368
+ if (td) setAttrs(td, { "aria-selected": null });
369
+ return;
370
+ }
371
+ button.hidden = false;
372
+ setAttrs(button, {
373
+ "data-key": cell.key,
374
+ "data-state": cell.state,
375
+ "data-weekend": cell.isWeekend,
376
+ "data-preview": cell.isInRangePreview && !cell.isSelected,
377
+ "data-outside": cell.isOutside,
378
+ tabindex: cell.isFocusTarget ? 0 : -1,
379
+ disabled: cell.isDisabled,
380
+ "aria-pressed": cell.isSelected ? "true" : "false",
381
+ "aria-current": cell.isToday ? "date" : null
382
+ });
383
+ if (td) setAttrs(td, { "aria-selected": cell.isSelected ? "true" : null });
384
+ const [name, label, sub, dot] = button.children;
385
+ setText(name, cell.ariaLabel);
386
+ setText(label, cell.label);
387
+ setText(sub, cell.subLabel ?? "");
388
+ sub.hidden = cell.subLabel === null;
389
+ const event = cell.events[0];
390
+ dot.hidden = !event;
391
+ dot.style.setProperty("--ndp-dot-color", event?.color ?? null);
392
+ }
393
+ /** "Kartik 2083" → ["Kartik", "2083"]; the year is the last word in every locale we ship. */
394
+ function splitTitle(title) {
395
+ const space = title.lastIndexOf(" ");
396
+ return space === -1 ? [title, ""] : [title.slice(0, space), title.slice(space + 1)];
397
+ }
398
+ //#endregion
399
+ //#region src/element-utils.ts
400
+ /** Attribute parsing and shared helpers for the custom elements. */
401
+ /** Lets this module load during server rendering, where HTMLElement does not exist. */
402
+ const Base = typeof HTMLElement === "undefined" ? Object : HTMLElement;
403
+ function str(element, name) {
404
+ return element.getAttribute(name) ?? void 0;
405
+ }
406
+ function bool(element, name) {
407
+ return element.hasAttribute(name);
408
+ }
409
+ /** An attribute that is on unless set to "false". */
410
+ function onUnlessFalse(element, name) {
411
+ const value = element.getAttribute(name);
412
+ return value === null ? void 0 : value !== "false";
413
+ }
414
+ function calendarAttr(element, name) {
415
+ const value = element.getAttribute(name)?.toUpperCase();
416
+ return value === "BS" || value === "AD" ? value : void 0;
417
+ }
418
+ function weekday(element, name) {
419
+ const value = Number(element.getAttribute(name) ?? NaN);
420
+ return Number.isInteger(value) && value >= 0 && value <= 6 ? value : void 0;
421
+ }
422
+ function int(element, name) {
423
+ const value = Number(element.getAttribute(name) ?? NaN);
424
+ return Number.isInteger(value) ? value : void 0;
425
+ }
426
+ function theme(element) {
427
+ const value = element.getAttribute("theme");
428
+ return value === "light" || value === "dark" || value === "auto" ? value : void 0;
429
+ }
430
+ function panelLayout(element) {
431
+ const value = element.getAttribute("panel-layout");
432
+ return value === "auto" || value === "popover" || value === "sheet" ? value : void 0;
433
+ }
434
+ /** presets="today, last7Days" → ['today', 'last7Days']; unknown ids show as disabled. */
435
+ function presetIds(element) {
436
+ const value = element.getAttribute("presets");
437
+ return value === null ? void 0 : value.split(",").map((id) => id.trim()).filter(Boolean);
438
+ }
439
+ /** Stop the inner inputs' native change events: the element fires its own. */
440
+ function swallowInnerChange(host) {
441
+ host.addEventListener("change", (event) => {
442
+ if (event.target !== host) event.stopPropagation();
443
+ }, true);
444
+ }
445
+ function isoOf(date) {
446
+ return date ? (0, _nepdatejs_core.toIsoDate)(date) : "";
447
+ }
448
+ //#endregion
449
+ //#region src/registry.ts
450
+ /** The tag names this package registers. */
451
+ const ELEMENT_NAMES = Object.freeze({
452
+ datePicker: "nep-date-picker",
453
+ calendar: "nep-calendar",
454
+ dateRangePicker: "nep-date-range-picker",
455
+ dateTimePicker: "nep-date-time-picker",
456
+ multiDatePicker: "nep-multi-date-picker"
457
+ });
458
+ /** Define one element unless the name is taken. No-op during server rendering. */
459
+ function defineElement(name, element, registry) {
460
+ const target = registry ?? (typeof customElements === "undefined" ? void 0 : customElements);
461
+ if (target && !target.get(name)) target.define(name, element);
462
+ }
463
+ //#endregion
464
+ Object.defineProperty(exports, "Base", {
465
+ enumerable: true,
466
+ get: function() {
467
+ return Base;
468
+ }
469
+ });
470
+ Object.defineProperty(exports, "CalendarView", {
471
+ enumerable: true,
472
+ get: function() {
473
+ return CalendarView;
474
+ }
475
+ });
476
+ Object.defineProperty(exports, "ELEMENT_NAMES", {
477
+ enumerable: true,
478
+ get: function() {
479
+ return ELEMENT_NAMES;
480
+ }
481
+ });
482
+ Object.defineProperty(exports, "bool", {
483
+ enumerable: true,
484
+ get: function() {
485
+ return bool;
486
+ }
487
+ });
488
+ Object.defineProperty(exports, "calendarAttr", {
489
+ enumerable: true,
490
+ get: function() {
491
+ return calendarAttr;
492
+ }
493
+ });
494
+ Object.defineProperty(exports, "defineElement", {
495
+ enumerable: true,
496
+ get: function() {
497
+ return defineElement;
498
+ }
499
+ });
500
+ Object.defineProperty(exports, "el", {
501
+ enumerable: true,
502
+ get: function() {
503
+ return el;
504
+ }
505
+ });
506
+ Object.defineProperty(exports, "icon", {
507
+ enumerable: true,
508
+ get: function() {
509
+ return icon;
510
+ }
511
+ });
512
+ Object.defineProperty(exports, "int", {
513
+ enumerable: true,
514
+ get: function() {
515
+ return int;
516
+ }
517
+ });
518
+ Object.defineProperty(exports, "isoOf", {
519
+ enumerable: true,
520
+ get: function() {
521
+ return isoOf;
522
+ }
523
+ });
524
+ Object.defineProperty(exports, "onUnlessFalse", {
525
+ enumerable: true,
526
+ get: function() {
527
+ return onUnlessFalse;
528
+ }
529
+ });
530
+ Object.defineProperty(exports, "panelLayout", {
531
+ enumerable: true,
532
+ get: function() {
533
+ return panelLayout;
534
+ }
535
+ });
536
+ Object.defineProperty(exports, "presetIds", {
537
+ enumerable: true,
538
+ get: function() {
539
+ return presetIds;
540
+ }
541
+ });
542
+ Object.defineProperty(exports, "setAttrs", {
543
+ enumerable: true,
544
+ get: function() {
545
+ return setAttrs;
546
+ }
547
+ });
548
+ Object.defineProperty(exports, "setPopupMode", {
549
+ enumerable: true,
550
+ get: function() {
551
+ return setPopupMode;
552
+ }
553
+ });
554
+ Object.defineProperty(exports, "setText", {
555
+ enumerable: true,
556
+ get: function() {
557
+ return setText;
558
+ }
559
+ });
560
+ Object.defineProperty(exports, "str", {
561
+ enumerable: true,
562
+ get: function() {
563
+ return str;
564
+ }
565
+ });
566
+ Object.defineProperty(exports, "swallowInnerChange", {
567
+ enumerable: true,
568
+ get: function() {
569
+ return swallowInnerChange;
570
+ }
571
+ });
572
+ Object.defineProperty(exports, "theme", {
573
+ enumerable: true,
574
+ get: function() {
575
+ return theme;
576
+ }
577
+ });
578
+ Object.defineProperty(exports, "uid", {
579
+ enumerable: true,
580
+ get: function() {
581
+ return uid;
582
+ }
583
+ });
584
+ Object.defineProperty(exports, "weekday", {
585
+ enumerable: true,
586
+ get: function() {
587
+ return weekday;
588
+ }
589
+ });
590
+
591
+ //# sourceMappingURL=registry-3qzdVB7H.cjs.map