Part of #22853 (event-scheduling umbrella) — widens the FS foundation.
#23393 makes the new dependency types work (the engine enforces them); this issue makes them visible and creatable: render the SS/FF/SF arrows on the timeline and let users create them by dragging terminals, extending the FS-only rendering (#22855) and creation flow (#22856).
Arrow geometry per type
Each type connects different edges of the two events:
| Type |
From edge |
To edge |
| FS |
end |
start |
| SS |
start |
start |
| FF |
end |
end |
| SF |
start |
end |
Picking the anchor points is the easy part: the geometry resolver already exposes getEdgePoint(anchor, 'start' | 'end'), so the per-type anchors are just a parameter.
The real work is the orthogonal routing — the path the arrow draws between those two points. Today's routing (~800 lines) only knows the end → start journey. Each new type brings its own layouts to solve: SS with the successor starting left of the predecessor, FF wrapping around the successor's right edge, and so on — including the "backwards" layouts where the data already violates the constraint. Benchmark the shapes against Bryntum before inventing.
The arrowhead stays at the target end of the relationship, whatever edge that is.
Start-edge terminals
Today only the end-edge terminal exists — which is why only FS can be created by gesture. Adding the start-edge terminal, on both source and target, completes the umbrella's implicit type selection: the type is defined by which edge you drag from and which edge you drop on (fromSide / toSide → type).
Concretely: the creation-drag state already models sourceSide; the drop side needs the equivalent, and addDependency receives the resolved type.
The creation rules (recurring / read-only / duplicate / cycle rejection) are type-agnostic and reuse #22856's flow untouched — with one adjustment: duplicate detection must allow two dependencies of different types between the same pair of events, matching the vendors (the code already carries a TODO for this).
Accessibility
Extend the existing FS aria-describedby wording (#22855) with a per-type sentence — "starts together with", "cannot finish until … finishes", etc. — and include the lag when present. Same design as today: aria-hidden arrow, description on the successor.
Open questions
- Violated-dependency rendering: with push-only, a broken constraint can stay on screen (read-only successor, violations already present in the data), and today the only cue is the arrow's shape — the backwards S route. No distinct styling, no
data-* attribute to target, nothing announced to assistive tech. The geometry already knows when it routes the backwards case, so exposing it (e.g. a data-violated attribute on the arrow) would be cheap and would enable a distinct look (color/dash), and possibly a mention in the aria-describedby wording. To decide: do we want a violated state at all, and how far does it go (styling hook only vs tooltip/announcement)? It applies to FS today, but the backwards layouts multiply with the new types, so this issue is its natural home.
Tests
- Geometry snapshots per type, including violated ("backwards") layouts and multi-resource rows.
- Terminal gesture → resolved type, for all four from/to combinations.
- Description wording per type.
Out of scope
Part of #22853 (event-scheduling umbrella) — widens the FS foundation.
#23393 makes the new dependency types work (the engine enforces them); this issue makes them visible and creatable: render the SS/FF/SF arrows on the timeline and let users create them by dragging terminals, extending the FS-only rendering (#22855) and creation flow (#22856).
Arrow geometry per type
Each type connects different edges of the two events:
Picking the anchor points is the easy part: the geometry resolver already exposes
getEdgePoint(anchor, 'start' | 'end'), so the per-type anchors are just a parameter.The real work is the orthogonal routing — the path the arrow draws between those two points. Today's routing (~800 lines) only knows the end → start journey. Each new type brings its own layouts to solve: SS with the successor starting left of the predecessor, FF wrapping around the successor's right edge, and so on — including the "backwards" layouts where the data already violates the constraint. Benchmark the shapes against Bryntum before inventing.
The arrowhead stays at the target end of the relationship, whatever edge that is.
Start-edge terminals
Today only the end-edge terminal exists — which is why only FS can be created by gesture. Adding the start-edge terminal, on both source and target, completes the umbrella's implicit type selection: the type is defined by which edge you drag from and which edge you drop on (
fromSide/toSide→ type).Concretely: the creation-drag state already models
sourceSide; the drop side needs the equivalent, andaddDependencyreceives the resolved type.The creation rules (recurring / read-only / duplicate / cycle rejection) are type-agnostic and reuse #22856's flow untouched — with one adjustment: duplicate detection must allow two dependencies of different types between the same pair of events, matching the vendors (the code already carries a TODO for this).
Accessibility
Extend the existing FS
aria-describedbywording (#22855) with a per-type sentence — "starts together with", "cannot finish until … finishes", etc. — and include the lag when present. Same design as today:aria-hiddenarrow, description on the successor.Open questions
data-*attribute to target, nothing announced to assistive tech. The geometry already knows when it routes the backwards case, so exposing it (e.g. adata-violatedattribute on the arrow) would be cheap and would enable a distinct look (color/dash), and possibly a mention in thearia-describedbywording. To decide: do we want a violated state at all, and how far does it go (styling hook only vs tooltip/announcement)? It applies to FS today, but the backwards layouts multiply with the new types, so this issue is its natural home.Tests
Out of scope