@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/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
- kind: "move" | "resize";
60
- appointment: TAppointment;
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
- kind: "move" | "resize";
60
- appointment: TAppointment;
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("button", { className: "rfs-btn", type: "button", onClick: () => onSelectedDateChange(shiftDays(selectedDate, -1)), children: prevButtonLabel }),
333
- renderDatePicker ? renderDatePicker({ selectedDate, onSelectedDateChange }) : /* @__PURE__ */ jsx("strong", { className: "rfs-date-label", children: selectedISO }),
334
- /* @__PURE__ */ jsx("button", { className: "rfs-btn", type: "button", onClick: () => onSelectedDateChange(shiftDays(selectedDate, 1)), children: nextButtonLabel })
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("div", { className: "rfs-resource-header", style: { minWidth: RESOURCE_MIN_W, flex: 1 }, children: [
340
- renderResourceHeader(resource),
341
- isNameLike(resource) ? /* @__PURE__ */ jsx("div", { className: "rfs-resource-subtitle", children: fullName(resource) }) : null
342
- ] }, String(resource.id)))
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("div", { className: "rfs-time-tick", style: { top: TOP_PAD + i * 60 * PX_PER_MIN }, children: [
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
- ref: (el) => {
354
- colRefs.current[String(resource.id)] = el;
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
- Array.from({ length: Math.floor(dayMinutes / 60) + 1 }).map((_, i) => /* @__PURE__ */ jsx(
360
- "div",
361
- {
362
- className: "rfs-hour-line",
363
- style: { top: TOP_PAD + i * 60 * PX_PER_MIN }
364
- },
365
- `major-${String(resource.id)}-${i}`
366
- )),
367
- Array.from({ length: Math.floor(dayMinutes / STEP_MIN) + 1 }).map((_, i) => /* @__PURE__ */ jsx(
368
- "div",
369
- {
370
- className: "rfs-slot-line",
371
- style: { top: TOP_PAD + i * STEP_MIN * PX_PER_MIN }
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
- `minor-${String(resource.id)}-${i}`
374
- )),
375
- (laidOutByResource.get(resource.id) ?? []).map((appointment) => {
376
- const laneWidthPct = 100 / appointment.lanes;
377
- const top = TOP_PAD + appointment.startMin * PX_PER_MIN;
378
- const height = Math.max(MIN_EVENT_MIN * PX_PER_MIN, (appointment.endMin - appointment.startMin) * PX_PER_MIN);
379
- const appointmentBackgroundColor = appointmentBgByResource.get(resource.id);
380
- return /* @__PURE__ */ jsx(
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
- children: renderAppointment({
391
- appointment,
392
- onPointerDown: (event) => onApptPointerDown(event, appointment),
393
- onResizePointerDown: (event) => onResizePointerDown(event, appointment),
394
- appointmentBackgroundColor,
395
- drag,
396
- suppressClickRef
397
- })
398
- },
399
- String(appointment.id)
400
- );
401
- })
402
- ]
403
- }
404
- ) }, String(resource.id))) })
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
- export { Scheduler };
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