@umriss-ui/schedule 0.7.1 → 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/CHANGELOG.md +36 -2
- package/README.md +10 -7
- package/dist/index.d.ts +26 -23
- package/dist/schedule.css +1 -1
- package/dist/schedule.js +1325 -1307
- package/docs/llms-full.md +520 -96
- package/package.json +9 -8
package/docs/llms-full.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @umriss-ui/schedule 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
|
|
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
|
|
|
@@ -1028,7 +1028,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
1028
1028
|
|
|
1029
1029
|
| Prop | Type | Default | Description |
|
|
1030
1030
|
|---|---|---|---|
|
|
1031
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
1031
|
+
| [`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. |
|
|
1032
1032
|
|
|
1033
1033
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
1034
1034
|
|
|
@@ -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
|
-
| `
|
|
1282
|
-
| `
|
|
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
|
|
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
|
|
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
|
|
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`.
|
|
@@ -1358,9 +1370,9 @@ type IntentKind = Intent["kind"];
|
|
|
1358
1370
|
|
|
1359
1371
|
###### `PlacingItem`
|
|
1360
1372
|
|
|
1361
|
-
What the application says it is dragging in, while it drags it
|
|
1362
|
-
|
|
1363
|
-
the drop
|
|
1373
|
+
What the application says it is dragging in, while it drags it: the
|
|
1374
|
+
browser hands over the dragged data only on the drop, so the ghost before
|
|
1375
|
+
the drop can only come from the caller.
|
|
1364
1376
|
|
|
1365
1377
|
| Prop | Type | Default | Description |
|
|
1366
1378
|
|---|---|---|---|
|
|
@@ -1498,7 +1510,7 @@ Put the subtask on another lane.
|
|
|
1498
1510
|
###### `PlaceIntent`
|
|
1499
1511
|
|
|
1500
1512
|
Put work on the plan that was not on it: the answer to a drag from outside
|
|
1501
|
-
the schedule
|
|
1513
|
+
the schedule. It carries no subtask id - there is
|
|
1502
1514
|
no subtask yet; the caller creates one, with its own identity, from
|
|
1503
1515
|
`subtaskFromPlace`.
|
|
1504
1516
|
|
|
@@ -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
|
|
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
|
|
@@ -1671,7 +1683,7 @@ A group is structure, never a lane: nothing sits on it, no finding is reported f
|
|
|
1671
1683
|
|
|
1672
1684
|
Folded, a group shows a miniature: every lane in it as a thin strip with its work in the tasks' colours. Dependencies still arrive at the right strip, findings are marked on the row, and a strip can be hovered and selected. Labels, appearances and grips need room and wait for the group to open.
|
|
1673
1685
|
|
|
1674
|
-
Folding is part of the schedule's view and never an intent: `folded` in `initialView` starts with groups folded, `toggleGroup`, `foldAll` and `unfoldAll` fold from outside, and `onViewChange` reports every fold - see [View](#/view).
|
|
1686
|
+
Folding is part of the schedule's view and never an intent: `folded` in `initialView` starts with groups folded, `toggleGroup`, `foldAll` and `unfoldAll` fold from outside, and `onViewChange` reports every fold the planner makes - see [View](#/view).
|
|
1675
1687
|
|
|
1676
1688
|
#### Examples
|
|
1677
1689
|
|
|
@@ -1765,7 +1777,7 @@ export default function Nesting() {
|
|
|
1765
1777
|
|
|
1766
1778
|
##### Fold groups from outside
|
|
1767
1779
|
|
|
1768
|
-
`foldAll`, `unfoldAll` and `toggleGroup` fold from outside, and `view.folded` says what is folded - start from `initialView`, keep what `onViewChange` reports.
|
|
1780
|
+
`foldAll`, `unfoldAll` and `toggleGroup` fold from outside, and `view.folded` says what is folded - start from `initialView`, go to a whole view with `setView`, keep what `onViewChange` reports.
|
|
1769
1781
|
|
|
1770
1782
|
```tsx
|
|
1771
1783
|
import { Button, Stack, Text } from "@umriss-ui/core";
|
|
@@ -1910,8 +1922,8 @@ import { useSchedule } from "@umriss-ui/schedule";
|
|
|
1910
1922
|
import type { Subtask, Task } from "@umriss-ui/schedule";
|
|
1911
1923
|
|
|
1912
1924
|
/* The schedule keeps the fold from here on. To store it, keep what
|
|
1913
|
-
`onViewChange` reports; to steer it, use the setters
|
|
1914
|
-
back. */
|
|
1925
|
+
`onViewChange` reports; to steer it, use `setView` and the setters
|
|
1926
|
+
`useSchedule` hands back. `initialView` is read once. */
|
|
1915
1927
|
|
|
1916
1928
|
const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
|
|
1917
1929
|
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
|
@@ -2328,7 +2340,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
2328
2340
|
|
|
2329
2341
|
| Prop | Type | Default | Description |
|
|
2330
2342
|
|---|---|---|---|
|
|
2331
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
2343
|
+
| [`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. |
|
|
2332
2344
|
|
|
2333
2345
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
2334
2346
|
|
|
@@ -2642,7 +2654,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
2642
2654
|
|
|
2643
2655
|
| Prop | Type | Default | Description |
|
|
2644
2656
|
|---|---|---|---|
|
|
2645
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
2657
|
+
| [`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. |
|
|
2646
2658
|
|
|
2647
2659
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
2648
2660
|
|
|
@@ -2825,7 +2837,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
2825
2837
|
|
|
2826
2838
|
| Prop | Type | Default | Description |
|
|
2827
2839
|
|---|---|---|---|
|
|
2828
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
2840
|
+
| [`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. |
|
|
2829
2841
|
|
|
2830
2842
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
2831
2843
|
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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) |
|
|
@@ -3460,7 +3472,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
3460
3472
|
|
|
3461
3473
|
| Prop | Type | Default | Description |
|
|
3462
3474
|
|---|---|---|---|
|
|
3463
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
3475
|
+
| [`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. |
|
|
3464
3476
|
|
|
3465
3477
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
3466
3478
|
|
|
@@ -3803,7 +3815,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
3803
3815
|
|
|
3804
3816
|
| Prop | Type | Default | Description |
|
|
3805
3817
|
|---|---|---|---|
|
|
3806
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
3818
|
+
| [`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. |
|
|
3807
3819
|
|
|
3808
3820
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
3809
3821
|
|
|
@@ -4545,7 +4557,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
4545
4557
|
|
|
4546
4558
|
| Prop | Type | Default | Description |
|
|
4547
4559
|
|---|---|---|---|
|
|
4548
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
4560
|
+
| [`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. |
|
|
4549
4561
|
|
|
4550
4562
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
4551
4563
|
|
|
@@ -4681,7 +4693,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
4681
4693
|
|
|
4682
4694
|
| Prop | Type | Default | Description |
|
|
4683
4695
|
|---|---|---|---|
|
|
4684
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
4696
|
+
| [`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. |
|
|
4685
4697
|
|
|
4686
4698
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
4687
4699
|
|
|
@@ -4916,7 +4928,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
4916
4928
|
|
|
4917
4929
|
| Prop | Type | Default | Description |
|
|
4918
4930
|
|---|---|---|---|
|
|
4919
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
4931
|
+
| [`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. |
|
|
4920
4932
|
|
|
4921
4933
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
4922
4934
|
|
|
@@ -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
|
|
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) |
|
|
@@ -5556,9 +5568,9 @@ import { useSchedule } from "@umriss-ui/schedule";
|
|
|
5556
5568
|
|
|
5557
5569
|
Demo page: https://romanhaendler.github.io/umriss-ui/schedule/view/
|
|
5558
5570
|
|
|
5559
|
-
The schedule keeps its view itself and puts it nowhere, not in the address and not in any storage. `view` on what [`useSchedule`](#/api/useSchedule) hands back holds it, and `onViewChange` reports every change
|
|
5571
|
+
The schedule keeps its view itself and puts it nowhere, not in the address and not in any storage. `view` on what [`useSchedule`](#/api/useSchedule) hands back holds it, and `onViewChange` reports every change the planner makes to it - a pan or zoom at most once per frame; keep it where the application keeps things and go back to it with `setView`.
|
|
5560
5572
|
|
|
5561
|
-
|
|
5573
|
+
`initialView` is the start, read once: a different value on a later render is ignored. `setView(view)` goes to a whole view at once, and what it leaves out goes back to its default; the same view again changes nothing, and `onViewChange` does not hear it. Without a span the schedule shows the extent of its subtasks, within `zoomLimits`. A group no `LaneGroup` declares falls out.
|
|
5562
5574
|
|
|
5563
5575
|
`setDomain`, `toggleGroup`, `foldAll` and `unfoldAll` change the view from outside - a button of the application's own that shows the whole plan or folds every team. The selection is not part of the view (`selectedTask`).
|
|
5564
5576
|
|
|
@@ -5566,7 +5578,7 @@ A view that differs in content from the last one handed in applies at once, and
|
|
|
5566
5578
|
|
|
5567
5579
|
##### Keep and restore a view
|
|
5568
5580
|
|
|
5569
|
-
`onViewChange` reports the span and the folded groups as one view; keep it - here in the browser's storage, so it outlives a reload - and
|
|
5581
|
+
`onViewChange` reports the span and the folded groups as one view; keep it - here in the browser's storage, so it outlives a reload - and go back to it with `setView`. Pan, zoom, fold, keep, reload, restore.
|
|
5570
5582
|
|
|
5571
5583
|
```tsx
|
|
5572
5584
|
import { useState } from "react";
|
|
@@ -5612,11 +5624,10 @@ const WORK: Subtask[] = [
|
|
|
5612
5624
|
];
|
|
5613
5625
|
|
|
5614
5626
|
export default function KeepAndRestore() {
|
|
5615
|
-
/* The
|
|
5616
|
-
|
|
5617
|
-
const [view, setView] = useState<ScheduleView>(START);
|
|
5627
|
+
/* The schedule holds its view; `view` is what it shows now, and `setView`
|
|
5628
|
+
restores a kept one. */
|
|
5618
5629
|
const [kept, setKept] = useState<ScheduleView | null>(readKept);
|
|
5619
|
-
const { Schedule, Lane, LaneGroup, Subtasks, setDomain } = useSchedule({ initialView:
|
|
5630
|
+
const { Schedule, Lane, LaneGroup, Subtasks, view, setView, setDomain } = useSchedule({ initialView: START });
|
|
5620
5631
|
|
|
5621
5632
|
return (
|
|
5622
5633
|
<Stack gap={3}>
|
|
@@ -5677,13 +5688,13 @@ The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
|
5677
5688
|
|
|
5678
5689
|
| Prop | Type | Default | Description |
|
|
5679
5690
|
|---|---|---|---|
|
|
5680
|
-
| `initialView` | [`ScheduleView`](#type-ScheduleView) | — | The view to start from,
|
|
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 |
|
|
5681
5692
|
|
|
5682
5693
|
###### Events
|
|
5683
5694
|
|
|
5684
5695
|
| Prop | Type | Default | Description |
|
|
5685
5696
|
|---|---|---|---|
|
|
5686
|
-
| `onViewChange` | `(view: `[`ScheduleView`](#type-ScheduleView)`) => void` | — | Every change
|
|
5697
|
+
| `onViewChange` | `(view: `[`ScheduleView`](#type-ScheduleView)`) => void` | — | Every change the planner makes, once, always the whole view - the one to keep, or to hand another schedule's `setView`. A pan or zoom is reported at most once per frame. Not called for the view the schedule starts with, nor for one `setView` applies.<br>Shown in: [Keep two schedules in step (Linked schedules)](#/linked-schedules/in-step), [Read a rota beside the incidents (Linked schedules)](#/linked-schedules/rota-beside-incidents) |
|
|
5687
5698
|
|
|
5688
5699
|
##### `ScheduleView`
|
|
5689
5700
|
|
|
@@ -5702,7 +5713,7 @@ import { useSchedule } from "@umriss-ui/schedule";
|
|
|
5702
5713
|
|
|
5703
5714
|
Demo page: https://romanhaendler.github.io/umriss-ui/schedule/linked-schedules/
|
|
5704
5715
|
|
|
5705
|
-
Each schedule has its own [`useSchedule`](#/api/useSchedule).
|
|
5716
|
+
Each schedule has its own [`useSchedule`](#/api/useSchedule). Send what one reports to the other's `setView`, in both directions: the other goes there at once, without a remount, and `setView` is not reported, so the two never answer each other.
|
|
5706
5717
|
|
|
5707
5718
|
While a drag is in flight the two can stand a frame apart; they settle as soon as it ends.
|
|
5708
5719
|
|
|
@@ -5710,13 +5721,12 @@ While a drag is in flight the two can stand a frame apart; they settle as soon a
|
|
|
5710
5721
|
|
|
5711
5722
|
##### Keep two schedules in step
|
|
5712
5723
|
|
|
5713
|
-
|
|
5724
|
+
Send what `onViewChange` reports to the other schedule's `setView`: pan or zoom either one and the other follows - no `key`, no remount.
|
|
5714
5725
|
|
|
5715
5726
|
```tsx
|
|
5716
|
-
import { useState } from "react";
|
|
5717
5727
|
import { Stack, Text } from "@umriss-ui/core";
|
|
5718
5728
|
import { useSchedule } from "@umriss-ui/schedule";
|
|
5719
|
-
import type {
|
|
5729
|
+
import type { ScheduleParts, Subtask, Task } from "@umriss-ui/schedule";
|
|
5720
5730
|
|
|
5721
5731
|
const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
|
|
5722
5732
|
const min = (n: number) => n * 60_000;
|
|
@@ -5757,12 +5767,12 @@ const ELECTRIC_LEGS = on(ELECTRIC);
|
|
|
5757
5767
|
const time = (instant: number) => new Date(instant).toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" });
|
|
5758
5768
|
|
|
5759
5769
|
export default function InStep() {
|
|
5760
|
-
/*
|
|
5761
|
-
|
|
5762
|
-
const
|
|
5763
|
-
const diesel = useSchedule({ initialView:
|
|
5764
|
-
const electric = useSchedule({ initialView:
|
|
5765
|
-
const span = view.domain ??
|
|
5770
|
+
/* Both start on the same span; each reports what the reader does to it and
|
|
5771
|
+
the other goes there by `setView`, which is not reported in turn. */
|
|
5772
|
+
const start = { domain: [at(5, 30), at(18)] } as const;
|
|
5773
|
+
const diesel: ScheduleParts = useSchedule({ initialView: start, onViewChange: (v) => electric.setView(v) });
|
|
5774
|
+
const electric: ScheduleParts = useSchedule({ initialView: start, onViewChange: (v) => diesel.setView(v) });
|
|
5775
|
+
const span = diesel.view.domain ?? start.domain;
|
|
5766
5776
|
return (
|
|
5767
5777
|
<Stack gap={2}>
|
|
5768
5778
|
<diesel.Schedule ariaLabel="Diesel vehicles on Tuesday, 17 March" height={240}>
|
|
@@ -5790,10 +5800,9 @@ export default function InStep() {
|
|
|
5790
5800
|
Two schedules with different lanes over one span: who was on call, above the incidents they were paged for.
|
|
5791
5801
|
|
|
5792
5802
|
```tsx
|
|
5793
|
-
import { useState } from "react";
|
|
5794
5803
|
import { Stack } from "@umriss-ui/core";
|
|
5795
5804
|
import { useSchedule } from "@umriss-ui/schedule";
|
|
5796
|
-
import type {
|
|
5805
|
+
import type { ScheduleParts, Subtask, Task } from "@umriss-ui/schedule";
|
|
5797
5806
|
|
|
5798
5807
|
/* Data from the operations world, written out here so the example runs on its own. */
|
|
5799
5808
|
|
|
@@ -5920,9 +5929,9 @@ const PAGED: readonly Subtask[] = INCIDENTS.map((incident) => ({
|
|
|
5920
5929
|
const HIT = SERVICES.filter((service) => PAGED.some((incident) => incident.lane === service.id));
|
|
5921
5930
|
|
|
5922
5931
|
export default function RotaBesideIncidents() {
|
|
5923
|
-
const
|
|
5924
|
-
const rota = useSchedule({ initialView:
|
|
5925
|
-
const incidents = useSchedule({ initialView:
|
|
5932
|
+
const start = { domain: [day(16, 6), day(17, 14)] } as const;
|
|
5933
|
+
const rota: ScheduleParts = useSchedule({ initialView: start, onViewChange: (v) => incidents.setView(v) });
|
|
5934
|
+
const incidents: ScheduleParts = useSchedule({ initialView: start, onViewChange: (v) => rota.setView(v) });
|
|
5926
5935
|
return (
|
|
5927
5936
|
<Stack gap={2}>
|
|
5928
5937
|
<rota.Schedule ariaLabel="Who was on call" height={140}>
|
|
@@ -6003,13 +6012,13 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
6003
6012
|
|
|
6004
6013
|
| Prop | Type | Default | Description |
|
|
6005
6014
|
|---|---|---|---|
|
|
6006
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
6015
|
+
| [`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. |
|
|
6007
6016
|
|
|
6008
6017
|
###### Events
|
|
6009
6018
|
|
|
6010
6019
|
| Prop | Type | Default | Description |
|
|
6011
6020
|
|---|---|---|---|
|
|
6012
|
-
| [`onViewChange`](#/view/ScheduleOptions-onViewChange) | `(view: `[`ScheduleView`](#/view/type-ScheduleView)`) => void` | — | Every change
|
|
6021
|
+
| [`onViewChange`](#/view/ScheduleOptions-onViewChange) | `(view: `[`ScheduleView`](#/view/type-ScheduleView)`) => void` | — | Every change the planner makes, once, always the whole view - the one to keep, or to hand another schedule's `setView`. A pan or zoom is reported at most once per frame. Not called for the view the schedule starts with, nor for one `setView` applies. |
|
|
6013
6022
|
|
|
6014
6023
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
6015
6024
|
|
|
@@ -6136,6 +6145,7 @@ From `ScheduleProps` — the full table stands on [First schedule](#/schedule/ty
|
|
|
6136
6145
|
|
|
6137
6146
|
| Prop | Type | Default | Description |
|
|
6138
6147
|
|---|---|---|---|
|
|
6148
|
+
| [`ref`](#/schedule/ScheduleProps-ref) | `Ref<`[`ScheduleHandle`](#/schedule/type-ScheduleHandle)`>` | — | Receives the `ScheduleHandle` - not an element. |
|
|
6139
6149
|
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
6140
6150
|
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
6141
6151
|
|
|
@@ -6196,7 +6206,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
6196
6206
|
|
|
6197
6207
|
| Prop | Type | Default | Description |
|
|
6198
6208
|
|---|---|---|---|
|
|
6199
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
6209
|
+
| [`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. |
|
|
6200
6210
|
|
|
6201
6211
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
6202
6212
|
|
|
@@ -6779,7 +6789,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
6779
6789
|
|
|
6780
6790
|
| Prop | Type | Default | Description |
|
|
6781
6791
|
|---|---|---|---|
|
|
6782
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
6792
|
+
| [`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. |
|
|
6783
6793
|
|
|
6784
6794
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
6785
6795
|
|
|
@@ -6962,7 +6972,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
6962
6972
|
|
|
6963
6973
|
| Prop | Type | Default | Description |
|
|
6964
6974
|
|---|---|---|---|
|
|
6965
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
6975
|
+
| [`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. |
|
|
6966
6976
|
|
|
6967
6977
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
6968
6978
|
|
|
@@ -7196,7 +7206,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
7196
7206
|
|
|
7197
7207
|
| Prop | Type | Default | Description |
|
|
7198
7208
|
|---|---|---|---|
|
|
7199
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
7209
|
+
| [`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. |
|
|
7200
7210
|
|
|
7201
7211
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
7202
7212
|
|
|
@@ -7406,7 +7416,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
7406
7416
|
|
|
7407
7417
|
| Prop | Type | Default | Description |
|
|
7408
7418
|
|---|---|---|---|
|
|
7409
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
7419
|
+
| [`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. |
|
|
7410
7420
|
|
|
7411
7421
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
7412
7422
|
|
|
@@ -7827,7 +7837,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
7827
7837
|
|
|
7828
7838
|
| Prop | Type | Default | Description |
|
|
7829
7839
|
|---|---|---|---|
|
|
7830
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
7840
|
+
| [`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. |
|
|
7831
7841
|
|
|
7832
7842
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
7833
7843
|
|
|
@@ -8116,7 +8126,7 @@ From `ScheduleOptions` — the full table stands on [View](#/view/type-ScheduleO
|
|
|
8116
8126
|
|
|
8117
8127
|
| Prop | Type | Default | Description |
|
|
8118
8128
|
|---|---|---|---|
|
|
8119
|
-
| [`initialView`](#/view/ScheduleOptions-initialView) | [`ScheduleView`](#/view/type-ScheduleView) | — | The view to start from,
|
|
8129
|
+
| [`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. |
|
|
8120
8130
|
|
|
8121
8131
|
From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView).
|
|
8122
8132
|
|
|
@@ -8131,6 +8141,419 @@ From `ScheduleView` — the full table stands on [View](#/view/type-ScheduleView
|
|
|
8131
8141
|
|
|
8132
8142
|
What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
|
|
8133
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
|
+
|
|
8134
8557
|
## API index
|
|
8135
8558
|
|
|
8136
8559
|
Every name the package exports, in one place.
|
|
@@ -8147,14 +8570,14 @@ Demo page: https://romanhaendler.github.io/umriss-ui/schedule/api/
|
|
|
8147
8570
|
|
|
8148
8571
|
Declares a schedule: hands back `Schedule` and the parts declared inside it
|
|
8149
8572
|
- `Lane`, `LaneGroup`, `Subtasks`, `Dependencies`, `BlockedTimes`, `Milestones` -, its
|
|
8150
|
-
`view` and the setters `setDomain`, `toggleGroup`, `foldAll` and
|
|
8573
|
+
`view` and the setters `setView`, `setDomain`, `toggleGroup`, `foldAll` and
|
|
8151
8574
|
`unfoldAll`. A ref on `Schedule` still gives the `ScheduleHandle`.
|
|
8152
8575
|
|
|
8153
8576
|
```ts
|
|
8154
8577
|
function useSchedule(options?: ScheduleOptions): ScheduleParts;
|
|
8155
8578
|
```
|
|
8156
8579
|
|
|
8157
|
-
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)
|
|
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).
|
|
8158
8581
|
|
|
8159
8582
|
#### Functions
|
|
8160
8583
|
|
|
@@ -8334,7 +8757,7 @@ Its table stands on [Dependencies](#/dependencies/type-DependenciesProps).
|
|
|
8334
8757
|
|
|
8335
8758
|
Its table stands on [Dependencies](#/dependencies/type-Dependency).
|
|
8336
8759
|
|
|
8337
|
-
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)
|
|
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).
|
|
8338
8761
|
|
|
8339
8762
|
##### `DependencyAttachment`
|
|
8340
8763
|
|
|
@@ -8475,7 +8898,7 @@ Its table stands on [Findings as data](#/findings/type-Overlap).
|
|
|
8475
8898
|
##### `PlaceIntent`
|
|
8476
8899
|
|
|
8477
8900
|
Put work on the plan that was not on it: the answer to a drag from outside
|
|
8478
|
-
the schedule
|
|
8901
|
+
the schedule. It carries no subtask id - there is
|
|
8479
8902
|
no subtask yet; the caller creates one, with its own identity, from
|
|
8480
8903
|
`subtaskFromPlace`.
|
|
8481
8904
|
|
|
@@ -8492,9 +8915,9 @@ no subtask yet; the caller creates one, with its own identity, from
|
|
|
8492
8915
|
|
|
8493
8916
|
##### `PlacingItem`
|
|
8494
8917
|
|
|
8495
|
-
What the application says it is dragging in, while it drags it
|
|
8496
|
-
|
|
8497
|
-
the drop
|
|
8918
|
+
What the application says it is dragging in, while it drags it: the
|
|
8919
|
+
browser hands over the dragged data only on the drop, so the ghost before
|
|
8920
|
+
the drop can only come from the caller.
|
|
8498
8921
|
|
|
8499
8922
|
| Prop | Type | Default | Description |
|
|
8500
8923
|
|---|---|---|---|
|
|
@@ -8510,15 +8933,13 @@ Used on [Placing from outside](#/placing) and [Where a subtask may go](#/where-i
|
|
|
8510
8933
|
|
|
8511
8934
|
What the drawing needs to know, with the contradiction already settled.
|
|
8512
8935
|
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
now named after a drawing they no longer use, and the channel each one
|
|
8516
|
-
really owns stands beside it.
|
|
8936
|
+
Two of the field names (`dashed`, `hatched`) are older than the drawing;
|
|
8937
|
+
the channel each one owns stands beside it.
|
|
8517
8938
|
|
|
8518
8939
|
| Prop | Type | Default | Description |
|
|
8519
8940
|
|---|---|---|---|
|
|
8520
8941
|
| `dashed` *required* | `boolean` | — | `provisional`: the FILL - none at all, so the surface shows through, with a dashed outline in the task colour. Planned, not released. |
|
|
8521
|
-
| `hatched` *required* | `boolean` | — | `fixed`: the ENDS - a cap at each end of the main time. Not a hatch
|
|
8942
|
+
| `hatched` *required* | `boolean` | — | `fixed`: the ENDS - a cap at each end of the main time. Not a hatch: a hatch says "not available" of a refused lane. The field keeps the name `hatched`. |
|
|
8522
8943
|
| `muted` *required* | `boolean` | — | `muted`: the SATURATION - the task colour mixed half into the surface, opaque and at full height. Another team's, another crew's. |
|
|
8523
8944
|
| `open` *required* | `boolean` | — | `open`: the FADE, where the bar passes the edge of the view. It goes on past what is drawn. |
|
|
8524
8945
|
|
|
@@ -8552,7 +8973,7 @@ type ScheduleHit =
|
|
|
8552
8973
|
|
|
8553
8974
|
Its table stands on [Interactions](#/interactions/type-ScheduleInteraction).
|
|
8554
8975
|
|
|
8555
|
-
Used on [Scenarios](#/), [Interactions](#/interactions)
|
|
8976
|
+
Used on [Scenarios](#/), [Interactions](#/interactions), [Tooltip](#/tooltip) and [Benchmark](#/benchmark).
|
|
8556
8977
|
|
|
8557
8978
|
##### `ScheduleOptions`
|
|
8558
8979
|
|
|
@@ -8565,19 +8986,22 @@ it, its view and the setters that change it.
|
|
|
8565
8986
|
|
|
8566
8987
|
| Prop | Type | Default | Description |
|
|
8567
8988
|
|---|---|---|---|
|
|
8568
|
-
| `Schedule` *required* | `
|
|
8569
|
-
| `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
|
|
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 |
|
|
8570
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 |
|
|
8571
|
-
| `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
|
|
8572
|
-
| `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
|
|
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 |
|
|
8573
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 |
|
|
8574
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) |
|
|
8575
|
-
| `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), [
|
|
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 |
|
|
8997
|
+
| `setView` *required* | `(view: `[`ScheduleView`](#/view/type-ScheduleView)`) => void` | — | Goes to a whole view; what it leaves out is shown whole again. Not reported through `onViewChange`: two schedules kept in step by `onViewChange: (v) => other.setView(v)` in both directions do not answer each other. A view with the content already shown changes nothing.<br>Shown in: [Keep and restore a view (View)](#/view/keep-and-restore), [Keep two schedules in step (Linked schedules)](#/linked-schedules/in-step), [Read a rota beside the incidents (Linked schedules)](#/linked-schedules/rota-beside-incidents) |
|
|
8576
8998
|
| `setDomain` *required* | `(span: readonly [number, number] \| null) => void` | — | Puts a span of two wall-clock instants in view; `null` shows the subtasks' extent.<br>Shown in: [Keep and restore a view (View)](#/view/keep-and-restore) |
|
|
8577
8999
|
| `toggleGroup` *required* | `(id: string) => void` | — | Folds or unfolds one **Lane group**. |
|
|
8578
9000
|
| `foldAll` *required* | `() => void` | — | Folds every group.<br>Shown in: [Fold groups from outside (Lane groups)](#/lane-groups/fold-from-outside) |
|
|
8579
9001
|
| `unfoldAll` *required* | `() => void` | — | Unfolds every group.<br>Shown in: [Fold groups from outside (Lane groups)](#/lane-groups/fold-from-outside) |
|
|
8580
9002
|
|
|
9003
|
+
Used on [Linked schedules](#/linked-schedules).
|
|
9004
|
+
|
|
8581
9005
|
##### `ScheduleProps`
|
|
8582
9006
|
|
|
8583
9007
|
Its table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
@@ -8592,7 +9016,7 @@ Used on [Milestones](#/milestones) and [Tooltip](#/tooltip).
|
|
|
8592
9016
|
|
|
8593
9017
|
Its table stands on [View](#/view/type-ScheduleView).
|
|
8594
9018
|
|
|
8595
|
-
Used on [View](#/view)
|
|
9019
|
+
Used on [View](#/view).
|
|
8596
9020
|
|
|
8597
9021
|
##### `SnapRaster`
|
|
8598
9022
|
|
|
@@ -8620,7 +9044,7 @@ Stretch the main time at one or both of its edges.
|
|
|
8620
9044
|
|
|
8621
9045
|
Its table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
8622
9046
|
|
|
8623
|
-
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)
|
|
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).
|
|
8624
9048
|
|
|
8625
9049
|
##### `SubtaskAppearance`
|
|
8626
9050
|
|
|
@@ -8638,7 +9062,7 @@ Its table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
|
8638
9062
|
|
|
8639
9063
|
Its table stands on [Subtasks](#/subtasks/type-Task).
|
|
8640
9064
|
|
|
8641
|
-
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)
|
|
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).
|
|
8642
9066
|
|
|
8643
9067
|
##### `ViolatedDependency`
|
|
8644
9068
|
|