@nowline/layout 0.8.6 → 0.10.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.
Files changed (338) hide show
  1. package/dist/axis-columns.d.ts +70 -0
  2. package/dist/axis-columns.d.ts.map +1 -0
  3. package/dist/axis-columns.js +104 -0
  4. package/dist/axis-columns.js.map +1 -0
  5. package/dist/calendar-resolver.d.ts +27 -0
  6. package/dist/calendar-resolver.d.ts.map +1 -0
  7. package/dist/calendar-resolver.js +132 -0
  8. package/dist/calendar-resolver.js.map +1 -0
  9. package/dist/calendar.d.ts +0 -19
  10. package/dist/calendar.d.ts.map +1 -1
  11. package/dist/calendar.js +4 -44
  12. package/dist/calendar.js.map +1 -1
  13. package/dist/canvas-width.d.ts +23 -0
  14. package/dist/canvas-width.d.ts.map +1 -0
  15. package/dist/canvas-width.js +26 -0
  16. package/dist/canvas-width.js.map +1 -0
  17. package/dist/capacity.d.ts +28 -0
  18. package/dist/capacity.d.ts.map +1 -1
  19. package/dist/capacity.js +64 -29
  20. package/dist/capacity.js.map +1 -1
  21. package/dist/chart-translation.d.ts +22 -0
  22. package/dist/chart-translation.d.ts.map +1 -0
  23. package/dist/chart-translation.js +83 -0
  24. package/dist/chart-translation.js.map +1 -0
  25. package/dist/container-header-geometry.d.ts +64 -0
  26. package/dist/container-header-geometry.d.ts.map +1 -0
  27. package/dist/container-header-geometry.js +89 -0
  28. package/dist/container-header-geometry.js.map +1 -0
  29. package/dist/dsl-utils.d.ts +3 -4
  30. package/dist/dsl-utils.d.ts.map +1 -1
  31. package/dist/dsl-utils.js +8 -25
  32. package/dist/dsl-utils.js.map +1 -1
  33. package/dist/edge-routing.d.ts +69 -78
  34. package/dist/edge-routing.d.ts.map +1 -1
  35. package/dist/edge-routing.js +271 -401
  36. package/dist/edge-routing.js.map +1 -1
  37. package/dist/frame-tab-geometry.d.ts +24 -14
  38. package/dist/frame-tab-geometry.d.ts.map +1 -1
  39. package/dist/frame-tab-geometry.js +69 -23
  40. package/dist/frame-tab-geometry.js.map +1 -1
  41. package/dist/header-card-geometry.d.ts +12 -0
  42. package/dist/header-card-geometry.d.ts.map +1 -1
  43. package/dist/header-card-geometry.js +14 -2
  44. package/dist/header-card-geometry.js.map +1 -1
  45. package/dist/header-logo.d.ts +28 -0
  46. package/dist/header-logo.d.ts.map +1 -0
  47. package/dist/header-logo.js +51 -0
  48. package/dist/header-logo.js.map +1 -0
  49. package/dist/i18n.d.ts +11 -0
  50. package/dist/i18n.d.ts.map +1 -1
  51. package/dist/i18n.js +11 -1
  52. package/dist/i18n.js.map +1 -1
  53. package/dist/index.d.ts +20 -8
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +17 -7
  56. package/dist/index.js.map +1 -1
  57. package/dist/inline-date-pin-geometry.d.ts +19 -11
  58. package/dist/inline-date-pin-geometry.d.ts.map +1 -1
  59. package/dist/inline-date-pin-geometry.js +45 -46
  60. package/dist/inline-date-pin-geometry.js.map +1 -1
  61. package/dist/item-bar-geometry.d.ts +192 -4
  62. package/dist/item-bar-geometry.d.ts.map +1 -1
  63. package/dist/item-bar-geometry.js +258 -5
  64. package/dist/item-bar-geometry.js.map +1 -1
  65. package/dist/item-port-geometry.d.ts +13 -0
  66. package/dist/item-port-geometry.d.ts.map +1 -0
  67. package/dist/item-port-geometry.js +63 -0
  68. package/dist/item-port-geometry.js.map +1 -0
  69. package/dist/layout-context.d.ts +115 -51
  70. package/dist/layout-context.d.ts.map +1 -1
  71. package/dist/layout-context.js +96 -5
  72. package/dist/layout-context.js.map +1 -1
  73. package/dist/layout-insights.d.ts.map +1 -1
  74. package/dist/layout-insights.js +73 -1
  75. package/dist/layout-insights.js.map +1 -1
  76. package/dist/layout.d.ts +35 -0
  77. package/dist/layout.d.ts.map +1 -1
  78. package/dist/layout.js +18 -1315
  79. package/dist/layout.js.map +1 -1
  80. package/dist/nodes/anchor-node.d.ts.map +1 -1
  81. package/dist/nodes/anchor-node.js +11 -4
  82. package/dist/nodes/anchor-node.js.map +1 -1
  83. package/dist/nodes/content-extent.d.ts +24 -0
  84. package/dist/nodes/content-extent.d.ts.map +1 -0
  85. package/dist/nodes/content-extent.js +100 -0
  86. package/dist/nodes/content-extent.js.map +1 -0
  87. package/dist/nodes/dependency-edges.d.ts +6 -0
  88. package/dist/nodes/dependency-edges.d.ts.map +1 -0
  89. package/dist/nodes/dependency-edges.js +148 -0
  90. package/dist/nodes/dependency-edges.js.map +1 -0
  91. package/dist/nodes/footnote-node.d.ts +24 -3
  92. package/dist/nodes/footnote-node.d.ts.map +1 -1
  93. package/dist/nodes/footnote-node.js +129 -25
  94. package/dist/nodes/footnote-node.js.map +1 -1
  95. package/dist/nodes/group-node.d.ts +10 -21
  96. package/dist/nodes/group-node.d.ts.map +1 -1
  97. package/dist/nodes/group-node.js +79 -152
  98. package/dist/nodes/group-node.js.map +1 -1
  99. package/dist/nodes/header-node.d.ts +56 -0
  100. package/dist/nodes/header-node.d.ts.map +1 -0
  101. package/dist/nodes/header-node.js +163 -0
  102. package/dist/nodes/header-node.js.map +1 -0
  103. package/dist/nodes/include-node.d.ts +22 -12
  104. package/dist/nodes/include-node.d.ts.map +1 -1
  105. package/dist/nodes/include-node.js +95 -62
  106. package/dist/nodes/include-node.js.map +1 -1
  107. package/dist/nodes/item-measure.d.ts +135 -0
  108. package/dist/nodes/item-measure.d.ts.map +1 -0
  109. package/dist/nodes/item-measure.js +514 -0
  110. package/dist/nodes/item-measure.js.map +1 -0
  111. package/dist/nodes/item-node.d.ts +162 -9
  112. package/dist/nodes/item-node.d.ts.map +1 -1
  113. package/dist/nodes/item-node.js +256 -69
  114. package/dist/nodes/item-node.js.map +1 -1
  115. package/dist/nodes/marker-band.d.ts +118 -0
  116. package/dist/nodes/marker-band.d.ts.map +1 -0
  117. package/dist/nodes/marker-band.js +303 -0
  118. package/dist/nodes/marker-band.js.map +1 -0
  119. package/dist/nodes/marker-geometry.js +1 -1
  120. package/dist/nodes/marker-geometry.js.map +1 -1
  121. package/dist/nodes/milestone-node.d.ts +112 -15
  122. package/dist/nodes/milestone-node.d.ts.map +1 -1
  123. package/dist/nodes/milestone-node.js +246 -95
  124. package/dist/nodes/milestone-node.js.map +1 -1
  125. package/dist/nodes/nowline-node.d.ts +8 -0
  126. package/dist/nodes/nowline-node.d.ts.map +1 -0
  127. package/dist/nodes/nowline-node.js +74 -0
  128. package/dist/nodes/nowline-node.js.map +1 -0
  129. package/dist/nodes/parallel-node.d.ts +7 -12
  130. package/dist/nodes/parallel-node.d.ts.map +1 -1
  131. package/dist/nodes/parallel-node.js +66 -30
  132. package/dist/nodes/parallel-node.js.map +1 -1
  133. package/dist/nodes/region-markers.d.ts +41 -0
  134. package/dist/nodes/region-markers.d.ts.map +1 -0
  135. package/dist/nodes/region-markers.js +130 -0
  136. package/dist/nodes/region-markers.js.map +1 -0
  137. package/dist/nodes/roadmap-node.d.ts +9 -72
  138. package/dist/nodes/roadmap-node.d.ts.map +1 -1
  139. package/dist/nodes/roadmap-node.js +38 -788
  140. package/dist/nodes/roadmap-node.js.map +1 -1
  141. package/dist/nodes/row-track.d.ts +33 -0
  142. package/dist/nodes/row-track.d.ts.map +1 -0
  143. package/dist/nodes/row-track.js +170 -0
  144. package/dist/nodes/row-track.js.map +1 -0
  145. package/dist/nodes/sequence-item.d.ts +25 -0
  146. package/dist/nodes/sequence-item.d.ts.map +1 -0
  147. package/dist/nodes/sequence-item.js +396 -0
  148. package/dist/nodes/sequence-item.js.map +1 -0
  149. package/dist/nodes/sequence-one.d.ts +5 -0
  150. package/dist/nodes/sequence-one.d.ts.map +1 -0
  151. package/dist/nodes/sequence-one.js +26 -0
  152. package/dist/nodes/sequence-one.js.map +1 -0
  153. package/dist/nodes/swimlane-node.d.ts +5 -17
  154. package/dist/nodes/swimlane-node.d.ts.map +1 -1
  155. package/dist/nodes/swimlane-node.js +62 -145
  156. package/dist/nodes/swimlane-node.js.map +1 -1
  157. package/dist/nodes/wave-node.d.ts +52 -0
  158. package/dist/nodes/wave-node.d.ts.map +1 -0
  159. package/dist/nodes/wave-node.js +483 -0
  160. package/dist/nodes/wave-node.js.map +1 -0
  161. package/dist/non-working-display.d.ts +14 -0
  162. package/dist/non-working-display.d.ts.map +1 -0
  163. package/dist/non-working-display.js +28 -0
  164. package/dist/non-working-display.js.map +1 -0
  165. package/dist/phases/date-window.d.ts +48 -0
  166. package/dist/phases/date-window.d.ts.map +1 -0
  167. package/dist/phases/date-window.js +130 -0
  168. package/dist/phases/date-window.js.map +1 -0
  169. package/dist/phases/finalize.d.ts +198 -0
  170. package/dist/phases/finalize.d.ts.map +1 -0
  171. package/dist/phases/finalize.js +1058 -0
  172. package/dist/phases/finalize.js.map +1 -0
  173. package/dist/phases/measure.d.ts +77 -0
  174. package/dist/phases/measure.d.ts.map +1 -0
  175. package/dist/phases/measure.js +222 -0
  176. package/dist/phases/measure.js.map +1 -0
  177. package/dist/phases/place.d.ts +28 -0
  178. package/dist/phases/place.d.ts.map +1 -0
  179. package/dist/phases/place.js +225 -0
  180. package/dist/phases/place.js.map +1 -0
  181. package/dist/renderable.d.ts.map +1 -1
  182. package/dist/renderable.js +23 -3
  183. package/dist/renderable.js.map +1 -1
  184. package/dist/resolve-today.d.ts +11 -1
  185. package/dist/resolve-today.d.ts.map +1 -1
  186. package/dist/resolve-today.js +26 -12
  187. package/dist/resolve-today.js.map +1 -1
  188. package/dist/row-packer.d.ts +42 -16
  189. package/dist/row-packer.d.ts.map +1 -1
  190. package/dist/row-packer.js +51 -78
  191. package/dist/row-packer.js.map +1 -1
  192. package/dist/schedule.d.ts +58 -1
  193. package/dist/schedule.d.ts.map +1 -1
  194. package/dist/schedule.js +280 -106
  195. package/dist/schedule.js.map +1 -1
  196. package/dist/start-rules.d.ts +27 -0
  197. package/dist/start-rules.d.ts.map +1 -0
  198. package/dist/start-rules.js +91 -0
  199. package/dist/start-rules.js.map +1 -0
  200. package/dist/start-terms.d.ts +23 -0
  201. package/dist/start-terms.d.ts.map +1 -0
  202. package/dist/start-terms.js +27 -0
  203. package/dist/start-terms.js.map +1 -0
  204. package/dist/status-dot.d.ts +46 -0
  205. package/dist/status-dot.d.ts.map +1 -0
  206. package/dist/status-dot.js +78 -0
  207. package/dist/status-dot.js.map +1 -0
  208. package/dist/style-resolution.d.ts.map +1 -1
  209. package/dist/style-resolution.js +23 -43
  210. package/dist/style-resolution.js.map +1 -1
  211. package/dist/text-measure.d.ts +28 -0
  212. package/dist/text-measure.d.ts.map +1 -0
  213. package/dist/text-measure.js +70 -0
  214. package/dist/text-measure.js.map +1 -0
  215. package/dist/themes/contrast.d.ts +4 -0
  216. package/dist/themes/contrast.d.ts.map +1 -0
  217. package/dist/themes/contrast.js +32 -0
  218. package/dist/themes/contrast.js.map +1 -0
  219. package/dist/themes/dark.d.ts.map +1 -1
  220. package/dist/themes/dark.js +28 -1
  221. package/dist/themes/dark.js.map +1 -1
  222. package/dist/themes/grayscale.d.ts.map +1 -1
  223. package/dist/themes/grayscale.js +28 -1
  224. package/dist/themes/grayscale.js.map +1 -1
  225. package/dist/themes/index.d.ts +4 -11
  226. package/dist/themes/index.d.ts.map +1 -1
  227. package/dist/themes/index.js +6 -4
  228. package/dist/themes/index.js.map +1 -1
  229. package/dist/themes/light.d.ts.map +1 -1
  230. package/dist/themes/light.js +28 -1
  231. package/dist/themes/light.js.map +1 -1
  232. package/dist/themes/shape.d.ts +31 -0
  233. package/dist/themes/shape.d.ts.map +1 -1
  234. package/dist/themes/shared.d.ts +44 -50
  235. package/dist/themes/shared.d.ts.map +1 -1
  236. package/dist/themes/shared.js +79 -83
  237. package/dist/themes/shared.js.map +1 -1
  238. package/dist/time-scale.d.ts +42 -6
  239. package/dist/time-scale.d.ts.map +1 -1
  240. package/dist/time-scale.js +109 -17
  241. package/dist/time-scale.js.map +1 -1
  242. package/dist/types.d.ts +528 -11
  243. package/dist/types.d.ts.map +1 -1
  244. package/dist/view-preset.d.ts +61 -6
  245. package/dist/view-preset.d.ts.map +1 -1
  246. package/dist/view-preset.js +439 -24
  247. package/dist/view-preset.js.map +1 -1
  248. package/dist/wave-barrier.d.ts +107 -0
  249. package/dist/wave-barrier.d.ts.map +1 -0
  250. package/dist/wave-barrier.js +174 -0
  251. package/dist/wave-barrier.js.map +1 -0
  252. package/dist/wave-hatch.d.ts +4 -0
  253. package/dist/wave-hatch.d.ts.map +1 -0
  254. package/dist/wave-hatch.js +21 -0
  255. package/dist/wave-hatch.js.map +1 -0
  256. package/dist/wave-layout.d.ts +99 -0
  257. package/dist/wave-layout.d.ts.map +1 -0
  258. package/dist/wave-layout.js +130 -0
  259. package/dist/wave-layout.js.map +1 -0
  260. package/dist/working-calendar.d.ts +128 -4
  261. package/dist/working-calendar.d.ts.map +1 -1
  262. package/dist/working-calendar.js +725 -51
  263. package/dist/working-calendar.js.map +1 -1
  264. package/dist/working-span.d.ts +11 -0
  265. package/dist/working-span.d.ts.map +1 -0
  266. package/dist/working-span.js +18 -0
  267. package/dist/working-span.js.map +1 -0
  268. package/package.json +4 -4
  269. package/src/axis-columns.ts +140 -0
  270. package/src/calendar-resolver.ts +161 -0
  271. package/src/calendar.ts +4 -45
  272. package/src/canvas-width.ts +36 -0
  273. package/src/capacity.ts +71 -30
  274. package/src/chart-translation.ts +88 -0
  275. package/src/container-header-geometry.ts +116 -0
  276. package/src/dsl-utils.ts +8 -26
  277. package/src/edge-routing.ts +347 -491
  278. package/src/frame-tab-geometry.ts +78 -25
  279. package/src/header-card-geometry.ts +17 -2
  280. package/src/header-logo.ts +67 -0
  281. package/src/i18n.ts +22 -1
  282. package/src/index.ts +97 -12
  283. package/src/inline-date-pin-geometry.ts +55 -58
  284. package/src/item-bar-geometry.ts +341 -5
  285. package/src/item-port-geometry.ts +69 -0
  286. package/src/layout-context.ts +210 -72
  287. package/src/layout-insights.ts +109 -2
  288. package/src/layout.ts +57 -1530
  289. package/src/nodes/anchor-node.ts +11 -4
  290. package/src/nodes/content-extent.ts +107 -0
  291. package/src/nodes/dependency-edges.ts +171 -0
  292. package/src/nodes/footnote-node.ts +171 -31
  293. package/src/nodes/group-node.ts +92 -214
  294. package/src/nodes/header-node.ts +255 -0
  295. package/src/nodes/include-node.ts +124 -110
  296. package/src/nodes/item-measure.ts +723 -0
  297. package/src/nodes/item-node.ts +358 -80
  298. package/src/nodes/marker-band.ts +406 -0
  299. package/src/nodes/marker-geometry.ts +1 -1
  300. package/src/nodes/milestone-node.ts +321 -136
  301. package/src/nodes/nowline-node.ts +87 -0
  302. package/src/nodes/parallel-node.ts +69 -38
  303. package/src/nodes/region-markers.ts +194 -0
  304. package/src/nodes/roadmap-node.ts +46 -950
  305. package/src/nodes/row-track.ts +217 -0
  306. package/src/nodes/sequence-item.ts +433 -0
  307. package/src/nodes/sequence-one.ts +40 -0
  308. package/src/nodes/swimlane-node.ts +66 -205
  309. package/src/nodes/wave-node.ts +609 -0
  310. package/src/non-working-display.ts +32 -0
  311. package/src/phases/date-window.ts +191 -0
  312. package/src/phases/finalize.ts +1303 -0
  313. package/src/phases/measure.ts +329 -0
  314. package/src/phases/place.ts +318 -0
  315. package/src/renderable.ts +23 -3
  316. package/src/resolve-today.ts +28 -25
  317. package/src/row-packer.ts +85 -84
  318. package/src/schedule.ts +362 -114
  319. package/src/start-rules.ts +113 -0
  320. package/src/start-terms.ts +38 -0
  321. package/src/status-dot.ts +81 -0
  322. package/src/style-resolution.ts +27 -57
  323. package/src/text-measure.ts +71 -0
  324. package/src/themes/contrast.ts +34 -0
  325. package/src/themes/dark.ts +28 -1
  326. package/src/themes/grayscale.ts +28 -1
  327. package/src/themes/index.ts +10 -7
  328. package/src/themes/light.ts +28 -1
  329. package/src/themes/shape.ts +38 -0
  330. package/src/themes/shared.ts +85 -93
  331. package/src/time-scale.ts +117 -19
  332. package/src/types.ts +529 -20
  333. package/src/view-preset.ts +520 -27
  334. package/src/wave-barrier.ts +242 -0
  335. package/src/wave-hatch.ts +25 -0
  336. package/src/wave-layout.ts +203 -0
  337. package/src/working-calendar.ts +875 -57
  338. package/src/working-span.ts +19 -0
