@nowline/layout 0.8.5 → 0.9.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 (339) 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/band-scale.d.ts.map +1 -1
  6. package/dist/calendar-resolver.d.ts +27 -0
  7. package/dist/calendar-resolver.d.ts.map +1 -0
  8. package/dist/calendar-resolver.js +132 -0
  9. package/dist/calendar-resolver.js.map +1 -0
  10. package/dist/calendar.d.ts +0 -19
  11. package/dist/calendar.d.ts.map +1 -1
  12. package/dist/calendar.js +4 -44
  13. package/dist/calendar.js.map +1 -1
  14. package/dist/canvas-width.d.ts +23 -0
  15. package/dist/canvas-width.d.ts.map +1 -0
  16. package/dist/canvas-width.js +26 -0
  17. package/dist/canvas-width.js.map +1 -0
  18. package/dist/capacity.d.ts +28 -0
  19. package/dist/capacity.d.ts.map +1 -1
  20. package/dist/capacity.js +64 -29
  21. package/dist/capacity.js.map +1 -1
  22. package/dist/chart-translation.d.ts +22 -0
  23. package/dist/chart-translation.d.ts.map +1 -0
  24. package/dist/chart-translation.js +83 -0
  25. package/dist/chart-translation.js.map +1 -0
  26. package/dist/container-header-geometry.d.ts +64 -0
  27. package/dist/container-header-geometry.d.ts.map +1 -0
  28. package/dist/container-header-geometry.js +89 -0
  29. package/dist/container-header-geometry.js.map +1 -0
  30. package/dist/dsl-utils.d.ts +3 -4
  31. package/dist/dsl-utils.d.ts.map +1 -1
  32. package/dist/dsl-utils.js +8 -25
  33. package/dist/dsl-utils.js.map +1 -1
  34. package/dist/edge-routing.d.ts +69 -78
  35. package/dist/edge-routing.d.ts.map +1 -1
  36. package/dist/edge-routing.js +271 -401
  37. package/dist/edge-routing.js.map +1 -1
  38. package/dist/frame-tab-geometry.d.ts +24 -14
  39. package/dist/frame-tab-geometry.d.ts.map +1 -1
  40. package/dist/frame-tab-geometry.js +69 -23
  41. package/dist/frame-tab-geometry.js.map +1 -1
  42. package/dist/header-card-geometry.d.ts +12 -0
  43. package/dist/header-card-geometry.d.ts.map +1 -1
  44. package/dist/header-card-geometry.js +14 -2
  45. package/dist/header-card-geometry.js.map +1 -1
  46. package/dist/header-logo.d.ts +28 -0
  47. package/dist/header-logo.d.ts.map +1 -0
  48. package/dist/header-logo.js +51 -0
  49. package/dist/header-logo.js.map +1 -0
  50. package/dist/i18n.d.ts +11 -0
  51. package/dist/i18n.d.ts.map +1 -1
  52. package/dist/i18n.js +11 -1
  53. package/dist/i18n.js.map +1 -1
  54. package/dist/index.d.ts +20 -8
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +17 -7
  57. package/dist/index.js.map +1 -1
  58. package/dist/inline-date-pin-geometry.d.ts +19 -11
  59. package/dist/inline-date-pin-geometry.d.ts.map +1 -1
  60. package/dist/inline-date-pin-geometry.js +45 -46
  61. package/dist/inline-date-pin-geometry.js.map +1 -1
  62. package/dist/item-bar-geometry.d.ts +192 -4
  63. package/dist/item-bar-geometry.d.ts.map +1 -1
  64. package/dist/item-bar-geometry.js +258 -5
  65. package/dist/item-bar-geometry.js.map +1 -1
  66. package/dist/item-port-geometry.d.ts +13 -0
  67. package/dist/item-port-geometry.d.ts.map +1 -0
  68. package/dist/item-port-geometry.js +63 -0
  69. package/dist/item-port-geometry.js.map +1 -0
  70. package/dist/layout-context.d.ts +115 -51
  71. package/dist/layout-context.d.ts.map +1 -1
  72. package/dist/layout-context.js +96 -5
  73. package/dist/layout-context.js.map +1 -1
  74. package/dist/layout-insights.d.ts.map +1 -1
  75. package/dist/layout-insights.js +73 -1
  76. package/dist/layout-insights.js.map +1 -1
  77. package/dist/layout.d.ts +35 -0
  78. package/dist/layout.d.ts.map +1 -1
  79. package/dist/layout.js +18 -1315
  80. package/dist/layout.js.map +1 -1
  81. package/dist/nodes/anchor-node.d.ts.map +1 -1
  82. package/dist/nodes/anchor-node.js +11 -4
  83. package/dist/nodes/anchor-node.js.map +1 -1
  84. package/dist/nodes/content-extent.d.ts +24 -0
  85. package/dist/nodes/content-extent.d.ts.map +1 -0
  86. package/dist/nodes/content-extent.js +100 -0
  87. package/dist/nodes/content-extent.js.map +1 -0
  88. package/dist/nodes/dependency-edges.d.ts +6 -0
  89. package/dist/nodes/dependency-edges.d.ts.map +1 -0
  90. package/dist/nodes/dependency-edges.js +148 -0
  91. package/dist/nodes/dependency-edges.js.map +1 -0
  92. package/dist/nodes/footnote-node.d.ts +24 -3
  93. package/dist/nodes/footnote-node.d.ts.map +1 -1
  94. package/dist/nodes/footnote-node.js +129 -25
  95. package/dist/nodes/footnote-node.js.map +1 -1
  96. package/dist/nodes/group-node.d.ts +10 -21
  97. package/dist/nodes/group-node.d.ts.map +1 -1
  98. package/dist/nodes/group-node.js +79 -154
  99. package/dist/nodes/group-node.js.map +1 -1
  100. package/dist/nodes/header-node.d.ts +56 -0
  101. package/dist/nodes/header-node.d.ts.map +1 -0
  102. package/dist/nodes/header-node.js +163 -0
  103. package/dist/nodes/header-node.js.map +1 -0
  104. package/dist/nodes/include-node.d.ts +22 -12
  105. package/dist/nodes/include-node.d.ts.map +1 -1
  106. package/dist/nodes/include-node.js +95 -62
  107. package/dist/nodes/include-node.js.map +1 -1
  108. package/dist/nodes/item-measure.d.ts +135 -0
  109. package/dist/nodes/item-measure.d.ts.map +1 -0
  110. package/dist/nodes/item-measure.js +514 -0
  111. package/dist/nodes/item-measure.js.map +1 -0
  112. package/dist/nodes/item-node.d.ts +162 -9
  113. package/dist/nodes/item-node.d.ts.map +1 -1
  114. package/dist/nodes/item-node.js +256 -69
  115. package/dist/nodes/item-node.js.map +1 -1
  116. package/dist/nodes/marker-band.d.ts +118 -0
  117. package/dist/nodes/marker-band.d.ts.map +1 -0
  118. package/dist/nodes/marker-band.js +303 -0
  119. package/dist/nodes/marker-band.js.map +1 -0
  120. package/dist/nodes/marker-geometry.js +1 -1
  121. package/dist/nodes/marker-geometry.js.map +1 -1
  122. package/dist/nodes/milestone-node.d.ts +112 -15
  123. package/dist/nodes/milestone-node.d.ts.map +1 -1
  124. package/dist/nodes/milestone-node.js +246 -95
  125. package/dist/nodes/milestone-node.js.map +1 -1
  126. package/dist/nodes/nowline-node.d.ts +8 -0
  127. package/dist/nodes/nowline-node.d.ts.map +1 -0
  128. package/dist/nodes/nowline-node.js +74 -0
  129. package/dist/nodes/nowline-node.js.map +1 -0
  130. package/dist/nodes/parallel-node.d.ts +7 -12
  131. package/dist/nodes/parallel-node.d.ts.map +1 -1
  132. package/dist/nodes/parallel-node.js +66 -32
  133. package/dist/nodes/parallel-node.js.map +1 -1
  134. package/dist/nodes/region-markers.d.ts +41 -0
  135. package/dist/nodes/region-markers.d.ts.map +1 -0
  136. package/dist/nodes/region-markers.js +130 -0
  137. package/dist/nodes/region-markers.js.map +1 -0
  138. package/dist/nodes/roadmap-node.d.ts +9 -72
  139. package/dist/nodes/roadmap-node.d.ts.map +1 -1
  140. package/dist/nodes/roadmap-node.js +38 -788
  141. package/dist/nodes/roadmap-node.js.map +1 -1
  142. package/dist/nodes/row-track.d.ts +33 -0
  143. package/dist/nodes/row-track.d.ts.map +1 -0
  144. package/dist/nodes/row-track.js +170 -0
  145. package/dist/nodes/row-track.js.map +1 -0
  146. package/dist/nodes/sequence-item.d.ts +25 -0
  147. package/dist/nodes/sequence-item.d.ts.map +1 -0
  148. package/dist/nodes/sequence-item.js +396 -0
  149. package/dist/nodes/sequence-item.js.map +1 -0
  150. package/dist/nodes/sequence-one.d.ts +5 -0
  151. package/dist/nodes/sequence-one.d.ts.map +1 -0
  152. package/dist/nodes/sequence-one.js +26 -0
  153. package/dist/nodes/sequence-one.js.map +1 -0
  154. package/dist/nodes/swimlane-node.d.ts +5 -17
  155. package/dist/nodes/swimlane-node.d.ts.map +1 -1
  156. package/dist/nodes/swimlane-node.js +62 -147
  157. package/dist/nodes/swimlane-node.js.map +1 -1
  158. package/dist/nodes/wave-node.d.ts +52 -0
  159. package/dist/nodes/wave-node.d.ts.map +1 -0
  160. package/dist/nodes/wave-node.js +483 -0
  161. package/dist/nodes/wave-node.js.map +1 -0
  162. package/dist/non-working-display.d.ts +14 -0
  163. package/dist/non-working-display.d.ts.map +1 -0
  164. package/dist/non-working-display.js +28 -0
  165. package/dist/non-working-display.js.map +1 -0
  166. package/dist/phases/date-window.d.ts +48 -0
  167. package/dist/phases/date-window.d.ts.map +1 -0
  168. package/dist/phases/date-window.js +130 -0
  169. package/dist/phases/date-window.js.map +1 -0
  170. package/dist/phases/finalize.d.ts +198 -0
  171. package/dist/phases/finalize.d.ts.map +1 -0
  172. package/dist/phases/finalize.js +1058 -0
  173. package/dist/phases/finalize.js.map +1 -0
  174. package/dist/phases/measure.d.ts +77 -0
  175. package/dist/phases/measure.d.ts.map +1 -0
  176. package/dist/phases/measure.js +222 -0
  177. package/dist/phases/measure.js.map +1 -0
  178. package/dist/phases/place.d.ts +28 -0
  179. package/dist/phases/place.d.ts.map +1 -0
  180. package/dist/phases/place.js +225 -0
  181. package/dist/phases/place.js.map +1 -0
  182. package/dist/renderable.d.ts.map +1 -1
  183. package/dist/renderable.js +23 -3
  184. package/dist/renderable.js.map +1 -1
  185. package/dist/resolve-today.d.ts +11 -1
  186. package/dist/resolve-today.d.ts.map +1 -1
  187. package/dist/resolve-today.js +26 -12
  188. package/dist/resolve-today.js.map +1 -1
  189. package/dist/row-packer.d.ts +42 -16
  190. package/dist/row-packer.d.ts.map +1 -1
  191. package/dist/row-packer.js +51 -78
  192. package/dist/row-packer.js.map +1 -1
  193. package/dist/schedule.d.ts +58 -1
  194. package/dist/schedule.d.ts.map +1 -1
  195. package/dist/schedule.js +280 -106
  196. package/dist/schedule.js.map +1 -1
  197. package/dist/start-rules.d.ts +27 -0
  198. package/dist/start-rules.d.ts.map +1 -0
  199. package/dist/start-rules.js +91 -0
  200. package/dist/start-rules.js.map +1 -0
  201. package/dist/start-terms.d.ts +23 -0
  202. package/dist/start-terms.d.ts.map +1 -0
  203. package/dist/start-terms.js +27 -0
  204. package/dist/start-terms.js.map +1 -0
  205. package/dist/status-dot.d.ts +46 -0
  206. package/dist/status-dot.d.ts.map +1 -0
  207. package/dist/status-dot.js +78 -0
  208. package/dist/status-dot.js.map +1 -0
  209. package/dist/style-resolution.d.ts.map +1 -1
  210. package/dist/style-resolution.js +23 -43
  211. package/dist/style-resolution.js.map +1 -1
  212. package/dist/text-measure.d.ts +28 -0
  213. package/dist/text-measure.d.ts.map +1 -0
  214. package/dist/text-measure.js +70 -0
  215. package/dist/text-measure.js.map +1 -0
  216. package/dist/themes/contrast.d.ts +4 -0
  217. package/dist/themes/contrast.d.ts.map +1 -0
  218. package/dist/themes/contrast.js +32 -0
  219. package/dist/themes/contrast.js.map +1 -0
  220. package/dist/themes/dark.d.ts.map +1 -1
  221. package/dist/themes/dark.js +28 -1
  222. package/dist/themes/dark.js.map +1 -1
  223. package/dist/themes/grayscale.d.ts.map +1 -1
  224. package/dist/themes/grayscale.js +28 -1
  225. package/dist/themes/grayscale.js.map +1 -1
  226. package/dist/themes/index.d.ts +4 -11
  227. package/dist/themes/index.d.ts.map +1 -1
  228. package/dist/themes/index.js +6 -4
  229. package/dist/themes/index.js.map +1 -1
  230. package/dist/themes/light.d.ts.map +1 -1
  231. package/dist/themes/light.js +28 -1
  232. package/dist/themes/light.js.map +1 -1
  233. package/dist/themes/shape.d.ts +31 -0
  234. package/dist/themes/shape.d.ts.map +1 -1
  235. package/dist/themes/shared.d.ts +44 -50
  236. package/dist/themes/shared.d.ts.map +1 -1
  237. package/dist/themes/shared.js +79 -83
  238. package/dist/themes/shared.js.map +1 -1
  239. package/dist/time-scale.d.ts +42 -6
  240. package/dist/time-scale.d.ts.map +1 -1
  241. package/dist/time-scale.js +109 -17
  242. package/dist/time-scale.js.map +1 -1
  243. package/dist/types.d.ts +528 -11
  244. package/dist/types.d.ts.map +1 -1
  245. package/dist/view-preset.d.ts +61 -6
  246. package/dist/view-preset.d.ts.map +1 -1
  247. package/dist/view-preset.js +439 -24
  248. package/dist/view-preset.js.map +1 -1
  249. package/dist/wave-barrier.d.ts +107 -0
  250. package/dist/wave-barrier.d.ts.map +1 -0
  251. package/dist/wave-barrier.js +174 -0
  252. package/dist/wave-barrier.js.map +1 -0
  253. package/dist/wave-hatch.d.ts +4 -0
  254. package/dist/wave-hatch.d.ts.map +1 -0
  255. package/dist/wave-hatch.js +21 -0
  256. package/dist/wave-hatch.js.map +1 -0
  257. package/dist/wave-layout.d.ts +99 -0
  258. package/dist/wave-layout.d.ts.map +1 -0
  259. package/dist/wave-layout.js +130 -0
  260. package/dist/wave-layout.js.map +1 -0
  261. package/dist/working-calendar.d.ts +128 -4
  262. package/dist/working-calendar.d.ts.map +1 -1
  263. package/dist/working-calendar.js +725 -51
  264. package/dist/working-calendar.js.map +1 -1
  265. package/dist/working-span.d.ts +11 -0
  266. package/dist/working-span.d.ts.map +1 -0
  267. package/dist/working-span.js +18 -0
  268. package/dist/working-span.js.map +1 -0
  269. package/package.json +7 -7
  270. package/src/axis-columns.ts +140 -0
  271. package/src/calendar-resolver.ts +161 -0
  272. package/src/calendar.ts +4 -45
  273. package/src/canvas-width.ts +36 -0
  274. package/src/capacity.ts +71 -30
  275. package/src/chart-translation.ts +88 -0
  276. package/src/container-header-geometry.ts +116 -0
  277. package/src/dsl-utils.ts +8 -26
  278. package/src/edge-routing.ts +347 -491
  279. package/src/frame-tab-geometry.ts +78 -25
  280. package/src/header-card-geometry.ts +17 -2
  281. package/src/header-logo.ts +67 -0
  282. package/src/i18n.ts +22 -1
  283. package/src/index.ts +97 -12
  284. package/src/inline-date-pin-geometry.ts +55 -58
  285. package/src/item-bar-geometry.ts +341 -5
  286. package/src/item-port-geometry.ts +69 -0
  287. package/src/layout-context.ts +210 -72
  288. package/src/layout-insights.ts +109 -2
  289. package/src/layout.ts +57 -1530
  290. package/src/nodes/anchor-node.ts +11 -4
  291. package/src/nodes/content-extent.ts +107 -0
  292. package/src/nodes/dependency-edges.ts +171 -0
  293. package/src/nodes/footnote-node.ts +171 -31
  294. package/src/nodes/group-node.ts +92 -215
  295. package/src/nodes/header-node.ts +255 -0
  296. package/src/nodes/include-node.ts +124 -110
  297. package/src/nodes/item-measure.ts +723 -0
  298. package/src/nodes/item-node.ts +358 -80
  299. package/src/nodes/marker-band.ts +406 -0
  300. package/src/nodes/marker-geometry.ts +1 -1
  301. package/src/nodes/milestone-node.ts +321 -136
  302. package/src/nodes/nowline-node.ts +87 -0
  303. package/src/nodes/parallel-node.ts +69 -39
  304. package/src/nodes/region-markers.ts +194 -0
  305. package/src/nodes/roadmap-node.ts +46 -950
  306. package/src/nodes/row-track.ts +217 -0
  307. package/src/nodes/sequence-item.ts +433 -0
  308. package/src/nodes/sequence-one.ts +40 -0
  309. package/src/nodes/swimlane-node.ts +66 -206
  310. package/src/nodes/wave-node.ts +609 -0
  311. package/src/non-working-display.ts +32 -0
  312. package/src/phases/date-window.ts +191 -0
  313. package/src/phases/finalize.ts +1303 -0
  314. package/src/phases/measure.ts +329 -0
  315. package/src/phases/place.ts +318 -0
  316. package/src/renderable.ts +23 -3
  317. package/src/resolve-today.ts +28 -25
  318. package/src/row-packer.ts +85 -84
  319. package/src/schedule.ts +362 -114
  320. package/src/start-rules.ts +113 -0
  321. package/src/start-terms.ts +38 -0
  322. package/src/status-dot.ts +81 -0
  323. package/src/style-resolution.ts +27 -57
  324. package/src/text-measure.ts +71 -0
  325. package/src/themes/contrast.ts +34 -0
  326. package/src/themes/dark.ts +28 -1
  327. package/src/themes/grayscale.ts +28 -1
  328. package/src/themes/index.ts +10 -7
  329. package/src/themes/light.ts +28 -1
  330. package/src/themes/shape.ts +38 -0
  331. package/src/themes/shared.ts +85 -93
  332. package/src/time-scale.ts +117 -19
  333. package/src/types.ts +529 -20
  334. package/src/view-preset.ts +520 -27
  335. package/src/wave-barrier.ts +242 -0
  336. package/src/wave-hatch.ts +25 -0
  337. package/src/wave-layout.ts +203 -0
  338. package/src/working-calendar.ts +875 -57
  339. package/src/working-span.ts +19 -0
