@umriss-ui/schedule 0.34.0 → 0.35.0

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/docs/llms-full.md CHANGED
@@ -1,4 +1,4 @@
1
- # @umriss-ui/schedule 0.34.0
1
+ # @umriss-ui/schedule 0.35.0
2
2
 
3
3
  > React Gantt-style schedule for data-dense applications - work on lanes over time, with dependencies, blocked time, findings and controlled editing.
4
4
 
@@ -915,7 +915,7 @@ npm install @umriss-ui/schedule @umriss-ui/core @umriss-ui/charts
915
915
 
916
916
  Demo page: https://romanhaendler.github.io/umriss-ui/schedule/installation/
917
917
 
918
- The command brings its two peers along: core for the formats and the wording, charts for the time scale and the operating calendar ([ADR-0022](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0022-the-schedule-is-a-package-that-depends-on-core-and-charts.md)). React 18 or 19 is a peer as well and stays the application's own. The stylesheets load themselves - each package's script imports its own, so there is nothing to import by hand; `@umriss-ui/schedule/styles.css` stays exported for setups that link stylesheets themselves.
918
+ The command brings its two peers along: core for the formats and the wording, charts for the time scale and the operating calendar ([ADR-0022](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0022-the-schedule-is-a-package-that-depends-on-core-and-charts.md)). React 19 or newer is a peer as well and stays the application's own. The stylesheets load themselves - each package's script imports its own, so there is nothing to import by hand; `@umriss-ui/schedule/styles.css` stays exported for setups that link stylesheets themselves.
919
919
 
920
920
  The plan is plain data ([ADR-0023](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0023-editing-is-controlled-the-schedule-reports-intents.md)). A lane is a person, a vehicle or a room, declared in JSX by its id. A task is an id, a colour and a name; a subtask is a main time on one lane, belonging to a task, with an optional lead-in and lead-out; a dependency joins two subtasks of one task with a lag. Times are epoch milliseconds.
921
921
 
@@ -1278,8 +1278,9 @@ Under forced colours the plot paints itself in the system colours: the work in t
1278
1278
 
1279
1279
  | Prop | Type | Default | Description |
1280
1280
  |---|---|---|---|