@@ -5,24 +5,20 @@
5
5
  // reserved 18 px above the first region; subsequent regions are
6
6
  // separated by GAP_BETWEEN_REGIONS px.
7
7
 
8
- import type {
9
- EntityProperty,
10
- GroupBlock,
11
- IsolatedRegion,
12
- ItemDeclaration,
13
- ParallelBlock,
14
- } from '@nowline/core';
15
- import { resolveSizes } from '../calendar.js';
8
+ import type { IsolatedRegion } from '@nowline/core';
9
+ import { translateSwimlaneY } from '../chart-translation.js';
16
10
  import { includeChromeGeometry } from '../include-chrome-geometry.js';
17
- import type { LayoutContext, TrackCursor } from '../layout-context.js';
11
+ import { createLayoutContext, type LayoutContext, type LayoutHelpers } from '../layout-context.js';
18
12
  import { resolveStyle } from '../style-resolution.js';
19
- import type {
20
- BoundingBox,
21
- PositionedIncludeRegion,
22
- PositionedItem,
23
- PositionedSwimlane,
24
- PositionedTrackChild,
25
- } from '../types.js';
13
+ import type { BoundingBox, PositionedIncludeRegion, PositionedSwimlane } from '../types.js';
14
+ import { seedWaveEdges } from '../wave-layout.js';
15
+ import { maxLeafItemRightX } from './content-extent.js';
16
+ import { indexFootnotes } from './footnote-node.js';
17
+ import {
18
+ placeRegionMarkers,
19
+ regionMarkerLabelsRightX,
20
+ seedRegionAnchorEdges,
21
+ } from './region-markers.js';
26
22
  import { SwimlaneNode } from './swimlane-node.js';
