@super-calendar/dom 2.1.5 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/index.d.mts +327 -12
- package/dist/index.d.ts +327 -12
- package/dist/index.js +1111 -286
- package/dist/index.mjs +1087 -289
- package/package.json +2 -2
- package/src/Agenda.tsx +77 -46
- package/src/Calendar.tsx +40 -4
- package/src/DateRangePicker.tsx +360 -0
- package/src/MonthList.tsx +43 -11
- package/src/MonthView.tsx +329 -130
- package/src/ResourceTimeline.tsx +431 -0
- package/src/TimeGrid.tsx +247 -148
- package/src/index.ts +37 -3
- package/src/slots.ts +87 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@super-calendar/dom",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Virtualized month / week / day calendar and date picker for react-dom. No React Native, no react-native-web.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"calendar",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"access": "public"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@super-calendar/core": "2.
|
|
51
|
+
"@super-calendar/core": "2.2.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"@legendapp/list": ">=3",
|
package/src/Agenda.tsx
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { LegendList } from "@legendapp/list/react";
|
|
2
2
|
import { format, isSameDay, type Locale, startOfDay } from "date-fns";
|
|
3
3
|
import { type ComponentType, type CSSProperties, type ReactElement, useMemo } from "react";
|
|
4
|
-
import type { CalendarEvent } from "@super-calendar/core";
|
|
4
|
+
import type { CalendarEvent, EventAccessibilityLabeler } from "@super-calendar/core";
|
|
5
5
|
import { eventTimeLabel, getIsToday, isAllDayEvent } from "@super-calendar/core";
|
|
6
|
+
import { createSlots, type ResolvedSlot, type SlotStyleProps } from "./slots";
|
|
6
7
|
import { type DomCalendarTheme, mergeDomTheme } from "./theme";
|
|
7
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Styleable parts of {@link Agenda}. Pass a class or inline style per slot via the
|
|
11
|
+
* `classNames` / `styles` props.
|
|
12
|
+
*/
|
|
13
|
+
export type AgendaSlot = "dayHeader" | "eventRow" | "event" | "empty";
|
|
14
|
+
|
|
8
15
|
/** Props passed to a custom agenda (schedule) event renderer. */
|
|
9
16
|
export interface DomAgendaEventArgs<T = unknown> {
|
|
10
17
|
/** The event to render. */
|
|
@@ -23,7 +30,7 @@ export interface DomAgendaEventArgs<T = unknown> {
|
|
|
23
30
|
export type DomAgendaEvent<T = unknown> = ComponentType<DomAgendaEventArgs<T>>;
|
|
24
31
|
|
|
25
32
|
/** Props for {@link Agenda}. */
|
|
26
|
-
export interface AgendaProps<T = unknown> {
|
|
33
|
+
export interface AgendaProps<T = unknown> extends SlotStyleProps<AgendaSlot> {
|
|
27
34
|
/** Events to list. The consumer controls which (and therefore the date range). */
|
|
28
35
|
events: CalendarEvent<T>[];
|
|
29
36
|
/** date-fns locale for the day headers and time labels. */
|
|
@@ -38,6 +45,12 @@ export interface AgendaProps<T = unknown> {
|
|
|
38
45
|
height?: number | string;
|
|
39
46
|
/** Replace the built-in event row. */
|
|
40
47
|
renderEvent?: DomAgendaEvent<T>;
|
|
48
|
+
/**
|
|
49
|
+
* Override the screen-reader label for each event row. Receives the event and a
|
|
50
|
+
* `{ mode: "schedule", isAllDay, ampm }` context; return the full text to
|
|
51
|
+
* announce. Defaults to the row's own text content.
|
|
52
|
+
*/
|
|
53
|
+
eventAccessibilityLabel?: EventAccessibilityLabeler<T>;
|
|
41
54
|
/** Tap an event row. */
|
|
42
55
|
onPressEvent?: (event: CalendarEvent<T>) => void;
|
|
43
56
|
/** Tap a day's header. */
|
|
@@ -56,8 +69,8 @@ function DefaultAgendaRow<T>({
|
|
|
56
69
|
event,
|
|
57
70
|
isAllDay,
|
|
58
71
|
ampm = false,
|
|
59
|
-
|
|
60
|
-
}: DomAgendaEventArgs<T> & {
|
|
72
|
+
cardProps,
|
|
73
|
+
}: DomAgendaEventArgs<T> & { cardProps: ResolvedSlot }) {
|
|
61
74
|
const time =
|
|
62
75
|
eventTimeLabel({
|
|
63
76
|
mode: "schedule",
|
|
@@ -70,14 +83,7 @@ function DefaultAgendaRow<T>({
|
|
|
70
83
|
// A filled card with the title on top and the time below, matching the native
|
|
71
84
|
// schedule row.
|
|
72
85
|
return (
|
|
73
|
-
<div
|
|
74
|
-
style={{
|
|
75
|
-
padding: "6px 10px",
|
|
76
|
-
borderRadius: 8,
|
|
77
|
-
background: theme.eventBackground,
|
|
78
|
-
color: theme.eventText,
|
|
79
|
-
}}
|
|
80
|
-
>
|
|
86
|
+
<div {...cardProps}>
|
|
81
87
|
<div style={{ fontWeight: 600, fontSize: 14 }}>{event.title}</div>
|
|
82
88
|
{time ? <div style={{ fontSize: 13, opacity: 0.75 }}>{time}</div> : null}
|
|
83
89
|
</div>
|
|
@@ -103,12 +109,16 @@ export function Agenda<T = unknown>({
|
|
|
103
109
|
theme: themeOverrides,
|
|
104
110
|
height = 480,
|
|
105
111
|
renderEvent,
|
|
112
|
+
eventAccessibilityLabel,
|
|
106
113
|
onPressEvent,
|
|
107
114
|
onPressDay,
|
|
108
115
|
className,
|
|
109
116
|
style,
|
|
117
|
+
classNames,
|
|
118
|
+
styles,
|
|
110
119
|
}: AgendaProps<T>): ReactElement {
|
|
111
120
|
const theme = useMemo(() => mergeDomTheme(themeOverrides), [themeOverrides]);
|
|
121
|
+
const slot = createSlots<AgendaSlot>({ classNames, styles });
|
|
112
122
|
const Renderer = renderEvent;
|
|
113
123
|
|
|
114
124
|
const rows = useMemo<Row<T>[]>(() => {
|
|
@@ -143,24 +153,26 @@ export function Agenda<T = unknown>({
|
|
|
143
153
|
: getIsToday(item.date);
|
|
144
154
|
const label = format(item.date, "EEEE, d LLLL", locale ? { locale } : undefined);
|
|
145
155
|
const color = highlighted ? theme.todayBackground : theme.textMuted;
|
|
156
|
+
const headerProps = slot("dayHeader", {
|
|
157
|
+
base: onPressDay
|
|
158
|
+
? {
|
|
159
|
+
display: "block",
|
|
160
|
+
width: "100%",
|
|
161
|
+
border: "none",
|
|
162
|
+
background: "transparent",
|
|
163
|
+
cursor: "pointer",
|
|
164
|
+
font: "inherit",
|
|
165
|
+
textAlign: "left",
|
|
166
|
+
}
|
|
167
|
+
: { display: "block", width: "100%" },
|
|
168
|
+
themed: { padding: "12px 12px 4px", fontSize: 13, fontWeight: 600, color },
|
|
169
|
+
});
|
|
146
170
|
return onPressDay ? (
|
|
147
|
-
<button
|
|
148
|
-
type="button"
|
|
149
|
-
onClick={() => onPressDay(item.date)}
|
|
150
|
-
style={{
|
|
151
|
-
...headerStyle,
|
|
152
|
-
color,
|
|
153
|
-
border: "none",
|
|
154
|
-
background: "transparent",
|
|
155
|
-
cursor: "pointer",
|
|
156
|
-
font: "inherit",
|
|
157
|
-
textAlign: "left",
|
|
158
|
-
}}
|
|
159
|
-
>
|
|
171
|
+
<button type="button" onClick={() => onPressDay(item.date)} {...headerProps}>
|
|
160
172
|
{label}
|
|
161
173
|
</button>
|
|
162
174
|
) : (
|
|
163
|
-
<div
|
|
175
|
+
<div {...headerProps}>{label}</div>
|
|
164
176
|
);
|
|
165
177
|
}
|
|
166
178
|
const event = item.event;
|
|
@@ -171,33 +183,52 @@ export function Agenda<T = unknown>({
|
|
|
171
183
|
<button
|
|
172
184
|
type="button"
|
|
173
185
|
onClick={onPress}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
186
|
+
aria-label={
|
|
187
|
+
eventAccessibilityLabel
|
|
188
|
+
? eventAccessibilityLabel(event, { mode: "schedule", isAllDay, ampm })
|
|
189
|
+
: undefined
|
|
190
|
+
}
|
|
191
|
+
{...slot("eventRow", {
|
|
192
|
+
base: {
|
|
193
|
+
display: "block",
|
|
194
|
+
width: "100%",
|
|
195
|
+
textAlign: "left",
|
|
196
|
+
border: "none",
|
|
197
|
+
background: "transparent",
|
|
198
|
+
cursor: "pointer",
|
|
199
|
+
font: "inherit",
|
|
200
|
+
},
|
|
201
|
+
themed: { padding: "2px 12px" },
|
|
202
|
+
})}
|
|
184
203
|
>
|
|
185
|
-
{Renderer ?
|
|
204
|
+
{Renderer ? (
|
|
205
|
+
<Renderer {...args} />
|
|
206
|
+
) : (
|
|
207
|
+
<DefaultAgendaRow
|
|
208
|
+
{...args}
|
|
209
|
+
cardProps={slot("event", {
|
|
210
|
+
themed: {
|
|
211
|
+
padding: "6px 10px",
|
|
212
|
+
borderRadius: 8,
|
|
213
|
+
background: theme.eventBackground,
|
|
214
|
+
color: theme.eventText,
|
|
215
|
+
},
|
|
216
|
+
})}
|
|
217
|
+
/>
|
|
218
|
+
)}
|
|
186
219
|
</button>
|
|
187
220
|
);
|
|
188
221
|
}}
|
|
189
222
|
/>
|
|
190
223
|
{rows.length === 0 ? (
|
|
191
|
-
<div
|
|
224
|
+
<div
|
|
225
|
+
{...slot("empty", {
|
|
226
|
+
themed: { padding: "16px 12px", color: theme.textMuted, fontSize: 14 },
|
|
227
|
+
})}
|
|
228
|
+
>
|
|
229
|
+
No events
|
|
230
|
+
</div>
|
|
192
231
|
) : null}
|
|
193
232
|
</div>
|
|
194
233
|
);
|
|
195
234
|
}
|
|
196
|
-
|
|
197
|
-
const headerStyle: CSSProperties = {
|
|
198
|
-
display: "block",
|
|
199
|
-
width: "100%",
|
|
200
|
-
padding: "12px 12px 4px",
|
|
201
|
-
fontSize: 13,
|
|
202
|
-
fontWeight: 600,
|
|
203
|
-
};
|
package/src/Calendar.tsx
CHANGED
|
@@ -5,16 +5,27 @@ import type {
|
|
|
5
5
|
CalendarEvent,
|
|
6
6
|
DateRange,
|
|
7
7
|
DateSelectionConstraints,
|
|
8
|
+
EventAccessibilityLabeler,
|
|
8
9
|
TimeGridMode,
|
|
10
|
+
WeekdayFormat,
|
|
9
11
|
WeekStartsOn,
|
|
10
12
|
} from "@super-calendar/core";
|
|
11
|
-
import { Agenda, type DomAgendaEvent } from "./Agenda";
|
|
12
|
-
import { type DomMonthEvent, MonthView } from "./MonthView";
|
|
13
|
-
import
|
|
13
|
+
import { Agenda, type AgendaSlot, type DomAgendaEvent } from "./Agenda";
|
|
14
|
+
import { type DomMonthEvent, MonthView, type MonthViewSlot } from "./MonthView";
|
|
15
|
+
import type { SlotStyleProps } from "./slots";
|
|
16
|
+
import { type DomRenderEvent, TimeGrid, type TimeGridSlot } from "./TimeGrid";
|
|
14
17
|
import type { DomCalendarTheme } from "./theme";
|
|
15
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Styleable parts across every view {@link Calendar} can render. Only the slots
|
|
21
|
+
* for the active `mode` apply; the rest are ignored. See {@link MonthViewSlot},
|
|
22
|
+
* {@link TimeGridSlot}, and {@link AgendaSlot}.
|
|
23
|
+
*/
|
|
24
|
+
export type CalendarSlot = MonthViewSlot | TimeGridSlot | AgendaSlot;
|
|
25
|
+
|
|
16
26
|
/** Props for {@link Calendar}. */
|
|
17
|
-
export interface CalendarProps<T = unknown>
|
|
27
|
+
export interface CalendarProps<T = unknown>
|
|
28
|
+
extends DateSelectionConstraints, SlotStyleProps<CalendarSlot> {
|
|
18
29
|
/**
|
|
19
30
|
* The view to render (default "week"). `month` renders a month grid, `schedule`
|
|
20
31
|
* a day-grouped agenda list, and the others a time grid.
|
|
@@ -41,6 +52,12 @@ export interface CalendarProps<T = unknown> extends DateSelectionConstraints {
|
|
|
41
52
|
|
|
42
53
|
/** Tap an event (both layouts). */
|
|
43
54
|
onPressEvent?: (event: CalendarEvent<T>) => void;
|
|
55
|
+
/**
|
|
56
|
+
* Override the screen-reader label for each event. Receives the event and a
|
|
57
|
+
* `{ mode, isAllDay, ampm }` context; return the full text to announce. Defaults
|
|
58
|
+
* to each view's built-in label.
|
|
59
|
+
*/
|
|
60
|
+
eventAccessibilityLabel?: EventAccessibilityLabeler<T>;
|
|
44
61
|
|
|
45
62
|
// --- Time-grid modes (week / day / 3days / custom) ---
|
|
46
63
|
/** 12-hour AM/PM time labels (default false). */
|
|
@@ -81,6 +98,8 @@ export interface CalendarProps<T = unknown> extends DateSelectionConstraints {
|
|
|
81
98
|
moreLabel?: string;
|
|
82
99
|
/** Render neighbouring months' days in the leading/trailing cells (default true). */
|
|
83
100
|
showAdjacentMonths?: boolean;
|
|
101
|
+
/** Weekday header label width: `narrow` ("M"), `short` ("Mon", default), or `long` ("Monday"). */
|
|
102
|
+
weekdayFormat?: WeekdayFormat;
|
|
84
103
|
/** Fill the cell with the range background instead of the pill band. */
|
|
85
104
|
fillCellOnSelection?: boolean;
|
|
86
105
|
/** Selected span. */
|
|
@@ -128,6 +147,7 @@ export function Calendar<T = unknown>({
|
|
|
128
147
|
className,
|
|
129
148
|
style,
|
|
130
149
|
onPressEvent,
|
|
150
|
+
eventAccessibilityLabel,
|
|
131
151
|
// time grid
|
|
132
152
|
ampm,
|
|
133
153
|
hourHeight,
|
|
@@ -148,6 +168,7 @@ export function Calendar<T = unknown>({
|
|
|
148
168
|
maxVisibleEventCount,
|
|
149
169
|
moreLabel,
|
|
150
170
|
showAdjacentMonths,
|
|
171
|
+
weekdayFormat,
|
|
151
172
|
fillCellOnSelection,
|
|
152
173
|
selectedRange,
|
|
153
174
|
selectedDates,
|
|
@@ -160,6 +181,9 @@ export function Calendar<T = unknown>({
|
|
|
160
181
|
renderMonthEvent,
|
|
161
182
|
// schedule
|
|
162
183
|
renderScheduleEvent,
|
|
184
|
+
// styling
|
|
185
|
+
classNames,
|
|
186
|
+
styles,
|
|
163
187
|
}: CalendarProps<T>): ReactElement {
|
|
164
188
|
if (mode === "schedule") {
|
|
165
189
|
return (
|
|
@@ -172,7 +196,10 @@ export function Calendar<T = unknown>({
|
|
|
172
196
|
activeDate={date}
|
|
173
197
|
className={className}
|
|
174
198
|
style={style}
|
|
199
|
+
classNames={classNames}
|
|
200
|
+
styles={styles}
|
|
175
201
|
renderEvent={renderScheduleEvent}
|
|
202
|
+
eventAccessibilityLabel={eventAccessibilityLabel}
|
|
176
203
|
onPressEvent={onPressEvent}
|
|
177
204
|
onPressDay={onPressDay}
|
|
178
205
|
/>
|
|
@@ -185,10 +212,13 @@ export function Calendar<T = unknown>({
|
|
|
185
212
|
date={date}
|
|
186
213
|
events={events ?? []}
|
|
187
214
|
weekStartsOn={weekStartsOn}
|
|
215
|
+
weekdayFormat={weekdayFormat}
|
|
188
216
|
locale={locale}
|
|
189
217
|
theme={theme}
|
|
190
218
|
className={className}
|
|
191
219
|
style={style}
|
|
220
|
+
classNames={classNames}
|
|
221
|
+
styles={styles}
|
|
192
222
|
maxVisibleEventCount={maxVisibleEventCount}
|
|
193
223
|
moreLabel={moreLabel}
|
|
194
224
|
showAdjacentMonths={showAdjacentMonths}
|
|
@@ -200,9 +230,11 @@ export function Calendar<T = unknown>({
|
|
|
200
230
|
isDateDisabled={isDateDisabled}
|
|
201
231
|
keyboardDayNavigation={keyboardDayNavigation}
|
|
202
232
|
onPressDay={onPressDay}
|
|
233
|
+
onCreateEvent={onCreateEvent}
|
|
203
234
|
onPressEvent={onPressEvent}
|
|
204
235
|
onPressMore={onPressMore}
|
|
205
236
|
renderEvent={renderMonthEvent}
|
|
237
|
+
eventAccessibilityLabel={eventAccessibilityLabel}
|
|
206
238
|
/>
|
|
207
239
|
);
|
|
208
240
|
}
|
|
@@ -213,12 +245,15 @@ export function Calendar<T = unknown>({
|
|
|
213
245
|
mode={mode}
|
|
214
246
|
events={events}
|
|
215
247
|
weekStartsOn={weekStartsOn}
|
|
248
|
+
weekdayFormat={weekdayFormat}
|
|
216
249
|
numberOfDays={numberOfDays}
|
|
217
250
|
locale={locale}
|
|
218
251
|
theme={theme}
|
|
219
252
|
height={height}
|
|
220
253
|
className={className}
|
|
221
254
|
style={style}
|
|
255
|
+
classNames={classNames}
|
|
256
|
+
styles={styles}
|
|
222
257
|
ampm={ampm}
|
|
223
258
|
hourHeight={hourHeight}
|
|
224
259
|
scrollOffsetMinutes={scrollOffsetMinutes}
|
|
@@ -234,6 +269,7 @@ export function Calendar<T = unknown>({
|
|
|
234
269
|
onDragEvent={onDragEvent}
|
|
235
270
|
onPressDateHeader={onPressDateHeader}
|
|
236
271
|
renderEvent={renderTimeEvent}
|
|
272
|
+
eventAccessibilityLabel={eventAccessibilityLabel}
|
|
237
273
|
hourComponent={hourComponent}
|
|
238
274
|
/>
|
|
239
275
|
);
|