@ninthforge/scheduler 0.0.0-stage → 1.0.0-rc.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/LICENSE.md ADDED
@@ -0,0 +1,9 @@
1
+ Copyright (c) 2026 Inspire Labs Pty Ltd, trading as Ninth Forge. All rights reserved.
2
+
3
+ This repository and its contents are proprietary and confidential. No licence is
4
+ granted to use, copy, modify or distribute any part of it except under a written
5
+ agreement with Inspire Labs Pty Ltd. Packages published from this repository are
6
+ licensed under the Ninth Forge End User Licence Agreement at https://ninthforge.com/legal/eula.
7
+
8
+ Free-pack packages and `@ninthforge/tokens` are released under the MIT licence; for
9
+ those packages, the licence file inside the package applies to that package only.
package/README.md CHANGED
@@ -1,3 +1,94 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # @ninthforge/scheduler
2
+
3
+ A resource scheduler for Microsoft Power Apps code apps and any React app: people, rooms, vehicles, equipment or field jobs on one board. It's part of **[Ninth Forge Plan](https://ninthforge.com)**, the same component as the Ninth Forge Scheduler control for model-driven and canvas apps.
4
+
5
+ - **Views:** Day, Week, Two weeks, Month and Agenda. Agenda is the default below 600 px.
6
+ - **Editing:**
7
+ - drag to move or reassign, drag an edge to resize, drag across empty time to create
8
+ - assign work from the Unassigned panel
9
+ - every edit works from the keyboard too
10
+ - 20-step undo
11
+ - **Rules and capacity:**
12
+ - overlapping bookings allowed, warned or blocked
13
+ - unavailable time (leave, maintenance)
14
+ - capacity per day with a utilisation strip
15
+ - **Output and access:**
16
+ - print and PNG export
17
+ - light and dark themes with your accent
18
+ - right-to-left layouts and high-contrast mode
19
+ - **Lean and private:**
20
+ - no runtime dependencies beyond React (16.14 or later)
21
+ - no network calls, and the licence check is offline
22
+
23
+ ## Install
24
+
25
+ ```
26
+ npm install @ninthforge/scheduler@next
27
+ ```
28
+
29
+ Release candidates (1.0.0-rc.N) are under npm's `next` tag until 1.0.0 on 27 January 2027.
30
+
31
+ ```
32
+ # from 1.0.0
33
+ npm install @ninthforge/scheduler
34
+ ```
35
+
36
+ ## Use
37
+
38
+ You hold the data. The scheduler shows it and tells you what the user changed.
39
+
40
+ ```tsx
41
+ import { useState } from 'react';
42
+ import { Scheduler, type CreateRequest, type SchedBooking, type SchedChange, type SchedResource } from '@ninthforge/scheduler';
43
+
44
+ const resources: SchedResource[] = [
45
+ { id: 'r1', name: 'Aisha Khan', group: 'Customer Care', subtitle: 'Agent', capacityHours: 8 },
46
+ { id: 'r2', name: 'Ben Walker', group: 'Customer Care', subtitle: 'Agent', capacityHours: 8 }
47
+ ];
48
+
49
+ export function Roster({ licenseKey, tenantId }: { licenseKey?: string; tenantId?: string }) {
50
+ const [bookings, setBookings] = useState<SchedBooking[]>([
51
+ { id: 'b1', name: 'Morning shift', start: '2027-02-01T01:00:00Z', end: '2027-02-01T05:00:00Z', resourceId: 'r1', status: 'Confirmed' },
52
+ { id: 'b2', name: 'Callback queue', start: '2027-02-01T02:00:00Z', end: '2027-02-01T03:00:00Z', resourceId: null, status: 'Tentative' }
53
+ ]);
54
+
55
+ // Save to your backend; throw (or reject) to put the booking back with a message.
56
+ const onBookingChange = async (c: SchedChange) => {
57
+ setBookings((list) =>
58
+ list.map((b) =>
59
+ b.id !== c.id
60
+ ? b
61
+ : { ...b, ...(c.start ? { start: c.start } : {}), ...(c.end ? { end: c.end } : {}), ...('resourceId' in c ? { resourceId: c.resourceId ?? null } : {}) }
62
+ )
63
+ );
64
+ };
65
+ const onCreate = (r: CreateRequest) =>
66
+ setBookings((list) => [...list, { id: `new-${list.length + 1}`, name: 'New shift', start: r.start, end: r.end, resourceId: r.resourceId }]);
67
+
68
+ return (
69
+ <div style={{ height: 600 }}>
70
+ <Scheduler
71
+ preset="people"
72
+ title="Team rosters"
73
+ resources={resources}
74
+ bookings={bookings}
75
+ onBookingChange={onBookingChange}
76
+ onCreate={onCreate}
77
+ licenseKey={licenseKey}
78
+ tenantId={tenantId}
79
+ />
80
+ </div>
81
+ );
82
+ }
83
+ ```
84
+
85
+ - **Times** are instants: UTC milliseconds or ISO date-times with `Z` or an offset. Changes come back as ISO UTC strings. They're shown in `timeZone`, which defaults to the browser's. Pass `ianaZone('Europe/London')` or `fixedZone(minutes)` to pin one.
86
+ - **Unassigned work** is any booking with `resourceId: null`. It's listed in the Unassigned panel and can be dragged onto a row.
87
+ - **`preset`** (`people`, `rooms`, `vehicles`, `equipment`, `jobs`) sets the labels, default view, snapping, overlap rule and working hours. Every one can be overridden with its own prop.
88
+ - **`onRangeChange`** reports the dates on screen, so you can load just that window.
89
+
90
+ ## Licence
91
+
92
+ Ninth Forge Plan is a paid product. Without a key, everything works, with a small "Unlicensed" badge in the corner. Pass your Plan key as `licenseKey` and your Microsoft Entra tenant ID as `tenantId`. The check is offline. Trials and keys: [ninthforge.com](https://ninthforge.com).
93
+
94
+ See `LICENSE.md` for the terms.