@marco.colia/react-fast-scheduler 1.0.2 → 2.0.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/LICENSE +22 -22
- package/README.md +251 -215
- package/dist/index.cjs +255 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -18
- package/dist/index.d.ts +37 -18
- package/dist/index.js +255 -67
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +86 -86
package/dist/index.d.cts
CHANGED
|
@@ -43,6 +43,25 @@ type SchedulerDragState<TResourceId extends SchedulerId> = {
|
|
|
43
43
|
endMin: number;
|
|
44
44
|
};
|
|
45
45
|
type RenderSchedulerAppt<TAppointment, TResourceId extends SchedulerId> = SchedulerEvent<TAppointment, TResourceId>;
|
|
46
|
+
type SchedulerAppointmentChangeArgs<TAppointment, TResourceId extends SchedulerId> = {
|
|
47
|
+
kind: "move" | "resize";
|
|
48
|
+
appointment: TAppointment;
|
|
49
|
+
previous: {
|
|
50
|
+
resourceId: TResourceId;
|
|
51
|
+
start: Date;
|
|
52
|
+
end: Date;
|
|
53
|
+
};
|
|
54
|
+
next: {
|
|
55
|
+
resourceId: TResourceId;
|
|
56
|
+
start: Date;
|
|
57
|
+
end: Date;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
type SchedulerAppointmentAppearance = {
|
|
61
|
+
className?: string;
|
|
62
|
+
};
|
|
63
|
+
type SchedulerAppointmentColorToken = string;
|
|
64
|
+
type SchedulerResourceClassMap = Partial<Record<string, string>>;
|
|
46
65
|
type SchedulerProps<TAppointment, TResource extends BaseSchedulerResource<TResourceId>, TResourceId extends SchedulerId> = {
|
|
47
66
|
resources: TResource[];
|
|
48
67
|
appointments: TAppointment[];
|
|
@@ -55,32 +74,24 @@ type SchedulerProps<TAppointment, TResource extends BaseSchedulerResource<TResou
|
|
|
55
74
|
start: Date;
|
|
56
75
|
end: Date;
|
|
57
76
|
}) => Promise<void> | void;
|
|
58
|
-
onAppointmentChange?: (args:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
previous: {
|
|
62
|
-
resourceId: TResourceId;
|
|
63
|
-
start: Date;
|
|
64
|
-
end: Date;
|
|
65
|
-
};
|
|
66
|
-
next: {
|
|
67
|
-
resourceId: TResourceId;
|
|
68
|
-
start: Date;
|
|
69
|
-
end: Date;
|
|
70
|
-
};
|
|
71
|
-
}) => Promise<void> | void;
|
|
72
|
-
renderResourceHeader: (resource: TResource) => React.ReactNode;
|
|
73
|
-
renderAppointment: (args: {
|
|
77
|
+
onAppointmentChange?: (args: SchedulerAppointmentChangeArgs<TAppointment, TResourceId>) => Promise<void> | void;
|
|
78
|
+
renderResourceHeader?: (resource: TResource) => React.ReactNode;
|
|
79
|
+
renderAppointment?: (args: {
|
|
74
80
|
appointment: SchedulerEvent<TAppointment, TResourceId> & {
|
|
75
81
|
lane: number;
|
|
76
82
|
lanes: number;
|
|
77
83
|
};
|
|
78
84
|
onPointerDown: (e: React.PointerEvent) => void;
|
|
79
85
|
onResizePointerDown: (e: React.PointerEvent) => void;
|
|
86
|
+
appointmentAppearance?: SchedulerAppointmentAppearance;
|
|
80
87
|
appointmentBackgroundColor?: string;
|
|
81
88
|
drag: SchedulerDragState<TResourceId>;
|
|
82
89
|
suppressClickRef: RefObject<boolean>;
|
|
83
90
|
}) => React.ReactNode;
|
|
91
|
+
resourceAppointmentClassMap?: SchedulerResourceClassMap;
|
|
92
|
+
getResourceAppointmentAppearance?: (resource: TResource) => SchedulerAppointmentAppearance | undefined;
|
|
93
|
+
getResourceAppointmentColorToken?: (resource: TResource) => SchedulerAppointmentColorToken | undefined;
|
|
94
|
+
appointmentColorTokenClassMap?: Record<SchedulerAppointmentColorToken, string>;
|
|
84
95
|
getResourceAppointmentBackground?: (resource: TResource) => string | undefined;
|
|
85
96
|
renderDatePicker?: (args: {
|
|
86
97
|
selectedDate: Date;
|
|
@@ -92,6 +103,14 @@ type SchedulerProps<TAppointment, TResource extends BaseSchedulerResource<TResou
|
|
|
92
103
|
dayEnd?: string;
|
|
93
104
|
};
|
|
94
105
|
|
|
95
|
-
declare function Scheduler<TAppointment, TResource extends BaseSchedulerResource<TResourceId>, TResourceId extends SchedulerId>({ resources, appointments, selectedDate, onSelectedDateChange, adapter, onPersistMoveResize, onAppointmentChange, renderResourceHeader, renderAppointment, getResourceAppointmentBackground, renderDatePicker, prevButtonLabel, nextButtonLabel, dayStart, dayEnd }: SchedulerProps<TAppointment, TResource, TResourceId>): react_jsx_runtime.JSX.Element;
|
|
106
|
+
declare function Scheduler<TAppointment, TResource extends BaseSchedulerResource<TResourceId>, TResourceId extends SchedulerId>({ resources, appointments, selectedDate, onSelectedDateChange, adapter, onPersistMoveResize, onAppointmentChange, renderResourceHeader, renderAppointment, resourceAppointmentClassMap, getResourceAppointmentAppearance, getResourceAppointmentColorToken, appointmentColorTokenClassMap, getResourceAppointmentBackground, renderDatePicker, prevButtonLabel, nextButtonLabel, dayStart, dayEnd }: SchedulerProps<TAppointment, TResource, TResourceId>): react_jsx_runtime.JSX.Element;
|
|
107
|
+
|
|
108
|
+
type ApplySchedulerAppointmentChangeOptions<TAppointment, TResourceId extends SchedulerId> = {
|
|
109
|
+
getId: (appointment: TAppointment) => SchedulerId;
|
|
110
|
+
setResourceId: (appointment: TAppointment, resourceId: TResourceId) => TAppointment;
|
|
111
|
+
setStart: (appointment: TAppointment, start: Date) => TAppointment;
|
|
112
|
+
setEnd: (appointment: TAppointment, end: Date) => TAppointment;
|
|
113
|
+
};
|
|
114
|
+
declare function applySchedulerAppointmentChange<TAppointment, TResourceId extends SchedulerId>(appointments: TAppointment[], change: SchedulerAppointmentChangeArgs<TAppointment, TResourceId>, options: ApplySchedulerAppointmentChangeOptions<TAppointment, TResourceId>): TAppointment[];
|
|
96
115
|
|
|
97
|
-
export { type BaseSchedulerResource, type RenderSchedulerAppt, Scheduler, type SchedulerAppointmentAdapter, type SchedulerDragState, type SchedulerEvent, type SchedulerId, type SchedulerProps };
|
|
116
|
+
export { type ApplySchedulerAppointmentChangeOptions, type BaseSchedulerResource, type RenderSchedulerAppt, Scheduler, type SchedulerAppointmentAdapter, type SchedulerAppointmentAppearance, type SchedulerAppointmentChangeArgs, type SchedulerAppointmentColorToken, type SchedulerDragState, type SchedulerEvent, type SchedulerId, type SchedulerProps, type SchedulerResourceClassMap, applySchedulerAppointmentChange };
|
package/dist/index.d.ts
CHANGED
|
@@ -43,6 +43,25 @@ type SchedulerDragState<TResourceId extends SchedulerId> = {
|
|
|
43
43
|
endMin: number;
|
|
44
44
|
};
|
|
45
45
|
type RenderSchedulerAppt<TAppointment, TResourceId extends SchedulerId> = SchedulerEvent<TAppointment, TResourceId>;
|
|
46
|
+
type SchedulerAppointmentChangeArgs<TAppointment, TResourceId extends SchedulerId> = {
|
|
47
|
+
kind: "move" | "resize";
|
|
48
|
+
appointment: TAppointment;
|
|
49
|
+
previous: {
|
|
50
|
+
resourceId: TResourceId;
|
|
51
|
+
start: Date;
|
|
52
|
+
end: Date;
|
|
53
|
+
};
|
|
54
|
+
next: {
|
|
55
|
+
resourceId: TResourceId;
|
|
56
|
+
start: Date;
|
|
57
|
+
end: Date;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
type SchedulerAppointmentAppearance = {
|
|
61
|
+
className?: string;
|
|
62
|
+
};
|
|
63
|
+
type SchedulerAppointmentColorToken = string;
|
|
64
|
+
type SchedulerResourceClassMap = Partial<Record<string, string>>;
|
|
46
65
|
type SchedulerProps<TAppointment, TResource extends BaseSchedulerResource<TResourceId>, TResourceId extends SchedulerId> = {
|
|
47
66
|
resources: TResource[];
|
|
48
67
|
appointments: TAppointment[];
|
|
@@ -55,32 +74,24 @@ type SchedulerProps<TAppointment, TResource extends BaseSchedulerResource<TResou
|
|
|
55
74
|
start: Date;
|
|
56
75
|
end: Date;
|
|
57
76
|
}) => Promise<void> | void;
|
|
58
|
-
onAppointmentChange?: (args:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
previous: {
|
|
62
|
-
resourceId: TResourceId;
|
|
63
|
-
start: Date;
|
|
64
|
-
end: Date;
|
|
65
|
-
};
|
|
66
|
-
next: {
|
|
67
|
-
resourceId: TResourceId;
|
|
68
|
-
start: Date;
|
|
69
|
-
end: Date;
|
|
70
|
-
};
|
|
71
|
-
}) => Promise<void> | void;
|
|
72
|
-
renderResourceHeader: (resource: TResource) => React.ReactNode;
|
|
73
|
-
renderAppointment: (args: {
|
|
77
|
+
onAppointmentChange?: (args: SchedulerAppointmentChangeArgs<TAppointment, TResourceId>) => Promise<void> | void;
|
|
78
|
+
renderResourceHeader?: (resource: TResource) => React.ReactNode;
|
|
79
|
+
renderAppointment?: (args: {
|
|
74
80
|
appointment: SchedulerEvent<TAppointment, TResourceId> & {
|
|
75
81
|
lane: number;
|
|
76
82
|
lanes: number;
|
|
77
83
|
};
|
|
78
84
|
onPointerDown: (e: React.PointerEvent) => void;
|
|
79
85
|
onResizePointerDown: (e: React.PointerEvent) => void;
|
|
86
|
+
appointmentAppearance?: SchedulerAppointmentAppearance;
|
|
80
87
|
appointmentBackgroundColor?: string;
|
|
81
88
|
drag: SchedulerDragState<TResourceId>;
|
|
82
89
|
suppressClickRef: RefObject<boolean>;
|
|
83
90
|
}) => React.ReactNode;
|
|
91
|
+
resourceAppointmentClassMap?: SchedulerResourceClassMap;
|
|
92
|
+
getResourceAppointmentAppearance?: (resource: TResource) => SchedulerAppointmentAppearance | undefined;
|
|
93
|
+
getResourceAppointmentColorToken?: (resource: TResource) => SchedulerAppointmentColorToken | undefined;
|
|
94
|
+
appointmentColorTokenClassMap?: Record<SchedulerAppointmentColorToken, string>;
|
|
84
95
|
getResourceAppointmentBackground?: (resource: TResource) => string | undefined;
|
|
85
96
|
renderDatePicker?: (args: {
|
|
86
97
|
selectedDate: Date;
|
|
@@ -92,6 +103,14 @@ type SchedulerProps<TAppointment, TResource extends BaseSchedulerResource<TResou
|
|
|
92
103
|
dayEnd?: string;
|
|
93
104
|
};
|
|
94
105
|
|
|
95
|
-
declare function Scheduler<TAppointment, TResource extends BaseSchedulerResource<TResourceId>, TResourceId extends SchedulerId>({ resources, appointments, selectedDate, onSelectedDateChange, adapter, onPersistMoveResize, onAppointmentChange, renderResourceHeader, renderAppointment, getResourceAppointmentBackground, renderDatePicker, prevButtonLabel, nextButtonLabel, dayStart, dayEnd }: SchedulerProps<TAppointment, TResource, TResourceId>): react_jsx_runtime.JSX.Element;
|
|
106
|
+
declare function Scheduler<TAppointment, TResource extends BaseSchedulerResource<TResourceId>, TResourceId extends SchedulerId>({ resources, appointments, selectedDate, onSelectedDateChange, adapter, onPersistMoveResize, onAppointmentChange, renderResourceHeader, renderAppointment, resourceAppointmentClassMap, getResourceAppointmentAppearance, getResourceAppointmentColorToken, appointmentColorTokenClassMap, getResourceAppointmentBackground, renderDatePicker, prevButtonLabel, nextButtonLabel, dayStart, dayEnd }: SchedulerProps<TAppointment, TResource, TResourceId>): react_jsx_runtime.JSX.Element;
|
|
107
|
+
|
|
108
|
+
type ApplySchedulerAppointmentChangeOptions<TAppointment, TResourceId extends SchedulerId> = {
|
|
109
|
+
getId: (appointment: TAppointment) => SchedulerId;
|
|
110
|
+
setResourceId: (appointment: TAppointment, resourceId: TResourceId) => TAppointment;
|
|
111
|
+
setStart: (appointment: TAppointment, start: Date) => TAppointment;
|
|
112
|
+
setEnd: (appointment: TAppointment, end: Date) => TAppointment;
|
|
113
|
+
};
|
|
114
|
+
declare function applySchedulerAppointmentChange<TAppointment, TResourceId extends SchedulerId>(appointments: TAppointment[], change: SchedulerAppointmentChangeArgs<TAppointment, TResourceId>, options: ApplySchedulerAppointmentChangeOptions<TAppointment, TResourceId>): TAppointment[];
|
|
96
115
|
|
|
97
|
-
export { type BaseSchedulerResource, type RenderSchedulerAppt, Scheduler, type SchedulerAppointmentAdapter, type SchedulerDragState, type SchedulerEvent, type SchedulerId, type SchedulerProps };
|
|
116
|
+
export { type ApplySchedulerAppointmentChangeOptions, type BaseSchedulerResource, type RenderSchedulerAppt, Scheduler, type SchedulerAppointmentAdapter, type SchedulerAppointmentAppearance, type SchedulerAppointmentChangeArgs, type SchedulerAppointmentColorToken, type SchedulerDragState, type SchedulerEvent, type SchedulerId, type SchedulerProps, type SchedulerResourceClassMap, applySchedulerAppointmentChange };
|
package/dist/index.js
CHANGED
|
@@ -105,6 +105,46 @@ function isNameLike(resource) {
|
|
|
105
105
|
const maybe = resource;
|
|
106
106
|
return typeof maybe.firstName === "string" || typeof maybe.lastName === "string";
|
|
107
107
|
}
|
|
108
|
+
function toInputDateValue(date) {
|
|
109
|
+
const year = date.getFullYear();
|
|
110
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
111
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
112
|
+
return `${year}-${month}-${day}`;
|
|
113
|
+
}
|
|
114
|
+
function fromInputDateValue(value) {
|
|
115
|
+
const [yearRaw, monthRaw, dayRaw] = value.split("-");
|
|
116
|
+
const year = Number(yearRaw);
|
|
117
|
+
const month = Number(monthRaw);
|
|
118
|
+
const day = Number(dayRaw);
|
|
119
|
+
if (!Number.isInteger(year) || !Number.isInteger(month) || !Number.isInteger(day)) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
return new Date(year, month - 1, day);
|
|
123
|
+
}
|
|
124
|
+
var DEFAULT_APPOINTMENT_COLOR_TOKEN_CLASS_MAP = {
|
|
125
|
+
slate: "bg-slate-100 dark:bg-slate-900/40",
|
|
126
|
+
gray: "bg-gray-100 dark:bg-gray-900/40",
|
|
127
|
+
zinc: "bg-zinc-100 dark:bg-zinc-900/40",
|
|
128
|
+
neutral: "bg-neutral-100 dark:bg-neutral-900/40",
|
|
129
|
+
stone: "bg-stone-100 dark:bg-stone-900/40",
|
|
130
|
+
red: "bg-red-100 dark:bg-red-950/40",
|
|
131
|
+
orange: "bg-orange-100 dark:bg-orange-950/40",
|
|
132
|
+
amber: "bg-amber-100 dark:bg-amber-950/40",
|
|
133
|
+
yellow: "bg-yellow-100 dark:bg-yellow-950/40",
|
|
134
|
+
lime: "bg-lime-100 dark:bg-lime-950/40",
|
|
135
|
+
green: "bg-green-100 dark:bg-green-950/40",
|
|
136
|
+
emerald: "bg-emerald-100 dark:bg-emerald-950/40",
|
|
137
|
+
teal: "bg-teal-100 dark:bg-teal-950/40",
|
|
138
|
+
cyan: "bg-cyan-100 dark:bg-cyan-950/40",
|
|
139
|
+
sky: "bg-sky-100 dark:bg-sky-950/40",
|
|
140
|
+
blue: "bg-blue-100 dark:bg-blue-950/40",
|
|
141
|
+
indigo: "bg-indigo-100 dark:bg-indigo-950/40",
|
|
142
|
+
violet: "bg-violet-100 dark:bg-violet-950/40",
|
|
143
|
+
purple: "bg-purple-100 dark:bg-purple-950/40",
|
|
144
|
+
fuchsia: "bg-fuchsia-100 dark:bg-fuchsia-950/40",
|
|
145
|
+
pink: "bg-pink-100 dark:bg-pink-950/40",
|
|
146
|
+
rose: "bg-rose-100 dark:bg-rose-950/40"
|
|
147
|
+
};
|
|
108
148
|
function Scheduler({
|
|
109
149
|
resources,
|
|
110
150
|
appointments,
|
|
@@ -115,6 +155,10 @@ function Scheduler({
|
|
|
115
155
|
onAppointmentChange,
|
|
116
156
|
renderResourceHeader,
|
|
117
157
|
renderAppointment,
|
|
158
|
+
resourceAppointmentClassMap,
|
|
159
|
+
getResourceAppointmentAppearance,
|
|
160
|
+
getResourceAppointmentColorToken,
|
|
161
|
+
appointmentColorTokenClassMap,
|
|
118
162
|
getResourceAppointmentBackground,
|
|
119
163
|
renderDatePicker,
|
|
120
164
|
prevButtonLabel = "Prev",
|
|
@@ -186,6 +230,48 @@ function Scheduler({
|
|
|
186
230
|
}
|
|
187
231
|
return map;
|
|
188
232
|
}, [getResourceAppointmentBackground, resources]);
|
|
233
|
+
const appointmentColorTokenClassByResource = React.useMemo(() => {
|
|
234
|
+
const map = /* @__PURE__ */ new Map();
|
|
235
|
+
const mergedClassMap = {
|
|
236
|
+
...DEFAULT_APPOINTMENT_COLOR_TOKEN_CLASS_MAP,
|
|
237
|
+
...appointmentColorTokenClassMap ?? {}
|
|
238
|
+
};
|
|
239
|
+
if (!getResourceAppointmentColorToken) {
|
|
240
|
+
return map;
|
|
241
|
+
}
|
|
242
|
+
for (const resource of resources) {
|
|
243
|
+
const token = getResourceAppointmentColorToken(resource);
|
|
244
|
+
map.set(resource.id, token ? mergedClassMap[token] : void 0);
|
|
245
|
+
}
|
|
246
|
+
return map;
|
|
247
|
+
}, [appointmentColorTokenClassMap, getResourceAppointmentColorToken, resources]);
|
|
248
|
+
const appointmentAppearanceByResource = React.useMemo(() => {
|
|
249
|
+
const map = /* @__PURE__ */ new Map();
|
|
250
|
+
for (const resource of resources) {
|
|
251
|
+
const classFromIdMap = resourceAppointmentClassMap?.[String(resource.id)];
|
|
252
|
+
if (classFromIdMap) {
|
|
253
|
+
map.set(resource.id, { className: classFromIdMap });
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
const appearance = getResourceAppointmentAppearance?.(resource);
|
|
257
|
+
if (appearance) {
|
|
258
|
+
map.set(resource.id, appearance);
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const tokenClass = appointmentColorTokenClassByResource.get(resource.id);
|
|
262
|
+
if (tokenClass) {
|
|
263
|
+
map.set(resource.id, { className: tokenClass });
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
const legacyBackground = appointmentBgByResource.get(resource.id);
|
|
267
|
+
if (!legacyBackground) {
|
|
268
|
+
map.set(resource.id, void 0);
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
map.set(resource.id, { className: legacyBackground });
|
|
272
|
+
}
|
|
273
|
+
return map;
|
|
274
|
+
}, [appointmentBgByResource, appointmentColorTokenClassByResource, getResourceAppointmentAppearance, resourceAppointmentClassMap, resources]);
|
|
189
275
|
const pointerToMin = (resourceId, clientY) => {
|
|
190
276
|
const col = colRefs.current[String(resourceId)];
|
|
191
277
|
if (!col) {
|
|
@@ -320,88 +406,178 @@ function Scheduler({
|
|
|
320
406
|
void persistDrag(current);
|
|
321
407
|
}
|
|
322
408
|
};
|
|
409
|
+
const defaultRenderAppointment = ({
|
|
410
|
+
appointment,
|
|
411
|
+
onPointerDown,
|
|
412
|
+
onResizePointerDown: onResizePointerDown2,
|
|
413
|
+
appointmentAppearance,
|
|
414
|
+
appointmentBackgroundColor
|
|
415
|
+
}) => {
|
|
416
|
+
const rawMaybe = appointment.raw;
|
|
417
|
+
const description = typeof rawMaybe.description === "string" ? rawMaybe.description : void 0;
|
|
418
|
+
const legacyClassName = typeof appointmentBackgroundColor === "string" ? appointmentBackgroundColor : void 0;
|
|
419
|
+
const backgroundClassName = appointmentAppearance?.className ?? legacyClassName ?? "bg-muted/40 dark:bg-muted/30";
|
|
420
|
+
const className = `relative h-full cursor-grab overflow-hidden rounded-md border border-border p-2 pb-5 text-foreground ${backgroundClassName}`;
|
|
421
|
+
return /* @__PURE__ */ jsxs("div", { onPointerDown, className, children: [
|
|
422
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs font-semibold", children: appointment.title }),
|
|
423
|
+
description ? /* @__PURE__ */ jsx("div", { className: "mt-1 text-[10px] font-medium text-muted-foreground", children: description }) : null,
|
|
424
|
+
/* @__PURE__ */ jsx(
|
|
425
|
+
"div",
|
|
426
|
+
{
|
|
427
|
+
role: "button",
|
|
428
|
+
"aria-label": "Resize appointment",
|
|
429
|
+
onPointerDown: (event) => {
|
|
430
|
+
event.stopPropagation();
|
|
431
|
+
onResizePointerDown2(event);
|
|
432
|
+
},
|
|
433
|
+
className: "absolute inset-x-1 bottom-1 h-2 cursor-ns-resize rounded-full bg-border/90 transition-colors hover:bg-border"
|
|
434
|
+
}
|
|
435
|
+
)
|
|
436
|
+
] });
|
|
437
|
+
};
|
|
438
|
+
const defaultRenderDatePicker = ({
|
|
439
|
+
selectedDate: value,
|
|
440
|
+
onSelectedDateChange: onDateChange
|
|
441
|
+
}) => /* @__PURE__ */ jsx(
|
|
442
|
+
"input",
|
|
443
|
+
{
|
|
444
|
+
type: "date",
|
|
445
|
+
value: toInputDateValue(value),
|
|
446
|
+
onChange: (event) => {
|
|
447
|
+
const nextDate = fromInputDateValue(event.target.value);
|
|
448
|
+
if (nextDate) {
|
|
449
|
+
onDateChange(nextDate);
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
className: "h-7 rounded-md border border-border bg-card px-2 text-xs text-foreground",
|
|
453
|
+
"aria-label": "Select date"
|
|
454
|
+
}
|
|
455
|
+
);
|
|
456
|
+
const defaultRenderResourceHeader = (resource) => /* @__PURE__ */ jsx("strong", { children: resource.label });
|
|
323
457
|
return /* @__PURE__ */ jsxs(
|
|
324
458
|
"section",
|
|
325
459
|
{
|
|
326
|
-
className: `rfs-root ${drag.kind === "move" ? "rfs-root--drag-move" : ""} ${drag.kind === "resize" ? "rfs-root--drag-resize" : ""}`,
|
|
460
|
+
className: `rfs-root rounded-lg bg-background text-foreground ${drag.kind === "move" ? "rfs-root--drag-move" : ""} ${drag.kind === "resize" ? "rfs-root--drag-resize" : ""}`,
|
|
327
461
|
onPointerMove: onGlobalPointerMove,
|
|
328
462
|
onPointerUp: onGlobalPointerUp,
|
|
329
463
|
onPointerCancel: onGlobalPointerUp,
|
|
330
464
|
children: [
|
|
331
465
|
/* @__PURE__ */ jsxs("div", { className: "rfs-toolbar", children: [
|
|
332
|
-
/* @__PURE__ */ jsx(
|
|
333
|
-
|
|
334
|
-
|
|
466
|
+
/* @__PURE__ */ jsx(
|
|
467
|
+
"button",
|
|
468
|
+
{
|
|
469
|
+
className: "rfs-btn border-border bg-card text-foreground hover:bg-muted",
|
|
470
|
+
type: "button",
|
|
471
|
+
onClick: () => onSelectedDateChange(shiftDays(selectedDate, -1)),
|
|
472
|
+
children: prevButtonLabel
|
|
473
|
+
}
|
|
474
|
+
),
|
|
475
|
+
(renderDatePicker ?? defaultRenderDatePicker)({ selectedDate, onSelectedDateChange }),
|
|
476
|
+
/* @__PURE__ */ jsx(
|
|
477
|
+
"button",
|
|
478
|
+
{
|
|
479
|
+
className: "rfs-btn border-border bg-card text-foreground hover:bg-muted",
|
|
480
|
+
type: "button",
|
|
481
|
+
onClick: () => onSelectedDateChange(shiftDays(selectedDate, 1)),
|
|
482
|
+
children: nextButtonLabel
|
|
483
|
+
}
|
|
484
|
+
)
|
|
335
485
|
] }),
|
|
336
|
-
/* @__PURE__ */ jsx("div", { className: "rfs-shell", children: /* @__PURE__ */ jsxs("div", { style: { minWidth: gridMinWidth }, children: [
|
|
337
|
-
/* @__PURE__ */ jsxs("div", { className: "rfs-header", children: [
|
|
338
|
-
/* @__PURE__ */ jsx("div", { className: "rfs-gutter", style: { width: GUTTER_W } }),
|
|
339
|
-
resources.map((resource) => /* @__PURE__ */ jsxs(
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
486
|
+
/* @__PURE__ */ jsx("div", { className: "rfs-shell border-border bg-card", children: /* @__PURE__ */ jsxs("div", { style: { minWidth: gridMinWidth }, children: [
|
|
487
|
+
/* @__PURE__ */ jsxs("div", { className: "rfs-header border-border bg-card", children: [
|
|
488
|
+
/* @__PURE__ */ jsx("div", { className: "rfs-gutter border-border", style: { width: GUTTER_W } }),
|
|
489
|
+
resources.map((resource) => /* @__PURE__ */ jsxs(
|
|
490
|
+
"div",
|
|
491
|
+
{
|
|
492
|
+
className: "rfs-resource-header border-border bg-card text-foreground",
|
|
493
|
+
style: { minWidth: RESOURCE_MIN_W, flex: 1 },
|
|
494
|
+
children: [
|
|
495
|
+
(renderResourceHeader ?? defaultRenderResourceHeader)(resource),
|
|
496
|
+
isNameLike(resource) ? /* @__PURE__ */ jsx("div", { className: "rfs-resource-subtitle text-muted-foreground", children: fullName(resource) }) : null
|
|
497
|
+
]
|
|
498
|
+
},
|
|
499
|
+
String(resource.id)
|
|
500
|
+
))
|
|
343
501
|
] }),
|
|
344
502
|
/* @__PURE__ */ jsxs("div", { className: "rfs-body", children: [
|
|
345
|
-
/* @__PURE__ */ jsx("div", { className: "rfs-times", style: { width: GUTTER_W, height: gridHeight }, children: Array.from({ length: Math.floor(dayMinutes / 60) + 1 }).map((_, i) => /* @__PURE__ */ jsxs(
|
|
346
|
-
String(Math.floor((dayStartAbs + i * 60) / 60)).padStart(2, "0"),
|
|
347
|
-
":",
|
|
348
|
-
String((dayStartAbs + i * 60) % 60).padStart(2, "0")
|
|
349
|
-
] }, `tick-${i}`)) }),
|
|
350
|
-
/* @__PURE__ */ jsx("div", { className: "rfs-grid", children: resources.map((resource) => /* @__PURE__ */ jsx("div", { className: "rfs-col", style: { minWidth: RESOURCE_MIN_W, flex: 1 }, children: /* @__PURE__ */ jsxs(
|
|
503
|
+
/* @__PURE__ */ jsx("div", { className: "rfs-times border-border bg-card", style: { width: GUTTER_W, height: gridHeight }, children: Array.from({ length: Math.floor(dayMinutes / 60) + 1 }).map((_, i) => /* @__PURE__ */ jsxs(
|
|
351
504
|
"div",
|
|
352
505
|
{
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
},
|
|
356
|
-
className: "rfs-col-inner",
|
|
357
|
-
style: { height: gridHeight },
|
|
506
|
+
className: "rfs-time-tick text-muted-foreground",
|
|
507
|
+
style: { top: TOP_PAD + i * 60 * PX_PER_MIN },
|
|
358
508
|
children: [
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
509
|
+
String(Math.floor((dayStartAbs + i * 60) / 60)).padStart(2, "0"),
|
|
510
|
+
":",
|
|
511
|
+
String((dayStartAbs + i * 60) % 60).padStart(2, "0")
|
|
512
|
+
]
|
|
513
|
+
},
|
|
514
|
+
`tick-${i}`
|
|
515
|
+
)) }),
|
|
516
|
+
/* @__PURE__ */ jsx("div", { className: "rfs-grid", children: resources.map((resource) => /* @__PURE__ */ jsx(
|
|
517
|
+
"div",
|
|
518
|
+
{
|
|
519
|
+
className: "rfs-col border-border bg-card",
|
|
520
|
+
style: { minWidth: RESOURCE_MIN_W, flex: 1 },
|
|
521
|
+
children: /* @__PURE__ */ jsxs(
|
|
522
|
+
"div",
|
|
523
|
+
{
|
|
524
|
+
ref: (el) => {
|
|
525
|
+
colRefs.current[String(resource.id)] = el;
|
|
372
526
|
},
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
"div",
|
|
382
|
-
{
|
|
383
|
-
className: "rfs-card-slot",
|
|
384
|
-
style: {
|
|
385
|
-
top,
|
|
386
|
-
left: `${laneWidthPct * appointment.lane}%`,
|
|
387
|
-
width: `${laneWidthPct}%`,
|
|
388
|
-
height
|
|
527
|
+
className: "rfs-col-inner bg-card",
|
|
528
|
+
style: { height: gridHeight },
|
|
529
|
+
children: [
|
|
530
|
+
Array.from({ length: Math.floor(dayMinutes / 60) + 1 }).map((_, i) => /* @__PURE__ */ jsx(
|
|
531
|
+
"div",
|
|
532
|
+
{
|
|
533
|
+
className: "rfs-hour-line border-border/70",
|
|
534
|
+
style: { top: TOP_PAD + i * 60 * PX_PER_MIN }
|
|
389
535
|
},
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
536
|
+
`major-${String(resource.id)}-${i}`
|
|
537
|
+
)),
|
|
538
|
+
Array.from({ length: Math.floor(dayMinutes / STEP_MIN) + 1 }).map((_, i) => /* @__PURE__ */ jsx(
|
|
539
|
+
"div",
|
|
540
|
+
{
|
|
541
|
+
className: "rfs-slot-line border-border/50",
|
|
542
|
+
style: { top: TOP_PAD + i * STEP_MIN * PX_PER_MIN }
|
|
543
|
+
},
|
|
544
|
+
`minor-${String(resource.id)}-${i}`
|
|
545
|
+
)),
|
|
546
|
+
(laidOutByResource.get(resource.id) ?? []).map((appointment) => {
|
|
547
|
+
const laneWidthPct = 100 / appointment.lanes;
|
|
548
|
+
const top = TOP_PAD + appointment.startMin * PX_PER_MIN;
|
|
549
|
+
const height = Math.max(MIN_EVENT_MIN * PX_PER_MIN, (appointment.endMin - appointment.startMin) * PX_PER_MIN);
|
|
550
|
+
const appointmentAppearance = appointmentAppearanceByResource.get(resource.id);
|
|
551
|
+
const appointmentBackgroundColor = appointmentBgByResource.get(resource.id);
|
|
552
|
+
return /* @__PURE__ */ jsx(
|
|
553
|
+
"div",
|
|
554
|
+
{
|
|
555
|
+
className: "rfs-card-slot",
|
|
556
|
+
style: {
|
|
557
|
+
top,
|
|
558
|
+
left: `${laneWidthPct * appointment.lane}%`,
|
|
559
|
+
width: `${laneWidthPct}%`,
|
|
560
|
+
height
|
|
561
|
+
},
|
|
562
|
+
children: (renderAppointment ?? defaultRenderAppointment)({
|
|
563
|
+
appointment,
|
|
564
|
+
onPointerDown: (event) => onApptPointerDown(event, appointment),
|
|
565
|
+
onResizePointerDown: (event) => onResizePointerDown(event, appointment),
|
|
566
|
+
appointmentAppearance,
|
|
567
|
+
appointmentBackgroundColor,
|
|
568
|
+
drag,
|
|
569
|
+
suppressClickRef
|
|
570
|
+
})
|
|
571
|
+
},
|
|
572
|
+
String(appointment.id)
|
|
573
|
+
);
|
|
574
|
+
})
|
|
575
|
+
]
|
|
576
|
+
}
|
|
577
|
+
)
|
|
578
|
+
},
|
|
579
|
+
String(resource.id)
|
|
580
|
+
)) })
|
|
405
581
|
] })
|
|
406
582
|
] }) })
|
|
407
583
|
]
|
|
@@ -409,6 +585,18 @@ function Scheduler({
|
|
|
409
585
|
);
|
|
410
586
|
}
|
|
411
587
|
|
|
412
|
-
|
|
588
|
+
// src/appointment-change.ts
|
|
589
|
+
function applySchedulerAppointmentChange(appointments, change, options) {
|
|
590
|
+
return appointments.map((item) => {
|
|
591
|
+
if (options.getId(item) !== options.getId(change.appointment)) {
|
|
592
|
+
return item;
|
|
593
|
+
}
|
|
594
|
+
const withResource = options.setResourceId(item, change.next.resourceId);
|
|
595
|
+
const withStart = options.setStart(withResource, change.next.start);
|
|
596
|
+
return options.setEnd(withStart, change.next.end);
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
export { Scheduler, applySchedulerAppointmentChange };
|
|
413
601
|
//# sourceMappingURL=index.js.map
|
|
414
602
|
//# sourceMappingURL=index.js.map
|