27
23
 
28
24
  const TAB_RESERVE = 18;
@@ -31,103 +27,82 @@ const REGION_INSET_BOTTOM = 14;
31
27
  const GAP_BETWEEN_REGIONS = 16;
32
28
 
33
29
  // Visual breathing room added past the rightmost element when sizing
34
- // the include's bounding box. Keeps the dashed bracket from butting up
35
- // against an item's right edge while still trimming the wide
36
- // chart-width whitespace left over from full-width sizing.
37
- const INCLUDE_CONTENT_RIGHT_PAD_PX = 32;
38
-
39
- export interface IncludeNodeDeps {
40
- sequenceItem: (
41
- child: ItemDeclaration,
42
- cursor: TrackCursor,
43
- ctx: LayoutContext,
44
- ownerOverride?: string,
45
- ) => PositionedItem;
46
- sequenceOne: (
47
- child: ItemDeclaration | GroupBlock | ParallelBlock,
48
- cursor: TrackCursor,
49
- ctx: LayoutContext,
50
- ) => PositionedTrackChild;
51
- resolveChildStart: (
52
- props: EntityProperty[],
53
- seqDefault: number,
54
- laneLeftX: number,
55
- ctx: LayoutContext,
56
- ) => number;
57
- newCursor: (x: number, y: number) => TrackCursor;
58
- estimateTextWidth: (text: string, fontSize: number) => number;
59
- predictItemChipExtraHeight: (item: ItemDeclaration, ctx: LayoutContext) => number;
60
- }
30
+ // the include's bounding box. The rightmost element is the diagram's, not
31
+ // the region's own: every region reaches the same edge, past the furthest
32
+ // bar, spilled caption, marker or now-line anywhere in the chart. The
33
+ // renderer insets the dashed rect by 8 px, so its edge sits 16 px past it.
34
+ const INCLUDE_CONTENT_RIGHT_PAD_PX = 24;
61
35
 
