@savvycal/calendar 0.1.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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +472 -0
  3. package/dist/components/resource-grid-view/AllDayRow.d.ts +12 -0
  4. package/dist/components/resource-grid-view/AllDayRow.d.ts.map +1 -0
  5. package/dist/components/resource-grid-view/AllDayRow.js +54 -0
  6. package/dist/components/resource-grid-view/EventChip.d.ts +22 -0
  7. package/dist/components/resource-grid-view/EventChip.d.ts.map +1 -0
  8. package/dist/components/resource-grid-view/EventChip.js +112 -0
  9. package/dist/components/resource-grid-view/GridHeader.d.ts +13 -0
  10. package/dist/components/resource-grid-view/GridHeader.d.ts.map +1 -0
  11. package/dist/components/resource-grid-view/GridHeader.js +31 -0
  12. package/dist/components/resource-grid-view/NowIndicator.d.ts +13 -0
  13. package/dist/components/resource-grid-view/NowIndicator.d.ts.map +1 -0
  14. package/dist/components/resource-grid-view/NowIndicator.js +43 -0
  15. package/dist/components/resource-grid-view/ResourceColumn.d.ts +22 -0
  16. package/dist/components/resource-grid-view/ResourceColumn.d.ts.map +1 -0
  17. package/dist/components/resource-grid-view/ResourceColumn.js +52 -0
  18. package/dist/components/resource-grid-view/ResourceGridView.d.ts +3 -0
  19. package/dist/components/resource-grid-view/ResourceGridView.d.ts.map +1 -0
  20. package/dist/components/resource-grid-view/ResourceGridView.js +342 -0
  21. package/dist/components/resource-grid-view/SelectionOverlay.d.ts +22 -0
  22. package/dist/components/resource-grid-view/SelectionOverlay.d.ts.map +1 -0
  23. package/dist/components/resource-grid-view/SelectionOverlay.js +87 -0
  24. package/dist/components/resource-grid-view/SlotInteractionLayer.d.ts +28 -0
  25. package/dist/components/resource-grid-view/SlotInteractionLayer.d.ts.map +1 -0
  26. package/dist/components/resource-grid-view/SlotInteractionLayer.js +213 -0
  27. package/dist/components/resource-grid-view/TimeGutter.d.ts +11 -0
  28. package/dist/components/resource-grid-view/TimeGutter.d.ts.map +1 -0
  29. package/dist/components/resource-grid-view/TimeGutter.js +25 -0
  30. package/dist/components/resource-grid-view/UnavailabilityOverlay.d.ts +10 -0
  31. package/dist/components/resource-grid-view/UnavailabilityOverlay.d.ts.map +1 -0
  32. package/dist/components/resource-grid-view/UnavailabilityOverlay.js +37 -0
  33. package/dist/components/resource-grid-view/defaults.d.ts +3 -0
  34. package/dist/components/resource-grid-view/defaults.d.ts.map +1 -0
  35. package/dist/components/resource-grid-view/defaults.js +28 -0
  36. package/dist/components/resource-grid-view/index.d.ts +3 -0
  37. package/dist/components/resource-grid-view/index.d.ts.map +1 -0
  38. package/dist/components/resource-grid-view/useAnnouncer.d.ts +5 -0
  39. package/dist/components/resource-grid-view/useAnnouncer.d.ts.map +1 -0
  40. package/dist/components/resource-grid-view/useAnnouncer.js +12 -0
  41. package/dist/components/resource-grid-view/useEffectiveHourHeight.d.ts +15 -0
  42. package/dist/components/resource-grid-view/useEffectiveHourHeight.d.ts.map +1 -0
  43. package/dist/components/resource-grid-view/useEffectiveHourHeight.js +20 -0
  44. package/dist/components.css +31 -0
  45. package/dist/index.d.ts +6 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +10 -0
  48. package/dist/lib/availability.d.ts +12 -0
  49. package/dist/lib/availability.d.ts.map +1 -0
  50. package/dist/lib/availability.js +56 -0
  51. package/dist/lib/overlap.d.ts +16 -0
  52. package/dist/lib/overlap.d.ts.map +1 -0
  53. package/dist/lib/overlap.js +80 -0
  54. package/dist/lib/selection.d.ts +4 -0
  55. package/dist/lib/selection.d.ts.map +1 -0
  56. package/dist/lib/selection.js +14 -0
  57. package/dist/lib/time.d.ts +21 -0
  58. package/dist/lib/time.d.ts.map +1 -0
  59. package/dist/lib/time.js +52 -0
  60. package/dist/lib/utils.d.ts +3 -0
  61. package/dist/lib/utils.d.ts.map +1 -0
  62. package/dist/lib/utils.js +8 -0
  63. package/dist/preset.css +93 -0
  64. package/dist/types/calendar.d.ts +128 -0
  65. package/dist/types/calendar.d.ts.map +1 -0
  66. package/package.json +60 -0
