@minicalendar/react 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
File without changes
@@ -0,0 +1,39 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ type IsoDate = `${number}-${number}-${number}`;
4
+ type GetDateTimes = (start: IsoDate, end: IsoDate) => Promise<string[]>;
5
+ interface Options {
6
+ zone?: string;
7
+ }
8
+ declare function createCachedGetDateTimes(getDateTimes: GetDateTimes, options: Options): GetDateTimes;
9
+
10
+ interface DateSelectorOptions {
11
+ lastDate?: string;
12
+ }
13
+ interface DateSelectorProps {
14
+ setDate: (value: IsoDate | null) => void;
15
+ getDateTimes: GetDateTimes;
16
+ options?: DateSelectorOptions;
17
+ }
18
+ declare function DateSelector(props: DateSelectorProps): react_jsx_runtime.JSX.Element;
19
+
20
+ interface DateTimeSelectorOptions {
21
+ date?: DateSelectorOptions;
22
+ }
23
+ interface DateTimeSelectorProps {
24
+ dateTime: string | null;
25
+ setDateTime: (value: string | null) => void;
26
+ getDateTimes: GetDateTimes;
27
+ options?: DateTimeSelectorOptions;
28
+ }
29
+ declare function DateTimeSelector(props: DateTimeSelectorProps): react_jsx_runtime.JSX.Element;
30
+
31
+ interface TimeSelectorProps {
32
+ date: IsoDate;
33
+ dateTime: string | null;
34
+ setDateTime: (value: string | null) => void;
35
+ getDateTimes: GetDateTimes;
36
+ }
37
+ declare function TimeSelector(props: TimeSelectorProps): react_jsx_runtime.JSX.Element;
38
+
39
+ export { DateSelector, type DateSelectorProps, DateTimeSelector, type DateTimeSelectorProps, type GetDateTimes, type IsoDate, TimeSelector, type TimeSelectorProps, createCachedGetDateTimes };
package/dist/index.js ADDED
@@ -0,0 +1,283 @@
1
+ // src/DateSelector.tsx
2
+ import { useState, useMemo, useEffect } from "react";
3
+ import { DateTime } from "luxon";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ var countToClass = (count, max, selected) => {
6
+ if (selected) return "mncl-button mncl-button--selected";
7
+ if (count == 0) return "mncl-button mncl-button--default";
8
+ if (count < max * 0.2) return "mncl-button mncl-button--low";
9
+ if (count < max * 0.5) return "mncl-button mncl-button--medium";
10
+ else return "mncl-button mncl-button--high";
11
+ };
12
+ function DateSelector(props) {
13
+ const { setDate, getDateTimes, options } = props;
14
+ const [dateTimes, setDateTimes] = useState([]);
15
+ const [loading, setLoading] = useState(true);
16
+ const [day, setDay] = useState(null);
17
+ const [month, setMonth] = useState((/* @__PURE__ */ new Date()).getMonth() + 1);
18
+ const [year, setYear] = useState((/* @__PURE__ */ new Date()).getFullYear());
19
+ const today = useMemo(() => DateTime.now(), []);
20
+ const datetime = useMemo(() => DateTime.fromObject({ year, month }), [year, month]);
21
+ const monthStartDay = useMemo(() => datetime.startOf("month").weekday, [datetime]);
22
+ const daysInMonth = useMemo(() => datetime.daysInMonth || 0, [datetime]);
23
+ const countsByDay = useMemo(
24
+ () => dateTimes.reduce((acc, dateTime) => {
25
+ const { day: day2 } = DateTime.fromISO(dateTime);
26
+ acc[day2] = (acc[day2] ?? 0) + 1;
27
+ return acc;
28
+ }, {}),
29
+ [dateTimes]
30
+ );
31
+ const maxCount = useMemo(
32
+ () => Object.values(countsByDay).reduce((prev, current) => Math.max(prev, current), 0),
33
+ [countsByDay]
34
+ );
35
+ const canGoBack = useMemo(() => today.toMillis() < datetime.startOf("month").toMillis(), [today, datetime]);
36
+ const canGoForward = useMemo(
37
+ () => options?.lastDate ? DateTime.fromISO(options.lastDate).toMillis() > datetime.endOf("month").toMillis() : true,
38
+ [options?.lastDate, datetime]
39
+ );
40
+ const prevMonth = () => {
41
+ if (month == 1) {
42
+ setMonth(12);
43
+ setYear((prev) => prev - 1);
44
+ } else {
45
+ setMonth((prev) => prev - 1);
46
+ }
47
+ setDay(null);
48
+ };
49
+ const nextMonth = () => {
50
+ if (month == 12) {
51
+ setMonth(1);
52
+ setYear((prev) => prev + 1);
53
+ } else {
54
+ setMonth((prev) => prev + 1);
55
+ }
56
+ setDay(null);
57
+ };
58
+ useEffect(() => {
59
+ setLoading(true);
60
+ setDateTimes([]);
61
+ const start = datetime.startOf("month").toISODate();
62
+ const end = datetime.endOf("month").toISODate();
63
+ getDateTimes(start, end).then((datetimes_) => {
64
+ setDateTimes(datetimes_);
65
+ }).finally(() => {
66
+ setLoading(false);
67
+ });
68
+ }, [datetime]);
69
+ useEffect(() => {
70
+ if (!day) setDate(null);
71
+ else {
72
+ setDate(DateTime.fromObject({ year, month, day }).toISODate());
73
+ }
74
+ }, [year, month, day]);
75
+ return /* @__PURE__ */ jsxs("div", { className: "mncl-date-selector", children: [
76
+ /* @__PURE__ */ jsxs("div", { className: "mncl-date-selector__head", children: [
77
+ /* @__PURE__ */ jsx(
78
+ "button",
79
+ {
80
+ type: "button",
81
+ "aria-label": "Previous month",
82
+ className: `mncl-button mncl-button--accent`,
83
+ onClick: prevMonth,
84
+ disabled: !canGoBack,
85
+ children: "Back"
86
+ }
87
+ ),
88
+ /* @__PURE__ */ jsx("h2", { className: "mncl-h2", children: datetime.toFormat("LLLL yyyy") }),
89
+ /* @__PURE__ */ jsx(
90
+ "button",
91
+ {
92
+ type: "button",
93
+ "aria-label": "Next month",
94
+ className: `mncl-button mncl-button--accent`,
95
+ onClick: nextMonth,
96
+ disabled: !canGoForward,
97
+ children: "Next"
98
+ }
99
+ )
100
+ ] }),
101
+ /* @__PURE__ */ jsxs("div", { className: "mncl-date-selector__grid", children: [
102
+ ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"].map((day2) => /* @__PURE__ */ jsx("p", { children: day2 }, day2)),
103
+ Array.from({ length: monthStartDay - 1 }, (_, i) => i).map((_, i) => /* @__PURE__ */ jsx("div", { className: "mncl-ignore" }, i)),
104
+ Array.from({ length: daysInMonth }, (_, i) => i + 1).map((day_, i) => /* @__PURE__ */ jsx(
105
+ "button",
106
+ {
107
+ type: "button",
108
+ "aria-pressed": day == day_,
109
+ className: countToClass(countsByDay[day_] ?? 0, maxCount, day == day_),
110
+ onClick: () => setDay(day_),
111
+ disabled: !countsByDay[day_],
112
+ children: day_
113
+ },
114
+ `${day_}-${month}-${year}`
115
+ ))
116
+ ] }),
117
+ /* @__PURE__ */ jsxs("div", { className: "mncl-date-selector__foot", children: [
118
+ /* @__PURE__ */ jsxs("div", { children: [
119
+ /* @__PURE__ */ jsx("span", { className: "mncl-indicator mncl-indicator--high" }),
120
+ /* @__PURE__ */ jsx("p", { children: "High availability" })
121
+ ] }),
122
+ /* @__PURE__ */ jsxs("div", { children: [
123
+ /* @__PURE__ */ jsx("span", { className: "mncl-indicator mncl-indicator--medium" }),
124
+ /* @__PURE__ */ jsx("p", { children: "Medium availability" })
125
+ ] }),
126
+ /* @__PURE__ */ jsxs("div", { children: [
127
+ /* @__PURE__ */ jsx("span", { className: "mncl-indicator mncl-indicator--low" }),
128
+ /* @__PURE__ */ jsx("p", { children: "Low availability" })
129
+ ] }),
130
+ /* @__PURE__ */ jsxs("div", { children: [
131
+ /* @__PURE__ */ jsx("span", { className: "mncl-indicator mncl-indicator--no" }),
132
+ /* @__PURE__ */ jsx("p", { children: "No availability" })
133
+ ] })
134
+ ] })
135
+ ] });
136
+ }
137
+
138
+ // src/DateTimeSelector.tsx
139
+ import { useEffect as useEffect2, useState as useState2 } from "react";
140
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
141
+ function DateTimeSelector(props) {
142
+ const { dateTime, setDateTime, getDateTimes, options } = props;
143
+ const [date, setDate] = useState2(null);
144
+ useEffect2(() => {
145
+ setDateTime(null);
146
+ }, [date]);
147
+ return /* @__PURE__ */ jsxs2("div", { className: "mncl-datetime-selector", children: [
148
+ /* @__PURE__ */ jsx2(DateSelector, { setDate, getDateTimes, options: options?.date }),
149
+ date && /* @__PURE__ */ jsx2(TimeSelector, { date, dateTime, setDateTime, getDateTimes })
150
+ ] });
151
+ }
152
+
153
+ // src/TimeSelector.tsx
154
+ import { DateTime as DateTime2 } from "luxon";
155
+ import { useEffect as useEffect3, useState as useState3 } from "react";
156
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
157
+ function TimeSelector(props) {
158
+ const { date, dateTime, setDateTime, getDateTimes } = props;
159
+ const [dateTimes, setDateTimes] = useState3([]);
160
+ const [loading, setLoading] = useState3(true);
161
+ useEffect3(() => {
162
+ setLoading(true);
163
+ setDateTimes([]);
164
+ getDateTimes(date, date).then((datetimes_) => {
165
+ setDateTimes(datetimes_);
166
+ }).finally(() => {
167
+ setLoading(false);
168
+ });
169
+ }, [date]);
170
+ return /* @__PURE__ */ jsxs3("div", { className: "mncl-time-selector", children: [
171
+ /* @__PURE__ */ jsx3("div", { className: "mncl-time-selector__head", children: /* @__PURE__ */ jsxs3("h2", { className: "mncl-h2", children: [
172
+ "Select time on ",
173
+ DateTime2.fromISO(date).toFormat("d LLLL yyyy")
174
+ ] }) }),
175
+ /* @__PURE__ */ jsxs3("div", { className: "mncl-time-selector__grid", children: [
176
+ loading && /* @__PURE__ */ jsx3("p", { children: "Loading..." }),
177
+ dateTimes.map((dateTime_) => /* @__PURE__ */ jsx3(
178
+ "button",
179
+ {
180
+ type: "button",
181
+ className: `mncl-button mncl-button--${dateTime_ == dateTime ? "selected" : "default"}`,
182
+ onClick: () => setDateTime(dateTime_),
183
+ children: DateTime2.fromISO(dateTime_).toFormat("HH:mm")
184
+ },
185
+ dateTime_
186
+ ))
187
+ ] })
188
+ ] });
189
+ }
190
+
191
+ // src/createCachedGetDateTimes.ts
192
+ import { DateTime as DateTime3 } from "luxon";
193
+ function createCachedGetDateTimes(getDateTimes, options) {
194
+ const zone = options?.zone;
195
+ const byDay = /* @__PURE__ */ new Map();
196
+ const inFlight = /* @__PURE__ */ new Map();
197
+ const toDayKey = (iso) => DateTime3.fromISO(iso, { zone }).toISODate();
198
+ const listDays = (start, end) => {
199
+ const s = DateTime3.fromISO(start, { zone }).startOf("day");
200
+ const e = DateTime3.fromISO(end, { zone }).startOf("day");
201
+ const out = [];
202
+ for (let d = s; d < e; d = d.plus({ days: 1 })) out.push(d.toISODate());
203
+ return out;
204
+ };
205
+ const uniqueSorted = (arr) => Array.from(new Set(arr)).sort();
206
+ const markKnownEmpty = (start, end) => {
207
+ for (const day of listDays(start, end)) {
208
+ if (!byDay.has(day)) byDay.set(day, []);
209
+ }
210
+ };
211
+ const bucket = (isos) => {
212
+ for (const iso of isos) {
213
+ const day = toDayKey(iso);
214
+ const arr = byDay.get(day);
215
+ if (arr) arr.push(iso);
216
+ else byDay.set(day, [iso]);
217
+ }
218
+ };
219
+ async function fetchSegment(segStart, segEnd) {
220
+ console.log(segStart, segEnd);
221
+ const key = `${segStart}|${segEnd}`;
222
+ if (!inFlight.has(key)) {
223
+ inFlight.set(
224
+ key,
225
+ (async () => {
226
+ const dtIsos = await getDateTimes(segStart, segEnd);
227
+ markKnownEmpty(segStart, segEnd);
228
+ bucket(dtIsos);
229
+ })().finally(() => {
230
+ inFlight.delete(key);
231
+ })
232
+ );
233
+ }
234
+ await inFlight.get(key);
235
+ }
236
+ async function ensureCached(start, end) {
237
+ const days = listDays(start, end);
238
+ const unknown = days.filter((d) => !byDay.has(d));
239
+ if (unknown.length === 0) return;
240
+ let segStart = null;
241
+ let prev = null;
242
+ const flush = async () => {
243
+ if (!segStart || !prev) return;
244
+ const segEnd = prev.plus({ days: 1 }).toISODate();
245
+ await fetchSegment(segStart, segEnd);
246
+ segStart = null;
247
+ prev = null;
248
+ };
249
+ for (const day of unknown) {
250
+ const dt = DateTime3.fromISO(day, { zone }).startOf("day");
251
+ if (!segStart) {
252
+ segStart = day;
253
+ prev = dt;
254
+ continue;
255
+ }
256
+ const expectedNext = prev.plus({ days: 1 }).toISODate();
257
+ if (expectedNext !== day) {
258
+ await flush();
259
+ segStart = day;
260
+ prev = dt;
261
+ } else {
262
+ prev = dt;
263
+ }
264
+ }
265
+ await flush();
266
+ }
267
+ return async (start, end) => {
268
+ const endExclusive = DateTime3.fromISO(end, { zone }).plus({ days: 1 }).toISODate();
269
+ await ensureCached(start, endExclusive);
270
+ const out = [];
271
+ for (const day of listDays(start, endExclusive)) {
272
+ out.push(...byDay.get(day) ?? []);
273
+ }
274
+ return uniqueSorted(out);
275
+ };
276
+ }
277
+ export {
278
+ DateSelector,
279
+ DateTimeSelector,
280
+ TimeSelector,
281
+ createCachedGetDateTimes
282
+ };
283
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/DateSelector.tsx","../src/DateTimeSelector.tsx","../src/TimeSelector.tsx","../src/createCachedGetDateTimes.ts"],"sourcesContent":["import { useState, useMemo, useEffect } from \"react\"\r\nimport { DateTime } from \"luxon\"\r\nimport { GetDateTimes, IsoDate } from \"./createCachedGetDateTimes\"\r\n\r\nconst countToClass = (count: number, max: number, selected: boolean) => {\r\n if (selected) return \"mncl-button mncl-button--selected\"\r\n if (count == 0) return \"mncl-button mncl-button--default\" // also gets disabled\r\n if (count < max * 0.2) return \"mncl-button mncl-button--low\"\r\n if (count < max * 0.5) return \"mncl-button mncl-button--medium\"\r\n else return \"mncl-button mncl-button--high\"\r\n}\r\n\r\nexport interface DateSelectorOptions {\r\n lastDate?: string\r\n}\r\n\r\nexport interface DateSelectorProps {\r\n setDate: (value: IsoDate | null) => void\r\n getDateTimes: GetDateTimes\r\n options?: DateSelectorOptions\r\n}\r\n\r\nexport function DateSelector(props: DateSelectorProps) {\r\n const { setDate, getDateTimes, options } = props\r\n\r\n const [dateTimes, setDateTimes] = useState<string[]>([])\r\n const [loading, setLoading] = useState<boolean>(true)\r\n\r\n const [day, setDay] = useState<number | null>(null)\r\n const [month, setMonth] = useState<number>(new Date().getMonth() + 1)\r\n const [year, setYear] = useState<number>(new Date().getFullYear())\r\n\r\n const today = useMemo(() => DateTime.now(), [])\r\n\r\n const datetime = useMemo(() => DateTime.fromObject({ year, month }), [year, month])\r\n const monthStartDay = useMemo(() => datetime.startOf(\"month\").weekday, [datetime])\r\n const daysInMonth = useMemo(() => datetime.daysInMonth || 0, [datetime])\r\n\r\n const countsByDay = useMemo(\r\n () =>\r\n dateTimes.reduce<Record<number, number>>((acc, dateTime) => {\r\n const { day } = DateTime.fromISO(dateTime)\r\n acc[day] = (acc[day] ?? 0) + 1\r\n return acc\r\n }, {}),\r\n [dateTimes],\r\n )\r\n const maxCount = useMemo(\r\n () => Object.values(countsByDay).reduce((prev, current) => Math.max(prev, current), 0),\r\n [countsByDay],\r\n )\r\n\r\n const canGoBack = useMemo(() => today.toMillis() < datetime.startOf(\"month\").toMillis(), [today, datetime])\r\n const canGoForward = useMemo(\r\n () =>\r\n options?.lastDate\r\n ? DateTime.fromISO(options.lastDate).toMillis() > datetime.endOf(\"month\").toMillis()\r\n : true,\r\n [options?.lastDate, datetime],\r\n )\r\n\r\n const prevMonth = () => {\r\n if (month == 1) {\r\n setMonth(12)\r\n setYear((prev) => prev - 1)\r\n } else {\r\n setMonth((prev) => prev - 1)\r\n }\r\n setDay(null)\r\n }\r\n\r\n const nextMonth = () => {\r\n if (month == 12) {\r\n setMonth(1)\r\n setYear((prev) => prev + 1)\r\n } else {\r\n setMonth((prev) => prev + 1)\r\n }\r\n setDay(null)\r\n }\r\n\r\n useEffect(() => {\r\n setLoading(true)\r\n setDateTimes([])\r\n\r\n const start = datetime.startOf(\"month\").toISODate() as IsoDate\r\n const end = datetime.endOf(\"month\").toISODate() as IsoDate\r\n\r\n getDateTimes(start, end)\r\n .then((datetimes_) => {\r\n setDateTimes(datetimes_)\r\n })\r\n .finally(() => {\r\n setLoading(false)\r\n })\r\n }, [datetime])\r\n\r\n useEffect(() => {\r\n if (!day) setDate(null)\r\n else {\r\n setDate(DateTime.fromObject({ year, month, day }).toISODate() as IsoDate)\r\n }\r\n }, [year, month, day])\r\n\r\n return (\r\n <div className=\"mncl-date-selector\">\r\n <div className=\"mncl-date-selector__head\">\r\n <button\r\n type=\"button\"\r\n aria-label=\"Previous month\"\r\n className={`mncl-button mncl-button--accent`}\r\n onClick={prevMonth}\r\n disabled={!canGoBack}\r\n >\r\n Back\r\n </button>\r\n <h2 className=\"mncl-h2\">{datetime.toFormat(\"LLLL yyyy\")}</h2>\r\n <button\r\n type=\"button\"\r\n aria-label=\"Next month\"\r\n className={`mncl-button mncl-button--accent`}\r\n onClick={nextMonth}\r\n disabled={!canGoForward}\r\n >\r\n Next\r\n </button>\r\n </div>\r\n <div className=\"mncl-date-selector__grid\">\r\n {[\"MON\", \"TUE\", \"WED\", \"THU\", \"FRI\", \"SAT\", \"SUN\"].map((day) => (\r\n <p key={day}>{day}</p>\r\n ))}\r\n {Array.from({ length: monthStartDay - 1 }, (_, i) => i).map((_, i) => (\r\n <div className=\"mncl-ignore\" key={i}></div>\r\n ))}\r\n {Array.from({ length: daysInMonth }, (_, i) => i + 1).map((day_, i) => (\r\n <button\r\n type=\"button\"\r\n aria-pressed={day == day_}\r\n key={`${day_}-${month}-${year}`}\r\n className={countToClass(countsByDay[day_] ?? 0, maxCount, day == day_)}\r\n onClick={() => setDay(day_)}\r\n disabled={!countsByDay[day_]}\r\n >\r\n {day_}\r\n </button>\r\n ))}\r\n </div>\r\n <div className=\"mncl-date-selector__foot\">\r\n <div>\r\n <span className=\"mncl-indicator mncl-indicator--high\"></span>\r\n <p>High availability</p>\r\n </div>\r\n <div>\r\n <span className=\"mncl-indicator mncl-indicator--medium\"></span>\r\n <p>Medium availability</p>\r\n </div>\r\n <div>\r\n <span className=\"mncl-indicator mncl-indicator--low\"></span>\r\n <p>Low availability</p>\r\n </div>\r\n <div>\r\n <span className=\"mncl-indicator mncl-indicator--no\"></span>\r\n <p>No availability</p>\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n}\r\n","import React, { useEffect, useState } from \"react\"\r\nimport { DateSelector, IsoDate, TimeSelector, type GetDateTimes } from \"./\"\r\nimport { DateSelectorOptions } from \"./DateSelector\"\r\n\r\ninterface DateTimeSelectorOptions {\r\n date?: DateSelectorOptions\r\n}\r\n\r\nexport interface DateTimeSelectorProps {\r\n dateTime: string | null\r\n setDateTime: (value: string | null) => void\r\n getDateTimes: GetDateTimes\r\n options?: DateTimeSelectorOptions\r\n}\r\n\r\nexport function DateTimeSelector(props: DateTimeSelectorProps) {\r\n const { dateTime, setDateTime, getDateTimes, options } = props\r\n\r\n const [date, setDate] = useState<IsoDate | null>(null)\r\n\r\n useEffect(() => {\r\n setDateTime(null)\r\n }, [date])\r\n\r\n return (\r\n <div className=\"mncl-datetime-selector\">\r\n <DateSelector setDate={setDate} getDateTimes={getDateTimes} options={options?.date} />\r\n {date && (\r\n <TimeSelector date={date} dateTime={dateTime} setDateTime={setDateTime} getDateTimes={getDateTimes} />\r\n )}\r\n </div>\r\n )\r\n}\r\n","import { DateTime } from \"luxon\"\r\nimport { GetDateTimes, IsoDate } from \"./createCachedGetDateTimes\"\r\nimport { useEffect, useState } from \"react\"\r\n\r\nexport interface TimeSelectorProps {\r\n date: IsoDate\r\n dateTime: string | null\r\n setDateTime: (value: string | null) => void\r\n getDateTimes: GetDateTimes\r\n}\r\n\r\nexport function TimeSelector(props: TimeSelectorProps) {\r\n const { date, dateTime, setDateTime, getDateTimes } = props\r\n\r\n const [dateTimes, setDateTimes] = useState<string[]>([])\r\n const [loading, setLoading] = useState<boolean>(true)\r\n\r\n useEffect(() => {\r\n setLoading(true)\r\n setDateTimes([])\r\n\r\n getDateTimes(date, date)\r\n .then((datetimes_) => {\r\n setDateTimes(datetimes_)\r\n })\r\n .finally(() => {\r\n setLoading(false)\r\n })\r\n }, [date])\r\n\r\n return (\r\n <div className=\"mncl-time-selector\">\r\n <div className=\"mncl-time-selector__head\">\r\n <h2 className=\"mncl-h2\">Select time on {DateTime.fromISO(date).toFormat(\"d LLLL yyyy\")}</h2>\r\n </div>\r\n <div className=\"mncl-time-selector__grid\">\r\n {loading && <p>Loading...</p>}\r\n {dateTimes.map((dateTime_) => (\r\n <button\r\n type=\"button\"\r\n key={dateTime_}\r\n className={`mncl-button mncl-button--${dateTime_ == dateTime ? \"selected\" : \"default\"}`}\r\n onClick={() => setDateTime(dateTime_)}\r\n >\r\n {DateTime.fromISO(dateTime_).toFormat(\"HH:mm\")}\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n )\r\n}\r\n","import { DateTime } from \"luxon\"\r\n\r\nexport type IsoDate = `${number}-${number}-${number}`\r\nexport type GetDateTimes = (start: IsoDate, end: IsoDate) => Promise<string[]>\r\n\r\ninterface Options {\r\n zone?: string\r\n}\r\n\r\nexport function createCachedGetDateTimes(getDateTimes: GetDateTimes, options: Options): GetDateTimes {\r\n const zone = options?.zone\r\n\r\n const byDay = new Map<IsoDate, string[]>()\r\n const inFlight = new Map<string, Promise<void>>()\r\n\r\n const toDayKey = (iso: string) => DateTime.fromISO(iso, { zone }).toISODate() as IsoDate\r\n\r\n const listDays = (start: IsoDate, end: IsoDate): IsoDate[] => {\r\n const s = DateTime.fromISO(start, { zone }).startOf(\"day\")\r\n const e = DateTime.fromISO(end, { zone }).startOf(\"day\")\r\n const out: IsoDate[] = []\r\n for (let d = s; d < e; d = d.plus({ days: 1 })) out.push(d.toISODate() as IsoDate)\r\n return out\r\n }\r\n\r\n const uniqueSorted = (arr: string[]) => Array.from(new Set(arr)).sort()\r\n\r\n const markKnownEmpty = (start: IsoDate, end: IsoDate) => {\r\n for (const day of listDays(start, end)) {\r\n if (!byDay.has(day)) byDay.set(day, [])\r\n }\r\n }\r\n\r\n const bucket = (isos: string[]) => {\r\n for (const iso of isos) {\r\n const day = toDayKey(iso)\r\n const arr = byDay.get(day)\r\n if (arr) arr.push(iso)\r\n else byDay.set(day, [iso])\r\n }\r\n }\r\n\r\n async function fetchSegment(segStart: IsoDate, segEnd: IsoDate) {\r\n console.log(segStart, segEnd)\r\n const key = `${segStart}|${segEnd}`\r\n if (!inFlight.has(key)) {\r\n inFlight.set(\r\n key,\r\n (async () => {\r\n const dtIsos = await getDateTimes(segStart, segEnd)\r\n markKnownEmpty(segStart, segEnd)\r\n bucket(dtIsos)\r\n })().finally(() => {\r\n inFlight.delete(key)\r\n }),\r\n )\r\n }\r\n await inFlight.get(key)!\r\n }\r\n\r\n async function ensureCached(start: IsoDate, end: IsoDate) {\r\n const days = listDays(start, end)\r\n const unknown = days.filter((d) => !byDay.has(d))\r\n\r\n if (unknown.length === 0) return\r\n\r\n let segStart: IsoDate | null = null\r\n let prev: DateTime | null = null\r\n\r\n const flush = async () => {\r\n if (!segStart || !prev) return\r\n const segEnd = prev.plus({ days: 1 }).toISODate() as IsoDate\r\n await fetchSegment(segStart, segEnd)\r\n segStart = null\r\n prev = null\r\n }\r\n\r\n for (const day of unknown) {\r\n const dt = DateTime.fromISO(day, { zone }).startOf(\"day\")\r\n if (!segStart) {\r\n segStart = day\r\n prev = dt\r\n continue\r\n }\r\n const expectedNext = prev!.plus({ days: 1 }).toISODate()\r\n if (expectedNext !== day) {\r\n await flush()\r\n segStart = day\r\n prev = dt\r\n } else {\r\n prev = dt\r\n }\r\n }\r\n await flush()\r\n }\r\n\r\n return async (start: IsoDate, end: IsoDate) => {\r\n const endExclusive = DateTime.fromISO(end, { zone }).plus({ days: 1 }).toISODate() as IsoDate\r\n\r\n await ensureCached(start, endExclusive)\r\n\r\n const out: string[] = []\r\n for (const day of listDays(start, endExclusive)) {\r\n out.push(...(byDay.get(day) ?? []))\r\n }\r\n\r\n return uniqueSorted(out)\r\n }\r\n}\r\n"],"mappings":"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","names":["day","useEffect","useState","jsx","jsxs","useState","useEffect","DateTime","useEffect","useState","jsx","jsxs","DateTime"]}
package/dist/style.css ADDED
@@ -0,0 +1,191 @@
1
+ @import url("https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Rubik:ital,wght@0,300..900;1,300..900&family=Space+Grotesk:wght@300..700&display=swap");
2
+ .mncl-date-selector {
3
+ display: flex;
4
+ flex-direction: column;
5
+ align-items: center;
6
+ background-color: #ffffff;
7
+ border-radius: 1rem;
8
+ width: 32rem;
9
+ max-width: 100%;
10
+ box-shadow: 0 0 1rem 0 rgba(0, 0, 0, 0.1254901961);
11
+ }
12
+ .mncl-date-selector__head {
13
+ width: 100%;
14
+ display: flex;
15
+ justify-content: space-between;
16
+ align-items: center;
17
+ padding: 1.75rem 2rem 1.5rem 2rem;
18
+ border-bottom: 0.125rem solid #ced4da;
19
+ }
20
+ .mncl-date-selector__grid {
21
+ display: grid;
22
+ grid-template-columns: repeat(7, 1fr);
23
+ gap: 0.5rem;
24
+ padding: 2rem;
25
+ width: min-content;
26
+ }
27
+ .mncl-date-selector__grid > button {
28
+ display: flex;
29
+ flex-direction: column;
30
+ align-items: center;
31
+ justify-content: center;
32
+ text-align: center;
33
+ width: 3rem;
34
+ height: 2.75rem;
35
+ }
36
+ .mncl-date-selector__grid > button.ignore {
37
+ background-color: transparent;
38
+ box-shadow: none;
39
+ }
40
+ .mncl-date-selector__grid > p {
41
+ font-size: 0.875rem;
42
+ color: #868e96;
43
+ width: 100%;
44
+ text-align: center;
45
+ }
46
+ .mncl-date-selector__foot {
47
+ display: flex;
48
+ justify-content: center;
49
+ flex-wrap: wrap;
50
+ gap: 1rem 2rem;
51
+ padding: 1rem 2rem 2rem 2rem;
52
+ font-size: 0.875rem;
53
+ color: #868e96;
54
+ }
55
+ .mncl-date-selector__foot div {
56
+ display: flex;
57
+ align-items: center;
58
+ gap: 0.5rem;
59
+ }
60
+
61
+ .mncl-time-selector {
62
+ display: flex;
63
+ flex-direction: column;
64
+ align-items: center;
65
+ background-color: #ffffff;
66
+ border-radius: 1rem;
67
+ height: fit-content;
68
+ width: 32rem;
69
+ max-width: 100%;
70
+ box-shadow: 0 0 1rem 0 rgba(0, 0, 0, 0.1254901961);
71
+ padding: 2rem;
72
+ gap: 2rem;
73
+ }
74
+ .mncl-time-selector__head {
75
+ width: 100%;
76
+ }
77
+ .mncl-time-selector__head h2 {
78
+ font-size: 1.5rem;
79
+ }
80
+ .mncl-time-selector__grid {
81
+ width: 100%;
82
+ display: grid;
83
+ grid-template-columns: repeat(auto-fit, minmax(6rem, 1fr));
84
+ gap: 0.75rem;
85
+ }
86
+
87
+ .mncl-datetime-selector {
88
+ display: flex;
89
+ flex-direction: column;
90
+ align-items: center;
91
+ gap: 4rem;
92
+ padding: 4rem;
93
+ font-family: "Rubik", sans-serif;
94
+ }
95
+ .mncl-datetime-selector h2 {
96
+ font-family: "Space Grotesk", sans-serif;
97
+ }
98
+
99
+ /**
100
+ * BUTTONS
101
+ */
102
+ .mncl-button {
103
+ position: relative;
104
+ display: flex;
105
+ gap: 0.75rem;
106
+ align-items: center;
107
+ justify-content: center;
108
+ max-width: 100%;
109
+ padding: 0.5rem 1rem;
110
+ margin-bottom: 0.25rem;
111
+ font-size: 1rem;
112
+ font-family: inherit;
113
+ color: var(--mncl-button-text, #000000);
114
+ background-color: var(--mncl-button-light);
115
+ border-radius: 0.5rem;
116
+ border: 0.125rem solid var(--mncl-button-border, var(--mncl-button-light));
117
+ box-shadow: 0 0.25rem 0 0 var(--mncl-button-dark);
118
+ text-decoration: none;
119
+ }
120
+ .mncl-button:not(:disabled):not(.disabled):not(.no-interact) {
121
+ cursor: pointer;
122
+ }
123
+ .mncl-button::before {
124
+ content: "";
125
+ position: absolute;
126
+ top: -0.125rem;
127
+ left: -0.125rem;
128
+ width: calc(100% + 0.25rem);
129
+ height: calc(100% + 0.25rem);
130
+ }
131
+ .mncl-button:hover:not(:disabled):not(.disabled):not(.no-interact) {
132
+ border-color: var(--mncl-button-dark);
133
+ }
134
+ .mncl-button:active:not(:disabled):not(.disabled):not(.no-interact) {
135
+ transform: translateY(0.25rem);
136
+ box-shadow: none;
137
+ }
138
+ .mncl-button:active:not(:disabled):not(.disabled):not(.no-interact)::before {
139
+ top: -0.375rem;
140
+ }
141
+ .mncl-button--accent {
142
+ --mncl-button-light: #74c0fc;
143
+ --mncl-button-dark: #228be6;
144
+ }
145
+ .mncl-button--high {
146
+ --mncl-button-light: #69db7c;
147
+ --mncl-button-dark: #37b24d;
148
+ }
149
+ .mncl-button--medium {
150
+ --mncl-button-light: #ffd43b;
151
+ --mncl-button-dark: #fab005;
152
+ }
153
+ .mncl-button--low {
154
+ --mncl-button-light: #ff6b6b;
155
+ --mncl-button-dark: #e03131;
156
+ }
157
+ .mncl-button--default {
158
+ --mncl-button-light: #ced4da;
159
+ --mncl-button-dark: #adb5bd;
160
+ }
161
+ .mncl-button--selected {
162
+ --mncl-button-text: #1c7ed6;
163
+ --mncl-button-light: #ffffff;
164
+ --mncl-button-dark: #1c7ed6;
165
+ --mncl-button-border: #1c7ed6;
166
+ }
167
+ .mncl-button:disabled {
168
+ --mncl-button-text: #adb5bd;
169
+ --mncl-button-light: #f1f3f5;
170
+ --mncl-button-dark: #ced4da;
171
+ }
172
+
173
+ .mncl-indicator {
174
+ width: 0.75rem;
175
+ height: 0.75rem;
176
+ border-radius: 50%;
177
+ }
178
+ .mncl-indicator--high {
179
+ background-color: #69db7c;
180
+ }
181
+ .mncl-indicator--medium {
182
+ background-color: #fcc419;
183
+ }
184
+ .mncl-indicator--low {
185
+ background-color: #fa5252;
186
+ }
187
+ .mncl-indicator--no {
188
+ background-color: #ced4da;
189
+ }
190
+
191
+ /*# sourceMappingURL=style.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sourceRoot":"","sources":["../src/style.scss"],"names":[],"mappings":"AAAQ;AAER;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;;;AAKZ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAEA;EACI;;AAIR;EACI;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;;AAIR;AAAA;AAAA;AAIA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;;AAGJ;EACI;EACA;;AAEA;EACI;;AAIR;EACI;EACA;;AAEJ;EACI;EACA;;AAEJ;EACI;EACA;;AAEJ;EACI;EACA;;AAEJ;EACI;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAIR;EACI;EACA;EACA;;AAEA;EACI;;AAEJ;EACI;;AAEJ;EACI;;AAEJ;EACI","file":"style.css"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@minicalendar/react",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "description": "",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./style.css": "./dist/style.css"
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup && npm run build:css",
20
+ "build:css": "sass src/style.scss dist/style.css",
21
+ "dev": "tsup --watch",
22
+ "prepublishOnly": "npm run build"
23
+ },
24
+ "peerDependencies": {
25
+ "luxon": ">=3",
26
+ "react": ">=18 <20",
27
+ "react-dom": ">=18 <20"
28
+ },
29
+ "peerDependenciesMeta": {
30
+ "react-dom": {
31
+ "optional": true
32
+ }
33
+ },
34
+ "devDependencies": {
35
+ "@types/luxon": "^3.7.1",
36
+ "@types/react": "^19.2.14",
37
+ "sass": "^1.97.3",
38
+ "tsup": "^8.5.1",
39
+ "typescript": "^5.9.3"
40
+ },
41
+ "keywords": [],
42
+ "author": "",
43
+ "license": "ISC"
44
+ }