@@ -1,41 +1,145 @@
1
- // FootnoteNode + buildFootnotes — footnote area at the bottom of the
2
- // chart. Each footnote gets a stable index (1-based, sorted by id) and
1
+ // FootnoteNode + indexFootnotes / buildFootnotePanel — footnote area at the bottom of the
2
+ // chart. Each footnote gets a stable index (1-based, in document order) and
3
3
  // records its `on:` host references so item / swimlane sequencing can
4
- // emit the matching superscript indicators. The panel grows to fit:
5
- // 28 px header + (entries × FOOTNOTE_ROW_HEIGHT) + 16 px padding.
4
+ // emit the matching superscript indicators. An isolated region's
5
+ // footnotes continue the numbering after the host's, in include order,
6
+ // and share the one panel under a heading row with the region's title.
7
+ // An entry whose text does not fit the panel's width wraps onto more
8
+ // rows at the title's x. The panel grows to fit: 28 px header + (entry
9
+ // rows and region headings × FOOTNOTE_ROW_HEIGHT) + 16 px padding.
6
10
  import { propValues } from '../dsl-utils.js';
7
11
  import { resolveStyle } from '../style-resolution.js';
12
+ import { estimateTextWidth, wrapText } from '../text-measure.js';
8
13
  import { FOOTNOTE_HEADER_HEIGHT_PX, FOOTNOTE_PANEL_PADDING_PX, FOOTNOTE_ROW_HEIGHT, } from '../themes/shared.js';