@@ -0,0 +1,87 @@
1
+ import { jsx as i } from "react/jsx-runtime";
2
+ import { memo as g } from "react";
3
+ import { getMinuteRange as y } from "../../lib/time.js";
4
+ import { buildSyntheticEvent as S } from "../../lib/selection.js";
5
+ import { EventChip as M } from "./EventChip.js";
6
+ const j = g(function({
7
+ selectedRange: t,
8
+ column: m,
9
+ resource: u,
10
+ viewDate: h,
11
+ timeZone: r,
12
+ startHour: a,
13
+ hourHeight: v,
14
+ cls: n,
15
+ appearance: s = "highlight",
16
+ selectionRef: d,
17
+ renderEvent: c
18
+ }) {
19
+ const l = v / 60, p = a * 60, e = y(
20
+ t.startTime,
21
+ t.endTime,
22
+ h,
23
+ r
24
+ );
25
+ if (!e) return null;
26
+ const f = (e.startMin - p) * l, o = (e.endMin - e.startMin) * l;
27
+ return o <= 0 ? null : /* @__PURE__ */ i(
28
+ "div",
29
+ {
30
+ "aria-hidden": "true",
31
+ style: {
32
+ gridRow: "3 / -1",
33
+ gridColumn: m,
34
+ position: "relative",
35
+ pointerEvents: "none"
36
+ },
37
+ children: /* @__PURE__ */ i(
38
+ "div",
39
+ {
40
+ ref: d,
41
+ style: {
42
+ position: "absolute",
43
+ top: f,
44
+ left: 0,
45
+ right: 0,
46
+ height: o
47
+ },
48
+ children: s !== "highlight" ? /* @__PURE__ */ i("div", { className: n("eventColumn"), style: { height: "100%" }, children: /* @__PURE__ */ i(
49
+ M,
50
+ {
51
+ interactive: !1,
52
+ isSelected: !0,
53
+ positioned: {
54
+ event: S(
55
+ t.resourceId,
56
+ t.startTime,
57
+ t.endTime,
58
+ s.eventData
59
+ ),
60
+ top: 0,
61
+ height: o,
62
+ subColumn: 0,
63
+ totalSubColumns: 1
64
+ },
65
+ resource: u,
66
+ timeZone: r,
67
+ cls: n,
68
+ renderEvent: c
69
+ }
70
+ ) }) : /* @__PURE__ */ i(
71
+ "div",
72
+ {
73
+ className: n("selectionHighlight"),
74
+ style: {
75
+ position: "absolute",
76
+ inset: 0
77
+ }
78
+ }
79
+ )
80
+ }
81
+ )
82
+ }
83
+ );
84
+ });
85
+ export {
86
+ j as SelectionOverlay
87
+ };
@@ -0,0 +1,28 @@
1
+ import { Temporal } from 'temporal-polyfill';
2
+ import { CalendarResource, PositionedEvent, ResourceGridViewClassNames, SelectedRange, SelectionAppearance, TimedCalendarEvent } from '../../types/calendar';
3
+ interface SlotInteractionLayerProps {
4
+ resource: CalendarResource;
5
+ column: number;
6
+ date: Temporal.PlainDate;
7
+ timeZone: string;
8
+ startHour: number;
9
+ endHour: number;
10
+ hourHeight: number;
11
+ snapDuration: number;
12
+ placeholderDuration: number;
13
+ cls: (key: keyof ResourceGridViewClassNames) => string;
14
+ onSlotClick?: (info: {
15
+ resource: CalendarResource;
16
+ startTime: Temporal.ZonedDateTime;
17
+ endTime: Temporal.ZonedDateTime;
18
+ }) => void;
19
+ onSelect?: (range: SelectedRange | null) => void;
20
+ dragPreviewAppearance?: SelectionAppearance;
21
+ renderEvent?: (props: {
22
+ event: TimedCalendarEvent;
23
+ position: PositionedEvent;
24
+ }) => React.ReactNode;
25
+ }
26
+ export declare const SlotInteractionLayer: import('react').NamedExoticComponent<SlotInteractionLayerProps>;
27
+ export {};
28
+ //# sourceMappingURL=SlotInteractionLayer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SlotInteractionLayer.d.ts","sourceRoot":"","sources":["../../../src/components/resource-grid-view/SlotInteractionLayer.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,0BAA0B,EAC1B,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,kBAAkB,CAAC;AAI1B,UAAU,yBAAyB;IACjC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,0BAA0B,KAAK,MAAM,CAAC;IACvD,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;QACnB,QAAQ,EAAE,gBAAgB,CAAC;QAC3B,SAAS,EAAE,QAAQ,CAAC,aAAa,CAAC;QAClC,OAAO,EAAE,QAAQ,CAAC,aAAa,CAAC;KACjC,KAAK,IAAI,CAAC;IACX,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,qBAAqB,CAAC,EAAE,mBAAmB,CAAC;IAC5C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE;QACpB,KAAK,EAAE,kBAAkB,CAAC;QAC1B,QAAQ,EAAE,eAAe,CAAC;KAC3B,KAAK,KAAK,CAAC,SAAS,CAAC;CACvB;AAmBD,eAAO,MAAM,oBAAoB,iEA2T/B,CAAC"}
@@ -0,0 +1,213 @@
1
+ import { jsxs as rt, jsx as x } from "react/jsx-runtime";
2
+ import { memo as ot, useState as K, useRef as o, useCallback as m, useLayoutEffect as st, useEffect as it } from "react";
3
+ import { buildSyntheticEvent as ct } from "../../lib/selection.js";
4
+ import { EventChip as ut } from "./EventChip.js";
5
+ function E(U, u, C) {
6
+ const a = Math.floor(u / 60), i = u % 60;
7
+ return U.toPlainDateTime({ hour: a, minute: i }).toZonedDateTime(C);
8
+ }
9
+ const mt = ot(function({
10
+ resource: u,
11
+ column: C,
12
+ date: a,
13
+ timeZone: i,
14
+ startHour: Q,
15
+ endHour: V,
16
+ hourHeight: W,
17
+ snapDuration: R,
18
+ placeholderDuration: l,
19
+ cls: y,
20
+ onSlotClick: L,
21
+ onSelect: h,
22
+ dragPreviewAppearance: F = "highlight",
23
+ renderEvent: X
24
+ }) {
25
+ const [b, k] = K(null), [c, H] = K(null), S = o(null), M = o(null), w = o(!1), q = o(h), z = o(u), B = o(a), O = o(i), v = Q * 60, T = V * 60, d = W / 60, f = m(
26
+ (n) => {
27
+ const t = n / d, r = Math.floor(t / R) * R, e = v + r;
28
+ return e + l > T || e < v ? null : e;
29
+ },
30
+ [
31
+ d,
32
+ R,
33
+ l,
34
+ v,
35
+ T
36
+ ]
37
+ ), G = o(f), Y = o(T), _ = o(R), I = o(l), J = m((n, t) => {
38
+ const r = Math.min(n, t), e = Math.min(
39
+ Math.max(n, t) + I.current,
40
+ Y.current
41
+ );
42
+ return { startMin: r, endMin: e };
43
+ }, []), g = m(
44
+ (n) => {
45
+ const t = M.current, r = S.current;
46
+ if (!t || !r) return;
47
+ const e = r.getBoundingClientRect(), s = e.height, p = Math.max(
48
+ 0,
49
+ Math.min(n.clientY - e.top, s)
50
+ );
51
+ let j = G.current(p);
52
+ j == null && (j = Y.current - I.current);
53
+ const D = J(t.anchorSlotStart, j);
54
+ t.currentStartMin = D.startMin, t.currentEndMin = D.endMin, t.moved = !0, H(D);
55
+ },
56
+ [J]
57
+ ), N = o(() => {
58
+ }), P = m(() => {
59
+ const n = M.current;
60
+ n && (n.moved && (w.current = !0), q.current?.({
61
+ resourceId: z.current.id,
62
+ startTime: E(
63
+ B.current,
64
+ n.currentStartMin,
65
+ O.current
66
+ ),
67
+ endTime: E(
68
+ B.current,
69
+ n.currentEndMin,
70
+ O.current
71
+ )
72
+ })), M.current = null, H(null), document.removeEventListener("mousemove", g), document.removeEventListener("mouseup", N.current);
73
+ }, [g]);
74
+ st(() => {
75
+ q.current = h, z.current = u, B.current = a, O.current = i, G.current = f, Y.current = T, _.current = R, I.current = l, N.current = P;
76
+ }), it(() => () => {
77
+ document.removeEventListener("mousemove", g), document.removeEventListener("mouseup", N.current);
78
+ }, [g]);
79
+ const $ = m(
80
+ (n) => {
81
+ if (!h) return;
82
+ const t = S.current;
83
+ if (!t) return;
84
+ const r = t.getBoundingClientRect(), e = n.clientY - r.top, s = f(e);
85
+ if (s == null) return;
86
+ n.preventDefault(), h(null);
87
+ const p = s + l;
88
+ M.current = {
89
+ anchorSlotStart: s,
90
+ currentStartMin: s,
91
+ currentEndMin: p,
92
+ moved: !1
93
+ }, H({ startMin: s, endMin: p }), document.addEventListener("mousemove", g), document.addEventListener("mouseup", P);
94
+ },
95
+ [
96
+ h,
97
+ f,
98
+ l,
99
+ g,
100
+ P
101
+ ]
102
+ ), A = m(
103
+ (n) => {
104
+ if (M.current) return;
105
+ const t = S.current;
106
+ if (!t) return;
107
+ const r = t.getBoundingClientRect(), e = n.clientY - r.top;
108
+ k(f(e));
109
+ },
110
+ [f]
111
+ ), Z = m(() => {
112
+ M.current || k(null);
113
+ }, []), tt = m(
114
+ (n) => {
115
+ if (w.current) {
116
+ w.current = !1;
117
+ return;
118
+ }
119
+ const t = S.current;
120
+ if (!t) return;
121
+ const r = t.getBoundingClientRect(), e = n.clientY - r.top, s = f(e);
122
+ if (s == null) return;
123
+ const p = s + l;
124
+ L && L({
125
+ resource: u,
126
+ startTime: E(a, s, i),
127
+ endTime: E(a, p, i)
128
+ });
129
+ },
130
+ [L, f, l, u, a, i]
131
+ ), nt = b != null ? (b - v) * d : 0, et = l * d;
132
+ return /* @__PURE__ */ rt(
133
+ "div",
134
+ {
135
+ ref: S,
136
+ style: {
137
+ gridRow: "3 / -1",
138
+ gridColumn: C,
139
+ position: "relative",
140
+ pointerEvents: "auto",
141
+ cursor: L || h ? "pointer" : void 0
142
+ },
143
+ onMouseDown: $,
144
+ onMouseMove: A,
145
+ onMouseLeave: Z,
146
+ onClick: tt,
147
+ children: [
148
+ b != null && !c && /* @__PURE__ */ x(
149
+ "div",
150
+ {
151
+ "aria-hidden": "true",
152
+ className: y("slotHighlight"),
153
+ style: {
154
+ position: "absolute",
155
+ top: nt,
156
+ left: 0,
157
+ right: 0,
158
+ height: et,
159
+ pointerEvents: "none"
160
+ }
161
+ }
162
+ ),
163
+ c && (F !== "highlight" ? /* @__PURE__ */ x(
164
+ "div",
165
+ {
166
+ "aria-hidden": "true",
167
+ className: y("eventColumn"),
168
+ style: { pointerEvents: "none" },
169
+ children: /* @__PURE__ */ x(
170
+ ut,
171
+ {
172
+ interactive: !1,
173
+ positioned: {
174
+ event: ct(
175
+ u.id,
176
+ E(a, c.startMin, i),
177
+ E(a, c.endMin, i),
178
+ F.eventData
179
+ ),
180
+ top: (c.startMin - v) * d,
181
+ height: (c.endMin - c.startMin) * d,
182
+ subColumn: 0,
183
+ totalSubColumns: 1
184
+ },
185
+ resource: u,
186
+ timeZone: i,
187
+ cls: y,
188
+ renderEvent: X
189
+ }
190
+ )
191
+ }
192
+ ) : /* @__PURE__ */ x(
193
+ "div",
194
+ {
195
+ "aria-hidden": "true",
196
+ className: y("selectionHighlight"),
197
+ style: {
198
+ position: "absolute",
199
+ top: (c.startMin - v) * d,
200
+ left: 0,
201
+ right: 0,
202
+ height: (c.endMin - c.startMin) * d,
203
+ pointerEvents: "none"
204
+ }
205
+ }
206
+ ))
207
+ ]
208
+ }
209
+ );
210
+ });
211
+ export {
212
+ mt as SlotInteractionLayer
213
+ };
@@ -0,0 +1,11 @@
1
+ import { ResourceGridViewClassNames } from '../../types/calendar';
2
+ interface TimeGutterProps {
3
+ label: string;
4
+ row: number;
5
+ isHourStart: boolean;
6
+ isFirst: boolean;
7
+ cls: (key: keyof ResourceGridViewClassNames) => string;
8
+ }
9
+ export declare const TimeGutter: import('react').NamedExoticComponent<TimeGutterProps>;
10
+ export {};
11
+ //# sourceMappingURL=TimeGutter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimeGutter.d.ts","sourceRoot":"","sources":["../../../src/components/resource-grid-view/TimeGutter.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAEnE,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,0BAA0B,KAAK,MAAM,CAAC;CACxD;AAED,eAAO,MAAM,UAAU,uDAmBrB,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { jsx as t } from "react/jsx-runtime";
2
+ import { memo as l } from "react";
3
+ const g = l(function({
4
+ label: m,
5
+ row: i,
6
+ isHourStart: e,
7
+ isFirst: o,
8
+ cls: r
9
+ }) {
10
+ return /* @__PURE__ */ t(
11
+ "div",
12
+ {
13
+ className: r(e ? "gutterCell" : "gutterCellMinor"),
14
+ style: {
15
+ gridRow: i,
16
+ gridColumn: 1,
17
+ ...o ? { marginTop: 0 } : {}
18
+ },
19
+ children: e && /* @__PURE__ */ t("span", { className: r("gutterLabel"), children: m })
20
+ }
21
+ );
22
+ });
23
+ export {
24
+ g as TimeGutter
25
+ };
@@ -0,0 +1,10 @@
1
+ import { ResourceGridViewClassNames } from '../../types/calendar';
2
+ import { UnavailableBlock } from '../../lib/availability';
3
+ interface UnavailabilityOverlayProps {
4
+ blocks: UnavailableBlock[];
5
+ column: number;
6
+ cls: (key: keyof ResourceGridViewClassNames) => string;
7
+ }
8
+ export declare const UnavailabilityOverlay: import('react').NamedExoticComponent<UnavailabilityOverlayProps>;
9
+ export {};
10
+ //# sourceMappingURL=UnavailabilityOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnavailabilityOverlay.d.ts","sourceRoot":"","sources":["../../../src/components/resource-grid-view/UnavailabilityOverlay.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,UAAU,0BAA0B;IAClC,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,0BAA0B,KAAK,MAAM,CAAC;CACxD;AAED,eAAO,MAAM,qBAAqB,kEAgChC,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { jsx as e } from "react/jsx-runtime";
2
+ import { memo as l } from "react";
3
+ const p = l(function({
4
+ blocks: i,
5
+ column: r,
6
+ cls: a
7
+ }) {
8
+ return i.length === 0 ? null : /* @__PURE__ */ e(
9
+ "div",
10
+ {
11
+ "aria-hidden": "true",
12
+ style: {
13
+ gridRow: "3 / -1",
14
+ gridColumn: r,
15
+ position: "relative",
16
+ pointerEvents: "none"
17
+ },
18
+ children: i.map((t, n) => /* @__PURE__ */ e(
19
+ "div",
20
+ {
21
+ className: a("unavailableOverlay"),
22
+ style: {
23
+ position: "absolute",
24
+ top: t.top,
25
+ left: 0,
26
+ right: 0,
27
+ height: t.height
28
+ }
29
+ },
30
+ n
31
+ ))
32
+ }
33
+ );
34
+ });
35
+ export {
36
+ p as UnavailabilityOverlay
37
+ };
@@ -0,0 +1,3 @@
1
+ import { ResourceGridViewClassNames } from '../../types/calendar';
2
+ export declare const resourceGridViewDefaults: Required<ResourceGridViewClassNames>;
3
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/components/resource-grid-view/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAEnE,eAAO,MAAM,wBAAwB,EAAE,QAAQ,CAAC,0BAA0B,CAgCzE,CAAC"}
@@ -0,0 +1,28 @@
1
+ const e = {
2
+ root: "overflow-auto relative",
3
+ grid: "min-w-max",
4
+ cornerCell: "bg-cal-surface border-r border-cal-border sticky top-0 left-0 z-30 flex items-end justify-end",
5
+ headerCell: "bg-cal-surface border-cal-border sticky top-0 z-20 flex items-center gap-2 px-3 py-2",
6
+ headerName: "text-cal-text text-sm font-medium truncate",
7
+ headerAvatar: "size-6 rounded-full object-cover",
8
+ gutterCell: "bg-cal-surface border-r border-cal-border sticky left-0 z-10 flex items-start justify-end pr-2 -mt-[0.5rem]",
9
+ gutterCellMinor: "bg-cal-surface border-r border-cal-border sticky left-0 z-10",
10
+ gutterLabel: "font-medium text-cal-text-muted text-xs",
11
+ bodyCell: "border-t border-r border-cal-border",
12
+ bodyCellMinor: "border-t border-r border-cal-border",
13
+ eventColumn: "relative mr-3",
14
+ event: "absolute inset-x-0.5 rounded-md pl-2.5 pr-1.5 py-0.5 overflow-hidden cursor-pointer select-none text-left bg-cal-event-bg ring-1 ring-inset ring-cal-event-ring",
15
+ eventSelected: "shadow-lg shadow-cal-event-shadow ring-cal-event-ring-selected",
16
+ eventColorBar: "absolute left-0 top-0 bottom-0 w-1",
17
+ eventTitle: "text-cal-text-body text-xs/4 font-medium",
18
+ eventTime: "text-cal-text-muted text-xs/4",
19
+ eventClientName: "text-cal-text-muted text-xs/4",
20
+ nowIndicator: "absolute left-0 right-0 h-0.5 bg-cal-now pointer-events-none",
21
+ slotHighlight: "bg-cal-slot-highlight rounded-md transition-[top,opacity] duration-75",
22
+ selectionHighlight: "bg-cal-selection rounded-md",
23
+ allDayCell: "border-r sticky z-20 bg-cal-surface border-b border-cal-border px-1 py-1 flex gap-1",
24
+ unavailableOverlay: "cal-unavailable-overlay"
25
+ };
26
+ export {
27
+ e as resourceGridViewDefaults
28
+ };
@@ -0,0 +1,3 @@
1
+ export { ResourceGridView } from './ResourceGridView';
2
+ export { resourceGridViewDefaults } from './defaults';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/resource-grid-view/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function useAnnouncer(): {
2
+ message: string;
3
+ announce: (text: string) => void;
4
+ };
5
+ //# sourceMappingURL=useAnnouncer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAnnouncer.d.ts","sourceRoot":"","sources":["../../../src/components/resource-grid-view/useAnnouncer.ts"],"names":[],"mappings":"AAEA,wBAAgB,YAAY;;qBAIU,MAAM;EAU3C"}
@@ -0,0 +1,12 @@
1
+ import { useState as s, useRef as o, useCallback as c } from "react";
2
+ function i() {
3
+ const [n, t] = s(""), e = o(null), u = c((r) => {
4
+ e.current && clearTimeout(e.current), t(""), e.current = setTimeout(() => {
5
+ t(r);
6
+ }, 50);
7
+ }, []);
8
+ return { message: n, announce: u };
9
+ }
10
+ export {
11
+ i as useAnnouncer
12
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Computes an effective hour height that stretches rows to fill the container
3
+ * when there is extra vertical space. The provided `hourHeight` acts as a minimum.
4
+ *
5
+ * Also exposes the measured header height so the all-day row can be positioned
6
+ * sticky below the header.
7
+ */
8
+ export declare function useEffectiveHourHeight(hourHeight: number, totalHours: number): {
9
+ effectiveHourHeight: number;
10
+ rootRef: import('react').RefObject<HTMLDivElement | null>;
11
+ headerRef: import('react').RefObject<HTMLDivElement | null>;
12
+ allDayRef: import('react').RefObject<HTMLDivElement | null>;
13
+ headerHeight: number;
14
+ };
15
+ //# sourceMappingURL=useEffectiveHourHeight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEffectiveHourHeight.d.ts","sourceRoot":"","sources":["../../../src/components/resource-grid-view/useEffectiveHourHeight.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;;;;;;EAgC5E"}
@@ -0,0 +1,20 @@
1
+ import { useRef as n, useState as H, useLayoutEffect as y } from "react";
2
+ function p(e, r) {
3
+ const o = n(null), s = n(null), c = n(null), [h, l] = H(e), [g, d] = H(0);
4
+ return y(() => {
5
+ const t = o.current, i = s.current;
6
+ if (!t || !i) return;
7
+ function a() {
8
+ const v = t.clientHeight, u = i.offsetHeight;
9
+ d(u);
10
+ const b = c.current?.offsetHeight ?? 0, m = (v - u - b) / r;
11
+ l(Math.max(e, m));
12
+ }
13
+ a();
14
+ const f = new ResizeObserver(a);
15
+ return f.observe(t), () => f.disconnect();
16
+ }, [e, r]), { effectiveHourHeight: h, rootRef: o, headerRef: s, allDayRef: c, headerHeight: g };
17
+ }
18
+ export {
19
+ p as useEffectiveHourHeight
20
+ };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Component styles for @savvycal/calendar
3
+ *
4
+ * Import this file in your app's CSS AFTER the preset and tailwindcss:
5
+ *
6
+ * @import "@savvycal/calendar/preset.css";
7
+ * @import "tailwindcss";
8
+ * @import "@savvycal/calendar/components.css";
9
+ */
10
+
11
+ /* Unavailable time overlay with cross-hatching */
12
+ .cal-unavailable-overlay {
13
+ background-attachment: fixed;
14
+ background-image: repeating-linear-gradient(
15
+ -45deg,
16
+ oklch(0 0 0 / 0.02),
17
+ oklch(0 0 0 / 0.02) 3px,
18
+ oklch(0 0 0 / 0.08) 3px,
19
+ oklch(0 0 0 / 0.08) 6px
20
+ );
21
+ }
22
+
23
+ .dark .cal-unavailable-overlay {
24
+ background-image: repeating-linear-gradient(
25
+ -45deg,
26
+ oklch(1 0 0 / 0.02),
27
+ oklch(1 0 0 / 0.02) 3px,
28
+ oklch(1 0 0 / 0.08) 3px,
29
+ oklch(1 0 0 / 0.08) 6px
30
+ );
31
+ }
@@ -0,0 +1,6 @@
1
+ export { Temporal } from 'temporal-polyfill';
2
+ export { ResourceGridView } from './components/resource-grid-view';
3
+ export { resourceGridViewDefaults } from './components/resource-grid-view';
4
+ export type { CalendarResource, CalendarEvent, TimedCalendarEvent, AllDayCalendarEvent, TimeSlot, AvailabilityRange, TimeAxisConfig, ResourceGridViewProps, ResourceGridViewClassNames, PositionedEvent, SelectedRange, SelectionAppearance, SelectionEventData, EventLayout, } from './types/calendar';
5
+ export { cn } from './lib/utils';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAG3E,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,QAAQ,EACR,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,0BAA0B,EAC1B,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ import { Temporal as o } from "temporal-polyfill";
2
+ import { cn as m } from "./lib/utils.js";
3
+ import { ResourceGridView as t } from "./components/resource-grid-view/ResourceGridView.js";
4
+ import { resourceGridViewDefaults as x } from "./components/resource-grid-view/defaults.js";
5
+ export {
6
+ t as ResourceGridView,
7
+ o as Temporal,
8
+ m as cn,
9
+ x as resourceGridViewDefaults
10
+ };
@@ -0,0 +1,12 @@
1
+ import { Temporal } from 'temporal-polyfill';
2
+ import { AvailabilityRange } from '../types/calendar';
3
+ export interface UnavailableBlock {
4
+ top: number;
5
+ height: number;
6
+ }
7
+ /**
8
+ * Compute unavailable blocks for a single resource by merging the inverse
9
+ * of available ranges with explicit unavailable ranges.
10
+ */
11
+ export declare function computeUnavailableBlocks(availableRanges: AvailabilityRange[] | undefined, unavailableRanges: AvailabilityRange[] | undefined, timeZone: string, viewDate: Temporal.PlainDate, startHour: number, endHour: number, hourHeight: number): UnavailableBlock[];
12
+ //# sourceMappingURL=availability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability.d.ts","sourceRoot":"","sources":["../../src/lib/availability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAmED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,eAAe,EAAE,iBAAiB,EAAE,GAAG,SAAS,EAChD,iBAAiB,EAAE,iBAAiB,EAAE,GAAG,SAAS,EAClD,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,QAAQ,CAAC,SAAS,EAC5B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,gBAAgB,EAAE,CAuCpB"}
@@ -0,0 +1,56 @@
1
+ import { getMinuteRange as m } from "./time.js";
2
+ function l(o, r, s, n, e) {
3
+ return o.map((t) => {
4
+ const a = m(t.startTime, t.endTime, s, r);
5
+ return a ? {
6
+ start: Math.max(a.startMin, n),
7
+ end: Math.min(a.endMin, e)
8
+ } : null;
9
+ }).filter((t) => t !== null && t.start < t.end);
10
+ }
11
+ function d(o) {
12
+ if (o.length === 0) return [];
13
+ const r = [...o].sort((n, e) => n.start - e.start), s = [{ ...r[0] }];
14
+ for (let n = 1; n < r.length; n++) {
15
+ const e = s[s.length - 1];
16
+ r[n].start <= e.end ? e.end = Math.max(e.end, r[n].end) : s.push({ ...r[n] });
17
+ }
18
+ return s;
19
+ }
20
+ function p(o, r, s) {
21
+ const n = d(o), e = [];
22
+ let t = r;
23
+ for (const a of n)
24
+ t < a.start && e.push({ start: t, end: a.start }), t = Math.max(t, a.end);
25
+ return t < s && e.push({ start: t, end: s }), e;
26
+ }
27
+ function M(o, r, s, n, e, t, a) {
28
+ const c = e * 60, i = t * 60, h = a / 60, f = [];
29
+ if (o && o.length > 0) {
30
+ const u = l(
31
+ o,
32
+ s,
33
+ n,
34
+ c,
35
+ i
36
+ );
37
+ f.push(
38
+ ...p(u, c, i)
39
+ );
40
+ }
41
+ return r && r.length > 0 && f.push(
42
+ ...l(
43
+ r,
44
+ s,
45
+ n,
46
+ c,
47
+ i
48
+ )
49
+ ), d(f).map((u) => ({
50
+ top: (u.start - c) * h,
51
+ height: (u.end - u.start) * h
52
+ }));
53
+ }
54
+ export {
55
+ M as computeUnavailableBlocks
56
+ };