@typescript-calendar-lib/core 0.3.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/index.d.ts +25 -1
- package/dist/index.js +29 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -39,6 +39,12 @@ export declare function getWeekdayHeaders(locale: Locale, weekStart: WeekStart):
|
|
|
39
39
|
export declare function getMonthName(locale: Locale, month: number): string;
|
|
40
40
|
//#endregion
|
|
41
41
|
//#region src/utils.d.ts
|
|
42
|
+
interface CalendarCellState {
|
|
43
|
+
isWeekend: boolean;
|
|
44
|
+
isToday: boolean;
|
|
45
|
+
isHighlight: boolean;
|
|
46
|
+
isInRange: boolean;
|
|
47
|
+
}
|
|
42
48
|
/** 月初日(1日)を返す */
|
|
43
49
|
export declare function firstDayOfMonth(year: number, month: number): Date;
|
|
44
50
|
/** 月末日を返す */
|
|
@@ -55,11 +61,24 @@ export declare function isDateInRange(date: Date, range?: {
|
|
|
55
61
|
}): boolean;
|
|
56
62
|
/** 日付が今日と一致するか(日付のみ比較) */
|
|
57
63
|
export declare function isSameDay(a: Date, b: Date): boolean;
|
|
64
|
+
/** 日付セルの表示状態を計算する */
|
|
65
|
+
export declare function getCalendarCellState(date: Date, options?: {
|
|
66
|
+
today?: Date;
|
|
67
|
+
highlight?: Date;
|
|
68
|
+
range?: {
|
|
69
|
+
from: Date;
|
|
70
|
+
to: Date;
|
|
71
|
+
};
|
|
72
|
+
}): CalendarCellState;
|
|
58
73
|
/** 日付が範囲の開始年から終了年までの月リストを返す */
|
|
59
74
|
export declare function getMonthRange(from: Date, to: Date): {
|
|
60
75
|
year: number;
|
|
61
76
|
month: number;
|
|
62
77
|
}[];
|
|
78
|
+
/** グレゴリオ暦のうるう年判定(4で割れるが100では割れない、または400で割れる) */
|
|
79
|
+
export declare function isLeapYear(year: number): boolean;
|
|
80
|
+
/** 月の日数(1-31)を返す */
|
|
81
|
+
export declare function daysInMonth(year: number, month: number): number;
|
|
63
82
|
//#endregion
|
|
64
83
|
//#region src/validation.d.ts
|
|
65
84
|
/** サポートする年の最小値(JS Date は 0-99 を 1900+年 と解釈するため 1 から) */
|
|
@@ -72,8 +91,13 @@ export declare function assertValidDate(date: Date): void;
|
|
|
72
91
|
* ローカルの指定日 00:00:00 を生成する。
|
|
73
92
|
* `new Date(year, ...)` は year 0-99 を 1900+year と解釈するため、
|
|
74
93
|
* setFullYear を使って year 0-99 も正しく扱えるようにする。
|
|
94
|
+
*
|
|
95
|
+
* - year は 1-9999、monthIndex は 0-12、day は 0-31 の整数である必要がある(それ以外は RangeError)
|
|
96
|
+
* - monthIndex 12 は翌年1月(`new Date` と同じロールオーバー。lastDayOfMonth が 12月の月末取得に使う)
|
|
97
|
+
* - day 0 は前月の月末(`new Date` と同じ規則)
|
|
98
|
+
* - day がその月の日数を超える場合は翌月にロールする(`new Date` と同じ挙動)
|
|
75
99
|
*/
|
|
76
100
|
export declare function createDate(year: number, monthIndex: number, day: number): Date;
|
|
77
101
|
//#endregion
|
|
78
|
-
export type { CalendarOptions, CalendarRangeOptions, CalendarYearOptions, HighlightStyle, Locale, RenderMonthOptions, WeekStart };
|
|
102
|
+
export type { CalendarCellState, CalendarOptions, CalendarRangeOptions, CalendarYearOptions, HighlightStyle, Locale, LocaleData, RenderMonthOptions, WeekStart };
|
|
79
103
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -32,8 +32,16 @@ function assertValidDate(date) {
|
|
|
32
32
|
* ローカルの指定日 00:00:00 を生成する。
|
|
33
33
|
* `new Date(year, ...)` は year 0-99 を 1900+year と解釈するため、
|
|
34
34
|
* setFullYear を使って year 0-99 も正しく扱えるようにする。
|
|
35
|
+
*
|
|
36
|
+
* - year は 1-9999、monthIndex は 0-12、day は 0-31 の整数である必要がある(それ以外は RangeError)
|
|
37
|
+
* - monthIndex 12 は翌年1月(`new Date` と同じロールオーバー。lastDayOfMonth が 12月の月末取得に使う)
|
|
38
|
+
* - day 0 は前月の月末(`new Date` と同じ規則)
|
|
39
|
+
* - day がその月の日数を超える場合は翌月にロールする(`new Date` と同じ挙動)
|
|
35
40
|
*/
|
|
36
41
|
function createDate(year, monthIndex, day) {
|
|
42
|
+
assertValidYear(year);
|
|
43
|
+
assertIntegerInRange("monthIndex", monthIndex, 0, 12);
|
|
44
|
+
assertIntegerInRange("day", day, 0, 31);
|
|
37
45
|
const date = /* @__PURE__ */ new Date(0);
|
|
38
46
|
date.setHours(0, 0, 0, 0);
|
|
39
47
|
date.setFullYear(year, monthIndex, day);
|
|
@@ -299,6 +307,16 @@ function isSameDay(a, b) {
|
|
|
299
307
|
assertValidDate(b);
|
|
300
308
|
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
301
309
|
}
|
|
310
|
+
/** 日付セルの表示状態を計算する */
|
|
311
|
+
function getCalendarCellState(date, options = {}) {
|
|
312
|
+
assertValidDate(date);
|
|
313
|
+
return {
|
|
314
|
+
isWeekend: date.getDay() === 0 || date.getDay() === 6,
|
|
315
|
+
isToday: options.today !== void 0 && isSameDay(date, options.today),
|
|
316
|
+
isHighlight: options.highlight !== void 0 && isSameDay(date, options.highlight),
|
|
317
|
+
isInRange: options.range !== void 0 && isDateInRange(date, options.range)
|
|
318
|
+
};
|
|
319
|
+
}
|
|
302
320
|
/** 日付が範囲の開始年から終了年までの月リストを返す */
|
|
303
321
|
function getMonthRange(from, to) {
|
|
304
322
|
assertValidRange(from, to);
|
|
@@ -312,7 +330,17 @@ function getMonthRange(from, to) {
|
|
|
312
330
|
};
|
|
313
331
|
});
|
|
314
332
|
}
|
|
333
|
+
/** グレゴリオ暦のうるう年判定(4で割れるが100では割れない、または400で割れる) */
|
|
334
|
+
function isLeapYear(year) {
|
|
335
|
+
assertValidYear(year);
|
|
336
|
+
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
337
|
+
}
|
|
338
|
+
/** 月の日数(1-31)を返す */
|
|
339
|
+
function daysInMonth(year, month) {
|
|
340
|
+
assertValidYearMonth(year, month);
|
|
341
|
+
return lastDayOfMonth(year, month).getDate();
|
|
342
|
+
}
|
|
315
343
|
//#endregion
|
|
316
|
-
export { LOCALES, MAX_YEAR, MIN_YEAR, assertValidDate, buildMonthGrid, createDate, firstDayOfMonth, getMonthName, getMonthRange, getWeekdayHeaders, isDateInRange, isSameDay, lastDayOfMonth };
|
|
344
|
+
export { LOCALES, MAX_YEAR, MIN_YEAR, assertValidDate, buildMonthGrid, createDate, daysInMonth, firstDayOfMonth, getCalendarCellState, getMonthName, getMonthRange, getWeekdayHeaders, isDateInRange, isLeapYear, isSameDay, lastDayOfMonth };
|
|
317
345
|
|
|
318
346
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/validation.ts","../src/locale.ts","../src/utils.ts"],"sourcesContent":["// ─── 入力検証 ─────────────────────────────────────────────\n\n/** サポートする年の最小値(JS Date は 0-99 を 1900+年 と解釈するため 1 から) */\nexport const MIN_YEAR = 1;\n/** サポートする年の最大値 */\nexport const MAX_YEAR = 9999;\n\n/** 値が min-max の整数であることを検証する(不正なら RangeError) */\nfunction assertIntegerInRange(\n name: string,\n value: number,\n min: number,\n max: number,\n): void {\n if (!Number.isInteger(value) || value < min || value > max) {\n throw new RangeError(\n `Invalid ${name}: ${value} (expected an integer between ${min} and ${max})`,\n );\n }\n}\n\n/** 年が 1-9999 の整数であることを検証する */\nexport function assertValidYear(year: number): void {\n assertIntegerInRange(\"year\", year, MIN_YEAR, MAX_YEAR);\n}\n\n/** 月が 1-12 の整数であることを検証する */\nexport function assertValidMonth(month: number): void {\n assertIntegerInRange(\"month\", month, 1, 12);\n}\n\n/** 年の組み合わせ(year と month)を検証する */\nexport function assertValidYearMonth(year: number, month: number): void {\n assertValidYear(year);\n assertValidMonth(month);\n}\n\n/** 週の開始曜日を検証する */\nexport function assertValidWeekStart(weekStart: string): void {\n if (weekStart !== \"sunday\" && weekStart !== \"monday\") {\n throw new RangeError(\n `Invalid weekStart: \"${weekStart}\" (expected \"sunday\" or \"monday\")`,\n );\n }\n}\n\n/** Date が有効(Invalid Date でない)ことを検証する */\nexport function assertValidDate(date: Date): void {\n if (!(date instanceof Date) || Number.isNaN(date.getTime())) {\n throw new RangeError(`Invalid Date: ${String(date)}`);\n }\n}\n\n/**\n * ローカルの指定日 00:00:00 を生成する。\n * `new Date(year, ...)` は year 0-99 を 1900+year と解釈するため、\n * setFullYear を使って year 0-99 も正しく扱えるようにする。\n */\nexport function createDate(\n year: number,\n monthIndex: number,\n day: number,\n): Date {\n const date = new Date(0);\n date.setHours(0, 0, 0, 0);\n date.setFullYear(year, monthIndex, day);\n return date;\n}\n","import type { Locale, WeekStart } from \"./types.ts\";\nimport { assertValidMonth, assertValidWeekStart } from \"./validation.ts\";\n\nexport interface LocaleData {\n months: readonly string[];\n weekdays: readonly string[];\n weekdaysShort: readonly string[];\n weekdaysMonday: readonly string[];\n weekdaysMondayShort: readonly string[];\n}\n\n/** 月曜始まりの配列は日曜始まりの配列を前ローテーションして生成する */\nfunction makeLocale(\n months: readonly string[],\n weekdays: readonly string[],\n weekdaysShort: readonly string[] = weekdays,\n): LocaleData {\n const rotate = (arr: readonly string[]) => [...arr.slice(1), arr[0]!];\n return {\n months,\n weekdays,\n weekdaysShort,\n weekdaysMonday: rotate(weekdays),\n weekdaysMondayShort: rotate(weekdaysShort),\n };\n}\n\nexport const LOCALES: Record<Locale, LocaleData> = {\n en: makeLocale(\n [\n \"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\",\n ],\n [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"],\n [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"],\n ),\n ja: makeLocale(\n [\n \"1月\",\n \"2月\",\n \"3月\",\n \"4月\",\n \"5月\",\n \"6月\",\n \"7月\",\n \"8月\",\n \"9月\",\n \"10月\",\n \"11月\",\n \"12月\",\n ],\n [\"日\", \"月\", \"火\", \"水\", \"木\", \"金\", \"土\"],\n ),\n es: makeLocale(\n [\n \"enero\",\n \"febrero\",\n \"marzo\",\n \"abril\",\n \"mayo\",\n \"junio\",\n \"julio\",\n \"agosto\",\n \"septiembre\",\n \"octubre\",\n \"noviembre\",\n \"diciembre\",\n ],\n [\"dom\", \"lun\", \"mar\", \"mié\", \"jue\", \"vie\", \"sáb\"],\n [\"do\", \"lu\", \"ma\", \"mi\", \"ju\", \"vi\", \"sá\"],\n ),\n de: makeLocale(\n [\n \"Januar\",\n \"Februar\",\n \"März\",\n \"April\",\n \"Mai\",\n \"Juni\",\n \"Juli\",\n \"August\",\n \"September\",\n \"Oktober\",\n \"November\",\n \"Dezember\",\n ],\n [\"So\", \"Mo\", \"Di\", \"Mi\", \"Do\", \"Fr\", \"Sa\"],\n ),\n fr: makeLocale(\n [\n \"janvier\",\n \"février\",\n \"mars\",\n \"avril\",\n \"mai\",\n \"juin\",\n \"juillet\",\n \"août\",\n \"septembre\",\n \"octobre\",\n \"novembre\",\n \"décembre\",\n ],\n [\"dim.\", \"lun.\", \"mar.\", \"mer.\", \"jeu.\", \"ven.\", \"sam.\"],\n [\"di\", \"lu\", \"ma\", \"me\", \"je\", \"ve\", \"sa\"],\n ),\n ko: makeLocale(\n [\n \"1월\",\n \"2월\",\n \"3월\",\n \"4월\",\n \"5월\",\n \"6월\",\n \"7월\",\n \"8월\",\n \"9월\",\n \"10월\",\n \"11월\",\n \"12월\",\n ],\n [\"일\", \"월\", \"화\", \"수\", \"목\", \"금\", \"토\"],\n ),\n zh: makeLocale(\n [\n \"一月\",\n \"二月\",\n \"三月\",\n \"四月\",\n \"五月\",\n \"六月\",\n \"七月\",\n \"八月\",\n \"九月\",\n \"十月\",\n \"十一月\",\n \"十二月\",\n ],\n [\"日\", \"一\", \"二\", \"三\", \"四\", \"五\", \"六\"],\n ),\n};\n\n/** ロケールデータを取得する(未知のロケールは RangeError) */\nfunction getLocaleData(locale: Locale): LocaleData {\n const data = LOCALES[locale];\n if (data === undefined) {\n throw new RangeError(`Invalid locale: \"${locale}\"`);\n }\n return data;\n}\n\nexport function getWeekdayHeaders(\n locale: Locale,\n weekStart: WeekStart,\n): readonly string[] {\n assertValidWeekStart(weekStart);\n const data = getLocaleData(locale);\n return weekStart === \"monday\" ? data.weekdaysMonday : data.weekdays;\n}\n\nexport function getMonthName(locale: Locale, month: number): string {\n assertValidMonth(month);\n const data = getLocaleData(locale);\n return data.months[month - 1]!;\n}\n","import type { WeekStart } from \"./types.ts\";\nimport {\n assertValidDate,\n assertValidWeekStart,\n assertValidYearMonth,\n createDate,\n} from \"./validation.ts\";\n\n/** 月初日(1日)を返す */\nexport function firstDayOfMonth(year: number, month: number): Date {\n assertValidYearMonth(year, month);\n return createDate(year, month - 1, 1);\n}\n\n/** 月末日を返す */\nexport function lastDayOfMonth(year: number, month: number): Date {\n assertValidYearMonth(year, month);\n return createDate(year, month, 0);\n}\n\n/**\n * 月の日付グリッドを生成する(6行×7列)\n * 各セルは日数(1-31)または null(空欄)\n */\nexport function buildMonthGrid(\n year: number,\n month: number,\n weekStart: WeekStart,\n): (number | null)[][] {\n assertValidYearMonth(year, month);\n assertValidWeekStart(weekStart);\n\n const daysInMonth = lastDayOfMonth(year, month).getDate();\n let skip = firstDayOfMonth(year, month).getDay();\n if (weekStart === \"monday\") {\n skip = (skip + 6) % 7;\n }\n\n const grid: (number | null)[][] = [];\n let day = 1;\n for (let week = 0; week < 6; week++) {\n const row: (number | null)[] = [];\n for (let col = 0; col < 7; col++) {\n if (day > daysInMonth || (week === 0 && col < skip)) {\n row.push(null);\n } else {\n row.push(day++);\n }\n }\n grid.push(row);\n }\n return grid;\n}\n\n/** 範囲(from/to)が有効であることを検証する */\nfunction assertValidRange(from: Date, to: Date): void {\n assertValidDate(from);\n assertValidDate(to);\n if (from.getTime() > to.getTime()) {\n throw new RangeError(\"Invalid range: from must not be after to\");\n }\n}\n\n/** 日付が範囲内に含まれるか */\nexport function isDateInRange(\n date: Date,\n range?: { from: Date; to: Date },\n): boolean {\n if (!range) return false;\n assertValidRange(range.from, range.to);\n assertValidDate(date);\n const time = date.getTime();\n return time >= range.from.getTime() && time <= range.to.getTime();\n}\n\n/** 日付が今日と一致するか(日付のみ比較) */\nexport function isSameDay(a: Date, b: Date): boolean {\n assertValidDate(a);\n assertValidDate(b);\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\n/** 日付が範囲の開始年から終了年までの月リストを返す */\nexport function getMonthRange(\n from: Date,\n to: Date,\n): { year: number; month: number }[] {\n assertValidRange(from, to);\n const start = from.getFullYear() * 12 + from.getMonth();\n const end = to.getFullYear() * 12 + to.getMonth();\n return Array.from({ length: end - start + 1 }, (_, i) => {\n const n = start + i;\n return { year: Math.floor(n / 12), month: (n % 12) + 1 };\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/validation.ts","../src/locale.ts","../src/utils.ts"],"sourcesContent":["// ─── 入力検証 ─────────────────────────────────────────────\n\n/** サポートする年の最小値(JS Date は 0-99 を 1900+年 と解釈するため 1 から) */\nexport const MIN_YEAR = 1;\n/** サポートする年の最大値 */\nexport const MAX_YEAR = 9999;\n\n/** 値が min-max の整数であることを検証する(不正なら RangeError) */\nfunction assertIntegerInRange(\n name: string,\n value: number,\n min: number,\n max: number,\n): void {\n if (!Number.isInteger(value) || value < min || value > max) {\n throw new RangeError(\n `Invalid ${name}: ${value} (expected an integer between ${min} and ${max})`,\n );\n }\n}\n\n/** 年が 1-9999 の整数であることを検証する */\nexport function assertValidYear(year: number): void {\n assertIntegerInRange(\"year\", year, MIN_YEAR, MAX_YEAR);\n}\n\n/** 月が 1-12 の整数であることを検証する */\nexport function assertValidMonth(month: number): void {\n assertIntegerInRange(\"month\", month, 1, 12);\n}\n\n/** 年の組み合わせ(year と month)を検証する */\nexport function assertValidYearMonth(year: number, month: number): void {\n assertValidYear(year);\n assertValidMonth(month);\n}\n\n/** 週の開始曜日を検証する */\nexport function assertValidWeekStart(weekStart: string): void {\n if (weekStart !== \"sunday\" && weekStart !== \"monday\") {\n throw new RangeError(\n `Invalid weekStart: \"${weekStart}\" (expected \"sunday\" or \"monday\")`,\n );\n }\n}\n\n/** Date が有効(Invalid Date でない)ことを検証する */\nexport function assertValidDate(date: Date): void {\n if (!(date instanceof Date) || Number.isNaN(date.getTime())) {\n throw new RangeError(`Invalid Date: ${String(date)}`);\n }\n}\n\n/**\n * ローカルの指定日 00:00:00 を生成する。\n * `new Date(year, ...)` は year 0-99 を 1900+year と解釈するため、\n * setFullYear を使って year 0-99 も正しく扱えるようにする。\n *\n * - year は 1-9999、monthIndex は 0-12、day は 0-31 の整数である必要がある(それ以外は RangeError)\n * - monthIndex 12 は翌年1月(`new Date` と同じロールオーバー。lastDayOfMonth が 12月の月末取得に使う)\n * - day 0 は前月の月末(`new Date` と同じ規則)\n * - day がその月の日数を超える場合は翌月にロールする(`new Date` と同じ挙動)\n */\nexport function createDate(\n year: number,\n monthIndex: number,\n day: number,\n): Date {\n assertValidYear(year);\n assertIntegerInRange(\"monthIndex\", monthIndex, 0, 12);\n assertIntegerInRange(\"day\", day, 0, 31);\n const date = new Date(0);\n date.setHours(0, 0, 0, 0);\n date.setFullYear(year, monthIndex, day);\n return date;\n}\n","import type { Locale, WeekStart } from \"./types.ts\";\nimport { assertValidMonth, assertValidWeekStart } from \"./validation.ts\";\n\nexport interface LocaleData {\n months: readonly string[];\n weekdays: readonly string[];\n weekdaysShort: readonly string[];\n weekdaysMonday: readonly string[];\n weekdaysMondayShort: readonly string[];\n}\n\n/** 月曜始まりの配列は日曜始まりの配列を前ローテーションして生成する */\nfunction makeLocale(\n months: readonly string[],\n weekdays: readonly string[],\n weekdaysShort: readonly string[] = weekdays,\n): LocaleData {\n const rotate = (arr: readonly string[]) => [...arr.slice(1), arr[0]!];\n return {\n months,\n weekdays,\n weekdaysShort,\n weekdaysMonday: rotate(weekdays),\n weekdaysMondayShort: rotate(weekdaysShort),\n };\n}\n\nexport const LOCALES: Record<Locale, LocaleData> = {\n en: makeLocale(\n [\n \"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\",\n ],\n [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"],\n [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"],\n ),\n ja: makeLocale(\n [\n \"1月\",\n \"2月\",\n \"3月\",\n \"4月\",\n \"5月\",\n \"6月\",\n \"7月\",\n \"8月\",\n \"9月\",\n \"10月\",\n \"11月\",\n \"12月\",\n ],\n [\"日\", \"月\", \"火\", \"水\", \"木\", \"金\", \"土\"],\n ),\n es: makeLocale(\n [\n \"enero\",\n \"febrero\",\n \"marzo\",\n \"abril\",\n \"mayo\",\n \"junio\",\n \"julio\",\n \"agosto\",\n \"septiembre\",\n \"octubre\",\n \"noviembre\",\n \"diciembre\",\n ],\n [\"dom\", \"lun\", \"mar\", \"mié\", \"jue\", \"vie\", \"sáb\"],\n [\"do\", \"lu\", \"ma\", \"mi\", \"ju\", \"vi\", \"sá\"],\n ),\n de: makeLocale(\n [\n \"Januar\",\n \"Februar\",\n \"März\",\n \"April\",\n \"Mai\",\n \"Juni\",\n \"Juli\",\n \"August\",\n \"September\",\n \"Oktober\",\n \"November\",\n \"Dezember\",\n ],\n [\"So\", \"Mo\", \"Di\", \"Mi\", \"Do\", \"Fr\", \"Sa\"],\n ),\n fr: makeLocale(\n [\n \"janvier\",\n \"février\",\n \"mars\",\n \"avril\",\n \"mai\",\n \"juin\",\n \"juillet\",\n \"août\",\n \"septembre\",\n \"octobre\",\n \"novembre\",\n \"décembre\",\n ],\n [\"dim.\", \"lun.\", \"mar.\", \"mer.\", \"jeu.\", \"ven.\", \"sam.\"],\n [\"di\", \"lu\", \"ma\", \"me\", \"je\", \"ve\", \"sa\"],\n ),\n ko: makeLocale(\n [\n \"1월\",\n \"2월\",\n \"3월\",\n \"4월\",\n \"5월\",\n \"6월\",\n \"7월\",\n \"8월\",\n \"9월\",\n \"10월\",\n \"11월\",\n \"12월\",\n ],\n [\"일\", \"월\", \"화\", \"수\", \"목\", \"금\", \"토\"],\n ),\n zh: makeLocale(\n [\n \"一月\",\n \"二月\",\n \"三月\",\n \"四月\",\n \"五月\",\n \"六月\",\n \"七月\",\n \"八月\",\n \"九月\",\n \"十月\",\n \"十一月\",\n \"十二月\",\n ],\n [\"日\", \"一\", \"二\", \"三\", \"四\", \"五\", \"六\"],\n ),\n};\n\n/** ロケールデータを取得する(未知のロケールは RangeError) */\nfunction getLocaleData(locale: Locale): LocaleData {\n const data = LOCALES[locale];\n if (data === undefined) {\n throw new RangeError(`Invalid locale: \"${locale}\"`);\n }\n return data;\n}\n\nexport function getWeekdayHeaders(\n locale: Locale,\n weekStart: WeekStart,\n): readonly string[] {\n assertValidWeekStart(weekStart);\n const data = getLocaleData(locale);\n return weekStart === \"monday\" ? data.weekdaysMonday : data.weekdays;\n}\n\nexport function getMonthName(locale: Locale, month: number): string {\n assertValidMonth(month);\n const data = getLocaleData(locale);\n return data.months[month - 1]!;\n}\n","import type { WeekStart } from \"./types.ts\";\nimport {\n assertValidDate,\n assertValidWeekStart,\n assertValidYear,\n assertValidYearMonth,\n createDate,\n} from \"./validation.ts\";\n\nexport interface CalendarCellState {\n isWeekend: boolean;\n isToday: boolean;\n isHighlight: boolean;\n isInRange: boolean;\n}\n\n/** 月初日(1日)を返す */\nexport function firstDayOfMonth(year: number, month: number): Date {\n assertValidYearMonth(year, month);\n return createDate(year, month - 1, 1);\n}\n\n/** 月末日を返す */\nexport function lastDayOfMonth(year: number, month: number): Date {\n assertValidYearMonth(year, month);\n return createDate(year, month, 0);\n}\n\n/**\n * 月の日付グリッドを生成する(6行×7列)\n * 各セルは日数(1-31)または null(空欄)\n */\nexport function buildMonthGrid(\n year: number,\n month: number,\n weekStart: WeekStart,\n): (number | null)[][] {\n assertValidYearMonth(year, month);\n assertValidWeekStart(weekStart);\n\n const daysInMonth = lastDayOfMonth(year, month).getDate();\n let skip = firstDayOfMonth(year, month).getDay();\n if (weekStart === \"monday\") {\n skip = (skip + 6) % 7;\n }\n\n const grid: (number | null)[][] = [];\n let day = 1;\n for (let week = 0; week < 6; week++) {\n const row: (number | null)[] = [];\n for (let col = 0; col < 7; col++) {\n if (day > daysInMonth || (week === 0 && col < skip)) {\n row.push(null);\n } else {\n row.push(day++);\n }\n }\n grid.push(row);\n }\n return grid;\n}\n\n/** 範囲(from/to)が有効であることを検証する */\nfunction assertValidRange(from: Date, to: Date): void {\n assertValidDate(from);\n assertValidDate(to);\n if (from.getTime() > to.getTime()) {\n throw new RangeError(\"Invalid range: from must not be after to\");\n }\n}\n\n/** 日付が範囲内に含まれるか */\nexport function isDateInRange(\n date: Date,\n range?: { from: Date; to: Date },\n): boolean {\n if (!range) return false;\n assertValidRange(range.from, range.to);\n assertValidDate(date);\n const time = date.getTime();\n return time >= range.from.getTime() && time <= range.to.getTime();\n}\n\n/** 日付が今日と一致するか(日付のみ比較) */\nexport function isSameDay(a: Date, b: Date): boolean {\n assertValidDate(a);\n assertValidDate(b);\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\n/** 日付セルの表示状態を計算する */\nexport function getCalendarCellState(\n date: Date,\n options: {\n today?: Date;\n highlight?: Date;\n range?: { from: Date; to: Date };\n } = {},\n): CalendarCellState {\n assertValidDate(date);\n return {\n isWeekend: date.getDay() === 0 || date.getDay() === 6,\n isToday: options.today !== undefined && isSameDay(date, options.today),\n isHighlight:\n options.highlight !== undefined && isSameDay(date, options.highlight),\n isInRange:\n options.range !== undefined && isDateInRange(date, options.range),\n };\n}\n\n/** 日付が範囲の開始年から終了年までの月リストを返す */\nexport function getMonthRange(\n from: Date,\n to: Date,\n): { year: number; month: number }[] {\n assertValidRange(from, to);\n const start = from.getFullYear() * 12 + from.getMonth();\n const end = to.getFullYear() * 12 + to.getMonth();\n return Array.from({ length: end - start + 1 }, (_, i) => {\n const n = start + i;\n return { year: Math.floor(n / 12), month: (n % 12) + 1 };\n });\n}\n\n/** グレゴリオ暦のうるう年判定(4で割れるが100では割れない、または400で割れる) */\nexport function isLeapYear(year: number): boolean {\n assertValidYear(year);\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n}\n\n/** 月の日数(1-31)を返す */\nexport function daysInMonth(year: number, month: number): number {\n assertValidYearMonth(year, month);\n return lastDayOfMonth(year, month).getDate();\n}\n"],"mappings":";;AAGA,MAAa,WAAW;;AAExB,MAAa,WAAW;;AAGxB,SAAS,qBACP,MACA,OACA,KACA,KACM;CACN,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,OAAO,QAAQ,KACrD,MAAM,IAAI,WACR,WAAW,KAAK,IAAI,MAAM,gCAAgC,IAAI,OAAO,IAAI,EAC3E;AAEJ;;AAGA,SAAgB,gBAAgB,MAAoB;CAClD,qBAAqB,QAAQ,MAAA,GAAgB,QAAQ;AACvD;;AAGA,SAAgB,iBAAiB,OAAqB;CACpD,qBAAqB,SAAS,OAAO,GAAG,EAAE;AAC5C;;AAGA,SAAgB,qBAAqB,MAAc,OAAqB;CACtE,gBAAgB,IAAI;CACpB,iBAAiB,KAAK;AACxB;;AAGA,SAAgB,qBAAqB,WAAyB;CAC5D,IAAI,cAAc,YAAY,cAAc,UAC1C,MAAM,IAAI,WACR,uBAAuB,UAAU,kCACnC;AAEJ;;AAGA,SAAgB,gBAAgB,MAAkB;CAChD,IAAI,EAAE,gBAAgB,SAAS,OAAO,MAAM,KAAK,QAAQ,CAAC,GACxD,MAAM,IAAI,WAAW,iBAAiB,OAAO,IAAI,GAAG;AAExD;;;;;;;;;;;AAYA,SAAgB,WACd,MACA,YACA,KACM;CACN,gBAAgB,IAAI;CACpB,qBAAqB,cAAc,YAAY,GAAG,EAAE;CACpD,qBAAqB,OAAO,KAAK,GAAG,EAAE;CACtC,MAAM,uBAAO,IAAI,KAAK,CAAC;CACvB,KAAK,SAAS,GAAG,GAAG,GAAG,CAAC;CACxB,KAAK,YAAY,MAAM,YAAY,GAAG;CACtC,OAAO;AACT;;;;AC/DA,SAAS,WACP,QACA,UACA,gBAAmC,UACvB;CACZ,MAAM,UAAU,QAA2B,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG,IAAI,EAAG;CACpE,OAAO;EACL;EACA;EACA;EACA,gBAAgB,OAAO,QAAQ;EAC/B,qBAAqB,OAAO,aAAa;CAC3C;AACF;AAEA,MAAa,UAAsC;CACjD,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAO;EAAO;EAAO;EAAO;EAAO;EAAO;CAAK,GAChD;EAAC;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;CAAI,CAC3C;CACA,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;CAAG,CACpC;CACA,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAO;EAAO;EAAO;EAAO;EAAO;EAAO;CAAK,GAChD;EAAC;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;CAAI,CAC3C;CACA,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;CAAI,CAC3C;CACA,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAQ;EAAQ;EAAQ;EAAQ;EAAQ;EAAQ;CAAM,GACvD;EAAC;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;CAAI,CAC3C;CACA,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;CAAG,CACpC;CACA,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;CAAG,CACpC;AACF;;AAGA,SAAS,cAAc,QAA4B;CACjD,MAAM,OAAO,QAAQ;CACrB,IAAI,SAAS,KAAA,GACX,MAAM,IAAI,WAAW,oBAAoB,OAAO,EAAE;CAEpD,OAAO;AACT;AAEA,SAAgB,kBACd,QACA,WACmB;CACnB,qBAAqB,SAAS;CAC9B,MAAM,OAAO,cAAc,MAAM;CACjC,OAAO,cAAc,WAAW,KAAK,iBAAiB,KAAK;AAC7D;AAEA,SAAgB,aAAa,QAAgB,OAAuB;CAClE,iBAAiB,KAAK;CAEtB,OADa,cAAc,MACjB,CAAC,CAAC,OAAO,QAAQ;AAC7B;;;;AC7JA,SAAgB,gBAAgB,MAAc,OAAqB;CACjE,qBAAqB,MAAM,KAAK;CAChC,OAAO,WAAW,MAAM,QAAQ,GAAG,CAAC;AACtC;;AAGA,SAAgB,eAAe,MAAc,OAAqB;CAChE,qBAAqB,MAAM,KAAK;CAChC,OAAO,WAAW,MAAM,OAAO,CAAC;AAClC;;;;;AAMA,SAAgB,eACd,MACA,OACA,WACqB;CACrB,qBAAqB,MAAM,KAAK;CAChC,qBAAqB,SAAS;CAE9B,MAAM,cAAc,eAAe,MAAM,KAAK,CAAC,CAAC,QAAQ;CACxD,IAAI,OAAO,gBAAgB,MAAM,KAAK,CAAC,CAAC,OAAO;CAC/C,IAAI,cAAc,UAChB,QAAQ,OAAO,KAAK;CAGtB,MAAM,OAA4B,CAAC;CACnC,IAAI,MAAM;CACV,KAAK,IAAI,OAAO,GAAG,OAAO,GAAG,QAAQ;EACnC,MAAM,MAAyB,CAAC;EAChC,KAAK,IAAI,MAAM,GAAG,MAAM,GAAG,OACzB,IAAI,MAAM,eAAgB,SAAS,KAAK,MAAM,MAC5C,IAAI,KAAK,IAAI;OAEb,IAAI,KAAK,KAAK;EAGlB,KAAK,KAAK,GAAG;CACf;CACA,OAAO;AACT;;AAGA,SAAS,iBAAiB,MAAY,IAAgB;CACpD,gBAAgB,IAAI;CACpB,gBAAgB,EAAE;CAClB,IAAI,KAAK,QAAQ,IAAI,GAAG,QAAQ,GAC9B,MAAM,IAAI,WAAW,0CAA0C;AAEnE;;AAGA,SAAgB,cACd,MACA,OACS;CACT,IAAI,CAAC,OAAO,OAAO;CACnB,iBAAiB,MAAM,MAAM,MAAM,EAAE;CACrC,gBAAgB,IAAI;CACpB,MAAM,OAAO,KAAK,QAAQ;CAC1B,OAAO,QAAQ,MAAM,KAAK,QAAQ,KAAK,QAAQ,MAAM,GAAG,QAAQ;AAClE;;AAGA,SAAgB,UAAU,GAAS,GAAkB;CACnD,gBAAgB,CAAC;CACjB,gBAAgB,CAAC;CACjB,OACE,EAAE,YAAY,MAAM,EAAE,YAAY,KAClC,EAAE,SAAS,MAAM,EAAE,SAAS,KAC5B,EAAE,QAAQ,MAAM,EAAE,QAAQ;AAE9B;;AAGA,SAAgB,qBACd,MACA,UAII,CAAC,GACc;CACnB,gBAAgB,IAAI;CACpB,OAAO;EACL,WAAW,KAAK,OAAO,MAAM,KAAK,KAAK,OAAO,MAAM;EACpD,SAAS,QAAQ,UAAU,KAAA,KAAa,UAAU,MAAM,QAAQ,KAAK;EACrE,aACE,QAAQ,cAAc,KAAA,KAAa,UAAU,MAAM,QAAQ,SAAS;EACtE,WACE,QAAQ,UAAU,KAAA,KAAa,cAAc,MAAM,QAAQ,KAAK;CACpE;AACF;;AAGA,SAAgB,cACd,MACA,IACmC;CACnC,iBAAiB,MAAM,EAAE;CACzB,MAAM,QAAQ,KAAK,YAAY,IAAI,KAAK,KAAK,SAAS;CACtD,MAAM,MAAM,GAAG,YAAY,IAAI,KAAK,GAAG,SAAS;CAChD,OAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,QAAQ,EAAE,IAAI,GAAG,MAAM;EACvD,MAAM,IAAI,QAAQ;EAClB,OAAO;GAAE,MAAM,KAAK,MAAM,IAAI,EAAE;GAAG,OAAQ,IAAI,KAAM;EAAE;CACzD,CAAC;AACH;;AAGA,SAAgB,WAAW,MAAuB;CAChD,gBAAgB,IAAI;CACpB,OAAQ,OAAO,MAAM,KAAK,OAAO,QAAQ,KAAM,OAAO,QAAQ;AAChE;;AAGA,SAAgB,YAAY,MAAc,OAAuB;CAC/D,qBAAqB,MAAM,KAAK;CAChC,OAAO,eAAe,MAAM,KAAK,CAAC,CAAC,QAAQ;AAC7C"}
|