62
36
  export function buildIncludeRegions(
63
37
  regions: IsolatedRegion[],
64
38
  ctx: LayoutContext,
65
39
  startY: number,
66
- deps: IncludeNodeDeps,
67
- ): { regions: PositionedIncludeRegion[]; endY: number } {
40
+ helpers: LayoutHelpers,
41
+ chartRightX: number,
42
+ ): { regions: PositionedIncludeRegion[]; contexts: LayoutContext[]; endY: number } {
68
43
  let y = startY + TAB_RESERVE;
69
44
  const out: PositionedIncludeRegion[] = [];
45
+ const contexts: LayoutContext[] = [];
70
46
  let isFirst = true;
47
+ // Region footnotes number on after the host's, in include order.
48
+ let footnotesBefore = ctx.footnoteIndex.size;
71
49
  for (const region of regions) {
72
50
  if (!isFirst) y += GAP_BETWEEN_REGIONS;
73
51
  isFirst = false;
74
52
  const label = region.content.roadmap?.title ?? region.sourcePath;
75
53
  const innerStartY = y + REGION_INSET_TOP;
76
- const childCtx: LayoutContext = {
77
- cal: ctx.cal,
78
- styleCtx: {
54
+ const childCtx = createLayoutContext(
55
+ region,
56
+ {
79
57
  theme: ctx.styleCtx.theme,
80
- styles: region.config.styles,
81
- defaults: region.config.defaults,
82
- labels: region.content.labels,
58
+ cal: ctx.cal,
59
+ schedule: ctx.schedule,
60
+ timeline: ctx.timeline,
61
+ scale: ctx.scale,
62
+ calendar: ctx.calendar,
63
+ axisColumns: ctx.axisColumns,
64
+ bandScale: ctx.bandScale,
65
+ waves: ctx.waves,
83
66
  },
84
- // Each include region declares its own sizes; resolve them under
85
- // the parent's calendar so child sized items render at the same
86
- // pixels-per-day scale as the host roadmap.
87
- sizes: resolveSizes(region.content.sizes, ctx.cal),
88
- labels: region.content.labels,
89
- teams: region.content.teams,
90
- persons: region.content.persons,
91
- symbols: region.config.symbols,
92
- footnoteIndex: new Map(),
93
- footnoteHosts: new Map(),
94
- timeline: ctx.timeline,
95
- scale: ctx.scale,
96
- calendar: ctx.calendar,
97
- bandScale: ctx.bandScale,
98
- entityLeftEdges: new Map(),
99
- entityRightEdges: new Map(),
100
- entityMidpoints: new Map(),
101
- entityVisualLeftX: new Map(),
102
- entityVisualRightX: new Map(),
103
- itemArrowSource: new Map(),
104
- itemFlowKey: new Map(),
105
- currentFlowKey: '',
106
- itemSlackAttachY: new Map(),
107
- slackCorridors: [],
108
- markerRowPlacements: new Map(),
109
- chartTopY: innerStartY,
110
- chartBottomY: innerStartY,
111
- swimlaneBottomY: innerStartY,
112
- chartRightX: ctx.chartRightX,
113
- nextParallelId: 0,
114
- nextGroupId: 0,
115
- };
67
+ {
68
+ chartTopY: innerStartY,
69
+ chartBottomY: innerStartY,
70
+ swimlaneBottomY: innerStartY,
71
+ },
72
+ { footnotes: indexFootnotes(region.content.footnotes, footnotesBefore) },
73
+ );
74
+ footnotesBefore += region.content.footnotes.size;
75
+ // Region ids stay invisible to the host, but the wave edges are
76
+ // shared: seed them into the region's otherwise empty edge maps.
77
+ // Without waves, the region's own dated anchors resolve inside it
78
+ // instead, as engine C's `scheduleRegion` resolves them, so a lane
79
+ // `after:kickoff` naming the region's anchor starts on its date
80
+ // (specs/scheduler-unification.md §5 F5).
81
+ if (ctx.waves) {
82
+ seedWaveEdges(ctx.waves, childCtx.entityLeftEdges, childCtx.entityRightEdges);
83
+ } else {
84
+ seedRegionAnchorEdges(region.content.anchors, childCtx);
85
+ }
116
86
  const nestedSwimlanes: PositionedSwimlane[] = [];
117
87
  let cursorY = innerStartY;
118
88
  let bandIndex = 0;
119
- let nestedContentRightX = childCtx.timeline.originX;
120
89
  for (const lane of region.content.swimlanes.values()) {
121
90
  childCtx.nextParallelId = 0;
122
91
  childCtx.nextGroupId = 0;
123
- const { positioned, usedHeight, usedRightX } = new SwimlaneNode(
124
- { lane, bandIndex },
125
- deps,
126
- ).place({ x: childCtx.timeline.originX, y: cursorY }, childCtx);
92
+ const { positioned, usedHeight } = new SwimlaneNode({ lane, bandIndex }, helpers).place(
93
+ { x: childCtx.timeline.originX, y: cursorY },
94
+ childCtx,
95
+ );
127
96
  nestedSwimlanes.push(positioned);
128
97
  cursorY += usedHeight;
129
98
  bandIndex++;
130
- if (usedRightX > nestedContentRightX) nestedContentRightX = usedRightX;
99
+ }
100
+ // The region's own anchors and milestones take a marker row under
101
+ // its label tab, and the lanes move down below it.
102
+ const markers = placeRegionMarkers(region, childCtx, y, innerStartY, cursorY, chartRightX);
103
+ if (markers.laneShift !== 0) {
104
+ for (const lane of nestedSwimlanes) translateSwimlaneY(lane, markers.laneShift);
105
+ cursorY += markers.laneShift;
131
106
  }
132
107
  const innerEndY = cursorY;
133
108
  // Floor the region height to one row's bandwidth so an empty or
@@ -137,36 +112,75 @@ export function buildIncludeRegions(
137
112
  ctx.bandScale.bandwidth(),
138
113
  innerEndY - y + REGION_INSET_BOTTOM,
139
114
  );
140
- // Shrink-wrap the include's bounding box to fit chrome + content
141
- // (with a small right pad) instead of stretching to the full
142
- // chart width. An include that reaches past the timeline still
143
- // gets clamped to the chart's natural right edge so it never
144
- // extends into the attribution / right-margin area.
145
- const boxX = 0;
146
- const { chromeRightX } = includeChromeGeometry(boxX, label, region.sourcePath);
147
- const naturalRightX =
148
- Math.max(chromeRightX, nestedContentRightX) + INCLUDE_CONTENT_RIGHT_PAD_PX;
149
- const boxWidth = Math.min(ctx.chartRightX - boxX, naturalRightX - boxX);
115
+ // The width waits for the final canvas: finalize (f4) fits every
116
+ // kept region with `fitIncludeRegionWidth` once the canvas stops
117
+ // growing, so placement never reads the canvas.
150
118
  const box: BoundingBox = {
151
- x: boxX,
119
+ x: 0,
152
120
  y,
153
- width: boxWidth,
121
+ width: 0,
154
122
  height: regionHeight,
155
123
  };
156
- // Mirror the shrunk width onto each nested swimlane band so the
157
- // tinted background fits inside the dashed bracket instead of
158
- // bleeding past it on the right.
159
- for (const lane of nestedSwimlanes) {
160
- lane.box.width = boxWidth;
161
- }
162
- out.push({
124
+ const positioned: PositionedIncludeRegion = {
163
125
  sourcePath: region.sourcePath,
164
126
  label,
165
127
  box,
166
128
  nestedSwimlanes,
167
129
  style: resolveStyle('swimlane', [], ctx.styleCtx),
168
- });
130
+ };
131
+ if (markers.anchors.length > 0) positioned.anchors = markers.anchors;
132
+ if (markers.milestones.length > 0) positioned.milestones = markers.milestones;
133
+ out.push(positioned);
134
+ contexts.push(childCtx);
169
135
  y += regionHeight;
170
136
  }
171
- return { regions: out, endY: y };
137
+ return { regions: out, contexts, endY: y };
138
+ }
139
+
140
+ /**
141
+ * Size an include's bounding box to the diagram's content: it reaches past
142
+ * `contentRightX`, the furthest bar, spilled caption, marker or now-line
143
+ * anywhere in the chart (and past its own chrome), by a small right pad,
144
+ * so every region in a chart ends at the same edge (specs/rendering.md,
145
+ * Included Roadmaps). It is clamped to `chartRightX`;
146
+ * finalize grows the canvas to hold the pad first (f3). Finalize runs it
147
+ * once per kept region (f4), after the canvas width is final: the spill
148
+ * growth, the timeline extension and the marker labels can all still grow
149
+ * the canvas after the region is placed.
150
+ */
151
+ export function fitIncludeRegionWidth(
152
+ region: PositionedIncludeRegion,
153
+ chartRightX: number,
154
+ contentRightX: number,
155
+ ): void {
156
+ const boxWidth = includeRegionWidth(region, chartRightX, contentRightX);
157
+ region.box.width = boxWidth;
158
+ // Mirror the shrunk width onto each nested swimlane band so the
159
+ // tinted background fits inside the dashed bracket instead of
160
+ // bleeding past it on the right.
161
+ for (const lane of region.nestedSwimlanes) {
162
+ lane.box.width = boxWidth;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * The width `fitIncludeRegionWidth` gives `region` on a canvas ending at
168
+ * `chartRightX`, with the diagram's content ending at `contentRightX`.
169
+ */
170
+ export function includeRegionWidth(
171
+ region: PositionedIncludeRegion,
172
+ chartRightX: number,
173
+ contentRightX: number,
174
+ ): number {
175
+ const boxX = region.box.x;
176
+ const { chromeRightX } = includeChromeGeometry(boxX, region.label, region.sourcePath);
177
+ // Bars-only extent (never a spilled caption — see
178
+ // `maxLeafItemRightX`), so a long trailing item caption inside
179
+ // the include can overhang the dashed bracket instead of
180
+ // dragging it wider.
181
+ const barsRightX = maxLeafItemRightX(region.nestedSwimlanes);
182
+ const naturalRightX =
183
+ Math.max(chromeRightX, barsRightX, regionMarkerLabelsRightX(region), contentRightX) +
184
+ INCLUDE_CONTENT_RIGHT_PAD_PX;
185
+ return Math.min(chartRightX - boxX, naturalRightX - boxX);
172
186
  }