9
- export function buildFootnotes(footnotes, ctx, chartBottomY) {
10
- const entries = [];
14
+ /**
15
+ * Pure: depends only on the footnote declarations. Numbers start after
16
+ * `precedingCount` (an isolated region continues after the host and the
17
+ * regions before it). The map's order is document order: the resolver
18
+ * inserts a file's own footnotes as declared, then each merged include's.
19
+ */
20
+ export function indexFootnotes(footnotes, precedingCount = 0) {
11
21
  const index = new Map();
12
22
  const hosts = new Map();
13
- const ordered = [...footnotes.entries()].sort(([a], [b]) => a.localeCompare(b));
14
- ordered.forEach(([id, f], i) => {
15
- const n = i + 1;
16
- index.set(id, n);
23
+ [...footnotes.entries()].forEach(([id, f], i) => {
24
+ index.set(id, precedingCount + i + 1);
17
25
  hosts.set(id, propValues(f.properties, 'on'));
18
- entries.push({
19
- number: n,
20
- title: f.title ?? id,
21
- description: f.description?.text,
22
- style: resolveStyle('footnote', f.properties, ctx.styleCtx),
23
- });
24
26
  });
27
+ return { index, hosts };
28
+ }
29
+ /** Font sizes (px) of an entry's title and description. */
30
+ const FOOTNOTE_TEXT_FONT_SIZE_PX = 11;
31
+ /** The description column never starts closer than this to the title's x. */
32
+ const FOOTNOTE_DESCRIPTION_MIN_OFFSET_PX = 120;
33
+ /** Per-character advance the description column is placed by. */
34
+ const FOOTNOTE_TITLE_CHAR_ADVANCE_PX = 6;
35
+ const DESCRIPTION_LEAD = '— ';
36
+ /**
37
+ * The panel below the chart, spanning the final canvas (`chartRightX`):
38
+ * the host's footnotes, then each region's under its title, each in
39
+ * document order. The canvas does not grow for the panel: an entry whose
40
+ * title or description runs past the panel's inner right edge wraps onto
41
+ * more rows, which start at the title's x and use the whole width.
42
+ */
43
+ export function buildFootnotePanel(footnotes, ctx, chartBottomY, chartRightX, regions = []) {
44
+ const boxX = FOOTNOTE_PANEL_PADDING_PX;
45
+ const boxY = chartBottomY + FOOTNOTE_PANEL_PADDING_PX;
46
+ const boxWidth = chartRightX - 2 * FOOTNOTE_PANEL_PADDING_PX;
47
+ const titleX = boxX + 2 * FOOTNOTE_PANEL_PADDING_PX;
48
+ const textRightX = boxX + boxWidth - FOOTNOTE_PANEL_PADDING_PX;
49
+ const firstRowY = boxY + FOOTNOTE_HEADER_HEIGHT_PX + FOOTNOTE_PANEL_PADDING_PX;
50
+ const entries = [];
51
+ let row = 0;
52
+ const add = (decls, source, region) => {
53
+ for (const [id, f] of decls) {
54
+ const title = f.title ?? id;
55
+ const description = f.description?.text;
56
+ const lines = entryLines(title, description, titleX, textRightX);
57
+ const y = firstRowY + row * FOOTNOTE_ROW_HEIGHT;
58
+ const at = (l) => ({
59
+ x: l.x,
60
+ y: y + l.row * FOOTNOTE_ROW_HEIGHT,
61
+ text: l.text,
62
+ });
63
+ const entry = {
64
+ number: source.footnoteIndex.get(id) ?? entries.length + 1,
65
+ y,
66
+ title,
67
+ titleLines: lines.title.map(at),
68
+ description,
69
+ style: resolveStyle('footnote', f.properties, source.styleCtx),
70
+ };
71
+ if (lines.description.length > 0)
72
+ entry.descriptionLines = lines.description.map(at);
73
+ if (region !== undefined)
74
+ entry.region = region;
75
+ entries.push(entry);
76
+ row += lines.rows;
77
+ }
78
+ };
79
+ add(footnotes, ctx);
80
+ for (const r of regions) {
81
+ if (r.footnotes.size === 0)
82
+ continue;
83
+ // The region's heading takes a row of its own above its entries.
84
+ const headingY = firstRowY + row * FOOTNOTE_ROW_HEIGHT;
85
+ row += 1;
86
+ const first = entries.length;
87
+ add(r.footnotes, r.ctx, r.title);
88
+ entries[first].regionHeadingY = headingY;
89
+ }
25
90
  const box = {
26
- x: FOOTNOTE_PANEL_PADDING_PX,
27
- y: chartBottomY + FOOTNOTE_PANEL_PADDING_PX,
28
- width: ctx.chartRightX - 2 * FOOTNOTE_PANEL_PADDING_PX,
91
+ x: boxX,
92
+ y: boxY,
93
+ width: boxWidth,
29
94
  height: entries.length === 0
30
95
  ? 0
31
- : FOOTNOTE_HEADER_HEIGHT_PX +
32
- entries.length * FOOTNOTE_ROW_HEIGHT +
33
- FOOTNOTE_PANEL_PADDING_PX,
96
+ : FOOTNOTE_HEADER_HEIGHT_PX + row * FOOTNOTE_ROW_HEIGHT + FOOTNOTE_PANEL_PADDING_PX,
34
97
  };
98
+ return { box, entries };
99
+ }
100
+ /**
101
+ * Wrap one entry into rows. The title starts at `titleX`; the description
102
+ * follows on the title's row at the description column (`— ` first) and
103
+ * wraps at `titleX`. A wrapped title, or a description whose first word
104
+ * does not fit beside the title, starts the description on a row of its
105
+ * own. A single word wider than the panel stays whole on its row, as
106
+ * `wrapText` never splits a word.
107
+ */
108
+ function entryLines(title, description, titleX, textRightX) {
109
+ const fullWidth = textRightX - titleX;
110
+ const titleRows = fitsOrWraps(title, fullWidth, fullWidth);
111
+ const titleLines = titleRows.map((text, row) => ({ x: titleX, row, text }));
112
+ if (!description)
113
+ return { title: titleLines, description: [], rows: titleRows.length };
114
+ const leadWidth = estimateTextWidth(DESCRIPTION_LEAD, FOOTNOTE_TEXT_FONT_SIZE_PX);
115
+ const firstWord = description.trim().split(/\s+/)[0] ?? '';
116
+ const columnX = titleX +
117
+ Math.max(FOOTNOTE_DESCRIPTION_MIN_OFFSET_PX, title.length * FOOTNOTE_TITLE_CHAR_ADVANCE_PX);
118
+ const besideTitle = titleRows.length === 1 &&
119
+ leadWidth + estimateTextWidth(firstWord, FOOTNOTE_TEXT_FONT_SIZE_PX) <=
120
+ textRightX - columnX;
121
+ const firstX = besideTitle ? columnX : titleX;
122
+ const firstRow = besideTitle ? titleRows.length - 1 : titleRows.length;
123
+ const rows = fitsOrWraps(description, fullWidth, textRightX - firstX - leadWidth);
124
+ const descriptionLines = rows.map((text, i) => ({
125
+ x: i === 0 ? firstX : titleX,
126
+ row: firstRow + i,
127
+ text: i === 0 ? `${DESCRIPTION_LEAD}${text}` : text,
128
+ }));
35
129
  return {
36
- area: { box, entries },
37
- index,
38
- hosts,
130
+ title: titleLines,
131
+ description: descriptionLines,
132
+ rows: firstRow + rows.length,
39
133
  };
40
134
  }
135
+ /**
136
+ * `text` as is when it fits `firstWidth`, else wrapped (`wrapText`, which
137
+ * collapses whitespace), so an entry that fits keeps its exact text.
138
+ */
139
+ function fitsOrWraps(text, width, firstWidth) {
140
+ if (estimateTextWidth(text, FOOTNOTE_TEXT_FONT_SIZE_PX) <= firstWidth)
141
+ return [text];
142
+ const rows = wrapText(text, width, FOOTNOTE_TEXT_FONT_SIZE_PX, firstWidth);
143
+ return rows.length > 0 ? rows : [text];
144
+ }
41
145
  //# sourceMappingURL=footnote-node.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"footnote-node.js","sourceRoot":"","sources":["../../src/nodes/footnote-node.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,uEAAuE;AACvE,sEAAsE;AACtE,oEAAoE;AACpE,kEAAkE;AAGlE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EACH,yBAAyB,EACzB,yBAAyB,EACzB,mBAAmB,GACtB,MAAM,qBAAqB,CAAC;AAS7B,MAAM,UAAU,cAAc,CAC1B,SAA2C,EAC3C,GAAkB,EAClB,YAAoB;IAEpB,MAAM,OAAO,GAA8B,EAAE,CAAC;IAC9C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC1C,MAAM,OAAO,GAAG,CAAC,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAChF,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC3B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChB,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACjB,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC;YACT,MAAM,EAAE,CAAC;YACT,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE;YACpB,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,IAAI;YAChC,KAAK,EAAE,YAAY,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC;SAC9D,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IACH,MAAM,GAAG,GAAgB;QACrB,CAAC,EAAE,yBAAyB;QAC5B,CAAC,EAAE,YAAY,GAAG,yBAAyB;QAC3C,KAAK,EAAE,GAAG,CAAC,WAAW,GAAG,CAAC,GAAG,yBAAyB;QACtD,MAAM,EACF,OAAO,CAAC,MAAM,KAAK,CAAC;YAChB,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,yBAAyB;gBACzB,OAAO,CAAC,MAAM,GAAG,mBAAmB;gBACpC,yBAAyB;KACtC,CAAC;IACF,OAAO;QACH,IAAI,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE;QACtB,KAAK;QACL,KAAK;KACR,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"footnote-node.js","sourceRoot":"","sources":["../../src/nodes/footnote-node.ts"],"names":[],"mappings":"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"}
@@ -1,28 +1,17 @@
1
- import type { EntityProperty, GroupBlock, ItemDeclaration, ParallelBlock } from '@nowline/core';
2
- import type { LayoutContext, TrackCursor } from '../layout-context.js';
3
- import type { PositionedGroup, PositionedItem, PositionedTrackChild } from '../types.js';
4
- export interface GroupNodeDeps {
5
- sequenceItem: (child: ItemDeclaration, cursor: TrackCursor, ctx: LayoutContext, ownerOverride?: string) => PositionedItem;
6
- sequenceOne: (child: ItemDeclaration | GroupBlock | ParallelBlock, cursor: TrackCursor, ctx: LayoutContext) => PositionedTrackChild;
7
- resolveChildStart: (props: EntityProperty[], seqDefault: number, laneLeftX: number, ctx: LayoutContext) => number;
8
- newCursor: (x: number, y: number) => TrackCursor;
9
- estimateTextWidth: (text: string, fontSize: number) => number;
10
- /** Predict the extra vertical height an item's wrapped label-chip
11
- * rows will add to its bar; used to size the row-packer's row
12
- * pitch ahead of the call to `sequenceItem`. */
13
- predictItemChipExtraHeight: (item: ItemDeclaration, ctx: LayoutContext) => number;
14
- }
1
+ import type { GroupBlock } from '@nowline/core';
2
+ import type { LayoutContext, LayoutHelpers, TrackCursor } from '../layout-context.js';
3
+ import type { PositionedGroup } from '../types.js';
15
4
  export declare class GroupNode {
16
5
  readonly node: GroupBlock;
17
- private readonly deps;
18
- constructor(node: GroupBlock, deps: GroupNodeDeps);
6
+ private readonly helpers;
7
+ constructor(node: GroupBlock, helpers: LayoutHelpers);
19
8
  get id(): string;
20
9
  /**
21
- * Sequence children inside the group's content area, advance the
22
- * parent `cursor` past the group's right edge plus
23
- * `TRACK_BLOCK_TAIL_GUTTER_PX` of breathing room, and return a
24
- * `PositionedGroup` whose `box.height` covers the chiclet pad,
25
- * every row-packed child row, and the bottom pad.
10
+ * Sequence children inside the group's body, advance the parent
11
+ * `cursor` to the group's end in time (its children's duration ends,
12
+ * never a caption spill or a header title), and return a
13
+ * `PositionedGroup` whose box covers the header, the padded rows and
14
+ * the group's dates.
26
15
  */
27
16
  place(cursor: TrackCursor, ctx: LayoutContext): PositionedGroup;
28
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"group-node.d.ts","sourceRoot":"","sources":["../../src/nodes/group-node.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAKhG,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAYvE,OAAO,KAAK,EAER,eAAe,EACf,cAAc,EACd,oBAAoB,EACvB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,aAAa;IAC1B,YAAY,EAAE,CACV,KAAK,EAAE,eAAe,EACtB,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,aAAa,EAClB,aAAa,CAAC,EAAE,MAAM,KACrB,cAAc,CAAC;IACpB,WAAW,EAAE,CACT,KAAK,EAAE,eAAe,GAAG,UAAU,GAAG,aAAa,EACnD,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,aAAa,KACjB,oBAAoB,CAAC;IAC1B,iBAAiB,EAAE,CACf,KAAK,EAAE,cAAc,EAAE,EACvB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,aAAa,KACjB,MAAM,CAAC;IACZ,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,WAAW,CAAC;IACjD,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9D;;qDAEiD;IACjD,0BAA0B,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,aAAa,KAAK,MAAM,CAAC;CACrF;AAED,qBAAa,SAAS;aAEE,IAAI,EAAE,UAAU;IAEhC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAFL,IAAI,EAAE,UAAU,EAEf,IAAI,EAAE,aAAa;IAGxC,IAAI,EAAE,IAAI,MAAM,CAEf;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,aAAa,GAAG,eAAe;CAmLlE"}
1
+ {"version":3,"file":"group-node.d.ts","sourceRoot":"","sources":["../../src/nodes/group-node.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAIhD,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGtF,OAAO,KAAK,EAAe,eAAe,EAAE,MAAM,aAAa,CAAC;AAIhE,qBAAa,SAAS;aAEE,IAAI,EAAE,UAAU;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAF5B,YACoB,IAAI,EAAE,UAAU,EACf,OAAO,EAAE,aAAa,EACvC;IAEJ,IAAI,EAAE,IAAI,MAAM,CAEf;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,aAAa,GAAG,eAAe,CAgG9D;CACJ"}
@@ -1,195 +1,120 @@
1
1
  // GroupNode — Renderable for a `group { ... }` block. Sequences
2
- // children inside the group's content area using the same row-pack
3
- // engine `SwimlaneNode` uses, so an item whose desired start collides
4
- // with a sibling's `rightEdge`, caption `spillX`, or a slack-arrow
5
- // corridor bumps to a new row inside the group. The group's reported
6
- // `box.height` grows with the row stack so parent containers stack
7
- // against the actual painted extent.
2
+ // children inside the group's body through `sequenceRowTrack`
3
+ // (row-track.ts), the loop `SwimlaneNode` uses, so an item whose desired
4
+ // start collides with a sibling's `rightEdge`, caption `spillX`, or a
5
+ // slack-arrow corridor bumps to a new row inside the group.
8
6
  //
9
- // Filled-style groups paint a title chiclet flush in the upper-left
10
- // corner of the box; the layout reserves vertical top padding equal
11
- // to the chiclet height plus a small gutter before the first inner
12
- // row begins.
13
- import { isItemDeclaration } from '@nowline/core';
14
- import { deriveItemDurationDays } from '../calendar.js';
15
- import { propValues } from '../dsl-utils.js';
7
+ // The group is drawn above and around its content, never beside it
8
+ // (specs/true-width-layout.md §3.3): a header band (title, inline-date
9
+ // glyphs, a bracket spanning exactly its dates) over a body padded above
10
+ // and below its rows. Its box spans exactly its children's earliest start
11
+ // and latest end; see `container-header-geometry.ts`.
12
+ import { containerChrome } from '../container-header-geometry.js';
13
+ import { propValue, propValues } from '../dsl-utils.js';
16
14
  import { computeContainerInlineDatePins, pickInlineDate } from '../inline-date-pin-geometry.js';
17
- import { RowPacker } from '../row-packer.js';
15
+ import { resolvePinnedOrSequentialStart } from '../start-rules.js';
18
16
  import { resolveStyle } from '../style-resolution.js';
19
- import { GROUP_BOTTOM_PAD_PX, GROUP_BRACKET_LABEL_OVERHANG_PX, GROUP_TITLE_TAB_GUTTER_PX, GROUP_TITLE_TAB_HEIGHT_PX, ITEM_INSET_PX, MIN_ITEM_WIDTH, TRACK_BLOCK_TAIL_GUTTER_PX, } from '../themes/shared.js';
17
+ import { waveFloorX } from '../wave-layout.js';
18
+ import { sequenceRowTrack } from './row-track.js';
20
19
  export class GroupNode {
21
20
  node;
22
- deps;
23
- constructor(node,
24
- // biome-ignore lint/correctness/noUnusedPrivateClassMembers: accessed via `const { deps } = this` destructuring inside methods, which the analyzer does not detect.
25
- deps) {
21
+ helpers;
22
+ constructor(node, helpers) {
26
23
  this.node = node;
27
- this.deps = deps;
24
+ this.helpers = helpers;
28
25
  }
29
26
  get id() {
30
27
  return this.node.name ?? '';
31
28
  }
32
29
  /**
33
- * Sequence children inside the group's content area, advance the
34
- * parent `cursor` past the group's right edge plus
35
- * `TRACK_BLOCK_TAIL_GUTTER_PX` of breathing room, and return a
36
- * `PositionedGroup` whose `box.height` covers the chiclet pad,
37
- * every row-packed child row, and the bottom pad.
30
+ * Sequence children inside the group's body, advance the parent
31
+ * `cursor` to the group's end in time (its children's duration ends,
32
+ * never a caption spill or a header title), and return a
33
+ * `PositionedGroup` whose box covers the header, the padded rows and
34
+ * the group's dates.
38
35
  */
39
36
  place(cursor, ctx) {
40
37
  const { node } = this;
41
- const { deps } = this;
38
+ const { helpers } = this;
42
39
  const style = resolveStyle('group', node.properties, ctx.styleCtx);
43
- const startX = cursor.x;
44
- const title = node.title ?? node.name;
40
+ // The group starts after every `after:` term, then its own wave and
41
+ // its lead wave floor it, so its box never opens in a column before
42
+ // its first piece of work (specs/waves.md §5.1). A lane child's
43
+ // cursor already sits there (`resolveChildStart`), so this is the
44
+ // identity for it; a parallel's group track starts at the parallel's
45
+ // start, so this is where its `after:` applies
46
+ // (specs/scheduler-unification.md §8 decision 5).
47
+ const startX = waveFloorX(node, resolvePinnedOrSequentialStart(node.properties, cursor.x, ctx), ctx);
48
+ // In a roadmap with waves, a group with no title, no `style:` and
49
+ // no `labels:` that carries `wave:` only assigns membership: it
50
+ // draws nothing, which would otherwise sit exactly on the wave
51
+ // boundary its box opens at, and reserves nothing
52
+ // (specs/waves.md §9.7). An id alone does not make it titled
53
+ // (Example 4's `api-track`).
54
+ const waveOnly = ctx.waves !== undefined &&
55
+ node.title === undefined &&
56
+ propValue(node.properties, 'wave') !== undefined &&
57
+ propValue(node.properties, 'style') === undefined &&
58
+ propValues(node.properties, 'labels').length === 0;
59
+ const title = waveOnly ? undefined : (node.title ?? node.name);
45
60
  // Group children chain in time inside the group, so they
46
61
  // form one sub-flow under the parent's flow path. See
47
62
  // `LayoutContext.currentFlowKey`.
48
63
  const previousFlowKey = ctx.currentFlowKey;
49
64
  ctx.nextGroupId += 1;
50
65
  ctx.currentFlowKey = `${previousFlowKey}/group:${node.name ?? `group-${ctx.nextGroupId}`}`;
51
- // Mirrors `renderGroup`'s `hasFill` decision so the painted box
52
- // and the layout's reservation agree on whether a chiclet exists.
53
- const hasChiclet = style.bg !== 'none' && style.bg !== '#ffffff' && Boolean(title);
54
- const topPad = hasChiclet ? GROUP_TITLE_TAB_HEIGHT_PX + GROUP_TITLE_TAB_GUTTER_PX : 0;
55
- const bottomPad = hasChiclet ? GROUP_BOTTOM_PAD_PX : 0;
56
- // Bracket-style groups paint their label at `box.y - 2`, so the
57
- // label glyph overhangs ABOVE box.y. Without an explicit
58
- // reservation, two bracket-titled groups stacked in a parallel
59
- // collide: the previous sibling's bracket-foot ends at its
60
- // box.bottom, and the next sibling's label visual top sits just
61
- // above box.y — they touch in the gap. Shift `box.y` down by
62
- // the overhang amount so the glyph lands in space we own.
63
- const bracketLabelOverhang = !hasChiclet && title ? GROUP_BRACKET_LABEL_OVERHANG_PX : 0;
64
- const startY = cursor.y + bracketLabelOverhang;
65
- const step = ctx.bandScale.step();
66
- const groupContentLeftX = startX;
67
- const packer = new RowPacker({
68
- laneLeftX: groupContentLeftX,
69
- originY: startY + topPad,
70
- minRowHeight: step,
71
- slackCorridors: ctx.slackCorridors,
66
+ const afterDate = pickInlineDate(propValues(node.properties, 'after'));
67
+ const beforeDate = pickInlineDate(propValues(node.properties, 'before'));
68
+ const chrome = containerChrome({
69
+ drawn: !waveOnly,
70
+ hasTitle: Boolean(title),
71
+ hasPins: Boolean(afterDate || beforeDate),
72
+ hasBracket: style.bracket !== 'none',
72
73
  });
73
- let timeCursorX = groupContentLeftX;
74
- const children = [];
75
- for (const child of node.content) {
76
- if (child.$type === 'DescriptionDirective')
77
- continue;
78
- if (!isItemDeclaration(child)) {
79
- const blockProps = child.properties ?? [];
80
- const blockStart = deps.resolveChildStart(blockProps, timeCursorX, groupContentLeftX, ctx);
81
- const { rowIndex, y: blockY } = packer.placeBlock();
82
- const innerCursor = deps.newCursor(blockStart, blockY);
83
- const positioned = deps.sequenceOne(child, innerCursor, ctx);
84
- children.push(positioned);
85
- const blockEnd = positioned.box.x + positioned.box.width;
86
- const blockHeight = Math.max(step, innerCursor.height);
87
- packer.commitBlock({
88
- rowIndex,
89
- placed: positioned,
90
- blockHeight,
91
- blockEnd,
92
- });
93
- timeCursorX = Math.max(timeCursorX, blockEnd);
94
- continue;
95
- }
96
- const props = child.properties;
97
- const desiredStart = deps.resolveChildStart(props, timeCursorX, groupContentLeftX, ctx);
98
- // Predict logical extent so the row-packer can bump on
99
- // collision before we hand off to `sequenceItem`. Mirrors
100
- // SwimlaneNode's pre-flight width math.
101
- const durationDays = deriveItemDurationDays(props, ctx.sizes, ctx.cal);
102
- const naturalWidth = Math.max(MIN_ITEM_WIDTH, durationDays * ctx.timeline.pixelsPerDay);
103
- const desiredEnd = desiredStart + naturalWidth;
104
- const childId = child.name ?? '';
105
- const chipExtra = deps.predictItemChipExtraHeight(child, ctx);
106
- const predictedHeight = step + chipExtra;
107
- const { rowIndex, y: rowY } = packer.placeItem({
108
- childId,
109
- desiredStart,
110
- desiredEnd,
111
- // Row pitch = `step()` + extra chip-row height. Keeps
112
- // the inter-row visible gap (= step - bandwidth) intact
113
- // when an item's labels wrap and grow the bar.
114
- predictedHeight,
115
- });
116
- const innerCursor = deps.newCursor(desiredStart, rowY);
117
- const positioned = deps.sequenceItem(child, innerCursor, ctx);
118
- children.push(positioned);
119
- const itemLogicalEnd = positioned.box.x + positioned.box.width + ITEM_INSET_PX;
120
- timeCursorX = Math.max(timeCursorX, itemLogicalEnd);
121
- let spillReservation = null;
122
- const hasAnySpill = positioned.textSpills ||
123
- positioned.chipsOutside ||
124
- positioned.dotSpills ||
125
- positioned.iconSpills ||
126
- positioned.footnoteSpills;
127
- if (hasAnySpill) {
128
- const farRight = Math.max(positioned.decorationsRightX, positioned.chipsOutside ? positioned.chipsRightX : 0);
129
- spillReservation = farRight + 6;
130
- }
131
- packer.commitItem({
132
- rowIndex,
133
- placed: positioned,
134
- logicalEnd: itemLogicalEnd,
135
- spillReservation,
136
- rowHeight: predictedHeight,
137
- });
138
- }
139
- const innerHeight = Math.max(step, packer.usedHeight());
140
- // The group's painted box hugs everything its children put on
141
- // screen, including caption text that spills past a bar's right
142
- // edge. `usedRightX` is the rightmost extent any row reached —
143
- // either a bar's logical right or a caption's reserved spill —
144
- // so the orange tint visually "owns" the spilled title/meta.
145
- //
146
- // The cursor channel (`cursor.x` / `cursor.maxX`) stays on the
147
- // COMPACT `timeCursorX` (bar logical ends only). Bubbling the
148
- // wide `visualRightX` upward would propagate through
149
- // `ParallelNode.maxRight → parallel.box.width → swimlane
150
- // blockEnd → timeCursorX`, pushing every subsequent sibling
151
- // right by the spill width — including siblings on entirely
152
- // different rows of the parent swimlane. The painted box and
153
- // the logical cursor advance are intentionally decoupled here.
154
- const visualRightX = Math.max(timeCursorX, packer.usedRightX());
74
+ const track = sequenceRowTrack(node, { leftX: startX, firstRowY: cursor.y + chrome.header + chrome.pad }, ctx, helpers);
75
+ const { children, timeCursorX, timeStartX } = track;
76
+ // Every row's height carries the inter-row gap below it; the body
77
+ // ends `pad` below the last child's painted bottom, not below that
78
+ // gap, and the cursor adds the gap back after the body so a sibling
79
+ // stacked below keeps the same rhythm as two items.
80
+ const step = ctx.bandScale.step();
81
+ const interRowGap = step - ctx.bandScale.bandwidth();
82
+ const contentHeight = Math.max(step, track.packer.usedHeight()) - interRowGap;
83
+ // The bracket and body span exactly the children's dates
84
+ // (specs/true-width-layout.md §3.3): what the group paints past them
85
+ // (a spilled caption, its title) is footprint the row packer keeps,
86
+ // not width.
155
87
  const box = {
156
- x: startX,
157
- y: startY,
158
- width: visualRightX - startX,
159
- height: topPad + innerHeight + bottomPad,
88
+ x: timeStartX,
89
+ y: cursor.y,
90
+ width: timeCursorX - timeStartX,
91
+ height: chrome.header + chrome.pad + contentHeight + chrome.pad,
160
92
  };
161
- cursor.x = timeCursorX + TRACK_BLOCK_TAIL_GUTTER_PX;
162
- cursor.maxX = Math.max(cursor.maxX, cursor.x);
163
- // The painted `box.height` is the group's tight visual
164
- // footprint (chiclet + content + bottomPad). The cursor
165
- // advance, however, must include one inter-row gap
166
- // (`step - bandwidth`) so a sibling stacked below in a
167
- // `parallel` (or any track-pack consumer) doesn't butt
168
- // right up against the group's bottom edge. Items naturally
169
- // include that gap because they report `cursor.height = step`
170
- // (bandwidth + gap); groups need to add it explicitly since
171
- // their painted height is gap-less.
172
- const interRowGap = ctx.bandScale.step() - ctx.bandScale.bandwidth();
173
- cursor.height = Math.max(cursor.height, bracketLabelOverhang + box.height + interRowGap);
93
+ // A parallel joins on its tracks' ends, as engine C does
94
+ // (specs/scheduler-unification.md §8 decision 8).
95
+ cursor.startX = box.x;
96
+ cursor.x = timeCursorX;
97
+ cursor.height = Math.max(cursor.height, box.height + interRowGap);
174
98
  const id = node.name;
99
+ // `after:` the group is a time path: its last child's duration end.
175
100
  if (id) {
176
101
  ctx.entityLeftEdges.set(id, box.x);
177
- ctx.entityRightEdges.set(id, box.x + box.width);
102
+ ctx.entityRightEdges.set(id, timeCursorX);
178
103
  }
179
104
  ctx.currentFlowKey = previousFlowKey;
180
- const inlineDatePins = computeContainerInlineDatePins({
181
- box,
182
- afterDate: pickInlineDate(propValues(node.properties, 'after')),
183
- beforeDate: pickInlineDate(propValues(node.properties, 'before')),
184
- });
105
+ const inlineDatePins = waveOnly
106
+ ? []
107
+ : computeContainerInlineDatePins({ box, afterDate, beforeDate, title });
185
108
  return {
186
109
  kind: 'group',
187
110
  id,
188
111
  title,
189
112
  box,
113
+ headerHeight: chrome.header,
190
114
  children,
191
115
  style,
192
116
  inlineDatePins: inlineDatePins.length > 0 ? inlineDatePins : undefined,
117
+ ...(waveOnly ? { waveOnly: true } : {}),
193
118
  };
194
119
  }
195
120
  }
@@ -1 +1 @@
1
- {"version":3,"file":"group-node.js","sourceRoot":"","sources":["../../src/nodes/group-node.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"group-node.js","sourceRoot":"","sources":["../../src/nodes/group-node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import type { ScaledLogo } from '../header-logo.js';
2
+ import type { HeaderPosition, PositionedHeader, ResolvedStyle } from '../types.js';
3
+ export interface MeasuredHeader {
4
+ position: HeaderPosition;
5
+ titleLines: string[];
6
+ authorLines: string[];
7
+ cardWidth: number;
8
+ /** Card height, grown when the logo is taller than the text. */
9
+ cardHeight: number;
10
+ /** Card height the title / author text alone needs. */
11
+ textCardHeight: number;
12
+ /** Width the logo takes left of the text, gap included; 0 without a logo. */
13
+ logoSlot: number;
14
+ logo?: ScaledLogo;
15
+ /** Beside: the card's box width, which is also `chartLeftX`. Above: 0. */
16
+ chartLeftX: number;
17
+ /** Above: the band height, bumped for an `xl` logo. Beside never reads it. */
18
+ aboveHeight: number;
19
+ /** Where the chart may start: below the canvas top, or below the above band. */
20
+ chartTopY: number;
21
+ /** Beside: the lowest the header rows may end so the card fits (card + 4 px inset). Above: 0. */
22
+ minRowsBottomY: number;
23
+ }
24
+ /** The positioned header without its attribution box, which finalize adds last. */
25
+ export type PositionedHeaderParts = Omit<PositionedHeader, 'attributionBox'>;
26
+ /** Where the chart ended up, as far as the header needs to know. */
27
+ export interface HeaderFrame {
28
+ /** Bottom of the header rows; the beside card's bottom hugs it. */
29
+ rowsBottomY: number;
30
+ /** Bottom of the chart; the beside header column runs down to it. */
31
+ chartBottomY: number;
32
+ /** The final canvas right edge; the above band spans to it. */
33
+ canvasRightX: number;
34
+ }
35
+ export interface HeaderNodeInput {
36
+ /** The roadmap's title (or name); an empty string when it has neither. */
37
+ title: string;
38
+ author?: string;
39
+ /** The resolved `default roadmap` style; `headerPosition` picks the mode. */
40
+ style: ResolvedStyle;
41
+ /** The drawn logo size, when the file declares a logo and the caller loaded one. */
42
+ logo?: ScaledLogo;
43
+ }
44
+ export declare class HeaderNode {
45
+ private readonly input;
46
+ constructor(input: HeaderNodeInput);
47
+ measure(): MeasuredHeader;
48
+ /**
49
+ * The header box, the card, the logo box and the text inset, once the
50
+ * chart's extent is known. Beside: a column `chartLeftX` wide down to
51
+ * the chart bottom, with the card's bottom on `rowsBottomY`. Above: a
52
+ * band `aboveHeight` tall across the canvas, the card filling it.
53
+ */
54
+ place(measured: MeasuredHeader, frame: HeaderFrame): PositionedHeaderParts;
55
+ }
56
+ //# sourceMappingURL=header-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"header-node.d.ts","sourceRoot":"","sources":["../../src/nodes/header-node.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAkB,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAOpE,OAAO,KAAK,EAAe,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAehG,MAAM,WAAW,cAAc;IAC3B,QAAQ,EAAE,cAAc,CAAC;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,cAAc,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,WAAW,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,iGAAiG;IACjG,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,mFAAmF;AACnF,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;AAE7E,oEAAoE;AACpE,MAAM,WAAW,WAAW;IACxB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC5B,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,KAAK,EAAE,aAAa,CAAC;IACrB,oFAAoF;IACpF,IAAI,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,qBAAa,UAAU;IACP,OAAO,CAAC,QAAQ,CAAC,KAAK;IAAlC,YAA6B,KAAK,EAAE,eAAe,EAAI;IAEvD,OAAO,IAAI,cAAc,CA+BxB;IAED;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,WAAW,GAAG,qBAAqB,CAmDzE;CACJ"}