@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
@@ -0,0 +1,163 @@
1
+ // HeaderNode — the roadmap header (title, author, company logo) in both
2
+ // positions, `beside` (a card left of the chart) and `above` (a band over
3
+ // it). `measure` sizes it before anything else is laid out, because the
4
+ // header decides where the chart starts: its left edge in beside mode,
5
+ // its top in above mode, and how low the header rows must end so the
6
+ // beside card fits (specs/layout-phases.md §3.7).
7
+ //
8
+ // HeaderNode does not implement `Renderable`: that signature is built
9
+ // around a time scale and a row band, which a header has no use for.
10
+ import { HEADER_AUTHOR_FONT_SIZE_PX, HEADER_AUTHOR_LINE_HEIGHT_PX, HEADER_CARD_PADDING_BOTTOM, HEADER_CARD_PADDING_TOP, HEADER_CARD_PADDING_X, HEADER_LOGO_GAP_PX, HEADER_LOGO_PAD_Y_PX, HEADER_TITLE_FONT_SIZE_PX, HEADER_TITLE_LINE_HEIGHT_PX, HEADER_TITLE_TO_AUTHOR_GAP_PX, } from '../header-card-geometry.js';
11
+ import { estimateTextWidth, wrapText } from '../text-measure.js';
12
+ import { HEADER_ABOVE_HEIGHT_PX, HEADER_BESIDE_MAX_WIDTH_PX, HEADER_BESIDE_MIN_WIDTH_PX, } from '../themes/shared.js';
13
+ // Left margin between the canvas's left edge and the visible card. The
14
+ // matching right-side breathing room is owned by `GUTTER_PX` (the canonical
15
+ // content gutter, applied between `chartLeftX` and `originX`), so the gap
16
+ // from the card's right edge to the timeline strip is the same as the gap
17
+ // between two adjacent items.
18
+ const HEADER_CARD_OUTER_PAD = 6;
19
+ /** Clearance (px) the beside card keeps from the canvas top. */
20
+ const HEADER_CARD_TOP_INSET = 4;
21
+ /** Gap (px) between the header (or the canvas top) and the chart. */
22
+ const CHART_TOP_GAP_PX = 8;
23
+ export class HeaderNode {
24
+ input;
25
+ constructor(input) {
26
+ this.input = input;
27
+ }
28
+ measure() {
29
+ const { title, author, style, logo } = this.input;
30
+ const isBeside = style.headerPosition === 'beside';
31
+ // Pre-size the beside-mode header card. Width = max line width +
32
+ // padding, clamped to MIN..MAX with word-wrap once the title
33
+ // exceeds MAX. Above mode keeps the fixed-strip geometry (full
34
+ // canvas width, fixed height) but still reads the wrapped lines.
35
+ const sized = sizeBesideHeader(title, author, logo);
36
+ // Above-mode strip: fixed height, bumped only when the logo plus
37
+ // its clearance is taller (`logo-size:xl`).
38
+ const aboveHeight = logo
39
+ ? Math.max(HEADER_ABOVE_HEIGHT_PX, logo.height + 2 * HEADER_LOGO_PAD_Y_PX)
40
+ : HEADER_ABOVE_HEIGHT_PX;
41
+ return {
42
+ position: style.headerPosition,
43
+ titleLines: sized.titleLines,
44
+ authorLines: sized.authorLines,
45
+ cardWidth: sized.cardWidth,
46
+ cardHeight: sized.cardHeight,
47
+ textCardHeight: sized.textCardHeight,
48
+ logoSlot: sized.logoSlot,
49
+ ...(logo ? { logo } : {}),
50
+ chartLeftX: isBeside ? sized.boxWidth : 0,
51
+ aboveHeight,
52
+ chartTopY: isBeside ? CHART_TOP_GAP_PX : aboveHeight + CHART_TOP_GAP_PX,
53
+ // In beside mode the card's BOTTOM aligns with the bottom of the
54
+ // header rows so it visually anchors to the chart's top. The
55
+ // rows must end low enough for the card plus a 4 px top inset;
56
+ // the measure phase pushes the timeline down when they would not.
57
+ minRowsBottomY: isBeside ? sized.cardHeight + HEADER_CARD_TOP_INSET : 0,
58
+ };
59
+ }
60
+ /**
61
+ * The header box, the card, the logo box and the text inset, once the
62
+ * chart's extent is known. Beside: a column `chartLeftX` wide down to
63
+ * the chart bottom, with the card's bottom on `rowsBottomY`. Above: a
64
+ * band `aboveHeight` tall across the canvas, the card filling it.
65
+ */
66
+ place(measured, frame) {
67
+ const { title, author, style } = this.input;
68
+ const isBeside = measured.position === 'beside';
69
+ const box = isBeside
70
+ ? { x: 0, y: 0, width: measured.chartLeftX, height: frame.chartBottomY }
71
+ : { x: 0, y: 0, width: frame.canvasRightX, height: measured.aboveHeight };
72
+ // The visible card inside the box. Beside, its BOTTOM hugs the
73
+ // bottom of the header rows so the title block anchors to the
74
+ // chart's top edge whichever header rows are present; the measure
75
+ // phase already pushed the rows down far enough for the card to
76
+ // keep HEADER_CARD_TOP_INSET from the canvas top.
77
+ const cardBox = isBeside
78
+ ? {
79
+ x: HEADER_CARD_OUTER_PAD,
80
+ y: frame.rowsBottomY - measured.cardHeight,
81
+ width: measured.cardWidth,
82
+ height: measured.cardHeight,
83
+ }
84
+ : { x: 0, y: 0, width: frame.canvasRightX, height: measured.aboveHeight };
85
+ // Logo at the card's left padding, vertically centered; the text
86
+ // shifts right past it and centers in the (possibly taller) card.
87
+ let logo;
88
+ let textInset;
89
+ if (measured.logo) {
90
+ logo = {
91
+ box: {
92
+ x: box.x + cardBox.x + HEADER_CARD_PADDING_X,
93
+ y: box.y + cardBox.y + (cardBox.height - measured.logo.height) / 2,
94
+ width: measured.logo.width,
95
+ height: measured.logo.height,
96
+ },
97
+ assetRef: measured.logo.assetRef,
98
+ intrinsic: measured.logo.intrinsic,
99
+ };
100
+ textInset = {
101
+ x: measured.logoSlot,
102
+ y: Math.max(0, (cardBox.height - measured.textCardHeight) / 2),
103
+ };
104
+ }
105
+ return {
106
+ box,
107
+ position: style.headerPosition,
108
+ title,
109
+ author,
110
+ titleLines: measured.titleLines,
111
+ authorLines: measured.authorLines,
112
+ cardBox,
113
+ logo,
114
+ ...(textInset ? { textInset } : {}),
115
+ style,
116
+ };
117
+ }
118
+ }
119
+ function sizeBesideHeader(title, author, logo) {
120
+ const maxContentWidth = HEADER_BESIDE_MAX_WIDTH_PX - 2 * HEADER_CARD_PADDING_X;
121
+ const titleLines = wrapText(title, maxContentWidth, HEADER_TITLE_FONT_SIZE_PX);
122
+ const authorLines = wrapText(author ?? '', maxContentWidth, HEADER_AUTHOR_FONT_SIZE_PX);
123
+ let widest = 0;
124
+ for (const line of titleLines)
125
+ widest = Math.max(widest, estimateTextWidth(line, HEADER_TITLE_FONT_SIZE_PX));
126
+ for (const line of authorLines)
127
+ widest = Math.max(widest, estimateTextWidth(line, HEADER_AUTHOR_FONT_SIZE_PX));
128
+ // A logo sits left of the text and widens the card past the text-only
129
+ // MAX clamp (which bounds the text column, not the logo slot).
130
+ const hasText = titleLines.length > 0 || authorLines.length > 0;
131
+ const logoSlot = logo ? logo.width + (hasText ? HEADER_LOGO_GAP_PX : 0) : 0;
132
+ const naturalCardWidth = widest + 2 * HEADER_CARD_PADDING_X;
133
+ // `HEADER_BESIDE_{MIN,MAX}_WIDTH_PX` bound the **boxWidth** (= cardWidth
134
+ // + left outer pad). Subtract one outer pad to derive the cardWidth
135
+ // bounds.
136
+ const cardWidth = Math.max(HEADER_BESIDE_MIN_WIDTH_PX - HEADER_CARD_OUTER_PAD, Math.min(HEADER_BESIDE_MAX_WIDTH_PX - HEADER_CARD_OUTER_PAD, naturalCardWidth) + logoSlot);
137
+ const titleBlockHeight = titleLines.length > 0 ? (titleLines.length - 1) * HEADER_TITLE_LINE_HEIGHT_PX : 0;
138
+ const authorBlockHeight = authorLines.length > 0
139
+ ? HEADER_TITLE_TO_AUTHOR_GAP_PX +
140
+ (authorLines.length - 1) * HEADER_AUTHOR_LINE_HEIGHT_PX
141
+ : 0;
142
+ const textCardHeight = HEADER_CARD_PADDING_TOP + titleBlockHeight + authorBlockHeight + HEADER_CARD_PADDING_BOTTOM;
143
+ // A logo taller than the text block grows the card; logo and text are
144
+ // then both centered vertically.
145
+ const cardHeight = logo
146
+ ? Math.max(textCardHeight, logo.height + 2 * HEADER_LOGO_PAD_Y_PX)
147
+ : textCardHeight;
148
+ // `boxWidth` only includes the LEFT outer pad — the right-side breathing
149
+ // room between the card and the chart is owned by `GUTTER_PX` in the
150
+ // measure phase. So `boxWidth` doubles as `chartLeftX` (the card's right
151
+ // edge in canvas coordinates).
152
+ const boxWidth = cardWidth + HEADER_CARD_OUTER_PAD;
153
+ return {
154
+ titleLines,
155
+ authorLines,
156
+ cardWidth,
157
+ cardHeight,
158
+ textCardHeight,
159
+ logoSlot,
160
+ boxWidth,
161
+ };
162
+ }
163
+ //# sourceMappingURL=header-node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"header-node.js","sourceRoot":"","sources":["../../src/nodes/header-node.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,26 @@
1
- import type { EntityProperty, GroupBlock, IsolatedRegion, ItemDeclaration, ParallelBlock } from '@nowline/core';
2
- import type { LayoutContext, TrackCursor } from '../layout-context.js';
3
- import type { PositionedIncludeRegion, PositionedItem, PositionedTrackChild } from '../types.js';
4
- export interface IncludeNodeDeps {
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
- predictItemChipExtraHeight: (item: ItemDeclaration, ctx: LayoutContext) => number;
11
- }
12
- export declare function buildIncludeRegions(regions: IsolatedRegion[], ctx: LayoutContext, startY: number, deps: IncludeNodeDeps): {
1
+ import type { IsolatedRegion } from '@nowline/core';
2
+ import { type LayoutContext, type LayoutHelpers } from '../layout-context.js';
3
+ import type { PositionedIncludeRegion } from '../types.js';
4
+ export declare function buildIncludeRegions(regions: IsolatedRegion[], ctx: LayoutContext, startY: number, helpers: LayoutHelpers, chartRightX: number): {
13
5
  regions: PositionedIncludeRegion[];
6
+ contexts: LayoutContext[];
14
7
  endY: number;
15
8
  };
9
+ /**
10
+ * Size an include's bounding box to the diagram's content: it reaches past
11
+ * `contentRightX`, the furthest bar, spilled caption, marker or now-line
12
+ * anywhere in the chart (and past its own chrome), by a small right pad,
13
+ * so every region in a chart ends at the same edge (specs/rendering.md,
14
+ * Included Roadmaps). It is clamped to `chartRightX`;
15
+ * finalize grows the canvas to hold the pad first (f3). Finalize runs it
16
+ * once per kept region (f4), after the canvas width is final: the spill
17
+ * growth, the timeline extension and the marker labels can all still grow
18
+ * the canvas after the region is placed.
19
+ */
20
+ export declare function fitIncludeRegionWidth(region: PositionedIncludeRegion, chartRightX: number, contentRightX: number): void;
21
+ /**
22
+ * The width `fitIncludeRegionWidth` gives `region` on a canvas ending at
23
+ * `chartRightX`, with the diagram's content ending at `contentRightX`.
24
+ */
25
+ export declare function includeRegionWidth(region: PositionedIncludeRegion, chartRightX: number, contentRightX: number): number;
16
26
  //# sourceMappingURL=include-node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"include-node.d.ts","sourceRoot":"","sources":["../../src/nodes/include-node.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACR,cAAc,EACd,UAAU,EACV,cAAc,EACd,eAAe,EACf,aAAa,EAChB,MAAM,eAAe,CAAC;AAGvB,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEvE,OAAO,KAAK,EAER,uBAAuB,EACvB,cAAc,EAEd,oBAAoB,EACvB,MAAM,aAAa,CAAC;AAcrB,MAAM,WAAW,eAAe;IAC5B,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,0BAA0B,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,aAAa,KAAK,MAAM,CAAC;CACrF;AAED,wBAAgB,mBAAmB,CAC/B,OAAO,EAAE,cAAc,EAAE,EACzB,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,eAAe,GACtB;IAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAyGtD"}
1
+ {"version":3,"file":"include-node.d.ts","sourceRoot":"","sources":["../../src/nodes/include-node.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,EAAuB,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEnG,OAAO,KAAK,EAAe,uBAAuB,EAAsB,MAAM,aAAa,CAAC;AAuB5F,wBAAgB,mBAAmB,CAC/B,OAAO,EAAE,cAAc,EAAE,EACzB,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,EACtB,WAAW,EAAE,MAAM,GACpB;IAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC;IAAC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAgGjF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACjC,MAAM,EAAE,uBAAuB,EAC/B,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,GACtB,IAAI,CASN;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAC9B,MAAM,EAAE,uBAAuB,EAC/B,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,GACtB,MAAM,CAYR"}
@@ -4,118 +4,151 @@
4
4
  // vertically with the tick row above the region. The label tab is
5
5
  // reserved 18 px above the first region; subsequent regions are
6
6
  // separated by GAP_BETWEEN_REGIONS px.
7
- import { resolveSizes } from '../calendar.js';
7
+ import { translateSwimlaneY } from '../chart-translation.js';
8
8
  import { includeChromeGeometry } from '../include-chrome-geometry.js';
9
+ import { createLayoutContext } from '../layout-context.js';
9
10
  import { resolveStyle } from '../style-resolution.js';
11
+ import { seedWaveEdges } from '../wave-layout.js';
12
+ import { maxLeafItemRightX } from './content-extent.js';
13
+ import { indexFootnotes } from './footnote-node.js';
14
+ import { placeRegionMarkers, regionMarkerLabelsRightX, seedRegionAnchorEdges, } from './region-markers.js';
10
15
  import { SwimlaneNode } from './swimlane-node.js';
11
16
  const TAB_RESERVE = 18;
12
17
  const REGION_INSET_TOP = 14;
13
18
  const REGION_INSET_BOTTOM = 14;
14
19
  const GAP_BETWEEN_REGIONS = 16;
15
20
  // Visual breathing room added past the rightmost element when sizing
16
- // the include's bounding box. Keeps the dashed bracket from butting up
17
- // against an item's right edge while still trimming the wide
18
- // chart-width whitespace left over from full-width sizing.
19
- const INCLUDE_CONTENT_RIGHT_PAD_PX = 32;
20
- export function buildIncludeRegions(regions, ctx, startY, deps) {
21
+ // the include's bounding box. The rightmost element is the diagram's, not
22
+ // the region's own: every region reaches the same edge, past the furthest
23
+ // bar, spilled caption, marker or now-line anywhere in the chart. The
24
+ // renderer insets the dashed rect by 8 px, so its edge sits 16 px past it.
25
+ const INCLUDE_CONTENT_RIGHT_PAD_PX = 24;
26
+ export function buildIncludeRegions(regions, ctx, startY, helpers, chartRightX) {
21
27
  let y = startY + TAB_RESERVE;
22
28
  const out = [];
29
+ const contexts = [];
23
30
  let isFirst = true;
31
+ // Region footnotes number on after the host's, in include order.
32
+ let footnotesBefore = ctx.footnoteIndex.size;
24
33
  for (const region of regions) {
25
34
  if (!isFirst)
26
35
  y += GAP_BETWEEN_REGIONS;
27
36
  isFirst = false;
28
37
  const label = region.content.roadmap?.title ?? region.sourcePath;
29
38
  const innerStartY = y + REGION_INSET_TOP;
30
- const childCtx = {
39
+ const childCtx = createLayoutContext(region, {
40
+ theme: ctx.styleCtx.theme,
31
41
  cal: ctx.cal,
32
- styleCtx: {
33
- theme: ctx.styleCtx.theme,
34
- styles: region.config.styles,
35
- defaults: region.config.defaults,
36
- labels: region.content.labels,
37
- },
38
- // Each include region declares its own sizes; resolve them under
39
- // the parent's calendar so child sized items render at the same
40
- // pixels-per-day scale as the host roadmap.
41
- sizes: resolveSizes(region.content.sizes, ctx.cal),
42
- labels: region.content.labels,
43
- teams: region.content.teams,
44
- persons: region.content.persons,
45
- symbols: region.config.symbols,
46
- footnoteIndex: new Map(),
47
- footnoteHosts: new Map(),
42
+ schedule: ctx.schedule,
48
43
  timeline: ctx.timeline,
49
44
  scale: ctx.scale,
50
45
  calendar: ctx.calendar,
46
+ axisColumns: ctx.axisColumns,
51
47
  bandScale: ctx.bandScale,
52
- entityLeftEdges: new Map(),
53
- entityRightEdges: new Map(),
54
- entityMidpoints: new Map(),
55
- entityVisualLeftX: new Map(),
56
- entityVisualRightX: new Map(),
57
- itemArrowSource: new Map(),
58
- itemFlowKey: new Map(),
59
- currentFlowKey: '',
60
- itemSlackAttachY: new Map(),
61
- slackCorridors: [],
62
- markerRowPlacements: new Map(),
48
+ waves: ctx.waves,
49
+ }, {
63
50
  chartTopY: innerStartY,
64
51
  chartBottomY: innerStartY,
65
52
  swimlaneBottomY: innerStartY,
66
- chartRightX: ctx.chartRightX,
67
- nextParallelId: 0,
68
- nextGroupId: 0,
69
- };
53
+ }, { footnotes: indexFootnotes(region.content.footnotes, footnotesBefore) });
54
+ footnotesBefore += region.content.footnotes.size;
55
+ // Region ids stay invisible to the host, but the wave edges are
56
+ // shared: seed them into the region's otherwise empty edge maps.
57
+ // Without waves, the region's own dated anchors resolve inside it
58
+ // instead, as engine C's `scheduleRegion` resolves them, so a lane
59
+ // `after:kickoff` naming the region's anchor starts on its date
60
+ // (specs/scheduler-unification.md §5 F5).
61
+ if (ctx.waves) {
62
+ seedWaveEdges(ctx.waves, childCtx.entityLeftEdges, childCtx.entityRightEdges);
63
+ }
64
+ else {
65
+ seedRegionAnchorEdges(region.content.anchors, childCtx);
66
+ }
70
67
  const nestedSwimlanes = [];
71
68
  let cursorY = innerStartY;
72
69
  let bandIndex = 0;
73
- let nestedContentRightX = childCtx.timeline.originX;
74
70
  for (const lane of region.content.swimlanes.values()) {
75
71
  childCtx.nextParallelId = 0;
76
72
  childCtx.nextGroupId = 0;
77
- const { positioned, usedHeight, usedRightX } = new SwimlaneNode({ lane, bandIndex }, deps).place({ x: childCtx.timeline.originX, y: cursorY }, childCtx);
73
+ const { positioned, usedHeight } = new SwimlaneNode({ lane, bandIndex }, helpers).place({ x: childCtx.timeline.originX, y: cursorY }, childCtx);
78
74
  nestedSwimlanes.push(positioned);
79
75
  cursorY += usedHeight;
80
76
  bandIndex++;
81
- if (usedRightX > nestedContentRightX)
82
- nestedContentRightX = usedRightX;
77
+ }
78
+ // The region's own anchors and milestones take a marker row under
79
+ // its label tab, and the lanes move down below it.
80
+ const markers = placeRegionMarkers(region, childCtx, y, innerStartY, cursorY, chartRightX);
81
+ if (markers.laneShift !== 0) {
82
+ for (const lane of nestedSwimlanes)
83
+ translateSwimlaneY(lane, markers.laneShift);
84
+ cursorY += markers.laneShift;
83
85
  }
84
86
  const innerEndY = cursorY;
85
87
  // Floor the region height to one row's bandwidth so an empty or
86
88
  // tiny include still presents as a visible band — `bandwidth()`
87
89
  // tracks whatever the host theme uses for swimlane row height.
88
90
  const regionHeight = Math.max(ctx.bandScale.bandwidth(), innerEndY - y + REGION_INSET_BOTTOM);
89
- // Shrink-wrap the include's bounding box to fit chrome + content
90
- // (with a small right pad) instead of stretching to the full
91
- // chart width. An include that reaches past the timeline still
92
- // gets clamped to the chart's natural right edge so it never
93
- // extends into the attribution / right-margin area.
94
- const boxX = 0;
95
- const { chromeRightX } = includeChromeGeometry(boxX, label, region.sourcePath);
96
- const naturalRightX = Math.max(chromeRightX, nestedContentRightX) + INCLUDE_CONTENT_RIGHT_PAD_PX;
97
- const boxWidth = Math.min(ctx.chartRightX - boxX, naturalRightX - boxX);
91
+ // The width waits for the final canvas: finalize (f4) fits every
92
+ // kept region with `fitIncludeRegionWidth` once the canvas stops
93
+ // growing, so placement never reads the canvas.
98
94
  const box = {
99
- x: boxX,
95
+ x: 0,
100
96
  y,
101
- width: boxWidth,
97
+ width: 0,
102
98
  height: regionHeight,
103
99
  };
104
- // Mirror the shrunk width onto each nested swimlane band so the
105
- // tinted background fits inside the dashed bracket instead of
106
- // bleeding past it on the right.
107
- for (const lane of nestedSwimlanes) {
108
- lane.box.width = boxWidth;
109
- }
110
- out.push({
100
+ const positioned = {
111
101
  sourcePath: region.sourcePath,
112
102
  label,
113
103
  box,
114
104
  nestedSwimlanes,
115
105
  style: resolveStyle('swimlane', [], ctx.styleCtx),
116
- });
106
+ };
107
+ if (markers.anchors.length > 0)
108
+ positioned.anchors = markers.anchors;
109
+ if (markers.milestones.length > 0)
110
+ positioned.milestones = markers.milestones;
111
+ out.push(positioned);
112
+ contexts.push(childCtx);
117
113
  y += regionHeight;
118
114
  }
119
- return { regions: out, endY: y };
115
+ return { regions: out, contexts, endY: y };
116
+ }
117
+ /**
118
+ * Size an include's bounding box to the diagram's content: it reaches past
119
+ * `contentRightX`, the furthest bar, spilled caption, marker or now-line
120
+ * anywhere in the chart (and past its own chrome), by a small right pad,
121
+ * so every region in a chart ends at the same edge (specs/rendering.md,
122
+ * Included Roadmaps). It is clamped to `chartRightX`;
123
+ * finalize grows the canvas to hold the pad first (f3). Finalize runs it
124
+ * once per kept region (f4), after the canvas width is final: the spill
125
+ * growth, the timeline extension and the marker labels can all still grow
126
+ * the canvas after the region is placed.
127
+ */
128
+ export function fitIncludeRegionWidth(region, chartRightX, contentRightX) {
129
+ const boxWidth = includeRegionWidth(region, chartRightX, contentRightX);
130
+ region.box.width = boxWidth;
131
+ // Mirror the shrunk width onto each nested swimlane band so the
132
+ // tinted background fits inside the dashed bracket instead of
133
+ // bleeding past it on the right.
134
+ for (const lane of region.nestedSwimlanes) {
135
+ lane.box.width = boxWidth;
136
+ }
137
+ }
138
+ /**
139
+ * The width `fitIncludeRegionWidth` gives `region` on a canvas ending at
140
+ * `chartRightX`, with the diagram's content ending at `contentRightX`.
141
+ */
142
+ export function includeRegionWidth(region, chartRightX, contentRightX) {
143
+ const boxX = region.box.x;
144
+ const { chromeRightX } = includeChromeGeometry(boxX, region.label, region.sourcePath);
145
+ // Bars-only extent (never a spilled caption — see
146
+ // `maxLeafItemRightX`), so a long trailing item caption inside
147
+ // the include can overhang the dashed bracket instead of
148
+ // dragging it wider.
149
+ const barsRightX = maxLeafItemRightX(region.nestedSwimlanes);
150
+ const naturalRightX = Math.max(chromeRightX, barsRightX, regionMarkerLabelsRightX(region), contentRightX) +
151
+ INCLUDE_CONTENT_RIGHT_PAD_PX;
152
+ return Math.min(chartRightX - boxX, naturalRightX - boxX);
120
153
  }
121
154
  //# sourceMappingURL=include-node.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"include-node.js","sourceRoot":"","sources":["../../src/nodes/include-node.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"include-node.js","sourceRoot":"","sources":["../../src/nodes/include-node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ import type { EntityProperty, ItemDeclaration, LabelDeclaration } from '@nowline/core';
2
+ import { type ChipRowSample, type SpillChipPack } from '../item-bar-geometry.js';
3
+ import { type LayoutContext } from '../layout-context.js';
4
+ import { type StyleContext } from '../style-resolution.js';
5
+ import type { LinkIconKind, PositionedCapacity, PositionedLabelChip, ResolvedSize, ResolvedStyle, StatusKind } from '../types.js';
6
+ import { type ItemCaptionMeasure, type ItemNodeGeometry } from './item-node.js';
7
+ /** A label chip measured at its natural width, before it is placed. */
8
+ export type ChipSample = ChipRowSample<LabelDeclaration>;
9
+ export interface ResolvedItemMeta {
10
+ /** Secondary line text under the title, or undefined when none. */
11
+ metaText: string | undefined;
12
+ ownerDisplay: string | undefined;
13
+ capacity: PositionedCapacity | null;
14
+ /** Estimated px width of the capacity suffix (incl. its separator). */
15
+ capacityTrailingWidth: number;
16
+ }
17
+ export interface ItemMeasure extends ItemNodeGeometry {
18
+ node: ItemDeclaration;
19
+ /** The snapped start the bar is measured at (`ctx.scale.startX`). */
20
+ startX: number;
21
+ durationDays: number;
22
+ /** Logical width: the item's span in time. */
23
+ naturalWidth: number;
24
+ /**
25
+ * The bar box width: the logical extent `(startX + naturalWidth) -
26
+ * startX` less the insets, as `ItemNode` has always computed it. The
27
+ * caption fit, the narrow-bar spills and the chip pack read it.
28
+ */
29
+ visualWidth: number;
30
+ /**
31
+ * `naturalWidth` less the insets. Equal to `visualWidth` up to the
32
+ * rounding of the logical extent; the inside-chip fit and the title's
33
+ * first-line reserve read this one, as they always have.
34
+ */
35
+ naturalVisualWidth: number;
36
+ /** Resolved style with the status tint applied (a copy, never the shared object). */
37
+ style: ResolvedStyle;
38
+ /** The `size:` declaration the item names, or null. */
39
+ size: ResolvedSize | null;
40
+ status: StatusKind;
41
+ progress: number;
42
+ meta: ResolvedItemMeta;
43
+ link: {
44
+ icon: LinkIconKind;
45
+ href?: string;
46
+ };
47
+ chips: {
48
+ samples: ChipSample[];
49
+ outside: boolean;
50
+ pack: SpillChipPack<LabelDeclaration> | null;
51
+ rowCount: number;
52
+ };
53
+ footnoteIndicators: number[];
54
+ caption: ItemCaptionMeasure & {
55
+ /** The title as declared (`title ?? name ?? ''`). */
56
+ title: string;
57
+ /** A narrow bar pushes the link icon, and with it the caption, out of the bar. */
58
+ iconSpills: boolean;
59
+ /**
60
+ * The lines the title paints on (see `resolveCaptionTitleLines`),
61
+ * each truncated with `…` when the spilled caption is capped at the
62
+ * chart's end (`capCaptionAtAxisEnd`).
63
+ */
64
+ lines: string[];
65
+ /** True when the cap truncated a line; the full title stays the bar's tooltip. */
66
+ truncated: boolean;
67
+ /** Baseline of the caption's last line, px from the bar's top. */
68
+ lastBaseline: number;
69
+ };
70
+ /** Growth over the band height: max(title extra, chip extra). */
71
+ barExtra: number;
72
+ }
73
+ export declare function statusFromProp(raw: string | undefined): StatusKind;
74
+ export declare function parseLinkIcon(link: string | undefined): {
75
+ icon: LinkIconKind;
76
+ href?: string;
77
+ };
78
+ export declare function buildLabelChip(label: LabelDeclaration, ctx: StyleContext, x: number, y: number, maxWidth?: number): PositionedLabelChip;
79
+ /**
80
+ * Status kind and 0..1 progress fraction for an item: a pure function of
81
+ * the item's properties and the layout scope.
82
+ */
83
+ export declare function resolveItemProgress(props: EntityProperty[], ctx: LayoutContext): {
84
+ status: StatusKind;
85
+ progress: number;
86
+ };
87
+ /**
88
+ * Assemble an item's meta line and capacity suffix. The caption fit needs
89
+ * the real meta width to know whether a title wraps or spills, and
90
+ * `sequenceItem` paints from the same result.
91
+ */
92
+ export declare function resolveItemMeta(props: EntityProperty[], ctx: LayoutContext, sizeResolved: ResolvedSize | null, status: StatusKind, progress: number, capacityIconName: string): ResolvedItemMeta;
93
+ /**
94
+ * Footnote numbers attached to an item, ascending. Per `specs/dsl.md`,
95
+ * footnotes attach via the `on:` property on the footnote declaration
96
+ * only — there is no forward `footnote:` property on the host entity.
97
+ * Walk `footnoteHosts` (built from each footnote's `on:` list) and
98
+ * collect every footnote that names this item. The caption fit needs
99
+ * them, since the indicators narrow the title's first line.
100
+ */
101
+ export declare function collectItemFootnoteIndicators(name: string | undefined, ctx: LayoutContext): number[];
102
+ /**
103
+ * How far the title's first line must stay from the bar's right edge so
104
+ * it clears the top-right decoration cluster.
105
+ */
106
+ export declare function resolveTitleFirstLineReserve(barWidth: number, footnoteIndicators: readonly number[], beforeRaw: readonly string[]): number;
107
+ /**
108
+ * Compute the extra vertical px the bar grows to fit its label chips
109
+ * (a spilled chip column, or inside-bar chips stacked below a caption
110
+ * that reaches past the default chip row). The bar's painted footprint
111
+ * becomes `bandwidth + chipBarExtra`, the progress strip rides the new
112
+ * bottom, and chip rows pack inside the taller bar (anchored from the
113
+ * bar TOP so row 0 doesn't shift when the bar grows).
114
+ *
115
+ * Returns 0 when chips fit inside the bar, when there are no chips,
116
+ * or when the spilled column happens to fit inside `bandwidth` (a
117
+ * single row with the caption inside, for instance).
118
+ *
119
+ * `captionLastBaseline` is the in-bar caption's last text baseline
120
+ * (px from the bar's top): the meta baseline when the item has a meta
121
+ * line, otherwise the last title line's baseline. A wrapped title
122
+ * pushes it down; see `itemCaptionLastBaselineOffset`.
123
+ *
124
+ * The bar's final growth is `max(titleBarExtra, chipBarExtra)`; the
125
+ * same number is the row-pitch increase the swimlane / group
126
+ * row-packer reserves so the next row clears the taller bar.
127
+ */
128
+ export declare function computeChipBarExtra(chipsOutside: boolean, captionSpills: boolean, chipRowCount: number, bandwidth: number, captionLastBaseline: number): number;
129
+ /**
130
+ * Measure `node` as a bar starting at `startX`, the snapped start
131
+ * (`ctx.scale.startX`) it will be placed at. Pure: it writes nothing to
132
+ * `ctx`.
133
+ */
134
+ export declare function measureItem(node: ItemDeclaration, startX: number, ctx: LayoutContext): ItemMeasure;
135
+ //# sourceMappingURL=item-measure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"item-measure.d.ts","sourceRoot":"","sources":["../../src/nodes/item-measure.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAYvF,OAAO,EACH,KAAK,aAAa,EAiBlB,KAAK,aAAa,EACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,aAAa,EAAqB,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAuC,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAIhG,OAAO,KAAK,EACR,YAAY,EACZ,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,UAAU,EACb,MAAM,aAAa,CAAC;AAErB,OAAO,EACH,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EAKxB,MAAM,gBAAgB,CAAC;AAExB,uEAAuE;AACvE,MAAM,MAAM,UAAU,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAC;AAEzD,MAAM,WAAW,gBAAgB;IAC7B,mEAAmE;IACnE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACpC,uEAAuE;IACvE,qBAAqB,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,WAAY,SAAQ,gBAAgB;IACjD,IAAI,EAAE,eAAe,CAAC;IACtB,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,kBAAkB,EAAE,MAAM,CAAC;IAC3B,qFAAqF;IACrF,KAAK,EAAE,aAAa,CAAC;IACrB,uDAAuD;IACvD,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,KAAK,EAAE;QACH,OAAO,EAAE,UAAU,EAAE,CAAC;QACtB,OAAO,EAAE,OAAO,CAAC;QACjB,IAAI,EAAE,aAAa,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC;QAC7C,QAAQ,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,OAAO,EAAE,kBAAkB,GAAG;QAC1B,qDAAqD;QACrD,KAAK,EAAE,MAAM,CAAC;QACd,kFAAkF;QAClF,UAAU,EAAE,OAAO,CAAC;QACpB;;;;WAIG;QACH,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,kFAAkF;QAClF,SAAS,EAAE,OAAO,CAAC;QACnB,kEAAkE;QAClE,YAAY,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAiBlE;AAoCD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAS7F;AAGD,wBAAgB,cAAc,CAC1B,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,YAAY,EACjB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,QAAQ,CAAC,EAAE,MAAM,GAClB,mBAAmB,CAcrB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAC/B,KAAK,EAAE,cAAc,EAAE,EACvB,GAAG,EAAE,aAAa,GACnB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CA0B1C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC3B,KAAK,EAAE,cAAc,EAAE,EACvB,GAAG,EAAE,aAAa,EAClB,YAAY,EAAE,YAAY,GAAG,IAAI,EACjC,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,MAAM,GACzB,gBAAgB,CAyElB;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CACzC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,GAAG,EAAE,aAAa,GACnB,MAAM,EAAE,CAWV;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CACxC,QAAQ,EAAE,MAAM,EAChB,kBAAkB,EAAE,SAAS,MAAM,EAAE,EACrC,SAAS,EAAE,SAAS,MAAM,EAAE,GAC7B,MAAM,CAMR;AAiCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB,CAC/B,YAAY,EAAE,OAAO,EACrB,aAAa,EAAE,OAAO,EACtB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,mBAAmB,EAAE,MAAM,GAC5B,MAAM,CA8CR;AAkED;;;;GAIG;AACH,wBAAgB,WAAW,CACvB,IAAI,EAAE,eAAe,EACrB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,aAAa,GACnB,WAAW,CAkKb"}