@dxos/react-ui-calendar 0.8.4-main.c85a9c8dae → 0.8.4-main.e00bdcdb52
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 +39 -52
- 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 +39 -52
- 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 +11 -12
- package/dist/types/src/components/Calendar/Calendar.d.ts.map +1 -1
- package/dist/types/src/components/Calendar/Calendar.stories.d.ts +4 -5
- 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 -19
- package/src/components/Calendar/Calendar.stories.tsx +2 -2
- package/src/components/Calendar/Calendar.tsx +137 -148
- 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) => {
|
|
@@ -62,7 +51,7 @@ var CalendarRoot = /* @__PURE__ */ forwardRef(({ children, weekStartsOn = 1 }, f
|
|
|
62
51
|
}, children);
|
|
63
52
|
});
|
|
64
53
|
var CALENDAR_TOOLBAR_NAME = "CalendarHeader";
|
|
65
|
-
var CalendarToolbar = ({ classNames, ...props }) => {
|
|
54
|
+
var CalendarToolbar = composable(({ classNames, ...props }, forwardedRef) => {
|
|
66
55
|
const { t } = useTranslation(translationKey);
|
|
67
56
|
const { weekStartsOn, event, index, selected } = useCalendarContext(CALENDAR_TOOLBAR_NAME);
|
|
68
57
|
const top = useMemo(() => getDate(start, index ?? 0, 6, weekStartsOn), [
|
|
@@ -81,9 +70,14 @@ var CalendarToolbar = ({ classNames, ...props }) => {
|
|
|
81
70
|
today
|
|
82
71
|
]);
|
|
83
72
|
return /* @__PURE__ */ React.createElement("div", {
|
|
84
|
-
...props,
|
|
85
|
-
|
|
86
|
-
|
|
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,
|
|
87
81
|
style: {
|
|
88
82
|
width: defaultWidth
|
|
89
83
|
}
|
|
@@ -91,26 +85,31 @@ var CalendarToolbar = ({ classNames, ...props }) => {
|
|
|
91
85
|
className: "flex justify-start"
|
|
92
86
|
}, /* @__PURE__ */ React.createElement(IconButton, {
|
|
93
87
|
variant: "ghost",
|
|
94
|
-
size: 5,
|
|
95
88
|
icon: "ph--calendar--regular",
|
|
96
89
|
iconOnly: true,
|
|
97
90
|
classNames: "aspect-square",
|
|
98
|
-
label: t("today
|
|
91
|
+
label: t("today.button"),
|
|
99
92
|
onClick: handleToday
|
|
100
93
|
})), /* @__PURE__ */ React.createElement("div", {
|
|
101
94
|
className: "flex justify-center p-2 text-description"
|
|
102
95
|
}, format(selected ?? top, "MMMM")), /* @__PURE__ */ React.createElement("div", {
|
|
103
96
|
className: "flex justify-end p-2 text-description"
|
|
104
97
|
}, (selected ?? top).getFullYear()));
|
|
105
|
-
};
|
|
98
|
+
});
|
|
106
99
|
CalendarToolbar.displayName = CALENDAR_TOOLBAR_NAME;
|
|
107
100
|
var CALENDAR_GRID_NAME = "CalendarGrid";
|
|
108
|
-
var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
101
|
+
var CalendarGrid = composable(({ classNames, rows, dates = [], onSelect, ...props }, forwardedRef) => {
|
|
109
102
|
const { weekStartsOn, event, setIndex, selected, setSelected } = useCalendarContext(CALENDAR_GRID_NAME);
|
|
110
103
|
const { ref: containerRef, width = 0, height = 0 } = useResizeDetector();
|
|
111
104
|
const maxHeight = rows ? rows * size : void 0;
|
|
112
105
|
const listRef = useRef(null);
|
|
113
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
|
+
]);
|
|
114
113
|
const [initialized, setInitialized] = useState(false);
|
|
115
114
|
useEffect(() => {
|
|
116
115
|
const index = differenceInWeeks(today, start);
|
|
@@ -144,9 +143,6 @@ var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
|
144
143
|
return format(day, "EEE");
|
|
145
144
|
});
|
|
146
145
|
}, []);
|
|
147
|
-
const getNumAppointments = useCallback((_date) => {
|
|
148
|
-
return 0;
|
|
149
|
-
}, []);
|
|
150
146
|
const handleDaySelect = useCallback((date) => {
|
|
151
147
|
setSelected((current) => isSameDay(date, current) ? void 0 : date);
|
|
152
148
|
onSelect?.({
|
|
@@ -162,14 +158,10 @@ var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
|
162
158
|
const getBgColor = (date) => date.getMonth() % 2 === 0 && "bg-modal-surface";
|
|
163
159
|
return /* @__PURE__ */ React.createElement("div", {
|
|
164
160
|
key,
|
|
165
|
-
...props,
|
|
166
161
|
role: "none",
|
|
167
162
|
style,
|
|
168
|
-
className: "
|
|
163
|
+
className: "grid"
|
|
169
164
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
170
|
-
role: "none",
|
|
171
|
-
className: mx(getBgColor(getDate(start, index, 0, weekStartsOn)))
|
|
172
|
-
}), /* @__PURE__ */ React.createElement("div", {
|
|
173
165
|
role: "none",
|
|
174
166
|
className: "grid grid-cols-7 bg-input-surface",
|
|
175
167
|
style: {
|
|
@@ -179,8 +171,7 @@ var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
|
179
171
|
length: 7
|
|
180
172
|
}).map((_, i) => {
|
|
181
173
|
const date = getDate(start, index, i, weekStartsOn);
|
|
182
|
-
const
|
|
183
|
-
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;
|
|
184
175
|
return /* @__PURE__ */ React.createElement("div", {
|
|
185
176
|
key: i,
|
|
186
177
|
role: "none",
|
|
@@ -192,30 +183,27 @@ var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
|
192
183
|
className: "absolute top-0 text-xs text-description"
|
|
193
184
|
}, format(date, "MMM")), border && /* @__PURE__ */ React.createElement("div", {
|
|
194
185
|
role: "none",
|
|
195
|
-
className: mx("absolute
|
|
196
|
-
}), num > 0 && /* @__PURE__ */ React.createElement(Icon, {
|
|
197
|
-
classNames: "absolute bottom-0",
|
|
198
|
-
icon: num > 3 ? "ph--dots-three--regular" : "ph--dot--regular",
|
|
199
|
-
size: 5
|
|
186
|
+
className: mx("absolute inset-1 border-2 rounded-full", border)
|
|
200
187
|
}));
|
|
201
|
-
}))
|
|
202
|
-
className: mx(getBgColor(getDate(start, index, 6, weekStartsOn)))
|
|
203
|
-
}));
|
|
188
|
+
})));
|
|
204
189
|
}, [
|
|
205
190
|
handleDaySelect,
|
|
206
|
-
|
|
191
|
+
hasDate,
|
|
207
192
|
selected,
|
|
208
193
|
weekStartsOn
|
|
209
194
|
]);
|
|
210
195
|
return /* @__PURE__ */ React.createElement("div", {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
|
216
204
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
217
205
|
role: "none",
|
|
218
|
-
className: "
|
|
206
|
+
className: "grid w-full grid-cols-7",
|
|
219
207
|
style: {
|
|
220
208
|
width: defaultWidth
|
|
221
209
|
}
|
|
@@ -223,15 +211,14 @@ var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
|
223
211
|
key: i,
|
|
224
212
|
role: "none",
|
|
225
213
|
className: "flex justify-center p-2 text-sm font-thin"
|
|
226
|
-
}, date)))
|
|
214
|
+
}, date))), /* @__PURE__ */ React.createElement("div", {
|
|
227
215
|
role: "none",
|
|
228
216
|
className: "flex flex-col h-full w-full justify-center overflow-hidden",
|
|
229
217
|
ref: containerRef
|
|
230
218
|
}, /* @__PURE__ */ React.createElement(List, {
|
|
231
219
|
ref: listRef,
|
|
232
220
|
role: "none",
|
|
233
|
-
|
|
234
|
-
className: "[&>div]:snap-y scrollbar-none outline-hidden",
|
|
221
|
+
className: "scrollbar-none outline-hidden",
|
|
235
222
|
width,
|
|
236
223
|
height: maxHeight ?? height,
|
|
237
224
|
rowCount: maxRows,
|
|
@@ -241,7 +228,7 @@ var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
|
241
228
|
onScroll: handleScroll,
|
|
242
229
|
onRowsRendered: () => setInitialized(true)
|
|
243
230
|
})));
|
|
244
|
-
};
|
|
231
|
+
});
|
|
245
232
|
CalendarGrid.displayName = CALENDAR_GRID_NAME;
|
|
246
233
|
var Calendar = {
|
|
247
234
|
Root: CalendarRoot,
|
|
@@ -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// Header\n//\n\nconst CALENDAR_TOOLBAR_NAME = 'CalendarHeader';\n\ntype CalendarToolbarProps = ThemedClassName;\n\nconst CalendarToolbar = ({ classNames, ...props }: CalendarToolbarProps) => {\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 {...props}\n role='none'\n className={mx('shrink-0 w-full m-auto grid grid-cols-3 items-center bg-toolbar-surface', 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 = 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 = ThemedClassName<{\n rows?: number;\n onSelect?: (event: { date: Date }) => void;\n}>;\n\nconst CalendarGrid = ({ classNames, rows, onSelect, ...props }: CalendarGridProps) => {\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 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-modal-surface';\n return (\n <div\n key={key}\n {...props}\n role='none'\n style={style}\n className='w-full grid grid-cols-[1fr_max-content_1fr] snap-center'\n >\n <div role='none' className={mx(getBgColor(getDate(start, index, 0, weekStartsOn)))} />\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 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 w-full h-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 h-full w-full justify-center overflow-hidden', classNames)}>\n {/* Day labels */}\n <div role='none' className='flex justify-center bg-group-surface'>\n <div role='none' className='flex w-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 h-full w-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-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\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 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) => {
|
|
@@ -64,7 +53,7 @@ var CalendarRoot = /* @__PURE__ */ forwardRef(({ children, weekStartsOn = 1 }, f
|
|
|
64
53
|
}, children);
|
|
65
54
|
});
|
|
66
55
|
var CALENDAR_TOOLBAR_NAME = "CalendarHeader";
|
|
67
|
-
var CalendarToolbar = ({ classNames, ...props }) => {
|
|
56
|
+
var CalendarToolbar = composable(({ classNames, ...props }, forwardedRef) => {
|
|
68
57
|
const { t } = useTranslation(translationKey);
|
|
69
58
|
const { weekStartsOn, event, index, selected } = useCalendarContext(CALENDAR_TOOLBAR_NAME);
|
|
70
59
|
const top = useMemo(() => getDate(start, index ?? 0, 6, weekStartsOn), [
|
|
@@ -83,9 +72,14 @@ var CalendarToolbar = ({ classNames, ...props }) => {
|
|
|
83
72
|
today
|
|
84
73
|
]);
|
|
85
74
|
return /* @__PURE__ */ React.createElement("div", {
|
|
86
|
-
...props,
|
|
87
|
-
|
|
88
|
-
|
|
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,
|
|
89
83
|
style: {
|
|
90
84
|
width: defaultWidth
|
|
91
85
|
}
|
|
@@ -93,26 +87,31 @@ var CalendarToolbar = ({ classNames, ...props }) => {
|
|
|
93
87
|
className: "flex justify-start"
|
|
94
88
|
}, /* @__PURE__ */ React.createElement(IconButton, {
|
|
95
89
|
variant: "ghost",
|
|
96
|
-
size: 5,
|
|
97
90
|
icon: "ph--calendar--regular",
|
|
98
91
|
iconOnly: true,
|
|
99
92
|
classNames: "aspect-square",
|
|
100
|
-
label: t("today
|
|
93
|
+
label: t("today.button"),
|
|
101
94
|
onClick: handleToday
|
|
102
95
|
})), /* @__PURE__ */ React.createElement("div", {
|
|
103
96
|
className: "flex justify-center p-2 text-description"
|
|
104
97
|
}, format(selected ?? top, "MMMM")), /* @__PURE__ */ React.createElement("div", {
|
|
105
98
|
className: "flex justify-end p-2 text-description"
|
|
106
99
|
}, (selected ?? top).getFullYear()));
|
|
107
|
-
};
|
|
100
|
+
});
|
|
108
101
|
CalendarToolbar.displayName = CALENDAR_TOOLBAR_NAME;
|
|
109
102
|
var CALENDAR_GRID_NAME = "CalendarGrid";
|
|
110
|
-
var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
103
|
+
var CalendarGrid = composable(({ classNames, rows, dates = [], onSelect, ...props }, forwardedRef) => {
|
|
111
104
|
const { weekStartsOn, event, setIndex, selected, setSelected } = useCalendarContext(CALENDAR_GRID_NAME);
|
|
112
105
|
const { ref: containerRef, width = 0, height = 0 } = useResizeDetector();
|
|
113
106
|
const maxHeight = rows ? rows * size : void 0;
|
|
114
107
|
const listRef = useRef(null);
|
|
115
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
|
+
]);
|
|
116
115
|
const [initialized, setInitialized] = useState(false);
|
|
117
116
|
useEffect(() => {
|
|
118
117
|
const index = differenceInWeeks(today, start);
|
|
@@ -146,9 +145,6 @@ var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
|
146
145
|
return format(day, "EEE");
|
|
147
146
|
});
|
|
148
147
|
}, []);
|
|
149
|
-
const getNumAppointments = useCallback((_date) => {
|
|
150
|
-
return 0;
|
|
151
|
-
}, []);
|
|
152
148
|
const handleDaySelect = useCallback((date) => {
|
|
153
149
|
setSelected((current) => isSameDay(date, current) ? void 0 : date);
|
|
154
150
|
onSelect?.({
|
|
@@ -164,14 +160,10 @@ var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
|
164
160
|
const getBgColor = (date) => date.getMonth() % 2 === 0 && "bg-modal-surface";
|
|
165
161
|
return /* @__PURE__ */ React.createElement("div", {
|
|
166
162
|
key,
|
|
167
|
-
...props,
|
|
168
163
|
role: "none",
|
|
169
164
|
style,
|
|
170
|
-
className: "
|
|
165
|
+
className: "grid"
|
|
171
166
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
172
|
-
role: "none",
|
|
173
|
-
className: mx(getBgColor(getDate(start, index, 0, weekStartsOn)))
|
|
174
|
-
}), /* @__PURE__ */ React.createElement("div", {
|
|
175
167
|
role: "none",
|
|
176
168
|
className: "grid grid-cols-7 bg-input-surface",
|
|
177
169
|
style: {
|
|
@@ -181,8 +173,7 @@ var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
|
181
173
|
length: 7
|
|
182
174
|
}).map((_, i) => {
|
|
183
175
|
const date = getDate(start, index, i, weekStartsOn);
|
|
184
|
-
const
|
|
185
|
-
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;
|
|
186
177
|
return /* @__PURE__ */ React.createElement("div", {
|
|
187
178
|
key: i,
|
|
188
179
|
role: "none",
|
|
@@ -194,30 +185,27 @@ var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
|
194
185
|
className: "absolute top-0 text-xs text-description"
|
|
195
186
|
}, format(date, "MMM")), border && /* @__PURE__ */ React.createElement("div", {
|
|
196
187
|
role: "none",
|
|
197
|
-
className: mx("absolute
|
|
198
|
-
}), num > 0 && /* @__PURE__ */ React.createElement(Icon, {
|
|
199
|
-
classNames: "absolute bottom-0",
|
|
200
|
-
icon: num > 3 ? "ph--dots-three--regular" : "ph--dot--regular",
|
|
201
|
-
size: 5
|
|
188
|
+
className: mx("absolute inset-1 border-2 rounded-full", border)
|
|
202
189
|
}));
|
|
203
|
-
}))
|
|
204
|
-
className: mx(getBgColor(getDate(start, index, 6, weekStartsOn)))
|
|
205
|
-
}));
|
|
190
|
+
})));
|
|
206
191
|
}, [
|
|
207
192
|
handleDaySelect,
|
|
208
|
-
|
|
193
|
+
hasDate,
|
|
209
194
|
selected,
|
|
210
195
|
weekStartsOn
|
|
211
196
|
]);
|
|
212
197
|
return /* @__PURE__ */ React.createElement("div", {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
|
|
218
206
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
219
207
|
role: "none",
|
|
220
|
-
className: "
|
|
208
|
+
className: "grid w-full grid-cols-7",
|
|
221
209
|
style: {
|
|
222
210
|
width: defaultWidth
|
|
223
211
|
}
|
|
@@ -225,15 +213,14 @@ var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
|
225
213
|
key: i,
|
|
226
214
|
role: "none",
|
|
227
215
|
className: "flex justify-center p-2 text-sm font-thin"
|
|
228
|
-
}, date)))
|
|
216
|
+
}, date))), /* @__PURE__ */ React.createElement("div", {
|
|
229
217
|
role: "none",
|
|
230
218
|
className: "flex flex-col h-full w-full justify-center overflow-hidden",
|
|
231
219
|
ref: containerRef
|
|
232
220
|
}, /* @__PURE__ */ React.createElement(List, {
|
|
233
221
|
ref: listRef,
|
|
234
222
|
role: "none",
|
|
235
|
-
|
|
236
|
-
className: "[&>div]:snap-y scrollbar-none outline-hidden",
|
|
223
|
+
className: "scrollbar-none outline-hidden",
|
|
237
224
|
width,
|
|
238
225
|
height: maxHeight ?? height,
|
|
239
226
|
rowCount: maxRows,
|
|
@@ -243,7 +230,7 @@ var CalendarGrid = ({ classNames, rows, onSelect, ...props }) => {
|
|
|
243
230
|
onScroll: handleScroll,
|
|
244
231
|
onRowsRendered: () => setInitialized(true)
|
|
245
232
|
})));
|
|
246
|
-
};
|
|
233
|
+
});
|
|
247
234
|
CalendarGrid.displayName = CALENDAR_GRID_NAME;
|
|
248
235
|
var Calendar = {
|
|
249
236
|
Root: CalendarRoot,
|