@umriss-ui/schedule 0.3.16 → 0.4.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 +60 -0
- package/README.md +6 -2
- package/dist/index.d.ts +62 -23
- package/dist/schedule.js +445 -440
- package/docs/llms-full.md +2467 -477
- package/package.json +6 -6
package/docs/llms-full.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# @umriss-ui/schedule 0.
|
|
1
|
+
# @umriss-ui/schedule 0.4.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
|
|
|
5
|
-
Install with `
|
|
5
|
+
Install with `npm install @umriss-ui/schedule @umriss-ui/core @umriss-ui/charts`. This text is generated from the package's demo (https://romanhaendler.github.io/umriss-ui/schedule/): every page with its import line, its examples - the source exactly as it runs, with the package name where the demo imports its own source - its props tables generated from the code, and what it deliberately does not do. The pages index stands in https://romanhaendler.github.io/umriss-ui/schedule/llms.txt.
|
|
6
6
|
|
|
7
7
|
## Scenarios
|
|
8
8
|
|
|
@@ -909,11 +909,15 @@ Install the schedule with its two peers and hand it plain data: lanes, tasks, su
|
|
|
909
909
|
import { Schedule, Lane, Subtasks, Dependencies } from "@umriss-ui/schedule";
|
|
910
910
|
```
|
|
911
911
|
|
|
912
|
+
```sh
|
|
913
|
+
npm install @umriss-ui/schedule @umriss-ui/core @umriss-ui/charts
|
|
914
|
+
```
|
|
915
|
+
|
|
912
916
|
Demo page: https://romanhaendler.github.io/umriss-ui/schedule/installation/
|
|
913
917
|
|
|
914
|
-
|
|
918
|
+
The command brings its two peers along: core for the formats and the wording, charts for the time scale and the operating calendar ([ADR-0022](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0022-the-schedule-is-a-package-that-depends-on-core-and-charts.md)). React 18 or 19 is a peer as well and stays the application's own. The stylesheets load themselves - each package's script imports its own, so there is nothing to import by hand; `@umriss-ui/schedule/styles.css` stays exported for setups that link stylesheets themselves.
|
|
915
919
|
|
|
916
|
-
The plan is plain data (ADR-0023). 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.
|
|
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.
|
|
917
921
|
|
|
918
922
|
The schedule reports, the application decides. It draws the data it is given and changes none of it: a drag ends in an intent reported to `onIntent`, and only the application's own state update moves a bar. Without `intents` the schedule is read-only - see [Move and lane](#/move-and-lane).
|
|
919
923
|
|
|
@@ -951,9 +955,74 @@ export default function SmallestSchedule() {
|
|
|
951
955
|
}
|
|
952
956
|
```
|
|
953
957
|
|
|
954
|
-
|
|
958
|
+
#### Keyboard
|
|
955
959
|
|
|
956
|
-
|
|
960
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
961
|
+
|
|
962
|
+
#### Props on this page
|
|
963
|
+
|
|
964
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
965
|
+
|
|
966
|
+
| Prop | Type | Default | Description |
|
|
967
|
+
|---|---|---|---|
|
|
968
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
969
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
970
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
971
|
+
|
|
972
|
+
###### Accessibility
|
|
973
|
+
|
|
974
|
+
| Prop | Type | Default | Description |
|
|
975
|
+
|---|---|---|---|
|
|
976
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
977
|
+
|
|
978
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
979
|
+
|
|
980
|
+
| Prop | Type | Default | Description |
|
|
981
|
+
|---|---|---|---|
|
|
982
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
983
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
984
|
+
|
|
985
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
986
|
+
|
|
987
|
+
| Prop | Type | Default | Description |
|
|
988
|
+
|---|---|---|---|
|
|
989
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
990
|
+
| [`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. |
|
|
991
|
+
|
|
992
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
993
|
+
|
|
994
|
+
| Prop | Type | Default | Description |
|
|
995
|
+
|---|---|---|---|
|
|
996
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
997
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
998
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
999
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
1000
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
1001
|
+
| [`leadIn`](#/subtasks/Subtask-leadIn) | `number` | — | Duration of the lead-in before the main time; none is zero. |
|
|
1002
|
+
| [`leadOut`](#/subtasks/Subtask-leadOut) | `number` | — | Duration of the lead-out after the main time; none is zero. |
|
|
1003
|
+
|
|
1004
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
1005
|
+
|
|
1006
|
+
| Prop | Type | Default | Description |
|
|
1007
|
+
|---|---|---|---|
|
|
1008
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
1009
|
+
| [`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. |
|
|
1010
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
1011
|
+
|
|
1012
|
+
From `DependenciesProps` — the full table stands on [Dependencies](#/dependencies/type-DependenciesProps).
|
|
1013
|
+
|
|
1014
|
+
| Prop | Type | Default | Description |
|
|
1015
|
+
|---|---|---|---|
|
|
1016
|
+
| [`data`](#/dependencies/DependenciesProps-data) *required* | `readonly `[`Dependency`](#/dependencies/type-Dependency)`[]` | — | The dependencies, as the caller holds them. |
|
|
1017
|
+
|
|
1018
|
+
From `Dependency` — the full table stands on [Dependencies](#/dependencies/type-Dependency).
|
|
1019
|
+
|
|
1020
|
+
| Prop | Type | Default | Description |
|
|
1021
|
+
|---|---|---|---|
|
|
1022
|
+
| [`id`](#/dependencies/Dependency-id) *required* | `string` | — | The caller's identity of the dependency. |
|
|
1023
|
+
| [`from`](#/dependencies/Dependency-from) *required* | `string` | — | The id of the subtask it leaves. |
|
|
1024
|
+
| [`to`](#/dependencies/Dependency-to) *required* | `string` | — | The id of the subtask it arrives at. |
|
|
1025
|
+
| [`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. |
|
|
957
1026
|
|
|
958
1027
|
### First schedule
|
|
959
1028
|
|
|
@@ -969,7 +1038,7 @@ Lanes stand in the order they are declared; a subtask on a lane that is not decl
|
|
|
969
1038
|
|
|
970
1039
|
What cannot work is drawn, never repaired: two subtasks on one lane at once, a dependency whose lag does not fit, work in blocked time. [Findings as data](#/findings) returns the same list for the application to act on.
|
|
971
1040
|
|
|
972
|
-
The plot is one tab stop. The keys walk the subtasks as the pointer would hover them, the tooltip names the active one, and a live region reads it once the keys rest (ADR-0030, ADR-0033).
|
|
1041
|
+
The plot is one tab stop. The keys walk the subtasks as the pointer would hover them, the tooltip names the active one, and a live region reads it once the keys rest ([ADR-0030](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0030-a-chart-is-one-tab-stop-that-walks-its-hits.md), [ADR-0033](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0033-the-schedules-keys-walk-past-the-view.md)).
|
|
973
1042
|
|
|
974
1043
|
#### Examples
|
|
975
1044
|
|
|
@@ -1181,48 +1250,271 @@ export default function MachinePlan() {
|
|
|
1181
1250
|
| `Alt+← / Alt+→` | Proposes a move by one step of the raster, where the application handles `move`. |
|
|
1182
1251
|
| `Alt+Shift+← / →` | Proposes a new end, where the application handles `stretch`. |
|
|
1183
1252
|
|
|
1253
|
+
#### Accessibility
|
|
1254
|
+
|
|
1255
|
+
The schedule is a figure named by `ariaLabel`, and its plot one tab stop with the role `application`, read as "schedule" (`aria-roledescription`), named alike and described by a summary: the lanes, the subtasks in view, the visible span, the findings by kind, then the keys. The canvas is hidden from a reader; the lane headers are text, and a group's fold button is named "Fold group" or "Unfold group" with the group's label. `ariaLabel` is required - name what the plan shows, "Plan of week 38".
|
|
1256
|
+
|
|
1257
|
+
When a key comes to rest, a polite live region beside the plot reads the active subtask: its lane, task and name, the day and the times, and every finding on it by name - an overlap, a dependency short by how much, blocked time. On a dependency it reads the task, the lag and where the line runs. A pointer announces nothing; [Findings as data](#/findings) gives the application the same findings to list. The words are core's wording, so under `@umriss-ui/core/wording/de` the plot is read as "Belegungsplan".
|
|
1258
|
+
|
|
1259
|
+
Under forced colours the plot paints itself in the system colours: the work in the text colour, told apart by lane and label; the active subtask in the selection colour; findings marked by a dash; grips and the ghost's label outlined. With reduced motion a group's chevron turns without its movement.
|
|
1260
|
+
|
|
1184
1261
|
#### API
|
|
1185
1262
|
|
|
1186
1263
|
##### `ScheduleProps`
|
|
1187
1264
|
|
|
1188
1265
|
| Prop | Type | Default | Description |
|
|
1189
1266
|
|---|---|---|---|
|
|
1190
|
-
| `
|
|
1191
|
-
| `
|
|
1192
|
-
| `
|
|
1193
|
-
| `
|
|
1194
|
-
| `
|
|
1195
|
-
| `
|
|
1196
|
-
| `
|
|
1197
|
-
| `
|
|
1198
|
-
| `
|
|
1199
|
-
| `
|
|
1200
|
-
| `
|
|
1201
|
-
| `
|
|
1202
|
-
| `
|
|
1203
|
-
| `
|
|
1204
|
-
| `
|
|
1205
|
-
| `
|
|
1206
|
-
| `
|
|
1207
|
-
| `
|
|
1208
|
-
| `
|
|
1209
|
-
| `
|
|
1210
|
-
| `
|
|
1211
|
-
| `
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1267
|
+
| `initialDomain` *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back.<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 74 more |
|
|
1268
|
+
| `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 74 more |
|
|
1269
|
+
| `laneHeight` | `number` | `44` | Height of one lane in pixels.<br>Shown in: [Scroll more lanes than fit (Lanes)](#/lane/many-lanes) |
|
|
1270
|
+
| `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 |
|
|
1271
|
+
| `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) |
|
|
1272
|
+
| `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) |
|
|
1273
|
+
| `snap` | `"ticks" \| number \| `[`SnapRaster`](#type-SnapRaster)` \| false` | `"ticks"` | The raster a drag lands on: `"ticks"` - the fine band's current step -, a step in milliseconds from local midnight, a step with an offset (shifts at 06:00, 14:00 and 22:00 are eight hours offset by six), or `false` for none. It shapes the ghost and the intent, never the data.<br>Shown in: [Snap to a duration (Snapping)](#/snapping/snap-to-a-duration), [Snap to handover times (Snapping)](#/snapping/snap-to-handovers), [Place without snapping (Snapping)](#/snapping/no-snapping) |
|
|
1274
|
+
| `intents` | `readonly `[`IntentKind`](#type-IntentKind)`[]` | `[]` | The intents the caller handles. Each one enables its interaction; none leaves a read-only schedule ([ADR-0023](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0023-editing-is-controlled-the-schedule-reports-intents.md)).<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 |
|
|
1275
|
+
| `canMoveTo` | `(subtask: `[`Subtask`](#/subtasks/type-Subtask)`, lane: string) => boolean` | every lane is open | Whether a subtask may go to a lane. It narrows `"lane"`, it does not enable it. Asked once per lane when a drag takes hold, and asked again at the drop. The lanes it turns down are marked from the first frame of the drag - a planner sees the refusal before meeting it - and over one of them the ghost stays on the last lane that was allowed, the cursor says no and a line ties the ghost to the pointer. A refused lane costs the lane and nothing else: a drop after it still reports the move in time. It is asked for work dragged in from outside as well, with the key and task the application declared in `placing`.<br>Shown in: [Keep work on the lanes that fit (Where a subtask may go)](#/where-it-may-go/lanes-that-fit), [Apply the same rule to work dragged in (Where a subtask may go)](#/where-it-may-go/dragged-in), [Keep work out of someone's leave (Where a subtask may go)](#/where-it-may-go/around-leave) and 1 more |
|
|
1276
|
+
| `selectedTask` | `string \| null` | — | The selected task, controlled. Leave it out and the schedule keeps the selection itself.<br>Shown in: [Control the selection (Selection)](#/selection/control-the-selection) |
|
|
1277
|
+
| `onSelectedTaskChange` | `(task: string \| null, subtask: string \| null) => void` | — | Called when a click selects a task or clears the selection, with the subtask that was clicked - null where the click was on a dependency or on nothing. It is called again when another subtask of the same task is clicked.<br>Shown in: [Control the selection (Selection)](#/selection/control-the-selection) |
|
|
1278
|
+
| `defaultCollapsedGroups` | `readonly string[]` | — | Which groups are folded when the schedule mounts, where the schedule keeps the state itself. Ignored while `collapsedGroups` is given.<br>Shown in: [Start with groups folded (Lane groups)](#/lane-groups/start-with-groups-folded) |
|
|
1279
|
+
| `collapsedGroups` | `readonly string[]` | — | The **Lane group**s that are folded, controlled. Leave it out and the schedule keeps them itself, starting from `defaultCollapsedGroups`. Folding changes the view and not the plan, which is why it is no intent: a caller that applies every intent it receives must never find a fold among them ([ADR-0025](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0025-a-lane-group-is-structure-over-lanes-never-a-lane.md)). A folded outer group hides the inner ones without their entries leaving the list, so unfolding it gives back the view that was there.<br>Shown in: [Fold groups from outside (Lane groups)](#/lane-groups/controlled), [Read a folded group (Lane groups)](#/lane-groups/the-miniature) |
|
|
1280
|
+
| `onCollapsedGroupsChange` | `(groups: readonly string[]) => void` | — | Called with the whole list when the planner folds or unfolds a group.<br>Shown in: [Fold groups from outside (Lane groups)](#/lane-groups/controlled), [Read a folded group (Lane groups)](#/lane-groups/the-miniature) |
|
|
1281
|
+
| `placing` | [`PlacingItem`](#type-PlacingItem)` \| null` | — | What the application is dragging in from outside while it drags it - its key, task, the length of its main time, its lead-in and lead-out. The browser hands the dragged data over only on the drop, so the ghost before it can only come from here: set it on your own `dragstart`, clear it on `dragend`. Without `"place"` in `intents` no drop is accepted.<br>Shown in: [Drag work in from the backlog (Placing from outside)](#/placing/drag-from-the-backlog), [Apply the same rule to work dragged in (Where a subtask may go)](#/where-it-may-go/dragged-in) |
|
|
1282
|
+
| `route` | [`DependencyRoute`](#type-DependencyRoute)<br>`"curve" \| "straight" \| "orthogonal"` | `"curve"` | How the dependencies are drawn: a `"curve"` that leaves and arrives forwards, a `"straight"` line, or `"orthogonal"` segments. A dependency may say otherwise for itself.<br>Shown in: [Straight (Routes)](#/routes/straight), [Orthogonal (Routes)](#/routes/orthogonal), [Per dependency (Routes)](#/routes/per-dependency) |
|
|
1283
|
+
| `attach` | [`DependencyAttachment`](#type-DependencyAttachment)<br>`"centre" \| "nearest"` | `"centre"` | Where a dependency's ends sit on their bars: the `"centre"` of both, or the `"nearest"` edge - which is the shortest line between two stops. Within one lane both mean the middle. A dependency may say otherwise for itself. It changes the picture and never a finding: whether a dependency is violated follows from its `leaves` and `arrives` alone.<br>Shown in: [Choose where a line touches its bars (Dependencies)](#/dependencies/attach), [Mark the ends with a dot (Dependencies)](#/dependencies/ends), [Draw one handover its own way (Dependencies)](#/dependencies/one-handover-drawn-its-own-way) and 3 more |
|
|
1284
|
+
| `ends` | [`DependencyEnds`](#type-DependencyEnds)<br>`"dot" \| "none"` | `"dot"` | Whether a dependency's two ends carry a dot (`"dot"`) or the line stands alone (`"none"`). The dot says where the line is anchored - a help while a plan is being read, and noise in a plan full of short moves. A dependency may say otherwise for itself.<br>Shown in: [Mark the ends with a dot (Dependencies)](#/dependencies/ends), [Draw one handover its own way (Dependencies)](#/dependencies/one-handover-drawn-its-own-way) |
|
|
1285
|
+
| `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 |
|
|
1286
|
+
| `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: [Write your own tooltip content (Tooltip)](#/tooltip/own-tooltip), [Show a detail panel instead (Tooltip)](#/tooltip/detail-panel-instead), [Say what a bar covers and a line joins (Tooltip)](#/tooltip/say-what-a-bar-covers-and-a-line-joins) |
|
|
1287
|
+
| `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 |
|
|
1288
|
+
| `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 74 more |
|
|
1289
|
+
|
|
1290
|
+
###### Events
|
|
1291
|
+
|
|
1292
|
+
| Prop | Type | Default | Description |
|
|
1293
|
+
|---|---|---|---|
|
|
1294
|
+
| `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 |
|
|
1295
|
+
| `onInteraction` | `(interaction: `[`ScheduleInteraction`](#/interactions/type-ScheduleInteraction)`) => void` | — | Click, context menu and hover, with what the pointer is on and where. While it is set, a right-click opens no browser menu.<br>Shown in: [Report what the pointer is on (Interactions)](#/interactions/report-the-pointer), [Open a context menu (Interactions)](#/interactions/open-a-context-menu), [Show a detail panel instead (Tooltip)](#/tooltip/detail-panel-instead) and 2 more |
|
|
1296
|
+
| `onDomainChange` | `(domain: readonly [number, number]) => void` | — | The visible time span after the planner panned or zoomed, as two wall-clock instants - for keeping a second schedule or a chart in step. A span handed in through `initialDomain` is not reported back.<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), [Place a mark of your own (The handle)](#/handle/place-a-mark) |
|
|
1297
|
+
|
|
1298
|
+
###### Accessibility
|
|
1299
|
+
|
|
1300
|
+
| Prop | Type | Default | Description |
|
|
1301
|
+
|---|---|---|---|
|
|
1302
|
+
| `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 74 more |
|
|
1303
|
+
|
|
1304
|
+
###### Styling
|
|
1305
|
+
|
|
1306
|
+
| Prop | Type | Default | Description |
|
|
1307
|
+
|---|---|---|---|
|
|
1215
1308
|
| `className` | `string` | — | Goes to the root element. |
|
|
1216
1309
|
| `style` | `CSSProperties` | — | Goes to the root element. |
|
|
1217
|
-
|
|
1310
|
+
|
|
1311
|
+
##### Types on this page
|
|
1312
|
+
|
|
1313
|
+
###### `CalendarInput`
|
|
1314
|
+
|
|
1315
|
+
From `@umriss-ui/charts`.
|
|
1316
|
+
|
|
1317
|
+
Every function of this module takes either: the raw list as it stands on the
|
|
1318
|
+
axis, or the calendar built from it.
|
|
1319
|
+
|
|
1320
|
+
```ts
|
|
1321
|
+
type CalendarInput = WorkingCalendar | readonly WorkingInterval[];
|
|
1322
|
+
```
|
|
1323
|
+
|
|
1324
|
+
###### `ZoomLimits`
|
|
1325
|
+
|
|
1326
|
+
The narrowest and the widest span zoom may reach.
|
|
1327
|
+
|
|
1328
|
+
| Prop | Type | Default | Description |
|
|
1329
|
+
|---|---|---|---|
|
|
1330
|
+
| `min` *required* | `number` | — | <br>Shown in: [Move through the plan (Pan and zoom)](#/pan-and-zoom/pan-and-zoom) |
|
|
1331
|
+
| `max` *required* | `number` | — | <br>Shown in: [Move through the plan (Pan and zoom)](#/pan-and-zoom/pan-and-zoom) |
|
|
1332
|
+
|
|
1333
|
+
###### `SnapRaster`
|
|
1334
|
+
|
|
1335
|
+
A raster: a step, and where it starts after local midnight.
|
|
1336
|
+
|
|
1337
|
+
| Prop | Type | Default | Description |
|
|
1338
|
+
|---|---|---|---|
|
|
1339
|
+
| `step` *required* | `number` | — | The distance between two lines of the raster, in milliseconds.<br>Shown in: [Snap to handover times (Snapping)](#/snapping/snap-to-handovers) |
|
|
1340
|
+
| `offset` *required* | `number` | — | Where the raster starts after local midnight, in milliseconds: six hours for handovers at 06:00, 14:00 and 22:00.<br>Shown in: [Snap to handover times (Snapping)](#/snapping/snap-to-handovers) |
|
|
1341
|
+
|
|
1342
|
+
###### `IntentKind`
|
|
1343
|
+
|
|
1344
|
+
The names of the intents - the editing API of the schedule.
|
|
1345
|
+
|
|
1346
|
+
```ts
|
|
1347
|
+
type IntentKind = Intent["kind"];
|
|
1348
|
+
```
|
|
1349
|
+
|
|
1350
|
+
###### `PlacingItem`
|
|
1351
|
+
|
|
1352
|
+
What the application says it is dragging in, while it drags it
|
|
1353
|
+
(schedule-refinement 07): the browser hands over the dragged data only on
|
|
1354
|
+
the drop, so the ghost before the drop can only come from the caller.
|
|
1355
|
+
|
|
1356
|
+
| Prop | Type | Default | Description |
|
|
1357
|
+
|---|---|---|---|
|
|
1358
|
+
| `item` *required* | `string` | — | The caller's key for the dragged item; it comes back in the intent.<br>Shown in: [Drag work in from the backlog (Placing from outside)](#/placing/drag-from-the-backlog), [Apply the same rule to work dragged in (Where a subtask may go)](#/where-it-may-go/dragged-in) |
|
|
1359
|
+
| `task` *required* | `string` | — | The task the work belongs to.<br>Shown in: [Drag work in from the backlog (Placing from outside)](#/placing/drag-from-the-backlog), [Apply the same rule to work dragged in (Where a subtask may go)](#/where-it-may-go/dragged-in) |
|
|
1360
|
+
| `duration` *required* | `number` | — | How long its main time is.<br>Shown in: [Drag work in from the backlog (Placing from outside)](#/placing/drag-from-the-backlog), [Apply the same rule to work dragged in (Where a subtask may go)](#/where-it-may-go/dragged-in) |
|
|
1361
|
+
| `leadIn` | `number` | — | The lead-in it brings. |
|
|
1362
|
+
| `leadOut` | `number` | — | The lead-out it brings. |
|
|
1363
|
+
|
|
1364
|
+
###### `DependencyRoute`
|
|
1365
|
+
|
|
1366
|
+
How a dependency is drawn between its two ends: a curve that leaves and
|
|
1367
|
+
arrives forwards, a straight line, or axis-parallel segments.
|
|
1368
|
+
|
|
1369
|
+
```ts
|
|
1370
|
+
type DependencyRoute = "curve" | "straight" | "orthogonal";
|
|
1371
|
+
```
|
|
1372
|
+
|
|
1373
|
+
###### `DependencyAttachment`
|
|
1374
|
+
|
|
1375
|
+
Where on its bars a dependency's line attaches: the middle of both, or the
|
|
1376
|
+
edge that faces the other stop - which is the shortest line between them.
|
|
1377
|
+
|
|
1378
|
+
Deliberately not called an anchor: a dependency already HAS two anchors
|
|
1379
|
+
(`leaves`, `arrives`), and those decide what it connects and therefore
|
|
1380
|
+
whether it is violated. This decides where the line touches, and nothing else.
|
|
1381
|
+
The tree has an **Anchor** of its own as well (CONTEXT.md).
|
|
1382
|
+
|
|
1383
|
+
```ts
|
|
1384
|
+
type DependencyAttachment = "centre" | "nearest";
|
|
1385
|
+
```
|
|
1386
|
+
|
|
1387
|
+
###### `DependencyEnds`
|
|
1388
|
+
|
|
1389
|
+
Whether a dependency's two ends carry a dot. The dot says where the line is
|
|
1390
|
+
anchored, which is worth saying while a plan is being read and is noise in a
|
|
1391
|
+
plan full of short moves - so it is the caller's choice.
|
|
1392
|
+
|
|
1393
|
+
```ts
|
|
1394
|
+
type DependencyEnds = "dot" | "none";
|
|
1395
|
+
```
|
|
1396
|
+
|
|
1397
|
+
###### `Intent`
|
|
1398
|
+
|
|
1399
|
+
What the schedule reports when an interaction asks for a change. Every
|
|
1400
|
+
intent carries the values it asks for, not a difference: two intents of one
|
|
1401
|
+
drop - a move and a lane - give the same data in either order.
|
|
1402
|
+
|
|
1403
|
+
```ts
|
|
1404
|
+
type Intent = MoveIntent | StretchIntent | LeadInIntent | LeadOutIntent | LaneIntent | PlaceIntent;
|
|
1405
|
+
```
|
|
1406
|
+
|
|
1407
|
+
###### `WorkingCalendar`
|
|
1408
|
+
|
|
1409
|
+
From `@umriss-ui/charts`.
|
|
1410
|
+
|
|
1411
|
+
A working calendar: sorted, merged intervals with the working time
|
|
1412
|
+
accumulated before each one begins. An empty calendar is no calendar: it maps
|
|
1413
|
+
unchanged.
|
|
1414
|
+
|
|
1415
|
+
Build once, then pass around: the mapping runs once per point, and were it to
|
|
1416
|
+
sort and accumulate every time, the calendar would be the most expensive
|
|
1417
|
+
thing about the frame.
|
|
1418
|
+
|
|
1419
|
+
| Prop | Type | Default | Description |
|
|
1420
|
+
|---|---|---|---|
|
|
1421
|
+
| `intervals` *required* | `readonly `[`WorkingInterval`](#type-WorkingInterval)`[]` | — | |
|
|
1422
|
+
| `offsets` *required* | `readonly number[]` | — | Working time accumulated before the respective interval begins. |
|
|
1423
|
+
| `total` *required* | `number` | — | The whole working time - the axis' extent is [0, total]. |
|
|
1424
|
+
|
|
1425
|
+
###### `WorkingInterval`
|
|
1426
|
+
|
|
1427
|
+
From `@umriss-ui/charts`.
|
|
1428
|
+
|
|
1429
|
+
An interval in which time counts; thought of as half-open, but mappable from
|
|
1430
|
+
both sides at its edges: both `from` and `to` have a working time.
|
|
1431
|
+
|
|
1432
|
+
| Prop | Type | Default | Description |
|
|
1433
|
+
|---|---|---|---|
|
|
1434
|
+
| `from` *required* | `number` | — | |
|
|
1435
|
+
| `to` *required* | `number` | — | |
|
|
1436
|
+
|
|
1437
|
+
###### `MoveIntent`
|
|
1438
|
+
|
|
1439
|
+
Move the subtask in time: the main time keeps its length.
|
|
1440
|
+
|
|
1441
|
+
| Prop | Type | Default | Description |
|
|
1442
|
+
|---|---|---|---|
|
|
1443
|
+
| `kind` *required* | `"move"` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 8 more |
|
|
1444
|
+
| `subtask` *required* | `string` | — | The id of the subtask.<br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 5 more |
|
|
1445
|
+
| `from` *required* | `number` | — | The new start of the main time.<br>Shown in: [Push the later stops of a tour (Ripple)](#/ripple/push-the-later-stops), [Replan the day on the line (Scenarios)](#/scenarios/replan-the-day-on-the-line) |
|
|
1446
|
+
| `to` *required* | `number` | — | The new end of the main time.<br>Shown in: [Push the later stops of a tour (Ripple)](#/ripple/push-the-later-stops), [Replan the day on the line (Scenarios)](#/scenarios/replan-the-day-on-the-line) |
|
|
1447
|
+
|
|
1448
|
+
###### `StretchIntent`
|
|
1449
|
+
|
|
1450
|
+
Stretch the main time at one or both of its edges.
|
|
1451
|
+
|
|
1452
|
+
| Prop | Type | Default | Description |
|
|
1453
|
+
|---|---|---|---|
|
|
1454
|
+
| `kind` *required* | `"stretch"` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 7 more |
|
|
1455
|
+
| `subtask` *required* | `string` | — | The id of the subtask.<br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 4 more |
|
|
1456
|
+
| `from` *required* | `number` | — | The new start of the main time. |
|
|
1457
|
+
| `to` *required* | `number` | — | The new end of the main time. |
|
|
1458
|
+
|
|
1459
|
+
###### `LeadInIntent`
|
|
1460
|
+
|
|
1461
|
+
Change the lead-in on its own.
|
|
1462
|
+
|
|
1463
|
+
| Prop | Type | Default | Description |
|
|
1464
|
+
|---|---|---|---|
|
|
1465
|
+
| `kind` *required* | `"leadIn"` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 7 more |
|
|
1466
|
+
| `subtask` *required* | `string` | — | The id of the subtask.<br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 4 more |
|
|
1467
|
+
| `leadIn` *required* | `number` | — | The new duration of the lead-in.<br>Shown in: [Replan the day on the line (Scenarios)](#/scenarios/replan-the-day-on-the-line) |
|
|
1468
|
+
|
|
1469
|
+
###### `LeadOutIntent`
|
|
1470
|
+
|
|
1471
|
+
Change the lead-out on its own.
|
|
1472
|
+
|
|
1473
|
+
| Prop | Type | Default | Description |
|
|
1474
|
+
|---|---|---|---|
|
|
1475
|
+
| `kind` *required* | `"leadOut"` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 7 more |
|
|
1476
|
+
| `subtask` *required* | `string` | — | The id of the subtask.<br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 4 more |
|
|
1477
|
+
| `leadOut` *required* | `number` | — | The new duration of the lead-out. |
|
|
1478
|
+
|
|
1479
|
+
###### `LaneIntent`
|
|
1480
|
+
|
|
1481
|
+
Put the subtask on another lane.
|
|
1482
|
+
|
|
1483
|
+
| Prop | Type | Default | Description |
|
|
1484
|
+
|---|---|---|---|
|
|
1485
|
+
| `kind` *required* | `"lane"` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 7 more |
|
|
1486
|
+
| `subtask` *required* | `string` | — | The id of the subtask.<br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 4 more |
|
|
1487
|
+
| `lane` *required* | `string` | — | The id of the new lane. |
|
|
1488
|
+
|
|
1489
|
+
###### `PlaceIntent`
|
|
1490
|
+
|
|
1491
|
+
Put work on the plan that was not on it: the answer to a drag from outside
|
|
1492
|
+
the schedule (schedule-refinement 07). It carries no subtask id - there is
|
|
1493
|
+
no subtask yet; the caller creates one, with its own identity, from
|
|
1494
|
+
`subtaskFromPlace`.
|
|
1495
|
+
|
|
1496
|
+
| Prop | Type | Default | Description |
|
|
1497
|
+
|---|---|---|---|
|
|
1498
|
+
| `kind` *required* | `"place"` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 7 more |
|
|
1499
|
+
| `item` *required* | `string` | — | The caller's key for the dragged item, as it declared it while dragging.<br>Shown in: [Drag work in from the backlog (Placing from outside)](#/placing/drag-from-the-backlog), [Apply the same rule to work dragged in (Where a subtask may go)](#/where-it-may-go/dragged-in), [Replan the day on the line (Scenarios)](#/scenarios/replan-the-day-on-the-line) |
|
|
1500
|
+
| `task` *required* | `string` | — | The task the work belongs to. |
|
|
1501
|
+
| `lane` *required* | `string` | — | The lane it was dropped on.<br>Shown in: [Drag work in from the backlog (Placing from outside)](#/placing/drag-from-the-backlog), [Apply the same rule to work dragged in (Where a subtask may go)](#/where-it-may-go/dragged-in) |
|
|
1502
|
+
| `from` *required* | `number` | — | Where its main time would start. |
|
|
1503
|
+
| `to` *required* | `number` | — | Where its main time would end. |
|
|
1504
|
+
| `leadIn` | `number` | — | The lead-in it was declared with. |
|
|
1505
|
+
| `leadOut` | `number` | — | The lead-out it was declared with. |
|
|
1218
1506
|
|
|
1219
1507
|
#### Known limits
|
|
1220
1508
|
|
|
1221
|
-
- No dependency types, critical path or auto-scheduling: the application decides where work goes, the schedule shows the result and its findings (ADR-0032).
|
|
1509
|
+
- No dependency types, critical path or auto-scheduling: the application decides where work goes, the schedule shows the result and its findings ([ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/)).
|
|
1222
1510
|
- No milestones yet: a point in time on a lane has no mark of its own.
|
|
1223
1511
|
- A dependency joins two subtasks of one task; dependencies across tasks are not yet possible.
|
|
1224
1512
|
|
|
1225
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.
|
|
1513
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
|
|
1514
|
+
|
|
1515
|
+
## Plan
|
|
1516
|
+
|
|
1517
|
+
What the schedule draws: work on lanes, and everything a bar says besides its colour.
|
|
1226
1518
|
|
|
1227
1519
|
### Lanes
|
|
1228
1520
|
|
|
@@ -1342,14 +1634,18 @@ export default function ManyLanes() {
|
|
|
1342
1634
|
|
|
1343
1635
|
- Lanes that belong together, folded into one row → Lane groups
|
|
1344
1636
|
|
|
1637
|
+
#### Keyboard
|
|
1638
|
+
|
|
1639
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
1640
|
+
|
|
1345
1641
|
#### API
|
|
1346
1642
|
|
|
1347
1643
|
##### `LaneProps`
|
|
1348
1644
|
|
|
1349
1645
|
| Prop | Type | Default | Description |
|
|
1350
1646
|
|---|---|---|---|
|
|
1351
|
-
| `id`
|
|
1352
|
-
| `label` | `ReactNode` |
|
|
1647
|
+
| `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 74 more |
|
|
1648
|
+
| `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 74 more |
|
|
1353
1649
|
|
|
1354
1650
|
### Lane groups
|
|
1355
1651
|
|
|
@@ -1361,7 +1657,7 @@ import { LaneGroup, Lane } from "@umriss-ui/schedule";
|
|
|
1361
1657
|
|
|
1362
1658
|
Demo page: https://romanhaendler.github.io/umriss-ui/schedule/lane-groups/
|
|
1363
1659
|
|
|
1364
|
-
A group is structure, never a lane: nothing sits on it, no finding is reported for it and no intent names it (ADR-0025). The lanes keep the order they were declared in, whatever group they are in.
|
|
1660
|
+
A group is structure, never a lane: nothing sits on it, no finding is reported for it and no intent names it ([ADR-0025](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0025-a-lane-group-is-structure-over-lanes-never-a-lane.md)). The lanes keep the order they were declared in, whatever group they are in.
|
|
1365
1661
|
|
|
1366
1662
|
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.
|
|
1367
1663
|
|
|
@@ -1605,6 +1901,50 @@ export default function TheMiniature() {
|
|
|
1605
1901
|
}
|
|
1606
1902
|
```
|
|
1607
1903
|
|
|
1904
|
+
##### Start with groups folded
|
|
1905
|
+
|
|
1906
|
+
`defaultCollapsedGroups` folds groups when the schedule mounts and leaves the rest to the planner: Discovery starts folded, and its chevron opens it.
|
|
1907
|
+
|
|
1908
|
+
```tsx
|
|
1909
|
+
import { Lane, LaneGroup, Schedule, Subtasks } from "@umriss-ui/schedule";
|
|
1910
|
+
import type { Subtask, Task } from "@umriss-ui/schedule";
|
|
1911
|
+
|
|
1912
|
+
/* Uncontrolled: the schedule keeps the fold from here on. To store it or
|
|
1913
|
+
steer it, pass `collapsedGroups` instead. */
|
|
1914
|
+
|
|
1915
|
+
const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
|
|
1916
|
+
|
|
1917
|
+
const TASKS: Task[] = [{ id: "release", name: "Release 4.12", color: "light-dark(#0d9488, #3cc7b8)" }];
|
|
1918
|
+
|
|
1919
|
+
const WORK: Subtask[] = [
|
|
1920
|
+
{ id: "s1", task: "release", lane: "priya", from: at(7), to: at(9) },
|
|
1921
|
+
{ id: "s2", task: "release", lane: "jonas", from: at(9, 30), to: at(11) },
|
|
1922
|
+
{ id: "s3", task: "release", lane: "tomasz", from: at(11, 30), to: at(13) },
|
|
1923
|
+
{ id: "s4", task: "release", lane: "leila", from: at(13), to: at(14, 30) },
|
|
1924
|
+
];
|
|
1925
|
+
|
|
1926
|
+
export default function StartWithGroupsFolded() {
|
|
1927
|
+
return (
|
|
1928
|
+
<Schedule
|
|
1929
|
+
ariaLabel="Two teams rolling out a release, Discovery folded at the start"
|
|
1930
|
+
initialDomain={[at(6), at(15)]}
|
|
1931
|
+
height={280}
|
|
1932
|
+
defaultCollapsedGroups={["discovery"]}
|
|
1933
|
+
>
|
|
1934
|
+
<LaneGroup id="payments" label="Payments">
|
|
1935
|
+
<Lane id="priya" label="Priya Raman" />
|
|
1936
|
+
<Lane id="jonas" label="Jonas Keller" />
|
|
1937
|
+
</LaneGroup>
|
|
1938
|
+
<LaneGroup id="discovery" label="Discovery">
|
|
1939
|
+
<Lane id="tomasz" label="Tomasz Nowak" />
|
|
1940
|
+
<Lane id="leila" label="Leila Haddad" />
|
|
1941
|
+
</LaneGroup>
|
|
1942
|
+
<Subtasks data={WORK} tasks={TASKS} />
|
|
1943
|
+
</Schedule>
|
|
1944
|
+
);
|
|
1945
|
+
}
|
|
1946
|
+
```
|
|
1947
|
+
|
|
1608
1948
|
#### Keyboard
|
|
1609
1949
|
|
|
1610
1950
|
| Key | Action |
|
|
@@ -1612,21 +1952,23 @@ export default function TheMiniature() {
|
|
|
1612
1952
|
| `Tab` | Reaches each group's fold button - the only buttons the schedule puts in the tab order. |
|
|
1613
1953
|
| `Enter / Space` | Folds or unfolds the group. |
|
|
1614
1954
|
|
|
1955
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
1956
|
+
|
|
1615
1957
|
#### API
|
|
1616
1958
|
|
|
1617
1959
|
##### `LaneGroupProps`
|
|
1618
1960
|
|
|
1619
1961
|
| Prop | Type | Default | Description |
|
|
1620
1962
|
|---|---|---|---|
|
|
1621
|
-
| `id`
|
|
1622
|
-
| `label` | `ReactNode` |
|
|
1623
|
-
| `children` | `ReactNode` | — | `Lane`s and further `LaneGroup`s, to any depth
|
|
1963
|
+
| `id` *required* | `string` | — | The group's identity - what `collapsedGroups` names. It is never a lane: no subtask sits on it, no finding is reported for it, and no intent names it ([ADR-0025](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0025-a-lane-group-is-structure-over-lanes-never-a-lane.md)).<br>Shown in: [Group lanes under a head](#/lane-groups/a-group), [Nest groups to any depth](#/lane-groups/nesting), [Fold groups from outside](#/lane-groups/controlled) and 4 more |
|
|
1964
|
+
| `label` | `ReactNode` | `id` | What the group's header says - the team, the depot, the region. Real text, read by a screen reader.<br>Shown in: [Group lanes under a head](#/lane-groups/a-group), [Nest groups to any depth](#/lane-groups/nesting), [Fold groups from outside](#/lane-groups/controlled) and 4 more |
|
|
1965
|
+
| `children` | `ReactNode` | — | `Lane`s and further `LaneGroup`s, to any depth.<br>Shown in: [Group lanes under a head](#/lane-groups/a-group), [Nest groups to any depth](#/lane-groups/nesting), [Fold groups from outside](#/lane-groups/controlled) and 4 more |
|
|
1624
1966
|
|
|
1625
1967
|
#### Known limits
|
|
1626
1968
|
|
|
1627
|
-
- A folded group shows no summary - no utilisation band, no bar spanning its work: a computed claim would look like a drawn fact (ADR-0025).
|
|
1969
|
+
- A folded group shows no summary - no utilisation band, no bar spanning its work: a computed claim would look like a drawn fact ([ADR-0025](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0025-a-lane-group-is-structure-over-lanes-never-a-lane.md)).
|
|
1628
1970
|
|
|
1629
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.
|
|
1971
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
|
|
1630
1972
|
|
|
1631
1973
|
### Subtasks
|
|
1632
1974
|
|
|
@@ -1815,37 +2157,51 @@ export default function ASprint() {
|
|
|
1815
2157
|
}
|
|
1816
2158
|
```
|
|
1817
2159
|
|
|
2160
|
+
#### Keyboard
|
|
2161
|
+
|
|
2162
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
2163
|
+
|
|
1818
2164
|
#### API
|
|
1819
2165
|
|
|
1820
2166
|
##### `SubtasksProps`
|
|
1821
2167
|
|
|
1822
2168
|
| Prop | Type | Default | Description |
|
|
1823
2169
|
|---|---|---|---|
|
|
1824
|
-
| `data`
|
|
1825
|
-
| `tasks`
|
|
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 74 more |
|
|
2171
|
+
| `tasks` *required* | `readonly `[`Task`](#type-Task)`[]` | — | The tasks the subtasks belong to - their identity and their colour. A subtask whose task is not among them is drawn in a muted colour.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [Plan a sprint for a team](#/subtasks/a-sprint) and 74 more |
|
|
1826
2172
|
|
|
1827
2173
|
##### `Subtask`
|
|
1828
2174
|
|
|
1829
2175
|
| Prop | Type | Default | Description |
|
|
1830
2176
|
|---|---|---|---|
|
|
1831
|
-
| `id`
|
|
1832
|
-
| `task`
|
|
1833
|
-
| `lane`
|
|
1834
|
-
| `from`
|
|
1835
|
-
| `to`
|
|
1836
|
-
| `leadIn` | `number` | — | Duration of the lead-in before the main time; none is zero
|
|
1837
|
-
| `leadOut` | `number` | — | Duration of the lead-out after the main time; none is zero
|
|
1838
|
-
| `name` | `string` | — | What the subtask is called, where the schedule names it
|
|
1839
|
-
| `appearance` | `readonly 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
|
|
1840
|
-
| `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
|
|
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 71 more |
|
|
2178
|
+
| `task` *required* | `string` | — | The id of the task it belongs to.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 67 more |
|
|
2179
|
+
| `lane` *required* | `string` | — | The id of the lane it sits on.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 67 more |
|
|
2180
|
+
| `from` *required* | `number` | — | Start of the main time.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 67 more |
|
|
2181
|
+
| `to` *required* | `number` | — | End of the main time.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 67 more |
|
|
2182
|
+
| `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 24 more |
|
|
2183
|
+
| `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 21 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 25 more |
|
|
2185
|
+
| `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
|
+
| `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) |
|
|
1841
2187
|
|
|
1842
2188
|
##### `Task`
|
|
1843
2189
|
|
|
1844
2190
|
| Prop | Type | Default | Description |
|
|
1845
2191
|
|---|---|---|---|
|
|
1846
|
-
| `id`
|
|
1847
|
-
| `color`
|
|
1848
|
-
| `name` | `string` | — | What the task is called, where the schedule names it
|
|
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 66 more |
|
|
2193
|
+
| `color` *required* | `string` | — | Any CSS colour - a literal, a token, `light-dark(…)`. The colour means what the caller's domain needs it to mean.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 66 more |
|
|
2194
|
+
| `name` | `string` | — | What the task is called, where the schedule names it.<br>Shown in: [Main time, lead-in and lead-out](#/subtasks/lead-in-and-lead-out), [Colour by what the task means](#/subtasks/task-colours), [The smallest schedule (Installation)](#/installation/smallest-schedule) and 66 more |
|
|
2195
|
+
|
|
2196
|
+
##### Types on this page
|
|
2197
|
+
|
|
2198
|
+
###### `SubtaskAppearance`
|
|
2199
|
+
|
|
2200
|
+
The appearances a caller may give a subtask.
|
|
2201
|
+
|
|
2202
|
+
```ts
|
|
2203
|
+
type SubtaskAppearance = "provisional" | "fixed" | "muted" | "open";
|
|
2204
|
+
```
|
|
1849
2205
|
|
|
1850
2206
|
### Bar labels
|
|
1851
2207
|
|
|
@@ -1913,6 +2269,62 @@ export default function BarLabels() {
|
|
|
1913
2269
|
}
|
|
1914
2270
|
```
|
|
1915
2271
|
|
|
2272
|
+
#### Keyboard
|
|
2273
|
+
|
|
2274
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
2275
|
+
|
|
2276
|
+
#### Props on this page
|
|
2277
|
+
|
|
2278
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
2279
|
+
|
|
2280
|
+
| Prop | Type | Default | Description |
|
|
2281
|
+
|---|---|---|---|
|
|
2282
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
2283
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
2284
|
+
| [`label`](#/schedule/ScheduleProps-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. |
|
|
2285
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
2286
|
+
|
|
2287
|
+
###### Accessibility
|
|
2288
|
+
|
|
2289
|
+
| Prop | Type | Default | Description |
|
|
2290
|
+
|---|---|---|---|
|
|
2291
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
2292
|
+
|
|
2293
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
2294
|
+
|
|
2295
|
+
| Prop | Type | Default | Description |
|
|
2296
|
+
|---|---|---|---|
|
|
2297
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
2298
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
2299
|
+
|
|
2300
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
2301
|
+
|
|
2302
|
+
| Prop | Type | Default | Description |
|
|
2303
|
+
|---|---|---|---|
|
|
2304
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
2305
|
+
| [`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. |
|
|
2306
|
+
|
|
2307
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
2308
|
+
|
|
2309
|
+
| Prop | Type | Default | Description |
|
|
2310
|
+
|---|---|---|---|
|
|
2311
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
2312
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
2313
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
2314
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
2315
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
2316
|
+
| [`leadIn`](#/subtasks/Subtask-leadIn) | `number` | — | Duration of the lead-in before the main time; none is zero. |
|
|
2317
|
+
| [`leadOut`](#/subtasks/Subtask-leadOut) | `number` | — | Duration of the lead-out after the main time; none is zero. |
|
|
2318
|
+
| [`name`](#/subtasks/Subtask-name) | `string` | — | What the subtask is called, where the schedule names it. |
|
|
2319
|
+
|
|
2320
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
2321
|
+
|
|
2322
|
+
| Prop | Type | Default | Description |
|
|
2323
|
+
|---|---|---|---|
|
|
2324
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
2325
|
+
| [`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. |
|
|
2326
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
2327
|
+
|
|
1916
2328
|
### Appearances
|
|
1917
2329
|
|
|
1918
2330
|
What a bar says besides its colour: provisional, fixed, muted, running on past the view, and how far the work has got. Each takes one channel of the drawing, so several on one bar stay readable.
|
|
@@ -1925,7 +2337,7 @@ Demo page: https://romanhaendler.github.io/umriss-ui/schedule/appearances/
|
|
|
1925
2337
|
|
|
1926
2338
|
`"provisional"` owns the fill (none at all), `"fixed"` the ends (a cap inside each), `"muted"` the saturation, `"open"` a fade at the edge of the view, and `progress` a rail inside the main time. The faint, outlined fill belongs to a lead-in and a lead-out and to nothing else.
|
|
1927
2339
|
|
|
1928
|
-
`"provisional"` and `"fixed"` contradict, and the later one in the list wins. `resolveAppearance` is that rule, exported for the application to read as well.
|
|
2340
|
+
`"provisional"` and `"fixed"` contradict, and the later one in the list wins. [`resolveAppearance`](#/api/resolveAppearance) is that rule, exported for the application to read as well.
|
|
1929
2341
|
|
|
1930
2342
|
#### Examples
|
|
1931
2343
|
|
|
@@ -2156,6 +2568,63 @@ export default function Combinations() {
|
|
|
2156
2568
|
}
|
|
2157
2569
|
```
|
|
2158
2570
|
|
|
2571
|
+
#### Keyboard
|
|
2572
|
+
|
|
2573
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
2574
|
+
|
|
2575
|
+
#### Props on this page
|
|
2576
|
+
|
|
2577
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
2578
|
+
|
|
2579
|
+
| Prop | Type | Default | Description |
|
|
2580
|
+
|---|---|---|---|
|
|
2581
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
2582
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
2583
|
+
| [`label`](#/schedule/ScheduleProps-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. |
|
|
2584
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
2585
|
+
|
|
2586
|
+
###### Accessibility
|
|
2587
|
+
|
|
2588
|
+
| Prop | Type | Default | Description |
|
|
2589
|
+
|---|---|---|---|
|
|
2590
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
2591
|
+
|
|
2592
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
2593
|
+
|
|
2594
|
+
| Prop | Type | Default | Description |
|
|
2595
|
+
|---|---|---|---|
|
|
2596
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
2597
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
2598
|
+
|
|
2599
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
2600
|
+
|
|
2601
|
+
| Prop | Type | Default | Description |
|
|
2602
|
+
|---|---|---|---|
|
|
2603
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
2604
|
+
| [`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. |
|
|
2605
|
+
|
|
2606
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
2607
|
+
|
|
2608
|
+
| Prop | Type | Default | Description |
|
|
2609
|
+
|---|---|---|---|
|
|
2610
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
2611
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
2612
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
2613
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
2614
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
2615
|
+
| [`leadIn`](#/subtasks/Subtask-leadIn) | `number` | — | Duration of the lead-in before the main time; none is zero. |
|
|
2616
|
+
| [`leadOut`](#/subtasks/Subtask-leadOut) | `number` | — | Duration of the lead-out after the main time; none is zero. |
|
|
2617
|
+
| [`appearance`](#/subtasks/Subtask-appearance) | `readonly `[`SubtaskAppearance`](#/subtasks/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. |
|
|
2618
|
+
| [`progress`](#/subtasks/Subtask-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. |
|
|
2619
|
+
|
|
2620
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
2621
|
+
|
|
2622
|
+
| Prop | Type | Default | Description |
|
|
2623
|
+
|---|---|---|---|
|
|
2624
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
2625
|
+
| [`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. |
|
|
2626
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
2627
|
+
|
|
2159
2628
|
### Overlap
|
|
2160
2629
|
|
|
2161
2630
|
Two subtasks claiming one lane at the same time (also called a double booking or conflict): both drawn, offset and marked, never packed into sub-lanes.
|
|
@@ -2271,18 +2740,72 @@ export default function ThreeAtOnce() {
|
|
|
2271
2740
|
|
|
2272
2741
|
- The overlaps as a list to count and act on → Findings as data
|
|
2273
2742
|
|
|
2274
|
-
####
|
|
2743
|
+
#### Keyboard
|
|
2275
2744
|
|
|
2276
|
-
|
|
2745
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
2277
2746
|
|
|
2278
|
-
|
|
2747
|
+
#### Props on this page
|
|
2279
2748
|
|
|
2280
|
-
|
|
2749
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
2281
2750
|
|
|
2282
|
-
|
|
2751
|
+
| Prop | Type | Default | Description |
|
|
2752
|
+
|---|---|---|---|
|
|
2753
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
2754
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
2755
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
2283
2756
|
|
|
2284
|
-
|
|
2285
|
-
|
|
2757
|
+
###### Accessibility
|
|
2758
|
+
|
|
2759
|
+
| Prop | Type | Default | Description |
|
|
2760
|
+
|---|---|---|---|
|
|
2761
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
2762
|
+
|
|
2763
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
2764
|
+
|
|
2765
|
+
| Prop | Type | Default | Description |
|
|
2766
|
+
|---|---|---|---|
|
|
2767
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
2768
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
2769
|
+
|
|
2770
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
2771
|
+
|
|
2772
|
+
| Prop | Type | Default | Description |
|
|
2773
|
+
|---|---|---|---|
|
|
2774
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
2775
|
+
| [`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. |
|
|
2776
|
+
|
|
2777
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
2778
|
+
|
|
2779
|
+
| Prop | Type | Default | Description |
|
|
2780
|
+
|---|---|---|---|
|
|
2781
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
2782
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
2783
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
2784
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
2785
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
2786
|
+
| [`leadIn`](#/subtasks/Subtask-leadIn) | `number` | — | Duration of the lead-in before the main time; none is zero. |
|
|
2787
|
+
| [`leadOut`](#/subtasks/Subtask-leadOut) | `number` | — | Duration of the lead-out after the main time; none is zero. |
|
|
2788
|
+
|
|
2789
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
2790
|
+
|
|
2791
|
+
| Prop | Type | Default | Description |
|
|
2792
|
+
|---|---|---|---|
|
|
2793
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
2794
|
+
| [`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. |
|
|
2795
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
2796
|
+
|
|
2797
|
+
#### Known limits
|
|
2798
|
+
|
|
2799
|
+
- No stacked layout on request yet: an overlap is always drawn offset, as the finding it is.
|
|
2800
|
+
|
|
2801
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
|
|
2802
|
+
|
|
2803
|
+
### Dependencies
|
|
2804
|
+
|
|
2805
|
+
Lines from one subtask's end to the next one's start within a task, with the lag that must pass between them (also called links or predecessors). A lag that does not fit is marked, not repaired.
|
|
2806
|
+
|
|
2807
|
+
```ts
|
|
2808
|
+
import { Dependencies } from "@umriss-ui/schedule";
|
|
2286
2809
|
```
|
|
2287
2810
|
|
|
2288
2811
|
Demo page: https://romanhaendler.github.io/umriss-ui/schedule/dependencies/
|
|
@@ -2526,37 +3049,124 @@ export default function ViolatedDependency() {
|
|
|
2526
3049
|
}
|
|
2527
3050
|
```
|
|
2528
3051
|
|
|
3052
|
+
##### Draw one handover its own way
|
|
3053
|
+
|
|
3054
|
+
A dependency's own `attach` and `ends` override the schedule's for that one line: here the sign-off joins the middles and marks its ends, the rest stay quiet.
|
|
3055
|
+
|
|
3056
|
+
```tsx
|
|
3057
|
+
import { Lane, Schedule, Subtasks, Dependencies } from "@umriss-ui/schedule";
|
|
3058
|
+
import type { Subtask, Task, Dependency } from "@umriss-ui/schedule";
|
|
3059
|
+
|
|
3060
|
+
/* Picture only, like the schedule's own `attach` and `ends`: the finding
|
|
3061
|
+
follows from `leaves` and `arrives` alone. */
|
|
3062
|
+
|
|
3063
|
+
const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
|
|
3064
|
+
const min = (n: number) => n * 60_000;
|
|
3065
|
+
|
|
3066
|
+
const PROJECTS: Task[] = [{ id: "portal", name: "Member portal", color: "light-dark(#2563eb, #6b9bff)" }];
|
|
3067
|
+
|
|
3068
|
+
const WORK: Subtask[] = [
|
|
3069
|
+
{ id: "design", task: "portal", lane: "noah", from: at(7), to: at(8), name: "Design" },
|
|
3070
|
+
{ id: "build", task: "portal", lane: "arjun", from: at(8, 30), to: at(9, 30), name: "Build" },
|
|
3071
|
+
{ id: "test", task: "portal", lane: "eva", from: at(10), to: at(11), name: "Test" },
|
|
3072
|
+
{ id: "sign-off", task: "portal", lane: "noah", from: at(11, 30), to: at(12), name: "Sign-off" },
|
|
3073
|
+
];
|
|
3074
|
+
|
|
3075
|
+
const HANDOVERS: Dependency[] = [
|
|
3076
|
+
{ id: "to-build", from: "design", to: "build", lag: min(15) },
|
|
3077
|
+
{ id: "to-test", from: "build", to: "test", lag: min(15) },
|
|
3078
|
+
/* The one that matters: the designer signs off what was tested. */
|
|
3079
|
+
{ id: "to-sign-off", from: "test", to: "sign-off", lag: min(15), attach: "centre", ends: "dot" },
|
|
3080
|
+
];
|
|
3081
|
+
|
|
3082
|
+
export default function OneHandoverDrawnItsOwnWay() {
|
|
3083
|
+
return (
|
|
3084
|
+
<Schedule ariaLabel="Design, build, test and a sign-off drawn its own way" initialDomain={[at(6, 30), at(12, 30)]} height={188} attach="nearest" ends="none">
|
|
3085
|
+
<Lane id="noah" label="Noah Fischer" />
|
|
3086
|
+
<Lane id="arjun" label="Arjun Mehta" />
|
|
3087
|
+
<Lane id="eva" label="Eva Novak" />
|
|
3088
|
+
<Dependencies data={HANDOVERS} />
|
|
3089
|
+
<Subtasks data={WORK} tasks={PROJECTS} />
|
|
3090
|
+
</Schedule>
|
|
3091
|
+
);
|
|
3092
|
+
}
|
|
3093
|
+
```
|
|
3094
|
+
|
|
2529
3095
|
#### When to use something else
|
|
2530
3096
|
|
|
2531
3097
|
- The shape of the line → Routes
|
|
2532
3098
|
|
|
3099
|
+
#### Keyboard
|
|
3100
|
+
|
|
3101
|
+
| Key | Action |
|
|
3102
|
+
|---|---|
|
|
3103
|
+
| `] or t` | Out along the active subtask's dependency; pressed again, on to the subtask it arrives at. |
|
|
3104
|
+
| `[ or Shift+T` | Back along the dependency to the subtask it leaves. |
|
|
3105
|
+
|
|
3106
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
3107
|
+
|
|
2533
3108
|
#### API
|
|
2534
3109
|
|
|
2535
3110
|
##### `DependenciesProps`
|
|
2536
3111
|
|
|
2537
3112
|
| Prop | Type | Default | Description |
|
|
2538
3113
|
|---|---|---|---|
|
|
2539
|
-
| `data`
|
|
3114
|
+
| `data` *required* | `readonly `[`Dependency`](#type-Dependency)`[]` | — | The dependencies, as the caller holds them.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 27 more |
|
|
2540
3115
|
|
|
2541
3116
|
##### `Dependency`
|
|
2542
3117
|
|
|
2543
3118
|
| Prop | Type | Default | Description |
|
|
2544
3119
|
|---|---|---|---|
|
|
2545
|
-
| `id`
|
|
2546
|
-
| `from`
|
|
2547
|
-
| `to`
|
|
2548
|
-
| `lag`
|
|
2549
|
-
| `leaves` | `"main" \| "leadOut"` |
|
|
2550
|
-
| `arrives` | `"main" \| "leadIn"` |
|
|
2551
|
-
| `route` | `DependencyRoute` | — | 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
|
|
2552
|
-
| `attach` | `DependencyAttachment` | — | Where on the bars this one's line attaches, where it does not attach like the rest. Also picture only, and not to be confused with the two anchors above: those say what the dependency connects, this says where the line touches
|
|
2553
|
-
| `ends` | `DependencyEnds` | — | Whether this one's ends are marked with a dot, where it is not marked like the rest. Also picture only
|
|
3120
|
+
| `id` *required* | `string` | — | The caller's identity of the dependency.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 26 more |
|
|
3121
|
+
| `from` *required* | `string` | — | The id of the subtask it leaves.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 26 more |
|
|
3122
|
+
| `to` *required* | `string` | — | The id of the subtask it arrives at.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 26 more |
|
|
3123
|
+
| `lag` *required* | `number` | — | The least time between the two anchors; zero where the successor may begin as soon as the predecessor ends.<br>Shown in: [Join the stops of a tour](#/dependencies/stops-of-a-tour), [Choose what a dependency connects](#/dependencies/anchors), [Choose where a line touches its bars](#/dependencies/attach) and 26 more |
|
|
3124
|
+
| `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) |
|
|
3125
|
+
| `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 |
|
|
3126
|
+
| `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) |
|
|
3127
|
+
| `attach` | [`DependencyAttachment`](#type-DependencyAttachment)<br>`"centre" \| "nearest"` | — | Where on the bars this one's line attaches, where it does not attach like the rest. Also picture only, and not to be confused with the two anchors above: those say what the dependency connects, this says where the line touches.<br>Shown in: [Draw one handover its own way](#/dependencies/one-handover-drawn-its-own-way) |
|
|
3128
|
+
| `ends` | [`DependencyEnds`](#type-DependencyEnds)<br>`"dot" \| "none"` | — | Whether this one's ends are marked with a dot, where it is not marked like the rest. Also picture only.<br>Shown in: [Draw one handover its own way](#/dependencies/one-handover-drawn-its-own-way) |
|
|
3129
|
+
|
|
3130
|
+
##### Types on this page
|
|
3131
|
+
|
|
3132
|
+
###### `DependencyRoute`
|
|
3133
|
+
|
|
3134
|
+
How a dependency is drawn between its two ends: a curve that leaves and
|
|
3135
|
+
arrives forwards, a straight line, or axis-parallel segments.
|
|
3136
|
+
|
|
3137
|
+
```ts
|
|
3138
|
+
type DependencyRoute = "curve" | "straight" | "orthogonal";
|
|
3139
|
+
```
|
|
3140
|
+
|
|
3141
|
+
###### `DependencyAttachment`
|
|
3142
|
+
|
|
3143
|
+
Where on its bars a dependency's line attaches: the middle of both, or the
|
|
3144
|
+
edge that faces the other stop - which is the shortest line between them.
|
|
3145
|
+
|
|
3146
|
+
Deliberately not called an anchor: a dependency already HAS two anchors
|
|
3147
|
+
(`leaves`, `arrives`), and those decide what it connects and therefore
|
|
3148
|
+
whether it is violated. This decides where the line touches, and nothing else.
|
|
3149
|
+
The tree has an **Anchor** of its own as well (CONTEXT.md).
|
|
3150
|
+
|
|
3151
|
+
```ts
|
|
3152
|
+
type DependencyAttachment = "centre" | "nearest";
|
|
3153
|
+
```
|
|
3154
|
+
|
|
3155
|
+
###### `DependencyEnds`
|
|
3156
|
+
|
|
3157
|
+
Whether a dependency's two ends carry a dot. The dot says where the line is
|
|
3158
|
+
anchored, which is worth saying while a plan is being read and is noise in a
|
|
3159
|
+
plan full of short moves - so it is the caller's choice.
|
|
3160
|
+
|
|
3161
|
+
```ts
|
|
3162
|
+
type DependencyEnds = "dot" | "none";
|
|
3163
|
+
```
|
|
2554
3164
|
|
|
2555
3165
|
#### Known limits
|
|
2556
3166
|
|
|
2557
|
-
- Only finish-to-start within one task; no dependency types and no critical path (ADR-0032).
|
|
3167
|
+
- Only finish-to-start within one task; no dependency types and no critical path ([ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/)).
|
|
2558
3168
|
|
|
2559
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.
|
|
3169
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
|
|
2560
3170
|
|
|
2561
3171
|
### Routes
|
|
2562
3172
|
|
|
@@ -2727,6 +3337,77 @@ export default function PerDependency() {
|
|
|
2727
3337
|
}
|
|
2728
3338
|
```
|
|
2729
3339
|
|
|
3340
|
+
#### Keyboard
|
|
3341
|
+
|
|
3342
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
3343
|
+
|
|
3344
|
+
#### Props on this page
|
|
3345
|
+
|
|
3346
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
3347
|
+
|
|
3348
|
+
| Prop | Type | Default | Description |
|
|
3349
|
+
|---|---|---|---|
|
|
3350
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
3351
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
3352
|
+
| [`route`](#/schedule/ScheduleProps-route) | [`DependencyRoute`](#/schedule/type-DependencyRoute)<br>`"curve" \| "straight" \| "orthogonal"` | `"curve"` | How the dependencies are drawn: a `"curve"` that leaves and arrives forwards, a `"straight"` line, or `"orthogonal"` segments. A dependency may say otherwise for itself. |
|
|
3353
|
+
| [`attach`](#/schedule/ScheduleProps-attach) | [`DependencyAttachment`](#/schedule/type-DependencyAttachment)<br>`"centre" \| "nearest"` | `"centre"` | Where a dependency's ends sit on their bars: the `"centre"` of both, or the `"nearest"` edge - which is the shortest line between two stops. Within one lane both mean the middle. A dependency may say otherwise for itself. It changes the picture and never a finding: whether a dependency is violated follows from its `leaves` and `arrives` alone. |
|
|
3354
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
3355
|
+
|
|
3356
|
+
###### Accessibility
|
|
3357
|
+
|
|
3358
|
+
| Prop | Type | Default | Description |
|
|
3359
|
+
|---|---|---|---|
|
|
3360
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
3361
|
+
|
|
3362
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
3363
|
+
|
|
3364
|
+
| Prop | Type | Default | Description |
|
|
3365
|
+
|---|---|---|---|
|
|
3366
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
3367
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
3368
|
+
|
|
3369
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
3370
|
+
|
|
3371
|
+
| Prop | Type | Default | Description |
|
|
3372
|
+
|---|---|---|---|
|
|
3373
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
3374
|
+
| [`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. |
|
|
3375
|
+
|
|
3376
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
3377
|
+
|
|
3378
|
+
| Prop | Type | Default | Description |
|
|
3379
|
+
|---|---|---|---|
|
|
3380
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
3381
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
3382
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
3383
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
3384
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
3385
|
+
| [`name`](#/subtasks/Subtask-name) | `string` | — | What the subtask is called, where the schedule names it. |
|
|
3386
|
+
|
|
3387
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
3388
|
+
|
|
3389
|
+
| Prop | Type | Default | Description |
|
|
3390
|
+
|---|---|---|---|
|
|
3391
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
3392
|
+
| [`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. |
|
|
3393
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
3394
|
+
|
|
3395
|
+
From `DependenciesProps` — the full table stands on [Dependencies](#/dependencies/type-DependenciesProps).
|
|
3396
|
+
|
|
3397
|
+
| Prop | Type | Default | Description |
|
|
3398
|
+
|---|---|---|---|
|
|
3399
|
+
| [`data`](#/dependencies/DependenciesProps-data) *required* | `readonly `[`Dependency`](#/dependencies/type-Dependency)`[]` | — | The dependencies, as the caller holds them. |
|
|
3400
|
+
|
|
3401
|
+
From `Dependency` — the full table stands on [Dependencies](#/dependencies/type-Dependency).
|
|
3402
|
+
|
|
3403
|
+
| Prop | Type | Default | Description |
|
|
3404
|
+
|---|---|---|---|
|
|
3405
|
+
| [`id`](#/dependencies/Dependency-id) *required* | `string` | — | The caller's identity of the dependency. |
|
|
3406
|
+
| [`from`](#/dependencies/Dependency-from) *required* | `string` | — | The id of the subtask it leaves. |
|
|
3407
|
+
| [`to`](#/dependencies/Dependency-to) *required* | `string` | — | The id of the subtask it arrives at. |
|
|
3408
|
+
| [`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. |
|
|
3409
|
+
| [`route`](#/dependencies/Dependency-route) | [`DependencyRoute`](#/dependencies/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. |
|
|
3410
|
+
|
|
2730
3411
|
## Time
|
|
2731
3412
|
|
|
2732
3413
|
The axis the work stands on: the calendar, blocked time, the now line, and moving through it.
|
|
@@ -2979,6 +3660,85 @@ export default function OfficeHours() {
|
|
|
2979
3660
|
|
|
2980
3661
|
- Time a single lane is not available → Blocked time
|
|
2981
3662
|
|
|
3663
|
+
#### Keyboard
|
|
3664
|
+
|
|
3665
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
3666
|
+
|
|
3667
|
+
#### Props on this page
|
|
3668
|
+
|
|
3669
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
3670
|
+
|
|
3671
|
+
| Prop | Type | Default | Description |
|
|
3672
|
+
|---|---|---|---|
|
|
3673
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
3674
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
3675
|
+
| [`calendar`](#/schedule/ScheduleProps-calendar) | [`CalendarInput`](#/schedule/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. |
|
|
3676
|
+
| [`intents`](#/schedule/ScheduleProps-intents) | `readonly `[`IntentKind`](#/schedule/type-IntentKind)`[]` | `[]` | The intents the caller handles. Each one enables its interaction; none leaves a read-only schedule ([ADR-0023](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0023-editing-is-controlled-the-schedule-reports-intents.md)). |
|
|
3677
|
+
| [`label`](#/schedule/ScheduleProps-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. |
|
|
3678
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
3679
|
+
|
|
3680
|
+
###### Events
|
|
3681
|
+
|
|
3682
|
+
| Prop | Type | Default | Description |
|
|
3683
|
+
|---|---|---|---|
|
|
3684
|
+
| [`onIntent`](#/schedule/ScheduleProps-onIntent) | `(intent: `[`Intent`](#/schedule/type-Intent)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
3685
|
+
|
|
3686
|
+
###### Accessibility
|
|
3687
|
+
|
|
3688
|
+
| Prop | Type | Default | Description |
|
|
3689
|
+
|---|---|---|---|
|
|
3690
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
3691
|
+
|
|
3692
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
3693
|
+
|
|
3694
|
+
| Prop | Type | Default | Description |
|
|
3695
|
+
|---|---|---|---|
|
|
3696
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
3697
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
3698
|
+
|
|
3699
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
3700
|
+
|
|
3701
|
+
| Prop | Type | Default | Description |
|
|
3702
|
+
|---|---|---|---|
|
|
3703
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
3704
|
+
| [`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. |
|
|
3705
|
+
|
|
3706
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
3707
|
+
|
|
3708
|
+
| Prop | Type | Default | Description |
|
|
3709
|
+
|---|---|---|---|
|
|
3710
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
3711
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
3712
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
3713
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
3714
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
3715
|
+
| [`leadIn`](#/subtasks/Subtask-leadIn) | `number` | — | Duration of the lead-in before the main time; none is zero. |
|
|
3716
|
+
| [`leadOut`](#/subtasks/Subtask-leadOut) | `number` | — | Duration of the lead-out after the main time; none is zero. |
|
|
3717
|
+
| [`name`](#/subtasks/Subtask-name) | `string` | — | What the subtask is called, where the schedule names it. |
|
|
3718
|
+
|
|
3719
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
3720
|
+
|
|
3721
|
+
| Prop | Type | Default | Description |
|
|
3722
|
+
|---|---|---|---|
|
|
3723
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
3724
|
+
| [`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. |
|
|
3725
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
3726
|
+
|
|
3727
|
+
From `DependenciesProps` — the full table stands on [Dependencies](#/dependencies/type-DependenciesProps).
|
|
3728
|
+
|
|
3729
|
+
| Prop | Type | Default | Description |
|
|
3730
|
+
|---|---|---|---|
|
|
3731
|
+
| [`data`](#/dependencies/DependenciesProps-data) *required* | `readonly `[`Dependency`](#/dependencies/type-Dependency)`[]` | — | The dependencies, as the caller holds them. |
|
|
3732
|
+
|
|
3733
|
+
From `Dependency` — the full table stands on [Dependencies](#/dependencies/type-Dependency).
|
|
3734
|
+
|
|
3735
|
+
| Prop | Type | Default | Description |
|
|
3736
|
+
|---|---|---|---|
|
|
3737
|
+
| [`id`](#/dependencies/Dependency-id) *required* | `string` | — | The caller's identity of the dependency. |
|
|
3738
|
+
| [`from`](#/dependencies/Dependency-from) *required* | `string` | — | The id of the subtask it leaves. |
|
|
3739
|
+
| [`to`](#/dependencies/Dependency-to) *required* | `string` | — | The id of the subtask it arrives at. |
|
|
3740
|
+
| [`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. |
|
|
3741
|
+
|
|
2982
3742
|
### Blocked time
|
|
2983
3743
|
|
|
2984
3744
|
Leave, maintenance and other time a lane is not available: hatched behind the work, a finding where work covers it, and closed to a drag.
|
|
@@ -2989,7 +3749,7 @@ import { BlockedTimes, findings } from "@umriss-ui/schedule";
|
|
|
2989
3749
|
|
|
2990
3750
|
Demo page: https://romanhaendler.github.io/umriss-ui/schedule/blocked-time/
|
|
2991
3751
|
|
|
2992
|
-
Blocked time is data beside the work: one list, each interval naming its lane, as a leave table or a maintenance plan holds it. `findings` takes the same list as its third argument.
|
|
3752
|
+
Blocked time is data beside the work: one list, each interval naming its lane, as a leave table or a maintenance plan holds it. [`findings`](#/api/findings) takes the same list as its third argument.
|
|
2993
3753
|
|
|
2994
3754
|
Work the data already put into blocked time is never locked there: it may be moved within it and out of it, and the finding stays until it is.
|
|
2995
3755
|
|
|
@@ -3135,7 +3895,7 @@ export default function DragAround() {
|
|
|
3135
3895
|
|
|
3136
3896
|
##### Check a sprint against the leave calendar
|
|
3137
3897
|
|
|
3138
|
-
The team's holidays, sick days and training become `BlockedTimes`, and `findings` confirms that no work item runs into one.
|
|
3898
|
+
The team's holidays, sick days and training become `BlockedTimes`, and [`findings`](#/api/findings) confirms that no work item runs into one.
|
|
3139
3899
|
|
|
3140
3900
|
```tsx
|
|
3141
3901
|
import { Stack, Text } from "@umriss-ui/core";
|
|
@@ -3270,23 +4030,27 @@ export default function TeamLeave() {
|
|
|
3270
4030
|
|
|
3271
4031
|
- Hours nobody works, on every lane → Time axis and calendar
|
|
3272
4032
|
|
|
4033
|
+
#### Keyboard
|
|
4034
|
+
|
|
4035
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
4036
|
+
|
|
3273
4037
|
#### API
|
|
3274
4038
|
|
|
3275
4039
|
##### `BlockedTimesProps`
|
|
3276
4040
|
|
|
3277
4041
|
| Prop | Type | Default | Description |
|
|
3278
4042
|
|---|---|---|---|
|
|
3279
|
-
| `data`
|
|
4043
|
+
| `data` *required* | `readonly `[`BlockedTime`](#type-BlockedTime)`[]` | — | The blocked time of the lanes - leave, maintenance, unavailability -, as the caller holds it: one list, each interval naming its lane.<br>Shown in: [Block out leave and maintenance](#/blocked-time/leave), [Plan work around someone's leave](#/blocked-time/drag-around), [Check a sprint against the leave calendar](#/blocked-time/team-leave) and 5 more |
|
|
3280
4044
|
|
|
3281
4045
|
##### `BlockedTime`
|
|
3282
4046
|
|
|
3283
4047
|
| Prop | Type | Default | Description |
|
|
3284
4048
|
|---|---|---|---|
|
|
3285
|
-
| `id`
|
|
3286
|
-
| `lane`
|
|
3287
|
-
| `from`
|
|
3288
|
-
| `to`
|
|
3289
|
-
| `label` | `string` | — | Why the lane is blocked - "Leave", "Maintenance" -, where the schedule names it
|
|
4049
|
+
| `id` *required* | `string` | — | The caller's identity of the interval - what a finding names.<br>Shown in: [Block out leave and maintenance](#/blocked-time/leave), [Plan work around someone's leave](#/blocked-time/drag-around), [Check a sprint against the leave calendar](#/blocked-time/team-leave) and 5 more |
|
|
4050
|
+
| `lane` *required* | `string` | — | The id of the lane it blocks.<br>Shown in: [Block out leave and maintenance](#/blocked-time/leave), [Plan work around someone's leave](#/blocked-time/drag-around), [Check a sprint against the leave calendar](#/blocked-time/team-leave) and 5 more |
|
|
4051
|
+
| `from` *required* | `number` | — | Where it begins.<br>Shown in: [Block out leave and maintenance](#/blocked-time/leave), [Plan work around someone's leave](#/blocked-time/drag-around), [Check a sprint against the leave calendar](#/blocked-time/team-leave) and 5 more |
|
|
4052
|
+
| `to` *required* | `number` | — | Where it ends.<br>Shown in: [Block out leave and maintenance](#/blocked-time/leave), [Plan work around someone's leave](#/blocked-time/drag-around), [Check a sprint against the leave calendar](#/blocked-time/team-leave) and 5 more |
|
|
4053
|
+
| `label` | `string` | — | Why the lane is blocked - "Leave", "Maintenance" -, where the schedule names it.<br>Shown in: [Block out leave and maintenance](#/blocked-time/leave), [Plan work around someone's leave](#/blocked-time/drag-around), [Check a sprint against the leave calendar](#/blocked-time/team-leave) and 5 more |
|
|
3290
4054
|
|
|
3291
4055
|
### Now line
|
|
3292
4056
|
|
|
@@ -3502,6 +4266,60 @@ export default function FollowTheClock() {
|
|
|
3502
4266
|
}
|
|
3503
4267
|
```
|
|
3504
4268
|
|
|
4269
|
+
#### Keyboard
|
|
4270
|
+
|
|
4271
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
4272
|
+
|
|
4273
|
+
#### Props on this page
|
|
4274
|
+
|
|
4275
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
4276
|
+
|
|
4277
|
+
| Prop | Type | Default | Description |
|
|
4278
|
+
|---|---|---|---|
|
|
4279
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
4280
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
4281
|
+
| [`now`](#/schedule/ScheduleProps-now) | `boolean \| number` | `false` | A line marking the present across the lanes: `true` follows the clock by the minute, an instant fixes it there. |
|
|
4282
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
4283
|
+
|
|
4284
|
+
###### Accessibility
|
|
4285
|
+
|
|
4286
|
+
| Prop | Type | Default | Description |
|
|
4287
|
+
|---|---|---|---|
|
|
4288
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
4289
|
+
|
|
4290
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
4291
|
+
|
|
4292
|
+
| Prop | Type | Default | Description |
|
|
4293
|
+
|---|---|---|---|
|
|
4294
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
4295
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
4296
|
+
|
|
4297
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
4298
|
+
|
|
4299
|
+
| Prop | Type | Default | Description |
|
|
4300
|
+
|---|---|---|---|
|
|
4301
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
4302
|
+
| [`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. |
|
|
4303
|
+
|
|
4304
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
4305
|
+
|
|
4306
|
+
| Prop | Type | Default | Description |
|
|
4307
|
+
|---|---|---|---|
|
|
4308
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
4309
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
4310
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
4311
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
4312
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
4313
|
+
| [`leadIn`](#/subtasks/Subtask-leadIn) | `number` | — | Duration of the lead-in before the main time; none is zero. |
|
|
4314
|
+
|
|
4315
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
4316
|
+
|
|
4317
|
+
| Prop | Type | Default | Description |
|
|
4318
|
+
|---|---|---|---|
|
|
4319
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
4320
|
+
| [`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. |
|
|
4321
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
4322
|
+
|
|
3505
4323
|
### Pan and zoom
|
|
3506
4324
|
|
|
3507
4325
|
Moving through a plan with the gestures of any scrolling surface: drag, wheel, Ctrl with the wheel, and a pinch. Only the view moves; the plan stays as it is.
|
|
@@ -3514,7 +4332,7 @@ Demo page: https://romanhaendler.github.io/umriss-ui/schedule/pan-and-zoom/
|
|
|
3514
4332
|
|
|
3515
4333
|
Dragging the background pans through time and through the lanes. The wheel scrolls the lanes and hands the scroll back to the page at their end; Shift with the wheel pans through time; Ctrl or ⌘ with the wheel, or a pinch, zooms around the pointer.
|
|
3516
4334
|
|
|
3517
|
-
Nothing is reported and no intent is raised: pan and zoom change the visible span and nothing else (ADR-0001). `onDomainChange` reports the span for a second view to follow - see [Linked schedules](#/linked-schedules).
|
|
4335
|
+
Nothing is reported and no intent is raised: pan and zoom change the visible span and nothing else ([ADR-0001](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0001-affine-scale-contract.md)). `onDomainChange` reports the span for a second view to follow - see [Linked schedules](#/linked-schedules).
|
|
3518
4336
|
|
|
3519
4337
|
#### Examples
|
|
3520
4338
|
|
|
@@ -3567,6 +4385,66 @@ export default function PanAndZoom() {
|
|
|
3567
4385
|
}
|
|
3568
4386
|
```
|
|
3569
4387
|
|
|
4388
|
+
#### Keyboard
|
|
4389
|
+
|
|
4390
|
+
| Key | Action |
|
|
4391
|
+
|---|---|
|
|
4392
|
+
| `Home / End` | The first or last subtask on the lane; the view pans to bring it in. |
|
|
4393
|
+
| `PageUp / PageDown` | Along the lane by about a tenth of the visible span, the view following. |
|
|
4394
|
+
|
|
4395
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
4396
|
+
|
|
4397
|
+
#### Props on this page
|
|
4398
|
+
|
|
4399
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
4400
|
+
|
|
4401
|
+
| Prop | Type | Default | Description |
|
|
4402
|
+
|---|---|---|---|
|
|
4403
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
4404
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
4405
|
+
| [`zoomLimits`](#/schedule/ScheduleProps-zoomLimits) | [`ZoomLimits`](#/schedule/type-ZoomLimits) | one hour to 28 days | The narrowest and widest time span zoom may reach, in milliseconds. |
|
|
4406
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
4407
|
+
|
|
4408
|
+
###### Accessibility
|
|
4409
|
+
|
|
4410
|
+
| Prop | Type | Default | Description |
|
|
4411
|
+
|---|---|---|---|
|
|
4412
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
4413
|
+
|
|
4414
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
4415
|
+
|
|
4416
|
+
| Prop | Type | Default | Description |
|
|
4417
|
+
|---|---|---|---|
|
|
4418
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
4419
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
4420
|
+
|
|
4421
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
4422
|
+
|
|
4423
|
+
| Prop | Type | Default | Description |
|
|
4424
|
+
|---|---|---|---|
|
|
4425
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
4426
|
+
| [`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. |
|
|
4427
|
+
|
|
4428
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
4429
|
+
|
|
4430
|
+
| Prop | Type | Default | Description |
|
|
4431
|
+
|---|---|---|---|
|
|
4432
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
4433
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
4434
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
4435
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
4436
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
4437
|
+
| [`leadIn`](#/subtasks/Subtask-leadIn) | `number` | — | Duration of the lead-in before the main time; none is zero. |
|
|
4438
|
+
| [`leadOut`](#/subtasks/Subtask-leadOut) | `number` | — | Duration of the lead-out after the main time; none is zero. |
|
|
4439
|
+
|
|
4440
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
4441
|
+
|
|
4442
|
+
| Prop | Type | Default | Description |
|
|
4443
|
+
|---|---|---|---|
|
|
4444
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
4445
|
+
| [`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. |
|
|
4446
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
4447
|
+
|
|
3570
4448
|
## Reading
|
|
3571
4449
|
|
|
3572
4450
|
What a planner takes out of the picture: what is selected, what the pointer is on, and what a second view makes of it.
|
|
@@ -3721,37 +4599,106 @@ export default function ControlTheSelection() {
|
|
|
3721
4599
|
| `Enter or Space` | Selects the active subtask's task, as a click does. |
|
|
3722
4600
|
| `Escape` | Lets go of the active subtask. |
|
|
3723
4601
|
|
|
3724
|
-
|
|
4602
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
3725
4603
|
|
|
3726
|
-
|
|
4604
|
+
#### Props on this page
|
|
3727
4605
|
|
|
3728
|
-
|
|
4606
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
3729
4607
|
|
|
3730
|
-
|
|
4608
|
+
| Prop | Type | Default | Description |
|
|
4609
|
+
|---|---|---|---|
|
|
4610
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
4611
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
4612
|
+
| [`selectedTask`](#/schedule/ScheduleProps-selectedTask) | `string \| null` | — | The selected task, controlled. Leave it out and the schedule keeps the selection itself. |
|
|
4613
|
+
| [`onSelectedTaskChange`](#/schedule/ScheduleProps-onSelectedTaskChange) | `(task: string \| null, subtask: string \| null) => void` | — | Called when a click selects a task or clears the selection, with the subtask that was clicked - null where the click was on a dependency or on nothing. It is called again when another subtask of the same task is clicked. |
|
|
4614
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
3731
4615
|
|
|
3732
|
-
|
|
4616
|
+
###### Accessibility
|
|
3733
4617
|
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
4618
|
+
| Prop | Type | Default | Description |
|
|
4619
|
+
|---|---|---|---|
|
|
4620
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
3737
4621
|
|
|
3738
|
-
|
|
4622
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
3739
4623
|
|
|
3740
|
-
|
|
4624
|
+
| Prop | Type | Default | Description |
|
|
4625
|
+
|---|---|---|---|
|
|
4626
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
4627
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
3741
4628
|
|
|
3742
|
-
|
|
4629
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
3743
4630
|
|
|
3744
|
-
|
|
4631
|
+
| Prop | Type | Default | Description |
|
|
4632
|
+
|---|---|---|---|
|
|
4633
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
4634
|
+
| [`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. |
|
|
3745
4635
|
|
|
3746
|
-
|
|
4636
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
3747
4637
|
|
|
3748
|
-
|
|
4638
|
+
| Prop | Type | Default | Description |
|
|
4639
|
+
|---|---|---|---|
|
|
4640
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
4641
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
4642
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
4643
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
4644
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
4645
|
+
| [`leadIn`](#/subtasks/Subtask-leadIn) | `number` | — | Duration of the lead-in before the main time; none is zero. |
|
|
4646
|
+
| [`leadOut`](#/subtasks/Subtask-leadOut) | `number` | — | Duration of the lead-out after the main time; none is zero. |
|
|
3749
4647
|
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
4648
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
4649
|
+
|
|
4650
|
+
| Prop | Type | Default | Description |
|
|
4651
|
+
|---|---|---|---|
|
|
4652
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
4653
|
+
| [`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. |
|
|
4654
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
4655
|
+
|
|
4656
|
+
From `DependenciesProps` — the full table stands on [Dependencies](#/dependencies/type-DependenciesProps).
|
|
4657
|
+
|
|
4658
|
+
| Prop | Type | Default | Description |
|
|
4659
|
+
|---|---|---|---|
|
|
4660
|
+
| [`data`](#/dependencies/DependenciesProps-data) *required* | `readonly `[`Dependency`](#/dependencies/type-Dependency)`[]` | — | The dependencies, as the caller holds them. |
|
|
4661
|
+
|
|
4662
|
+
From `Dependency` — the full table stands on [Dependencies](#/dependencies/type-Dependency).
|
|
4663
|
+
|
|
4664
|
+
| Prop | Type | Default | Description |
|
|
4665
|
+
|---|---|---|---|
|
|
4666
|
+
| [`id`](#/dependencies/Dependency-id) *required* | `string` | — | The caller's identity of the dependency. |
|
|
4667
|
+
| [`from`](#/dependencies/Dependency-from) *required* | `string` | — | The id of the subtask it leaves. |
|
|
4668
|
+
| [`to`](#/dependencies/Dependency-to) *required* | `string` | — | The id of the subtask it arrives at. |
|
|
4669
|
+
| [`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. |
|
|
4670
|
+
|
|
4671
|
+
#### Known limits
|
|
4672
|
+
|
|
4673
|
+
- One task at a time: there is no multiple selection.
|
|
4674
|
+
|
|
4675
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
|
|
4676
|
+
|
|
4677
|
+
### Interactions
|
|
4678
|
+
|
|
4679
|
+
Reports what the pointer does on the plan - hover, click, right-click - with what it hit and the time and lane under it. Reach for it to open a menu, fill a detail panel or write a status line.
|
|
4680
|
+
|
|
4681
|
+
```ts
|
|
4682
|
+
import { Schedule } from "@umriss-ui/schedule";
|
|
4683
|
+
```
|
|
4684
|
+
|
|
4685
|
+
Demo page: https://romanhaendler.github.io/umriss-ui/schedule/interactions/
|
|
4686
|
+
|
|
4687
|
+
A hit names a subtask together with the part of it (lead-in, main time, lead-out), a dependency, a lane, or nothing.
|
|
4688
|
+
|
|
4689
|
+
While `onInteraction` is set, a right-click opens no browser menu: your application is expected to answer it.
|
|
4690
|
+
|
|
4691
|
+
#### Examples
|
|
4692
|
+
|
|
4693
|
+
##### Report what the pointer is on
|
|
4694
|
+
|
|
4695
|
+
`onInteraction` hears hover, click and right-click with the target, its part, the time and the lane - here written into a status line.
|
|
4696
|
+
|
|
4697
|
+
```tsx
|
|
4698
|
+
import { useState } from "react";
|
|
4699
|
+
import { Stack, Text } from "@umriss-ui/core";
|
|
4700
|
+
import { Dependencies, Lane, Schedule, Subtasks } from "@umriss-ui/schedule";
|
|
4701
|
+
import type { Dependency, ScheduleInteraction, Subtask, Task } from "@umriss-ui/schedule";
|
|
3755
4702
|
|
|
3756
4703
|
const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
|
|
3757
4704
|
const min = (n: number) => n * 60_000;
|
|
@@ -3777,9 +4724,9 @@ const describe = (interaction: ScheduleInteraction): string => {
|
|
|
3777
4724
|
: hit.kind === "dependency"
|
|
3778
4725
|
? `dependency ${hit.dependency.id}`
|
|
3779
4726
|
: hit.kind === "lane"
|
|
3780
|
-
?
|
|
4727
|
+
? "free time"
|
|
3781
4728
|
: "nothing";
|
|
3782
|
-
return `${interaction.type}: ${target} at ${time}`;
|
|
4729
|
+
return `${interaction.type}: ${target} at ${time}, lane ${interaction.lane ?? "none"}`;
|
|
3783
4730
|
};
|
|
3784
4731
|
|
|
3785
4732
|
export default function ReportThePointer() {
|
|
@@ -3929,18 +4876,36 @@ export default function OpenAContextMenu() {
|
|
|
3929
4876
|
- You only need to know which task was picked → Selection
|
|
3930
4877
|
- You need the time at a point outside an interaction → The handle
|
|
3931
4878
|
|
|
4879
|
+
#### Keyboard
|
|
4880
|
+
|
|
4881
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
4882
|
+
|
|
3932
4883
|
#### API
|
|
3933
4884
|
|
|
3934
4885
|
##### `ScheduleInteraction`
|
|
3935
4886
|
|
|
3936
4887
|
| Prop | Type | Default | Description |
|
|
3937
4888
|
|---|---|---|---|
|
|
3938
|
-
| `type`
|
|
3939
|
-
| `hit`
|
|
3940
|
-
| `clientX`
|
|
3941
|
-
| `clientY`
|
|
3942
|
-
| `time`
|
|
3943
|
-
| `lane`
|
|
4889
|
+
| `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 |
|
|
4890
|
+
| `hit` *required* | [`ScheduleHit`](#type-ScheduleHit) | — | What the pointer is on.<br>Shown in: [Report what the pointer is on](#/interactions/report-the-pointer), [Open a context menu](#/interactions/open-a-context-menu), [Show a detail panel instead (Tooltip)](#/tooltip/detail-panel-instead) and 1 more |
|
|
4891
|
+
| `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) |
|
|
4892
|
+
| `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) |
|
|
4893
|
+
| `time` *required* | `number` | — | The wall-clock instant under the pointer.<br>Shown in: [Report what the pointer is on](#/interactions/report-the-pointer) |
|
|
4894
|
+
| `lane` *required* | `string \| null` | — | The lane under the pointer, or null below the last one.<br>Shown in: [Report what the pointer is on](#/interactions/report-the-pointer) |
|
|
4895
|
+
|
|
4896
|
+
##### Types on this page
|
|
4897
|
+
|
|
4898
|
+
###### `ScheduleHit`
|
|
4899
|
+
|
|
4900
|
+
What a pointer is on.
|
|
4901
|
+
|
|
4902
|
+
```ts
|
|
4903
|
+
type ScheduleHit =
|
|
4904
|
+
| { readonly kind: "subtask"; readonly subtask: Subtask; readonly part: "leadIn" | "main" | "leadOut" }
|
|
4905
|
+
| { readonly kind: "dependency"; readonly dependency: Dependency }
|
|
4906
|
+
| { readonly kind: "lane"; readonly lane: string }
|
|
4907
|
+
| { readonly kind: "nothing" };
|
|
4908
|
+
```
|
|
3944
4909
|
|
|
3945
4910
|
### Tooltip
|
|
3946
4911
|
|
|
@@ -4225,22 +5190,99 @@ export default function DetailPanelInstead() {
|
|
|
4225
5190
|
}
|
|
4226
5191
|
```
|
|
4227
5192
|
|
|
5193
|
+
##### Say what a bar covers and a line joins
|
|
5194
|
+
|
|
5195
|
+
The target says what is hovered: a bar brings its `subtask` and the `blocked` time it covers, a line its `dependency` with the subtasks it joins, `from` and `to`.
|
|
5196
|
+
|
|
5197
|
+
```tsx
|
|
5198
|
+
import { Stack, Text } from "@umriss-ui/core";
|
|
5199
|
+
import { BlockedTimes, Dependencies, Lane, Schedule, Subtasks } from "@umriss-ui/schedule";
|
|
5200
|
+
import type { BlockedTime, Dependency, ScheduleTooltipTarget, Subtask, Task } from "@umriss-ui/schedule";
|
|
5201
|
+
|
|
5202
|
+
const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
|
|
5203
|
+
const min = (n: number) => n * 60_000;
|
|
5204
|
+
|
|
5205
|
+
const PROJECTS: Task[] = [{ id: "portal", name: "Member portal", color: "light-dark(#2563eb, #6b9bff)" }];
|
|
5206
|
+
|
|
5207
|
+
const WORK: Subtask[] = [
|
|
5208
|
+
{ id: "design", task: "portal", lane: "noah", from: at(7), to: at(9), name: "Design" },
|
|
5209
|
+
{ id: "build", task: "portal", lane: "arjun", from: at(9, 30), to: at(13), name: "Build" },
|
|
5210
|
+
{ id: "test", task: "portal", lane: "eva", from: at(13, 30), to: at(15), name: "Test" },
|
|
5211
|
+
];
|
|
5212
|
+
|
|
5213
|
+
const HANDOVERS: Dependency[] = [
|
|
5214
|
+
{ id: "to-build", from: "design", to: "build", lag: min(15) },
|
|
5215
|
+
{ id: "to-test", from: "build", to: "test", lag: min(15) },
|
|
5216
|
+
];
|
|
5217
|
+
|
|
5218
|
+
const LEAVE: BlockedTime[] = [{ id: "arjun-dentist", lane: "arjun", from: at(11), to: at(12), label: "Dentist" }];
|
|
5219
|
+
|
|
5220
|
+
const time = (instant: number) => new Date(instant).toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" });
|
|
5221
|
+
|
|
5222
|
+
function Covers({ target }: { target: ScheduleTooltipTarget }) {
|
|
5223
|
+
if (target.kind === "dependency") {
|
|
5224
|
+
return (
|
|
5225
|
+
<Stack gap={1}>
|
|
5226
|
+
<Text size="sm" weight="semibold">
|
|
5227
|
+
Handover {target.dependency.id}
|
|
5228
|
+
</Text>
|
|
5229
|
+
<Text size="xs" tone="secondary">
|
|
5230
|
+
{target.from?.name ?? "?"} → {target.to?.name ?? "?"}
|
|
5231
|
+
</Text>
|
|
5232
|
+
</Stack>
|
|
5233
|
+
);
|
|
5234
|
+
}
|
|
5235
|
+
return (
|
|
5236
|
+
<Stack gap={1}>
|
|
5237
|
+
<Text size="sm" weight="semibold">
|
|
5238
|
+
{target.subtask.name}
|
|
5239
|
+
</Text>
|
|
5240
|
+
<Text size="xs" tone="secondary">
|
|
5241
|
+
{time(target.subtask.from)} – {time(target.subtask.to)}
|
|
5242
|
+
</Text>
|
|
5243
|
+
{target.blocked.map((blocked) => (
|
|
5244
|
+
<Text size="xs" tone="secondary" key={blocked.id}>
|
|
5245
|
+
Covers {blocked.label}, {time(blocked.from)} – {time(blocked.to)}
|
|
5246
|
+
</Text>
|
|
5247
|
+
))}
|
|
5248
|
+
</Stack>
|
|
5249
|
+
);
|
|
5250
|
+
}
|
|
5251
|
+
|
|
5252
|
+
export default function SayWhatABarCoversAndALineJoins() {
|
|
5253
|
+
return (
|
|
5254
|
+
<Schedule ariaLabel="Design, build and test, with leave under the build" initialDomain={[at(6, 30), at(15, 30)]} height={188} tooltip={(target) => <Covers target={target} />}>
|
|
5255
|
+
<Lane id="noah" label="Noah Fischer" />
|
|
5256
|
+
<Lane id="arjun" label="Arjun Mehta" />
|
|
5257
|
+
<Lane id="eva" label="Eva Novak" />
|
|
5258
|
+
<BlockedTimes data={LEAVE} />
|
|
5259
|
+
<Dependencies data={HANDOVERS} />
|
|
5260
|
+
<Subtasks data={WORK} tasks={PROJECTS} />
|
|
5261
|
+
</Schedule>
|
|
5262
|
+
);
|
|
5263
|
+
}
|
|
5264
|
+
```
|
|
5265
|
+
|
|
5266
|
+
#### Keyboard
|
|
5267
|
+
|
|
5268
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
5269
|
+
|
|
4228
5270
|
#### API
|
|
4229
5271
|
|
|
4230
5272
|
##### `ScheduleTooltipTarget`
|
|
4231
5273
|
|
|
4232
5274
|
| Prop | Type | Default | Description |
|
|
4233
5275
|
|---|---|---|---|
|
|
4234
|
-
| `kind`
|
|
4235
|
-
| `subtask` | `Subtask` | — | The hovered subtask
|
|
4236
|
-
| `task`
|
|
4237
|
-
| `overlapping` | `readonly Subtask[]` | — | The subtasks it overlaps with on its lane
|
|
4238
|
-
| `violatedDependencies` | `readonly ViolatedDependency[]` | — | The violated dependencies leaving or reaching it
|
|
4239
|
-
| `blocked` | `readonly BlockedTime[]` | — | The blocked time it covers on its lane
|
|
4240
|
-
| `dependency` | `Dependency` | — | The hovered dependency
|
|
4241
|
-
| `from` | `Subtask \| undefined` | — | The subtask it leaves
|
|
4242
|
-
| `to` | `Subtask \| undefined` | — | The subtask it reaches
|
|
4243
|
-
| `violated` | `ViolatedDependency \| undefined` | — | Its finding, where it is violated
|
|
5276
|
+
| `kind` *required* | `"subtask" \| "dependency"` | — | A subtask is hovered. A dependency is hovered.<br>Shown in: [Write your own tooltip content](#/tooltip/own-tooltip), [Say what a bar covers and a line joins](#/tooltip/say-what-a-bar-covers-and-a-line-joins) |
|
|
5277
|
+
| `subtask` | [`Subtask`](#/subtasks/type-Subtask) | — | The hovered subtask.<br>Shown in: [Say what a bar covers and a line joins](#/tooltip/say-what-a-bar-covers-and-a-line-joins) |
|
|
5278
|
+
| `task` *required* | [`Task`](#/subtasks/type-Task)` \| undefined` | — | Its task, where the tasks name it.<br>Shown in: [Write your own tooltip content](#/tooltip/own-tooltip) |
|
|
5279
|
+
| `overlapping` | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks it overlaps with on its lane.<br>Shown in: [Write your own tooltip content](#/tooltip/own-tooltip) |
|
|
5280
|
+
| `violatedDependencies` | `readonly `[`ViolatedDependency`](#/findings/type-ViolatedDependency)`[]` | — | The violated dependencies leaving or reaching it.<br>Shown in: [Write your own tooltip content](#/tooltip/own-tooltip) |
|
|
5281
|
+
| `blocked` | `readonly `[`BlockedTime`](#/blocked-time/type-BlockedTime)`[]` | — | The blocked time it covers on its lane.<br>Shown in: [Say what a bar covers and a line joins](#/tooltip/say-what-a-bar-covers-and-a-line-joins) |
|
|
5282
|
+
| `dependency` | [`Dependency`](#/dependencies/type-Dependency) | — | The hovered dependency.<br>Shown in: [Say what a bar covers and a line joins](#/tooltip/say-what-a-bar-covers-and-a-line-joins) |
|
|
5283
|
+
| `from` | [`Subtask`](#/subtasks/type-Subtask)` \| undefined` | — | The subtask it leaves.<br>Shown in: [Say what a bar covers and a line joins](#/tooltip/say-what-a-bar-covers-and-a-line-joins) |
|
|
5284
|
+
| `to` | [`Subtask`](#/subtasks/type-Subtask)` \| undefined` | — | The subtask it reaches.<br>Shown in: [Say what a bar covers and a line joins](#/tooltip/say-what-a-bar-covers-and-a-line-joins) |
|
|
5285
|
+
| `violated` | [`ViolatedDependency`](#/findings/type-ViolatedDependency)` \| undefined` | — | Its finding, where it is violated.<br>Shown in: [Write your own tooltip content](#/tooltip/own-tooltip) |
|
|
4244
5286
|
|
|
4245
5287
|
### Linked schedules
|
|
4246
5288
|
|
|
@@ -4486,11 +5528,72 @@ export default function RotaBesideIncidents() {
|
|
|
4486
5528
|
|
|
4487
5529
|
- The lanes belong together in one plan → Lane groups
|
|
4488
5530
|
|
|
5531
|
+
#### Keyboard
|
|
5532
|
+
|
|
5533
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
5534
|
+
|
|
5535
|
+
#### Props on this page
|
|
5536
|
+
|
|
5537
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
5538
|
+
|
|
5539
|
+
| Prop | Type | Default | Description |
|
|
5540
|
+
|---|---|---|---|
|
|
5541
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
5542
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
5543
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
5544
|
+
|
|
5545
|
+
###### Events
|
|
5546
|
+
|
|
5547
|
+
| Prop | Type | Default | Description |
|
|
5548
|
+
|---|---|---|---|
|
|
5549
|
+
| [`onDomainChange`](#/schedule/ScheduleProps-onDomainChange) | `(domain: readonly [number, number]) => void` | — | The visible time span after the planner panned or zoomed, as two wall-clock instants - for keeping a second schedule or a chart in step. A span handed in through `initialDomain` is not reported back. |
|
|
5550
|
+
|
|
5551
|
+
###### Accessibility
|
|
5552
|
+
|
|
5553
|
+
| Prop | Type | Default | Description |
|
|
5554
|
+
|---|---|---|---|
|
|
5555
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
5556
|
+
|
|
5557
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
5558
|
+
|
|
5559
|
+
| Prop | Type | Default | Description |
|
|
5560
|
+
|---|---|---|---|
|
|
5561
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
5562
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
5563
|
+
|
|
5564
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
5565
|
+
|
|
5566
|
+
| Prop | Type | Default | Description |
|
|
5567
|
+
|---|---|---|---|
|
|
5568
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
5569
|
+
| [`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. |
|
|
5570
|
+
|
|
5571
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
5572
|
+
|
|
5573
|
+
| Prop | Type | Default | Description |
|
|
5574
|
+
|---|---|---|---|
|
|
5575
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
5576
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
5577
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
5578
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
5579
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
5580
|
+
| [`leadIn`](#/subtasks/Subtask-leadIn) | `number` | — | Duration of the lead-in before the main time; none is zero. |
|
|
5581
|
+
| [`leadOut`](#/subtasks/Subtask-leadOut) | `number` | — | Duration of the lead-out after the main time; none is zero. |
|
|
5582
|
+
| [`name`](#/subtasks/Subtask-name) | `string` | — | What the subtask is called, where the schedule names it. |
|
|
5583
|
+
|
|
5584
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
5585
|
+
|
|
5586
|
+
| Prop | Type | Default | Description |
|
|
5587
|
+
|---|---|---|---|
|
|
5588
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
5589
|
+
| [`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. |
|
|
5590
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
5591
|
+
|
|
4489
5592
|
#### Known limits
|
|
4490
5593
|
|
|
4491
5594
|
- Only the span is shared - not the selection, the hover or the vertical scroll.
|
|
4492
5595
|
|
|
4493
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.
|
|
5596
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
|
|
4494
5597
|
|
|
4495
5598
|
### The handle
|
|
4496
5599
|
|
|
@@ -4597,109 +5700,392 @@ export default function PlaceAMark() {
|
|
|
4597
5700
|
|
|
4598
5701
|
- You need the time under the pointer during a hover or a click → Interactions
|
|
4599
5702
|
|
|
4600
|
-
|
|
5703
|
+
#### Keyboard
|
|
4601
5704
|
|
|
4602
|
-
|
|
5705
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
4603
5706
|
|
|
4604
|
-
|
|
5707
|
+
#### Props on this page
|
|
4605
5708
|
|
|
4606
|
-
|
|
5709
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
4607
5710
|
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
5711
|
+
| Prop | Type | Default | Description |
|
|
5712
|
+
|---|---|---|---|
|
|
5713
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
5714
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
5715
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
4611
5716
|
|
|
4612
|
-
|
|
5717
|
+
###### Events
|
|
4613
5718
|
|
|
4614
|
-
|
|
5719
|
+
| Prop | Type | Default | Description |
|
|
5720
|
+
|---|---|---|---|
|
|
5721
|
+
| [`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. |
|
|
5722
|
+
| [`onDomainChange`](#/schedule/ScheduleProps-onDomainChange) | `(domain: readonly [number, number]) => void` | — | The visible time span after the planner panned or zoomed, as two wall-clock instants - for keeping a second schedule or a chart in step. A span handed in through `initialDomain` is not reported back. |
|
|
4615
5723
|
|
|
4616
|
-
|
|
5724
|
+
###### Accessibility
|
|
4617
5725
|
|
|
4618
|
-
|
|
5726
|
+
| Prop | Type | Default | Description |
|
|
5727
|
+
|---|---|---|---|
|
|
5728
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
4619
5729
|
|
|
4620
|
-
|
|
5730
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
4621
5731
|
|
|
4622
|
-
|
|
5732
|
+
| Prop | Type | Default | Description |
|
|
5733
|
+
|---|---|---|---|
|
|
5734
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
5735
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
4623
5736
|
|
|
4624
|
-
|
|
5737
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
4625
5738
|
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
5739
|
+
| Prop | Type | Default | Description |
|
|
5740
|
+
|---|---|---|---|
|
|
5741
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
5742
|
+
| [`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. |
|
|
4630
5743
|
|
|
4631
|
-
|
|
5744
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
4632
5745
|
|
|
4633
|
-
|
|
5746
|
+
| Prop | Type | Default | Description |
|
|
5747
|
+
|---|---|---|---|
|
|
5748
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
5749
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
5750
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
5751
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
5752
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
5753
|
+
| [`leadIn`](#/subtasks/Subtask-leadIn) | `number` | — | Duration of the lead-in before the main time; none is zero. |
|
|
5754
|
+
| [`leadOut`](#/subtasks/Subtask-leadOut) | `number` | — | Duration of the lead-out after the main time; none is zero. |
|
|
4634
5755
|
|
|
4635
|
-
|
|
4636
|
-
{ id: "w-102", task: "portal", lane: "arjun", from: day(17), to: day(18, 17), name: "Profile page" },
|
|
4637
|
-
{ id: "w-105", task: "portal", lane: "chloe", from: day(18), to: day(19, 17), name: "Change of address form" },
|
|
4638
|
-
];
|
|
5756
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
4639
5757
|
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
5758
|
+
| Prop | Type | Default | Description |
|
|
5759
|
+
|---|---|---|---|
|
|
5760
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
5761
|
+
| [`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. |
|
|
5762
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
5763
|
+
|
|
5764
|
+
From `ScheduleInteraction` — the full table stands on [Interactions](#/interactions/type-ScheduleInteraction).
|
|
5765
|
+
|
|
5766
|
+
| Prop | Type | Default | Description |
|
|
5767
|
+
|---|---|---|---|
|
|
5768
|
+
| [`clientX`](#/interactions/ScheduleInteraction-clientX) *required* | `number` | — | The pointer's horizontal client coordinate - where a `ContextMenu` opens. |
|
|
5769
|
+
| [`clientY`](#/interactions/ScheduleInteraction-clientY) *required* | `number` | — | The pointer's vertical client coordinate. |
|
|
5770
|
+
|
|
5771
|
+
### Findings as data
|
|
5772
|
+
|
|
5773
|
+
Lists what is wrong with a plan - double bookings on a lane, dependencies that do not fit, work in blocked time - from the same data the schedule draws. Reach for it to list, count or filter the problems beside the picture.
|
|
5774
|
+
|
|
5775
|
+
```ts
|
|
5776
|
+
import { findings, overlaps, violatedDependencies, inBlockedTime } from "@umriss-ui/schedule";
|
|
4656
5777
|
```
|
|
4657
5778
|
|
|
4658
|
-
|
|
5779
|
+
Demo page: https://romanhaendler.github.io/umriss-ui/schedule/findings/
|
|
4659
5780
|
|
|
4660
|
-
|
|
5781
|
+
`findings(subtasks, dependencies, blocked)` returns all three kinds; [`overlaps`](#/api/overlaps), [`violatedDependencies`](#/api/violatedDependencies) and [`inBlockedTime`](#/api/inBlockedTime) return one each. They are pure functions: run them wherever the data changes, with or without a schedule on screen.
|
|
5782
|
+
|
|
5783
|
+
Lead-in and lead-out count as occupied time; touching at a shared edge is no overlap.
|
|
5784
|
+
|
|
5785
|
+
#### Examples
|
|
5786
|
+
|
|
5787
|
+
##### List the findings
|
|
5788
|
+
|
|
5789
|
+
[`findings`](#/api/findings) returns what the schedule marks - overlaps, violated dependencies, work in blocked time - as data for a list beside it.
|
|
4661
5790
|
|
|
4662
5791
|
```tsx
|
|
4663
|
-
import { useState } from "react";
|
|
4664
5792
|
import { Stack, Text } from "@umriss-ui/core";
|
|
4665
|
-
import { Dependencies, Lane, Schedule, Subtasks,
|
|
4666
|
-
import type {
|
|
4667
|
-
|
|
4668
|
-
const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
|
|
4669
|
-
const min = (n: number) => n * 60_000;
|
|
5793
|
+
import { BlockedTimes, Dependencies, Lane, Schedule, Subtasks, findings } from "@umriss-ui/schedule";
|
|
5794
|
+
import type { BlockedTime, Dependency, Subtask, Task } from "@umriss-ui/schedule";
|
|
4670
5795
|
|
|
4671
|
-
const
|
|
4672
|
-
{ id: "truck-118", label: "Truck FP 118 R" },
|
|
4673
|
-
{ id: "van-402", label: "Van FP 402 R" },
|
|
4674
|
-
{ id: "truck-520", label: "Truck FP 520 E" },
|
|
4675
|
-
{ id: "van-455", label: "E-van FP 455 R" },
|
|
4676
|
-
{ id: "van-290", label: "Van FP 290 E" },
|
|
4677
|
-
];
|
|
5796
|
+
const day = (d: number, hours = 9) => new Date(2026, 2, d, hours).getTime();
|
|
4678
5797
|
|
|
4679
|
-
const
|
|
4680
|
-
{ id: "
|
|
4681
|
-
{ id: "
|
|
4682
|
-
{ id: "c-2045", name: "C-2045 Tamsin's Bakery", color: "light-dark(#be185d, #f06aa6)" },
|
|
4683
|
-
{ id: "c-2046", name: "C-2046 Pellham Hardware", color: "light-dark(#4d7c0f, #8fc43e)" },
|
|
5798
|
+
const PROJECTS: readonly Task[] = [
|
|
5799
|
+
{ id: "shop", name: "Online shop relaunch", color: "light-dark(#2563eb, #6b9bff)" },
|
|
5800
|
+
{ id: "portal", name: "Member portal", color: "light-dark(#7c3aed, #a98bfa)" },
|
|
4684
5801
|
];
|
|
4685
5802
|
|
|
4686
|
-
const
|
|
4687
|
-
{ id: "
|
|
4688
|
-
{ id: "
|
|
4689
|
-
{ id: "
|
|
4690
|
-
{ id: "
|
|
4691
|
-
{ id: "c-2043-3", task: "c-2043", lane: "van-455", from: at(12), to: at(14), leadIn: min(20), leadOut: min(20) },
|
|
4692
|
-
{ id: "c-2045-3", task: "c-2045", lane: "van-290", from: at(15, 45), to: at(16, 30) },
|
|
5803
|
+
const WORK: readonly Subtask[] = [
|
|
5804
|
+
{ id: "design", task: "shop", lane: "noah", from: day(16), to: day(17, 17), name: "Search results layout" },
|
|
5805
|
+
{ id: "build", task: "shop", lane: "chloe", from: day(17), to: day(19, 17), name: "Search results page" },
|
|
5806
|
+
{ id: "address", task: "portal", lane: "chloe", from: day(18), to: day(19, 17), name: "Change of address form" },
|
|
5807
|
+
{ id: "profile", task: "portal", lane: "arjun", from: day(17), to: day(19, 17), name: "Profile page" },
|
|
4693
5808
|
];
|
|
4694
5809
|
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
{ id: "t-2043-2", from: "c-2043-2", to: "c-2043-3", lag: min(25) },
|
|
4698
|
-
];
|
|
5810
|
+
/* The build may start only a morning after the design is done. */
|
|
5811
|
+
const HANDOVERS: readonly Dependency[] = [{ id: "design-to-build", from: "design", to: "build", lag: 4 * 60 * 60_000 }];
|
|
4699
5812
|
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
5813
|
+
const LEAVE: readonly BlockedTime[] = [{ id: "arjun-holiday", lane: "arjun", from: day(18, 0), to: day(21, 0), label: "Holiday" }];
|
|
5814
|
+
|
|
5815
|
+
const when = (instant: number) => new Date(instant).toLocaleString("en-GB", { weekday: "short", hour: "2-digit", minute: "2-digit" });
|
|
5816
|
+
const hours = (ms: number) => Math.round(ms / 3_600_000);
|
|
5817
|
+
|
|
5818
|
+
export default function ListTheFindings() {
|
|
5819
|
+
const found = findings(WORK, HANDOVERS, LEAVE);
|
|
5820
|
+
|
|
5821
|
+
return (
|
|
5822
|
+
<Stack gap={3}>
|
|
5823
|
+
<Schedule ariaLabel="Three people's week with its findings" initialDomain={[day(16, 0), day(21, 0)]} height={184}>
|
|
5824
|
+
<Lane id="noah" label="Noah Fischer" />
|
|
5825
|
+
<Lane id="chloe" label="Chloe Durand" />
|
|
5826
|
+
<Lane id="arjun" label="Arjun Mehta" />
|
|
5827
|
+
<BlockedTimes data={LEAVE} />
|
|
5828
|
+
<Dependencies data={HANDOVERS} />
|
|
5829
|
+
<Subtasks data={WORK} tasks={PROJECTS} />
|
|
5830
|
+
</Schedule>
|
|
5831
|
+
<ul style={{ margin: 0, paddingLeft: 18 }}>
|
|
5832
|
+
{found.overlaps.map((o) => (
|
|
5833
|
+
<Text as="li" size="sm" key={`${o.first}/${o.second}`}>
|
|
5834
|
+
Double-booked: {o.lane} has {o.first} and {o.second} from {when(o.from)} to {when(o.to)}
|
|
5835
|
+
</Text>
|
|
5836
|
+
))}
|
|
5837
|
+
{found.violatedDependencies.map((v) => (
|
|
5838
|
+
<Text as="li" size="sm" key={v.dependency}>
|
|
5839
|
+
Too early: {v.dependency} leaves {when(v.departure)} for a start at {when(v.arrival)}, {hours(v.shortBy)} hours short
|
|
5840
|
+
</Text>
|
|
5841
|
+
))}
|
|
5842
|
+
{found.inBlockedTime.map((b) => (
|
|
5843
|
+
<Text as="li" size="sm" key={`${b.subtask}/${b.blocked}`}>
|
|
5844
|
+
In leave: {b.subtask} covers {b.blocked} from {when(b.from)} to {when(b.to)}
|
|
5845
|
+
</Text>
|
|
5846
|
+
))}
|
|
5847
|
+
</ul>
|
|
5848
|
+
</Stack>
|
|
5849
|
+
);
|
|
5850
|
+
}
|
|
5851
|
+
```
|
|
5852
|
+
|
|
5853
|
+
##### Say when there is nothing to fix
|
|
5854
|
+
|
|
5855
|
+
When all three lists [`findings`](#/api/findings) returns are empty, say so plainly instead of showing an empty list.
|
|
5856
|
+
|
|
5857
|
+
```tsx
|
|
5858
|
+
import { EmptyState, Stack } from "@umriss-ui/core";
|
|
5859
|
+
import { Lane, Schedule, Subtasks, findings } from "@umriss-ui/schedule";
|
|
5860
|
+
import type { Subtask, Task } from "@umriss-ui/schedule";
|
|
5861
|
+
|
|
5862
|
+
const day = (d: number, hours = 9) => new Date(2026, 2, d, hours).getTime();
|
|
5863
|
+
|
|
5864
|
+
const PROJECTS: readonly Task[] = [{ id: "booking", name: "Booking app", color: "light-dark(#0d9488, #3cc7b8)" }];
|
|
5865
|
+
|
|
5866
|
+
const WORK: readonly Subtask[] = [
|
|
5867
|
+
{ id: "w-111", task: "booking", lane: "hana", from: day(16), to: day(18, 17), name: "Push notifications" },
|
|
5868
|
+
{ id: "w-113", task: "booking", lane: "kofi", from: day(16), to: day(18, 17), name: "Calendar sync" },
|
|
5869
|
+
];
|
|
5870
|
+
|
|
5871
|
+
export default function NothingToFix() {
|
|
5872
|
+
const found = findings(WORK, []);
|
|
5873
|
+
const count = found.overlaps.length + found.violatedDependencies.length + found.inBlockedTime.length;
|
|
5874
|
+
|
|
5875
|
+
return (
|
|
5876
|
+
<Stack gap={3}>
|
|
5877
|
+
<Schedule ariaLabel="Two developers' week, without findings" initialDomain={[day(16, 0), day(21, 0)]} height={140}>
|
|
5878
|
+
<Lane id="hana" label="Hana Sato" />
|
|
5879
|
+
<Lane id="kofi" label="Kofi Mensah" />
|
|
5880
|
+
<Subtasks data={WORK} tasks={PROJECTS} />
|
|
5881
|
+
</Schedule>
|
|
5882
|
+
{count === 0 && <EmptyState title="Nothing to fix" description="Nobody is double-booked, every hand-over fits, and no work falls into leave." />}
|
|
5883
|
+
</Stack>
|
|
5884
|
+
);
|
|
5885
|
+
}
|
|
5886
|
+
```
|
|
5887
|
+
|
|
5888
|
+
##### Count the findings per kind
|
|
5889
|
+
|
|
5890
|
+
[`overlaps`](#/api/overlaps) and [`violatedDependencies`](#/api/violatedDependencies) are the halves of [`findings`](#/api/findings) on their own - here as counts above the day's legs.
|
|
5891
|
+
|
|
5892
|
+
```tsx
|
|
5893
|
+
import { Badge, Stack } from "@umriss-ui/core";
|
|
5894
|
+
import { Dependencies, Lane, Schedule, Subtasks, overlaps, violatedDependencies } from "@umriss-ui/schedule";
|
|
5895
|
+
import type { Dependency, Subtask, Task } from "@umriss-ui/schedule";
|
|
5896
|
+
|
|
5897
|
+
const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
|
|
5898
|
+
const min = (n: number) => n * 60_000;
|
|
5899
|
+
|
|
5900
|
+
const VEHICLES = [
|
|
5901
|
+
{ id: "van-402", label: "Van FP 402 R" },
|
|
5902
|
+
{ id: "truck-520", label: "Truck FP 520 E" },
|
|
5903
|
+
{ id: "van-455", label: "E-van FP 455 R" },
|
|
5904
|
+
];
|
|
5905
|
+
|
|
5906
|
+
const CONSIGNMENTS: readonly Task[] = [
|
|
5907
|
+
{ id: "c-2041", name: "C-2041 Holloway Garden Supplies", color: "light-dark(#2563eb, #6b9bff)" },
|
|
5908
|
+
{ id: "c-2043", name: "C-2043 Oakridge Pharmacy", color: "light-dark(#c2410c, #f08a52)" },
|
|
5909
|
+
];
|
|
5910
|
+
|
|
5911
|
+
const LEGS: readonly Subtask[] = [
|
|
5912
|
+
{ id: "c-2041-2", task: "c-2041", lane: "van-402", from: at(8), to: at(10, 30), leadIn: min(30), leadOut: min(15) },
|
|
5913
|
+
{ id: "c-2043-1", task: "c-2043", lane: "truck-520", from: at(6, 30), to: at(8), leadIn: min(30), leadOut: min(15) },
|
|
5914
|
+
{ id: "c-2043-2", task: "c-2043", lane: "van-402", from: at(10), to: at(11, 30), leadIn: min(15) },
|
|
5915
|
+
{ id: "c-2043-3", task: "c-2043", lane: "van-455", from: at(12), to: at(14), leadIn: min(20), leadOut: min(20) },
|
|
5916
|
+
];
|
|
5917
|
+
|
|
5918
|
+
const TRANSFERS: readonly Dependency[] = [
|
|
5919
|
+
{ id: "t-2043-1", from: "c-2043-1", to: "c-2043-2", lag: min(45) },
|
|
5920
|
+
{ id: "t-2043-2", from: "c-2043-2", to: "c-2043-3", lag: min(25) },
|
|
5921
|
+
];
|
|
5922
|
+
|
|
5923
|
+
export default function CountPerKind() {
|
|
5924
|
+
const doubleBooked = overlaps(LEGS).length;
|
|
5925
|
+
const late = violatedDependencies(LEGS, TRANSFERS).length;
|
|
5926
|
+
|
|
5927
|
+
return (
|
|
5928
|
+
<Stack gap={3}>
|
|
5929
|
+
<Stack direction="row" gap={2}>
|
|
5930
|
+
<Badge tone={doubleBooked > 0 ? "warning" : "success"}>{doubleBooked} double-booked</Badge>
|
|
5931
|
+
<Badge tone={late > 0 ? "warning" : "success"}>{late} transfers too short</Badge>
|
|
5932
|
+
</Stack>
|
|
5933
|
+
<Schedule ariaLabel="The day's legs with their findings counted" initialDomain={[at(5, 30), at(18)]} height={196}>
|
|
5934
|
+
{VEHICLES.map((vehicle) => (
|
|
5935
|
+
<Lane key={vehicle.id} id={vehicle.id} label={vehicle.label} />
|
|
5936
|
+
))}
|
|
5937
|
+
<Dependencies data={TRANSFERS} />
|
|
5938
|
+
<Subtasks data={LEGS} tasks={CONSIGNMENTS} />
|
|
5939
|
+
</Schedule>
|
|
5940
|
+
</Stack>
|
|
5941
|
+
);
|
|
5942
|
+
}
|
|
5943
|
+
```
|
|
5944
|
+
|
|
5945
|
+
#### Keyboard
|
|
5946
|
+
|
|
5947
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
5948
|
+
|
|
5949
|
+
#### API
|
|
5950
|
+
|
|
5951
|
+
##### `Overlap`
|
|
5952
|
+
|
|
5953
|
+
| Prop | Type | Default | Description |
|
|
5954
|
+
|---|---|---|---|
|
|
5955
|
+
| `lane` *required* | `string` | — | The lane both sit on.<br>Shown in: [List the findings](#/findings/list-the-findings), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) |
|
|
5956
|
+
| `first` *required* | `string` | — | The subtask that starts earlier (lead-in included); on a tie, the one that stands first in the data.<br>Shown in: [List the findings](#/findings/list-the-findings), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) |
|
|
5957
|
+
| `second` *required* | `string` | — | The other one.<br>Shown in: [List the findings](#/findings/list-the-findings), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) |
|
|
5958
|
+
| `from` *required* | `number` | — | Where the covering begins.<br>Shown in: [List the findings](#/findings/list-the-findings) |
|
|
5959
|
+
| `to` *required* | `number` | — | Where it ends.<br>Shown in: [List the findings](#/findings/list-the-findings) |
|
|
5960
|
+
|
|
5961
|
+
##### `ViolatedDependency`
|
|
5962
|
+
|
|
5963
|
+
| Prop | Type | Default | Description |
|
|
5964
|
+
|---|---|---|---|
|
|
5965
|
+
| `dependency` *required* | `string` | — | The id of the dependency.<br>Shown in: [List the findings](#/findings/list-the-findings) |
|
|
5966
|
+
| `departure` *required* | `number` | — | When it leaves, by its anchor.<br>Shown in: [List the findings](#/findings/list-the-findings) |
|
|
5967
|
+
| `arrival` *required* | `number` | — | When it has to have arrived, by its anchor.<br>Shown in: [List the findings](#/findings/list-the-findings) |
|
|
5968
|
+
| `shortBy` *required* | `number` | — | How much time is missing: departure plus lag, minus arrival.<br>Shown in: [List the findings](#/findings/list-the-findings) |
|
|
5969
|
+
|
|
5970
|
+
##### `InBlockedTime`
|
|
5971
|
+
|
|
5972
|
+
| Prop | Type | Default | Description |
|
|
5973
|
+
|---|---|---|---|
|
|
5974
|
+
| `subtask` *required* | `string` | — | The id of the subtask.<br>Shown in: [List the findings](#/findings/list-the-findings), [Block out leave and maintenance (Blocked time)](#/blocked-time/leave), [Check a sprint against the leave calendar (Blocked time)](#/blocked-time/team-leave) and 2 more |
|
|
5975
|
+
| `blocked` *required* | `string` | — | The id of the blocked time it covers.<br>Shown in: [List the findings](#/findings/list-the-findings), [Block out leave and maintenance (Blocked time)](#/blocked-time/leave), [Plan the sprint around leave (Scenarios)](#/scenarios/plan-the-sprint-around-leave) |
|
|
5976
|
+
| `lane` *required* | `string` | — | The lane both are on.<br>Shown in: [Hand over the on-call week (Scenarios)](#/scenarios/hand-over-the-on-call-week), [Plan the sprint around leave (Scenarios)](#/scenarios/plan-the-sprint-around-leave) |
|
|
5977
|
+
| `from` *required* | `number` | — | Where the covering begins.<br>Shown in: [List the findings](#/findings/list-the-findings), [Block out leave and maintenance (Blocked time)](#/blocked-time/leave), [Hand over the on-call week (Scenarios)](#/scenarios/hand-over-the-on-call-week) |
|
|
5978
|
+
| `to` *required* | `number` | — | Where it ends.<br>Shown in: [List the findings](#/findings/list-the-findings), [Block out leave and maintenance (Blocked time)](#/blocked-time/leave), [Hand over the on-call week (Scenarios)](#/scenarios/hand-over-the-on-call-week) |
|
|
5979
|
+
|
|
5980
|
+
#### Known limits
|
|
5981
|
+
|
|
5982
|
+
- Overlapping work is marked, not packed into sub-lanes; stacked overlap is not built yet.
|
|
5983
|
+
|
|
5984
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
|
|
5985
|
+
|
|
5986
|
+
## Editing
|
|
5987
|
+
|
|
5988
|
+
Direct manipulation that changes nothing by itself: the schedule reports, the application decides.
|
|
5989
|
+
|
|
5990
|
+
### Move and lane
|
|
5991
|
+
|
|
5992
|
+
Drag a bar to a new time or onto another lane (also called drag-and-drop rescheduling). A ghost shows where it would land and what that would cause; the drop reports the change for your application to apply.
|
|
5993
|
+
|
|
5994
|
+
```ts
|
|
5995
|
+
import { Schedule, applyIntent } from "@umriss-ui/schedule";
|
|
5996
|
+
```
|
|
5997
|
+
|
|
5998
|
+
Demo page: https://romanhaendler.github.io/umriss-ui/schedule/move-and-lane/
|
|
5999
|
+
|
|
6000
|
+
Each name in `intents` enables one gesture. Without `intents` the schedule is read-only, and pressing a bar pans the plot.
|
|
6001
|
+
|
|
6002
|
+
The schedule never changes your data ([ADR-0023](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0023-editing-is-controlled-the-schedule-reports-intents.md)): `onIntent` reports a move and a lane change as values, and [`applyIntent`](#/api/applyIntent) is the arithmetic to apply them. A drop across lanes and time reports both, and your handler may apply them, refuse them, or apply one.
|
|
6003
|
+
|
|
6004
|
+
Held at the edge of the plot, a drag pans it along; Escape cancels the drag.
|
|
6005
|
+
|
|
6006
|
+
#### Examples
|
|
6007
|
+
|
|
6008
|
+
##### Move work in time
|
|
6009
|
+
|
|
6010
|
+
List `move` in `intents` and apply what `onIntent` reports with [`applyIntent`](#/api/applyIntent); the plan changes only in your state.
|
|
6011
|
+
|
|
6012
|
+
```tsx
|
|
6013
|
+
import { useState } from "react";
|
|
6014
|
+
import { Lane, Schedule, Subtasks, applyIntent } from "@umriss-ui/schedule";
|
|
6015
|
+
import type { Subtask, Task } from "@umriss-ui/schedule";
|
|
6016
|
+
|
|
6017
|
+
const day = (d: number, hours = 9) => new Date(2026, 2, d, hours).getTime();
|
|
6018
|
+
|
|
6019
|
+
const PROJECTS: readonly Task[] = [{ id: "portal", name: "Member portal", color: "light-dark(#7c3aed, #a98bfa)" }];
|
|
6020
|
+
|
|
6021
|
+
const START: readonly Subtask[] = [
|
|
6022
|
+
{ id: "w-102", task: "portal", lane: "arjun", from: day(17), to: day(18, 17), name: "Profile page" },
|
|
6023
|
+
{ id: "w-105", task: "portal", lane: "chloe", from: day(18), to: day(19, 17), name: "Change of address form" },
|
|
6024
|
+
];
|
|
6025
|
+
|
|
6026
|
+
export default function MoveInTime() {
|
|
6027
|
+
const [work, setWork] = useState(START);
|
|
6028
|
+
return (
|
|
6029
|
+
<Schedule
|
|
6030
|
+
ariaLabel="Two people's work this week"
|
|
6031
|
+
initialDomain={[day(16, 0), day(21, 0)]}
|
|
6032
|
+
height={140}
|
|
6033
|
+
intents={["move"]}
|
|
6034
|
+
onIntent={(intent) => setWork((current) => current.map((item) => applyIntent(item, intent)))}
|
|
6035
|
+
>
|
|
6036
|
+
<Lane id="arjun" label="Arjun Mehta" />
|
|
6037
|
+
<Lane id="chloe" label="Chloe Durand" />
|
|
6038
|
+
<Subtasks data={work} tasks={PROJECTS} />
|
|
6039
|
+
</Schedule>
|
|
6040
|
+
);
|
|
6041
|
+
}
|
|
6042
|
+
```
|
|
6043
|
+
|
|
6044
|
+
##### Move work onto another lane
|
|
6045
|
+
|
|
6046
|
+
Add `lane` to `intents`: a drop reports a move and a lane change separately, and the ghost shows the findings first.
|
|
6047
|
+
|
|
6048
|
+
```tsx
|
|
6049
|
+
import { useState } from "react";
|
|
6050
|
+
import { Stack, Text } from "@umriss-ui/core";
|
|
6051
|
+
import { Dependencies, Lane, Schedule, Subtasks, applyIntent } from "@umriss-ui/schedule";
|
|
6052
|
+
import type { Dependency, Intent, Subtask, Task } from "@umriss-ui/schedule";
|
|
6053
|
+
|
|
6054
|
+
const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
|
|
6055
|
+
const min = (n: number) => n * 60_000;
|
|
6056
|
+
|
|
6057
|
+
const VEHICLES = [
|
|
6058
|
+
{ id: "truck-118", label: "Truck FP 118 R" },
|
|
6059
|
+
{ id: "van-402", label: "Van FP 402 R" },
|
|
6060
|
+
{ id: "truck-520", label: "Truck FP 520 E" },
|
|
6061
|
+
{ id: "van-455", label: "E-van FP 455 R" },
|
|
6062
|
+
{ id: "van-290", label: "Van FP 290 E" },
|
|
6063
|
+
];
|
|
6064
|
+
|
|
6065
|
+
const CONSIGNMENTS: readonly Task[] = [
|
|
6066
|
+
{ id: "c-2041", name: "C-2041 Holloway Garden Supplies", color: "light-dark(#2563eb, #6b9bff)" },
|
|
6067
|
+
{ id: "c-2043", name: "C-2043 Oakridge Pharmacy", color: "light-dark(#c2410c, #f08a52)" },
|
|
6068
|
+
{ id: "c-2045", name: "C-2045 Tamsin's Bakery", color: "light-dark(#be185d, #f06aa6)" },
|
|
6069
|
+
{ id: "c-2046", name: "C-2046 Pellham Hardware", color: "light-dark(#4d7c0f, #8fc43e)" },
|
|
6070
|
+
];
|
|
6071
|
+
|
|
6072
|
+
const LEGS: readonly Subtask[] = [
|
|
6073
|
+
{ id: "c-2041-1", task: "c-2041", lane: "truck-118", from: at(6), to: at(7), leadIn: min(15), leadOut: min(10) },
|
|
6074
|
+
{ id: "c-2043-1", task: "c-2043", lane: "truck-520", from: at(6, 30), to: at(8), leadIn: min(30), leadOut: min(15) },
|
|
6075
|
+
{ id: "c-2043-2", task: "c-2043", lane: "van-402", from: at(10), to: at(11, 30), leadIn: min(15) },
|
|
6076
|
+
{ id: "c-2046-2", task: "c-2046", lane: "van-402", from: at(13), to: at(14, 30), leadIn: min(20), leadOut: min(10) },
|
|
6077
|
+
{ id: "c-2043-3", task: "c-2043", lane: "van-455", from: at(12), to: at(14), leadIn: min(20), leadOut: min(20) },
|
|
6078
|
+
{ id: "c-2045-3", task: "c-2045", lane: "van-290", from: at(15, 45), to: at(16, 30) },
|
|
6079
|
+
];
|
|
6080
|
+
|
|
6081
|
+
const TRANSFERS: readonly Dependency[] = [
|
|
6082
|
+
{ id: "t-2043-1", from: "c-2043-1", to: "c-2043-2", lag: min(45) },
|
|
6083
|
+
{ id: "t-2043-2", from: "c-2043-2", to: "c-2043-3", lag: min(25) },
|
|
6084
|
+
];
|
|
6085
|
+
|
|
6086
|
+
export default function MoveToAnotherLane() {
|
|
6087
|
+
const [legs, setLegs] = useState(LEGS);
|
|
6088
|
+
const [last, setLast] = useState<Intent | null>(null);
|
|
4703
6089
|
|
|
4704
6090
|
return (
|
|
4705
6091
|
<Stack gap={3}>
|
|
@@ -4729,7 +6115,7 @@ export default function MoveToAnotherLane() {
|
|
|
4729
6115
|
|
|
4730
6116
|
##### Refuse a move that double-books someone
|
|
4731
6117
|
|
|
4732
|
-
Your `onIntent` decides: here it applies a drop only when `overlaps` finds no new double booking, and says why otherwise.
|
|
6118
|
+
Your `onIntent` decides: here it applies a drop only when [`overlaps`](#/api/overlaps) finds no new double booking, and says why otherwise.
|
|
4733
6119
|
|
|
4734
6120
|
```tsx
|
|
4735
6121
|
import { useRef, useState } from "react";
|
|
@@ -4876,12 +6262,95 @@ export default function RefuseADoubleBooking() {
|
|
|
4876
6262
|
| `Alt+← Alt+→` | Proposes moving the active subtask one raster step earlier or later, stepping over blocked time. |
|
|
4877
6263
|
| `Escape` | Cancels a drag in flight: the ghost goes and nothing is reported. |
|
|
4878
6264
|
|
|
4879
|
-
|
|
6265
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
4880
6266
|
|
|
4881
|
-
|
|
4882
|
-
- The keys move work in time only; a lane change needs the pointer.
|
|
6267
|
+
#### Props on this page
|
|
4883
6268
|
|
|
4884
|
-
|
|
6269
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
6270
|
+
|
|
6271
|
+
| Prop | Type | Default | Description |
|
|
6272
|
+
|---|---|---|---|
|
|
6273
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
6274
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
6275
|
+
| [`intents`](#/schedule/ScheduleProps-intents) | `readonly `[`IntentKind`](#/schedule/type-IntentKind)`[]` | `[]` | The intents the caller handles. Each one enables its interaction; none leaves a read-only schedule ([ADR-0023](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0023-editing-is-controlled-the-schedule-reports-intents.md)). |
|
|
6276
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
6277
|
+
|
|
6278
|
+
###### Events
|
|
6279
|
+
|
|
6280
|
+
| Prop | Type | Default | Description |
|
|
6281
|
+
|---|---|---|---|
|
|
6282
|
+
| [`onIntent`](#/schedule/ScheduleProps-onIntent) | `(intent: `[`Intent`](#/schedule/type-Intent)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
6283
|
+
|
|
6284
|
+
###### Accessibility
|
|
6285
|
+
|
|
6286
|
+
| Prop | Type | Default | Description |
|
|
6287
|
+
|---|---|---|---|
|
|
6288
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
6289
|
+
|
|
6290
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
6291
|
+
|
|
6292
|
+
| Prop | Type | Default | Description |
|
|
6293
|
+
|---|---|---|---|
|
|
6294
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
6295
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
6296
|
+
|
|
6297
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
6298
|
+
|
|
6299
|
+
| Prop | Type | Default | Description |
|
|
6300
|
+
|---|---|---|---|
|
|
6301
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
6302
|
+
| [`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. |
|
|
6303
|
+
|
|
6304
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
6305
|
+
|
|
6306
|
+
| Prop | Type | Default | Description |
|
|
6307
|
+
|---|---|---|---|
|
|
6308
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
6309
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
6310
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
6311
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
6312
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
6313
|
+
| [`leadIn`](#/subtasks/Subtask-leadIn) | `number` | — | Duration of the lead-in before the main time; none is zero. |
|
|
6314
|
+
| [`leadOut`](#/subtasks/Subtask-leadOut) | `number` | — | Duration of the lead-out after the main time; none is zero. |
|
|
6315
|
+
| [`name`](#/subtasks/Subtask-name) | `string` | — | What the subtask is called, where the schedule names it. |
|
|
6316
|
+
|
|
6317
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
6318
|
+
|
|
6319
|
+
| Prop | Type | Default | Description |
|
|
6320
|
+
|---|---|---|---|
|
|
6321
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
6322
|
+
| [`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. |
|
|
6323
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
6324
|
+
|
|
6325
|
+
From `DependenciesProps` — the full table stands on [Dependencies](#/dependencies/type-DependenciesProps).
|
|
6326
|
+
|
|
6327
|
+
| Prop | Type | Default | Description |
|
|
6328
|
+
|---|---|---|---|
|
|
6329
|
+
| [`data`](#/dependencies/DependenciesProps-data) *required* | `readonly `[`Dependency`](#/dependencies/type-Dependency)`[]` | — | The dependencies, as the caller holds them. |
|
|
6330
|
+
|
|
6331
|
+
From `Dependency` — the full table stands on [Dependencies](#/dependencies/type-Dependency).
|
|
6332
|
+
|
|
6333
|
+
| Prop | Type | Default | Description |
|
|
6334
|
+
|---|---|---|---|
|
|
6335
|
+
| [`id`](#/dependencies/Dependency-id) *required* | `string` | — | The caller's identity of the dependency. |
|
|
6336
|
+
| [`from`](#/dependencies/Dependency-from) *required* | `string` | — | The id of the subtask it leaves. |
|
|
6337
|
+
| [`to`](#/dependencies/Dependency-to) *required* | `string` | — | The id of the subtask it arrives at. |
|
|
6338
|
+
| [`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. |
|
|
6339
|
+
|
|
6340
|
+
From `Overlap` — the full table stands on [Findings as data](#/findings/type-Overlap).
|
|
6341
|
+
|
|
6342
|
+
| Prop | Type | Default | Description |
|
|
6343
|
+
|---|---|---|---|
|
|
6344
|
+
| [`lane`](#/findings/Overlap-lane) *required* | `string` | — | The lane both sit on. |
|
|
6345
|
+
| [`first`](#/findings/Overlap-first) *required* | `string` | — | The subtask that starts earlier (lead-in included); on a tie, the one that stands first in the data. |
|
|
6346
|
+
| [`second`](#/findings/Overlap-second) *required* | `string` | — | The other one. |
|
|
6347
|
+
|
|
6348
|
+
#### Known limits
|
|
6349
|
+
|
|
6350
|
+
- No undo: your application owns the data, and with it the history ([ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/)).
|
|
6351
|
+
- The keys move work in time only; a lane change needs the pointer.
|
|
6352
|
+
|
|
6353
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
|
|
4885
6354
|
|
|
4886
6355
|
### Stretch, lead-in, lead-out
|
|
4887
6356
|
|
|
@@ -4980,11 +6449,71 @@ export default function ChangeLeadInAndLeadOut() {
|
|
|
4980
6449
|
|---|---|
|
|
4981
6450
|
| `Alt+Shift+← Alt+Shift+→` | Proposes ending the active subtask one raster step earlier or later. |
|
|
4982
6451
|
|
|
6452
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
6453
|
+
|
|
6454
|
+
#### Props on this page
|
|
6455
|
+
|
|
6456
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
6457
|
+
|
|
6458
|
+
| Prop | Type | Default | Description |
|
|
6459
|
+
|---|---|---|---|
|
|
6460
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
6461
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
6462
|
+
| [`intents`](#/schedule/ScheduleProps-intents) | `readonly `[`IntentKind`](#/schedule/type-IntentKind)`[]` | `[]` | The intents the caller handles. Each one enables its interaction; none leaves a read-only schedule ([ADR-0023](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0023-editing-is-controlled-the-schedule-reports-intents.md)). |
|
|
6463
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
6464
|
+
|
|
6465
|
+
###### Events
|
|
6466
|
+
|
|
6467
|
+
| Prop | Type | Default | Description |
|
|
6468
|
+
|---|---|---|---|
|
|
6469
|
+
| [`onIntent`](#/schedule/ScheduleProps-onIntent) | `(intent: `[`Intent`](#/schedule/type-Intent)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
6470
|
+
|
|
6471
|
+
###### Accessibility
|
|
6472
|
+
|
|
6473
|
+
| Prop | Type | Default | Description |
|
|
6474
|
+
|---|---|---|---|
|
|
6475
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
6476
|
+
|
|
6477
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
6478
|
+
|
|
6479
|
+
| Prop | Type | Default | Description |
|
|
6480
|
+
|---|---|---|---|
|
|
6481
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
6482
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
6483
|
+
|
|
6484
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
6485
|
+
|
|
6486
|
+
| Prop | Type | Default | Description |
|
|
6487
|
+
|---|---|---|---|
|
|
6488
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
6489
|
+
| [`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. |
|
|
6490
|
+
|
|
6491
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
6492
|
+
|
|
6493
|
+
| Prop | Type | Default | Description |
|
|
6494
|
+
|---|---|---|---|
|
|
6495
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
6496
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
6497
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
6498
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
6499
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
6500
|
+
| [`leadIn`](#/subtasks/Subtask-leadIn) | `number` | — | Duration of the lead-in before the main time; none is zero. |
|
|
6501
|
+
| [`leadOut`](#/subtasks/Subtask-leadOut) | `number` | — | Duration of the lead-out after the main time; none is zero. |
|
|
6502
|
+
| [`name`](#/subtasks/Subtask-name) | `string` | — | What the subtask is called, where the schedule names it. |
|
|
6503
|
+
|
|
6504
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
6505
|
+
|
|
6506
|
+
| Prop | Type | Default | Description |
|
|
6507
|
+
|---|---|---|---|
|
|
6508
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
6509
|
+
| [`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. |
|
|
6510
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
6511
|
+
|
|
4983
6512
|
#### Known limits
|
|
4984
6513
|
|
|
4985
6514
|
- A main time never becomes shorter than one raster step, or a minute without a raster.
|
|
4986
6515
|
|
|
4987
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.
|
|
6516
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
|
|
4988
6517
|
|
|
4989
6518
|
### Snapping
|
|
4990
6519
|
|
|
@@ -4998,7 +6527,7 @@ Demo page: https://romanhaendler.github.io/umriss-ui/schedule/snapping/
|
|
|
4998
6527
|
|
|
4999
6528
|
Without `snap` a drag lands on the fine band's step, which follows the zoom. A number is a step in milliseconds; `{ step, offset }` counts from local midnight; `false` places to the minute.
|
|
5000
6529
|
|
|
5001
|
-
Snapping shapes the ghost and so the intent; it never moves data that is not being dragged. `snapTime` is the same arithmetic for your own use.
|
|
6530
|
+
Snapping shapes the ghost and so the intent; it never moves data that is not being dragged. [`snapTime`](#/api/snapTime) is the same arithmetic for your own use.
|
|
5002
6531
|
|
|
5003
6532
|
#### Examples
|
|
5004
6533
|
|
|
@@ -5142,6 +6671,67 @@ export default function NoSnapping() {
|
|
|
5142
6671
|
}
|
|
5143
6672
|
```
|
|
5144
6673
|
|
|
6674
|
+
#### Keyboard
|
|
6675
|
+
|
|
6676
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
6677
|
+
|
|
6678
|
+
#### Props on this page
|
|
6679
|
+
|
|
6680
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
6681
|
+
|
|
6682
|
+
| Prop | Type | Default | Description |
|
|
6683
|
+
|---|---|---|---|
|
|
6684
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
6685
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
6686
|
+
| [`snap`](#/schedule/ScheduleProps-snap) | `"ticks" \| number \| `[`SnapRaster`](#/schedule/type-SnapRaster)` \| false` | `"ticks"` | The raster a drag lands on: `"ticks"` - the fine band's current step -, a step in milliseconds from local midnight, a step with an offset (shifts at 06:00, 14:00 and 22:00 are eight hours offset by six), or `false` for none. It shapes the ghost and the intent, never the data. |
|
|
6687
|
+
| [`intents`](#/schedule/ScheduleProps-intents) | `readonly `[`IntentKind`](#/schedule/type-IntentKind)`[]` | `[]` | The intents the caller handles. Each one enables its interaction; none leaves a read-only schedule ([ADR-0023](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0023-editing-is-controlled-the-schedule-reports-intents.md)). |
|
|
6688
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
6689
|
+
|
|
6690
|
+
###### Events
|
|
6691
|
+
|
|
6692
|
+
| Prop | Type | Default | Description |
|
|
6693
|
+
|---|---|---|---|
|
|
6694
|
+
| [`onIntent`](#/schedule/ScheduleProps-onIntent) | `(intent: `[`Intent`](#/schedule/type-Intent)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
6695
|
+
|
|
6696
|
+
###### Accessibility
|
|
6697
|
+
|
|
6698
|
+
| Prop | Type | Default | Description |
|
|
6699
|
+
|---|---|---|---|
|
|
6700
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
6701
|
+
|
|
6702
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
6703
|
+
|
|
6704
|
+
| Prop | Type | Default | Description |
|
|
6705
|
+
|---|---|---|---|
|
|
6706
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
6707
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
6708
|
+
|
|
6709
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
6710
|
+
|
|
6711
|
+
| Prop | Type | Default | Description |
|
|
6712
|
+
|---|---|---|---|
|
|
6713
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
6714
|
+
| [`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. |
|
|
6715
|
+
|
|
6716
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
6717
|
+
|
|
6718
|
+
| Prop | Type | Default | Description |
|
|
6719
|
+
|---|---|---|---|
|
|
6720
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
6721
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
6722
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
6723
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
6724
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
6725
|
+
| [`name`](#/subtasks/Subtask-name) | `string` | — | What the subtask is called, where the schedule names it. |
|
|
6726
|
+
|
|
6727
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
6728
|
+
|
|
6729
|
+
| Prop | Type | Default | Description |
|
|
6730
|
+
|---|---|---|---|
|
|
6731
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
6732
|
+
| [`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. |
|
|
6733
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
6734
|
+
|
|
5145
6735
|
### Placing from outside
|
|
5146
6736
|
|
|
5147
6737
|
Drag work that is not on the plan yet - from a backlog or a list of unassigned jobs - onto a lane, with the browser's own drag and drop. The drop reports where it should go; your application creates it.
|
|
@@ -5154,13 +6744,13 @@ Demo page: https://romanhaendler.github.io/umriss-ui/schedule/placing/
|
|
|
5154
6744
|
|
|
5155
6745
|
The browser hands over dragged data only on the drop, so declare what is being dragged in `placing` on your `dragstart` and clear it on `dragend`. The schedule then shows the ghost at the snapped time, with the findings the drop would create.
|
|
5156
6746
|
|
|
5157
|
-
A `place` intent carries your item's key, the task, the lane and the times. The id of the new subtask is yours; `subtaskFromPlace` builds it from the intent.
|
|
6747
|
+
A `place` intent carries your item's key, the task, the lane and the times. The id of the new subtask is yours; [`subtaskFromPlace`](#/api/subtaskFromPlace) builds it from the intent.
|
|
5158
6748
|
|
|
5159
6749
|
#### Examples
|
|
5160
6750
|
|
|
5161
6751
|
##### Drag work in from the backlog
|
|
5162
6752
|
|
|
5163
|
-
Set `placing` on your list's `dragstart` and clear it on `dragend`; the drop reports a `place` intent that `subtaskFromPlace` turns into work.
|
|
6753
|
+
Set `placing` on your list's `dragstart` and clear it on `dragend`; the drop reports a `place` intent that [`subtaskFromPlace`](#/api/subtaskFromPlace) turns into work.
|
|
5164
6754
|
|
|
5165
6755
|
```tsx
|
|
5166
6756
|
import { useState } from "react";
|
|
@@ -5265,6 +6855,82 @@ export default function DragFromTheBacklog() {
|
|
|
5265
6855
|
|
|
5266
6856
|
- The work is already on the plan → Move and lane
|
|
5267
6857
|
|
|
6858
|
+
#### Keyboard
|
|
6859
|
+
|
|
6860
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
6861
|
+
|
|
6862
|
+
#### Props on this page
|
|
6863
|
+
|
|
6864
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
6865
|
+
|
|
6866
|
+
| Prop | Type | Default | Description |
|
|
6867
|
+
|---|---|---|---|
|
|
6868
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
6869
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
6870
|
+
| [`intents`](#/schedule/ScheduleProps-intents) | `readonly `[`IntentKind`](#/schedule/type-IntentKind)`[]` | `[]` | The intents the caller handles. Each one enables its interaction; none leaves a read-only schedule ([ADR-0023](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0023-editing-is-controlled-the-schedule-reports-intents.md)). |
|
|
6871
|
+
| [`placing`](#/schedule/ScheduleProps-placing) | [`PlacingItem`](#/schedule/type-PlacingItem)` \| null` | — | What the application is dragging in from outside while it drags it - its key, task, the length of its main time, its lead-in and lead-out. The browser hands the dragged data over only on the drop, so the ghost before it can only come from here: set it on your own `dragstart`, clear it on `dragend`. Without `"place"` in `intents` no drop is accepted. |
|
|
6872
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
6873
|
+
|
|
6874
|
+
###### Events
|
|
6875
|
+
|
|
6876
|
+
| Prop | Type | Default | Description |
|
|
6877
|
+
|---|---|---|---|
|
|
6878
|
+
| [`onIntent`](#/schedule/ScheduleProps-onIntent) | `(intent: `[`Intent`](#/schedule/type-Intent)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
6879
|
+
|
|
6880
|
+
###### Accessibility
|
|
6881
|
+
|
|
6882
|
+
| Prop | Type | Default | Description |
|
|
6883
|
+
|---|---|---|---|
|
|
6884
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
6885
|
+
|
|
6886
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
6887
|
+
|
|
6888
|
+
| Prop | Type | Default | Description |
|
|
6889
|
+
|---|---|---|---|
|
|
6890
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
6891
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
6892
|
+
|
|
6893
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
6894
|
+
|
|
6895
|
+
| Prop | Type | Default | Description |
|
|
6896
|
+
|---|---|---|---|
|
|
6897
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
6898
|
+
| [`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. |
|
|
6899
|
+
|
|
6900
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
6901
|
+
|
|
6902
|
+
| Prop | Type | Default | Description |
|
|
6903
|
+
|---|---|---|---|
|
|
6904
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
6905
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
6906
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
6907
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
6908
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
6909
|
+
| [`name`](#/subtasks/Subtask-name) | `string` | — | What the subtask is called, where the schedule names it. |
|
|
6910
|
+
|
|
6911
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
6912
|
+
|
|
6913
|
+
| Prop | Type | Default | Description |
|
|
6914
|
+
|---|---|---|---|
|
|
6915
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
6916
|
+
| [`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. |
|
|
6917
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
6918
|
+
|
|
6919
|
+
From `DependenciesProps` — the full table stands on [Dependencies](#/dependencies/type-DependenciesProps).
|
|
6920
|
+
|
|
6921
|
+
| Prop | Type | Default | Description |
|
|
6922
|
+
|---|---|---|---|
|
|
6923
|
+
| [`data`](#/dependencies/DependenciesProps-data) *required* | `readonly `[`Dependency`](#/dependencies/type-Dependency)`[]` | — | The dependencies, as the caller holds them. |
|
|
6924
|
+
|
|
6925
|
+
From `Dependency` — the full table stands on [Dependencies](#/dependencies/type-Dependency).
|
|
6926
|
+
|
|
6927
|
+
| Prop | Type | Default | Description |
|
|
6928
|
+
|---|---|---|---|
|
|
6929
|
+
| [`id`](#/dependencies/Dependency-id) *required* | `string` | — | The caller's identity of the dependency. |
|
|
6930
|
+
| [`from`](#/dependencies/Dependency-from) *required* | `string` | — | The id of the subtask it leaves. |
|
|
6931
|
+
| [`to`](#/dependencies/Dependency-to) *required* | `string` | — | The id of the subtask it arrives at. |
|
|
6932
|
+
| [`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. |
|
|
6933
|
+
|
|
5268
6934
|
### Where a subtask may go
|
|
5269
6935
|
|
|
5270
6936
|
Marks the lanes and times a piece of work may not go to as soon as a drag begins, and holds the ghost where it is allowed. Reach for it when rules of your domain - equipment, skills, leave - limit where work can stand.
|
|
@@ -5598,11 +7264,88 @@ export default function AroundLeave() {
|
|
|
5598
7264
|
|
|
5599
7265
|
- The rule depends on the result, such as no double booking → Move and lane
|
|
5600
7266
|
|
|
7267
|
+
#### Keyboard
|
|
7268
|
+
|
|
7269
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
7270
|
+
|
|
7271
|
+
#### Props on this page
|
|
7272
|
+
|
|
7273
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
7274
|
+
|
|
7275
|
+
| Prop | Type | Default | Description |
|
|
7276
|
+
|---|---|---|---|
|
|
7277
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
7278
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
7279
|
+
| [`intents`](#/schedule/ScheduleProps-intents) | `readonly `[`IntentKind`](#/schedule/type-IntentKind)`[]` | `[]` | The intents the caller handles. Each one enables its interaction; none leaves a read-only schedule ([ADR-0023](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0023-editing-is-controlled-the-schedule-reports-intents.md)). |
|
|
7280
|
+
| [`canMoveTo`](#/schedule/ScheduleProps-canMoveTo) | `(subtask: `[`Subtask`](#/subtasks/type-Subtask)`, lane: string) => boolean` | every lane is open | Whether a subtask may go to a lane. It narrows `"lane"`, it does not enable it. Asked once per lane when a drag takes hold, and asked again at the drop. The lanes it turns down are marked from the first frame of the drag - a planner sees the refusal before meeting it - and over one of them the ghost stays on the last lane that was allowed, the cursor says no and a line ties the ghost to the pointer. A refused lane costs the lane and nothing else: a drop after it still reports the move in time. It is asked for work dragged in from outside as well, with the key and task the application declared in `placing`. |
|
|
7281
|
+
| [`placing`](#/schedule/ScheduleProps-placing) | [`PlacingItem`](#/schedule/type-PlacingItem)` \| null` | — | What the application is dragging in from outside while it drags it - its key, task, the length of its main time, its lead-in and lead-out. The browser hands the dragged data over only on the drop, so the ghost before it can only come from here: set it on your own `dragstart`, clear it on `dragend`. Without `"place"` in `intents` no drop is accepted. |
|
|
7282
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
7283
|
+
|
|
7284
|
+
###### Events
|
|
7285
|
+
|
|
7286
|
+
| Prop | Type | Default | Description |
|
|
7287
|
+
|---|---|---|---|
|
|
7288
|
+
| [`onIntent`](#/schedule/ScheduleProps-onIntent) | `(intent: `[`Intent`](#/schedule/type-Intent)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
7289
|
+
|
|
7290
|
+
###### Accessibility
|
|
7291
|
+
|
|
7292
|
+
| Prop | Type | Default | Description |
|
|
7293
|
+
|---|---|---|---|
|
|
7294
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
7295
|
+
|
|
7296
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
7297
|
+
|
|
7298
|
+
| Prop | Type | Default | Description |
|
|
7299
|
+
|---|---|---|---|
|
|
7300
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
7301
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
7302
|
+
|
|
7303
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
7304
|
+
|
|
7305
|
+
| Prop | Type | Default | Description |
|
|
7306
|
+
|---|---|---|---|
|
|
7307
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
7308
|
+
| [`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. |
|
|
7309
|
+
|
|
7310
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
7311
|
+
|
|
7312
|
+
| Prop | Type | Default | Description |
|
|
7313
|
+
|---|---|---|---|
|
|
7314
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
7315
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
7316
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
7317
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
7318
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
7319
|
+
|
|
7320
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
7321
|
+
|
|
7322
|
+
| Prop | Type | Default | Description |
|
|
7323
|
+
|---|---|---|---|
|
|
7324
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
7325
|
+
| [`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. |
|
|
7326
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
7327
|
+
|
|
7328
|
+
From `BlockedTimesProps` — the full table stands on [Blocked time](#/blocked-time/type-BlockedTimesProps).
|
|
7329
|
+
|
|
7330
|
+
| Prop | Type | Default | Description |
|
|
7331
|
+
|---|---|---|---|
|
|
7332
|
+
| [`data`](#/blocked-time/BlockedTimesProps-data) *required* | `readonly `[`BlockedTime`](#/blocked-time/type-BlockedTime)`[]` | — | The blocked time of the lanes - leave, maintenance, unavailability -, as the caller holds it: one list, each interval naming its lane. |
|
|
7333
|
+
|
|
7334
|
+
From `BlockedTime` — the full table stands on [Blocked time](#/blocked-time/type-BlockedTime).
|
|
7335
|
+
|
|
7336
|
+
| Prop | Type | Default | Description |
|
|
7337
|
+
|---|---|---|---|
|
|
7338
|
+
| [`id`](#/blocked-time/BlockedTime-id) *required* | `string` | — | The caller's identity of the interval - what a finding names. |
|
|
7339
|
+
| [`lane`](#/blocked-time/BlockedTime-lane) *required* | `string` | — | The id of the lane it blocks. |
|
|
7340
|
+
| [`from`](#/blocked-time/BlockedTime-from) *required* | `number` | — | Where it begins. |
|
|
7341
|
+
| [`to`](#/blocked-time/BlockedTime-to) *required* | `number` | — | Where it ends. |
|
|
7342
|
+
| [`label`](#/blocked-time/BlockedTime-label) | `string` | — | Why the lane is blocked - "Leave", "Maintenance" -, where the schedule names it. |
|
|
7343
|
+
|
|
5601
7344
|
#### Known limits
|
|
5602
7345
|
|
|
5603
7346
|
- A rule that changes while a drag runs is noticed at the drop, not before.
|
|
5604
7347
|
|
|
5605
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.
|
|
7348
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
|
|
5606
7349
|
|
|
5607
7350
|
### Ripple
|
|
5608
7351
|
|
|
@@ -5616,13 +7359,13 @@ Demo page: https://romanhaendler.github.io/umriss-ui/schedule/ripple/
|
|
|
5616
7359
|
|
|
5617
7360
|
`ripple(subtasks, dependencies, intent)` returns move intents down the whole chain, in the order they were pushed. A successor keeps its length and is never pulled earlier: room that opens up is the planner's.
|
|
5618
7361
|
|
|
5619
|
-
`shiftTask` moves every subtask of one task by the same amount, so all its dependencies keep fitting.
|
|
7362
|
+
[`shiftTask`](#/api/shiftTask) moves every subtask of one task by the same amount, so all its dependencies keep fitting.
|
|
5620
7363
|
|
|
5621
7364
|
#### Examples
|
|
5622
7365
|
|
|
5623
7366
|
##### Push the later stops of a tour
|
|
5624
7367
|
|
|
5625
|
-
`ripple` returns the moves that push every stop whose drive no longer fits behind a late one; you decide whether to apply them.
|
|
7368
|
+
[`ripple`](#/api/ripple) returns the moves that push every stop whose drive no longer fits behind a late one; you decide whether to apply them.
|
|
5626
7369
|
|
|
5627
7370
|
```tsx
|
|
5628
7371
|
import { useState } from "react";
|
|
@@ -5690,7 +7433,7 @@ export default function PushTheLaterStops() {
|
|
|
5690
7433
|
|
|
5691
7434
|
##### Move a whole tour
|
|
5692
7435
|
|
|
5693
|
-
`shiftTask` returns one move per stop, all by the same amount, so every drive that fitted still fits.
|
|
7436
|
+
[`shiftTask`](#/api/shiftTask) returns one move per stop, all by the same amount, so every drive that fitted still fits.
|
|
5694
7437
|
|
|
5695
7438
|
```tsx
|
|
5696
7439
|
import { useState } from "react";
|
|
@@ -5749,7 +7492,7 @@ export default function MoveAWholeTour() {
|
|
|
5749
7492
|
|
|
5750
7493
|
##### Ripple on every drag
|
|
5751
7494
|
|
|
5752
|
-
Run `ripple` inside `onIntent` and apply its moves with the drop: drag the design later and build and test follow.
|
|
7495
|
+
Run [`ripple`](#/api/ripple) inside `onIntent` and apply its moves with the drop: drag the design later and build and test follow.
|
|
5753
7496
|
|
|
5754
7497
|
```tsx
|
|
5755
7498
|
import { useState } from "react";
|
|
@@ -5799,356 +7542,603 @@ export default function RippleOnEveryDrag() {
|
|
|
5799
7542
|
}
|
|
5800
7543
|
```
|
|
5801
7544
|
|
|
7545
|
+
#### Keyboard
|
|
7546
|
+
|
|
7547
|
+
The keys of [First schedule](#/schedule/keyboard-schedule) apply here.
|
|
7548
|
+
|
|
7549
|
+
#### Props on this page
|
|
7550
|
+
|
|
7551
|
+
From `ScheduleProps` — the full table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
7552
|
+
|
|
7553
|
+
| Prop | Type | Default | Description |
|
|
7554
|
+
|---|---|---|---|
|
|
7555
|
+
| [`initialDomain`](#/schedule/ScheduleProps-initialDomain) *required* | `readonly [number, number]` | — | The time in view when the schedule mounts, as two wall-clock instants. Pan and zoom take it from there; a new pair of values puts it back. |
|
|
7556
|
+
| [`height`](#/schedule/ScheduleProps-height) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
7557
|
+
| [`intents`](#/schedule/ScheduleProps-intents) | `readonly `[`IntentKind`](#/schedule/type-IntentKind)`[]` | `[]` | The intents the caller handles. Each one enables its interaction; none leaves a read-only schedule ([ADR-0023](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0023-editing-is-controlled-the-schedule-reports-intents.md)). |
|
|
7558
|
+
| [`children`](#/schedule/ScheduleProps-children) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
7559
|
+
|
|
7560
|
+
###### Events
|
|
7561
|
+
|
|
7562
|
+
| Prop | Type | Default | Description |
|
|
7563
|
+
|---|---|---|---|
|
|
7564
|
+
| [`onIntent`](#/schedule/ScheduleProps-onIntent) | `(intent: `[`Intent`](#/schedule/type-Intent)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
7565
|
+
|
|
7566
|
+
###### Accessibility
|
|
7567
|
+
|
|
7568
|
+
| Prop | Type | Default | Description |
|
|
7569
|
+
|---|---|---|---|
|
|
7570
|
+
| [`ariaLabel`](#/schedule/ScheduleProps-ariaLabel) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
7571
|
+
|
|
7572
|
+
From `LaneProps` — the full table stands on [Lanes](#/lane/type-LaneProps).
|
|
7573
|
+
|
|
7574
|
+
| Prop | Type | Default | Description |
|
|
7575
|
+
|---|---|---|---|
|
|
7576
|
+
| [`id`](#/lane/LaneProps-id) *required* | `string` | — | The identity subtasks name in their `lane`. |
|
|
7577
|
+
| [`label`](#/lane/LaneProps-label) | `ReactNode` | `id` | What the lane header says - the person, vehicle or room. Real text, read by a screen reader. |
|
|
7578
|
+
|
|
7579
|
+
From `SubtasksProps` — the full table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
7580
|
+
|
|
7581
|
+
| Prop | Type | Default | Description |
|
|
7582
|
+
|---|---|---|---|
|
|
7583
|
+
| [`data`](#/subtasks/SubtasksProps-data) *required* | `readonly `[`Subtask`](#/subtasks/type-Subtask)`[]` | — | The subtasks, as the caller holds them. The schedule never changes one. |
|
|
7584
|
+
| [`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. |
|
|
7585
|
+
|
|
7586
|
+
From `Subtask` — the full table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
7587
|
+
|
|
7588
|
+
| Prop | Type | Default | Description |
|
|
7589
|
+
|---|---|---|---|
|
|
7590
|
+
| [`id`](#/subtasks/Subtask-id) *required* | `string` | — | The caller's identity of the subtask. |
|
|
7591
|
+
| [`task`](#/subtasks/Subtask-task) *required* | `string` | — | The id of the task it belongs to. |
|
|
7592
|
+
| [`lane`](#/subtasks/Subtask-lane) *required* | `string` | — | The id of the lane it sits on. |
|
|
7593
|
+
| [`from`](#/subtasks/Subtask-from) *required* | `number` | — | Start of the main time. |
|
|
7594
|
+
| [`to`](#/subtasks/Subtask-to) *required* | `number` | — | End of the main time. |
|
|
7595
|
+
| [`name`](#/subtasks/Subtask-name) | `string` | — | What the subtask is called, where the schedule names it. |
|
|
7596
|
+
|
|
7597
|
+
From `Task` — the full table stands on [Subtasks](#/subtasks/type-Task).
|
|
7598
|
+
|
|
7599
|
+
| Prop | Type | Default | Description |
|
|
7600
|
+
|---|---|---|---|
|
|
7601
|
+
| [`id`](#/subtasks/Task-id) *required* | `string` | — | The caller's identity of the task. |
|
|
7602
|
+
| [`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. |
|
|
7603
|
+
| [`name`](#/subtasks/Task-name) | `string` | — | What the task is called, where the schedule names it. |
|
|
7604
|
+
|
|
7605
|
+
From `DependenciesProps` — the full table stands on [Dependencies](#/dependencies/type-DependenciesProps).
|
|
7606
|
+
|
|
7607
|
+
| Prop | Type | Default | Description |
|
|
7608
|
+
|---|---|---|---|
|
|
7609
|
+
| [`data`](#/dependencies/DependenciesProps-data) *required* | `readonly `[`Dependency`](#/dependencies/type-Dependency)`[]` | — | The dependencies, as the caller holds them. |
|
|
7610
|
+
|
|
7611
|
+
From `Dependency` — the full table stands on [Dependencies](#/dependencies/type-Dependency).
|
|
7612
|
+
|
|
7613
|
+
| Prop | Type | Default | Description |
|
|
7614
|
+
|---|---|---|---|
|
|
7615
|
+
| [`id`](#/dependencies/Dependency-id) *required* | `string` | — | The caller's identity of the dependency. |
|
|
7616
|
+
| [`from`](#/dependencies/Dependency-from) *required* | `string` | — | The id of the subtask it leaves. |
|
|
7617
|
+
| [`to`](#/dependencies/Dependency-to) *required* | `string` | — | The id of the subtask it arrives at. |
|
|
7618
|
+
| [`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. |
|
|
7619
|
+
|
|
5802
7620
|
#### Known limits
|
|
5803
7621
|
|
|
5804
|
-
- No dependency types, slack or critical path: the schedule is no project-planning engine (ADR-0032).
|
|
7622
|
+
- No dependency types, slack or critical path: the schedule is no project-planning engine ([ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/)).
|
|
5805
7623
|
- A dependency joins subtasks of one task, so work of other tasks is never pushed.
|
|
5806
7624
|
|
|
5807
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.
|
|
7625
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
|
|
5808
7626
|
|
|
5809
|
-
##
|
|
7627
|
+
## API index
|
|
5810
7628
|
|
|
5811
|
-
|
|
7629
|
+
Every name the package exports, in one place.
|
|
5812
7630
|
|
|
5813
|
-
###
|
|
7631
|
+
### API index
|
|
5814
7632
|
|
|
5815
|
-
|
|
7633
|
+
Everything `@umriss-ui/schedule` exports, with its signature. A component's props stand on its own page.
|
|
5816
7634
|
|
|
5817
|
-
|
|
5818
|
-
import { findings, overlaps, violatedDependencies, inBlockedTime } from "@umriss-ui/schedule";
|
|
5819
|
-
```
|
|
7635
|
+
Demo page: https://romanhaendler.github.io/umriss-ui/schedule/api/
|
|
5820
7636
|
|
|
5821
|
-
|
|
7637
|
+
#### Components
|
|
5822
7638
|
|
|
5823
|
-
|
|
7639
|
+
##### `BlockedTimes`
|
|
5824
7640
|
|
|
5825
|
-
|
|
7641
|
+
[Blocked time](#/blocked-time) – A layer of blocked time. Wherever it is declared, it is drawn behind every
|
|
7642
|
+
subtask and dependency: it is a property of the lane, not something on it.
|
|
5826
7643
|
|
|
5827
|
-
|
|
7644
|
+
Used on [Scenarios](#/), [Blocked time](#/blocked-time), [Tooltip](#/tooltip), [Findings as data](#/findings) and [Where a subtask may go](#/where-it-may-go).
|
|
5828
7645
|
|
|
5829
|
-
#####
|
|
7646
|
+
##### `Dependencies`
|
|
5830
7647
|
|
|
5831
|
-
|
|
7648
|
+
[Dependencies](#/dependencies) – Lines from one subtask's end to the next one's start within a task, with the lag that must pass between them (also called links or predecessors). A lag that does not fit is marked, not repaired.
|
|
5832
7649
|
|
|
5833
|
-
|
|
5834
|
-
import { Stack, Text } from "@umriss-ui/core";
|
|
5835
|
-
import { BlockedTimes, Dependencies, Lane, Schedule, Subtasks, findings } from "@umriss-ui/schedule";
|
|
5836
|
-
import type { BlockedTime, Dependency, Subtask, Task } from "@umriss-ui/schedule";
|
|
7650
|
+
Used on [Scenarios](#/), [Installation](#/installation), [First schedule](#/schedule), [Lane groups](#/lane-groups), [Dependencies](#/dependencies), [Routes](#/routes), [Time axis and calendar](#/time-axis), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Placing from outside](#/placing) and [Ripple](#/ripple).
|
|
5837
7651
|
|
|
5838
|
-
|
|
7652
|
+
##### `Lane`
|
|
5839
7653
|
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
{ id: "portal", name: "Member portal", color: "light-dark(#7c3aed, #a98bfa)" },
|
|
5843
|
-
];
|
|
7654
|
+
[Lanes](#/lane) – One lane: a person, a vehicle, a room. The lanes run top to bottom in the order
|
|
7655
|
+
they are declared - whichever group they are declared in.
|
|
5844
7656
|
|
|
5845
|
-
|
|
5846
|
-
{ id: "design", task: "shop", lane: "noah", from: day(16), to: day(17, 17), name: "Search results layout" },
|
|
5847
|
-
{ id: "build", task: "shop", lane: "chloe", from: day(17), to: day(19, 17), name: "Search results page" },
|
|
5848
|
-
{ id: "address", task: "portal", lane: "chloe", from: day(18), to: day(19, 17), name: "Change of address form" },
|
|
5849
|
-
{ id: "profile", task: "portal", lane: "arjun", from: day(17), to: day(19, 17), name: "Profile page" },
|
|
5850
|
-
];
|
|
7657
|
+
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), [Now line](#/now-line), [Pan and zoom](#/pan-and-zoom), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [Linked schedules](#/linked-schedules), [The handle](#/handle), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Stretch, lead-in, lead-out](#/stretch), [Snapping](#/snapping), [Placing from outside](#/placing), [Where a subtask may go](#/where-it-may-go) and [Ripple](#/ripple).
|
|
5851
7658
|
|
|
5852
|
-
|
|
5853
|
-
const HANDOVERS: readonly Dependency[] = [{ id: "design-to-build", from: "design", to: "build", lag: 4 * 60 * 60_000 }];
|
|
7659
|
+
##### `LaneGroup`
|
|
5854
7660
|
|
|
5855
|
-
|
|
7661
|
+
[Lane groups](#/lane-groups) – A group of lanes: structure over them, and never a lane itself.
|
|
5856
7662
|
|
|
5857
|
-
|
|
5858
|
-
|
|
7663
|
+
It gives its id to its children through context, so a lane never names its
|
|
7664
|
+
group and a group reads in JSX as it reads in the organisation. Folded, it becomes
|
|
7665
|
+
one row showing a **Miniature** of everything in it; open, it shows a slim
|
|
7666
|
+
head above its lanes. Which groups are folded is `collapsedGroups` on
|
|
7667
|
+
`Schedule` - a view state, never an **Intent**.
|
|
5859
7668
|
|
|
5860
|
-
|
|
5861
|
-
const found = findings(WORK, HANDOVERS, LEAVE);
|
|
7669
|
+
Used on [Scenarios](#/) and [Lane groups](#/lane-groups).
|
|
5862
7670
|
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
</ul>
|
|
5890
|
-
</Stack>
|
|
5891
|
-
);
|
|
5892
|
-
}
|
|
7671
|
+
##### `Schedule`
|
|
7672
|
+
|
|
7673
|
+
[First schedule](#/schedule) – A plan of subtasks on lanes over time - people, vehicles, rooms - with
|
|
7674
|
+
dependencies between them. The contents are declared as children (`Lane`,
|
|
7675
|
+
`LaneGroup`, `Subtasks`, `Dependencies`, `BlockedTimes`); the planner pans,
|
|
7676
|
+
zooms and drags, and every drag ends as an **Intent** through `onIntent`.
|
|
7677
|
+
The data changes only where the caller applies it; without `intents` the
|
|
7678
|
+
schedule is read-only. A ref gives the `ScheduleHandle`.
|
|
7679
|
+
|
|
7680
|
+
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), [Now line](#/now-line), [Pan and zoom](#/pan-and-zoom), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [Linked schedules](#/linked-schedules), [The handle](#/handle), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Stretch, lead-in, lead-out](#/stretch), [Snapping](#/snapping), [Placing from outside](#/placing), [Where a subtask may go](#/where-it-may-go) and [Ripple](#/ripple).
|
|
7681
|
+
|
|
7682
|
+
##### `Subtasks`
|
|
7683
|
+
|
|
7684
|
+
[Subtasks](#/subtasks) – The bars: a main time with an optional lead-in before it and lead-out after it, in the colour of the task they belong to (also called bookings or assignments).
|
|
7685
|
+
|
|
7686
|
+
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), [Now line](#/now-line), [Pan and zoom](#/pan-and-zoom), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [Linked schedules](#/linked-schedules), [The handle](#/handle), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Stretch, lead-in, lead-out](#/stretch), [Snapping](#/snapping), [Placing from outside](#/placing), [Where a subtask may go](#/where-it-may-go) and [Ripple](#/ripple).
|
|
7687
|
+
|
|
7688
|
+
#### Functions
|
|
7689
|
+
|
|
7690
|
+
##### `applyIntent`
|
|
7691
|
+
|
|
7692
|
+
The subtask as the intent asks for it. An intent for another subtask leaves
|
|
7693
|
+
it as it is.
|
|
7694
|
+
|
|
7695
|
+
```ts
|
|
7696
|
+
function applyIntent<S extends Subtask>(subtask: S, intent: Intent): S;
|
|
5893
7697
|
```
|
|
5894
7698
|
|
|
5895
|
-
|
|
7699
|
+
Used on [Scenarios](#/), [Lane groups](#/lane-groups), [Time axis and calendar](#/time-axis), [Blocked time](#/blocked-time), [Interactions](#/interactions), [Move and lane](#/move-and-lane), [Stretch, lead-in, lead-out](#/stretch), [Snapping](#/snapping), [Placing from outside](#/placing), [Where a subtask may go](#/where-it-may-go) and [Ripple](#/ripple).
|
|
5896
7700
|
|
|
5897
|
-
|
|
7701
|
+
##### `arrival`
|
|
5898
7702
|
|
|
5899
|
-
|
|
5900
|
-
import { EmptyState, Stack } from "@umriss-ui/core";
|
|
5901
|
-
import { Lane, Schedule, Subtasks, findings } from "@umriss-ui/schedule";
|
|
5902
|
-
import type { Subtask, Task } from "@umriss-ui/schedule";
|
|
7703
|
+
When a dependency has to have arrived at its subtask, by its anchor.
|
|
5903
7704
|
|
|
5904
|
-
|
|
7705
|
+
```ts
|
|
7706
|
+
function arrival(dependency: Dependency, to: Subtask): number;
|
|
7707
|
+
```
|
|
5905
7708
|
|
|
5906
|
-
|
|
7709
|
+
Used on [Scenarios](#/), [Now line](#/now-line) and [Findings as data](#/findings).
|
|
5907
7710
|
|
|
5908
|
-
|
|
5909
|
-
{ id: "w-111", task: "booking", lane: "hana", from: day(16), to: day(18, 17), name: "Push notifications" },
|
|
5910
|
-
{ id: "w-113", task: "booking", lane: "kofi", from: day(16), to: day(18, 17), name: "Calendar sync" },
|
|
5911
|
-
];
|
|
7711
|
+
##### `departure`
|
|
5912
7712
|
|
|
5913
|
-
|
|
5914
|
-
const found = findings(WORK, []);
|
|
5915
|
-
const count = found.overlaps.length + found.violatedDependencies.length + found.inBlockedTime.length;
|
|
7713
|
+
When a dependency leaves its subtask, by its anchor.
|
|
5916
7714
|
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
<Schedule ariaLabel="Two developers' week, without findings" initialDomain={[day(16, 0), day(21, 0)]} height={140}>
|
|
5920
|
-
<Lane id="hana" label="Hana Sato" />
|
|
5921
|
-
<Lane id="kofi" label="Kofi Mensah" />
|
|
5922
|
-
<Subtasks data={WORK} tasks={PROJECTS} />
|
|
5923
|
-
</Schedule>
|
|
5924
|
-
{count === 0 && <EmptyState title="Nothing to fix" description="Nobody is double-booked, every hand-over fits, and no work falls into leave." />}
|
|
5925
|
-
</Stack>
|
|
5926
|
-
);
|
|
5927
|
-
}
|
|
7715
|
+
```ts
|
|
7716
|
+
function departure(dependency: Dependency, from: Subtask): number;
|
|
5928
7717
|
```
|
|
5929
7718
|
|
|
5930
|
-
|
|
7719
|
+
Used on [Findings as data](#/findings).
|
|
5931
7720
|
|
|
5932
|
-
|
|
7721
|
+
##### `findings`
|
|
5933
7722
|
|
|
5934
|
-
|
|
5935
|
-
import { Badge, Stack } from "@umriss-ui/core";
|
|
5936
|
-
import { Dependencies, Lane, Schedule, Subtasks, overlaps, violatedDependencies } from "@umriss-ui/schedule";
|
|
5937
|
-
import type { Dependency, Subtask, Task } from "@umriss-ui/schedule";
|
|
7723
|
+
Every finding at once. Without blocked time there is none in it.
|
|
5938
7724
|
|
|
5939
|
-
|
|
5940
|
-
|
|
7725
|
+
```ts
|
|
7726
|
+
function findings(subtasks: readonly Subtask[], dependencies: readonly Dependency[], blocked?: readonly BlockedTime[]): Findings;
|
|
7727
|
+
```
|
|
5941
7728
|
|
|
5942
|
-
|
|
5943
|
-
{ id: "van-402", label: "Van FP 402 R" },
|
|
5944
|
-
{ id: "truck-520", label: "Truck FP 520 E" },
|
|
5945
|
-
{ id: "van-455", label: "E-van FP 455 R" },
|
|
5946
|
-
];
|
|
7729
|
+
Used on [Scenarios](#/), [First schedule](#/schedule), [Lane groups](#/lane-groups), [Blocked time](#/blocked-time), [Tooltip](#/tooltip) and [Findings as data](#/findings).
|
|
5947
7730
|
|
|
5948
|
-
|
|
5949
|
-
{ id: "c-2041", name: "C-2041 Holloway Garden Supplies", color: "light-dark(#2563eb, #6b9bff)" },
|
|
5950
|
-
{ id: "c-2043", name: "C-2043 Oakridge Pharmacy", color: "light-dark(#c2410c, #f08a52)" },
|
|
5951
|
-
];
|
|
7731
|
+
##### `inBlockedTime`
|
|
5952
7732
|
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
{ id: "c-2043-2", task: "c-2043", lane: "van-402", from: at(10), to: at(11, 30), leadIn: min(15) },
|
|
5957
|
-
{ id: "c-2043-3", task: "c-2043", lane: "van-455", from: at(12), to: at(14), leadIn: min(20), leadOut: min(20) },
|
|
5958
|
-
];
|
|
7733
|
+
Every subtask that covers blocked time on its lane, lead-in and lead-out
|
|
7734
|
+
included - once per blocked interval it covers, in the order of the
|
|
7735
|
+
subtasks. Touching at a shared edge is not covering.
|
|
5959
7736
|
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
];
|
|
7737
|
+
```ts
|
|
7738
|
+
function inBlockedTime(subtasks: readonly Subtask[], blocked: readonly BlockedTime[]): InBlockedTime[];
|
|
7739
|
+
```
|
|
5964
7740
|
|
|
5965
|
-
|
|
5966
|
-
const doubleBooked = overlaps(LEGS).length;
|
|
5967
|
-
const late = violatedDependencies(LEGS, TRANSFERS).length;
|
|
7741
|
+
Used on [Scenarios](#/), [Blocked time](#/blocked-time) and [Findings as data](#/findings).
|
|
5968
7742
|
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
))}
|
|
5979
|
-
<Dependencies data={TRANSFERS} />
|
|
5980
|
-
<Subtasks data={LEGS} tasks={CONSIGNMENTS} />
|
|
5981
|
-
</Schedule>
|
|
5982
|
-
</Stack>
|
|
5983
|
-
);
|
|
5984
|
-
}
|
|
7743
|
+
##### `occupied`
|
|
7744
|
+
|
|
7745
|
+
The interval a subtask occupies on its lane: lead-in and lead-out included.
|
|
7746
|
+
|
|
7747
|
+
```ts
|
|
7748
|
+
function occupied(subtask: Subtask): {
|
|
7749
|
+
from: number;
|
|
7750
|
+
to: number;
|
|
7751
|
+
};
|
|
5985
7752
|
```
|
|
5986
7753
|
|
|
5987
|
-
|
|
7754
|
+
##### `overlaps`
|
|
5988
7755
|
|
|
5989
|
-
|
|
7756
|
+
Every pair of subtasks that cover each other on a lane. Touching at a
|
|
7757
|
+
shared edge is not covering, and a subtask that covers no time covers
|
|
7758
|
+
nothing.
|
|
5990
7759
|
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
| `first` (required) | `string` | — | The subtask that starts earlier (lead-in included); on a tie, the one that stands first in the data. |
|
|
5995
|
-
| `second` (required) | `string` | — | The other one. |
|
|
5996
|
-
| `from` (required) | `number` | — | Where the covering begins. |
|
|
5997
|
-
| `to` (required) | `number` | — | Where it ends. |
|
|
7760
|
+
```ts
|
|
7761
|
+
function overlaps(subtasks: readonly Subtask[]): Overlap[];
|
|
7762
|
+
```
|
|
5998
7763
|
|
|
5999
|
-
|
|
7764
|
+
Used on [Scenarios](#/), [Lane groups](#/lane-groups), [Findings as data](#/findings) and [Move and lane](#/move-and-lane).
|
|
6000
7765
|
|
|
6001
|
-
|
|
6002
|
-
|---|---|---|---|
|
|
6003
|
-
| `dependency` (required) | `string` | — | The id of the dependency. |
|
|
6004
|
-
| `departure` (required) | `number` | — | When it leaves, by its anchor. |
|
|
6005
|
-
| `arrival` (required) | `number` | — | When it has to have arrived, by its anchor. |
|
|
6006
|
-
| `shortBy` (required) | `number` | — | How much time is missing: departure plus lag, minus arrival. |
|
|
7766
|
+
##### `resolveAppearance`
|
|
6007
7767
|
|
|
6008
|
-
|
|
7768
|
+
Settles a subtask's appearances into what is drawn. `provisional` and
|
|
7769
|
+
`fixed` contradict each other; the later one in the list wins.
|
|
6009
7770
|
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
| `subtask` (required) | `string` | — | The id of the subtask. |
|
|
6013
|
-
| `blocked` (required) | `string` | — | The id of the blocked time it covers. |
|
|
6014
|
-
| `lane` (required) | `string` | — | The lane both are on. |
|
|
6015
|
-
| `from` (required) | `number` | — | Where the covering begins. |
|
|
6016
|
-
| `to` (required) | `number` | — | Where it ends. |
|
|
7771
|
+
- `appearance` – The subtask's `appearance`, in the order it was given.
|
|
7772
|
+
- Returns Which of the four channels are on.
|
|
6017
7773
|
|
|
6018
|
-
|
|
7774
|
+
```ts
|
|
7775
|
+
function resolveAppearance(appearance: readonly SubtaskAppearance[] | undefined): ResolvedAppearance;
|
|
7776
|
+
```
|
|
6019
7777
|
|
|
6020
|
-
|
|
7778
|
+
Used on [Appearances](#/appearances).
|
|
7779
|
+
|
|
7780
|
+
##### `ripple`
|
|
6021
7781
|
|
|
6022
|
-
|
|
7782
|
+
The moves that push every successor whose dependency no longer fits after
|
|
7783
|
+
`intent` - transitively, in the order they were first pushed. The subtask the
|
|
7784
|
+
intent is about is never moved, and a cycle among the successors ends after a
|
|
7785
|
+
bounded number of pushes instead of running on.
|
|
6023
7786
|
|
|
6024
|
-
|
|
7787
|
+
```ts
|
|
7788
|
+
function ripple(subtasks: readonly Subtask[], dependencies: readonly Dependency[], intent: Intent): MoveIntent[];
|
|
7789
|
+
```
|
|
6025
7790
|
|
|
6026
|
-
|
|
7791
|
+
Used on [Scenarios](#/), [Dependencies](#/dependencies) and [Ripple](#/ripple).
|
|
6027
7792
|
|
|
6028
|
-
|
|
7793
|
+
##### `shiftTask`
|
|
7794
|
+
|
|
7795
|
+
The moves that carry a whole task in time - every subtask of it by the same
|
|
7796
|
+
amount, so that its lengths and the distances between its stops stay as
|
|
7797
|
+
they were. The schedule never runs it: apply the moves like any other
|
|
7798
|
+
intent, or run [`ripple`](#/api/ripple) over them first.
|
|
7799
|
+
|
|
7800
|
+
- `subtasks` – All subtasks; only those of `task` are moved.
|
|
7801
|
+
- `task` – The id of the task, as its subtasks name it in `task`.
|
|
7802
|
+
- `by` – How far, in milliseconds; negative is earlier.
|
|
7803
|
+
- Returns One move intent per subtask of the task - none where `by` is zero
|
|
7804
|
+
or not finite.
|
|
6029
7805
|
|
|
6030
7806
|
```ts
|
|
6031
|
-
|
|
6032
|
-
function occupied(subtask: Subtask): {
|
|
6033
|
-
from: number;
|
|
6034
|
-
to: number;
|
|
6035
|
-
};
|
|
7807
|
+
function shiftTask(subtasks: readonly Subtask[], task: string, by: number): MoveIntent[];
|
|
6036
7808
|
```
|
|
6037
7809
|
|
|
6038
|
-
|
|
7810
|
+
Used on [Scenarios](#/) and [Ripple](#/ripple).
|
|
7811
|
+
|
|
7812
|
+
##### `snapTime`
|
|
7813
|
+
|
|
7814
|
+
`time` onto the nearest line of the raster in local time - a step alone
|
|
7815
|
+
starts at local midnight. A step of zero or less is no raster: the time
|
|
7816
|
+
stays as it is.
|
|
6039
7817
|
|
|
6040
7818
|
```ts
|
|
6041
|
-
|
|
6042
|
-
interface LaneIntent {
|
|
6043
|
-
readonly kind: "lane";
|
|
6044
|
-
/** The id of the subtask. */
|
|
6045
|
-
readonly subtask: string;
|
|
6046
|
-
/** The id of the new lane. */
|
|
6047
|
-
readonly lane: string;
|
|
6048
|
-
}
|
|
7819
|
+
function snapTime(time: number, raster: number | SnapRaster): number;
|
|
6049
7820
|
```
|
|
6050
7821
|
|
|
6051
|
-
|
|
7822
|
+
Used on [Snapping](#/snapping).
|
|
7823
|
+
|
|
7824
|
+
##### `subtaskFromPlace`
|
|
7825
|
+
|
|
7826
|
+
The subtask a place intent asks for, under an id the caller chooses.
|
|
6052
7827
|
|
|
6053
7828
|
```ts
|
|
6054
|
-
|
|
6055
|
-
interface LeadInIntent {
|
|
6056
|
-
readonly kind: "leadIn";
|
|
6057
|
-
/** The id of the subtask. */
|
|
6058
|
-
readonly subtask: string;
|
|
6059
|
-
/** The new duration of the lead-in. */
|
|
6060
|
-
readonly leadIn: number;
|
|
6061
|
-
}
|
|
7829
|
+
function subtaskFromPlace(intent: PlaceIntent, id: string): Subtask;
|
|
6062
7830
|
```
|
|
6063
7831
|
|
|
6064
|
-
|
|
7832
|
+
Used on [Placing from outside](#/placing) and [Where a subtask may go](#/where-it-may-go).
|
|
7833
|
+
|
|
7834
|
+
##### `violatedDependencies`
|
|
7835
|
+
|
|
7836
|
+
Every dependency whose successor is to be reached before the predecessor's
|
|
7837
|
+
departure plus the dependency's lag. A dependency naming a subtask that
|
|
7838
|
+
is not in the data is passed over: there is nothing to judge.
|
|
6065
7839
|
|
|
6066
7840
|
```ts
|
|
6067
|
-
|
|
6068
|
-
interface StretchIntent {
|
|
6069
|
-
readonly kind: "stretch";
|
|
6070
|
-
/** The id of the subtask. */
|
|
6071
|
-
readonly subtask: string;
|
|
6072
|
-
/** The new start of the main time. */
|
|
6073
|
-
readonly from: number;
|
|
6074
|
-
/** The new end of the main time. */
|
|
6075
|
-
readonly to: number;
|
|
6076
|
-
}
|
|
7841
|
+
function violatedDependencies(subtasks: readonly Subtask[], dependencies: readonly Dependency[]): ViolatedDependency[];
|
|
6077
7842
|
```
|
|
6078
7843
|
|
|
6079
|
-
|
|
7844
|
+
Used on [Scenarios](#/), [Lane groups](#/lane-groups), [Tooltip](#/tooltip) and [Findings as data](#/findings).
|
|
7845
|
+
|
|
7846
|
+
#### Types
|
|
7847
|
+
|
|
7848
|
+
##### `BlockedTime`
|
|
7849
|
+
|
|
7850
|
+
Its table stands on [Blocked time](#/blocked-time/type-BlockedTime).
|
|
7851
|
+
|
|
7852
|
+
Used on [Scenarios](#/), [Blocked time](#/blocked-time), [Tooltip](#/tooltip), [Findings as data](#/findings) and [Where a subtask may go](#/where-it-may-go).
|
|
7853
|
+
|
|
7854
|
+
##### `BlockedTimesProps`
|
|
7855
|
+
|
|
7856
|
+
Its table stands on [Blocked time](#/blocked-time/type-BlockedTimesProps).
|
|
7857
|
+
|
|
7858
|
+
##### `DependenciesProps`
|
|
7859
|
+
|
|
7860
|
+
Its table stands on [Dependencies](#/dependencies/type-DependenciesProps).
|
|
7861
|
+
|
|
7862
|
+
##### `Dependency`
|
|
7863
|
+
|
|
7864
|
+
Its table stands on [Dependencies](#/dependencies/type-Dependency).
|
|
7865
|
+
|
|
7866
|
+
Used on [Scenarios](#/), [Installation](#/installation), [First schedule](#/schedule), [Lane groups](#/lane-groups), [Dependencies](#/dependencies), [Routes](#/routes), [Time axis and calendar](#/time-axis), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Placing from outside](#/placing) and [Ripple](#/ripple).
|
|
7867
|
+
|
|
7868
|
+
##### `DependencyAttachment`
|
|
7869
|
+
|
|
7870
|
+
Where on its bars a dependency's line attaches: the middle of both, or the
|
|
7871
|
+
edge that faces the other stop - which is the shortest line between them.
|
|
7872
|
+
|
|
7873
|
+
Deliberately not called an anchor: a dependency already HAS two anchors
|
|
7874
|
+
(`leaves`, `arrives`), and those decide what it connects and therefore
|
|
7875
|
+
whether it is violated. This decides where the line touches, and nothing else.
|
|
7876
|
+
The tree has an **Anchor** of its own as well (CONTEXT.md).
|
|
6080
7877
|
|
|
6081
7878
|
```ts
|
|
6082
|
-
|
|
6083
|
-
interface LeadOutIntent {
|
|
6084
|
-
readonly kind: "leadOut";
|
|
6085
|
-
/** The id of the subtask. */
|
|
6086
|
-
readonly subtask: string;
|
|
6087
|
-
/** The new duration of the lead-out. */
|
|
6088
|
-
readonly leadOut: number;
|
|
6089
|
-
}
|
|
7879
|
+
type DependencyAttachment = "centre" | "nearest";
|
|
6090
7880
|
```
|
|
6091
7881
|
|
|
6092
|
-
|
|
7882
|
+
Used on [Dependencies](#/dependencies).
|
|
7883
|
+
|
|
7884
|
+
##### `DependencyEnds`
|
|
7885
|
+
|
|
7886
|
+
Whether a dependency's two ends carry a dot. The dot says where the line is
|
|
7887
|
+
anchored, which is worth saying while a plan is being read and is noise in a
|
|
7888
|
+
plan full of short moves - so it is the caller's choice.
|
|
6093
7889
|
|
|
6094
7890
|
```ts
|
|
6095
|
-
|
|
6096
|
-
interface Findings {
|
|
6097
|
-
readonly overlaps: readonly Overlap[];
|
|
6098
|
-
readonly violatedDependencies: readonly ViolatedDependency[];
|
|
6099
|
-
readonly inBlockedTime: readonly InBlockedTime[];
|
|
6100
|
-
}
|
|
7891
|
+
type DependencyEnds = "dot" | "none";
|
|
6101
7892
|
```
|
|
6102
7893
|
|
|
6103
|
-
|
|
7894
|
+
Used on [Dependencies](#/dependencies).
|
|
7895
|
+
|
|
7896
|
+
##### `DependencyRoute`
|
|
7897
|
+
|
|
7898
|
+
How a dependency is drawn between its two ends: a curve that leaves and
|
|
7899
|
+
arrives forwards, a straight line, or axis-parallel segments.
|
|
6104
7900
|
|
|
6105
7901
|
```ts
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
7902
|
+
type DependencyRoute = "curve" | "straight" | "orthogonal";
|
|
7903
|
+
```
|
|
7904
|
+
|
|
7905
|
+
##### `Findings`
|
|
7906
|
+
|
|
7907
|
+
Every kind of finding over the same data.
|
|
7908
|
+
|
|
7909
|
+
| Prop | Type | Default | Description |
|
|
7910
|
+
|---|---|---|---|
|
|
7911
|
+
| `overlaps` *required* | `readonly `[`Overlap`](#/findings/type-Overlap)`[]` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [List the findings (Findings as data)](#/findings/list-the-findings), [Say when there is nothing to fix (Findings as data)](#/findings/nothing-to-fix) and 1 more |
|
|
7912
|
+
| `violatedDependencies` *required* | `readonly `[`ViolatedDependency`](#/findings/type-ViolatedDependency)`[]` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [List the findings (Findings as data)](#/findings/list-the-findings), [Say when there is nothing to fix (Findings as data)](#/findings/nothing-to-fix) and 1 more |
|
|
7913
|
+
| `inBlockedTime` *required* | `readonly `[`InBlockedTime`](#/findings/type-InBlockedTime)`[]` | — | <br>Shown in: [Block out leave and maintenance (Blocked time)](#/blocked-time/leave), [Check a sprint against the leave calendar (Blocked time)](#/blocked-time/team-leave), [List the findings (Findings as data)](#/findings/list-the-findings) and 3 more |
|
|
7914
|
+
|
|
7915
|
+
##### `InBlockedTime`
|
|
7916
|
+
|
|
7917
|
+
Its table stands on [Findings as data](#/findings/type-InBlockedTime).
|
|
7918
|
+
|
|
7919
|
+
##### `Intent`
|
|
7920
|
+
|
|
7921
|
+
What the schedule reports when an interaction asks for a change. Every
|
|
7922
|
+
intent carries the values it asks for, not a difference: two intents of one
|
|
7923
|
+
drop - a move and a lane - give the same data in either order.
|
|
7924
|
+
|
|
7925
|
+
```ts
|
|
7926
|
+
type Intent = MoveIntent | StretchIntent | LeadInIntent | LeadOutIntent | LaneIntent | PlaceIntent;
|
|
6127
7927
|
```
|
|
6128
7928
|
|
|
6129
|
-
|
|
7929
|
+
Used on [Scenarios](#/), [Blocked time](#/blocked-time), [Move and lane](#/move-and-lane), [Placing from outside](#/placing), [Where a subtask may go](#/where-it-may-go) and [Ripple](#/ripple).
|
|
7930
|
+
|
|
7931
|
+
##### `IntentKind`
|
|
7932
|
+
|
|
7933
|
+
The names of the intents - the editing API of the schedule.
|
|
6130
7934
|
|
|
6131
7935
|
```ts
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
7936
|
+
type IntentKind = Intent["kind"];
|
|
7937
|
+
```
|
|
7938
|
+
|
|
7939
|
+
##### `LaneGroupProps`
|
|
7940
|
+
|
|
7941
|
+
Its table stands on [Lane groups](#/lane-groups/type-LaneGroupProps).
|
|
7942
|
+
|
|
7943
|
+
##### `LaneIntent`
|
|
7944
|
+
|
|
7945
|
+
Put the subtask on another lane.
|
|
7946
|
+
|
|
7947
|
+
| Prop | Type | Default | Description |
|
|
7948
|
+
|---|---|---|---|
|
|
7949
|
+
| `kind` *required* | `"lane"` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 7 more |
|
|
7950
|
+
| `subtask` *required* | `string` | — | The id of the subtask.<br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 4 more |
|
|
7951
|
+
| `lane` *required* | `string` | — | The id of the new lane. |
|
|
7952
|
+
|
|
7953
|
+
##### `LaneProps`
|
|
7954
|
+
|
|
7955
|
+
Its table stands on [Lanes](#/lane/type-LaneProps).
|
|
7956
|
+
|
|
7957
|
+
##### `LeadInIntent`
|
|
7958
|
+
|
|
7959
|
+
Change the lead-in on its own.
|
|
7960
|
+
|
|
7961
|
+
| Prop | Type | Default | Description |
|
|
7962
|
+
|---|---|---|---|
|
|
7963
|
+
| `kind` *required* | `"leadIn"` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 7 more |
|
|
7964
|
+
| `subtask` *required* | `string` | — | The id of the subtask.<br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 4 more |
|
|
7965
|
+
| `leadIn` *required* | `number` | — | The new duration of the lead-in.<br>Shown in: [Replan the day on the line (Scenarios)](#/scenarios/replan-the-day-on-the-line) |
|
|
7966
|
+
|
|
7967
|
+
##### `LeadOutIntent`
|
|
7968
|
+
|
|
7969
|
+
Change the lead-out on its own.
|
|
7970
|
+
|
|
7971
|
+
| Prop | Type | Default | Description |
|
|
7972
|
+
|---|---|---|---|
|
|
7973
|
+
| `kind` *required* | `"leadOut"` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 7 more |
|
|
7974
|
+
| `subtask` *required* | `string` | — | The id of the subtask.<br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 4 more |
|
|
7975
|
+
| `leadOut` *required* | `number` | — | The new duration of the lead-out. |
|
|
7976
|
+
|
|
7977
|
+
##### `MoveIntent`
|
|
7978
|
+
|
|
7979
|
+
Move the subtask in time: the main time keeps its length.
|
|
7980
|
+
|
|
7981
|
+
| Prop | Type | Default | Description |
|
|
7982
|
+
|---|---|---|---|
|
|
7983
|
+
| `kind` *required* | `"move"` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 8 more |
|
|
7984
|
+
| `subtask` *required* | `string` | — | The id of the subtask.<br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 5 more |
|
|
7985
|
+
| `from` *required* | `number` | — | The new start of the main time.<br>Shown in: [Push the later stops of a tour (Ripple)](#/ripple/push-the-later-stops), [Replan the day on the line (Scenarios)](#/scenarios/replan-the-day-on-the-line) |
|
|
7986
|
+
| `to` *required* | `number` | — | The new end of the main time.<br>Shown in: [Push the later stops of a tour (Ripple)](#/ripple/push-the-later-stops), [Replan the day on the line (Scenarios)](#/scenarios/replan-the-day-on-the-line) |
|
|
7987
|
+
|
|
7988
|
+
Used on [Ripple](#/ripple).
|
|
7989
|
+
|
|
7990
|
+
##### `Overlap`
|
|
7991
|
+
|
|
7992
|
+
Its table stands on [Findings as data](#/findings/type-Overlap).
|
|
7993
|
+
|
|
7994
|
+
##### `PlaceIntent`
|
|
7995
|
+
|
|
7996
|
+
Put work on the plan that was not on it: the answer to a drag from outside
|
|
7997
|
+
the schedule (schedule-refinement 07). It carries no subtask id - there is
|
|
7998
|
+
no subtask yet; the caller creates one, with its own identity, from
|
|
7999
|
+
`subtaskFromPlace`.
|
|
8000
|
+
|
|
8001
|
+
| Prop | Type | Default | Description |
|
|
8002
|
+
|---|---|---|---|
|
|
8003
|
+
| `kind` *required* | `"place"` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 7 more |
|
|
8004
|
+
| `item` *required* | `string` | — | The caller's key for the dragged item, as it declared it while dragging.<br>Shown in: [Drag work in from the backlog (Placing from outside)](#/placing/drag-from-the-backlog), [Apply the same rule to work dragged in (Where a subtask may go)](#/where-it-may-go/dragged-in), [Replan the day on the line (Scenarios)](#/scenarios/replan-the-day-on-the-line) |
|
|
8005
|
+
| `task` *required* | `string` | — | The task the work belongs to. |
|
|
8006
|
+
| `lane` *required* | `string` | — | The lane it was dropped on.<br>Shown in: [Drag work in from the backlog (Placing from outside)](#/placing/drag-from-the-backlog), [Apply the same rule to work dragged in (Where a subtask may go)](#/where-it-may-go/dragged-in) |
|
|
8007
|
+
| `from` *required* | `number` | — | Where its main time would start. |
|
|
8008
|
+
| `to` *required* | `number` | — | Where its main time would end. |
|
|
8009
|
+
| `leadIn` | `number` | — | The lead-in it was declared with. |
|
|
8010
|
+
| `leadOut` | `number` | — | The lead-out it was declared with. |
|
|
8011
|
+
|
|
8012
|
+
##### `PlacingItem`
|
|
8013
|
+
|
|
8014
|
+
What the application says it is dragging in, while it drags it
|
|
8015
|
+
(schedule-refinement 07): the browser hands over the dragged data only on
|
|
8016
|
+
the drop, so the ghost before the drop can only come from the caller.
|
|
8017
|
+
|
|
8018
|
+
| Prop | Type | Default | Description |
|
|
8019
|
+
|---|---|---|---|
|
|
8020
|
+
| `item` *required* | `string` | — | The caller's key for the dragged item; it comes back in the intent.<br>Shown in: [Drag work in from the backlog (Placing from outside)](#/placing/drag-from-the-backlog), [Apply the same rule to work dragged in (Where a subtask may go)](#/where-it-may-go/dragged-in) |
|
|
8021
|
+
| `task` *required* | `string` | — | The task the work belongs to.<br>Shown in: [Drag work in from the backlog (Placing from outside)](#/placing/drag-from-the-backlog), [Apply the same rule to work dragged in (Where a subtask may go)](#/where-it-may-go/dragged-in) |
|
|
8022
|
+
| `duration` *required* | `number` | — | How long its main time is.<br>Shown in: [Drag work in from the backlog (Placing from outside)](#/placing/drag-from-the-backlog), [Apply the same rule to work dragged in (Where a subtask may go)](#/where-it-may-go/dragged-in) |
|
|
8023
|
+
| `leadIn` | `number` | — | The lead-in it brings. |
|
|
8024
|
+
| `leadOut` | `number` | — | The lead-out it brings. |
|
|
8025
|
+
|
|
8026
|
+
Used on [Placing from outside](#/placing) and [Where a subtask may go](#/where-it-may-go).
|
|
8027
|
+
|
|
8028
|
+
##### `ResolvedAppearance`
|
|
8029
|
+
|
|
8030
|
+
What the drawing needs to know, with the contradiction already settled.
|
|
8031
|
+
|
|
8032
|
+
The four names are the ones this module was born with, and they are kept so
|
|
8033
|
+
that a caller's code does not change because a picture did. Two of them are
|
|
8034
|
+
now named after a drawing they no longer use, and the channel each one
|
|
8035
|
+
really owns stands beside it.
|
|
8036
|
+
|
|
8037
|
+
| Prop | Type | Default | Description |
|
|
8038
|
+
|---|---|---|---|
|
|
8039
|
+
| `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. |
|
|
8040
|
+
| `hatched` *required* | `boolean` | — | `fixed`: the ENDS - a cap at each end of the main time. Not a hatch any more; a hatch now says "not available" of a refused lane, and the name is kept only so that this type did not change with the picture. |
|
|
8041
|
+
| `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. |
|
|
8042
|
+
| `open` *required* | `boolean` | — | `open`: the FADE, where the bar passes the edge of the view. It goes on past what is drawn. |
|
|
8043
|
+
|
|
8044
|
+
##### `ScheduleHandle`
|
|
8045
|
+
|
|
8046
|
+
What a schedule offers a caller imperatively: the arithmetic between a
|
|
8047
|
+
point on the screen and a time on a lane. Everything else is props.
|
|
8048
|
+
|
|
8049
|
+
| Prop | Type | Default | Description |
|
|
8050
|
+
|---|---|---|---|
|
|
8051
|
+
| `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) |
|
|
8052
|
+
| `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) |
|
|
8053
|
+
| `visibleDomain` *required* | `() => readonly [number, number]` | — | The visible span, as two wall-clock instants. |
|
|
8054
|
+
|
|
8055
|
+
Used on [The handle](#/handle).
|
|
8056
|
+
|
|
8057
|
+
##### `ScheduleHit`
|
|
8058
|
+
|
|
8059
|
+
What a pointer is on.
|
|
8060
|
+
|
|
8061
|
+
```ts
|
|
8062
|
+
type ScheduleHit =
|
|
8063
|
+
| { readonly kind: "subtask"; readonly subtask: Subtask; readonly part: "leadIn" | "main" | "leadOut" }
|
|
8064
|
+
| { readonly kind: "dependency"; readonly dependency: Dependency }
|
|
8065
|
+
| { readonly kind: "lane"; readonly lane: string }
|
|
8066
|
+
| { readonly kind: "nothing" };
|
|
8067
|
+
```
|
|
8068
|
+
|
|
8069
|
+
##### `ScheduleInteraction`
|
|
8070
|
+
|
|
8071
|
+
Its table stands on [Interactions](#/interactions/type-ScheduleInteraction).
|
|
8072
|
+
|
|
8073
|
+
Used on [Scenarios](#/), [Interactions](#/interactions) and [Tooltip](#/tooltip).
|
|
8074
|
+
|
|
8075
|
+
##### `ScheduleProps`
|
|
8076
|
+
|
|
8077
|
+
Its table stands on [First schedule](#/schedule/type-ScheduleProps).
|
|
8078
|
+
|
|
8079
|
+
##### `ScheduleTooltipTarget`
|
|
8080
|
+
|
|
8081
|
+
Its table stands on [Tooltip](#/tooltip/type-ScheduleTooltipTarget).
|
|
8082
|
+
|
|
8083
|
+
Used on [Tooltip](#/tooltip).
|
|
8084
|
+
|
|
8085
|
+
##### `SnapRaster`
|
|
8086
|
+
|
|
8087
|
+
A raster: a step, and where it starts after local midnight.
|
|
8088
|
+
|
|
8089
|
+
| Prop | Type | Default | Description |
|
|
8090
|
+
|---|---|---|---|
|
|
8091
|
+
| `step` *required* | `number` | — | The distance between two lines of the raster, in milliseconds.<br>Shown in: [Snap to handover times (Snapping)](#/snapping/snap-to-handovers) |
|
|
8092
|
+
| `offset` *required* | `number` | — | Where the raster starts after local midnight, in milliseconds: six hours for handovers at 06:00, 14:00 and 22:00.<br>Shown in: [Snap to handover times (Snapping)](#/snapping/snap-to-handovers) |
|
|
8093
|
+
|
|
8094
|
+
Used on [Snapping](#/snapping).
|
|
8095
|
+
|
|
8096
|
+
##### `StretchIntent`
|
|
8097
|
+
|
|
8098
|
+
Stretch the main time at one or both of its edges.
|
|
8099
|
+
|
|
8100
|
+
| Prop | Type | Default | Description |
|
|
8101
|
+
|---|---|---|---|
|
|
8102
|
+
| `kind` *required* | `"stretch"` | — | <br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 7 more |
|
|
8103
|
+
| `subtask` *required* | `string` | — | The id of the subtask.<br>Shown in: [Read a folded group (Lane groups)](#/lane-groups/the-miniature), [Plan work around someone's leave (Blocked time)](#/blocked-time/drag-around), [Refuse a move that double-books someone (Move and lane)](#/move-and-lane/refuse-a-double-booking) and 4 more |
|
|
8104
|
+
| `from` *required* | `number` | — | The new start of the main time. |
|
|
8105
|
+
| `to` *required* | `number` | — | The new end of the main time. |
|
|
8106
|
+
|
|
8107
|
+
##### `Subtask`
|
|
8108
|
+
|
|
8109
|
+
Its table stands on [Subtasks](#/subtasks/type-Subtask).
|
|
8110
|
+
|
|
8111
|
+
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), [Now line](#/now-line), [Pan and zoom](#/pan-and-zoom), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [Linked schedules](#/linked-schedules), [The handle](#/handle), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Stretch, lead-in, lead-out](#/stretch), [Snapping](#/snapping), [Placing from outside](#/placing), [Where a subtask may go](#/where-it-may-go) and [Ripple](#/ripple).
|
|
8112
|
+
|
|
8113
|
+
##### `SubtaskAppearance`
|
|
8114
|
+
|
|
8115
|
+
The appearances a caller may give a subtask.
|
|
8116
|
+
|
|
8117
|
+
```ts
|
|
8118
|
+
type SubtaskAppearance = "provisional" | "fixed" | "muted" | "open";
|
|
6154
8119
|
```
|
|
8120
|
+
|
|
8121
|
+
##### `SubtasksProps`
|
|
8122
|
+
|
|
8123
|
+
Its table stands on [Subtasks](#/subtasks/type-SubtasksProps).
|
|
8124
|
+
|
|
8125
|
+
##### `Task`
|
|
8126
|
+
|
|
8127
|
+
Its table stands on [Subtasks](#/subtasks/type-Task).
|
|
8128
|
+
|
|
8129
|
+
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), [Now line](#/now-line), [Pan and zoom](#/pan-and-zoom), [Selection](#/selection), [Interactions](#/interactions), [Tooltip](#/tooltip), [Linked schedules](#/linked-schedules), [The handle](#/handle), [Findings as data](#/findings), [Move and lane](#/move-and-lane), [Stretch, lead-in, lead-out](#/stretch), [Snapping](#/snapping), [Placing from outside](#/placing), [Where a subtask may go](#/where-it-may-go) and [Ripple](#/ripple).
|
|
8130
|
+
|
|
8131
|
+
##### `ViolatedDependency`
|
|
8132
|
+
|
|
8133
|
+
Its table stands on [Findings as data](#/findings/type-ViolatedDependency).
|
|
8134
|
+
|
|
8135
|
+
Used on [Dependencies](#/dependencies).
|
|
8136
|
+
|
|
8137
|
+
##### `ZoomLimits`
|
|
8138
|
+
|
|
8139
|
+
The narrowest and the widest span zoom may reach.
|
|
8140
|
+
|
|
8141
|
+
| Prop | Type | Default | Description |
|
|
8142
|
+
|---|---|---|---|
|
|
8143
|
+
| `min` *required* | `number` | — | <br>Shown in: [Move through the plan (Pan and zoom)](#/pan-and-zoom/pan-and-zoom) |
|
|
8144
|
+
| `max` *required* | `number` | — | <br>Shown in: [Move through the plan (Pan and zoom)](#/pan-and-zoom/pan-and-zoom) |
|