@umriss-ui/schedule 0.4.0 → 0.5.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/CHANGELOG.md +67 -0
- package/README.md +17 -8
- package/dist/index.d.ts +64 -37
- package/dist/schedule.js +1541 -1476
- package/docs/llms-full.md +684 -334
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,73 @@ moves from here under the rule above.
|
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
+
## 0.5.1 – Charts 0.12.0 (Oct. 2026)
|
|
19
|
+
|
|
20
|
+
Needs `@umriss-ui/charts` 0.12; the peer range moves to `^0.12.0`. Nothing else changes for a caller.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 0.5.0 – Declared through useSchedule, with a view of its own (Oct. 2026)
|
|
25
|
+
|
|
26
|
+
Released together with `@umriss-ui/charts` and `@umriss-ui/table`, which
|
|
27
|
+
break in the same release. A schedule is declared through `useSchedule`, as a
|
|
28
|
+
table is through `useTable` and a chart through `useChart` (ADR-0048), and it
|
|
29
|
+
holds its own **view** - the span in view and the folded lane groups -, taken
|
|
30
|
+
as a start and reported whole (ADR-0047). The free components and the
|
|
31
|
+
controlled pairs are removed, not deprecated.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
**Moving over.** Every export and prop that went, and what stands in its
|
|
36
|
+
place:
|
|
37
|
+
|
|
38
|
+
| Was | Is |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `import { Schedule, Lane, LaneGroup, Subtasks, Dependencies, BlockedTimes }` | `const { Schedule, Lane, … } = useSchedule()` - one `Schedule` per call; a ref on it still gives the `ScheduleHandle` |
|
|
41
|
+
| `Schedule initialDomain` (required) | `useSchedule({ initialView: { domain } })`; without a span the schedule shows the extent of its subtasks |
|
|
42
|
+
| `Schedule collapsedGroups` (controlled) | `view.folded`, and `toggleGroup`, `foldAll`, `unfoldAll` from `useSchedule`; or a new `initialView: { folded }` |
|
|
43
|
+
| `Schedule defaultCollapsedGroups` | `useSchedule({ initialView: { folded } })` |
|
|
44
|
+
| `Schedule onCollapsedGroupsChange` | `useSchedule({ onViewChange })`, `view.folded` |
|
|
45
|
+
| `Schedule onDomainChange` | `useSchedule({ onViewChange })`, `view.domain` |
|
|
46
|
+
|
|
47
|
+
- **`Schedule` and its parts are no exports of their own.** `useSchedule()`
|
|
48
|
+
hands them out; they keep their identity over every render. Their props
|
|
49
|
+
stay public types.
|
|
50
|
+
- **A span is optional.** `initialDomain` was required; without a `domain`
|
|
51
|
+
in the view the schedule shows the extent of its subtasks, lead-in and
|
|
52
|
+
lead-out included, widened or narrowed around its middle into
|
|
53
|
+
`zoomLimits` - fitted once, not after every change of the data, so a
|
|
54
|
+
dragged bar does not make the plan jump; without subtasks the local day of
|
|
55
|
+
today.
|
|
56
|
+
- **A view handed in applies by its content.** `initialDomain` went back to
|
|
57
|
+
a new pair of values; `initialView` applies whenever it differs in content
|
|
58
|
+
from the last one handed in - the folded groups compared as a set -, the
|
|
59
|
+
same view again changes nothing, and what it leaves out is reset. A group
|
|
60
|
+
id no group carries falls out. **A known limit:** a view handed in that
|
|
61
|
+
equals one the schedule reported less than a second ago, and that has not
|
|
62
|
+
come back yet, is taken for the schedule's own report coming back late and
|
|
63
|
+
is not applied - so that linked schedules do not jump back mid-pan. An
|
|
64
|
+
application that restores a just-reported view within that second sees no
|
|
65
|
+
change.
|
|
66
|
+
- **One report for both.** `onViewChange(view)` replaces
|
|
67
|
+
`onDomainChange` and `onCollapsedGroupsChange`: every change once, always
|
|
68
|
+
the whole view, a pan or zoom at most once per frame, not the view the
|
|
69
|
+
schedule starts with. `selectedTask` and `onSelectedTaskChange` are a
|
|
70
|
+
selection, not the view, and stay as they are; so does `zoomLimits`.
|
|
71
|
+
|
|
72
|
+
### Added
|
|
73
|
+
|
|
74
|
+
- **`useSchedule({ initialView, onViewChange })`** with `view`,
|
|
75
|
+
`setDomain(span | null)` (`null` = the subtasks' extent), `toggleGroup(id)`,
|
|
76
|
+
`foldAll()` and `unfoldAll()` on what it hands back.
|
|
77
|
+
- **Types**: `ScheduleParts`, `ScheduleOptions`, `ScheduleView`.
|
|
78
|
+
- **The demo** has a page 'View' (keep a view across a reload and restore
|
|
79
|
+
it); 'Linked schedules' keep in step through a shared view, and Lane
|
|
80
|
+
groups' "Fold groups from outside" folds through the setters, at the
|
|
81
|
+
anchor `#fold-from-outside` - the old `#controlled` lands there.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
18
85
|
## 0.4.0 – Every export explained, and lane counts in every language (Oct. 2026)
|
|
19
86
|
|
|
20
87
|
The package explains itself where it is used: every export carries a comment,
|
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ the working calendar, the canvas colour resolution — from charts. React 18 or
|
|
|
24
24
|
## The smallest schedule that runs
|
|
25
25
|
|
|
26
26
|
```tsx
|
|
27
|
-
import {
|
|
27
|
+
import { useSchedule } from "@umriss-ui/schedule";
|
|
28
28
|
import type { Subtask, Task, Dependency } from "@umriss-ui/schedule";
|
|
29
29
|
|
|
30
30
|
const at = (h: number, m = 0) => new Date(2026, 2, 17, h, m).getTime();
|
|
@@ -37,8 +37,9 @@ const subtasks: Subtask[] = [
|
|
|
37
37
|
const dependencies: Dependency[] = [{ id: "move", from: "cut", to: "mill", lag: 15 * 60_000 }];
|
|
38
38
|
|
|
39
39
|
export function Plan() {
|
|
40
|
+
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(5), at(12)] } });
|
|
40
41
|
return (
|
|
41
|
-
<Schedule ariaLabel="Plan of Tuesday"
|
|
42
|
+
<Schedule ariaLabel="Plan of Tuesday">
|
|
42
43
|
<Lane id="saw" label="Saw" />
|
|
43
44
|
<Lane id="mill" label="Mill" />
|
|
44
45
|
<Dependencies data={dependencies} />
|
|
@@ -115,9 +116,8 @@ reported for it, and no intent names it (ADR-0025).
|
|
|
115
116
|
Folded, a group becomes one row showing a **miniature** — every lane in it as a
|
|
116
117
|
thin strip, the real work smaller. Dependencies still arrive at the right strip,
|
|
117
118
|
findings are still marked, and a strip can still be hovered and selected:
|
|
118
|
-
folding costs a planner detail and never access.
|
|
119
|
-
|
|
120
|
-
application's hands; it is a view state, never an intent.
|
|
119
|
+
folding costs a planner detail and never access. Which groups are folded is
|
|
120
|
+
part of the schedule's view, never an intent.
|
|
121
121
|
|
|
122
122
|
## Reading and moving
|
|
123
123
|
|
|
@@ -127,9 +127,18 @@ off. `now` draws the present across the lanes. The wheel over the schedule,
|
|
|
127
127
|
lane headers included, scrolls the lanes and releases the page at their end,
|
|
128
128
|
Ctrl or ⌘ and a pinch zoom, Shift pans; on a touch screen one finger pans and a
|
|
129
129
|
tap selects. The lane headers take at most 40 % of the width, so that on a
|
|
130
|
-
phone the plot keeps the larger part;
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
phone the plot keeps the larger part; a ref handle turns a client point into a
|
|
131
|
+
time and a lane and back.
|
|
132
|
+
|
|
133
|
+
## The view
|
|
134
|
+
|
|
135
|
+
The schedule holds its own view (ADR-0047): the span in view and the folded
|
|
136
|
+
groups. `useSchedule({ initialView, onViewChange })` takes a start and reports
|
|
137
|
+
every change, always the whole view; a view handed in that differs from the
|
|
138
|
+
last one applies at once, so two schedules keep in step by handing each other
|
|
139
|
+
what they report. Without a span the schedule shows the extent of its subtasks.
|
|
140
|
+
`view`, `setDomain`, `toggleGroup`, `foldAll` and `unfoldAll` stand on what the
|
|
141
|
+
hook hands back.
|
|
133
142
|
|
|
134
143
|
## Blocked time
|
|
135
144
|
|
package/dist/index.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export declare interface BlockedTime {
|
|
|
35
35
|
|
|
36
36
|
/** A layer of blocked time. Wherever it is declared, it is drawn behind every
|
|
37
37
|
subtask and dependency: it is a property of the lane, not something on it. */
|
|
38
|
-
|
|
38
|
+
declare function BlockedTimes({ data }: BlockedTimesProps): null;
|
|
39
39
|
|
|
40
40
|
/** The props of `BlockedTimes`. */
|
|
41
41
|
export declare interface BlockedTimesProps {
|
|
@@ -49,7 +49,7 @@ export declare function departure(dependency: Dependency, from: Subtask): number
|
|
|
49
49
|
|
|
50
50
|
/** A layer of dependencies. Declared before `Subtasks`, the lines run beneath the
|
|
51
51
|
bars; after them, above. */
|
|
52
|
-
|
|
52
|
+
declare function Dependencies({ data }: DependenciesProps): null;
|
|
53
53
|
|
|
54
54
|
/** The props of `Dependencies`. */
|
|
55
55
|
export declare interface DependenciesProps {
|
|
@@ -148,20 +148,20 @@ export declare type IntentKind = Intent["kind"];
|
|
|
148
148
|
|
|
149
149
|
/** One lane: a person, a vehicle, a room. The lanes run top to bottom in the order
|
|
150
150
|
they are declared - whichever group they are declared in. */
|
|
151
|
-
|
|
151
|
+
declare function Lane({ id, label }: LaneProps): null;
|
|
152
152
|
|
|
153
153
|
/** A group of lanes: structure over them, and never a lane itself.
|
|
154
154
|
|
|
155
155
|
It gives its id to its children through context, so a lane never names its
|
|
156
156
|
group and a group reads in JSX as it reads in the organisation. Folded, it becomes
|
|
157
157
|
one row showing a **Miniature** of everything in it; open, it shows a slim
|
|
158
|
-
head above its lanes. Which groups are folded is
|
|
159
|
-
`
|
|
160
|
-
|
|
158
|
+
head above its lanes. Which groups are folded is part of the schedule's
|
|
159
|
+
view (`useSchedule`) - never an **Intent**. */
|
|
160
|
+
declare function LaneGroup({ id, label, children }: LaneGroupProps): ReactNode;
|
|
161
161
|
|
|
162
162
|
/** The props of `LaneGroup`. */
|
|
163
163
|
export declare interface LaneGroupProps {
|
|
164
|
-
/** The group's identity - what `
|
|
164
|
+
/** The group's identity - what the view's `folded` names. It is never a lane:
|
|
165
165
|
no subtask sits on it, no finding is reported for it, and no intent names
|
|
166
166
|
it (ADR-0025). */
|
|
167
167
|
id: string;
|
|
@@ -319,14 +319,6 @@ export declare interface ResolvedAppearance {
|
|
|
319
319
|
bounded number of pushes instead of running on. */
|
|
320
320
|
export declare function ripple(subtasks: readonly Subtask[], dependencies: readonly Dependency[], intent: Intent): MoveIntent[];
|
|
321
321
|
|
|
322
|
-
/** A plan of subtasks on lanes over time - people, vehicles, rooms - with
|
|
323
|
-
dependencies between them. The contents are declared as children (`Lane`,
|
|
324
|
-
`LaneGroup`, `Subtasks`, `Dependencies`, `BlockedTimes`); the planner pans,
|
|
325
|
-
zooms and drags, and every drag ends as an **Intent** through `onIntent`.
|
|
326
|
-
The data changes only where the caller applies it; without `intents` the
|
|
327
|
-
schedule is read-only. A ref gives the `ScheduleHandle`. */
|
|
328
|
-
export declare const Schedule: ForwardRefExoticComponent<ScheduleProps & RefAttributes<ScheduleHandle>>;
|
|
329
|
-
|
|
330
322
|
/** What a schedule offers a caller imperatively: the arithmetic between a
|
|
331
323
|
point on the screen and a time on a lane. Everything else is props. */
|
|
332
324
|
export declare interface ScheduleHandle {
|
|
@@ -377,13 +369,49 @@ export declare interface ScheduleInteraction {
|
|
|
377
369
|
readonly lane: string | null;
|
|
378
370
|
}
|
|
379
371
|
|
|
372
|
+
/** What `useSchedule` takes: the view to start from and the handler that
|
|
373
|
+
hears every change of it. */
|
|
374
|
+
export declare interface ScheduleOptions {
|
|
375
|
+
/** The view to start from, and to go to whenever one differing in content
|
|
376
|
+
from the last is handed in - the same view again changes nothing, and
|
|
377
|
+
what it leaves out is reset; one the schedule reported itself, handed
|
|
378
|
+
back late, is its own state coming back and not gone to. The schedule
|
|
379
|
+
remembers none: where a view is kept is the application's decision. */
|
|
380
|
+
initialView?: ScheduleView;
|
|
381
|
+
/** Every change of the view, once, always the whole view - the one to keep,
|
|
382
|
+
or to hand another schedule as its `initialView`. A pan or zoom is
|
|
383
|
+
reported at most once per frame. Not called for the view the schedule
|
|
384
|
+
starts with. */
|
|
385
|
+
onViewChange?: (view: ScheduleView) => void;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** What `useSchedule` hands back: the schedule and what is declared inside
|
|
389
|
+
it, its view and the setters that change it. */
|
|
390
|
+
export declare interface ScheduleParts {
|
|
391
|
+
/** The schedule. One per `useSchedule`: a second schedule is a second call. */
|
|
392
|
+
Schedule: ForwardRefExoticComponent<ScheduleProps & RefAttributes<ScheduleHandle>>;
|
|
393
|
+
Lane: typeof Lane;
|
|
394
|
+
LaneGroup: typeof LaneGroup;
|
|
395
|
+
Subtasks: typeof Subtasks;
|
|
396
|
+
Dependencies: typeof Dependencies;
|
|
397
|
+
BlockedTimes: typeof BlockedTimes;
|
|
398
|
+
/** How the planner is looking at the plan: the span and the folded groups. */
|
|
399
|
+
view: ScheduleView;
|
|
400
|
+
/** Puts a span of two wall-clock instants in view; `null` shows the
|
|
401
|
+
subtasks' extent. */
|
|
402
|
+
setDomain: (span: readonly [number, number] | null) => void;
|
|
403
|
+
/** Folds or unfolds one **Lane group**. */
|
|
404
|
+
toggleGroup: (id: string) => void;
|
|
405
|
+
/** Folds every group. */
|
|
406
|
+
foldAll: () => void;
|
|
407
|
+
/** Unfolds every group. */
|
|
408
|
+
unfoldAll: () => void;
|
|
409
|
+
}
|
|
410
|
+
|
|
380
411
|
/** The props of `Schedule`. */
|
|
381
412
|
export declare interface ScheduleProps {
|
|
382
413
|
/** What the schedule shows, for a screen reader: "Plan of week 38". */
|
|
383
414
|
ariaLabel: string;
|
|
384
|
-
/** The time in view when the schedule mounts, as two wall-clock instants.
|
|
385
|
-
Pan and zoom take it from there; a new pair of values puts it back. */
|
|
386
|
-
initialDomain: readonly [number, number];
|
|
387
415
|
/** Height in CSS pixels, both bands included. The width is the host's.
|
|
388
416
|
@default 400 */
|
|
389
417
|
height?: number;
|
|
@@ -440,24 +468,6 @@ export declare interface ScheduleProps {
|
|
|
440
468
|
nothing. It is called again when another subtask of the same task is
|
|
441
469
|
clicked. */
|
|
442
470
|
onSelectedTaskChange?: (task: string | null, subtask: string | null) => void;
|
|
443
|
-
/** The **Lane group**s that are folded, controlled. Leave it out and the
|
|
444
|
-
schedule keeps them itself, starting from `defaultCollapsedGroups`.
|
|
445
|
-
|
|
446
|
-
Folding changes the view and not the plan, which is why it is no intent:
|
|
447
|
-
a caller that applies every intent it receives must never find a fold
|
|
448
|
-
among them (ADR-0025). A folded outer group hides the inner ones without
|
|
449
|
-
their entries leaving the list, so unfolding it gives back the view that
|
|
450
|
-
was there. */
|
|
451
|
-
collapsedGroups?: readonly string[];
|
|
452
|
-
/** Which groups are folded when the schedule mounts, where the schedule
|
|
453
|
-
keeps the state itself. Ignored while `collapsedGroups` is given. */
|
|
454
|
-
defaultCollapsedGroups?: readonly string[];
|
|
455
|
-
/** Called with the whole list when the planner folds or unfolds a group. */
|
|
456
|
-
onCollapsedGroupsChange?: (groups: readonly string[]) => void;
|
|
457
|
-
/** The visible time span after the planner panned or zoomed, as two
|
|
458
|
-
wall-clock instants - for keeping a second schedule or a chart in step. A
|
|
459
|
-
span handed in through `initialDomain` is not reported back. */
|
|
460
|
-
onDomainChange?: (domain: readonly [number, number]) => void;
|
|
461
471
|
/** What the application is dragging in from outside while it drags it - its
|
|
462
472
|
key, task, the length of its main time, its lead-in and lead-out. The
|
|
463
473
|
browser hands the dragged data over only on the drop, so the ghost before
|
|
@@ -536,6 +546,17 @@ export declare type ScheduleTooltipTarget = {
|
|
|
536
546
|
readonly violated: ViolatedDependency | undefined;
|
|
537
547
|
};
|
|
538
548
|
|
|
549
|
+
/** How a planner is looking at the plan. Whatever is at its default is absent. */
|
|
550
|
+
export declare interface ScheduleView {
|
|
551
|
+
/** The span in view, as two wall-clock instants. Absent, the schedule shows
|
|
552
|
+
the extent of its subtasks, within `zoomLimits`. */
|
|
553
|
+
domain?: readonly [number, number];
|
|
554
|
+
/** The **Lane group**s that are folded, by id. An id no group carries falls
|
|
555
|
+
out. A folded outer group hides the inner ones without their ids leaving
|
|
556
|
+
the list, so unfolding it gives back the view that was there. */
|
|
557
|
+
folded?: readonly string[];
|
|
558
|
+
}
|
|
559
|
+
|
|
539
560
|
/** The moves that carry a whole task in time - every subtask of it by the same
|
|
540
561
|
amount, so that its lengths and the distances between its stops stay as
|
|
541
562
|
they were. The schedule never runs it: apply the moves like any other
|
|
@@ -608,7 +629,7 @@ export declare type SubtaskAppearance = "provisional" | "fixed" | "muted" | "ope
|
|
|
608
629
|
export declare function subtaskFromPlace(intent: PlaceIntent, id: string): Subtask;
|
|
609
630
|
|
|
610
631
|
/** A layer of subtasks. Several layers draw in the order they are declared. */
|
|
611
|
-
|
|
632
|
+
declare function Subtasks({ data, tasks }: SubtasksProps): null;
|
|
612
633
|
|
|
613
634
|
/** The props of `Subtasks`. */
|
|
614
635
|
export declare interface SubtasksProps {
|
|
@@ -631,6 +652,12 @@ export declare interface Task {
|
|
|
631
652
|
readonly name?: string;
|
|
632
653
|
}
|
|
633
654
|
|
|
655
|
+
/** Declares a schedule: hands back `Schedule` and the parts declared inside it
|
|
656
|
+
- `Lane`, `LaneGroup`, `Subtasks`, `Dependencies`, `BlockedTimes` -, its
|
|
657
|
+
`view` and the setters `setDomain`, `toggleGroup`, `foldAll` and
|
|
658
|
+
`unfoldAll`. A ref on `Schedule` still gives the `ScheduleHandle`. */
|
|
659
|
+
export declare function useSchedule(options?: ScheduleOptions): ScheduleParts;
|
|
660
|
+
|
|
634
661
|
/** Every dependency whose successor is to be reached before the predecessor's
|
|
635
662
|
departure plus the dependency's lag. A dependency naming a subtask that
|
|
636
663
|
is not in the data is passed over: there is nothing to judge. */
|