adc-calendar
Version:
Calendar ที่มีทั้ง EN | TH และสามารถ เป็นจาก ค.ศ. เป็น พ.ศ. และ custom calendar ได้ตามต้องการ
1,453 lines (1,407 loc) • 47.3 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
swCalendar: () => swCalendar,
swCalendarBetween: () => swCalendarBetween
});
module.exports = __toCommonJS(index_exports);
// src/composition-calendar.ts
var renderBodyDay = (daysContainer, days) => {
while (daysContainer.firstChild) {
daysContainer.removeChild(daysContainer.firstChild);
}
const fragment = document.createDocumentFragment();
days.children.forEach((day) => {
var _a;
const dayElement = document.createElement("div");
if (day.props) {
Object.entries(day.props).forEach(([key, value]) => {
dayElement.setAttribute(key, value);
});
}
if (typeof day.children === "string") {
dayElement.textContent = day.children;
}
if ((_a = day.methods) == null ? void 0 : _a.click) {
dayElement.addEventListener("click", day.methods.click);
}
fragment.appendChild(dayElement);
});
daysContainer.appendChild(fragment);
};
var CalendarError = class extends Error {
constructor(message) {
super(message);
this.name = "CalendarError";
}
};
var DateValidationError = class extends CalendarError {
constructor(message) {
super(message);
this.name = "DateValidationError";
}
};
// src/main.ts
var import_adc_directive = require("adc-directive");
// src/data-calendar.ts
var lists = [
{
english: "January",
en: "Jan",
th: "\u0E21.\u0E04.",
thai: "\u0E21\u0E01\u0E23\u0E32\u0E04\u0E21",
month_value: "01",
days: 31,
year: 0
},
{
english: "February",
en: "Feb",
th: "\u0E01.\u0E1E.",
thai: "\u0E01\u0E38\u0E21\u0E20\u0E32\u0E1E\u0E31\u0E19\u0E18\u0E4C",
month_value: "02",
days: 27,
year: 0
},
{
english: "March",
en: "Mar",
th: "\u0E21\u0E35.\u0E04.",
thai: "\u0E21\u0E35\u0E19\u0E32\u0E04\u0E21",
month_value: "03",
days: 31,
year: 0
},
{
english: "April",
en: "Apr",
th: "\u0E40\u0E21.\u0E22.",
thai: "\u0E40\u0E21\u0E29\u0E32\u0E22\u0E19",
month_value: "04",
days: 30,
year: 0
},
{
english: "May",
en: "May",
th: "\u0E1E.\u0E04.",
thai: "\u0E1E\u0E24\u0E29\u0E20\u0E32\u0E04\u0E21",
month_value: "05",
days: 31,
year: 0
},
{
english: "June",
en: "June",
th: "\u0E21\u0E34.\u0E22.",
thai: "\u0E21\u0E34\u0E16\u0E38\u0E19\u0E32\u0E22\u0E19",
month_value: "06",
days: 30,
year: 0
},
{
english: "July",
en: "July",
th: "\u0E01.\u0E04.",
thai: "\u0E01\u0E23\u0E01\u0E0E\u0E32\u0E04\u0E21",
month_value: "07",
days: 31,
year: 0
},
{
english: "August",
en: "Aug",
th: "\u0E2A.\u0E04.",
thai: "\u0E2A\u0E34\u0E07\u0E2B\u0E32\u0E04\u0E21",
month_value: "08",
days: 31,
year: 0
},
{
english: "September",
en: "Sept",
th: "\u0E01.\u0E22.",
thai: "\u0E01\u0E31\u0E19\u0E22\u0E32\u0E22\u0E19",
month_value: "09",
days: 30,
year: 0
},
{
english: "October",
en: "Oct",
th: "\u0E15.\u0E04.",
thai: "\u0E15\u0E38\u0E25\u0E32\u0E04\u0E21",
month_value: "10",
days: 31,
year: 0
},
{
english: "November",
en: "Nov",
th: "\u0E1E.\u0E22.",
thai: "\u0E1E\u0E24\u0E28\u0E08\u0E34\u0E01\u0E32\u0E22\u0E19",
month_value: "11",
days: 30,
year: 0
},
{
english: "December",
en: "Dec",
th: "\u0E18.\u0E04.",
thai: "\u0E18\u0E31\u0E19\u0E27\u0E32\u0E04\u0E21",
month_value: "12",
days: 31,
year: 0
}
];
var css = `
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
[calendar='root'] {
--font-family: 'Arial', sans-serif;
--background: #f3f8fe;
--picker: #0ea5e9;
--text-picker: #fff;
--dateRadius: 50%;
--disabled: #c3c2c8; /* disabled */
--current: #ffdfd2;
--text: #151426;
--text-week: #1e293b;
--borderRadius: .75rem;
--border: none;
--width: 290px;
--shadow: none;
--text-current: #ffffff; /* text current */
--week-line: #cbd5e1;
min-width: var(--width);
max-width: var(--width);
--h_header: 40px;
}
[data-box='container'] {
font-family: var(--font-family);
box-shadow: var(--shadow);
border-radius: var(--borderRadius);
border: var(--border);
width: inherit;
height: max-content;
background-color: var(--background);
overflow: hidden;
position: relative;
}
:is([data-type='YEAR'],[data-type='MONTH']) :is([data-box='menu-container'],[data-box='menu-header']){
display: flex;
}
[data-type='MONTH'] [data-box='menu-month-container']{
display: grid;
}
[data-type='YEAR'] [data-box='menu-year-container']{
display: grid;
}
[data-box='container'][data-type='CALENDAR'] :is([data-box='body-week'],[data-box='body-day']){
display: grid;
}
[data-box='container'][data-type='CALENDAR'] :is([data-box='body-header']){
display: flex;
}
[data-box='body-header'],[data-box='menu-header'] {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 18px;
font-weight: 700;
color: var(--text);
padding: 0;
overflow: hidden;
display: none;
}
:is([data-box='month'],[data-box='year'],[data-box='menu-year']):hover {
color: var(--picker);
}
.calendar--arrow:hover {
border-color: var(--picker);
}
:is([data-box='month'],[data-box='year'],[data-box='menu-year']){
padding: 0px;
cursor: pointer;
position: relative;
font-style: normal;
font-weight: 700;
font-size: 18px;
width: 100%;
height: var(--h_header);
align-items: center;
display: flex;
justify-content: center;
}
[data-box='body-week'] {
font-weight: 400;
grid-template-columns: repeat(7, 1fr);
color: var(--text);
font-size: 1rem;
border-top: 1px solid var(--week-line);
border-bottom: 1px solid var(--week-line);
display: none;
}
[data-box='body-week'] div {
color: var(--text-week);
height: 36px;
background: inherit;
display: flex;
justify-content: center;
align-items: center;
}
[data-box='body-day'] {
grid-template-columns: repeat(7, 1fr);
color: var(--text);
display: none;
}
[data-box='body-day'] div {
display: grid;
place-items: center;
padding: 0px;
position: relative;
cursor: pointer;
width: 100%;
aspect-ratio: 1/1;
font-size: 1rem;
transform: scale(1.005, 0.95);
}
[data-box='body-day'] [tabindex='-1'] {
cursor: no-drop !important;
background-color: inherit;
opacity: 0.3;
text-decoration: line-through;
pointer-events: none;
color: var(--text);
}
:is([aria-placeholder='before'],[aria-placeholder='after']) {
color: var(--disabled);
cursor: pointer;
}
[data-box='body-day'] [aria-placeholder='current'] {
background-color: var(--current);
color: var(--text-current);
font-size: 20px;
font-weight: 700;
border-radius: var(--dateRadius);
}
[data-box='body-day'] [aria-selected='true'][aria-details='DAY'] {
background-color: var(--picker);
border-radius: var(--dateRadius);
border: 2px solid #ebf0fc;
color: var(--text-picker);
}
[data-box='body-day'] :is(.first,.last) {
background-color: var(--picker);
border-radius: var(--dateRadius);
border: 2px solid #ebf0fc;
color: var(--text-picker);
isolation: isolate;
z-index:1;
position: relative;
}
.between:not(:is(.first,.last)) {
position: relative;
border-radius: 0%;
color: var(--text-picker);
background-color: var(--picker);
border-radius: var(--dateRadius);
opacity: 0.75;
}
[aria-placeholder='current'].between {
color: var(--text-color);
}
:is([data-box='arrow'], [data-box='menu-arrow']) {
width: 42px;
height: var(--h_header);
background-color: transparent;
cursor: pointer;
display: flex;
justify-content: flex-start;
align-items: center;
padding: 0px 16px;
}
:is([data-box='arrow'], [data-box='menu-arrow']):has(.right) {
justify-content: flex-end;
}
.calendar--arrow {
border: solid var(--text);
border-width: 0 2px 2px 0;
display: inline-block;
padding: 3px;
}
.calendar--arrow.right {
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
.calendar--arrow.left {
transform: rotate(135deg);
-webkit-transform: rotate(135deg);
}
.calendar--arrow.up {
transform: rotate(-135deg);
-webkit-transform: rotate(-135deg);
}
.calendar--arrow.down {
transform: rotate(45deg);
-webkit-transform: rotate(45deg);
}
[data-box='menu-container'] {
flex-direction: column;
width: var(--width);
display: none;
}
[data-box='menu-month-container'] {
display: none;
grid-template-columns: repeat(3, 1fr);
grid-gap: 8px;
padding: 16px;
}
[data-box='menu-year-container'] {
display: none;
grid-template-columns: repeat(4, 1fr);
grid-gap: 8px;
padding: 16px;
}
[attr-menu-content] {
border-radius: 6px;
padding: 8px;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
}
[attr-menu-content]:hover {
background-color: #F3F4F6;
}
[attr-menu-content='true'] {
background-color: var(--picker) !important;
color: var(--text-picker) !important;
}
`;
var onWeeks = (lang) => {
if (lang === "th" || lang === "thai") {
return ["\u0E2D\u0E32", "\u0E08", "\u0E2D", "\u0E1E", "\u0E1E\u0E24", "\u0E28", "\u0E2A"];
} else if (lang === "en" || lang === "english") {
return ["Sun", "Mon", "Tue", "Wen", "Thu", "Fri", "Sat"];
} else return ["Sun", "Mon", "Tue", "Wen", "Thu", "Fri", "Sat"];
};
// src/main.ts
var main = class {
constructor(id, category) {
/**
* check สถานะของปฏิทินว่าเป็น created หรือไม่
*/
this.created = false;
/**
* ประเภทของปฏิทิน
*/
this.calendarType = "CALENDAR";
this.eventListeners = [];
// จำนวนปีที่จะแสดงในเมนูปี
this.countYear = 15;
this.lang = "en";
this.year = "en";
this.min = /* @__PURE__ */ new Date();
this.max = /* @__PURE__ */ new Date("2200-01-01");
/**
* ค่าที่ใช้ในการแสดง UI
*/
this.ui_value = /* @__PURE__ */ new Date();
this.style = {};
this.makeInputEvent = (container) => {
const hiddenInput = document.createElement("input");
hiddenInput.type = "text";
hiddenInput.setAttribute("aria-label", "\u0E04\u0E27\u0E1A\u0E04\u0E38\u0E21\u0E1B\u0E0F\u0E34\u0E17\u0E34\u0E19\u0E14\u0E49\u0E27\u0E22\u0E41\u0E1B\u0E49\u0E19\u0E1E\u0E34\u0E21\u0E1E\u0E4C");
hiddenInput.setAttribute("data-box", "hidden-input");
hiddenInput.style.cssText = `
position: absolute !important;
width: 1px !important;
height: 1px !important;
padding: 0 !important;
margin: -1px !important;
overflow: hidden !important;
clip: rect(0, 0, 0, 0) !important;
white-space: nowrap !important;
border: 0 !important;
z-index: -1 !important;
top: 0 !important;
`;
container.appendChild(hiddenInput);
this.addEventListenerWithCleanup(container, "click", () => {
hiddenInput.focus();
});
this.addEventListenerWithCleanup(hiddenInput, "keydown", (e) => {
const keyEvent = e;
keyEvent.preventDefault();
const d = this.ui_value;
let year = d.getFullYear();
let month = d.getMonth() + 1;
const fnForArrowUpAndDown = () => {
if (this.calendarType === "YEAR") {
this.onClickMonthOrYear(container, "YEAR");
} else {
this.render();
}
};
switch (keyEvent.key) {
case "ArrowRight":
this.onChangeMonth("RIGHT");
this.announceChange("\u0E40\u0E14\u0E37\u0E2D\u0E19\u0E16\u0E31\u0E14\u0E44\u0E1B");
break;
case "ArrowLeft":
this.onChangeMonth("LEFT");
this.announceChange("\u0E40\u0E14\u0E37\u0E2D\u0E19\u0E01\u0E48\u0E2D\u0E19\u0E2B\u0E19\u0E49\u0E32");
break;
case "ArrowUp":
this.ui_value = /* @__PURE__ */ new Date(`${year + 1}-${month}-01`);
fnForArrowUpAndDown();
this.announceChange("\u0E1B\u0E35\u0E16\u0E31\u0E14\u0E44\u0E1B");
break;
case "ArrowDown":
this.ui_value = /* @__PURE__ */ new Date(`${year - 1}-${month}-01`);
fnForArrowUpAndDown();
this.announceChange("\u0E1B\u0E35\u0E01\u0E48\u0E2D\u0E19\u0E2B\u0E19\u0E49\u0E32");
break;
case "Enter":
this.calendarType = "CALENDAR";
this.announceChange("\u0E01\u0E25\u0E31\u0E1A\u0E2A\u0E39\u0E48\u0E21\u0E38\u0E21\u0E21\u0E2D\u0E07\u0E1B\u0E0F\u0E34\u0E17\u0E34\u0E19");
this.render();
break;
case "Escape":
this.calendarType = "CALENDAR";
this.ui_value = this.getDateValue();
this.announceChange("\u0E01\u0E25\u0E31\u0E1A\u0E44\u0E1B\u0E2B\u0E19\u0E49\u0E32\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48\u0E40\u0E25\u0E37\u0E2D\u0E01");
this.render();
break;
}
});
};
/**
* สร้าง elements สำหรับ header ของปฏิทิน หรือ เมนู
* @param container [data-box="container"] || [data-box="menu-container"]
*/
this.makeHeader = (container, type) => {
const header = document.createElement("div");
const attr = type === "calendar" ? "body-header" : "menu-header";
header.setAttribute("data-box", attr);
const { month, year } = this.getConfigValue();
const arrowLeft = this.createArrowButton("left");
header.appendChild(arrowLeft);
if (type === "calendar") {
const textMonth = document.createElement("div");
textMonth.setAttribute("data-box", "month");
textMonth.innerHTML = `${month}`;
header.appendChild(textMonth);
}
const textYear = document.createElement("div");
const yearAttr = type === "calendar" ? "year" : "menu-year";
textYear.setAttribute("data-box", yearAttr);
textYear.innerHTML = `${year}`;
header.appendChild(textYear);
const arrowRight = this.createArrowButton("right");
header.appendChild(arrowRight);
container.appendChild(header);
};
/**
* สร้าง elements สำหรับแสดงวันในสัปดาห์
*/
this.makeWeek = (container) => {
const week = document.createElement("div");
week.setAttribute("data-box", "body-week");
const fragment = document.createDocumentFragment();
onWeeks(this.lang).forEach((v) => {
const div = document.createElement("div");
div.textContent = v;
div.setAttribute("data-box", "week");
fragment.appendChild(div);
});
week.appendChild(fragment);
container.appendChild(week);
};
/**
* สร้าง elements สำหรับแสดงวันที่
*/
this.makeDay = (container) => {
const dayBody = document.createElement("div");
dayBody.setAttribute("data-box", "body-day");
const days = this.createDays();
const fragment = document.createDocumentFragment();
days.children.forEach((day) => {
var _a;
const dayElement = document.createElement("div");
if (day.props) {
Object.entries(day.props).forEach(([key, value]) => {
dayElement.setAttribute(key, value);
});
}
if (typeof day.children === "string") {
dayElement.textContent = day.children;
}
if ((_a = day.methods) == null ? void 0 : _a.click) {
dayElement.addEventListener("click", day.methods.click);
}
fragment.appendChild(dayElement);
});
dayBody.appendChild(fragment);
container.appendChild(dayBody);
};
/**
* สร้าง box elements สำหรับเมนูเลือกเดือนและปี
* @param container [data-box="container"]
*/
this.makeMenuContainer = (container) => {
const menu = document.createElement("div");
menu.setAttribute("data-box", "menu-container");
this.makeHeader(menu, "menu");
this.createMonthButton(menu);
this.createYearButton(menu);
container.appendChild(menu);
};
this.id = id;
this.category = category;
this.initStyleAndCss();
this.setupAccessibility();
}
// abstract render(): void
render() {
if (!this.isClient()) return;
const { root, rootContainer } = this.validateRootEl();
if (!root) return;
this.applyStyles();
if (rootContainer) {
rootContainer.setAttribute("data-type", this.calendarType);
if (this.calendarType === "CALENDAR") {
this.updateContentCalendar(rootContainer);
} else {
this.updateContentMenu(rootContainer);
}
} else {
this.createInitialContainer(root);
}
this.initInputHidden();
}
/**
* update การ render ส่วนของเมนู
* @param container [data-box="container"]
*/
updateContentMenu(container) {
const menu = container.querySelector('[data-box="menu-container"]');
if (!menu) return;
const yearTitle = menu.querySelector('[data-box="menu-year"]');
const { year } = this.getConfigValue();
if (yearTitle) {
yearTitle.textContent = `${year}`;
}
}
/**
* update การ render ส่วนของปฏิทิน
* @param container [data-box="container"]
*/
updateContentCalendar(container) {
const daysContainer = container.querySelector('[data-box="body-day"]');
const monthTitle = container.querySelector('[data-box="month"]');
const yearTitle = container.querySelector('[data-box="year"]');
if (daysContainer) {
renderBodyDay(daysContainer, this.createDays());
}
const { month, year } = this.getConfigValue();
if (yearTitle) {
yearTitle.textContent = `${year}`;
}
if (monthTitle) {
monthTitle.textContent = `${month}`;
}
}
getConfigValue() {
const yearType = this.year === "th" ? 543 : 0;
const month = this.getMonth(this.ui_value)[this.lang || "th"];
const year = this.ui_value.getFullYear() + yearType;
return {
year,
month
};
}
validateRootEl() {
const root = document.querySelector(this.id);
if (!this.isClient() && !root)
return { root: null, rootContainer: null };
return {
root,
rootContainer: (root == null ? void 0 : root.querySelector(`[data-box="container"]`)) || null
};
}
isClient() {
return typeof window !== "undefined";
}
createDate(date, placeholder, isDisabled = false, className) {
const data = {
tag: "div",
props: {
role: "gridcell",
"aria-details": this.category,
// สำหรับเช็คว่าเป็นวันที่ระหว่างหรือไม่
"aria-label": (0, import_adc_directive.dateToCombine)(date).valueOfDate,
// ใช้เป็นค่าสำหรับ update this.ui_value
"aria-selected": this.validateCheckPicker(date).toString(),
// สำหรับเช็คว่าเป็นวันที่ที่เลือกหรือไม่ datepicker
tabindex: isDisabled ? "-1" : "0",
// สำหรับเช็คว่าเป็นวันที่ disabled หรือไม่
"aria-placeholder": placeholder
},
children: date.getDate() + ""
};
if (className) {
data.props["class"] = className;
}
return data;
}
onChangeMonth(type) {
const d = this.ui_value;
let year = d.getFullYear();
let month = d.getMonth() + 1;
if (this.calendarType === "CALENDAR") {
const date = /* @__PURE__ */ new Date(`${year}-${month}-01`);
this.ui_value = (0, import_adc_directive.addMonth)(date, type === "LEFT" ? -1 : 1);
if (typeof this.nextMonth == "function") {
this.nextMonth(this.ui_value);
}
} else if (this.calendarType === "MONTH") {
year += type === "LEFT" ? -1 : 1;
this.ui_value = /* @__PURE__ */ new Date(`${year}-${month}-01`);
} else if (this.calendarType === "YEAR") {
const num = type === "LEFT" ? -16 : 16;
this.ui_value = /* @__PURE__ */ new Date(`${year + num}-${month}-01`);
this.renderUpdateYearMenu();
}
this.render();
}
/**
* stop คือการทำลาย container ปฏิธินทั้งหมด
*/
stop() {
if (!this.created) return;
requestAnimationFrame(() => {
const { rootContainer } = this.validateRootEl();
if (rootContainer) {
rootContainer.remove();
this.destroyEvent();
}
this.created = false;
});
}
/**
* ใช้สำหรับการนำค่า style ที่กำหนดไว้ใน this.style ไปใช้กับ root element
* จะถูกเรียกทุกครั้งที่มีการ render เพื่อให้มั่นใจว่า style เป็นปัจจุบันเสมอ
*/
applyStyles() {
const { root } = this.validateRootEl();
if (!root) return;
if (this.style && typeof this.style === "object") {
for (const key in this.style) {
if (Object.prototype.hasOwnProperty.call(this.style, key)) {
const value = `${this.style[key]}`;
root.style.setProperty(`--${key}`, value, "important");
}
}
}
}
/**
* แยกส่วนของการกำหนด style และการเพิ่ม CSS ออกจากกัน
* - การกำหนด style จะทำทุกครั้งที่ render
* - การเพิ่ม CSS จะทำเพียงครั้งเดียวตอนสร้าง calendar
*/
initStyleAndCss() {
const { root } = this.validateRootEl();
if (!root) return;
this.applyStyles();
if (root.getAttribute("calendar") !== "root") {
const styleCss = document.createElement("style");
styleCss.textContent = css;
root.appendChild(styleCss);
root.setAttribute("calendar", "root");
}
}
/**
* ตรวจสอบว่าวันที่ที่เลือกอยู่ในช่วงวันที่ระหว่างหรือไม่
* @param date
* @param min
* @param max
*/
onCheckDisabled(date, min, max) {
const dateValueOf = date.valueOf();
const minValueOf = (0, import_adc_directive.addDate)(min, -1).valueOf();
const maxValueOf = max.valueOf();
return dateValueOf < minValueOf || dateValueOf > maxValueOf;
}
checkSameDate(a, b) {
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
}
/**
* get ค่าวันแรกและวันสุดท้ายของเดือน
* @param date วันที่ใดๆในเดือนนั้น
*/
onBeforeAfterDay(date) {
let first_day = new Date(date.getFullYear(), date.getMonth(), 1);
let last_day = new Date(
date.getFullYear(),
date.getMonth(),
this.getMonth(date).days
);
return [first_day.getDay(), 7 - (last_day.getDay() + 1)];
}
/**
* แปลงวันที่เป็น string
* หาวันที่โดยเฉพาะเดือนกุมภาพันธ์
* @param date วันที่
*/
getYear(date) {
const _getFebDays = (year) => {
let isLeapYear = year % 4 === 0 && year % 100 !== 0 && year % 400 !== 0 || year % 100 === 0 && year % 400 === 0;
return isLeapYear ? 29 : 28;
};
const items = [];
lists.forEach((m, i) => {
m.year = date.getFullYear();
if (i === 1) {
m.days = _getFebDays(date.getFullYear());
}
items.push(m);
});
return items;
}
getMonth(date) {
const year = this.getYear(date);
return year[date.getMonth()];
}
/**
* จัดการเมื่อมีการคลิกที่ปุ่มเปลี่ยนเดือนหรือปีในขณะที่ this.calendarType คือ 'CALENDAR'
* @param container [data-box="container"]
*/
onClickMonthOrYear(container, type) {
this.calendarType = type;
if (type === "MONTH") {
const months = container.querySelector(
'[data-box="menu-month-container"]'
);
if (months) {
const val = String(this.ui_value.getMonth() + 1);
Array.from(months.children).forEach((element) => {
const active = element.getAttribute("data-month") === val;
element.setAttribute("attr-menu-content", String(active));
});
}
} else if (type === "YEAR") {
this.renderUpdateYearMenu();
}
this.render();
}
/**
* update render เนื้อหาของปฏิทินเมื่อมีการเปลี่ยนปี
* @param typeClick ประเภทการคลิก (arrow,menu year)
* @param year ปีที่ต้องการอัพเดท
*/
renderUpdateYearMenu() {
const { rootContainer } = this.validateRootEl();
if (!rootContainer) return;
const years = rootContainer.querySelector(
'[data-box="menu-year-container"]'
);
if (years) {
const { year } = this.getConfigValue();
Array.from(years.children).forEach((element, i) => {
const val = year + i;
const dataYear = this.year === "en" ? val : val - 543;
element.setAttribute("attr-menu-content", String(i === 0));
element.setAttribute("data-year", String(dataYear));
element.innerHTML = String(val);
});
}
}
//---------------------- เกิดขึ้นครั้งเดียว Create Element --------------------------//
/**
* สร้าง container และ elements ที่จำเป็นสำหรับการแสดงปฏิทิน
* จะถูกเรียกใช้ครั้งแรกเมื่อปฏิทินถูกสร้างขึ้นเพียงครั้งเดียว
* @param root [calendar="root"]
*/
createInitialContainer(root) {
if (!root) return;
this.created = true;
const container = document.createElement("div");
container.setAttribute("data-type", this.calendarType);
container.setAttribute("data-box", "container");
root.appendChild(container);
this.makeHeader(container, "calendar");
this.makeWeek(container);
this.makeDay(container);
this.makeMenuContainer(container);
this.makeInputEvent(container);
this.setupEventListeners();
}
// เพิ่มฟังก์ชันสำหรับประกาศการเปลี่ยนแปลงให้ screen reader
announceChange(message) {
const announcer = document.querySelector('[role="status"]');
if (announcer) {
announcer.textContent = message;
}
}
/**
* สร้าง menu elements content สำหรับเลือกปี
*/
createYearButton(menu) {
const menuYear = document.createElement("div");
menuYear.setAttribute("data-box", "menu-year-container");
const { year } = this.getConfigValue();
for (let i = 0; i <= this.countYear; i++) {
const yearBtn = document.createElement("button");
const val = year + i;
yearBtn.textContent = String(val);
yearBtn.setAttribute("attr-menu-content", String(i === 0));
yearBtn.setAttribute(
"data-year",
String(this.year === "en" ? val : val - 543)
);
menuYear.appendChild(yearBtn);
}
menu.appendChild(menuYear);
}
/**
* สร้าง menu elements content สำหรับเลือกเดือน
*/
createMonthButton(menu) {
const menuMonth = document.createElement("div");
menuMonth.setAttribute("data-box", "menu-month-container");
const months = this.getYear(this.ui_value);
months.forEach((month) => {
const monthBtn = document.createElement("button");
monthBtn.textContent = month[this.lang];
monthBtn.setAttribute("data-month", String(+month.month_value));
monthBtn.setAttribute(
"attr-menu-content",
String(+month.month_value - 1 === this.ui_value.getMonth())
);
menuMonth.appendChild(monthBtn);
});
menu.appendChild(menuMonth);
}
/**
* สร้าง elements สำหรับปุ่มเปลี่ยนเดือนหรือปี
* @param direction ทิศทางของปุ่ม
*/
createArrowButton(direction) {
const button = document.createElement("button");
button.setAttribute("data-box", "arrow");
button.setAttribute("data-box", "arrow");
const span = document.createElement("span");
span.classList.add("calendar--arrow", direction.toLocaleLowerCase());
button.appendChild(span);
return button;
}
//---------------------x เกิดขึ้นครั้งเดียว Create Element x-------------------------//
//---------------------- setUpEvent --------------------------//
destroyEvent() {
this.eventListeners.forEach(({ element, type, handler }) => {
element.removeEventListener(type, handler);
});
this.eventListeners = [];
}
addEventListenerWithCleanup(element, type, handler) {
element.addEventListener(type, handler);
this.eventListeners.push({ element, type, handler });
}
/**
* ตั้งค่า ARIA attributes สำหรับการเข้าถึง
*/
setupAccessibility() {
if (!this.isClient()) return;
const { root } = this.validateRootEl();
if (!root) return;
root.setAttribute("role", "application");
root.setAttribute("aria-label", "\u0E1B\u0E0F\u0E34\u0E17\u0E34\u0E19");
this.setupScreenReaderAnnouncements();
}
/**
* สร้าง element สำหรับการอ่านข้อความผ่าน screen reader
*/
setupScreenReaderAnnouncements() {
const { root } = this.validateRootEl();
if (!root) return;
const announcer = document.createElement("div");
announcer.setAttribute("role", "status");
announcer.setAttribute("aria-live", "polite");
announcer.classList.add("sr-only");
announcer.style.display = "none";
root == null ? void 0 : root.appendChild(announcer);
}
/***
* ตั้งค่า focus ให้กับ input hidden
*/
initInputHidden() {
const { rootContainer } = this.validateRootEl();
if (!rootContainer) return;
const input = rootContainer.querySelector(
'[data-box="hidden-input"]'
);
if (input) {
input.focus();
}
}
// เพิ่มเมธอดสำหรับตั้งค่า event handlers แบบ delegation
setupEventListeners() {
const { root, rootContainer } = this.validateRootEl();
if (!root || !rootContainer) return;
this.addEventListenerWithCleanup(root, "click", (e) => {
var _a, _b, _c;
const target = e.target;
const dateTypeCalendar = (_a = target.closest('[role="gridcell"]')) == null ? void 0 : _a.getAttribute("aria-label");
if (dateTypeCalendar) {
const dateVal = new Date(dateTypeCalendar);
this.onDatePicker(dateVal);
}
const yearButton = target.closest('[data-box="year"]');
if (yearButton) {
this.onClickMonthOrYear(rootContainer, "YEAR");
}
const monthButton = target.closest('[data-box="month"]');
if (monthButton) {
this.onClickMonthOrYear(rootContainer, "MONTH");
}
const arrowButton = target.closest('[data-box="arrow"]');
if (arrowButton) {
const direction = arrowButton.querySelector(".left") ? "LEFT" : "RIGHT";
this.onChangeMonth(direction);
}
const menuYear = target.closest('[data-box="menu-year"]');
if (menuYear) {
this.calendarType = "CALENDAR";
this.render();
}
const menuDataMonth = (_b = target.closest("[data-month]")) == null ? void 0 : _b.getAttribute("data-month");
if (menuDataMonth) {
this.ui_value = /* @__PURE__ */ new Date(
`${this.ui_value.getFullYear()}-${menuDataMonth}-01`
);
this.calendarType = "CALENDAR";
this.render();
}
const menuDataYear = (_c = target.closest("[data-year]")) == null ? void 0 : _c.getAttribute("data-year");
if (menuDataYear) {
this.ui_value = /* @__PURE__ */ new Date(
`${menuDataYear}-${this.ui_value.getMonth() + 1}-01`
);
this.calendarType = "CALENDAR";
this.render();
}
});
}
//---------------------x setUpEvent x-------------------------//
};
var main_default = main;
// src/calendar.ts
var swCalendar = class extends main_default {
constructor(id, config) {
super(id, "DAY");
/*------------------------------Set---------------------------------*/
/*-------------x----------------Set-----------------x---------------*/
this.value = /* @__PURE__ */ new Date();
this.validateConfig(config);
this.initializeState(config);
}
/**
* กำหนดค่าเริ่มต้นให้กับ state ทั้งหมดของ Calendar
* @private
* @param config - ค่า configuration ที่รับมาจาก constructor
*/
initializeState(config) {
this.value = config.value || /* @__PURE__ */ new Date();
this.ui_value = config.value || /* @__PURE__ */ new Date();
this.lang = config.lang || "en";
this.year = config.year === "th" ? "th" : "en";
this.nextDate = config.nextDate;
this.nextMonth = config.nextMonth;
this.setDateOfMinMax(config);
if (typeof config.style === "object" && config.style !== null) {
this.style = __spreadValues(__spreadValues({}, this.style), config.style);
}
}
/**
* ตรวจสอบความถูกต้องของ config
* @private
*/
validateConfig(config) {
if (!config.value) {
throw new DateValidationError("\u0E15\u0E49\u0E2D\u0E07\u0E23\u0E30\u0E1A\u0E38\u0E04\u0E48\u0E32 value \u0E40\u0E23\u0E34\u0E48\u0E21\u0E15\u0E49\u0E19");
}
if (config.min && config.max && config.min > config.max) {
throw new DateValidationError("\u0E04\u0E48\u0E32 min \u0E15\u0E49\u0E2D\u0E07\u0E19\u0E49\u0E2D\u0E22\u0E01\u0E27\u0E48\u0E32\u0E2B\u0E23\u0E37\u0E2D\u0E40\u0E17\u0E48\u0E32\u0E01\u0E31\u0E1A max");
}
}
/**
* ล้างการเลือกวันที่
* @public
*/
clear() {
this.onSetValue(/* @__PURE__ */ new Date());
this.render();
}
/**
* อัพเดทค่า config ของปฏิทิน
* @public
* @param config - ค่า config ใหม่
* @throws {DateValidationError} เมื่อค่า config ไม่ถูกต้อง
*/
update(config) {
this.validateConfig(__spreadValues(__spreadValues({}, this.getState()), config));
if (config.style && typeof config.style === "object") {
this.style = __spreadValues(__spreadValues({}, this.style), config.style);
}
if (config.value) {
this.setDateOfMinMax(config);
this.onSetValue(config.value);
}
this.render();
}
/**
* ดึงค่าสถานะปัจจุบันของปฏิทิน
* @public
* @returns สถานะปัจจุบันของปฏิทิน
*/
getState() {
return {
value: this.value,
min: this.min,
max: this.max,
lang: this.lang,
year: this.year,
style: this.style
};
}
createDays() {
const days = {
tag: "div",
props: {
calendar: `body-day`
},
children: []
};
const date = this.ui_value;
const [first_week, last_week] = this.onBeforeAfterDay(date);
const _beforeDays = () => {
const lists2 = [];
for (let i = 0; i < first_week; i++) {
const index_month = date.getMonth() === 0 ? 11 : date.getMonth() - 1;
const days2 = this.getYear(date)[index_month].days;
const day = days2 - (first_week - 1) + i;
const _year = date.getMonth() === 0 ? date.getFullYear() - 1 : date.getFullYear();
lists2.push(new Date(_year, index_month, day));
}
return lists2;
};
const beforeLists = [];
const dayLists = [];
const afterLists = [];
_beforeDays().forEach((_date) => {
beforeLists.push(
this.createDate(
_date,
"before",
this.onCheckDisabled(_date, this.min, this.max)
)
);
});
for (let i = 0; i < this.getMonth(date).days; i++) {
const _date = new Date(date.getFullYear(), date.getMonth(), i + 1);
const current = this.checkSameDate(/* @__PURE__ */ new Date(), _date) ? "current" : "date";
dayLists.push(
this.createDate(
_date,
current,
this.onCheckDisabled(_date, this.min, this.max)
)
);
}
for (let i = 0; i < last_week; i++) {
const _year = this.ui_value.getMonth() === 11 ? this.ui_value.getFullYear() + 1 : this.ui_value.getFullYear();
const _month = this.ui_value.getMonth() === 11 ? 0 : this.ui_value.getMonth() + 1;
const _date = new Date(_year, _month, i + 1);
afterLists.push(
this.createDate(
_date,
"after",
this.onCheckDisabled(_date, this.min, this.max)
)
);
}
days.children = [...beforeLists, ...dayLists, ...afterLists];
return days;
}
validateCheckPicker(date) {
return this.checkSameDate(date, this.value);
}
getDateValue() {
return this.value;
}
onDatePicker(date) {
this.onSetValue(date);
if (typeof this.nextDate == "function") {
this.nextDate(date);
}
this.render();
}
setDateOfMinMax(config) {
const valueOfDate = this.value.valueOf();
if (config.min instanceof Date && config.min.valueOf() <= valueOfDate) {
this.min = config.min;
}
if (config.max instanceof Date && config.max.valueOf() >= valueOfDate) {
this.max = config.max;
}
}
onSetValue(date) {
this.ui_value = date;
this.value = date;
}
};
// src/calendarBetween.ts
var swCalendarBetween = class extends main_default {
constructor(id, config) {
super(id, "BETWEEN");
this.values = [/* @__PURE__ */ new Date(), /* @__PURE__ */ new Date()];
this.betweens = [/* @__PURE__ */ new Date(), /* @__PURE__ */ new Date()];
this.validateConfig(config);
this.initializeState(config);
}
/**
* กำหนดค่าเริ่มต้นให้กับ state ทั้งหมดของ Calendar
* @private
* @param config - ค่า configuration ที่รับมาจาก constructor
*/
initializeState(config) {
const startDate = config.values[0] || /* @__PURE__ */ new Date();
const endDate = config.values[1] || /* @__PURE__ */ new Date();
this.values = [startDate, endDate];
this.ui_value = this.getValues()[0];
this.betweens = this.values;
this.lang = config.lang || "en";
this.year = config.year === "th" ? "th" : "en";
this.nextDate = config.nextDate;
this.nextMonth = config.nextMonth;
this.setDateOfMinMax(config);
if (typeof config.style === "object" && config.style !== null) {
this.style = __spreadValues(__spreadValues({}, this.style), config.style);
}
}
update(config) {
this.validateConfig(__spreadValues(__spreadValues({}, this.getState()), config));
if (config.style && typeof config.style === "object") {
this.style = __spreadValues(__spreadValues({}, this.style), config.style);
}
if (config.values) {
this.setDateOfMinMax(config);
this.onSetValue(config.values);
}
this.render();
}
getState() {
return {
id: this.id,
value: this.values,
ui_value: this.ui_value,
el: this.validateRootEl().root
};
}
createDays() {
const days = {
tag: "div",
props: {
calendar: `body-day`
},
children: []
};
const date = this.ui_value;
const [first_week, last_week] = this.onBeforeAfterDay(date);
const dateBetweens = this.getDatesInRange().map(
(d) => this.dateToString(d)
);
const clsBetween = (date2) => {
const index = dateBetweens.indexOf(this.dateToString(date2));
let cls = [];
if (this.category == "BETWEEN") {
if (index !== -1) cls.push("between");
if (index == 0) cls.push("first");
if (index == dateBetweens.length - 1) cls.push("last");
}
return cls.join(" ");
};
const _beforeDays = () => {
const lists2 = [];
for (let i = 0; i < first_week; i++) {
const index_month = date.getMonth() === 0 ? 11 : date.getMonth() - 1;
const days2 = this.getYear(date)[index_month].days;
const day = days2 - (first_week - 1) + i;
const _year = date.getMonth() === 0 ? date.getFullYear() - 1 : date.getFullYear();
lists2.push(new Date(_year, index_month, day));
}
return lists2;
};
const beforeLists = [];
const dayLists = [];
const afterLists = [];
_beforeDays().forEach((_date) => {
beforeLists.push(
this.createDate(
_date,
"before",
this.onCheckDisabled(_date, this.min, this.max),
clsBetween(_date)
)
);
});
for (let i = 0; i < this.getMonth(date).days; i++) {
const _date = new Date(date.getFullYear(), date.getMonth(), i + 1);
const current = this.checkSameDate(/* @__PURE__ */ new Date(), _date) ? "current" : "date";
dayLists.push(
this.createDate(
_date,
current,
this.onCheckDisabled(_date, this.min, this.max),
clsBetween(_date)
)
);
}
for (let i = 0; i < last_week; i++) {
const _year = this.ui_value.getMonth() === 11 ? this.ui_value.getFullYear() + 1 : this.ui_value.getFullYear();
const _month = this.ui_value.getMonth() === 11 ? 0 : this.ui_value.getMonth() + 1;
const _date = new Date(_year, _month, i + 1);
afterLists.push(
this.createDate(
_date,
"after",
this.onCheckDisabled(_date, this.min, this.max),
clsBetween(_date)
)
);
}
days.children = [...beforeLists, ...dayLists, ...afterLists];
return days;
}
getValues() {
const startDate = this.values[0] < this.values[1] ? this.values[0] : this.values[1];
const endDate = this.values[0] > this.values[1] ? this.values[0] : this.values[1];
this.values = [startDate, endDate];
return [startDate, endDate];
}
getDatesInRange() {
const lists2 = [];
const [startDate, endDate] = this.getValues();
const date = new Date(startDate.getTime());
while (date <= endDate) {
lists2.push(new Date(date));
date.setDate(date.getDate() + 1);
}
return lists2;
}
dateToString(date) {
const day = date.getDate();
const month = date.getMonth() + 1;
const year = date.getFullYear();
const currentDate = `${year}-${month}-${day}`;
return currentDate;
}
onSortDate(a, b) {
const startDate = a < b ? a : b;
const endDate = a > b ? a : b;
return [startDate, endDate];
}
validateCheckPicker(date) {
return this.checkSameDate(date, this.betweens[0]);
}
getDateValue() {
return this.values[0];
}
onDatePicker(date) {
this.category = "DAY";
if (this.betweens[0] === void 0) {
this.betweens[0] = date;
} else if (this.betweens[0] && this.betweens[1] === void 0) {
this.category = "BETWEEN";
this.betweens = this.onSortDate(this.betweens[0], date);
this.values = [this.betweens[0], this.betweens[1]];
this.onSetValue(this.values);
if (typeof this.nextDate == "function") {
this.nextDate(this.values);
}
} else if (this.betweens[0] && this.betweens[1]) {
this.betweens[0] = date;
this.betweens[1] = void 0;
}
this.render();
}
setDateOfMinMax(config) {
const [start, end] = this.getValues();
const valueOfStart = start.valueOf();
const valueOfEnd = end.valueOf();
if (config.min instanceof Date && config.min.valueOf() <= valueOfStart) {
this.min = config.min;
}
if (config.max instanceof Date && config.max.valueOf() >= valueOfEnd) {
this.max = config.max;
}
}
onSetValue(dates) {
this.ui_value = dates[0];
this.values = dates;
}
/**
* ตรวจสอบความถูกต้องของ config
* @private
*/
validateConfig(config) {
if (config.values.length !== 2) {
throw new DateValidationError("\u0E15\u0E49\u0E2D\u0E07\u0E23\u0E30\u0E1A\u0E38\u0E04\u0E48\u0E32 Date between \u0E40\u0E23\u0E34\u0E48\u0E21\u0E15\u0E49\u0E19");
}
if (config.min && config.max && config.min > config.max) {
throw new DateValidationError("\u0E04\u0E48\u0E32 min \u0E15\u0E49\u0E2D\u0E07\u0E19\u0E49\u0E2D\u0E22\u0E01\u0E27\u0E48\u0E32\u0E2B\u0E23\u0E37\u0E2D\u0E40\u0E17\u0E48\u0E32\u0E01\u0E31\u0E1A max");
}
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
swCalendar,
swCalendarBetween
});