@neo-reckoning/core 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.
Files changed (2) hide show
  1. package/README.md +149 -0
  2. package/package.json +2 -2
package/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # @neo-reckoning/core
2
+
3
+ Headless calendar state management library. Zero dependencies. Framework-agnostic.
4
+
5
+ A modern TypeScript rewrite of the concepts from [reckoning](https://github.com/sdougbrown/reckoning), extended with sub-day time support, hourly recurrence, timezone handling, and agent-ready scheduling primitives.
6
+
7
+ ## What this does
8
+
9
+ Neo-reckoning is a **computation library**, not a UI library. It tells you *what* and *when* — your app decides *how it looks*.
10
+
11
+ - **DateRange evaluation** — does a date/time fall within a range? Supports explicit dates, day-of-week/month recurrence, hourly recurrence (`everyHour` or `startTime`/`repeatEvery`), and timezone conversion.
12
+ - **Calendar grid generation** — produces Month/Week/Day data structures for rendering, with configurable fidelity (year/month/week/day) so you only compute what you need.
13
+ - **Timeline positioning** — computes event positions for hourly views with overlap detection and column assignment.
14
+ - **Span detection** — groups contiguous days into spans with lane assignment for consistent multi-day bar rendering.
15
+ - **Conflict detection** — finds overlapping timed ranges on a given day or across a window.
16
+ - **Free slot detection** — finds gaps in a schedule where new events could fit.
17
+ - **Schedule scoring** — computes quality metrics (conflicts, free time, focus blocks, context switches) for evaluating rearrangements.
18
+ - **Event normalization** — converts DateRanges into a flat `CalendarEvent[]` that can be merged with imported calendar events.
19
+
20
+ ## Install
21
+
22
+ ```
23
+ npm install @neo-reckoning/core
24
+ ```
25
+
26
+ ## Quick start
27
+
28
+ ```typescript
29
+ import { RangeEvaluator, CalendarGrid } from '@neo-reckoning/core';
30
+ import type { DateRange } from '@neo-reckoning/core';
31
+
32
+ // Define some ranges
33
+ const ranges: DateRange[] = [
34
+ {
35
+ id: 'standup',
36
+ label: 'Daily Standup',
37
+ everyWeekday: [1, 2, 3, 4, 5], // Mon-Fri
38
+ startTime: '09:00',
39
+ endTime: '09:15',
40
+ timezone: 'UTC',
41
+ },
42
+ {
43
+ id: 'meds',
44
+ label: 'Medication',
45
+ everyHour: [8, 14, 20], // 8am, 2pm, 8pm
46
+ duration: 5,
47
+ },
48
+ {
49
+ id: 'vacation',
50
+ label: 'Spring Break',
51
+ fromDate: '2026-03-23',
52
+ toDate: '2026-03-27',
53
+ fixedBetween: true,
54
+ },
55
+ ];
56
+
57
+ // Evaluate ranges
58
+ const evaluator = new RangeEvaluator('America/New_York');
59
+
60
+ // Check if a date is in a range
61
+ evaluator.isDateInRange('2026-03-25', ranges[2]); // true (vacation)
62
+
63
+ // Expand occurrences in a window
64
+ const occurrences = evaluator.expand(ranges[0], new Date(2026, 2, 23), new Date(2026, 2, 27));
65
+ // → [{ date: '2026-03-23', startTime: '04:00', ... }, ...] (UTC→ET converted)
66
+
67
+ // Find conflicts
68
+ const conflicts = evaluator.findConflicts(ranges, '2026-03-23');
69
+
70
+ // Find free slots
71
+ const freeSlots = evaluator.findFreeSlots(ranges, '2026-03-23', {
72
+ dayStart: '09:00',
73
+ dayEnd: '17:00',
74
+ minDuration: 30,
75
+ });
76
+
77
+ // Generate a calendar grid
78
+ const grid = new CalendarGrid({
79
+ focusDate: '2026-03-15',
80
+ numberOfMonths: 1,
81
+ ranges,
82
+ fidelity: 'month', // skip time slot computation
83
+ weekStartsOn: 1, // Monday
84
+ userTimezone: 'America/New_York',
85
+ });
86
+
87
+ grid.months[0].weeks[0].days[0].ranges;
88
+ // → [{ rangeId: '...', label: '...', isStart: true, isEnd: false, ... }]
89
+ ```
90
+
91
+ ## Core concepts
92
+
93
+ ### DateRange
94
+
95
+ The fundamental data model. Defines a set of dates and/or times using explicit values or recurrence patterns.
96
+
97
+ **Day-level** (from original Reckoning):
98
+ - `dates` — explicit date list
99
+ - `everyWeekday` — days of week (0=Sun, 6=Sat)
100
+ - `everyDate` — days of month (1-31)
101
+ - `everyMonth` — months (1-12)
102
+ - `fromDate` / `toDate` / `fixedBetween` — date bounds
103
+
104
+ **Sub-day** (two mutually exclusive approaches):
105
+ - `everyHour` — explicit hours list, e.g. `[6, 14, 22]`
106
+ - `startTime` / `endTime` / `repeatEvery` / `duration` — interval-based
107
+
108
+ Day and time fields combine as AND: `everyWeekday: [1,3,5]` + `everyHour: [9,17]` means "9am and 5pm on Mon/Wed/Fri."
109
+
110
+ ### Timezone handling
111
+
112
+ - **UTC** (`timezone: 'UTC'`): Times are converted to the user's timezone via `Intl.DateTimeFormat`. Default for API-sourced ranges.
113
+ - **Floating** (`timezone: null`): Times are as-is, no conversion. "9am" means 9am wherever you are.
114
+ - **Specific timezone**: Converted to user's timezone.
115
+
116
+ ### View fidelity
117
+
118
+ `CalendarGrid` accepts a `fidelity` option to control how much it computes per day:
119
+
120
+ | Fidelity | What's computed | Use case |
121
+ |---|---|---|
122
+ | `'year'` | `hasActivity` boolean only | Year overview, heatmaps |
123
+ | `'month'` | `ranges[]` (span info) | Month grid |
124
+ | `'week'` | `ranges[]` + `timeSlots[]` | Week view |
125
+ | `'day'` | `ranges[]` + `timeSlots[]` | Day detail |
126
+
127
+ ### No styling
128
+
129
+ This library carries identifiers (`rangeId`, `sourceId`), not colors or CSS. Your app maps range IDs to colors via its own palette/theme system.
130
+
131
+ ## API reference
132
+
133
+ ### Classes
134
+
135
+ - **`RangeEvaluator`** — `isDateInRange()`, `isInRange()`, `expand()`, `expandDay()`, `computeSpans()`, `findConflicts()`, `findConflictsInWindow()`, `findFreeSlots()`, `findNextFreeSlot()`
136
+ - **`CalendarGrid`** — Month/week/day grid generation with navigation (`next()`, `prev()`, `goTo()`)
137
+ - **`TimelineGrid`** — Hourly timeline with event positioning and overlap detection
138
+ - **`YearGrid`** — Lightweight year-level view with per-day range counts
139
+
140
+ ### Functions
141
+
142
+ - **`scoreSchedule()`** — Schedule quality metrics
143
+ - **`resolveDisplayType()`** — Auto-resolve display hints based on range type and view fidelity
144
+ - **`fromDateRange()`** / **`expandToEvents()`** — Convert ranges to normalized `CalendarEvent[]`
145
+ - **`computeEventPositions()`** — Standalone overlap detection for timeline views
146
+
147
+ ## License
148
+
149
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neo-reckoning/core",
3
- "version": "0.1.0-alpha.1",
3
+ "version": "0.1.0-alpha.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -20,7 +20,7 @@
20
20
  ],
21
21
  "repository": {
22
22
  "type": "git",
23
- "url": "https://github.com/sdougbrown/neo-reckoning.git",
23
+ "url": "git+https://github.com/sdougbrown/neo-reckoning.git",
24
24
  "directory": "packages/core"
25
25
  },
26
26
  "publishConfig": {