1281
- | `height` | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's.<br>Shown in: [A day of tours](#/schedule/first-schedule), [Start from an empty plan](#/schedule/no-work-yet), [Plan a day in the machine shop](#/schedule/machine-plan) and 77 more |
1282
- | `laneHeight` | `number` | `44` | Height of one lane in pixels.<br>Shown in: [Scroll more lanes than fit (Lanes)](#/lane/many-lanes) |
1281
+ | `ref` | `Ref<`[`ScheduleHandle`](#type-ScheduleHandle)`>` | — | Receives the `ScheduleHandle` - not an element.<br>Shown in: [Place a mark of your own (The handle)](#/handle/place-a-mark) |
1282
+ | `height` | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's.<br>Shown in: [A day of tours](#/schedule/first-schedule), [Start from an empty plan](#/schedule/no-work-yet), [Plan a day in the machine shop](#/schedule/machine-plan) and 78 more |
1283
+ | `laneHeight` | `number` | `44` | Height of one lane in pixels.<br>Shown in: [Scroll more lanes than fit (Lanes)](#/lane/many-lanes), [Measure a plan (Benchmark)](#/benchmark/benchmark) |
1283
1284
  | `headerWidth` | `number` | `160` | Width of the lane headers in pixels - at most 40 % of the schedule, so that on a phone the plot keeps the larger part.<br>Shown in: [What a lane header says (Lanes)](#/lane/lane-headers), [Scroll more lanes than fit (Lanes)](#/lane/many-lanes), [Group lanes under a head (Lane groups)](#/lane-groups/a-group) and 1 more |
1284
1285
  | `calendar` | [`CalendarInput`](#type-CalendarInput) | `[]` | A working calendar: the intervals in which time counts. Nights and weekends outside them are cut out of the axis. Without intervals every hour counts, as on the wall clock.<br>Shown in: [Cut the nights out of the axis (Time axis and calendar)](#/time-axis/working-calendar), [Plan in office hours only (Time axis and calendar)](#/time-axis/office-hours), [Plan the sprint around leave (Scenarios)](#/scenarios/plan-the-sprint-around-leave) |
1285
1286
  | `zoomLimits` | [`ZoomLimits`](#type-ZoomLimits) | one hour to 28 days | The narrowest and widest time span zoom may reach, in milliseconds.<br>Shown in: [Move through the plan (Pan and zoom)](#/pan-and-zoom/pan-and-zoom) |
@@ -1295,20 +1296,20 @@ Under forced colours the plot paints itself in the system colours: the work in t
1295
1296
  | `label` | `(subtask: `[`Subtask`](#/subtasks/type-Subtask)`) => string` | — | What stands written in a bar: a function from a subtask to a line of text, or nothing for bars without text. The text is cut off with an ellipsis where the bar is too narrow for it and left out where even that would say nothing; a bar that began before the view keeps its text at the view's edge.<br>Shown in: [Plan a day in the machine shop](#/schedule/machine-plan), [Plan a sprint for a team (Subtasks)](#/subtasks/a-sprint), [Write into the bars (Bar labels)](#/bar-labels/bar-labels) and 7 more |
1296
1297
  | `tooltip` | `false \| ((target: `[`ScheduleTooltipTarget`](#/tooltip/type-ScheduleTooltipTarget)`) => ReactNode)` | — | The tooltip on a hovered subtask or dependency: its order, its times, its parts and its findings. `false` switches it off; a function receives what the pointer rests on and returns content of the application's own.<br>Shown in: [Say what a milestone is in your own tooltip (Milestones)](#/milestones/say-what-a-milestone-is), [Write your own tooltip content (Tooltip)](#/tooltip/own-tooltip), [Show a detail panel instead (Tooltip)](#/tooltip/detail-panel-instead) and 1 more |
1297
1298
  | `now` | `boolean \| number` | `false` | A line marking the present across the lanes: `true` follows the clock by the minute, an instant fixes it there.<br>Shown in: [Plan a day in the machine shop](#/schedule/machine-plan), [Mark the present (Now line)](#/now-line/now-line), [Follow the clock (Now line)](#/now-line/follow-the-clock) and 2 more |
1298
- | `children` | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn.<br>Shown in: [A day of tours](#/schedule/first-schedule), [Start from an empty plan](#/schedule/no-work-yet), [Plan a day in the machine shop](#/schedule/machine-plan) and 77 more |
1299
+ | `children` | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn.<br>Shown in: [A day of tours](#/schedule/first-schedule), [Start from an empty plan](#/schedule/no-work-yet), [Plan a day in the machine shop](#/schedule/machine-plan) and 78 more |
1299
1300
 
1300
1301
  ###### Events
1301
1302
 
1302
1303
  | Prop | Type | Default | Description |
1303
1304
  |---|---|---|---|
1304
1305
  | `onIntent` | `(intent: `[`Intent`](#type-Intent)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it.<br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Cut the nights out of the axis (Time axis and calendar)](#/time-axis/working-calendar), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around) and 18 more |
1305
- | `onInteraction` | `(interaction: `[`ScheduleInteraction`](#/interactions/type-ScheduleInteraction)`) => void` | — | Click, context menu and hover, with what the pointer is on and where. While it is set, a right-click opens no browser menu.<br>Shown in: [Report what the pointer is on (Interactions)](#/interactions/report-the-pointer), [Open a context menu (Interactions)](#/interactions/open-a-context-menu), [Show a detail panel instead (Tooltip)](#/tooltip/detail-panel-instead) and 2 more |
1306
+ | `onInteraction` | `(interaction: `[`ScheduleInteraction`](#/interactions/type-ScheduleInteraction)`) => void` | — | Click, context menu and hover, with what the pointer is on and where. While it is set, a right-click opens no browser menu.<br>Shown in: [Report what the pointer is on (Interactions)](#/interactions/report-the-pointer), [Open a context menu (Interactions)](#/interactions/open-a-context-menu), [Show a detail panel instead (Tooltip)](#/tooltip/detail-panel-instead) and 3 more |
1306
1307
 
1307
1308
  ###### Accessibility
1308
1309
 
1309
1310
  | Prop | Type | Default | Description |
1310
1311
  |---|---|---|---|
1311
- | `ariaLabel` *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38".<br>Shown in: [A day of tours](#/schedule/first-schedule), [Start from an empty plan](#/schedule/no-work-yet), [Plan a day in the machine shop](#/schedule/machine-plan) and 77 more |
1312
+ | `ariaLabel` *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38".<br>Shown in: [A day of tours](#/schedule/first-schedule), [Start from an empty plan](#/schedule/no-work-yet), [Plan a day in the machine shop](#/schedule/machine-plan) and 78 more |
1312
1313
 
1313
1314
  ###### Styling
1314
1315
 
@@ -1319,6 +1320,17 @@ Under forced colours the plot paints itself in the system colours: the work in t
1319
1320
 
1320
1321
  ##### Types on this page
1321
1322
 
1323
+ ###### `ScheduleHandle`
1324
+
1325
+ What a schedule offers a caller imperatively: the arithmetic between a
1326
+ point on the screen and a time on a lane. Everything else is props.
1327
+
1328
+ | Prop | Type | Default | Description |
1329
+ |---|---|---|---|
1330
+ | `positionAt` *required* | `(clientX: number, clientY: number) => { time: number; lane: string \| null } \| null` | — | The time and the lane at a client point, or null outside the plot.<br>Shown in: [Place a mark of your own (The handle)](#/handle/place-a-mark) |
1331
+ | `clientPointOf` *required* | `(time: number, lane?: string) => { x: number; y: number } \| null` | — | The client point of a time - on the middle of a lane where one is named - or null while the schedule is not on screen.<br>Shown in: [Place a mark of your own (The handle)](#/handle/place-a-mark) |
1332
+ | `visibleDomain` *required* | `() => readonly [number, number]` | — | The visible span, as two wall-clock instants. |
1333
+
1322
1334
  ###### `CalendarInput`
1323
1335
 
1324
1336
  From `@umriss-ui/charts`.
@@ -1654,7 +1666,7 @@ The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
1654
1666
 
1655
1667
  | Prop | Type | Default | Description |
1656
1668
  |---|---|---|---|
1657
- | `id` *required* | `string` | — | The identity subtasks name in their `lane`.<br>Shown in: [What a lane header says](#/lane/lane-headers), [Scroll more lanes than fit](#/lane/many-lanes), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 77 more |
1669
+ | `id` *required* | `string` | — | The identity subtasks name in their `lane`.<br>Shown in: [What a lane header says](#/lane/lane-headers), [Scroll more lanes than fit](#/lane/many-lanes), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 78 more |
1658
1670
  | `label` | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader.<br>Shown in: [What a lane header says](#/lane/lane-headers), [Scroll more lanes than fit](#/lane/many-lanes), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 77 more |
1659
1671
 
1660
1672
  ### Lane groups
@@ -2167,21 +2179,21 @@ The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
2167
2179
 
2168
2180
  | Prop | Type | Default | Description |
2169
2181
  |---|---|---|---|
2170
- | `data` *required* | `readonly `[`Subtask`](#type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [Plan a sprint for a team](#/subtasks/a-sprint) and 77 more |
2171
- | `tasks` *required* | `readonly `[`Task`](#type-Task)`[]` | — | The tasks the subtasks belong to - their identity and their colour. A subtask whose task is not among them is drawn in a muted colour.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [Plan a sprint for a team](#/subtasks/a-sprint) and 77 more |
2182
+ | `data` *required* | `readonly `[`Subtask`](#type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [Plan a sprint for a team](#/subtasks/a-sprint) and 78 more |
2183
+ | `tasks` *required* | `readonly `[`Task`](#type-Task)`[]` | — | The tasks the subtasks belong to - their identity and their colour. A subtask whose task is not among them is drawn in a muted colour.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [Plan a sprint for a team](#/subtasks/a-sprint) and 78 more |
2172
2184
 
2173
2185
  ##### `Subtask`
2174
2186
 
2175
2187
  | Prop | Type | Default | Description |
2176
2188
  |---|---|---|---|
2177
- | `id` *required* | `string` | — | The caller's identity of the subtask.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [Plan a sprint for a team](#/subtasks/a-sprint) and 74 more |
2178
- | `task` *required* | `string` | — | The id of the task it belongs to.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 70 more |
2179
- | `lane` *required* | `string` | — | The id of the lane it sits on.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 70 more |
2180
- | `from` *required* | `number` | — | Start of the main time.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 70 more |
2181
- | `to` *required* | `number` | — | End of the main time.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 70 more |
2189
+ | `id` *required* | `string` | — | The caller's identity of the subtask.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [Plan a sprint for a team](#/subtasks/a-sprint) and 75 more |
2190
+ | `task` *required* | `string` | — | The id of the task it belongs to.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 71 more |
2191
+ | `lane` *required* | `string` | — | The id of the lane it sits on.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 71 more |
2192
+ | `from` *required* | `number` | — | Start of the main time.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 71 more |
2193
+ | `to` *required* | `number` | — | End of the main time.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 71 more |
2182
2194
  | `leadIn` | `number` | — | Duration of the lead-in before the main time; none is zero.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule) and 25 more |
2183
2195
  | `leadOut` | `number` | — | Duration of the lead-out after the main time; none is zero.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule) and 22 more |
2184
- | `name` | `string` | — | What the subtask is called, where the schedule names it.<br>Shown in: [Plan a sprint for a team](#/subtasks/a-sprint), [Write into the bars (Bar labels)](#/bar-labels/bar-labels), [Join the stops of a tour (Dependencies)](#/dependencies/stops-of-a-tour) and 27 more |
2196
+ | `name` | `string` | — | What the subtask is called, where the schedule names it.<br>Shown in: [Plan a sprint for a team](#/subtasks/a-sprint), [Write into the bars (Bar labels)](#/bar-labels/bar-labels), [Join the stops of a tour (Dependencies)](#/dependencies/stops-of-a-tour) and 28 more |
2185
2197
  | `appearance` | `readonly `[`SubtaskAppearance`](#type-SubtaskAppearance)`[]` | — | What the bar says besides its colour: `"provisional"`, `"fixed"`, `"muted"`, `"open"`. Several hold at once; `"provisional"` and `"fixed"` contradict, and the later one in the list wins.<br>Shown in: [Plan a sprint for a team](#/subtasks/a-sprint), [Provisional (Appearances)](#/appearances/provisional), [Fixed (Appearances)](#/appearances/fixed) and 3 more |
2186
2198
  | `progress` | `number` | — | The share of the work that is done, from 0 to 1, drawn as a filled part of the bar. Without it nothing is claimed - an empty bar and a bar at zero per cent are two different statements.<br>Shown in: [Progress (Appearances)](#/appearances/progress), [Several at once (Appearances)](#/appearances/combinations) |
2187
2199
 
@@ -2189,9 +2201,9 @@ The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
2189
2201
 
2190
2202
  | Prop | Type | Default | Description |
2191
2203
  |---|---|---|---|
2192
- | `id` *required* | `string` | — | The caller's identity of the task.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 69 more |
2193
- | `color` *required* | `string` | — | Any CSS colour - a literal, a token, `light-dark(…)`. The colour means what the caller's domain needs it to mean.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 69 more |
2194
- | `name` | `string` | — | What the task is called, where the schedule names it.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 69 more |
2204
+ | `id` *required* | `string` | — | The caller's identity of the task.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 70 more |
2205
+ | `color` *required* | `string` | — | Any CSS colour - a literal, a token, `light-dark(…)`. The colour means what the caller's domain needs it to mean.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 70 more |
2206
+ | `name` | `string` | — | What the task is called, where the schedule names it.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 70 more |
2195
2207
 
2196
2208
  ##### Types on this page
2197
2209
 
@@ -3156,16 +3168,16 @@ The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
3156
3168
 
3157
3169
  | Prop | Type | Default | Description |
3158
3170
  |---|---|---|---|
3159
- | `data` *required* | `readonly `[`Dependency`](#type-Dependency)`[]` | — | The dependencies, as the caller holds them.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 27 more |
3171
+ | `data` *required* | `readonly `[`Dependency`](#type-Dependency)`[]` | — | The dependencies, as the caller holds them.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 28 more |
3160
3172
 
3161
3173
  ##### `Dependency`
3162
3174
 
3163
3175
  | Prop | Type | Default | Description |
3164
3176
  |---|---|---|---|
3165
- | `id` *required* | `string` | — | The caller's identity of the dependency.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 26 more |
3166
- | `from` *required* | `string` | — | The id of the subtask it leaves.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 26 more |
3167
- | `to` *required* | `string` | — | The id of the subtask it arrives at.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 26 more |
3168
- | `lag` *required* | `number` | — | The least time between the two anchors; zero where the successor may begin as soon as the predecessor ends.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 26 more |
3177
+ | `id` *required* | `string` | — | The caller's identity of the dependency.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 27 more |
3178
+ | `from` *required* | `string` | — | The id of the subtask it leaves.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 27 more |
3179
+ | `to` *required* | `string` | — | The id of the subtask it arrives at.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 27 more |
3180
+ | `lag` *required* | `number` | — | The least time between the two anchors; zero where the successor may begin as soon as the predecessor ends.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 27 more |
3169
3181
  | `leaves` | `"main" \| "leadOut"` | `"leadOut"` | Where it leaves: at the end of the main time, or after the lead-out. The predecessor counts as ended once its lead-out is.<br>Shown in: [Choose what a dependency connects](#/dependencies/anchors), [Plan a day in the machine shop (First schedule)](#/schedule/machine-plan), [Replan the day on the line (Scenarios)](#/scenarios/replan-the-day-on-the-line) |
3170
3182
  | `arrives` | `"main" \| "leadIn"` | `"leadIn"` | Where it arrives: at the start of the main time, or before the lead-in. The lag must have run out before the successor's lead-in begins.<br>Shown in: [Choose what a dependency connects](#/dependencies/anchors), [A day of tours (First schedule)](#/schedule/first-schedule), [Plan a day in the machine shop (First schedule)](#/schedule/machine-plan) and 1 more |
3171
3183
  | `route` | [`DependencyRoute`](#type-DependencyRoute)<br>`"curve" \| "straight" \| "orthogonal"` | — | How this one is drawn, where it is not drawn like the rest. It changes the picture and never the finding: whether a dependency is violated follows from `leaves` and `arrives` alone.<br>Shown in: [Per dependency (Routes)](#/routes/per-dependency) |
@@ -5143,7 +5155,7 @@ The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
5143
5155
  | Prop | Type | Default | Description |
5144
5156
  |---|---|---|---|
5145
5157
  | `type` *required* | `"click" \| "contextmenu" \| "hover"` | — | `"hover"` is reported when the target under the pointer changes, not on every movement.<br>Shown in: [Report what the pointer is on](#/interactions/report-the-pointer), [Open a context menu](#/interactions/open-a-context-menu), [Show a detail panel instead (Tooltip)](#/tooltip/detail-panel-instead) and 1 more |
5146
- | `hit` *required* | [`ScheduleHit`](#type-ScheduleHit) | — | What the pointer is on.<br>Shown in: [Report what the pointer is on](#/interactions/report-the-pointer), [Open a context menu](#/interactions/open-a-context-menu), [Show a detail panel instead (Tooltip)](#/tooltip/detail-panel-instead) and 1 more |
5158
+ | `hit` *required* | [`ScheduleHit`](#type-ScheduleHit) | — | What the pointer is on.<br>Shown in: [Report what the pointer is on](#/interactions/report-the-pointer), [Open a context menu](#/interactions/open-a-context-menu), [Show a detail panel instead (Tooltip)](#/tooltip/detail-panel-instead) and 2 more |
5147
5159
  | `clientX` *required* | `number` | — | The pointer's horizontal client coordinate - where a `ContextMenu` opens.<br>Shown in: [Open a context menu](#/interactions/open-a-context-menu), [Place a mark of your own (The handle)](#/handle/place-a-mark), [Replan the day on the line (Scenarios)](#/scenarios/replan-the-day-on-the-line) |
5148
5160
  | `clientY` *required* | `number` | — | The pointer's vertical client coordinate.<br>Shown in: [Open a context menu](#/interactions/open-a-context-menu), [Place a mark of your own (The handle)](#/handle/place-a-mark), [Replan the day on the line (Scenarios)](#/scenarios/replan-the-day-on-the-line) |
5149
5161
  | `time` *required* | `number` | — | The wall-clock instant under the pointer.<br>Shown in: [Report what the pointer is on](#/interactions/report-the-pointer) |
@@ -5676,7 +5688,7 @@ The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
5676
5688
 
5677
5689
  | Prop | Type | Default | Description |
5678
5690
  |---|---|---|---|
5679
- | `initialView` | [`ScheduleView`](#type-ScheduleView) | — | The view to start from, read once when the hook first runs; a different value on a later render is ignored, as React ignores a changed `defaultValue`. To go to a view later, call `setView`. The schedule remembers none: where a view is kept is the application's decision.<br>Shown in: [Keep and restore a view](#/view/keep-and-restore), [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule) and 77 more |
5691
+ | `initialView` | [`ScheduleView`](#type-ScheduleView) | — | The view to start from, read once when the hook first runs; a different value on a later render is ignored, as React ignores a changed `defaultValue`. To go to a view later, call `setView`. The schedule remembers none: where a view is kept is the application's decision.<br>Shown in: [Keep and restore a view](#/view/keep-and-restore), [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule) and 78 more |
5680
5692
 
5681
5693
  ###### Events
5682
5694
 
@@ -5688,7 +5700,7 @@ The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
5688
5700
 
5689
5701
  | Prop | Type | Default | Description |
5690
5702
  |---|---|---|---|
5691
- | `domain` | `readonly [number, number]` | — | The span in view, as two wall-clock instants. Absent, the schedule shows the extent of its subtasks, within `zoomLimits`.<br>Shown in: [Keep and restore a view](#/view/keep-and-restore), [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule) and 76 more |
5703
+ | `domain` | `readonly [number, number]` | — | The span in view, as two wall-clock instants. Absent, the schedule shows the extent of its subtasks, within `zoomLimits`.<br>Shown in: [Keep and restore a view](#/view/keep-and-restore), [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule) and 77 more |
5692
5704
  | `folded` | `readonly string[]` | — | The **Lane group**s that are folded, by id. An id no group carries falls out. A folded outer group hides the inner ones without their ids leaving the list, so unfolding it gives back the view that was there.<br>Shown in: [Fold groups from outside (Lane groups)](#/lane-groups/fold-from-outside), [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Start with groups folded (Lane groups)](#/lane-groups/start-with-groups-folded) |
5693
5705
 
5694
5706
  ### Linked schedules
@@ -6133,6 +6145,7 @@ From `ScheduleProps` — the full table stands on [First schedule](#/schedule/ty
6133
6145
 
6134
6146
  | Prop | Type | Default | Description |
6135
6147
  |---|---|---|---|
6148
+ | [`ref`](#/schedule/ScheduleProps-ref) | `Ref<`[`ScheduleHandle`](#/schedule/type-ScheduleHandle)`>` | — | Receives the `ScheduleHandle` - not an element. |
6136
6149
  | [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
6137
6150
  | [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
6138
6151
 
@@ -8128,6 +8141,419 @@ From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView
8128
8141
 
8129
8142
  What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
8130
8143
 
8144
+ ## Measuring
8145
+
8146
+ What the schedule costs, measured in this browser rather than claimed.
8147
+
8148
+ ### Benchmark
8149
+
8150
+ A plan of up to five thousand subtasks and as many dependencies, measured in this browser: the first render, and the time and frames of a scripted pointer walk, pan and wheel zoom.
8151
+
8152
+ ```ts
8153
+ import { useSchedule } from "@umriss-ui/schedule";
8154
+ ```
8155
+
8156
+ Demo page: https://romanhaendler.github.io/umriss-ui/schedule/benchmark/
8157
+
8158
+ The figures in `packages/schedule/docs/capabilities.md` come from here. The page dispatches the pointer and wheel events itself, on the schedule's canvas, and adds no prop to the schedule.
8159
+
8160
+ #### Examples
8161
+
8162
+ ##### Measure a plan
8163
+
8164
+ Pick a plan size and run the scripted pointer walk, pan and wheel zoom: the times and frame counts say what drawing and moving it cost here.
8165
+
8166
+ ```tsx
8167
+ /* A plan whose size is set by a button, and the figures of what drawing and
8168
+ moving it cost. Everything is measured from outside: React's profiler, the
8169
+ clock and the frame callbacks; the pointer walk, the pan and the wheel zoom
8170
+ are dispatched on the schedule's canvas by the page itself, so a script only
8171
+ presses a button and waits for the status to read `done`. Not photographed:
8172
+ it measures the moment it runs. */
8173
+
8174
+ import { useEffect, useMemo, useRef, useState } from "react";
8175
+ import { Button, Text } from "@umriss-ui/core";
8176
+ import { useSchedule } from "@umriss-ui/schedule";
8177
+ import type { Dependency, ScheduleInteraction, Subtask, Task } from "@umriss-ui/schedule";
8178
+
8179
+ const MINUTE = 60_000;
8180
+ const HOUR = 60 * MINUTE;
8181
+ const T0 = Date.UTC(2026, 2, 16, 6);
8182
+ const VIEW: readonly [number, number] = [T0, T0 + 8 * HOUR];
8183
+ const HEIGHT = 440;
8184
+ const LANE_HEIGHT = 44;
8185
+ /* Events per scripted run, one to a frame. */
8186
+ const EVENTS = 240;
8187
+
8188
+ const SIZES = {
8189
+ small: { lanes: 20, subtasks: 200 },
8190
+ medium: { lanes: 50, subtasks: 1_000 },
8191
+ large: { lanes: 100, subtasks: 5_000 },
8192
+ } as const;
8193
+ type Size = keyof typeof SIZES;
8194
+
8195
+ interface Plan {
8196
+ lanes: readonly string[];
8197
+ tasks: readonly Task[];
8198
+ subtasks: readonly Subtask[];
8199
+ dependencies: readonly Dependency[];
8200
+ }
8201
+
8202
+ /** Lane 0 holds one long bar, the probe the pointer walk runs along. The other
8203
+ lanes share the remaining subtasks in 20-minute bars every half hour, each
8204
+ lane one task, and every bar after the first on a lane hangs on the bar
8205
+ before it - as many dependencies as there are such pairs. */
8206
+ function plan({ lanes, subtasks }: { lanes: number; subtasks: number }): Plan {
8207
+ const laneIds = Array.from({ length: lanes }, (_, i) => `lane-${i}`);
8208
+ const tasks = laneIds.map((_, i): Task => ({ id: `task-${i}`, name: `Task ${i}`, color: `hsl(${(i * 37) % 360} 60% 50%)` }));
8209
+ const work: Subtask[] = [{ id: "probe", task: "task-0", lane: "lane-0", from: T0 + HOUR, to: T0 + 7 * HOUR, name: "Probe" }];
8210
+ const dependencies: Dependency[] = [];
8211
+ const others = lanes - 1;
8212
+ for (let j = 0; j < subtasks; j++) {
8213
+ const lane = 1 + (j % others);
8214
+ const from = T0 + Math.floor(j / others) * 30 * MINUTE;
8215
+ work.push({ id: `s-${j}`, task: `task-${lane}`, lane: `lane-${lane}`, from, to: from + 20 * MINUTE, name: `Work ${j}` });
8216
+ if (j >= others) dependencies.push({ id: `d-${j}`, from: `s-${j - others}`, to: `s-${j}`, lag: 0 });
8217
+ }
8218
+ return { lanes: laneIds, tasks, subtasks: work, dependencies };
8219
+ }
8220
+
8221
+ type Figures = Record<string, number | undefined>;
8222
+ const FIGURES = [
8223
+ ["first-render-ms", "First render, click to frame"],
8224
+ ["walk-bar-ms", "Pointer walk along one bar, ms per event"],
8225
+ ["walk-bar-renders", "Pointer walk along one bar, renders"],
8226
+ ["walk-bar-frame-ms", "Pointer walk along one bar, ms from event to end of its frame"],
8227
+ ["walk-many-ms", "Pointer walk across many bars, ms per event"],
8228
+ ["walk-many-renders", "Pointer walk across many bars, renders"],
8229
+ ["walk-many-frame-ms", "Pointer walk across many bars, ms from event to end of its frame"],
8230
+ ["pan-ms", "Pan, ms per event"],
8231
+ ["pan-frame-ms", "Pan, ms from event to end of its frame"],
8232
+ ["zoom-ms", "Wheel zoom, ms per event"],
8233
+ ["zoom-frame-ms", "Wheel zoom, ms from event to end of its frame"],
8234
+ ] as const;
8235
+
8236
+ /** What the page keeps between renders without drawing it: when the size was
8237
+ asked for, the the target last under the pointer. */
8238
+ interface Meter {
8239
+ clickAt: number;
8240
+ hover: ScheduleInteraction | null;
8241
+ }
8242
+
8243
+ /* One page, one meter: a module value, since no render may read or write it. */
8244
+ const meter: Meter = { clickAt: 0, hover: null };
8245
+
8246
+ const frame = () => new Promise<void>((resolve) => requestAnimationFrame(() => resolve()));
8247
+ const elapsed = (meter: Meter) => performance.now() - meter.clickAt;
8248
+ const remember = (e: ScheduleInteraction) => {
8249
+ meter.hover = e;
8250
+ };
8251
+ const stamp = (meter: Meter) => {
8252
+ meter.clickAt = performance.now();
8253
+ };
8254
+
8255
+ const pointer = (type: string, target: Element, x: number, y: number) =>
8256
+ target.dispatchEvent(
8257
+ new PointerEvent(type, { bubbles: true, cancelable: true, pointerId: 1, pointerType: "mouse", button: 0, buttons: type === "pointerup" ? 0 : 1, clientX: x, clientY: y }),
8258
+ );
8259
+
8260
+ /* The y of lane 0's row: moving down the probe's column until the schedule
8261
+ reports the probe under the pointer. */
8262
+ function probeY(meter: Meter, el: Element, rect: DOMRect): number {
8263
+ for (let y = 0; y < HEIGHT; y += 3) {
8264
+ pointer("pointermove", el, rect.left + rect.width / 2, rect.top + y);
8265
+ const h = meter.hover;
8266
+ if (h?.hit.kind === "subtask" && h.hit.subtask.id === "probe") return rect.top + y;
8267
+ }
8268
+ return rect.top + LANE_HEIGHT;
8269
+ }
8270
+
8271
+ interface Sinks {
8272
+ put: (values: Figures) => void;
8273
+ status: (s: "running" | "done") => void;
8274
+ }
8275
+
8276
+ type Step = (el: Element, rect: DOMRect, y0: number, i: number) => void;
8277
+
8278
+ /* The end of the next frame: a task queued from a frame callback runs after
8279
+ that frame has been drawn, and the schedule's own draw callback, registered
8280
+ by the event before ours, has run by then. */
8281
+ const frameEnd = () =>
8282
+ new Promise<void>((resolve) => {
8283
+ const channel = new MessageChannel();
8284
+ channel.port1.onmessage = () => {
8285
+ channel.port1.close();
8286
+ resolve();
8287
+ };
8288
+ requestAnimationFrame(() => channel.port2.postMessage(null));
8289
+ });
8290
+
8291
+ /* A scripted measurement: EVENTS events, one to a frame. It reports the time
8292
+ the dispatch itself took per event, the time from the dispatch to the end of
8293
+ the frame that drew it, and the batches of markup changes counted meanwhile.
8294
+ The synthetic pointer id is unknown to the browser, so the plot's pointer
8295
+ capture is switched off for the run. */
8296
+ async function measure(name: string, root: HTMLElement | null, meter: Meter, sinks: Sinks, step: Step, drag: boolean): Promise<void> {
8297
+ const el = root?.querySelector("[data-schedule-plot] canvas");
8298
+ const plot = el?.parentElement;
8299
+ if (el === null || el === undefined || plot === null || plot === undefined) return;
8300
+ sinks.status("running");
8301
+ plot.setPointerCapture = () => undefined;
8302
+ const rect = el.getBoundingClientRect();
8303
+ const y0 = probeY(meter, el, rect);
8304
+ const middle = rect.left + rect.width / 2;
8305
+ if (drag) pointer("pointerdown", el, middle, y0);
8306
+ await frame();
8307
+ /* The production build has no profiler; a commit shows as a batch of changes
8308
+ to the schedule's markup, which is what is counted. */
8309
+ let renders = 0;
8310
+ const observer = new MutationObserver(() => renders++);
8311
+ observer.observe(root!, { subtree: true, childList: true, attributes: true, characterData: true });
8312
+ let busy = 0;
8313
+ let drawn = 0;
8314
+ for (let i = 0; i < EVENTS; i++) {
8315
+ await frame();
8316
+ const t = performance.now();
8317
+ step(el, rect, y0, i);
8318
+ busy += performance.now() - t;
8319
+ await frameEnd();
8320
+ drawn += performance.now() - t;
8321
+ }
8322
+ if (drag) pointer("pointerup", el, middle, y0);
8323
+ await frame();
8324
+ observer.disconnect();
8325
+ delete (plot as Partial<HTMLElement>).setPointerCapture;
8326
+ sinks.put({
8327
+ [`${name}-ms`]: busy / EVENTS,
8328
+ [`${name}-frame-ms`]: drawn / EVENTS,
8329
+ ...(name.startsWith("walk") ? { [`${name}-renders`]: renders } : {}),
8330
+ });
8331
+ sinks.status("done");
8332
+ }
8333
+
8334
+ const rows = Math.max(1, Math.floor(HEIGHT / LANE_HEIGHT) - 1);
8335
+ const STEPS: Record<string, { step: Step; drag: boolean }> = {
8336
+ "walk-bar": { step: (el, r, y0, i) => pointer("pointermove", el, r.left + r.width * (0.12 + (0.76 * i) / EVENTS), y0), drag: false },
8337
+ "walk-many": { step: (el, r, y0, i) => pointer("pointermove", el, r.left + r.width * ((i * 0.618) % 1), y0 + (i % rows) * LANE_HEIGHT), drag: false },
8338
+ /* The pan goes left for half the events and back again, so the view ends where it began. */
8339
+ pan: { step: (el, r, y0, i) => pointer("pointermove", el, r.left + r.width / 2 + (i < EVENTS / 2 ? -3 * i : -3 * (EVENTS - i)), y0), drag: true },
8340
+ /* Ctrl held, as a pinch arrives; in and out in turn. */
8341
+ zoom: {
8342
+ step: (el, r, y0, i) =>
8343
+ el.dispatchEvent(
8344
+ new WheelEvent("wheel", { bubbles: true, cancelable: true, ctrlKey: true, deltaY: i % 2 === 0 ? -120 : 120, clientX: r.left + r.width / 2, clientY: y0 }),
8345
+ ),
8346
+ drag: false,
8347
+ },
8348
+ };
8349
+ const RUNS = [
8350
+ ["walk-bar", "Walk along one bar"],
8351
+ ["walk-many", "Walk across many"],
8352
+ ["pan", "Pan"],
8353
+ ["zoom", "Wheel zoom"],
8354
+ ] as const;
8355
+
8356
+ function Plot({ data, onInteraction }: { data: Plan; onInteraction: (e: ScheduleInteraction) => void }) {
8357
+ const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: VIEW } });
8358
+ return (
8359
+ <Schedule ariaLabel="Benchmark plan" height={HEIGHT} laneHeight={LANE_HEIGHT} onInteraction={onInteraction}>
8360
+ {data.lanes.map((id) => (
8361
+ <Lane key={id} id={id} />
8362
+ ))}
8363
+ <Dependencies data={data.dependencies} />
8364
+ <Subtasks data={data.subtasks} tasks={data.tasks} />
8365
+ </Schedule>
8366
+ );
8367
+ }
8368
+
8369
+ export default function Benchmark() {
8370
+ const [size, setSize] = useState<Size>("small");
8371
+ /* Pressing a size again draws the plan anew, so the first render can be taken twice. */
8372
+ const [round, setRound] = useState(0);
8373
+ const [status, setStatus] = useState<"idle" | "running" | "done">("running");
8374
+ const [figures, setFigures] = useState<Figures>({});
8375
+ const data = useMemo(() => plan(SIZES[size]), [size]);
8376
+ const host = useRef<HTMLDivElement>(null);
8377
+
8378
+ const sinks: Sinks = {
8379
+ put: (values) => setFigures((f) => ({ ...f, ...values })),
8380
+ status: setStatus,
8381
+ };
8382
+
8383
+ /* The second frame after the commit has the canvases drawn. */
8384
+ useEffect(() => {
8385
+ let live = true;
8386
+ void frame()
8387
+ .then(frame)
8388
+ .then(() => {
8389
+ if (!live) return;
8390
+ setFigures((f) => ({ ...f, "first-render-ms": elapsed(meter) }));
8391
+ setStatus("done");
8392
+ });
8393
+ return () => {
8394
+ live = false;
8395
+ };
8396
+ }, [size, round]);
8397
+
8398
+ const show = (next: Size) => {
8399
+ stamp(meter);
8400
+ setStatus("running");
8401
+ setFigures({});
8402
+ setSize(next);
8403
+ setRound((r) => r + 1);
8404
+ };
8405
+
8406
+ const busy = status === "running";
8407
+ return (
8408
+ <>
8409
+ <div style={{ display: "flex", flexWrap: "wrap", gap: "0.5rem" }}>
8410
+ {(Object.keys(SIZES) as Size[]).map((s) => (
8411
+ <Button key={s} size="sm" data-role={`size-${s}`} disabled={busy} onClick={() => show(s)}>
8412
+ {SIZES[s].subtasks.toLocaleString("en-US")} subtasks
8413
+ </Button>
8414
+ ))}
8415
+ {RUNS.map(([name, label]) => (
8416
+ <Button
8417
+ key={name}
8418
+ size="sm"
8419
+ data-role={`run-${name}`}
8420
+ disabled={busy}
8421
+ onClick={() => void measure(name, host.current, meter, sinks, STEPS[name]!.step, STEPS[name]!.drag)}
8422
+ >
8423
+ {label}
8424
+ </Button>
8425
+ ))}
8426
+ </div>
8427
+ <dl style={{ display: "flex", flexWrap: "wrap", gap: "1.5rem", margin: 0 }}>
8428
+ <div>
8429
+ <Text as="dt">Status</Text>
8430
+ <Text as="dd" mono style={{ margin: 0 }} data-role="status">{status}</Text>
8431
+ </div>
8432
+ <div>
8433
+ <Text as="dt">Lanes</Text>
8434
+ <Text as="dd" mono style={{ margin: 0 }} data-role="plan-lanes">{data.lanes.length}</Text>
8435
+ </div>
8436
+ <div>
8437
+ <Text as="dt">Subtasks</Text>
8438
+ <Text as="dd" mono style={{ margin: 0 }} data-role="plan-subtasks">{data.subtasks.length}</Text>
8439
+ </div>
8440
+ <div>
8441
+ <Text as="dt">Dependencies</Text>
8442
+ <Text as="dd" mono style={{ margin: 0 }} data-role="plan-dependencies">{data.dependencies.length}</Text>
8443
+ </div>
8444
+ {FIGURES.map(([role, name]) => {
8445
+ const value = figures[role];
8446
+ return (
8447
+ <div key={role}>
8448
+ <Text as="dt">{name}</Text>
8449
+ <Text as="dd" mono style={{ margin: 0 }} data-role={role}>{value === undefined ? "-" : value.toFixed(role.endsWith("ms") ? 2 : 0)}</Text>
8450
+ </div>
8451
+ );
8452
+ })}
8453
+ </dl>
8454
+ <div ref={host}>
8455
+ <Plot
8456
+ key={`${size}-${round}`}
8457
+ data={data}
8458
+ onInteraction={remember}
8459
+ />
8460
+ </div>
8461
+ </>
8462
+ );
8463
+ }
8464
+ ```
8465
+
8466
+ #### Keyboard
8467
+
8468
+ The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
8469
+
8470
+ #### Props on this page
8471
+
8472
+ From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
8473
+
8474
+ | Prop | Type | Default | Description |
8475
+ |---|---|---|---|
8476
+ | [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
8477
+ | [`laneHeight`](#/schedule/ScheduleProps-laneHeight) | `number` | `44` | Height of one lane in pixels. |
8478
+ | [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
8479
+
8480
+ ###### Events
8481
+
8482
+ | Prop | Type | Default | Description |
8483
+ |---|---|---|---|
8484
+ | [`onInteraction`](#/schedule/ScheduleProps-onInteraction) | `(interaction: `[`ScheduleInteraction`](#/interactions/type-ScheduleInteraction)`) => void` | — | Click, context menu and hover, with what the pointer is on and where. While it is set, a right-click opens no browser menu. |
8485
+
8486
+ ###### Accessibility
8487
+
8488
+ | Prop | Type | Default | Description |
8489
+ |---|---|---|---|
8490
+ | [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
8491
+
8492
+ From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
8493
+
8494
+ | Prop | Type | Default | Description |
8495
+ |---|---|---|---|
8496
+ | [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
8497
+
8498
+ From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
8499
+
8500
+ | Prop | Type | Default | Description |
8501
+ |---|---|---|---|
8502
+ | [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
8503
+ | [`tasks`](#/subtasks/SubtasksProps-tasks) *required* | `readonly `[`Task`](#/subtasks/type-Task)`[]` | — | The tasks the subtasks belong to - their identity and their colour. A subtask whose task is not among them is drawn in a muted colour. |
8504
+
8505
+ From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
8506
+
8507
+ | Prop | Type | Default | Description |
8508
+ |---|---|---|---|
8509
+ | [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
8510
+ | [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
8511
+ | [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
8512
+ | [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
8513
+ | [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
8514
+ | [`name`](#/subtasks/Subtask-name) | `string` | — | What the subtask is called, where the schedule names it. |
8515
+
8516
+ From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
8517
+
8518
+ | Prop | Type | Default | Description |
8519
+ |---|---|---|---|
8520
+ | [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
8521
+ | [`color`](#/subtasks/Task-color) *required* | `string` | — | Any CSS colour - a literal, a token, `light-dark(…)`. The colour means what the caller's domain needs it to mean. |
8522
+ | [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
8523
+
8524
+ From `DependenciesProps` — the full table stands on [Dependencies](#/dependencies/type-DependenciesProps).
8525
+
8526
+ | Prop | Type | Default | Description |
8527
+ |---|---|---|---|
8528
+ | [`data`](#/dependencies/DependenciesProps-data) *required* | `readonly `[`Dependency`](#/dependencies/type-Dependency)`[]` | — | The dependencies, as the caller holds them. |
8529
+
8530
+ From `Dependency` — the full table stands on [Dependencies](#/dependencies/type-Dependency).
8531
+
8532
+ | Prop | Type | Default | Description |
8533
+ |---|---|---|---|
8534
+ | [`id`](#/dependencies/Dependency-id) *required* | `string` | — | The caller's identity of the dependency. |
8535
+ | [`from`](#/dependencies/Dependency-from) *required* | `string` | — | The id of the subtask it leaves. |
8536
+ | [`to`](#/dependencies/Dependency-to) *required* | `string` | — | The id of the subtask it arrives at. |
8537
+ | [`lag`](#/dependencies/Dependency-lag) *required* | `number` | — | The least time between the two anchors; zero where the successor may begin as soon as the predecessor ends. |
8538
+
8539
+ From `ScheduleInteraction` — the full table stands on [Interactions](#/interactions/type-ScheduleInteraction).
8540
+
8541
+ | Prop | Type | Default | Description |
8542
+ |---|---|---|---|
8543
+ | [`hit`](#/interactions/ScheduleInteraction-hit) *required* | [`ScheduleHit`](#/interactions/type-ScheduleHit) | — | What the pointer is on. |
8544
+
8545
+ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleOptions).
8546
+
8547
+ | Prop | Type | Default | Description |
8548
+ |---|---|---|---|
8549
+ | [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from, read once when the hook first runs; a different value on a later render is ignored, as React ignores a changed `defaultValue`. To go to a view later, call `setView`. The schedule remembers none: where a view is kept is the application's decision. |
8550
+
8551
+ From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
8552
+
8553
+ | Prop | Type | Default | Description |
8554
+ |---|---|---|---|
8555
+ | [`domain`](#/view/ScheduleView-domain) | `readonly [number, number]` | — | The span in view, as two wall-clock instants. Absent, the schedule shows the extent of its subtasks, within `zoomLimits`. |
8556
+
8131
8557
  ## API index
8132
8558
 
8133
8559
  Every name the package exports, in one place.
@@ -8151,7 +8577,7 @@ Declares a schedule: hands back `Schedule` and the parts declared inside it
8151
8577
  function useSchedule(options?: ScheduleOptions): ScheduleParts;
8152
8578
  ```
8153
8579
 
8154
- Used on [Scenarios](#/), [Installation](#/installation), [First schedule](#/schedule), [Lanes](#/lane), [Lane groups](#/lane-groups), [Subtasks](#/subtasks), [Bar labels](#/bar-labels), [Appearances](#/appearances), [Overlap](#/overlap), [Dependencies](#/dependencies), [Routes](#/routes), [Time axis and calendar](#/time-axis), [Blocked time](#/blocked-time), [Milestones](#/milestones), [Now line](#/now-line), [Pan and zoom](#/pan-and-zoom), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [View](#/view), [Linked schedules](#/linked-schedules), [The handle](#/handle), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Stretch, lead-in, lead-out](#/stretch), [Snapping](#/snapping), [Placing from outside](#/placing), [Where a subtask may go](#/where-it-may-go) and [Ripple](#/ripple).
8580
+ Used on [Scenarios](#/), [Installation](#/installation), [First schedule](#/schedule), [Lanes](#/lane), [Lane groups](#/lane-groups), [Subtasks](#/subtasks), [Bar labels](#/bar-labels), [Appearances](#/appearances), [Overlap](#/overlap), [Dependencies](#/dependencies), [Routes](#/routes), [Time axis and calendar](#/time-axis), [Blocked time](#/blocked-time), [Milestones](#/milestones), [Now line](#/now-line), [Pan and zoom](#/pan-and-zoom), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [View](#/view), [Linked schedules](#/linked-schedules), [The handle](#/handle), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Stretch, lead-in, lead-out](#/stretch), [Snapping](#/snapping), [Placing from outside](#/placing), [Where a subtask may go](#/where-it-may-go), [Ripple](#/ripple) and [Benchmark](#/benchmark).
8155
8581
 
8156
8582
  #### Functions
8157
8583
 
@@ -8331,7 +8757,7 @@ Its table stands on [Dependencies](#/dependencies/type-DependenciesProps).
8331
8757
 
8332
8758
  Its table stands on [Dependencies](#/dependencies/type-Dependency).
8333
8759
 
8334
- Used on [Scenarios](#/), [Installation](#/installation), [First schedule](#/schedule), [Lane groups](#/lane-groups), [Dependencies](#/dependencies), [Routes](#/routes), [Time axis and calendar](#/time-axis), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Placing from outside](#/placing) and [Ripple](#/ripple).
8760
+ Used on [Scenarios](#/), [Installation](#/installation), [First schedule](#/schedule), [Lane groups](#/lane-groups), [Dependencies](#/dependencies), [Routes](#/routes), [Time axis and calendar](#/time-axis), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Placing from outside](#/placing), [Ripple](#/ripple) and [Benchmark](#/benchmark).
8335
8761
 
8336
8762
  ##### `DependencyAttachment`
8337
8763
 
@@ -8547,7 +8973,7 @@ type ScheduleHit =
8547
8973
 
8548
8974
  Its table stands on [Interactions](#/interactions/type-ScheduleInteraction).
8549
8975
 
8550
- Used on [Scenarios](#/), [Interactions](#/interactions) and [Tooltip](#/tooltip).
8976
+ Used on [Scenarios](#/), [Interactions](#/interactions), [Tooltip](#/tooltip) and [Benchmark](#/benchmark).
8551
8977
 
8552
8978
  ##### `ScheduleOptions`
8553
8979
 
@@ -8560,11 +8986,11 @@ it, its view and the setters that change it.
8560
8986
 
8561
8987
  | Prop | Type | Default | Description |
8562
8988
  |---|---|---|---|
8563
- | `Schedule` *required* | `ForwardRefExoticComponent<`[`ScheduleProps`](#/schedule/type-ScheduleProps)` & RefAttributes<`[`ScheduleHandle`](#type-ScheduleHandle)`>>` | — | The schedule. One per `useSchedule`: a second schedule is a second call.<br>Shown in: [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule), [Start from an empty plan (First schedule)](#/schedule/no-work-yet) and 77 more |
8564
- | `Lane` *required* | `typeof Lane` | — | <br>Shown in: [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule), [Start from an empty plan (First schedule)](#/schedule/no-work-yet) and 77 more |
8989
+ | `Schedule` *required* | `(props: `[`ScheduleProps`](#/schedule/type-ScheduleProps)`) => ReactNode` | — | The schedule. One per `useSchedule`: a second schedule is a second call.<br>Shown in: [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule), [Start from an empty plan (First schedule)](#/schedule/no-work-yet) and 78 more |
8990
+ | `Lane` *required* | `typeof Lane` | — | <br>Shown in: [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule), [Start from an empty plan (First schedule)](#/schedule/no-work-yet) and 78 more |
8565
8991
  | `LaneGroup` *required* | `typeof LaneGroup` | — | <br>Shown in: [Group lanes under a head (Lane groups)](#/lane-groups/a-group), [Nest groups to any depth (Lane groups)](#/lane-groups/nesting), [Fold groups from outside (Lane groups)](#/lane-groups/fold-from-outside) and 5 more |
8566
- | `Subtasks` *required* | `typeof Subtasks` | — | <br>Shown in: [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule), [Start from an empty plan (First schedule)](#/schedule/no-work-yet) and 77 more |
8567
- | `Dependencies` *required* | `typeof Dependencies` | — | <br>Shown in: [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule), [Plan a day in the machine shop (First schedule)](#/schedule/machine-plan) and 27 more |
8992
+ | `Subtasks` *required* | `typeof Subtasks` | — | <br>Shown in: [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule), [Start from an empty plan (First schedule)](#/schedule/no-work-yet) and 78 more |
8993
+ | `Dependencies` *required* | `typeof Dependencies` | — | <br>Shown in: [The smallest schedule (Installation)](#/installation/smallest-schedule), [A day of tours (First schedule)](#/schedule/first-schedule), [Plan a day in the machine shop (First schedule)](#/schedule/machine-plan) and 28 more |
8568
8994
  | `BlockedTimes` *required* | `typeof BlockedTimes` | — | <br>Shown in: [Block out leave and maintenance (Blocked time)](#/blocked-time/leave), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Check a sprint against the leave calendar (Blocked time)](#/blocked-time/team-leave) and 5 more |
8569
8995
  | `Milestones` *required* | `typeof Milestones` | — | <br>Shown in: [Mark a handover and a release (Milestones)](#/milestones/handovers-and-releases), [Say what a milestone is in your own tooltip (Milestones)](#/milestones/say-what-a-milestone-is) |
8570
8996
  | `view` *required* | [`ScheduleView`](#/view/type-ScheduleView) | — | How the planner is looking at the plan: the span and the folded groups.<br>Shown in: [Fold groups from outside (Lane groups)](#/lane-groups/fold-from-outside), [Keep and restore a view (View)](#/view/keep-and-restore), [Keep two schedules in step (Linked schedules)](#/linked-schedules/in-step) and 1 more |
@@ -8618,7 +9044,7 @@ Stretch the main time at one or both of its edges.
8618
9044
 
8619
9045
  Its table stands on [Subtasks](#/subtasks/type-Subtask).
8620
9046
 
8621
- Used on [Scenarios](#/), [Installation](#/installation), [First schedule](#/schedule), [Lanes](#/lane), [Lane groups](#/lane-groups), [Subtasks](#/subtasks), [Bar labels](#/bar-labels), [Appearances](#/appearances), [Overlap](#/overlap), [Dependencies](#/dependencies), [Routes](#/routes), [Time axis and calendar](#/time-axis), [Blocked time](#/blocked-time), [Milestones](#/milestones), [Now line](#/now-line), [Pan and zoom](#/pan-and-zoom), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [View](#/view), [Linked schedules](#/linked-schedules), [The handle](#/handle), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Stretch, lead-in, lead-out](#/stretch), [Snapping](#/snapping), [Placing from outside](#/placing), [Where a subtask may go](#/where-it-may-go) and [Ripple](#/ripple).
9047
+ Used on [Scenarios](#/), [Installation](#/installation), [First schedule](#/schedule), [Lanes](#/lane), [Lane groups](#/lane-groups), [Subtasks](#/subtasks), [Bar labels](#/bar-labels), [Appearances](#/appearances), [Overlap](#/overlap), [Dependencies](#/dependencies), [Routes](#/routes), [Time axis and calendar](#/time-axis), [Blocked time](#/blocked-time), [Milestones](#/milestones), [Now line](#/now-line), [Pan and zoom](#/pan-and-zoom), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [View](#/view), [Linked schedules](#/linked-schedules), [The handle](#/handle), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Stretch, lead-in, lead-out](#/stretch), [Snapping](#/snapping), [Placing from outside](#/placing), [Where a subtask may go](#/where-it-may-go), [Ripple](#/ripple) and [Benchmark](#/benchmark).
8622
9048
 
8623
9049
  ##### `SubtaskAppearance`
8624
9050
 
@@ -8636,7 +9062,7 @@ Its table stands on [Subtasks](#/subtasks/type-SubtasksProps).
8636
9062
 
8637
9063
  Its table stands on [Subtasks](#/subtasks/type-Task).
8638
9064
 
8639
- Used on [Scenarios](#/), [Installation](#/installation), [First schedule](#/schedule), [Lanes](#/lane), [Lane groups](#/lane-groups), [Subtasks](#/subtasks), [Bar labels](#/bar-labels), [Appearances](#/appearances), [Overlap](#/overlap), [Dependencies](#/dependencies), [Routes](#/routes), [Time axis and calendar](#/time-axis), [Blocked time](#/blocked-time), [Milestones](#/milestones), [Now line](#/now-line), [Pan and zoom](#/pan-and-zoom), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [View](#/view), [Linked schedules](#/linked-schedules), [The handle](#/handle), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Stretch, lead-in, lead-out](#/stretch), [Snapping](#/snapping), [Placing from outside](#/placing), [Where a subtask may go](#/where-it-may-go) and [Ripple](#/ripple).
9065
+ Used on [Scenarios](#/), [Installation](#/installation), [First schedule](#/schedule), [Lanes](#/lane), [Lane groups](#/lane-groups), [Subtasks](#/subtasks), [Bar labels](#/bar-labels), [Appearances](#/appearances), [Overlap](#/overlap), [Dependencies](#/dependencies), [Routes](#/routes), [Time axis and calendar](#/time-axis), [Blocked time](#/blocked-time), [Milestones](#/milestones), [Now line](#/now-line), [Pan and zoom](#/pan-and-zoom), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [View](#/view), [Linked schedules](#/linked-schedules), [The handle](#/handle), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Stretch, lead-in, lead-out](#/stretch), [Snapping](#/snapping), [Placing from outside](#/placing), [Where a subtask may go](#/where-it-may-go), [Ripple](#/ripple) and [Benchmark](#/benchmark).
8640
9066
 
8641
9067
  ##### `ViolatedDependency`
8642
9068