@umriss-ui/schedule 0.41.1 → 0.43.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 +47 -3
- package/README.md +35 -12
- package/dist/index.d.ts +96 -44
- package/dist/schedule.css +1 -1
- package/dist/schedule.js +881 -787
- package/docs/llms-full.md +394 -285
- package/package.json +8 -7
package/docs/llms-full.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @umriss-ui/schedule 0.
|
|
1
|
+
# @umriss-ui/schedule 0.43.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
|
|
|
@@ -133,7 +133,7 @@ export default function HandOver() {
|
|
|
133
133
|
</Stack>
|
|
134
134
|
<div data-callout="2">
|
|
135
135
|
<Schedule
|
|
136
|
-
|
|
136
|
+
aria-label="On-call rota, 16 to 23 March"
|
|
137
137
|
height={420}
|
|
138
138
|
now={NOW}
|
|
139
139
|
intents={["lane"]}
|
|
@@ -418,7 +418,7 @@ export default function TourPlan() {
|
|
|
418
418
|
<Stack gap={3}>
|
|
419
419
|
<div data-callout="1">
|
|
420
420
|
<Schedule
|
|
421
|
-
|
|
421
|
+
aria-label="Tours of Wednesday, 18 March"
|
|
422
422
|
height={470}
|
|
423
423
|
intents={["move"]}
|
|
424
424
|
onIntent={apply}
|
|
@@ -652,7 +652,7 @@ export default function SprintAroundLeave() {
|
|
|
652
652
|
</Stack>
|
|
653
653
|
<div data-callout="2">
|
|
654
654
|
<Schedule
|
|
655
|
-
|
|
655
|
+
aria-label="Sprint 14, work per person"
|
|
656
656
|
calendar={WORKING_DAYS}
|
|
657
657
|
height={570}
|
|
658
658
|
now={NOW}
|
|
@@ -844,7 +844,7 @@ export default function ReplanTheDay() {
|
|
|
844
844
|
</div>
|
|
845
845
|
<div data-callout="2">
|
|
846
846
|
<Schedule
|
|
847
|
-
|
|
847
|
+
aria-label="Plan of Tuesday, 17 March, in the planner's hands"
|
|
848
848
|
height={380}
|
|
849
849
|
intents={["move", "lane", "stretch", "leadIn", "leadOut"]}
|
|
850
850
|
onIntent={apply}
|
|
@@ -863,7 +863,7 @@ export default function ReplanTheDay() {
|
|
|
863
863
|
onOpenChange={(open) => {
|
|
864
864
|
if (!open) setMenu(null);
|
|
865
865
|
}}
|
|
866
|
-
|
|
866
|
+
aria-label={target !== null ? `Actions for ${target.id}` : "Actions for the plan"}
|
|
867
867
|
>
|
|
868
868
|
{target !== null ? (
|
|
869
869
|
<>
|
|
@@ -944,7 +944,7 @@ const dependencies: Dependency[] = [{ id: "handover", from: "design", to: "build
|
|
|
944
944
|
export default function SmallestSchedule() {
|
|
945
945
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(8), at(16)] } });
|
|
946
946
|
return (
|
|
947
|
-
<Schedule
|
|
947
|
+
<Schedule aria-label="Tuesday, design and build" height={150}>
|
|
948
948
|
<Lane id="noah" label="Noah Fischer" />
|
|
949
949
|
<Lane id="arjun" label="Arjun Mehta" />
|
|
950
950
|
<Dependencies data={dependencies} />
|
|
@@ -964,15 +964,9 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
964
964
|
|
|
965
965
|
| Prop | Type | Default | Description |
|
|
966
966
|
|---|---|---|---|
|
|
967
|
-
| [`height`](#first-schedule) | `number` |
|
|
967
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
968
968
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
969
969
|
|
|
970
|
-
###### Accessibility
|
|
971
|
-
|
|
972
|
-
| Prop | Type | Default | Description |
|
|
973
|
-
|---|---|---|---|
|
|
974
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
975
|
-
|
|
976
970
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
977
971
|
|
|
978
972
|
| Prop | Type | Default | Description |
|
|
@@ -1101,7 +1095,7 @@ const HANDOVERS: readonly Dependency[] = [
|
|
|
1101
1095
|
export default function FirstSchedule() {
|
|
1102
1096
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: DAY } });
|
|
1103
1097
|
return (
|
|
1104
|
-
<Schedule
|
|
1098
|
+
<Schedule aria-label="Tours of Tuesday, 17 March" height={240}>
|
|
1105
1099
|
{VEHICLES.map((vehicle) => (
|
|
1106
1100
|
<Lane key={vehicle.id} id={vehicle.id} label={vehicle.label} />
|
|
1107
1101
|
))}
|
|
@@ -1134,7 +1128,7 @@ const PEOPLE = [
|
|
|
1134
1128
|
export default function NoWorkYet() {
|
|
1135
1129
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(23, 8), at(27, 18)] } });
|
|
1136
1130
|
return (
|
|
1137
|
-
<Schedule
|
|
1131
|
+
<Schedule aria-label="Sprint 15, nothing planned yet" height={170}>
|
|
1138
1132
|
{PEOPLE.map((person) => (
|
|
1139
1133
|
<Lane key={person.id} id={person.id} label={person.label} />
|
|
1140
1134
|
))}
|
|
@@ -1229,7 +1223,7 @@ export default function MachinePlan() {
|
|
|
1229
1223
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: DAY_OF_PLAN } });
|
|
1230
1224
|
return (
|
|
1231
1225
|
<Schedule
|
|
1232
|
-
|
|
1226
|
+
aria-label="Machine shop, Tuesday 17 March"
|
|
1233
1227
|
height={380}
|
|
1234
1228
|
now={HALF_PAST_TEN}
|
|
1235
1229
|
label={(step) => NAMES.get(step.task) ?? step.task}
|
|
@@ -1244,6 +1238,164 @@ export default function MachinePlan() {
|
|
|
1244
1238
|
}
|
|
1245
1239
|
```
|
|
1246
1240
|
|
|
1241
|
+
##### Fill a pane of fixed height
|
|
1242
|
+
|
|
1243
|
+
Without `height`, a schedule takes the height of its frame: this pane is 480 px, and the schedule is exactly that, bands included. Drag the pane's corner and the schedule follows.
|
|
1244
|
+
|
|
1245
|
+
```tsx
|
|
1246
|
+
import { useSchedule } from "@umriss-ui/schedule";
|
|
1247
|
+
import type { Subtask, Task } from "@umriss-ui/schedule";
|
|
1248
|
+
|
|
1249
|
+
const at = (hours: number) => new Date(2026, 2, 17, hours).getTime();
|
|
1250
|
+
|
|
1251
|
+
const ORDERS: Task[] = [{ id: "a-2041", name: "A-2041 Housing", color: "light-dark(#2563eb, #6b9bff)" }];
|
|
1252
|
+
|
|
1253
|
+
const STEPS: Subtask[] = [
|
|
1254
|
+
{ id: "a-2041-1", task: "a-2041", lane: "saw", from: at(6), to: at(7) },
|
|
1255
|
+
{ id: "a-2041-2", task: "a-2041", lane: "mill", from: at(8), to: at(10) },
|
|
1256
|
+
{ id: "a-2041-3", task: "a-2041", lane: "qa", from: at(11), to: at(12) },
|
|
1257
|
+
];
|
|
1258
|
+
|
|
1259
|
+
export default function FillsItsPane() {
|
|
1260
|
+
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(5), at(13)] } });
|
|
1261
|
+
return (
|
|
1262
|
+
<div data-pane="" style={{ height: 480, resize: "vertical", overflow: "hidden" }}>
|
|
1263
|
+
<Schedule aria-label="Plan of Tuesday in a pane">
|
|
1264
|
+
<Lane id="saw" label="Saw" />
|
|
1265
|
+
<Lane id="mill" label="Mill" />
|
|
1266
|
+
<Lane id="qa" label="Inspection" />
|
|
1267
|
+
<Subtasks data={STEPS} tasks={ORDERS} />
|
|
1268
|
+
</Schedule>
|
|
1269
|
+
</div>
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
```
|
|
1273
|
+
|
|
1274
|
+
##### Thirty lanes, a floor of 400 px
|
|
1275
|
+
|
|
1276
|
+
In a block with no height, a schedule is 400 px whatever its lanes. The lanes beyond the plot scroll inside it, and the page does not grow.
|
|
1277
|
+
|
|
1278
|
+
```tsx
|
|
1279
|
+
import { useSchedule } from "@umriss-ui/schedule";
|
|
1280
|
+
import type { Subtask, Task } from "@umriss-ui/schedule";
|
|
1281
|
+
|
|
1282
|
+
const at = (hours: number) => new Date(2026, 2, 17, hours).getTime();
|
|
1283
|
+
|
|
1284
|
+
const ORDERS: Task[] = [{ id: "round", name: "Round", color: "light-dark(#0d9488, #3cc7b8)" }];
|
|
1285
|
+
|
|
1286
|
+
const STATIONS = Array.from({ length: 30 }, (_, index) => ({ id: `s-${index + 1}`, label: `Station ${index + 1}` }));
|
|
1287
|
+
|
|
1288
|
+
const STEPS: Subtask[] = STATIONS.map((station, index) => ({
|
|
1289
|
+
id: `round-${index + 1}`,
|
|
1290
|
+
task: "round",
|
|
1291
|
+
lane: station.id,
|
|
1292
|
+
from: at(6 + (index % 6)),
|
|
1293
|
+
to: at(7 + (index % 6)),
|
|
1294
|
+
}));
|
|
1295
|
+
|
|
1296
|
+
export default function ThirtyLanes() {
|
|
1297
|
+
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(5), at(14)] } });
|
|
1298
|
+
return (
|
|
1299
|
+
<Schedule aria-label="Round of thirty stations">
|
|
1300
|
+
{STATIONS.map((station) => (
|
|
1301
|
+
<Lane key={station.id} id={station.id} label={station.label} />
|
|
1302
|
+
))}
|
|
1303
|
+
<Subtasks data={STEPS} tasks={ORDERS} />
|
|
1304
|
+
</Schedule>
|
|
1305
|
+
);
|
|
1306
|
+
}
|
|
1307
|
+
```
|
|
1308
|
+
|
|
1309
|
+
##### Show that a plan is on its way
|
|
1310
|
+
|
|
1311
|
+
`loading`, as the chart and the table have it: over a plan the plan stays, dims after a moment and starts no drag, tooltip or key intent until the answer is in; before the first lanes, placeholder lines stand in the lane column.
|
|
1312
|
+
|
|
1313
|
+
```tsx
|
|
1314
|
+
import { useEffect, useRef, useState } from "react";
|
|
1315
|
+
import { Button, Text } from "@umriss-ui/core";
|
|
1316
|
+
import { useSchedule } from "@umriss-ui/schedule";
|
|
1317
|
+
import type { Subtask, Task } from "@umriss-ui/schedule";
|
|
1318
|
+
|
|
1319
|
+
const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
|
|
1320
|
+
const DAY: readonly [number, number] = [at(6), at(16)];
|
|
1321
|
+
|
|
1322
|
+
const TOURS: readonly Task[] = [
|
|
1323
|
+
{ id: "t-01", name: "T-01 Harbour", color: "light-dark(#2563eb, #6b9bff)" },
|
|
1324
|
+
{ id: "t-03", name: "T-03 Old Town", color: "light-dark(#c2410c, #f08a52)" },
|
|
1325
|
+
];
|
|
1326
|
+
|
|
1327
|
+
/** Each answer shifts the second tour by a quarter of an hour. */
|
|
1328
|
+
function legs(answer: number): readonly Subtask[] {
|
|
1329
|
+
const shift = (answer % 4) * 15;
|
|
1330
|
+
return [
|
|
1331
|
+
{ id: "t-01-1", task: "t-01", lane: "van-1", from: at(7), to: at(9) },
|
|
1332
|
+
{ id: "t-03-1", task: "t-03", lane: "van-2", from: at(8, shift), to: at(10, shift) },
|
|
1333
|
+
{ id: "t-01-2", task: "t-01", lane: "e-van", from: at(11), to: at(13) },
|
|
1334
|
+
];
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
const LANES = [
|
|
1338
|
+
{ id: "van-1", label: "Van FP 214 K" },
|
|
1339
|
+
{ id: "van-2", label: "Van FP 402 R" },
|
|
1340
|
+
{ id: "e-van", label: "E-van FP 377 K" },
|
|
1341
|
+
];
|
|
1342
|
+
|
|
1343
|
+
function Plan({ answer, loading }: { answer: number; loading: boolean }) {
|
|
1344
|
+
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: DAY } });
|
|
1345
|
+
return (
|
|
1346
|
+
<Schedule aria-label="Tours of the day" height={220} loading={loading} intents={["move", "lane"]}>
|
|
1347
|
+
{LANES.map((lane) => (
|
|
1348
|
+
<Lane key={lane.id} id={lane.id} label={lane.label} />
|
|
1349
|
+
))}
|
|
1350
|
+
<Subtasks data={legs(answer)} tasks={TOURS} />
|
|
1351
|
+
</Schedule>
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
function Waiting() {
|
|
1356
|
+
const { Schedule } = useSchedule({ initialView: { domain: DAY } });
|
|
1357
|
+
return <Schedule aria-label="Tours of the day, loading" height={220} loading />;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
export default function Loading() {
|
|
1361
|
+
const [answer, setAnswer] = useState(0);
|
|
1362
|
+
const [loading, setLoading] = useState(false);
|
|
1363
|
+
const pending = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
|
1364
|
+
useEffect(() => () => clearTimeout(pending.current), []);
|
|
1365
|
+
|
|
1366
|
+
const reload = () => {
|
|
1367
|
+
setLoading(true);
|
|
1368
|
+
clearTimeout(pending.current);
|
|
1369
|
+
pending.current = setTimeout(() => {
|
|
1370
|
+
setAnswer((n) => n + 1);
|
|
1371
|
+
setLoading(false);
|
|
1372
|
+
}, 1500);
|
|
1373
|
+
};
|
|
1374
|
+
|
|
1375
|
+
return (
|
|
1376
|
+
<div className="pair">
|
|
1377
|
+
<div>
|
|
1378
|
+
<Text as="p" size="sm" tone="muted">
|
|
1379
|
+
loading over a plan - the answer takes 1.5 s
|
|
1380
|
+
</Text>
|
|
1381
|
+
<Plan answer={answer} loading={loading} />
|
|
1382
|
+
<div className="demo-actions">
|
|
1383
|
+
<Button size="sm" onClick={reload} disabled={loading}>
|
|
1384
|
+
Reload
|
|
1385
|
+
</Button>
|
|
1386
|
+
</div>
|
|
1387
|
+
</div>
|
|
1388
|
+
<div>
|
|
1389
|
+
<Text as="p" size="sm" tone="muted">
|
|
1390
|
+
loading, before the first lanes
|
|
1391
|
+
</Text>
|
|
1392
|
+
<Waiting />
|
|
1393
|
+
</div>
|
|
1394
|
+
</div>
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1397
|
+
```
|
|
1398
|
+
|
|
1247
1399
|
#### Keyboard
|
|
1248
1400
|
|
|
1249
1401
|
| Key | Action |
|
|
@@ -1262,7 +1414,7 @@ export default function MachinePlan() {
|
|
|
1262
1414
|
|
|
1263
1415
|
#### Accessibility
|
|
1264
1416
|
|
|
1265
|
-
The schedule is a figure named by `
|
|
1417
|
+
The schedule is a figure named by `aria-label`, 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. `aria-label` is required - name what the plan shows, "Plan of week 38".
|
|
1266
1418
|
|
|
1267
1419
|
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-as-data) 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".
|
|
1268
1420
|
|
|
@@ -1274,14 +1426,14 @@ Under forced colours the plot paints itself in the system colours: the work in t
|
|
|
1274
1426
|
|
|
1275
1427
|
| Prop | Type | Default | Description |
|
|
1276
1428
|
|---|---|---|---|
|
|
1277
|
-
| `ref` | `Ref<``ScheduleHandle
|
|
1278
|
-
| `height` | `number` |
|
|
1429
|
+
| `ref` | `Ref<HTMLDivElement> \| RefObject<``ScheduleHandle`` \| null> \| undefined` | — | Receives the root element. A ref to the deprecated `ScheduleHandle` still works for one more minor release: the element carries its three functions. |
|
|
1430
|
+
| `height` | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's.<br>Shown in: [A day of tours](#first-schedule), [Start from an empty plan](#first-schedule), [Plan a day in the machine shop](#first-schedule) and 80 more |
|
|
1279
1431
|
| `laneHeight` | `number` | `44` | Height of one lane in pixels at the default font size of 16 px; the schedule multiplies it by the root font size over 16 px when that ratio is above 1, so lane names keep their room in a reader's larger font.<br>Shown in: [Scroll more lanes than fit (Lanes)](#lanes), [Measure a plan (Benchmark)](#benchmark) |
|
|
1280
1432
|
| `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)](#lanes), [Scroll more lanes than fit (Lanes)](#lanes), [Group lanes under a head (Lane groups)](#lane-groups) and 1 more |
|
|
1281
1433
|
| `calendar` | `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-and-calendar), [Plan in office hours only (Time axis and calendar)](#time-axis-and-calendar), [Plan the sprint around leave (Scenarios)](#plan-the-sprint-around-leave) |
|
|
1282
1434
|
| `zoomLimits` | `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) |
|
|
1283
1435
|
| `snap` | `"ticks" \| number \| ``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 handover times (Snapping)](#snapping), [Place without snapping (Snapping)](#snapping) |
|
|
1284
|
-
| `intents` | `readonly ``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), [Cut the nights out of the axis (Time axis and calendar)](#time-axis-and-calendar)
|
|
1436
|
+
| `intents` | `readonly ``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: [Show that a plan is on its way](#first-schedule), [Read a folded group (Lane groups)](#lane-groups), [Cut the nights out of the axis (Time axis and calendar)](#time-axis-and-calendar) and 19 more |
|
|
1285
1437
|
| `canMoveTo` | `(subtask: `[`Subtask`](#subtasks)`, 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-a-subtask-may-go), [Apply the same rule to work dragged in (Where a subtask may go)](#where-a-subtask-may-go), [Keep work out of someone's leave (Where a subtask may go)](#where-a-subtask-may-go) and 1 more |
|
|
1286
1438
|
| `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) |
|
|
1287
1439
|
| `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) |
|
|
@@ -1292,7 +1444,8 @@ Under forced colours the plot paints itself in the system colours: the work in t
|
|
|
1292
1444
|
| `label` | `(subtask: `[`Subtask`](#subtasks)`) => 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](#first-schedule), [Plan a sprint for a team (Subtasks)](#subtasks), [Write into the bars (Bar labels)](#bar-labels) and 7 more |
|
|
1293
1445
|
| `tooltip` | `false \| ((target: `[`ScheduleTooltipTarget`](#tooltip)`) => ReactNode)` | — | The tooltip on a hovered subtask or dependency: its order, its times, its parts and its findings. `false` switches it off; a function receives what the pointer rests on and returns content of the application's own.<br>Shown in: [Say what a milestone is in your own tooltip (Milestones)](#milestones), [Write your own tooltip content (Tooltip)](#tooltip), [Show a detail panel instead (Tooltip)](#tooltip) and 1 more |
|
|
1294
1446
|
| `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](#first-schedule), [Mark the present (Now line)](#now-line), [Follow the clock (Now line)](#now-line) and 2 more |
|
|
1295
|
-
| `
|
|
1447
|
+
| `loading` | `boolean` | `false` | The plan is on its way, as the chart's `loading` says ([ADR-0042](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0042-a-rows-height-never-follows-what-it-shows.md)). A plan already drawn stays: it dims after a moment and takes no pointer - no new drag, no tooltip, no intent by key - until the answer is in; a drag begun before finishes and reports. The keys still walk it. With no lanes, placeholder lines stand in the lane column. The plot is `aria-busy` meanwhile.<br>Shown in: [Show that a plan is on its way](#first-schedule) |
|
|
1448
|
+
| `children` | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn.<br>Shown in: [A day of tours](#first-schedule), [Start from an empty plan](#first-schedule), [Plan a day in the machine shop](#first-schedule) and 82 more |
|
|
1296
1449
|
|
|
1297
1450
|
###### Events
|
|
1298
1451
|
|
|
@@ -1301,18 +1454,7 @@ Under forced colours the plot paints itself in the system colours: the work in t
|
|
|
1301
1454
|
| `onIntent` | `(intent: ``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), [Cut the nights out of the axis (Time axis and calendar)](#time-axis-and-calendar), [Plan work around someone's leave (Blocked time)](#blocked-time) and 18 more |
|
|
1302
1455
|
| `onInteraction` | `(interaction: `[`ScheduleInteraction`](#interactions)`) => 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), [Open a context menu (Interactions)](#interactions), [Show a detail panel instead (Tooltip)](#tooltip) and 3 more |
|
|
1303
1456
|
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
| Prop | Type | Default | Description |
|
|
1307
|
-
|---|---|---|---|
|
|
1308
|
-
| `ariaLabel` *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38".<br>Shown in: [A day of tours](#first-schedule), [Start from an empty plan](#first-schedule), [Plan a day in the machine shop](#first-schedule) and 78 more |
|
|
1309
|
-
|
|
1310
|
-
###### Styling
|
|
1311
|
-
|
|
1312
|
-
| Prop | Type | Default | Description |
|
|
1313
|
-
|---|---|---|---|
|
|
1314
|
-
| `className` | `string` | — | Goes to the root element. |
|
|
1315
|
-
| `style` | `CSSProperties` | — | Goes to the root element. |
|
|
1457
|
+
Also takes every attribute of `<div>` – without `aria-label`, `children`.
|
|
1316
1458
|
|
|
1317
1459
|
##### Types on this page
|
|
1318
1460
|
|
|
@@ -1323,8 +1465,8 @@ point on the screen and a time on a lane. Everything else is props.
|
|
|
1323
1465
|
|
|
1324
1466
|
| Prop | Type | Default | Description |
|
|
1325
1467
|
|---|---|---|---|
|
|
1326
|
-
| `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
|
|
1327
|
-
| `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
|
|
1468
|
+
| `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. |
|
|
1469
|
+
| `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. |
|
|
1328
1470
|
| `visibleDomain` *required* | `() => readonly [number, number]` | — | The visible span, as two wall-clock instants. |
|
|
1329
1471
|
|
|
1330
1472
|
###### `CalendarInput`
|
|
@@ -1523,11 +1665,11 @@ no subtask yet; the caller creates one, with its own identity, from
|
|
|
1523
1665
|
|
|
1524
1666
|
#### Known limits
|
|
1525
1667
|
|
|
1526
|
-
- 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://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
1668
|
+
- 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://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md)).
|
|
1527
1669
|
- No milestones yet: a point in time on a lane has no mark of its own.
|
|
1528
1670
|
- A dependency joins two subtasks of one task; dependencies across tasks are not yet possible.
|
|
1529
1671
|
|
|
1530
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
1672
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
|
|
1531
1673
|
|
|
1532
1674
|
## Plan
|
|
1533
1675
|
|
|
@@ -1568,7 +1710,7 @@ const LEGS: Subtask[] = [
|
|
|
1568
1710
|
export default function LaneHeaders() {
|
|
1569
1711
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(6), at(12)] } });
|
|
1570
1712
|
return (
|
|
1571
|
-
<Schedule
|
|
1713
|
+
<Schedule aria-label="Two vans of the North depot" height={150} headerWidth={210}>
|
|
1572
1714
|
<Lane
|
|
1573
1715
|
id="v1"
|
|
1574
1716
|
label={
|
|
@@ -1632,7 +1774,7 @@ export default function ManyLanes() {
|
|
|
1632
1774
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(6), at(14)] } });
|
|
1633
1775
|
return (
|
|
1634
1776
|
<Schedule
|
|
1635
|
-
|
|
1777
|
+
aria-label="Twenty vans, Tuesday morning"
|
|
1636
1778
|
height={300}
|
|
1637
1779
|
laneHeight={32}
|
|
1638
1780
|
headerWidth={110}
|
|
@@ -1660,8 +1802,8 @@ The keys of [First schedule](#first-schedule) apply here.
|
|
|
1660
1802
|
|
|
1661
1803
|
| Prop | Type | Default | Description |
|
|
1662
1804
|
|---|---|---|---|
|
|
1663
|
-
| `id` *required* | `string` | — | The identity subtasks name in their `lane`.<br>Shown in: [What a lane header says](#lanes), [Scroll more lanes than fit](#lanes), [The smallest schedule (Installation)](#installation) and
|
|
1664
|
-
| `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](#lanes), [Scroll more lanes than fit](#lanes), [The smallest schedule (Installation)](#installation) and
|
|
1805
|
+
| `id` *required* | `string` | — | The identity subtasks name in their `lane`.<br>Shown in: [What a lane header says](#lanes), [Scroll more lanes than fit](#lanes), [The smallest schedule (Installation)](#installation) and 82 more |
|
|
1806
|
+
| `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](#lanes), [Scroll more lanes than fit](#lanes), [The smallest schedule (Installation)](#installation) and 81 more |
|
|
1665
1807
|
|
|
1666
1808
|
### Lane groups
|
|
1667
1809
|
|
|
@@ -1708,7 +1850,7 @@ const WORK: Subtask[] = [
|
|
|
1708
1850
|
export default function AGroup() {
|
|
1709
1851
|
const { Schedule, Lane, LaneGroup, Subtasks } = useSchedule({ initialView: { domain: [at(6), at(15)] } });
|
|
1710
1852
|
return (
|
|
1711
|
-
<Schedule
|
|
1853
|
+
<Schedule aria-label="Two developers in a team, a designer and a tester outside it" height={240} headerWidth={200}>
|
|
1712
1854
|
<LaneGroup id="developers" label="Developers">
|
|
1713
1855
|
<Lane id="arjun" label="Arjun Mehta" />
|
|
1714
1856
|
<Lane id="chloe" label="Chloe Durand" />
|
|
@@ -1751,7 +1893,7 @@ const LEGS: Subtask[] = [
|
|
|
1751
1893
|
export default function Nesting() {
|
|
1752
1894
|
const { Schedule, Lane, LaneGroup, Subtasks } = useSchedule({ initialView: { domain: [at(6), at(15)] } });
|
|
1753
1895
|
return (
|
|
1754
|
-
<Schedule
|
|
1896
|
+
<Schedule aria-label="North depot with its vans and a truck, and a van from Riverside" height={330} headerWidth={200}>
|
|
1755
1897
|
<LaneGroup id="north" label="North depot">
|
|
1756
1898
|
<LaneGroup id="vans" label="Vans">
|
|
1757
1899
|
<Lane id="fp-214" label={`Van ${plate("FP 214 K")}`} />
|
|
@@ -1804,7 +1946,7 @@ export default function FoldFromOutside() {
|
|
|
1804
1946
|
Unfold everything
|
|
1805
1947
|
</Button>
|
|
1806
1948
|
</Stack>
|
|
1807
|
-
<Schedule
|
|
1949
|
+
<Schedule aria-label="Two teams rolling out a release, folded from outside" height={280}>
|
|
1808
1950
|
<LaneGroup id="payments" label="Payments">
|
|
1809
1951
|
<Lane id="priya" label="Priya Raman" />
|
|
1810
1952
|
<Lane id="jonas" label="Jonas Keller" />
|
|
@@ -1876,7 +2018,7 @@ export default function TheMiniature() {
|
|
|
1876
2018
|
return (
|
|
1877
2019
|
<Stack gap={3}>
|
|
1878
2020
|
<Schedule
|
|
1879
|
-
|
|
2021
|
+
aria-label="A depot that folds into one row"
|
|
1880
2022
|
height={240}
|
|
1881
2023
|
intents={["move", "lane"]}
|
|
1882
2024
|
onIntent={(intent) => {
|
|
@@ -1931,7 +2073,7 @@ const WORK: Subtask[] = [
|
|
|
1931
2073
|
export default function StartWithGroupsFolded() {
|
|
1932
2074
|
const { Schedule, Lane, LaneGroup, Subtasks } = useSchedule({ initialView: { domain: [at(6), at(15)], folded: ["discovery"] } });
|
|
1933
2075
|
return (
|
|
1934
|
-
<Schedule
|
|
2076
|
+
<Schedule aria-label="Two teams rolling out a release, Discovery folded at the start" height={280}>
|
|
1935
2077
|
<LaneGroup id="payments" label="Payments">
|
|
1936
2078
|
<Lane id="priya" label="Priya Raman" />
|
|
1937
2079
|
<Lane id="jonas" label="Jonas Keller" />
|
|
@@ -1969,7 +2111,7 @@ The keys of [First schedule](#first-schedule) apply here.
|
|
|
1969
2111
|
|
|
1970
2112
|
- 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)).
|
|
1971
2113
|
|
|
1972
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
2114
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
|
|
1973
2115
|
|
|
1974
2116
|
### Subtasks
|
|
1975
2117
|
|
|
@@ -2005,7 +2147,7 @@ const ROUNDS: Subtask[] = [
|
|
|
2005
2147
|
export default function LeadInAndLeadOut() {
|
|
2006
2148
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(6), at(14, 30)] } });
|
|
2007
2149
|
return (
|
|
2008
|
-
<Schedule
|
|
2150
|
+
<Schedule aria-label="Three rounds of one van" height={110}>
|
|
2009
2151
|
<Lane id="van" label="Van FP 214 K" />
|
|
2010
2152
|
<Subtasks data={ROUNDS} tasks={TOURS} />
|
|
2011
2153
|
</Schedule>
|
|
@@ -2043,7 +2185,7 @@ const WORK: Subtask[] = [
|
|
|
2043
2185
|
export default function TaskColours() {
|
|
2044
2186
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(16, 6), at(20, 20)] } });
|
|
2045
2187
|
return (
|
|
2046
|
-
<Schedule
|
|
2188
|
+
<Schedule aria-label="Projects due this week among the rest" height={150}>
|
|
2047
2189
|
<Lane id="chloe" label="Chloe Durand" />
|
|
2048
2190
|
<Lane id="eva" label="Eva Novak" />
|
|
2049
2191
|
<Subtasks data={WORK} tasks={PROJECTS} />
|
|
@@ -2149,7 +2291,7 @@ const SPRINT_14: readonly [number, number] = [new Date(2026, 2, 9, 6).getTime(),
|
|
|
2149
2291
|
export default function ASprint() {
|
|
2150
2292
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: SPRINT_14 } });
|
|
2151
2293
|
return (
|
|
2152
|
-
<Schedule
|
|
2294
|
+
<Schedule aria-label="Sprint 14, 9 to 20 March" height={500} label={(s) => s.name ?? s.id}>
|
|
2153
2295
|
{PEOPLE.map((person) => (
|
|
2154
2296
|
<Lane key={person.id} id={person.id} label={person.name} />
|
|
2155
2297
|
))}
|
|
@@ -2169,18 +2311,18 @@ The keys of [First schedule](#first-schedule) apply here.
|
|
|
2169
2311
|
|
|
2170
2312
|
| Prop | Type | Default | Description |
|
|
2171
2313
|
|---|---|---|---|
|
|
2172
|
-
| `data` *required* | `readonly ``Subtask``[]` | — | The subtasks, as the caller holds them. The schedule never changes one.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [Plan a sprint for a team](#subtasks) and
|
|
2173
|
-
| `tasks` *required* | `readonly ``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), [Colour by what the task means](#subtasks), [Plan a sprint for a team](#subtasks) and
|
|
2314
|
+
| `data` *required* | `readonly ``Subtask``[]` | — | The subtasks, as the caller holds them. The schedule never changes one.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [Plan a sprint for a team](#subtasks) and 82 more |
|
|
2315
|
+
| `tasks` *required* | `readonly ``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), [Colour by what the task means](#subtasks), [Plan a sprint for a team](#subtasks) and 82 more |
|
|
2174
2316
|
|
|
2175
2317
|
##### `Subtask`
|
|
2176
2318
|
|
|
2177
2319
|
| Prop | Type | Default | Description |
|
|
2178
2320
|
|---|---|---|---|
|
|
2179
|
-
| `id` *required* | `string` | — | The caller's identity of the subtask.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [Plan a sprint for a team](#subtasks) and
|
|
2180
|
-
| `task` *required* | `string` | — | The id of the task it belongs to.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and
|
|
2181
|
-
| `lane` *required* | `string` | — | The id of the lane it sits on.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and
|
|
2182
|
-
| `from` *required* | `number` | — | Start of the main time.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and
|
|
2183
|
-
| `to` *required* | `number` | — | End of the main time.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and
|
|
2321
|
+
| `id` *required* | `string` | — | The caller's identity of the subtask.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [Plan a sprint for a team](#subtasks) and 79 more |
|
|
2322
|
+
| `task` *required* | `string` | — | The id of the task it belongs to.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and 75 more |
|
|
2323
|
+
| `lane` *required* | `string` | — | The id of the lane it sits on.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and 75 more |
|
|
2324
|
+
| `from` *required* | `number` | — | Start of the main time.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and 75 more |
|
|
2325
|
+
| `to` *required* | `number` | — | End of the main time.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and 75 more |
|
|
2184
2326
|
| `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), [The smallest schedule (Installation)](#installation), [A day of tours (First schedule)](#first-schedule) and 25 more |
|
|
2185
2327
|
| `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), [The smallest schedule (Installation)](#installation), [A day of tours (First schedule)](#first-schedule) and 22 more |
|
|
2186
2328
|
| `name` | `string` | — | What the subtask is called, where the schedule names it.<br>Shown in: [Plan a sprint for a team](#subtasks), [Write into the bars (Bar labels)](#bar-labels), [Join the stops of a tour (Dependencies)](#dependencies) and 28 more |
|
|
@@ -2191,9 +2333,9 @@ The keys of [First schedule](#first-schedule) apply here.
|
|
|
2191
2333
|
|
|
2192
2334
|
| Prop | Type | Default | Description |
|
|
2193
2335
|
|---|---|---|---|
|
|
2194
|
-
| `id` *required* | `string` | — | The caller's identity of the task.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and
|
|
2195
|
-
| `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), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and
|
|
2196
|
-
| `name` | `string` | — | What the task is called, where the schedule names it.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and
|
|
2336
|
+
| `id` *required* | `string` | — | The caller's identity of the task.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and 74 more |
|
|
2337
|
+
| `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), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and 74 more |
|
|
2338
|
+
| `name` | `string` | — | What the task is called, where the schedule names it.<br>Shown in: [Main time, lead-in and lead-out](#subtasks), [Colour by what the task means](#subtasks), [The smallest schedule (Installation)](#installation) and 74 more |
|
|
2197
2339
|
|
|
2198
2340
|
##### Types on this page
|
|
2199
2341
|
|
|
@@ -2256,7 +2398,7 @@ export default function BarLabels() {
|
|
|
2256
2398
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: DAY } });
|
|
2257
2399
|
return (
|
|
2258
2400
|
<Schedule
|
|
2259
|
-
|
|
2401
|
+
aria-label="Tuesday, 17 March, with the work items written in"
|
|
2260
2402
|
height={196}
|
|
2261
2403
|
label={(subtask) => subtask.name ?? subtask.id}
|
|
2262
2404
|
>
|
|
@@ -2279,16 +2421,10 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
2279
2421
|
|
|
2280
2422
|
| Prop | Type | Default | Description |
|
|
2281
2423
|
|---|---|---|---|
|
|
2282
|
-
| [`height`](#first-schedule) | `number` |
|
|
2424
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
2283
2425
|
| [`label`](#first-schedule) | `(subtask: `[`Subtask`](#subtasks)`) => 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. |
|
|
2284
2426
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
2285
2427
|
|
|
2286
|
-
###### Accessibility
|
|
2287
|
-
|
|
2288
|
-
| Prop | Type | Default | Description |
|
|
2289
|
-
|---|---|---|---|
|
|
2290
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
2291
|
-
|
|
2292
2428
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
2293
2429
|
|
|
2294
2430
|
| Prop | Type | Default | Description |
|
|
@@ -2371,7 +2507,7 @@ const WORK: Subtask[] = [
|
|
|
2371
2507
|
export default function Provisional() {
|
|
2372
2508
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(6, 30), at(11)] } });
|
|
2373
2509
|
return (
|
|
2374
|
-
<Schedule
|
|
2510
|
+
<Schedule aria-label="Agreed work above, provisional work below" height={144}>
|
|
2375
2511
|
<Lane id="released" label="Agreed, with lead-in" />
|
|
2376
2512
|
<Lane id="draft" label="Provisional" />
|
|
2377
2513
|
<Subtasks data={WORK} tasks={PROJECTS} />
|
|
@@ -2401,7 +2537,7 @@ export default function Fixed() {
|
|
|
2401
2537
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(6, 30), at(11)] } });
|
|
2402
2538
|
return (
|
|
2403
2539
|
<Schedule
|
|
2404
|
-
|
|
2540
|
+
aria-label="A round that may move above, a booked slot below"
|
|
2405
2541
|
height={144}
|
|
2406
2542
|
label={(leg) => (leg.id === "nailed" ? "T-05 · booked slot" : "T-05")}
|
|
2407
2543
|
>
|
|
@@ -2435,7 +2571,7 @@ export default function Muted() {
|
|
|
2435
2571
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(6, 30), at(11)] } });
|
|
2436
2572
|
return (
|
|
2437
2573
|
<Schedule
|
|
2438
|
-
|
|
2574
|
+
aria-label="Our team's work above, another team's below"
|
|
2439
2575
|
height={144}
|
|
2440
2576
|
label={() => "Checkout migration"}
|
|
2441
2577
|
>
|
|
@@ -2468,7 +2604,7 @@ const WORK: Subtask[] = [
|
|
|
2468
2604
|
export default function Progress() {
|
|
2469
2605
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(6, 30), at(11)] } });
|
|
2470
2606
|
return (
|
|
2471
|
-
<Schedule
|
|
2607
|
+
<Schedule aria-label="Work claiming nothing above, work at 65 per cent below" height={144}>
|
|
2472
2608
|
<Lane id="unclaimed" label="Says nothing" />
|
|
2473
2609
|
<Lane id="started" label="65 per cent done" />
|
|
2474
2610
|
<Subtasks data={WORK} tasks={PROJECTS} />
|
|
@@ -2501,7 +2637,7 @@ const WORK: Subtask[] = [
|
|
|
2501
2637
|
export default function Open() {
|
|
2502
2638
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(6, 30), at(11)] } });
|
|
2503
2639
|
return (
|
|
2504
|
-
<Schedule
|
|
2640
|
+
<Schedule aria-label="Work running past the view at either edge" height={188}>
|
|
2505
2641
|
<Lane id="runs-on" label="Runs on" />
|
|
2506
2642
|
<Lane id="whole" label="Wholly in view" />
|
|
2507
2643
|
<Lane id="began" label="Began before" />
|
|
@@ -2567,7 +2703,7 @@ export default function Combinations() {
|
|
|
2567
2703
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(6, 30), at(11)] } });
|
|
2568
2704
|
return (
|
|
2569
2705
|
<Schedule
|
|
2570
|
-
|
|
2706
|
+
aria-label="Bars carrying several appearances at once"
|
|
2571
2707
|
height={230}
|
|
2572
2708
|
label={(leg) => NAMES[leg.id] ?? leg.id}
|
|
2573
2709
|
>
|
|
@@ -2590,16 +2726,10 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
2590
2726
|
|
|
2591
2727
|
| Prop | Type | Default | Description |
|
|
2592
2728
|
|---|---|---|---|
|
|
2593
|
-
| [`height`](#first-schedule) | `number` |
|
|
2729
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
2594
2730
|
| [`label`](#first-schedule) | `(subtask: `[`Subtask`](#subtasks)`) => 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. |
|
|
2595
2731
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
2596
2732
|
|
|
2597
|
-
###### Accessibility
|
|
2598
|
-
|
|
2599
|
-
| Prop | Type | Default | Description |
|
|
2600
|
-
|---|---|---|---|
|
|
2601
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
2602
|
-
|
|
2603
2733
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
2604
2734
|
|
|
2605
2735
|
| Prop | Type | Default | Description |
|
|
@@ -2684,7 +2814,7 @@ const WORK: Subtask[] = [
|
|
|
2684
2814
|
export default function DoubleBooking() {
|
|
2685
2815
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(8), at(16)] } });
|
|
2686
2816
|
return (
|
|
2687
|
-
<Schedule
|
|
2817
|
+
<Schedule aria-label="Kofi booked on two projects at once" height={150}>
|
|
2688
2818
|
<Lane id="kofi" label="Kofi Mensah" />
|
|
2689
2819
|
<Lane id="hana" label="Hana Sato" />
|
|
2690
2820
|
<Subtasks data={WORK} tasks={PROJECTS} />
|
|
@@ -2717,7 +2847,7 @@ const LEGS: Subtask[] = [
|
|
|
2717
2847
|
export default function LeadOutMeetsLeadIn() {
|
|
2718
2848
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(6, 30), at(11, 30)] } });
|
|
2719
2849
|
return (
|
|
2720
|
-
<Schedule
|
|
2850
|
+
<Schedule aria-label="Two rounds of one van, touching at unloading and loading" height={110}>
|
|
2721
2851
|
<Lane id="fp-402" label="Van FP 402 R" />
|
|
2722
2852
|
<Subtasks data={LEGS} tasks={TOURS} />
|
|
2723
2853
|
</Schedule>
|
|
@@ -2751,7 +2881,7 @@ const WORK: Subtask[] = [
|
|
|
2751
2881
|
export default function ThreeAtOnce() {
|
|
2752
2882
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(7), at(14)] } });
|
|
2753
2883
|
return (
|
|
2754
|
-
<Schedule
|
|
2884
|
+
<Schedule aria-label="Priya on three incidents at once" height={150}>
|
|
2755
2885
|
<Lane id="priya" label="Priya Raman" />
|
|
2756
2886
|
<Lane id="jonas" label="Jonas Keller" />
|
|
2757
2887
|
<Subtasks data={WORK} tasks={INCIDENTS} />
|
|
@@ -2774,15 +2904,9 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
2774
2904
|
|
|
2775
2905
|
| Prop | Type | Default | Description |
|
|
2776
2906
|
|---|---|---|---|
|
|
2777
|
-
| [`height`](#first-schedule) | `number` |
|
|
2907
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
2778
2908
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
2779
2909
|
|
|
2780
|
-
###### Accessibility
|
|
2781
|
-
|
|
2782
|
-
| Prop | Type | Default | Description |
|
|
2783
|
-
|---|---|---|---|
|
|
2784
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
2785
|
-
|
|
2786
2910
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
2787
2911
|
|
|
2788
2912
|
| Prop | Type | Default | Description |
|
|
@@ -2833,7 +2957,7 @@ From `ScheduleView` — the full table stands on [View](#view).
|
|
|
2833
2957
|
|
|
2834
2958
|
- No stacked layout on request yet: an overlap is always drawn offset, as the finding it is.
|
|
2835
2959
|
|
|
2836
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
2960
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
|
|
2837
2961
|
|
|
2838
2962
|
### Dependencies
|
|
2839
2963
|
|
|
@@ -2882,7 +3006,7 @@ const DRIVES: Dependency[] = [
|
|
|
2882
3006
|
export default function StopsOfATour() {
|
|
2883
3007
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(7), at(10)] } });
|
|
2884
3008
|
return (
|
|
2885
|
-
<Schedule
|
|
3009
|
+
<Schedule aria-label="Two morning tours with their stops" height={150}>
|
|
2886
3010
|
<Lane id="fp-214" label="Van FP 214 K" />
|
|
2887
3011
|
<Lane id="fp-377" label="E-van FP 377 K" />
|
|
2888
3012
|
<Dependencies data={DRIVES} />
|
|
@@ -2926,7 +3050,7 @@ const HANDOVERS: Dependency[] = [
|
|
|
2926
3050
|
export default function Anchors() {
|
|
2927
3051
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(6, 30), at(16, 30)] } });
|
|
2928
3052
|
return (
|
|
2929
|
-
<Schedule
|
|
3053
|
+
<Schedule aria-label="Two handovers with different anchors" height={150}>
|
|
2930
3054
|
<Lane id="truck" label="Truck FP 520 E" />
|
|
2931
3055
|
<Lane id="van" label="Van FP 290 E" />
|
|
2932
3056
|
<Dependencies data={HANDOVERS} />
|
|
@@ -2974,7 +3098,7 @@ function Variant({ attach }: { attach: DependencyAttachment }) {
|
|
|
2974
3098
|
<Text size="xs" tone="muted" mono>
|
|
2975
3099
|
attach="{attach}"
|
|
2976
3100
|
</Text>
|
|
2977
|
-
<Schedule
|
|
3101
|
+
<Schedule aria-label={`A release through three engineers, lines from the ${attach}`} height={188} attach={attach}>
|
|
2978
3102
|
<Lane id="priya" label="Priya Raman" />
|
|
2979
3103
|
<Lane id="ada" label="Ada Mwangi" />
|
|
2980
3104
|
<Lane id="sam" label="Sam Okafor" />
|
|
@@ -3030,7 +3154,7 @@ function Variant({ ends }: { ends: DependencyEnds }) {
|
|
|
3030
3154
|
<Text size="xs" tone="muted" mono>
|
|
3031
3155
|
ends="{ends}"
|
|
3032
3156
|
</Text>
|
|
3033
|
-
<Schedule
|
|
3157
|
+
<Schedule aria-label={`Design, build and test, ends ${ends}`} height={188} attach="nearest" ends={ends}>
|
|
3034
3158
|
<Lane id="noah" label="Noah Fischer" />
|
|
3035
3159
|
<Lane id="arjun" label="Arjun Mehta" />
|
|
3036
3160
|
<Lane id="eva" label="Eva Novak" />
|
|
@@ -3077,7 +3201,7 @@ const HANDOVERS: Dependency[] = [{ id: "transfer", from: "line-haul", to: "round
|
|
|
3077
3201
|
export default function ViolatedDependency() {
|
|
3078
3202
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(6, 30), at(11)] } });
|
|
3079
3203
|
return (
|
|
3080
|
-
<Schedule
|
|
3204
|
+
<Schedule aria-label="A handover from the truck to the van that is too short" height={150}>
|
|
3081
3205
|
<Lane id="truck" label="Truck FP 118 R" />
|
|
3082
3206
|
<Lane id="van" label="Van FP 214 K" />
|
|
3083
3207
|
<Dependencies data={HANDOVERS} />
|
|
@@ -3120,7 +3244,7 @@ const HANDOVERS: Dependency[] = [
|
|
|
3120
3244
|
export default function OneHandoverDrawnItsOwnWay() {
|
|
3121
3245
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(6, 30), at(12, 30)] } });
|
|
3122
3246
|
return (
|
|
3123
|
-
<Schedule
|
|
3247
|
+
<Schedule aria-label="Design, build, test and a sign-off drawn its own way" height={188} attach="nearest" ends="none">
|
|
3124
3248
|
<Lane id="noah" label="Noah Fischer" />
|
|
3125
3249
|
<Lane id="arjun" label="Arjun Mehta" />
|
|
3126
3250
|
<Lane id="eva" label="Eva Novak" />
|
|
@@ -3203,9 +3327,9 @@ type DependencyEnds = "dot" | "none";
|
|
|
3203
3327
|
|
|
3204
3328
|
#### Known limits
|
|
3205
3329
|
|
|
3206
|
-
- Only finish-to-start within one task; no dependency types and no critical path ([ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
3330
|
+
- Only finish-to-start within one task; no dependency types and no critical path ([ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md)).
|
|
3207
3331
|
|
|
3208
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
3332
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
|
|
3209
3333
|
|
|
3210
3334
|
### Routes
|
|
3211
3335
|
|
|
@@ -3246,7 +3370,7 @@ const HANDOVERS: Dependency[] = [
|
|
|
3246
3370
|
export default function Curve() {
|
|
3247
3371
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(6, 30), at(13, 30)] } });
|
|
3248
3372
|
return (
|
|
3249
|
-
<Schedule
|
|
3373
|
+
<Schedule aria-label="Search results, from layout to polish, curved lines" height={188}>
|
|
3250
3374
|
<Lane id="noah" label="Noah Fischer" />
|
|
3251
3375
|
<Lane id="chloe" label="Chloe Durand" />
|
|
3252
3376
|
<Lane id="eva" label="Eva Novak" />
|
|
@@ -3286,7 +3410,7 @@ const HANDOVERS: Dependency[] = [
|
|
|
3286
3410
|
export default function Straight() {
|
|
3287
3411
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(6, 30), at(13, 30)] } });
|
|
3288
3412
|
return (
|
|
3289
|
-
<Schedule
|
|
3413
|
+
<Schedule aria-label="Search results, from layout to polish, straight lines" height={188} route="straight" attach="nearest">
|
|
3290
3414
|
<Lane id="noah" label="Noah Fischer" />
|
|
3291
3415
|
<Lane id="chloe" label="Chloe Durand" />
|
|
3292
3416
|
<Lane id="eva" label="Eva Novak" />
|
|
@@ -3326,7 +3450,7 @@ const HANDOVERS: Dependency[] = [
|
|
|
3326
3450
|
export default function Orthogonal() {
|
|
3327
3451
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(6, 30), at(13, 30)] } });
|
|
3328
3452
|
return (
|
|
3329
|
-
<Schedule
|
|
3453
|
+
<Schedule aria-label="Search results, from layout to polish, orthogonal lines" height={188} route="orthogonal" attach="nearest">
|
|
3330
3454
|
<Lane id="noah" label="Noah Fischer" />
|
|
3331
3455
|
<Lane id="chloe" label="Chloe Durand" />
|
|
3332
3456
|
<Lane id="eva" label="Eva Novak" />
|
|
@@ -3367,7 +3491,7 @@ const HANDOVERS: Dependency[] = [
|
|
|
3367
3491
|
export default function PerDependency() {
|
|
3368
3492
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(6, 30), at(13, 30)] } });
|
|
3369
3493
|
return (
|
|
3370
|
-
<Schedule
|
|
3494
|
+
<Schedule aria-label="Search results, from layout to polish, straight lines but one" height={188} route="straight" attach="nearest">
|
|
3371
3495
|
<Lane id="noah" label="Noah Fischer" />
|
|
3372
3496
|
<Lane id="chloe" label="Chloe Durand" />
|
|
3373
3497
|
<Lane id="eva" label="Eva Novak" />
|
|
@@ -3388,17 +3512,11 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
3388
3512
|
|
|
3389
3513
|
| Prop | Type | Default | Description |
|
|
3390
3514
|
|---|---|---|---|
|
|
3391
|
-
| [`height`](#first-schedule) | `number` |
|
|
3515
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
3392
3516
|
| [`route`](#first-schedule) | [`DependencyRoute`](#first-schedule)<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. |
|
|
3393
3517
|
| [`attach`](#first-schedule) | [`DependencyAttachment`](#first-schedule)<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. |
|
|
3394
3518
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
3395
3519
|
|
|
3396
|
-
###### Accessibility
|
|
3397
|
-
|
|
3398
|
-
| Prop | Type | Default | Description |
|
|
3399
|
-
|---|---|---|---|
|
|
3400
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
3401
|
-
|
|
3402
3520
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
3403
3521
|
|
|
3404
3522
|
| Prop | Type | Default | Description |
|
|
@@ -3538,7 +3656,7 @@ const WEEK: readonly [number, number] = [new Date(2026, 2, 16).getTime(), new Da
|
|
|
3538
3656
|
export default function AWeek() {
|
|
3539
3657
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: WEEK } });
|
|
3540
3658
|
return (
|
|
3541
|
-
<Schedule
|
|
3659
|
+
<Schedule aria-label="On-call rota, 16 to 23 March" height={420}>
|
|
3542
3660
|
{ENGINEERS.map((engineer) => (
|
|
3543
3661
|
<Lane key={engineer.id} id={engineer.id} label={engineer.name} />
|
|
3544
3662
|
))}
|
|
@@ -3582,7 +3700,7 @@ export default function WorkingCalendar() {
|
|
|
3582
3700
|
const [legs, setLegs] = useState<readonly Subtask[]>(LEGS);
|
|
3583
3701
|
return (
|
|
3584
3702
|
<Schedule
|
|
3585
|
-
|
|
3703
|
+
aria-label="Three days at East Gate depot, nights removed"
|
|
3586
3704
|
calendar={OPENING_HOURS}
|
|
3587
3705
|
height={220}
|
|
3588
3706
|
intents={["move"]}
|
|
@@ -3693,7 +3811,7 @@ export default function OfficeHours() {
|
|
|
3693
3811
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(9, 9), at(20, 17)] } });
|
|
3694
3812
|
return (
|
|
3695
3813
|
<Schedule
|
|
3696
|
-
|
|
3814
|
+
aria-label="Sprint 14 of the web team, office hours only"
|
|
3697
3815
|
calendar={OFFICE_HOURS}
|
|
3698
3816
|
height={280}
|
|
3699
3817
|
label={(item) => item.name ?? item.id}
|
|
@@ -3721,7 +3839,7 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
3721
3839
|
|
|
3722
3840
|
| Prop | Type | Default | Description |
|
|
3723
3841
|
|---|---|---|---|
|
|
3724
|
-
| [`height`](#first-schedule) | `number` |
|
|
3842
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
3725
3843
|
| [`calendar`](#first-schedule) | [`CalendarInput`](#first-schedule) | `[]` | 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. |
|
|
3726
3844
|
| [`intents`](#first-schedule) | `readonly `[`IntentKind`](#first-schedule)`[]` | `[]` | 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)). |
|
|
3727
3845
|
| [`label`](#first-schedule) | `(subtask: `[`Subtask`](#subtasks)`) => 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. |
|
|
@@ -3733,12 +3851,6 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
3733
3851
|
|---|---|---|---|
|
|
3734
3852
|
| [`onIntent`](#first-schedule) | `(intent: `[`Intent`](#first-schedule)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
3735
3853
|
|
|
3736
|
-
###### Accessibility
|
|
3737
|
-
|
|
3738
|
-
| Prop | Type | Default | Description |
|
|
3739
|
-
|---|---|---|---|
|
|
3740
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
3741
|
-
|
|
3742
3854
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
3743
3855
|
|
|
3744
3856
|
| Prop | Type | Default | Description |
|
|
@@ -3870,7 +3982,7 @@ export default function Leave() {
|
|
|
3870
3982
|
|
|
3871
3983
|
return (
|
|
3872
3984
|
<Stack gap={3}>
|
|
3873
|
-
<Schedule
|
|
3985
|
+
<Schedule aria-label="Team plan, week of 16 March" height={240}>
|
|
3874
3986
|
{PEOPLE.map((person) => (
|
|
3875
3987
|
<Lane key={person.id} id={person.id} label={person.label} />
|
|
3876
3988
|
))}
|
|
@@ -3936,7 +4048,7 @@ export default function DragAround() {
|
|
|
3936
4048
|
return (
|
|
3937
4049
|
<Stack gap={3}>
|
|
3938
4050
|
<Schedule
|
|
3939
|
-
|
|
4051
|
+
aria-label="Two people, one on leave"
|
|
3940
4052
|
height={150}
|
|
3941
4053
|
intents={["move", "lane"]}
|
|
3942
4054
|
onIntent={onIntent}
|
|
@@ -4071,7 +4183,7 @@ export default function TeamLeave() {
|
|
|
4071
4183
|
const clashes = findings(WORK, [], BLOCKED).inBlockedTime;
|
|
4072
4184
|
return (
|
|
4073
4185
|
<Stack gap={3}>
|
|
4074
|
-
<Schedule
|
|
4186
|
+
<Schedule aria-label="Sprint 14 with the team's leave" height={500}>
|
|
4075
4187
|
{PEOPLE.map((person) => (
|
|
4076
4188
|
<Lane key={person.id} id={person.id} label={person.name} />
|
|
4077
4189
|
))}
|
|
@@ -4171,7 +4283,7 @@ export default function HandoversAndReleases() {
|
|
|
4171
4283
|
const { Schedule, Lane, Subtasks, Milestones } = useSchedule({ initialView: { domain: [day(0, 6), day(5, 0)] } });
|
|
4172
4284
|
return (
|
|
4173
4285
|
<Stack gap={3}>
|
|
4174
|
-
<Schedule
|
|
4286
|
+
<Schedule aria-label="Portal and billing plan, week of 16 March" height={188}>
|
|
4175
4287
|
<Lane id="anna" label="Anna Berg" />
|
|
4176
4288
|
<Lane id="ben" label="Ben Ortiz" />
|
|
4177
4289
|
<Lane id="chloe" label="Chloe Lind" />
|
|
@@ -4223,7 +4335,7 @@ function Own({ target }: { target: ScheduleTooltipTarget }) {
|
|
|
4223
4335
|
export default function SayWhatAMilestoneIs() {
|
|
4224
4336
|
const { Schedule, Lane, Subtasks, Milestones } = useSchedule({ initialView: { domain: [at(6, 30), at(15, 30)] } });
|
|
4225
4337
|
return (
|
|
4226
|
-
<Schedule
|
|
4338
|
+
<Schedule aria-label="Build and test around the code freeze" height={150} tooltip={(target) => <Own target={target} />}>
|
|
4227
4339
|
<Lane id="arjun" label="Arjun Mehta" />
|
|
4228
4340
|
<Lane id="eva" label="Eva Novak" />
|
|
4229
4341
|
<Subtasks data={WORK} tasks={PROJECTS} />
|
|
@@ -4422,7 +4534,7 @@ const ROUNDS: Subtask[] = TOURS.map((tour) => ({
|
|
|
4422
4534
|
export default function NowLine() {
|
|
4423
4535
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(5, 30), at(18)] } });
|
|
4424
4536
|
return (
|
|
4425
|
-
<Schedule
|
|
4537
|
+
<Schedule aria-label="Today's tours, with the present" height={420} now={NOW}>
|
|
4426
4538
|
{VEHICLES.map((vehicle) => (
|
|
4427
4539
|
<Lane key={vehicle.id} id={vehicle.id} label={vehicle.plate} />
|
|
4428
4540
|
))}
|
|
@@ -4462,7 +4574,7 @@ const DUTIES: Subtask[] = [
|
|
|
4462
4574
|
export default function FollowTheClock() {
|
|
4463
4575
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [current - 6 * HOUR, current + 6 * HOUR] } });
|
|
4464
4576
|
return (
|
|
4465
|
-
<Schedule
|
|
4577
|
+
<Schedule aria-label="Today's on-call rota, with the present" height={188} now>
|
|
4466
4578
|
<Lane id="ada" label="Ada Mwangi" />
|
|
4467
4579
|
<Lane id="tomasz" label="Tomasz Nowak" />
|
|
4468
4580
|
<Lane id="leila" label="Leila Haddad" />
|
|
@@ -4482,16 +4594,10 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
4482
4594
|
|
|
4483
4595
|
| Prop | Type | Default | Description |
|
|
4484
4596
|
|---|---|---|---|
|
|
4485
|
-
| [`height`](#first-schedule) | `number` |
|
|
4597
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
4486
4598
|
| [`now`](#first-schedule) | `boolean \| number` | `false` | A line marking the present across the lanes: `true` follows the clock by the minute, an instant fixes it there. |
|
|
4487
4599
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
4488
4600
|
|
|
4489
|
-
###### Accessibility
|
|
4490
|
-
|
|
4491
|
-
| Prop | Type | Default | Description |
|
|
4492
|
-
|---|---|---|---|
|
|
4493
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
4494
|
-
|
|
4495
4601
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
4496
4602
|
|
|
4497
4603
|
| Prop | Type | Default | Description |
|
|
@@ -4587,7 +4693,7 @@ export default function PanAndZoom() {
|
|
|
4587
4693
|
const { Schedule, Lane, Subtasks } = useSchedule({ initialView: { domain: [at(5, 30), at(18)] } });
|
|
4588
4694
|
return (
|
|
4589
4695
|
<Schedule
|
|
4590
|
-
|
|
4696
|
+
aria-label="A plan to pan and zoom"
|
|
4591
4697
|
height={196}
|
|
4592
4698
|
zoomLimits={{ min: 2 * HOUR, max: 48 * HOUR }}
|
|
4593
4699
|
>
|
|
@@ -4615,16 +4721,10 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
4615
4721
|
|
|
4616
4722
|
| Prop | Type | Default | Description |
|
|
4617
4723
|
|---|---|---|---|
|
|
4618
|
-
| [`height`](#first-schedule) | `number` |
|
|
4724
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
4619
4725
|
| [`zoomLimits`](#first-schedule) | [`ZoomLimits`](#first-schedule) | one hour to 28 days | The narrowest and widest time span zoom may reach, in milliseconds. |
|
|
4620
4726
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
4621
4727
|
|
|
4622
|
-
###### Accessibility
|
|
4623
|
-
|
|
4624
|
-
| Prop | Type | Default | Description |
|
|
4625
|
-
|---|---|---|---|
|
|
4626
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
4627
|
-
|
|
4628
4728
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
4629
4729
|
|
|
4630
4730
|
| Prop | Type | Default | Description |
|
|
@@ -4723,7 +4823,7 @@ const TRANSFERS: readonly Dependency[] = [
|
|
|
4723
4823
|
export default function SelectATask() {
|
|
4724
4824
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(5, 30), at(13, 30)] } });
|
|
4725
4825
|
return (
|
|
4726
|
-
<Schedule
|
|
4826
|
+
<Schedule aria-label="Two consignments at North depot" height={140}>
|
|
4727
4827
|
<Lane id="truck-118" label="Truck FP 118 R" />
|
|
4728
4828
|
<Lane id="van-214" label="Van FP 214 K" />
|
|
4729
4829
|
<Dependencies data={TRANSFERS} />
|
|
@@ -4787,7 +4887,7 @@ export default function ControlTheSelection() {
|
|
|
4787
4887
|
return (
|
|
4788
4888
|
<Stack gap={3}>
|
|
4789
4889
|
<Schedule
|
|
4790
|
-
|
|
4890
|
+
aria-label="Legs at North depot on Tuesday, 17 March"
|
|
4791
4891
|
height={284}
|
|
4792
4892
|
selectedTask={selected}
|
|
4793
4893
|
onSelectedTaskChange={(task, subtask) => {
|
|
@@ -4832,17 +4932,11 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
4832
4932
|
|
|
4833
4933
|
| Prop | Type | Default | Description |
|
|
4834
4934
|
|---|---|---|---|
|
|
4835
|
-
| [`height`](#first-schedule) | `number` |
|
|
4935
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
4836
4936
|
| [`selectedTask`](#first-schedule) | `string \| null` | — | The selected task, controlled. Leave it out and the schedule keeps the selection itself. |
|
|
4837
4937
|
| [`onSelectedTaskChange`](#first-schedule) | `(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. |
|
|
4838
4938
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
4839
4939
|
|
|
4840
|
-
###### Accessibility
|
|
4841
|
-
|
|
4842
|
-
| Prop | Type | Default | Description |
|
|
4843
|
-
|---|---|---|---|
|
|
4844
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
4845
|
-
|
|
4846
4940
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
4847
4941
|
|
|
4848
4942
|
| Prop | Type | Default | Description |
|
|
@@ -4908,7 +5002,7 @@ From `ScheduleView` — the full table stands on [View](#view).
|
|
|
4908
5002
|
|
|
4909
5003
|
- One task at a time: there is no multiple selection.
|
|
4910
5004
|
|
|
4911
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
5005
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
|
|
4912
5006
|
|
|
4913
5007
|
### Interactions
|
|
4914
5008
|
|
|
@@ -4970,7 +5064,7 @@ export default function ReportThePointer() {
|
|
|
4970
5064
|
return (
|
|
4971
5065
|
<Stack gap={3}>
|
|
4972
5066
|
<Schedule
|
|
4973
|
-
|
|
5067
|
+
aria-label="One consignment on a truck and a van"
|
|
4974
5068
|
height={152}
|
|
4975
5069
|
onInteraction={(interaction) => setLast(describe(interaction))}
|
|
4976
5070
|
>
|
|
@@ -5070,7 +5164,7 @@ export default function OpenAContextMenu() {
|
|
|
5070
5164
|
return (
|
|
5071
5165
|
<>
|
|
5072
5166
|
<Schedule
|
|
5073
|
-
|
|
5167
|
+
aria-label="On-call rota, 16 to 23 March"
|
|
5074
5168
|
height={420}
|
|
5075
5169
|
onInteraction={onInteraction}
|
|
5076
5170
|
>
|
|
@@ -5085,7 +5179,7 @@ export default function OpenAContextMenu() {
|
|
|
5085
5179
|
onOpenChange={(open) => {
|
|
5086
5180
|
if (!open) setMenu(null);
|
|
5087
5181
|
}}
|
|
5088
|
-
|
|
5182
|
+
aria-label={menu !== null ? `Hand over ${menu.duty.id}` : "Hand over"}
|
|
5089
5183
|
>
|
|
5090
5184
|
{menu !== null &&
|
|
5091
5185
|
ENGINEERS.filter((engineer) => engineer.id !== menu.duty.lane).map((engineer) => (
|
|
@@ -5108,7 +5202,7 @@ export default function OpenAContextMenu() {
|
|
|
5108
5202
|
#### When to use something else
|
|
5109
5203
|
|
|
5110
5204
|
- You only need to know which task was picked → Selection
|
|
5111
|
-
- You need the time at a point outside an interaction →
|
|
5205
|
+
- You need the time at a point outside an interaction → Functions on the hook
|
|
5112
5206
|
|
|
5113
5207
|
#### Keyboard
|
|
5114
5208
|
|
|
@@ -5122,8 +5216,8 @@ The keys of [First schedule](#first-schedule) apply here.
|
|
|
5122
5216
|
|---|---|---|---|
|
|
5123
5217
|
| `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), [Open a context menu](#interactions), [Show a detail panel instead (Tooltip)](#tooltip) and 1 more |
|
|
5124
5218
|
| `hit` *required* | `ScheduleHit` | — | What the pointer is on.<br>Shown in: [Report what the pointer is on](#interactions), [Open a context menu](#interactions), [Show a detail panel instead (Tooltip)](#tooltip) and 2 more |
|
|
5125
|
-
| `clientX` *required* | `number` | — | The pointer's horizontal client coordinate - where a `ContextMenu` opens.<br>Shown in: [Open a context menu](#interactions), [Place a mark of your own (
|
|
5126
|
-
| `clientY` *required* | `number` | — | The pointer's vertical client coordinate.<br>Shown in: [Open a context menu](#interactions), [Place a mark of your own (
|
|
5219
|
+
| `clientX` *required* | `number` | — | The pointer's horizontal client coordinate - where a `ContextMenu` opens.<br>Shown in: [Open a context menu](#interactions), [Place a mark of your own (Functions on the hook)](#functions-on-the-hook), [Replan the day on the line (Scenarios)](#replan-the-day-on-the-line) |
|
|
5220
|
+
| `clientY` *required* | `number` | — | The pointer's vertical client coordinate.<br>Shown in: [Open a context menu](#interactions), [Place a mark of your own (Functions on the hook)](#functions-on-the-hook), [Replan the day on the line (Scenarios)](#replan-the-day-on-the-line) |
|
|
5127
5221
|
| `time` *required* | `number` | — | The wall-clock instant under the pointer.<br>Shown in: [Report what the pointer is on](#interactions) |
|
|
5128
5222
|
| `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) |
|
|
5129
5223
|
|
|
@@ -5195,7 +5289,7 @@ const TRANSFERS: readonly Dependency[] = [
|
|
|
5195
5289
|
export default function DefaultTooltip() {
|
|
5196
5290
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(5, 30), at(18)] } });
|
|
5197
5291
|
return (
|
|
5198
|
-
<Schedule
|
|
5292
|
+
<Schedule aria-label="Three vehicles with the default tooltip" height={196}>
|
|
5199
5293
|
{VEHICLES.map((vehicle) => (
|
|
5200
5294
|
<Lane key={vehicle.id} id={vehicle.id} label={vehicle.label} />
|
|
5201
5295
|
))}
|
|
@@ -5268,7 +5362,7 @@ export default function OwnTooltip() {
|
|
|
5268
5362
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(5, 30), at(18)] } });
|
|
5269
5363
|
return (
|
|
5270
5364
|
<Schedule
|
|
5271
|
-
|
|
5365
|
+
aria-label="Three vehicles with the load in the tooltip"
|
|
5272
5366
|
height={196}
|
|
5273
5367
|
tooltip={(target) => <LoadTooltip target={target} />}
|
|
5274
5368
|
>
|
|
@@ -5388,7 +5482,7 @@ export default function DetailPanelInstead() {
|
|
|
5388
5482
|
return (
|
|
5389
5483
|
<Stack gap={3}>
|
|
5390
5484
|
<Schedule
|
|
5391
|
-
|
|
5485
|
+
aria-label="Sprint 14 of the web team"
|
|
5392
5486
|
height={260}
|
|
5393
5487
|
tooltip={false}
|
|
5394
5488
|
onInteraction={onInteraction}
|
|
@@ -5488,7 +5582,7 @@ function Covers({ target }: { target: ScheduleTooltipTarget }) {
|
|
|
5488
5582
|
export default function SayWhatABarCoversAndALineJoins() {
|
|
5489
5583
|
const { Schedule, Lane, Subtasks, Dependencies, BlockedTimes } = useSchedule({ initialView: { domain: [at(6, 30), at(15, 30)] } });
|
|
5490
5584
|
return (
|
|
5491
|
-
<Schedule
|
|
5585
|
+
<Schedule aria-label="Design, build and test, with leave under the build" height={188} tooltip={(target) => <Covers target={target} />}>
|
|
5492
5586
|
<Lane id="noah" label="Noah Fischer" />
|
|
5493
5587
|
<Lane id="arjun" label="Arjun Mehta" />
|
|
5494
5588
|
<Lane id="eva" label="Eva Novak" />
|
|
@@ -5593,7 +5687,7 @@ export default function KeepAndRestore() {
|
|
|
5593
5687
|
|
|
5594
5688
|
return (
|
|
5595
5689
|
<Stack gap={3}>
|
|
5596
|
-
<Schedule
|
|
5690
|
+
<Schedule aria-label="Two teams on Tuesday, 17 March" height={290}>
|
|
5597
5691
|
<LaneGroup id="product" label="Product">
|
|
5598
5692
|
<Lane id="noah" label="Noah Fischer" />
|
|
5599
5693
|
<Lane id="arjun" label="Arjun Mehta" />
|
|
@@ -5650,7 +5744,7 @@ The keys of [First schedule](#first-schedule) apply here.
|
|
|
5650
5744
|
|
|
5651
5745
|
| Prop | Type | Default | Description |
|
|
5652
5746
|
|---|---|---|---|
|
|
5653
|
-
| `initialView` | `ScheduleView` | — | The view to start from, read once when the hook first runs; a different value on a later render is ignored, as React ignores a changed `defaultValue`. To go to a view later, call `setView`. The schedule remembers none: where a view is kept is the application's decision.<br>Shown in: [Keep and restore a view](#view), [The smallest schedule (Installation)](#installation), [A day of tours (First schedule)](#first-schedule) and
|
|
5747
|
+
| `initialView` | `ScheduleView` | — | The view to start from, read once when the hook first runs; a different value on a later render is ignored, as React ignores a changed `defaultValue`. To go to a view later, call `setView`. The schedule remembers none: where a view is kept is the application's decision.<br>Shown in: [Keep and restore a view](#view), [The smallest schedule (Installation)](#installation), [A day of tours (First schedule)](#first-schedule) and 82 more |
|
|
5654
5748
|
|
|
5655
5749
|
###### Events
|
|
5656
5750
|
|
|
@@ -5662,7 +5756,7 @@ The keys of [First schedule](#first-schedule) apply here.
|
|
|
5662
5756
|
|
|
5663
5757
|
| Prop | Type | Default | Description |
|
|
5664
5758
|
|---|---|---|---|
|
|
5665
|
-
| `domain` | `readonly [number, number]` | — | The span in view, as two wall-clock instants. Absent, the schedule shows the extent of its subtasks, within `zoomLimits`.<br>Shown in: [Keep and restore a view](#view), [The smallest schedule (Installation)](#installation), [A day of tours (First schedule)](#first-schedule) and
|
|
5759
|
+
| `domain` | `readonly [number, number]` | — | The span in view, as two wall-clock instants. Absent, the schedule shows the extent of its subtasks, within `zoomLimits`.<br>Shown in: [Keep and restore a view](#view), [The smallest schedule (Installation)](#installation), [A day of tours (First schedule)](#first-schedule) and 81 more |
|
|
5666
5760
|
| `folded` | `readonly string[]` | — | The **Lane group**s that are folded, by id. An id no group carries falls out. A folded outer group hides the inner ones without their ids leaving the list, so unfolding it gives back the view that was there.<br>Shown in: [Fold groups from outside (Lane groups)](#lane-groups), [Read a folded group (Lane groups)](#lane-groups), [Start with groups folded (Lane groups)](#lane-groups) |
|
|
5667
5761
|
|
|
5668
5762
|
### Linked schedules
|
|
@@ -5735,13 +5829,13 @@ export default function InStep() {
|
|
|
5735
5829
|
const span = diesel.view.domain ?? start.domain;
|
|
5736
5830
|
return (
|
|
5737
5831
|
<Stack gap={2}>
|
|
5738
|
-
<diesel.Schedule
|
|
5832
|
+
<diesel.Schedule aria-label="Diesel vehicles on Tuesday, 17 March" height={240}>
|
|
5739
5833
|
{DIESEL.map((vehicle) => (
|
|
5740
5834
|
<diesel.Lane key={vehicle.id} id={vehicle.id} label={vehicle.label} />
|
|
5741
5835
|
))}
|
|
5742
5836
|
<diesel.Subtasks data={DIESEL_LEGS} tasks={CONSIGNMENTS} />
|
|
5743
5837
|
</diesel.Schedule>
|
|
5744
|
-
<electric.Schedule
|
|
5838
|
+
<electric.Schedule aria-label="Electric vans, the same hours" height={152}>
|
|
5745
5839
|
{ELECTRIC.map((vehicle) => (
|
|
5746
5840
|
<electric.Lane key={vehicle.id} id={vehicle.id} label={vehicle.label} />
|
|
5747
5841
|
))}
|
|
@@ -5894,12 +5988,12 @@ export default function RotaBesideIncidents() {
|
|
|
5894
5988
|
const incidents: ScheduleParts = useSchedule({ initialView: start, onViewChange: (v) => rota.setView(v) });
|
|
5895
5989
|
return (
|
|
5896
5990
|
<Stack gap={2}>
|
|
5897
|
-
<rota.Schedule
|
|
5991
|
+
<rota.Schedule aria-label="Who was on call" height={140}>
|
|
5898
5992
|
<rota.Lane id="primary" label="Primary" />
|
|
5899
5993
|
<rota.Lane id="secondary" label="Secondary" />
|
|
5900
5994
|
<rota.Subtasks data={DUTIES} tasks={PEOPLE} />
|
|
5901
5995
|
</rota.Schedule>
|
|
5902
|
-
<incidents.Schedule
|
|
5996
|
+
<incidents.Schedule aria-label="Incidents, the same hours" height={290}>
|
|
5903
5997
|
{HIT.map((service) => (
|
|
5904
5998
|
<incidents.Lane key={service.id} id={service.id} label={service.name} />
|
|
5905
5999
|
))}
|
|
@@ -5924,15 +6018,9 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
5924
6018
|
|
|
5925
6019
|
| Prop | Type | Default | Description |
|
|
5926
6020
|
|---|---|---|---|
|
|
5927
|
-
| [`height`](#first-schedule) | `number` |
|
|
6021
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
5928
6022
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
5929
6023
|
|
|
5930
|
-
###### Accessibility
|
|
5931
|
-
|
|
5932
|
-
| Prop | Type | Default | Description |
|
|
5933
|
-
|---|---|---|---|
|
|
5934
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
5935
|
-
|
|
5936
6024
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
5937
6025
|
|
|
5938
6026
|
| Prop | Type | Default | Description |
|
|
@@ -5990,9 +6078,9 @@ From `ScheduleView` — the full table stands on [View](#view).
|
|
|
5990
6078
|
|
|
5991
6079
|
- Only the view is shared - the span and the folded groups, not the selection, the hover or the vertical scroll.
|
|
5992
6080
|
|
|
5993
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
6081
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
|
|
5994
6082
|
|
|
5995
|
-
###
|
|
6083
|
+
### Functions on the hook
|
|
5996
6084
|
|
|
5997
6085
|
Converts between a point on the screen and a time on a lane, so marks of your own - a cut-off, a delivery window, a pin - stand at the right place beside the plan.
|
|
5998
6086
|
|
|
@@ -6000,10 +6088,12 @@ Converts between a point on the screen and a time on a lane, so marks of your ow
|
|
|
6000
6088
|
import { useSchedule } from "@umriss-ui/schedule";
|
|
6001
6089
|
```
|
|
6002
6090
|
|
|
6003
|
-
|
|
6091
|
+
[`useSchedule`](#api-index-1) hands back three functions for what is on the screen: `clientPointOf(time, lane?)`, `positionAt(clientX, clientY)` and `visibleDomain()`. Before a schedule is mounted the first two answer `null`. The `ref` of `Schedule` is its root element.
|
|
6004
6092
|
|
|
6005
6093
|
Place your marks again whenever `view.domain` changes.
|
|
6006
6094
|
|
|
6095
|
+
`scrollToLane(lane)`, `scrollToSubtask(id)` and `focusSubtask(id)` show a lane or a subtask picked from a list of your own, a findings list or a search. `scrollToSubtask` brings the lane and the time into view and leaves the focus where it is; `focusSubtask` also makes the subtask the active one and focuses the plot. All three answer `false`, and change nothing, for an unknown lane or subtask, a lane inside a folded group (none is unfolded) and a schedule that is not mounted.
|
|
6096
|
+
|
|
6007
6097
|
#### Examples
|
|
6008
6098
|
|
|
6009
6099
|
##### Place a mark of your own
|
|
@@ -6014,7 +6104,7 @@ Place your marks again whenever `view.domain` changes.
|
|
|
6014
6104
|
import { useEffect, useRef, useState } from "react";
|
|
6015
6105
|
import { Stack, Text } from "@umriss-ui/core";
|
|
6016
6106
|
import { useSchedule } from "@umriss-ui/schedule";
|
|
6017
|
-
import type {
|
|
6107
|
+
import type { Subtask, Task } from "@umriss-ui/schedule";
|
|
6018
6108
|
|
|
6019
6109
|
const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
|
|
6020
6110
|
const min = (n: number) => n * 60_000;
|
|
@@ -6043,18 +6133,17 @@ const CUT_OFF = at(14);
|
|
|
6043
6133
|
const clock = (time: number) => new Date(time).toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" });
|
|
6044
6134
|
|
|
6045
6135
|
export default function PlaceAMark() {
|
|
6046
|
-
const { Schedule, Lane, Subtasks, view } = useSchedule({ initialView: { domain: [at(5, 30), at(18)] } });
|
|
6047
|
-
const plan = useRef<ScheduleHandle>(null);
|
|
6136
|
+
const { Schedule, Lane, Subtasks, view, clientPointOf, positionAt } = useSchedule({ initialView: { domain: [at(5, 30), at(18)] } });
|
|
6048
6137
|
const host = useRef<HTMLDivElement>(null);
|
|
6049
6138
|
const [pin, setPin] = useState<number | null>(null);
|
|
6050
6139
|
const [under, setUnder] = useState("Move the pointer over the plan");
|
|
6051
6140
|
|
|
6052
6141
|
/* The client point, turned into one inside this example - anew whenever the span moves. */
|
|
6053
6142
|
useEffect(() => {
|
|
6054
|
-
const point =
|
|
6143
|
+
const point = clientPointOf(CUT_OFF);
|
|
6055
6144
|
const left = host.current?.getBoundingClientRect().left;
|
|
6056
6145
|
setPin(point == null || left === undefined ? null : point.x - left);
|
|
6057
|
-
}, [view.domain]);
|
|
6146
|
+
}, [view.domain, clientPointOf]);
|
|
6058
6147
|
|
|
6059
6148
|
return (
|
|
6060
6149
|
<Stack gap={2}>
|
|
@@ -6066,13 +6155,12 @@ export default function PlaceAMark() {
|
|
|
6066
6155
|
)}
|
|
6067
6156
|
</div>
|
|
6068
6157
|
<Schedule
|
|
6069
|
-
|
|
6070
|
-
ariaLabel="Three vehicles with a cut-off of the application's own"
|
|
6158
|
+
aria-label="Three vehicles with a cut-off of the application's own"
|
|
6071
6159
|
height={196}
|
|
6072
6160
|
onInteraction={(interaction) => {
|
|
6073
6161
|
/* The interaction carries time and lane already; `positionAt` is for
|
|
6074
6162
|
listeners of your own, which have only a point. */
|
|
6075
|
-
const there =
|
|
6163
|
+
const there = positionAt(interaction.clientX, interaction.clientY);
|
|
6076
6164
|
setUnder(there == null ? "off the plan" : `${clock(there.time)} on ${there.lane ?? "no lane"}`);
|
|
6077
6165
|
}}
|
|
6078
6166
|
>
|
|
@@ -6089,6 +6177,69 @@ export default function PlaceAMark() {
|
|
|
6089
6177
|
}
|
|
6090
6178
|
```
|
|
6091
6179
|
|
|
6180
|
+
##### Show a finding
|
|
6181
|
+
|
|
6182
|
+
`scrollToSubtask` brings a subtask's lane and time into view and leaves the focus; `focusSubtask` also makes it the active subtask. Pick a finding, or press Enter on it.
|
|
6183
|
+
|
|
6184
|
+
```tsx
|
|
6185
|
+
import { Button, Stack, Text } from "@umriss-ui/core";
|
|
6186
|
+
import { useSchedule } from "@umriss-ui/schedule";
|
|
6187
|
+
import type { Subtask, Task } from "@umriss-ui/schedule";
|
|
6188
|
+
|
|
6189
|
+
const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
|
|
6190
|
+
|
|
6191
|
+
const STATIONS = Array.from({ length: 60 }, (_, i) => ({ id: `station-${i + 1}`, label: `Station ${String(i + 1).padStart(2, "0")}` }));
|
|
6192
|
+
|
|
6193
|
+
const ORDERS: readonly Task[] = [{ id: "order", name: "Order O-7731", color: "light-dark(#2563eb, #6b9bff)" }];
|
|
6194
|
+
|
|
6195
|
+
const STEPS: readonly Subtask[] = STATIONS.map((station, i) => ({
|
|
6196
|
+
id: `step-${i + 1}`,
|
|
6197
|
+
task: "order",
|
|
6198
|
+
lane: station.id,
|
|
6199
|
+
from: at(6 + (i % 10)),
|
|
6200
|
+
to: at(7 + (i % 10)),
|
|
6201
|
+
}));
|
|
6202
|
+
|
|
6203
|
+
const FINDINGS = [
|
|
6204
|
+
{ subtask: "step-4", text: "Station 04 starts before its material arrives" },
|
|
6205
|
+
{ subtask: "step-37", text: "Station 37 overlaps a shift break" },
|
|
6206
|
+
{ subtask: "step-58", text: "Station 58 ends after the cut-off" },
|
|
6207
|
+
];
|
|
6208
|
+
|
|
6209
|
+
export default function ShowAFinding() {
|
|
6210
|
+
const { Schedule, Lane, Subtasks, scrollToSubtask, focusSubtask } = useSchedule({ initialView: { domain: [at(5, 30), at(10)] } });
|
|
6211
|
+
return (
|
|
6212
|
+
<Stack gap={2}>
|
|
6213
|
+
<Stack gap={1} data-findings>
|
|
6214
|
+
{FINDINGS.map((finding) => (
|
|
6215
|
+
<Button
|
|
6216
|
+
key={finding.subtask}
|
|
6217
|
+
data-finding={finding.subtask}
|
|
6218
|
+
onClick={() => scrollToSubtask(finding.subtask)}
|
|
6219
|
+
onKeyDown={(event) => {
|
|
6220
|
+
if (event.key !== "Enter") return;
|
|
6221
|
+
event.preventDefault();
|
|
6222
|
+
focusSubtask(finding.subtask);
|
|
6223
|
+
}}
|
|
6224
|
+
>
|
|
6225
|
+
{finding.text}
|
|
6226
|
+
</Button>
|
|
6227
|
+
))}
|
|
6228
|
+
</Stack>
|
|
6229
|
+
<Schedule aria-label="Sixty stations of one order" height={240}>
|
|
6230
|
+
{STATIONS.map((station) => (
|
|
6231
|
+
<Lane key={station.id} id={station.id} label={station.label} />
|
|
6232
|
+
))}
|
|
6233
|
+
<Subtasks data={STEPS} tasks={ORDERS} />
|
|
6234
|
+
</Schedule>
|
|
6235
|
+
<Text size="sm" tone="muted">
|
|
6236
|
+
A click shows the subtask; Enter also moves the focus to the plot.
|
|
6237
|
+
</Text>
|
|
6238
|
+
</Stack>
|
|
6239
|
+
);
|
|
6240
|
+
}
|
|
6241
|
+
```
|
|
6242
|
+
|
|
6092
6243
|
#### When to use something else
|
|
6093
6244
|
|
|
6094
6245
|
- You need the time under the pointer during a hover or a click → Interactions
|
|
@@ -6103,8 +6254,7 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
6103
6254
|
|
|
6104
6255
|
| Prop | Type | Default | Description |
|
|
6105
6256
|
|---|---|---|---|
|
|
6106
|
-
| [`
|
|
6107
|
-
| [`height`](#first-schedule) | `number` | `400` | Height in CSS pixels, both bands included. The width is the host's. |
|
|
6257
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
6108
6258
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
6109
6259
|
|
|
6110
6260
|
###### Events
|
|
@@ -6113,12 +6263,6 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
6113
6263
|
|---|---|---|---|
|
|
6114
6264
|
| [`onInteraction`](#first-schedule) | `(interaction: `[`ScheduleInteraction`](#interactions)`) => 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. |
|
|
6115
6265
|
|
|
6116
|
-
###### Accessibility
|
|
6117
|
-
|
|
6118
|
-
| Prop | Type | Default | Description |
|
|
6119
|
-
|---|---|---|---|
|
|
6120
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
6121
|
-
|
|
6122
6266
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
6123
6267
|
|
|
6124
6268
|
| Prop | Type | Default | Description |
|
|
@@ -6223,7 +6367,7 @@ export default function ListTheFindings() {
|
|
|
6223
6367
|
|
|
6224
6368
|
return (
|
|
6225
6369
|
<Stack gap={3}>
|
|
6226
|
-
<Schedule
|
|
6370
|
+
<Schedule aria-label="Three people's week with its findings" height={184}>
|
|
6227
6371
|
<Lane id="noah" label="Noah Fischer" />
|
|
6228
6372
|
<Lane id="chloe" label="Chloe Durand" />
|
|
6229
6373
|
<Lane id="arjun" label="Arjun Mehta" />
|
|
@@ -6278,7 +6422,7 @@ export default function NothingToFix() {
|
|
|
6278
6422
|
|
|
6279
6423
|
return (
|
|
6280
6424
|
<Stack gap={3}>
|
|
6281
|
-
<Schedule
|
|
6425
|
+
<Schedule aria-label="Two developers' week, without findings" height={140}>
|
|
6282
6426
|
<Lane id="hana" label="Hana Sato" />
|
|
6283
6427
|
<Lane id="kofi" label="Kofi Mensah" />
|
|
6284
6428
|
<Subtasks data={WORK} tasks={PROJECTS} />
|
|
@@ -6335,7 +6479,7 @@ export default function CountPerKind() {
|
|
|
6335
6479
|
<Badge tone={doubleBooked > 0 ? "warning" : "success"}>{doubleBooked} double-booked</Badge>
|
|
6336
6480
|
<Badge tone={late > 0 ? "warning" : "success"}>{late} transfers too short</Badge>
|
|
6337
6481
|
</Stack>
|
|
6338
|
-
<Schedule
|
|
6482
|
+
<Schedule aria-label="The day's legs with their findings counted" height={196}>
|
|
6339
6483
|
{VEHICLES.map((vehicle) => (
|
|
6340
6484
|
<Lane key={vehicle.id} id={vehicle.id} label={vehicle.label} />
|
|
6341
6485
|
))}
|
|
@@ -6386,7 +6530,7 @@ The keys of [First schedule](#first-schedule) apply here.
|
|
|
6386
6530
|
|
|
6387
6531
|
- Overlapping work is marked, not packed into sub-lanes; stacked overlap is not built yet.
|
|
6388
6532
|
|
|
6389
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
6533
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
|
|
6390
6534
|
|
|
6391
6535
|
## Editing
|
|
6392
6536
|
|
|
@@ -6431,7 +6575,7 @@ export default function MoveInTime() {
|
|
|
6431
6575
|
const [work, setWork] = useState(START);
|
|
6432
6576
|
return (
|
|
6433
6577
|
<Schedule
|
|
6434
|
-
|
|
6578
|
+
aria-label="Two people's work this week"
|
|
6435
6579
|
height={140}
|
|
6436
6580
|
intents={["move"]}
|
|
6437
6581
|
onIntent={(intent) => setWork((current) => current.map((item) => applyIntent(item, intent)))}
|
|
@@ -6494,7 +6638,7 @@ export default function MoveToAnotherLane() {
|
|
|
6494
6638
|
return (
|
|
6495
6639
|
<Stack gap={3}>
|
|
6496
6640
|
<Schedule
|
|
6497
|
-
|
|
6641
|
+
aria-label="Five vehicles on Tuesday, 17 March, editable"
|
|
6498
6642
|
height={284}
|
|
6499
6643
|
intents={["move", "lane"]}
|
|
6500
6644
|
onIntent={(intent) => {
|
|
@@ -6634,7 +6778,7 @@ export default function RefuseADoubleBooking() {
|
|
|
6634
6778
|
return (
|
|
6635
6779
|
<Stack gap={3}>
|
|
6636
6780
|
<Schedule
|
|
6637
|
-
|
|
6781
|
+
aria-label="Sprint 14 of the web team, editable"
|
|
6638
6782
|
height={240}
|
|
6639
6783
|
intents={["move", "lane"]}
|
|
6640
6784
|
onIntent={onIntent}
|
|
@@ -6673,7 +6817,7 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
6673
6817
|
|
|
6674
6818
|
| Prop | Type | Default | Description |
|
|
6675
6819
|
|---|---|---|---|
|
|
6676
|
-
| [`height`](#first-schedule) | `number` |
|
|
6820
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
6677
6821
|
| [`intents`](#first-schedule) | `readonly `[`IntentKind`](#first-schedule)`[]` | `[]` | 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)). |
|
|
6678
6822
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
6679
6823
|
|
|
@@ -6683,12 +6827,6 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
6683
6827
|
|---|---|---|---|
|
|
6684
6828
|
| [`onIntent`](#first-schedule) | `(intent: `[`Intent`](#first-schedule)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
6685
6829
|
|
|
6686
|
-
###### Accessibility
|
|
6687
|
-
|
|
6688
|
-
| Prop | Type | Default | Description |
|
|
6689
|
-
|---|---|---|---|
|
|
6690
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
6691
|
-
|
|
6692
6830
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
6693
6831
|
|
|
6694
6832
|
| Prop | Type | Default | Description |
|
|
@@ -6761,10 +6899,10 @@ From `Overlap` — the full table stands on [Findings as data](#findings-as-data
|
|
|
6761
6899
|
|
|
6762
6900
|
#### Known limits
|
|
6763
6901
|
|
|
6764
|
-
- No undo: your application owns the data, and with it the history ([ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
6902
|
+
- No undo: your application owns the data, and with it the history ([ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md)).
|
|
6765
6903
|
- The keys move work in time only; a lane change needs the pointer.
|
|
6766
6904
|
|
|
6767
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
6905
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
|
|
6768
6906
|
|
|
6769
6907
|
### Stretch, lead-in, lead-out
|
|
6770
6908
|
|
|
@@ -6803,7 +6941,7 @@ export default function StretchTheMainTime() {
|
|
|
6803
6941
|
const [work, setWork] = useState(START);
|
|
6804
6942
|
return (
|
|
6805
6943
|
<Schedule
|
|
6806
|
-
|
|
6944
|
+
aria-label="Two estimates to adjust"
|
|
6807
6945
|
height={140}
|
|
6808
6946
|
intents={["stretch"]}
|
|
6809
6947
|
onIntent={(intent) => setWork((current) => current.map((item) => applyIntent(item, intent)))}
|
|
@@ -6842,7 +6980,7 @@ export default function ChangeLeadInAndLeadOut() {
|
|
|
6842
6980
|
|
|
6843
6981
|
return (
|
|
6844
6982
|
<Schedule
|
|
6845
|
-
|
|
6983
|
+
aria-label="Two tours from North depot"
|
|
6846
6984
|
height={150}
|
|
6847
6985
|
intents={["stretch", "leadIn", "leadOut"]}
|
|
6848
6986
|
onIntent={(intent) => setTours((current) => current.map((tour) => applyIntent(tour, intent)))}
|
|
@@ -6869,7 +7007,7 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
6869
7007
|
|
|
6870
7008
|
| Prop | Type | Default | Description |
|
|
6871
7009
|
|---|---|---|---|
|
|
6872
|
-
| [`height`](#first-schedule) | `number` |
|
|
7010
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
6873
7011
|
| [`intents`](#first-schedule) | `readonly `[`IntentKind`](#first-schedule)`[]` | `[]` | 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)). |
|
|
6874
7012
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
6875
7013
|
|
|
@@ -6879,12 +7017,6 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
6879
7017
|
|---|---|---|---|
|
|
6880
7018
|
| [`onIntent`](#first-schedule) | `(intent: `[`Intent`](#first-schedule)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
6881
7019
|
|
|
6882
|
-
###### Accessibility
|
|
6883
|
-
|
|
6884
|
-
| Prop | Type | Default | Description |
|
|
6885
|
-
|---|---|---|---|
|
|
6886
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
6887
|
-
|
|
6888
7020
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
6889
7021
|
|
|
6890
7022
|
| Prop | Type | Default | Description |
|
|
@@ -6936,7 +7068,7 @@ From `ScheduleView` — the full table stands on [View](#view).
|
|
|
6936
7068
|
|
|
6937
7069
|
- A main time never becomes shorter than one raster step, or a minute without a raster.
|
|
6938
7070
|
|
|
6939
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
7071
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
|
|
6940
7072
|
|
|
6941
7073
|
### Snapping
|
|
6942
7074
|
|
|
@@ -6972,7 +7104,7 @@ export default function SnapToTheTicks() {
|
|
|
6972
7104
|
const [tours, setTours] = useState(START);
|
|
6973
7105
|
return (
|
|
6974
7106
|
<Schedule
|
|
6975
|
-
|
|
7107
|
+
aria-label="A tour on the default raster"
|
|
6976
7108
|
height={100}
|
|
6977
7109
|
intents={["move"]}
|
|
6978
7110
|
onIntent={(intent) => setTours((current) => current.map((tour) => applyIntent(tour, intent)))}
|
|
@@ -7008,7 +7140,7 @@ export default function SnapToADuration() {
|
|
|
7008
7140
|
const [work, setWork] = useState(START);
|
|
7009
7141
|
return (
|
|
7010
7142
|
<Schedule
|
|
7011
|
-
|
|
7143
|
+
aria-label="Work planned in half days"
|
|
7012
7144
|
height={140}
|
|
7013
7145
|
snap={HALF_DAY}
|
|
7014
7146
|
intents={["move", "stretch"]}
|
|
@@ -7046,7 +7178,7 @@ export default function SnapToHandovers() {
|
|
|
7046
7178
|
const [watches, setWatches] = useState(START);
|
|
7047
7179
|
return (
|
|
7048
7180
|
<Schedule
|
|
7049
|
-
|
|
7181
|
+
aria-label="An on-call watch on the handover raster"
|
|
7050
7182
|
height={110}
|
|
7051
7183
|
snap={HANDOVERS}
|
|
7052
7184
|
intents={["move"]}
|
|
@@ -7079,7 +7211,7 @@ export default function NoSnapping() {
|
|
|
7079
7211
|
const [windows, setWindows] = useState(START);
|
|
7080
7212
|
return (
|
|
7081
7213
|
<Schedule
|
|
7082
|
-
|
|
7214
|
+
aria-label="A maintenance window placed freely"
|
|
7083
7215
|
height={100}
|
|
7084
7216
|
snap={false}
|
|
7085
7217
|
intents={["move"]}
|
|
@@ -7102,7 +7234,7 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
7102
7234
|
|
|
7103
7235
|
| Prop | Type | Default | Description |
|
|
7104
7236
|
|---|---|---|---|
|
|
7105
|
-
| [`height`](#first-schedule) | `number` |
|
|
7237
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
7106
7238
|
| [`snap`](#first-schedule) | `"ticks" \| number \| `[`SnapRaster`](#first-schedule)` \| 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. |
|
|
7107
7239
|
| [`intents`](#first-schedule) | `readonly `[`IntentKind`](#first-schedule)`[]` | `[]` | 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)). |
|
|
7108
7240
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
@@ -7113,12 +7245,6 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
7113
7245
|
|---|---|---|---|
|
|
7114
7246
|
| [`onIntent`](#first-schedule) | `(intent: `[`Intent`](#first-schedule)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
7115
7247
|
|
|
7116
|
-
###### Accessibility
|
|
7117
|
-
|
|
7118
|
-
| Prop | Type | Default | Description |
|
|
7119
|
-
|---|---|---|---|
|
|
7120
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
7121
|
-
|
|
7122
7248
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
7123
7249
|
|
|
7124
7250
|
| Prop | Type | Default | Description |
|
|
@@ -7261,7 +7387,7 @@ export default function DragFromTheBacklog() {
|
|
|
7261
7387
|
))}
|
|
7262
7388
|
</Stack>
|
|
7263
7389
|
<Schedule
|
|
7264
|
-
|
|
7390
|
+
aria-label="Today's plan of three people, with the backlog beside it"
|
|
7265
7391
|
height={196}
|
|
7266
7392
|
intents={["place", "move", "lane"]}
|
|
7267
7393
|
placing={placing}
|
|
@@ -7295,7 +7421,7 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
7295
7421
|
|
|
7296
7422
|
| Prop | Type | Default | Description |
|
|
7297
7423
|
|---|---|---|---|
|
|
7298
|
-
| [`height`](#first-schedule) | `number` |
|
|
7424
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
7299
7425
|
| [`intents`](#first-schedule) | `readonly `[`IntentKind`](#first-schedule)`[]` | `[]` | 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)). |
|
|
7300
7426
|
| [`placing`](#first-schedule) | [`PlacingItem`](#first-schedule)` \| 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. |
|
|
7301
7427
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
@@ -7306,12 +7432,6 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
7306
7432
|
|---|---|---|---|
|
|
7307
7433
|
| [`onIntent`](#first-schedule) | `(intent: `[`Intent`](#first-schedule)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
7308
7434
|
|
|
7309
|
-
###### Accessibility
|
|
7310
|
-
|
|
7311
|
-
| Prop | Type | Default | Description |
|
|
7312
|
-
|---|---|---|---|
|
|
7313
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
7314
|
-
|
|
7315
7435
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
7316
7436
|
|
|
7317
7437
|
| Prop | Type | Default | Description |
|
|
@@ -7436,7 +7556,7 @@ export default function LanesThatFit() {
|
|
|
7436
7556
|
return (
|
|
7437
7557
|
<Stack gap={3}>
|
|
7438
7558
|
<Schedule
|
|
7439
|
-
|
|
7559
|
+
aria-label="Two cooled vans and a dry van"
|
|
7440
7560
|
height={190}
|
|
7441
7561
|
intents={["move", "lane"]}
|
|
7442
7562
|
canMoveTo={mayGo}
|
|
@@ -7522,7 +7642,7 @@ export default function DraggedIn() {
|
|
|
7522
7642
|
</div>
|
|
7523
7643
|
</Card>
|
|
7524
7644
|
<Schedule
|
|
7525
|
-
|
|
7645
|
+
aria-label="A chilled delivery waiting beside two cooled vans and a dry van"
|
|
7526
7646
|
height={190}
|
|
7527
7647
|
intents={["place"]}
|
|
7528
7648
|
placing={placing}
|
|
@@ -7679,7 +7799,7 @@ export default function AroundLeave() {
|
|
|
7679
7799
|
return (
|
|
7680
7800
|
<Stack gap={3}>
|
|
7681
7801
|
<Schedule
|
|
7682
|
-
|
|
7802
|
+
aria-label="The apps team this week, with leave"
|
|
7683
7803
|
height={236}
|
|
7684
7804
|
intents={["move", "lane"]}
|
|
7685
7805
|
canMoveTo={mayGo}
|
|
@@ -7713,7 +7833,7 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
7713
7833
|
|
|
7714
7834
|
| Prop | Type | Default | Description |
|
|
7715
7835
|
|---|---|---|---|
|
|
7716
|
-
| [`height`](#first-schedule) | `number` |
|
|
7836
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
7717
7837
|
| [`intents`](#first-schedule) | `readonly `[`IntentKind`](#first-schedule)`[]` | `[]` | 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)). |
|
|
7718
7838
|
| [`canMoveTo`](#first-schedule) | `(subtask: `[`Subtask`](#subtasks)`, 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`. |
|
|
7719
7839
|
| [`placing`](#first-schedule) | [`PlacingItem`](#first-schedule)` \| 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. |
|
|
@@ -7725,12 +7845,6 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
7725
7845
|
|---|---|---|---|
|
|
7726
7846
|
| [`onIntent`](#first-schedule) | `(intent: `[`Intent`](#first-schedule)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
7727
7847
|
|
|
7728
|
-
###### Accessibility
|
|
7729
|
-
|
|
7730
|
-
| Prop | Type | Default | Description |
|
|
7731
|
-
|---|---|---|---|
|
|
7732
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
7733
|
-
|
|
7734
7848
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
7735
7849
|
|
|
7736
7850
|
| Prop | Type | Default | Description |
|
|
@@ -7795,7 +7909,7 @@ From `ScheduleView` — the full table stands on [View](#view).
|
|
|
7795
7909
|
|
|
7796
7910
|
- A rule that changes while a drag runs is noticed at the drop, not before.
|
|
7797
7911
|
|
|
7798
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
7912
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
|
|
7799
7913
|
|
|
7800
7914
|
### Ripple
|
|
7801
7915
|
|
|
@@ -7852,7 +7966,7 @@ export default function PushTheLaterStops() {
|
|
|
7852
7966
|
|
|
7853
7967
|
return (
|
|
7854
7968
|
<Stack gap={3}>
|
|
7855
|
-
<Schedule
|
|
7969
|
+
<Schedule aria-label="Tour T-01 on van FP 214 K" height={100}>
|
|
7856
7970
|
<Lane id="van-214" label="Van FP 214 K" />
|
|
7857
7971
|
<Dependencies data={DRIVES} />
|
|
7858
7972
|
<Subtasks data={stops} tasks={TOURS} />
|
|
@@ -7921,7 +8035,7 @@ export default function MoveAWholeTour() {
|
|
|
7921
8035
|
|
|
7922
8036
|
return (
|
|
7923
8037
|
<Stack gap={3}>
|
|
7924
|
-
<Schedule
|
|
8038
|
+
<Schedule aria-label="Two tours from North depot" height={140}>
|
|
7925
8039
|
<Lane id="van-214" label="Van FP 214 K" />
|
|
7926
8040
|
<Lane id="van-377" label="E-van FP 377 K" />
|
|
7927
8041
|
<Dependencies data={DRIVES} />
|
|
@@ -7977,7 +8091,7 @@ export default function RippleOnEveryDrag() {
|
|
|
7977
8091
|
|
|
7978
8092
|
return (
|
|
7979
8093
|
<Schedule
|
|
7980
|
-
|
|
8094
|
+
aria-label="Design, build and test of the shop search, rippling"
|
|
7981
8095
|
height={184}
|
|
7982
8096
|
intents={["move", "stretch"]}
|
|
7983
8097
|
onIntent={onIntent}
|
|
@@ -8002,7 +8116,7 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
8002
8116
|
|
|
8003
8117
|
| Prop | Type | Default | Description |
|
|
8004
8118
|
|---|---|---|---|
|
|
8005
|
-
| [`height`](#first-schedule) | `number` |
|
|
8119
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
8006
8120
|
| [`intents`](#first-schedule) | `readonly `[`IntentKind`](#first-schedule)`[]` | `[]` | 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)). |
|
|
8007
8121
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
8008
8122
|
|
|
@@ -8012,12 +8126,6 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
8012
8126
|
|---|---|---|---|
|
|
8013
8127
|
| [`onIntent`](#first-schedule) | `(intent: `[`Intent`](#first-schedule)`) => void` | — | Called once per intent when a drag ends. The data changes only if the caller changes it. |
|
|
8014
8128
|
|
|
8015
|
-
###### Accessibility
|
|
8016
|
-
|
|
8017
|
-
| Prop | Type | Default | Description |
|
|
8018
|
-
|---|---|---|---|
|
|
8019
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
8020
|
-
|
|
8021
8129
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
8022
8130
|
|
|
8023
8131
|
| Prop | Type | Default | Description |
|
|
@@ -8080,10 +8188,10 @@ From `ScheduleView` — the full table stands on [View](#view).
|
|
|
8080
8188
|
|
|
8081
8189
|
#### Known limits
|
|
8082
8190
|
|
|
8083
|
-
- No dependency types, slack or critical path: the schedule is no project-planning engine ([ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
8191
|
+
- No dependency types, slack or critical path: the schedule is no project-planning engine ([ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md)).
|
|
8084
8192
|
- A dependency joins subtasks of one task, so work of other tasks is never pushed.
|
|
8085
8193
|
|
|
8086
|
-
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.
|
|
8194
|
+
What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/schedule-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
|
|
8087
8195
|
|
|
8088
8196
|
## Measuring
|
|
8089
8197
|
|
|
@@ -8298,7 +8406,7 @@ const RUNS = [
|
|
|
8298
8406
|
function Plot({ data, onInteraction }: { data: Plan; onInteraction: (e: ScheduleInteraction) => void }) {
|
|
8299
8407
|
const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: VIEW } });
|
|
8300
8408
|
return (
|
|
8301
|
-
<Schedule
|
|
8409
|
+
<Schedule aria-label="Benchmark plan" height={HEIGHT} laneHeight={LANE_HEIGHT} onInteraction={onInteraction}>
|
|
8302
8410
|
{data.lanes.map((id) => (
|
|
8303
8411
|
<Lane key={id} id={id} />
|
|
8304
8412
|
))}
|
|
@@ -8415,7 +8523,7 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
8415
8523
|
|
|
8416
8524
|
| Prop | Type | Default | Description |
|
|
8417
8525
|
|---|---|---|---|
|
|
8418
|
-
| [`height`](#first-schedule) | `number` |
|
|
8526
|
+
| [`height`](#first-schedule) | `number` | fills the frame, at least 400 px | Height in CSS pixels, both bands included, fixed. Left out, the schedule fills its frame - a stretched grid cell, a card the grid stretches, a container of definite height - and never goes below 400 px, which is also its height in a frame without one. A different floor goes through `style`'s `minHeight` ([ADR-0050](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0050-a-chart-fills-its-frame-never-below-its-floor.md)). The width is the host's. |
|
|
8419
8527
|
| [`laneHeight`](#first-schedule) | `number` | `44` | Height of one lane in pixels at the default font size of 16 px; the schedule multiplies it by the root font size over 16 px when that ratio is above 1, so lane names keep their room in a reader's larger font. |
|
|
8420
8528
|
| [`children`](#first-schedule) | `ReactNode` | — | `Lane`, `Dependencies` and `Subtasks`, in the order they are to stand and be drawn. |
|
|
8421
8529
|
|
|
@@ -8425,12 +8533,6 @@ From `ScheduleProps` — the full table stands on [First schedule](#first-schedu
|
|
|
8425
8533
|
|---|---|---|---|
|
|
8426
8534
|
| [`onInteraction`](#first-schedule) | `(interaction: `[`ScheduleInteraction`](#interactions)`) => 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. |
|
|
8427
8535
|
|
|
8428
|
-
###### Accessibility
|
|
8429
|
-
|
|
8430
|
-
| Prop | Type | Default | Description |
|
|
8431
|
-
|---|---|---|---|
|
|
8432
|
-
| [`ariaLabel`](#first-schedule) *required* | `string` | — | What the schedule shows, for a screen reader: "Plan of week 38". |
|
|
8433
|
-
|
|
8434
8536
|
From `LaneProps` — the full table stands on [Lanes](#lanes).
|
|
8435
8537
|
|
|
8436
8538
|
| Prop | Type | Default | Description |
|
|
@@ -8511,13 +8613,14 @@ Everything `@umriss-ui/schedule` exports, with its signature. A component's prop
|
|
|
8511
8613
|
Declares a schedule: hands back `Schedule` and the parts declared inside it
|
|
8512
8614
|
- `Lane`, `LaneGroup`, `Subtasks`, `Dependencies`, `BlockedTimes`, `Milestones` -, its
|
|
8513
8615
|
`view` and the setters `setView`, `setDomain`, `toggleGroup`, `foldAll` and
|
|
8514
|
-
`unfoldAll
|
|
8616
|
+
`unfoldAll`, `positionAt`, `clientPointOf` and `visibleDomain`, and `scrollToLane`, `scrollToSubtask` and
|
|
8617
|
+
`focusSubtask`.
|
|
8515
8618
|
|
|
8516
8619
|
```ts
|
|
8517
8620
|
function useSchedule(options?: ScheduleOptions): ScheduleParts;
|
|
8518
8621
|
```
|
|
8519
8622
|
|
|
8520
|
-
Used on [Scenarios](#scenarios), [Installation](#installation), [First schedule](#first-schedule), [Lanes](#lanes), [Lane groups](#lane-groups), [Subtasks](#subtasks), [Bar labels](#bar-labels), [Appearances](#appearances), [Overlap](#overlap), [Dependencies](#dependencies), [Routes](#routes), [Time axis and calendar](#time-axis-and-calendar), [Blocked time](#blocked-time), [Milestones](#milestones), [Now line](#now-line), [Pan and zoom](#pan-and-zoom), [Selection](#selection), [Interactions](#interactions), [Tooltip](#tooltip), [View](#view), [Linked schedules](#linked-schedules), [
|
|
8623
|
+
Used on [Scenarios](#scenarios), [Installation](#installation), [First schedule](#first-schedule), [Lanes](#lanes), [Lane groups](#lane-groups), [Subtasks](#subtasks), [Bar labels](#bar-labels), [Appearances](#appearances), [Overlap](#overlap), [Dependencies](#dependencies), [Routes](#routes), [Time axis and calendar](#time-axis-and-calendar), [Blocked time](#blocked-time), [Milestones](#milestones), [Now line](#now-line), [Pan and zoom](#pan-and-zoom), [Selection](#selection), [Interactions](#interactions), [Tooltip](#tooltip), [View](#view), [Linked schedules](#linked-schedules), [Functions on the hook](#functions-on-the-hook), [Findings as data](#findings-as-data), [Move and lane](#move-and-lane), [Stretch, lead-in, lead-out](#stretch-lead-in-lead-out), [Snapping](#snapping), [Placing from outside](#placing-from-outside), [Where a subtask may go](#where-a-subtask-may-go), [Ripple](#ripple) and [Benchmark](#benchmark).
|
|
8521
8624
|
|
|
8522
8625
|
#### Functions
|
|
8523
8626
|
|
|
@@ -8560,7 +8663,7 @@ Every finding at once. Without blocked time there is none in it.
|
|
|
8560
8663
|
function findings(subtasks: readonly Subtask[], dependencies: readonly Dependency[], blocked?: readonly BlockedTime[]): Findings;
|
|
8561
8664
|
```
|
|
8562
8665
|
|
|
8563
|
-
Used on [Scenarios](#scenarios), [First schedule](#first-schedule), [Lane groups](#lane-groups), [Blocked time](#blocked-time), [Tooltip](#tooltip) and [Findings as data](#findings-as-data).
|
|
8666
|
+
Used on [Scenarios](#scenarios), [First schedule](#first-schedule), [Lane groups](#lane-groups), [Blocked time](#blocked-time), [Tooltip](#tooltip), [Functions on the hook](#functions-on-the-hook) and [Findings as data](#findings-as-data).
|
|
8564
8667
|
|
|
8565
8668
|
##### `inBlockedTime`
|
|
8566
8669
|
|
|
@@ -8595,7 +8698,7 @@ nothing.
|
|
|
8595
8698
|
function overlaps(subtasks: readonly Subtask[]): Overlap[];
|
|
8596
8699
|
```
|
|
8597
8700
|
|
|
8598
|
-
Used on [Scenarios](#scenarios), [Lane groups](#lane-groups), [Findings as data](#findings-as-data) and [Move and lane](#move-and-lane).
|
|
8701
|
+
Used on [Scenarios](#scenarios), [Lane groups](#lane-groups), [Functions on the hook](#functions-on-the-hook), [Findings as data](#findings-as-data) and [Move and lane](#move-and-lane).
|
|
8599
8702
|
|
|
8600
8703
|
##### `resolveAppearance`
|
|
8601
8704
|
|
|
@@ -8890,11 +8993,11 @@ point on the screen and a time on a lane. Everything else is props.
|
|
|
8890
8993
|
|
|
8891
8994
|
| Prop | Type | Default | Description |
|
|
8892
8995
|
|---|---|---|---|
|
|
8893
|
-
| `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
|
|
8894
|
-
| `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
|
|
8996
|
+
| `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. |
|
|
8997
|
+
| `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. |
|
|
8895
8998
|
| `visibleDomain` *required* | `() => readonly [number, number]` | — | The visible span, as two wall-clock instants. |
|
|
8896
8999
|
|
|
8897
|
-
|
|
9000
|
+
*Deprecated* since 0.43 - use the functions on [`useSchedule`](#api-index-1)'s return.
|
|
8898
9001
|
|
|
8899
9002
|
##### `ScheduleHit`
|
|
8900
9003
|
|
|
@@ -8926,10 +9029,10 @@ it, its view and the setters that change it.
|
|
|
8926
9029
|
|
|
8927
9030
|
| Prop | Type | Default | Description |
|
|
8928
9031
|
|---|---|---|---|
|
|
8929
|
-
| `Schedule` *required* | `(props: `[`ScheduleProps`](#first-schedule)`) => ReactNode` | — | The schedule. One per `useSchedule`: a second schedule is a second call.<br>Shown in: [The smallest schedule (Installation)](#installation), [A day of tours (First schedule)](#first-schedule), [Start from an empty plan (First schedule)](#first-schedule) and
|
|
8930
|
-
| `Lane` *required* | `typeof Lane` | — | <br>Shown in: [The smallest schedule (Installation)](#installation), [A day of tours (First schedule)](#first-schedule), [Start from an empty plan (First schedule)](#first-schedule) and
|
|
9032
|
+
| `Schedule` *required* | `(props: `[`ScheduleProps`](#first-schedule)`) => ReactNode` | — | The schedule. One per `useSchedule`: a second schedule is a second call.<br>Shown in: [The smallest schedule (Installation)](#installation), [A day of tours (First schedule)](#first-schedule), [Start from an empty plan (First schedule)](#first-schedule) and 82 more |
|
|
9033
|
+
| `Lane` *required* | `typeof Lane` | — | <br>Shown in: [The smallest schedule (Installation)](#installation), [A day of tours (First schedule)](#first-schedule), [Start from an empty plan (First schedule)](#first-schedule) and 82 more |
|
|
8931
9034
|
| `LaneGroup` *required* | `typeof LaneGroup` | — | <br>Shown in: [Group lanes under a head (Lane groups)](#lane-groups), [Nest groups to any depth (Lane groups)](#lane-groups), [Fold groups from outside (Lane groups)](#lane-groups) and 5 more |
|
|
8932
|
-
| `Subtasks` *required* | `typeof Subtasks` | — | <br>Shown in: [The smallest schedule (Installation)](#installation), [A day of tours (First schedule)](#first-schedule), [Start from an empty plan (First schedule)](#first-schedule) and
|
|
9035
|
+
| `Subtasks` *required* | `typeof Subtasks` | — | <br>Shown in: [The smallest schedule (Installation)](#installation), [A day of tours (First schedule)](#first-schedule), [Start from an empty plan (First schedule)](#first-schedule) and 82 more |
|
|
8933
9036
|
| `Dependencies` *required* | `typeof Dependencies` | — | <br>Shown in: [The smallest schedule (Installation)](#installation), [A day of tours (First schedule)](#first-schedule), [Plan a day in the machine shop (First schedule)](#first-schedule) and 28 more |
|
|
8934
9037
|
| `BlockedTimes` *required* | `typeof BlockedTimes` | — | <br>Shown in: [Block out leave and maintenance (Blocked time)](#blocked-time), [Plan work around someone's leave (Blocked time)](#blocked-time), [Check a sprint against the leave calendar (Blocked time)](#blocked-time) and 5 more |
|
|
8935
9038
|
| `Milestones` *required* | `typeof Milestones` | — | <br>Shown in: [Mark a handover and a release (Milestones)](#milestones), [Say what a milestone is in your own tooltip (Milestones)](#milestones) |
|
|
@@ -8937,6 +9040,12 @@ it, its view and the setters that change it.
|
|
|
8937
9040
|
| `setView` *required* | `(view: `[`ScheduleView`](#view)`) => void` | — | Goes to a whole view; what it leaves out is shown whole again. Not reported through `onViewChange`: two schedules kept in step by `onViewChange: (v) => other.setView(v)` in both directions do not answer each other. A view with the content already shown changes nothing.<br>Shown in: [Keep and restore a view (View)](#view), [Keep two schedules in step (Linked schedules)](#linked-schedules), [Read a rota beside the incidents (Linked schedules)](#linked-schedules) |
|
|
8938
9041
|
| `setDomain` *required* | `(span: readonly [number, number] \| null) => void` | — | Puts a span of two wall-clock instants in view; `null` shows the subtasks' extent.<br>Shown in: [Keep and restore a view (View)](#view) |
|
|
8939
9042
|
| `toggleGroup` *required* | `(id: string) => void` | — | Folds or unfolds one **Lane group**. |
|
|
9043
|
+
| `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 - and null while no schedule is mounted.<br>Shown in: [Place a mark of your own (Functions on the hook)](#functions-on-the-hook) |
|
|
9044
|
+
| `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 (Functions on the hook)](#functions-on-the-hook) |
|
|
9045
|
+
| `visibleDomain` *required* | `() => readonly [number, number]` | — | The visible span, as two wall-clock instants. |
|
|
9046
|
+
| `scrollToLane` *required* | `(lane: string) => boolean` | — | Scrolls the lanes until the lane's row is in view, and returns `true`; `false` and nothing changed for an unknown lane, one inside a folded **Lane group** (none is unfolded), or while no schedule is mounted. |
|
|
9047
|
+
| `scrollToSubtask` *required* | `(id: string) => boolean` | — | Brings the subtask's lane and time into view, the span moving to it and keeping its width as `setDomain` would, and leaves the focus where it is; `false` and nothing changed in the cases of `scrollToLane`.<br>Shown in: [Show a finding (Functions on the hook)](#functions-on-the-hook) |
|
|
9048
|
+
| `focusSubtask` *required* | `(id: string) => boolean` | — | Does what `scrollToSubtask` does, then makes the subtask the **Active subtask** and moves the focus to the plot, where the live region reads it out as the arrow keys do; `false` and nothing changed in the cases of `scrollToLane`.<br>Shown in: [Show a finding (Functions on the hook)](#functions-on-the-hook) |
|
|
8940
9049
|
| `foldAll` *required* | `() => void` | — | Folds every group.<br>Shown in: [Fold groups from outside (Lane groups)](#lane-groups) |
|
|
8941
9050
|
| `unfoldAll` *required* | `() => void` | — | Unfolds every group.<br>Shown in: [Fold groups from outside (Lane groups)](#lane-groups) |
|
|
8942
9051
|
|
|
@@ -8984,7 +9093,7 @@ Stretch the main time at one or both of its edges.
|
|
|
8984
9093
|
|
|
8985
9094
|
Its table stands on [Subtasks](#subtasks).
|
|
8986
9095
|
|
|
8987
|
-
Used on [Scenarios](#scenarios), [Installation](#installation), [First schedule](#first-schedule), [Lanes](#lanes), [Lane groups](#lane-groups), [Subtasks](#subtasks), [Bar labels](#bar-labels), [Appearances](#appearances), [Overlap](#overlap), [Dependencies](#dependencies), [Routes](#routes), [Time axis and calendar](#time-axis-and-calendar), [Blocked time](#blocked-time), [Milestones](#milestones), [Now line](#now-line), [Pan and zoom](#pan-and-zoom), [Selection](#selection), [Interactions](#interactions), [Tooltip](#tooltip), [View](#view), [Linked schedules](#linked-schedules), [
|
|
9096
|
+
Used on [Scenarios](#scenarios), [Installation](#installation), [First schedule](#first-schedule), [Lanes](#lanes), [Lane groups](#lane-groups), [Subtasks](#subtasks), [Bar labels](#bar-labels), [Appearances](#appearances), [Overlap](#overlap), [Dependencies](#dependencies), [Routes](#routes), [Time axis and calendar](#time-axis-and-calendar), [Blocked time](#blocked-time), [Milestones](#milestones), [Now line](#now-line), [Pan and zoom](#pan-and-zoom), [Selection](#selection), [Interactions](#interactions), [Tooltip](#tooltip), [View](#view), [Linked schedules](#linked-schedules), [Functions on the hook](#functions-on-the-hook), [Findings as data](#findings-as-data), [Move and lane](#move-and-lane), [Stretch, lead-in, lead-out](#stretch-lead-in-lead-out), [Snapping](#snapping), [Placing from outside](#placing-from-outside), [Where a subtask may go](#where-a-subtask-may-go), [Ripple](#ripple) and [Benchmark](#benchmark).
|
|
8988
9097
|
|
|
8989
9098
|
##### `SubtaskAppearance`
|
|
8990
9099
|
|
|
@@ -9002,7 +9111,7 @@ Its table stands on [Subtasks](#subtasks).
|
|
|
9002
9111
|
|
|
9003
9112
|
Its table stands on [Subtasks](#subtasks).
|
|
9004
9113
|
|
|
9005
|
-
Used on [Scenarios](#scenarios), [Installation](#installation), [First schedule](#first-schedule), [Lanes](#lanes), [Lane groups](#lane-groups), [Subtasks](#subtasks), [Bar labels](#bar-labels), [Appearances](#appearances), [Overlap](#overlap), [Dependencies](#dependencies), [Routes](#routes), [Time axis and calendar](#time-axis-and-calendar), [Blocked time](#blocked-time), [Milestones](#milestones), [Now line](#now-line), [Pan and zoom](#pan-and-zoom), [Selection](#selection), [Interactions](#interactions), [Tooltip](#tooltip), [View](#view), [Linked schedules](#linked-schedules), [
|
|
9114
|
+
Used on [Scenarios](#scenarios), [Installation](#installation), [First schedule](#first-schedule), [Lanes](#lanes), [Lane groups](#lane-groups), [Subtasks](#subtasks), [Bar labels](#bar-labels), [Appearances](#appearances), [Overlap](#overlap), [Dependencies](#dependencies), [Routes](#routes), [Time axis and calendar](#time-axis-and-calendar), [Blocked time](#blocked-time), [Milestones](#milestones), [Now line](#now-line), [Pan and zoom](#pan-and-zoom), [Selection](#selection), [Interactions](#interactions), [Tooltip](#tooltip), [View](#view), [Linked schedules](#linked-schedules), [Functions on the hook](#functions-on-the-hook), [Findings as data](#findings-as-data), [Move and lane](#move-and-lane), [Stretch, lead-in, lead-out](#stretch-lead-in-lead-out), [Snapping](#snapping), [Placing from outside](#placing-from-outside), [Where a subtask may go](#where-a-subtask-may-go), [Ripple](#ripple) and [Benchmark](#benchmark).
|
|
9006
9115
|
|
|
9007
9116
|
##### `ViolatedDependency`
|
|
9008
9117
|
|