@dxos/react-ui-calendar 0.8.4-main.bc674ce → 0.8.4-main.bd9b33e6c8
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 +46 -52
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +46 -52
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Calendar/Calendar.d.ts +20 -18
- package/dist/types/src/components/Calendar/Calendar.d.ts.map +1 -1
- package/dist/types/src/components/Calendar/Calendar.stories.d.ts +7 -8
- package/dist/types/src/components/Calendar/Calendar.stories.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -16
- package/src/components/Calendar/Calendar.stories.tsx +14 -39
- package/src/components/Calendar/Calendar.tsx +143 -156
|
@@ -1,12 +1,12 @@
|
|
|
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";
|
|
8
|
+
import { IconButton, useTranslation } from "@dxos/react-ui";
|
|
9
|
+
import { composable, composableProps, mx } from "@dxos/ui-theme";
|
|
10
10
|
|
|
11
11
|
// src/translations.ts
|
|
12
12
|
var translationKey = "@dxos/react-ui-calendar";
|
|
@@ -61,16 +61,10 @@ var CalendarRoot = /* @__PURE__ */ forwardRef(({ children, weekStartsOn = 1 }, f
|
|
|
61
61
|
setSelected
|
|
62
62
|
}, children);
|
|
63
63
|
});
|
|
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 }) => {
|
|
64
|
+
var CALENDAR_TOOLBAR_NAME = "CalendarHeader";
|
|
65
|
+
var CalendarToolbar = composable(({ classNames, ...props }, forwardedRef) => {
|
|
72
66
|
const { t } = useTranslation(translationKey);
|
|
73
|
-
const { weekStartsOn, event, index, selected } = useCalendarContext(
|
|
67
|
+
const { weekStartsOn, event, index, selected } = useCalendarContext(CALENDAR_TOOLBAR_NAME);
|
|
74
68
|
const top = useMemo(() => getDate(start, index ?? 0, 6, weekStartsOn), [
|
|
75
69
|
index,
|
|
76
70
|
weekStartsOn
|
|
@@ -87,8 +81,14 @@ var CalendarToolbar = ({ classNames }) => {
|
|
|
87
81
|
today
|
|
88
82
|
]);
|
|
89
83
|
return /* @__PURE__ */ React.createElement("div", {
|
|
90
|
-
|
|
91
|
-
|
|
84
|
+
...composableProps(props, {
|
|
85
|
+
role: "none",
|
|
86
|
+
classNames: [
|
|
87
|
+
"shrink-0 grid! grid-cols-3 items-center bg-toolbar-surface",
|
|
88
|
+
classNames
|
|
89
|
+
]
|
|
90
|
+
}),
|
|
91
|
+
ref: forwardedRef,
|
|
92
92
|
style: {
|
|
93
93
|
width: defaultWidth
|
|
94
94
|
}
|
|
@@ -96,7 +96,6 @@ var CalendarToolbar = ({ classNames }) => {
|
|
|
96
96
|
className: "flex justify-start"
|
|
97
97
|
}, /* @__PURE__ */ React.createElement(IconButton, {
|
|
98
98
|
variant: "ghost",
|
|
99
|
-
size: 5,
|
|
100
99
|
icon: "ph--calendar--regular",
|
|
101
100
|
iconOnly: true,
|
|
102
101
|
classNames: "aspect-square",
|
|
@@ -107,14 +106,21 @@ var CalendarToolbar = ({ classNames }) => {
|
|
|
107
106
|
}, format(selected ?? top, "MMMM")), /* @__PURE__ */ React.createElement("div", {
|
|
108
107
|
className: "flex justify-end p-2 text-description"
|
|
109
108
|
}, (selected ?? top).getFullYear()));
|
|
110
|
-
};
|
|
111
|
-
CalendarToolbar.displayName =
|
|
112
|
-
var
|
|
113
|
-
|
|
109
|
+
});
|
|
110
|
+
CalendarToolbar.displayName = CALENDAR_TOOLBAR_NAME;
|
|
111
|
+
var CALENDAR_GRID_NAME = "CalendarGrid";
|
|
112
|
+
var CalendarGrid = composable(({ classNames, rows, dates = [], onSelect, ...props }, forwardedRef) => {
|
|
113
|
+
const { weekStartsOn, event, setIndex, selected, setSelected } = useCalendarContext(CALENDAR_GRID_NAME);
|
|
114
114
|
const { ref: containerRef, width = 0, height = 0 } = useResizeDetector();
|
|
115
115
|
const maxHeight = rows ? rows * size : void 0;
|
|
116
116
|
const listRef = useRef(null);
|
|
117
117
|
const today = useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
118
|
+
const dateSet = useMemo(() => new Set(dates.map((date) => startOfDay(date).toISOString())), [
|
|
119
|
+
dates
|
|
120
|
+
]);
|
|
121
|
+
const hasDate = useCallback((date) => dateSet.has(startOfDay(date).toISOString()), [
|
|
122
|
+
dateSet
|
|
123
|
+
]);
|
|
118
124
|
const [initialized, setInitialized] = useState(false);
|
|
119
125
|
useEffect(() => {
|
|
120
126
|
const index = differenceInWeeks(today, start);
|
|
@@ -148,9 +154,6 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
148
154
|
return format(day, "EEE");
|
|
149
155
|
});
|
|
150
156
|
}, []);
|
|
151
|
-
const getNumAppointments = useCallback((_date) => {
|
|
152
|
-
return 0;
|
|
153
|
-
}, []);
|
|
154
157
|
const handleDaySelect = useCallback((date) => {
|
|
155
158
|
setSelected((current) => isSameDay(date, current) ? void 0 : date);
|
|
156
159
|
onSelect?.({
|
|
@@ -163,18 +166,15 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
163
166
|
setIndex(Math.round(info.scrollTop / size));
|
|
164
167
|
}, []);
|
|
165
168
|
const rowRenderer = useCallback(({ key, index, style }) => {
|
|
166
|
-
const getBgColor = (date) => date.getMonth() % 2 === 0 && "bg-
|
|
169
|
+
const getBgColor = (date) => date.getMonth() % 2 === 0 && "bg-modal-surface";
|
|
167
170
|
return /* @__PURE__ */ React.createElement("div", {
|
|
168
171
|
key,
|
|
169
172
|
role: "none",
|
|
170
173
|
style,
|
|
171
|
-
className: "
|
|
174
|
+
className: "grid"
|
|
172
175
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
173
176
|
role: "none",
|
|
174
|
-
className:
|
|
175
|
-
}), /* @__PURE__ */ React.createElement("div", {
|
|
176
|
-
role: "none",
|
|
177
|
-
className: "grid grid-cols-7",
|
|
177
|
+
className: "grid grid-cols-7 bg-input-surface",
|
|
178
178
|
style: {
|
|
179
179
|
gridTemplateColumns: `repeat(7, ${size}px)`
|
|
180
180
|
}
|
|
@@ -182,8 +182,7 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
182
182
|
length: 7
|
|
183
183
|
}).map((_, i) => {
|
|
184
184
|
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;
|
|
185
|
+
const border = isSameDay(date, selected) ? "border-primary-500" : isSameDay(date, today) ? "border-amber-500" : hasDate(date) ? "border-neutral-700 border-dashed" : void 0;
|
|
187
186
|
return /* @__PURE__ */ React.createElement("div", {
|
|
188
187
|
key: i,
|
|
189
188
|
role: "none",
|
|
@@ -195,30 +194,27 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
195
194
|
className: "absolute top-0 text-xs text-description"
|
|
196
195
|
}, format(date, "MMM")), border && /* @__PURE__ */ React.createElement("div", {
|
|
197
196
|
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
|
|
197
|
+
className: mx("absolute inset-1 border-2 rounded-full", border)
|
|
203
198
|
}));
|
|
204
|
-
}))
|
|
205
|
-
className: mx(getBgColor(getDate(start, index, 6, weekStartsOn)))
|
|
206
|
-
}));
|
|
199
|
+
})));
|
|
207
200
|
}, [
|
|
208
201
|
handleDaySelect,
|
|
209
|
-
|
|
202
|
+
hasDate,
|
|
210
203
|
selected,
|
|
211
204
|
weekStartsOn
|
|
212
205
|
]);
|
|
213
206
|
return /* @__PURE__ */ React.createElement("div", {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
207
|
+
...composableProps(props, {
|
|
208
|
+
role: "none",
|
|
209
|
+
classNames: [
|
|
210
|
+
"flex flex-col h-full w-full justify-center overflow-hidden",
|
|
211
|
+
classNames
|
|
212
|
+
]
|
|
213
|
+
}),
|
|
214
|
+
ref: forwardedRef
|
|
219
215
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
220
216
|
role: "none",
|
|
221
|
-
className: "
|
|
217
|
+
className: "grid w-full grid-cols-7",
|
|
222
218
|
style: {
|
|
223
219
|
width: defaultWidth
|
|
224
220
|
}
|
|
@@ -226,15 +222,14 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
226
222
|
key: i,
|
|
227
223
|
role: "none",
|
|
228
224
|
className: "flex justify-center p-2 text-sm font-thin"
|
|
229
|
-
}, date)))
|
|
225
|
+
}, date))), /* @__PURE__ */ React.createElement("div", {
|
|
230
226
|
role: "none",
|
|
231
|
-
className: "flex flex-col
|
|
227
|
+
className: "flex flex-col h-full w-full justify-center overflow-hidden",
|
|
232
228
|
ref: containerRef
|
|
233
229
|
}, /* @__PURE__ */ React.createElement(List, {
|
|
234
230
|
ref: listRef,
|
|
235
231
|
role: "none",
|
|
236
|
-
|
|
237
|
-
className: "[&>div]:snap-y scrollbar-none outline-none",
|
|
232
|
+
className: "scrollbar-none outline-hidden",
|
|
238
233
|
width,
|
|
239
234
|
height: maxHeight ?? height,
|
|
240
235
|
rowCount: maxRows,
|
|
@@ -244,11 +239,10 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
244
239
|
onScroll: handleScroll,
|
|
245
240
|
onRowsRendered: () => setInitialized(true)
|
|
246
241
|
})));
|
|
247
|
-
};
|
|
248
|
-
CalendarGrid.displayName =
|
|
242
|
+
});
|
|
243
|
+
CalendarGrid.displayName = CALENDAR_GRID_NAME;
|
|
249
244
|
var Calendar = {
|
|
250
245
|
Root: CalendarRoot,
|
|
251
|
-
Viewport: CalendarViewport,
|
|
252
246
|
Toolbar: CalendarToolbar,
|
|
253
247
|
Grid: CalendarGrid
|
|
254
248
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/Calendar/Calendar.tsx", "../../../src/translations.ts", "../../../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, 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", "
|
|
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 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": "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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", "translations", "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/translations.ts":{"bytes":1196,"imports":[],"format":"esm"},"src/components/Calendar/util.ts":{"bytes":2802,"imports":[],"format":"esm"},"src/components/Calendar/Calendar.tsx":{"bytes":
|
|
1
|
+
{"inputs":{"src/translations.ts":{"bytes":1196,"imports":[],"format":"esm"},"src/components/Calendar/util.ts":{"bytes":2802,"imports":[],"format":"esm"},"src/components/Calendar/Calendar.tsx":{"bytes":29966,"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":"src/translations.ts","kind":"import-statement","original":"../../translations"},{"path":"src/components/Calendar/util.ts","kind":"import-statement","original":"./util"}],"format":"esm"},"src/components/Calendar/index.ts":{"bytes":476,"imports":[{"path":"src/components/Calendar/Calendar.tsx","kind":"import-statement","original":"./Calendar"}],"format":"esm"},"src/components/index.ts":{"bytes":467,"imports":[{"path":"src/components/Calendar/index.ts","kind":"import-statement","original":"./Calendar"}],"format":"esm"},"src/index.ts":{"bytes":462,"imports":[{"path":"src/components/index.ts","kind":"import-statement","original":"./components"}],"format":"esm"}},"outputs":{"dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":18163},"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}],"exports":["Calendar"],"entryPoint":"src/index.ts","inputs":{"src/components/Calendar/Calendar.tsx":{"bytesInOutput":7386},"src/translations.ts":{"bytesInOutput":167},"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":8269}}}
|
|
@@ -2,13 +2,13 @@ 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";
|
|
10
|
+
import { IconButton, useTranslation } from "@dxos/react-ui";
|
|
11
|
+
import { composable, composableProps, mx } from "@dxos/ui-theme";
|
|
12
12
|
|
|
13
13
|
// src/translations.ts
|
|
14
14
|
var translationKey = "@dxos/react-ui-calendar";
|
|
@@ -63,16 +63,10 @@ var CalendarRoot = /* @__PURE__ */ forwardRef(({ children, weekStartsOn = 1 }, f
|
|
|
63
63
|
setSelected
|
|
64
64
|
}, children);
|
|
65
65
|
});
|
|
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 }) => {
|
|
66
|
+
var CALENDAR_TOOLBAR_NAME = "CalendarHeader";
|
|
67
|
+
var CalendarToolbar = composable(({ classNames, ...props }, forwardedRef) => {
|
|
74
68
|
const { t } = useTranslation(translationKey);
|
|
75
|
-
const { weekStartsOn, event, index, selected } = useCalendarContext(
|
|
69
|
+
const { weekStartsOn, event, index, selected } = useCalendarContext(CALENDAR_TOOLBAR_NAME);
|
|
76
70
|
const top = useMemo(() => getDate(start, index ?? 0, 6, weekStartsOn), [
|
|
77
71
|
index,
|
|
78
72
|
weekStartsOn
|
|
@@ -89,8 +83,14 @@ var CalendarToolbar = ({ classNames }) => {
|
|
|
89
83
|
today
|
|
90
84
|
]);
|
|
91
85
|
return /* @__PURE__ */ React.createElement("div", {
|
|
92
|
-
|
|
93
|
-
|
|
86
|
+
...composableProps(props, {
|
|
87
|
+
role: "none",
|
|
88
|
+
classNames: [
|
|
89
|
+
"shrink-0 grid! grid-cols-3 items-center bg-toolbar-surface",
|
|
90
|
+
classNames
|
|
91
|
+
]
|
|
92
|
+
}),
|
|
93
|
+
ref: forwardedRef,
|
|
94
94
|
style: {
|
|
95
95
|
width: defaultWidth
|
|
96
96
|
}
|
|
@@ -98,7 +98,6 @@ var CalendarToolbar = ({ classNames }) => {
|
|
|
98
98
|
className: "flex justify-start"
|
|
99
99
|
}, /* @__PURE__ */ React.createElement(IconButton, {
|
|
100
100
|
variant: "ghost",
|
|
101
|
-
size: 5,
|
|
102
101
|
icon: "ph--calendar--regular",
|
|
103
102
|
iconOnly: true,
|
|
104
103
|
classNames: "aspect-square",
|
|
@@ -109,14 +108,21 @@ var CalendarToolbar = ({ classNames }) => {
|
|
|
109
108
|
}, format(selected ?? top, "MMMM")), /* @__PURE__ */ React.createElement("div", {
|
|
110
109
|
className: "flex justify-end p-2 text-description"
|
|
111
110
|
}, (selected ?? top).getFullYear()));
|
|
112
|
-
};
|
|
113
|
-
CalendarToolbar.displayName =
|
|
114
|
-
var
|
|
115
|
-
|
|
111
|
+
});
|
|
112
|
+
CalendarToolbar.displayName = CALENDAR_TOOLBAR_NAME;
|
|
113
|
+
var CALENDAR_GRID_NAME = "CalendarGrid";
|
|
114
|
+
var CalendarGrid = composable(({ classNames, rows, dates = [], onSelect, ...props }, forwardedRef) => {
|
|
115
|
+
const { weekStartsOn, event, setIndex, selected, setSelected } = useCalendarContext(CALENDAR_GRID_NAME);
|
|
116
116
|
const { ref: containerRef, width = 0, height = 0 } = useResizeDetector();
|
|
117
117
|
const maxHeight = rows ? rows * size : void 0;
|
|
118
118
|
const listRef = useRef(null);
|
|
119
119
|
const today = useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
120
|
+
const dateSet = useMemo(() => new Set(dates.map((date) => startOfDay(date).toISOString())), [
|
|
121
|
+
dates
|
|
122
|
+
]);
|
|
123
|
+
const hasDate = useCallback((date) => dateSet.has(startOfDay(date).toISOString()), [
|
|
124
|
+
dateSet
|
|
125
|
+
]);
|
|
120
126
|
const [initialized, setInitialized] = useState(false);
|
|
121
127
|
useEffect(() => {
|
|
122
128
|
const index = differenceInWeeks(today, start);
|
|
@@ -150,9 +156,6 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
150
156
|
return format(day, "EEE");
|
|
151
157
|
});
|
|
152
158
|
}, []);
|
|
153
|
-
const getNumAppointments = useCallback((_date) => {
|
|
154
|
-
return 0;
|
|
155
|
-
}, []);
|
|
156
159
|
const handleDaySelect = useCallback((date) => {
|
|
157
160
|
setSelected((current) => isSameDay(date, current) ? void 0 : date);
|
|
158
161
|
onSelect?.({
|
|
@@ -165,18 +168,15 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
165
168
|
setIndex(Math.round(info.scrollTop / size));
|
|
166
169
|
}, []);
|
|
167
170
|
const rowRenderer = useCallback(({ key, index, style }) => {
|
|
168
|
-
const getBgColor = (date) => date.getMonth() % 2 === 0 && "bg-
|
|
171
|
+
const getBgColor = (date) => date.getMonth() % 2 === 0 && "bg-modal-surface";
|
|
169
172
|
return /* @__PURE__ */ React.createElement("div", {
|
|
170
173
|
key,
|
|
171
174
|
role: "none",
|
|
172
175
|
style,
|
|
173
|
-
className: "
|
|
176
|
+
className: "grid"
|
|
174
177
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
175
178
|
role: "none",
|
|
176
|
-
className:
|
|
177
|
-
}), /* @__PURE__ */ React.createElement("div", {
|
|
178
|
-
role: "none",
|
|
179
|
-
className: "grid grid-cols-7",
|
|
179
|
+
className: "grid grid-cols-7 bg-input-surface",
|
|
180
180
|
style: {
|
|
181
181
|
gridTemplateColumns: `repeat(7, ${size}px)`
|
|
182
182
|
}
|
|
@@ -184,8 +184,7 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
184
184
|
length: 7
|
|
185
185
|
}).map((_, i) => {
|
|
186
186
|
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;
|
|
187
|
+
const border = isSameDay(date, selected) ? "border-primary-500" : isSameDay(date, today) ? "border-amber-500" : hasDate(date) ? "border-neutral-700 border-dashed" : void 0;
|
|
189
188
|
return /* @__PURE__ */ React.createElement("div", {
|
|
190
189
|
key: i,
|
|
191
190
|
role: "none",
|
|
@@ -197,30 +196,27 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
197
196
|
className: "absolute top-0 text-xs text-description"
|
|
198
197
|
}, format(date, "MMM")), border && /* @__PURE__ */ React.createElement("div", {
|
|
199
198
|
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
|
|
199
|
+
className: mx("absolute inset-1 border-2 rounded-full", border)
|
|
205
200
|
}));
|
|
206
|
-
}))
|
|
207
|
-
className: mx(getBgColor(getDate(start, index, 6, weekStartsOn)))
|
|
208
|
-
}));
|
|
201
|
+
})));
|
|
209
202
|
}, [
|
|
210
203
|
handleDaySelect,
|
|
211
|
-
|
|
204
|
+
hasDate,
|
|
212
205
|
selected,
|
|
213
206
|
weekStartsOn
|
|
214
207
|
]);
|
|
215
208
|
return /* @__PURE__ */ React.createElement("div", {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
209
|
+
...composableProps(props, {
|
|
210
|
+
role: "none",
|
|
211
|
+
classNames: [
|
|
212
|
+
"flex flex-col h-full w-full justify-center overflow-hidden",
|
|
213
|
+
classNames
|
|
214
|
+
]
|
|
215
|
+
}),
|
|
216
|
+
ref: forwardedRef
|
|
221
217
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
222
218
|
role: "none",
|
|
223
|
-
className: "
|
|
219
|
+
className: "grid w-full grid-cols-7",
|
|
224
220
|
style: {
|
|
225
221
|
width: defaultWidth
|
|
226
222
|
}
|
|
@@ -228,15 +224,14 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
228
224
|
key: i,
|
|
229
225
|
role: "none",
|
|
230
226
|
className: "flex justify-center p-2 text-sm font-thin"
|
|
231
|
-
}, date)))
|
|
227
|
+
}, date))), /* @__PURE__ */ React.createElement("div", {
|
|
232
228
|
role: "none",
|
|
233
|
-
className: "flex flex-col
|
|
229
|
+
className: "flex flex-col h-full w-full justify-center overflow-hidden",
|
|
234
230
|
ref: containerRef
|
|
235
231
|
}, /* @__PURE__ */ React.createElement(List, {
|
|
236
232
|
ref: listRef,
|
|
237
233
|
role: "none",
|
|
238
|
-
|
|
239
|
-
className: "[&>div]:snap-y scrollbar-none outline-none",
|
|
234
|
+
className: "scrollbar-none outline-hidden",
|
|
240
235
|
width,
|
|
241
236
|
height: maxHeight ?? height,
|
|
242
237
|
rowCount: maxRows,
|
|
@@ -246,11 +241,10 @@ var CalendarGrid = ({ classNames, rows, onSelect }) => {
|
|
|
246
241
|
onScroll: handleScroll,
|
|
247
242
|
onRowsRendered: () => setInitialized(true)
|
|
248
243
|
})));
|
|
249
|
-
};
|
|
250
|
-
CalendarGrid.displayName =
|
|
244
|
+
});
|
|
245
|
+
CalendarGrid.displayName = CALENDAR_GRID_NAME;
|
|
251
246
|
var Calendar = {
|
|
252
247
|
Root: CalendarRoot,
|
|
253
|
-
Viewport: CalendarViewport,
|
|
254
248
|
Toolbar: CalendarToolbar,
|
|
255
249
|
Grid: CalendarGrid
|
|
256
250
|
};
|