@dxos/react-ui-calendar 0.8.4-main.9735255 → 0.8.4-main.abd8ff62ef
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/dist/lib/browser/index.mjs +48 -65
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/translations.mjs +16 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +48 -65
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/translations.mjs +18 -0
- package/dist/lib/node-esm/translations.mjs.map +7 -0
- package/dist/types/src/components/Calendar/Calendar.d.ts +12 -18
- package/dist/types/src/components/Calendar/Calendar.d.ts.map +1 -1
- package/dist/types/src/components/Calendar/Calendar.stories.d.ts +4 -9
- package/dist/types/src/components/Calendar/Calendar.stories.d.ts.map +1 -1
- package/dist/types/src/components/Calendar/util.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +1 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +25 -20
- package/src/components/Calendar/Calendar.stories.tsx +15 -40
- package/src/components/Calendar/Calendar.tsx +145 -158
- package/src/translations.ts +1 -1
|
@@ -1,24 +1,13 @@
|
|
|
1
1
|
// src/components/Calendar/Calendar.tsx
|
|
2
2
|
import { createContext } from "@radix-ui/react-context";
|
|
3
|
-
import { addDays, differenceInWeeks, format, startOfWeek } from "date-fns";
|
|
3
|
+
import { addDays, differenceInWeeks, format, startOfDay, startOfWeek } from "date-fns";
|
|
4
4
|
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
5
5
|
import { useResizeDetector } from "react-resize-detector";
|
|
6
6
|
import { List } from "react-virtualized";
|
|
7
7
|
import { Event } from "@dxos/async";
|
|
8
|
-
import {
|
|
9
|
-
import { mx } from "@dxos/ui-theme";
|
|
10
|
-
|
|
11
|
-
// src/translations.ts
|
|
12
|
-
var translationKey = "@dxos/react-ui-calendar";
|
|
13
|
-
var translations = [
|
|
14
|
-
{
|
|
15
|
-
"en-US": {
|
|
16
|
-
[translationKey]: {
|
|
17
|
-
"today button": "Today"
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
];
|
|
8
|
+
import { IconButton, useTranslation } from "@dxos/react-ui";
|
|
9
|
+
import { composable, composableProps, mx } from "@dxos/ui-theme";
|
|
10
|
+
import { translationKey } from "#translations";
|
|
22
11
|
|
|
23
12
|
// src/components/Calendar/util.ts
|
|
24
13
|
var getDate = (start2, weekNumber, dayOfWeek, weekStartsOn) => {
|
|
@@ -61,16 +50,10 @@ var CalendarRoot = /* @__PURE__ */ forwardRef(({ children, weekStartsOn = 1 }, f
|
|
|
61
50
|
setSelected
|
|
62
51
|
}, children);
|
|
63
52
|
});
|
|
64
|
-
var
|
|
65
|
-
|
|
66
|
-
role: "none",
|
|
67
|
-
className: mx("flex flex-col items-center overflow-hidden bg-inputSurface", classNames)
|
|
68
|
-
}, children);
|
|
69
|
-
};
|
|
70
|
-
CalendarViewport.displayName = "CalendarContent";
|
|
71
|
-
var CalendarToolbar = ({ classNames }) => {
|
|
53
|
+
var CALENDAR_TOOLBAR_NAME = "CalendarHeader";
|
|
54
|
+
var CalendarToolbar = composable(({ classNames, ...props }, forwardedRef) => {
|
|
72
55
|
const { t } = useTranslation(translationKey);
|
|
73
|
-
const { weekStartsOn, event, index, selected } = useCalendarContext(
|
|
56
|
+
const { weekStartsOn, event, index, selected } = useCalendarContext(CALENDAR_TOOLBAR_NAME);
|
|
74
57
|
const top = useMemo(() => getDate(start, index ?? 0, 6, weekStartsOn), [
|
|
75
58
|
index,
|
|
76
59
|
weekStartsOn
|
|
@@ -87,8 +70,14 @@ var CalendarToolbar = ({ classNames }) => {
|
|
|
87
70
|
today
|
|
88
71
|
]);
|
|
89
72
|
return /* @__PURE__ */ React.createElement("div", {
|
|
90
|
-
|
|
91
|
-
|
|
73
|
+
...composableProps(props, {
|
|
74
|
+
role: "none",
|
|
75
|
+
classNames: [
|
|
76
|
+
"shrink-0 grid! grid-cols-3 items-center bg-toolbar-surface",
|
|
77
|
+
classNames
|
|
78
|
+
]
|
|
79
|
+
}),
|
|
80
|
+
ref: forwardedRef,
|
|
92
81
|
style: {
|
|
93
82
|
width: defaultWidth
|
|
94
83
|
}
|
|
@@ -96,25 +85,31 @@ var CalendarToolbar = ({ classNames }) => {
|
|
|
96
85
|
className: "flex justify-start"
|
|
97
86
|
}, /* @__PURE__ */ React.createElement(IconButton, {
|
|
98
87
|
variant: "ghost",
|
|
99
|
-
size: 5,
|
|
100
88
|
icon: "ph--calendar--regular",
|
|
101
89
|
iconOnly: true,
|
|
102
90
|
classNames: "aspect-square",
|
|
103
|
-
label: t("today
|
|
91
|
+
label: t("today.button"),
|
|
104
92
|
onClick: handleToday
|
|
105
93
|
})), /* @__PURE__ */ React.createElement("div", {
|
|
106
94
|
className: "flex justify-center p-2 text-description"
|
|
107
95
|
}, format(selected ?? top, "MMMM")), /* @__PURE__ */ React.createElement("div", {
|
|
108
96
|
className: "flex justify-end p-2 text-description"
|
|
109
97
|
}, (selected ?? top).getFullYear()));
|
|
110
|
-
};
|
|
111
|
-
CalendarToolbar.displayName =
|
|
112
|
-
var
|
|
113
|
-
|
|
98
|
+
});
|
|
99
|
+
CalendarToolbar.displayName = CALENDAR_TOOLBAR_NAME;
|
|
100
|
+
var CALENDAR_GRID_NAME = "CalendarGrid";
|
|
101
|
+
var CalendarGrid = composable(({ classNames, rows, dates = [], onSelect, ...props }, forwardedRef) => {
|
|
102
|
+
const { weekStartsOn, event, setIndex, selected, setSelected } = useCalendarContext(CALENDAR_GRID_NAME);
|
|
114
103
|
const { ref: containerRef, width = 0, height = 0 } = useResizeDetector();
|
|
115
104
|
const maxHeight = rows ? rows * size : void 0;
|
|
116
105
|
const listRef = useRef(null);
|
|
117
106
|
const today = useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
107
|
+
const dateSet = useMemo(() => new Set(dates.map((date) => startOfDay(date).toISOString())), [
|
|
108
|
+
dates
|
|
109
|
+
]);
|
|
110
|
+
const hasDate = useCallback((date) => dateSet.has(startOfDay(date).toISOString()), [
|
|
111
|
+
dateSet
|
|
112
|
+
]);
|
|
118
113
|
const [initialized, setInitialized] = useState(false);
|
|
119
114
|
useEffect(() => {
|
|
120
115
|
const index = differenceInWeeks(today, start);
|
|
@@ -148,9 +143,6 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
148
143
|
return format(day, "EEE");
|
|
149
144
|
});
|
|
150
145
|
}, []);
|
|
151
|
-
const getNumAppointments = useCallback((_date) => {
|
|
152
|
-
return 0;
|
|
153
|
-
}, []);
|
|
154
146
|
const handleDaySelect = useCallback((date) => {
|
|
155
147
|
setSelected((current) => isSameDay(date, current) ? void 0 : date);
|
|
156
148
|
onSelect?.({
|
|
@@ -163,18 +155,15 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
163
155
|
setIndex(Math.round(info.scrollTop / size));
|
|
164
156
|
}, []);
|
|
165
157
|
const rowRenderer = useCallback(({ key, index, style }) => {
|
|
166
|
-
const getBgColor = (date) => date.getMonth() % 2 === 0 && "bg-
|
|
158
|
+
const getBgColor = (date) => date.getMonth() % 2 === 0 && "bg-modal-surface";
|
|
167
159
|
return /* @__PURE__ */ React.createElement("div", {
|
|
168
160
|
key,
|
|
169
161
|
role: "none",
|
|
170
162
|
style,
|
|
171
|
-
className: "
|
|
163
|
+
className: "grid"
|
|
172
164
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
173
165
|
role: "none",
|
|
174
|
-
className:
|
|
175
|
-
}), /* @__PURE__ */ React.createElement("div", {
|
|
176
|
-
role: "none",
|
|
177
|
-
className: "grid grid-cols-7",
|
|
166
|
+
className: "grid grid-cols-7 bg-input-surface",
|
|
178
167
|
style: {
|
|
179
168
|
gridTemplateColumns: `repeat(7, ${size}px)`
|
|
180
169
|
}
|
|
@@ -182,8 +171,7 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
182
171
|
length: 7
|
|
183
172
|
}).map((_, i) => {
|
|
184
173
|
const date = getDate(start, index, i, weekStartsOn);
|
|
185
|
-
const
|
|
186
|
-
const border = isSameDay(date, selected) ? "border-primary-500" : isSameDay(date, today) ? "border-amber-500" : void 0;
|
|
174
|
+
const border = isSameDay(date, selected) ? "border-primary-500" : isSameDay(date, today) ? "border-amber-500" : hasDate(date) ? "border-neutral-700 border-dashed" : void 0;
|
|
187
175
|
return /* @__PURE__ */ React.createElement("div", {
|
|
188
176
|
key: i,
|
|
189
177
|
role: "none",
|
|
@@ -195,30 +183,27 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
195
183
|
className: "absolute top-0 text-xs text-description"
|
|
196
184
|
}, format(date, "MMM")), border && /* @__PURE__ */ React.createElement("div", {
|
|
197
185
|
role: "none",
|
|
198
|
-
className: mx("absolute
|
|
199
|
-
}), num > 0 && /* @__PURE__ */ React.createElement(Icon, {
|
|
200
|
-
classNames: "absolute bottom-0",
|
|
201
|
-
icon: num > 3 ? "ph--dots-three--regular" : "ph--dot--regular",
|
|
202
|
-
size: 5
|
|
186
|
+
className: mx("absolute inset-1 border-2 rounded-full", border)
|
|
203
187
|
}));
|
|
204
|
-
}))
|
|
205
|
-
className: mx(getBgColor(getDate(start, index, 6, weekStartsOn)))
|
|
206
|
-
}));
|
|
188
|
+
})));
|
|
207
189
|
}, [
|
|
208
190
|
handleDaySelect,
|
|
209
|
-
|
|
191
|
+
hasDate,
|
|
210
192
|
selected,
|
|
211
193
|
weekStartsOn
|
|
212
194
|
]);
|
|
213
195
|
return /* @__PURE__ */ React.createElement("div", {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
196
|
+
...composableProps(props, {
|
|
197
|
+
role: "none",
|
|
198
|
+
classNames: [
|
|
199
|
+
"flex flex-col h-full w-full justify-center overflow-hidden",
|
|
200
|
+
classNames
|
|
201
|
+
]
|
|
202
|
+
}),
|
|
203
|
+
ref: forwardedRef
|
|
219
204
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
220
205
|
role: "none",
|
|
221
|
-
className: "
|
|
206
|
+
className: "grid w-full grid-cols-7",
|
|
222
207
|
style: {
|
|
223
208
|
width: defaultWidth
|
|
224
209
|
}
|
|
@@ -226,15 +211,14 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
226
211
|
key: i,
|
|
227
212
|
role: "none",
|
|
228
213
|
className: "flex justify-center p-2 text-sm font-thin"
|
|
229
|
-
}, date)))
|
|
214
|
+
}, date))), /* @__PURE__ */ React.createElement("div", {
|
|
230
215
|
role: "none",
|
|
231
|
-
className: "flex flex-col
|
|
216
|
+
className: "flex flex-col h-full w-full justify-center overflow-hidden",
|
|
232
217
|
ref: containerRef
|
|
233
218
|
}, /* @__PURE__ */ React.createElement(List, {
|
|
234
219
|
ref: listRef,
|
|
235
220
|
role: "none",
|
|
236
|
-
|
|
237
|
-
className: "[&>div]:snap-y scrollbar-none outline-none",
|
|
221
|
+
className: "scrollbar-none outline-hidden",
|
|
238
222
|
width,
|
|
239
223
|
height: maxHeight ?? height,
|
|
240
224
|
rowCount: maxRows,
|
|
@@ -244,11 +228,10 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
244
228
|
onScroll: handleScroll,
|
|
245
229
|
onRowsRendered: () => setInitialized(true)
|
|
246
230
|
})));
|
|
247
|
-
};
|
|
248
|
-
CalendarGrid.displayName =
|
|
231
|
+
});
|
|
232
|
+
CalendarGrid.displayName = CALENDAR_GRID_NAME;
|
|
249
233
|
var Calendar = {
|
|
250
234
|
Root: CalendarRoot,
|
|
251
|
-
Viewport: CalendarViewport,
|
|
252
235
|
Toolbar: CalendarToolbar,
|
|
253
236
|
Grid: CalendarGrid
|
|
254
237
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/components/Calendar/Calendar.tsx", "../../../src/
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { createContext } from '@radix-ui/react-context';\nimport { type Day, addDays, differenceInWeeks, format, startOfWeek } from 'date-fns';\nimport React, {\n type Dispatch,\n type PropsWithChildren,\n type SetStateAction,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useResizeDetector } from 'react-resize-detector';\nimport { List, type ListProps, type ListRowRenderer } from 'react-virtualized';\n\nimport { Event } from '@dxos/async';\nimport { Icon, IconButton, type ThemedClassName, useTranslation } from '@dxos/react-ui';\nimport { mx } from '@dxos/ui-theme';\n\nimport { translationKey } from '../../translations';\n\nimport { getDate, isSameDay } from './util';\n\nconst maxRows = 50 * 100;\nconst start = new Date('1970-01-01');\nconst size = 48;\nconst defaultWidth = 7 * size;\n\n//\n// Context\n//\n\ntype CalendarEvent = {\n type: 'scroll';\n date: Date;\n};\n\ntype CalendarContextValue = {\n weekStartsOn: Day;\n event: Event<CalendarEvent>;\n index: number | undefined;\n setIndex: Dispatch<SetStateAction<number | undefined>>;\n selected: Date | undefined;\n setSelected: Dispatch<SetStateAction<Date | undefined>>;\n};\n\nconst [CalendarContextProvider, useCalendarContext] = createContext<CalendarContextValue>('Calendar');\n\n//\n// Controller\n//\n\ntype CalendarController = {\n scrollTo: (date: Date) => void;\n};\n\n//\n// Root\n//\n\ntype CalendarRootProps = PropsWithChildren<Partial<Pick<CalendarContextValue, 'weekStartsOn'>>>;\n\nconst CalendarRoot = forwardRef<CalendarController, CalendarRootProps>(\n ({ children, weekStartsOn = 1 }, forwardedRef) => {\n const event = useMemo(() => new Event<CalendarEvent>(), []);\n const [selected, setSelected] = useState<Date | undefined>();\n const [index, setIndex] = useState<number | undefined>();\n\n useImperativeHandle(\n forwardedRef,\n () => ({\n scrollTo: (date: Date) => {\n event.emit({ type: 'scroll', date });\n },\n }),\n [event],\n );\n\n return (\n <CalendarContextProvider\n weekStartsOn={weekStartsOn}\n event={event}\n index={index}\n setIndex={setIndex}\n selected={selected}\n setSelected={setSelected}\n >\n {children}\n </CalendarContextProvider>\n );\n },\n);\n\n//\n// Viewport\n//\n\ntype CalendarViewportProps = PropsWithChildren<ThemedClassName>;\n\nconst CalendarViewport = ({ children, classNames }: CalendarViewportProps) => {\n return (\n <div role='none' className={mx('flex flex-col items-center overflow-hidden bg-inputSurface', classNames)}>\n {children}\n </div>\n );\n};\n\nCalendarViewport.displayName = 'CalendarContent';\n\n//\n// Header\n//\n\ntype CalendarToolbarProps = ThemedClassName;\n\nconst CalendarToolbar = ({ classNames }: CalendarToolbarProps) => {\n const { t } = useTranslation(translationKey);\n const { weekStartsOn, event, index, selected } = useCalendarContext(CalendarToolbar.displayName);\n const top = useMemo(() => getDate(start, index ?? 0, 6, weekStartsOn), [index, weekStartsOn]);\n const today = useMemo(() => new Date(), []);\n\n const handleToday = useCallback(() => {\n event.emit({ type: 'scroll', date: today });\n }, [event, start, today]);\n\n return (\n <div\n role='none'\n className={mx('shink-0 is-full grid grid-cols-3 items-center bg-barSurface', classNames)}\n style={{ width: defaultWidth }}\n >\n <div className='flex justify-start'>\n <IconButton\n variant='ghost'\n size={5}\n icon='ph--calendar--regular'\n iconOnly\n classNames='aspect-square'\n label={t('today button')}\n onClick={handleToday}\n />\n </div>\n <div className='flex justify-center p-2 text-description'>{format(selected ?? top, 'MMMM')}</div>\n <div className='flex justify-end p-2 text-description'>{(selected ?? top).getFullYear()}</div>\n </div>\n );\n};\n\nCalendarToolbar.displayName = 'CalendarHeader';\n\n//\n// Grid\n// TODO(burdon): Key nav.\n// TODO(burdon): Drag range.\n//\n\ntype CalendarGridProps = ThemedClassName<{\n rows?: number;\n onSelect?: (event: { date: Date }) => void;\n}>;\n\nconst CalendarGrid = ({ classNames, rows, onSelect }: CalendarGridProps) => {\n const { weekStartsOn, event, setIndex, selected, setSelected } = useCalendarContext(CalendarGrid.displayName);\n const { ref: containerRef, width = 0, height = 0 } = useResizeDetector();\n const maxHeight = rows ? rows * size : undefined;\n const listRef = useRef<List>(null);\n const today = useMemo(() => new Date(), []);\n\n const [initialized, setInitialized] = useState(false);\n useEffect(() => {\n const index = differenceInWeeks(today, start);\n listRef.current?.scrollToRow(index);\n }, [initialized, start, today]);\n\n useEffect(() => {\n return event.on((event) => {\n switch (event.type) {\n case 'scroll': {\n const index = differenceInWeeks(event.date, start);\n listRef.current?.scrollToRow(index);\n break;\n }\n }\n });\n }, [event]);\n\n const days = useMemo(() => {\n const weekStart = startOfWeek(new Date(), { weekStartsOn });\n return Array.from({ length: 7 }, (_, i) => {\n const day = addDays(weekStart, i);\n return format(day, 'EEE'); // Short day name (Mon, Tue, etc.)\n });\n }, []);\n\n // TODO(burdon): Get info by range.\n // TODO(burdon): Border marker for \"all day events?\"\n const getNumAppointments = useCallback((_date: Date) => {\n // return Math.floor(Math.random() * 10);\n return 0;\n }, []);\n\n const handleDaySelect = useCallback(\n (date: Date) => {\n setSelected((current) => (isSameDay(date, current) ? undefined : date));\n onSelect?.({ date });\n },\n [onSelect],\n );\n\n const handleScroll = useCallback<NonNullable<ListProps['onScroll']>>((info) => {\n setIndex(Math.round(info.scrollTop / size));\n }, []);\n\n const rowRenderer = useCallback<ListRowRenderer>(\n ({ key, index, style }) => {\n const getBgColor = (date: Date) => date.getMonth() % 2 === 0 && 'bg-modalSurface';\n return (\n <div key={key} role='none' style={style} className='is-full grid grid-cols-[1fr_max-content_1fr] snap-center'>\n <div role='none' className={mx(getBgColor(getDate(start, index, 0, weekStartsOn)))} />\n <div role='none' className='grid grid-cols-7' style={{ gridTemplateColumns: `repeat(7, ${size}px)` }}>\n {Array.from({ length: 7 }).map((_, i) => {\n const date = getDate(start, index, i, weekStartsOn);\n const num = getNumAppointments(date);\n const border = isSameDay(date, selected)\n ? 'border-primary-500'\n : isSameDay(date, today)\n ? 'border-amber-500'\n : undefined;\n\n return (\n <div\n key={i}\n role='none'\n className={mx('relative flex justify-center items-center cursor-pointer', getBgColor(date))}\n onClick={() => handleDaySelect(date)}\n >\n <span className='text-description'>{date.getDate()}</span>\n {!border && date.getDate() === 1 && (\n <span className='absolute top-0 text-xs text-description'>{format(date, 'MMM')}</span>\n )}\n {border && (\n <div\n role='none'\n className={mx('absolute top-0 left-0 is-full bs-full border-2 rounded-full', border)}\n />\n )}\n {num > 0 && (\n <Icon\n classNames='absolute bottom-0'\n icon={num > 3 ? 'ph--dots-three--regular' : 'ph--dot--regular'}\n size={5}\n />\n )}\n </div>\n );\n })}\n </div>\n <div className={mx(getBgColor(getDate(start, index, 6, weekStartsOn)))} />\n </div>\n );\n },\n [handleDaySelect, getNumAppointments, selected, weekStartsOn],\n );\n\n return (\n <div role='none' className={mx('flex flex-col bs-full is-full justify-center overflow-hidden', classNames)}>\n {/* Day labels */}\n <div role='none' className='flex justify-center bg-groupSurface'>\n <div role='none' className='flex is-full grid grid-cols-7' style={{ width: defaultWidth }}>\n {days.map((date, i) => (\n <div key={i} role='none' className='flex justify-center p-2 text-sm font-thin'>\n {date}\n </div>\n ))}\n </div>\n </div>\n\n {/* Grid */}\n <div role='none' className='flex flex-col bs-full is-full justify-center overflow-hidden' ref={containerRef}>\n <List\n ref={listRef}\n role='none'\n // TODO(burdon): Snap isn't working.\n className='[&>div]:snap-y scrollbar-none outline-none'\n width={width}\n height={maxHeight ?? height}\n rowCount={maxRows}\n rowHeight={size}\n rowRenderer={rowRenderer}\n scrollToAlignment='start'\n onScroll={handleScroll}\n onRowsRendered={() => setInitialized(true)}\n />\n </div>\n </div>\n );\n};\n\nCalendarGrid.displayName = 'CalendarGrid';\n\n//\n// Calendar\n//\n\nexport const Calendar = {\n Root: CalendarRoot,\n Viewport: CalendarViewport,\n Toolbar: CalendarToolbar,\n Grid: CalendarGrid,\n};\n\nexport type { CalendarController, CalendarRootProps, CalendarViewportProps, CalendarToolbarProps, CalendarGridProps };\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Resource } from '@dxos/react-ui';\n\nexport const translationKey = '@dxos/react-ui-calendar';\n\nexport const translations = [\n {\n 'en-US': {\n [translationKey]: {\n 'today button': 'Today',\n },\n },\n },\n] as const satisfies Resource[];\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Day } from 'date-fns';\n\nexport const getDate = (start: Date, weekNumber: number, dayOfWeek: number, weekStartsOn: Day): Date => {\n const result = new Date(start);\n const startDayOfWeek = start.getDay(); // 0 = Sunday, 1 = Monday, etc.\n const adjustedStartDay = (startDayOfWeek === 0 ? 7 : startDayOfWeek) - weekStartsOn; // Adjust for weekStartsOn.\n result.setDate(start.getDate() - adjustedStartDay + weekNumber * 7 + dayOfWeek);\n return result;\n};\n\nexport const isSameDay = (date1: Date, date2: Date | undefined): boolean => {\n return (\n !!date2 &&\n date1.getFullYear() === date2.getFullYear() &&\n date1.getMonth() === date2.getMonth() &&\n date1.getDate() === date2.getDate()\n );\n};\n"],
|
|
5
|
-
"mappings": ";AAIA,SAASA,qBAAqB;AAC9B,SAAmBC,SAASC,mBAAmBC,QAAQC,mBAAmB;
|
|
6
|
-
"names": ["createContext", "addDays", "differenceInWeeks", "format", "startOfWeek", "React", "forwardRef", "useCallback", "useEffect", "useImperativeHandle", "useMemo", "useRef", "useState", "useResizeDetector", "List", "Event", "
|
|
3
|
+
"sources": ["../../../src/components/Calendar/Calendar.tsx", "../../../src/components/Calendar/util.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { createContext } from '@radix-ui/react-context';\nimport { type Day, addDays, differenceInWeeks, format, startOfDay, startOfWeek } from 'date-fns';\nimport React, {\n type Dispatch,\n type PropsWithChildren,\n type SetStateAction,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useResizeDetector } from 'react-resize-detector';\nimport { List, type ListProps, type ListRowRenderer } from 'react-virtualized';\n\nimport { Event } from '@dxos/async';\nimport { IconButton, useTranslation } from '@dxos/react-ui';\nimport { composable, composableProps, mx } from '@dxos/ui-theme';\n\nimport { translationKey } from '#translations';\n\nimport { getDate, isSameDay } from './util';\n\nconst maxRows = 50 * 100;\nconst start = new Date('1970-01-01');\nconst size = 48;\nconst defaultWidth = 7 * size;\n\n//\n// Context\n//\n\ntype CalendarEvent = {\n type: 'scroll';\n date: Date;\n};\n\ntype CalendarContextValue = {\n weekStartsOn: Day;\n event: Event<CalendarEvent>;\n index: number | undefined;\n setIndex: Dispatch<SetStateAction<number | undefined>>;\n selected: Date | undefined;\n setSelected: Dispatch<SetStateAction<Date | undefined>>;\n};\n\nconst [CalendarContextProvider, useCalendarContext] = createContext<CalendarContextValue>('Calendar');\n\n//\n// Controller\n//\n\ntype CalendarController = {\n scrollTo: (date: Date) => void;\n};\n\n//\n// Root\n//\n\ntype CalendarRootProps = PropsWithChildren<Partial<Pick<CalendarContextValue, 'weekStartsOn'>>>;\n\nconst CalendarRoot = forwardRef<CalendarController, CalendarRootProps>(\n ({ children, weekStartsOn = 1 }, forwardedRef) => {\n const event = useMemo(() => new Event<CalendarEvent>(), []);\n const [selected, setSelected] = useState<Date | undefined>();\n const [index, setIndex] = useState<number | undefined>();\n\n useImperativeHandle(\n forwardedRef,\n () => ({\n scrollTo: (date: Date) => {\n event.emit({ type: 'scroll', date });\n },\n }),\n [event],\n );\n\n return (\n <CalendarContextProvider\n weekStartsOn={weekStartsOn}\n event={event}\n index={index}\n setIndex={setIndex}\n selected={selected}\n setSelected={setSelected}\n >\n {children}\n </CalendarContextProvider>\n );\n },\n);\n\n//\n// Header\n//\n\nconst CALENDAR_TOOLBAR_NAME = 'CalendarHeader';\n\ntype CalendarToolbarProps = {};\n\nconst CalendarToolbar = composable<HTMLDivElement, CalendarToolbarProps>(({ classNames, ...props }, forwardedRef) => {\n const { t } = useTranslation(translationKey);\n const { weekStartsOn, event, index, selected } = useCalendarContext(CALENDAR_TOOLBAR_NAME);\n const top = useMemo(() => getDate(start, index ?? 0, 6, weekStartsOn), [index, weekStartsOn]);\n const today = useMemo(() => new Date(), []);\n\n const handleToday = useCallback(() => {\n event.emit({ type: 'scroll', date: today });\n }, [event, start, today]);\n\n return (\n <div\n {...composableProps(props, {\n role: 'none',\n classNames: ['shrink-0 grid! grid-cols-3 items-center bg-toolbar-surface', classNames],\n })}\n ref={forwardedRef}\n style={{ width: defaultWidth }}\n >\n <div className='flex justify-start'>\n <IconButton\n variant='ghost'\n icon='ph--calendar--regular'\n iconOnly\n classNames='aspect-square'\n label={t('today.button')}\n onClick={handleToday}\n />\n </div>\n <div className='flex justify-center p-2 text-description'>{format(selected ?? top, 'MMMM')}</div>\n <div className='flex justify-end p-2 text-description'>{(selected ?? top).getFullYear()}</div>\n </div>\n );\n});\n\nCalendarToolbar.displayName = CALENDAR_TOOLBAR_NAME;\n\n//\n// Grid\n// TODO(burdon): Key nav.\n// TODO(burdon): Drag range.\n//\n\nconst CALENDAR_GRID_NAME = 'CalendarGrid';\n\ntype CalendarGridProps = {\n rows?: number;\n /** Dates to highlight on the grid. Each date that appears in this array receives a border indicator. */\n dates?: Date[];\n onSelect?: (event: { date: Date }) => void;\n};\n\nconst CalendarGrid = composable<HTMLDivElement, CalendarGridProps>(\n ({ classNames, rows, dates = [], onSelect, ...props }, forwardedRef) => {\n const { weekStartsOn, event, setIndex, selected, setSelected } = useCalendarContext(CALENDAR_GRID_NAME);\n const { ref: containerRef, width = 0, height = 0 } = useResizeDetector();\n const maxHeight = rows ? rows * size : undefined;\n const listRef = useRef<List>(null);\n const today = useMemo(() => new Date(), []);\n\n // Build a set of ISO date strings (YYYY-MM-DD) for O(1) per-cell lookup.\n const dateSet = useMemo(() => new Set(dates.map((date) => startOfDay(date).toISOString())), [dates]);\n\n const hasDate = useCallback((date: Date) => dateSet.has(startOfDay(date).toISOString()), [dateSet]);\n\n const [initialized, setInitialized] = useState(false);\n useEffect(() => {\n const index = differenceInWeeks(today, start);\n listRef.current?.scrollToRow(index);\n }, [initialized, start, today]);\n\n useEffect(() => {\n return event.on((event) => {\n switch (event.type) {\n case 'scroll': {\n const index = differenceInWeeks(event.date, start);\n listRef.current?.scrollToRow(index);\n break;\n }\n }\n });\n }, [event]);\n\n const days = useMemo(() => {\n const weekStart = startOfWeek(new Date(), { weekStartsOn });\n return Array.from({ length: 7 }, (_, i) => {\n const day = addDays(weekStart, i);\n return format(day, 'EEE'); // Short day name (Mon, Tue, etc.)\n });\n }, []);\n\n // TODO(burdon): Get info by range.\n\n const handleDaySelect = useCallback(\n (date: Date) => {\n setSelected((current) => (isSameDay(date, current) ? undefined : date));\n onSelect?.({ date });\n },\n [onSelect],\n );\n\n const handleScroll = useCallback<NonNullable<ListProps['onScroll']>>((info) => {\n setIndex(Math.round(info.scrollTop / size));\n }, []);\n\n const rowRenderer = useCallback<ListRowRenderer>(\n ({ key, index, style }) => {\n const getBgColor = (date: Date) => date.getMonth() % 2 === 0 && 'bg-modal-surface';\n return (\n <div key={key} role='none' style={style} className='grid'>\n <div\n role='none'\n className='grid grid-cols-7 bg-input-surface'\n style={{ gridTemplateColumns: `repeat(7, ${size}px)` }}\n >\n {Array.from({ length: 7 }).map((_, i) => {\n const date = getDate(start, index, i, weekStartsOn);\n const border = isSameDay(date, selected)\n ? 'border-primary-500'\n : isSameDay(date, today)\n ? 'border-amber-500'\n : hasDate(date)\n ? 'border-neutral-700 border-dashed'\n : undefined;\n\n return (\n <div\n key={i}\n role='none'\n className={mx('relative flex justify-center items-center cursor-pointer', getBgColor(date))}\n onClick={() => handleDaySelect(date)}\n >\n <span className='text-description'>{date.getDate()}</span>\n {!border && date.getDate() === 1 && (\n <span className='absolute top-0 text-xs text-description'>{format(date, 'MMM')}</span>\n )}\n {border && <div role='none' className={mx('absolute inset-1 border-2 rounded-full', border)} />}\n </div>\n );\n })}\n </div>\n </div>\n );\n },\n [handleDaySelect, hasDate, selected, weekStartsOn],\n );\n\n return (\n <div\n {...composableProps(props, {\n role: 'none',\n classNames: ['flex flex-col h-full w-full justify-center overflow-hidden', classNames],\n })}\n ref={forwardedRef}\n >\n {/* Day of week labels */}\n <div role='none' className='grid w-full grid-cols-7' style={{ width: defaultWidth }}>\n {days.map((date, i) => (\n <div key={i} role='none' className='flex justify-center p-2 text-sm font-thin'>\n {date}\n </div>\n ))}\n </div>\n\n {/* Grid */}\n <div role='none' className='flex flex-col h-full w-full justify-center overflow-hidden' ref={containerRef}>\n <List\n ref={listRef}\n role='none'\n className='scrollbar-none outline-hidden'\n width={width}\n height={maxHeight ?? height}\n rowCount={maxRows}\n rowHeight={size}\n rowRenderer={rowRenderer}\n scrollToAlignment='start'\n onScroll={handleScroll}\n onRowsRendered={() => setInitialized(true)}\n />\n </div>\n </div>\n );\n },\n);\n\nCalendarGrid.displayName = CALENDAR_GRID_NAME;\n\n//\n// Calendar\n//\n\nexport const Calendar = {\n Root: CalendarRoot,\n Toolbar: CalendarToolbar,\n Grid: CalendarGrid,\n};\n\nexport type { CalendarController, CalendarRootProps, CalendarToolbarProps, CalendarGridProps };\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Day } from 'date-fns';\n\nexport const getDate = (start: Date, weekNumber: number, dayOfWeek: number, weekStartsOn: Day): Date => {\n const result = new Date(start);\n const startDayOfWeek = start.getDay(); // 0 = Sunday, 1 = Monday, etc.\n const adjustedStartDay = (startDayOfWeek === 0 ? 7 : startDayOfWeek) - weekStartsOn; // Adjust for weekStartsOn.\n result.setDate(start.getDate() - adjustedStartDay + weekNumber * 7 + dayOfWeek);\n return result;\n};\n\nexport const isSameDay = (date1: Date, date2: Date | undefined): boolean => {\n return (\n !!date2 &&\n date1.getFullYear() === date2.getFullYear() &&\n date1.getMonth() === date2.getMonth() &&\n date1.getDate() === date2.getDate()\n );\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["createContext", "addDays", "differenceInWeeks", "format", "startOfDay", "startOfWeek", "React", "forwardRef", "useCallback", "useEffect", "useImperativeHandle", "useMemo", "useRef", "useState", "useResizeDetector", "List", "Event", "IconButton", "useTranslation", "composable", "composableProps", "mx", "translationKey", "getDate", "start", "weekNumber", "dayOfWeek", "weekStartsOn", "result", "Date", "startDayOfWeek", "getDay", "adjustedStartDay", "setDate", "isSameDay", "date1", "date2", "getFullYear", "getMonth", "maxRows", "start", "Date", "size", "defaultWidth", "CalendarContextProvider", "useCalendarContext", "createContext", "CalendarRoot", "forwardRef", "children", "weekStartsOn", "forwardedRef", "event", "useMemo", "Event", "selected", "setSelected", "useState", "index", "setIndex", "useImperativeHandle", "scrollTo", "date", "emit", "type", "CALENDAR_TOOLBAR_NAME", "CalendarToolbar", "composable", "classNames", "props", "t", "useTranslation", "translationKey", "top", "getDate", "today", "handleToday", "useCallback", "div", "composableProps", "role", "ref", "style", "width", "className", "IconButton", "variant", "icon", "iconOnly", "label", "onClick", "format", "getFullYear", "displayName", "CALENDAR_GRID_NAME", "CalendarGrid", "rows", "dates", "onSelect", "containerRef", "height", "useResizeDetector", "maxHeight", "undefined", "listRef", "useRef", "dateSet", "Set", "map", "startOfDay", "toISOString", "hasDate", "has", "initialized", "setInitialized", "useEffect", "differenceInWeeks", "current", "scrollToRow", "on", "days", "weekStart", "startOfWeek", "Array", "from", "length", "_", "i", "day", "addDays", "handleDaySelect", "isSameDay", "handleScroll", "info", "Math", "round", "scrollTop", "rowRenderer", "key", "getBgColor", "getMonth", "gridTemplateColumns", "border", "mx", "span", "List", "rowCount", "rowHeight", "scrollToAlignment", "onScroll", "onRowsRendered", "Calendar", "Root", "Toolbar", "Grid"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"src/
|
|
1
|
+
{"inputs":{"src/components/Calendar/util.ts":{"bytes":2699,"imports":[],"format":"esm"},"src/components/Calendar/Calendar.tsx":{"bytes":29849,"imports":[{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"date-fns","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react-resize-detector","kind":"import-statement","external":true},{"path":"react-virtualized","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true},{"path":"#translations","kind":"import-statement","external":true},{"path":"src/components/Calendar/util.ts","kind":"import-statement","original":"./util"}],"format":"esm"},"src/components/Calendar/index.ts":{"bytes":376,"imports":[{"path":"src/components/Calendar/Calendar.tsx","kind":"import-statement","original":"./Calendar"}],"format":"esm"},"src/components/index.ts":{"bytes":376,"imports":[{"path":"src/components/Calendar/index.ts","kind":"import-statement","original":"./Calendar"}],"format":"esm"},"src/index.ts":{"bytes":382,"imports":[{"path":"src/components/index.ts","kind":"import-statement","original":"./components"}],"format":"esm"},"src/translations.ts":{"bytes":1105,"imports":[],"format":"esm"}},"outputs":{"dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":17699},"dist/lib/browser/index.mjs":{"imports":[{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"date-fns","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react-resize-detector","kind":"import-statement","external":true},{"path":"react-virtualized","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true},{"path":"#translations","kind":"import-statement","external":true}],"exports":["Calendar"],"entryPoint":"src/index.ts","inputs":{"src/components/Calendar/Calendar.tsx":{"bytesInOutput":7434},"src/components/Calendar/util.ts":{"bytesInOutput":517},"src/components/Calendar/index.ts":{"bytesInOutput":0},"src/components/index.ts":{"bytesInOutput":0},"src/index.ts":{"bytesInOutput":0}},"bytes":8126},"dist/lib/browser/translations.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":582},"dist/lib/browser/translations.mjs":{"imports":[],"exports":["translationKey","translations"],"entryPoint":"src/translations.ts","inputs":{"src/translations.ts":{"bytesInOutput":167}},"bytes":277}}}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/translations.ts
|
|
2
|
+
var translationKey = "@dxos/react-ui-calendar";
|
|
3
|
+
var translations = [
|
|
4
|
+
{
|
|
5
|
+
"en-US": {
|
|
6
|
+
[translationKey]: {
|
|
7
|
+
"today.button": "Today"
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
];
|
|
12
|
+
export {
|
|
13
|
+
translationKey,
|
|
14
|
+
translations
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=translations.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/translations.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Resource } from '@dxos/react-ui';\n\nexport const translationKey = '@dxos/react-ui-calendar';\n\nexport const translations = [\n {\n 'en-US': {\n [translationKey]: {\n 'today.button': 'Today',\n },\n },\n },\n] as const satisfies Resource[];\n"],
|
|
5
|
+
"mappings": ";AAMO,IAAMA,iBAAiB;AAEvB,IAAMC,eAAe;EAC1B;IACE,SAAS;MACP,CAACD,cAAAA,GAAiB;QAChB,gBAAgB;MAClB;IACF;EACF;;",
|
|
6
|
+
"names": ["translationKey", "translations"]
|
|
7
|
+
}
|
|
@@ -2,25 +2,14 @@ import { createRequire } from 'node:module';const require = createRequire(import
|
|
|
2
2
|
|
|
3
3
|
// src/components/Calendar/Calendar.tsx
|
|
4
4
|
import { createContext } from "@radix-ui/react-context";
|
|
5
|
-
import { addDays, differenceInWeeks, format, startOfWeek } from "date-fns";
|
|
5
|
+
import { addDays, differenceInWeeks, format, startOfDay, startOfWeek } from "date-fns";
|
|
6
6
|
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
7
7
|
import { useResizeDetector } from "react-resize-detector";
|
|
8
8
|
import { List } from "react-virtualized";
|
|
9
9
|
import { Event } from "@dxos/async";
|
|
10
|
-
import {
|
|
11
|
-
import { mx } from "@dxos/ui-theme";
|
|
12
|
-
|
|
13
|
-
// src/translations.ts
|
|
14
|
-
var translationKey = "@dxos/react-ui-calendar";
|
|
15
|
-
var translations = [
|
|
16
|
-
{
|
|
17
|
-
"en-US": {
|
|
18
|
-
[translationKey]: {
|
|
19
|
-
"today button": "Today"
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
];
|
|
10
|
+
import { IconButton, useTranslation } from "@dxos/react-ui";
|
|
11
|
+
import { composable, composableProps, mx } from "@dxos/ui-theme";
|
|
12
|
+
import { translationKey } from "#translations";
|
|
24
13
|
|
|
25
14
|
// src/components/Calendar/util.ts
|
|
26
15
|
var getDate = (start2, weekNumber, dayOfWeek, weekStartsOn) => {
|
|
@@ -63,16 +52,10 @@ var CalendarRoot = /* @__PURE__ */ forwardRef(({ children, weekStartsOn = 1 }, f
|
|
|
63
52
|
setSelected
|
|
64
53
|
}, children);
|
|
65
54
|
});
|
|
66
|
-
var
|
|
67
|
-
|
|
68
|
-
role: "none",
|
|
69
|
-
className: mx("flex flex-col items-center overflow-hidden bg-inputSurface", classNames)
|
|
70
|
-
}, children);
|
|
71
|
-
};
|
|
72
|
-
CalendarViewport.displayName = "CalendarContent";
|
|
73
|
-
var CalendarToolbar = ({ classNames }) => {
|
|
55
|
+
var CALENDAR_TOOLBAR_NAME = "CalendarHeader";
|
|
56
|
+
var CalendarToolbar = composable(({ classNames, ...props }, forwardedRef) => {
|
|
74
57
|
const { t } = useTranslation(translationKey);
|
|
75
|
-
const { weekStartsOn, event, index, selected } = useCalendarContext(
|
|
58
|
+
const { weekStartsOn, event, index, selected } = useCalendarContext(CALENDAR_TOOLBAR_NAME);
|
|
76
59
|
const top = useMemo(() => getDate(start, index ?? 0, 6, weekStartsOn), [
|
|
77
60
|
index,
|
|
78
61
|
weekStartsOn
|
|
@@ -89,8 +72,14 @@ var CalendarToolbar = ({ classNames }) => {
|
|
|
89
72
|
today
|
|
90
73
|
]);
|
|
91
74
|
return /* @__PURE__ */ React.createElement("div", {
|
|
92
|
-
|
|
93
|
-
|
|
75
|
+
...composableProps(props, {
|
|
76
|
+
role: "none",
|
|
77
|
+
classNames: [
|
|
78
|
+
"shrink-0 grid! grid-cols-3 items-center bg-toolbar-surface",
|
|
79
|
+
classNames
|
|
80
|
+
]
|
|
81
|
+
}),
|
|
82
|
+
ref: forwardedRef,
|
|
94
83
|
style: {
|
|
95
84
|
width: defaultWidth
|
|
96
85
|
}
|
|
@@ -98,25 +87,31 @@ var CalendarToolbar = ({ classNames }) => {
|
|
|
98
87
|
className: "flex justify-start"
|
|
99
88
|
}, /* @__PURE__ */ React.createElement(IconButton, {
|
|
100
89
|
variant: "ghost",
|
|
101
|
-
size: 5,
|
|
102
90
|
icon: "ph--calendar--regular",
|
|
103
91
|
iconOnly: true,
|
|
104
92
|
classNames: "aspect-square",
|
|
105
|
-
label: t("today
|
|
93
|
+
label: t("today.button"),
|
|
106
94
|
onClick: handleToday
|
|
107
95
|
})), /* @__PURE__ */ React.createElement("div", {
|
|
108
96
|
className: "flex justify-center p-2 text-description"
|
|
109
97
|
}, format(selected ?? top, "MMMM")), /* @__PURE__ */ React.createElement("div", {
|
|
110
98
|
className: "flex justify-end p-2 text-description"
|
|
111
99
|
}, (selected ?? top).getFullYear()));
|
|
112
|
-
};
|
|
113
|
-
CalendarToolbar.displayName =
|
|
114
|
-
var
|
|
115
|
-
|
|
100
|
+
});
|
|
101
|
+
CalendarToolbar.displayName = CALENDAR_TOOLBAR_NAME;
|
|
102
|
+
var CALENDAR_GRID_NAME = "CalendarGrid";
|
|
103
|
+
var CalendarGrid = composable(({ classNames, rows, dates = [], onSelect, ...props }, forwardedRef) => {
|
|
104
|
+
const { weekStartsOn, event, setIndex, selected, setSelected } = useCalendarContext(CALENDAR_GRID_NAME);
|
|
116
105
|
const { ref: containerRef, width = 0, height = 0 } = useResizeDetector();
|
|
117
106
|
const maxHeight = rows ? rows * size : void 0;
|
|
118
107
|
const listRef = useRef(null);
|
|
119
108
|
const today = useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
109
|
+
const dateSet = useMemo(() => new Set(dates.map((date) => startOfDay(date).toISOString())), [
|
|
110
|
+
dates
|
|
111
|
+
]);
|
|
112
|
+
const hasDate = useCallback((date) => dateSet.has(startOfDay(date).toISOString()), [
|
|
113
|
+
dateSet
|
|
114
|
+
]);
|
|
120
115
|
const [initialized, setInitialized] = useState(false);
|
|
121
116
|
useEffect(() => {
|
|
122
117
|
const index = differenceInWeeks(today, start);
|
|
@@ -150,9 +145,6 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
150
145
|
return format(day, "EEE");
|
|
151
146
|
});
|
|
152
147
|
}, []);
|
|
153
|
-
const getNumAppointments = useCallback((_date) => {
|
|
154
|
-
return 0;
|
|
155
|
-
}, []);
|
|
156
148
|
const handleDaySelect = useCallback((date) => {
|
|
157
149
|
setSelected((current) => isSameDay(date, current) ? void 0 : date);
|
|
158
150
|
onSelect?.({
|
|
@@ -165,18 +157,15 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
165
157
|
setIndex(Math.round(info.scrollTop / size));
|
|
166
158
|
}, []);
|
|
167
159
|
const rowRenderer = useCallback(({ key, index, style }) => {
|
|
168
|
-
const getBgColor = (date) => date.getMonth() % 2 === 0 && "bg-
|
|
160
|
+
const getBgColor = (date) => date.getMonth() % 2 === 0 && "bg-modal-surface";
|
|
169
161
|
return /* @__PURE__ */ React.createElement("div", {
|
|
170
162
|
key,
|
|
171
163
|
role: "none",
|
|
172
164
|
style,
|
|
173
|
-
className: "
|
|
165
|
+
className: "grid"
|
|
174
166
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
175
167
|
role: "none",
|
|
176
|
-
className:
|
|
177
|
-
}), /* @__PURE__ */ React.createElement("div", {
|
|
178
|
-
role: "none",
|
|
179
|
-
className: "grid grid-cols-7",
|
|
168
|
+
className: "grid grid-cols-7 bg-input-surface",
|
|
180
169
|
style: {
|
|
181
170
|
gridTemplateColumns: `repeat(7, ${size}px)`
|
|
182
171
|
}
|
|
@@ -184,8 +173,7 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
184
173
|
length: 7
|
|
185
174
|
}).map((_, i) => {
|
|
186
175
|
const date = getDate(start, index, i, weekStartsOn);
|
|
187
|
-
const
|
|
188
|
-
const border = isSameDay(date, selected) ? "border-primary-500" : isSameDay(date, today) ? "border-amber-500" : void 0;
|
|
176
|
+
const border = isSameDay(date, selected) ? "border-primary-500" : isSameDay(date, today) ? "border-amber-500" : hasDate(date) ? "border-neutral-700 border-dashed" : void 0;
|
|
189
177
|
return /* @__PURE__ */ React.createElement("div", {
|
|
190
178
|
key: i,
|
|
191
179
|
role: "none",
|
|
@@ -197,30 +185,27 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
197
185
|
className: "absolute top-0 text-xs text-description"
|
|
198
186
|
}, format(date, "MMM")), border && /* @__PURE__ */ React.createElement("div", {
|
|
199
187
|
role: "none",
|
|
200
|
-
className: mx("absolute
|
|
201
|
-
}), num > 0 && /* @__PURE__ */ React.createElement(Icon, {
|
|
202
|
-
classNames: "absolute bottom-0",
|
|
203
|
-
icon: num > 3 ? "ph--dots-three--regular" : "ph--dot--regular",
|
|
204
|
-
size: 5
|
|
188
|
+
className: mx("absolute inset-1 border-2 rounded-full", border)
|
|
205
189
|
}));
|
|
206
|
-
}))
|
|
207
|
-
className: mx(getBgColor(getDate(start, index, 6, weekStartsOn)))
|
|
208
|
-
}));
|
|
190
|
+
})));
|
|
209
191
|
}, [
|
|
210
192
|
handleDaySelect,
|
|
211
|
-
|
|
193
|
+
hasDate,
|
|
212
194
|
selected,
|
|
213
195
|
weekStartsOn
|
|
214
196
|
]);
|
|
215
197
|
return /* @__PURE__ */ React.createElement("div", {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
198
|
+
...composableProps(props, {
|
|
199
|
+
role: "none",
|
|
200
|
+
classNames: [
|
|
201
|
+
"flex flex-col h-full w-full justify-center overflow-hidden",
|
|
202
|
+
classNames
|
|
203
|
+
]
|
|
204
|
+
}),
|
|
205
|
+
ref: forwardedRef
|
|
221
206
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
222
207
|
role: "none",
|
|
223
|
-
className: "
|
|
208
|
+
className: "grid w-full grid-cols-7",
|
|
224
209
|
style: {
|
|
225
210
|
width: defaultWidth
|
|
226
211
|
}
|
|
@@ -228,15 +213,14 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
228
213
|
key: i,
|
|
229
214
|
role: "none",
|
|
230
215
|
className: "flex justify-center p-2 text-sm font-thin"
|
|
231
|
-
}, date)))
|
|
216
|
+
}, date))), /* @__PURE__ */ React.createElement("div", {
|
|
232
217
|
role: "none",
|
|
233
|
-
className: "flex flex-col
|
|
218
|
+
className: "flex flex-col h-full w-full justify-center overflow-hidden",
|
|
234
219
|
ref: containerRef
|
|
235
220
|
}, /* @__PURE__ */ React.createElement(List, {
|
|
236
221
|
ref: listRef,
|
|
237
222
|
role: "none",
|
|
238
|
-
|
|
239
|
-
className: "[&>div]:snap-y scrollbar-none outline-none",
|
|
223
|
+
className: "scrollbar-none outline-hidden",
|
|
240
224
|
width,
|
|
241
225
|
height: maxHeight ?? height,
|
|
242
226
|
rowCount: maxRows,
|
|
@@ -246,11 +230,10 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
246
230
|
onScroll: handleScroll,
|
|
247
231
|
onRowsRendered: () => setInitialized(true)
|
|
248
232
|
})));
|
|
249
|
-
};
|
|
250
|
-
CalendarGrid.displayName =
|
|
233
|
+
});
|
|
234
|
+
CalendarGrid.displayName = CALENDAR_GRID_NAME;
|
|
251
235
|
var Calendar = {
|
|
252
236
|
Root: CalendarRoot,
|
|
253
|
-
Viewport: CalendarViewport,
|
|
254
237
|
Toolbar: CalendarToolbar,
|
|
255
238
|
Grid: CalendarGrid
|
|
256
239
|
};
|