@umriss-ui/schedule 0.1.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.
@@ -0,0 +1,560 @@
1
+ import { CalendarInput } from '@umriss-ui/charts';
2
+ import { CSSProperties } from 'react';
3
+ import { ForwardRefExoticComponent } from 'react';
4
+ import { ReactNode } from 'react';
5
+ import { RefAttributes } from 'react';
6
+
7
+ /** The subtask as the intent asks for it. An intent for another subtask leaves
8
+ it as it is. */
9
+ export declare function applyIntent<S extends Subtask>(subtask: S, intent: Intent): S;
10
+
11
+ /** When a transport has to have arrived at its subtask, by its anchor. */
12
+ export declare function arrival(transport: Transport, to: Subtask): number;
13
+
14
+ /** When a transport leaves its subtask, by its anchor. */
15
+ export declare function departure(transport: Transport, from: Subtask): number;
16
+
17
+ /** Both kinds of finding over the same data. */
18
+ export declare interface Findings {
19
+ readonly overlaps: readonly Overlap[];
20
+ readonly lateTransports: readonly LateTransport[];
21
+ }
22
+
23
+ /** Overlaps and late transports at once. */
24
+ export declare function findings(subtasks: readonly Subtask[], transports: readonly Transport[]): Findings;
25
+
26
+ /** What the schedule reports when an interaction asks for a change. Every
27
+ intent carries the values it asks for, not a difference: two intents of one
28
+ drop - a move and a lane - give the same data in either order. */
29
+ export declare type Intent = MoveIntent | StretchIntent | SetupIntent | TeardownIntent | LaneIntent | PlaceIntent;
30
+
31
+ /** The names of the intents - the editing API of the schedule. */
32
+ export declare type IntentKind = Intent["kind"];
33
+
34
+ /** One lane: a machine or station. The lanes run top to bottom in the order
35
+ they are declared - whichever group they are declared in. */
36
+ export declare function Lane({ id, label }: LaneProps): null;
37
+
38
+ /** A group of lanes: structure over them, and never a lane itself.
39
+
40
+ It gives its id to its children through context, so a lane never names its
41
+ group and a group reads in JSX as it reads in the plant. Folded, it becomes
42
+ one row showing a **Miniature** of everything in it; open, it shows a slim
43
+ head above its lanes. Which groups are folded is `collapsedGroups` on
44
+ `Schedule` - a view state, never an **Intent**. */
45
+ export declare function LaneGroup({ id, label, children }: LaneGroupProps): ReactNode;
46
+
47
+ export declare interface LaneGroupProps {
48
+ /** The group's identity - what `collapsedGroups` names. It is never a lane:
49
+ no subtask sits on it, no finding is reported for it, and no intent names
50
+ it (ADR-0025). */
51
+ id: string;
52
+ /** What the group's header says - the hall, the line, the machine group.
53
+ Real text, read by a screen reader; without one the header shows the id. */
54
+ label?: ReactNode;
55
+ /** `Lane`s and further `LaneGroup`s, to any depth. */
56
+ children?: ReactNode;
57
+ }
58
+
59
+ /** Put the subtask on another lane. */
60
+ export declare interface LaneIntent {
61
+ readonly kind: "lane";
62
+ /** The id of the subtask. */
63
+ readonly subtask: string;
64
+ /** The id of the new lane. */
65
+ readonly lane: string;
66
+ }
67
+
68
+ export declare interface LaneProps {
69
+ /** The identity subtasks name in their `lane`. */
70
+ id: string;
71
+ /** What the lane header says - the machine or station. Real text, read by a
72
+ screen reader; without one the header shows the id. */
73
+ label?: ReactNode;
74
+ }
75
+
76
+ /** A transport whose duration does not fit between its anchors. */
77
+ export declare interface LateTransport {
78
+ /** The id of the transport. */
79
+ readonly transport: string;
80
+ /** When it leaves, by its anchor. */
81
+ readonly departure: number;
82
+ /** When it has to have arrived, by its anchor. */
83
+ readonly arrival: number;
84
+ /** How much time is missing: departure plus duration, minus arrival. */
85
+ readonly shortBy: number;
86
+ }
87
+
88
+ /** Every transport whose successor is to be reached before the predecessor's
89
+ departure plus the transport's duration. A transport naming a subtask that
90
+ is not in the data is passed over: there is nothing to judge. */
91
+ export declare function lateTransports(subtasks: readonly Subtask[], transports: readonly Transport[]): LateTransport[];
92
+
93
+ /** Move the subtask in time: the main time keeps its length. */
94
+ export declare interface MoveIntent {
95
+ readonly kind: "move";
96
+ /** The id of the subtask. */
97
+ readonly subtask: string;
98
+ /** The new start of the main time. */
99
+ readonly from: number;
100
+ /** The new end of the main time. */
101
+ readonly to: number;
102
+ }
103
+
104
+ /** The interval a subtask occupies on its lane: setup and teardown included. */
105
+ export declare function occupied(subtask: Subtask): {
106
+ from: number;
107
+ to: number;
108
+ };
109
+
110
+ /** Two subtasks covering the same time on one lane. */
111
+ export declare interface Overlap {
112
+ /** The lane both sit on. */
113
+ readonly lane: string;
114
+ /** The subtask that starts earlier (setup included); on a tie, the one that
115
+ stands first in the data. */
116
+ readonly first: string;
117
+ /** The other one. */
118
+ readonly second: string;
119
+ /** Where the covering begins. */
120
+ readonly from: number;
121
+ /** Where it ends. */
122
+ readonly to: number;
123
+ }
124
+
125
+ /** Every pair of subtasks that cover each other on a lane. Touching at a
126
+ shared edge is not covering, and a subtask that covers no time covers
127
+ nothing. */
128
+ export declare function overlaps(subtasks: readonly Subtask[]): Overlap[];
129
+
130
+ /** Put work on the plan that was not on it: the answer to a drag from outside
131
+ the schedule (schedule-refinement 07). It carries no subtask id - there is
132
+ no subtask yet; the caller creates one, with its own identity, from
133
+ `subtaskFromPlace`. */
134
+ export declare interface PlaceIntent {
135
+ readonly kind: "place";
136
+ /** The caller's key for the dragged item, as it declared it while dragging. */
137
+ readonly item: string;
138
+ /** The task the work belongs to. */
139
+ readonly task: string;
140
+ /** The lane it was dropped on. */
141
+ readonly lane: string;
142
+ /** Where its main time would start. */
143
+ readonly from: number;
144
+ /** Where its main time would end. */
145
+ readonly to: number;
146
+ /** The setup it was declared with. */
147
+ readonly setup?: number;
148
+ /** The teardown it was declared with. */
149
+ readonly teardown?: number;
150
+ }
151
+
152
+ /** What the application says it is dragging in, while it drags it
153
+ (schedule-refinement 07): the browser hands over the dragged data only on
154
+ the drop, so the ghost before the drop can only come from the caller. */
155
+ export declare interface PlacingItem {
156
+ /** The caller's key for the dragged item; it comes back in the intent. */
157
+ readonly item: string;
158
+ /** The task the work belongs to. */
159
+ readonly task: string;
160
+ /** How long its main time is. */
161
+ readonly duration: number;
162
+ /** The setup it brings. */
163
+ readonly setup?: number;
164
+ /** The teardown it brings. */
165
+ readonly teardown?: number;
166
+ }
167
+
168
+ export declare function resolveAppearance(appearance: readonly SubtaskAppearance[] | undefined): ResolvedAppearance;
169
+
170
+ /** What the drawing needs to know, with the contradiction already settled.
171
+
172
+ The four names are the ones this module was born with, and they are kept so
173
+ that a caller's code does not change because a picture did. Two of them are
174
+ now named after a drawing they no longer use, and the channel each one
175
+ really owns stands beside it (`sceneDraw.ts`, "ONE CHANNEL PER
176
+ STATEMENT"). */
177
+ export declare interface ResolvedAppearance {
178
+ /** `provisional`: the FILL - none at all, so the surface shows through, with
179
+ a dashed outline in the task colour. Planned, not released. */
180
+ readonly dashed: boolean;
181
+ /** `fixed`: the ENDS - a cap at each end of the main time. Not a hatch any
182
+ more; a hatch now says "not available" of a refused lane, and the name is
183
+ kept only so that this type did not change with the picture. */
184
+ readonly hatched: boolean;
185
+ /** `muted`: the SATURATION - the task colour mixed half into the surface,
186
+ opaque and at full height. Another shift's, another crew's. */
187
+ readonly muted: boolean;
188
+ /** `open`: the FADE, where the bar passes the edge of the view. It goes on
189
+ past what is drawn. */
190
+ readonly open: boolean;
191
+ }
192
+
193
+ /** The moves that push every successor whose transport no longer fits after
194
+ `intent` - transitively, in the order they were first pushed. The subtask the
195
+ intent is about is never moved, and a cycle among the successors ends after a
196
+ bounded number of pushes instead of running on. */
197
+ export declare function ripple(subtasks: readonly Subtask[], transports: readonly Transport[], intent: Intent): MoveIntent[];
198
+
199
+ export declare const Schedule: ForwardRefExoticComponent<ScheduleProps & RefAttributes<ScheduleHandle>>;
200
+
201
+ /** What a schedule offers a caller imperatively: the arithmetic between a
202
+ point on the screen and a time on a lane. Everything else is props. */
203
+ export declare interface ScheduleHandle {
204
+ /** The time and the lane at a client point, or null outside the plot. */
205
+ positionAt: (clientX: number, clientY: number) => {
206
+ time: number;
207
+ lane: string | null;
208
+ } | null;
209
+ /** The client point of a time - on the middle of a lane where one is named -
210
+ or null while the schedule is not on screen. */
211
+ clientPointOf: (time: number, lane?: string) => {
212
+ x: number;
213
+ y: number;
214
+ } | null;
215
+ /** The visible span, as two wall-clock instants. */
216
+ visibleDomain: () => readonly [number, number];
217
+ }
218
+
219
+ /** What a pointer is on. */
220
+ export declare type ScheduleHit = {
221
+ readonly kind: "subtask";
222
+ readonly subtask: Subtask;
223
+ readonly part: "setup" | "main" | "teardown";
224
+ } | {
225
+ readonly kind: "transport";
226
+ readonly transport: Transport;
227
+ } | {
228
+ readonly kind: "lane";
229
+ readonly lane: string;
230
+ } | {
231
+ readonly kind: "nothing";
232
+ };
233
+
234
+ /** A pointer interaction, reported with its target and its position. */
235
+ export declare interface ScheduleInteraction {
236
+ /** `"hover"` is reported when the target under the pointer changes, not on
237
+ every movement. */
238
+ readonly type: "click" | "contextmenu" | "hover";
239
+ /** What the pointer is on. */
240
+ readonly hit: ScheduleHit;
241
+ /** The pointer's horizontal client coordinate - where a `ContextMenu` opens. */
242
+ readonly clientX: number;
243
+ /** The pointer's vertical client coordinate. */
244
+ readonly clientY: number;
245
+ /** The wall-clock instant under the pointer. */
246
+ readonly time: number;
247
+ /** The lane under the pointer, or null below the last one. */
248
+ readonly lane: string | null;
249
+ }
250
+
251
+ export declare interface ScheduleProps {
252
+ /** What the schedule shows, for a screen reader: "Plan of week 38". */
253
+ ariaLabel: string;
254
+ /** The time in view when the schedule mounts, as two wall-clock instants.
255
+ Pan and zoom take it from there; a new pair of values puts it back. */
256
+ initialDomain: readonly [number, number];
257
+ /** Height in CSS pixels, both bands included. The width is the host's. */
258
+ height?: number;
259
+ /** Height of one lane in pixels. */
260
+ laneHeight?: number;
261
+ /** Width of the lane headers in pixels. */
262
+ headerWidth?: number;
263
+ /** An operating calendar: the intervals in which time counts. Nights and
264
+ weekends outside them are cut out of the axis. Default: the wall clock. */
265
+ calendar?: CalendarInput;
266
+ /** The narrowest and widest time span zoom may reach, in milliseconds.
267
+ Default: one hour to 28 days. */
268
+ zoomLimits?: ZoomLimits;
269
+ /** The raster a drag lands on: `"ticks"` - the fine band's current step -, a
270
+ step in milliseconds from local midnight, a step with an offset (shifts at
271
+ 06:00, 14:00 and 22:00 are eight hours offset by six), or `false` for none.
272
+ It shapes the ghost and the intent, never the data. */
273
+ snap?: "ticks" | number | SnapRaster | false;
274
+ /** The intents the caller handles. Each one enables its interaction; none
275
+ leaves a read-only schedule (ADR-0023). */
276
+ intents?: readonly IntentKind[];
277
+ /** Whether a subtask may go to a lane. Without it every lane is open; it
278
+ narrows `"lane"`, it does not enable it.
279
+
280
+ Asked once per lane when a drag takes hold, and asked again at the drop.
281
+ The lanes it turns down are marked from the first frame of the drag - a
282
+ planner sees the refusal before meeting it - and over one of them the
283
+ ghost stays on the last lane that was allowed, the cursor says no and a
284
+ line ties the ghost to the pointer. A refused lane costs the lane and
285
+ nothing else: a drop after it still reports the move in time.
286
+
287
+ It is asked for work dragged in from outside as well, with the key and
288
+ task the application declared in `placing`. */
289
+ canMoveTo?: (subtask: Subtask, lane: string) => boolean;
290
+ /** Called once per intent when a drag ends. The data changes only if the
291
+ caller changes it. */
292
+ onIntent?: (intent: Intent) => void;
293
+ /** Click, context menu and hover, with what the pointer is on and where.
294
+ While it is set, a right-click opens no browser menu. */
295
+ onInteraction?: (interaction: ScheduleInteraction) => void;
296
+ /** The selected task, controlled. Leave it out and the schedule keeps the
297
+ selection itself. */
298
+ selectedTask?: string | null;
299
+ /** Called when a click selects a task or clears the selection, with the
300
+ subtask that was clicked - null where the click was on a transport or on
301
+ nothing. It is called again when another subtask of the same task is
302
+ clicked. */
303
+ onSelectedTaskChange?: (task: string | null, subtask: string | null) => void;
304
+ /** The **Lane group**s that are folded, controlled. Leave it out and the
305
+ schedule keeps them itself, starting from `defaultCollapsedGroups`.
306
+
307
+ Folding changes the view and not the plan, which is why it is no intent:
308
+ a caller that applies every intent it receives must never find a fold
309
+ among them (ADR-0025). A folded outer group hides the inner ones without
310
+ their entries leaving the list, so unfolding it gives back the view that
311
+ was there. */
312
+ collapsedGroups?: readonly string[];
313
+ /** Which groups are folded when the schedule mounts, where the schedule
314
+ keeps the state itself. Ignored while `collapsedGroups` is given. */
315
+ defaultCollapsedGroups?: readonly string[];
316
+ /** Called with the whole list when the planner folds or unfolds a group. */
317
+ onCollapsedGroupsChange?: (groups: readonly string[]) => void;
318
+ /** The visible time span after the planner panned or zoomed, as two
319
+ wall-clock instants - for keeping a second schedule or a chart in step. A
320
+ span handed in through `initialDomain` is not reported back. */
321
+ onDomainChange?: (domain: readonly [number, number]) => void;
322
+ /** What the application is dragging in from outside while it drags it - its
323
+ key, task, the length of its main time, its setup and teardown. The
324
+ browser hands the dragged data over only on the drop, so the ghost before
325
+ it can only come from here: set it on your own `dragstart`, clear it on
326
+ `dragend`. Without `"place"` in `intents` no drop is accepted. */
327
+ placing?: PlacingItem | null;
328
+ /** How the transports are drawn: a `"curve"` that leaves and arrives
329
+ forwards, a `"straight"` line, or `"orthogonal"` segments. A transport may
330
+ say otherwise for itself. */
331
+ route?: TransportRoute;
332
+ /** Where a transport's ends sit on their bars: the `"centre"` of both, or the
333
+ `"nearest"` edge - which is the shortest line between two stops. Within
334
+ one lane both mean the middle. A transport may say otherwise for itself.
335
+
336
+ It changes the picture and never a finding: whether a transport is late
337
+ follows from its `leaves` and `arrives` alone. */
338
+ attach?: TransportAttachment;
339
+ /** Whether a transport's two ends carry a dot (`"dot"`, the default) or the
340
+ line stands alone (`"none"`). The dot says where the line is anchored - a
341
+ help while a plan is being read, and noise in a plan full of short moves.
342
+ A transport may say otherwise for itself. */
343
+ ends?: TransportEnds;
344
+ /** What stands written in a bar: a function from a subtask to a line of
345
+ text, or nothing for bars without text. The text is cut off with an
346
+ ellipsis where the bar is too narrow for it and left out where even that
347
+ would say nothing; a bar that began before the view keeps its text at the
348
+ view's edge. */
349
+ label?: (subtask: Subtask) => string;
350
+ /** The tooltip on a hovered subtask or transport: its order, its times, its
351
+ parts and its findings. `false` switches it off; a function receives
352
+ what the pointer rests on and returns content of the application's own. */
353
+ tooltip?: false | ((target: ScheduleTooltipTarget) => ReactNode);
354
+ /** A line marking the present across the lanes: `true` follows the clock by
355
+ the minute, an instant fixes it there. Off by default. */
356
+ now?: boolean | number;
357
+ /** Goes to the root element. */
358
+ className?: string;
359
+ /** Goes to the root element. */
360
+ style?: CSSProperties;
361
+ /** `Lane`, `Transports` and `Subtasks`, in the order they are to stand and
362
+ be drawn. */
363
+ children?: ReactNode;
364
+ }
365
+
366
+ /** What a tooltip is about: the hovered subtask or transport, with what the
367
+ schedule knows about it. */
368
+ export declare type ScheduleTooltipTarget = {
369
+ /** A subtask is hovered. */
370
+ readonly kind: "subtask";
371
+ /** The hovered subtask. */
372
+ readonly subtask: Subtask;
373
+ /** Its task, where the tasks name it. */
374
+ readonly task: Task | undefined;
375
+ /** The subtasks it overlaps with on its lane. */
376
+ readonly overlapping: readonly Subtask[];
377
+ /** The late transports leaving or reaching it. */
378
+ readonly lateTransports: readonly LateTransport[];
379
+ } | {
380
+ /** A transport is hovered. */
381
+ readonly kind: "transport";
382
+ /** The hovered transport. */
383
+ readonly transport: Transport;
384
+ /** Its task, where the tasks name it. */
385
+ readonly task: Task | undefined;
386
+ /** The subtask it leaves. */
387
+ readonly from: Subtask | undefined;
388
+ /** The subtask it reaches. */
389
+ readonly to: Subtask | undefined;
390
+ /** Its finding, where it is late. */
391
+ readonly late: LateTransport | undefined;
392
+ };
393
+
394
+ /** Change the setup on its own. */
395
+ export declare interface SetupIntent {
396
+ readonly kind: "setup";
397
+ /** The id of the subtask. */
398
+ readonly subtask: string;
399
+ /** The new duration of the setup. */
400
+ readonly setup: number;
401
+ }
402
+
403
+ export declare function shiftTask(subtasks: readonly Subtask[], task: string, by: number): MoveIntent[];
404
+
405
+ /** A raster: a step, and where it starts after local midnight. */
406
+ export declare interface SnapRaster {
407
+ /** The distance between two lines of the raster, in milliseconds. */
408
+ readonly step: number;
409
+ /** Where the raster starts after local midnight, in milliseconds: six
410
+ hours for shifts that change at 06:00. */
411
+ readonly offset: number;
412
+ }
413
+
414
+ /** `time` onto the nearest line of the raster in local time - a step alone
415
+ starts at local midnight. A step of zero or less is no raster: the time
416
+ stays as it is. */
417
+ export declare function snapTime(time: number, raster: number | SnapRaster): number;
418
+
419
+ /** Stretch the main time at one or both of its edges. */
420
+ export declare interface StretchIntent {
421
+ readonly kind: "stretch";
422
+ /** The id of the subtask. */
423
+ readonly subtask: string;
424
+ /** The new start of the main time. */
425
+ readonly from: number;
426
+ /** The new end of the main time. */
427
+ readonly to: number;
428
+ }
429
+
430
+ /** The drawn interval: a main time on one lane, with an optional setup before
431
+ it and a teardown after it. */
432
+ export declare interface Subtask {
433
+ /** The caller's identity of the subtask. */
434
+ readonly id: string;
435
+ /** The id of the task it belongs to. */
436
+ readonly task: string;
437
+ /** The id of the lane it sits on. */
438
+ readonly lane: string;
439
+ /** Start of the main time. */
440
+ readonly from: number;
441
+ /** End of the main time. */
442
+ readonly to: number;
443
+ /** Duration of the setup before the main time; none is zero. */
444
+ readonly setup?: number;
445
+ /** Duration of the teardown after the main time; none is zero. */
446
+ readonly teardown?: number;
447
+ /** What the subtask is called, where the schedule names it. */
448
+ readonly name?: string;
449
+ /** What the bar says besides its colour: `"provisional"`, `"fixed"`,
450
+ `"muted"`, `"open"`. Several hold at once; `"provisional"` and `"fixed"`
451
+ contradict, and the later one in the list wins. */
452
+ readonly appearance?: readonly SubtaskAppearance[];
453
+ /** The share of the work that is done, from 0 to 1, drawn as a filled part
454
+ of the bar. Without it nothing is claimed - an empty bar and a bar at
455
+ zero per cent are two different statements. */
456
+ readonly progress?: number;
457
+ }
458
+
459
+ /** The appearances a caller may give a subtask. */
460
+ export declare type SubtaskAppearance = "provisional" | "fixed" | "muted" | "open";
461
+
462
+ /** The subtask a place intent asks for, under an id the caller chooses. */
463
+ export declare function subtaskFromPlace(intent: PlaceIntent, id: string): Subtask;
464
+
465
+ /** A layer of subtasks. Several layers draw in the order they are declared. */
466
+ export declare function Subtasks({ data, tasks }: SubtasksProps): null;
467
+
468
+ export declare interface SubtasksProps {
469
+ /** The subtasks, as the caller holds them. The schedule never changes one. */
470
+ data: readonly Subtask[];
471
+ /** The tasks the subtasks belong to - their identity and their colour. A
472
+ subtask whose task is not among them is drawn in a muted colour. */
473
+ tasks: readonly Task[];
474
+ }
475
+
476
+ /** One whole undertaking. It is never drawn as a thing of its own: it shows as
477
+ the colour its subtasks share, and in selection, which takes all of it. */
478
+ export declare interface Task {
479
+ /** The caller's identity of the task. */
480
+ readonly id: string;
481
+ /** Any CSS colour - a literal, a token, `light-dark(…)`. The colour means what
482
+ the caller's domain needs it to mean. */
483
+ readonly color: string;
484
+ /** What the task is called, where the schedule names it. */
485
+ readonly name?: string;
486
+ }
487
+
488
+ /** Change the teardown on its own. */
489
+ export declare interface TeardownIntent {
490
+ readonly kind: "teardown";
491
+ /** The id of the subtask. */
492
+ readonly subtask: string;
493
+ /** The new duration of the teardown. */
494
+ readonly teardown: number;
495
+ }
496
+
497
+ /** A task's move between two of its subtasks: always from an end to a start. */
498
+ export declare interface Transport {
499
+ /** The caller's identity of the transport. */
500
+ readonly id: string;
501
+ /** The id of the subtask it leaves. */
502
+ readonly from: string;
503
+ /** The id of the subtask it arrives at. */
504
+ readonly to: string;
505
+ /** How long the move takes. */
506
+ readonly duration: number;
507
+ /** Where it leaves: at the end of the main time, or after the teardown.
508
+ Default `"teardown"` - the part leaves once the machine is cleared. */
509
+ readonly leaves?: "main" | "teardown";
510
+ /** Where it arrives: at the start of the main time, or before the setup.
511
+ Default `"setup"` - the part must be there before the machine is set up. */
512
+ readonly arrives?: "main" | "setup";
513
+ /** How this one is drawn, where it is not drawn like the rest. It changes
514
+ the picture and never the finding: whether a transport is late follows
515
+ from `leaves` and `arrives` alone. */
516
+ readonly route?: TransportRoute;
517
+ /** Where on the bars this one's line attaches, where it does not attach like
518
+ the rest. Also picture only, and not to be confused with the two anchors
519
+ above: those say what the transport connects, this says where the line
520
+ touches. */
521
+ readonly attach?: TransportAttachment;
522
+ /** Whether this one's ends are marked with a dot, where it is not marked
523
+ like the rest. Also picture only. */
524
+ readonly ends?: TransportEnds;
525
+ }
526
+
527
+ /** Where on its bars a transport's line attaches: the middle of both, or the
528
+ edge that faces the other stop - which is the shortest line between them.
529
+
530
+ Deliberately not called an anchor: a transport already HAS two anchors
531
+ (`leaves`, `arrives`), and those decide what it connects and therefore
532
+ whether it is late. This decides where the line touches, and nothing else.
533
+ The tree has an **Anchor** of its own as well (CONTEXT.md). */
534
+ export declare type TransportAttachment = "centre" | "nearest";
535
+
536
+ /** Whether a transport's two ends carry a dot. The dot says where the line is
537
+ anchored, which is worth saying while a plan is being read and is noise in a
538
+ plan full of short moves - so it is the caller's choice. */
539
+ export declare type TransportEnds = "dot" | "none";
540
+
541
+ /** How a transport is drawn between its two ends: a curve that leaves and
542
+ arrives forwards, a straight line, or axis-parallel segments. */
543
+ export declare type TransportRoute = "curve" | "straight" | "orthogonal";
544
+
545
+ /** A layer of transports. Declared before `Subtasks`, the lines run beneath the
546
+ bars; after them, above. */
547
+ export declare function Transports({ data }: TransportsProps): null;
548
+
549
+ export declare interface TransportsProps {
550
+ /** The transports, as the caller holds them. */
551
+ data: readonly Transport[];
552
+ }
553
+
554
+ /** The narrowest and the widest span zoom may reach. */
555
+ export declare interface ZoomLimits {
556
+ readonly min: number;
557
+ readonly max: number;
558
+ }
559
+
560
+ export { }
@@ -0,0 +1 @@
1
+ @layer umriss.tokens,umriss.base,umriss.components;@layer umriss.base{._text_18b86_23{font-family:var(--u-font-sans);font-size:var(--u-text-md);line-height:var(--u-leading-normal);color:var(--u-color-text);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}._field_18b86_34{caret-color:var(--u-color-accent)}._scroll_18b86_40{scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--u-color-text) 25%,transparent) transparent}._scroll_18b86_40::-webkit-scrollbar{width:10px;height:10px}._scroll_18b86_40::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--u-color-text) 22%,transparent);border-radius:var(--u-radius-full);border:3px solid transparent;background-clip:content-box}._scroll_18b86_40::-webkit-scrollbar-track{background:transparent}}@layer umriss.components{._ring_18b86_65:focus-visible{outline:none;box-shadow:var(--u-focus-ring)}._field_18b86_34:-webkit-autofill,._field_18b86_34:-webkit-autofill:hover,._field_18b86_34:-webkit-autofill:focus{-webkit-box-shadow:inset 0 0 0 1000px var(--u-color-surface),0 0 0 1px var(--u-edge-color-strong);-webkit-text-fill-color:var(--u-color-text);caret-color:var(--u-color-accent)}}@layer umriss.tokens,umriss.base,umriss.components;@layer umriss.components{._root_ekx9o_4,._root_ekx9o_4:before,._root_ekx9o_4:after{box-sizing:border-box}._corner_ekx9o_18,._corner_ekx9o_18:before,._corner_ekx9o_18:after{box-sizing:border-box}._dayBand_ekx9o_22,._dayBand_ekx9o_22:before,._dayBand_ekx9o_22:after{box-sizing:border-box}._tickBand_ekx9o_23,._tickBand_ekx9o_23:before,._tickBand_ekx9o_23:after{box-sizing:border-box}._day_ekx9o_22,._day_ekx9o_22:before,._day_ekx9o_22:after{box-sizing:border-box}._dayLabel_ekx9o_46,._dayLabel_ekx9o_46:before,._dayLabel_ekx9o_46:after{box-sizing:border-box}._tick_ekx9o_23,._tick_ekx9o_23:before,._tick_ekx9o_23:after{box-sizing:border-box}._tickLabel_ekx9o_64,._tickLabel_ekx9o_64:before,._tickLabel_ekx9o_64:after{box-sizing:border-box}._headers_ekx9o_72,._headers_ekx9o_72:before,._headers_ekx9o_72:after{box-sizing:border-box}._header_ekx9o_72,._header_ekx9o_72:before,._header_ekx9o_72:after{box-sizing:border-box}._headerLabel_ekx9o_90,._headerLabel_ekx9o_90:before,._headerLabel_ekx9o_90:after{box-sizing:border-box}._headerCount_ekx9o_103,._headerCount_ekx9o_103:before,._headerCount_ekx9o_103:after{box-sizing:border-box}._chevron_ekx9o_112,._chevron_ekx9o_112:before,._chevron_ekx9o_112:after{box-sizing:border-box}._plot_ekx9o_160,._plot_ekx9o_160:before,._plot_ekx9o_160:after{box-sizing:border-box}._layer_ekx9o_166,._layer_ekx9o_166:before,._layer_ekx9o_166:after{box-sizing:border-box}._grip_ekx9o_175,._grip_ekx9o_175:before,._grip_ekx9o_175:after{box-sizing:border-box}._ghostLabel_ekx9o_185,._ghostLabel_ekx9o_185:before,._ghostLabel_ekx9o_185:after{box-sizing:border-box}._finding_ekx9o_198,._finding_ekx9o_198:before,._finding_ekx9o_198:after{box-sizing:border-box}._refusal_ekx9o_206,._refusal_ekx9o_206:before,._refusal_ekx9o_206:after{box-sizing:border-box}._tooltip_ekx9o_210,._tooltip_ekx9o_210:before,._tooltip_ekx9o_210:after{box-sizing:border-box}._tooltipHead_ekx9o_228,._tooltipHead_ekx9o_228:before,._tooltipHead_ekx9o_228:after{box-sizing:border-box}._tooltipTimes_ekx9o_233,._tooltipTimes_ekx9o_233:before,._tooltipTimes_ekx9o_233:after{box-sizing:border-box}._now_ekx9o_242,._now_ekx9o_242:before,._now_ekx9o_242:after{box-sizing:border-box}._barLabel_ekx9o_256,._barLabel_ekx9o_256:before,._barLabel_ekx9o_256:after{box-sizing:border-box}._barLabelText_ekx9o_269,._barLabelText_ekx9o_269:before,._barLabelText_ekx9o_269:after{box-sizing:border-box}._root_ekx9o_4{display:grid;grid-template-rows:28px minmax(0,1fr) 28px;width:100%;font-size:var(--u-text-sm);background:var(--u-color-surface);box-shadow:var(--u-edge);border-radius:var(--u-radius-md);corner-shape:squircle;overflow:hidden;font-variant-numeric:tabular-nums;-webkit-user-select:none;user-select:none}._corner_ekx9o_18{background:var(--u-color-surface)}._dayBand_ekx9o_22,._tickBand_ekx9o_23{position:relative;overflow:hidden;color:var(--u-color-text-muted);font-size:var(--u-text-xs)}._dayBand_ekx9o_22{border-bottom:1px solid var(--u-hairline-strong)}._tickBand_ekx9o_23{border-top:1px solid var(--u-hairline-strong)}._day_ekx9o_22{position:absolute;top:0;bottom:0;border-left:1px solid var(--u-hairline-strong);overflow:hidden}._dayLabel_ekx9o_46{position:absolute;left:var(--u-space-2);top:50%;transform:translateY(-50%);white-space:nowrap;color:var(--u-color-text);font-weight:var(--u-weight-medium)}._tick_ekx9o_23{position:absolute;top:0;bottom:0;width:1px;background:var(--u-hairline)}._tickLabel_ekx9o_64{position:absolute;top:50%;left:0;transform:translate(-50%,-50%);white-space:nowrap}._headers_ekx9o_72{position:relative;overflow:hidden;border-right:1px solid var(--u-hairline-strong)}._header_ekx9o_72{display:flex;align-items:center;gap:var(--u-space-2);padding-right:var(--u-space-3);border-bottom:1px solid var(--u-hairline);overflow:hidden;white-space:nowrap}._headerLabel_ekx9o_90{min-width:0;overflow:hidden;text-overflow:ellipsis}._header_ekx9o_72[data-row=groupHead],._header_ekx9o_72[data-row=miniature]{font-weight:var(--u-weight-medium)}._headerCount_ekx9o_103{flex:none;color:var(--u-color-text-muted);font-size:var(--u-text-xs);font-variant-numeric:tabular-nums}._chevron_ekx9o_112{flex:none;display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;border-radius:var(--u-radius-xs);corner-shape:squircle;background:transparent;color:var(--u-color-text-secondary);cursor:pointer}._chevron_ekx9o_112:hover{color:var(--u-color-text)}._chevron_ekx9o_112:focus-visible{outline:none;box-shadow:var(--u-focus-ring);color:var(--u-color-text)}._chevron_ekx9o_112 svg{box-sizing:border-box}._chevron_ekx9o_112 svg{transition:transform var(--u-duration-fast) var(--u-ease-standard)}._chevron_ekx9o_112 svg[data-open]{box-sizing:border-box}._chevron_ekx9o_112 svg[data-open]{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){._chevron_ekx9o_112 svg{transition:none}}._header_ekx9o_72[data-refused]{color:var(--u-color-text-muted)}._plot_ekx9o_160{position:relative;overflow:hidden;touch-action:none}._layer_ekx9o_166{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;display:block;pointer-events:none}._grip_ekx9o_175{position:absolute;width:9px;margin-left:-4px;border-radius:var(--u-radius-xs);corner-shape:squircle;background:var(--u-color-surface);box-shadow:inset 0 0 0 1.5px var(--u-color-text);cursor:ew-resize}._ghostLabel_ekx9o_185{position:absolute;display:inline-flex;gap:var(--u-space-2);padding:1px var(--u-space-2);border-radius:var(--u-radius-sm);corner-shape:squircle;background:var(--u-color-text);color:var(--u-color-surface);font-size:var(--u-text-xs);white-space:nowrap;pointer-events:none}._finding_ekx9o_198{font-weight:var(--u-weight-semibold);color:var(--u-color-danger-subtle)}._refusal_ekx9o_206{font-weight:var(--u-weight-semibold)}._tooltip_ekx9o_210{position:absolute;z-index:1;display:flex;flex-direction:column;gap:1px;max-width:260px;padding:var(--u-space-2) var(--u-space-3);border-radius:var(--u-radius-sm);corner-shape:squircle;background:var(--u-color-surface);box-shadow:var(--u-shadow-overlay);color:var(--u-color-text-secondary);font-size:var(--u-text-xs);line-height:var(--u-leading-tight);pointer-events:none;white-space:nowrap}._tooltipHead_ekx9o_228{color:var(--u-color-text);font-weight:var(--u-weight-semibold)}._tooltipTimes_ekx9o_233{color:var(--u-color-text)}._tooltip_ekx9o_210 ._finding_ekx9o_198{color:var(--u-color-danger)}._now_ekx9o_242{position:absolute;top:0;width:0;height:0;margin-left:-4px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:6px solid var(--u-color-accent)}._barLabel_ekx9o_256{position:absolute;display:flex;align-items:center;padding:0 var(--u-space-1);overflow:hidden;font-size:var(--u-text-xs);line-height:var(--u-leading-tight);pointer-events:none}._barLabelText_ekx9o_269{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}._barLabel_ekx9o_256[data-on=dark]{color:var(--u-color-on-accent)}._barLabel_ekx9o_256[data-on=light]{color:var(--u-color-text)}}