UNPKG

adc-calendar

Version:

Calendar ที่มีทั้ง EN | TH และสามารถ เป็นจาก ค.ศ. เป็น พ.ศ. และ custom calendar ได้ตามต้องการ

1,453 lines (1,407 loc) 47.3 kB
"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 });