@neo-reckoning/core 0.1.0-alpha.1
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/displayType.d.ts +9 -0
- package/dist/displayType.d.ts.map +1 -0
- package/dist/displayType.js +23 -0
- package/dist/displayType.js.map +1 -0
- package/dist/evaluator.d.ts +86 -0
- package/dist/evaluator.d.ts.map +1 -0
- package/dist/evaluator.js +608 -0
- package/dist/evaluator.js.map +1 -0
- package/dist/events.d.ts +10 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +28 -0
- package/dist/events.js.map +1 -0
- package/dist/grid.d.ts +36 -0
- package/dist/grid.d.ts.map +1 -0
- package/dist/grid.js +177 -0
- package/dist/grid.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/scoring.d.ts +14 -0
- package/dist/scoring.d.ts.map +1 -0
- package/dist/scoring.js +152 -0
- package/dist/scoring.js.map +1 -0
- package/dist/time.d.ts +58 -0
- package/dist/time.d.ts.map +1 -0
- package/dist/time.js +169 -0
- package/dist/time.js.map +1 -0
- package/dist/timeline.d.ts +24 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +158 -0
- package/dist/timeline.js.map +1 -0
- package/dist/types.d.ts +349 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/yearGrid.d.ts +16 -0
- package/dist/yearGrid.d.ts.map +1 -0
- package/dist/yearGrid.js +61 -0
- package/dist/yearGrid.js.map +1 -0
- package/package.json +29 -0
package/dist/time.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal time/date utilities for neo-reckoning.
|
|
3
|
+
* Uses Intl.DateTimeFormat for timezone conversion — no external dependencies.
|
|
4
|
+
*/
|
|
5
|
+
/** Parse "HH:mm" into { hour, minute } */
|
|
6
|
+
export function parseTime(time) {
|
|
7
|
+
const [h, m] = time.split(':').map(Number);
|
|
8
|
+
return { hour: h, minute: m };
|
|
9
|
+
}
|
|
10
|
+
/** Format { hour, minute } into "HH:mm" */
|
|
11
|
+
export function formatTime(hour, minute) {
|
|
12
|
+
return `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`;
|
|
13
|
+
}
|
|
14
|
+
/** Convert minutes since midnight to "HH:mm" */
|
|
15
|
+
export function minutesToTime(minutes) {
|
|
16
|
+
const h = Math.floor(minutes / 60);
|
|
17
|
+
const m = minutes % 60;
|
|
18
|
+
return formatTime(h, m);
|
|
19
|
+
}
|
|
20
|
+
/** Convert "HH:mm" to minutes since midnight */
|
|
21
|
+
export function timeToMinutes(time) {
|
|
22
|
+
const { hour, minute } = parseTime(time);
|
|
23
|
+
return hour * 60 + minute;
|
|
24
|
+
}
|
|
25
|
+
/** Add minutes to a time string, clamping at 24:00. Returns null if result >= 24:00. */
|
|
26
|
+
export function addMinutes(time, minutes) {
|
|
27
|
+
const total = timeToMinutes(time) + minutes;
|
|
28
|
+
if (total >= 1440)
|
|
29
|
+
return null; // past midnight
|
|
30
|
+
return minutesToTime(total);
|
|
31
|
+
}
|
|
32
|
+
/** Parse "YYYY-MM-DD" into { year, month, day } */
|
|
33
|
+
export function parseDate(date) {
|
|
34
|
+
const [y, m, d] = date.split('-').map(Number);
|
|
35
|
+
return { year: y, month: m - 1, day: d }; // month is 0-indexed like JS Date
|
|
36
|
+
}
|
|
37
|
+
/** Format a Date to "YYYY-MM-DD" */
|
|
38
|
+
export function formatDate(date) {
|
|
39
|
+
const y = date.getFullYear();
|
|
40
|
+
const m = String(date.getMonth() + 1).padStart(2, '0');
|
|
41
|
+
const d = String(date.getDate()).padStart(2, '0');
|
|
42
|
+
return `${y}-${m}-${d}`;
|
|
43
|
+
}
|
|
44
|
+
/** Get the day of week (0=Sunday) for a "YYYY-MM-DD" string */
|
|
45
|
+
export function getDayOfWeek(dateStr) {
|
|
46
|
+
const { year, month, day } = parseDate(dateStr);
|
|
47
|
+
return new Date(year, month, day).getDay();
|
|
48
|
+
}
|
|
49
|
+
/** Get the number of days in a given month (0-indexed month) */
|
|
50
|
+
export function daysInMonth(year, month) {
|
|
51
|
+
return new Date(year, month + 1, 0).getDate();
|
|
52
|
+
}
|
|
53
|
+
/** Compare two "YYYY-MM-DD" strings. Returns -1, 0, or 1. */
|
|
54
|
+
export function compareDates(a, b) {
|
|
55
|
+
if (a < b)
|
|
56
|
+
return -1;
|
|
57
|
+
if (a > b)
|
|
58
|
+
return 1;
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
/** Generate all dates (as "YYYY-MM-DD") between from and to, inclusive. */
|
|
62
|
+
export function dateRange(from, to) {
|
|
63
|
+
const dates = [];
|
|
64
|
+
const { year: fy, month: fm, day: fd } = parseDate(from);
|
|
65
|
+
const { year: ty, month: tm, day: td } = parseDate(to);
|
|
66
|
+
const start = new Date(fy, fm, fd);
|
|
67
|
+
const end = new Date(ty, tm, td);
|
|
68
|
+
const current = new Date(start);
|
|
69
|
+
while (current <= end) {
|
|
70
|
+
dates.push(formatDate(current));
|
|
71
|
+
current.setDate(current.getDate() + 1);
|
|
72
|
+
}
|
|
73
|
+
return dates;
|
|
74
|
+
}
|
|
75
|
+
/** Get today's date as "YYYY-MM-DD" in a given timezone (or local if not specified). */
|
|
76
|
+
export function getToday(timezone) {
|
|
77
|
+
if (timezone) {
|
|
78
|
+
return formatDateInTimezone(new Date(), timezone);
|
|
79
|
+
}
|
|
80
|
+
return formatDate(new Date());
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Format a Date as "YYYY-MM-DD" in a specific timezone using Intl.DateTimeFormat.
|
|
84
|
+
*/
|
|
85
|
+
export function formatDateInTimezone(date, timezone) {
|
|
86
|
+
const formatter = new Intl.DateTimeFormat('en-CA', {
|
|
87
|
+
timeZone: timezone,
|
|
88
|
+
year: 'numeric',
|
|
89
|
+
month: '2-digit',
|
|
90
|
+
day: '2-digit',
|
|
91
|
+
});
|
|
92
|
+
// en-CA gives YYYY-MM-DD format
|
|
93
|
+
return formatter.format(date);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get the hour and minute of a Date in a specific timezone.
|
|
97
|
+
*/
|
|
98
|
+
export function getTimeInTimezone(date, timezone) {
|
|
99
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
100
|
+
timeZone: timezone,
|
|
101
|
+
hour: 'numeric',
|
|
102
|
+
minute: 'numeric',
|
|
103
|
+
hour12: false,
|
|
104
|
+
});
|
|
105
|
+
const parts = formatter.formatToParts(date);
|
|
106
|
+
const hour = Number(parts.find(p => p.type === 'hour')?.value ?? 0);
|
|
107
|
+
const minute = Number(parts.find(p => p.type === 'minute')?.value ?? 0);
|
|
108
|
+
return { hour, minute };
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Convert a time from one timezone to another on a given date.
|
|
112
|
+
* Returns the converted time as "HH:mm", or null if the time doesn't exist
|
|
113
|
+
* (e.g., spring-forward DST gap).
|
|
114
|
+
*/
|
|
115
|
+
export function convertTime(dateStr, time, fromTimezone, toTimezone) {
|
|
116
|
+
if (fromTimezone === toTimezone)
|
|
117
|
+
return time;
|
|
118
|
+
const { year, month, day } = parseDate(dateStr);
|
|
119
|
+
const { hour, minute } = parseTime(time);
|
|
120
|
+
// Create a Date in the source timezone by using a known UTC offset approach.
|
|
121
|
+
// We build a UTC date then adjust based on the source timezone offset.
|
|
122
|
+
const utcDate = new Date(Date.UTC(year, month, day, hour, minute));
|
|
123
|
+
// Get the offset of the source timezone at this time
|
|
124
|
+
const sourceOffset = getTimezoneOffset(utcDate, fromTimezone);
|
|
125
|
+
// Adjust to actual UTC
|
|
126
|
+
const actualUtc = new Date(utcDate.getTime() + sourceOffset * 60000);
|
|
127
|
+
// Now get the time in the target timezone
|
|
128
|
+
const targetTime = getTimeInTimezone(actualUtc, toTimezone);
|
|
129
|
+
// Check if the source time actually exists (DST spring-forward gap)
|
|
130
|
+
const verifyTime = getTimeInTimezone(actualUtc, fromTimezone);
|
|
131
|
+
if (verifyTime.hour !== hour || verifyTime.minute !== minute) {
|
|
132
|
+
return null; // Time doesn't exist in source timezone (DST gap)
|
|
133
|
+
}
|
|
134
|
+
return formatTime(targetTime.hour, targetTime.minute);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get the UTC offset of a timezone in minutes at a given instant.
|
|
138
|
+
* Positive means behind UTC (e.g., UTC-5 returns 300).
|
|
139
|
+
*/
|
|
140
|
+
function getTimezoneOffset(date, timezone) {
|
|
141
|
+
const utcStr = date.toLocaleString('en-US', { timeZone: 'UTC' });
|
|
142
|
+
const tzStr = date.toLocaleString('en-US', { timeZone: timezone });
|
|
143
|
+
const utcDate = new Date(utcStr);
|
|
144
|
+
const tzDate = new Date(tzStr);
|
|
145
|
+
return (utcDate.getTime() - tzDate.getTime()) / 60000;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Build a Date object from a date string and time string in a given timezone.
|
|
149
|
+
* If timezone is null/undefined (floating), uses local time.
|
|
150
|
+
*/
|
|
151
|
+
export function buildDate(dateStr, time, timezone) {
|
|
152
|
+
const { year, month, day } = parseDate(dateStr);
|
|
153
|
+
if (!time) {
|
|
154
|
+
return new Date(year, month, day);
|
|
155
|
+
}
|
|
156
|
+
const { hour, minute } = parseTime(time);
|
|
157
|
+
if (!timezone) {
|
|
158
|
+
// Floating — local time
|
|
159
|
+
return new Date(year, month, day, hour, minute);
|
|
160
|
+
}
|
|
161
|
+
if (timezone === 'UTC') {
|
|
162
|
+
return new Date(Date.UTC(year, month, day, hour, minute));
|
|
163
|
+
}
|
|
164
|
+
// Specific timezone — build via UTC offset
|
|
165
|
+
const utcGuess = new Date(Date.UTC(year, month, day, hour, minute));
|
|
166
|
+
const offset = getTimezoneOffset(utcGuess, timezone);
|
|
167
|
+
return new Date(utcGuess.getTime() + offset * 60000);
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=time.js.map
|
package/dist/time.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time.js","sourceRoot":"","sources":["../src/time.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { TimelineGridConfig, TimelineSlot, PositionedEvent, CalendarEvent } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* TimelineGrid — produces the data structure for rendering hourly/timeline
|
|
4
|
+
* day views. Handles event positioning including overlap detection for
|
|
5
|
+
* side-by-side concurrent events.
|
|
6
|
+
*/
|
|
7
|
+
export declare class TimelineGrid {
|
|
8
|
+
slots: TimelineSlot[];
|
|
9
|
+
private date;
|
|
10
|
+
private startHour;
|
|
11
|
+
private endHour;
|
|
12
|
+
private intervalMinutes;
|
|
13
|
+
private events;
|
|
14
|
+
constructor(config: TimelineGridConfig);
|
|
15
|
+
private generate;
|
|
16
|
+
private getEventStartMinutes;
|
|
17
|
+
private getEventEndMinutes;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Compute positioned events with column assignments for overlapping events.
|
|
21
|
+
* Uses a greedy column-assignment algorithm.
|
|
22
|
+
*/
|
|
23
|
+
export declare function computeEventPositions(events: CalendarEvent[], startHour?: number, endHour?: number): PositionedEvent[];
|
|
24
|
+
//# sourceMappingURL=timeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../src/timeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,aAAa,EACd,MAAM,YAAY,CAAC;AAGpB;;;;GAIG;AACH,qBAAa,YAAY;IACvB,KAAK,EAAE,YAAY,EAAE,CAAC;IAEtB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,EAAE,kBAAkB;IAStC,OAAO,CAAC,QAAQ;IAsChB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,kBAAkB;CAO3B;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,aAAa,EAAE,EACvB,SAAS,GAAE,MAAU,EACrB,OAAO,GAAE,MAAW,GACnB,eAAe,EAAE,CA8EnB"}
|
package/dist/timeline.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { formatTime, timeToMinutes } from './time.js';
|
|
2
|
+
/**
|
|
3
|
+
* TimelineGrid — produces the data structure for rendering hourly/timeline
|
|
4
|
+
* day views. Handles event positioning including overlap detection for
|
|
5
|
+
* side-by-side concurrent events.
|
|
6
|
+
*/
|
|
7
|
+
export class TimelineGrid {
|
|
8
|
+
slots;
|
|
9
|
+
date;
|
|
10
|
+
startHour;
|
|
11
|
+
endHour;
|
|
12
|
+
intervalMinutes;
|
|
13
|
+
events;
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.date = config.date;
|
|
16
|
+
this.startHour = config.startHour ?? 0;
|
|
17
|
+
this.endHour = config.endHour ?? 24;
|
|
18
|
+
this.intervalMinutes = config.intervalMinutes ?? 60;
|
|
19
|
+
this.events = config.events;
|
|
20
|
+
this.slots = this.generate();
|
|
21
|
+
}
|
|
22
|
+
generate() {
|
|
23
|
+
const slots = [];
|
|
24
|
+
const positioned = computeEventPositions(this.events, this.startHour, this.endHour);
|
|
25
|
+
const totalMinutes = (this.endHour - this.startHour) * 60;
|
|
26
|
+
let currentMinutes = this.startHour * 60;
|
|
27
|
+
const endMinutes = this.endHour * 60;
|
|
28
|
+
while (currentMinutes < endMinutes) {
|
|
29
|
+
const hour = Math.floor(currentMinutes / 60);
|
|
30
|
+
const minute = currentMinutes % 60;
|
|
31
|
+
const time = formatTime(hour, minute);
|
|
32
|
+
// Find events that overlap this slot
|
|
33
|
+
const slotEnd = currentMinutes + this.intervalMinutes;
|
|
34
|
+
const overlapping = positioned.filter(pe => {
|
|
35
|
+
const eventStart = this.getEventStartMinutes(pe.event);
|
|
36
|
+
const eventEnd = this.getEventEndMinutes(pe.event);
|
|
37
|
+
return eventStart < slotEnd && eventEnd > currentMinutes;
|
|
38
|
+
});
|
|
39
|
+
slots.push({
|
|
40
|
+
time,
|
|
41
|
+
hour,
|
|
42
|
+
minute,
|
|
43
|
+
events: overlapping,
|
|
44
|
+
});
|
|
45
|
+
currentMinutes += this.intervalMinutes;
|
|
46
|
+
}
|
|
47
|
+
return slots;
|
|
48
|
+
}
|
|
49
|
+
getEventStartMinutes(event) {
|
|
50
|
+
return event.start.getHours() * 60 + event.start.getMinutes();
|
|
51
|
+
}
|
|
52
|
+
getEventEndMinutes(event) {
|
|
53
|
+
if (event.end) {
|
|
54
|
+
return event.end.getHours() * 60 + event.end.getMinutes();
|
|
55
|
+
}
|
|
56
|
+
// Default to 30 minutes if no end time
|
|
57
|
+
return this.getEventStartMinutes(event) + 30;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Compute positioned events with column assignments for overlapping events.
|
|
62
|
+
* Uses a greedy column-assignment algorithm.
|
|
63
|
+
*/
|
|
64
|
+
export function computeEventPositions(events, startHour = 0, endHour = 24) {
|
|
65
|
+
if (events.length === 0)
|
|
66
|
+
return [];
|
|
67
|
+
const totalMinutes = (endHour - startHour) * 60;
|
|
68
|
+
const timelineStart = startHour * 60;
|
|
69
|
+
// Sort by start time, then by duration (longer first)
|
|
70
|
+
const sorted = [...events].sort((a, b) => {
|
|
71
|
+
const aStart = a.start.getHours() * 60 + a.start.getMinutes();
|
|
72
|
+
const bStart = b.start.getHours() * 60 + b.start.getMinutes();
|
|
73
|
+
if (aStart !== bStart)
|
|
74
|
+
return aStart - bStart;
|
|
75
|
+
const aEnd = a.end
|
|
76
|
+
? a.end.getHours() * 60 + a.end.getMinutes()
|
|
77
|
+
: aStart + 30;
|
|
78
|
+
const bEnd = b.end
|
|
79
|
+
? b.end.getHours() * 60 + b.end.getMinutes()
|
|
80
|
+
: bStart + 30;
|
|
81
|
+
return (bEnd - bStart) - (aEnd - aStart); // Longer events first
|
|
82
|
+
});
|
|
83
|
+
// Assign columns using a greedy approach
|
|
84
|
+
// Track when each column becomes free
|
|
85
|
+
const columnEnds = [];
|
|
86
|
+
const assignments = [];
|
|
87
|
+
for (const event of sorted) {
|
|
88
|
+
const eventStart = event.start.getHours() * 60 + event.start.getMinutes();
|
|
89
|
+
const eventEnd = event.end
|
|
90
|
+
? event.end.getHours() * 60 + event.end.getMinutes()
|
|
91
|
+
: eventStart + 30;
|
|
92
|
+
// Find the first available column
|
|
93
|
+
let assignedColumn = -1;
|
|
94
|
+
for (let col = 0; col < columnEnds.length; col++) {
|
|
95
|
+
if (columnEnds[col] <= eventStart) {
|
|
96
|
+
assignedColumn = col;
|
|
97
|
+
columnEnds[col] = eventEnd;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (assignedColumn === -1) {
|
|
102
|
+
assignedColumn = columnEnds.length;
|
|
103
|
+
columnEnds.push(eventEnd);
|
|
104
|
+
}
|
|
105
|
+
assignments.push({
|
|
106
|
+
event,
|
|
107
|
+
column: assignedColumn,
|
|
108
|
+
startMin: eventStart,
|
|
109
|
+
endMin: eventEnd,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
// Compute total columns for each group of overlapping events
|
|
113
|
+
// We need to find connected components of overlapping events
|
|
114
|
+
const groups = findOverlapGroups(assignments);
|
|
115
|
+
const positioned = [];
|
|
116
|
+
for (const group of groups) {
|
|
117
|
+
const maxColumn = Math.max(...group.map(a => a.column)) + 1;
|
|
118
|
+
for (const assignment of group) {
|
|
119
|
+
const top = ((assignment.startMin - timelineStart) / totalMinutes) * 100;
|
|
120
|
+
const height = ((assignment.endMin - assignment.startMin) / totalMinutes) * 100;
|
|
121
|
+
positioned.push({
|
|
122
|
+
event: assignment.event,
|
|
123
|
+
top: Math.max(0, top),
|
|
124
|
+
height: Math.min(height, 100 - Math.max(0, top)),
|
|
125
|
+
column: assignment.column,
|
|
126
|
+
totalColumns: maxColumn,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return positioned;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Find groups of events that overlap with each other (connected components).
|
|
134
|
+
*/
|
|
135
|
+
function findOverlapGroups(assignments) {
|
|
136
|
+
if (assignments.length === 0)
|
|
137
|
+
return [];
|
|
138
|
+
const sorted = [...assignments].sort((a, b) => a.startMin - b.startMin);
|
|
139
|
+
const groups = [];
|
|
140
|
+
let currentGroup = [sorted[0]];
|
|
141
|
+
let groupEnd = sorted[0].endMin;
|
|
142
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
143
|
+
if (sorted[i].startMin < groupEnd) {
|
|
144
|
+
// Overlaps with current group
|
|
145
|
+
currentGroup.push(sorted[i]);
|
|
146
|
+
groupEnd = Math.max(groupEnd, sorted[i].endMin);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// New group
|
|
150
|
+
groups.push(currentGroup);
|
|
151
|
+
currentGroup = [sorted[i]];
|
|
152
|
+
groupEnd = sorted[i].endMin;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
groups.push(currentGroup);
|
|
156
|
+
return groups;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=timeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../src/timeline.ts"],"names":[],"mappings":"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"}
|