@neo-reckoning/react 0.1.0-alpha.1 → 0.1.0-alpha.2
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 +175 -0
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# @neo-reckoning/react
|
|
2
|
+
|
|
3
|
+
Headless React hooks for calendar state management. Built on [@neo-reckoning/core](https://www.npmjs.com/package/@neo-reckoning/core).
|
|
4
|
+
|
|
5
|
+
All hooks return data structures — no DOM, no components, no CSS. You bring the rendering.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
npm install @neo-reckoning/react @neo-reckoning/core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
React 18+ is a peer dependency.
|
|
14
|
+
|
|
15
|
+
## Hooks
|
|
16
|
+
|
|
17
|
+
### `useCalendar`
|
|
18
|
+
|
|
19
|
+
Calendar grid with navigation. The primary hook for month/week views.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { useCalendar } from '@neo-reckoning/react';
|
|
23
|
+
|
|
24
|
+
const { months, next, prev, goTo, focusDate } = useCalendar({
|
|
25
|
+
focusDate: '2026-03-15',
|
|
26
|
+
numberOfMonths: 1,
|
|
27
|
+
ranges: myRanges,
|
|
28
|
+
fidelity: 'month', // 'year' | 'month' | 'week' | 'day'
|
|
29
|
+
weekStartsOn: 1, // Monday
|
|
30
|
+
userTimezone: 'America/New_York',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// months[0].weeks[0].days[0].ranges → DayRangeInfo[]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### `useCalendarEvents`
|
|
37
|
+
|
|
38
|
+
Merges native DateRanges and imported calendar events into a single sorted `CalendarEvent[]`.
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { useCalendarEvents } from '@neo-reckoning/react';
|
|
42
|
+
|
|
43
|
+
const events = useCalendarEvents({
|
|
44
|
+
ranges: myRanges,
|
|
45
|
+
importedEvents: icsEvents, // from @neo-reckoning/ical
|
|
46
|
+
from: windowStart,
|
|
47
|
+
to: windowEnd,
|
|
48
|
+
userTimezone: 'America/New_York',
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### `useTimeline`
|
|
53
|
+
|
|
54
|
+
Timeline data for day views with positioned events and overlap detection.
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { useTimeline } from '@neo-reckoning/react';
|
|
58
|
+
|
|
59
|
+
const { slots } = useTimeline({
|
|
60
|
+
date: '2026-03-23',
|
|
61
|
+
events: dayEvents,
|
|
62
|
+
startHour: 8,
|
|
63
|
+
endHour: 18,
|
|
64
|
+
intervalMinutes: 30,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// slots[0].events[0] → { event, top, height, column, totalColumns }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### `useSpans`
|
|
71
|
+
|
|
72
|
+
Span-level overlap detection with lane assignment for consistent multi-day bar rendering.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { useSpans } from '@neo-reckoning/react';
|
|
76
|
+
|
|
77
|
+
const spans = useSpans({
|
|
78
|
+
ranges: myRanges,
|
|
79
|
+
from: windowStart,
|
|
80
|
+
to: windowEnd,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// spans[0] → { rangeId, startDate, endDate, lane, totalLanes, maxOverlap }
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `useDayDetail`
|
|
87
|
+
|
|
88
|
+
Time slots and all-day range info for a specific day.
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { useDayDetail } from '@neo-reckoning/react';
|
|
92
|
+
|
|
93
|
+
const { timeSlots, allDayRanges } = useDayDetail(
|
|
94
|
+
'2026-03-23',
|
|
95
|
+
myRanges,
|
|
96
|
+
'America/New_York',
|
|
97
|
+
);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `useRangeCheck`
|
|
101
|
+
|
|
102
|
+
Range evaluation — check which ranges a datetime falls within.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { useRangeCheck } from '@neo-reckoning/react';
|
|
106
|
+
|
|
107
|
+
const { isInRange, getOccurrences } = useRangeCheck(myRanges, 'America/New_York');
|
|
108
|
+
|
|
109
|
+
const matchingRanges = isInRange(new Date());
|
|
110
|
+
const occurrences = getOccurrences(from, to);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### `useConflicts`
|
|
114
|
+
|
|
115
|
+
Find scheduling conflicts across a date window.
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { useConflicts } from '@neo-reckoning/react';
|
|
119
|
+
|
|
120
|
+
const conflicts = useConflicts({
|
|
121
|
+
ranges: myRanges,
|
|
122
|
+
from: windowStart,
|
|
123
|
+
to: windowEnd,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// conflicts[0] → { rangeA, rangeB, date, overlapStart, overlapEnd }
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### `useFreeSlots`
|
|
130
|
+
|
|
131
|
+
Find available time on a given day.
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import { useFreeSlots } from '@neo-reckoning/react';
|
|
135
|
+
|
|
136
|
+
const freeSlots = useFreeSlots({
|
|
137
|
+
ranges: myRanges,
|
|
138
|
+
date: '2026-03-23',
|
|
139
|
+
minDuration: 30,
|
|
140
|
+
dayStart: '09:00',
|
|
141
|
+
dayEnd: '17:00',
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// freeSlots[0] → { date, startTime, endTime, duration }
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### `useScheduleScore`
|
|
148
|
+
|
|
149
|
+
Schedule quality metrics for evaluating arrangements.
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { useScheduleScore } from '@neo-reckoning/react';
|
|
153
|
+
|
|
154
|
+
const score = useScheduleScore({
|
|
155
|
+
ranges: myRanges,
|
|
156
|
+
from: windowStart,
|
|
157
|
+
to: windowEnd,
|
|
158
|
+
focusBlockMinutes: 60,
|
|
159
|
+
dayStart: '09:00',
|
|
160
|
+
dayEnd: '17:00',
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// score → { conflicts, freeMinutes, focusBlocks, avgContextSwitches, conflictDays }
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Design philosophy
|
|
167
|
+
|
|
168
|
+
- **Headless** — returns data, not DOM. Works with any component library or React Native.
|
|
169
|
+
- **No styling** — range IDs, not colors. Your app maps IDs to palettes.
|
|
170
|
+
- **Memoized** — all hooks use `useMemo` for efficient re-renders.
|
|
171
|
+
- **Framework-agnostic core** — all computation lives in `@neo-reckoning/core`. These hooks are thin wrappers.
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neo-reckoning/react",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"repository": {
|
|
31
31
|
"type": "git",
|
|
32
|
-
"url": "https://github.com/sdougbrown/neo-reckoning.git",
|
|
32
|
+
"url": "git+https://github.com/sdougbrown/neo-reckoning.git",
|
|
33
33
|
"directory": "packages/react"
|
|
34
34
|
},
|
|
35
35
|
"publishConfig": {
|